是否可以从链接器脚本访问 C 变量
Is it possible to access a C variable from a linker script
例如,我需要获取加载到内存中的进程的大小,然后我在我的代码中定义它:
#include <stdio.h>
ssize_t prog_sz;
int main()
{
printf("%x\n", prog_sz);
}
然后我有一个链接描述文件使用这样的行访问它 proc_sz = .
注意:我用我的程序测试的所有链接描述文件总是会产生错误,这就是为什么我只指定了脚本中的一行。例如像这样简单的东西没有我第一次谈到的那行:
SECTIONS
{
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
产生如下烦人的错误:
/usr/bin/ld: a.out: error: PHDR segment not covered by LOAD segment
/usr/bin/ld: /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS): in function `__libc_csu_init':
(.text+0x9): undefined reference to `__init_array_start'
/usr/bin/ld: (.text+0x20): undefined reference to `__init_array_end'
/usr/bin/ld: a.out: hidden symbol `__init_array_end' isn't defined
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
即使是 ld 信息文档中的一个示例也会产生那个恼人的错误。也许你也可以帮我解决这个问题。
您似乎有两个不同的问题。
第一期涉及symbol/variableprog_sz
。您展示的方法只会导致链接器尝试创建另一个名为 prog_sz
的符号,这不太可能实现目标。
在不详细说明正在做什么的情况下,我将介绍三个目标及其解决方案:
- 设置变量
prog_sz
以包含链接器文件中定义的符号的地址。
在命令文件中用不同的名称定义符号,例如 prog_sz__
。然后,您可以直接在代码中 prog_sz
的声明上方添加以下行:
extern char prog_sz;
类型 char
在这里并不重要。该语句仅用于告诉编译器该符号将在其他地方定义。在此之后,您可以通过将定义修改为:
来将符号的地址分配给 prog_sz
size_t prog_sz = (size_t)(&prog_sz__);
使用 &
告诉程序将与符号 prog_sz__
关联的地址存储在变量 prog_sz
中。这会将链接描述文件中定义的符号分配给变量 prog_sz
.
- 使用链接描述文件将变量定位在固定位置,有一种方法可以做到这一点。
假设您使用的是 GNU 工具链,在构建时使用 GCC 选项 -fdata-sections
。这会将每个变量放入其自己的数据部分。请注意,您的 .bss
和 .data
部分将替换为前缀为 .data
或 .bss
的每个变量的部分,您可能需要使用通配符 *
捕获 .bss
和 .data
部分。
然后您可以在链接器文件中 .
设置为所需地址的位置下方添加一个部分。
例如:
SECTION
{
...
. = where_i_want_prog_sz;
prog_sz_section :
{
* (.bss.prog_sz)
}
...
}
请注意,这会将 prog_sz
存储在特定位置,但不会将 prog_sz
设置为该位置的值。
- 将命令文件中定义的链接器符号视为
size_t
变量。
使用extern
关键字定义变量:extern size_t prog_sz;
这告诉编译器该符号在别处定义,但属于 size_t 类型。请记住,如果这是正在做的事情,那么您将需要确保该内存位置没有被用于任何其他用途,否则 prog_sz 可能会与系统中的其他数据重叠。
关于第二个问题,即链接器错误消息列表,我相信您可能没有正确配置链接器。符号__init_array_end
和__init_array_start
与初始化C编程环境有关。我建议查看链接器设置和文档以确保程序配置正确。如果您使用的是 GNU 工具链,您可以在此处找到文档:
例如,我需要获取加载到内存中的进程的大小,然后我在我的代码中定义它:
#include <stdio.h>
ssize_t prog_sz;
int main()
{
printf("%x\n", prog_sz);
}
然后我有一个链接描述文件使用这样的行访问它 proc_sz = .
注意:我用我的程序测试的所有链接描述文件总是会产生错误,这就是为什么我只指定了脚本中的一行。例如像这样简单的东西没有我第一次谈到的那行:
SECTIONS
{
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
产生如下烦人的错误:
/usr/bin/ld: a.out: error: PHDR segment not covered by LOAD segment
/usr/bin/ld: /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS): in function `__libc_csu_init':
(.text+0x9): undefined reference to `__init_array_start'
/usr/bin/ld: (.text+0x20): undefined reference to `__init_array_end'
/usr/bin/ld: a.out: hidden symbol `__init_array_end' isn't defined
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
即使是 ld 信息文档中的一个示例也会产生那个恼人的错误。也许你也可以帮我解决这个问题。
您似乎有两个不同的问题。
第一期涉及symbol/variableprog_sz
。您展示的方法只会导致链接器尝试创建另一个名为 prog_sz
的符号,这不太可能实现目标。
在不详细说明正在做什么的情况下,我将介绍三个目标及其解决方案:
- 设置变量
prog_sz
以包含链接器文件中定义的符号的地址。
在命令文件中用不同的名称定义符号,例如 prog_sz__
。然后,您可以直接在代码中 prog_sz
的声明上方添加以下行:
extern char prog_sz;
类型 char
在这里并不重要。该语句仅用于告诉编译器该符号将在其他地方定义。在此之后,您可以通过将定义修改为:
prog_sz
size_t prog_sz = (size_t)(&prog_sz__);
使用 &
告诉程序将与符号 prog_sz__
关联的地址存储在变量 prog_sz
中。这会将链接描述文件中定义的符号分配给变量 prog_sz
.
- 使用链接描述文件将变量定位在固定位置,有一种方法可以做到这一点。
假设您使用的是 GNU 工具链,在构建时使用 GCC 选项 -fdata-sections
。这会将每个变量放入其自己的数据部分。请注意,您的 .bss
和 .data
部分将替换为前缀为 .data
或 .bss
的每个变量的部分,您可能需要使用通配符 *
捕获 .bss
和 .data
部分。
然后您可以在链接器文件中 .
设置为所需地址的位置下方添加一个部分。
例如:
SECTION
{
...
. = where_i_want_prog_sz;
prog_sz_section :
{
* (.bss.prog_sz)
}
...
}
请注意,这会将 prog_sz
存储在特定位置,但不会将 prog_sz
设置为该位置的值。
- 将命令文件中定义的链接器符号视为
size_t
变量。
使用extern
关键字定义变量:extern size_t prog_sz;
这告诉编译器该符号在别处定义,但属于 size_t 类型。请记住,如果这是正在做的事情,那么您将需要确保该内存位置没有被用于任何其他用途,否则 prog_sz 可能会与系统中的其他数据重叠。
关于第二个问题,即链接器错误消息列表,我相信您可能没有正确配置链接器。符号__init_array_end
和__init_array_start
与初始化C编程环境有关。我建议查看链接器设置和文档以确保程序配置正确。如果您使用的是 GNU 工具链,您可以在此处找到文档: