0

我想在 MASM 中重现 C++ 代码的行为:

C++ 代码:

#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>

int                     _tmain(int ac, TCHAR **av)
{
    HANDLE              hFile;
    WIN32_FIND_DATA     findFileData;
    BOOL                retFindNextFile;

    if ((hFile = FindFirstFile(TEXT("C:\\Users\\Bloodsucker94\\Desktop\\TestFolder\\*.txt"), &findFileData)) == INVALID_HANDLE_VALUE)
    else {
        do {
            _tprintf(TEXT("%s\n"), findFileData.cFileName);
            retFindNextFile = FindNextFile(hFile, &findFileData);

        } while (retFindNextFile == TRUE);
    }
    getchar();
    return (EXIT_SUCCESS);
}

和 MASM 代码:

.386
.model                          flat, stdcall
option                          casemap :none

include                         \masm32\include\windows.inc
include                         \masm32\include\kernel32.inc
include                         \masm32\include\masm32.inc
include                         \masm32\include\masm32rt.inc
includelib                      \masm32\lib\kernel32.lib
includelib                      \masm32\lib\masm32.lib
include                         \masm32\include\msvcrt.inc
includelib                      \masm32\lib\msvcrt.lib

.data

FolderPath                      BYTE                        "C:\Users\Bloodsucker94\Desktop\TestASM\*.txt", 0
FindFirstFileError              BYTE                        "FindFirstFile() failed with code %d", 0
FindFirstFileSuccess            BYTE                        "First file found with success - hfile=%d", 0
PrintStructAddr                 BYTE                        "addr=Ox%08X", 0
PrintFileName                   BYTE                        "%s", 0

.data?

hFile                           HANDLE                      ?
findFileData                    WIN32_FIND_DATA             <>
retFindNextFile                 BOOL                        ?
ErrorCode                       DWORD                       ?

.code
start:

    ;--------------------------------------------------------

    invoke  FindFirstFile,      ADDR FolderPath,            \
                                ADDR findFileData

    mov     hFile,              eax

    .IF hFile == INVALID_HANDLE_VALUE
        invoke  GetLastError
        mov     ErrorCode,      eax
        invoke  crt_printf,     ADDR FindFirstFileError,    \
                                ErrorCode
        jmp                     _quit                                
    .ENDIF

    ;--------------------------------------------------------

    mov     ebx,                OFFSET findFileData
    mov     al,                 [ebx].WIN32_FIND_DATA.cFileName

    print   str$(findFileData.cFileName)
    ;print  str$([ebx].WIN32_FIND_DATA.cFileName)
    ;print  str$(al)

    ;INVOKE crt_printf,         ADDR PrintFileName,         \
    ;                           findFileData.cFileName

    ;--------------------------------------------------------

_quit:
    invoke  ExitProcess,        0

end start

目前,如您所见,我只想打印目录“TestASM”中的第一个文件名。在执行时 FindFirstFile() 似乎执行得很好,并且 hFile 句柄似乎也是正确的。但是我不明白为什么我所有的打印调用都会导致一个显示错误消息的消息框。我认为这是一个分段错误。但我尊重 C++ 代码行为。我徒劳地尝试了几种代码组合。

有人可以帮助我吗?

4

3 回答 3

1

你应该声明printf PROTO C :VARARG;

于 2013-03-15T00:05:56.483 回答
0

我用窗口日志(MessageBox)替换我的控制台日志,它可以工作。为什么我的控制台日志失败?但是,这是相同的数据!


你使用str$不正确。如果您查看它的定义(masm32\macros\macros.asm),您会发现它的作用是采用DWORD-size 整数,使用创建该整数的字符串表示(例如 123 -> "123")dwtoa,然后返回字符串的地址。

由于您正在尝试打印已经是字符串的内容,因此正确的方法是:

print   ADDR findFileData.cFileName


至于您看到的崩溃 - 您当前的代码 ( print str$(findFileData.cFileName)) 会发生什么,str$它将执行以下操作:

invoke dwtoa,findFileData.cFileName,ADDR rvstring

当 MASM 扩展此invoke宏并且在参数前面没有找到ADDR运算符时,它将按值传递该参数。在这种情况下,它将假定您正在尝试传递 的第一个元素findFileData.cFileName,即 a BYTE(或者WORD如果您使用的是宽字符串版本)。
所以实际上,这实际上将作为第一个参数推入堆栈:

mov al,findFileData.cFileName  ; al is set to the first character in the string
movzx ax,al
push ax   ; can't push bytes on x86 so the byte is extended to a word

由于dwtoa期望 aDWORD作为第一个参数并且您传递 aWORD时,您将在从 返回时得到一个不平衡的堆栈dwtoa,这可能导致各种不良行为(在这种情况下是崩溃)。

于 2013-03-15T20:38:42.790 回答
0

这没问题。

mov     ebx,                OFFSET findFileData
lea     eax,                 [ebx].WIN32_FIND_DATA.cFileName

print   eax 

这样做也是如此:

INVOKE crt_printf,         ADDR PrintFileName,         \
                           offset findFileData.cFileName

看到这段代码和你的代码之间的区别了吗?您需要传递字符串的地址。我们对第一个使用lea并使用偏移量printf

于 2013-03-16T03:22:27.537 回答