C/C++中书写汇编指令

汇编语言的指令格式目前有两种不同的标准:Windows下的汇编语言基本上都遵循Intel风格的语法,比如:MASM、NASM,Unix/Linux下的汇编语言基本上都遵循AT&T风格的语法。 下面主要介绍Unix/Linux下的汇编,具体格式如下:

[名称[:]] 指令码 源操作数SRC,目的操作数DST ;注释

开发一个OS,尽管绝大部分代码只需要用C/C++等高级语言,但是和硬件相关部分的代码需要使用汇编语言;由于启动部分的代码有大小限制,使用精练的汇编可以缩小目标代码的Size;另外,对于某些需要被经常调用的代码,使用汇编可以提高性能。
如果我们选择的OS开发工具是GCC以及GAS的话,就必须了解AT&T汇编语言语法,因为GCC/GAS只支持这种汇编语法。下面介绍GCC的内嵌汇编语法。
GCC 支持在C/C++代码中嵌入汇编代码,这些汇编代码被称作GCC Inline ASM——GCC内联汇编。这是一个非常有用的功能,有利于我们将一些C/C++语法无法表达的指令直接潜入C/C++代码中,另外也允许我们直接写 C/C++代码中使用汇编编写简洁高效的代码。

1.基本内联汇编

基本格式如下:

__asm__ [__volatile__] ( assembler template
: [output operand list] /* optional */
: [input operand list] /* optional */
: [clobbered register list] /* optional */
);

(1)关键字“__asm__”,其实也可以写成“asm”。但是“asm”并不是所有版本的GCC编译器都支持的,而且有可能和程序中别的地方定义的变量或函数名冲突,所以用“__asm__”的话,兼容性会好一点。 

(2)“__volatile__”关键字,这个是可选的,其作用是禁止编译器对后面编写的汇编指令再进行优化。一般情况下,自己写的汇编代码肯定是自己进行设计优化过了的,如果编译器再进行优化的话,很有可能效果还不如不优化,而且也有可能会出现奇怪的错误,所以通常都会带上这个关键字。同样,“__volatile__”也可以写成“volatile”,但可能兼容性会没那么好。

(3)汇编代码由4部分组成,分别是汇编代码模板、输出操作数列表、输入操作数列表和修改寄存器列表,下面进行介绍。

1)汇编代码模板

汇编代码部分是必需的,所以即使一行汇编代码没有也需要传入空字符串(""),否则会报错。所有的汇编代码必须用双引号括起来。如果有多行汇编代码的话,每一条语句都要用双引号括起来,并且在代码后面要加上换行符(“\n”或者“\n\t”)。这样做是因为GCC会将汇编代码部分作为字符串形式直接传给汇编器,加上换行符后,汇编器就能准确知道哪些字符串表示的是一条汇编语句。同时,为了增加可读性,每条汇编语句都可以换行。

2)输入操作数列表与输出操作数列表

前面介绍了,第二部分和第三部分分别表示输出操作数列表和输入操作数列表。

输入操作数表示要作为汇编代码输入的C表达式,而输出操作数刚好相反,表示汇编代码处理完后要输出结果的C表达式。如果有多个输出或输入表达式,需要用逗号(“,”)将它们分隔开来。

可以再前面的汇编代码模板中直接应用定义的输出操作数和输入操作数,其用法是使用百分号(“%”)后面接一个数字,0表示定义的第一个操作数,1表示定义的第二个操作数,依次类推。下面举个例子:

__asm__("mov %0, %1, ror #1"
            : "=r" (result)
            : "r" (value)
        );

这里%0代表后面定义的第一个操作数,即输出操作数,代表C语言中的result变量。%1代表定义的第二个操作数,即输入操作数,代表C语言中的value变量。其作用是将value的值右移一位,然后保存到result中。

每一个操作数由三部分组成,分别是修改符(Modifier),限定符(Constraint)和C表达式,其中修改符是可选的。具体形式如下:  

"[modifier]constraint" (C expression)

修改符和限定符要用双引号括起来,而C表达式要用括号括起来。那么这些修改符和限定符又是什么呢?有什么作用呢?
我们接下来先来说说所谓的限定符。可以看出,操作数在这里的作用是将C语言定义的变量与汇编语言中要使用到的变量进行一一对应。但并不是所有的汇编指令都可以接受任何类型的变量作为输入或输出变量的,因此汇编器需要知道这些变量到底用在什么地方,从而帮助在传递之前做一些转换。常用的限定符主要有以下一些,而且汇编语句到底是ARM的还是Thumb的,对限定符的定义也会不同:

  

参考文章 :

(1)如何在C或C++代码中嵌入ARM汇编代码 https://blog.csdn.net/Roland_Sun/article/details/42921131

(2)汇编与C/C++内联嵌入汇编 https://blog.csdn.net/Levet/article/details/78516307

原文地址:https://www.cnblogs.com/mazhimazhi/p/11367634.html

