Open and write to file in assembly on mac - macos

I'm learning 32 bit assembly on mac, and I've have been trying to write to a file on my desktop. I used this code:
global _start
section .data
path: db "/Users/jackliu/Desktop/test.txt",0
string: db "hello",0
.len: equ $ - string
section .text
_start:
mov eax, 5
push dword 2
push dword path
sub esp, 8
int 0x80
add esp, 16
mov ebx, eax
mov eax, 4
push dword string.len
push dword string
push dword ebx
sub esp, 4
int 0x80
add esp, 16
mov eax, 1
push 0
sub esp, 12
int 0x80
The file is empty and it already exists on my desktop. After running it, it doesn't change the file at all.
Is there anything wrong with my code?

On MAC OS int 0x80 open system call is:
5 AUE_OPEN_RWTC ALL { int open(user_addr_t path, int flags, int mode); }
Your code passes 2 parameters:
mov eax, 5 ; Open system call = 5
push dword 2 ; Read/Write flag
push dword path ; Path
sub esp, 8 ; Alignment
int 0x80
Since you are opening an existing file specify a mode of 0 for the third parameter. Your code could look like this:
mov eax, 5 ; Open system call = 5
push dword 0 ; Mode = 0
push dword 2 ; Read/Write flag
push dword path ; Path
sub esp, 4 ; Reserved space for system call
int 0x80

Related

Assembly code isn't executing from terminal after I compiled. It shows up in the same folder? [duplicate]

The following program compiles without errors, but when run it doesn't prompt for any input and nothing prints. What's the problem, and how can I fix it?
I use these commands to assemble and link:
/usr/local/bin/nasm -f macho32 $1
ld -macosx_version_min 10.9.0 -lSystem -o run $filename.o -e _start -lc
My code is:
section .data
;New line string
NEWLINE: db 0xa, 0xd
LENGTH: equ $-NEWLINE
section .bss
INPT: resd 1
section .text
global _start
_start:
;Read character
mov eax, 0x3
mov ebx, 0x1
mov ecx, INPT
mov edx, 0x1
int 80h
;print character
mov eax, 0x4
mov ebx, 0x1
mov ecx, INPT
mov edx, 0x1
int 80h
;Print new line after the output
mov eax, 0x4
mov ebx, 0x1
mov ecx, NEWLINE
mov edx, LENGTH
int 0x80
;Terminate
mov eax, 0x1
xor ebx, ebx
int 0x80
There are signs in your code that you may have been using a Linux tutorial when producing code for OS/X(BSD). Linux and OS/X have differing SYSCALL calling conventions. In OS/X 32-bit programs int 0x80 requires parameters (except the syscall in EAX) to be passed on a stack.
The important things to be aware of with 32-bit SYSCALLs via int 0x80 on OS/X are:
arguments passed on the stack, pushed right-to-left
you must allocate an additional 4 bytes (a DWORD) on the stack after you push all the arguments
syscall number in the eax register
call by interrupt 0x80
After pushing arguments on the stack in reverse order for int 0x80 you must allocate an additional 4 bytes (a DWORD) on the stack. The value in that memory location on the stack doesn't matter. This requirement is an artifact from an old UNIX convention.
A list of the SYSCALL numbers and their parameters can be found in the APPLE header files. You'll need these SYSCALLs:
1 AUE_EXIT ALL { void exit(int rval); }
3 AUE_NULL ALL { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); }
4 AUE_NULL ALL { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); }
I have commented some example code that would be similar in functionality to what you may have been attempting to achieve:
section .data
;New line string
NEWLINE: db 0xa, 0xd
LENGTH: equ $-NEWLINE
section .bss
INPT: resd 1
global _start
section .text
_start:
and esp, -16 ; Make sure stack is 16 byte aligned at program start
; not necessary in this example since we don't call
; external functions that conform to the OS/X 32-bit ABI
push dword 1 ; Read 1 character
push dword INPT ; Input buffer
push dword 0 ; Standard input = FD 0
mov eax, 3 ; syscall sys_read
sub esp, 4 ; Extra 4 bytes on stack needed by int 0x80
int 0x80
add esp, 16 ; Restore stack
push dword 1 ; Print 1 character
push dword INPT ; Output buffer = buffer we read characters into
push dword 1 ; Standard output = FD 1
mov eax, 4 ; syscall sys_write
sub esp, 4 ; Extra 4 bytes on stack needed by int 0x80
int 0x80
add esp, 16 ; Restore stack
push dword LENGTH ; Number of characters to write
push dword NEWLINE ; Write the data in the NEWLINE string
push dword 1 ; Standard output = FD 1
mov eax, 4 ; syscall sys_write
sub esp, 4 ; Extra 4 bytes on stack needed by int 0x80
int 0x80
add esp, 16 ; Restore stack
push dword 0 ; Return value from program = 0
mov eax, 1 ; syscall sys_exit
sub esp, 4 ; Extra 4 bytes on stack needed by int 0x80
int 0x80
The and esp, -16 is only necessary if you need to align the stack to a 16-byte boundary as a baseline for future stack operations. If you intend to call external functions that conform to the OS/X 32-bit ABI the stack is expected to be 16-byte aligned immediately preceding a function CALL. This alignment is not necessary for system calls via int 0x80.
You should be able to assemble and link it with:
nasm -f macho32 test.asm -o test.o
ld -macosx_version_min 10.9.0 -o test test.o -e _start -lSystem
And run it with:
./test

