Page 2 of 3

Re: Calling C function from assembly

Posted: Sun Jan 27, 2013 4:53 am
by iansjack
Oops! My fault. 16 bit would make little sense.

I much prefer the 64-bit ABI where parameters are (mostly) passed in registers.

Re: Calling C function from assembly

Posted: Sun Jan 27, 2013 2:04 pm
by BMW
Combuster wrote:
BMW wrote:16 bit boundary...
bit != byte :wink:
Yeah I know that... sorry I got it from here:
iansjack wrote:GCC (modern versions) require that the stack is aligned to a 16-bit boundary before a function call.

Re: Calling C function from assembly

Posted: Sun Jan 27, 2013 2:55 pm
by BMW
Ok...

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
Still not working lol... I'll look into it, unless I am not doing the stack alignment correctly?

Re: Calling C function from assembly

Posted: Sun Jan 27, 2013 8:59 pm
by BMW
Wait... why do I need to do

Code: Select all

and esp, -16
sub esp, 16
to align esp to a 16-byte boundary.....

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
EDIT #2: If I use jmp ebx instead of call ebx, it works. But then there is no return address... dafuq?

Re: Calling C function from assembly

Posted: Mon Jan 28, 2013 3:15 am
by Combuster
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).

Re: Calling C function from assembly

Posted: Mon Jan 28, 2013 3:23 am
by bluemoon
Yesh, it's called Dry Run.

Re: Calling C function from assembly

Posted: Wed Jan 30, 2013 3:23 am
by BMW
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)

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

Now this is how I call kmain from assembly:

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
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:

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);
}
That kmain function prints mmap_address instead of mmapentrycount.

I am totally confused right now...

Re: Calling C function from assembly

Posted: Wed Jan 30, 2013 3:39 am
by iansjack
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.

Re: Calling C function from assembly

Posted: Wed Jan 30, 2013 11:11 am
by Kazinsal
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.

Re: Calling C function from assembly

Posted: Wed Jan 30, 2013 1:20 pm
by Combuster
char* a;
itoa(mmapentrycount, a, 10);
You obviously haven't been paying attention anywhere.

- Introducing more code to an existing problem
- Using libc
- Using it wrongly:
reference for itoa, second argument wrote:str
Array in memory where to store the resulting null-terminated string.
I've seen enough. Go take a course C for absolute beginners.

Re: Calling C function from assembly

Posted: Wed Jan 30, 2013 8:55 pm
by BMW
Combuster wrote:
char* a;
itoa(mmapentrycount, a, 10);
You obviously haven't been paying attention anywhere.

- Introducing more code to an existing problem
- Using libc
- Using it wrongly:
reference for itoa, second argument wrote:str
Array in memory where to store the resulting null-terminated string.
I've seen enough. Go take a course C for absolute beginners.
I think I am the one that should be saying "I've seen enough".

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)

:roll:
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.
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.

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.

Re: Calling C function from assembly

Posted: Wed Jan 30, 2013 10:14 pm
by BMW
Ok. This code is the code generated by GCC for calling the kmain function:

Code: Select all

and	esp, -16
	sub	esp, 16
	mov	DWORD PTR [esp+4], 2
	mov	DWORD PTR [esp], 1
	call	kmain
It puts the first argument into [esp], then calls kmain. Wouldn't the call kmain overwrite the first argument with the return address?????

Re: Calling C function from assembly

Posted: Wed Jan 30, 2013 10:46 pm
by thepowersgang
(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)

SOLVED!!! :D

Posted: Wed Jan 30, 2013 11:05 pm
by BMW
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)
Ok, is this better: ?

Code: Select all

char a[16] = {NULL};
itoa(number, a, 10);
Ok I see...
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.

Re: Calling C function from assembly

Posted: Thu Jan 31, 2013 12:23 am
by Antti
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.