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 [2026/01/09 12:56] – [Merging of the High-Level Languages and Assembler Code] pczekalski | en:multiasm:papc:chapter_6_9 [2026/02/27 02:50] (current) – [Merging of the High-Level Languages and Assembler Code] jtokarz | ||
|---|---|---|---|
| Line 3: | Line 3: | ||
| The integration of assembler code with applications written in high-level languages brings benefits in particular scenarios, such as implementing complex mathematical algorithms and real-time tasks that require efficient, compact code. No one uses an assembler to implement a graphical user interface (GUI) anymore, as there is no reason to do so. Modern desktop operating systems are designed to provide a rich user experience, supporting languages such as C#, C++, and Python for implementing user interfaces (UIs) through libraries. While those UI generation functions can be executed from the assembler level, there is virtually no reason to do it. A more effective approach is to have the main application is written in a high-level language and execute assembly code as needed to perform backend operations efficiently. | The integration of assembler code with applications written in high-level languages brings benefits in particular scenarios, such as implementing complex mathematical algorithms and real-time tasks that require efficient, compact code. No one uses an assembler to implement a graphical user interface (GUI) anymore, as there is no reason to do so. Modern desktop operating systems are designed to provide a rich user experience, supporting languages such as C#, C++, and Python for implementing user interfaces (UIs) through libraries. While those UI generation functions can be executed from the assembler level, there is virtually no reason to do it. A more effective approach is to have the main application is written in a high-level language and execute assembly code as needed to perform backend operations efficiently. | ||
| - | In the case of multi-tier web applications, | + | In the case of multi-tier web applications, |
| + | |||
| + | It is possible to merge assembler code with high-level languages either as: | ||
| + | * static, where assembler code is compiled as a library object file and merged with the code during linking (figure {{ref> | ||
| + | * dynamic, where the assembler code library is loaded during runtime (figure {{ref> | ||
| + | |||
| + | <figure staticlinking> | ||
| + | {{ : | ||
| + | < | ||
| + | </ | ||
| + | <figure dynamiclinking> | ||
| + | {{ : | ||
| + | < | ||
| + | </ | ||
| + | Dynamic code loading is considered an advantage because the original application does not contain the assembler binary executable; it is kept in a separate file and loaded on demand, allowing it to be compiled and exchanged independently. On the other hand, it raises several challenges, such as versioning, compatibility, | ||
| ===== Programming in Assembler for Windows ===== | ===== 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 " | 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 " | ||
| Line 17: | Line 31: | ||
| ==== Dynamic memory management considerations ==== | ==== Dynamic memory management considerations ==== | ||
| - | Using dynamic memory management at the level of the assembler code is troublesome: | + | Using dynamic memory management at the assembler |
| <note tip> | <note tip> | ||
| + | <figure dynamicmemory> | ||
| + | {{ : | ||
| + | < | ||
| + | </ | ||
| ==== Pure Assembler Applications for Windows CMD ==== | ==== Pure Assembler Applications for Windows CMD ==== | ||
| 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. | 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. | ||
| Line 86: | Line 104: | ||
| **Programming for applications written in unmanaged code** | **Programming for applications written in unmanaged code** | ||
| + | In the case of the unmanaged code, integration is straightforward. Assembler code is usually encapsulated in the DLL library (or multiple libraries). | ||
| Below is a sample dummy assembler function that returns an integer (no parameters), | Below is a sample dummy assembler function that returns an integer (no parameters), | ||
| Line 113: | Line 132: | ||
| int main() | int main() | ||
| { | { | ||
| - | dllHandle = LoadLibrary(TEXT(" | + | |
| - | if (!dllHandle) | + | if (!dllHandle) |
| - | { | + | { |
| - | std::cerr << " | + | std::cerr << " |
| - | return 1; | + | return 1; |
| - | } | + | } |
| - | MyProc myAsmProcedure = (MyProc)GetProcAddress(dllHandle, | + | MyProc myAsmProcedure = (MyProc)GetProcAddress(dllHandle, |
| - | if (!myAsmProcedure) | + | if (!myAsmProcedure) |
| - | { | + | { |
| - | std::cerr << " | + | std::cerr << " |
| - | FreeLibrary(dllHandle); | + | FreeLibrary(dllHandle); |
| - | return 2; | + | return 2; |
| - | } | + | } |
| - | std::cout << myAsmProcedure(); | + | std::cout << myAsmProcedure(); |
| - | FreeLibrary(dllHandle); | + | FreeLibrary(dllHandle); |
| - | return 0; | + | return 0; |
| } | } | ||
| Line 196: | Line 215: | ||
| ===== Programming in Assembler for Linux ===== | ===== Programming in Assembler for Linux ===== | ||
| + | Principles for composing assembler code and high-level language into a single application on Linux OSes are similar to those on Windows; dynamic loading is more complex. Thus, we consider only static linking of the code. The most common use of C++ is as a high-level application. Still other options are possible, such as Python. | ||
| + | |||
| + | Linux provides more parameters passed via registers in its x64 standard calls (up to 6) than Windows (only up to 4). Refer to the chapter [[en: | ||
| + | |||
| + | A common scenario is to use the [[https:// | ||
| + | |||
| + | The sample project is composed of the '' | ||
| + | |||
| + | The '' | ||
| + | <code ini Makefile> | ||
| + | all: main | ||
| + | |||
| + | main: main.o asmfunc.o | ||
| + | g++ -o main main.o asmfunc.o | ||
| + | |||
| + | main.o: main.cpp | ||
| + | g++ -c -g -F dwarf main.cpp | ||
| + | |||
| + | asmfunc.o: asmfunc.asm | ||
| + | nasm -g -f elf64 -F dwarf asmfunc.asm -l asmfunc.lst | ||
| + | |||
| + | clean: | ||
| + | rm -f ./main || true | ||
| + | rm -f ./main.o || true | ||
| + | rm -f ./asmfunc.o || true | ||
| + | rm -f ./ | ||
| + | </ | ||
| + | |||
| + | <note important> | ||
| + | |||
| + | Assembler code exposes functions to the linker using the '' | ||
| + | |||
| + | <code assembler asmfunc.asm> | ||
| + | section .data | ||
| + | section .bss | ||
| + | section .text | ||
| + | |||
| + | global addInAsm | ||
| + | |||
| + | addInAsm: | ||
| + | nop | ||
| + | mov rax, rsi | ||
| + | add rax, rdi | ||
| + | ret | ||
| + | </ | ||
| + | |||
| + | Finally, the calling side (C++ application) uses the '' | ||
| + | <code cpp main.cpp> | ||
| + | #include < | ||
| + | |||
| + | extern " | ||
| + | |||
| + | long long a=10; | ||
| + | long long b=7; | ||
| + | long long returnValue; | ||
| + | |||
| + | int main() { | ||
| + | std::cout << " | ||
| + | returnValue = addInAsm(a, | ||
| + | std::cout << "Sum of " << a << " and " << b << " is " << returnValue | ||
| + | << std::endl; | ||
| + | return 0; | ||
| + | } | ||
| + | </ | ||