【问题标题】:How do I compile assembly routines for use with a C program (GNU assembler)?如何编译汇编例程以用于 C 程序(GNU 汇编器)?
【发布时间】:2010-10-22 23:27:23
【问题描述】:

我有一组汇编函数,我想通过创建一个头文件在 C 程序中使用它。例如,如果我有定义实际汇编例程的 asm_functions.s 和具有函数原型的 asm_functions.h 以及我需要的一些标准#define。我的目标是使用 C 程序,比如 test_asm.c 来调用汇编函数。

asm__functions.h:


 #define ASM_CONST_1    0x80
 #define ASM_CONST_2    0xaf

uint8_t asm_foo( int, int, int );

asm__functions.s:


 /* dont need this: #include "asm_functions.h" */

.section .text .type asm_foo, @function asm__foo: /* asm code with proper stack manipulation for C calling conventions */ ret

test__asm.c:


 #include "asm_foo.h"

int main() { uint8_t res = asm_foo( 1, 2, 3); return 0; }

在这种情况下,编译链接程序的正确方法是什么?我正在尝试这样的事情:


gas -o asm_foo.o asm_foo.s
gcc -o test_asm test_asm.c

但我仍然收到来自 GCC 的链接器错误,说我的汇编例程未定义。我希望这个人为的例子足以解释这种情况。

谢谢!

编辑:

这是我使用单个命令编译时的输出 sn-p:


tja@tja-desktop:~/RIT/SP2/latest$ gcc -o test_pci pci_config.s test_pci.c
/tmp/ccY0SmMN.o: In function _pci_bios_read_byte':
(.text+0x8): undefined reference toPCI_FUNCTION_ID'
/tmp/ccY0SmMN.o: In function _pci_bios_read_byte':
(.text+0xa): undefined reference toREAD_CONFIG_BYTE'
/tmp/ccY0SmMN.o: In function _pci_bios_read_byte':
(.text+0x18): undefined reference toPCI_BIOS_FUNCTION_INT'
/tmp/ccY0SmMN.o: In function _pci_bios_read_byte':
(.text+0x1b): undefined reference toBAD_REGISTER_NUMBER'
/tmp/ccY0SmMN.o: In function _pci_bios_read_word':
(.text+0x30): undefined reference toPCI_FUNCTION_ID'
...

所有这些,例如 PCI_FUNCTION_ID,都在我的头文件中定义,该头文件包含在 C 程序中。当我自己编译汇编代码时没有错误。

【问题讨论】:

    标签: assembly linker x86 compilation


    【解决方案1】:

    根据您问题中的文件,我设法对其进行了编译。我已经更改了文件名和文件内容。

    asm_const.h:

    #define ASM_CONST_1    0x80
    #define ASM_CONST_2    0xaf
    

    asm_functions.h:

    #include "asm_const.h"
    unsigned char asm_foo( int, int, int );
    

    asm_functions.S(尾随的 S 必须大写!#include 需要它):

    #include "asm_const.h"
    .section .text
    .globl asm_foo
    .type asm_foo, @function
    asm_foo:
      mov $ASM_CONST_1, %eax
      /* asm code with proper stack manipulation for C calling conventions */
      ret
    

    test_asm.c:

    #include "asm_functions.h"
    int main() {
      return asm_foo( 1, 2, 3);
    }
    

    请注意,您需要带有大写 S 的程序集文件扩展名 .S。使用 .s,.s 文件不会通过预处理器运行,因此 #include 不起作用,您也不会能够在 .s 文件中使用 ASM_CONST_1。

    使用单个命令编译:

    gcc -o test_asm asm_functions.S test_asm.c
    

    或者,作为替代方案,使用多个命令进行编译,创建 .o 文件:

    gcc -c asm_functions.S
    gcc -c test_asm.c
    gcc -o test_asm asm_functions.o test_asm.o
    

    单命令 gcc 负责使用 gas 编译 .S 文件,使用 GCC 的 C 编译器编译 .c 文件,并使用 ld 将生成的临时 .o 文件链接在一起。 gcc 默认使用适当的标志运行所有这些命令。

    在某些系统上(但不是在默认安装 GCC 的 Linux 上),您必须在 .S 文件(但不是 .c 或 .h 文件)中的导出函数名称前加上下划线。因此,asm_foo 的所有实例都将仅在 .S 文件中变为 _asm_foo

    【讨论】:

    • 我的预处理器似乎仍然存在问题。在我的头文件中,我有一堆#defines。当我尝试使用单个命令从源代码编译所有内容时,我会在头文件中为 #defines 获得一堆未定义的引用。
    • 但我认为这就是重点?我创建了 .h 文件,就好像它要与 C 代码链接一样。但是我只是在汇编中实现了这些功能......我从汇编文件中取出了#include,但我显然在C程序中仍然需要它。所以最后我希望 C 程序包含具有汇编函数原型/常量的头文件。谢谢!
    • 嗯,添加 .globl 后,我仍然遇到错误。我应该直接发布我的代码,但我倾向于简洁......
    • 我刚刚更新、扩展并修复了我的答案。请再看看。
    • 我正在调查一个不同的问题,但遇到了这篇文章。您可能希望将 .note.GNU-stack 部分添加到汇编例程中,以禁止在 Linux 上设置可执行堆栈标志。您可以阅读this 了解更多信息。
    【解决方案2】:

    你考虑过using inline assembly吗?这比使用汇编文件要容易得多。

    编辑:此外,您收到链接器错误的原因可能是因为 C 编译器在实际符号的标识符上添加了前导下划线。尝试在您的程序集文件中添加下划线。

    【讨论】:

    • 是的,我考虑过,但我正在编写设备级代码,我想创建定向的汇编例程。我认为最终它会比大量的 asm() 调用更干净。
    • 呵呵,在我实际的汇编文件和头文件中,它们确实是用下划线定义的:uint8_t _pci_bios_read_word(int, int int);
    • 不,你不应该在头文件中用下划线定义它(这会给你双下划线)。您只需要汇编文件中的下划线。
    猜你喜欢
    • 2011-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多