Ассемблер hello world windows

Коротко о FASM, ассемблере, WinAPI

  • Что такое FASM? — Это компилятор ассемблера (flat assembler).

  • Что такое ассемблер? — это машинные инструкции, то есть команды что делать процессору.

  • Что такое Windows API/WinAPI? — Это функции Windows, без них нельзя работать с Windows.

    Что дают WinAPI функции? — Очень много чего:

  • Работа с файлами.

  • Работа с окнами, отрисовка картинок, OpenGL, DirectX, GDI, и все в таком духе.

  • Взаимодействие с другими процессами.

  • Работа с портами.

  • Работа с консолью Windows

  • И еще очень много интересных функций.

Зачем нужен ассемблер?

На нем можно сделать все что угодно, от ОС до 3D игр.

Вот плюсы ассемблера:

  • Он очень быстрый.

  • На нем можно сделать любую программу.

А вот минусы ассемблера:

  • Долго делать программу. (относительно)

  • Сложен в освоении.

Что нужно для программирования на ассемблере (FASM)?

  • FASM компилятор — https://flatassembler.net/

  • FASM Editor 2.0 — Удобная IDE для FASM, от fasmworld.ru (asmworld), качаем от сюда: https://fasmworld.ru/content/files/tools/FEditor-v2.0.rar

  • OlyDbg — удобный отладчик ассемблера от ollydbg.de: https://www.ollydbg.de/odbg201.zip

    Это все мероприятие весит всего лишь 8.5MB.

Установка компонентов (если можно так назвать)

Архив FASM-а распаковуем в C:\\FASM\ или любой другой, но потом не забудьте настроить FASMEditor.

Архив FASMEdit-a распаковуем куда-то, в моем случае C:\\FASM Editor 2.0\

Архив OlyDbg распаковуем тоже куда-то, в моем случае C:\\Users\****\Documents\FasmEditorProjects\

Настройка FASM Editor-a

Для этого его нужно запустить.

Сразу вас приветствует FASM Editor соей заставкой.

Теперь вам нужно зайти в вкладку «Сервис» (на картинке выделил синим) -> «Настройки…»

Жмем на кнопку с названием «…» и выбираем путь к файлам или папкам.

Теперь мы полностью готовы. К началу.

Пишем «Hello world!» на FASM

В Fasm Editor нужно нажать на кнопку слева сверху или «файл» -> «новый». Выбираем любое, но можно выбрать «Console»

По началу вас это может напугать, но не боимся и разбираемся.

format PE Console ; говорим компилятору FASM какой файл делать

entry start ; говорим windows-у где из этой каши стартовать программу.

include 'win32a.inc' ; подключаем библиотеку FASM-а
;можно и без нее но будет очень сложно.

section '.data' data readable writeable ; секция данных

	hello db 'hello world!',0 ; наша строка которую нужно вывести

section '.code' code readable writeable executable ; секция кода

start: ; метка старта
	invoke printf, hello ; вызываем функцию printf
  
  invoke getch ; вызываем её для того чтоб программа не схлопнулась
  ;то есть не закрылась сразу.
  
  invoke ExitProcess, 0 ; говорим windows-у что у нас программа закончилась
  ; то есть нужно программу закрыть (завершить)

section '.idata' data import readable ; секция импорта
        library kernel, 'kernel32.dll',\ ; тут немного сложней, объясню чуть позже
                msvcrt, 'msvcrt.dll'
  
  import kernel,\
  				ExitProcess, 'ExitProcess'
          
  import msvcrt,\
  				printf, 'printf',\
          getch, '_getch'

На самом деле из всей этой каши текста, команд всего 3: на 16, 18, 21 строках. (и то это не команды, а макросы. Мы к командам даже не подобрались)

Все остальное это просто подготовка программы к запуску.

Программа при запуске должна выглядеть так:

Самое интересное то что программа весит 2КБ. (Можно сократить и до 1КБ, но для упрощения и так пойдет)

