Electronics Competition Group:
5-year Electronic Design Competition D Topic 481123148;
15-year Electronic Design Competition E Topic 481123833; 15-year Electronic Design Competition F Topic 73646017;
15-year Electronic Design Competition G Topic 45169719; 15-year Electronic Design Competition H Topic 16986998; 15-year Electronic Design Competition I Topic 80699535; 15-year Electronic Design Competition J Topic 475528830;
The first problem I encountered was, what is the format? I searched online for information, and the previous articles all used the format _asm_ _volatile_(…); however, when I tried it myself, it never worked. This shows that while the internet is great, one should not blindly trust it. After many tests, I found that the format for embedded assembly under Windows only includes the _asm keyword, without volatile; the previous parentheses have now changed to curly braces, and there are no quotes at the end. A simple test program I wrote is:
#include
// Test bsf instruction
void test()
{
int value,index=32;
_asm {
mov eax,index
bsf ebx,eax
mov value,ebx
}
printf(“value is %d/n”,value);
}
void main()
{
printf(“Hello World/n”);
test();
}
The characteristics of embedded assembly in Windows are:
1. The assembly is Intel assembly, not AT&T assembly;
2. The keyword is _asm, not others. This may be related to your own environment. If you redefine the macro, then it will be your own defined keyword;
3. Although there is a volatile keyword, using it results in an error; I don’t know how to use it specifically;
4. There is no colon to specify input/output; you can directly use the numbers in the assembly language;
5. Assembly code must be surrounded by curly braces, not parentheses, and there is no semicolon at the end;
6. If you do not use curly braces, then there must be an _asm keyword before each assembly line.
From the above description, it seems that Windows embedded assembly is much simpler.
After getting it done in Windows, I had to test it in Linux. The first thing I did was directly copy the program from Windows to Linux, and obviously, my ignorance would result in errors.
After many tests, I obtained the following code that executes correctly in Linux:
#include
void test()
{
int bsf=0,bsr=0,input=0x12345,flag;
asm volatile (“movl %3,%%eax/n”
“movl %3,%%ebx/n”
“bsf %3,%%cx/n”
“movzwl %%cx,%0/n”
“bsr %3,%%dx/n”
“movzwl %%dx,%1/n”
“pushf/n”
“pop %2/n”
:”=r”(bsf),”=r”(bsr),”=r”(flag)
:”m”(input)
);
printf(“bsf value is %d/n”,bsf);
printf(“bsr value is %d/n”,bsr);
printf(“flag is %x/n”,flag);
}
int main()
{
printf(“Hello World/n”);
test();
return 0;
}
Structurally, the Linux version is much more complicated. First, the assembly language is AT&T, which Windows programmers are not familiar with, and you also have to define input/output. Additionally, using registers requires two % signs… In summary, it is quite troublesome. However, I do not mean to belittle Linux; as long as it is used well, it is still very powerful.
The characteristics of embedded assembly in Linux are:
1. The assembly language is AT&T; the source operand and destination operand are in the opposite positions compared to Intel assembly. For details on AT&T assembly, please refer to other literature;
2. The keywords for embedded assembly are not _asm_ _volatile_; the correct way I discovered is: asm volatile. This is still related to the configuration of your machine. If the keyword is incorrect, you can test other similar keywords, such as asm_, __asm, etc., and the same goes for volatile;
3. Embedded assembly in Linux has input/output and modification identifiers, placed at the end of the assembly code, separated by colons. The first colon indicates input parameters, formatted as “=r” (C language variable, results obtained from assembly code to C language), where the letters in quotes have various formats. Please refer to other articles. The second colon indicates input, formatted as “r” (C language defined variable used in assembly language), with the letter meaning the same as output; the third colon indicates that memory or a specific register will change during assembly execution, allowing the compiler to handle it;
4. Due to the presence of input and output options, matching constraints must be used in the assembly code to refer to input/output values. The format is %0—9, allowing a maximum of 10 inputs/outputs, arranged in the order of output parameters followed by input parameters;
5. Because matching constraints use %, and AT&T assembly registers also require %, to distinguish them, you need to use two % signs before the register;
6. Assembly statements must be surrounded by parentheses, and there must be a semicolon at the end;
7. If following the above code format, each assembly line must have a “/n” newline character at the end.
The above is my experience in writing embedded assembly, hoping to help friends who encounter similar problems.