我正在尝试使用 gcc/binutils 创建最小可执行文件。 我的 ld 脚本如下:
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64"); SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.35.164"); SEARCH_DIR("/usr/local/lib64"); SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib"); SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.35.1"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
SECTIONS
{
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(SORT(.text.sorted.*))
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
}
}
对我来说一切都很好,除了我看到一个名为“GNU_STACK”、大小为 0 的额外段头。 标头当然增加了 56 个字节。有谁知道如何删除它?手工创建 elf 太疯狂了,我想使用 gcc/binutils 来完成。
看来没办法了。最后我修改了 binutils 源以将其删除。
注意:需要
GNU_STACK
ELF 程序头条目将堆栈标记为在旧系统(例如 32 位 x86、arm 和 powerpc)上不可执行。如果删除它,堆栈将自动被内核标记为可执行文件:
linux-5.17/arch/arm/kernel.elf.c#n80
在现代架构中不需要 GNU_STACK,因此应使用以下内容修改链接器脚本:
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64"); SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.35.164"); SEARCH_DIR("/usr/local/lib64"); SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib"); SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.35.1"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
PHDRS
{
READONLY PT_LOAD FILEHDR PHDRS;
READWRITE PT_LOAD;
}
SECTIONS
{
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(SORT(.text.sorted.*))
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
} : READONLY
. = ALIGN(0x1000);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
} : READWRITE
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
}
}
根据需要更改
PHDRS
配置。
如果删除
GNU_STACK
条目,您可能应该使用 -Wtrampoline
或 -fno-trampolines
编译器标志:
patchelf 0.18.0 支持在二进制文件上打印、清除和设置可执行堆栈状态。
“--print-execstack” 打印 GNU_STACK 程序头的可执行标志的状态(如果存在)。
“--clear-execstack” 清除 GNU_STACK 程序头的可执行标志,或添加新头。
“--set-execstack” 设置 GNU_STACK 程序头的可执行标志,或添加新头。