8

I know this is a really simple question, but I couldn't find an answer to this. Are the registers in x86 assembly (eax, ebx edx etc) signed or unsigned? If they're signed by default, how does the computer know to treat the registers as unsigned if for example we will declare a variable as unsigned int? Thanks!

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
user3604597
  • 251
  • 1
  • 5
  • 8
  • 3
    Registers simply hold a fixed number of bits. The instructions used will determine how the bits are treated. The same is true for memory. – Jeff Dec 28 '14 at 15:52
  • 2
    Some instructions, such as add or subtract, are the same for signed or unsigned values. The borrow / carry flag is set assuming the numbers are unsigned, while the overflow flag is set assuming the numbers are signed. Other instructions, like multiply or divide, have signed and unsigned versions. Most instructions that set the sign will set the sign flag (SF) equal to the most significant bit of the result, which is a sign flag if the number is assumed to be signed. – rcgldr Dec 28 '14 at 15:55
  • 7
    Types are an illusion provided by high-level languages. – harold Dec 28 '14 at 17:18

2 Answers2

11

The CPU does not know nor does it care. Instead, bits in the Flags register are set on certain operations, and how your program acts on those flags depends on what the source code told it to.

E.g.,

mov eax, 0FFFFFFFFh
test eax, eax
js isNegative

vs.

mov eax, 0FFFFFFFFh
test eax, eax
jb isNegative

The first jumps to 'IsNegative' because test sets the Sign Flag here. The second does not, because test resets the Carry Flag to 0 and jb only jumps if it is 1.

Jongware
  • 22,200
  • 8
  • 54
  • 100
  • 2
    Note that `x < 0` is *always* false for an unsigned compare, so actually writing `test same,same` / `jb` is something you'd never do in real life. The condition is known to be false (not take) for every possible EAX value, including zero. Perhaps a better example would be `cmp eax, 10` for signed vs. unsigned `eax < 10`. (Then you'd need to use `jl`, not `js`, for the signed condition.) – Peter Cordes Oct 22 '20 at 08:17
1

32-bit registers in x86 are default unsigned. For example, a move from 32-bit operand to a 64-bit register always get zero-extended under long model. But instructions each has its own interpretation of registers based on its purpose, like 'add' instruction take registers both signed or unsigned. You should refer intel documents for detail.

Jacky Tsao
  • 19
  • 4
  • 5
    That's an awkward way to state it. In `mov eax, ecx`, both operands are 32-bit. Writing a 32-bit register always [implicitly zero-extends into the full 64-bit register](https://stackoverflow.com/questions/11177137/why-do-most-x64-instructions-zero-the-upper-part-of-a-32-bit-register), but the only way to *explicitly* do a 32->64 bit move is with `movsxd rax, ecx` (which sign-extends). `mov rax, ecx` won't assemble (operand-size mismatch). There's no form of `movzx` with a 32-bit source, because you don't need it (just use `mov`). So it's actually impossible to *explicitly* zero-extend 64. – Peter Cordes Nov 20 '17 at 23:03