汇编 Linux 系统调用与汇编 OS x 系统调用 [英] Assembly Linux system calls vs assembly OS x system calls
问题描述
我在 Mac 上运行汇编代码时遇到问题.我目前正在阅读 Jeff Duntemann 的书 Assembly Step by Step.问题在于它专注于为 32 位 linux 系统编写程序集.我使用的是 64 位 mac os x 系统.我仍然可以使用 nasm -f macho32 在我的 64 位系统上运行 32 位程序集,但显然 Duntemann 书中的代码不起作用,因为 Linux 和 mac os x 中的系统调用不同.我将如何转换这个程序:
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
这样它就可以在我的 mac os x 系统上运行?我更喜欢 32 位汇编的解决方案,因为我正在尝试学习它,而不是更复杂的 64 位汇编.
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.
我在网上找到了一个解决方案,但它使用堆栈并有其他差异,例如从 esp 寄存器中减去,即使 Duntemann 的程序根本没有引用 esp 寄存器:
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
所以我想我想知道的是如何将linux系统调用转换为mac os x系统调用的分步过程?这样,当我阅读本书时,我就可以做到这一点,而不必在虚拟机或其他东西上下载 linux.
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.
推荐答案
那个解决方案是错误的.sub esp, 12
行应该是 sub esp, 4
.它没有传递 0 作为退出状态;它正在传递一个垃圾值.
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 有 BSD 系统调用.示例很难找到,因为大多数 BSD 程序不进行直接系统调用;它们链接到 libc 并调用 libc 中包装系统调用的函数.但是在汇编语言中,直接系统调用可以比 libc 调用更简单.
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.
对于 32 位 Intel 代码,OS X 和 Linux 都响应 int 0x80
.它们都在eax
中获取系统调用号,并在eax
中返回结果.主要区别如下:
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 接受寄存器中的参数(
ebx
、ecx
、edx
),但 OS X 接受堆栈中的参数.您以相反的顺序推送参数,然后再推送 4 个字节. - 发生错误时,Linux 在
eax
中放入一个负数,而 OS X 在eax
中放入一个正数.OS X 还设置了一个条件代码,因此jb
或jnb
会在错误发生或未发生时跳转. - 系统调用有不同的编号,有些有不同的参数.
- 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 ineax
. OS X also sets a condition code sojb
orjnb
would jump if an error did or did not happen. - The system calls have different numbers, and some have different arguments.
BSD 系统使用一个名为 syscalls.master 的文件来定义系统调用.我已经从 Mac OS X 链接到 syscalls.master10.4.11x86.我们可以使用它来查找每个系统调用的名称、参数和返回类型.例如:
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); }
write(2) 系统调用是数字 4,所以我们用 4 加载 eax
.它有 3 个参数,所以我们以相反的顺序推送它们:我们推送缓冲区中的字节数,然后推送一个指向缓冲区的指针,然后推送文件描述符.推入参数后,我们推入 4 个额外字节,可能带有 sub esp, 4
.然后我们做int 0x80
.然后我们可能想要add esp, 16
来移除我们推送的内容.
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.
大多数参数和返回值是 4 字节整数,但 off_t
在 OS X 中始终是 8 字节整数.我们必须小心像 lseek(2) 这样的调用.
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); }
offset 参数是一个 8 字节的整数,所以我们将它作为一对 4 字节的双字推送.Intel 处理器是 little-endian,堆栈向下增长,因此我们先推送高双字,然后再推送低双字.lseek(2) 的返回类型也是 off_t.它出现在寄存器 eax
和 edx
中,低位字在 eax
中,高位字在 edx
中.
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
.
有些系统调用很奇怪.为了捕捉信号,与 Linux 不同,OS X 没有对 signal(3) 的系统调用.我们必须使用 sigaction(2),但很奇怪:
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); }
第二个参数不是常规的 sigaction 结构.这是一个更大的结构,包括一个额外的蹦床字段.如果我们不在 libc 中调用 sigaction(),那么我们必须 提供我们自己的蹦床!它不同于 Linux 和其他 BSD 内核.
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.
这篇关于汇编 Linux 系统调用与汇编 OS x 系统调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!