在共享库中混合 PIC 和非 PIC 对象

2023-11-21

这个问题与this one以及它的答案。

我刚刚发现我正在开发的构建中有一些丑陋之处。情况有点像下面这样(以 gmake 格式编写);请注意,这特别适用于 sparc 和 x86 硬件上的 32 位内存模型:

OBJ_SET1  := some objects
OBJ_SET2  := some objects

# note: OBJ_SET2 doesn't get this flag
${OBJ_SET1} : CCFLAGS += -PIC

${OBJ_SET1} ${OBJ_SET2} : %.o : %.cc
  ${CCC} ${CCFLAGS} -m32 -o ${@} -c ${<}

obj1.o       : ${OBJ_SET1}
obj2.o       : ${OBJ_SET2}
sharedlib.so : obj1.o obj2.o
obj1.o obj2.o sharedlib.so :
  ${LINK} ${LDFLAGS} -m32 -PIC -o ${@} ${^}

显然,它可以将使用和不使用 PIC 编译的对象混合在共享对象中(这已经使用多年)。我对 PIC 的了解不够,不知道这是否是一个好主意/聪明,我的猜测是在这种情况下它是不需要的,而是它正在发生,因为有人在处理时没有足够关心找到正确的方法来做到这一点关于构建的新内容。

我的问题是:

  1. 这样安全吗
  2. 这是不是一个好主意
  3. 结果可能会出现哪些潜在问题
  4. 如果我将所有内容都切换到 PIC,是否有任何我可能需要注意的不明显的问题。

忘了我什至写过这个问题。

首先按顺序进行一些解释:

  • 在[大多数?]现代操作系统中,非 PIC 代码可以由操作系统加载到内存中的任何位置。加载所有内容后,它会经历一个修复文本段(可执行文件结束的地方)的阶段,以便它正确地寻址全局变量;为了实现这一点,文本段必须是可写的。
  • PIC 可执行数据可由操作系统加载一次并在多个用户/进程之间共享。然而,要让操作系统执行此操作,文本段必须是只读的——这意味着不需要修复。代码被编译为使用全局偏移表 (GOT),因此它可以寻址相对于 GOT 的全局变量,从而减少修复的需要。
  • 如果在没有 PIC 的情况下构建共享对象,尽管强烈鼓励这样做,但似乎并不是绝对必要的;如果操作系统必须修复文本段,那么它被迫将其加载到标记为读写的内存中......这会阻止跨进程/用户共享。
  • 如果使用 PIC 构建可执行二进制文件,我不知道幕后出了什么问题,但我亲眼目睹了一些工具变得不稳定(神秘的崩溃等)。

答案:

  • Mixing PIC/non-PIC, or using PIC in executables can cause hard to predict and track down instabilities. I don't have a technical explanation for why.
    • ...包括段错误、总线错误、堆栈损坏,可能还有更多。
  • 共享对象中的非 PIC 可能不会导致任何严重问题,但如果跨进程和/或用户多次使用库,可能会导致使用更多 RAM。

更新(4/17)

我从此发现了原因some我以前见过的车祸。为了显示:

/*header.h*/
#include <map>
typedef std::map<std::string,std::string> StringMap;
StringMap asdf;

/*file1.cc*/
#include "header.h"

/*file2.cc*/
#include "header.h"

int main( int argc, char** argv ) {
  for( int ii = 0; ii < argc; ++ii ) {
    asdf[argv[ii]] = argv[ii];
  }

  return 0;
}

... 然后:

$ g++ file1.cc -shared -PIC -o libblah1.so
$ g++ file1.cc -shared -PIC -o libblah2.so
$ g++ file1.cc -shared -PIC -o libblah3.so
$ g++ file1.cc -shared -PIC -o libblah4.so
$ g++ file1.cc -shared -PIC -o libblah5.so

$ g++ -zmuldefs file2.cc -Wl,-{L,R}$(pwd) -lblah{1..5} -o fdsa
#     ^^^^^^^^^
#     This is the evil that made it possible
$ args=(this is the song that never ends);
$ eval ./fdsa $(for i in {1..100}; do echo -n ${args[*]}; done)

该特定示例可能不会最终崩溃,但这基本上是该组代码中存在的情况。如果它does崩溃很可能发生在析构函数中,通常是双重释放错误。

许多年前他们补充道-zmuldefs到他们的构建中以消除多重定义的符号错误。编译器发出用于在全局对象上运行构造函数/析构函数的代码。-zmuldefs强制它们位于内存中的同一位置,但它仍然为 exe 和包含有问题标头的每个库运行一次构造函数/析构函数 - 因此是双重释放。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在共享库中混合 PIC 和非 PIC 对象 的相关文章

