Relocatable ELF Object Help

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
alexfru
Member
Member
Posts: 1111
Joined: Tue Mar 04, 2014 5:27 am

Re: Relocatable ELF Object Help

Post by alexfru »

klange wrote:
alexfru wrote:So, it looks like you're loading object files, not executable ones?
Yes, you'll find that my relocatable object loader loads relocatable objects. :wink: There is an executable loader in the function below that, though. There's also a dynamic linker but that is in userspace...
alexfru wrote:Do I understand it correctly that a proper ELF executable that can be loaded anywhere (because of ASLR or lack of page translation) needs to have a whole bunch of extra sections for the dynamic loader, even where a simple object file would suffice?
Don't confuse position independence with dynamic executables: you can have one, the other, both, or neither.
I don't think I am.
klange wrote:Time for some rambling:

Object files can represent any sort of code: executable, library; static, dynamic; position-independent or not... But regardless of what's in them, you absolutely need a linker to turn them into a final product - they are only an intermediary format. Object files consist only of sections, and lack the program headers found in executables and shared objects.
Right.
klange wrote:On most architectures, position-independent executables and libraries can actually be built statically and without any extra sections through the use of "thunks" and native IP-relative addressing schemes. On x86-32 these were notably slower at runtime than patched up absolute code, which was a very good reason to pick relocatable objects for device drivers. x86-64 and various other architectures don't suffer from the same speed impact, with x86-64 in particular introducing RIP-relative instructions.

The main benefit behind position-independent code, even when it does involve relocations - which it will in the case of a dynamic library that references other libraries as relocations are what fills in the addresses of runtime-resolved symbols - is that the relocations are moved away from the code so that the number of pages that need to be modified per-process is minimized (usually through a global offset table). This means you can "load once, run anywhere" in the sense that you can have a shared library in physical memory once and then map it into userspace memory layouts for every process that references that library, and they'll only need their own private copies of the small set of pages with relocations.
Let me sort of rephrase or explain myself... I kinda know how to handle ELF object files (I have written a linker that links them statically) and I know how to make ELF executable files (with 2 segments for code and data and nothing else) that are non-relocatable. I also know how to make PE executable files that are relocatable (there's a very simple relocation table in the file in addition to the segments/sections containing code/data). If I wanted relocatable ELF executables similar to relocatable PE executables, how would I do that?

Can I just slap relocations onto an ELF executable?

Or maybe instead slap program segments onto an ELF object file?

Or do I need to do something different altogether? Like really produce position independent code in the first place, but then how would I tell the OS/loader that it may safely load it anywhere instead of the address(es) mentioned in the various ELF headers?

Technically, to relocate an executable at load time (for simplicity, say, x86-32), the simplest solution is to just add a constant to a bunch of locations within the executable file to adjust the addresses up or down (and a table would tell which locations those are). I'm pretty much describing what happens with PEs in Windows. But what's the equivalent for this in the ELF executables? How do I express it? Do I make an ELF file that has both relocations and program segments? Do I use some of all of those things from the dynamic loader world even if I don't intend to link to e.g. glibc's printf()?
klange
Member
Member
Posts: 679
Joined: Wed Mar 30, 2011 12:31 am
Libera.chat IRC: klange
Discord: klange

Re: Relocatable ELF Object Help

Post by klange »

alexfru wrote:Can I just slap relocations onto an ELF executable?
Sure.
alexfru wrote:But what's the equivalent for this in the ELF executables? How do I express it? Do I make an ELF file that has both relocations and program segments?
Yes?

Make a dynamic executable, slap it full of the architecture's most basic relocation type (eg. R_X86_64_64) to shift everything to load address, and that's about it. You might have to mark it DYN rather than EXEC to get a loader to actually recognize that its base address is adjustable, check whatever PIE produces and do the same thing minus the PIC code.
User avatar
zaval
Member
Member
Posts: 656
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: Relocatable ELF Object Help

Post by zaval »

alexfru wrote: Do I understand it correctly that a proper ELF executable that can be loaded anywhere (because of ASLR or lack of page translation) needs to have a whole bunch of extra sections for the dynamic loader, even where a simple object file would suffice?
it seems, that you understood it right. because how else one can make an ELF executable both non-PIC and relocatable? only by storing all base relocations (in terms of PE) in it. how to do that for the format, that has no notion of the image base and direct provision for storing the base relocations? you would need to provide the "dynamic" segment, pointing to the .dynamic section, which in turn would point to relocations. as if this were a "dynamic" object (shared or executable, in terms of ELF). this is basically those "extras" of the dynamic linker (in terms of ELF), you mentioned. and this is probably what PIE option creates. but I'm not sure, since I myself only learn this clumsy thing.

but with an object file (relocatable object, in terms of ELF), you don't have to have all that, just plain relocations, lying in some section (what?) of course, if all the object relocations are resolved and removed and only base relocations (in terms of PE) are left. because otherwise, that would be a lot of litter, as pointed out above.

in both cases, however, trying to insert there importing/exporting somehow, constantly fails (at least, how I see it), without resorting to that horrendous .got, .plt, .gotplt PIC thing. of course, a compiler writer might reproduce IAT semantics, given he creates a compiler for the environment, that would understand it. after all, the main problem is the compiler not understanding, that an imported function should be called through an indirect call (using a format provided special function table), being resolved at the load time or even later.
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).
alexfru
Member
Member
Posts: 1111
Joined: Tue Mar 04, 2014 5:27 am