Program will assemble and link but not run(ASM) on OSX [duplicate]

The following program compiles without errors, but when run it doesn't prompt for any input and nothing prints. What's the problem, and how can I fix it?
I use these commands to assemble and link:
/usr/local/bin/nasm -f macho32 $1
ld -macosx_version_min 10.9.0 -lSystem -o run $filename.o -e _start -lc
My code is:
section .data
;New line string
NEWLINE: db 0xa, 0xd
LENGTH: equ $-NEWLINE
section .bss
INPT: resd 1
section .text
global _start
_start:
;Read character
mov eax, 0x3
mov ebx, 0x1
mov ecx, INPT
mov edx, 0x1
int 80h
;print character
mov eax, 0x4
mov ebx, 0x1
mov ecx, INPT
mov edx, 0x1
int 80h
;Print new line after the output
mov eax, 0x4
mov ebx, 0x1
mov ecx, NEWLINE
mov edx, LENGTH
int 0x80
;Terminate
mov eax, 0x1
xor ebx, ebx
int 0x80
There are signs in your code that you may have been using a Linux tutorial when producing code for OS/X(BSD). Linux and OS/X have differing SYSCALL calling conventions. In OS/X 32-bit programs int 0x80 requires parameters (except the syscall in EAX) to be passed on a stack.
The important things to be aware of with 32-bit SYSCALLs via int 0x80 on OS/X are:
arguments passed on the stack, pushed right-to-left
you must allocate an additional 4 bytes (a DWORD) on the stack after you push all the arguments
syscall number in the eax register
call by interrupt 0x80
After pushing arguments on the stack in reverse order for int 0x80 you must allocate an additional 4 bytes (a DWORD) on the stack. The value in that memory location on the stack doesn't matter. This requirement is an artifact from an old UNIX convention.
A list of the SYSCALL numbers and their parameters can be found in the APPLE header files. You'll need these SYSCALLs:
1 AUE_EXIT ALL { void exit(int rval); }
3 AUE_NULL ALL { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); }
4 AUE_NULL ALL { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); }
I have commented some example code that would be similar in functionality to what you may have been attempting to achieve:
section .data
;New line string
NEWLINE: db 0xa, 0xd
LENGTH: equ $-NEWLINE
section .bss
INPT: resd 1
global _start
section .text
_start:
and esp, -16 ; Make sure stack is 16 byte aligned at program start
; not necessary in this example since we don't call
; external functions that conform to the OS/X 32-bit ABI
push dword 1 ; Read 1 character
push dword INPT ; Input buffer
push dword 0 ; Standard input = FD 0
mov eax, 3 ; syscall sys_read
sub esp, 4 ; Extra 4 bytes on stack needed by int 0x80
int 0x80
add esp, 16 ; Restore stack
push dword 1 ; Print 1 character
push dword INPT ; Output buffer = buffer we read characters into
push dword 1 ; Standard output = FD 1
mov eax, 4 ; syscall sys_write
sub esp, 4 ; Extra 4 bytes on stack needed by int 0x80
int 0x80
add esp, 16 ; Restore stack
push dword LENGTH ; Number of characters to write
push dword NEWLINE ; Write the data in the NEWLINE string
push dword 1 ; Standard output = FD 1
mov eax, 4 ; syscall sys_write
sub esp, 4 ; Extra 4 bytes on stack needed by int 0x80
int 0x80
add esp, 16 ; Restore stack
push dword 0 ; Return value from program = 0
mov eax, 1 ; syscall sys_exit
sub esp, 4 ; Extra 4 bytes on stack needed by int 0x80
int 0x80
The and esp, -16 is only necessary if you need to align the stack to a 16-byte boundary as a baseline for future stack operations. If you intend to call external functions that conform to the OS/X 32-bit ABI the stack is expected to be 16-byte aligned immediately preceding a function CALL. This alignment is not necessary for system calls via int 0x80.
You should be able to assemble and link it with:
nasm -f macho32 test.asm -o test.o
ld -macosx_version_min 10.9.0 -o test test.o -e _start -lSystem
And run it with:
./test

