1

It looks like the suggested way to set a register to 0 is:

xor %eax, %eax    # like mov $0, %eax  but sets FLAGS

What is the corresponding preferred way to set a register to 1? A few that I've thought of are:

mov $1, %eax
or  $1, %eax        # as discussed in comments, doesn't work for most EAX inputs

Additionally, is there a way in gdb or elsewhere to see quickly see the byte size of an instruction with all its operands? Unless my counting is wrong (and I'm pretty bad at counting in hex) it looks like the size is as follows from gdb:

>>> x/7i $rip
=> 0x400078 <_start>:       xor    %eax,%eax  # 2 bytes
   0x40007a <_start+2>:     xor    %rax,%rax  # 3 bytes
   0x40007d <_start+5>:     or     $0x1,%rax  # 4 bytes
   0x400081 <_start+9>:     or     $0x1,%eax  # 3 bytes
   0x400084 <_start+12>:    mov    $0x1,%eax  # 5 bytes
   0x400089 <_start+17>:    mov    $0x1,%rax  # 7 bytes
   0x400090 <_start+24>:
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
carl.hiass
  • 1,526
  • 1
  • 6
  • 26
  • 2
    `or $1, %eax` won't work. `xor %eax, %eax` and `inc %eax` is the one pops up in my head. It is 3 bytes and may be the shortest. But I would just use `mov` (5 bytes). `or -1, %eax` is a shorter form of `mov -1, %eax`. Keep in mind that they are not the same. `mov` doesn't modify `FLAGS`. – W. Chang Sep 13 '20 at 04:38
  • 2
    BTW, `inc %eax` takes one more byte in 64-bit mode. – W. Chang Sep 13 '20 at 04:44
  • 2
    For what it's worth, all the compilers I checked on [godbolt](https://godbolt.org/z/h55eWx) simply do `mov $1, %eax` (5 bytes), even when optimizing for size. – Nate Eldredge Sep 13 '20 at 06:02
  • 3
    @NateEldredge: `clang -Oz` (optimize for size *without* caring about speed, unlike `-Os`) will use `push $1` / `pop %rax`. That's the only 3-byte way on x86-64 that doesn't depend on some other value in a register. [Tips for golfing in x86/x64 machine code](https://codegolf.stackexchange.com/q/132981). If you know another register value (e.g. zero), you can efficiently use a 3-byte LEA with a `[reg+disp8]` addressing mode to generate small constants. Unfortunately AMD64 didn't bother to provide a `mov r/m32, sign_extended_imm8` using one of the opcodes it freed up :( – Peter Cordes Sep 13 '20 at 10:30
  • 1
    @carl: use `objdump -drwC foo.o` instead of GDB, or even use `nasm -felf64 -l/dev/stdout foo.asm` to make a listing to stdout. Objdump by default hex dumps the machine code, making it very easy to visually count the bytes without having to subtract addresses – Peter Cordes Sep 13 '20 at 10:35
  • 1
    xor-zeroing is not exactly equivalent to `mov $0, %eax`. XOR sets FLAGS, MOV doesn't. But yes, it's better because it's smaller code-size and has no downsides. [What is the best way to set a register to zero in x86 assembly: xor, mov or and?](https://stackoverflow.com/q/33666617) – Peter Cordes Sep 13 '20 at 10:51
  • 2
    Not an *exact* duplicate, but I don't want to re-write the whole linked answer replacing `-1` with `+1` (and dec with inc); basically everything I said there applies here, except for using a single `or` which is not possible here. TL:DR: use 5-byte `mov`-immediate like compilers do. – Peter Cordes Sep 13 '20 at 11:37

0 Answers0