Calling C function from assembly
Re: Calling C function from assembly
Oops! My fault. 16 bit would make little sense.
I much prefer the 64-bit ABI where parameters are (mostly) passed in registers.
I much prefer the 64-bit ABI where parameters are (mostly) passed in registers.
Re: Calling C function from assembly
Yeah I know that... sorry I got it from here:Combuster wrote:bit != byteBMW wrote:16 bit boundary...
iansjack wrote:GCC (modern versions) require that the stack is aligned to a 16-bit boundary before a function call.
Currently developing Lithium OS (LiOS).
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Re: Calling C function from assembly
Ok...
Still not working lol... I'll look into it, unless I am not doing the stack alignment correctly?
Code: Select all
;align stack to a 16 byte boundary
and esp, -16
sub esp, 16
;push args onto stack in reverse order
mov dword eax, [memSize]
push eax
movzx eax, word [mmap_entries]
push eax
mov dword eax, MemMapAddress
push eax
mov ebx, KernelAddress
call ebx
Currently developing Lithium OS (LiOS).
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Re: Calling C function from assembly
Wait... why do I need to do
to align esp to a 16-byte boundary.....
Why can't I just use this
?
EDIT: And what does this do in AT&T assembly?
EDIT #2: If I use jmp ebx instead of call ebx, it works. But then there is no return address... dafuq?
Code: Select all
and esp, -16
sub esp, 16
Why can't I just use this
Code: Select all
and esp, -16
EDIT: And what does this do in AT&T assembly?
Code: Select all
.cfi_def_cfa_register 5
Currently developing Lithium OS (LiOS).
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
- Combuster
- 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: Calling C function from assembly
Ever heard of desk checking?
Get a pencil, eraser and a sheet of paper. Then physically draw the stack, and afterwards, perform each instruction by hand and see where each variable ends up in memory in each scenario you're doubting about.
Worst thing of it, is that this is actually a school exercise given in the first month of the computer science bachelor programme (hint: required knowledge).
Get a pencil, eraser and a sheet of paper. Then physically draw the stack, and afterwards, perform each instruction by hand and see where each variable ends up in memory in each scenario you're doubting about.
Worst thing of it, is that this is actually a school exercise given in the first month of the computer science bachelor programme (hint: required knowledge).
Re: Calling C function from assembly
Yesh, it's called Dry Run.
Re: Calling C function from assembly
I have done the test on paper, and it all seemed good. I compiled a call to kmain into GAS with gcc, and this is the result: (the main function calls kmain)
Now this is how I call kmain from assembly:
I am doing the same stack operations as the code generated by GCC. (Except subtracting 16 from esp, which I tried and it makes no difference)
This is the kmain function:
That kmain function prints mmap_address instead of mmapentrycount.
I am totally confused right now...
Code: Select all
.file "test.c"
.section .rodata
.LC0:
.string "Skux OS\n"
.text
.globl kmain
.type kmain, @function
kmain:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $40, %esp
movl $31, (%esp)
call SetColour
call ClearScreen
movl $.LC0, (%esp)
call PrintString
call SetupInterrupts
call timer_install
call keyboard_install
#APP
# 14 "kernel.c" 1
sti
# 0 "" 2
#NO_APP
movl $10, 8(%esp)
movl -12(%ebp), %eax
movl %eax, 4(%esp)
movl 12(%ebp), %eax
movl %eax, (%esp)
call itoa
movl -12(%ebp), %eax
movl %eax, (%esp)
call PrintString
nop
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size kmain, .-kmain
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
movl $2, 4(%esp)
movl $1, (%esp)
call kmain
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2"
.section .note.GNU-stack,"",@progbits
Code: Select all
mov ebp, esp
;align stack to a 16 byte boundary
and esp, -16
;push args onto stack in reverse order
movzx eax, word [mmap_entries]
push eax
mov dword eax, MemMapAddress
push eax
;call kernel
mov ebx, KernelAddress
call ebx
This is the kmain function:
Code: Select all
void kmain(void* mmap_address, uint32_t mmapentrycount)
{
SetColour(0x1F);
ClearScreen();
PrintString("Skux OS\n");
SetupInterrupts();
timer_install();
keyboard_install();
__asm__ __volatile__("sti");
char* a;
itoa(mmapentrycount, a, 10);
PrintString(a);
}
I am totally confused right now...
Currently developing Lithium OS (LiOS).
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Re: Calling C function from assembly
At the risk of stating the obvious, you are not calling kmain() in the same way that the compiled main function does. You are also not looking at the generated instructions but at the generated assembler source code. I would recommend using objdump to see exactly what instructions have been generated in the object file; that way you don't need to puzzle over strange compiler directives.
The compiled main function aligns the stack to a 16-byte boundary, subtracts 16-bytes from the stack pointer (preserving that alignment) and then places the parameters at the appropriate positions in the stack (it does this directly rather than with push instructions - that's why it subtracted 16 from the stack pointer before placing the parameters; only 8 bytes are needed for the two parameters, but it has to be 16 to preserve stack alignment).
Your code aligns the stack to a 16-byte boundary and then pushes 2 4-byte variables to the stack (8 bytes in all), thus misaligning it.
I've no idea whether that difference is the cause of your problem, but I would suggest that it would be reasonable to try the same call sequence as the generated C code rather than your own variation of it. In the end, single-stepping through the code, watching the value of the stack pointer and its contents at each instruction, should reveal the error. That's the same as doing it on paper but without any false assumptions and letting the computer do the hard work.
The compiled main function aligns the stack to a 16-byte boundary, subtracts 16-bytes from the stack pointer (preserving that alignment) and then places the parameters at the appropriate positions in the stack (it does this directly rather than with push instructions - that's why it subtracted 16 from the stack pointer before placing the parameters; only 8 bytes are needed for the two parameters, but it has to be 16 to preserve stack alignment).
Your code aligns the stack to a 16-byte boundary and then pushes 2 4-byte variables to the stack (8 bytes in all), thus misaligning it.
I've no idea whether that difference is the cause of your problem, but I would suggest that it would be reasonable to try the same call sequence as the generated C code rather than your own variation of it. In the end, single-stepping through the code, watching the value of the stack pointer and its contents at each instruction, should reveal the error. That's the same as doing it on paper but without any false assumptions and letting the computer do the hard work.
- Kazinsal
- Member
- Posts: 559
- Joined: Wed Jul 13, 2011 7:38 pm
- Libera.chat IRC: Kazinsal
- Location: Vancouver
- Contact:
Re: Calling C function from assembly
The lack of manual of style in your code (notably the mixed forms of function naming) suggests to me that you are copying and pasting from a multitude of sources and expecting everything to work. I am beginning to seriously doubt that you have the required knowledge for operating system development. Consider how the stack works. Then ask yourself why that sub esp, 16 is there.
I claim not that I am a master of OS dev. In fact, I am in most regards, the opposite. I simply learn from sources of my own finding, my own mistakes, R-ing TFM, and most importantly, thinking critically.
I claim not that I am a master of OS dev. In fact, I am in most regards, the opposite. I simply learn from sources of my own finding, my own mistakes, R-ing TFM, and most importantly, thinking critically.
- Combuster
- 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: Calling C function from assembly
You obviously haven't been paying attention anywhere.char* a;
itoa(mmapentrycount, a, 10);
- Introducing more code to an existing problem
- Using libc
- Using it wrongly:
I've seen enough. Go take a course C for absolute beginners.reference for itoa, second argument wrote:str
Array in memory where to store the resulting null-terminated string.
Re: Calling C function from assembly
I think I am the one that should be saying "I've seen enough".Combuster wrote:You obviously haven't been paying attention anywhere.char* a;
itoa(mmapentrycount, a, 10);
- Introducing more code to an existing problem
- Using libc
- Using it wrongly:I've seen enough. Go take a course C for absolute beginners.reference for itoa, second argument wrote:str
Array in memory where to store the resulting null-terminated string.
What makes you think that I am noob enough to use libc, and use it wrongly? Your two accusations are based on an assumption, that I am using the itoa() function from libc. The truth is that I implemented my own itoa() function, and I am using my own itoa() function correctly. (Ok, I wasn't using it correctly but I am now)
I think it is harder to use code from different sources than to blindly follow one tutorial, not even understanding the code. And I don't see anything wrong with copying and pasting provided you understand the code you are copying (which I do). This problem arose when I tried to put in my own code, and has nothing to do with "copying and pasting from a multitude of sources and expecting everything to work". I can program well enough to integrate different tutorials (although most people on this forum assume that I am a total noob). As for the function naming, I will be standardising the function names once I get everything working and have decided on a suitable naming convention.Blacklight wrote:The lack of manual of style in your code (notably the mixed forms of function naming) suggests to me that you are copying and pasting from a multitude of sources and expecting everything to work. I am beginning to seriously doubt that you have the required knowledge for operating system development. Consider how the stack works. Then ask yourself why that sub esp, 16 is there.
I claim not that I am a master of OS dev. In fact, I am in most regards, the opposite. I simply learn from sources of my own finding, my own mistakes, R-ing TFM, and most importantly, thinking critically.
Going back to the problem, I admit I could have done a better job at debugging. But what makes me angry is that people on this forum start to doubt my abilities using totally irrelevant information and unfair assumptions. The assumptions in themselves show that people don't trust my ability. For example someone assumed that I used itoa() from libc, and hadn't implemented my own.
And to all the people that think I never try to debug problems myself, but rather post questions of the forum, stop assuming!!! I have successfully debugged many problems myself, many more that I have posted here on these forums.
Last edited by BMW on Thu Jan 31, 2013 1:32 am, edited 3 times in total.
Currently developing Lithium OS (LiOS).
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Re: Calling C function from assembly
Ok. This code is the code generated by GCC for calling the kmain function:
It puts the first argument into [esp], then calls kmain. Wouldn't the call kmain overwrite the first argument with the return address?????
Code: Select all
and esp, -16
sub esp, 16
mov DWORD PTR [esp+4], 2
mov DWORD PTR [esp], 1
call kmain
Currently developing Lithium OS (LiOS).
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
- thepowersgang
- Member
- Posts: 734
- Joined: Tue Dec 25, 2007 6:03 am
- Libera.chat IRC: thePowersGang
- Location: Perth, Western Australia
- Contact:
Re: Calling C function from assembly
(first off, from the C code snippet above, you _are_ calling itoa incorrectly, unless you're using C++ and references, in which case you should be shot)
Secondly, that code will work correctly, as ESP is decremented before the write when something is pushed to the stack (functionally the same as *--esp in C)
(Finally, is that actually the emitted code? that 'add esp, -16' looks very out of place)
Secondly, that code will work correctly, as ESP is decremented before the write when something is pushed to the stack (functionally the same as *--esp in C)
(Finally, is that actually the emitted code? that 'add esp, -16' looks very out of place)
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
SOLVED!!! :D
Ok, is this better: ?thepowersgang wrote:(first off, from the C code snippet above, you _are_ calling itoa incorrectly, unless you're using C++ and references, in which case you should be shot)
Secondly, that code will work correctly, as ESP is decremented before the write when something is pushed to the stack (functionally the same as *--esp in C)
(Finally, is that actually the emitted code? that 'add esp, -16' looks very out of place)
Code: Select all
char a[16] = {NULL};
itoa(number, a, 10);
It is and not add (that makes more sense).
Anyway, I have solved it. Sorry for wasting everyones time. Such a stupid mistake on my part.
When I called kmain from assembly, I was not actually calling kmain, but calling the loader stub (as used in the bare bones tutorial). This loader stub then CALLed kmain, pushing an extra return address onto the stack. Changing the CALL in the stub to JMP fixed my problem.
Once again, sorry guys for wasting your time. Thanks anyway for all your help.
Currently developing Lithium OS (LiOS).
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Re: Calling C function from assembly
As an offtopic note, I think your posts are quite good nowadays. Spelling, politeness etc. meet the standards of this forum. Keep going! Do not take "noob" accusations too seriously.