Разбор: что значат этот весь текст?

На 1 строчке: «format PE Console» — это строчка говорит FASM-у какой файл скомпилировать, точнее 1 слово, все остальные слова это аргументы (можно так сказать).

PE — EXE файл, программа.

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

Но есть кроме это остальные:

  • format MZ — EXE-файл НО под MS-DOS

  • format PE — EXE-файл под Windows, аналогично format PE GUI 4.0

  • format PE64 — EXE-файл под Windows, 64 битное приложение.

  • format PE GUI 4.0 — EXE-файл под Windows, графическое приложение.

  • format PE Console — EXE-файл под Windows, консольная программа. (просто подключается заранее консоль)

  • format PE Native — драйвер

  • format PE DLL — DLL-файл Windows, поясню позднее.

  • format COFF — OBJ-файл Linux

  • format MS COFF — аналогично предыдущему

  • format ELF — OBJ-файл для gcc (Linux)

  • format ELF64 — OBJ-файл для gcc (Linux), 64-bit

Сразу за командой (для компилятора) format PE Console идет ; это значит комментарий. К сожалению он есть только однострочный.

3 строка: entry start

  • Говорим windows-у где\в каком месте стартовать. «start» это метка, но о метках чуть позже.

5 строка: include 'win32a.inc'

  • Подключает к проекту файл, в данном случае «win32a.inc» он находиться в папке INCLUDE (в папке с FASM). этот файл создает константы и создает макросы для облегчения программирования.

8 строка: section '.data' data readable writeable

  • Секция данных, то есть программа делиться на секции (части), к этим секциям мы можем дать разрешение, имя.

Флаг «data» (Флаг это бит\байт\аргумент хранившей в себе какую-то информацию) говорит то что эта секция данных.

Флаги «readable writeable» говорят то что эта секция может читаться кем-то и записываться кем-то.

Текст ‘.data’ — имя секции

10 строка: hello db 'hello world!',0

hello — это метка, она может быть любого имени (почти, есть некоторые зарезервированные имена), эта метка хранит в себе адрес строки, это не переменная, а просто адрес, но чтобы не запоминать адреса в ручную, помогает FASM он запоминает адрес и потом когда видит эту метку снова, то он заменяет слово на адрес.

db — говорит то что под каждый символ резервируем 1 байт. То есть 1 символ храниться в одном байте.

‘hello world!’ — наша строка в кодировке ASCII

Что значит «,0» в конце строки? — это символ с номером 0 (или просто ноль), у вас на клавиатуре нет клавиши которая имела символ с номером 0, по этому этот символ используют как показатель конца строки. То есть это значит конец строки. Просто ноль записываем в байт после строки.

12 строка: section '.code' code readable writeable executable

Флаг «code» — говорит то что это секция кода.

Флаг «executable» — говорит то что эта секция исполняема, то есть в этой секции может выполняться код.

Все остальное уже разобрали.

14 строка: start:

Это второй вид меток. Просто эта метка указывает на следующую команду. Обратите внимание на то что в 3 строке мы указали start как метку входа в программу, это она и есть. Может иметь эта метка любое имя, главное не забудьте ваше новое имя метки вписать в entry

15 строка: invoke printf, hello

  • Функция printf — выводит текст\число в консоль. В данном случае текст по адресу «hello»

Это штото на подобие команды, но это и близко не команда ассемблера, а просто макрос.

Макрос — Это макро команда для компилятора, то есть вместо имени макроса подставляется что-то другое.

Например, макро команда invoke делиться на такие команды: (взят в пример команда с 15 строки)

push hello
call [printf]

Не переживайте если нечего не поняли.

17 строка: invoke getch

  • getch — функция получения нажатой кнопки, то есть просто ждет нажатия кнопки и потом возвращает нажатую кнопку.

