当前位置:网站首页>gnu汇编语言使用内联汇编 扩展asm
gnu汇编语言使用内联汇编 扩展asm
2020-11-10 08:45:00 【osc_qalfjuu8】
Extended ASM format 扩展的asm格式:
asm关键字的扩展格式如下:
asm ("assembly code" : output operands : input operands : changed registers);
上面的扩展格式由四个部分组成,每个部分之间使用冒号隔开:
Assembly code: The inline assembly code using the same syntax used for the basic asm format
assembly code:即汇编代码部分,可以在该部分编写所需的内联汇编代码,和基本asm格式相比,扩展格式里的汇编代码除了在百分号的使用上有所不同外(下面会介绍),其他的汇编指令的书写格式都是差不多的
Output operands: A list of registers and memory locations that will contain the output values
from the inline assembly code
输出操作数:用于指定内联汇编代码的执行结果需要输出到哪个寄存器,以及需要输出到哪个C变量里
Input operands: A list of registers and memory locations that contain input values for the inline
assembly code
输入操作数:可以将C变量的值输入到指定的寄存器,这样就可以在内联汇编代码里,通过这些寄存器来使用到C变量的值了,这里的C变量既可以是全局变量,也可以是局部变量
Changed registers: A list of any additional registers that are changed by the inline code
被修改的寄存器:用于指明在内联汇编代码里修改了哪些寄存器,编译器会根据实际情况,对这些修改的寄存器进行一些push、pop之类的操作,这样,汇编代码修改的寄存器就不会影响到外面C代码的正常执行
并非每个部分都必须进行设置,假设你不需要第二个输出操作数,那么输出操作数部分就可以留空,不过需要注意的是,即便输出操作数留空,开头的两个冒号也必须保留,如:asm (“assembly code” : : input operands : changed registers);的格式,另外,如果不需要设置被修改的寄存器部分,那么最后一个冒号可以省略,如:asm (“assembly code” : output locations : input operands);的格式。
下面就介绍下扩展asm格式里输入和输出操作数的具体格式。
Specifying input and output values 输入和输出操作数:
输入和输出操作数的格式如下:
“constraint”(variable)
其中,括号里的variable表示C代码里定义的全局变量或局部变量,而引号里的constraint(约束)则表示用于存储variable变量值的寄存器或内存位置。对于输入操作数,constraint就是将variable变量的值读取到指定的寄存器,或者直接使用变量的内存位置。对于输出操作数,constraint就是先将结果存储到指定的寄存器,再将寄存器里的值设置到variable变量里,某些constraint(约束)也可以直接将结果写入到变量所在的内存里。
constraint(约束)是一个单一的字符,可用的约束符如下表所示:
Constraint
约束符 Description
描述
a Use the %eax, %ax, or %al registers.
使用%eax, %ax或%al寄存器
b Use the %ebx, %bx, or %bl registers.
使用%ebx, %bx或%bl寄存器
c Use the %ecx, %cx, or %cl registers.
使用%ecx, %cx或%cl寄存器
d Use the %edx, %dx, or $dl registers.
使用%edx, %dx或%dl寄存器
S Use the %esi or %si registers.
使用%esi或%si寄存器
D Use the %edi or %di registers.
使用%edi或%di寄存器
r Use any available general-purpose register.
使用任何可用的通用寄存器
q Use either the %eax, %ebx, %ecx, or %edx register.
使用%eax, %ebx, %ecx或%edx寄存器
A Use the %eax and the %edx registers
for a 64-bit value.
使用%eax和%edx寄存器来存储一个64位的值
f Use a floating-point register.
使用一个浮点寄存器
t Use the first (top) floating-point register.
使用第一个ST0浮点寄存器
u Use the second floating-point register.
使用第二个ST1浮点寄存器
m Use the variable’s memory location.
使用变量的内存位置
o Use an offset memory location.
使用一个带有偏移值的内存位置,例如:使用4(%edi)来表示EDI加偏移值4的内存地址,多用于数组元素的访问
V Use only a direct memory location.
使用不带偏移值的内存位置
i Use an immediate integer value.
表示操作数是一个立即数(常量整数值)
n Use an immediate integer value with a known value.
表示操作数是一个已知数值的立即数,在许多系统里,当操作数小于1个word(字)宽时,就不能使用i,而应使用n来表示立即数
g Use any register or memory location available.
可以使用任一通用寄存器或内存位置,或者操作数是一个立即数
除了上面的这些约束外,对于操作数还包含一个constraint modifier(约束修饰符),用于表示操作数是否可读写之类的,可用的约束修饰符如下表所示:
Constraint modifier
约束修饰符 Description
描述
- The operand can be both read from
and written to.
说明操作数是可读写的,例如"+r",指的是在内联汇编指令开始前,必须先将变量的值赋值给对应的寄存器(也就是读的过程),在执行完汇编指令后,再将寄存器的值写入变量(即写的过程)
= The operand can only be written to.
说明操作数是只写的,例如"=r",就是说,只需将结果写入变量,至于内联汇编指令执行前,对应寄存器里的值则可以是任意值,无需在执行前读取变量的值。
% The operand can be switched with the
next operand if necessary.
在必要时,操作数可以和下一个操作数进行交换,下面会举例说明
& use ‘&’ for each output operand that may
not overlap an input
&修饰符是用来强制编译器为输入操作数与输出操作数分配不同的寄存器
可以参考
http://blog.csdn.net/bokee/article/details/7029353
该链接里的文章
上面的约束修饰符里"+"、"="、"&“这三个只能用于修饰输出操作数,不能用于修饰输入操作数,而”%“则刚好相反,只能用于修饰输入操作数,”%"的用法可以参考下面的代码:
int main(int __argc, char* __argv[])
{
int __in1 = 8, __in2 = 4, __out = 3;
asm (“addl %1, %0\n\t”
: “=r”(__out)
: “%r” (__in1), “0” (__in2));
return 0;
}
在此例中,由于指令是一个加法运算,相当于等式__out = __in1 + __in2,而它与等式__out = __in2 + __in1没有什么不同。所以使用百分号修饰,让GCC知道__in1和__in2可以互换,也就是说GCC可以自动将本例的内联汇编改变为:
-
asm (“addl %1, %0\n\t”
-
“=r”(__out)
-
“%r” (__in2), “0” (__in1));
上面的代码例子来源于:http://tieba.baidu.com/p/310375553 ,另外上面例子里的%1和%0等是占位符,占位符的含义会在下面的介绍里进行说明。用的较多的是第一个"+“和第二个”="修饰符,例如下面的代码模板:
asm (“assembly code” : “=a”(result) : “d”(data1), “c”(data2));
上面的代码模板,表示将data1变量的值读取到EDX寄存器,将data2变量的值读取到ECX寄存器,内联汇编代码在执行完后,会将结果保存到EAX寄存器,最后,EAX里的值会写入到result变量里,这里必须要在"a"约束前面添加"="修饰符,表示result操作数可以写入数据,否则,由于在没有修饰符的情况,该操作数表示只读,GCC编译器就会报"output operand constraint lacks ‘=’“的错误,即输出操作数的约束缺少”=“修饰符。当然也可以使用”+"修饰符来表示输出操作数可读写。
Using registers 在扩展asm格式里使用寄存器:
在上一篇文章里介绍的基本asm内联汇编格式里,寄存器的使用方式和在单独的汇编文件里的使用方式一样,只需要在寄存器名称前加一个百分号即可,但是在本章介绍的扩展asm格式里,内联汇编代码里要使用寄存器时,必须在寄存器的名称前加两个百分号,例如:%%eax 这样的形式,第一个百分号用于对第二个百分号进行转义,这样两个百分号就可以表示一个普通的百分号来修饰eax,之所以要这么做,是因为%在扩展asm格式里有特殊的用途,就像C语言字符串里的"\n"字符里的"\"字符用于和"n"字符一起来表示特殊的换行符一样,单个百分号用于和数字一起来表示下面会提到的占位符。
下面的regtest1.c程式就演示了如何在扩展的asm格式里使用寄存器:
/* regtest1.c – An example of using registers */
#include <stdio.h>
int main()
{
int data1 = 10;
int data2 = 20;
int result;
asm ("imull %%edx, %%ecx\n\t"
"movl %%ecx, %%eax"
: "=a"(result)
: "d"(data1), "c"(data2));
printf("The result is %d\n", result);
return 0;
}
上面的代码里,在将data1和data2局部变量的值分别加载到EDX和ECX后,在asm的汇编代码里,就会通过imull %%edx, %%ecx指令将EDX和ECX寄存器的值相乘,计算结果存储到ECX里,然后通过movl %%ecx, %%eax指令将ECX里的值输出到EAX里,最后EAX里的值会写入到result局部变量里,这样在随后的C代码里就可以使用printf函数来将result的值给显示出来。这里需要注意寄存器的写法,如:%%ecx等都有两个百分号,原因在上面已经解释了。
参考文章:
https://www.zengl.com/a/201404/146.html
版权声明
本文为[osc_qalfjuu8]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/4389636/blog/4710497
边栏推荐
- [paper reading notes] a multilayered informational random walk for attributed social network embedding
- csdn bug5:待加
- mac终端Iterm2支持rz和sz的解决方案
- What's the difference between delete, truncate, and drop, and what to do if you delete data by mistake
- Coding style: SSM environment in MVC mode, code hierarchical management
- 编码风格:Mvc模式下SSM环境,代码分层管理
- CUDA_主机内存
- 实验2
- [论文阅读笔记] Network Embedding with Attribute Refinement
- 推动中国制造升级,汽车装配车间生产流水线 3D 可视化
猜你喜欢

