Linking with an odd setup via a linker script assistance

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.
amyipdev
Posts: 18
Joined: Tue Nov 09, 2021 11:40 am

Linking with an odd setup via a linker script assistance

Post by amyipdev »

I've been working on a bootloader for an OS development project. Currently I'm trying to manage the linking of the bootloader.

My boot sector code loads the first parts of the bootloader at 0x10000. It's designed to work in 64K chunks because of this.

I haven't been using a linker script because I've only been at the boot sector phase until now. Now that I'm entering this however, that changes things.

The primary issue comes with how the linker is handling linking the symbols. Boot sector code needs to be linked relative to 0x7c00 (as cs,ds=0 at that time) but entry segment code needs to be linked relative to 0x0 (as cs,ds=1).

For reference I'm assembling with GNU as, and linking with GNU binutils.

What linker script do I need to make this possible?
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Linking with an odd setup via a linker script assistance

Post by Octocontrabass »

amyipdev wrote:My boot sector code loads the first parts of the bootloader at 0x10000. It's designed to work in 64K chunks because of this.
How big are you expecting your bootloader to be? I've written a lot of bootloader code and I haven't run out of space under 0x10000 yet.
amyipdev wrote:(as cs,ds=1)
You mean 0x1000 and not 1, right? Setting a real-mode segment register to 1 changes the segment base to 0x10, not 0x10000.
amyipdev wrote:What linker script do I need to make this possible?
You need to specify the VMA and LMA separately, possibly with overlapping VMA. There's another example at the bottom of this page that might also help.

But before you get into all of that, why do you want to link it all into a single binary? Do you really need a linker to resolve symbols across the two parts of your bootloader?
amyipdev
Posts: 18
Joined: Tue Nov 09, 2021 11:40 am

Re: Linking with an odd setup via a linker script assistance

Post by amyipdev »

Octocontrabass wrote:
amyipdev wrote:My boot sector code loads the first parts of the bootloader at 0x10000. It's designed to work in 64K chunks because of this.
How big are you expecting your bootloader to be? I've written a lot of bootloader code and I haven't run out of space under 0x10000 yet.
Decently large - I'm loading my bootloader at 0x10000 to ensure I don't run into other tables below 0x7c00. It also allows a much simpler and easier addressing scheme. It's fully possible that my bootloader may be as large as (but definitely not larger than) 384KB, as I want to make it fairly fancy (supporting multi-boot kernels, having some basic filesystem drivers, plus potentially fancy boot-up graphics). I'm also beginning addressing at 0x10000 to make the bootloader's structure much easier to conceptualize. I could shift it downwards to 0x7e00 but where's the fun in that?
Octocontrabass wrote:
amyipdev wrote:(as cs,ds=1)
You mean 0x1000 and not 1, right? Setting a real-mode segment register to 1 changes the segment base to 0x10, not 0x10000.
Yes, my apologies - I meant 0x1000.
Octocontrabass wrote:
amyipdev wrote:What linker script do I need to make this possible?
You need to specify the VMA and LMA separately, possibly with overlapping VMA. There's another example at the bottom of this page that might also help.

But before you get into all of that, why do you want to link it all into a single binary? Do you really need a linker to resolve symbols across the two parts of your bootloader?
It would be preferable to do it all into one, yes. I'd like to be able to safely call functions across segments. In addition, for whatever reason, stuff seems to go haywire when I just shove separate binaries together for boot...

And thank you for that - I'll try to have a look at that. Do you think you could assist a bit more, however? I can't seem to get anything working in terms of a linker script, even just for the initial setup (1 file, loaded at 0x7c00).
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Linking with an odd setup via a linker script assistance

Post by Octocontrabass »

amyipdev wrote:In addition, for whatever reason, stuff seems to go haywire when I just shove separate binaries together for boot...
It works just fine when I do it. Are you doing something funny like using a binary with unresolved symbols or booting from USB?
amyipdev wrote:I can't seem to get anything working in terms of a linker script, even just for the initial setup (1 file, loaded at 0x7c00).
Here's a typical flat binary linker script. Yours should look similar, although you'll probably have only one section since it doesn't make sense to have more than one section in a 512-byte binary.
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: Linking with an odd setup via a linker script assistance

Post by nexos »

In the linker script you linked to, shouldn't "*(.rodata)" be *(.rodata*)"? I remember until spending like 30 minutes hunting down a string bug until I realized GCC put strings in subsections, and I needed to include those as well.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Linking with an odd setup via a linker script assistance

