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


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

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

8 74

8 ответов:

примеры NASM.

вызов libc stdio printf, осуществляет 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

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

16-битный код с системными вызовами MS-DOS: работает в эмуляторах DOS или в 32-битных окнах с поддержкой 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 со всеми сегментными регистрами, равными друг другу (крошечная модель памяти).

удачи.

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

    global _main
    extern  _GetStdHandle@4
    extern  _WriteFile@20
    extern  _ExitProcess@4

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

    ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
    push    -11
    call    _GetStdHandle@4
    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    _WriteFile@20

    ; ExitProcess(0)
    push    0
    call    _ExitProcess@4

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

для компиляции вам понадобится NASM и ссылка.EXE (от Visual studio Standard Edition)

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

это примеры Win32 и Win64 с использованием вызовов API Windows. Они предназначены для 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

Плоский Ассемблер не нужен дополнительный компоновщик. Это делает ассемблерное Программирование довольно легким. Он также доступен для 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.

и это программа, в Мар:

enter image description here

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

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

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

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

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

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

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

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

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

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

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

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

FORMAT PE CONSOLE 

раздел под названием '.idata ' содержит таблицу, которая помогает windows во время запуска связывать имена функций со средами выполнения адреса. Он также содержит ссылку на ядро.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:
    _ExitProcess@4    DD rva _ExitProcess
    CreateFile        DD rva _CreateFileA
        ...
        ...
    _GetStdHandle@4   DD rva _GetStdHandle
                      DD 0

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

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

    section '.text' code executable readable writable

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

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