tcc:在汇编代码

时间:2017-08-28 13:34:10

标签: c assembly x86 nasm tcc

我有 NASM 创建的简单汇编文件。我想将它们与tcc相关联。为了进行调试,我想在汇编代码中使用printf()。但是当我这样做时,tcc会因tcc: undefined symbol 'printf'而失败。

以下是重现错误的最小示例代码:

extern printf
hello: db "Hello world!",0

global main
main:
    push hello
    call printf
    pop eax
ret

控制台:

nasm -felf hello.asm
tcc hello.o
tcc: undefined symbol 'printf'

当我使用gcc hello.o时,一切正常,所以它必须是特定于tcc的问题。如何使用tcc?

编辑:我使用的是Windows版本的 NASM TCC 来生成32位Windows可执行文件。

1 个答案:

答案 0 :(得分:5)

TCC 似乎需要有关printf等外部链接的函数的特定类型信息。默认情况下, NASM 会在 ELF 对象中创建对具有 NOTYPE 属性的符号的引用。这似乎会混淆 TCC ,因为它似乎期望外部函数符号用 FUNCTION 类型标记。

我通过简单的 C 程序发现了这一点:

#include <stdio.h>
int main()
{
    printf ("hello\n");
}

并将其编译为目标文件( TCC 默认使用 ELF 对象),其命令如下:

tcc -c simple.c 

这会生成simple.o。我碰巧使用 OBJDUMP 来显示汇编代码和 ELF 标题。我没有在代码中看到任何异常,但标题中的符号表显示出差异。如果您使用程序 READELF ,您可以获得符号的详细转储。

readelf -s simple.o
Symbol table '.symtab' contains 5 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS simple.c
     2: 00000000     7 OBJECT  LOCAL  DEFAULT    2 L.0
     3: 00000000    26 FUNC    GLOBAL DEFAULT    1 main
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf

特别感兴趣的是printf的符号表条目:

    4: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf

如果要转储hello.o对象的 ELF 标题,您似乎与此类似:

readelf -s hello.o
Symbol table '.symtab' contains 6 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS hello.asm
     2: 00000000     0 SECTION LOCAL  DEFAULT    1
     3: 00000000     0 NOTYPE  LOCAL  DEFAULT    1 hello
     4: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND printf
     5: 0000000d     0 NOTYPE  GLOBAL DEFAULT    1 main

请注意printf中的符号hello.o与上面simple.o中的符号有何不同。 NASM 默认使用 NOTYPE 属性而不是 FUNCTION 定义标签。

使用YASM代替NASM

我不知道如何解决 NASM 中的问题,因为我不知道如何强制它使用 FUNCTION 在定义为extern的符号上键入而不是 NOTYPE 。我在十六进制编辑器中更改了类型,并将其链接并按预期运行。

另一种选择是download YASM(重写 NASM )。对于大多数部分, NASM YASM 的工作方式相同。 YASM 的命令行主要与 NASM 兼容,因此您应该可以将其用作直接替代品。 YASM 有一项额外功能,可让您使用type directive指定符号类型:

9.3.3. TYPE: Set symbol type

ELF’s symbol table has the capability of indicating whether a symbol is a
function or data. While this can be specified directly in the GLOBAL
directive (see Section 9.4), the TYPE directive allows specifying the
symbol type for any symbol, including local symbols.

The directive takes two parameters; the first parameter is the symbol
name, and the second is the symbol type. The symbol type must be either
function or object. An unrecognized type will cause a warning to be
generated. Example of use:

func:
        ret
type func function
section .data
var dd 4
type var object

您只需为您使用的每个外部函数在汇编代码中添加额外的类型信息。您的汇编代码可以修改为:

extern printf
type printf function

hello: db "Hello world!",0

global main
main:
    push hello
    call printf
    pop eax
ret 

它应该编译并与此链接:

yasm -felf hello.asm -o hello.o
tcc hello.o -o hello.exe