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 [2026/02/12 12:58] – ktokarz | en:multiasm:papc:chapter_6_8 [2026/02/27 01:48] (current) – [Callig Windows system functions] jtokarz | ||
|---|---|---|---|
| Line 12: | Line 12: | ||
| Since the parameter passing method has changed in 64-bit operating systems, the **PROC** directive calculates the addresses of local variables and arguments on the stack properly, but if we want to use the stack for argument passing, we need to put parameters on the stack manually before a procedure call. With the use of additional directives, it is possible to provide information about stack utilisation for stack unwinding. | Since the parameter passing method has changed in 64-bit operating systems, the **PROC** directive calculates the addresses of local variables and arguments on the stack properly, but if we want to use the stack for argument passing, we need to put parameters on the stack manually before a procedure call. 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 (RAX), and floating-point values are returned through XMM0. Parameters passing in Windows x64 ABI is summarised in a table {{ref> | + | 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. |
| + | |||
| + | **Windows Application Binary Interface.**\\ | ||
| + | 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 passing in Windows x64 ABI is summarised in a table {{ref> | ||
| <table masmparampass> | <table masmparampass> | ||
| < | < | ||
| Line 44: | Line 47: | ||
| 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:// | ||
| + | Some registers are considered non-volatile. It means that they must be saved and restored by a function that uses them. They are RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15, and XMM6-XMM15.\\ | ||
| + | |||
| 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> | ||
| Line 60: | Line 65: | ||
| 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:// | ||
| + | **Linux System V Application Binary Interface.**\\ | ||
| In the Linux x64 Calling Convention, the first six arguments of type integer/ | In the Linux x64 Calling Convention, the first six arguments of type integer/ | ||
| <table linuxparampass> | <table linuxparampass> | ||
| Line 74: | Line 80: | ||
| | subsequent | stack | stack | | | subsequent | stack | stack | | ||
| </ | </ | ||
| + | The non-volatile registers are RBX, RBP, R12, R13, R14, and R15. They should be saved and restored by a function that uses them. | ||
| ===== Calling the system functions ===== | ===== Calling the system functions ===== | ||
| Line 110: | Line 117: | ||
| push rbp ; push rpb to the stack | push rbp ; push rpb to the stack | ||
| mov rbp, rsp ; store rsp to rbp | mov rbp, rsp ; store rsp to rbp | ||
| - | sub rsp, 48 ; shadow space (32 bytes) and stack alignment (additional 8 bytes) | + | sub rsp, 48 ; shadow space (32 bytes) and stack alignment (additional |
| + | ; | ||
| ; we need the handle of the console window | ; we need the handle of the console window | ||
| Line 158: | Line 166: | ||
| </ | </ | ||
| - | Modern processors have new instructions | + | ===== Syscall mechanism ===== |
| + | Modern processors have a new instruction | ||
| + | The **syscall** instruction doesn' | ||
| + | |||
| + | The **syscall** instruction is supported in both Windows and Linux operating systems. It replaces Linux **int 80h**, and is the preferred mechanism for system calls in the 64-bit version of this system. The Linux system sets this register, and the programmer selects the function using the RAX register, as in the previous model of system calls. | ||
| <code asm> | <code asm> | ||
| Line 181: | Line 193: | ||
| len equ $ - msg | len equ $ - msg | ||
| </ | </ | ||
| + | |||
| + | In Windows, low-level system functions are gathered in the ntdll.dll library. While using a high-level Windows API function, it results in calling a corresponding syscall. Although it is possible to call the low-level system function with syscall, API calls are preferred for user software. | ||