运行C语言内嵌汇编程序linux与VS2019
GCC内嵌汇编
基本行内汇编
基本格式:
asm("statements");// statements为汇编语句
__asm__ __volatile__("hlt");// 不要优化代码,保持原样指令
如果有多行汇编,则每一行后都要加上“\n\t”,例如:
asm( "pushl %eax\n\t"
"movl $0,%eax\n\t"
"popl %eax");
或者可以写多行:
asm("movl %eax,%ebx");
asm("xorl %ebx,%edx");
asm("movl $0,_booga);
扩展的行内汇编
- 在扩展的行内汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入寄存器,以及如何将计算结果写回C变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可, GCC会自动插入代码完成必要的操作。
- 使用内嵌汇编,要先编写汇编指令模板,然后将C语言表达式与指令的操作数相关联,并告诉GCC对这些操作有哪些限制条件。例如:
__asm__ __violate__ ("movl %1,%0" : "=r" (result) : "r"(input));
// “movl %1,%0”是指令模板;“%0”和“%1”代表指令的操作数,称为占位符,“=r”代表它之后是输入变量且需用到寄存器,指令模板后面用小括号括起来的是C语言表达式 ,其中input是输入变量,该指令会完成把input的值复制到result中的操作
内嵌汇编语法
基本格式:
// __asm__(
// 汇编语句模板:
// 输出部分:
// 输入部分:
// 寄存器修改部分--提醒编译器这个寄存器的值将要改变);
asm ( "statements" : output_regs : input_regs : registers-modified)
扩展行内汇编共分四个部分:汇编语句模板,输出部分,输入部分,破坏描述部分,各部分使用“:”格开,汇编语句模板必不可少,其他三部分可选,如果使用了后面的部分,而前面部分为空,也需要用“:”格开,相应部分内容为空。例如:
int main(void)
{
int dest;
int value=1;
asm(
"movl %1, %0"
: "=a"(dest)
: "c" (value)
: "%ebx");
printf("%d\n", dest);
return 0;
}
- 限定字符
限定字符便是内嵌汇编中放在引用的C变量之前的字符,它们的作用是指示编译器如何处理其后的C语言变量与指令操作数之间的关系,例如是将变量放在寄存器中还是放在内存中等,常用的如下:
限定字符 | 描述 |
---|---|
a、b、 c、 d、 s、 D | 具体的一个寄存器 |
q、r、A | 混合的寄存器 |
m、o、V、p | 内存 |
g、X | 寄存器或内存 |
I、J、N、i、n | 立即数 |
=、+ | 操作数类型 |
- 汇编语句模板
汇编语句模板由汇编语句序列组成,语句之间使用“;”、“\n”或“\n\t”分开。
例如:
asm( "pushl %eax\n\t"
"movl $0,%eax\n\t"
"popl %eax");
指令中的操作数可以使用占位符引用C语言变量,操作数占位符最多10个,名称如下:%0,%1…,%9。指令中使用占位符表示的操作数,总被视为long型(4,个字节)。
但对其施加的操作根据指令可以是字或者字节,当把操作数当作字或者字节使用时,默认为低字或者低字节。对字节操作可以显式的指明是低字节还是次字节。方法是在%和序号之间插入一个字母,“b”代表低字节,“h”代表高字节,例如:%h1。
- 输出部分
输出部分描述输出操作数,不同的操作数描述符之间用逗号格开,每个操作数描述符由限定字符串和C语言变量组成。每个输出操作数的限定字符串**必须包含“=”**表示它是一个输出操作数。例如:
__asm__ __volatile__ ("pushfl ; popl %0 ; cli":"=g" (x) )
//在这里“x”便是最终存放输出结果的C程序变量,而“=g”则是限定字符串,限定字符串表示了对它之后的变量的限制条件
- 输入部分
输入部分描述输入操作数,不同的操作数描述符之间使用逗号格开,每个操作数描述符同样也由限定字符串和C语言表达式或者C语言变量组成。例如:
__asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
Visual C++使用内联汇编
基本汇编块
基本格式:
__asm{
statements}//statements为汇编语句
// 例子
__asm
{
MOV AL, 2
MOV DX, 0XD007
OUT AL, DX
}
也可以分多行写,需要在每一句前面加__asm,例如:
__asm MOV AL, 2
__asm MOV DX, 0xD007
__asm OUT AL, DX
扩展写法(使用C语言变量)
亲自运行一个内联汇编程序
1.符号,包括标号、变量和函数名;
2.常量,包括符号常量和枚举型(enum)成员;
3.宏定义和预处理指示符;
4.注释,包括"“和”//";
5.类型名,包括所有MASM中合法的类型
6.typedef名称, 像PTR、TYPE、特定的结构成员或枚举成员这样的通用操作符。
例如:
int dest;
int value = 666;
__asm {
MOV eax, value;
MOV dest, eax;
};
printf("%d\n", dest);
return 0;
Linux Ubuntu
程序:
int main(void)
{
int dest;
int value=1;
asm(
"movl %1, %0"
: "=a"(dest)
: "c" (value)
: "%ebx");
printf("%d\n", dest);
return 0;
}
运行结果:
Visual Studio 2019
程序:
#include<stdio.h>
int main(void)
{
int dest;
int value = 666;
__asm {
MOV eax, value;
MOV dest, eax;
};
printf("%d\n", dest);
return 0;
}
运行截图: