5

When attempting to run the following assembly program:

.globl start

start:
    pushq $0x0 
    movq $0x1, %rax
    subq $0x8, %rsp
    int $0x80

I am receiving the following errors:

dyld: no writable segment
Trace/BPT trap

Any idea what could be causing this? The analogous program in 32 bit assembly runs fine.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Hawken
  • 2,059
  • 19
  • 34

2 Answers2

10

OSX now requires your executable to have a writable data segment with content, so it can relocate and link your code dynamically. Dunno why, maybe security reasons, maybe due to the new RIP register. If you put a .data segment in there (with some bogus content), you'll avoid the "no writable segment" error. IMO this is an ld bug.

Regarding the 64-bit syscall, you can do it 2 ways. GCC-style, which uses the _syscall PROCEDURE from libSystem.dylib, or raw. Raw uses the syscall instruction, not the int 0x80 trap. int 0x80 is an illegal instruction in 64-bit.

The "GCC method" will take care of categorizing the syscall for you, so you can use the same 32-bit numbers found in sys/syscall.h. But if you go raw, you'll have to classify what kind of syscall it is by ORing it with a type id. Here is an example of both. Note that the calling convention is different! (this is NASM syntax because gas annoys me)

; assemble with
; nasm -f macho64 -o syscall64.o syscall64.asm && ld -lc -ldylib1.o -e start -o syscall64 syscall64.o
extern _syscall
global start

[section .text align=16]
start:
    ; do it gcc-style
    mov rdi, 0x4 ; sys_write
    mov rsi, 1 ; file descriptor
    mov rdx, hello
    mov rcx, size
    call _syscall ; we're calling a procedure, not trapping.
    
    ;now let's do it raw
    mov rax, 0x2000001 ; SYS_exit = 1 and is type 2 (bsd call)
    mov rdi, 0 ; Exit success = 0
    syscall ; faster than int 0x80, and legal!
    
    
[section .data align=16]
hello: db "hello 64-bit syscall!", 0x0a
size: equ $-hello

check out http://www.opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/syscall_sw.h for more info on how a syscall is typed.

David Jones
  • 4,766
  • 3
  • 32
  • 45
Jeremy
  • 116
  • 2
  • But I was under the impression syscalls were also able to be used in 32 bit assembly; what makes them mandatory in 64 bit? Is there any comparison between interrupts and syscalls to be found? Also would syscalls be found on other architectures or x86 only? I have a gut feeling syscalls are not a standard from what I have been able to find; to be clear I would like to have some knowledge I could use on PPC or ARM systems at some far off point in the future. – Hawken Mar 31 '12 at 00:48
  • `lea rdx, [rel hello]` would be more efficient than a `mov` with a 64-bit immediate address. And BTW, "illegal instruction" is the wrong term: That would means it doesn't even decode and raises a `#UD` exception. (Like the [`ud2` instruction](https://github.com/HJLebbink/asm-dude/wiki/UD).) `int 0x80` will fault if the kernel decides it should, but it does decode and execute. (And BTW, [Linux allows 64-bit processes to use the 32-bit `int 0x80` ABI](https://stackoverflow.com/q/46087730/224132). It's not generally useful and not recommended, though.) – Peter Cordes Dec 16 '17 at 07:55
  • You can and should still put your string in `section .rodata`, though, right? Just just need an empty `.data` section? Or do you need to have at least one byte in `.data` for NASM to emit one? – Peter Cordes Dec 16 '17 at 07:56
2

The system call interface is different between 32 and 64 bits. Firstly, int $80 is replaced by syscall and the system call numbers are different. You will need to look up documentation for a 64-bit version of your system call. Here is an example of what a 64-bit program may look like.

Jens Björnhager
  • 5,632
  • 3
  • 27
  • 47
  • you can use syscalls in 32 bit as well but I'm pretty sure the syscall is just a wrapper for the kernel interrupt. Any idea what the actual interrupt is or should I just start going through one-by-one? – Hawken Mar 27 '12 at 02:33
  • Here's a list of OSX syscalls: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/kern/syscalls.master – Jens Björnhager Mar 27 '12 at 03:04
  • but the syscall is wrapper for an interrupt, that's how it can invoke the kernel; maybe its not *recommended* but there must be a way to directly call the kernel interrupt in 64b – Hawken Mar 27 '12 at 03:13
  • `syscall` is not a wrapper, if anything it is a more direct way to invoke the kernel. – Jens Björnhager Mar 27 '12 at 04:52
  • How can it 'ask' the kernel to do something if not through an interrupt? The name sys**call** suggests it is a function/subroutine not that you are *call*ing, I thought to invoke the kernel you need to have the kernel run in its thread; how can calling something change the execution of the kernel if not through an interrupt? – Hawken Mar 27 '12 at 10:53
  • You don't need interrupts to perform a system call, realy only save current instruction address and transfer control to the OS. Read more here: http://en.wikipedia.org/wiki/System_call#Typical_implementations and here: http://www.codeguru.com/cpp/misc/misc/system/article.php/c8223/System-Call-Optimization-with-the-SYSENTER-Instruction.htm – Jens Björnhager Mar 27 '12 at 14:23
  • 1
    @Hawken: [`syscall` is a CPU instruction](https://github.com/HJLebbink/asm-dude/wiki/SYSCALL) for fast system calls (i.e. switching to kernel mode (ring0) at an entry point the kernel configured earlier). It works very much like a software-generated interrupt (`int $0x80`), but with a simpler faster implementation than the legacy interrupt mechanism. e.g. it doesn't touch stack memory, it clobbers RCX and R11 with the saved RIP and RFLAGS values. – Peter Cordes Dec 16 '17 at 07:46