20 строка: invoke ExitProcess, 0

  • ExitProcess — WinAPI функция, она завершает программу. Она принимает значение, с которым завершиться, то есть код ошибки, ноль это нет ошибок.

23 строка: section '.idata' data import readable

Флаг «import» — говорит то что это секция импорта библиотек.

24-25 строки:

library kernel, 'kernel32.dll',\
  				msvcrt, 'msvcrt.dll'
  • Макро команда «library» загружает DLL библиотеки в виртуальную память (не в ОЗУ, вам ОЗУ не хватит чтоб хранить всю виртуальную память).

Что такое DLL объясню позже.

kernel — имя которое привязывается к библиотеке, оно может быть любым.

Следующий текст после запятой: 'kernel32.dll' — это имя DLL библиотеки который вы хотите подключить.

Дальше есть знак \ это значит что текст на следующей строке нужно подставить в эту строку.

То есть код:

library kernel, 'kernel32.dll',\
  				msvcrt, 'msvcrt.dll'

Заменяется на:

library kernel, 'kernel32.dll', msvcrt, 'msvcrt.dll'

Это нужно потому что у ассемблера 1 строка это 1 команда.

27-28 строка:

import kernel,\
  			ExitProcess, 'ExitProcess'

import — Макро команда, которая загружает функции из DLL.

kernel — Имя к которой привязана DLL, может быть любым.

ExitProcess — Как будет называться функция в программе, это имя будет только в вашей программе, и по этому имени вы будете вызывать функцию. (WinAPI функция)

'ExitProcess' — Это имя функции которое будет загружено из DLL, то есть это имя функции которое прописано в DLL.

Дальше думаю не стоит объяснять, вроде все понятно.

Что такое DLL библиотека?

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

Подводим итог

На ассемблере писать можно не зная самого языка, а используя всего лишь макро команды компилятора. За всю статью я упомянул всего 2 команды ассемблера это push hello и call [printf] . Что это значит расскажу в следующей статье.

Introduction

Before telling you what this post is, let me tell you what this is not:

    • It is not a step-by-step guide to Assembly language programming.
    • It is not a step-by-step guide to Win32 programming.
    • It is not a replacement for the official NASM documentation.
    • It is not a replacement for the official GCC documentation.

Having said that, let me tell you what this post is: this post is a collection of my experiences, the sum total of my mistakes, hard earned, while trying to program in assembly, C and Win32. Hopefully, someone will find it useful.

In order to understand and gain the maximum use out of this series, you will need:

  1. Good experience in C programming
  2. Some experience in calling Win32 API (from within C/C++ or other language)
  3. Some exposure to assembly programming, hopefully in NASM

Assembly programming is hard. Win32 programming is hard. Mixing them both is harder. Add to that the 32-bit/64-bit mix-ups and it’s going to be a veritable nightmare. That is why this blog exists. It will outline where I’ve gone wrong, and why I’ve gone wrong. But most importantly, it will log how I’ve corrected those mistakes.

On we go, then.

Getting the Tools

Editors

I like to use Notepad++ as my primary editor, but when I’m doing multi-file Windows programming it makes much sense to use DevCPP. Keep in mind that DevCPP uses MinGW port of GCC under the hood. You might need that fact later.

Assembler

There are a good lot of assemblers out there. I was strongly tempted to try Microsoft Macro Assembler (MASM), but in the end I decided against it. After all, if I wanted it easy, I’d have gone for C#.NET: the whole purpose of this excursion was to take a deep dive. Reminding myself of that, I chose to go with Netwide Assembler. In all programs in this blog, I will be using version 2.11.05, but you’re free to download the latest version here.

Although I am not a big fan of the argument “Command line tools build character”, I decided not to go with IDE tools for assembly. However, there are good tools out there, and I can mention at least one here: SASM. You can download for Windows here.

C Compiler

GCC or MinGW? You can read all about the difference between GNU, GCC and MinGW in this excellent stackoverflow question (and this as well).

