内联汇编

AT&T汇编语法

GCC只支持AT&T汇编语法内嵌在C语言中。

Intel和AT&T汇编风格对比:

compare.png

AT&T寻址

寄存器间接寻址:

  • mov (%eax), %ebx ;表示将地址eax所指的内存复制4字节到ebx

寄存器相对寻址:

  • movb -4(%eax), %al; 表示将地址(eax - 4)所指的内存复制一字节到al

变址寻址:

segreg(段基址):base_address(offset_address,index,size)
对应表达式为:
segreg(段基址):base_address + offset_address + index * size

格式中不存在的部分要用‘,’占位,共有4种组合:

  • 无base_address,无offset_address

    movl %eax, (,%esi,2) -- 表示将eax的值写入esi*2所指的内存

  • 无base_address,有offset_address

    movl %eax,(%ebx,%esi,2) -- 表示将eax的值写入ebx + esi*2所指的内存

  • 有base_address,无offset_address

    movl %eax, base_value(,%esi,2) -- 表示将eax的值写入base_value + esi*2`所指的内存

  • 有base_address,有offset_address

    movl %eax, base_value(%ebx,%esi,2) -- 表示将eax的值写入base_value + %ebx + esi*2`所指的内存

基本内联汇编

内联汇编基本格式:

  asm [volatile] ("assembly code")  
  volatile关键字可选,使得gcc在-O指定优化时,不改变汇编代码

assembly code规则:

  1. 指令必须在双引号内。
  2. 指令之间用分号、换行符\n或者换行符加制表符\n\t分隔

示例:

char* str = "hello,world\n";
int count = 0;
void main(){
    asm volatile ("\
        pusha; \
        movl $4, %eax; \
        movl $1, %ebx; \
        movl str, %ecx; \
        movl $12, %edx; \
        int $0x80; \
        movl %eax, count; \
        popa \
    ");
}

扩展内联汇编

当汇编代码嵌入到C代码中,如何找到可用的寄存器是个问题,程序员不知道哪些寄存器已经被分配。GCC提供了扩展内联汇编格式。

扩展内联汇编格式:

asm [volatile] ("assembly code" : output : input : clobber/modify)

  1. output : <output> 用来指定汇编代码的数据如何传递给C代码使用,output中每个操作数的格式为:

"操作数修饰符 + 约束名"(C变量名)

引号和圆括号不可少,操作数修饰符通常为‘=’。多个操作数之间用‘,’分隔

  1. input : <input> 用来指定C中数据如何传递给汇编使用,input中每个操作数的格式为:

”[操作数修饰符] + 约束名“(C变量名)

引号和圆括号不可少,操作数修饰符为可选项。多个操作数之间用‘,’分隔

  1. clobber/modify : 汇编代码执行后会破坏一些内存或寄存器资源,通过此项通知编译器,哪些寄存器或内存需要提前保护起来。

  2. 约束名

    寄存器约束

    寄存器约束就是要求gcc使用哪个寄存器

    a: eax/ax/al
    b: ebx/bx/bl
    c: ecx/cx/cl
    d: edx/dx/dl
    D: edi/di
    S: esi/si
    q: eax/ebx/ecx/edx中任意一个
    r: eax/ebx/ecx/edx/esi/edi中任意一个
    g: 表示存放到任意地点(寄存器和内存)
    A:把eax和edx组合成64位整数
    f: 表示浮点寄存器
    t: 表示第1个浮点寄存器
    u: 表示第2个浮点寄存器
    

    示例:

 #include <stdio.h>
 void main(){
     int in_a = 1, in_b = 2, out_sum;
     asm ("addl %%ebx, %%eax":"=a"(out_sum):"a"(in_a),"b"(in_b));
     printf("sum = %d\n",out_sum);
  }

ps: 扩展内联汇编中寄存器前缀是两个%

内存约束

m: 表示操作数可以使用任意一种内存形式
o: 操作数位内存变量

示例 :

#include <stdio.h>

void main(){
    int in_a = 1, in_b = 2;
    asm ("movb %b0, %1"::"a"(in_a),"m"(in_b));
    printf("in_b = %d\n",in_b);
}

%1序号占位符,代表in_b的内存地址(指针)

%b0表示对寄存器eax的引用,b表示一个字节,所以%b0表示al寄存器

立即数约束

只放在input中

i: 整数立即数
F: 浮点数立即数
I: 0-31之间的立即数
J: 0-63之间的立即数
N: 0-255之间的立即数
O: 0-32之间的立即数
X: 任何类型的立即数

通用约束

0-9: 只用在input部分,表示与output和input中第n个操作数用相同的寄存器或内存
  1. 占位符

    为方便对操作数的引用,扩展内联汇编提供了占位符来表示指定操作数。

    序号占位符

    序号占位符是对在output和input中的操作数,按照他们从左到右出现的次序从0开始编号,一直到9,最多支持10个序号占位符。引用它的格式是%0-9

    若%0表示eax,则%h0 -- 表示ah,%b0表示al

    名称占位符

    可以对操作数进行显示命名,格式如下:

    [名称]”约束名“(c变量)
    采用%[名称]的形式引用操作数

    示例:

    #include <stdio.h>
    
    void main(){
        int in_a = 18, in_b = 3, out = 0;
        asm ("divb %[divisor]; movb %b1, %[result]":[result]"=m"(out):"a"(in_a),[divisor]"m"(in_b));
        printf("out = %d\n",out);
    }
    
  2. 操作数修饰符

    在output中:

    =: 表示操作数只写
    +: 表示操作数可读写
    &: 表示此output中的操作数要独占约束(分配的)寄存器,只供output使用,任何input中分配的寄存器不能与此相同
    

    input中:

    %: 该操作数可以和下一个输入操作数交换
    

    一般情况下input中的C变量是只读的,output中的C变量是只写的。

    示例:

    #include <stdio.h>
    
    void main(){
        int in_a = 1, in_b = 2;
        asm ("addl %%ebx, %%eax":"+a"(in_a):"b"(in_b));
        printf("sum = %d\n",in_a);
    }
    

    参考

《操作系统真相还原》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容

  • 原文作者 Sandeep.S英文原文 [https://www.ibiblio.org/gferg/ldp/GCC...
    JeffreyLi阅读 40,071评论 8 41
  • lodsb: ds:[esi] -> al stosb: al -> es:[edi] SCASB: 比较 [ed...
    lindyang阅读 749评论 0 0
  • 对于输出部和输入部编号 输入代表在汇编开始的时候进行的赋值,或者与汇编中的占位相对应,在本例中,汇编中只用到%4,...
    Wi1ls努力努力再努力阅读 709评论 0 1
  • 文章来自这里:gcc内联汇编...... 在阅读Linux内核源码或对代码做性能优化时,经常会有在C语言中嵌入一段...
    Yihulee阅读 824评论 0 0
  • 推荐指数: 6.0 书籍主旨关键词:特权、焦点、注意力、语言联想、情景联想 观点: 1.统计学现在叫数据分析,社会...
    Jenaral阅读 5,717评论 0 5