Assembly under Mac OS X: Find files in a directory / read content of a directory using syscalls

How can I read the content of a directory in assembly under Mac OS X using syscalls? I tried opening the directory with the following:
;; Open the current working directory for reading
;;
push dword 0 ; O_RDONLY (Mode = 0) as directory already exists
push dword 0 ; flags
push dword testdir ; Defined in .data as: testdir db "test", 0
mov eax, 0x05 ; Open system call
sub esp, 4 ; OS X (and BSD) system calls need extra space on stack
int 0x80
jc exit_error_after_call_16
add esp, byte 16 ; 3 args * 4 bytes/arg + 4 bytes extra space = 16 bytes
I then tried to access the content of the directory reading the file content (all directories are files as well?) into a buffer.
push dword MAXFNAMELEN ; input length
push dword tempFName ; buffer
push dword eax ; file descriptor value
mov eax, 0x03 ; Execute read system call
sub esp, 4
int 0x80
add esp, byte 16
; Check if file could be read without error or EOF
jc exit_error ; CF set = error --> exit
test eax, eax
jz exit_noerror ; If EAX is 0 then EOF reached (stack breakdown at exit)
Then I tried printing the buffer for debugging, but don't get content:
push dword eax ; The length of the buffer to print
push dword tempFName ; The buffer to print
push dword 1 ; File descriptor value
mov eax, 0x04
sub esp, 4
int 0x80
add esp, byte 16
Any idea? Also, in good old DOS times there were two DOS functions FindFirst (0x4E) and FindNext. Is there any equivalent in syscalls?
Thanks for helping.

Why does this code not retrieve a valid file handle?

Complete source:
SECTION .data ; initialized data
SEEK_SET dd 0;
SEEK_CUR dd 1;
SEEK_END dd 2;
fname: db "d:\asmplus\tsources\s1.txt", 0
fread: db "r", 0
mopf: db "open", 0
mskf: db "seek", 0
mcld: db "[FILE] call [%s]: %d", 10, 0
mcls: db "[FILE] call [%s]: %s", 10, 0
merr: db "[FILE] error opening %s", 10, 0
mret: db "[FILE] ret [%s]: %d", 10, 0
SECTION .text ; code
extern _fopen
extern _fseek
extern _printf
global _main
_main:
; stash base stack pointer
push ebp
mov ebp, esp
push DWORD fname
push DWORD mopf
push DWORD mcls
call _printf
add esp, 12
; open file
push DWORD fread
push DWORD fname
call _fopen
add esp, 8
mov [fh], eax
; output result
push DWORD [fh]
push DWORD mopf
push DWORD mret
call _printf
add esp, 12
push DWORD [fh]
push DWORD mskf
push DWORD mcld
call _printf
add esp, 12
; C:
; fseek(fp, 0L, SEEK_END); ; set up constants: SEEK_END, SEEK_SET, etc.
push DWORD SEEK_END
push DWORD 0
push DWORD [fh] ; file handle
call _fseek ; ret [eax]: 0 okay; otherwise nz
add esp, 12 ; reset stack pointer
; output result
push DWORD eax
push DWORD mskf
push DWORD mret
call _printf
add esp, 12
;; NEXT: sz = ftell(fp); ; result to eax
.done:
; restore base stack pointer
mov esp, ebp
pop ebp
ret
SECTION .bss ; uninitialized data
fh: resd 1
Output when provided a valid file name:
[FILE] call [open]: d:\asmplus\tsources\s1.txt
[FILE] ret [open]: 2002397536
[FILE] call [seek]: 2002397536
[FILE] ret [seek]: -1
The 2nd & 3rd lines should display a file handle. What I see does not look right and would be why the seek return is -1. What am I doing wrong to open the file?