I decided to go with gcc, simply for the sake of trust on the community. I use version 5.1.0 in this document.

Linker

Since I chose the GCC suite, I already get ld for free. But if you want an alternative, I can suggest ALINK.

“Hello, World”–from NASM, the Wrong Way

I’m sure most of you have seen some version of the following code as the “first Hello, World” program.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
section .text
global _start
_start: 
mov ecx,msg 
mov ebx,1 
mov eax,4 
int 0x80 

mov eax,1 
int 0x80 

section .data

msg db 'Hello, Windows!',0xa 
len equ $ - msg 

This will work fine in Linux and pretty much any *nix. But, the sad news is that this won’t work under Windows at all! Why? Because you’re calling the Linux interrupt code (syscall) 0x80, which doesn’t exist in Windows. In Windows (or rather, DOS), the correct interrupt function would be 0x21 (or 21h), but that would mean you’re forced to write in 16-bit. Either way, calling the kernel directly in Windows seems to be not the way forward.

If we cannot directly call the kernel, then what options are available to us? The obvious choice is C runtime libraries. And why not the trusted printf? Let’s see that version.

“Hello, Windows”–Take Two, with printf

This time, we call printf. We’ll have a deep look at the way the arguments are passed in Part 2 of this article.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    global  _main
    extern  _printf

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

You need to compile this with the following line.

C:\work>nasm -f win32 hello.asm

And then link it with gcc like so:

C:\work>gcc -m32 hello.obj -o hello.exe

Remember that both NASM and GCC succeed silently. That means, unless there’s an error, you get no output on console.

Couple of points to note here:

  1. It is important to use the flag -f win32 here. (Both -fwin32 and -f win32 will work.) Unless you do so, NASM will happily try to compile your assembly file into a binary format (*.bin), find that it has an external reference, and fail with “error: binary output does not support external references“.
  2. It is important to use the option -m32 with gcc here. (Unlike nasm, gcc will not let you put a space between -m and 32.) If you do not specify -m32, then gcc will try to build a 64-bit exe, fail, and complain that “i386 architecture of input file hello.obj is incompatible with i386:x86-64 output.” In addition, you’ll get an error saying “undefined reference to WinMain“.
  3. The -o option lets gcc know the name of the output file. Quite inconsistently, here, gcc will not mind the space between -o and hello.exe. If you don’t specify the output file name, you’ll get a file called “a.exe”.

Assuming everything went right, you should get a file called “hello.exe” in your directory, which you can execute like so:

C:\work>hello
Hello, World
C:\work>

Cheers! You just called a C library routine from assembly, and made some basic I/O work happen.

However, note that we’re still using DOS subsystem. Our aim was to program for Win32, not call a C routine. Let’s do so now.

“Hello, World”–Take Three, with _WriteFile@20

This time, we’re going to use Win32 API to directly access the console.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    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:

Like in the previous examples, you have to assemble, link and run. However, let me introduce another way to do all 3 in one line:

1
C:\work>nasm -fwin32 hellow.asm && gcc -m32 hellow.obj -o hellow.exe && hellow

If all went well, you should see something like this:

1
2
3
C:\work>nasm -fwin32 hellow.asm && gcc -m32 hellow.obj -o hellow.exe && hellow
Hello, World
C:\work>

Again, couple of important points:

  1. Where is GetStdHandle declared in? The answer is, Kernel32.dll. The immediate next question is, how did gcc know to link with Kernel32.lib? Aren’t we supposed to get an error like this? The short answer is,  because we specified the -m32 flag.
  2. Why the funny names, like _GetStdHandle@4? The answer has to do something with the way method names are mangled or decorated in Win32. That’s juicy material for a next article. For now, remember that the calling convention for Win32 is known as __stdcall, which defines the way functions are made available to public after compilation. Specifically, the MSDN article says, that under __stdcall, “an underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list.
  3. Why the constant (-11)? That’s how we tell _GetStdHandle@4 to get us the “Standard Output” (which in this case, is the screen). Consider this the equivalent way of grabbing a handle to stdout in C, and cout in C++.

