0
int main() {
    int64_t di = -10;
    uint64_t ui = UINT64_MAX - 9;

    return 0;
}

When I disassemble main it gives me this output:

Dump of assembler code for function main:
   0x0000000000001119 <+0>:     push   rbp
   0x000000000000111a <+1>:     mov    rbp,rsp
   0x000000000000111d <+4>:     mov    QWORD PTR [rbp-0x10],0xfffffffffffffff6
   0x0000000000001125 <+12>:    mov    QWORD PTR [rbp-0x8],0xfffffffffffffff6
   0x000000000000112d <+20>:    mov    eax,0x0
   0x0000000000001132 <+25>:    pop    rbp
   0x0000000000001133 <+26>:    ret    

Both of them are 0xfffffffffffffff6 I understand one bit in signed variable is to determine its sign but how it knows it is signed or unsigned variable. Maybe it sets some flag idk

Kanony
  • 509
  • 2
  • 12
  • 1
    See also: [How does assembly code know if a value is signed or unsigned?](https://stackoverflow.com/q/40276790/555045) – harold Apr 08 '22 at 22:09
  • The assembler doesn't really know or care; the processor doesn't really know or care. The only one that will care is the program, so the program's machine code should be written to work with appropriate data types. In your example, the program doesn't *use* these values; if it did (e.g. compare each against 100) you would see a difference. – Erik Eidt Apr 08 '22 at 22:57

2 Answers2

4

The assembler does not know whether a signed or an unsigned value is stored. How the value will be interpreted depends on which machine instructions the compiler will generate for dealing with the value.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
4

In this processor architecture, and commonly in today’s processors, there is no indication of whether the bits in a register are a signed integer, an unsigned integer, an address, or something else. There is no type information associated with the register; it is simply a sequence of bits.

When you write additional C code to use the data, such as a test if (di < 3) …, the compiler will generate instructions that depend on the type of data. For example, there is a compare instruction that produces several bits describing the relationship between two numbers, and there are branch instructions that use those bits to perform branches such as “branch if the first number is less than the second number using a signed interpretation.” Thus, the type information is built into the assembly instructions that use the data.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • okay, let's say I added that `if (di < 3) …` line how it knows if `di` is bigger or smaller than 3 if it's just sequence of bits what else have to be generated/set to compare them? – Kanony Apr 08 '22 at 21:14
  • 1
    The other thing that has to be generated is the choice of instructions The processor will most likely offer two sets of instructions, one that performs signed operations and one that performs unsigned operations. It is the job of the compiler to choose the right instruction based on the types involved in the expression (or the programmer if working directly at the assembly code level). – SoronelHaetir Apr 08 '22 at 21:53
  • @SoronelHaetir can't we see behind the scenes like what step by step done by compiler to do so? – Kanony Apr 08 '22 at 22:02
  • If using gcc you can use the -S option and get the assembly-language output from the compiler. I know MSVC has a similar option but I don't know what it is off-hand. You can also use objdump (dumpbin if using MSVC) and get disassembly from binaries. – SoronelHaetir Apr 08 '22 at 22:38
  • @SoronelHaetir: https://godbolt.org/ has MSVC asm output. – Peter Cordes Apr 08 '22 at 23:58