C语言函数内可以自定义一段汇编代码,在GCC编译器中使用 asm 或 __asm__ 关键词定义一段汇编代码,并可选添加volatile关键字,表示不要让编译器优化这段汇编代码。

内嵌汇编代码格式如下:

__asm__
(
    "汇编代码"
    :输出描述
    :输入描述
    :修改描述
);

汇编代码部分

汇编代码部分是一个字符串,嵌入的汇编代码使用此字符串存储,多个汇编代码语句之间使用;符号隔开,字符串可以换行存储,换行存储方式如下:

__asm__
(
    "mov eax,ecx; \
    add eax,ebx;"
);

或者:

__asm__
(
    "mov eax,ecx;"
    "add eax,ebx;"
);

注:
1.汇编代码中16进制数据只能使用0x前缀,不能使用h后缀。
2.指定内存数据长度时,使用 word prt 关键词,不能省略 prt。
3.内嵌汇编代码默认使用AT&T语法,若使用inter语法则需要在编译时添加如下参数:-masm=intel,本文使用inter汇编语法。

输出描述部分

若汇编代码执行完毕后需要将寄存器、内存单元中的数据保存在C语言代码定义的局部变量中,则需要在输出描述部分定义寄存器或内存单元与局部变量的绑定关系,绑定代码格式如下:

#include <stdio.h>
int main()
{
    int i;     __asm__
    (
        "mov eax,1; \
        mov ebx,2; \
        add eax,ebx;"
        
        :"=a"(i)          //输出描述部分,"=a"表示输出eax寄存器,(i)表示使用变量i接收输出数据
    );
    
    printf("%d\n", i);
    return 0;
}

输出描述部分使用简写代码表示要输出的寄存器或内存单元,常用代码如下:
a,表示ax系寄存器
b,表示bx系寄存器
c,表示cx系寄存器
d,表示dx系寄存器
S,表示si系寄存器
D,表示di系寄存器
r,表示自动分配的寄存器
m,表示自动分配的内存单元
g,表示自动分配的寄存器或内存单元

绑定的局部变量可以使用指针指定。

#include <stdio.h>
int main()
{
    int i;
    int *p1 = &i;
    
    __asm__
    (
        "mov eax,1; \
        mov ebx,2; \
        add eax,ebx;"
        
        :"=a"(*p1)
    );
    
    printf("%d\n", i);
    return 0;
}

输入描述部分

输入描述用于将局部变量与指定的寄存器或内存单元绑定,绑定的变量会首先复制到对应的寄存器或内存单元,然后再执行汇编代码。

#include <stdio.h>
int main()
{
    int i1, i2, i3;
    
    printf("输入两个整数\n");
    scanf("%d%d", &i1, &i2);
    
    __asm__
    (
        "add eax,ebx;"
        
        :"=a"(i3)            //输出描述部分,eax写入i3
        
        :"a"(i1), "b"(i2)    //输入描述部分,i1写入eax,i2写入ebx
    );
    
    printf("两数相加结果为:%d\n", i3);
    return 0;
}

修改描述部分

修改描述用于告知编译器哪些寄存器、内存单元被汇编代码修改过,让编译器在编译代码时对这些寄存器或内存单元进行保护,当然也可以手动进行保护,在使用寄存器之前首先将其入栈存储,在汇编代码末尾处还原寄存器。

修改描述注意事项:
1.若被修改的寄存器在输出描述、输入描述中记录过,则无需在修改描述中重复指定,编译器会自动处理。
2.若修改了内存单元,则应该在此部分定义"memory"。
3.若修改了标志寄存器,则应该在此部分定义"c"。

#include <stdio.h>
int main()
{
    int i1, i2, i3;
    
    printf("输入两个整数\n");
    scanf("%d%d", &i1, &i2);
    
    __asm__
    (
        "add eax,ebx; \
        mov edx,3; \
        imul ecx,edx"        //ecx与edx相乘仅做示例,没有实际作用
        
        :"=a"(i3)            //输出描述部分,eax写入i3
        
        :"a"(i1), "b"(i2)    //输入描述部分,i1写入eax,i2写入ebx
        
        :"ecx", "edx"        //修改描述部分,告知编译器ecx、edx被修改过,并且没有在输入输出描述中记录
    );
    
    printf("两数相加结果为:%d\n", i3);
    return 0;
}

