如何设置全新节的对齐方式

问题描述 投票:0回答:1

在我的 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 的情况下我无法定义内存区域

c ld memory-alignment sections linker-scripts
1个回答
0
投票

关于强制 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
© www.soinside.com 2019 - 2024. All rights reserved.