0

In my FASM project (Object), I'm trying to create a jump-table and I use dq for each jump address but there is a problem!
For each dq .jmp1 (jump address definition), 24 bytes more (plus 8 bytes for .jmp1 address (totalling 32 bytes)) will be added to my final .o file's total size!
What is that extra 24 bytes? Is there any way to avoid it? This happens only in object file, not in executable!

Instead of 8 bytes for each jump address, it defines 32 bytes! What is the problem?

format ELF64

section '.text'

func:
        lea     rax, [8*rax+.jmp_table]

 .jmp1:

 .jmp_table:
        dq .jmp1 ; 8 bytes + 24 bytes !!! (to .o total size)
        dq .jmp1 ; 8 bytes + 24 bytes !!! (to .o total size)   

But when I create an executable, each dq takes only 8 bytes (what I expect) ...

format ELF64 EXECUTABLE

segment readable executable

func:
        lea     rax, [8*rax+.jmp_table]

 .jmp1:

 .jmp_table:
        dq .jmp1 ; 8-BYTE, no extra 24 bytes to .o total size
        dq .jmp1 ; 8-BYTE, no extra 24 bytes to .o total size
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
HelloMachine
  • 355
  • 2
  • 8
  • 1
    "But when I create an executable" - I don't understand. How are you determining that the `dq` takes up 32 bytes, if not by creating an executable? – ecm May 08 '22 at 17:20
  • 1
    @ecm: FASM can create an executable *directly*, instead of creating a `.o` that you can link with `ld`. – Peter Cordes May 08 '22 at 17:41
  • 1
    Please show the actual test that led you to conclude they are 32 bytes. Hex dump of the executable? Single-step in a debugger? Show the exact command(s) you executed and the complete output that they produced. – Nate Eldredge May 08 '22 at 17:43
  • 1
    I can't reproduce this when making a `.o`. Putting `times 20 nop` before/after this, and looking at the `.o` with `hexdump -C`, there's clearly not 32 bytes, let alone 64, between the LEA bytes and start of the next block of `90 90 90` ... bytes. Only the expected 16 = 2x8. I used FASM 1.73.27 on x86-64 GNU/Linux. – Peter Cordes May 08 '22 at 17:45
  • @NateEldredge both sources are very simple ... in the first sample, by adding each dq .jmp1, 32 bytes will be added to your object file. in the second sample, 8 bytes... – HelloMachine May 08 '22 at 17:46
  • @PeterCordes so in the first code, why 32 bytes will be added to object-file for each 'dq .jmp1' ??? you can add more 'dq .jmp1' and you get 32 bytes extra, for each dq ... – HelloMachine May 08 '22 at 17:47
  • 2
    @HelloMachine: Oh, you're talking about the total size of the `.o` object file, not 32 bytes in the .text section itself? Yeah, there's the space in `.text`, and there's a relocation entry so the linker can fill in the correct absolute address. The `dq` doesn't *define* 32 bytes in the output for that section like your title implies, though. – Peter Cordes May 08 '22 at 17:47
  • 1
    So you should *definitely* update your question with exactly what you mean, (and how you measured, i.e. by looking at the total size of the `.o` (which is what FASM reports when running), not the bytes in the `.text` section), like @Nate said. – Peter Cordes May 08 '22 at 17:49
  • @PeterCordes Ok ... i delete this question and create a new one ... thank you very much .. – HelloMachine May 08 '22 at 17:50
  • 3
    don't delete this. **[edit]** this, to say what you mean. (Or some version of what you meant before you found out the answer.) Never delete a question and post a new version of it in response to comments, unless the existing question was answerable and there already are answers. – Peter Cordes May 08 '22 at 17:50
  • 3
    According to https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-54839.html, x86-64 uses Elf64_Rela relocation entries, which consist of 3 x 64-bit words. So that's 24 bytes, which together with the 8 bytes in the text section itself, would perfectly explain your 32 byte increase in .o file size. – Nate Eldredge May 08 '22 at 17:51
  • @PeterCordes question updated – HelloMachine May 08 '22 at 17:58

1 Answers1

9

Remember that a .o file is not just a flat image of the code and data you assembled; it also contains metadata, such as relocations.

Since dq .jmp1 references a symbol whose absolute address will not be known until after linking, it requires a relocation entry. The link above shows that ELF on x86-64 uses Elf64_Rela relocation entries, which are 24 bytes. So the 8 bytes of actual data, plus 24 bytes of metadata, accounts exactly for the 32-byte increase in file size. (It could be more or less in other instances, e.g. perhaps due to padding for alignment requirements.)

Once linking is complete, the relocation metadata is not included in the executable, so the executable size increased only by the size of the actual data.

So what you're seeing is completely normal and there is nothing to avoid. The jump table entries will in fact occupy 8 bytes in program memory, and the arithmetic of your lea rax, [8*rax+.jmp_table] remains correct.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82