编译器自动分配寄存器、内存单元

在汇编代码中存储数据时可以让编译器自动分配寄存器或内存,汇编代码使用“%数字”的方式调用编译器自动分配的寄存器或内存,比如:%0、%1、%2,这些名称称为占位符,占位符可以不按顺序定义。

占位符可以与输入输出描述中的局部变量绑定,绑定顺序为局部变量在输入输出描述中出现的顺序,%0绑定第一个变量、%1第二个、%2第三个。

#include <stdio.h>
int main()
{
    int i1, i2, i3;
    
    printf("输入两个整数\n");
    scanf("%d%d", &i1, &i2);
    
    __asm__
    (
        "add %1,%2; \
        mov %0,%1"
        
        :"=m"(i3)            //输出描述部分,%0写入i3,这里使用m,表示让编译器自动分配内存单元存储绑定的i3
        
        :"r"(i1), "r"(i2)    //输入描述部分,i1写入%1,i2写入%2,这里使用r,表示让编译器自动分配寄存器存储绑定的i1、i2
    );
    
    printf("两数相加结果为:%d\n", i3);
    return 0;
}

上面汇编代码中三个变量出现顺序是i3、i1、i2,%0绑定i3,%1绑定i1,%2绑定i2。

使用全局变量

在汇编代码中调用全局变量无需进行任何设置,直接使用变量名即可,编译器会自动转换为对应的内存地址。

#include <stdio.h>
int i1, i2;
int main()
{
    printf("输入两个整数\n");
    scanf("%d%d", &i1, &i2);
    
    __asm__  __volatile__
    (
        "push rax; \
        mov eax,i1; \
        add eax,i2; \
        mov i1,eax; \
        pop rax;"
    );
    
    printf("两数相加结果为:%d\n", i1);
    return 0;
}

上述汇编代码中,全局数据的名称无需放在[]符号内,但是若将一个立即数写入内存数据,则需要使用如下代码:mov dwort ptr[i1], 5;

