【问题标题】:Why doesn't the GCC assembly output generate a .GLOBAL for printf为什么 GCC 程序集输出不为 printf 生成 .GLOBAL
【发布时间】:2018-05-13 18:56:03
【问题描述】:

我有一个简单的 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 指令的全部意义,因此所有标签都是单个程序集文件的本地标签,除非使用 .global 导出以从其他目标文件访问,或者也使用 .global 从另一个目标文件导入。

我在这里错过了什么?

【问题讨论】:

  • 链接器在 C 运行时自动链接。由于这个原因,我认为不需要全局指令。
  • .global 会将当前文件中的标签标记为具有全局范围(可用于其他模块)。也许你的意思是.extern。尽管.extern 可以用来表示标签是外部的,但该指令实际上被忽略了。 GNU 汇编器假定它在当前文件中不知道的任何标签都被自动假定为外部标签(由链接器决定它是否未定义)。这就是为什么您看不到任何将 printf 标记为外部的指令的原因——这没有必要。
  • 所以你说你需要使用 .global 从模块导出但不需要使用 .global 导入?猜猜这解释了为什么它仍然使用 .global 作为 main。
  • 是的,就是这样。

标签: gcc assembly gnu-assembler riscv


【解决方案1】:

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

.extern 在源程序中被接受——为了与其他汇编程序兼容——但它被忽略as 将所有未定义的符号视为外部符号。

as = GNU 汇编器。

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

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


.global .d​​irective 不导入标签,因为它本质上是导出的。它仅将当前文件中的标签标记为对其他模块全局可用。它不用于从其他模块导入标签。来自手册:

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

为了与其他汇编程序兼容,接受两种拼写(“.globl”和“.global”)。


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

【讨论】:

  • 相关:其他汇编程序,如 NASM,需要extern printf
  • @PeterCordes。是的,但 GNU 汇编器没有。这就是这个问题的意义所在,因为它特别是关于为什么 GCC 没有发出它。
  • 对,但我认为值得一提的是,还有其他设计不同的汇编器,所以 OP 的期望并不疯狂。以及为什么我说“相关”,而不是“更正”:P
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-03
  • 2023-01-02
  • 1970-01-01
  • 2022-06-29
  • 2013-04-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多