[SOLVED] RIP-relative vs. absolute addressing in 64-bit

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
remy
Posts: 23
Joined: Thu Nov 20, 2014 4:06 pm

[SOLVED] RIP-relative vs. absolute addressing in 64-bit

Post by remy »

EDIT : please read below the next posts

Hi,

This is the structure of my project :
- "boot.asm" : enters 64-bit mode, make a CHS read and load "kernel" to 0x100000, then jmp to 0x100000
- "kernel.asm"

This is "kernel.asm" :

Code: Select all

        [bits 64]
	msg:	db		"K"
	mov al, [msg]
	mov ah, 3 ; cyan
	mov word [0xb8000], ax
	jmp $
This code works when is put in "boot.asm". But only prints strange glyphs or an "S" when put in "kernel.asm"... I don't know why. The problem seems to be with "msg" declaration.
For example, when I replace " msg: db "K" " by " msg equ "K" " then it works, I can't figure out the problem, do you have any suggestions ?

Cheers,
Last edited by remy on Wed Nov 26, 2014 10:00 am, edited 3 times in total.
User avatar
Roman
Member
Member
Posts: 568
Joined: Thu Mar 27, 2014 3:57 am
Location: Moscow, Russia
Contact:

Re: Issue with VGA memory after booting to the kernel

Post by Roman »

Maybe the problem is, that the CPU tries to execute "K" (data instead of code)?
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
- Alan Kay
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Issue with VGA memory after booting to the kernel

Post by Gigasoft »

This indicates that an incorrect base address was used when linking. You should also note that you are also jumping to the "K" instead of the mov al, [msg] instruction, thereby changing the meaning to mov al, [msg + r12].
remy
Posts: 23
Joined: Thu Nov 20, 2014 4:06 pm

Re: Issue with VGA memory after booting to the kernel

Post by remy »

@Gigasoft: it gaves me the same result when I move 'msg' declaration after the 'jmp $' for example.
Concerning the base address, I don't know, I didn't linked the code actually, this is what I did :

build.sh:

Code: Select all

#Put bootloader in sector 0x1 (the first sector)
nasm boot.asm -o boot.bin
dd if=/dev/zero of=image.bin bs=512 count=2880
dd if=boot.bin of=image.bin conv=notrunc

#Put kernel in sector 0x2
nasm kernel.asm -o kernel.bin
dd if=kernel.bin of=image.bin conv=notrunc bs=512 seek=1

qemu-system-x86_64  image.bin 
I just load kernel.bin from disk to 0x100000 then make a jmp to it. Else, how do I configure the base address ?

Thanks,
remy
Posts: 23
Joined: Thu Nov 20, 2014 4:06 pm

Re: Issue with VGA memory after booting to the kernel

Post by remy »

The problem is PARTIALLY fixed with the

Code: Select all

default rel
directive.
Please, read my next post...

For infos, see : http://www.nasm.us/doc/nasmdo11.html

The question then is why but why do I jump into RIP-relative addressing whereas 64-bit mode is by default in absolute path addressing ??
Any idea ?

Working code is now :

Code: Select all

[bits 64]
[default rel]

	mov al, [msg]
	mov ah, 3 ; cyan
	mov word [abs 0xb8002], ax
	
	mov al, [msg+1]
	mov ah, 3 ; cyan
	mov word [abs 0xb8002+2], ax
	
	jmp $

	msg:	    db		"Hi"
Note that I now have to prefix the absolute addresses with abs

Cheers,
Last edited by remy on Wed Nov 26, 2014 3:59 am, edited 1 time in total.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Issue with VGA memory after booting to the kernel

Post by Schol-R-LEA »

Good work solving this; you're at the point where you can load a second stage, which is crucial for later work.

However, you now have a few choices to make:
  • Do you want to try and load the kernel as the second stage directly, or do you want to have an intermediate second stage which can be larger and more elaborate than the 510-byte boot loader?
  • Do you want to keep the code to switch to long mode in the boot loader, or do you want to have it in the second stage, which would give you greater flexibility in the boot loader and more room for things like error checking and interacting with the file system?
  • What file system do you want to use? Are you planning on using an existing file system such as FAT32 or ext3fs, or were you going to roll your own (not generally advisable)? Do you have tools to partition the disk image file, format it, etc to the file system you want to use? Does the file system of your choice restrict how you can set up the boot loader and second stage?
  • What object format are you planning on using? In your previous thread, you found that your C compiler was generating ELF executables, which is the most commonly used object format in the Linux world (and in Unix in general, today); do you mean to stick to that, or do you want to use some other format (GCC can generate several different ones depending on how you configure it)?
I'm not trying to intimidate you with this list; on the contrary, I'm just giving you some idea of the road ahead.

Of these decisions, I would say that choice of where to set up the protected/long mode switch is the first priority, because having that in the boot loader really gives up too much flexibility in the form of code space that could be used for other purposes. I specifically would recommend having a sort of rump file system in the boot loader instead, just enough to read the location of a second stage loader file. By having a second stage loader, and making it a regular file in the filesystem rather than a fixed location on the disk partition, you make it much easier to fix things like changes in the size of the second stage later on.

