使用自定义链接描述文件了解分段错误,用于简单的 'Hello World' - 64k 以下的段名称或基址

Understanding Segmentation Faults with a custom linker script for a simple 'Hello World' - section names or base address below 64k

之前在 x86_64 上多次看到的基本 Hello World Linux:

global my_start_symbol 

section .text

my_start_symbol:
        mov rax, 1
        mov rdi, 1 
        mov rsi, msg
        mov rdx, msg_len
        syscall 

        mov rax, 60
        xor rdi, rdi
        syscall

section .rodata:
msg: db "Hello, world!", 10 
msg_len: equ $ - msg

我的工作 ld 链接描述文件:

ENTRY(my_start_symbol)
SECTIONS 
{
  . = 0x10000;
  .text : { *(.text*) }
  .rodata : { *(.rodata*) }
}

调用方式:

nasm -f elf64 assembly.asm -o assembly.o
ld -T linker.ld assembly.o -o assembly

当我尝试进行以下更改时遇到各种分段错误:

  1. 如果我删除链接描述文件中的 . = 0x10000 或使其小于 0x10000 ,我会遇到段错误。我认为这可能是由于页面大小,但是 getconf PAGE_SIZE returns 4K,所以我不知道为什么需要 8K。
  2. 如果我将汇编文件中的 .text 部分更改为 .my_section_name 并将链接器更新为 .my_section_name : { *(.my_section_name*) } 我会遇到段错误。我认为 .text.data 等部分名称是约定俗成的,您可以根据需要随意命名。如果我错了,为什么 .text : { *(.my_section_name*) } 也会给出段错误?

0x10000 最小值可能是由于 vm.mmap_min_addr = 65536 (https://wiki.debian.org/mmap_min_addr) 的默认设置,阻止 user-space 映射任何 low-address 页面来制作确保 NULL-deref 会大声出错,即使对于像 ptr[i] 这样带有一些 medium-sized 索引的代码也是如此。

一些像 .text 这样的名字是特殊的(对于 NASM and/or ld),并且有一组默认的权限(在本例中为 read + exec)。一些随机名称可能是 read + write without exec。检查 readelf -a a.out,特别是程序 Headers(它管理内核如何将可执行文件映射到内存)。

查看 readelf -a hello.o 以检查 NASM 输出中的 headers 部分也可能很有趣。