【发布时间】:2023-01-03 02:45:02
【问题描述】:
如果您在 C 中为全局变量定义自定义部分,并在链接描述文件中定义自定义输出部分,链接器(?)如何确定该部分的属性(W = 可写,A = 可分配,...) ?
发行和 MWE
我目前面临的问题是,我将同一部分分配给两个全局变量,其中一个是常量(在其用法中,而不是程序代码),而另一个则不是。最后,它们都进入了一个只能分配但不可写的部分,并且程序以分段错误终止。
示例程序(test.c):
static double some_thing[5] __attribute__ ((section ("my_nonconst_section"))) = {2.0, 4.0, 6.0, 8.0, 10.0};
static double another_thing[5] __attribute__ ((section ("my_nonconst_section")));
int main(int argc, char const *argv[]) {
another_thing[1] = some_thing[argc];
return another_thing[argc] == 0.0;
}
我的自定义链接描述文件扩展(linkerscript.ld,请注意,自定义地址对我来说至关重要,这就是我首先使用这些部分的原因):
SECTIONS {
. = 0x0000001b000002e0;
my_nonconst_section : {KEEP(*(my_nonconst_section))}
/* . = 0xAddressForThisSection;
my_const_section : {KEEP(*(my_const_section))}
... */
}
INSERT AFTER .gnu.attributes;
我使用 clang(测试10.0.0-4ubuntu1 和自建 12)用我的链接器脚本编译/链接它(clang 也不是可选的,见下文):
clang -mcmodel=large -O1 test.c -Wl,-Tlinkerscript.ld -o test.tmp
然后执行它:
./test.tmp
但是,我注意到 clang -O0(它没有推导出 some_thing 是常量)和 gcc(9.4.0,具有任何优化级别)没有表现出这种行为。
我使用的链接器是GNU ld (GNU Binutils for Ubuntu) 2.34,但是我可以看到与gold链接器相同的效果。我的目标是x86_64。
我能否以某种方式影响自定义链接器部分具有的属性(最好在链接描述文件中定义)?我最好有一些未写在可写部分中的变量。
背景/背景:
我正在编写一个 (LLVM/clang) 编译器传递,它使用自定义链接器部分注释全局变量。我在自定义链接描述文件(通过这些部分扩展默认链接描述文件)中为这些全局变量定义了链接器输出部分,类似于上述内容。
该过程通过查看全局变量属性来区分常量和非常量全局变量。如果它是常量,则选择常量的节标签,否则选择包含可写数据的节标签。然而,后添加部分注释后,另一个编译器通道能够显示其中一个变量——用(意识形态上的)非常量部分注释——确实只被读取,因此通道将其标记为常量。
结果是包含标记为const 的全局变量的部分变为只读,但它仍然包含非常量全局变量。在程序执行期间,尝试在此部分写入另一个全局变量会导致分段错误(如预期)。
我确定这两个变量都是只读的nm:
0000001b00000310 r another_thing
0000001b000002e0 r some_thing
该部分如下所示(由readelf -S 确定):
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[..] my_nonconst_section PROGBITS 0000001b000002e0 0032e0 000058 00 A 0 0 16
通常,我希望非常量数据部分使用Flg = WA,而常量部分使用Flg = A。
笔记
目前,我不必手写一个完整的链接描述文件,并且编译器通道兼容处理已经有部分注释的 C 源代码,保留这个属性会很好。
我看到可以使用 MEMORY 指令完全定义内存布局,但据我所知,这需要为所有部分定义内存,我不想这样做。
目前,由于我正在使用“绑定”来确定这些部分的地址,我不能(据我所知)将绑定与命名内存结合使用,即属性特征> (RW) 以确保该部分是可写的一。
【问题讨论】:
-
我从来不记得这些链接描述文件的确切语法,但 iirc 之类的
MEMORY { cant_touch_this (r) : ... }...SECTIONS { my_nonconst_section : ... } > cant_touch_this可能有用。 -
我认为
my_nonconst_section (aw) : {KEEP(*(my_nonconst_section))}设置了可分配和可写的属性,但不确定是否能解决这里的问题 -
@Lundin 你知道是否有办法扩展已经存在的
MEMORY定义(例如,用于放置.text等部分)而不必手动重新定义所有这些定义?我宁愿自己不完全定义MEMORY,因为这似乎比我需要的更具侵入性(一些全局变量分配给一些自定义部分)。我想从长远来看,它也会更加脆弱。目前,我只添加了几个部分,并且使用MEMORY,我必须定义整个链接描述文件(如果我正确理解它的用法)。 -
关于节定义中的属性(@nos):据我了解,这些属性不能直接与节相关联(语法不允许)。据我了解,这是因为,例如,可写是输出部分分配给的内存的一个属性,而不是部分本身。如果我尝试建议的解决方案,我会收到错误消息:
/usr/bin/ld:linkerscript.ld:3: non constant or forward reference address expression for section my_nonconst_section