0

I'm new to assembly and from what I learned the .code is same with .text, but the code below will crash using the .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

Actually, I don't think it's different. Why this happen ?

Jester
  • 56,577
  • 4
  • 81
  • 125
longack
  • 105
  • 7
  • 2
    You learned it wrong. In nasm `.code` is not recognized. See the [manual](https://www.nasm.us/xdoc/2.11.08/html/nasmdoc7.html#section-7.9.2). Notice in particular that unrecognized sections are `noexec`. – Jester Apr 14 '21 at 00:41
  • `section .text` is the NASM / Linux *equivalent* of Windows MASM `.code`, i.e. where you put your instructions. `section .code` doesn't actually do what you want in NASM. – Peter Cordes Apr 14 '21 at 03:40

1 Answers1

6

On Linux with the standard toolchain (GNU Binutils ld), .text is a "special" section name that gets special treatment (exec permission by default), but .code isn't. (Other special sections include .data (writeable) and .bss (writable nobits), and all with a default alignment > 1.)

section .text is the NASM ELF/Linux equivalent of Windows MASM .code directive, but that does not mean that Linux tools recognize a .code directive or section name1.

section .code is no different from section xyz123; it just uses the defaults which are noexec nowrite. See the other entry at the bottom of the table in the NASM docs.

Use readelf -a hello to see the section (linking) and segment (program-loader) attributes, with a distinct lack of an X anywhere.

Footnote 1: In fact, I think Windows executables still use the actual section name .text. At least GNU objdump -d still says the code is in the .text section. So the MASM .code directive is a shortcut for switching to the .text section.


Fun fact: this does happen to run correctly "by accident" if you build it as 32-bit code (which you should because it's using only 32-bit int 0x80 system calls), like in this case that used section .code when incorrectly porting from 16-bit MASM code to Linux NASM.
Or if you'd run your 64-bit code on an older kernel.

The reason is that without explicitly specifying a PT_GNU_STACK note, the kernel uses backwards-compat assumptions for 32-bit executables and uses READ_IMPLIES_EXEC which affects every single page: Linux default behavior of executable .data section changed between 5.4 and 5.9?. Older kernels do this even for 64-bit executables, newer kernels only make the stack itself executable in this case.

Adding section .note.GNU-stack noalloc noexec nowrite progbits to your source makes it segfault as it should, even when build into a 32-bit executable. (nasm -felf32 / ld -melf_i386 -o foo foo.o). See this answer.

See also Unexpected exec permission from mmap when assembly files included in the project about the old situation.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    _Side note:_ Peter, if you haven't already seen this one: https://stackoverflow.com/questions/67098983/why-does-a-loop-transitioning-from-having-its-uops-fed-by-the-uop-cache-to-lsd-c you're gonna love it. For content/questions. And, OP's question is as detailed as one of your answers. And, the formatting style looks very much like one of your answers. – Craig Estey Apr 14 '21 at 22:10