I am developing a OS kernel in the ELF format. I am implementing modules and required information on the kernel's symbol table to link up with the kernel modules. Understanding the ELF documentation is quite difficult for me, and I think it is a little incomplete about some things (maybe I am really wrong about this).

1. My kernel is loaded at 0xC0100000 (virtual address) and I check for the ELF magic numbers there and they aren't there. Does GRUB not write the ELF header there? Do I have to use the MULTIBOOT_ELF_SECTION type in Multiboot2.h instead of using the elf header for getting information on sections (no other information is there). Because then, I will have to write code specially for the 'core-kernel-binary'.

2. I am confused about the GOT (Global Offset Table) and PLT (Procedure Linkage Table). I have created a simple module - name KTERM. I am using GCC with -l MainKernel to (dynamically) link with the kernel. I found a relocation table using readelf. How should I locate and use the GOT and PLT to finish the linking of modules?

3. ELF Symbols - ELF32_SYMBOL contains the field 'Value' (see ELF documentation). It is the value of the symbol. Why is that needed and does it need to be bothered by my loader?

4. How do I locate the relocation table. readelf shows no DT_RELA or related tags in dynamic section. Do I use the section name ".rel.dyn" or type SHT_RELA (section type) to locate the relocation section?

5. How do I do relocation? I get what relocations are and what the entries are. I am confused by the specs in what to 'calculate'.

Compile the code to an object file and perform the final link during runtime.

Compile the code to a shared object, perform dynamic linking at runtime.

The advantages of the first approach relative to the second are:

The first approach might be a bit easier to understand as there is no GOT and PLT.

The disadvantages are:

The code and data segments cannot be shared (this won't be a problem for the kernel).

Requires write access to the code segment, which might have security implications.

You're considering the second approach. It might make sense to also take a look at the first one.

Regarding your questions:

SukantPal wrote:

1. My kernel is loaded at 0xC0100000 (virtual address) and I check for the ELF magic numbers there and they aren't there. Does GRUB not write the ELF header there? Do I have to use the MULTIBOOT_ELF_SECTION type in Multiboot2.h instead of using the elf header for getting information on sections (no other information is there). Because then, I will have to write code specially for the 'core-kernel-binary'.

The ELF standard only requires GRUB to load the segments that are defined by PHDRs (see readelf -l). Those segments are enough to perform dynamic linking, so you don't need to look at ELF sections. Dynamic linking information is stored in the PT_DYNAMIC segment. In particular, the public symbols are accessible through the DT_SYMTAB entry. Notice the difference between sections (relevant during compile-time linking) and segments (relevant during runtime). If you need to access your kernel's PHDRs during runtime, make sure it has a PT_PHDR segment.

SukantPal wrote:

2. I am confused about the GOT (Global Offset Table) and PLT (Procedure Linkage Table). I have created a simple module - name KTERM. I am using GCC with -l MainKernel to (dynamically) link with the kernel. I found a relocation table using readelf. How should I locate and use the GOT and PLT to finish the linking of modules?

You mostly do not need to care about GOT and PLT. The only thing you need to care about is putting your lazy binding stub information into GOT slots 1 and 2. If you don't know what lazy binding is, google it. The GOT can be found through the (extremely stupidly named) DT_PLTGOT entry.

SukantPal wrote:

3. ELF Symbols - ELF32_SYMBOL contains the field 'Value' (see ELF documentation). It is the value of the symbol. Why is that needed and does it need to be bothered by my loader?

That is generally the virtual address/offset of the symbol. It's interpretation depends on the file type.

SukantPal wrote:

4. How do I locate the relocation table. readelf shows no DT_RELA or related tags in dynamic section. Do I use the section name ".rel.dyn" or type SHT_RELA (section type) to locate the relocation section?

Use DT_RELA and DT_REL. If they not present there is either no relocation necessary, or you're compiling your files incorrectly.

SukantPal wrote:

5. How do I do relocation? I get what relocations are and what the entries are. I am confused by the specs in what to 'calculate'.

That question is quite broad. What you have to calculate depends on the relocation type. If it helps: In my code, the calculation looks like this: Click me. Note that R_X86_64_JUMP_SLOT entries have to be initialized even if you use lazy binding.

1. I get what you are saying about the program headers & segments. I number of questions arise on what you have given - i) How do I locate where these segments are? I have only used SECTIONS in the linker script. I am really unknown to program segments and have heard about them after starting to load modules. How will I access data in the PT_DYNAMIC segment. ii) How do I 'make sure' that the kernel has a PT_PHDR segment? iii) Should I use the MULTIBOOT_ELF_SECTIONS tag or should I try using the kernel program header & segments for dynamic linking with the modules? I feel that using the MULTIBOOT_ELF_SECTIONS tag may be easier, but I need your advice.

