【问题标题】:Define a section in the ld default linker script and print its value在 ld 默认链接描述文件中定义一个节并打印它的值
【发布时间】:2023-04-04 02:14:02
【问题描述】:

我想在链接描述文件中定义一个部分,并在运行时从源代码中获取它的值。

到目前为止,我采用了默认的gcc linker 脚本文件,并添加了如下部分:

...
.my_section : { BYTE(0xAA); }
...

编译后可以看到部分:

> gcc -T ls.ld main.c -o main
> objdump -h main
...
...
 27 .my_section   00000001  0000000000a01040  0000000000a01040  00001040  2**0
                  CONTENTS, ALLOC, LOAD, DATA
 28 .comment      00000034  0000000000000000  0000000000000000  00001041  2**0
                  CONTENTS, READONLY

现在,我想将该值打印到stdout(我希望获得0xAA):

#include <stdio.h>

static volatile unsigned char SECTION __attribute__((section(".my_section")));

int main(){
    printf("hello %d\n", SECTION);
    return 0;
}

我得到的值总是0。我做错了什么?

【问题讨论】:

  • 不确定您是否可以那样做。您可以尝试#include &lt;stdio.h&gt; extern unsigned char __my_section_addr[]; int main(){ printf("hello %x\n", *(unsigned char *)(__my_section_addr)); return 0; } 并在链接器脚本中:.my_section : { __my_section_addr = .; BYTE(0xAA); }

标签: gcc linker ld linker-scripts


【解决方案1】:

我做错了什么?

您正在强制链接器在程序 两个 部分中输出,每个部分都调用 .my_section.

其中一个原因是:

static volatile unsigned char SECTION __attribute__((section(".my_section")));

main.c。在这个.my_section 中,一个名为SECTION 的符号被静态定义为 解决默认情况下静态初始化 = 0 的 char。当您

printf("hello %d\n", SECTION)

您当然是在那个初始化为 0 的符号处打印整数。

另一个.my_section是由以下原因引起的:

.my_section : { BYTE(0xAA); }

ls.ld。这第二个 .my_section 以字节 = 0xAA 开头,但从不 由程序访问。

这是一个插图。我有:

ma​​in.c

#include <stdio.h>

static volatile unsigned char MY_SECTION __attribute__((section(".my_section"))) = '!';

int main(){
    printf("hello %c\n", MY_SECTION);
    return 0;
}

我有一个链接器脚本ls.ld,这是我的gcc 默认链接器脚本:

.my_section : { BYTE(0xAA); }

最后附加在SECTIONS

编译、链接并运行:

$ gcc -Wall -Wextra -T ls.ld -o prog main.c
$ ./prog
hello !

prog的板块详情:

$ readelf -t prog
There are 31 section headers, starting at offset 0x3990:

Section Headers:
  [Nr] Name
       Type              Address          Offset            Link
       Size              EntSize          Info              Align
       Flags
  ...
  [24] .my_section
       PROGBITS               PROGBITS         0000000000004010  0000000000003010  0
       0000000000000001 0000000000000000  0                 1
       [0000000000000003]: WRITE, ALLOC
  [25] .bss
       NOBITS                 NOBITS           0000000000004011  0000000000003011  0
       0000000000000007 0000000000000000  0                 1
       [0000000000000003]: WRITE, ALLOC
  [26] .comment
       PROGBITS               PROGBITS         0000000000000000  0000000000003019  0
       0000000000000023 0000000000000001  0                 1
       [0000000000000030]: MERGE, STRINGS
  [27] .my_section
       PROGBITS               PROGBITS         0000000000006018  0000000000003018  0
       0000000000000001 0000000000000000  0                 1
       [0000000000000003]: WRITE, ALLOC
  ...

第 24 节称为 .my_section,第 27 节也是如此。本地符号 MY_SECTION

$ readelf -s prog | grep 'MY_SECTION'
37: 0000000000004010     1 OBJECT  LOCAL  DEFAULT   24 MY_SECTION

