Normally, in x86, to load a pointer to a null-terminated string you would use

MOV EDX, OFFSET ds:mystring

In x64, however, I noticed that the compiler does it like this

lea rdx, OFFSET FLAT:$mystring ; 'it is ten'

Why is that?


If you disassemble the instructions for

mov edx, offset ds:mystring


lea rdx, offset ds:mystring

You'll notice the LEA instruction length (in bytes) was smaller. Its a compiler optimization!

Or, it could be the compilers way of addressing pointer arithmetic in an easier manner.

Check out this for more info on both.

  • 1
    it's incorrect. mov edx, offset is 5 bytes long, whereas lea rax, offset is 7 bytes long. The 64-bit version is longer partly due to the REX prefix – phuclv Jul 22 '18 at 17:12
  • check the source i cited; its a known compiler trick that also relies on whether or not $RDX is treated as a pointer in his example. Generally the compiler will do this because its usually a shorter series of bytes (if $RDX is used as a pointer, of which most C++ functions do for string operations). – grepNstepN Mar 5 '19 at 18:13
  • Your link doesn't even work. Checked the archive and I don't see it says LEA is shorter anywhere. Probably I copied the wrong Godbolt link in the comment above. Here's another one. One can clearly see that the compiler outputs a longer LEA. In fact there are many mov reg, imm forms from 5 to 10 bytes. mov reg, [mem] will be longer if you need an SIB byte or REX prefix. Same to LEA – phuclv Mar 6 '19 at 2:44
  • You need to read the instruction encoding from Intel's manual, not from a blog. Or check it from the real assembler output. You can also paste mystring: mov edx, offset ds:mystring; lea rdx, [ds:mystring] into the only assembler and see the output. The LEA version is always longer because the immediate must be encoded as the memory displacement. There's no lea reg, imm version like mov reg, imm – phuclv Mar 6 '19 at 2:49
  • the link works. – grepNstepN Mar 19 '19 at 23:08

Your Answer

