Skip to content
Advertisement

How to make a custom section executable (other than .text)

Basic Hello World as seen many times before on x86_64 Linux:

global my_start_symbol 

section .my_section

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 current ld linker script:

__linux_mmap_min_addr = 0x10000;

ENTRY(my_start_symbol)

MEMORY
{
  rom (rx) : ORIGIN = 0, LENGTH = 512K
}

SECTIONS 
{
  . = __linux_mmap_min_addr;
  .my_section : 
  { 
    *(.my_section*) 
  } > rom
  .rodata : 
  {
    *(.rodata*) 
  } > rom
}

Invoked with:

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

I’m currently getting a segfault. Inspecting the output of readelf -a I can see that my_section does not have executable permissions. I believe this is causing the segfault. If I replace it with .text : { *(.my_section*) } > rom it still does not get set as executable. Only if I revert to using .text everywhere as is convention, does it set it as executable.

Advertisement

Answer

My assessments (at least on x86_64 Linux with NASM):

  1. The flags set in ld MEMORY definition are irrelevant in setting the section to executable. The NASM ELF Section extensions are what matter, i.e. section .my_section exec will work even if MEMORY does not have x flag (thanks to @peter-cordes).
  2. If you have specific ld MEMORY definitions that you are using, the origin cannot be 0, but must be at least 0x10000 (see this S.O q&a for more info) Using . = 0x10000; at the start of the section is not sufficient.
Advertisement