64-bit kernel not passing (char *) correctly

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.
User avatar
sngskunk
Member
Member
Posts: 47
Joined: Mon Mar 31, 2008 1:00 pm
Location: Louisville, KY, USA

64-bit kernel not passing (char *) correctly

Post by sngskunk »

I am in long mode and I have a function put(char) which writes to the screen corretly no problems there. But I then have a function write(char *) which will not print the string correctly it prints nothing.

Code: Select all

void write(char *c) {
    int i = 0;
    while(c[i]) {
        put(c[i++]);
    }
}
The function above prints nothing because c[0] is equal to zero when it should be if I pass it a string like "hello". I don't get a fault or anything just nothing gets printed. I found this in an objdump of my file and wonding if this could be a cause:

Code: Select all

 <.rodata>:
   0:   68 65 6c 6c 6f          pushq  $0x6f6c6c65
My linker script is also below, it maybe could be something in there, I have tryed many things but cannot seem to get it to work.

Code: Select all

OUTPUT_FORMAT(binary)
ENTRY(start)
SECTIONS
{
    . = KERNEL_VMA;

    .text : AT(ADDR(.text) - KERNEL_VMA)
    {
        _code = .;
        *(.text)
        *(.rodata) /* Also tryed *(.rodata*) niether work */
        . = ALIGN(4096);
    }

   .data : AT(ADDR(.data) - KERNEL_VMA)
   {
        _data = .;
        *(.data)
        . = ALIGN(4096);
   }
   
   .ehframe : AT(ADDR(.ehframe) - KERNEL_VMA)
   {
       _ehframe = .;
       *(.ehframe)
        . = ALIGN(4096);
   }

   .bss : AT(ADDR(.bss) - KERNEL_VMA)
   {
       _bss = .;
       *(.bss)
       . = ALIGN(4096);
   }

   _end = .;

   /DISCARD/ :
   {
        *(.comment)
   }
}
Any help would be great, thanks!
Currently Working On:
Bootloader (Stage 1) (Complete)
Bootloader (Stage 2) (Inprogress)
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: 64-bit kernel not passing (char *) correctly

Post by AJ »

Hi,

I wonder if the problem could be that you are putting your readonly data in your code section. My data section runs as follows:

Code: Select all

.data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    *(.rodata)
    . = ALIGN(0x1000);
  }
..I have taken some lines out for my ctors and dtors sections. This is partly why your disassembler is trying do disassemble the data.

Cheers,
Adam
User avatar
sngskunk
Member
Member
Posts: 47
Joined: Mon Mar 31, 2008 1:00 pm
Location: Louisville, KY, USA

Re: 64-bit kernel not passing (char *) correctly

Post by sngskunk »

I tryed what you sujested but it did not work, isn't rodata code since it looks like this:

Code: Select all

 <.rodata>:
   0:   68 65 6c 6c 6f          pushq  $0x6f6c6c65
It has a push command meaning it should go in the .text section.

I also checked my binary out put file and the string is in the binary, since the string is in rodata and i put it after the .text section, then that is where it is, just don't know why its not working, becuase the linker is putting it in the binary.

Code: Select all

0x3f0 | C0 75 D8 C9 C3 68 65 6C 6C 6F 00 00 00 00 00 00 00 00
        .  u  .  .  .  h  e  l  l  o  .  .  .  .  .  .  .  .   
Currently Working On:
Bootloader (Stage 1) (Complete)
Bootloader (Stage 2) (Inprogress)
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: 64-bit kernel not passing (char *) correctly

Post by AJ »

Hi,

I have a couple more suggestions. Firstly, does it work if you just do:

Code: Select all

put('a');
?

Next, have you currently got any way of checking the value of the char *c is when "write" gets called? Perhaps use some inline asm to load this pointer value in to a register, terminate Bochs and view the Bochs register dump. Is that value what you expect it to be? Of course, once you get it working, you will want a few sanity checks at the start of the write function (like is c NULL).

