Пара-тройка статеек про ассемблер i386 для Mac OS X такие есть. А что насчет x86_64? Я взял "Hello World" для i386 и попробовал превратить его в x86_64. Код (Text): # Hello World x86 asm - MacOS X # By Erik Wrenholt # gcc hello.s -o hello ; ./hello ; echo $? # References: # http://forums.osxfaq.com/viewtopic.php?t=13976 # http://www.zathras.de/angelweb/blog-intel-assembler-on-mac-os-x.htm hello: .ascii "Hello World!\n" len = . - hello .text .globl _main _syscall: int $0x80 # call syscall ret _main: pushl $len # pass the length of the string pushl $hello # pass the ptr to the hello string pushl $1 # pass stdout (1) movl $0x4, %eax # SYS_write (4) call _syscall add $12, %esp # clear stack (we pushed 3 args) pushl $0 # we want to call exit(0), push 0 movl $1, %eax # SYS_exit=1 call _syscall leave ret Как и следовало ожидать, при попытке сконвертировать этот код возникла куча проблем. Самым нехорошим оказалась смена номеров системных вызовов в 64-битной версии Mac OS X.Частично это победить удалось. Вот что я наваял: Код (Text): .cstring hello: .ascii "Hello World!\n" hello_len = . - hello .text .globl _main _main: push $hello_len push hello(%rip) push $1 movl $0x02000004,%eax # SYS_write (4) syscall _exit: pushq $0 movl $0x02000001,%eax # SYS_exit (1) syscall Номера системных вызовов я взял из otool -tV /usr/lib/libSystem.B.dylib. Выход из программы происходит корректно, но она ничего не выводит. Возможно, я неправильно употребил RIP relative addressing и строка push hello(%rip) кладет на стек не совсем то, что я хочу? Или параметры вызова write тоже изменились? P.S. И, да, есть ли под Mac OS X нормальный отладчик, где сразу будет видно содержимое регистров и стека, а то GDB как-то не очень информативен?
>>P.S. И, да, есть ли под Mac OS X нормальный отладчик, где сразу будет видно содержимое регистров и стека, а то GDB как-то не очень информативен? - Есть же IDA (дизассм + дебуг) под osX (; А так можете есче посмотреть LLDB. Приведу пример дебуга LLDB и GDB. GDB: Код (Text): (gdb) b main Breakpoint 1 at 0x100000edb: file test.c, line 14. (gdb) r Starting program: /private/tmp/a.out Reading symbols for shared libraries +. done Breakpoint 1, main () at test.c:14 14 struct i10 v = fun(); (gdb) disass main Dump of assembler code for function main: 0x0000000100000ed0 : push %rbp 0x0000000100000ed1 : mov %rsp,%rbp 0x0000000100000ed4 : sub $0x20000,%rsp 0x0000000100000edb : lea -0x20000(%rbp),%rdi 0x0000000100000ee2 : mov $0x0,%eax 0x0000000100000ee7 : callq 0x100000ea0 0x0000000100000eec : leaveq 0x0000000100000eed : retq End of assembler dump. LLDB: Код (Text): (lldb) breakpoint set -n main Breakpoint created: 1 Breakpoint by name: 'main' with 1 location; (lldb) r Launching '/private/tmp/a.out' (x86_64) (lldb) Process 50271 Stopped * thread #1: tid = 0x2c03, pc = 0x0000000100000edb, where = a.out`main + 11 at /private/tmp/test.c:14, stop reason = breakpoint 1.1, queue = com.apple.main-thread 11 12 int main() 13 { 14 -> struct i10 v = fun(); 15 } (lldb) disass 0x100000ed0: pushq %rbp 0x100000ed1: movq %rsp, %rbp 0x100000ed4: subq $131072, %rsp 0x100000edb: leaq -131072(%rbp), %rdi 0x100000ee2: movl $0, %eax 0x100000ee7: callq 0x100000ea0 ; fun at /private/tmp/test.c:7 0x100000eec: leave 0x100000eed: ret
ОК, все заработало. Оказывается, в Mac OS X в 64-битном режиме то же соглашение вызовов, что и у Linux. (Удивительно -- я же видел упоминание этого на сайте Apple, в упор смотрел, но не верил). Код (Text): .cstring HelloString: .ascii "Hello World!\n" HelloStringLen = . - HelloString .text .globl _main _main: leaq HelloString(%rip), %rsi movq $HelloStringLen, %rdx movq $1,%rdi movl $0x02000004, %eax # SYS_write (4) syscall _exit: xor %rdi, %rdi movl $0x02000001, %eax # SYS_exit (1) syscall За наводку на lldb cпасибо.
Satsura A не подскажете, как в x86_64 закодить что-то вроде mov al, [Label+eax]? Если написать movb Label(%rax), %al, то gas эту строчку не примет, ибо "32-bit absolute addressing is not supported for x86-64". Это значит, сначала надо загружать адрес Label в какой-нибудь регистр, прибавлять к нему содержимое %rax, и только потом вытаскивать байт из этого адреса? Но ведь это получается три команды вместо одной.