为什么GCC程序集输出不会为printf

时间:2017-11-29 23:10:44

标签: gcc assembly gas riscv

我有一个简单的C程序示例: -

#include <stdio.h>
int main()
{
    printf("hello world!");
    return 1;
}

我使用以下命令编译它并生成程序集: -

riscv32-unknown-elf-gcc -S hello.c -o hello.asm

生成以下程序集: -

    .file   "hello.c"
    .option nopic
    .section    .rodata
    .align  2
.LC0:
    .string "hello world!"
    .text
    .align  2
    .globl  main
    .type   main, @function
main:
    addi    sp,sp,-16
    sw  ra,12(sp)
    sw  s0,8(sp)
    addi    s0,sp,16
    lui a5,%hi(.LC0)
    addi    a0,a5,%lo(.LC0)
    call    printf
    li  a5,1
    mv  a0,a5
    lw  ra,12(sp)
    lw  s0,8(sp)
    addi    sp,sp,16
    jr  ra
    .size   main, .-main
    .ident  "GCC: (GNU) 7.2.0"

有一个预期的call printf行但是因为在这个程序集文件中没有printf的实现,我本来希望看到它请求外部实现这样的东西......

.global printf

但是装配中没有这样的线。我认为如果没有全局指令,它意味着链接器只会尝试将其解析为此单个程序集文件中的标签。我认为这是全局指令的重点,所以所有标签都是单个汇编文件的本地标签,除非使用.global导出以从其他目标文件访问或通过使用.global从另一个目标文件导入。

我在这里缺少什么?

1 个答案:

答案 0 :(得分:6)

.global会将当前文件中的标签标记为具有全局范围(可供其他模块使用)。也许你的意思是.extern。尽管可以使用.extern来表示标签是外部的,但GNU汇编程序实际上忽略了该指令。来自manual

  源程序中接受

.extern - 为了与其他汇编程序兼容 - 但忽略as 将所有未定义的符号视为外部符号。

as = GNU汇编程序。

GNU汇编程序假定它在当前文件中不知道的任何标签都是外部引用。由链接器决定是否未定义。这就是为什么你没有看到任何将printf标记为外部的指令。在GNU汇编程序中,它是没有必要的。

注意:部分混淆可能在于像NASM / YASM这样的汇编程序需要显式extern语句来表示符号不在正在汇编的本地模块中。那些汇编器将返回错误,表示符号未定义。这是GNU Assembler和NASM / YASM之间的一个区别。

.global .directive不会导入标签,因为它实质上是导出。它仅将当前文件中的标签标记为全局可供其他模块使用。它不用于从其他模块导入标签。从手册:

  

.global 使符号对ld 可见。如果在部分程序中定义符号,则其值可用于与其链接的其他部分程序。否则,符号从链接到同一程序的另一个文件中获取同名符号的属性。

     

两种拼写('.globl'和'.global')都被接受,以便与其他汇编程序兼容。

有一个.global main指令将main标记为全局。如果没有它,链接器将假定main本质上是一个特定于模块的静态标签,不能被其他模块使用。 C 运行时库需要访问main,因为必须调用main作为将控制权转移到 C 代码条目的最后一步。