tcc:在汇编代码中使用 C 标准函数
tcc: Use C standard functions in assembly code
我有 NASM 创建的简单汇编文件。我想 link 他们 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 一起工作?
编辑:我正在使用 NASM 和 TCC 的 Windows 版本生成 32-位 Windows 个可执行文件。
TCC 似乎需要有关外部函数的特定类型信息 linkage,如 printf
。默认情况下 NASM 在 ELF object秒。这似乎混淆了 TCC,因为它似乎期望外部函数符号用 FUNCTION 类型标记。
我通过简单的 C 程序发现了这一点:
#include <stdio.h>
int main()
{
printf ("hello\n");
}
并将其编译为 object 文件(TCC 默认使用 ELF objects)像这样的命令:
tcc -c simple.c
这会生成 simple.o
。正好用OBJDUMP显示汇编代码和ELFheaders。我没有在代码中看到任何异常,但 headers 中的符号 table 显示出差异。如果您使用程序 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
:
的符号 table 条目
4: 00000000 0 FUNC GLOBAL DEFAULT UND printf
如果你要为你的 hello.o
object 转储 ELF headers 你会看起来像这样:
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
请注意 hello.o
中的符号 printf
与上面 simple.o
中的符号有何不同。 NASM 默认使用 NOTYPE 属性而不是 FUNCTION 定义标签。
使用 YASM 代替 NASM
我不知道有什么方法可以解决 NASM 中的问题,因为我不知道有什么方法可以强制它使用 FUNCTION 类型而不是 NOTYPE 定义为 extern
的符号。我在十六进制编辑器中更改了类型,它按预期 linked 和 运行。
另一种选择是 download YASM (a rewrite of NASM). For the most part NASM and YASM work the same. YASM's command line is mostly compatible with NASM so you should be able to use it as a direct replacement. YASM has an extra feature that allows you to specify the type of a symbol with the 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
它应该编译并 link 这样:
yasm -felf hello.asm -o hello.o
tcc hello.o -o hello.exe
我有 NASM 创建的简单汇编文件。我想 link 他们 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 一起工作?
编辑:我正在使用 NASM 和 TCC 的 Windows 版本生成 32-位 Windows 个可执行文件。
TCC 似乎需要有关外部函数的特定类型信息 linkage,如 printf
。默认情况下 NASM 在 ELF object秒。这似乎混淆了 TCC,因为它似乎期望外部函数符号用 FUNCTION 类型标记。
我通过简单的 C 程序发现了这一点:
#include <stdio.h>
int main()
{
printf ("hello\n");
}
并将其编译为 object 文件(TCC 默认使用 ELF objects)像这样的命令:
tcc -c simple.c
这会生成 simple.o
。正好用OBJDUMP显示汇编代码和ELFheaders。我没有在代码中看到任何异常,但 headers 中的符号 table 显示出差异。如果您使用程序 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
object 转储 ELF headers 你会看起来像这样:
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
请注意 hello.o
中的符号 printf
与上面 simple.o
中的符号有何不同。 NASM 默认使用 NOTYPE 属性而不是 FUNCTION 定义标签。
使用 YASM 代替 NASM
我不知道有什么方法可以解决 NASM 中的问题,因为我不知道有什么方法可以强制它使用 FUNCTION 类型而不是 NOTYPE 定义为 extern
的符号。我在十六进制编辑器中更改了类型,它按预期 linked 和 运行。
另一种选择是 download YASM (a rewrite of NASM). For the most part NASM and YASM work the same. YASM's command line is mostly compatible with NASM so you should be able to use it as a direct replacement. YASM has an extra feature that allows you to specify the type of a symbol with the 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
它应该编译并 link 这样:
yasm -felf hello.asm -o hello.o
tcc hello.o -o hello.exe