24 部分定义。

然后看反汇编:

$ objdump --disassemble-all prog
prog:     file format elf64-x86-64
...
...
Disassembly of section .my_section:

0000000000004010 <__TMC_END__>:
    4010:   21                      .byte 0x21
...
...
Disassembly of section .my_section:

0000000000006018 <.my_section>:
    6018:   aa                      stos   %al,%es:(%rdi)
...
...

第一个,以0x21 = ! 开头,是在main.c 中创建的 并由程序访问。第二个,以0xaa 开头,是 由链接描述文件创建且未被程序访问的。

选择一种输出.my_section 的方式或另一种方式:-

您可以在源代码中使用:

static volatile unsigned char MY_SECTION __attribute__((section(".my_section"))) = 0xAA;

或者您可以按照@MichaelPetch 的评论在链接器脚本中执行此操作,例如:

.my_section : { my_section_addr = .; BYTE(0xAA); }

并在以下程序中访问该部分:

$ cat main1.c
#include <stdio.h>

extern unsigned char my_section_addr[];

int main(){
    printf("section `.my_section` starts at %p and the 1st byte is %x\n",
            my_section_addr, (unsigned int)my_section_addr[0]);
    return 0;
}
$ gcc -Wall -Wextra -T ls.ld -o prog main1.c
$ ./prog
section `.my_section` starts at 0x560a32964018 and the 1st byte is aa

但实际上并不需要自定义链接描述文件以获得 程序中自定义部分的地址。见:

$ cat main2.c
#include <stdio.h>

static unsigned char pling __attribute__((section("my_section"))) = '!';
extern unsigned char __start_my_section;
extern unsigned char __stop_my_section;
static char * p_my_section_start = &__start_my_section;
static char * p_my_section_end = &__stop_my_section;

int main(){
    printf("section `my_section` starts at %p, ends at %p, and the 1st byte is %c\n",
            p_my_section_start, p_my_section_end, p_my_section_start[0]);
    return 0;
}

$ gcc -o prog main2.c
$ ./prog
section `my_section` starts at 0x55db7b0fb020, ends at 0x55db7b0fb021, and the 1st byte is !

看到extern 形式为__start_&lt;section_name__stop_&lt;section_name&gt; 的声明, 链接器会自动将这些符号分别放在 部分&lt;section_name&gt;

如果你想编译和链接多个源文件都访问相同的自定义 section my_section 在程序中,您可以简单地定义归属于 section 的符号 my_section 在几个源文件和链接器中,使用默认的链接器脚本, 将输入对象文件中名为my_section 的所有部分合并为一个 在程序中输出my_section。 (就像它合并一样,例如所有 .text 部分 输入目标文件到单个.text 程序部分)。见:

$ cat foo.c
#include <stdio.h>

unsigned int foo __attribute__((section("my_section"))) = 0xf00;

$ cat boo.c
#include <stdio.h>

unsigned int boo __attribute__((section("my_section"))) = 0xb00;

$ cat main3.c
#include <stdio.h>

extern unsigned int foo;
extern unsigned int boo;

int main(){
    printf("foo=%x, boo=%x\n",foo,boo);
    return 0;
}

$ gcc -Wall -o prog main3.c foo.c boo.c
$ ./prog
foo=f00, boo=b00

和:

$ readelf -t prog | grep my_section
  [24] my_section

程序中只有一个部分,24,称为my_section,它:

$ readelf -s prog | egrep '(foo|boo)'
    36: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS foo.c
    37: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS boo.c
    59: 0000000000004010     4 OBJECT  GLOBAL DEFAULT   24 foo
    66: 0000000000004014     4 OBJECT  GLOBAL DEFAULT   24 boo

包含fooboo 的定义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-09
    • 1970-01-01
    • 1970-01-01
    • 2017-10-28
    • 2013-05-17
    • 1970-01-01
    • 2012-04-19
    相关资源
    最近更新 更多