0

借助在线帮助,我能够在 Mac OS X 中编写nasm 代码argv[0],从而生成一个可执行文件,该可执行文件以等效的 C 代码打印其自己的文件名。当我在 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 专业版 x64
  • MacBook Pro 2009
4

3 回答 3

2

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

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

于 2012-10-07T07:36:34.167 回答
2

您调用 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>
于 2012-10-08T02:08:10.660 回答
0

嗯,是的,也不是。在 Linux 中,在_start:标签处,argc是 at[esp]argv[0]is at [esp + 4]。如果您的代码有效,那么 Mac OSX 也必须如此。通过-e main在 ld 命令行上做,本质上main是在谎报它的名字。它不是真正的“C 风格的主要”。这个标签被跳转到,而不是被调用。如果main(或 _main,对于 'doze 和 Mac OSX)被“C 启动代码”(crt2.o)调用,那么堆栈上有一个返回地址,所以argcis at[esp + 4]argv[0]is at [esp + 8]。此外,正如 Tim 在新闻中告诉你的那样:comp.lang.asm.x86argv是一个**- “指向指针的指针” - 所以你还需要mov ebx, [ebx](“取消引用”)。我很确定在 Windows 中,无论我们如何命名入口点,都会调用我们的代码。你能让它这样工作吗?

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

;  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
;----------------------
于 2012-10-07T18:20:27.760 回答