OSX assembly questions [duplicate] - macos

This question already has answers here:
Assembly Linux system calls vs assembly OS x system calls
(1 answer)
Why syscall doesn't work?
(2 answers)
User input and output doesn't work in my assembly code
(1 answer)
Closed 2 years ago.
I have written x32 hello world on osx.
section .data ; .data section declaration
hello_text db "Hello, World!",10 ; declared "Hello, World!\n" as bytes
hello_length equ $ - hello_text ; length of hello_bytes in hex
section .text ; .text section declaration
global _main
_main:
push dword hello_length ; push length of the string to stack
push dword hello_text ; push pointer to string to stack
push dword 1 ; push stdout (1) to stack
mov eax, 4 ; syscall - write
sub esp, 4 ; subtract 4 bytes from stack pointer (move)
int 0x80 ; interrupt (call kernel)
add esp, 16 ; why we moving pointer?
push dword 0 ; set exit call param
mov eax, 1 ; syscall - exit
sub esp, 12 ; why?
int 0x80 ; interrupt (call kernel)
Can anyone please explain why we have to push arguments to stack and what exactly we are doing with stack pointer in above program?
Initially I did this, but it didn't work.
mov eax, 4
mov ebx, 1
mov ecx, userMsg
mov edx, lenUserMsg
int 80h
Is it osx or bsd conventions?
Another question is regarding x64 hello world.
_main:
mov rax, 0x2000004 ; syscall - write
mov rdi, 1 ; write stdout
mov rsi, hello_text ; string pointer to stack pointer
mov rdx, hello_length ; string length to data register
syscall ; call kernel
mov rax, 0x2000001 ; syscal - exit
mov rdi, 0 ; exit argument (return 0)
syscall ; call kernel
Why we using registers rsi / rsi instead of ebx / ecx?
If that's mac / bsd specific, can anyone point me to documentation pls.

Related

Segmentation fault when adding 2 digits - nasm MacOS x86_64

I am trying to write a program that accepts 2 digits as user input, and then outputs their sum. I keep getting segmentation error when trying to run program(I am able to input 2 digits, but then the program crashes). I already check answers to similar questions and many of them pointed out to clear the registers, which I did, but I am still getting a segmentation fault.
section .text
global _main ;must be declared for linker (ld)
default rel
_main: ;tells linker entry point
call _readData
call _readData1
call _addData
call _displayData
mov RAX, 0x02000001 ;system call number (sys_exit)
syscall
_addData:
mov byte [sum], 0 ; init sum with 0
lea EAX, [buffer] ; load value from buffer to register
lea EBX, [buffer1] ; load value from buffer1 to register
sub byte [EAX], '0' ; transfrom to digit
sub byte [EBX], '0' ; transform to digit
add [sum], EAX ; increment value of sum by value from register
add [sum], EBX ; increment value of sum by value from 2nd register
add byte [sum], '0' ; convert to ASCI
xor EAX, EAX ; clear registers
xor EBX, EBX ; clear registers
ret
_readData:
mov RAX, 0x02000003
mov RDI, 2
mov RSI, buffer
mov RDX, SIZE
syscall
ret
_readData1:
mov RAX, 0x02000003
mov RDI, 2
mov RSI, buffer1
mov RDX, SIZE
syscall
ret
_displayData:
mov RAX, 0x02000004
mov RDI, 1
mov RSI, sum
mov RDX, SIZE
syscall
ret
section .bss
SIZE equ 4
buffer: resb SIZE
buffer1: resb SIZE
sum: resb SIZE
I see that, unlike other languages I learned, it is quite difficult to find a good source /tutorial about programming assembly using nasm on x86_64 architecture. Is there any kind of walkthrough for beginners(so I do not need to ask on SO everytime I am stuck :D)

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

Reading from STDIN and printing to STDOUT with nasm assembly?

As the title suggest I seem to be having a hard time converting the below code to do the exact same thing, which is to read from stdin and stdout. My professor wants us to stop using int 80h and switch over to using gcc. I've had no problems with reading input with the below code however, switching over to gcc is where I start getting segmentation core dump errors.
section .bss
buf resb 1 ; 1000-byte buffer (in data section)
section .text
global _start
_start:
loop1: mov edx, 1 ; max length
mov ecx, buf ; buffer
mov ebx, 0 ; stdin
mov eax, 3 ; sys_read
int 80h
cmp eax, 0 ; end loop if read <= 0
jle lpend1
mov edx, eax ; length
mov ecx, buf ; buffer
mov ebx, 1 ; stdout
mov eax, 4 ; sys_write
int 80h
jmp loop1 ; go back for more
lpend1:
mov eax, 1
mov ebx, 0
int 80h
My attempt at converting the above to perform the same task
SECTION .data
format: db "%c",0
SECTION .bss
buff: resb 1
SECTION .text
extern printf
extern scanf
global main
main:
loop1:
push buff ;buff will hold the characters in the string/file
push format ;expect character for every buff
call scanf
add esp, 8 ;clear stack
cmp eax, 0 ;if eax is equal to 0 then EOF
je lpend1 ;jump to end main func
xor eax, eax ;clear eax
mov eax, buff ;mov buff to eax register
push eax ;push eax onto the stack
mov eax, format ;mov the string format to eax
push eax ;push onto the stack
call printf ;call printf, prints to screen
add esp, 8 ;clear the stack
jmp loop1 ;jump back to top and repeat
lpend1:
ret ;end of main