Again, knowing how a Win32 function is mangled, or decorated after compiling seems like far too much to expect at this level. After all, all C programmers get to happily write “ExitProcess” instead of “_ExitProcess@4”.

In the next step, we will look at how this can be done.

“Hello, World”–Take Four, with WriteFile

I would like to warn you beforehand: we’ll run into a (rather annoying) known issue with NASM here. This will force us to so something out of the ordinary. Also, this will force us to use ALINK instead of gcc/ld as our linker.

Here’s the code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[BITS 32]

extern ExitProcess
import ExitProcess kernel32.dll

extern  GetStdHandle
import GetStdHandle kernel32.dll

extern  WriteFile
import WriteFile kernel32.dll

segment .data use32
Text db "Hello, World",0

segment .code use32
..start:
    push    -11
    call    [GetStdHandle]
    mov     ebx, eax  
    
    ; WriteFile( hstdOut, message, length(message), &bytes, 0);
    push    dword 0
    lea     eax, [ebp-4]
    push    eax
    push    (message_end - message)
    push    message
    push    ebx
    call    [WriteFile]

    ; ExitProcess(0)
    push    dword 0
    call    [ExitProcess]

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

Couple of things to note:

  1. Note that this is identical to the previous version, Take #3, except for this section:
    1
    2
    3
    4
    5
    6
    7
    8
    extern ExitProcess
    import ExitProcess kernel32.dll
    
    extern  GetStdHandle
    import GetStdHandle kernel32.dll
    
    extern  WriteFile
    import WriteFile kernel32.dll
    

    What this does is to import function names directly as defined in the DLLs, thereby freeing us from having to mangle the function names ourselves.

  2. Note that we’re using the function names within square brackets, like to: [ExitProcess]

However, if you try to assemble this with NASM in the usual way, using -fwin32, NASM will throw an error:

C:\work>nasm -fwin32 hellow2.asm
hellow2.asm:4: error: parser: instruction expected
hellow2.asm:7: error: symbol `import' redefined
hellow2.asm:7: error: parser: instruction expected
hellow2.asm:10: error: symbol `import' redefined
hellow2.asm:10: error: parser: instruction expected

Unfortunately, there is nothing we can do about this, so we will use a workaround. We are going to use -fobj instead of -fwin32. At least this will give us an obj file.

C:\work>nasm -fobj hellow2.asm

Now, if we use our usual way of gcc to link this, we will get an error.

C:\work>gcc -m32 hellow2.obj -o hellow2.exe
hellow2.obj: file not recognized: File format not recognized
collect2.exe: error: ld returned 1 exit status

This means that ld (which is the linker under the hood of gcc) did not like our obj format. And it’s right. We did indeed supply a wrong file format. What we should now do is to find a less restricting linker that will overlook this fact. Enter alink.

C:\work>alink -subsys console -oPE hellow2.obj
ALINK v1.6 (C) Copyright 1998-9 Anthony A.J. Williams.
All Rights Reserved

Loading file hellow2.obj
matched Externs
matched ComDefs
Generating PE file hellow2.exe

C:\work>

Here, -subsys can have two values: console and gui. Since this is a console application, we will go with -subsys console. Also, similar to -m32 in gcc, we will need to specify that we want a Win32 PE format executable file: hence the flag -oPE.

If all went well, you should get an output like so:

C:\work>hellow2
Hello, World
C:\work>

Good!

Now, we will finally look at how to go to the other mode, the GUI mode. The simplest way of displaying text output in Win32 is MessageBox function, which comes in 2 flavors: MessageBoxA for ANSI strings and MessageBoxW for UNICODE strings. We will go with ANSI version for now.

“Hello, World”–Take Five, with WriteConsoleA

