在我的 Linux 上的软件项目中,我需要创建一个特殊的部分,需要填充 40 字节的大结构。然后我想把这个部分当作一个数组。
为此,我添加了带有
-T
选项的链接器脚本:
SECTIONS
{
/* section for CLI cmd array */
.CLI_cmd_section : ALIGN(8)
{
PROVIDE(__CLI_cmd_start = .);
KEEP(*(.CLI_cmd*));
. = ALIGN(8) ;
PROVIDE(__CLI_cmd_end = .);
}
}
INSERT AFTER .data;
不过,用
objdump
检查,我发现该部分已对齐到 32 字节:
Sections:
Idx Name Size VMA LMA File off Algn Flags
[...]
25 .data 00000008 0000000000009000 0000000000009000 00008000 2**3 CONTENTS, ALLOC, LOAD, DATA
26 .CLI_cmd_section 00000068 0000000000009020 0000000000009020 00008020 2**5 CONTENTS, ALLOC, LOAD, DATA
27 .bss 00000078 00000000000090a0 00000000000090a0 00008088 2**5 ALLOC
[...]
我想这可能是因为某些相邻部分有这样的对齐方式,但即使移动它也不会改变
Sections:
Idx Name Size VMA LMA File off Algn Flags
[...]
23 .dynamic 000001f0 0000000000008cf0 0000000000008cf0 00007cf0 2**3 CONTENTS, ALLOC, LOAD, DATA
24 .CLI_cmd_section 00000068 0000000000008ee0 0000000000008ee0 00007ee0 2**5 CONTENTS, ALLOC, LOAD, DATA
25 .got 000000a8 0000000000008f48 0000000000008f48 00007f48 2**3 CONTENTS, ALLOC, LOAD, DATA
26 .data 00000008 0000000000009000 0000000000009000 00008000 2**3 CONTENTS, ALLOC, LOAD, DATA
[...]
我想尝试看看发生了什么施加更高的对齐(64),在这种情况下它设置了它。所以看来由于某种原因,我现在在该部分无法低于 32。
这非常烦人,因为在数组中,编译器认为条目偏移了 40 字节,而链接器则将它们偏移了 64 字节。
我应该如何让我的数组索引良好,然后强制对齐 8?
另外,我希望本节是只读的,但如果我尝试强加它,我会在链接上收到一条警告,我不知道它有多“严重”:
/usr/bin/ld: /tmp/ccDmg9Dd.o: warning: relocation in read-only section `.CLI_cmd.__CLI_cmd_help'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
是否有一种安全、可靠且“干净”的方法来强加 READONLY
.CLI_cmd_section
,而不会出现来自链接器的错误/警告?
编辑
我的地图文件显示:
Memory Configuration
Name Origin Length Attributes
*default* 0x0000000000000000 0xffffffffffffffff
所以默认情况下似乎没有定义内存区域。
因此,@giackkk,我认为在不知道 ORIGIN 和 LENGTH 的情况下我无法定义内存区域
关于强制 READONLY
.CLI_cmd_section
的“干净”方式,而不会出现问题的链接器部分的错误/警告,您可以通过更改节标题标志来获取它,在这种情况下,您需要确保在节标志中.CLI_cmd_section
w
标志不存在
来自 binutils 文档:
w: section is writable
以下是如何操作的示例:
section.s
.section .CLI_cmd_section, "a"
.global cli_cmd_data
cli_cmd_data:
.ascii "Hello from assembly section\n"
在这段代码中,我添加了一个新部分,其中仅包含
a
标志(可分配)。
使用
readelf
您可以检查节标题标志:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 00000000004002a8 000002a8
000000000000001b 0000000000000000 A 0 0 1
[ 2] .note.gnu.bu[...] NOTE 00000000004002c4 000002c4
0000000000000024 0000000000000000 A 0 0 4
[ 3] .note.ABI-tag NOTE 00000000004002e8 000002e8
0000000000000020 0000000000000000 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000400308 00000308
000000000000001c 0000000000000000 A 5 0 8
[ 5] .dynsym DYNSYM 0000000000400328 00000328
00000000000000a8 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 00000000004003d0 000003d0
0000000000000085 0000000000000000 A 0 0 1
[ 7] .gnu.version VERSYM 0000000000400456 00000456
000000000000000e 0000000000000002 A 5 0 2
[ 8] .gnu.version_r VERNEED 0000000000400468 00000468
0000000000000030 0000000000000000 A 6 1 8
[ 9] .rela.dyn RELA 0000000000400498 00000498
0000000000000048 0000000000000018 A 5 0 8
[10] .rela.plt RELA 00000000004004e0 000004e0
0000000000000060 0000000000000018 AI 5 23 8
[11] .init PROGBITS 0000000000410000 00010000
000000000000001c 0000000000000000 AX 0 0 4
[12] .plt PROGBITS 0000000000410020 00010020
0000000000000060 0000000000000000 AX 0 0 16
[13] .text PROGBITS 0000000000410080 00010080
000000000000017c 0000000000000000 AX 0 0 64
[14] .fini PROGBITS 00000000004101fc 000101fc
0000000000000018 0000000000000000 AX 0 0 4
[15] .rodata PROGBITS 0000000000420000 00020000
000000000000003d 0000000000000000 A 0 0 8
[16] .CLI_cmd_section PROGBITS 000000000042003d 0002003d
000000000000001c 0000000000000000 A 0 0 1
您可以看到唯一的标志是 a 并且与
.rodata
部分相同。
如果您想进一步检查,这里有一个简单的 main 来检查此部分是否是只读的:
#include <stdio.h>
#include <string.h>
extern const char cli_cmd_data[];
int main() {
printf("%s", cli_cmd_data);
// Attempt to write to the read-only section
char *ptr = (char *)cli_cmd_data;
strcpy(ptr, "Trying to write to read-only section");
return 0;
}
./main_program
Hello from assembly section
Segmentation fault (core dumped)
所以如果我将 w 部分也添加到汇编代码中,这样:
.section .CLI_cmd_section, "wa"
.global cli_cmd_data
cli_cmd_data:
.ascii "Hello from assembly section\n"
我可以检查:
readelf -a main_program
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 00000000004002a8 000002a8
000000000000001b 0000000000000000 A 0 0 1
[ 2] .note.gnu.bu[...] NOTE 00000000004002c4 000002c4
0000000000000024 0000000000000000 A 0 0 4
[ 3] .note.ABI-tag NOTE 00000000004002e8 000002e8
0000000000000020 0000000000000000 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000400308 00000308
000000000000001c 0000000000000000 A 5 0 8
[ 5] .dynsym DYNSYM 0000000000400328 00000328
00000000000000a8 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 00000000004003d0 000003d0
0000000000000085 0000000000000000 A 0 0 1
[ 7] .gnu.version VERSYM 0000000000400456 00000456
000000000000000e 0000000000000002 A 5 0 2
[ 8] .gnu.version_r VERNEED 0000000000400468 00000468
0000000000000030 0000000000000000 A 6 1 8
[ 9] .rela.dyn RELA 0000000000400498 00000498
0000000000000048 0000000000000018 A 5 0 8
[10] .rela.plt RELA 00000000004004e0 000004e0
0000000000000060 0000000000000018 AI 5 22 8
[11] .init PROGBITS 0000000000410000 00010000
000000000000001c 0000000000000000 AX 0 0 4
[12] .plt PROGBITS 0000000000410020 00010020
0000000000000060 0000000000000000 AX 0 0 16
[13] .text PROGBITS 0000000000410080 00010080
000000000000017c 0000000000000000 AX 0 0 64
[14] .fini PROGBITS 00000000004101fc 000101fc
0000000000000018 0000000000000000 AX 0 0 4
[15] .rodata PROGBITS 0000000000420000 00020000
000000000000003d 0000000000000000 A 0 0 8
[16] .eh_frame_hdr PROGBITS 0000000000420040 00020040
0000000000000044 0000000000000000 A 0 0 4
[17] .eh_frame PROGBITS 0000000000420088 00020088
00000000000000dc 0000000000000000 A 0 0 8
[18] .init_array INIT_ARRAY 000000000043fde8 0002fde8
0000000000000008 0000000000000008 WA 0 0 8
[19] .fini_array FINI_ARRAY 000000000043fdf0 0002fdf0
0000000000000008 0000000000000008 WA 0 0 8
[20] .dynamic DYNAMIC 000000000043fdf8 0002fdf8
00000000000001d0 0000000000000010 WA 6 0 8
[21] .got PROGBITS 000000000043ffc8 0002ffc8
0000000000000020 0000000000000008 WA 0 0 8
[22] .got.plt PROGBITS 000000000043ffe8 0002ffe8
0000000000000038 0000000000000008 WA 0 0 8
[23] .data PROGBITS 0000000000440020 00030020
0000000000000004 0000000000000000 WA 0 0 1
[24] .CLI_cmd_section PROGBITS 0000000000440024 00030024
000000000000001c 0000000000000000 WA 0 0 1
在这里你可以看到我实际上添加了 w 标志,因此该部分不应该再是只读的。
现在运行它,我们得到了。
./main_program
Hello from assembly section
请注意,当我复制
的结果时,我已经剪切了一些节标题readelf -a