0

I'm studying x86-64 assembly and for code to store a strings in a char* array;

char *name[2];  
name[0] = "Name";
name[1] = "null";

here's the assembly generated by the compiler (function prologue immediately precedes this):

mov    %fs:0x28,%rax
mov    %rax,-0x8(%rbp)
xor    %eax,%eax
lea    0x9689d(%rip),%rax
mov    %rax,-0x20(%rbp)
lea    0x9689a(%rip),%rax
mov    %rax,-0x18(%rbp)

To the best of my knowledge, I believe this copies the address of the supposed string into the rax register and then into the address space at an 8-byte negative offset from the rbp register. The next three instructions, however, I'm lost out on. I believe the xor %eax,%eax instruction, stores the value 0 in the eax register.

I'm not sure exactly what the lea 0x9689d(%rip),%rax and lea 0x9689a(%rip),%rax instructions are supposed to do. My guess is, copy the address stored in the rip (64-bit instruction pointer) register to the rax register? (with it's lower 32-bits now zero, thanks to the xor instruction?).

First question

Am I right or wrong with that assumption? And why the compiler chose those instructions? (Recall, rax register held the address to the string)

Second question

And why didn't the compiler just copy the addresses of the string like it did in the first instruction %fs:0x28,%rax?

Third question

As local variables, the first string's address was stored at a negative 8-byte offset from the rbp. Why is the second string stored at offset of negative 24-bytes (16 bytes away from the first string instead of just 8), and I'm guessing '/0' character stored at offset of negative 32-bytes?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
clancy
  • 101
  • 5
  • [`xor %eax,%eax` zeros the full RAX](//stackoverflow.com/q/11177137) and see [xor zeroing](//stackoverflow.com/q/33666617). It's a GCC missed optimization that GCC includes that as part of `-fstack-protector-strong` to avoid leaving the stack cookie in a register, even though it's about to overwrite the register anyway with LEA, which also writes the whole destination. It's just generating addresses in a PIE-compatible way. [How to load address of function or label into register](https://stackoverflow.com/q/57212012) – Peter Cordes Oct 05 '22 at 11:32
  • 1
    Did you consider to use [Compiler Explorer](https://godbolt.org/) to investigate? It shows which line in C translates to what instructions in assembly. -- Which compiler in what version and with which command line did you use? – the busybee Oct 05 '22 at 11:33
  • The two string addresses (LEA results) are stored adjacent to each other. To avoid the distraction of the stack cookie stuff with `%fs:0x28` while you're learning the basics, compile with `-fno-stack-protector`. – Peter Cordes Oct 05 '22 at 11:37
  • A `char *strings[2]` array won't contain any characters directly, only pointers. The string literals have `'\0'` terminators, but there isn't a zero byte in the array of pointers (except as part of addresses, not a separate terminator.) If you did `char str[] = "hello world";`, as a local var, then the compiler would store character data to the stack, including the implicit terminator. – Peter Cordes Oct 05 '22 at 11:44

0 Answers0