This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| en:multiasm:exercisesbook:pc [2026/05/22 12:29] – [Displaying integers in hex] ktokarz | en:multiasm:exercisesbook:pc [2026/06/03 12:54] (current) – [Solution with static assembly library] ktokarz | ||
|---|---|---|---|
| Line 32: | Line 32: | ||
| TO BE DONE | TO BE DONE | ||
| </ | </ | ||
| + | |||
| + | ===== Solution with static assembly library ===== | ||
| + | In this section, we'll go through the process of creating a solution with a C++ main file and a static assembler library.\\ | ||
| + | |||
| + | **1.** Create the solution. You can create a simple "Hello world" example written in C++ for execution in a console window.\\ | ||
| + | <figure createsln> | ||
| + | {{: | ||
| + | < | ||
| + | </ | ||
| + | <figure consoleapp> | ||
| + | {{: | ||
| + | < | ||
| + | </ | ||
| + | <figure nameapp> | ||
| + | {{: | ||
| + | < | ||
| + | </ | ||
| + | At this stage, you can test the application. It should print "Hello World" in a console window. | ||
| + | |||
| + | **2.** Add assembler module with library functions. | ||
| + | <figure addasmproj> | ||
| + | {{: | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| ===== Standalone assembly ===== | ===== Standalone assembly ===== | ||
| Line 62: | Line 89: | ||
| The easiest way is to put all required files in the same folder on the disk. This is not the case for more complex projects, so file names should be preceded by their full paths. | The easiest way is to put all required files in the same folder on the disk. This is not the case for more complex projects, so file names should be preceded by their full paths. | ||
| </ | </ | ||
| - | It will not be very surprising that the first code example will be the "Hello world!" | ||
| - | * GetStdHandle - returns the handle of the console window, which is the main window of our application. | ||
| - | * WriteConsole - displays the text in the console. | ||
| - | * ExitProcess - returns control to the operating system. | ||
| - | The functions are implemented in a library file kernel32.lib, | ||
| - | The details of each statement of the program are explained in comments. | ||
| - | <code asm> | ||
| - | option casemap: | ||
| - | |||
| - | includelib kernel32.lib | ||
| - | |||
| - | EXTERN GetStdHandle: | ||
| - | EXTERN WriteConsoleA: | ||
| - | EXTERN ExitProcess: | ||
| - | |||
| - | STD_OUTPUT_HANDLE equ -11 ; STD_OUTPUT_HANDLE costant | ||
| - | |||
| - | ; In the data section of our program, there is a string to be displayed | ||
| - | .data | ||
| - | message db " | ||
| - | msgLen | ||
| - | |||
| - | ; In the code section of our program, there are instructions for execution | ||
| - | .code | ||
| - | main PROC ; main function - entry point | ||
| - | sub rsp, 28h ; shadow space + align | ||
| - | |||
| - | ; HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE) | ||
| - | mov ecx, STD_OUTPUT_HANDLE | ||
| - | call GetStdHandle | ||
| - | |||
| - | ; WriteConsoleA(hConsole, | ||
| - | mov rcx, rax ; console window handle | ||
| - | lea rdx, message | ||
| - | mov r8d, msgLen | ||
| - | lea r9, written | ||
| - | mov qword ptr [rsp+20h], 0 ; 5th argument (lpReserved = NULL) | ||
| - | call WriteConsoleA | ||
| - | |||
| - | ; ExitProcess(0) | ||
| - | xor ecx, ecx ; value to be returned | ||
| - | call ExitProcess | ||
| - | main ENDP ; end of the main function | ||
| - | |||
| - | ; In the uninitialised data section of our program, there is a " | ||
| - | .data? | ||
| - | written dq ? ; variable which holds the number of written chars | ||
| - | |||
| - | END ; end of source file</ | ||
| - | ===== Creating static libraries ===== | ||
| - | To create the static library, the assembler module shouldn' | ||
| - | The first step is to assemble the source file with MASM. | ||
| - | < | ||
| - | ml64 /c source.asm | ||
| - | </ | ||
| - | * /c - assemble without linking. | ||
| - | The second step is to create the lib file with the lib tool. | ||
| - | < | ||
| - | lib source.obj | ||
| - | </ | ||
| - | This will create the source.lib file, which can be imported into the program, where we can use all available procedures. | ||
| - | |||
| - | The example for the library will be the program containing the function " | ||
| - | <note info> | ||
| - | Please note that the code of the library module does not have the " | ||
| - | </ | ||
| - | <code asm> | ||
| - | option casemap: | ||
| - | |||
| - | .code | ||
| - | ; ---------------------------------------- | ||
| - | ; int_to_ascii | ||
| - | ; input: | ||
| - | ; output: | ||
| - | ; RAX = length of the resulting string | ||
| - | ; ---------------------------------------- | ||
| - | int_to_ascii PROC | ||
| - | push rbx ; rbx is nonvolatile | ||
| - | push rdi ; rdi is nonvolatile | ||
| - | sub rsp, 24 ; shadow space | ||
| - | mov [rsp+8], | ||
| - | mov [rsp+16], rdx | ||
| - | mov rax, rcx ; mov imput number to rax | ||
| - | |||
| - | ; point rdi into the buffer end | ||
| - | mov rdi, rdx ; pointer to a string | ||
| - | add rdi, 31 | ||
| - | mov byte ptr [rdi], 0 ; mark string end with terminator | ||
| - | |||
| - | mov rbx, 10 | ||
| - | |||
| - | ; test if the numer is positive or negative | ||
| - | xor r8d, r8d ; r8 = 0 → positive flag | ||
| - | test rax, rax ; test the sign | ||
| - | jge convert | ||
| - | |||
| - | neg rax ; change the sign of rax | ||
| - | mov r8d, 1 ; r8 = 1 → negative flag | ||
| - | |||
| - | ; conversion loop | ||
| - | convert: | ||
| - | dec rdi ; starting from the end of the text (least significant digit) | ||
| - | xor rdx, rdx ; prepare to divide rdx:rax by rbx | ||
| - | |||
| - | div rbx ; rax / 10 → remainder in rdx | ||
| - | add dl, " | ||
| - | mov [rdi], dl ; write character of a digit to buffer | ||
| - | test rax, rax ; test if there is still a value for conversion | ||
| - | jne convert | ||
| - | |||
| - | ; add minus if needed | ||
| - | cmp r8d, 0 ; r8 = 1 → negative flag | ||
| - | je write | ||
| - | dec rdi ; add minus character | ||
| - | mov byte ptr [rdi], ' | ||
| - | |||
| - | write: | ||
| - | ; calculate length of the text (end – rdi) | ||
| - | mov rax, [rsp+16] | ||
| - | add rax, 31 | ||
| - | sub rax, rdi ; resulting number length in rax | ||
| - | mov rdx, rdi ; adjusted pointer to string in a buffer | ||
| - | | ||
| - | add rsp, 24 ; restore stack pointer | ||
| - | pop rdi | ||
| - | pop rbx | ||
| - | ret | ||
| - | int_to_ascii ENDP | ||
| - | |||
| - | END | ||
| - | </ | ||
| - | |||
| - | This library can be imported into the assembler program or a program written in another programming language. Assembly program can look as follows: | ||
| - | <code asm> | ||
| - | option casemap: | ||
| - | |||
| - | ; include the system library and our convert library | ||
| - | includelib kernel32.lib | ||
| - | includelib convert.lib | ||
| - | |||
| - | ; declare function we use in our program | ||
| - | EXTERN GetStdHandle: | ||
| - | EXTERN WriteConsoleA: | ||
| - | EXTERN ExitProcess: | ||
| - | EXTERN int_to_ascii: | ||
| - | |||
| - | ; costant required by GetStdHandle system function | ||
| - | STD_OUTPUT_HANDLE equ -11 | ||
| - | |||
| - | ; data section | ||
| - | .data | ||
| - | buffer db 32 dup(0) ; buffer for a string | ||
| - | hOut dq ? ; placeholder for console handle | ||
| - | dummy dq ? ; place for dummy parameter | ||
| - | |||
| - | ;code section | ||
| - | .code | ||
| - | |||
| - | ; ------------------------------------------- | ||
| - | ; main function of the program - entry point | ||
| - | ; ------------------------------------------- | ||
| - | main PROC | ||
| - | ; shadow space | ||
| - | sub rsp, 40 | ||
| - | |||
| - | ; get the handle of stdout | ||
| - | mov ecx, STD_OUTPUT_HANDLE ; console output | ||
| - | call GetStdHandle | ||
| - | mov hOut, rax ; store the handle | ||
| - | |||
| - | ; call conversion function | ||
| - | mov rcx, 33550336 | ||
| - | lea rdx, buffer | ||
| - | call int_to_ascii | ||
| - | |||
| - | ; prepare agruments for WriteConsoleA(hOut, | ||
| - | mov rcx, hOut ; console handle | ||
| - | ; pointer to the beginning of a string is in rdx | ||
| - | mov r8, rax ; nNumberOfCharsToWrite is in rax | ||
| - | lea r9, dummy ; dummy for lpNumberOfCharsWritten | ||
| - | mov qword ptr [rsp+20h], 0 ; lpReserved (must be NULL) | ||
| - | |||
| - | call WriteConsoleA | ||
| - | |||
| - | xor ecx, ecx ; return value of a program | ||
| - | call ExitProcess | ||
| - | main ENDP | ||
| - | |||
| - | END | ||
| - | </ | ||
| - | |||
| - | |||
| - | ===== Introduction to Linux assembly programming ===== | ||
| - | NASM | ||
| - | ====== Scenarios ====== | ||