ASM functions in c

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
pskyboy

ASM functions in c

Post by pskyboy »

Hey guys

What do i need to do in order to get a function in assembler to be able to be called from c. By this i mean how do i declare them in c

do i just do extern _function ?

Peter
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:ASM functions in c

Post by Pype.Clicker »

your asm function must be declared global in the asm file ... then you have to declare the prototype of the function in a C header.

Code: Select all

-=-=-=-=-= 8< -=-= ASM =-=-=-=-
global _my_func
_my_func:
       push ebp
       mov ebp,esp

       ; your asm code here
       ; [ebp+8] == first C parameter, [ebp+12]=second,
       ; [ebp+16] == third ...
       mov eax,<return code>
       pop ebp
       ret

-=-=-=-=-= 8< -=-=- C -=-=-=-=-=-
int my_func(...);
i strongly suggest your ASM function only return pointers or integers (do not return structures as it means other calling conventions) -- and same rule apply for parameters.
pskyboy

Re:ASM functions in c

Post by pskyboy »

Hmm whenever i try and call my ASM funtions it crashes the program.

do i need to have

global _name
_name:

or

global _name
name:

Also how can i get the ASM to be put inline or does this happen automatically. If not will defining my function as inline in teh c header file do it.

Peter
Berserk

Re:ASM functions in c

Post by Berserk »

This is what you do:

Int your asm source file put

Code: Select all

 [GLOBAL _Function]
Function is the name of your function.

Then in your C source file put a prototype that looks something like this:

Code: Select all

extern void _Function(int args);
Replace it with the return type of your function & the args of your function.
Berserk

Re:ASM functions in c

Post by Berserk »

Hey,

Sorry i did some typos: where i said Int i meant in.

And one more thing:

When you put

Code: Select all

[GLOBAL _Function]
Before your function in your asm file, just put it at the top.

After you do the prototype, use the function as a normal 'c' function!!

Ciao ;)
Berserk

Re:ASM functions in c

Post by Berserk »

Sorry, i forgot to say something:

When you do the prototype you don't need to put the underscore (_) so just put something like this

Code: Select all

 extern void Function(void);
Cya, that's all i have to say!!
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:ASM functions in c

Post by Pype.Clicker »

pskyboy wrote: Hmm whenever i try and call my ASM funtions it crashes the program.
what do you mean by "crash" ? a reboot at run-time ? This should not occur unless you have trashed some registers that the C code expects to be saved/restored by the callee ...

You need to know that C/C++ compilers splits the register set in two parts :
- registers saved by the caller (mainly %eax and %edx)
- registers saved by the callee (mainly every other registers)

it is therefore wise to put a pusha / popa pair around your code so that you're sure you did not trash anything ... (though it might makes more complicated to set a return value in %eax with that technique...)

Now, another possible reason why your code crash is that you did something wrong with the stack (pushed something you don't pop or pop something you didn't push), which leaves the stack inconsistent state at the time of executing the RET instruction

A way you can protect yourself from this is to use

Code: Select all

    push ebp
    mov ebp, esp
    ...
    mov esp,ebp
    pop ebp
    ret
which will at least reset the stack pointer (%esp) to its right value though it cannot guarantee you didn't overwrote the return address with misbehaved code 8)
do i need to have

global _name
_name:
this is that ^ one ... a typo from mine ... note that the leading underscore is only mandatory if you have a DOS/windows-based system: the ELF file format used in Linux do not prepend a '_' to the function names ...
Also how can i get the ASM to be put inline or does this happen automatically. If not will defining my function as inline in teh c header file do it.
by no way the compiler will be able to inline an ASM function written in stuff.asm into a C function written in other_stuff.c
Mainly because the compiler completely ingore what is in stuff.asm by the time it writes other_stuff.o ...
If you want your ASM function to be inlined, you need to declare it as a

Code: Select all

static __inline__ fct( <args> )
in a header file that other_stuff.c will include (or directly in other_stuff.c, but you probably don't want it, do you ?) and write your ASM code as an inline assembly command through

Code: Select all

 asm __volatile__ ("<code>" : <registers use & arguments passing)
...

oh . i'm afraid i assumed you use GCC in the latest (__inline__ and __volatile__) hints. of course those ones are compiler-specific (better not use them with VC++ :)
pskyboy

Re:ASM functions in c

Post by pskyboy »

You assumed right i am using GCC :)

