OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 1:25 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: [SOLVED]Bootloader working wierdly
PostPosted: Mon Apr 29, 2019 2:40 am 
Offline

Joined: Mon Apr 29, 2019 1:52 am
Posts: 8
Hello everyone!
I've been running into a weird problem and I can't figure out exactly what's causing the issue. Here's the part of code that's working weirdly:

Code:
.code16
.globl _start
.section .text

_start:
        ljmp $0x7c0, $_here
    _here:
        movw    %cs,  %ax
        movw    %ax,  %ds
        movw    %ax,  %es
        movw    %ax,  %ss
#Rest of the code
     


and the Makefile:
Code:
LDFLAGS := -melf_i386 --oformat=binary

all: disk.img

boot: boot.o
        ld $(LDFLAGS) -Ttext 0x7c00 -e _start -o boot boot.o

boot.o: boot.s
        as --32 -o boot.o boot.s

#Rest of the Makefile


So here's the issue (I guess it has something to do with the linker), if I set -Ttext to 0x7c00, the code below _here doesn't execute BUT everything works fine if I set -Ttext to 0x0. Why is that ?
I tried looking at the values of segment registers in both cases (Ctrl+Alt+2 in qemu) and in the first case only CS seems to have the value 0x07c0 and the rest are in their default state, however in the second case, everything is as they should be.
I even tried using int $0x10 just below _here to see whether the code below the label is being executed or not and it's not executing when -Ttext 0x7c00 is used.
Why is that ?


Last edited by 0xd3ba on Wed May 01, 2019 7:19 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Bootloader working wierdly
PostPosted: Mon Apr 29, 2019 3:09 am 
Offline
Member
Member
User avatar

Joined: Thu Oct 13, 2016 4:55 pm
Posts: 1584
Hi,

0xd3ba wrote:
if I set -Ttext to 0x7c00, the code below _here doesn't execute BUT everything works fine if I set -Ttext to 0x0. Why is that ?
This is not weird, this is the expected behaviour. You should read a bit more on real mode addressing.
address = segment * 16 + offset, therefore 0x7C0:0 == 0:0x7C00.
Also note, that -Ttext expects and address, while in the asm file there are no direct addresses, the ORG directive expects an offset, and LJMP instruction a segment:offset pair.

So you should either do
Code:
-Ttext 0
org $0x7C00
ljmp $0:_here
or
Code:
-Ttext 0x7c00
org $0
ljmp $0x7c0:_here
or
Code:
-Ttext 0
org $0x7c00
ljmp $0x7c0:_here
org $0
_here:
To jump to the correct address.

Cheers,
bzt


Top
 Profile  
 
 Post subject: Re: Bootloader working wierdly
PostPosted: Mon Apr 29, 2019 10:35 am 
Offline

Joined: Mon Apr 29, 2019 1:52 am
Posts: 8
bzt wrote:
Hi,

0xd3ba wrote:
if I set -Ttext to 0x7c00, the code below _here doesn't execute BUT everything works fine if I set -Ttext to 0x0. Why is that ?
This is not weird, this is the expected behaviour. You should read a bit more on real mode addressing.
address = segment * 16 + offset, therefore 0x7C0:0 == 0:0x7C00.
Also note, that -Ttext expects and address, while in the asm file there are no direct addresses, the ORG directive expects an offset, and LJMP instruction a segment:offset pair.

So you should either do
Code:
-Ttext 0
org $0x7C00
ljmp $0:_here
or
Code:
-Ttext 0x7c00
org $0
ljmp $0x7c0:_here
or
Code:
-Ttext 0
org $0x7c00
ljmp $0x7c0:_here
org $0
_here:
To jump to the correct address.

Cheers,
bzt


Hi there. Thanks for the reply, I'm still learning.
So I'm using GNU Assembler and it's org directive is different from NASM's. In fact I haven't found its equivalent (https://ftp.gnu.org/old-gnu/Manuals/gas-2.9.1/html_chapter/as_7.html).

Anyways, as far as I know, -Ttext <linear_address> places the text section starting at location linear_address right ? So if that is true, then shouldn't ljmp work only when -Ttext 0x7c00 ? I mean ljmp jumps to location 0x7c0:offset and the offset is calculated from the starting address of the code and BIOS places the bootloader at address 0x7c00. Please correct me if I'm wrong :?:


Top
 Profile  
 
 Post subject: Re: Bootloader working wierdly
PostPosted: Mon Apr 29, 2019 10:54 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 27, 2004 11:00 pm
Posts: 874
Location: WA
Quote:
Anyways, as far as I know, -Ttext <linear_address> places the text section starting at location linear_address right ? So if that is true, then shouldn't ljmp work only when -Ttext 0x7c00 ? I mean ljmp jumps to location 0x7c0:offset and the offset is calculated from the starting address of the code and BIOS places the bootloader at address 0x7c00. Please correct me if I'm wrong :?:

that doesn't sound right... you are setting text to 0x7C00, which means the assembler/linker would assume that the address is at offset 0x7C00... but if you set the segment to 0x7C0 then the offset is 0 (not 0x7C00) -- if you want to use segment 0x7C0 then you would need to tell the assembler that the code is located at offset 0 (because the address 0x7C00 is located at offset 0 from segment 0x7C0)

or you could set the offset to 7C00 (as you are doing) and set the segment to 0 (because the address 0x7C00 is located at offset 0x7C00 from segment 0)

GAS is designed for working in a flat environment where segments are ignored (and not RMode...) and thus you need to realize that it doesn't see the physical address, but only the linear offset

at least this is what I assume to be the case, I have little understanding of gas, and I have never seen anyone use it to build a legacy 1st stage...


alternatively, you could skip the jump entirely, as there is no reason to use it unless you are planning to make use of function pointers or switch statements... both of which are common in higher-level languages, but rare in small sections of manually written ASM (and you will need a FAR jump later anyway when transitioning to later bootloader stages) -- however you would need to change the code immediately after the jump so that it doesn't rely on copying CS into the other segment registers (which isn't really a good idea anyway -- those values are not generally useful for data references)