To clarify the objdump thing, just because objdump can find opcodes which match the hex data "68 65 6c 6c 6f" (translating it to a pushfq instruction) does not mean that your kernel ever tries to run that as code. You will note that these hex values translate to "hello", which means that it is stored as it should be.

Cheers,
Adam
User avatar
sngskunk
Member
Member
Posts: 47
Joined: Mon Mar 31, 2008 1:00 pm
Location: Louisville, KY, USA

Re: 64-bit kernel not passing (char *) correctly

Post by sngskunk »

My put() function works fine, I have a working hex and integer printing functions so I did this to get the value that my write function gets.

Code: Select all

void write(char *c) {
    writeHex(c[0]);
    put('\n');
    writeHex(&c);
    put('\n');
    writeHex(c);
}
Output is like this:

Code: Select all

0x0
0x8FFD8
0x1011F1
So the function is getting 0 for the characters.
Currently Working On:
Bootloader (Stage 1) (Complete)
Bootloader (Stage 2) (Inprogress)
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: 64-bit kernel not passing (char *) correctly

Post by Combuster »

The offset to c is 0x1011f1, whereas in the binary its at 0x3f5 (which is 0x1003f5 in memory)

Right now I wonder why the padding doesn't get into the output binary...
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
sngskunk
Member
Member
Posts: 47
Joined: Mon Mar 31, 2008 1:00 pm
Location: Louisville, KY, USA

Re: 64-bit kernel not passing (char *) correctly

Post by sngskunk »

Combuster, I looked at what you said and I had change my linker script to see if it would fix it, but of cource it did not, so I looked at the binary file again, and this is where the string is located:

Code: Select all

0x11E3 | 00 00 00 00 00 00 80 0B 00 00 00 00 00 0F 68 65 6C 6C 6F
         .  .  .  .  .  .  .  .  .  .  .  .  .  .  h  e  l  l  o
It look like to me it is in the right place and it should see the string.
Currently Working On:
Bootloader (Stage 1) (Complete)
Bootloader (Stage 2) (Inprogress)
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Re: 64-bit kernel not passing (char *) correctly

Post by 01000101 »

I remember there being some issues in an earlier post about the va_arg macros. If you use them, you might want to check out this post.
User avatar
sngskunk
Member
Member
Posts: 47
Joined: Mon Mar 31, 2008 1:00 pm
Location: Louisville, KY, USA

Re: 64-bit kernel not passing (char *) correctly

Post by sngskunk »

I am not trying to do anything with va_arg macros, I am just trying to print a string, I am not trying to pass it a string that needs to be formated, with arguments.

I did take a look at some linux source, and the only difference I see is that the use (const char*) instead of mine being (char *), i made that change and that didn't fix anything.

Does anyone have a working 64-bit string printing function that I could look at?
Currently Working On:
Bootloader (Stage 1) (Complete)
Bootloader (Stage 2) (Inprogress)
User avatar
sngskunk
Member
Member
Posts: 47
Joined: Mon Mar 31, 2008 1:00 pm
Location: Louisville, KY, USA

Re: 64-bit kernel not passing (char *) correctly

Post by sngskunk »

I have been looking at where the pointer points to and it points to the beginning of the string in memory, I am 100% sure of this, but no matter what I do to dereference that location I get zero, why?
Currently Working On:
Bootloader (Stage 1) (Complete)
Bootloader (Stage 2) (Inprogress)
Korona
Member
Member
Posts: 1000
Joined: Thu May 17, 2007 1:27 pm
Contact:

Re: 64-bit kernel not passing (char *) correctly

Post by Korona »

Try to disassemble the function that is generated by gcc.
EDIT: Are you sure the pages that contain the string are properly mapped?
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].
User avatar
sngskunk
Member
Member
Posts: 47
Joined: Mon Mar 31, 2008 1:00 pm
Location: Louisville, KY, USA

