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
Octocontrabass wrote:
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?
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 :

Code: Select all

.section .sector1
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 :

Code: Select all

as -o boot.o boot.s
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
liwinux wrote:

Code: Select all

.section .sector1
I think LD is discarding your output sections when none of the input sections are allocatable. Try making this section allocatable:

Code: Select all

.section .sector1, "a"
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.)
liwinux wrote:

Code: Select all

    mov sp, bp
    ...
    mov ss, ax
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

    mov ss, ax
    mov sp, bp
liwinux wrote:

Code: Select all

    mov [BOOT_DRIVE], dl # Saving the drive number
You're overwriting the IVT. Why?
liwinux wrote:

Code: Select all

.section .sector2
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

Code: Select all

.set BOOT_DRIVE, 0
was to declare a variable as you would do

Code: Select all

int var= 0;
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

Code: Select all

.set BOOT_DRIVE, 0
was to declare a variable as you would do

Code: Select all

int var= 0;
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

Code: Select all

.set BOOT_DRIVE, 0
was to declare a variable as you would do

Code: Select all

int var= 0;
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"