2. You have said that GOT can be found with DT_PLTGOT entry (in dynamic section). But in the documentation, it said that the address can be associated with the GOT OR PLT. Confusing....

I have done some relocation work now. In my modules 'KModuleMain' function, I call a core-kernel's function elf_dbg(). There is only one relocation entry so I just do the R_386_JMP_SLOT relocationand it works. Is lazy binding required for the kernel? I think that kernel-modules shoudn't face the non-uniformness of timing of function calling, especially because I WILL implement real-time schedulingsupport & lazy binding WILL (as I believe) hinder with real-time support. If I don't implement lazy binding AT ALL then I don't have to even touch the GOT or PLT, I am correct?

Thank You Korona, as you have cleared 80% of my doubts and have helped me to relocated the elf_dbg() symbol in my module.

Compile the code to an object file and perform the final link during runtime.

Compile the code to a shared object, perform dynamic linking at runtime.

There's also a third option (which I use for kernel modules); compile the code to a "relocatable executable", do no runtime linking (only basic fixed-offset relocation) and simply pass a pointer to a dispatch table as a parameter to the entry point of the executable.

Advantages:

Very simple; no complex linking code in the kernel, no need to load the kernel's symbol table, etc.

I have done the relocation for my KTERM module. It is linked to the core-kernel by only on symbol - elf_dbg(). Actually, I didn't search the kernel symbol table for the "elf_dbg" symbol, but just set all found relocation symbols to the value of "elf_dbg" (only one was present, and it was actually for elf_dbg()). Now, I need a mechanism to search my kernel symbol table.

I've worked on doing this. I have using the Multiboot-ELF-Section type (MULTIBOOT_ELF_SECTION) for getting all the section headers & getting the .symtab & .strtab & .shstrtab sections. But, I have also found that my kernel executable DOES NOT contain a .dynamic section OR a .dynsym section. This means it doesn't have any dynamic tags or dynamic symbol table. The question is that how would I move symbols into the dynamic symbol table for linking with kernel modules? Also, Why doesn't my kernel executable contain any .dynamic section (it contains a dynamic segment with VMA equal to 0)?

I never tried to turn my kernel into a dynamic executable (I'm using a microkernel without modules). I'm using dynamic linking in user mode only and there LD automatically generates PT_DYNAMIC (I guess that is because it has to link against my dynamically linked libc). I'd suggest to look at the LD manual and try to get the flags right so that is creates a proper PT_DYNAMIC section.

Regarding your earlier question about lazy binding: No, you don't need lazy binding in the kernel; and as you said, it's probably a good idea to not implement it. You don't even need it in user mode though it will improve application startup time.

SukantPal wrote:

You have said that GOT can be found with DT_PLTGOT entry (in dynamic section). But in the documentation, it said that the address can be associated with the GOT OR PLT.

Yeah, as I said, that entries name is very stupid. I am sure that it is the GOT though. IIRC the x86 ELF supplement clears that up.

Actually I've already read the LD manual. I search for "PT_DYNAMIC" and there was no specific explanation in my notice. Can you help me in finding that? I have also tried creating my own linker script with PHDRS command -

LD's default linker script also includes (*.dynsym) and (*.dynstr), as well as a few additional sections (see Linux' LD script here). Can you provide the output of readelf -l? You may also need to link with -E to force LD to generate a dynamic symbol table for executables.

flag to the linker to get the .dynamic, .dynsym, .dynstr sections. I did add them to the linker script before, but still they didn't appear. Does that mean a dynamic binary has to be a Position-Independent-Executable???

Also, for some reason the .dynsym section has corrupt entries, as said by readelf --dyn-syms <executable-name>. Any reasons???

New update - I HAVE FOUND THE SOLUTION. THE DYNAMIC SYMBOL TABLE WAS CORRUPT BECAUSE I HAD .dynsym, .dynstr, .dynamic... entries in my LINKER SCRIPT. I REMOVED THE ENTRIES AND NOW THE DYNAMIC SYMBOL TABLE IS COMPLETE.

Finishing up, I've some questions to ask -

1. Why doesn't the linux kernel use the .dynsym (dynamic symbol table) for linking kernel modules. It could use the dynamic list for symbols to only keep the exported symbols. Isn't keeping the stupid .ksymtab & whatever kernel sections as seperate useless?

