Calling C function from assembly

Programming, for all ages and all languages.
User avatar
BMW
Member
Member
Posts: 286
Joined: Mon Nov 05, 2012 8:31 pm
Location: New Zealand

Calling C function from assembly

Post by BMW »

I have a C function:

Code: Select all

void kmain(void* mmap_address, uint32_t mmapentrycount, uint32_t memSize)
I call the function in assembly like this:

Code: Select all

mov eax, [memSize]
push eax
movzx eax, word [mmap_entries]
push eax
mov eax, MemMapAddress ;MemMapAddress is a defined constant
push eax
call kmain
However when I access the arguments in the C function, it gives the wrong argument - memSize actually gives mmapentrycount, and mmapentrycount actually gives mmap_address.....

Am I calling the function wrong?

And if you're going to tell me to RTFM or something similar, I am going off this: http://www.delorie.com/djgpp/doc/ug/asm/calling.html
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 »

Since your problem have yet to occur in the posted code snippets, and the consequential lack of trust in your question accuracy or your toolchain setup, post the exact code and disassembly of kmain, including compilation commands.

Oh and, since you probably wouldn't bother if I didn't call you out on it, read the disassembly. My crystal ball says it is not what you expect.
"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 ]
Casm
Member
Member
Posts: 221
Joined: Sun Oct 17, 2010 2:21 pm
Location: United Kingdom

Re: Calling C function from assembly

Post by Casm »

That looks like the calling convention most 32 bit C compilers use, but maybe yours is different.

You could try pushing it from left to right, instead of right to left, or try sticking _cdecl in front of the function definition. If neither of those work, you will need to consult the documentation for your compiler.

Are you using a 64 bit compiler?
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 »

kmain:

Code: Select all

void kmain(void* mmap_address, uint32_t mmapentrycount, uint32_t memSize)
{
	SetColour(0x1F);
	ClearScreen();
	PrintString("Skux OS\n");
	SetupInterrupts();
	timer_install();
	keyboard_install();
	__asm__ __volatile__("sti");
	
	//initialise physical memory manager
	PrintNumberBase16(memSize >> 24);
	PrintNumberBase16(memSize >> 16 & 0xFF);
	PrintNumberBase16(memSize >> 8 & 0xFF);
	PrintNumberBase16(memSize & 0xFF);
	
	
	
	
	//Process memory map
	SMAP_entry* sm = (SMAP_entry*)mmap_address;
	for(unsigned int i=0;i<mmapentrycount;i++)
	{
		if(sm[i].Type == 1 || sm[i].Type == 3) //Free for use or ACPI reclaimable
		{
			//init region
		}
	}
	
	
	
	for(;;)
	{
		__asm__ __volatile__("hlt");
	}
}
This is the assembly code generated by gcc:

Code: Select all

	.file	"kernel.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	16(%ebp), %eax
	shrl	$24, %eax
	movzbl	%al, %eax
	movl	%eax, (%esp)
	call	PrintNumberBase16
	movl	16(%ebp), %eax
	shrl	$16, %eax
	movzbl	%al, %eax
	movl	%eax, (%esp)
	call	PrintNumberBase16
	movl	16(%ebp), %eax
	shrl	$8, %eax
	movzbl	%al, %eax
	movl	%eax, (%esp)
	call	PrintNumberBase16
	movl	16(%ebp), %eax
	movzbl	%al, %eax
	movl	%eax, (%esp)
	call	PrintNumberBase16
	movl	8(%ebp), %eax
	movl	%eax, -16(%ebp)
	movl	$0, -12(%ebp)
	jmp	.L2
.L4:
	movl	-12(%ebp), %edx
	movl	%edx, %eax
	addl	%eax, %eax
	addl	%edx, %eax
	sall	$3, %eax
	movl	%eax, %edx
	movl	-16(%ebp), %eax
	addl	%edx, %eax
	movzwl	16(%eax), %eax
	cmpw	$1, %ax
	je	.L3
	movl	-12(%ebp), %edx
	movl	%edx, %eax
	addl	%eax, %eax
	addl	%edx, %eax
	sall	$3, %eax
.L3:
	addl	$1, -12(%ebp)
.L2:
	movl	-12(%ebp), %eax
	cmpl	12(%ebp), %eax
	jb	.L4
.L5:
#APP
# 39 "kernel.c" 1
	hlt
# 0 "" 2
#NO_APP
	jmp	.L5
	.cfi_endproc
.LFE0:
	.size	kmain, .-kmain
	.ident	"GCC: (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2"
	.section	.note.GNU-stack,"",@progbits
And this is how I compile kmain:

Code: Select all

gcc -o kernel.o -c kernel.c -Wall -Wextra -nostdlib -nostartfiles -nodefaultlibs -fno-builtin -std=c99
I have had a look at the assembly code but I don't really understand GAS that well.
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 »

Casm wrote:That looks like the calling convention most 32 bit C compilers use, but maybe yours is different.

You could try pushing it from left to right, instead of right to left, or try sticking _cdecl in front of the function definition. If neither of those work, you will need to consult the documentation for your compiler.

Are you using a 64 bit compiler?
GCC doesn't like _cdecl or __cdecl....

The GCC docs say the same way http://gcc.gnu.org/onlinedocs/gnat_ugn_ ... ntion.html

I am using 32-bit compiler.
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: 4689
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Calling C function from assembly

Post by iansjack »