Re: 64-bit kernel not passing (char *) correctly

Post by sngskunk »

I have all memory mapped to 1:1 paging right now all the way up to 34mb.

Here it is:

Code: Select all

0000000000000319 <write>:
 319:	55                   	push   %rbp
 31a:	48 89 e5             	mov    %rsp,%rbp
 31d:	48 83 ec 10          	sub    $0x10,%rsp
 321:	48 89 7d f8          	mov    %rdi,-0x8(%rbp)
 325:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
 329:	0f b6 00             	movzbl (%rax),%eax
 32c:	0f be f8             	movsbl %al,%edi
 32f:	e8 00 00 00 00       	callq  334 <write+0x1b>
 334:	c9                   	leaveq 
 335:	c3                   	retq   
after binary linking my function looks like this:

Code: Select all

0000000000000319 <write>:
 319:	55                   	push   %rbp
 31a:	48 89 e5             	mov    %rsp,%rbp
 31d:	48 83 ec 10          	sub    $0x10,%rsp
 321:	48 89 7d f8          	mov    %rdi,-0x8(%rbp)
 325:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
 329:	0f b6 00             	movzbl (%rax),%eax
 32c:	0f be f8             	movsbl %al,%edi
 32f:	e8 05 FE FF FF       	callq  (Do not know what is here now)    <---- Those "00 00 00 00" become "05 FE FF FF"
 334:	c9                   	leaveq 
 335:	c3                   	retq   
Currently Working On:
Bootloader (Stage 1) (Complete)
Bootloader (Stage 2) (Inprogress)
User avatar
sngskunk
Member
Member
Posts: 47
Joined: Mon Mar 31, 2008 1:00 pm
Location: Louisville, KY, USA

Re: 64-bit kernel not passing (char *) correctly

Post by sngskunk »

I found out that the string that is passed through the function (example: write("hello");) the hello gets put in the .rodata section as a pushq command, which is weird the parameter is not a (const char *). I include the .rodata at the end of my .text secion linker and then my linker compiles it to binary.

Is that how it should be done? or should I change something in my linker script?
Currently Working On:
Bootloader (Stage 1) (Complete)
Bootloader (Stage 2) (Inprogress)
xyzzy
Member
Member
Posts: 391
Joined: Wed Jul 25, 2007 8:45 am
Libera.chat IRC: aejsmith
Location: London, UK
Contact:

Re: 64-bit kernel not passing (char *) correctly

Post by xyzzy »

No. The .rodata section ideally should be in its own section, .rodata, rather than .text, as mentioned at the start of the thread. It is not a pushq instruction, it just so happens that the hex for "hello" translates to that instruction when objdump tries to disassemble it because you put it in the wrong section, as mentioned before as well. See AJ's first post about the linker script.

EDIT: It was pointed out to me on IRC that .rodata should really be in its own section, as by definition it is read-only so shouldn't be in .data, which is read-write. Corrected.
Last edited by xyzzy on Sat Jun 21, 2008 4:43 am, edited 1 time in total.
User avatar
sngskunk
Member
Member
Posts: 47
Joined: Mon Mar 31, 2008 1:00 pm
Location: Louisville, KY, USA

Re: 64-bit kernel not passing (char *) correctly

Post by sngskunk »

Okay i understand about the jump command, but it still isn't working.

It doesn't matter what section I put it in, if i put it in .data is doesn't work, if i put it in its own section it doesn't work, if i put it in .text it doesn't work. they all get the same result.

If i get the address of the passed string it is correct:

0x1011F1 - (0x100000 "Loaded Address") = 0x11F1

Checked with hex editor:

0x11F1 | 68 65 6C 6C 6F 00 < "h e l l o \0"
Currently Working On:
Bootloader (Stage 1) (Complete)
Bootloader (Stage 2) (Inprogress)
Post Reply