Page 1 of 2
64-bit kernel not passing (char *) correctly
Posted: Wed Jun 18, 2008 10:02 pm
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!
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 3:39 am
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
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 5:22 am
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 . . . . . . . .
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 5:51 am
by AJ
Hi,
I have a couple more suggestions. Firstly, does it work if you just do:
?
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
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 6:51 am
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:
So the function is getting 0 for the characters.
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 7:13 am
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...
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 7:34 am
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.
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 9:16 am
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.
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 11:43 am
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?
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 12:38 pm
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?
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 12:43 pm
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?
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 12:48 pm
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
Re: 64-bit kernel not passing (char *) correctly
Posted: Thu Jun 19, 2008 7:39 pm
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?
Re: 64-bit kernel not passing (char *) correctly
Posted: Fri Jun 20, 2008 12:17 am
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.
Re: 64-bit kernel not passing (char *) correctly
Posted: Fri Jun 20, 2008 6:55 am
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"