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:
. = 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..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?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.