for me, my legacy 1st-stage doesn't FAR JMP until I am ready to leave the 1st stage (transition to the 2nd stage), and I set all other segment registers (but not FS/GS, as I don't use those) to 0 (that way I can access and use the lower memory where all the important things are and where memory is guaranteed to exist)

_________________
## ---- ----- ------ Intel Manuals
OSdev wiki


Top
 Profile  
 
 Post subject: Re: Bootloader working wierdly
PostPosted: Mon Apr 29, 2019 11:08 am 
Offline
Member
Member
User avatar

Joined: Thu Oct 13, 2016 4:55 pm
Posts: 1584
0xd3ba wrote:
Anyways, as far as I know, -Ttext <linear_address> places the text section starting at location linear_address right ? So if that is true, then shouldn't ljmp work only when -Ttext 0x7c00 ? I mean ljmp jumps to location 0x7c0:offset and the offset is calculated from the starting address of the code and BIOS places the bootloader at address 0x7c00. Please correct me if I'm wrong :?:
That's correct, you specify the address on the command line (without segment). But if you set the segment base address, then your segment offset should start at zero.

Now imagine that the difference of the text segment and your _here label is 0x1b for example. Then if you tell your linker to start the text segment at 0x7c00, then your _here label will be placed at address 0x7c1b. So the "ljmp 0x7c0:_here" will be translated to "ljmp 0x7c0:0x7c1b" which jumps to the wrong address. You either need "ljmp 0x7c0:0x1b" or "ljmp 0:0x7c1b".

I'd recommend to use CS=0 instead ("ljmp 0:_here"), that's clearer and easier, because there linear address == segment offset. It has a downside that you'll be limited to approx 32k of code (7c00-ffff instead of 500-ffff), but that should be more than enough to load your kernel. My loader for example is 11k in size, and that includes serial console, VBE handling, gzip deflate uncompressor, PE and ELF parser, CRC32c and SHA-256 checksum calculation, SMP set up, GPT parser, USTAR, CPIO, FAT16, FAT32 and other filesystem parsers, and even initrd decryption, not to mention RAID mirror support, El Torito, Multiboot, Linux boot and BBS ROM compatibility layers. And with all those features I've only filled up the 1/3rd of the available space.

Cheers,
bzt


Top
 Profile  
 
 Post subject: Re: Bootloader working wierdly
PostPosted: Tue Apr 30, 2019 9:05 am 
Offline

Joined: Mon Apr 29, 2019 1:52 am
Posts: 8
Quote:
that doesn't sound right... you are setting text to 0x7C00, which means the assembler/linker would assume that the address is at offset 0x7C00... but if you set the segment to 0x7C0 then the offset is 0 (not 0x7C00) -- if you want to use segment 0x7C0 then you would need to tell the assembler that the code is located at offset 0 (because the address 0x7C00 is located at offset 0 from segment 0x7C0)

or you could set the offset to 7C00 (as you are doing) and set the segment to 0 (because the address 0x7C00 is located at offset 0x7C00 from segment 0)

GAS is designed for working in a flat environment where segments are ignored (and not RMode...) and thus you need to realize that it doesn't see the physical address, but only the linear offset


Quote:
That's correct, you specify the address on the command line (without segment). But if you set the segment base address, then your segment offset should start at zero.

Now imagine that the difference of the text segment and your _here label is 0x1b for example. Then if you tell your linker to start the text segment at 0x7c00, then your _here label will be placed at address 0x7c1b. So the "ljmp 0x7c0:_here" will be translated to "ljmp 0x7c0:0x7c1b" which jumps to the wrong address. You either need "ljmp 0x7c0:0x1b" or "ljmp 0:0x7c1b".

I'd recommend to use CS=0 instead ("ljmp 0:_here"), that's clearer and easier, because there linear address == segment offset. It has a downside that you'll be limited to approx 32k of code (7c00-ffff instead of 500-ffff), but that should be more than enough to load your kernel. My loader for example is 11k in size, and that includes serial console, VBE handling, gzip deflate uncompressor, PE and ELF parser, CRC32c and SHA-256 checksum calculation, SMP set up, GPT parser, USTAR, CPIO, FAT16, FAT32 and other filesystem parsers, and even initrd decryption, not to mention RAID mirror support, El Torito, Multiboot, Linux boot and BBS ROM compatibility layers. And with all those features I've only filled up the 1/3rd of the available space.

Cheers,
bzt


Finally I get it :mrgreen:
So I was misinterpreting offset in the ljmp (I thought offset = address_of_label - starting_address)

Thanks a lot to both of you !!

Quote:
at least this is what I assume to be the case, I have little understanding of gas, and I have never seen anyone use it to build a legacy 1st stage...

XV6 uses Gas :P :P


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot] and 60 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group