Запуск приложения Win32, написанного на NASM, приводит к ошибке «Это приложение не может быть запущено на вашем ПК»

#assembly #x86 #mingw #nasm #ld

# #сборка #x86 #mingw #nasm #ld

Вопрос:

Я начинаю изучать сборку x86 в Windows. Я изучаю 32-разрядную сборку x86. Я использую nasm и ld для компиляции своих программ. Я использую mingw32-make makefile в качестве моей системы сборки. Я предполагаю ld , что оно включено в MinGW, но я не уверен в этом. Все, что я знаю, это то, что оно уже было на моем компьютере.

Я хотел скомпилировать очень простую программу, чтобы убедиться, что все работает, и, конечно, это не так. При запуске моего исполняемого файла появилось гигантское синее окно с надписью «Это приложение не может быть запущено на вашем ПК», и после закрытия уведомления слова Access is denied были напечатаны на моем терминале.

Это моя программа:

 global _main

_main:
  mov eax, 1
  ret
 

И это мой makefile:

 main: learn.asm
    nasm -f win32 learn.asm -o learn.o
    ld learn.o -o learn.exe
 

Может кто-нибудь помочь мне исправить это?

Комментарии:

1. Вы уверены, что это не просто сбой, как и должно быть? Вам необходимо завершить работу программы. В Windows, я полагаю, вы можете просто ret .

2. Не могли бы вы предоставить код в качестве ответа?

3. Просто вставьте ret after mov eax, 1 .

4. @Jester не работает: (

5. Есть ли в вашей среде file команда? Что он скажет, если вы запустите file learn.exe ?

Ответ №1:

Первоначально в вашем вопросе задавался вопрос об использовании _start в качестве точки входа. Способ, которым вы связывали, не включал среду выполнения C.

В некоторых версиях Windows вы можете получить ошибку This app cant run on your pc при соединении с MinGW LD, если .rdata при некоторых обстоятельствах нет раздела (данные только для чтения). Одним из обстоятельств является исполняемый файл с .idata разделом (каталог импорта), на который не ссылается заголовок, и который не содержит .rdata раздела. Похоже, это тот случай, когда компоновщик MinGW LD создает исполняемый файл из вашего кода, когда не используется среда выполнения C. Чтобы устранить проблему, добавьте .rdata раздел с хотя бы одним байтом данных. Это должно сработать:

 global _start

section .rdata
db 0

section .text
_start:
    mov eax, 1
    ret 
 

Вам также необходимо разместить свой код в этом .text разделе, иначе вы можете столкнуться с другими проблемами. Затем вы можете собрать и связать с:

 nasm -fwin32 learn.asm -o learn.obj
ld -o learn.obj -o learn.exe
 

Если вы хотите использовать _main и намерены использовать среду выполнения C, то вам не нужно создавать .rdata раздел, однако вы могли бы собрать и связать с:

 nasm -fwin32 learn.asm -o learn.obj
gcc -m32 learn.obj -o learn.exe
 

Моя рекомендация по связыванию

В качестве альтернативы вы можете использовать компоновщик, отличный от LD. GoLink, в частности, должен сгенерировать исполняемый файл из используемого вами кода. Вы можете создать консольное приложение Win32 с точкой _start входа таким образом:

 nasm -fwin32 learn.asm -o learn.obj
golink /console /entry _start learn.obj
 

GoLink создаст исполняемый файл с соответствующими заголовками и разделами, с которыми у Windows не должно возникнуть проблем при запуске без необходимости добавления .rdata раздела.

Если у вас установлен MSVC / C , вы также можете использовать компоновщик Microsoft:

 nasm -fwin32 learn.asm -o learn.obj
link learn.obj /entry:start /subsystem:console
 

Комментарии:

1. Фоном, похоже, является раздел «.idata» (который, кстати, не должен называться «.idata»): если ld используется так, как это сделал OP, код запуска не используется, поэтому точка входа _main (или _start , если функция названатаким образом). Поскольку программа должна вызывать ОС (по крайней мере, для exit редактирования), а единственная надежная (и разрешенная) возможность вызова ядра Windows — это использование DLL, программа должна использовать DLL. Возврат using ret из кода точки входа не разрешен ни в Windows, ни в Linux.

2. @MartinRosenau: процесс Win32 может завершиться, если основной поток возвращается со ret значением, если и только если основной поток является единственным активным потоком.

3. Если загрузчик Windows когда-либо создавал более одного потока, возможно, это ret не приведет к завершению процесса. Общее эмпирическое правило, однако, чтобы избежать этой проблемы, нужно вызвать ExitProcess . Я сам не из тех, кто использует ret подобное.

4. Интересно. Однако я заметил, что многие версии Windows отказывались загружать исполняемый файл, если в разделе импорта не было указано ни одного DLL-файла. Windows Vista или Windows 7 (я не уверен) просто ничего не делает, если EXE-файл не содержит импорта: код не выполняется, но программа возвращается сразу. Вы можете проверить это, запрограммировав бесконечный цикл или некоторый код, который вызывает исключение. Я могу себе представить, что Windows 10 печатает сообщение об ошибке, указанное в вопросе, вместо того, чтобы «молча» ничего не делать.