This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| en:multiasm:papc:chapter_6_8 [2025/11/17 13:17] – ktokarz | en:multiasm:papc:chapter_6_8 [2025/11/25 12:46] (current) – [Calling the system functions] ktokarz | ||
|---|---|---|---|
| Line 11: | Line 11: | ||
| With the use of additional directives, it is possible to provide information about stack utilisation for stack unwinding. | With the use of additional directives, it is possible to provide information about stack utilisation for stack unwinding. | ||
| - | Procedures can have parameters. In general, parameters can be passed through the stack, registers, common memory or a combination of these. In different operating systems, the rules of passing parameters differ. In 64-bit Windows, the fast call calling convention is used. In this convention, the first four parameters are passed through registers, and each subsequent parameter is passed through the stack. If the parameters are integers, they are passed through general-purpose registers. If parameters are floating-point numbers, they are passed through XMM registers as scalars. If the procedure plays the role of a function, it returns the resulting value. Integers are returned through the accumulator (AL, AX, EAX or RAX), and floating-point values are returned through XMM0. Parameter | + | Procedures can have parameters. In general, parameters can be passed through the stack, registers, common memory or a combination of these. In different operating systems, the rules of passing parameters differ. In 64-bit Windows, the fast call calling convention is used. In this convention, the first four parameters are passed through registers, and each subsequent parameter is passed through the stack. If the parameters are integers, they are passed through general-purpose registers. If parameters are floating-point numbers, they are passed through XMM registers as scalars. If the procedure plays the role of a function, it returns the resulting value. Integers are returned through the accumulator (RAX), and floating-point values are returned through XMM0. Parameters |
| <table masmparampass> | <table masmparampass> | ||
| < | < | ||
| Line 43: | Line 43: | ||
| The Microsoft Windows x64 calling convention requires that even when the parameters are passed through registers, a 32-byte space for them should be reserved on the stack. It is referred to as a shadow space or home space. The shadow space size can be increased to store local variables of the procedure. Why does the x64 calling convention require the shadow space to be explained in the Microsoft blog article((https:// | The Microsoft Windows x64 calling convention requires that even when the parameters are passed through registers, a 32-byte space for them should be reserved on the stack. It is referred to as a shadow space or home space. The shadow space size can be increased to store local variables of the procedure. Why does the x64 calling convention require the shadow space to be explained in the Microsoft blog article((https:// | ||
| - | Another requirement is that the stack must be aligned to the 16-byte boundaries. This is done for the performance, | + | Another requirement is that the stack must be aligned to the 16-byte boundaries. This is done for the performance, |
| <code asm> | <code asm> | ||
| AlignProc PROC | AlignProc PROC | ||
| Line 58: | Line 58: | ||
| </ | </ | ||
| Certainly, these rules are to be used if there is a need to call a system function or to maintain compatibility with a high-level compiler. If the procedure is written in pure assembly and called from an assembly program, it is the programmer' | Certainly, these rules are to be used if there is a need to call a system function or to maintain compatibility with a high-level compiler. If the procedure is written in pure assembly and called from an assembly program, it is the programmer' | ||
| - | The rules of passing parameters, stack and registers use, and data storage layout in 64-bit Microsoft Windows are described in the document about x64 Application Binary Interface (ABI)((https:// | + | The rules of passing parameters, stack and registers use, and data storage layout in 64-bit Microsoft Windows are described in the document about x64 Application Binary Interface (ABI)((https:// |
| + | In the Linux x64 Calling Convention, the first six arguments of type integer/ | ||
| + | <table linuxparampass> | ||
| + | < | ||
| + | ^ Parameter ^ integer register ^ floating point register ^ | ||
| + | | first | RDI | XMM0 | | ||
| + | | second | RSI | XMM1 | | ||
| + | | third | RDX | XMM2 | | ||
| + | | fourth | RCX | XMM3 | | ||
| + | | fivth | R8 | XMM4 | | ||
| + | | sixth | R9 | XMM5 | | ||
| + | | seventh | stack | XMM6 | | ||
| + | | eigth | stack | XMM7 | | ||
| + | | subsequent | stack | stack | | ||
| + | </ | ||
| + | ===== Calling the system functions ===== | ||
| + | The operating systems offer a set of functions which help write an application. These functions include reading characters and text from standard input, usually the keyboard, displaying characters or text on standard output, usually the monitor, handling files, data streams and many others. In previous generations of operating systems, the software interrupt mechanism was used. In Microsoft DOS, it was **int 21h** while in 32-bit versions of Linux it was **int 80h** (or in the C-style hex notation int 0x80). Calling the system function required preparing the arguments in scratch registers and signalling the software interrupt. | ||
| + | < | ||
| + | You can still find many examples using the software interrupt system call on the Internet. In Linux, they should work properly, although they are slower than the new method. In 64-bit Windows, the **int 21** method is no longer supported. | ||
| + | </ | ||
| + | Modern 64-bit operating systems use alternative methods for calling system functions. They significantly differ between Linux and Windows, so we'll briefly summarise both. | ||
| + | |||
| + | ===== Callig Windows system functions ===== | ||
| + | The Microsoft Windows operating system implements functions visible to programmers in the API (Application Programming Interface). Functions are identifiable by names, and they can be called as any other function in the program. Windows API functions for 32 and 64-bit Windows are documented on the Microsoft website ((https:// | ||
| + | Let's see the Hello World example written in the Windows API. | ||
| + | <code asm> | ||
| + | ; include the library with system functions | ||
| + | includelib kernel32.lib | ||
| + | |||
| + | ; define function names as external symbols | ||
| + | EXTERN GetStdHandle: | ||
| + | EXTERN WriteConsoleA: | ||
| + | |||
| + | ; data section with constants and variables definitions | ||
| + | .DATA | ||
| + | |||
| + | STD_OUTPUT_HANDLE = -11 | ||
| + | stdout_handle | ||
| + | hello_msg | ||
| + | dummy dq 0 | ||
| + | |||
| + | ; code section | ||
| + | .CODE | ||
| + | MyAssemblerFunction PROC | ||
| + | |||
| + | ; the stack must be aligned to an address divisible by 16 - mod(16) | ||
| + | ; after the function call is aligned to mod(8) | ||
| + | ; the Windows requires the shadow space on the stack | ||
| + | push rbp ; push rpb to the stack | ||
| + | mov rbp, rsp ; store rsp to rbp | ||
| + | sub rsp, 48 ; shadow space (32 bytes) and stack alignment (additional 8 bytes) | ||
| + | |||
| + | ; we need the handle of the console window | ||
| + | mov rcx, STD_OUTPUT_HANDLE | ||
| + | call GetStdHandle | ||
| + | mov | ||
| + | |||
| + | ; display the text in the console window | ||
| + | mov rcx, stdout_handle | ||
| + | mov rdx, offset hello_msg | ||
| + | mov | ||
| + | mov | ||
| + | call WriteConsoleA | ||
| + | |||
| + | ; restore the stack pointer and rbp | ||
| + | mov rsp, rbp | ||
| + | pop rbp | ||
| + | |||
| + | ; return from the function | ||
| + | ret | ||
| + | MyAssemblerFunction ENDP | ||
| + | END | ||
| + | </ | ||
| + | |||
| + | ===== Callig Linux system functions ===== | ||
| + | The Linux operating system still supports the traditional calling of system functions using software interrupts. It is based on the **int 0x80** interrupt, which recognises the number of the function in the EAX register and up to six arguments in EBX, ECX, EDX, ESI, EDI, and EBP. | ||
| + | The example of the Hello World program in Linux interrupt-based system call is shown in the following code. | ||
| + | |||
| + | <code asm> | ||
| + | section | ||
| + | global | ||
| + | _start: | ||
| + | ; write function | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | ; exit from program | ||
| + | | ||
| + | | ||
| + | |||
| + | section | ||
| + | msg db "Hello World!", | ||
| + | len equ $ - msg | ||
| + | </ | ||
| + | |||
| + | Modern processors have new instructions especially designed for calling system functions. They are supported in the Linux operating system. The **syscall** instruction doesn' | ||
| + | |||
| + | <code asm> | ||
| + | global _start | ||
| + | section .text | ||
| + | |||
| + | _start: | ||
| + | |||
| + | ; write function | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | ; exit from program | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | msg: db "Hello World!", | ||
| + | len equ $ - msg | ||
| + | </ | ||