Assembly GCC生成的程序集-在C函数调用时出现Segfault

Assembly GCC生成的程序集-在C函数调用时出现Segfault,assembly,gnu-assembler,Assembly,Gnu Assembler,我最近一直在用windows中的GCC练习x86汇编。目前我混合使用汇编和C代码进行测试。我遇到了一些奇怪的事情,用我目前的知识无法解释,因此我求助于so 让我们看一个简单的例子。我们在C代码中有一个test_func()函数,我们想把它转换成汇编,然后从C代码中调用它。不过,这个函数正在从项目中调用其他函数,这就是问题所在。从程序集中调用其他C代码函数都会导致分段错误 我们希望在汇编中看到的函数: #include "rf_string.h" void test_func() {//nonse

我最近一直在用windows中的GCC练习x86汇编。目前我混合使用汇编和C代码进行测试。我遇到了一些奇怪的事情,用我目前的知识无法解释,因此我求助于so

让我们看一个简单的例子。我们在C代码中有一个test_func()函数,我们想把它转换成汇编,然后从C代码中调用它。不过,这个函数正在从项目中调用其他函数,这就是问题所在。从程序集中调用其他C代码函数都会导致分段错误

我们希望在汇编中看到的函数:

#include "rf_string.h"
void test_func()
{//nonsense function, just calling another C function of the project
    RF_String s;
    rfString_Init(&s,"anything");
}
要求gcc为此提供汇编代码给我们:

    .file   "to_asm.c"
    .section .rdata,"dr"
    .align 4
LC0:
    .ascii "anything\0"
    .text
    .globl  _test_func
    .def    _test_func; .scl    2;  .type   32; .endef
_test_func:
LFB6:
    .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    $LC0, 4(%esp)
    leal    -16(%ebp), %eax
    movl    %eax, (%esp)
    movl    _rfString_Init, %eax
    call    *%eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE6:
然后将其保存到一个名为“asm_test.S”的文件中,并将其包含到项目的构建过程中,它将构建并链接良好。所以我们试着编写一个简单的程序来调用这个函数

int main()
{
    test_func();
    return 0;
}
调试时会出现问题。从汇编代码内部调用另一个C函数时,我得到了一个分段错误。这将发生在我试图从汇编代码调用的任何其他函数中,它与我使用的函数无关

我认为这与这里的函数调用有关:

 movl    %eax, (%esp)
 movl    _rfString_Init, %eax
 call    *%eax
它为什么这样做?这意味着什么?具体来说,为什么不直接调用函数呢?还有,在%eax寄存器之前的*是什么?我还需要补充的是,如果我用一个简单的函数调用来替换最后两行,就像下面这样,一切似乎都工作得很好,这让我很困惑

 call     _rfString_Init
另一个小问题是关于所有这些cfi_指令。如果我要根据SO中提出的问题的答案来判断,它们似乎是出于异常处理目的而生成的。问题是,就代码的功能而言,我可以安全地忽略它们吗?

这里:

 movl    _rfString_Init, %eax
 call    *%eax
请注意,在
\rfString\u Init
之前没有
$
(与
movl$LC0中不同,4(%esp)
)。这意味着
\u rfString\u Init
不是立即常数(例如,函数或对象的常量地址或只是常量),而是内存变量

因此,
movl
加载名为
\rfString\u Init
的变量的内容

然后,
call
eax
中包含的地址执行调用。星号是一些语法上的糖,表示通过引用/指针间接传递控件

因此,
rfString\u Init
实际上是指向函数的指针。在您的C代码中查找它

当然,如果您试图将控制权转移到指针中包含的字节,则不会有什么好结果,因为它是数据,不希望被解释为代码。此外,底层内存可能被配置为不可执行


我对这些指令了解不多。它们也可以用于调试。无论如何,它们不会在您看到它们的地方插入代码。

请记下我之前的评论。是我的电话。函数不是函数指针,但我的问题忽略了一些细节。函数是库的一部分。已导出到dll中。测试用例没有生成dll,但在声明中错误地忘记了dllimport。这导致它在函数符号名称之前添加了一个_imp。我注意到了它,并将其删除,以为它会正常工作。看来这种调用函数的方法就是通过dll来实现的。我会接受你的回答,因为你对func指针的提示让我找到了答案。我很喜欢在这里问问题时我是如何学到新东西的。不总是通过直接的方式:)DLL或不是,如果机器代码做了一个间接调用,它使用一个指针。我在测试时的初衷是不进行间接调用,但由于忘记了declspec(import),这就是发生的情况。现在多亏了你们,我知道了函数指针调用是如何发生的,以及如何在汇编中识别它。谢谢你,伙计。