时间: 2024-10-05 23:09:05

C/C++中书写汇编指令的相关文章

[zhuan]arm中的汇编指令

http://blog.csdn.net/qqliyunpeng/article/details/45116615 一. 带点的(一般都是ARM GNU伪汇编指令) 1. ".text".".data".".bss" 依次表示的是 “以下是代码段”, “以下是初始化数据段”, “以下是未初始化数据段”. 2.".global" 定义一个全局符号,通常是为ld使用.比如经常看到的 .global _start 3.".

ARM中的汇编指令

BIC:ARM指令,对某些位,清零.先取反再相与. asm("BIC  r2, r2, #0x1f");        ##对R2的低5位清零. ORR:ARM指令,逻辑或 asm("ORR r2, r2, #0x10");       ##R2逻辑与0x10. MRS:asm("MRS  r2, CPSR");          ##将CPSR的值加载到R2中. MSR:asm("MSR  CPSR, r2");      

一些汇编指令

AX Accumulator   用累加器进行的操作 输入输出 乘除 操作BX 基址寄存器 (Base Register) CX 计数寄存器 (Count Register)常用于 循环 计数器  在 位操作中 要用 CL来指明 位移的位数DX  数据寄存器(Data Register)  在 进行 双字节 运算时  也可以 存放 io 的端口地址MOV 数据传送指令 ADD 算数指令编程环境 Masm  调试 工具 DebugDebug  cpu 各种 寄存器 的 内容 内存的情况 在机器码中

Android 图解逆向工程中ARM常用汇编指令(一)

我们走得太快,灵魂都跟不上了. 微小的幸福就在身边,容易满足就是天堂. 在逆向和爆破中我们经常会在IDA中接触到汇编,一般做安卓的不会太了解VB回编等,不太了解的同学可以先查看上篇文章<Android ARM常用的汇编指令合集> 再来继续我们的学习,我们先来看张图. 这个view里面有 PUSH/LDR/SUB/MOVS/BLX/SUBS/BEQ/CMP ,这些差不多都是常见的,不过也不需要看得懂,理解这个指令即可,接下来我们就来分析下这些指令分别有什么作用吧. 先引入 概念性 东西,免得大家

汇编指令大全

blt   小于跳转 tst r0,#02 bne sleep ldr  r1,#0 解释:位比较,先进行and运算,如果r0第2位不为1,则与的结果为0,设置标志位zero=1,继续下面的ldr指令.反之,zero=0,跳转到sleep执行. bne指令: 非零则跳转 个人总结:tst 和bne连用: 先是用tst进行位与运算,然后将位与的结果与0比较,如果不为0,则跳到bne紧跟着的标记(如bne sleep,则跳到sleep处). tst 和beq连用: 先是用tst进行位与运算,然后将位

ARM汇编指令汇总

1.ARM汇编的格式:    在ARM汇编里,有些字符是用来标记行号的,这些字符要求顶格写:有些伪码是需要成对出现的,例如ENTRY和END,就需要对齐出现,也就是说他们要么都顶格,要么都空相等的空,否则编译器将报错.常量定义需要顶格书写,不然,编译器同样会报错.    2.字符串变量的值是一系列的字符,并且使用双引号作为分界符,如果要在字符串中使用双引号,则必须连续使用两个双引号.    3.在使用LDR时,当格式是LDR r0,=0x022248,则第二个参数表示地址,即0x022248,同

GNU ARM 汇编指令

http://blog.chinaunix.net/u2/87718/showart_1683402.html GNU ARM 汇编指令简介第一部分 Linux下ARM汇编语法尽管在Linux下使用C或C++编写程序很方便,但汇编源程序用于系统最基本的初始化,如初始化堆栈指针.设置页表.操作 ARM的协处理器等.初始化完成后就可以跳转到C代码执行.需要注意的是,GNU的汇编器遵循AT&T的汇编语法,可以从GNU的站点(www.gnu.org)上下载有关规范. 一. Linux汇编行结构任何汇编行

lab4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

李俊锋 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验原理 1.1系统调用的意义 (1)把用户从底层的硬件编程中解放出来 (2)极大的提高了系统的安全性 (3)使用户程序具有可移植性 1.2系统调用过程 (1)当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数. (2)在Linux中是通过执行int $0x80来执行系统调用的,这条汇编指令产生向量

Linux中的汇编简介

GNU as汇编语法 GNU汇编语法使用的是AT&T汇编它和Intel汇编的语法主要有以下一些不同: AT&T汇编中的立即操作数前面要加上'$',寄存器操作数名前要加上百分号'%',绝对跳转操作数前要加上'*',Intel的语法均不包含这些符号: AT&T语法与Intel语法中使用的源操作数和目的操作数顺序正好相反,AT&T的源操作数和目的操作数是从左到右,Intel语法是从右到左,例如add eax, 4在AT&T语法中是addl $4, %eax: AT&