使用 ELF 文件的“.init_array”部分
Using ".init_array" section of ELF file
程序启动时(Linux上需要运行一段代码时,如何正确使用.init_section
可执行文件(ELF32- i386)?我有以下代码(GNU 汇编器),它有 ctor
初始化函数,这个函数的地址放在 .init_array
部分:
.intel_syntax noprefix
.data
s1: .asciz "Init code\n"
s2: .asciz "Main code\n"
.global _start
.global ctor
.text
ctor:
mov eax, 4 # sys_write()
mov ebx, 1 # stdout
mov ecx, offset s1
mov edx, 10
int 0x80
ret
.section .init_array
.long ctor
.text
_start:
mov eax, 4
mov ebx, 1
mov ecx, offset s2
mov edx, 10
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
此代码由以下代码汇编而成:
as -o init.o init.asm
ld -o init init.o
当生成的可执行文件为 运行 时,仅打印 "Main code" 字符串。如何正确使用 .init_array 部分?
EDIT1:我想使用 .init_array 因为有多个源文件都有自己的初始化代码。可以在启动时调用所有这些代码 'manually' 并在每次将源文件添加到项目或从项目中删除时修改它,但是 .init_array
似乎就是为这种情况设计的:
Before transferring control to an application, the runtime linker
processes any initialization sections found in the application and any
loaded dependencies. The initialization sections .preinit_array,
.init_array, and .init are created by the link-editor when a dynamic
object is built.
The runtime linker executes functions whose addresses are contained in
the .preinit_array and .init_array sections. These functions are
executed in the same order in which their addresses appear in the
array.
如果在没有 gcc 的情况下创建可执行文件,链接器似乎不执行启动代码。我尝试编写自己的标准 init 例程,它读取 .init_array 部分中的函数指针并调用它们。它适用于一个文件,其中可以标记该部分的结尾,例如,用零标记。但是对于多个文件,这个零可以重新定位在部分的中间。如何正确判断由多个源文件组合而成的一节的大小?
如果你按照你现在的方式静态linked裸可执行文件,在_start
入口点使用你自己的代码,你的代码只是从那一点开始运行。如果你想让某事发生,你的代码必须让它发生。没有魔法。
使用节可以将来自多个源文件的启动代码组合在一起,因此所有启动代码都是冷的并且可能被调出页面,或者至少不需要 TLB 条目。
所以你 "properly use" 部分通过将函数放在那里并从在 _start
.
之后运行的代码调用它们
在您的代码示例中,.init_array
看起来像是一个函数指针列表。我假设标准 CRT 启动文件读取 ELF 文件并找到该部分的长度,然后通过它间接调用这些函数。由于您正在编写自定义代码,因此调用一个执行所有操作的 init 函数会更快。
动态 linking:
"runtime linker" 是动态二进制文件的 ELF 解释器。它在 _start
之前在您的进程中运行代码,所以是的,显然它确实处理了 ELF 部分并让奇迹发生了。
因此,为了响应您的编辑,您的选择是:自己实施 .init_array
的此处理,或创建动态可执行文件。我很确定这个过程已经包含在其他问题中,我没有时间为仍然没有 link libc 的动态可执行文件研究正确的命令行。 (尽管您可能只想使用 gcc -nostartfiles
或其他东西。)
如果遇到困难,请发表评论。无论如何,我可能会在以后有更多时间时更新它,或者随时在工作命令中进行编辑。
对于普通的 C 程序,.init_array
由在调用 main 之前从 _start
调用的函数遍历。 this 网站上有很好的描述。
所以我看到了两种方法:您可以简单地 link 针对 glibc 启动代码。或者你必须自己找出另一种机制来解决这个问题。
程序启动时(Linux上需要运行一段代码时,如何正确使用.init_section
可执行文件(ELF32- i386)?我有以下代码(GNU 汇编器),它有 ctor
初始化函数,这个函数的地址放在 .init_array
部分:
.intel_syntax noprefix
.data
s1: .asciz "Init code\n"
s2: .asciz "Main code\n"
.global _start
.global ctor
.text
ctor:
mov eax, 4 # sys_write()
mov ebx, 1 # stdout
mov ecx, offset s1
mov edx, 10
int 0x80
ret
.section .init_array
.long ctor
.text
_start:
mov eax, 4
mov ebx, 1
mov ecx, offset s2
mov edx, 10
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
此代码由以下代码汇编而成:
as -o init.o init.asm
ld -o init init.o
当生成的可执行文件为 运行 时,仅打印 "Main code" 字符串。如何正确使用 .init_array 部分?
EDIT1:我想使用 .init_array 因为有多个源文件都有自己的初始化代码。可以在启动时调用所有这些代码 'manually' 并在每次将源文件添加到项目或从项目中删除时修改它,但是 .init_array
似乎就是为这种情况设计的:
Before transferring control to an application, the runtime linker processes any initialization sections found in the application and any loaded dependencies. The initialization sections .preinit_array, .init_array, and .init are created by the link-editor when a dynamic object is built.
The runtime linker executes functions whose addresses are contained in the .preinit_array and .init_array sections. These functions are executed in the same order in which their addresses appear in the array.
如果在没有 gcc 的情况下创建可执行文件,链接器似乎不执行启动代码。我尝试编写自己的标准 init 例程,它读取 .init_array 部分中的函数指针并调用它们。它适用于一个文件,其中可以标记该部分的结尾,例如,用零标记。但是对于多个文件,这个零可以重新定位在部分的中间。如何正确判断由多个源文件组合而成的一节的大小?
如果你按照你现在的方式静态linked裸可执行文件,在_start
入口点使用你自己的代码,你的代码只是从那一点开始运行。如果你想让某事发生,你的代码必须让它发生。没有魔法。
使用节可以将来自多个源文件的启动代码组合在一起,因此所有启动代码都是冷的并且可能被调出页面,或者至少不需要 TLB 条目。
所以你 "properly use" 部分通过将函数放在那里并从在 _start
.
在您的代码示例中,.init_array
看起来像是一个函数指针列表。我假设标准 CRT 启动文件读取 ELF 文件并找到该部分的长度,然后通过它间接调用这些函数。由于您正在编写自定义代码,因此调用一个执行所有操作的 init 函数会更快。
动态 linking:
"runtime linker" 是动态二进制文件的 ELF 解释器。它在 _start
之前在您的进程中运行代码,所以是的,显然它确实处理了 ELF 部分并让奇迹发生了。
因此,为了响应您的编辑,您的选择是:自己实施 .init_array
的此处理,或创建动态可执行文件。我很确定这个过程已经包含在其他问题中,我没有时间为仍然没有 link libc 的动态可执行文件研究正确的命令行。 (尽管您可能只想使用 gcc -nostartfiles
或其他东西。)
如果遇到困难,请发表评论。无论如何,我可能会在以后有更多时间时更新它,或者随时在工作命令中进行编辑。
对于普通的 C 程序,.init_array
由在调用 main 之前从 _start
调用的函数遍历。 this 网站上有很好的描述。
所以我看到了两种方法:您可以简单地 link 针对 glibc 启动代码。或者你必须自己找出另一种机制来解决这个问题。