flat assembler
Message board for the users of flat assembler.

flat assembler > Compiler Internals > Relocations problem

Author
Thread Post new topic Reply to topic
pfranz



Joined: 13 Jan 2007
Posts: 49
Location: Italy
I am still working on a EFI64 (PE64) program.
I don't quite understand the way FASM treats a label as "relocatable".

Suppose TheSymbol is defined in a .data section, and there is a .reloc section with fixups.
In the .code section, it seems to me that:

mov rax, TheSymbol
lea rax, [TheSymbol]

make TheSymbol relocatable, while

push TheSymbol

does not. When exactly is a label reloacatable? How can I make TheSymbol relocatable in the latter example?

Thanks in advance
Post 24 May 2018, 14:24
View user's profile Send private message Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6996
Location: Kraków, Poland
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.
Post 24 May 2018, 20:04
View user's profile Send private message Visit poster's website Reply with quote
pfranz



Joined: 13 Jan 2007
Posts: 49
Location: Italy
;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
Post 25 May 2018, 14:24
View user's profile Send private message Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6996
Location: Kraków, Poland
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    
Each new fixup adds an additional 16-bit word to the table, and 4 words (2 double words) go to set up the block header, so you should see number 5 if there is one fixups in the block, 6 if there are two, etc. The above example shows number 7, that is three fixups are generated - one for each of the MOV, CMP and PUSH instructions.

You may also test that this:
Code:
        lea     rdx,[msg]    
does not create a fixup, since it uses RIP-relative addressing, but this one does:
Code:
        lea     rdx,[rbx+msg]    
because this one cannot be encoded as RIP-relative.

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    
This should be more reliable (as long as the entire code section you test fits in one 4096-byte page, as then only one block of fixups is needed).
Post 25 May 2018, 14:46
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6996
Location: Kraków, Poland
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.
Post 25 May 2018, 15:03
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6996
Location: Kraków, Poland
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    
Post 25 May 2018, 15:17
View user's profile Send private message Visit poster's website Reply with quote
pfranz



Joined: 13 Jan 2007
Posts: 49
Location: Italy
The problem was actually the sign extension you mentioned.
Why are 32bit relocations allowed? They generate incorrect code like in my example.
Post 30 May 2018, 17:40
View user's profile Send private message Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6996
Location: Kraków, Poland
pfranz wrote:
Why are 32bit relocations allowed? They generate incorrect code like in my example.
They were added at the request. Please read to the end of that thread. You may notice that at the time I did point out the problem of ensuring that the image resides in the low 2G address space.

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?".
Post 31 May 2018, 12:21
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2018, Tomasz Grysztar.

Powered by rwasa.