使用winapi链接Windows的64位“ Hello,world”

时间:2019-01-25 16:02:42

标签: winapi gcc assembly nasm x86-64

最近,我一直只是在尝试学习一些汇编程序,我认为Nasm是一个不错的选择,因为我更习惯于它的intel_syntax。无论如何,在故意尝试找到一些用于64位Windows的示例程序之后,我发现了this帖子,并尝试使用第二个答案提供的代码。唯一的问题是该代码是针对x86 Windows的,而不是我的目标平台。因此,我试图编写了用于64位Windows的程序(请注意单词试图)。我对Assembly很陌生,因此我的代码很可能是不正确的,如果有人指出此类错误,我将不胜感激。

但是,我遇到的问题是链接。出于某种原因,当我尝试链接目标文件时, gcc 链接器无法解析外部符号(即winapi函数),而且我无法弄清楚为什么这样做。

这是我的代码(我在每一行中都加了注释,以便我可以尝试了解程序在做什么,但是请随时编辑此帖子,并在错误的地方进行任何更改)。

section .text               ;Section of the src file that contains the actual runtime code
global WinMain@16           ;Makes the address WinMain global. @16 signifies 16 bytes of parameters

extern  _GetStdHandle@4     ;Assures compiler of an external definition of the declared function 'GetStdHandle()'
extern  _WriteFile@36       ;Assures compiler of an external definition of the declared function 'WriteFile()'
extern  _ExitProcess@4      ;Assures compiler of an external definition of the declared function 'ExitProcess()'

WinMain@16:                 ;Label marking the entry-point of the program (Windows expects 'WinMain' unless explicitly specified)
    mov rbp, rsp            ;Move Stack Pointer value equal to Base Pointer
    sub rsp, 4              ;Move Stack Pointer back (i.e. subtract) 4 bytes to store DWORD '-11' (defined by 'STD_OUTPUT_HANDLE')

    push -11                ;Push '-11' into stack
    call _GetStdHandle@4    ;Calls GetStdHandle(-11) since -11 has been pushed. @4 signifies 4 bytes of parameters
    mov rbx, rax            ;rax stores return value -> move that value to rbx

    push 0                  ;Push 0 (NULL) onto the stack (This is the last argument in the function)
    lea rax, [rbp - 4]      ;Store address of DWORD in rax register (4 byte value, 8 byte pointer)
    push rax                ;Push address of DWORD as the next parameter
    push (msg_end - msg)    ;Push number of bytes to write (3rd parameter)
    push msg                ;Push pointer to constant data bytes (2nd parameter)
    push rbx                ;Push value stored in 'rbx' (The HANDLE) into the 1st parameter
    call _WriteFile@36      ;Calls WriteFile(hStdOut, msg, msg_len, bytes_written, NULL). @36 signifies 36 bytes of parameters

    push 0                  ;Push 0 onto the stack (parameter)
    call _ExitProcess@4     ;Calls ExitProcess(0) and ends the program. @4 signifies 4 bytes of parameters

                ; ---- << Nothing gets called a beyond this line >> ---- ;

    hlt                     ;I have no clue why you need to halt here
    msg:                    ;Label marking the start of the message
        db "Hey world", 10  ;Actual data, (db = define bytes). "Hey world" and 10 (new-line character)
    msg_end:                ;Label marking the end of the message

要进行编译,请运行以下命令

nasm -f win64 Main.asm -o Main.bin

链接,我运行它并获得以下输出...

gcc -o Hello.exe Main.o
bin/Main.o:src/Main.asm:(.text+0xa): undefined reference to `_GetStdHandle@4'
bin/Main.o:src/Main.asm:(.text+0x21): undefined reference to `_WriteFile@36'
bin/Main.o:src/Main.asm:(.text+0x28): undefined reference to `_ExitProcess@4'
collect2.exe: error: ld returned 1 exit status

如您所见,它无法链接到外部函数,有趣的是,当我尝试调用“ puts”之类的“ c”函数时,它工作得很好

无论如何,如果您能在这里帮助我并指出我的代码中的任何错误,我将不胜感激。

0 个答案:

没有答案