This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| en:multiasm:papc:chapter_6_9 [2025/06/14 07:17] – pczekalski | en:multiasm:papc:chapter_6_9 [2025/12/14 17:58] (current) – [Pure Assembler Applications for Windows] pczekalski | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== Compatibility with HLL Compilers (C++, C#) and Operating Systems ====== | ====== Compatibility with HLL Compilers (C++, C#) and Operating Systems ====== | ||
| - | The integration of assembler code with applications written in high-level languages brings benefits in particular scenarios, such as the implementation of complex mathematical algorithms and real-time tasks that require efficient | + | The integration of assembler code with applications written in high-level languages brings benefits in particular scenarios, such as implementing |
| + | |||
| + | In the case of multi-tier web applications, | ||
| + | ===== Programming in Assembler for Windows ===== | ||
| + | Windows OS has historically supported unmanaged code written primarily in C++. This kind of code runs directly on the CPU, but divergence in hardware platforms, such as the introduction of ARM-core-based platforms running Windows, causes incompatibility issues. Since the introduction of the .NET framework, Windows has provided developers with a safer way to execute their code, called " | ||
| + | There are significant differences between x86 (32-bit) and x64 (64-bit) code, mostly in the scope of integration methods. As we're at a very low level of programming, | ||
| + | |||
| + | <note tip>Code written in assembler and compiled to machine code is always an unmanaged one!</ | ||
| + | |||
| + | ==== Pure Assembler Applications for Windows ==== | ||
| + | It is possible to write an application for Windows solely in assembler. While the reason to do it is doubtful, some hints presented below, such as calling system functions, may be helpful. | ||
| + | Calls to the Windows system functions is possible via classical '' | ||
| + | A common approach to development is to start with a stub command-line C++ application and manually convert it to assembler requirements. Visual Studio Community ([[https:// | ||
| + | |||
| + | A template of the typical pure assembler, command-line application for Windows is as follows: | ||
| + | <code asm> | ||
| + | ... | ||
| + | .code | ||
| + | hello_world_asm PROC | ||
| + | push rbp ; save frame pointer | ||
| + | mov rbp, rsp ; fix stack pointer | ||
| + | sub rsp, 8 * (4 + 2) | ||
| + | |||
| + | .... ; here comes your code | ||
| + | |||
| + | |||
| + | mov rsp, rbp | ||
| + | pop rbp | ||
| + | ret | ||
| + | hello_world_asm ENDP | ||
| + | END | ||
| + | |||
| + | </ | ||
| + | |||
| + | The name '' | ||
| + | |||
| + | Calling system functions, such as the system message box, requires understanding the arguments passed to them. As there is no direct assembler help, documentation of the Windows system API for C++ is helpful. | ||
| + | Code below presents the necessary components of the assembler app to call system functions (library includes are configured on the project level): | ||
| + | <code adm> | ||
| + | .data | ||
| + | STD_INPUT_HANDLE = -10 | ||
| + | STD_OUTPUT_HANDLE = -11 | ||
| + | STD_ERROR_HANDLE = -12 | ||
| + | |||
| + | handler dq 0 | ||
| + | hello_msg db "Hello world", | ||
| + | info_msg | ||
| + | ... | ||
| + | includelib | ||
| + | includelib | ||
| + | EXTERN MessageBoxA: | ||
| + | ... | ||
| + | |||
| + | | ||
| + | ; RCX => _In_opt_ HWND hWnd, | ||
| + | ; RDX => _In_opt_ LPCSTR lpText, | ||
| + | ; R8 => _In_opt_ LPCSTR lpCaption, | ||
| + | ; R9 => _In_ UINT uType); | ||
| + | mov rcx, handler | ||
| + | mov rdx, offset hello_msg | ||
| + | mov r8, offset info_msg | ||
| + | mov r9, 0 ; 0 is MB_OK | ||
| + | and rsp, not 8 | ||
| + | call MessageBoxA | ||
| + | ... | ||
| + | </ | ||
| + | The majority of standard library functions accept ASCII strings and must be terminated with a 0 byte (0 is a value), so they do not require passing the string length. | ||
| + | The '' | ||
| + | |||
| + | ==== Dynamic memory management considerations ==== | ||
| + | Using dynamic memory management at the level of the assembler code is troublesome: | ||
| + | |||
| + | <note tip> | ||
| + | |||
| + | **Programming for applications written in unmanaged code** | ||
| + | |||
| + | <todo pczekalski> | ||
| + | |||
| + | **Programming for applications written in managed code** | ||
| + | In the case of managed code, things get more complex. The .NET framework features automated memory management, which automatically releases unused memory (e.g., objects for which there are no more references) and optimises variable locations for improved performance. It is known as a .NET Garbage Collector (GC). GC instantly traces references and, in the event of an object relocation in memory, updates all references accordingly. It also releases objects that are no longer referenced. This automated mechanism, however, applies only across managed code apps. The problem arises when developers integrate a front-end application written in managed code with assembler libraries written in unmanaged code. All pointers and references passed to the assembler code are not automatically traced by the GC. Using dynamically allocated variables on the .NET side and accessing them from the assembler code is a very common scenario. GC cannot " | ||
| + | Luckily, there is a strict set of rules that must be followed when integrating managed and unmanaged code. We discuss it below. | ||
| + | |||
| + | |||
| + | ===== Programming in Assembler for Linux ===== | ||