2. Could a kernel modules act as a messenger b/w a user-mode application & the kernel. For example, a library could be mapped in kernel space & user-space. In user-space, the code could read some buffers & send filtered information to application (as desired by it) & in kernel-mode it could ask for more buffers. Also, the kernel & userspace could share some utility shared library like memcpy & and all right?

3. Any more things that I should implement for faster module performance?

I guess SukantPal will forgive me for reusing his mostly answered thread?

Why making another ELF thread if there is one, quite fresh?

I am writing a utility converting ELF into PE. For using in my FW and OS. And I faced a weird linker behavior. Maybe some of you know is it possible to tell it do things not as dumb. Namely, there is a File Alignment and Section Alignment for executables. First tells how to align sections inside a file as it is stored on disk. The second tells how to put sections in memory. All offsets encoded into instructions of course are valid only when sections are placed with those distances between sections as it was assigned at link time, not as they placed in the file. there, they are compacted for saving space.When you compile with GCC, for bare metal MIPS at least, without any alignment directives in the linker script, sections get non aligned locations, no page alignment, no sector alignment, just aligned at 4 as for the first symbol lying inside of it. It's weird by itself but OK, linker scripts have ALIGN command, for the output sections (resulting linker generated ones). That's exactly what we need! And everything is good. Except that in the file sections are placed with huge gaps between them too! They aren't aligned there (relative to file start), but the distance between beginnings of two consecutive sections now is Section Alignment in size! What the hell! Why? That placement is supposed to get real only in memory, not in the file.Basically the problem is the linker puts sections inside a file with the distance == Section Alignment, whereas it has been assigned for sections when they go in memory for execution, not for storage in the file. Why it is doing so and is there a way to tell it not to do that?Here is the example of linker script for testing.

Note, ".text" section is section aligned (0x1000) without the ALIGN, just by setting the position. And in the file it gets "normal" file offset, something like 0x78. Others are ALIGNed and for example .rdata gets 0x1078 offset. and .data - 0x2078. I suspect should .text be explicitly aligned, it would get that huge file offset too. Despite it is stated ALIGN command just adjusts the current position to the nearest upper aligned location. basically the same as manipulation with the "dot" element.

I don't get it, doesn't ELF likner understand the difference between file position and memory position of sections in memory?And yet, sections must be placed page aligned in memory, no matter hat the executable foramt is. For applying different page attributes, corresponding to section attributes, for CoW etc. Why GCC puts sections not aligned at page? Is it only on bare metal MIPS, or it behaves the same for x86? I don't have the latter to check.

If someone is interested in this utility, I might upload its code or the program itself later. Now it only supports MIPS32 targets. I don't know if GCC for bare metal, freestanding, on x86 lets you generate PE/COFF, but for ARM, ARM64 and MIPS32 it doesn't. That's why I do it by myself.It lets you use PE format for your images. It's a simple utility so you need to decide on your section arrangement with your linker. the utility won't do section merging or reordering. It just translates resulting Elf executable into PE executable. Also, only ET_EXEC elf type is supported, because PE doesn't use PIC approach, or at least I am not using it. As it is extremely complicated and not giving any advantages.For executables there is a need to generate import information, and for DLLs export information as well. For my assembly written files now, I do it by hand. How to do it with C, that's the question. Not resolved yet. But when it is, the utility is ready for making a proper PE import and export tables. That's all one needs for comfortable dynamic linking. But an input Elf file can not be position independent code, only Elf executable, linked at the desired address.

I'm not sure if I understand your question. ALIGN aligns segments in virtual memory. The linker tries to keep virtual memory offsets and file offsets in sync so that mmap() suffices to load the executable, without the need to copy read-only segments from the file to a process-specific chunk of memory.

The linker tries to keep virtual memory offsets and file offsets in sync so that mmap() suffices to load the executable, without the need to copy read-only segments from the file to a process-specific chunk of memory.

This. It's not a big problem for me, since I still will be converting it, but don't you know, is there a way to tell linker to not do so, and keep section placement in the file as compact as possible?

For example in my case the executables are small and file size overhead caused by this behavior is significant (should I use these ELFs). The amount of space on disk (SD card) where I can place the Firmware Volume is small, oppositely, the memory amount is enough. So it would be nice to have a little file and only on loading place sections at aligned positions not caring much about the space.

But anyway, all these efforts were to avoid doing relocations at the translation stage. Now I figured out that it's almost impossible to safely derive image base form ELF file, so I decided to not avoid them, and since, I may not bother with aligning sections at the elf linker stage.Thank you for your answer.

Who is online

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum