【问题标题】:Compiling C program with assembly function and vice versa用汇编函数编译 C 程序,反之亦然
【发布时间】:2014-04-03 20:48:05
【问题描述】:

我的程序有问题。当我尝试使用此行编译带有汇编函数的 C 程序时:

gcc -o program factarial.c

我明白了,但我不知道为什么:

/tmp/ccFKqbDP.o: In function `main':
factarial.c:(.text+0x11): undefined reference to `factarial_asm'
collect2: ld returned 1 exit status

这是我的 C 代码:

#include <stdio.h>

extern void factarial_asm();

int main ()
{
 factarial_asm (5);
 return 0;
}

这是汇编代码:

.data
.text
.global _main
.type factarial_asm, @function

factarial_asm:
    pushl %ebp
    movl %esp, %ebp
    movl 8(%ebp), %eax
    cmpl $1, %eax
je koniec
    decl %eax
    pushl %eax
call factarial_asm
    movl 8(%ebp), %ebx
    mull %ebx
koniec:
leave
ret

另外,当我尝试使用此行使用 C 函数编译 asm 代码时:

gcc -o program factarial.s

我遇到了这个问题:

/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
/tmp/ccWCmTBe.o: In function `main':
(.text+0x3): undefined reference to `factarial'
collect2: ld returned 1 exit status

这是我的汇编代码:

SYSEXIT = 1
EXIT_SUCC = 0
SYSWRITE = 4
SYSCALL = 0x80
SYSREAD = 3

.align 32
.text
.global _main
main:

pushl $5
call factarial

movl $SYSEXIT, %eax
movl $EXIT_SUCC, %ebx
int $SYSCALL

还有我的 C 代码:

#include <stdio.h>

int factarial(int n)
{
    if(n == 0) return 1;
    else       return n * factarial(n - 1);
}

我知道有很多问题,但到目前为止我正在准备编译器和 ld 链接器,所以我不完全知道如何使用 gcc。 另外,谁能帮我准备makefile文件?

【问题讨论】:

    标签: c linux assembly x86


    【解决方案1】:

    问题是您的每个编译行都试图在没有完整程序的情况下创建可执行文件。如果您的源文件名称相同但扩展名不同,事情就会变得有些复杂。

    一个简单的选项是,这个命令:gcc -o program factarial.c factarial.s

    或者,您可能会考虑编译但不链接您的各个源文件,然后将它们的对象链接在一起以构建您的可执行文件。假设您的源文件被命名为 a.cb.s,您将:

    gcc -c a.c
    gcc -c b.s
    gcc -o program a.o b.o
    

    最后(当然与您的问题无关),我相信您正在寻找的词是factorial :)


    您的程序集仍然存在问题。首先,我重新创建了您的结果,如下所示:

    $ gcc -c factarial.c
    $ gcc -c factarial_asm.s
    $ gcc -o program factarial.o factarial_asm.o
    factarial.o: In function `main':
    factarial.c:(.text+0xf): undefined reference to `factarial_asm'
    collect2: error: ld returned 1 exit status
    

    接下来,我使用nm 命令检查目标文件:

    $ nm factarial.o
                     U factarial_asm
    0000000000000000 T main
    $ nm factarial_asm.o
                     U _main
    0000000000000000 t factarial_asm
    000000000000001a t koniec
    

    在程序集对象的nm 输出中有一些有趣的东西。首先,U _main 告诉我们 main() 在该对象中是未定义的,这意味着当我们链接程序时预计会找到它。这个文件没有调用main(),所以我们真的不应该关心它。这是由.global _main 引起的,可以安全删除。

    接下来,factarial_asm 的符号是小写的 t,而不是来自主要 C 源代码的 main() 中的 T... 显示为 t 表示该符号是该符号的本地符号仅源文件,不会导出给其他人。 (在 C 中,这是 void function() {}static void function() {} 之间的区别)。我们需要通过添加正确的.global 指令来解决这个问题。

    总结:在您的程序集中,将.global _main 更改为.global factarial_asm

    【讨论】:

    • 我刚刚注意到你的 main() 是一个汇编函数。尝试将其从 main: 重命名为 _main:。您可能还需要将call factarial 更改为call _factarial
    • 还是不行。我认为编译程序的顺序可能有问题,因为它没有看到 main,但我不知道如何修复它。
    • 我能够通过一些更改来编译它。首先, _ 对我来说不是必需的(它可能适合你,这取决于编译器)。其次,您必须在程序集文件的顶部添加.global factarial_asm!第三(对我来说,你可能不需要这个)我不得不将 pushl 指令更改为 64 位指令。这让我开始构建,但它在运行时崩溃了;如果您还击中它,您将需要弄清楚崩溃(或为它发布一个新问题,但如果您使用的是 32 位系统,它可能对您有用)。我会尽快编辑我的答案以提供更多帮助。
    • 非常感谢!现在,一切正常!谢谢!! :)
    猜你喜欢
    • 2016-04-27
    • 2012-09-23
    • 1970-01-01
    • 1970-01-01
    • 2012-06-17
    • 2011-03-12
    • 2012-11-19
    • 2010-10-22
    • 2023-03-19
    相关资源
    最近更新 更多