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. 【Java】这条语句一共创建了多少个对象:String s="a"+"b"+"c"+"d";

    String s1 = "a"; String s2 = s1 + "b"; String s3 = "a" + "b" ...

  2. 掌上新闻随心播控,HarmonyOS SDK助力新浪新闻打造精致易用的资讯服务新体验

    原生智能是HarmonyOS NEXT的核心亮点之一,依托HarmonyOS SDK丰富全面的开放能力,开发者只需通过几行代码,即可快速实现AI功能.新浪新闻作为鸿蒙原生应用开发的先行者之一,从有声资 ...

  3. char * 、BSTR、long、wchar_t *、LPCWSTR、string、QString、CStringA类型转换

    char* 转 BSTR char* s1 = "zhangsan"; CString s2 = CString(s1); BSTR s3 = s2.AllocSysString( ...

  4. JS判断浏览器是否是IE

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Copy 进阶用法

    Copy 进阶用法 本文出处:https://www.modb.pro/db/239809 copy 是最基础的导入导出命令,那么它有什么其他用法可以帮助我们更好地进行导入导出的工作呢? 关于导入方式 ...

  6. 优先队列的基本实现【数据结构与算法—TypeScript 实现】

    笔记整理自 coderwhy 『TypeScript 高阶数据结构与算法』课程 特性 效率比普通队列高 每个出队元素拥有最高优先级 可以用 数组.链表 等数据结构实现,但是 堆结构 是最常用的实现方式 ...

  7. Tailwind CSS 使用指南

    0x01 概述 (1)简介 Tailwind CSS 官网:https://www.tailwindcss.cn/ Tailwind CSS 是一个 CSS 框架,使用初级"工具" ...

  8. Flutter笔记 - 事件分发

    事件处理流程 Flutter 事件处理流程主要分两步,为了聚焦核心流程,我们以用户触摸事件为例来说明: 命中测试:当手指按下时,触发 PointerDownEvent 事件,按照深度优先遍历当前渲染( ...

  9. PyQt 快速使用

    1.安装 PyQt:使用 pip 命令在终端或命令提示符中运行以下命令: pip install pyqt5 2.创建 PyQt 应用程序:导入 PyQt5 模块并创建一个 QApplication ...

  10. 1.css的初认识

    1.什么是CSS? Cascading Style Sheet 层叠级联样式表 CSS:表现层(美化网页) 字体.颜色.边距.高度.宽度.背景图片.网页定位.网页浮动.... 2.CSS发展史 CSS ...