flat assembler
Message board for the users of flat assembler.
![]() |
Author |
|
Tomasz Grysztar 24 May 2018, 20:04
The difference between PE fixups and "classic" relocations in object format is that in case of PE the program image moves as a whole within memory, so relative offsets between any code or data cannot change, only the base address of entire image.
Therefore any instructions that use RIP-relative addressing, where the relative offset between the instruction and target object is used in the opcode, is not going to generate fixup. In this case it is "LEA RAX,[TheSymbol]" that automatically uses RIP-relative addressing and thus needs no relocating. However both "MOV RAX,TheSymbol" and "PUSH TheSymbol" use the absolute address as an immediate and this (as opposed to offsets within image) changes when the image is moved (that is when the base address is changed from the default). Therefore both these instructions are going to generate fixup entries and they need to be relocated by the loader. If the address that ends up on the stack after that PUSH is not a valid one, it might be some other issue in your code, because fasm certainly generates a fixup for such PUSH when the ".reloc" section is defined. |
|||
![]() |
|
pfranz 25 May 2018, 14:24
;From my tests on FASM 1.73.02, MOV generates relocation information, PUSH and CMP do not.
format pe64 efi entry Main section '.text' code executable readable Main: and spl, 11110000b sub rsp, 4 * 8 mov rcx, [rdx + 64] ;EFI_SYSTEM_TABLE.ConOut mov rdx, msg cmp rdx, msg jne .ValuesAreDifferent call qword [rcx + 8] ;SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString .ValuesAreDifferent: jmp $ section '.data' data readable writeable msg dq 4300420041h section '.reloc' fixups data discardable |
|||
![]() |
|
Tomasz Grysztar 25 May 2018, 14:46
It is easy to test which instruction generates fixups by counting words in the automatically generated contents of the fixups table:
Code: format pe64 efi section '.text' code executable readable mov rdx, msg ; comment out instructions or add new ones cmp rdx, msg ; to test how many fixups are generated push msg lea rdx,[msg] lea rdx,[rbx+msg] section '.data' data readable writeable msg dq ? section '.reloc' fixups data discardable display '0' + ($-$$)/2 You may also test that this: Code: lea rdx,[msg] Code: lea rdx,[rbx+msg] PS. You could also use a bit more advanced code to count the actual fixups in the first block: Code: section '.reloc' fixups data discardable load size dword from $$+4 count = '0' repeat (size-8)/2 load fixup word from $$+8+(%-1)*2 if fixup count = count + 1 end if end repeat display count |
|||
![]() |
|
Tomasz Grysztar 25 May 2018, 15:03
I have just realized what might the problem you encountered. MOV is the only instruction of these three that is able to use 64-bit immediate (and thus a full-size 64-bit fixup is then generated). PUSH and CMP can only be encoded with 32-bit immediates and the fixups are also 32-bit then. If the base address turns out to be outside of the 32-bit range, 32-bit immediates obviously are not going to contain correct values. The 32-bit fixups should then actually fail in the loader.
But there may also be a problem with sign-extension here. 32-bit immediates are sign extended in these instructions, if 32-bit addresses created by the loader when applying fixup have the highest bit set, they are going to be incorrectly sign-extended with 0FFFFFFFFh in the high double word. |
|||
![]() |
|
Tomasz Grysztar 25 May 2018, 15:17
Here's an improved version of my fixup-counting code, this one should show you how many 64-bit ones and how many 32-bit ones are generated. Only MOV or a definition like DQ can generate a 64-bit one.
Code: section '.reloc' fixups data discardable load size dword from $$+4 count32 = '0' count64 = '0' repeat (size-8)/2 load fixup word from $$+8+(%-1)*2 fixup_type = fixup shr 12 if fixup_type = 10 count64 = count64 + 1 else if fixup_type = 3 count32 = count32 + 1 end if end repeat display '64-bit: ',count64,13,10,'32-bit: ',count32,13,10 |
|||
![]() |
|
pfranz 30 May 2018, 17:40
The problem was actually the sign extension you mentioned.
Why are 32bit relocations allowed? They generate incorrect code like in my example. |
|||
![]() |
|
Tomasz Grysztar 31 May 2018, 12:21
pfranz wrote: Why are 32bit relocations allowed? They generate incorrect code like in my example. If you'd like to disable 32-bit relocations in the PE format, the simplest solution I can recommend right away is to use fasmg and customize PE.INC for your project by removing/disabling "macro dword?". |
|||
![]() |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.