首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >tcc:在汇编代码中使用C标准函数

tcc:在汇编代码中使用C标准函数
EN

Stack Overflow用户
提问于 2017-08-28 13:34:09
回答 1查看 899关注 0票数 2

我有由NASM创建的简单汇编文件。我想把他们和tcc联系起来。为了进行调试,我希望在程序集代码中使用printf()。但是当我这样做的时候,tcctcc: undefined symbol 'printf'上失败了。

下面是再现错误的最小示例代码:

代码语言:javascript
复制
extern printf
hello: db "Hello world!",0

global main
main:
    push hello
    call printf
    pop eax
ret

控制台:

代码语言:javascript
复制
nasm -felf hello.asm
tcc hello.o

tcc:未定义符号“printf”

当我使用gcc hello.o时,一切都很好,所以它必须是一个特定于tcc的问题。我如何让它与tcc一起工作?

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-08-28 17:25:17

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

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

代码语言:javascript
复制
#include <stdio.h>
int main()
{
    printf ("hello\n");
}

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

代码语言:javascript
复制
tcc -c simple.c 

这会生成simple.o。我碰巧使用OBJDUMP来显示程序集代码和ELF头。我在代码中没有看到什么不寻常的地方,但是头中的符号表显示了不同的地方。如果使用READELF程序,您可以获得符号的详细转储。

代码语言:javascript
复制
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头,那么您可能看起来类似于以下内容:

代码语言:javascript
复制
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

注意,printfhello.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对象

您只需为使用的每个外部函数向程序集代码中添加额外的类型信息行。可以将程序集代码修改为如下所示:

代码语言:javascript
复制
extern printf
type printf function

hello: db "Hello world!",0

global main
main:
    push hello
    call printf
    pop eax
ret 

它应该编译并链接到以下内容:

代码语言:javascript
复制
yasm -felf hello.asm -o hello.o
tcc hello.o -o hello.exe
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45920355

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档