09. C语言内嵌汇编代码的更多相关文章

  1. Ok6410裸机驱动学习(三)C语言内嵌汇编

    1.C语言内嵌汇编使用方法 C内嵌汇编以关键字”_asm_或asm开始,下辖4个部分,各部分之间用“:”分开,第一部分是必须写的,后面3个部分可以省略,但是分号:不能省略 优化后的代码 2.汇编程序框 ...

  2. C语言内嵌汇编(arm-v7)----加减乘移位

    在现代嵌入式操作系统中,汇编语言当然必不可少,汇编语言的优势就是执行速度快.如果在C语言的代码中,在关键的地方内嵌汇编,那么效率将会大大的提高,我们来看看代码: #include <stdio. ...

  3. 简单了解C语言内嵌汇编

    最近看自旋锁的实现,自选锁的循环查找锁的主要实现类似如下,该实现使用到了内嵌的汇编(摘自sanos内核,源代码有2处实现,一处使用intel汇编,是没有问题的,另一处使用内嵌汇编语法,源代码中为cmp ...

  4. vs2010 c++中内嵌汇编代码

    在研究汇编时,需要自己写点汇编代码测试,用Ollydbg写每次加载程序就没了,不是很方便. 可以考虑直接在程序中写入汇编代码,只需要加上关键字“_asm”宏(C++代码中). 如下示例 编写环境 :v ...

  5. 复习-C语言内嵌汇编-初级(1)

    打印hello world并改变变量i的值 # include <stdio.h> int main() { ; __asm__( "mov %0, #4\n" :&q ...

  6. 复习-C语言内嵌汇编-初级(2)

    汇编取出内存中的值 # include <stdio.h> int main() { ; ; int *p = &i; //ret = *p; __asm__( "ldr ...

  7. C++内嵌汇编代码,简单文件加密

    #include <iostream> #include <fstream> using namespace std; int main(int argc, char* arg ...

  8. GCC在C语言中内嵌汇编 asm __volatile__ 【转】

    转自:http://blog.csdn.net/pbymw8iwm/article/details/8227839 在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达 ...

  9. GCC在C语言中内嵌汇编 asm __volatile__

    2012-11-26 22:20 17958人阅读 评论(2) 收藏 举报  分类: linux(59)  架构管理(24)  C/C++(59)  目录(?)[+] 在内嵌汇编中,可以将C语言表达式 ...

  10. Beennan的内嵌汇编指导(译)Brennan's Guide to Inline Assembly

    注:写在前面,这是一篇翻译文章,本人的英文水平很有限,但内嵌汇编是学习操作系统不可少的知识,本人也常去查看这方面的内容,本文是在做mit的jos实验中的一篇关于内嵌汇编的介绍.关于常用的内嵌汇编(AT ...

随机推荐

  1. CSS样式中的各种居中方式

    1.水平居中 将margin-left和margin-right属性设置为auto,从而达到水平居中的效果. 代码: margin:0 auto; 2.文字水平垂直居中 利用line-height设为 ...

  2. #分治,Kruskal#洛谷 3206 [HNOI2010]城市建设

    题目 动态改边权求最小生成树 \(n\leq 2*10^4,m\leq 5*10^4,q\leq 5*10^4\) 分析 乍一看是线段树分治,但有一个很大的问题就是局部的Kruskal不一定是最后的选 ...

  3. 深究可见性,原子性,有序性的解决方案之volatile源码解析

    上节java内存模型(jmm)概念初探大致了解了由于cpu的快速发展,导致的越来越复杂的内存模型诞生,java内存模型相当于是底层内存模型的映射(实际并不是一一映射,但可以借鉴理解),也是衍生出并发三 ...

  4. keycloak~网站对接到Keycloak的步骤

    新网站对接到KC的部署 kc的环境 向kc申请自己的客户端 kc的登录接口 通过code换token接口 刷新token接口 kc的用户信息接口 kc的jwt token说明 1. kc的环境 测试环 ...

  5. 初学STM32 SDIO (二)

    ​ SD命令由主机发出,以广播命令和寻址命令为例,广播命令是针对与SD主机总线连接的所有从设备发送的,寻址命令是指定某个地址设备进行命令传输. 1.SD命令格式 SD命令格式固定为48bit,都是通过 ...

  6. 干货分享|身为顶尖的Hr,这个Excel插件你不能不知道,用上它事业开挂!

    第一季度,老板看了历年不同地区各销售业绩数据表的总结,说想知道新人进来多久才能成为成熟的销售,成长周期有多长? 我们人事被老板这个灵光一现的想法吓到了,大家伙上上下下为这件事情忙了4个日夜. 整整五年 ...

  7. 使用 K8S 部署 RSS 全套自托管解决方案- RssHub + Tiny Tiny Rss

    前言 什么是 RSS? RSS 是一种描述和同步网站内容的格式,是使用最广泛的 XML 应用.RSS 搭建了信息迅速传播的一个技术平台,使得每个人都成为潜在的信息提供者.发布一个 RSS 文件后,这个 ...

  8. Godot.NET C#IOC重构(2):TileMap 详解

    目录 前言 TileMap添加 TileMap绘制 TileMap 连续图块 修改纹理原点 统一设置 自动地形 匹配规则 修改匹配概率 修改概率前 修改概率后 随机图块 Scattering 不连续间 ...

  9. 日志分析qsnctfwp

    使用工具:http Logs Viewer 使用 http Logs Viewer 载入 access.log 按照 Status 排序 其中大量 Status 为404的日志不难推断出,这是在进行目 ...

  10. 重新点亮linux 命令树————内存与文件系统的查看[二十七]

    前言 简单介绍一下内存的查看. 正文 常用命令. free top 查看磁盘使用率: fdisk df du du和ls的区别 free -h 查看内存使用率: free -g 显示按G来显示,-m用 ...