Как написать привет мир в ассемблере под Windows?

Я хотел написать что-то базовое в сборке под Windows, я использую NASM, но я ничего не могу сделать.

Как писать и компилировать мир привет без помощи функций C в Windows?

Ответ 1

Примеры NASM.

Вызов libc stdio printf, реализующий int main(){ return printf(message); } int main(){ return printf(message); }

; ----------------------------------------------------------------------------
; helloworld.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It needs to be linked with a C library.
; ----------------------------------------------------------------------------

    global  _main
    extern  _printf

    section .text
_main:
    push    message
    call    _printf
    add     esp, 4
    ret
message:
    db  'Hello, World', 10, 0

Затем запустите

nasm -fwin32 helloworld.asm
gcc helloworld.obj
a

Там также The Clueless Newbies Guide для Hello World в Nasm без использования библиотеки C. Тогда код будет выглядеть так.

16-разрядный код с системными вызовами MS-DOS: работает в эмуляторах DOS или в 32-битной Windows с поддержкой NTVDM. Невозможно запустить "прямо" (прозрачно) под любую 64-разрядную Windows, потому что ядро x86-64 не может использовать режим vm86.

org 100h
mov dx,msg
mov ah,9
int 21h
mov ah,4Ch
int 21h
msg db 'Hello, World!',0Dh,0Ah,'$'

Постройте это в исполняемый файл .com чтобы он загружался в cs:100h причем все регистры сегментов равны друг другу (малая модель памяти).

Удачи.

Ответ 2

В этом примере показано, как перейти непосредственно в Windows API, а не в ссылку в стандартной библиотеке C.

    global _main
    extern  [email protected]
    extern  [email protected]
    extern  [email protected]

    section .text
_main:
    ; DWORD  bytes;    
    mov     ebp, esp
    sub     esp, 4

    ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
    push    -11
    call    [email protected]
    mov     ebx, eax    

    ; WriteFile( hstdOut, message, length(message), &bytes, 0);
    push    0
    lea     eax, [ebp-4]
    push    eax
    push    (message_end - message)
    push    message
    push    ebx
    call    [email protected]

    ; ExitProcess(0)
    push    0
    call    [email protected]

    ; never here
    hlt
message:
    db      'Hello, World', 10
message_end:

Для компиляции вам понадобятся NASM и LINK.EXE(из Visual Studio Standard Edition)

   nasm -fwin32 hello.asm
   link /subsystem:console /nodefaultlib /entry:main hello.obj 

Ответ 3

Это примеры Win32 и Win64 с использованием вызовов Windows API. Они предназначены для MASM, а не NASM, но посмотрите на них. Вы можете найти более подробную информацию в этой статье.

;---ASM Hello World Win32 MessageBox

.386
.model flat, stdcall
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib

.data
title db 'Win32', 0
msg db 'Hello World', 0

.code

Main:
push 0            ; uType = MB_OK
push offset title ; LPCSTR lpCaption
push offset msg   ; LPCSTR lpText
push 0            ; hWnd = HWND_DESKTOP
call MessageBoxA
push eax          ; uExitCode = MessageBox(...)
call ExitProcess

End Main

;---ASM Hello World Win64 MessageBox

extrn MessageBoxA: PROC
extrn ExitProcess: PROC

.data
title db 'Win64', 0
msg db 'Hello World!', 0

.code
main proc
  sub rsp, 28h  
  mov rcx, 0       ; hWnd = HWND_DESKTOP
  lea rdx, msg     ; LPCSTR lpText
  lea r8,  title   ; LPCSTR lpCaption
  mov r9d, 0       ; uType = MB_OK
  call MessageBoxA
  add rsp, 28h  
  mov ecx, eax     ; uExitCode = MessageBox(...)
  call ExitProcess
main endp

End

Чтобы собрать и связать их с помощью MASM, используйте это для 32-разрядного исполняемого файла:

ml.exe [filename] /link /subsystem:windows 
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main

или для 64-битного исполняемого файла:

ml64.exe [filename] /link /subsystem:windows 
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main

Ответ 4

Плоский ассемблер не нуждается в дополнительном компоновщике. Это упрощает программирование ассемблера. Он также доступен для Linux.

Это hello.asm из примеров Fasm:

include 'win32ax.inc'

.code

  start:
    invoke  MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK
    invoke  ExitProcess,0

.end start

Fasm создает исполняемый файл:

>fasm hello.asm
flat assembler  version 1.70.03  (1048575 kilobytes memory)
4 passes, 1536 bytes.

И это программа в IDA:

enter image description here

Вы можете увидеть три вызова: GetCommandLine, MessageBox и ExitProcess.

Ответ 5

Чтобы получить .exe с помощью NASM'compiler и компоновщика Visual Studio, этот код отлично работает:

global WinMain
extern ExitProcess  ; external functions in system libraries 
extern MessageBoxA

section .data 
title:  db 'Win64', 0
msg:    db 'Hello world!', 0

