Linking with an odd setup via a linker script assistance
Linking with an odd setup via a linker script assistance
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?
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?
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Linking with an odd setup via a linker script assistance
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:My boot sector code loads the first parts of the bootloader at 0x10000. It's designed to work in 64K chunks because of this.
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:(as cs,ds=1)
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.amyipdev wrote:What linker script do I need to make this possible?
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?
Re: Linking with an odd setup via a linker script assistance
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: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:My boot sector code loads the first parts of the bootloader at 0x10000. It's designed to work in 64K chunks because of this.
Yes, my apologies - I meant 0x1000.Octocontrabass wrote: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:(as cs,ds=1)
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...Octocontrabass wrote: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.amyipdev wrote:What linker script do I need to make this possible?
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?
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).
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Linking with an odd setup via a linker script assistance
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:In addition, for whatever reason, stuff seems to go haywire when I just shove separate binaries together for boot...
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.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).
Re: Linking with an odd setup via a linker script assistance
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.
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Linking with an odd setup via a linker script assistance
You're right, that example is missing wildcards to catch subsections. I think GCC can generate subsections for all of them, not just .rodata.
Re: Linking with an odd setup via a linker script assistance
Nope - maybe it was something wrong with how I shoved them together, but for some reason it just started infinitely incrementing `%ip`.Octocontrabass wrote: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:In addition, for whatever reason, stuff seems to go haywire when I just shove separate binaries together for boot...
Thank you for this.Octocontrabass wrote: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.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).
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.
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Linking with an odd setup via a linker script assistance
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:for some reason it just started infinitely incrementing `%ip`.
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.amyipdev wrote:Do I actually have to split my code into sections to use this? Will a general .text be sufficient?
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.
Re: Linking with an odd setup via a linker script assistance
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: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:for some reason it just started infinitely incrementing `%ip`.
I wasn't worrying about splitting segment code.Octocontrabass wrote: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.amyipdev wrote:Do I actually have to split my code into sections to use this? Will a general .text be sufficient?
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.
Thank you so much for your assistance! I'll let you know how things go.
Re: Linking with an odd setup via a linker script assistance
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 40 times
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Linking with an odd setup via a linker script assistance
Code: Select all
amy@fedora:~/Development/aucs $ ld -L linker.ld -o global global.o entry.o
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)
}
}
Re: Linking with an odd setup via a linker script assistance
Ah, thank you, my bad - I'll try that out when I'm back at my development system.Octocontrabass wrote:That's supposed to be "-T linker.ld".Code: Select all
amy@fedora:~/Development/aucs $ ld -L linker.ld -o global global.o entry.o
Yes, I did mean the latter - thank you so much for your assistance!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:
If you do use the OVERLAY command, you'll have to exclude the boot sector since it starts at a different VMA.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) } }
Re: Linking with an odd setup via a linker script assistance
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
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Linking with an odd setup via a linker script assistance
That's odd, it works perfectly fine for me. Here's the corresponding bytes from the binary I built:
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?
Code: Select all
BE 59 00
89 46 E6
9A 84 7C 00 00
8B 46 E6
EB FE
Re: Linking with an odd setup via a linker script assistance
Absolutely zero warnings. The LD script was verbatim except for removing the example.o section.Octocontrabass wrote:That's odd, it works perfectly fine for me. Here's the corresponding bytes from the binary I built:
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?Code: Select all
BE 59 00 89 46 E6 9A 84 7C 00 00 8B 46 E6 EB FE