内联汇编

参考:GCC-Inline-Assembly-HOWTO (ibiblio.org)

1.概述

说明:

指定编译器将一个函数代码直接复制到调用其代码的地方执行,与默认压栈调用方式不同,称这种函数为内联函数

实现:

指定编译器将一个函数处理为内联函数,在函数声明前加上 inline 关键字

特性:

可以操作 C 语言变量,比如可以从 C 语言变量获取值,输出值到 C 语言变量,因此asm 用作汇编指令和包含它的 C 程序之间的接口

2.GCC汇编格式

UNIX 汇编语法(两种格式)

AT&T格式

OP-code src dst 
  • AT&T 语法中,第一个操作数是源操作数,第二个是目的操作数
  • AT&T 语法中,寄存器名前面有 % 前缀
  • AT&T 语法中,立即数都有 ‘$’ 前缀
  • AT&T 语法中,操作符的最后一个字符决定着操作数访问内存的长度:以 ‘b’、‘w’ 和 ‘l’ 为后缀指明内存访问长度是 byte(8-bit)、word(16-bit) 还是 long(32-bit)
  • AT&T 语法中,基址寄存器是放在小括号 ()内的

Intel格式

Intel 语法

1. 基本指令格式

OP-code dst, src
  • Intel语法中,第一个操作数是目的操作数,第二个是源操作数
  • Intel语法中,寄存器名前面没有 % 前缀
  • Intel语法中,基址寄存器是放在小括号 []内的

3.基本内联汇编

asm("assembly code");

内联汇编有多条指令,则每行都要加上双引号,并且该行要以 \n\t 结尾(标准格式的规范性)

例如:

 asm ("movl %eax, %ebx\n\t"
         "movl $56, %esi\n\t"
         "movl %ecx, $label(%edx,%ebx,$4)\n\t"
         "movb %ah, (%ebx)");

4.扩展内联汇编

基本内联汇编只涉及到嵌入汇编指令,扩展形式中还可以指定操作数,可以选择输入输出寄存器,以及指明要修改的寄存器列表

对于要访问的寄存器,并不一定要要显式指明,也可以留给GCC自己去选择,这可能让GCC更好去优化代码

模板

asm (
   "assembler template"                /* 汇编指令模板,包含具体的汇编代码 */
  : "output operands"                 /* 输出操作数,可选部分 */
  : "input operands"                  /* 输入操作数,可选部分 */
  : "list of clobbered registers"     /* 被修改的寄存器列表,可选部分 */
);

具体示例

int a = 5, b = 10, result;

asm (
   "addl %%ebx, %%eax;"  /* 汇编指令:将 ebx 中的值加到 eax 中 */
  : "=a" (result)       /* 输出:result 存储 eax 的结果 */
  : "a" (a), "b" (b)    /* 输入:a 和 b 分别存储在 eax 和 ebx 中 */
  : "eax", "ebx"        /* 被修改的寄存器:eax 和 ebx */
);

语法解析

没有输出操作数但有输入操作数,那么输出操作数前的冒号不能省

    asm ("cld\n\t"
   "rep\n\t"
   "stosl"
  : /* no output registers */
  : "c" (count), "a" (fill_value), "D" (dest)
  : "%ecx", "%edi"
  );

每个操作数由一个操作数约束字符串描述,后面小括号中跟 C 语言变量或表达式

    int a=10, b;
   asm ("movl %1, %%eax;
        movl %%eax, %0;"
        :"=b"(b)        /* output */
        :"c"(a)         /* input */
        :"%eax"         /* clobbered register */
      );  

限制字符表

限定字符含义
a将输入变量放入eax
b将输入变量放入ebx
c将输入变量放入ecx
d将输入变量放入edx
S将输入变量放入esi
D将输入变量放入edi
q将输入变量放入eax,ebx ,ecx ,edx中的一个
r将输入变量放入通用寄存器,也就是eax ,ebx,ecx,edx,esi,edi中的一个
A放入eax和edx,把eax和edx,合成一个64位的寄存器(uselong longs)
m内存变量
o操作数为内存变量,但是其寻址方式是偏移量类型,也即是基址寻址,或者是基址加变址寻址
V操作数为内存变量,但寻址方式不是偏移量类型
,操作数为内存变量,但寻址方式为自动增量
p操作数是一个合法的内存地址(指针)
g将输入变量放入eax,ebx,ecx ,edx中的一个或者作为内存变量
X操作数可以是任何类型
+操作数在指令中是读写类型的(输入输出操作数)
f浮点数
t第一个浮点寄存器
u第二个浮点寄存器
G标准的80387
%该操作数可以和下一个操作数交换位置
#部分注释
*表示如果选用寄存器,则其后的字母被忽略
&表示输入和输出操作数不能使用相同的寄存器

5.简单示例

#include <stdio.h>

int main()
{
int a = 10; // 定义并初始化变量 a 为 10
int b = 20; // 定义并初始化变量 b 为 20
int c; // 定义变量 c
int d; // 定义变量 d

// 内联汇编代码块
asm("movl %3, %%eax \n" // 将变量 b 的值移动到 eax 寄存器
"movl %%eax, %1 \n" // 将 eax 寄存器的值移动到变量 d
:"=b"(c),"=c"(d) // 输出操作数,c 和 d 分别绑定到 b 和 c 寄存器
:"d"(a),"S"(b) // 输入操作数,a 和 b 分别绑定到 d 和 S 寄存器
:"%eax" // 通知编译器 eax 寄存器在此代码块中被修改
);

printf("d = %d\n", d); // 打印变量 d 的值
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