我有由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.otcc:未定义符号“printf”
当我使用gcc hello.o时,一切都很好,所以它必须是一个特定于tcc的问题。我如何让它与tcc一起工作?
编辑:我使用Windows版本的NASM和TCC来生成32位的Windows可执行文件.
发布于 2017-08-28 17:25:17
看来,TCC需要关于外部链接(如printf )的函数的特定类型信息。默认情况下,NASM在ELF对象中创建对带有NOTYPE属性的符号的引用。这似乎混淆了TCC,因为它似乎期望外部函数符号被标记为函数类型。
我通过简单的C程序发现了这一点:
#include <stdio.h>
int main()
{
printf ("hello\n");
}并使用如下命令将其编译为对象文件(默认情况下,TCC使用ELF对象):
tcc -c simple.c 这会生成simple.o。我碰巧使用OBJDUMP来显示程序集代码和ELF头。我在代码中没有看到什么不寻常的地方,但是头中的符号表显示了不同的地方。如果使用READELF程序,您可以获得符号的详细转储。
readelf -s simple.o符号表'.symtab‘包含5个条目: Num:值大小类型绑定对Ndx名称0: 00000000 0 NOTYPE本地默认UND 1: 00000000 0文件本地默认ABSsimple.c2: 00000000 7对象本地默认值2 L.0 3: 00000000 26 FUNC全局缺省值1主4: 00000000 0 FUNC全局默认UND
特别感兴趣的是printf的符号表条目。
4: 00000000 0 FUNC GLOBAL DEFAULT UND printf
如果您要为您的hello.o对象转储ELF头,那么您可能看起来类似于以下内容:
readelf -s hello.o符号表'.symtab‘包含6个条目: Num:值大小类型绑定对Ndx名称0: 00000000 0 NOTYPE本地默认UND 1: 00000000 0文件本地默认hello.asm 2: 00000000 0节本地默认值1 3: 00000000 0 NOTYPE本地默认值1 hello 4: 00000000 0 NOTYPE全局默认UND printf 5: 0000000d0 NOTYPE全局默认1
注意,printf在hello.o中的符号与上面simple.o中的符号有什么不同。NASM默认使用NOTYPE属性而不是函数来定义标签。
用YASM代替NASM
我不知道如何解决NASM中的问题,因为我不知道如何强制它使用函数类型,而不是在定义为extern的符号上使用NOTYPE。我在十六进制编辑器中更改了类型,并按预期的方式链接和运行。
一个替代方案是download (重写NASM)。在大多数情况下,NASM和YASM的工作原理是一样的。YASM的命令行主要与NASM兼容,因此您应该能够使用它作为直接的替代。YASM有一个额外的特性,允许您使用 directive指定符号的类型。
9.3.3.类型: Set符号类型ELF的符号表具有指示符号是函数还是数据的功能。虽然可以在全局指令中直接指定这一点(参见9.4节),但TYPE指令允许为任何符号(包括本地符号)指定符号类型。指令接受两个参数;第一个参数是符号名,第二个参数是符号类型。符号类型必须是函数或对象。无法识别的类型将导致生成警告。使用示例: func: ret类型func函数节.data var dd 4类型var对象
您只需为使用的每个外部函数向程序集代码中添加额外的类型信息行。可以将程序集代码修改为如下所示:
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.exehttps://stackoverflow.com/questions/45920355
复制相似问题