Post by Octocontrabass »

You're right, that example is missing wildcards to catch subsections. I think GCC can generate subsections for all of them, not just .rodata.
amyipdev
Posts: 18
Joined: Tue Nov 09, 2021 11:40 am

Re: Linking with an odd setup via a linker script assistance

Post by amyipdev »

Octocontrabass wrote:
amyipdev wrote:In addition, for whatever reason, stuff seems to go haywire when I just shove separate binaries together for boot...
It works just fine when I do it. Are you doing something funny like using a binary with unresolved symbols or booting from USB?
Nope - maybe it was something wrong with how I shoved them together, but for some reason it just started infinitely incrementing `%ip`.
Octocontrabass wrote:
amyipdev wrote:I can't seem to get anything working in terms of a linker script, even just for the initial setup (1 file, loaded at 0x7c00).
Here's a typical flat binary linker script. Yours should look similar, although you'll probably have only one section since it doesn't make sense to have more than one section in a 512-byte binary.
Thank you for this.

Do I actually have to split my code into sections to use this? Will a general .text be sufficient? Previously when using sections my code would refuse to link, so I've been leaving sections out of the equation ever since.
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Linking with an odd setup via a linker script assistance

Post by Octocontrabass »

amyipdev wrote:for some reason it just started infinitely incrementing `%ip`.
That usually means you've jumped somewhere that doesn't contain any code. Intel had enough foresight to ensure 0xFFFF (open bus) would be an invalid instruction when they designed the 8086, but uninitialized RAM often contains 0x0000, which is a valid instruction.
amyipdev wrote:Do I actually have to split my code into sections to use this? Will a general .text be sufficient?
You don't have to split your boot sector code into multiple sections, but you might get warnings from the linker if you use a standard section name like .text in unusual ways.

When you start using more than one segment, you'll need to somehow separate the code that goes into each segment. You can separate them by file name if you want to use the same section name everywhere.
amyipdev
Posts: 18
Joined: Tue Nov 09, 2021 11:40 am

Re: Linking with an odd setup via a linker script assistance

Post by amyipdev »

Octocontrabass wrote:
amyipdev wrote:for some reason it just started infinitely incrementing `%ip`.
That usually means you've jumped somewhere that doesn't contain any code. Intel had enough foresight to ensure 0xFFFF (open bus) would be an invalid instruction when they designed the 8086, but uninitialized RAM often contains 0x0000, which is a valid instruction.
That's what I thought had been going on - I know the boot sector code loaded, as it didn't stop boot (so the sector word was there), but maybe it got somehow messed up?
Octocontrabass wrote:
amyipdev wrote:Do I actually have to split my code into sections to use this? Will a general .text be sufficient?
You don't have to split your boot sector code into multiple sections, but you might get warnings from the linker if you use a standard section name like .text in unusual ways.

When you start using more than one segment, you'll need to somehow separate the code that goes into each segment. You can separate them by file name if you want to use the same section name everywhere.
I wasn't worrying about splitting segment code.

Thank you so much for your assistance! I'll let you know how things go.
amyipdev
Posts: 18
Joined: Tue Nov 09, 2021 11:40 am

Re: Linking with an odd setup via a linker script assistance

Post by amyipdev »

Didn't seem to work. I attached my assembly (apologize for the horrible conventions, I'll clean it up soon(TM)) and my linker script. I got the following linker error:

Code: Select all

amy@fedora:~/Development/aucs $ ld -L linker.ld -o global global.o entry.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
global.o: in function `ini':
(.text+0x2): relocation truncated to fit: R_X86_64_16 against `.text'
global.o: in function `rddsk_routine':
(.text+0x60): relocation truncated to fit: R_X86_64_16 against `.text'
(.text+0x6c): relocation truncated to fit: R_X86_64_16 against `.text'
global.o: in function `no_lba_ex':
(.text+0x7a): relocation truncated to fit: R_X86_64_16 against `.text'
(.text+0x7d): relocation truncated to fit: R_X86_64_16 against symbol `prs' defined in .text section in global.o
global.o: in function `det_apm_abs':
(.text+0xda): relocation truncated to fit: R_X86_64_16 against `.text'
(.text+0xdd): relocation truncated to fit: R_X86_64_16 against symbol `prs' defined in .text section in global.o
global.o: in function `det_apm_err':
(.text+0xe3): relocation truncated to fit: R_X86_64_16 against `.text'
(.text+0xe6): relocation truncated to fit: R_X86_64_16 against symbol `prs' defined in .text section in global.o
entry.o: in function `get_bios_mmap':
(.text+0x22): relocation truncated to fit: R_X86_64_16 against `.text'
(.text+0x28): additional relocation overflows omitted from the output
Attachments