Write a simple wrapper function that calls the kmain() function. Compile to assembler code with gcc. Study that generated assembler code to see what you should be doing when you call a C function. Pay particular attention to any stack-alignment instructions.

If you want to mix assembler and C functions compiled with gcc life will be a lot easier if you use "as" rather than other assemblers (IMO).
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 »

iansjack wrote:Write a simple wrapper function that calls the kmain() function. Compile to assembler code with gcc. Study that generated assembler code to see what you should be doing when you call a C function. Pay particular attention to any stack-alignment instructions.

If you want to mix assembler and C functions compiled with gcc life will be a lot easier if you use "as" rather than other assemblers (IMO).
I am not switching from NASM to GAS... sorry... I hate GAS.

EDIT: Ok I compiled a call to kmain() to assembly... here it is:

Code: Select all

andl	$-16, %esp
subl	$16, %esp
movl	$3, 8(%esp)
movl	$2, 4(%esp)
movl	$1, (%esp)
call	kmain
If I understand it correctly, it ANDs esp with -16, subtracts 16 from esp then puts each argument on the stack (right to left) then calls the function.

I don't understand why it ANDs esp with -16???? (-16 binary = 1111111111110000) Is that the stack alignment you are talking about?
Currently developing Lithium OS (LiOS).

Recursive paging saves lives.
"I want to change the world, but they won't give me the source code."
Casm
Member
Member
Posts: 221
Joined: Sun Oct 17, 2010 2:21 pm
Location: United Kingdom

Re: Calling C function from assembly

Post by Casm »

BMW wrote:
iansjack wrote: If I understand it correctly, it ANDs esp with -16, subtracts 16 from esp then puts each argument on the stack (right to left) then calls the function.

I don't understand why it ANDs esp with -16???? (-16 binary = 1111111111110000) Is that the stack alignment you are talking about?
I am not overly familiar with AT&T syntax, but the code following that seems to be:

Code: Select all

and esp, -16                                 ;if esp was 0x1234, that would make it 0x1230
sub esp, 16                                  ;and that would make it 0x1220 - rounded down to a 16 byte boundary
mov dwrord ptr [esp + 8], 3
mov dword ptr [esp + 4], 2
mov dword ptr [esp], 1
Which would be roughly equivalent to:

Code: Select all

and esp, -16
sub esp, 4                                  ;that is probably the bit which is causing the problems.
mov eax, 3
push eax
mov eax, 2
push eax
mov eax, 1
push eax
User avatar
iansjack
Member
Member
Posts: 4689
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Calling C function from assembly

Post by iansjack »

It's your choice to avoid using what is (IMO) the best tool for this particular job. Personally I relish the chance to learn as much as possible. You will need to understand the assembler syntax used by GCC and "as" if you want to mix C and assembler.

GCC (modern versions) require that the stack is aligned to a 16-bit boundary before a function call.

You are learning some good techniques here to aid in your progress:

1. When things go wrong start debugging. If necessary single-step through the assembler code.

2. Study the code produced by your compiler. It is very instructive. Try to understand why it does what it does. Look at every compiler switch that you use and make sure that you understand exactly what each one does.

3. Learn and use all the tools in your toolset. Have you played with "objdump" yet?

4. Read the appropriate manuals to understand how your processor, other hardware, and toolset work. Read them again. And keep them handy for reference.

5. Remember that computers work logically. Hardware failures aside, there is always a rational explanation for unexpected behaviour. Sometimes it may be a bug in the tools you are using but 99% (or more) of the time it is down to imperfect understanding.

Once you start on the complicated stuff you will need to remember those points and a whole lot more.
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 »

@iansjack: Was it necessary to religiously advocate the use of AT&T syntax? Yes, you need to be able to read it, but that doesn't mean you'd need to write everything in it (and besides, objdump can do intel syntax for a reason)

@BMW: there's way too much code between your "inspection" and where the values are loaded. You won't be able to easily single-step in that code to see if the values on either end are loaded as you expect - especially not in the likely case your unposted code screwed something up again.
"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
iansjack
Member
Member
Posts: 4689
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Calling C function from assembly

Post by iansjack »

@Cobuster - When I repeatedly use the expression IMO you should understand that I am expressing my personal opinion and not religiously advocating anything. I'm sorry if that is not clear.

I sincerely believe that if the OP were to learn to read and write AT&T syntax he would find life easier when interfacing C and assembler. But that's just my belief from my experience; it's not a religion. I'll try to avoid mentioning the subject in future.
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Calling C function from assembly

Post by Gigasoft »

There is nothing wrong with the code that was posted. Is one of the functions that kmain calls written in assembly, and changing EBP?
User avatar
iansjack
Member
Member
Posts: 4689
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Calling C function from assembly

Post by iansjack »

I would try to narrow the problem down. When you call the function from a C wrapper does it give the correct results? If so the problem is in the call mechanism. If the fault is with the function, try commenting out all functions called by kmain. Does it work now? (If not then something is very wrong.) If so, reneable the functions one by one until you discover where the fault lies. Then you can investigate that function, and so on.
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, I reckon I will need to align the stack to a 16 bit boundary... I will try it tomorrow, too tired atm.

When calling the function and aligning stack to 16 bit boundary, I will need to store ESP aye? Or it will muck up the stack.
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 »

BMW wrote:16 bit boundary...
bit != byte :wink:
"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 ]
Locked