Explanation of Z-index attribute

CSDN bug6: to be added

【LeetCode】 93 平衡二叉树

对于程序员,那些既陌生又熟悉的计算机硬件

Promote China manufacturing upgrade, 3D visualization of production line in automobile assembly workshop

An unsafe class named unsafe

Seam engraving algorithm: a seemingly impossible image size adjustment method

Android quick shutdown app

Mongodb index management of distributed document storage database

初级工程师如何在职场生存
随机推荐
One image can hold 16x16 words! ——Transformers for large scale image scaling recognition (a brief review of ICLR 2021 papers)
编码风格:Mvc模式下SSM环境,代码分层管理
《Python Cookbook 3rd》笔记(2.2):字符串开头或结尾匹配
Promote China manufacturing upgrade, 3D visualization of production line in automobile assembly workshop
接缝雕刻算法:一种看似不可能的图像大小调整方法
异常:Invalid or unexpected token
csdn bug7:待加
CSDN bug4: to be added
利用尾巴作为时间序列进行处理来识别鲸鱼
Several solutions to the problem that selenium webdriver always fails to use click
CUDA_获取指定设备
OSChina 周二乱弹 —— 我养的绿植分别为土豆,生姜,蒜
csdn bug4:待加
[论文阅读笔记] Large-Scale Heterogeneous Feature Embedding
lodash.js源码-flatten
[论文阅读笔记] Network Embedding with Attribute Refinement
CSDN bug7: to be added
分布式文档存储数据库之MongoDB索引管理
一个名为不安全的类Unsafe
【LeetCode】 92 整数反转