29

是否可以使用 GCC 从 C 函数生成汇编语言函数,以便可以从汇编语言程序中调用它们?我知道 gcc 将 C 编译为机器代码(可以很容易地反汇编成汇编语言),并且我已经知道可以在 C 中内联汇编语言函数,但是我还没有找到从汇编中调用 C 函数的方法语言程序,基本上与此相反。

在这里,我试图在 x86 汇编程序中内联 C 函数。如果内联是不可能的,那么还有其他方法可以从汇编语言程序中调用 C 函数吗?

.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
4

2 回答 2

35

我是从记忆中来的,所以我可能会稍微偏离一两个细节。但是,我希望这足以让您朝着正确的方向前进。

你需要告诉 GCC 汇编器你的例程printSomething()没有在你的汇编文件中定义。在“C”中,您将使用extern关键字。对于组装,您需要使用.globl

.globl printSomething

如果您使用的汇编程序与 GCC 不同,则关键字可能不同。

下一个大问题是“我如何传递论点”?这在很大程度上取决于您的处理器和操作系统。由于您的问题标题指示 x86,我将假设您使用的是 16 位或 32 位模式和标准 x86 ABI(与 Windows 和 Linux 之间也不同的 x86-64 不同)。C 参数通过将它们压入堆栈来传递给被调用的例程。它们从右到左被推入堆栈。

因此,

printSomething (arg1, arg2, arg3, arg4);

翻译为...

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

你可能会问自己,这是什么

addl $0x10, %esp

? 我们将四个 32 位参数传递(也称为推送)到例程(到堆栈上)。尽管例程知道期望这些参数,但它不负责将它们从堆栈中弹出。调用者对此负责。因此,从例程返回后,我们调整堆栈指针以丢弃我们之前压入堆栈的四个 32 位参数。

在上面的示例中,我假设我们在 32 位模式下运行。如果是 16 位模式,那将是......

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

我意识到在您的示例中,printSomething()仅采用一 (1) 个参数,而在我的示例中,我使用了四 (4) 个参数。只需根据需要调整我的示例。

对于最后的步骤,您需要将 C 和汇编文件都编译为目标文件,链接目标文件然后执行。

我希望这有帮助。

于 2013-04-28T13:43:21.923 回答
2

对于 x86_64,请注意您必须小心一些额外的事情:

于 2019-05-27T15:17:15.760 回答