Diagonal Output of Assembly program

I have this assembly program and I want diagonal output of this program but I dont know how to put tabspace in assembly.
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
mov edx, len ;message length
mov ecx, msg ;message to write
mov ebx, 1 ;file descriptor (stdout)
mov eax, 4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax, 1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db 'Y',10,'O',10,'U',10,'S',10,'U',10,'F' ;our dear string
len equ $ - msg ;length of our dear string
Output of my program is:
Y
O
U
S
U
F
Output should like this:
Y
O
U
S
U
F
Is there any other way to write this program and get this output?
is there an other way to do this
Of course there is! You can do it anyway that you want! Since you say you are using Windows, but are using Linux Interrupts, this code is OS Neutral (meaning it will work on Windows or Linux)
extern exit, printf, malloc, free
global main
section .data
szText db "Gunner Diagonally!!"
Text_Len equ $ - szText
fmtstr db "%s", 10, 0
section .text
main:
push Text_Len
push szText
call PrintDiagonal
call exit
;~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;~ PrintDiagonal - Prints text to terminal diagonally
;~ In: esp + 4 = address of text to print
;~ esp + 8 = length of string to print
;~ Returns - Nothing
;~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PrintDiagonal:
%define Text_ dword [ebp + 8]
%define TextLen_ dword [ebp + 12]
%define _Buffer dword [ebp - 4]
%define _SpaceCount dword [ebp - 8]
%define _CurLine dword [ebp - 12]
push ebp
mov ebp, esp
sub esp, 4 * 3
mov eax, TextLen_
add eax, eax
push eax
call malloc
add esp, 4 * 1
mov _Buffer, eax
mov _SpaceCount, 1
mov _CurLine, 1
mov esi, Text_
.NextLine:
mov edi, _Buffer
mov edx, _SpaceCount
dec edx
jz .SpaceDone
.SpaceStart:
mov ecx, _SpaceCount
dec ecx
.FillSpaces:
mov byte [edi], 32
inc edi
dec ecx
jnz .FillSpaces
.SpaceDone:
mov al, byte [esi]
mov byte [edi], al
mov byte [edi + 1], 0
push _Buffer
push fmtstr
call printf
add esp, 4 * 2
inc esi
add _SpaceCount, 2
mov edx, TextLen_
inc _CurLine
cmp _CurLine, edx
jng .NextLine
push _Buffer
call free
add esp, 4 * 1
leave
ret 4 * 2
There is no error checking, of course you would add your own.
We take the string and add the correct spaces in a loop then print.
You could put in your msg
msg db 'Y',10,9,'O',10,9,9,'U',10,9,9,9,'S',10,9,9,9,9,'U',10,9,9,9,9,9,'F' ;our dear string
9 is ascii for tab.
Only Windows (because of DOS legacy) has separated CR (carriage return) that moves the carriage at X position 0, and LF (line feed) that moves one line down without changing the carriage X position.
In Linux LF only is used and it do both: moves the carriage down and left to 0.
In order to have the same diagonal output in Linux, you should cheat a little:
; replace dots with spaces.
msg db 'Y',10,'.O',10,'..U',10,'...S',10,'....U',10,'.....F'

Resources