My code that crashes the program is

[glogal _read_cr0]
_read:
mov eax, cr0
retn

This was taken from a tuitorial on bona fide OS dev

Oh and when i say crash it causes the system to be reset

Peter
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:ASM functions in c

Post by Pype.Clicker »

this should not crash the system in a correct environment ...
you're facing an "obscure event" :-(

i suspect there is something with about your stack, or about the way nasm handled the "retn" instruction (maybe you could disassemble your file using "objdump -d [.o file] > [.dis file]" and check if the opcodes are the one expected ...

i guess "_read" instead of "_read_cr0" is a typo ... however, the linker should not let you go ahead if _read wasn't defined ... maybe you can disassemble the calling function and see if the address for the call is the right one as well (once the whole file has been linked and is ready for loading ...)
.bdjames

Re:ASM functions in c

Post by .bdjames »

inline volatile static int cr0(){
int a;
asm(
"movl %%cr0, %0\n\t"
: "=a" (a)
);
return a;
}
richie

Re:ASM functions in c

Post by richie »

Perhaps you does something wrong with the extern-statement. It should look something like this:
extern long _read_cr0();
In this case, gcc knows that the eax register will be changed after the function-call. If the type of the return value is void (no return value), gcc uses eax before the function is called and afterwards it assumes that eax has the same value like before. So you must save eax in a function that returns nothing. The code for your asm-function looks like this:

Code: Select all

;asm-file
[global _read_cr0]

;some other asm-code

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; long _read_cr0(); ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

_read_cr0:
 mov eax, cr0
 ret

;....

Code: Select all

//C-file

//include ....

extern long _read_cr0();

//other c-stuff

//some dummy-function (only to demonstrate it)
void dummy(int para1, int para2)
{
 long temp;    //a local variable
 //...
 //now we need cr0
 temp = _read_cr0();
 //now we have cr0 in temp
}
This way works in nasm and gcc. I compile/assemble both files to their object file and link these two object files to one binary.

Another thing is that there is no need to name your asm-function with a beginnig underscore ( _read_cr0 ). it can also have normal names like C-funktions ( read_cr0 ).

If it still doesn't work you should try to declare a asm-function that does nothing else than return back. It this also trashes your PC the problem isn't the way you call your function but the addressing of your function (the call instruction generated by gcc doesn't jump (call) to the right offset of your function).

I hope I could help you!
pskyboy

Re:ASM functions in c

Post by pskyboy »

These are my C declarations for the same code

extern "C" inline unsigned int read_cr0();
extern "C" inline void write_cr0(unsigned int);
extern "C" inline unsigned int read_cr3();
extern "C" inline void write_cr3(unsigned int);
extern "C" inline void jump(unsigned int);
pskyboy

Re:ASM functions in c

Post by pskyboy »

Got it working

LOL, my kernel had become bigger then 512bytes and i was onyl loading in 1 sector so it was cutting the ASM code linked on the end off.

Peter
.bdjames

Re:ASM functions in c

Post by .bdjames »

__inline__ static int cr0(){
int a;
asm(
"movl %%cr0, %0\n\t"
: "=a" (a)
);
return a;
}

int main(){
return cr0();
}


00000000 55 push ebp
00000001 89E5 mov ebp,esp
00000003 50 push eax
00000004 50 push eax
00000005 0F20C0 mov eax,cr0
00000008 83E4F0 and esp,byte -0x10
0000000B 89EC mov esp,ebp
0000000D 5D pop ebp
0000000E C3 ret
0000000F 90 nop

C:\DOCUME~1\ADMINI~1.BDJ\Desktop\NEWFOL~1>gcc -O2 -c test.c

C:\DOCUME~1\ADMINI~1.BDJ\Desktop\NEWFOL~1>ld --oformat=binary --entry=_main --Ttext=0x0 -o test.bin test.o

C:\DOCUME~1\ADMINI~1.BDJ\Desktop\NEWFOL~1>ndisasmw -b32 test.bin > test.txt
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:ASM functions in c

Post by Pype.Clicker »

pskyboy wrote: LOL, my kernel had become bigger then 512bytes and i was onyl loading in 1 sector so it was cutting the ASM code linked on the end off.
Hehe ... i knew this was an environment problem :-D
Post Reply