In the previous example, we used the function WriteFile as the method to write to the console. Technically, the console is a logical file, so there is nothing wrong with that. However, there is a dedicated routine to write text to the console, known as WriteConsoleA. Let us use that now.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[BITS 32] 

extern ExitProcess 
import ExitProcess kernel32.dll 

extern GetStdHandle 
import GetStdHandle kernel32.dll 

extern WriteConsoleA 
import WriteConsoleA kernel32.dll 

segment .data use32 
msg db "Hello, World",0 
written dword   ?

segment .code use32 
..start: 
push -11
call [GetStdHandle] 
mov ebx, eax

push 0
lea eax, written
push eax
push 13
push offset msg
push ebx
call [WriteConsoleA]

push 0
call [ExitProcess]

“Hello, World”–Take Six, with MessageBoxA

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
[BITS 32]

extern ExitProcess
import ExitProcess kernel32.dll
extern MessageBoxA
import MessageBoxA user32.dll

segment .data use32
Caption db 'From Assembly',0
Text db "Hello, World",0

segment .code use32
..start:
push dword 0
push dword Caption
push dword Text
push dword 0
call [MessageBoxA]

push dword 0
call [ExitProcess]

We assemble, link and execute in one step, like so:

I:\Work\Shellcode\Samples\0>nasm -fobj hellowin.asm && alink -subsys gui -oPE he
llowin.obj && hellowin
ALINK v1.6 (C) Copyright 1998-9 Anthony A.J. Williams.
All Rights Reserved

Loading file hellowin.obj
matched Externs
matched ComDefs
Generating PE file hellowin.exe

I:\Work\Shellcode\Samples\0>

Note the flag -subsys -gui to alink. There will be no console output, but you should see a familiar message box popping up.

This concludes the first part. In the next part, we’ll take a deeper look at interfacing with C library functions, with special attention to what are known as calling conventions.

Hey there!

This year I studied computer’s organisation II in College. I’ve been fascinated thus far with how computation is done on an assembler language and I want to share with you a little of my knowledge.

Maybe this will become a series because I’m finding myself really captivated with this subject and I think a lot of people will understand better how programming works with this info.

But first things first

❓ What is ASM?

Alt Text

ASM, short for Assembler (or assembly), is not a unique language such as C, Java, Go or whatever, it is instead a program that converts code into machine language. This means there’s assembler languages for the different types of machines. For example: There is assembler for the Intel and AMD processor’ architectures (x86_64) and there’s another for ARM architectures.

This tutorial is going to be oriented toward Intel’s Architecture

🔧 What are we going to use?

Alt Text

For this short program we are going to use NASM and whatever text editor you like. In my case, I’m going to use VS Code since it has some nice plugins.

To install NASM on Debian systems (Ubuntu, PopOs!, Linux Mint, etc..)

sudo apt-get update -y
sudo apt-get install -y nasm

I’m only going to show this example in a linux system since the sys calls are different for mac, hence the example won’t work in that system (believe me, this post was intended for mac as well…)

🏗️ Structure of an ASM program

Ok, now we have our assembler and our Text Editor or IDE. What now?

Let’s create a new file and name it helloWorld.asm

Alt Text

Now that we have our empty file. We need to determine how the file is going to be used. In ASM each file has 4 sections. This sections will always exist even if you don’t define them. However, if you need one, you will have to do it.

The 4 sections are:

  • .data : where we are going to declare our global initialised variables

  • .rodata : where we are going to declare our global un-itialised constants

  • .bss : where we are going to declare our global un-initialised variables

  • .text : where we are going to define our code

👏 Hands On

Ok, so what we are trying to build here is a CLI program that prints Hello World!. Sounds fairly easy. But in order to do so, we need to inform the processor that this function that we are going to name ‘start’ is global to all the system. so we add our .text section with the ‘start’ function and the global statement outside the section. Like this:

Alt Text

Since we don’t want to use any fancy C functions, nor none of those other high level languages functions for the matter, we are going to rely on Syscalls.

