Assembly Linux system calls vs assembly OS x system calls

六眼飞鱼酱① 提交于 2020-08-19 04:57:45

问题


I have a problem with running assembly code on my mac. I am currently going through Jeff Duntemann's book Assembly Step by Step. The problem is that it focuses on writing assembly for 32 bit linux systems. I am using a 64 bit mac os x system. I can still run 32 bit assembly on my 64 bit system using nasm -f macho32, but apparently the code from Duntemann's book does not work because the system calls in Linux and mac os x are different. How would I convert this program:

;  Executable name : EATSYSCALL
;  Version         : 1.0
;  Created date    : 1/7/2009
;  Last update     : 2/18/2009
;  Author          : Jeff Duntemann
;  Description     : A simple program in assembly for Linux, using NASM 2.05,
;    demonstrating the use of Linux INT 80H syscalls to display text.
;
;  Build using these commands:
;    nasm -f elf -g -F stabs eatsyscall.asm
;    ld -o eatsyscall eatsyscall.o
;

 SECTION .data          ; Section containing initialised data

     EatMsg: db "Eat at Joe's!",10
     EatLen: equ $-EatMsg   

 SECTION .bss           ; Section containing uninitialized data 

 SECTION .text          ; Section containing code

 global     _start          ; Linker needs this to find the entry point!

_start:
     nop            ; This no-op keeps gdb happy...
     mov eax,4      ; Specify sys_write call
     mov ebx,1      ; Specify File Descriptor 1: Standard Output
     mov ecx,EatMsg     ; Pass offset of the message
     mov edx,EatLen     ; Pass the length of the message
     int 80H            ; Make kernel call

     mov eax,1      ; Code for Exit Syscall
     mov ebx,0      ; Return a code of zero 
     int 80H            ; Make kernel call

so that it would run on my mac os x system? I would prefer a solution that in 32 bit assembly because I am trying to learn that instead of 64 bit assembly which is much more complicated.

I have found a solution online, but it uses the stack and has other differences such as subtracting from the esp register even though Duntemann's program doesn't reference the esp register at all:

global start

 section .text
 start:
    push    dword msg.len
       push    dword msg
    push    dword 1
    mov     eax, 4
    sub     esp, 4
    int     0x80
    add     esp, 16

    push    dword 0
    mov     eax, 1
    sub     esp, 12
    int     0x80

 section .data

 msg:    db      "Hello, world!", 10
.len:   equ     $ - msg

So I guess what I want to know is a step by step process of how to convert a linux system call to a mac os x system call? That way as I'm going through this book I can just do that instead of having to download linux on a virtual machine or something.


回答1:


That solution is wrong. The line sub esp, 12 should be sub esp, 4. It's not passing 0 as the exit status; it's passing a garbage value.

Mac OS X has BSD system calls. Examples are hard to find, because most programs for BSD don't make direct system calls; they link to libc and call functions in libc that wrap the system calls. But in assembly language, direct system calls can be simpler than libc calls.

For 32-bit Intel code, OS X and Linux both respond to int 0x80. They both take the system call number in eax, and they both return the result in eax. The major differences are these:

  • Linux takes the arguments in registers (ebx, ecx, edx), but OS X takes the arguments on the stack. You push the arguments in reverse order, then push an extra 4 bytes.
  • When an error happens, Linux puts a negative number in eax, but OS X puts a positive number in eax. OS X also sets a condition code so jb or jnb would jump if an error did or did not happen.
  • The system calls have different numbers, and some have different arguments.

Important file: syscalls.master

BSD systems use a file named syscalls.master to define system calls. I have linked to syscalls.master from Mac OS X 10.4.11x86. We can use it to find the name, arguments, and return type for each system call. For example:

4   PRE     NONE    ALL { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); } 

The write(2) system call is number 4, so we load eax with 4. It has 3 arguments, so we push them in reverse order: we push the number of bytes in the buffer, then push a pointer to the buffer, then push the file descriptor. After pushing the arguments, we push 4 extra bytes, perhaps with sub esp, 4. Then we do int 0x80. Then we probably want to add esp, 16 to remove what we pushed.

Most arguments and return values are 4-byte integers, but off_t in OS X is always an 8-byte integer. We must be careful with calls like lseek(2).

199 NONE    NONE    ALL { off_t lseek(int fd, off_t offset, int whence); } 

The offset argument is an 8-byte integer, so we push it as a pair of 4-byte double-words. Intel processors are little-endian, and the stack grows down, so we push the high dword before pushing the low dword. The return type of lseek(2) is also an off_t. It comes in registers eax and edx, with the low word in eax and the high word in edx.

Some system calls are strange. To catch a signal, OS X has no system call for signal(3), unlike Linux. We must use sigaction(2), but it's strange:

46  NONE    KERN    ALL { int sigaction(int signum, struct __sigaction *nsa, struct sigaction *osa); } 

The second argument isn't a regular sigaction struct. It's a bigger struct that includes an extra field for a trampoline. If we don't call sigaction() in libc, then we must provide our own trampoline! It's different from Linux and from other BSD kernels.



来源:https://stackoverflow.com/questions/33194207/assembly-linux-system-calls-vs-assembly-os-x-system-calls

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!