在nasm / Windows中打印argv [0]?

时间:2012-10-06 20:29:09

标签: windows assembly nasm argv

通过在线帮助,我能够在Mac OS X中编写nasm code,从而生成一个可执行文件,在同等的C代码中打印自己的文件名argv[0]。当我在Windows中使用相同的代码时,我希望它打印程序名称:

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

但实际打印的是空虚:

C:\> scriptname.exe
Program: 

规格:

  • golink 0.27.0.0
  • nasm 2.10.05
  • Windows 7 Professional x64
  • MacBook Pro 2009

3 个答案:

答案 0 :(得分:2)

argcargv参数仅适用于基于C的程序。基于程序集的程序必须使用C库中的__getmainargs__wgetmainargs函数来生成这些变量,就像它们由基于C的程序在内部使用一样。有关详细信息,请参阅以下MSDN文章:

http://msdn.microsoft.com/en-us/library/ff770599.aspx

答案 1 :(得分:1)

您调用GetStdHandle并将返回的值保存到ecx,ecx是一个易失性寄存器,除非您按下/弹出它,否则不会在调用中保存该值。你对WriteConsoleA的第一次调用就是使用它,然后再次打电话给下一次调用,ecx不是你所期望的。

*编辑* 我很无聊所以这里是工作代码:

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

答案 2 :(得分:0)

嗯,是的,不是。在Linux中,在_start:标签处,argc位于[esp]argv[0]位于[esp + 4]。如果您的代码有效,那么Mac OSX也必须如此。通过在ld命令行上执行-e main,基本上main就是它的名字。它不是真正的“C风格主力”。此标签被跳转到,而不是被称为。如果“C启动代码”(crt2.o)调用了main(或_main,对于'doze和Mac OSX),则堆栈上有一个返回地址,因此argc位于{{ 1}}和[esp + 4]位于argv[0]。另外,正如蒂姆在新闻中告诉你的那样:comp.lang.asm.x86 [esp + 8]是一个argv - 一个“指向指针的指针” - 所以你还需要**(一个“de” -参考”)。我很确定在Windows中,无论我们将入口点命名为什么,都会调用我们的代码。你能以这种方式工作吗?

编辑:嗯,这几乎被打死了,“解决了”(?),但我也感到无聊。这适用于Linux,“可能”是可移植的。

mov ebx, [ebx]