Without digging that deep, Syscalls are just calls to the OS. We need to call the 0x80 interruption (on UNIX systems) and pass to that interruption the parameters we want it to handle.

For the function that we are going to use (sys_write) the interruption receives 4 parameters:

  1. The function number (RAX)
  2. Where do we want it to execute (RBX)
  3. The direction of the memory we want to execute (RCX)
  4. The size of the message in bytes (RDX)

RAX, RBX, RCX and RDX are just multi-purpose registers that we are going to use and that I’m going to explain in further chapters of this series. So bare with me for now.

So let’s define the message first and let’s call int 0x80 after that.

Alt Text

A lot of new info here. Let’s go line by line.

This is the section were we are going to define our ‘Hello World!’ string variable. Since it will be already initialised, we declare in .data

msg: DB 'Hello World!', 10

This is our new string. It’s declared under the name msg and we initialise it with DB (define byte) the characters that will be displayed and a ‘, 10’ which is going to be our \n character. What I want you to get out of this step is that Each char comprising ‘Hello World!’ takes one byte of memory. So by using DB we are asking the processor for a memory slot that will take 13 bytes (counting the space and \n char).

This one is a little bit tougher. We are declaring a variable call msgSize that is going to step on the right end of Hello World! ($) and will subtract the address were your msg variable began. Thus leaving us with the bytes used for msg

We have our message, let’s display it now!

Alt Text

Again, let’s explain what is happening here

    mov rax, 4          ; function 4
    mov rbx, 1          ; stdout
    mov rcx, msg        ; msg
    mov rdx, msgSize    ; size
    int 0x80

Intel has a very weird way of doing things most of the time. So each line of text will be divided into 4 fragments again

  1. Mov : an instruction which moves the elements from B to A
  2. A : the destiny Register/Memory
  3. B : the origin Register/Memory
  4. comments : where the comments are :p

So what we are doing in here is moving the number 4 to our RAX register (because sys_write is our function number 4 on UNIX). We move the number 1 to RBX (representing STDOUT). Then the memory in which msg is defined will be stored on RCX and finally the size on RCX. By calling int 0x80 we are asking the interruption 0x80 to handle all the parameters we threw to it and do what it’s supposed to do.

Alt Text

Our final step is to exit the program. And guess what? that requires another Syscall. In this case, our function will be number 1 (exit) and our parameter will be 0 (because that’s the number we want to return. 0 usually means that the program was executed successfully while 1 means that it wasn’t)

    mov rax, 1          ; function 1
    mov rbx, 0          ; code
    int 0x80

🔗 Assembling and Linking

Let’s save our file as helloWorld.asm and head over to the terminal.

If you have already installed NASM, head to the folder where you saved your .asm file and assemble and link it.

Linux:

nasm -f elf64 -g -F DWARF helloWorld.asm
ld -e start -o helloWorld helloWorld.o
./helloWorld

And that’s it for today. You should get a ‘Hello World message on your terminal.

Alt Text

If you want to see the full code, here is the Repository: Hello World!

Автор: xrnd | Рубрика: Учебный курс | 16-03-2010 |  Распечатать запись

В этой части наконец-то напишем долгожданный «Hello, world!». Теперь почти всё должно быть понятно. Для начала необходимо с помощью директивы db объявить строку, содержащую сообщение «Hello, word!». Лучше сделать это в конце программы, за последней командой, иначе процессор может принять строку за код и попытаться её выполнить.

Для вывода строки используется системная функция DOS. Чтобы напечатать строку, нужно поместить 9 в регистр AH, а в регистр DX поместить адрес строки, которая должна заканчиваться символом ‘$’. Обращение к функциям DOS осуществляется с помощью команды int 21h. Вот код программы:

