Gcc 在ld default链接器脚本中定义节并打印其值

Gcc 在ld default链接器脚本中定义节并打印其值,gcc,linker,ld,linker-scripts,Gcc,Linker,Ld,Linker Scripts,我想在链接器脚本中定义一个节,并在运行时从源代码中获取其值 到目前为止,我使用了默认的gcc链接器script文件,并添加了如下部分: ... .my_section : { BYTE(0xAA); } ... 编译后,我可以看到以下部分: > gcc -T ls.ld main.c -o main > objdump -h main ... ... 27 .my_section 00000001 0000000000a01040 0000000000a01040 00

我想在链接器脚本中定义一个节,并在运行时从源代码中获取其值

到目前为止,我使用了默认的
gcc链接器
script文件,并添加了如下部分:

...
.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
):

#包括
静态易失性无符号字符段uuu属性uuu((段(“.my_段”));
int main(){
printf(“你好%d\n”,节);
返回0;
}
我获得的值始终为0。我做错了什么?

我做错了什么

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

其中一个原因是:

static volatile unsigned char SECTION __attribute__((section(".my_section")));
main.c
中。在此
.my_部分
中,名为
部分
的符号静态定义为 处理默认情况下静态初始化为0的
char
。当你

printf("hello %d\n", SECTION)
当然,您是在0初始化符号处打印整数

另一个
.my_部分
是由以下原因引起的:

.my_section : { BYTE(0xAA); }
ls.ld中
。第二个
.my_部分
以字节=
0xAA开始,但从来都不是
由程序访问

这是一个例子。我有:

main.c

#include <stdio.h>

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

int main(){
    printf("hello %c\n", MY_SECTION);
    return 0;
}
章节中最后追加

编译、链接和运行:

$ 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_节和第27节也被称为
。本地符号
myu部分

$ 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)
...
...
或者您可以在链接器脚本中按照@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
以及:

程序中只有一个部分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

包含
foo
boo

的定义,但不确定您是否可以通过这种方式执行所需操作。您可以尝试
#包含外部无符号字符uu my_section_addr[];int main(){printf(“hello%x\n”,*(unsigned char*)(uuu my_section_addr));返回0;}
并在链接器脚本中:
。my_section:{uu my_section_addr=;BYTE(0xAA);}
.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 !
$ 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
$ 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