mcandre
mcandre

Reputation: 24602

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 - [email protected]
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:

Upvotes: 0

Views: 2199

Answers (3)

Frank Kotler
Frank Kotler

Reputation: 1452

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
;----------------------

Upvotes: 0

Gunner
Gunner

Reputation: 5884

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>

Upvotes: 2

Jay
Jay

Reputation: 4686

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

Upvotes: 2

Related Questions