Недавно я просто пытался изучить некоторую сборку и подумал, что Nasm будет хорошим выбором, так как я более привык к его intel_syntax. В любом случае, после преднамеренной попытки найти примеры программ для 64-битной Windows, я обнаружил этот SO пост и попытался использовать код, предоставленный во втором ответе. Единственное, что код был для 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
Как видите, он не может связываться с внешними функциями. Интересно то, что он прекрасно работает, когда я пытаюсь вызывать функции 'c', такие как 'put'
В любом случае, если бы вы могли помочь мне здесь и указать на любые ошибки в моем коде, я был бы очень признателен.