随机推荐

  • 如何在Java中创建进程[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 我想在我的应用程序中创建一个流程 但在查看了 Java 的 API 后 我仍然不太明白 基本上我想创建一个多进程应用程序 但新流程是我的应用程序中的
  • C++:参数传递“通过引用传递”

    我理解与任何其他变量一样 参数的类型决定了参数与其参数之间的交互 我的问题是 为什么您会引用参数 而为什么不引用参数背后的原因是什么 为什么有些函数参数可以引用 有些则不能 无法理解这样做的好处 有人可以解释一下吗 通过引用传递的能力存在有
  • Windows 桌面应用程序的使用情况跟踪[关闭]

    Closed 这个问题是无关 目前不接受答案 我正在寻找一些可用于收集 Windows 桌面应用程序的使用信息并对其进行分析的框架 例如 我希望能够回答以下问题 a 人们一天内使用此应用程序多少次 b 他们最喜欢的菜单项等 我简单地浏览了
  • 如何在终端中更改我的 Git 用户名?

    我在终端中从 git 进行推送和拉取 然后在 github com 上更改了我的用户名 我去推送一些更改 但它无法推送 因为它仍然识别我的旧用户名 如何在终端中的 git 上更改 更新我的用户名 在您的终端中 导航到您想要进行更改的存储库
  • 跟踪 YouTube 观看历史记录

    为了自动跟踪我的时间 我想获取我的观看历史记录 最好的情况 每天一次 最坏的情况是每分钟一次 并将其添加为 Google 日历事件 虽然我成功添加了 Google 日历活动 但无法获取 YouTube 观看历史记录 所以我想知道 v3 AP
  • 捕获动态添加到 Jquery Datatables 表的输入字段上的更改事件

    我有一个 ajax 调用 它使用以下代码为响应中的每条记录添加一些行到数据表中 strAppName data Application Name maintCost
  • Eclipse:这些 JSP 错误是什么?

    我继承了一个 Web 应用程序 当在 Eclipse 中设置它时 它显示特定 JSP 中的错误 这些错误在 Problems 视图中没有与之相关的描述 单击它们会将我带到 JSP 的顶部 其中红色错误下划线出现在字符串的中间 如下所示 想象
  • jQuery动态改变元素高度

    我正在开发一个流体布局项目 我的文档中有一些固定高度的 DIV 并且它们的高度都不同 我需要在浏览器调整大小时按比例更改这些 DIV 高度 这是标记 div class target div div class target div div
  • 两个角度之间的最小差?

    我正在尝试计算两个角度之间的最小差异 这是我当前的代码 与我在网上找到的代码略有不同 float a1 MathHelper ToDegrees Rot float a2 MathHelper ToDegrees m fTargetRot
  • 为什么这里循环优于索引?

    几年前 有人posted on 活跃状态食谱出于比较目的 三个 python NumPy 函数 每个都接受相同的参数并返回相同的结果 a距离矩阵 其中两个摘自公开来源 它们都是 或者在我看来是 惯用的 numpy 代码 创建距离矩阵所需的重
  • 数组赋值的性能

    代码优化在 SO 中提到 分析是优化 javascript 的第一步 建议的引擎是 Chrome 和 Firefox 的分析器 这些的问题在于它们以某种奇怪的方式告诉每个函数执行的时间 但我对它们没有很好的理解 最有用的方法是探查器会告诉您
  • 如何让 fgcolor 属性在最新的 Android 版本上工作?

    我曾经能够做到这一点
  • 用PHP执行mysql“创建函数”语句

    我想运行以下命令mysql从 PHP 创建函数语句 DELIMITER CREATE FUNCTION myFunc instring varchar 4000 RETURNS int 11 NO SQL DETERMINISTIC SQL
  • 这里发生了什么?我将结果分配给 C++ 中的结果[重复]

    这个问题在这里已经有答案了 你能告诉我这是怎么回事吗 为什么这是可能的 std make unique
  • 错误 SIPEPS,版本=5.0.0.0 UCMA 4.0 VS2010/VS2013

    我在 VS 2013 和 VS 2010 上开发了 UCMA 4 0 应用程序 运行项目时 出现以下错误 无法加载文件或程序集 SIPEPS Version 5 0 0 0 Culture neutral PublicKeyToken 31
  • 将小部件放置在 QScrollArea 的中心

    如何将固定大小的自定义小部件放置在 QScrollArea 的中心 我可以使用 myWidget pos x y 手动将小部件放置在 QScrollArea 内 但 QScrollArea 中没有 sizeChanged 信号 因此如果滚动
  • 使用 WebKit.NET 从 JavaScript 调用 C# 函数

    我一直在 c win forms 项目中使用 webkit net 并且喜欢使用以下命令从 C 程序中调用 JavaScript 函数是多么容易 browser Document InvokeScriptMethod functionNam
  • 如何通过删除不必要的字段来扩展评论框架(django)?

    我一直在阅读有关评论框架以及如何自定义它的 django 文档 http docs djangoproject com en 1 1 ref contrib comments custom 在该页面中 它显示了如何add表单中的新字段 但我
  • 使用 Python Spark Redshift

    我正在尝试将 Spark 与 amazon Redshift 连接 但收到此错误 我的代码如下 from pyspark sql import SQLContext from pyspark import SparkContext sc S
  • 在共享库中混合 PIC 和非 PIC 对象

    这个问题与this one以及它的答案 我刚刚发现我正在开发的构建中有一些丑陋之处 情况有点像下面这样 以 gmake 格式编写 请注意 这特别适用于 sparc 和 x86 硬件上的 32 位内存模型 OBJ SET1 some obje