Page 1 of 2
Linker script wiht custom memory location
Posted: Sat Feb 26, 2022 3:44 pm
by liwinux
Hi, So I'm kind of lost when it comes to linker scripts and I have a basic problem that I can't resolve. So for example I have 2 files : bootloader.s which just load sectors, and another file : bootloader2.s which is the rest of my bootloader. Now, I want to have a linker script that put the bootloader.s at memory address 0x7c00 and the bootloader2.s let's say at address 0x500. How would I do that with a linker script ? How should I add sections to my assembly code to achieve that ? Could someone give an example ? I'm using the GAS syntax by the way.
I know that I could just load my sectors at memory address 0x7e00, which is just next to the where the bootloader is loaded but I really want to understand how to do that with a linker script
Thank you !
Re: Linker script wiht custom memory location
Posted: Sat Feb 26, 2022 4:16 pm
by Octocontrabass
liwinux wrote:0x500
This may collide with the BDA on some BIOSes. You should choose a higher address, like 0x600.
Have you tried any of the suggestions in your other thread on the same topic?
Re: Linker script wiht custom memory location
Posted: Sat Feb 26, 2022 4:22 pm
by liwinux
Well yes, I tried your linker script right here :
Code: Select all
SECTIONS
{
.sector1 0x7c00 : AT(0) {
*(.sector1)
}
.sector2 0x9000 : AT(0x200) {
*(.sector2)
}
}
But after looking at the hexadecimal with xxd, I get something as this :
Code: Select all
00000000: 0400 0000 2000 0000 0500 0000 474e 5500 .... .......GNU.
00000010: 0200 01c0 0400 0000 0000 0000 0000 0000 ................
00000020: 0100 01c0 0400 0000 0100 0000 0000 0000 ................
which obviously is not right...
I'm actually not sure about my sections. Here at the the beginning of my bootloader I added this :
and in the other file I added the same but replace .sector1 by .sector2
Re: Linker script wiht custom memory location
Posted: Sat Feb 26, 2022 4:42 pm
by liwinux
The thing that I don't understand is why would I need tot tell my linker script to place my code at address 0x600 in the first place as I'm asking to load my code at address 0x600 and then to jump to it as it's supposed to be loaded in memory right ? I noticed that i successfully managed to hit the loaded code by jumping to it, but the issue was that I couldn't reach my print function after reaching the loaded code, which I don't know why. So for example before loading sectors, I could use my function "print", but after loading sectors and jumping to that, I can't use this function anymore. And rewriting it with another name and calling it, works. Am I missing something here ?
Re: Linker script wiht custom memory location
Posted: Sat Feb 26, 2022 4:54 pm
by Octocontrabass
liwinux wrote:Am I missing something here ?
Yes.
The linker's job is to resolve symbols to addresses. You tell the linker where you are going to load your code, and the linker writes addresses into the binary so that your code will run when you load it. If you don't tell the linker where your code will be loaded, the linker will write the wrong addresses. This is why your "print" symbol doesn't point to the right code.
liwinux wrote:But after looking at the hexadecimal with xxd, I get something as this :
[...]
which obviously is not right...
What code are you using to get this binary?
Re: Linker script wiht custom memory location
Posted: Sat Feb 26, 2022 5:07 pm
by liwinux
Octocontrabass wrote:Yes.
The linker's job is to resolve symbols to addresses. You tell the linker where you are going to load your code, and the linker writes addresses into the binary so that your code will run when you load it. If you don't tell the linker where your code will be loaded, the linker will write the wrong addresses. This is why your "print" symbol doesn't point to the right code.
I get it, it's been a long time since I haven't touched to my bootloader, it was a stupid question.
Octocontrabass wrote:What code are you using to get this binary?
Here is my single bootloader.s
Code: Select all
.intel_syntax noprefix
.code16
.set BOOT_DRIVE, 0
.globl _start
.section .sector1
_start:
.space 80, 0 # Faking the BPB for some buggy BIOS's
mov bp, _start
jmp 0x0000, _init
_init:
cld
mov bp, _start
mov sp, bp
xor ax, ax
mov ds, ax
mov ss, ax
mov es, ax
mov [BOOT_DRIVE], dl # Saving the drive number
mov bx, offset flat:init_str
call print16
mov bx, offset flat:start_addr_str
call print16
mov dh, 1
mov bx, 0x9000
mov dl, [BOOT_DRIVE]
call load_disk
ljmp 0x0000:0x9000
.include "16_print.s"
.include "disk.s"
init_str:
.asciz "INIT BOOT 0x0000\n\r"
start_addr_str:
.asciz "Bootloader loaded at Address 0x7c00\n\r"
.space 510-(.-_start), 0
.word 0xaa55
.section .sector2
testing:
mov al, 7
call prin16_digit
jmp .
And the linker script used :
Code: Select all
SECTIONS
{
.sector1 0x7c00 : AT(0) {
*(.sector1)
}
.sector2 0x9000 : AT(0x200) {
*(.sector2)
}
}
To compile this I use first :
and to link it :
Code: Select all
ld -o boot.bin --oformat binary -T linker.ld boot.o
Re: Linker script wiht custom memory location
Posted: Sat Feb 26, 2022 7:18 pm
by Octocontrabass
I think LD is discarding your output sections when none of the input sections are allocatable.
Try making this section allocatable:
liwinux wrote:Code: Select all
_start:
.space 80, 0 # Faking the BPB for some buggy BIOS's
You're executing your BPB as code. You need a JMP instruction before the fake BPB. (Also, it's not a BIOS bug - those BIOSes are behaving exactly as intended.)
Between these two instructions, your stack is invalid. You must either disable interrupts or rearrange these instructions so no interrupts can happen between them:
liwinux wrote:Code: Select all
mov [BOOT_DRIVE], dl # Saving the drive number
You're overwriting the IVT. Why?
Make this section allocatable too.
Re: Linker script wiht custom memory location
Posted: Sun Feb 27, 2022 4:47 am
by liwinux
I think LD is discarding your output sections when none of the input sections are allocatable. Try making this section allocatable:
That was it, now LD produces code as expected !
(Also, it's not a BIOS bug - those BIOSes are behaving exactly as intended.)
But aren't BIOSes supposed to continue executing code even if there is no BPB ?
Between these two instructions, your stack is invalid. You must either disable interrupts or rearrange these instructions so no interrupts can happen between them:
Code: Select all
cli
mov bp, _start
mov sp, bp
xor ax, ax
mov ds, ax
mov ss, ax
mov es, ax
cld
I guess this sould now be better, but why should we disable interrupts and re-enable them after setting up the stack ?
You're overwriting the IVT. Why?
I'm not sure what do you mean here tough. I'm just saving the disk_number into a variable, then before loading sectors, I'm making sure that dl, didn't got overwritten by just copying back the disk number saved into a variable. Is this a bad practice ?
Re: Linker script wiht custom memory location
Posted: Sun Feb 27, 2022 4:56 am
by klange
liwinux wrote:I'm not sure what do you mean here tough. I'm just saving the disk_number into a variable, then before loading sectors, I'm making sure that dl, didn't got overwritten by just copying back the disk number saved into a variable. Is this a bad practice ?
The address you are storing to, 0, is already being used by the BIOS.
Re: Linker script wiht custom memory location
Posted: Sun Feb 27, 2022 5:04 am
by liwinux
klange wrote:liwinux wrote:I'm not sure what do you mean here tough. I'm just saving the disk_number into a variable, then before loading sectors, I'm making sure that dl, didn't got overwritten by just copying back the disk number saved into a variable. Is this a bad practice ?
The address you are storing to, 0, is already being used by the BIOS.
I might have miss understood something then. I thought the directive
was to declare a variable as you would do
in C. I think this is why I don’t understand what the error was
Re: Linker script wiht custom memory location
Posted: Sun Feb 27, 2022 5:30 am
by klange
liwinux wrote:I might have miss understood something then. I thought the directive
was to declare a variable as you would do
in C. I think this is why I don’t understand what the error was
.set defines symbols, not variables.
Re: Linker script wiht custom memory location
Posted: Sun Feb 27, 2022 6:01 am
by liwinux
klange wrote:liwinux wrote:I might have miss understood something then. I thought the directive
was to declare a variable as you would do
in C. I think this is why I don’t understand what the error was
.set defines symbols, not variables.
But how is this related to the IVT ? I mean it’s a symbol
Re: Linker script wiht custom memory location
Posted: Sun Feb 27, 2022 6:24 am
by klange
liwinux wrote:But how is this related to the IVT ? I mean it’s a symbol
Symbols are not variables. They are names for addresses - the value of a symbol is an address. You created a symbol with a value of 0. Essentially you’ve told the linker there’s a thing called BOOT_DRIVE of unspecified size at address 0. When you reference BOOT_DRIVE as a memory operand in a
mov, the linker will fill in the address 0. That’s where the IVT is, so you are overwriting the beginning of the IVT.
Re: Linker script wiht custom memory location
Posted: Sun Feb 27, 2022 7:29 am
by liwinux
klange wrote:liwinux wrote:But how is this related to the IVT ? I mean it’s a symbol
Symbols are not variables. They are names for addresses - the value of a symbol is an address. You created a symbol with a value of 0. Essentially you’ve told the linker there’s a thing called BOOT_DRIVE of unspecified size at address 0. When you reference BOOT_DRIVE as a memory operand in a
mov, the linker will fill in the address 0. That’s where the IVT is, so you are overwriting the beginning of the IVT.
I get it. So essentially, symbols are like #define but for an address, like an alias or something
Re: Linker script wiht custom memory location
Posted: Sun Feb 27, 2022 12:13 pm
by liwinux
I'm still not able to hit my code after loading it memory adress 0x9000. Not sure why as everything seems to be set up correctly.
Code: Select all
.intel_syntax noprefix
.code16
.globl _start
.section .sector1, "a"
_start:
ljmp 0x0000:_init
.space 80, 0 # Faking the BPB for some buggy BIOS's
mov bp, _start
jmp _init
_init:
cli
mov bp, _start
mov sp, bp
xor ax, ax
mov ds, ax
mov ss, ax
mov es, ax
cld
mov [BOOT_DRIVE], dl # Saving the drive number
call prin16_digit
mov bx, offset flat:init_str
call print16
mov bx, offset flat:start_addr_str
call print16
mov dh, 2
mov bx, 0x8000
mov dl, [BOOT_DRIVE]
call load_disk
ljmp 0x0000:0x8000
.include "16_print.s"
.include "disk.s"
init_str:
.asciz "INIT BOOT 0x0000\n\r"
start_addr_str:
.asciz "Bootloader loaded at Address 0x7c00\n\r"
BOOT_DRIVE:
.value 0
.space 510-(.-_start), 0
.word 0xaa55
.section .sector2,"a"
testing:
mov bx, offset flat:str
call print16
jmp .
str:
.asciz "Hello World !\n\r"