[The extension s has been deactivated and can no longer be displayed.]

[The extension s has been deactivated and can no longer be displayed.]

linker.ld
(155 Bytes) Downloaded 41 times
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Linking with an odd setup via a linker script assistance

Post by Octocontrabass »

Code: Select all

amy@fedora:~/Development/aucs $ ld -L linker.ld -o global global.o entry.o
That's supposed to be "-T linker.ld".

Are you intending to pack the sections together when the code and data doesn't occupy a full 64kiB, or do you want them padded so it's easier to load? If it's the former, the OVERLAY command is the right choice, but if it's the latter, you probably want something more like this:

Code: Select all

ENTRY(ini)
OUTPUT_FORMAT("binary")

SECTIONS
{
	.text0 0x7c00 : AT(0x10000-0x200) {
		global.o(.text)
	}
	.text1 0x0 : AT(0x10000) {
		entry.o(.text)
	}
	.text2 0x0 : AT(0x20000) {
		example.o(.text)
	}
}
If you do use the OVERLAY command, you'll have to exclude the boot sector since it starts at a different VMA.
amyipdev
Posts: 18
Joined: Tue Nov 09, 2021 11:40 am

Re: Linking with an odd setup via a linker script assistance

Post by amyipdev »

Octocontrabass wrote:

Code: Select all

amy@fedora:~/Development/aucs $ ld -L linker.ld -o global global.o entry.o
That's supposed to be "-T linker.ld".
Ah, thank you, my bad - I'll try that out when I'm back at my development system.
Octocontrabass wrote:Are you intending to pack the sections together when the code and data doesn't occupy a full 64kiB, or do you want them padded so it's easier to load? If it's the former, the OVERLAY command is the right choice, but if it's the latter, you probably want something more like this:

Code: Select all

ENTRY(ini)
OUTPUT_FORMAT("binary")

SECTIONS
{
	.text0 0x7c00 : AT(0x10000-0x200) {
		global.o(.text)
	}
	.text1 0x0 : AT(0x10000) {
		entry.o(.text)
	}
	.text2 0x0 : AT(0x20000) {
		example.o(.text)
	}
}
If you do use the OVERLAY command, you'll have to exclude the boot sector since it starts at a different VMA.
Yes, I did mean the latter - thank you so much for your assistance!
amyipdev
Posts: 18
Joined: Tue Nov 09, 2021 11:40 am

Re: Linking with an odd setup via a linker script assistance

Post by amyipdev »

Hello - it is still not linking properly. Loading the packet loads $0x7e59, while the packet should load as $0x59. Code jumps occur correctly but data jumps do not.

Code: Select all

 221:	be 59 7e             	mov    $0x7e59,%si
 224:	89 46 e6             	mov    %ax,-0x1a(%bp)
 227:	9a 84 7c 00 00       	lcall  $0x0,$0x7c84
 22c:	8b 46 e6             	mov    -0x1a(%bp),%ax
 22f:	eb fe                	jmp    0x22f
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Linking with an odd setup via a linker script assistance

Post by Octocontrabass »

That's odd, it works perfectly fine for me. Here's the corresponding bytes from the binary I built:

Code: Select all

BE 59 00
89 46 E6
9A 84 7C 00 00
8B 46 E6
EB FE
Do you see any warnings when you build everything? Did you make any changes to the example LD script aside from removing references to the nonexistent example.o?
amyipdev
Posts: 18
Joined: Tue Nov 09, 2021 11:40 am

Re: Linking with an odd setup via a linker script assistance

Post by amyipdev »

Octocontrabass wrote:That's odd, it works perfectly fine for me. Here's the corresponding bytes from the binary I built:

Code: Select all

BE 59 00
89 46 E6
9A 84 7C 00 00
8B 46 E6
EB FE
Do you see any warnings when you build everything? Did you make any changes to the example LD script aside from removing references to the nonexistent example.o?
Absolutely zero warnings. The LD script was verbatim except for removing the example.o section.
Post Reply