出现“重定位符号索引无效”错误时会发生什么?

2024-05-25

这是重现问题的测试:

$ echo "void whatever() {}" > prog.c
$ gcc prog.c

这会在 GCC 4.8.4 上产生以下错误:

    /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 11
    /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 1 has invalid symbol index 12
    /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 2 has invalid symbol index 2
    /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 3 has invalid symbol index 2
    ... etc ...
    /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 18 has invalid symbol index 13
    /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 19 has invalid symbol index 21
    /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_line): relocation 0 has invalid symbol index 2
    /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
    (.text+0x20): undefined reference to `main'
    collect2: error: ld returned 1 exit status

请注意,在 GCC 6.2.0 上,与此问题相关的错误消失了,它只生成:

/usr/lib/x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status

许多用户已在 Stack Overflow 和其他地方多次报告过这一情况。

我想理解这个错误,不解决它(它已经解决了)。

执行此操作时会发生此错误gcc-4.8 prog.c没有main()内部功能prog.c.


我在 binutils-source 包上对这个错误进行了文本搜索。乏味的谷歌搜索只给了我一个有用的链接帮助我更好地理解搬迁处理的概念 https://www.mirbsd.org/htman/i386/manINFO/bfdint.html#BFD-relocation-handling.

错误的数量似乎并不取决于程序,这表明所考虑的重定位并非源于此文件,而是缺失的直接结果main()功能。我假设其中 3 个带有错误索引的重定位可能是为了main(), argc and argv,但许多仍然存在,这只是一个未经证实的假设。

这超出了我的理解范围,任何可以帮助我更好地理解它的信息,或者 GCC 后续版本中发生的变化,都将受到热烈欢迎。


C 程序特性(类 Unix)

  • 每个程序都单独编译成elf格式
  • c程序可以使用外部变量/函数引用,稍后链接
  • main不是像你最初想象的那样是程序的开始,c lib 有一个启动程序(crt1.o)其中有一个_start程序将调用我们的main并做好清洁工作main
  • 总结以上陈述,我们可以知道,即使是像OP所示的非常简单的程序也需要链接

ELF格式

ELF 有两个 header,如下所示:

  • 节头——用于链接多个elf以制作过程映像
  • 程序头——用于加载过程映像

这里我们只关注节头结构:

    mapping<var_name, offset, size...>
    // and special cases
    mapping<external_var_name, offset, size...>

每个程序都是单独编译的,这意味着地址分配是相似的(在早期版本的linux中,每个编译的程序都以相同的虚拟地址开始 -0x08000000,很多攻击都可以利用这一点,所以改为添加一些随机增量来解决以缓解问题),因此可能存在一些覆盖区域。这就是需要地址迁移的原因。

搬迁

重定位信息(偏移量、值等)存储在.rel.*部分:

    Relocation section '.rel.text' at offset 0x7a4 contains 2 entries:
     Offset     Info    Type            Sym.Value  Sym. Name
    0000000d  00000e02 R_386_PC32        00000000   main
    00000015  00000f02 R_386_PC32        00000000   exit

    Relocation section '.rel.debug_info' at offset 0x7b4 contains 43 entries:
     Offset     Info    Type            Sym.Value  Sym. Name
    00000006  00000601 R_386_32          00000000   .debug_abbrev
    0000000c  00000901 R_386_32          00000000   .debug_str

当链接器想要设置地址时main在重定位过程中,它在编译的 elf 文件中找不到符号,因此它会抱怨并停止链接过程。

Example

Here https://github.com/zzt93/os-lab1/是操作系统实现的简化版本,start.c https://github.com/zzt93/os-lab1/blob/master/user_program/start.c对应于crt1.o的源代码:

    int entry(char *); // corresponds to main

    void _start(char *args) {
        entry(args);
        exit();
    }

Ref

  • ELF https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#Program_header
  • 搬迁 https://en.wikipedia.org/wiki/Relocation_(computing)#Unix-like_systems
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

出现“重定位符号索引无效”错误时会发生什么? 的相关文章

  • 通过 CMIS (dotCMIS) 连接到 SP2010:异常未经授权

    我正在使用 dotCMIS 并且想要简单连接到我的 SP2010 服务器 我尝试用 C 来做到这一点 如下所示http chemistry apache org dotnet getting started with dotcmis htm
  • 为什么 C# Array.BinarySearch 这么快?

    我已经实施了一个很简单用于在整数数组中查找整数的 C 中的 binarySearch 实现 二分查找 static int binarySearch int arr int i int low 0 high arr Length 1 mid
  • WCF RIA 服务 - 加载多个实体

    我正在寻找一种模式来解决以下问题 我认为这很常见 我正在使用 WCF RIA 服务在初始加载时将多个实体返回给客户端 我希望两个实体异步加载 以免锁定 UI 并且我想利用 RIA 服务来执行此操作 我的解决方案如下 似乎有效 这种方法会遇到
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 这些作业之间是否存在顺序点?

    以下代码中的两个赋值之间是否存在序列点 f f x 1 1 x 2 不 没有 在这种情况下 标准确实是含糊不清的 如果你想确认这一点 gcc 有这个非常酷的选项 Wsequence point在这种情况下 它会警告您该操作可能未定义
  • 使用 x509 证书签署 json 文档或字符串

    如何使用 x509 证书签署 json 文档或字符串 public static void fund string filePath C Users VIKAS Desktop Data xml Read the file XmlDocum
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • GCC 如何运行其他程序?

    也许标题并没有那么准确地表达问题 我知道当我跑步时gcc foo cGCC 调用其他为其完成所有工作的子程序 使 gcc 主程序只是一个接口 但这到底是如何完成的呢 是否使用system or exec或者其他一些功能 我之所以想知道这个是
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

    我正在使用 NUNIT 在 Visual Studio 中使用 Selenium WebDriver 测试用例的代码是 我想在执行测试用例后立即在变量中记录测试用例通过或失败的情况 我怎样才能实现这一点 NUnit 假设您使用 NUnit
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new
  • 如何防止用户控件表单在 C# 中处理键盘输入(箭头键)

    我的用户控件包含其他可以选择的控件 我想实现使用箭头键导航子控件的方法 问题是家长控制拦截箭头键并使用它来滚动其视图什么是我想避免的事情 我想自己解决控制内容的导航问题 我如何控制由箭头键引起的标准行为 提前致谢 MTH 这通常是通过重写
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