Printing argv[0] in nasm/Windows? - 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
;----------------------

Related

OSX assembly questions [duplicate]

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.

How to get length of long strings in x86 assembly to print on assertion

I am trying to build an x86 program that reads a file into memory. It uses a few different syscalls, and messes with memory and such. There's a lot in there to figure out.
To simplify debugging and figuring this out, I wanted to add assert statements which, if there's a mismatch, it prints out a nice error message. This is the first step in learning assembly so I can print the numbers and strings that get placed on different registers and such after operations. Then I can print them out and debug them without any fancy tools.
Wondering if one could help me write an ASSERT AND PRINT in NASM for Mac x86-64. I have this so far:
%define a rdi
%define b rsi
%define c rdx
%define d r10
%define e r8
%define f r9
%define i rax
%define EXIT 0x2000001
%define EXIT_STATUS 0
%define READ 0x2000003 ; read
%define WRITE 0x2000004 ; write
%define OPEN 0x2000005 ; open(path, oflag)
%define CLOSE 0x2000006 ; CLOSE
%define MMAP 0x2000197 ; mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t offset)
%define PROT_NONE 0x00 ; no permissions
%define PROT_READ 0x01 ; pages can be read
%define PROT_WRITE 0x02 ; pages can be written
%define PROT_EXEC 0x04 ; pages can be executed
%define MAP_SHARED 0x0001 ; share changes
%define MAP_PRIVATE 0x0002 ; changes are private
%define MAP_FIXED 0x0010 ; map addr must be exactly as requested
%define MAP_RENAME 0x0020 ; Sun: rename private pages to file
%define MAP_NORESERVE 0x0040 ; Sun: don't reserve needed swap area
%define MAP_INHERIT 0x0080 ; region is retained after exec
%define MAP_NOEXTEND 0x0100 ; for MAP_FILE, don't change file size
%define MAP_HASSEMAPHORE 0x0200 ; region may contain semaphores
;
; Assert equals.
;
%macro ASSERT 3
cmp %1, %2
jne prepare_error
prepare_error:
push %3
jmp throw_error
%endmacro
;
; Print to stdout.
;
%macro PRINT 1
mov c, getLengthOf(%1) ; "rdx" stores the string length
mov b, %1 ; "rsi" stores the byte string to be used
mov a, 1 ; "rdi" tells where to write (stdout file descriptor: 1)
mov i, WRITE ; syscall: write
syscall
%endmacro
;
; Read file into memory.
;
start:
ASSERT PROT_READ, 0x01, "Something wrong with PROT_READ"
mov b, PROT_READ
mov a, PROT_WRITE
xor a, b
mov f, 0
mov e, -1
mov d, MAP_PRIVATE
mov c, a
mov b, 500000
mov a, 0
mov i, MMAP
syscall
PRINT "mmap output "
PRINT i ; check what's returned
PRINT "\n"
mov e, i
mov b, O_RDONLY
mov a, "Makefile"
mov i, OPEN
syscall
mov a, i
mov b, e
mov i, READ
syscall
;
; Exit status
;
exit:
mov a, EXIT_STATUS ; exit status
mov i, EXIT ; syscall: exit
syscall
throw_error:
PRINT pop() ; print error or something
jmp exit
mov rsi, "abcdefgh" is a mov-immediate of the string contents, not a pointer to it. It only exists as an immediate if you do that.
Your macro will need to switch to .rodata and back to put the string in memory; possibly you could turn it into a sequence of push-immediate onto the stack with NASM macros, but that sounds hard.
So you can use the usual msglen equ $ - msg to get the length. (Actually using NASM local labels so the macro doesn't create conflicts).
See NASM - Macro local label as parameter to another macro where I wrote basically this answer a couple weeks ago. But not exactly a duplicate because it didn't have the bug of using the string as an immediate.
NASM's mechanism for letting macros switch sections and then return to whatever section they expanded in is to have section foo define a macro __?SECT?__ as [SECTION foo]. See the manual and the above linked Q&A.
; write(1, string, sizeof(stringarray))
; clobbers: RDI, RSI, RDX, RCX,R11 (by syscall itself)
: output: RAX = bytes written, or -errno
%macro PRINT 1
[section .rodata] ; change section without updating __?SECT?__ macro
;; NASM macro-local labels
%%str db %1 ; put the string in read-only memory
%%strln equ $ - %%str ; current position - string start
__?SECT?__ ; change back to original sectoin
mov edx, %%strlen ; len
lea rsi, [rel %%str] ; buf = the string. (RIP-relative for position-independent)
mov edi, 1 ; fd = stdout
mov eax, WRITE
syscall
%endmacro
This doesn't attempt to combine duplicates of the same string. Using it many times with the same message will be inefficient. This doesn't matter for debugging.
I could have left your %defines for RDI, and let NASM optimize mov rdi, 1 (7 bytes) into mov edi, 1 (5 bytes). But YASM won't do that so it's better to make it explicit if you care about anyone building your code with YASM.
I used a RIP-relative LEA because that's the most efficient way to put a static address into a register in position-independent code. In Linux non-PIE executables, use mov esi, %%str (5 bytes and can run on any port, more than LEA). But on OS X, the base virtual address where an executable is mapped/loaded is always above 2^32, and you never want mov r64, imm64 with a 64-bit absolute address.
See How to load address of function or label into register
On Linux, where system-call numbers are small integers, you could use lea eax, [rdi-1 + WRITE] to do eax = SYS_write with a 3 byte instruction vs. 5 for mov.
The standard names for call-number constants are POSIX SYS_foo from sys/syscall.h or Linux __NR_foo from asm/unistd.h. But NASM can't #include C preprocessor #define macros, so you'd need to mechanically convert one of those headers to NASM syntax, e.g. with some script.
Or if manually defining names, just choose %define SYS_write 1

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

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