Reputation: 50127
The write
syscall has the following functional prototype:
size_t write(int, const void *buf, size_t nbytes);
How do I call the write
syscall using inline assembler in GCC under MacOS X?
Upvotes: 3
Views: 4803
Reputation: 7065
A generic solution to this type of question: Write a short test program doing the write() call you are interested in, and then use gcc -S
to produce assembly or use otool
to disassemble the binary; find out how the write() call was assembled and transform that into the appropriate inline assembly.
(edit) To see the actual syscall, follow the library call in the assembly code. In the example of write()
, following the indirections will lead you via libSystem.B.dylib
to _write
in libsystem_kernel.dylib
, which you can disassemble using otool
.
(edit2) Full example below, using this test program test.c
:
#include <stdio.h>
int main(void)
{
char buf[] = "test\n";
ssize_t n;
n = write(2, buf, sizeof(buf));
return n;
}
Compile and test, using -O1 -fverbose-asm
to get concise, readable machine code:
% gcc -O1 -fverbose-asm -o test test.c
% ./test
test
Use otool
to disassemble main()
in the test
binary:
% otool -p _main -tvV test
test:
(__TEXT,__text) section
_main:
0000000100000ef0 pushq %rbp
0000000100000ef1 movq %rsp,%rbp
0000000100000ef4 subq $0x10,%rsp
0000000100000ef8 leaq 0xfa(%rbp),%rsi
0000000100000efc movb $0x74,0xfa(%rbp)
0000000100000f00 movb $0x65,0xfb(%rbp)
0000000100000f04 movb $0x73,0xfc(%rbp)
0000000100000f08 movb $0x74,0xfd(%rbp)
0000000100000f0c movb $0x0a,0xfe(%rbp)
0000000100000f10 movb $0x00,0xff(%rbp)
0000000100000f14 movl $0x00000002,%edi
0000000100000f19 movl $0x00000006,%edx
0000000100000f1e xorb %al,%al
0000000100000f20 callq 0x100000f32 ; symbol stub for: _write
0000000100000f25 addq $0x10,%rsp
0000000100000f29 popq %rbp
0000000100000f2a ret
List the libraries test
is dynamically linked against to find _write
:
% otool -L test
test:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
Try to locate _write
in libSystem.B.dylib
:
% otool -p _write -tvV /usr/lib/libSystem.B.dylib
/usr/lib/libSystem.B.dylib:
(__TEXT,__text) section
Can't find -p symbol: _write
Check the dependencies of libSystem.B.dylib
:
% otool -L /usr/lib/libSystem.B.dylib
/usr/lib/libSystem.B.dylib:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
/usr/lib/system/libcache.dylib (compatibility version 1.0.0, current version 47.0.0)
/usr/lib/system/libcommonCrypto.dylib (compatibility version 1.0.0, current version 55010.0.0)
/usr/lib/system/libcompiler_rt.dylib (compatibility version 1.0.0, current version 6.0.0)
/usr/lib/system/libcopyfile.dylib (compatibility version 1.0.0, current version 85.1.0)
/usr/lib/system/libdispatch.dylib (compatibility version 1.0.0, current version 187.9.0)
/usr/lib/system/libdnsinfo.dylib (compatibility version 1.0.0, current version 395.11.0)
/usr/lib/system/libdyld.dylib (compatibility version 1.0.0, current version 195.6.0)
/usr/lib/system/libkeymgr.dylib (compatibility version 1.0.0, current version 23.0.0)
/usr/lib/system/liblaunch.dylib (compatibility version 1.0.0, current version 392.38.0)
/usr/lib/system/libmacho.dylib (compatibility version 1.0.0, current version 800.0.0)
/usr/lib/system/libmathCommon.A.dylib (compatibility version 1.0.0, current version 2026.0.0)
/usr/lib/system/libquarantine.dylib (compatibility version 1.0.0, current version 36.6.0)
/usr/lib/system/libremovefile.dylib (compatibility version 1.0.0, current version 21.1.0)
/usr/lib/system/libsystem_blocks.dylib (compatibility version 1.0.0, current version 53.0.0)
/usr/lib/system/libsystem_c.dylib (compatibility version 1.0.0, current version 763.13.0)
/usr/lib/system/libsystem_dnssd.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/system/libsystem_info.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/system/libsystem_kernel.dylib (compatibility version 1.0.0, current version 1699.26.8)
/usr/lib/system/libsystem_network.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/system/libsystem_notify.dylib (compatibility version 1.0.0, current version 80.1.0)
/usr/lib/system/libsystem_sandbox.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/system/libunc.dylib (compatibility version 1.0.0, current version 24.0.0)
/usr/lib/system/libunwind.dylib (compatibility version 1.0.0, current version 30.0.0)
/usr/lib/system/libxpc.dylib (compatibility version 1.0.0, current version 77.19.0)
Guess that _write
is probably contained in libsystem_kernel.dylib
(or alternatively try all of them):
% otool -p _write -tvV /usr/lib/system/libsystem_kernel.dylib | head -20
(__TEXT,__text) section
_write:
0000000000017fd4 movl $0x02000004,%eax
0000000000017fd9 movq %rcx,%r10
0000000000017fdc syscall
0000000000017fde jae 0x00017fe5
0000000000017fe0 jmp cerror
0000000000017fe5 ret
0000000000017fe6 nop
0000000000017fe7 nop
[...]
Now we have all the assembly we need to construct the inline assembly version of test
:
#include <stdio.h>
int main(void)
{
char buf[] = "test\n";
ssize_t n;
asm volatile (
"movl $0x00000002, %%edi\n" /* first argument */
"movl $0x00000006, %%edx\n" /* third argument */
"movl $0x02000004, %%eax\n" /* syscall number */
"syscall\n"
: "=A"(n) /* %rax: return value */
: "S"(buf)); /* %rsi: second argument */
return n;
}
Compile and test:
% gcc -O1 -fverbose-asm -o test-asm test-asm.c
% ./test-asm
test
That seems to work. The inline assembly above is not very refined; for example, you could pass in the first and third arguments dynamically as well, instead of hardcoding them in the assembly code.
Upvotes: 11
Reputation: 15989
The Linux solution is something like this:
.data mytext:
.ascii "Hello World\n"
.text
_mywrite:
movl $0x04, %eax # Syscall No. 4 = write
movl $0x01, %ebx # File. 1 = stdout
movl $mytext, %ecx
movl $0x0c, %edx # text length (hope I counted correctly)
int $0x80 # Interrupt 0x80 -> make syscall
Should be similar on other Unix systems like Mac, but better check the syscall number (0x04) in the documentation.
Upvotes: 2