Как скомпилировать сборку Hello World в Windows?

#windows #visual-studio #assembly #masm

Вопрос:

Имея такую простую assembly Win 32 программу:

 .386
.model flat, stdcall
option casemap :none

EXTERN printf :PROC ; declare printf

.data
    HelloWorld db "Hello Wolrd!:-)", 0

.code
start:
  sub esp, 4
  push offset HelloWorld
  call printf
  add esp, 4
  ret
end start
 

Я могу успешно скомпилировать его, просто:

 ml.exe /c HelloWorld.asm
 

НО у меня есть проблема с его связыванием. Когда я использую:

 link HelloWorld.obj libcmt.lib
 

Я получаю сообщение об ошибке:

 unresolved external symbol _main called in _mainCRTStartup
 

Что я должен изменить/исправить, чтобы успешно связать программу для ее запуска?

P.S.

Пожалуйста, не говорите мне, чтобы я использовал только nasm . Я хотел бы использовать ml amp; link из моего MSVC.

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

1. Разве это не должно быть ml.exe /c /coff HelloWorld.asm , link /SUBSYSTEM:CONSOLE HelloWorld.obj libcmt.lib ?

2. @Michael Я попробовал Ваше предложение, но все еще с той же ошибкой компоновщика.:-(..

3. Никто не скажет вам использовать NASM; он не смог собрать этот файл, в котором используется синтаксис / директивы MASM. И NASM-это просто ассемблер, в любом случае он не поставляется с компоновщиком.

Ответ №1:

С некоторыми незначительными изменениями это теперь строится правильно.

 .386    
.model flat, c
option casemap :none

includelib libcmt.lib
includelib legacy_stdio_definitions.lib

EXTERN printf :PROC ; declare printf

.data
    HelloWorld db "Hello World!:-)", 0

.code
main PROC
  push offset HelloWorld
  call printf
  add esp, 4
  ret
main ENDP
END
 

Основными изменениями являются

  • .model flat, c устанавливает соглашения о вызовах для процедур на C.
    Если вы решите сохранить .model flat, для этого потребуется внести эти изменения.

Заменять

 EXTERN printf :PROC

main PROC 
 

с

 printf PROTO NEAR C,:DWORD

main PROC NEAR C    
 
  • Включены libcmt.lib и legacy_stdio_definitions.lib, которые статически связывают запуск собственной среды выполнения C с вашим кодом.
  • Изменена точка входа с начальной на основную. В библиотеке C-Runtime (CRT) libcmt.lib есть точка входа (_mainCRTStartup), которая выполняет некоторые задачи инициализации, а затем передает управление точке входа для основного приложения. Вы можете изменить точку входа по умолчанию, но обычно вам нужно удобство инициализации, которую точка входа CRT выполняет для вас автоматически.
  • Удален первый дополнительный esp,4,поэтому оставшийся один толчок уравновешивается дополнительным esp, 4, поэтому ESP указывает на обратный адрес при запуске ret.

Для сборки откройте командную строку Windows и запустите:

 "C:Program Files (x86)Microsoft Visual Studio2019ProfessionalVCAuxiliaryBuildvcvars32.bat"
 

чтобы установить среду MSVC, инициализированную для: ‘x86’

Затем выполните следующие команды MASM

 ml.exe /c /coff HelloWorld.asm

link.exe /SUBSYSTEM:console HelloWorld.obj
 

Программа отображает

Привет, Мир!:-)

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

1. Вы должны упомянуть то, что вы изменили , например main , вместо start , и удалить первое sub esp,4 , чтобы оставшийся один толчок был сбалансирован add esp,4 , поэтому ESP указывает на обратный адрес при ret запуске.

2. @vengy Thx друг, это наконец-то работает!: -) НО я получаю предупреждение компоновщика об этом . Раздел CRT был объединен с разделом .data с различными атрибутами… Что это значит и как это исправить?

3. Быстрое решение состоит в том, чтобы добавить параметр компоновщика /MERGE в x86 для объединения . Раздел CRT (только для чтения) с разделами .rdata (только для чтения): link.exe /ПОДСИСТЕМА:консоль /ОБЪЕДИНЕНИЕ:.CRT=.rdata HelloWorld.obj

Ответ №2:

В вашем сообщении об ошибке говорится, что он не может найти экспортированный символ (т. е. функцию) «_main». Я ожидаю, что переименование вашей функции запуска в _main приведет к ее компиляции.

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

1. Я переименовался start в _main и тоже пытался, _mainCRTStartup но все равно безуспешно…

2. @darek_911: может быть , попробуйте позвонить в него main ; Я думаю, я читал, что MASM может дополнительно украсить имена для вас ведущим _ , в зависимости от некоторых директив или опций. Но да, конечно start (и отсутствие символа _main) — это проблема, вероятно , проблема.