Printing argv[0] in nasm/Windows?

With online help, I was able to write nasm code in Mac OS X resulting in an executable that prints its own filename, argv[0] in equivalent C code. When I use the same code in Windows, I want it to print the programs name:
C:\> nasm -f win32 -o scriptname.obj scriptname.asm
C:\> golink /fo scriptname.exe scriptname.obj /console kernel32.dll Msvcrt.dll
GoLink.Exe Version 0.27.0.0 - Copyright Jeremy Gordon 2002/12 - JG#JGnet.co.uk
Output file: scriptname.exe
Format: win32 size: 2,048 bytes
C:\> scriptname.exe
Program: scriptname.exe
But what it actually prints is emptiness:
C:\> scriptname.exe
Program:
Specs:
golink 0.27.0.0
nasm 2.10.05
Windows 7 Professional x64
MacBook Pro 2009
You call GetStdHandle and save the returned value to ecx, ecx is a volatile register, the value will not be saved across calls unless you push/pop it. Your first call to WriteConsoleA uses it and clobbers it so the next call, ecx is not what you expect.
* EDIT *
I was bored so here is working code:
[bits 32]
section .data
program db "Program: ", 0
programlen equ $-program
nl db "", 13, 10, 0
nllen equ $-nl
section .bss
buf resd 1
argc resd 1
argv resb 255
section .text
global Start
extern GetStdHandle
extern __getmainargs
extern WriteConsoleA
extern ExitProcess
strlen: ; eax: a string ending in 0
push eax ; cache eax
.strloop:
mov bl, byte [eax]
cmp bl, 0
je .strret ; return len if bl == 0
inc eax ; else eax++
jmp .strloop
.strret:
pop ebx ; ebx = cached eax
sub eax, ebx ; eax -= ebx
ret ; eax = len
Start:
push 0
push buf
push argv
push argc
call __getmainargs
add esp, 16 ; clear stack (4 * 4 arguments)
push -11 ; get stdout
call GetStdHandle
mov esi, eax
add esp, 4 ; clear stack (4 * 1 argument)
push 0 ; null
push buf ; [chars written]
push programlen
push program
push esi ; stdout
call WriteConsoleA
add esp, 20 ; clear stack (4 * 5 arguments)
mov edx, [argv]
mov eax, [edx] ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
call strlen
push 0 ; null
push buf ; [chars written]
push eax ; len argv[0]
push dword [edx] ;<<<<<<<<<<<<<<<<<<<<<<<<<<<< ; argv[0]
push esi ; stdout
call WriteConsoleA
add esp, 20 ; clear stack (4 * 5 arguments)
push 0 ; null
push buf ; [chars written]
push nllen
push nl
push esi ; stdout
call WriteConsoleA
add esp, 20 ; clear stack (4 * 5 arguments)
push 0
call ExitProcess
D:\NASM Projects\ReadArgs>ReadArgs.exe
Program: ReadArgs.exe
D:\NASM Projects\ReadArgs>
The argc and argv arguments are for C based programs only. Assembly based programs are must use __getmainargs or __wgetmainargs functions from the C library to generate those variables like they are internally used by C based programs. See below MSDN article for details:
http://msdn.microsoft.com/en-us/library/ff770599.aspx
Well, yes and no. In Linux, at the _start: label, argc is at [esp] and argv[0] is at [esp + 4]. If your code works, this must also be true of Mac OSX. By doing -e main on the ld command line, essentially main is lying about its name. It isn't really a "C style main". This label is jumped to, not called. If main (or _main, for 'doze and Mac OSX) is called by "C startup code" (crt2.o), then there's a return address on the stack, so argc is at [esp + 4] and argv[0] is at [esp + 8]. Also, as Tim tells you at news:comp.lang.asm.x86 argv is a ** - a "pointer to pointer" - so you also need the mov ebx, [ebx] (a "de-reference"). I'm pretty sure in Windows, our code is called regardless of what we name the entrypoint. Can you get it to work that way?
EDIT: Well this has pretty much been beaten to death, and "solved"(?), but I got bored, too. This works in Linux, and "might" be portable.
; prints its own name (possibly portable?)
; nasm -f elf32 myprog.asm
; nasm -f macho myprog.asm --prefix _
; nasm -f win32 myprog.asm --prefix _
; gcc -o myprog myprog.o(bj) (-m32 for 64-bit systems)
global main
extern printf
section .data
prog db `Program: %s \n`, 0
section .text
main:
mov eax, [esp + 8]
mov eax, [eax]
push eax
push prog
call printf
add esp, 4 * 2
ret
;----------------------

Resources