假设我正在try 从以下位置创建可执行二进制文件:

// main.c

#include <stdio.h>

int main() {
    printf("Hello, world!");
    return 0;
}

我只需运行gcc main.c,就可以得到可执行的二进制a.out,它会打印出‘Hello,world!’,这是我想要的.

有人告诉我,gcc在这里做了两件事:

  1. main.c个编译成目标代码,
  2. 已将该代码与标准库联系起来,这样printf就可以工作了.

如何手动逐个手动完成这两个步骤?

我通过运行gcc -c main.c开始将main.c编译为目标代码,创建目标文件main.o.现在,我想要执行链接步骤.似乎我也可以用gcc来做这件事,只需运行gcc main.o,产生可执行的二进制a.out.

我读到这个gcc的第二次调用实际上是在幕后运行链接器ld.我如何使用ld而不是第二次调用gcc来实现这一点呢?如果我运行ld main.o,我得到一个警告和一个错误:

ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
ld: main.o: in function `main':
main.c:(.text+0x10): undefined reference to `printf'

该错误似乎表明我需要告诉它链接到C标准库,这样我才能使用printf.我可以用-lc号旗帜ld main.o -lc号.这会产生a.out个结果,但我仍然收到警告:

ld: warning: cannot find entry symbol _start; defaulting to 00000000004002e0

当我运行a.out时,它会永远在屏幕上打印Hello, world!:

Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello,

What's the correct way to invoke 100 here to eliminate the warning and get the correct executable?

推荐答案

在这里调用ld以消除警告并获得正确的可执行文件的正确方式是什么?

only链接用户空间C二进制文件的正确方法是使用适当的编译器前端:gcc main.o.

直接使用ldnever是正确的.

你可以通过调用gcc -v main.o看到gcc实际上做了什么.但是请注意,结果ld(或collect2命令):

  • 可能会有所不同,具体取决于gcc的配置方式
  • 不同的操作系统版本可能会有所不同
  • 可能会有所不同,具体取决于使用的是哪个libc

TL;DR:欢迎您了解gcc如何在您的系统上调用ld,但是您不应该将结果放入任何Makefile或构建脚本中.

C++相关问答推荐

C中的ATONE会扰乱SEN/CLUTE GMS应用程序中的其他字符串

为什么信号量为空= 0,而不是阻塞?

如何设置指针指向在函数中初始化的复合文字中的整数?

如果我释放其他内容,返回值就会出错

如何知道我是否从非阻塞套接字读取所有内容

为什么sscanf不能正确地从这个字符串格式中提取所有数字?

为静态库做准备中的奇怪行为

如何将常量char*复制到char数组

C在声明带有值的数组时,声明大小有用吗?

如何使用指向 struct 数组的指针并访问数组中特定索引处的 struct

为什么此共享库没有预期的依赖项?

如何在C中使数组变量的值为常量?

从C文件中删除注释

如何使用FSeek和文件流指针在C中查找文件的前一个元素和前一个减go 一个元素

为什么编译器不能简单地将数据从EDI转移到EAX?

对于STM32微控制器,全局偏移表.get和.Got.plt必须为零初始化

无算术运算符和循环的二进制乘法

C: NULL>;NULL总是false?

关于不同C编译器中的__attribute__支持

cs50拼写器分配中的无限循环