You can load the second stage as a 16-bit real mode raw binary, and have the switch to long mode there. This also gives you more room for testing, gathering hardware information from the BIOS, and for setting up the GDTs, IDT, etc. properly when you do the mode switch. Finally, it gives you enough room for a slightly more elaborate version of your mini-filesystem reader, one which can load the actual kernel in whichever object format you choose to support.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
remy
Posts: 23
Joined: Thu Nov 20, 2014 4:06 pm

Re: Issue with VGA memory after booting to the kernel

Post by remy »

@Schol-R-LEA : my 'goto' is keeping things the simplest. Concerning the file system : I will keep the first sectors of the drive as binaries, ie. out of the file system. I will probably then implement my own file system. But for the moment, I do things step by step..!

PROBLEM:
Actually, the problem is not solved. I still have a problem with RIP-relative and absolute addressing.
For example, this code works :

Code: Select all

[bits 64]
[default rel]          ;braces are optional

mov al, [msg+1]
mov ah, 3 ; cyan
mov word [abs 0xb8002+2], ax

jmp $

msg:    db      "Hi"
But this code prints something wrong, which seems to be an address mismatch. And the other hand, this code works when put in my boot.asm.

Code: Select all

[bits 64]
[default rel]

mov ebx, 1
mov ecx, 2

mov al, [msg + ebx]
mov ah, 3 ; cyan
mov word [abs 0xb8000 + ecx], ax

jmp $

msg:    db      "Hi"

Any suggestions to fix this mess between RIP-relative and absolute addressing ?
Thanks,
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Issue with RIP-relative vs. absolute addressing in 64-bi

Post by Schol-R-LEA »

I think you'll find that the two pieces of code are not quite equivalent. This would be closer to what you are looking for:

Code: Select all

[bits 64]
[default rel]

mov rbx, 1
mov rcx, 0xb8000

mov al, [msg]
mov ah, 3 ; cyan
mov word [rcx], ax

mov al, [msg + rbx]
mov ah, 3 ; cyan
mov word [rcx + 2], ax

jmp $

msg:    db      "Hi"
Though in fact I would really recommend a more general approach anyway:

Code: Select all

[bits 64]
[default rel]

video_base equ 0xb8000
cyan equ 3

[section .text]
entry:
    push video_base
    call set_cursor
    push msg
    push cyan
    call puts

end:
    hlt
    jmp end    

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; functions used by the program

set_cursor:
    push rbp
    mov rbp, rsp
    mov rax, [rbp + 16]
    mov [cursor], rax
    pop rbp
    ret  

advance_cursor:
    add [cursor], 2
    ret

puts:
    push rbp
    mov rbp, rsp
    push rcx
    mov rcx, 0
    mov rdx, [rbp + 16]
    mov ah, [rbp + 24]
    jmp .test    
 .loop:
    push al
    push ah
    call putchar
    add rcx, 1
 .test:
    mov al, [rdx + rcx]
    cmp al, 0
    jnz ,loop
    pop rcx
    pop rbp
    ret

putchar:
    push rbp
    mov rbp, rsp
    mov al, [rbp + 16]
    mov ah, [rbp + 24]
    mov word [cursor], ax
    call advance_cursor
    pop rbp
    ret

[section .data]
msg:    db      "Hello world", 0

[section .bss]
cursor: resq    1
Note that this isn't tested code; I just sort of whipped it up right now. Feel free to fix it as necessary,
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
remy
Posts: 23
Joined: Thu Nov 20, 2014 4:06 pm

Re: Issue with RIP-relative vs. absolute addressing in 64-bi

Post by remy »

@Schol-R-LEA: sorry that doesn't fix the problem.
Octocontrabass
Member
Member
Posts: 5590
Joined: Mon Mar 25, 2013 7:01 pm

Re: Issue with RIP-relative vs. absolute addressing in 64-bi

Post by Octocontrabass »

Using "default rel" does not make all addresses RIP-relative. (Here, have a diagram of valid addressing modes.)

RIP-relative addressing is intended primarily for position-independent code, though it can be used elsewhere. Position-independent code is code that will function correctly, even if you don't load it at the address the assembler is expecting.

You are loading your code at address 0x100000. Did you tell that to the assembler? (Hint: you didn't.)
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Issue with RIP-relative vs. absolute addressing in 64-bi

Post by Schol-R-LEA »

Ah! I feel foolish for missing that myself. Yes, you will need an ORG directive to indicate how the addresses should be assembled.

@remy: If I might suggest something that could potentially save you a lot of trouble in the future: if you are not using source control already, start doing so. You only need make a serious mistake in your code once to realize the importance of having your code securely versioned and easily retrievable. There are several to choose from, and some of the major repository sites (Sourceforge, GitHub) provide free, version-controlled storage space for open-source projects, or for a nominal fee for private projects. It would also make it a lot easier to collaborate with and get help from others. Trust me, it may seem like overkill right now, but once you get into the habit of using revision control, you'll wonder how you did without it.

So why do I mention this now? Because it would be a lot easier for both you and us if you had your code up on, say, GitHub, and could simply point to there, rather than pasting changes to the forum all the time. That way, we could always see exactly what you are working on most recently as well. Just a thought.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
remy
Posts: 23
Joined: Thu Nov 20, 2014 4:06 pm

Re: Issue with RIP-relative vs. absolute addressing in 64-bi

Post by remy »

@Octocontrabass : you're the one !! I'll put my woofer on next time !
Post Reply