NASM - The Netwide Assembler

NASM Forum => Programming with NASM => Topic started by: anyfoo on July 23, 2019, 09:53:00 PM

Title: Disable relocation, or specify constant to WRT?
Post by: anyfoo on July 23, 2019, 09:53:00 PM

I have code with a special section which is assembled to an ELF object file, for which I do not want any ELF relocations to happen.

Tricks like passing "--section-start=.somespecialsection=0" to ld don't work here, I really want the code to be generated without relocation (selective or for the whole section/file all works for me).

I have code similar to this:

SECTION .somespecialsection progbits alloc exec nowrite align=16

somevar: DB 0


    MOV eax, somevar
    CALL somefunc

For this, NASM creates an object file that will cause the linker to later relocate the value of "somevar" and "somefunc" relative to the section start defined by the linker. I tried several things to turn that off:

ORG. ORG is plain not accepted for ELF, so something like "ORG 0" at the start of the section does not work.

WRT. I tried e.g. replacing the call with "CALL somefunc WRT 0", which I think would make some sense. However, NASM does not seem to accept absolute constants for WRT and instead wants a segment. I also tried to create an "absolute" pseudo segment, but did not find any way.

Subtract the section start. For the MOV, this actually seems to work at first:

MOV eax, somevar-$$   ; $$ = section start

However, while this ultimately has the desired effect, NASM still marks the symbol to be relocated at that place, and we just cancel the effect of the relocation. So as soon as I do this (knowing that the address relative to the section start would be small enough to fit into 16 bits):

MOV ax, somevar-$$

The linker throws an error, because it's still applying the relocation, which in this case does not fit into the operand size.

Is there any way I can just turn off relocation? For a whole file, section, or per symbol individually?
Title: Re: Disable relocation, or specify constant to WRT?
Post by: Frank Kotler on July 24, 2019, 03:21:40 AM
Hi anyfoo,

Welcome to the forum!
I don't know... but here's what I think...
I don't think Nasm's -f elf format will do anything for you. ELF (Executable and Linkable Format) is what it is. Without the relocations it isn't really ELF. Source code for ld is available - maybe you can make that do what you want... or not do what you don't want... Maybe.

"org" is specific to -f bin. You can stuff an ELF or ELF-like executable header into a flat binary file. This may be your best bet. Limited to a single module, of course.

But perhaps we should start at the end... Once you have this "ELF-like but without relocations" file, what are you going to do with it? A "standard" loader won't work. Will it? If you've got a homemade loader that is under your control, maybe you can modify that?

I don't have an answer for you, but I'm willing to discuss it further...


Title: Re: Disable relocation, or specify constant to WRT?
Post by: anyfoo on July 24, 2019, 05:31:39 AM
Hi Frank,

The loader will just normally load the section to the address determined by the linker. But at some later point, the section will be mapped differently, and the code uses segment-relative addressing to deal with that. And I *do* also want to address the symbols from other (C language) source files to resolve to their normal, relocated address.

This is for mixing 16bit and 32bit code, so I acknowledge it's a bit of a special case, but here's the thing why I think that not relocating in places still keeps it "being ELF": I could totally get around the problem by hand-assembling the instructions. E.g. I could write stuff like "DB 0xe8,somefunc-$" instead of "CALL somefunc", or "somefunc-$$" for far calls where the operand is absolute instead of relative.

It would work, it would by all means still be an ELF file, there would just be some instructions in there with immediate operands that the linker won't consider to be symbols at all, which is totally legal. And obviously, I would prefer to let the assembler do the assembling for me.

Maybe "omitting relocations" is actually the wrong way to put it. I think what I want is the ability for the assembler to emit immediate values as operand that it computes from symbols either relative to the start of the section or to the current position (to satisfy near calls and jumps). This does not need relocation at all, as no matter where the section gets relocated to, the results of both of those computations will always stay the same (i.e. in both "$$-symbol = sectionrel-(symboloffset+sectionrel)" and "$-symbol = (currentoffset+sectionrel)-(symbol+sectionrel)", the sectionrel cancels itself out).
Title: Re: Disable relocation, or specify constant to WRT?
Post by: Frank Kotler on July 25, 2019, 02:21:53 AM
Code: [Select]
; nasm -elf23 ekfzero.asm
; ld -o elfzero elfzero.o. -melf_i386

global _start

section .data
msg db "hello", 10
msglen equ $ - msg

;section .bss
absolute 0
msgaddr resd 1

section .text
mov eax, 4
mov ebx, 1
mov ecx, msg
mov edx, msglen
int 80h

mov eax, msg
mov [msgaddr], eax

mov eax, 4
mov ebx, 1
mov ecx, [msgaddr]
mov edx, msglen
int 80h

mov eax, 1
int 80h

As posted, this segfaults... as expected.
With the "absolute" line commented out and "msgaddr" in .bss, it works - prints "hello" twice/

I don't know if it's doing what you want or not. I'm still confused. This is as far as I've gotten.


Title: Re: Disable relocation, or specify constant to WRT?
Post by: anyfoo on July 25, 2019, 09:20:24 PM
If I understand what you're doing here, this requires you to already know where the symbols are relative to the section start. Now, how do you do this with e.g. code labels, without calculating where they are?

At the end of the day, all I want is a constant that's set to how far a symbol is from its section start, without NASM creating a relocation entry for it in the object file.

This does create such a constant as the operand for the "mov eax":

Code: [Select]
mov ecx, msg-$$

But it also creates a (redundant, unwanted) relocation entry. Because change it into this:

Code: [Select]
xor ecx, ecx
mov cx, msg-$$

And while NASM still assembles it fine, ld will emit an error because it has to truncate the relocation to 16bit. Were it an actual constant without a relocation entry, the constant (which in your example combined with mine is 0, because msg is flush at the start of the section) would fit into 16 bits without problem.

My workaround is to actually do e.g. "mov eax, $$-somefun; call ax", but this wastes a register for no reason. There is vm86 code in there, which is why the CALL operand is 16bit. Try "call $$-somefun", and you get the same relocation truncation error from the linker for that reason.
Title: Re: Disable relocation, or specify constant to WRT?
Post by: Frank Kotler on July 26, 2019, 04:08:34 AM
Hi anyfoo,

I dunno. My example segfaults because there's no physical
memory mapped to virtual zero, where my variable is. No surprise.

I'm not too surprised that ld balks at a 16-bit relocation, but I don't know much about the inner workings of ld. My attempt to use wrt got a message that ld didn't use wrt "that way". It uses "wrt got" or "wrt plt", ect. If your environment has a Global Offset Table and/or a Procedure Llnkage Table, maybe you could use them?

Perhaps you could modify the code in outelf,c to not generate a relocation entry in certain cases, I don't know what ld would think about that.

I think you're really over my head here. I doubt if I''m going to be able to help you much...