1

So I saw some code

.LC0:
        .string "Hello world"
main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:.LC0
        call    puts
        xor     eax, eax
        add     rsp, 8
        ret

From what I've gathered, OFFSET FLAT is used when the memory model is flat. OFFSET would have translated to a segment selector (DS) and OFFSET, whereas OFFSET FLAT translates to an absolute address of the label LC0 relative to 0 (seeing as that's the base of the DS segment in flat mode), which the linker resolves after it is assembled.

But why edi and not rdi? Why wouldn't the instruction be mov rdi, moffs64? The label will have a 64 bit address. I thought maybe it's because the ELF base will be at 4MiB on linux? (although I don't know much about Linux kernel, only Windows, where it''s at 0x140000000). So maybe this is a size optimisation of the instruction, but doesn't this preclude the data section from being larger than 4GB? (not that it ever would be). Is it just safely assumed that it won't be?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Lewis Kelsey
  • 4,129
  • 1
  • 32
  • 42
  • 1
    This *is* GAS `.intel_syntax noprefix`. It's not A&T; it's GAS's other syntax. – Peter Cordes Apr 03 '20 at 05:46
  • And yes, `mov r32, imm32` for symbol addresses is an optimization for non-PIE GNU/Linux executables (not PIC / PIE shared objects), because the default code model places all static code/data in the low 2GiB of virtual address space. You need to use a different code model if you have more than 2GiB of static data, like a huge BSS array. See the x86-64 System V ABI docs. – Peter Cordes Apr 03 '20 at 05:47
  • 1
    *Why wouldn't the instruction be `mov rdi, moffs64`* Because [that's](https://www.felixcloutier.com/x86/MOV.html) a 64-bit load from a 64-bit absolute memory address, and only works with an RAX destination. On Godbolt use `-fPIE` to get GCC to use RIP-relative LEA when 32-bit absolute doesn't work. – Peter Cordes Apr 03 '20 at 05:51
  • @PeterCordes I entirely forgot about ASLR when writing this, which just furthers the point of my original question, which you answered. And oh, yeah, I forgot about that. I'm guessing theres no ModRM byte so it establishes `rax` as a default – Lewis Kelsey Apr 11 '20 at 22:07
  • 1
    Right, as you can see from the encoding table (https://www.felixcloutier.com/x86/mov#instruction-operand-encoding), and from the lack of a `/r` in the table above it, there's no ModRM in the `moffs` AL/AX/EAX/RAX forms. Yes, the accumulator is an implicit operand, implied by the opcode. It's not a "default" per se because there's no way to specify anything else for that opcode. Anyway, this is different from `mov reg, imm64` - that is available for any register because it's much more commonly useful. Also, you wouldn't want 64-bit absolute anyway; it's even larger than RIP-relative LEA. – Peter Cordes Apr 11 '20 at 22:11
  • @PeterCordes yes it seems /digit is only r/m where reg is an optional opcode extension (000 for immediate instructions), /r is reg+r/m and nothing is no ModRM. I understand now that yes it's an optimisation for non-PIE that is smaller than using rip-relative lea (5 bytes instead of 6 due to lack of ModRM), or indeed 64 bit moffs, but rip-relative lea on an ASLR binary would be smaller than moffs64 as in most cases 32bit disp could be used . – Lewis Kelsey Apr 11 '20 at 23:43
  • 1
    RIP-relative LEA is 7 bytes because it also needs a REX prefix unless I guess you're using it just for position-independence in an ILP32 ABI (like Linux x32) with addresses only randomized into the low 4GiB of virtual address space. x86-64 Linux/ELF randomizes into the whole 47-bit low-half canonical range of virtual address space so truncating the result with 32-bit operand-size would lead to segfaults (the X86_64_PC32 relocation wouldn't cause a problem at link time; it's still a RIP+rel32 addressing mode. There is no RIP+rel64). MacOS also has the default base address outside the low 32 – Peter Cordes Apr 12 '20 at 00:20

0 Answers0