【问题标题】:Step by step C compilation result in segfault逐步C编译导致段错误
【发布时间】:2020-03-03 08:27:55
【问题描述】:

我正在尝试理解 C 编译

鉴于 main.c 中的这个简单 C 代码:

int main() {
    int a;
    a = 42;
    return 0;
}

我执行了以下操作:

cpp main.c main.i
/usr/lib/gcc/x86_64-linux-gnu/9/cc1 main.i -o main.s
as -o main.o main.s
ld -o main.exe main.o

执行 main.exe 时,出现分段错误。

如何在本例中获得良好的内存寻址?

【问题讨论】:

  • 使用你的 olatrm gcc
  • 如果将main() 函数重命名为start() 会发生什么?
  • @Jabberwocky 替换 C 启动代码并非易事。使用函数_start(),链接器警告消失了,但程序从_start()返回后出现段错误。
  • @Bodo 我怀疑会发生什么
  • @johnnnn - 分段错误main() 返回时发生,因为堆栈上没有返回地址。通常,main() 是从 C 运行时代码调用的。您可以了解gcc -v -o main.exe main.o 在链接步骤中所做的工作。

标签: c linux compilation ld


【解决方案1】:

当我在 x86_64 Ubuntu 19.10 系统上尝试您问题中的命令序列时,我收到来自 ld 的警告:

ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000

这表明有问题。

错误意味着链接器没有找到符号_start,而是使用了默认地址。当运行你的程序时,它会尝试在这个地址执行代码,这显然是无效的。

从 C 代码编译的可执行程序不仅仅包含您的代码。编译器指示链接器添加 C 运行时库和启动代码。启动代码负责初始化和调用main 函数。

运行例如

gcc -v -o main.exe main.o

查看哪些其他文件被添加到您的程序中。在我的系统上,这显示了一些名称以 crt 开头的文件,这意味着“C 运行时”。

如果您不使用gcc 链接您的程序,而是直接使用ld,则您必须手动添加所有必要的目标文件,方法与编译器自动执行的方式类似。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多