Inline Asm
In this post i wish to give the same information about inline assembly.
What is Assembly?
In short, Assembly is the machine language form of CPU. Each line of the command will be compiled to know processor instructions directly in ASM language.
Why we are using?
Writing a complete application in ASM language is really hard. But instate of compiled languages, like C or C++, you can easily sand direct command to the processor.
Writing short of ASM codes brings you fantastic capabilities such as.
- You can write your own hardware interface for any operation systems
- It brings sending code to the hardware, such as GPU, ability to you.
- You can use MMX, SSE or AVX registers for high-speed computing (SIMD).
What is GAS syntax?
There are two type ASM syntax in common area, AT&T and Intel syntax. If you know how to write your code on MASM, NASM or even FASM you are familiar Intel syntax. However, Visual studio on Windows environment represent disassembly codes in intel syntax and its compiler accept Intel syntax in inline asm, you have to learn AT&T syntax which is used on GAS the famous GNU assembly compiler.
Gcc (g++) and clang understand this gas syntax in asm(); inline structure. Simple differences are:
- Names of the registers start with % character. Basically eax on nasm, %eax on gas.
- Order is reverse in gas. Example
mov eax, edx
(move edx register values into eax register) in inter syntax,movl %edx, %eax
in gas. - Operator needs suffixes on AT&T notation. b: byte 8 bit, w: word 16 bit, l: long 32 bit, q: quant 64 bit, t: tenbyte 80 bit
- However AT&T syntax needs suffixes, Gas understands and solves the size of the operator. But using suffixes is the best option.
- Immediate operands are marked with a $ prefix, as in addl $5,%eax (add immediate long value 5 to register %eax)
mov eax, foo
pushes the address of foo into eax register in intel notation, butmovl $foo, %eax
pushes the address of foo into eax register.mov DWORDPTR eax, [foo}
pushes the value of foo into eax register in intel notation, butmovl foo, %eax
pushes the value of foo into eax register.
In AT&T has complex addressing strategy with register little bit complicated. Here an example of it
1 |
movl 3(%ebp, %edx, 2), %eax |
it calcules (3 +ebp + (edx * 2)) as a memory pointer and moves the value of it into eax register.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
movl -8(%ebp, %ebx, 4), eax ;; adress is -8 + ebp + (4 * ebx) movl (%ebp, %ebx, 4), eax ;; adress is ebp + (4 * ebx) movl -8(%ebp), eax ;; adress is ebp - 8 movl (%ebp), eax ;; adress is ebp movl (%ebp, %ebx), eax ;; adress is ebp + ebx movl -8(, %ebx, 4), eax ;; adress is (4 * ebx) - 8 |
How can I write it inline?
To write a basic asm code in your C/C++ environment you only need asm directive. But keep it in mind you have to add new lines for every command
1 2 3 4 5 6 |
int main(int argc, char const *argv[]) { asm("movl %ebx,%eax \n\t" //usin \n\t need to add new line "movl %edx,%eax"); //It allows you to add multi line return EXIT_SUCCESS; } |
you can use multiple lines of assembly command in assembler directive but keep it this rules in your mind.
- Protecting data and managing the strategy of code is your responsibility, that means changing pointers of any segment or value of an address may crash your code however modern operation systems flats the memory spaces.
- Using too many lines of the code inside asm directive may not compile.
- You have to provide new line characters (generally \n\t) necessary. In some systems, it is possible to be another semicolon symbol.
- In virtual studio windows environment prefer __asm instead asm instruction. On another system __asm__ is fine. (clang++ understands both of them and uses ; for semicolons.)
There is also extended version of asm command.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> int main(int argc, char const *argv[]) { int inp{11}; int out{12}; std::cout << "inp is " << inp << "\n"; std::cout << "out is " << out << "\n"; __asm__("movl %1,%0;" : "=r" (out) //out is now %0 : "r" (inp)); //inp is now %1 std::cout << "inp is " << inp << "\n"; std::cout << "out is " << out << "\n"; return EXIT_SUCCESS; } |
extend version of it uses variables as parameter.
To strict assembler code position in code section add __volatile__ or __volatile or volatile keyword after __asm__ or __asm or asm directives.
1 Response
[…] your calculation, you may use SSE or SSE2 registers and commands. The easiest way is by using inline assembly […]