Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
194 views
in Technique[技术] by (71.8m points)

Calling C functions from x86 assembly language

Is it possible to generate assembly language functions from C functions using GCC, so that they can be invoked from an assembly language program? I know that gcc compiles C to machine code (which can easily be disassembled into assembly language), and I already know that it's possible to inline assembly language functions in C, but I haven't yet found a way to invoke C functions from assembly language programs, which is basically the inverse of this.

Here, I'm attempting to inline a C function in an x86 assembly program. If inlining isn't possible, then is there some other way to invoke a C function from an assembly language program?

.686p
.model flat,stdcall
.stack 2048

.data

.code
start:

invoke  ExitProcess, 0

printSomething PROC ;now I'm attempting to inline a C function here
    void printSomething(thingToPrint){
        printf("This is a C function that I want to invoke from an assembly language program.");
        printf("There must be some way to do this - is it possible somehow?");
    }
printSomething ENDP

end start
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I'm going from memory here, so I may be off slightly on a detail or two. However, it should I hope be enough to get you going in the right direction.

You're going to need to tell the GCC assembler that your routine printSomething() is not defined in your assembly file. In 'C' you would use the extern keyword. For assembly you will need to use .globl.

.globl printSomething

If you are using a different assembler than GCC's, the keyword may be different.

The next big question is 'how do I pass the arguments'? This very much depends upon your processor AND OS. Since the title of your question indicates x86, I am going to assume that you are using either the 16-bit or 32-bit modes and the standard x86 ABI (as opposed to x86-64 which is also differs between Windows and Linux). The C parameters are passed to the called routine by pushing them onto the stack. They are pushed onto the stack from right to left.

Thus,

printSomething (arg1, arg2, arg3, arg4);

translates to ...

pushl arg4
pushl arg3
pushl arg2
pushl arg1
call  printSomething
addl  $0x10, %esp

You may be asking yourself, what is this

addl $0x10, %esp

? We passed (aka pushed) four 32-bit arguments to the routine (onto the stack). Although the routine knows to expect those arguments, it is NOT responsible for popping them off the stack. The caller is responsible for that. So, after we return from the routine, we adjust the stack pointer to discard the four 32-bit arguments we previously pushed onto the stack.

In the above example, I am assuming that we are operating in 32-bit mode. If it were 16-bit mode, it would be ...

pushw arg4
pushw arg3
pushw arg2
pushw arg1
call  printSomething
addw  $0x8, %sp

I realize that in your example, printSomething() only takes one (1) argument and in my example I used four (4). Just adjust my example as is needed.

For the final steps, you will need to compile both your C and assembly files into object files, link the object files and then execute.

I hope this helps.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...