Linker weirdness

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.
Post Reply
8infy
Member
Member
Posts: 188
Joined: Sun Apr 05, 2020 1:01 pm

Linker weirdness

Post by 8infy »

Hi! I'm currently using my own bootloader to load my OS, which doesn't support elf so I use the linker with --oformat=binary.

This works completely fine right now, although I have some suspicions, which I wanted to clarify.

1. ld seems to completely omit the .bss section in my NASM file, which uses RESB, when I switch to DB instead and use a different section it ends up in the exe. Is this correct?
2. For some reason the executable size drastically changes when I move sections around in the linker.ld script.
For example:

Code: Select all

    .data ALIGN(4K) : AT (ADDR (.data) - 0xC0000000)
    {
        *(.data)
        *(.paging_structures)
    }

    .bss ALIGN(4K) : AT (ADDR (.bss) - 0xC0000000)
    {
        *(COMMON)
        *(.bss)
        *(.kernel_stack)
    }
Moving .paging_structures from .bss to .data increases the binary file from 97K to 103K.
Moving everything from .bss to .data decreases the binary file from 103K to 98K.

What is going on here? Is it omitting anything? Is it alignment changing the size so much?
What happens if i put a custom section into bss? Does it not end up in the binary file as well?

All the experimenting that i've done so far shows absolutely controversial results so it's impossible to tell what's happening.

For example putting a huge uninitialized static array of 4MB in a .cpp file and then iterating over (so it doesn't get optimized out) does increase the executable to 4MB+
Why???? So is .bss in the binary or not, I'm super confused...

And one last thing, how difficult do you think it would be to make a simple elf loader in assembly? I'm tired of this raw binary weirdness and just wanna get rid of it...
The most complicated part is probably finding a spot to load the elf first then parsing it and then somehow loading the kernel in the same place where the elf header was, I'm not sure
how that would even work, hence why I'm asking.

Thanks :)
nullplan
Member
Member
Posts: 1919
Joined: Wed Aug 30, 2017 8:24 am

Re: Linker weirdness

Post by nullplan »

.bss is not supposed to be part of the file. It only contains zero-initialized data, so it is not necessary to preserve the actual contents. It is easiest to just put labels around the BSS section and clear the entire thing to 0 as one of the first things. E.g. in the linker script:

Code: Select all

 .bss ALIGN(4K) : AT (ADDR (.bss) - 0xC0000000)
    {
        bss_start = .;
        *(COMMON)
        *(.bss)
        *(.kernel_stack)
        . = ALIGN(4);
        bss_end = .;
    }
And in the assembly code, right after start (warning, clobbers EDI, ECX, and EAX, and with multiboot you might need one of those):

Code: Select all

movl $bss_start, %edi
movl $bss_end, %ecx
subl %edi, %ecx
subl $0xc0000000, %edi
shrl $2, %ecx
xorl %eax, %eax
rep stosd
That takes care of clearing BSS. Now all your static variables actually are initialized to 0. If your kernel stack is part of the BSS section, this means you must perform this initialization before using the stack, because afterwards, everything will be cleared to 0, including everything on stack.
8infy wrote:What happens if i put a custom section into bss? Does it not end up in the binary file as well?
Depends on the section. But BSS should have type NOBITS, meaning its contents do not get put into memory.
8infy wrote:And one last thing, how difficult do you think it would be to make a simple elf loader in assembly? I'm tired of this raw binary weirdness and just wanna get rid of it...
The most complicated part is probably finding a spot to load the elf first then parsing it and then somehow loading the kernel in the same place where the elf header was, I'm not sure
how that would even work, hence why I'm asking.
ELF is not a difficult format to parse. If you can initialize virtual memory in the boot loader, you only have to load the file to a page-aligned buffer, verify the ELF header and extract the entry point and the location of the program headers. Then iterate over the program headers, looking for PT_LOAD sections. Map all parts of the file as given in the PT_LOAD segments, zeroing out the difference between p_filesz and p_memsz (that will also clear BSS, so the above code will be unnecessary). Finally, activate paging and jump to the entry point.
Carpe diem!
Post Reply