section .text
WinMain:
    sub rsp, 28h  
    mov rcx, 0       ; hWnd = HWND_DESKTOP
    lea rdx,[msg]    ; LPCSTR lpText
    lea r8,[title]   ; LPCSTR lpCaption
    mov r9d, 0       ; uType = MB_OK
    call MessageBoxA
    add rsp, 28h  

    mov  ecx,eax
    call ExitProcess

    hlt     ; never here

Если этот код сохраняется, например. "test64.asm", затем компилировать:

nasm -f win64 test64.asm

Производит "test64.obj" Затем для ссылки из командной строки:

path_to_link\link.exe test64.obj /subsystem:windows /entry:WinMain  /libpath:path_to_libs /nodefaultlib kernel32.lib user32.lib /largeaddressaware:no

где path_to_link может быть C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin или где ваша программа link.exe на вашем компьютере, path_to_libs могут быть C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x64 или везде, где находятся ваши библиотеки (в этом случае и kernel32.lib, и user32.lib находятся на одном месте, иначе используйте один вариант для каждого пути, который вам нужен) и /largeaddressaware: нет необходимости в том, чтобы избежать компоновщика, жалующегося на длинные адреса (для этого в этом случае для user32.lib). Кроме того, как это делается здесь, если Visual linker вызывается из командной строки, необходимо предварительно установить среду (запустить один раз vcvarsall.bat и/или просмотреть MS С++ 2010 и mspdb100.dll).

Ответ 6

Если вы не вызываете какую-либо функцию, это вовсе не тривиально. (И, серьезно, нет никакой реальной разницы в сложности между вызовом printf и вызовом функции win32 api.)

Даже DOS int 21h - это просто вызов функции, даже если он отличается от API.

Если вы хотите сделать это без помощи, вам нужно напрямую поговорить с вашим видеооборудованием, вероятно, написав растровые изображения букв "Hello world" в фреймбуфере. Даже тогда видеокарта выполняет работу по переводу этих значений памяти в сигналы VGA/DVI.

Заметим, что, действительно, ни один из этих материалов вплоть до аппаратного обеспечения более интересен в ASM, чем в C. Программа "hello world" сводится к вызову функции. Одна приятная вещь в ASM заключается в том, что вы можете использовать любой ABI, который вы хотите довольно легко; вам просто нужно знать, что такое ABI.

Ответ 7

Если вы хотите использовать компоновщик NASM и Visual Studio (link.exe) с примером Hello World, вы должны будете вручную связать с C Runtime Libary, который содержит функцию printf().

nasm -fwin32 helloworld.asm
link.exe helloworld.obj libcmt.lib

Надеюсь, это поможет кому-то.

Ответ 8

Лучшими примерами являются те, у которых есть fasm, потому что fasm не использует компоновщик, который скрывает сложность программирования окон другим непрозрачным слоем сложности. Если вы довольствуетесь программой, которая записывает в окно gui, то есть пример для этого в каталоге примеров fasm.

Если вы хотите использовать консольную программу, которая также позволяет переназначать стандартные и стандартные. Существует (helas очень нетривиальная) примерная программа, доступная, которая не использует gui, и работает строго с консолью, которая сама по себе является fasm. Это может быть уменьшено до необходимого. (Я написал четвертый компилятор, который является еще одним примером не-gui, но он также нетривиальным).

Такая программа имеет следующую команду для создания правильного исполняемого заголовка, обычно выполняемого компоновщиком.

FORMAT PE CONSOLE 

Раздел под названием ".idata" содержит таблицу, которая помогает окнам во время запуска связывать имена функций с адресами времени выполнения. Он также содержит ссылку на KERNEL.DLL, которая является операционной системой Windows.

 section '.idata' import data readable writeable
    dd 0,0,0,rva kernel_name,rva kernel_table
    dd 0,0,0,0,0

  kernel_table:
    [email protected]    DD rva _ExitProcess
    CreateFile        DD rva _CreateFileA
        ...
        ...
    [email protected]   DD rva _GetStdHandle
                      DD 0

Формат таблицы накладывается окнами и содержит имена, которые просматриваются в системных файлах при запуске программы. FASM скрывает некоторую сложность ключевого слова rva. Таким образом, _ExitProcess @4 - ярлык fasm, а _exitProcess - это строка, которая просматривается Windows.

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

    section '.text' code executable readable writable

Вы можете вызвать все объекты, которые вы указали в разделе.idata. Для консольной программы вам нужно _GetStdHandle, чтобы найти его filedescriptors для стандартного и стандартного (с использованием символических имен, таких как STD_INPUT_HANDLE, которые fasm находит в файле include win32a.inc). Когда у вас есть файловые дескрипторы, вы можете делать WriteFile и ReadFile. Все функции описаны в документации ядра32. Вы, вероятно, знаете об этом, или вы не будете пытаться программировать ассемблер.

Итак: есть таблица с именами asci, которые соединяются с ОС Windows. Во время запуска он преобразуется в таблицу вызываемых адресов, которую вы используете в своей программе.