程序集部分 .code 和 .text 的行为不同

Assembly section .code and .text behave differently

我是汇编新手,据我了解,.code.text 相同,但使用 .code.

下面的代码会崩溃
segment .data
    msg db "hello, world", 0xa
    len equ $ - msg

section .text
    global _start

_start:
    mov edx, len
    mov ecx, msg

    mov ebx, 1
    mov eax, 4
    int 0x80

    mov ebx, 0
    mov eax, 1
    int 0x80

nasm -f elf64 -o hello.o hello.s 
ld -s -o hello hello.o
hello, world

sed -i s/.text/.code/ ./hello.s
nasm -f elf64 -o hello.o hello.s 
ld -s -o hello hello.o
./stack.sh: line 8:  4621 Segmentation fault      (core dumped) ./hello

其实我觉得没什么不同。为什么会这样?

在 Linux 使用标准工具链 (GNU Binutils ld) 时,.text 是一个“特殊”部分名称,得到特殊处理(默认为 exec 权限),但是 .code 不是。 (其他特殊部分包括 .data(可写)和 .bss(可写 nobits),并且都具有默认对齐方式 > 1。)

section .text 是 NASM ELF/Linux 等价于 Windows MASM .code 指令,但 不是 表示 Linux 工具识别 .code 指令或节名 1.

section .codesection xyz123没有区别;它只使用默认值 noexec nowrite. 请参阅 the table in the NASM docs.

底部的 other 条目

使用 readelf -a hello 查看节(链接)和段(程序加载器)属性,明显缺少任何地方的 X

脚注 1:事实上,我认为 Windows 可执行文件仍然使用实际的节名称 .text。至少 GNU objdump -d 仍然说代码在 .text 部分。 所以 MASM .code 指令是切换到 .text 部分的快捷方式。


有趣的事实:如果您将其构建为 32 位代码(您应该 ), like in 在错误移植时使用 section .code从 16 位 MASM 代码到 Linux NASM.
或者,如果您 运行 旧内核上的 64 位代码。

原因是在没有明确指定 PT_GNU_STACK 注释的情况下,内核对 32 位可执行文件使用向后兼容假设并使用影响每个页面的 READ_IMPLIES_EXEC .即使对于 64 位可执行文件,较旧的内核也会这样做,在这种情况下,较新的内核只会使堆栈本身可执行。

section .note.GNU-stack noalloc noexec nowrite progbits 添加到您的源代码会使其出现段错误,即使构建到 32 位可执行文件中也是如此。 (nasm -felf32 / ld -melf_i386 -o foo foo.o)。参见 this answer

另见旧情况。