Linux的gcc可以看汇编,linux gcc 内嵌汇编
通常嵌入到 C 代码中的汇编语句很难做到与其它部分没有任何关系,因此更多时候需要用到完整的内联汇编格式,即汇编模板:
__asm__ __volatile__ ("asm statements" : outputs : inputs : registers-modified);
__asm__
表示后面的代码为内嵌汇编,
asm
是
__asm__
的别名。
__volatile__
表示编译器不要优化代码,后面的指令保留原样,
volatile
是它的别名。括号里面是汇编指令。
插入到 C 代码中的汇编语句是以":"分隔的四个部分,其中第一部分就是汇编代码本身,通常称为指令部,其格式和在汇编语言中使用的格式基本相同。指令部分是必须的,而其它部分则可以根据实际情况而省略。如果使用了后面的部分,而前面部分为空,也需要用“:”格开,相应部分内容为空。
下面介绍模板中的四个部分:
1、汇编语句模板汇编语句模板由汇编语句序列组成,语句之间使用“;”、“\n”或“\n\t”分开。指令中的操作数可以使用占位符引用C语言变量,操作数占位符最多10个,名称如下:%0,%1,…,%9。指令中使用占位符表示的操作数,总被视为long型(4个字节),但对其施加的操作根据指令可以是字或者字节,当把操作数当作字或者字节使用时,默认为低字或者低字节。对字节操作可以显式的指明是低字节还是次字节。方法是在%和序号之间插入一个字母,b代表低字节,h 代表高字节,例如:%h1。2、输出部分输出部分描述输出操作数,不同的操作数描述符之间用逗号格开,每个操作数描述符由限定字符串和C 语言变量组成。每个输出操作数的限定字符串必须包含“=”表示他是一个输出操作数。例如:__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x) )描述符字符串表示对该变量的限制条件,这样GCC就可以根据这些条件决定如何分配寄存器,如何产生必要的代码处理指令操作数与C表达式或C变量之间的联系。3、输入部分输入部分描述输入操作数,不同的操作数描述符之间使用逗号格开,每个操作数描述符由限定字符串和C 语言表达式或者C语言变量组成。示例如下:例1:
__asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
例
2
:
Static __inline__ void __set_bit(int nr, volatile void * addr)
{
__asm__(
"btsl %1,%0"
:"=m" (ADDR)
:"Ir" (nr));
}
后例功能是将
(*addr)
的第
nr
位设为
1
。第一个占位符
%0
与
C
语言变量
ADDR
对应,第二个占位符
%1
与
C
语言变量
nr
对应。因此上面的汇编语句代码与下面的伪代码等价:
btsl nr, ADDR
,该指令的两个操作数不能全是内存变量,因此将
nr
的限定字符串指定为
“Ir”
,将
nr
与立即数或者寄存器相关联,这样两个操作数中只有
ADDR
为内存变量。
4、限制字符限制字符有很多种,有些是与特定体系结构相关,此处仅列出常用的限定字符和i386中可能用到的一些常用的限定符。它们的作用是指示编译器如何处理其后的C语言变量与指令操作数之间的关系。
5、破坏描述部分破坏描述符用于通知编译器我们使用了哪些寄存器或内存,由逗号格开的字符串组成,每个字符串描述一种情况,一般是寄存器名;除寄存器外还有“memory”。例如:“%eax”,“%ebx”,“memory”等。
第一个汇编的例子:输出字符
int main()
{
char const * MESSAGE = "hello world\n";
__asm__ __volatile__ ( "movl $4, %%eax;"
"movl $1, %%ebx;"
"movl %0, %%ecx;"
"movl $12 , %%edx;"
"int $0x80;"
: "=m" (MESSAGE)
);
//printf("hello\n");
return 0;
}
例子说明:
1.首先写出汇编的标识符:__asm__;然后写出模板的指令语句,在指令语句中寄存器的的前面要加两个%,但是在破坏描述部分语句中只用加一个%,具体参加例子2;
2.每条汇编语句用“”括起来,并用;标识语句的结束;语句中的%x标识站位符,由输入和输出语句中操作数描述符描述;内嵌汇编可以传递最多十个描述符;m标识变量为内存变量,= 标明是输出操作符;既然MESSAGE为输入变量,可以在模板中,直接把MESSAGE中的值直接写到ECX中,修改后的代码,如下所示:
int main()
{
char const * MESSAGE = "hello world\n";
__asm__ __volatile__ ( "movl $4, %%eax;"
"movl $1, %%ebx;"
"movl $12 , %%edx;"
"int $0x80;"
:
: "c" (MESSAGE)
);
return 0;
}实例代码2:
/* inline.c */
int main()
{
int a = 10, b = 0;
__asm__ __volatile__("movl %1, %%eax;\\n\\r"
"movl %%eax, %0;"
:"=r"(b) /* 输出 */
:"r"(a) /* 输入 */
:"%eax"); /* 不受影响的寄存器 */
printf("Result: %d, %d\\n", a, b);
}代码理解:
上面的程序完成将变量a的值赋予变量b,有几点需要说明:
变量b是输出操作数,通过%0来引用,而变量a是输入操作数,通过%1来引用。
输入操作数和输出操作数都使用r进行约束,表示将变量a和变量b存储在寄存器中。输入约束和输出约束的不同点在于输出约束多一个约束修饰符'='。
在内联汇编语句中使用寄存器eax时,寄存器名前应该加两个'%',即%%eax。内联汇编中使用%0、%1等来标识变量,任何只带一个'%'的标识符都看成是操作数,而不是寄存器。
内联汇编语句的最后一个部分告诉GCC它将改变寄存器eax中的值,GCC在处理时不应使用该寄存器来存储任何其它的值。
由于变量b被指定成输出操作数,当内联汇编语句执行完毕后,它所保存的值将被更新。
在内联汇编中用到的操作数从输出部的第一个约束开始编号,序号从0开始,每个约束记数一次,指令部要引用这些操作数时,只需在序号前加上'%'作为前缀就可以了。需要注意的是,内联汇编语句的指令部在引用一个操作数时总是将其作为32位的长字使用,但实际情况可能需要的是字或字节,因此应该在约束中指明正确的限定符:
限定符
意义
"m"、"v"、"o"
内存单元
"r"
任何寄存器
"q"
寄存器eax、ebx、ecx、edx之一
"i"、"h"
直接操作数
"E"和"F"
浮点数
"g"
任意
"a"、"b"、"c"、"d"
分别表示寄存器eax、ebx、ecx和edx
"S"和"D"
寄存器esi、edi
"I"
常数(0至31)
Linux的gcc可以看汇编,linux gcc 内嵌汇编相关推荐
- ATT汇编语言与GCC内嵌汇编简介
AT&T汇编语言与GCC内嵌汇编简介 1 AT&T 与INTEL的汇编语言语法的区别 1.1大小写 1.2操作数赋值方向 1.3前缀 1.4间接寻址语法 1.5后缀 1.6指令 2 G ...
- GCC如何编译内嵌汇编代码
内核代码绝大部分使用C 语言编写,只有一小部分使用汇编语言编写,例如与特定体系结构相关的代码和对性能影响很大的代码.GCC提供了内嵌汇编的功能,可以在C代码中直接内嵌汇编语言语句,大大方便了程序设计 ...
- GCC在C语言中内嵌汇编 asm __volatile__
在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器,以及如何将计算结果写回C 变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可 ...
- c语言转汇编编译器,【转】C语言内嵌汇编(asm)
TIPS:在编译过程汇中,汇编代码块是原封不动地送到汇编语言编译阶段的. 一.为什么会用到汇编? 1.为了提高速度和效率.不过这种情况很少了,现在C/C++编译器的优化很厉害了. 2.为了实现某些C语 ...
- linux c语言编程内嵌汇编,gcc编译c语言中内嵌汇编
gcc编译c语言中内嵌汇编 --AT&T and Intel 汇编语法对照 寄存器命名: AT&T: %eax Intel: eax AT&T 语法源地址在左侧,目的地址在右 ...
- __asm__ __volatile__ GCC的内嵌汇编语法 ATT汇编语言语法(Z)
此文在网上到处转载,已不知原出处,我也将之记录在此,并改正其中的一些小笔误. 开 发一个OS,尽管绝大部分代码只需要用C/C++等高级语言就可以了,但至少和硬件相关部分的代码需要使用汇编语言,另外,由 ...
- GCC的内嵌汇编语法 ATT汇编语言语法
__asm__ __volatile__ GCC的内嵌汇编语法 AT&T汇编语言语法(一) 2007年05月09日 12:36 开 发一个OS,尽管绝大部分代码只需要用C/C++等高级语言就可 ...
- 转载:asm volatile GCC的内嵌汇编语法 ATT汇编语言语法
asm volatile GCC的内嵌汇编语法 AT&T汇编语言语法 目录 asm volatile GCC的内嵌汇编语法 AT&T汇编语言语法 1 Overview 2. GC ...
- Linux C: 内嵌汇编语法
学内嵌汇编首先知道编译器的编译流程,内嵌汇编就是嵌套在高级程序语言中的汇编语言.在cpp 文件转成 .s 汇编文件时,内嵌汇编保持不动,只有高级程序语言会编译成汇编合成在.s文件中.下面的链接将了C的 ...
最新文章
- Tomcat 1099端口占用重启无效,查不到进程,改换端口无效解决方案
- java webpack web项目_官方出品,微信小程序和 Web 端同构解决方案——kbone
- 自己觉得比较好的专业书籍
- 苏老师首播3小时!超500人观看!录屏!源码!PPT……你要的都在这里!
- 并发基础知识:死锁和对象监视器
- pythonselenium一个简单的自动化测试实战:百度搜索
- 有没有人带?这些都是学习生信的一大助力!
- 阈值和阀值的区别_基于双阈值设定的图像识别产品策略
- 协议圣经 -协议之服务编写(九)
- 基于C语言的软件,基于C语言的计算机软件编程分析
- 计算机网络学习笔记(7. 报文交换与分组交换①)
- git原理和常用操作
- python字符串创建_python独特的字符串创建
- 西门子主程序调用子程序_西门子S7-200系列PLC子程序的调用方法
- python 绘制太阳花
- 唐平中讲座笔记 Reinforcement mechanism design 20171107
- html5 扩展 cs6,Dreamweaver CS6提高了HTML5工具的效率
- 计算机选择固态硬盘,好马配好鞍,电脑是选固态硬盘还是机械硬盘?
- 2021年饶州中学高考成绩查询,鄱阳饶州中学2019高考成绩喜报、一本二本上线人数情况...
- JAVA 创建文件和文件夹,删除文件和文件夹的实用工具(转载自-张长胜)
热门文章
- 步骤3 - Orchestra将请求转发给微服务提供者
- Apache HttpClient库的日志级别设置原理
- Percent encode in consulting package
- GraphQL query的schema校验
- junit - no runnable methods
- SAP CRM Fiori busy dialog的工作原理
- 增强现实和3D渲染技术是如何应用在SAP产品里的
- 从OpenFOAM的源码中查找信息
- ts获取服务器数据_基于Nginx的媒体服务器技术-线上公开课
- 高并发 python socket send 异步_在Python中使用异步Socket编程性能测试