Linker script wiht custom memory location
Linker script wiht custom memory location
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 !
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 !
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Linker script wiht custom memory location
This may collide with the BDA on some BIOSes. You should choose a higher address, like 0x600.liwinux wrote:0x500
Have you tried any of the suggestions in your other thread on the same topic?
Re: Linker script wiht custom memory location
Well yes, I tried your linker script right here :Octocontrabass wrote:This may collide with the BDA on some BIOSes. You should choose a higher address, like 0x600.liwinux wrote:0x500
Have you tried any of the suggestions in your other thread on the same topic?
Code: Select all
SECTIONS
{
.sector1 0x7c00 : AT(0) {
*(.sector1)
}
.sector2 0x9000 : AT(0x200) {
*(.sector2)
}
}
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 ................
I'm actually not sure about my sections. Here at the the beginning of my bootloader I added this :
Code: Select all
.section .sector1
Re: Linker script wiht custom memory location
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 ?
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Linker script wiht custom memory location
Yes.liwinux wrote:Am I missing something here ?
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.
What code are you using to get this binary?liwinux wrote:But after looking at the hexadecimal with xxd, I get something as this :
[...]
which obviously is not right...
Re: Linker script wiht custom memory location
I get it, it's been a long time since I haven't touched to my bootloader, it was a stupid question.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.
Here is my single bootloader.sOctocontrabass wrote:What code are you using to get this binary?
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 .
Code: Select all
SECTIONS
{
.sector1 0x7c00 : AT(0) {
*(.sector1)
}
.sector2 0x9000 : AT(0x200) {
*(.sector2)
}
}
Code: Select all
as -o boot.o boot.s
Code: Select all
ld -o boot.bin --oformat binary -T linker.ld boot.o
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Linker script wiht custom memory location
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
.section .sector1
Code: Select all
.section .sector1, "a"
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.)liwinux wrote:Code: Select all
_start: .space 80, 0 # Faking the BPB for some buggy BIOS's
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 sp, bp ... mov ss, ax
Code: Select all
mov ss, ax
mov sp, bp
You're overwriting the IVT. Why?liwinux wrote:Code: Select all
mov [BOOT_DRIVE], dl # Saving the drive number
Make this section allocatable too.liwinux wrote:Code: Select all
.section .sector2
Re: Linker script wiht custom memory location
That was it, now LD produces code as expected !I think LD is discarding your output sections when none of the input sections are allocatable. Try making this section allocatable:
But aren't BIOSes supposed to continue executing code even if there is no 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:
Code: Select all
cli
mov bp, _start
mov sp, bp
xor ax, ax
mov ds, ax
mov ss, ax
mov es, ax
cld
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 ?You're overwriting the IVT. Why?
Re: Linker script wiht custom memory location
The address you are storing to, 0, is already being used by the BIOS.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 ?
Re: Linker script wiht custom memory location
I might have miss understood something then. I thought the directiveklange wrote:The address you are storing to, 0, is already being used by the BIOS.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 ?
Code: Select all
.set BOOT_DRIVE, 0
Code: Select all
int var= 0;
Re: Linker script wiht custom memory location
.set defines symbols, not variables.liwinux wrote:I might have miss understood something then. I thought the directivewas to declare a variable as you would doCode: Select all
.set BOOT_DRIVE, 0
in C. I think this is why I don’t understand what the error wasCode: Select all
int var= 0;
Re: Linker script wiht custom memory location
But how is this related to the IVT ? I mean it’s a symbolklange wrote:.set defines symbols, not variables.liwinux wrote:I might have miss understood something then. I thought the directivewas to declare a variable as you would doCode: Select all
.set BOOT_DRIVE, 0
in C. I think this is why I don’t understand what the error wasCode: Select all
int var= 0;
Re: Linker script wiht custom memory location
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.liwinux wrote:But how is this related to the IVT ? I mean it’s a symbol
Re: Linker script wiht custom memory location
I get it. So essentially, symbols are like #define but for an address, like an alias or somethingklange wrote: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.liwinux wrote:But how is this related to the IVT ? I mean it’s a symbol
Re: Linker script wiht custom memory location
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"