Calling C function from assembly

Programming, for all ages and all languages.
User avatar
iansjack
Member
Member
Posts: 4686
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Calling C function from assembly

Post 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.
User avatar
BMW
Member
Member
Posts: 286
Joined: Mon Nov 05, 2012 8:31 pm
Location: New Zealand

Re: Calling C function from assembly

Post 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.
Currently developing Lithium OS (LiOS).

Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
User avatar
BMW
Member
Member
Posts: 286
Joined: Mon Nov 05, 2012 8:31 pm
Location: New Zealand

Re: Calling C function from assembly

Post 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?
Currently developing Lithium OS (LiOS).

Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
User avatar
BMW
Member
Member
Posts: 286
Joined: Mon Nov 05, 2012 8:31 pm
Location: New Zealand

Re: Calling C function from assembly

Post 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?
Currently developing Lithium OS (LiOS).

Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
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: Calling C function from assembly

Post 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).
"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
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Calling C function from assembly

Post by bluemoon »

Yesh, it's called Dry Run.
User avatar
BMW
Member
Member
Posts: 286
Joined: Mon Nov 05, 2012 8:31 pm
Location: New Zealand

Re: Calling C function from assembly

Post 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...
Currently developing Lithium OS (LiOS).

Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
User avatar
iansjack
Member
Member
Posts: 4686
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Calling C function from assembly

Post 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.
User avatar
Kazinsal
Member
Member
Posts: 559
Joined: Wed Jul 13, 2011 7:38 pm
Libera.chat IRC: Kazinsal
Location: Vancouver
Contact:

Re: Calling C function from assembly

Post 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.
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: Calling C function from assembly

Post 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.
"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
BMW
Member
Member
Posts: 286
Joined: Mon Nov 05, 2012 8:31 pm
Location: New Zealand

Re: Calling C function from assembly

Post 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.
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."
User avatar
BMW
Member
Member
Posts: 286
Joined: Mon Nov 05, 2012 8:31 pm
Location: New Zealand

Re: Calling C function from assembly

Post 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?????
Currently developing Lithium OS (LiOS).

Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
User avatar
thepowersgang
Member
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

Post 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)
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
User avatar
BMW
Member
Member
Posts: 286
Joined: Mon Nov 05, 2012 8:31 pm
Location: New Zealand

SOLVED!!! :D

Post 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.
Currently developing Lithium OS (LiOS).

Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: Calling C function from assembly

Post 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.
Locked