Search code examples
linuxassemblyx86-64ldlinker-scripts

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


Basic Hello World as seen many times before on x86_64 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

My working ld linker script:

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

Invoked with:

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

I get various segmentation faults when I experiment with the following changes:

  1. If I remove the . = 0x10000 inside of my linker script or make it anything less than 0x10000 I get a segfault. I thought this may be due to page size, however getconf PAGE_SIZE returns 4K, so I don't know why 8K is necessary.
  2. If I change the .text section in my assembly file to say .my_section_name and update the linker to say .my_section_name : { *(.my_section_name*) } I get a segfault. I thought the section names like .text, .data etc. were by convention, and that you could make them anything you wanted. If I'm wrong, why would .text : { *(.my_section_name*) } give a segfault also?

Solution

  • The 0x10000 minimum is probably due to the default setting of vm.mmap_min_addr = 65536 (https://wiki.debian.org/mmap_min_addr), preventing user-space from mapping any low-address pages to make sure that NULL-deref faults noisily, even for code like ptr[i] with some medium-sized index.

    A few names like .text are special (for NASM and/or ld), and have a default set of permissions (in this case read + exec). Some random name is probably read + write without exec. Check with readelf -a a.out, epsecially the Program Headers (which govern how an executable is mapped into memory by the kernel).

    Also probably interesting to have a look at readelf -a hello.o to check the section headers in the NASM output.