Re: Relocatable ELF Object Help

Post by alexfru »

zaval wrote:
alexfru wrote: Do I understand it correctly that a proper ELF executable that can be loaded anywhere (because of ASLR or lack of page translation) needs to have a whole bunch of extra sections for the dynamic loader, even where a simple object file would suffice?
it seems, that you understood it right. because how else one can make an ELF executable both non-PIC and relocatable? only by storing all base relocations (in terms of PE) in it. how to do that for the format, that has no notion of the image base and direct provision for storing the base relocations? you would need to provide the "dynamic" segment, pointing to the .dynamic section, which in turn would point to relocations. as if this were a "dynamic" object (shared or executable, in terms of ELF). this is basically those "extras" of the dynamic linker (in terms of ELF), you mentioned. and this is probably what PIE option creates. but I'm not sure, since I myself only learn this clumsy thing.

but with an object file (relocatable object, in terms of ELF), you don't have to have all that, just plain relocations, lying in some section (what?) of course, if all the object relocations are resolved and removed and only base relocations (in terms of PE) are left. because otherwise, that would be a lot of litter, as pointed out above.

in both cases, however, trying to insert there importing/exporting somehow, constantly fails (at least, how I see it), without resorting to that horrendous .got, .plt, .gotplt PIC thing. of course, a compiler writer might reproduce IAT semantics, given he creates a compiler for the environment, that would understand it. after all, the main problem is the compiler not understanding, that an imported function should be called through an indirect call (using a format provided special function table), being resolved at the load time or even later.
ELF section headers have an address field (sh_addr), so, it seems that if I preserve (or synthesize) the regular code/data sections (along with their respective relocation sections) and also add parallel segment headers (and program header), I may have everything necessary without anything unnecessary (well, I'll probably still need a tiny symbol table for section names). I haven't tried it yet though.
User avatar
bloodline
Member
Member
Posts: 264
Joined: Tue Sep 15, 2020 8:07 am
Location: London, UK

Re: Relocatable ELF Object Help

Post by bloodline »

nexos wrote:
zaval wrote:(but if I could choose, I'd definitely go with PE, - it's to the OP).
PE is much better the ELF in some ways (mainly dynamic linking). Loading an ELF, however, is very simple, so hence they both have there advantages and disadvantages.
@bloodline - For one thing, if you build an ELF app as position independent in GCC, then you can relocate it just like a simple object file. Loading only object files will prevent growth of your OS, hence I recommend looking into PIC (position independent code). Also, if you aren't making a Unix clone, you could trying looking into PE or Mach-O. PE is probably the simplest out of the bunch. I know nothing about Mach-O, so there is no help from me there :) TL;DR Don't just look at ELF because it is the de facto standard, there are other good formats out there you should check out
My experience with executables comes from Amiga Hunk executables, which is super simple (if you ignore the weird memory saving overlay feature, that no one used once all machines came with at least 512k minimum), you just load the sections into RAM and then walk a relocation table where you pretty much just write the load address to various offsets. The code would then just run... Also no need for load time linking as it linked to the shared libraries at run time, on demand using function tables, all rather elegant in a non security focused world!

I'm determined to learn how to use ELF properly. That is my goal for this part of the project.
CuriOS: A single address space GUI based operating system built upon a fairly pure Microkernel/Nanokernel. Download latest bootable x86 Disk Image: https://github.com/h5n1xp/CuriOS/blob/main/disk.img.zip
Discord:https://discord.gg/zn2vV2Su
User avatar
bloodline
Member
Member
Posts: 264
Joined: Tue Sep 15, 2020 8:07 am
Location: London, UK

Re: Relocatable ELF Object Help

Post by bloodline »

klange wrote:
alexfru wrote:Can I just slap relocations onto an ELF executable?
Sure.
alexfru wrote:But what's the equivalent for this in the ELF executables? How do I express it? Do I make an ELF file that has both relocations and program segments?
Yes?

Make a dynamic executable, slap it full of the architecture's most basic relocation type (eg. R_X86_64_64) to shift everything to load address, and that's about it. You might have to mark it DYN rather than EXEC to get a loader to actually recognize that its base address is adjustable, check whatever PIE produces and do the same thing minus the PIC code.
Ok, this sounds exactly like what I want to do!

I've tired using the -fpie option using my example code and examined the ELF, I think I'm finding the terminology very alien... I see three relocations, when really I'm only expecting the exern symbol needing relocating... All very confusing.

From this post, It seems I want gcc -static-pie: https://stackoverflow.com/questions/615 ... executable
CuriOS: A single address space GUI based operating system built upon a fairly pure Microkernel/Nanokernel. Download latest bootable x86 Disk Image: https://github.com/h5n1xp/CuriOS/blob/main/disk.img.zip
Discord:https://discord.gg/zn2vV2Su
User avatar
bloodline
Member
Member
Posts: 264
Joined: Tue Sep 15, 2020 8:07 am
Location: London, UK

Re: Relocatable ELF Object Help

Post by bloodline »

Ok, so I think I'm figuring this out.

I've created some ASM "startup" code for the linker, with a magic number in the header so know where to resolve my external symbol (and also a _start entry point which just calls main() for now, but I can put additional setup code in there if I need it in future). Now the code is compiled -fpie and the ELF isn't giving me any relocation entries... So lets see if this works :?

My program startup code:

Code: Select all

/* Declare constants for the header. */
.set FLAGS,    0x1                      /* no real flags yet */
.set MAGIC,    0xF3030000               /* 'magic number' lets loader find the header */
.set CHECKSUM, -(MAGIC + FLAGS)         /* checksum of above, to prove we are genuine */

.section .start
.align 4
magic:
.long MAGIC
.global executive    /* The loader will write a pointer to my global function table here*/
executive:
.skip 4

.section .text
.global _start
.type _start, @function
_start:

	call main
 
    ret

Edit: And the C code to make this post make more sense.

Code: Select all

typedef struct{
    void (*Call)(void);
} exec_t;

extern exec_t* executive;

void main(){
    
    executive->Call();
    
}
My ELF load should then put a valid address for the executive structure once the executable is loaded in memory.
Last edited by bloodline on Fri Jul 30, 2021 8:19 am, edited 3 times in total.
CuriOS: A single address space GUI based operating system built upon a fairly pure Microkernel/Nanokernel. Download latest bootable x86 Disk Image: https://github.com/h5n1xp/CuriOS/blob/main/disk.img.zip
Discord:https://discord.gg/zn2vV2Su
User avatar
bloodline
Member
Member
Posts: 264
Joined: Tue Sep 15, 2020 8:07 am
Location: London, UK

Re: Relocatable ELF Object Help

Post by bloodline »

ok, the story so far is that if I use the build options:

Code: Select all

i686-elf-as ./startup.s -o startup.o
i686-elf-gcc -c ./*.c -fPIE -static-pie -nostdlib -ffreestanding -O3 -Wall -Wextra -shared
i686-elf-gcc -T ./linker.ld -o first.elf -fPIE -static-pie -ffreestanding -O3 -nostdlib ./*.o -lgcc -s
I get code that can execute anywhere in RAM, but when I try and access the extern declared variable the code is just accessing address 0 + 4 ... which means it need to be given the correct offset (i.e. the load address). The only place I can see is the got.pla section in the ELF (but despite filling in all entries of the table with the load address the code always read/writes from address 0) Can some x86 expert see if this disassembly makes any sense? I assume it's trying to reference an offset somewhere, but I can't see it.

The first 8 bytes are just variables that I want to reference from my code, not code.

https://onlinedisassembler.com/odaweb/1oePObHx/0


-Edit- Also the ELF always seems to pad my file so the .text section starts at offset 4096... This is an unnecessary waste of space, but I can't seem to stop it from happening.
CuriOS: A single address space GUI based operating system built upon a fairly pure Microkernel/Nanokernel. Download latest bootable x86 Disk Image: https://github.com/h5n1xp/CuriOS/blob/main/disk.img.zip
Discord:https://discord.gg/zn2vV2Su
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Relocatable ELF Object Help

Post by Octocontrabass »

bloodline wrote:Can some x86 expert see if this disassembly makes any sense?
I see a couple of MOV instructions that are encoded with opcode 0xC7 instead of the shorter opcode 0xB8. It looks like the linker is applying an optimization that's not supposed to apply to position-independent code.

Doesn't -static-pie require you to link with startup code that will fix the relocations?
User avatar
bloodline
Member
Member
Posts: 264
Joined: Tue Sep 15, 2020 8:07 am
Location: London, UK

Re: Relocatable ELF Object Help

Post by bloodline »

Octocontrabass wrote:
bloodline wrote:Can some x86 expert see if this disassembly makes any sense?
I see a couple of MOV instructions that are encoded with opcode 0xC7 instead of the shorter opcode 0xB8. It looks like the linker is applying an optimization that's not supposed to apply to position-independent code.
Many thanks for looking at this, I’ve been really struggling to get the linker to give me something usable.
My ELF loader is supposed to apply relocations at load time, but there are no relocation sections in the ELF file so It doesn’t know where to apply them.
CuriOS: A single address space GUI based operating system built upon a fairly pure Microkernel/Nanokernel. Download latest bootable x86 Disk Image: https://github.com/h5n1xp/CuriOS/blob/main/disk.img.zip
Discord:https://discord.gg/zn2vV2Su
User avatar
bloodline
Member
Member
Posts: 264
Joined: Tue Sep 15, 2020 8:07 am
Location: London, UK

Re: Relocatable ELF Object Help

Post by bloodline »

Octocontrabass wrote:
bloodline wrote:Can some x86 expert see if this disassembly makes any sense?
I see a couple of MOV instructions that are encoded with opcode 0xC7 instead of the shorter opcode 0xB8. It looks like the linker is applying an optimization that's not supposed to apply to position-independent code.

Doesn't -static-pie require you to link with startup code that will fix the relocations?
The first 0xC7 instruction moves 0x0 (which seems like a prime candidate for a relocation fix up) into a location pointed by register ebp, so I manually wrote the program load-address into the code for that instruction at loadtime (so the instruction is now movl &loadaddress,-0x4(%ebp) ), but now the code thinks my global variable is located about 400kb into the first megabyte of the address space… I really don’t understand x86 asm :(

-edit- So after a fair bit of x86 asm reading, it seems ebp is a stack-frame pointer so, unlikely to be involved in what I'm trying to do... The next few instructions are the troublesome ones:

Code: Select all


mov $0x4,%edx
mov -0x4(%eax),%eax
add %eax,%eax
mov %eax,(%edx)

So the data (which is correct and doubled) is written to the address at edx, but edx isn't my variable location, it is address 4 :(
CuriOS: A single address space GUI based operating system built upon a fairly pure Microkernel/Nanokernel. Download latest bootable x86 Disk Image: https://github.com/h5n1xp/CuriOS/blob/main/disk.img.zip
Discord:https://discord.gg/zn2vV2Su
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Relocatable ELF Object Help

Post by Octocontrabass »

bloodline wrote:

Code: Select all

mov $0x4,%edx
mov -0x4(%eax),%eax
add %eax,%eax
mov %eax,(%edx)
Is that first MOV encoded using opcode 0xC7 instead of the shorter opcode 0xBA? If it is, the linker patched that instruction.

Anyway, trying to guess where relocations should be applied isn't going to fix the actual problem, which is a lack of relocations in your binary. Unfortunately I have no suggestions for how to fix it...
User avatar
bloodline
Member
Member
Posts: 264
Joined: Tue Sep 15, 2020 8:07 am
Location: London, UK

Re: Relocatable ELF Object Help

Post by bloodline »

Octocontrabass wrote:
bloodline wrote:

Code: Select all

mov $0x4,%edx
mov -0x4(%eax),%eax
add %eax,%eax
mov %eax,(%edx)
Is that first MOV encoded using opcode 0xC7 instead of the shorter opcode 0xBA? If it is, the linker patched that instruction.
It is, so that’s interesting (see below).
Anyway, trying to guess where relocations should be applied isn't going to fix the actual problem, which is a lack of relocations in your binary.
Yes, I was manually patching just so I could figure out what the code is doing, and it has given me a better idea. I’m very new to x86 asm so I need to get a better mental model.
Unfortunately I have no suggestions for how to fix it...
Your comments are really helpful, it seem to me that the linker stage is the problem. I’m also concerned that for some reason the linker pads my ELF file so the text segment starts at 4096 bytes (which it doesn’t need to, and I haven’t requested in my linker script), so it is clear I’m getting something wrong with the linker.
CuriOS: A single address space GUI based operating system built upon a fairly pure Microkernel/Nanokernel. Download latest bootable x86 Disk Image: https://github.com/h5n1xp/CuriOS/blob/main/disk.img.zip
Discord:https://discord.gg/zn2vV2Su
User avatar
bloodline
Member
Member
Posts: 264
Joined: Tue Sep 15, 2020 8:07 am
Location: London, UK

Re: Relocatable ELF Object Help

Post by bloodline »

I’m wondering if there is a problem with my assembly startup code… could that be forcing everything to be relative to address 0?
CuriOS: A single address space GUI based operating system built upon a fairly pure Microkernel/Nanokernel. Download latest bootable x86 Disk Image: https://github.com/h5n1xp/CuriOS/blob/main/disk.img.zip
Discord:https://discord.gg/zn2vV2Su
User avatar
bloodline
Member
Member
Posts: 264
Joined: Tue Sep 15, 2020 8:07 am
Location: London, UK

Re: Relocatable ELF Object Help

Post by bloodline »

Ok, so after much experimentation, I’ve determined that symbols defined in my assembly code and linker script are not relocatable (and are not PC relative in the executable), but symbols defined in my C code are pc relative and so it doesn’t matter what address the code is loaded at… it would be nice to know how I can make all my symbols either PC relative or relocatable…
CuriOS: A single address space GUI based operating system built upon a fairly pure Microkernel/Nanokernel. Download latest bootable x86 Disk Image: https://github.com/h5n1xp/CuriOS/blob/main/disk.img.zip
Discord:https://discord.gg/zn2vV2Su
Post Reply