1
2
3
4
5
6
7
8
9
10
11
use16               ;Генерировать 16-битный код
org 100h            ;Программа начинается с адреса 100h
 
    mov dx,hello    ;В DX адрес строки.
    mov ah,9        ;Номер функции DOS.
    int 21h         ;Обращение к функции DOS.
 
    mov ax,4C00h    ;\
    int 21h         ;/ Завершение программы
;-------------------------------------------------------
hello db 'Hello, world!$'

В четвёртой строке FASM подставит адрес строки вместо hello. Не трудно догадаться, что завершение программы — это тоже функция DOS с номером 4Ch. Перед её вызовом в регистр AL помещается код завершения программы (ноль соответствует успешному завершению). Можно объединить эти две операции и сразу поместить в AX значение 4C00h.

В учебном курсе я не буду подробно описывать функции DOS, лишь кратко расскажу о тех функциях, которые мы будем использовать. Если вы захотите узнать больше, в Интернете можно найти подробное описание 🙂

Чтобы увидеть работу программы, надо запустить её из командной строки, иначе она печатает строку и сразу закрывается. Или можно написать простенький bat-файл для запуска:

Результат работы программы:

Если вы запустите программу в отладчике, то просмотреть выводимую строку можно, нажав Alt+F5 или выбрав в меню Turbo Debuger пункт Window->User Screen.

Следующая часть »

PacMan ест Hello, World!

В этой части наконец-то напишем долгожданный «Hello, world!». Теперь почти всё должно быть понятно. Откроем в текстовом редакторе новый файл и сохраним его как hello.asm в директории C:\fasm. Для начала необходимо с помощью директивы db объявить строку, содержащую сообщение «Hello, word!». Лучше сделать это в конце программы, за последней командой, иначе процессор может принять строку за код и попытаться её выполнить.

Для вывода строки используется системная функция DOS. Чтобы напечатать строку, нужно поместить 9 в регистр AH, а в регистр DX поместить адрес строки, которая должна заканчиваться символом ‘$’. Обращение к функциям DOS осуществляется с помощью команды int 21h. Вот код программы:

use16               ;Генерировать 16битный код

org 100h            ;Программа начинается с адреса 100h

    mov dx,hello    ;В DX адрес строки.

    mov ah,9        ;Номер функции DOS.

    int 21h         ;Обращение к функции DOS.

    mov ax,4C00h    ;\

    int 21h         ;/ Завершение программы

;

hello db ‘Hello, world!$’

В четвёртой строке FASM подставит адрес строки вместо hello. Не трудно догадаться, что завершение программы — это тоже функция DOS с номером 4Ch. Перед её вызовом в регистр AL помещается код завершения программы (ноль соответствует успешному завершению). Можно объединить эти две операции и сразу поместить в AX значение 4C00h.

В учебном курсе я не буду подробно описывать функции DOS, лишь кратко расскажу о тех функциях, которые мы будем использовать. Если вы захотите узнать больше, в Интернете можно найти подробное описание 

Чтобы увидеть работу программы, надо дать команду fasm для компиляции исходного кода в файл COM, а затем запустить её из командной строки DOSBox.

Если вы помните, в третьем уроке про отладчик мы разбирали нашу первую программу в дебагере. Для работы дебагера мы редактировали dosbox.conf, чтобы закоментировать DPMI хост. Теперь нам нужно снова вызвать хост и раскомменировать эти две строки:

#cd CWSDPMI/BIN/

#CWSDPMI -p -s-

Уберите знаки решетки в начале строк и сохраните dosbox.conf. Теперь запускаем DOSBox и вводим команды:

Результат работы программы:

Результат работы программы hello.com

Если вы запустите программу в отладчике Turbo Debugger, то просмотреть выводимую строку можно, нажав Alt+F5 или выбрав в меню Turbo Debugger пункт Window->User Screen.

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Как перейти с windows 32 bit на windows 64 bit
  • Где ввести код активации windows 7
  • Windows dfs подключить сетевой диск
  • Msinet ocx windows 10
  • Windows failed to install the following update with error 0x8024200b