I have a assembly program which should write "What's your name?", then wait for user input, and then print "Hello, ". This is my program(Mac, nasm):
section .data
question db "What's your name?"
answer db "Hello, "
ln db 10
section .bss
name resb 16
section .text
global start
start:
mov rsi, question
mov rdi, 17
call print
call getName
mov rsi, answer
mov rdi, 7
call print
mov rsi, ln
mov rdi, 1
call print
mov rax, 0x02000001
mov rdi, 0
syscall
print:
mov rax, 0x02000004
mov rdi, 1
syscall
ret
getName:
mov rax, 0x02000003
mov rdi, 0
mov rsi, name
mov rdx, 16
syscall
ret
But this program writes "What's your name?Hello," and only then awaits for user input.
Why doesn't it wait for the input before it writes "Hello,"?
I mixed up rdx and rdi in start and forgot to print out the name. My bad.
EDIT: For some reason I cannot accept this answer, so: This it the accepted answer!
Your code is totally wrong. Register RAX must the value of service syscall. I will help you to correct the code for full program.
compile it with:
nasm -f elf64 -o objname.o sourcecode.asm
ld -m elf_x86_64 -o execname objname.o
%macro print 2
mov rax,1
mov rdi,rax
mov rsi,%1
mov rdx,%2
syscall
%endmacro
%macro getinput 2
mov rax,0
mov rdi,rax
mov rsi,%1
mov rdx,%2
syscall
%endmacro
%macro exit 0
mov rax,60
xor rdi,rdi
syscall
%endmacro
section .data
question db "What's your name?"
lenques equ $-question
answer db "Hello, "
lenans equ $-answer
ln db 10
lenname equ 30
section .bss
name resb lenname
section .text
global _start
_start:
print question,lenques
push rax
getinput name,lenname
print answer,lenans
pop rbx
print name,rbx
print ln,1
exit
Related
I'm having trouble finding the good documentation for writing 64-bit assembly on MacOS.
The 64-bit SysV ABI says the following in section A.2.1 and this SO post quotes it:
A system-call is done via the syscall instruction. The kernel destroys
registers %rcx and %r11.
Returning from the syscall, register %rax contains the result of the
system-call. A value in the range between -4095 and -1 indicates an error,
it is -errno.
Those two sentences are ok on Linux but are wrong on macOS Sierra with the following code:
global _start
extern _exit
section .text
_start:
; Align stack to 16 bytes for libc
and rsp, 0xFFFFFFFFFFFFFFF0
; Call write
mov rdx, 12 ; size
mov rsi, hello ; buf
mov edi, 1 ; fd
mov rax, 0x2000004 ; write ; replace to mov rax, 0x1 on linux
syscall
jc .err ; Jumps on error on macOS, but why?
jnc .ok
.err:
mov rdi, -1
call _exit ; exit(-1)
.ok:
; Expect rdx to be 12, but it isn't on macOS!
mov rdi, rdx
call _exit ; exit(rdx)
; String for write
section .data
hello:
.str db `Hello world\n`
.len equ $-hello.str
Compile with NASM:
; MacOS: nasm -f macho64 syscall.asm && ld syscall.o -lc -macosx_version_min 10.12 -e _start -o syscall
; Linux: nasm -f elf64 syscall.asm -o syscall.o && ld syscall.o -lc -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o syscall
Run on macOS:
./syscall # Return value 0
./syscall >&- # Return value 255 (-1)
I found out that:
A syscall return errno an sets the carry flag on error, instead of returning -errno in rax
rdx register is clobbered by syscall
On Linux, everything works as expected
Why is rdx clobbered? Why doesn't a syscall return -errno? Where can I find the real documentation?
The only place I found where someone talks about the carry flag for syscall errors is here
I used this:
# as hello.asm -o hello.o
# ld hello.o -macosx_version_min 10.13 -e _main -o hello -lSystem
.section __DATA,__data
str:
.asciz "Hello world!\n"
.section __TEXT,__text
.globl _main
_main:
movl $0x2000004, %eax # preparing system call 4
movl $1, %edi # STDOUT file descriptor is 1
movq str#GOTPCREL(%rip), %rsi # The value to print
movq $13, %rdx # the size of the value to print
syscall
movl %eax, %edi
movl $0x2000001, %eax # exit (return value of the call to write())
syscall
and was able to catch return value into eax. Here return value is the number of bytes actually written by write system call. And yes MacOS being a BSD variant it is the carry flag that tells you if the syscall was wrong or not (errno is just an external linkage variable).
# hello_asm.s
# as hello_asm.s -o hello_asm.o
# ld hello_asm.o -e _main -o hello_asm
.section __DATA,__data
str:
.asciz "Hello world!\n"
good:
.asciz "OK\n"
.section __TEXT,__text
.globl _main
_main:
movl $0x2000004, %eax # preparing system call 4
movl $5, %edi # STDOUT file descriptor is 5
movq str#GOTPCREL(%rip), %rsi # The value to print
movq $13, %rdx # the size of the value to print
syscall
jc err
movl $0x2000004, %eax # preparing system call 4
movl $1, %edi # STDOUT file descriptor is 1
movq good#GOTPCREL(%rip), %rsi # The value to print
movq $3, %rdx # the size of the value to print
syscall
movl $0, %edi
movl $0x2000001, %eax # exit 0
syscall
err:
movl $1, %edi
movl $0x2000001, %eax # exit 1
syscall
This will exits with error code one because descriptor 5 was used, if you try descriptor 1 then it will work printing another message and exiting with 0.
I don't know why rdx gets clobbered, just to confirm that it indeed does seem to get zeroed across the "write" systemcall. I examined the status of every register:
global _start
section .text
_start:
mov rax, 0xDEADBEEF; 0xDEADBEEF = 3735928559; 3735928559 mod 256 = 239
mov rbx, 0xDEADBEEF
mov rcx, 0xDEADBEEF
mov rdx, 0xDEADBEEF
mov rsi, 0xDEADBEEF
mov rdi, 0xDEADBEEF
mov rsp, 0xDEADBEEF
mov rbp, 0xDEADBEEF
mov r8, 0xDEADBEEF
mov r9, 0xDEADBEEF
mov r10, 0xDEADBEEF
mov r11, 0xDEADBEEF
mov r12, 0xDEADBEEF
mov r13, 0xDEADBEEF
mov r14, 0xDEADBEEF
mov r15, 0xDEADBEEF
mov rdx, len2 ; size
mov rsi, msg2 ; buf
mov rdi, 1 ; fd
mov rax, 0x2000004 ; write
syscall
mov rdi, rsi ; CHANGE THIS TO EXAMINE DIFFERENT REGISTERS
mov rax, 0x2000001 ; exit
syscall
section .data
msg_pad db `aaaa\n` ; to make the buffer not to be page-aligned
msg2 db `bbbbbb\n` ; because then it's easier to notice whether
len2 equ $-msg2 ; clobbered or not
nasm -f macho64 syscall.asm && ld syscall.o -e _start -static && ./a.out; echo "status: $?"
The results I got:
clobber list of a "write" syscall
rax clobbered
rbx not clobbered
rcx clobbered
rdx clobbered <- This is the unexpected case?!
rsi not clobbered
rdi not clobbered
rsp not clobbered
rbp not clobbered
r8 not clobbered
r9 not clobbered
r10 not clobbered
r11 clobbered
r12 not clobbered
r13 not clobbered
r14 not clobbered
r15 not clobbered
It would be interesting to know other syscalls zero rdx too, I didn't have the energy to attempt a thorough investigation. But maybe, just to be safe, one should add rdx to the clobber list of all of the MacOS syscalls from now on.
I am working on a mac and writing an asm program supposed to printf its own source in another file with some modification, itself compile and run it. Therefor, I use the function system() to run a bash command.
Here is my problem, the line call _system works at a line, but a few lines later, nothing happen, its call seems to be ignored.
I made tests to be sure everything is fine, and it looks to be, I don't get error or whatever ... here is a sample :
section .data
i: equ 5
[...]
s_string: equ $ - string
name: db "Sully_%d.s", 0
s_name: equ $ - name
cc: db "nasm -fmacho64 Sully_%1$d.s -o Sully_%1$d.o", 0
s_cc: equ $ - cc
link: db "ld Sully_%1$d.o -o Sully_%1$d -macosx_version_min 10.8 -lSystem", 0
s_link: equ $ - link
ex: db "./Sully_%d", 0
s_ex: equ $ - ex
tmp: db "ls -l", 0
section .text
global start
global _main
extern _sprintf
extern _dprintf
extern _printf
extern _system
extern _close
extern _strlen
start:
call _main
ret
_main:
push rbp
mov rbp, rsp
sub rsp, 16
sub rsp, 0x650 ; 1616 byte to store strings later
mov rbx, i
cmp rbx, 0
je end_point
mov rdi, qword [rsi]
call _strlen
mov r12, rax
load_name:
lea rdi, [rbp + 16]
lea rsi, [rel name] ; string in data section, work fine since I can print it later at rbp + 16 location, I mean the result of 'name' string format with i as parameter
cmp r12, 7
jne ln_mov_i
mov rdx, i
cmp r12, 7
je ln_mov_i_1
ln_mov_i:
mov rdx, i - 1
ln_mov_i_1:
xor rax, rax
call _sprintf
cmp rax, 0
jl ret
load_cc:
lea rdi, [rel tmp]
call _system ; this does work
lea rdi, [rbp + 32 + s_name] ; string in data section, work fine since I can print it later
lea rsi, [rel cc]
cmp r12, 7
jne lc_mov_i
mov rdx, i
cmp r12, 7
je lc_mov_i_1
lc_mov_i:
mov rdx, i - 1
lc_mov_i_1:
xor rax, rax
call _sprintf
cmp rax, 0
jl ret
lea rdi, [rel tmp]
call _system ; this doesn't work
[...]
I noticed with a few more tests than system return 32512 which is if I well understand, 127. I tried to use sh -c 'my command' but it doesn't make any better thing ...
With dtruss, i found out that the call of posix_spawn fail, I don't know why, here is what I find for the 2 call _system of my sample :
PID/THRD RELATIVE ELAPSD CPU SYSCALL(args) = return
3040/0x143a1: 2271 243 240 posix_spawn(0x7FFEEFBFF454, 0x7FFF5BDBD256, 0x7FFEEFBFF360) = 0 0
3040/0x143a1: 2492 157 153 posix_spawn(0x7FFEEFBFF454, 0x7FFF5BDBD256, 0x7FFEEFBFF360) = -1 Err#14
I can't figure out why it doesn't work ! I can't find on the internet any specification about this function 'system'.
I'm having trouble finding the good documentation for writing 64-bit assembly on MacOS.
The 64-bit SysV ABI says the following in section A.2.1 and this SO post quotes it:
A system-call is done via the syscall instruction. The kernel destroys
registers %rcx and %r11.
Returning from the syscall, register %rax contains the result of the
system-call. A value in the range between -4095 and -1 indicates an error,
it is -errno.
Those two sentences are ok on Linux but are wrong on macOS Sierra with the following code:
global _start
extern _exit
section .text
_start:
; Align stack to 16 bytes for libc
and rsp, 0xFFFFFFFFFFFFFFF0
; Call write
mov rdx, 12 ; size
mov rsi, hello ; buf
mov edi, 1 ; fd
mov rax, 0x2000004 ; write ; replace to mov rax, 0x1 on linux
syscall
jc .err ; Jumps on error on macOS, but why?
jnc .ok
.err:
mov rdi, -1
call _exit ; exit(-1)
.ok:
; Expect rdx to be 12, but it isn't on macOS!
mov rdi, rdx
call _exit ; exit(rdx)
; String for write
section .data
hello:
.str db `Hello world\n`
.len equ $-hello.str
Compile with NASM:
; MacOS: nasm -f macho64 syscall.asm && ld syscall.o -lc -macosx_version_min 10.12 -e _start -o syscall
; Linux: nasm -f elf64 syscall.asm -o syscall.o && ld syscall.o -lc -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o syscall
Run on macOS:
./syscall # Return value 0
./syscall >&- # Return value 255 (-1)
I found out that:
A syscall return errno an sets the carry flag on error, instead of returning -errno in rax
rdx register is clobbered by syscall
On Linux, everything works as expected
Why is rdx clobbered? Why doesn't a syscall return -errno? Where can I find the real documentation?
The only place I found where someone talks about the carry flag for syscall errors is here
I used this:
# as hello.asm -o hello.o
# ld hello.o -macosx_version_min 10.13 -e _main -o hello -lSystem
.section __DATA,__data
str:
.asciz "Hello world!\n"
.section __TEXT,__text
.globl _main
_main:
movl $0x2000004, %eax # preparing system call 4
movl $1, %edi # STDOUT file descriptor is 1
movq str#GOTPCREL(%rip), %rsi # The value to print
movq $13, %rdx # the size of the value to print
syscall
movl %eax, %edi
movl $0x2000001, %eax # exit (return value of the call to write())
syscall
and was able to catch return value into eax. Here return value is the number of bytes actually written by write system call. And yes MacOS being a BSD variant it is the carry flag that tells you if the syscall was wrong or not (errno is just an external linkage variable).
# hello_asm.s
# as hello_asm.s -o hello_asm.o
# ld hello_asm.o -e _main -o hello_asm
.section __DATA,__data
str:
.asciz "Hello world!\n"
good:
.asciz "OK\n"
.section __TEXT,__text
.globl _main
_main:
movl $0x2000004, %eax # preparing system call 4
movl $5, %edi # STDOUT file descriptor is 5
movq str#GOTPCREL(%rip), %rsi # The value to print
movq $13, %rdx # the size of the value to print
syscall
jc err
movl $0x2000004, %eax # preparing system call 4
movl $1, %edi # STDOUT file descriptor is 1
movq good#GOTPCREL(%rip), %rsi # The value to print
movq $3, %rdx # the size of the value to print
syscall
movl $0, %edi
movl $0x2000001, %eax # exit 0
syscall
err:
movl $1, %edi
movl $0x2000001, %eax # exit 1
syscall
This will exits with error code one because descriptor 5 was used, if you try descriptor 1 then it will work printing another message and exiting with 0.
I don't know why rdx gets clobbered, just to confirm that it indeed does seem to get zeroed across the "write" systemcall. I examined the status of every register:
global _start
section .text
_start:
mov rax, 0xDEADBEEF; 0xDEADBEEF = 3735928559; 3735928559 mod 256 = 239
mov rbx, 0xDEADBEEF
mov rcx, 0xDEADBEEF
mov rdx, 0xDEADBEEF
mov rsi, 0xDEADBEEF
mov rdi, 0xDEADBEEF
mov rsp, 0xDEADBEEF
mov rbp, 0xDEADBEEF
mov r8, 0xDEADBEEF
mov r9, 0xDEADBEEF
mov r10, 0xDEADBEEF
mov r11, 0xDEADBEEF
mov r12, 0xDEADBEEF
mov r13, 0xDEADBEEF
mov r14, 0xDEADBEEF
mov r15, 0xDEADBEEF
mov rdx, len2 ; size
mov rsi, msg2 ; buf
mov rdi, 1 ; fd
mov rax, 0x2000004 ; write
syscall
mov rdi, rsi ; CHANGE THIS TO EXAMINE DIFFERENT REGISTERS
mov rax, 0x2000001 ; exit
syscall
section .data
msg_pad db `aaaa\n` ; to make the buffer not to be page-aligned
msg2 db `bbbbbb\n` ; because then it's easier to notice whether
len2 equ $-msg2 ; clobbered or not
nasm -f macho64 syscall.asm && ld syscall.o -e _start -static && ./a.out; echo "status: $?"
The results I got:
clobber list of a "write" syscall
rax clobbered
rbx not clobbered
rcx clobbered
rdx clobbered <- This is the unexpected case?!
rsi not clobbered
rdi not clobbered
rsp not clobbered
rbp not clobbered
r8 not clobbered
r9 not clobbered
r10 not clobbered
r11 clobbered
r12 not clobbered
r13 not clobbered
r14 not clobbered
r15 not clobbered
It would be interesting to know other syscalls zero rdx too, I didn't have the energy to attempt a thorough investigation. But maybe, just to be safe, one should add rdx to the clobber list of all of the MacOS syscalls from now on.
I'm having trouble finding the good documentation for writing 64-bit assembly on MacOS.
The 64-bit SysV ABI says the following in section A.2.1 and this SO post quotes it:
A system-call is done via the syscall instruction. The kernel destroys
registers %rcx and %r11.
Returning from the syscall, register %rax contains the result of the
system-call. A value in the range between -4095 and -1 indicates an error,
it is -errno.
Those two sentences are ok on Linux but are wrong on macOS Sierra with the following code:
global _start
extern _exit
section .text
_start:
; Align stack to 16 bytes for libc
and rsp, 0xFFFFFFFFFFFFFFF0
; Call write
mov rdx, 12 ; size
mov rsi, hello ; buf
mov edi, 1 ; fd
mov rax, 0x2000004 ; write ; replace to mov rax, 0x1 on linux
syscall
jc .err ; Jumps on error on macOS, but why?
jnc .ok
.err:
mov rdi, -1
call _exit ; exit(-1)
.ok:
; Expect rdx to be 12, but it isn't on macOS!
mov rdi, rdx
call _exit ; exit(rdx)
; String for write
section .data
hello:
.str db `Hello world\n`
.len equ $-hello.str
Compile with NASM:
; MacOS: nasm -f macho64 syscall.asm && ld syscall.o -lc -macosx_version_min 10.12 -e _start -o syscall
; Linux: nasm -f elf64 syscall.asm -o syscall.o && ld syscall.o -lc -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o syscall
Run on macOS:
./syscall # Return value 0
./syscall >&- # Return value 255 (-1)
I found out that:
A syscall return errno an sets the carry flag on error, instead of returning -errno in rax
rdx register is clobbered by syscall
On Linux, everything works as expected
Why is rdx clobbered? Why doesn't a syscall return -errno? Where can I find the real documentation?
The only place I found where someone talks about the carry flag for syscall errors is here
I used this:
# as hello.asm -o hello.o
# ld hello.o -macosx_version_min 10.13 -e _main -o hello -lSystem
.section __DATA,__data
str:
.asciz "Hello world!\n"
.section __TEXT,__text
.globl _main
_main:
movl $0x2000004, %eax # preparing system call 4
movl $1, %edi # STDOUT file descriptor is 1
movq str#GOTPCREL(%rip), %rsi # The value to print
movq $13, %rdx # the size of the value to print
syscall
movl %eax, %edi
movl $0x2000001, %eax # exit (return value of the call to write())
syscall
and was able to catch return value into eax. Here return value is the number of bytes actually written by write system call. And yes MacOS being a BSD variant it is the carry flag that tells you if the syscall was wrong or not (errno is just an external linkage variable).
# hello_asm.s
# as hello_asm.s -o hello_asm.o
# ld hello_asm.o -e _main -o hello_asm
.section __DATA,__data
str:
.asciz "Hello world!\n"
good:
.asciz "OK\n"
.section __TEXT,__text
.globl _main
_main:
movl $0x2000004, %eax # preparing system call 4
movl $5, %edi # STDOUT file descriptor is 5
movq str#GOTPCREL(%rip), %rsi # The value to print
movq $13, %rdx # the size of the value to print
syscall
jc err
movl $0x2000004, %eax # preparing system call 4
movl $1, %edi # STDOUT file descriptor is 1
movq good#GOTPCREL(%rip), %rsi # The value to print
movq $3, %rdx # the size of the value to print
syscall
movl $0, %edi
movl $0x2000001, %eax # exit 0
syscall
err:
movl $1, %edi
movl $0x2000001, %eax # exit 1
syscall
This will exits with error code one because descriptor 5 was used, if you try descriptor 1 then it will work printing another message and exiting with 0.
I don't know why rdx gets clobbered, just to confirm that it indeed does seem to get zeroed across the "write" systemcall. I examined the status of every register:
global _start
section .text
_start:
mov rax, 0xDEADBEEF; 0xDEADBEEF = 3735928559; 3735928559 mod 256 = 239
mov rbx, 0xDEADBEEF
mov rcx, 0xDEADBEEF
mov rdx, 0xDEADBEEF
mov rsi, 0xDEADBEEF
mov rdi, 0xDEADBEEF
mov rsp, 0xDEADBEEF
mov rbp, 0xDEADBEEF
mov r8, 0xDEADBEEF
mov r9, 0xDEADBEEF
mov r10, 0xDEADBEEF
mov r11, 0xDEADBEEF
mov r12, 0xDEADBEEF
mov r13, 0xDEADBEEF
mov r14, 0xDEADBEEF
mov r15, 0xDEADBEEF
mov rdx, len2 ; size
mov rsi, msg2 ; buf
mov rdi, 1 ; fd
mov rax, 0x2000004 ; write
syscall
mov rdi, rsi ; CHANGE THIS TO EXAMINE DIFFERENT REGISTERS
mov rax, 0x2000001 ; exit
syscall
section .data
msg_pad db `aaaa\n` ; to make the buffer not to be page-aligned
msg2 db `bbbbbb\n` ; because then it's easier to notice whether
len2 equ $-msg2 ; clobbered or not
nasm -f macho64 syscall.asm && ld syscall.o -e _start -static && ./a.out; echo "status: $?"
The results I got:
clobber list of a "write" syscall
rax clobbered
rbx not clobbered
rcx clobbered
rdx clobbered <- This is the unexpected case?!
rsi not clobbered
rdi not clobbered
rsp not clobbered
rbp not clobbered
r8 not clobbered
r9 not clobbered
r10 not clobbered
r11 clobbered
r12 not clobbered
r13 not clobbered
r14 not clobbered
r15 not clobbered
It would be interesting to know other syscalls zero rdx too, I didn't have the energy to attempt a thorough investigation. But maybe, just to be safe, one should add rdx to the clobber list of all of the MacOS syscalls from now on.
I'm trying to write a simple helloworld in assembler 64 on Mac with NASM.
Every time I try to run it I'm getting this error:
Illegal instruction: 4
Here is my code:
section .text
global _main
_main:
mov rax, 4
mov rbx, 1
mov rcx, tekst
mov rdx, dlugosc
int 80h
mov rax, 1
int 80h
section .data
tekst db "Hello, world", 0ah
dlugosc equ $ - tekst
I'm compiling with:
nasm -f macho64 HelloWorld.asm
And I'm linking with:
ld -o HelloWorld -arch x86_64 -macosx_version_min 10.10 -lSystem -no_pie HelloWorld.o
Any help is highly appreciated.
Let's start with the most important thing:
On Mac OSX, system calls are preceded by an 0x2000###, so for an exit it would 0x2000001.
Next, we need to use the correct registers to pass arguments.
The number of the syscall has to be passed in register rax.
rdi - used to pass 1st argument to functions
rsi - used to pass 2nd argument to functions
rdx - used to pass 3rd argument to functions
rcx - used to pass 4th argument to functions
r8 - used to pass 5th argument to functions
r9 - used to pass 6th argument to functions
A system-call is done via the syscall instruction. The kernel destroys registers rcx and r11.
So bringing this together, a fixed version of your code is:
section .text
global _main
_main:
mov rax, 0x2000004
mov rdi, 1
mov rsi, tekst
mov rdx, dlugosc
syscall
mov rax, 0x2000001
syscall
section .data
tekst db "Hello, world", 0ah
dlugosc equ $ - tekst