0

I am trying to place the value of 2^32 - 1 (4294967295) into a long label through the following code:

.data
    num:
        .long 4294967295

However, when I look at the data in the register after I push the variable to the register (movl num, %ecx), the dividend is displayed as -1. The program is running on a 32-bit computer. This seems strange, since shouldn't a 32-bit long be able to store 2^32 - 1 = 4294967295?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Adam Lee
  • 436
  • 1
  • 14
  • 49
  • 2
    As 32-bit integers, 4294967295 and -1 are the same; it's just a question of whether you interpret the value as unsigned or signed. – Nate Eldredge Nov 03 '20 at 02:46
  • @NateEldredge How do I force my Assembly program to interpret the value as unsigned? – Adam Lee Nov 03 '20 at 02:53
  • You write code such that, in the few places where it makes a difference, you execute instructions that do the right thing for unsigned values. For instance, when comparing, you use `ja/jb` instead of `jg/jl`, and you use `mul/div` instead of `imul/idiv` when multiplying or dividing. And when outputting the number, you format it appropriately (e.g. `printf` with `%u` instead of `%d`). If you would show your actual code and why you think it is wrong, it would help. – Nate Eldredge Nov 03 '20 at 03:00
  • 1
    If you are inspecting the register in a debugger, you simply need to tell the debugger to print the value as unsigned. For instance, in gdb, `print/u $ecx`. But that has nothing to do with the program itself. – Nate Eldredge Nov 03 '20 at 03:00
  • @NateEldredge Is there a link to a resource of x86 AT&T syntax commands pertaining to unsigned number usage (I know comparing is ja/jb, but what about addition/subtraction/right shift/left shift)? – Adam Lee Nov 03 '20 at 03:27
  • I don't know a comprehensive list, and since the x86 instruction set is constantly growing, it'd be hard to rely on it being complete. Ideally, you would find out what each instruction does, and whether it's appropriate for the task at hand, *before* you write it. However, addition and subtraction are the same - this is a very important property of two's complement arithmetic - as is left shift. Right shift is different; `shr` versus `sar`. There is also the issue that when moving smaller operands into larger registers, you need to decide whether to zero- or sign-extend. – Nate Eldredge Nov 03 '20 at 03:32
  • Any instructions that specifically treat a number as signed vs. unsigned will say so. e.g. AVX-512 [`vcvtusi2sd`](https://www.felixcloutier.com/x86/vcvtusi2sd) to do unsigned->double conversion instead of [`cvtsi2sd`](https://www.felixcloutier.com/x86/cvtsi2sd) signed conversion. Or [`pmaddubsw`](https://www.felixcloutier.com/x86/pmaddubsw) which carefully documents that one operand is treated as a vector of signed bytes, the other as unsigned bytes. (Translating from Intel to AT&T syntax is always just reversing the order of the operand list.) – Peter Cordes Nov 03 '20 at 03:44
  • But as Nate said, for assembling numbers into binary data in memory with `.long`, it's just a matter of how you display it in your debugger. There isn't an unsigned version of `.long`, that wouldn't make any sense. The same bit-pattern goes into memory either way (all-ones), it's a matter of interpreting it the correct way when you print it. – Peter Cordes Nov 03 '20 at 03:45

0 Answers0