知识大全 Linux 中 x86 的内联汇编

Posted 操作

篇首语:沉舟侧畔千帆进,病树前头万木春。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Linux 中 x86 的内联汇编相关的知识,希望对你有一定的参考价值。

Linux 中 x86 的内联汇编  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  作者 Bharata B Rao     将各个部分组合起来     如果您是 Linux 内核的开发人员 您会发现自己经常要对与体系结构高度相关的功能进行编码或优化代码路径 您很可能是通过将汇编语言指令插入到 C 语句的中间(又称为内联汇编的一种方法)来执行这些任务的 让我们看一下 Linux 中内联汇编的特定用法 (我们将讨论限制在 IA 汇编 )    GNU 汇编程序简述  让我们首先看一下 Linux 中使用的基本汇编程序语法 GCC(用于 Linux 的 GNU C 编译器)使用 AT&T 汇编语法 下面列出了这种语法的一些基本规则 (该列表肯定不完整 只包括了与内联汇编相关的那些规则 )    寄存器命名  寄存器名称有 % 前缀 即 如果必须使用 eax 它应该用作 %eax     源操作数和目的操作数的顺序  在所有指令中 先是源操作数 然后才是目的操作数 这与将源操作数放在目的操作数之后的 Intel 语法不同     mov %eax %ebx transfers the contents of eax to ebx     操作数大小  根据操作数是字节 (byte) 字 (word) 还是长型 (long) 指令的后缀可以是 b w 或 l 这并不是强制性的 GCC 会尝试通过读取操作数来提供相应的后缀 但手工指定后缀可以改善代码的可读性 并可以消除编译器猜测不正确的可能性     movb %al %bl Byte move   movw %ax %bx Word move   movl %eax %ebx Longword move    立即操作数  通过使用 $ 指定直接操作数     movl $ xffff %eax will move the value of xffff into eax register     间接内存引用  任何对内存的间接引用都是通过使用 ( ) 来完成的     movb (%esi) %al will transfer the byte in the memory     pointed by esi into al  register    内联汇编  GCC 为内联汇编提供特殊结构 它具有以下格式     GCG 的 asm 结构     asm ( assembler template     : output operands (optional)       : input operands (optional)       : list of clobbered registers    (optional)       );     本例中 汇编程序模板由汇编指令组成 输入操作数是充当指令输入操作数使用的 C 表达式 输出操作数是将对其执行汇编指令输出的 C 表达式     内联汇编的重要性体现在它能够灵活操作 而且可以使其输出通过 C 变量显示出来 因为它具有这种能力 所以 asm 可以用作汇编指令和包含它的 C 程序之间的接口     一个非常基本但很重要的区别在于简单内联汇编只包括指令 而扩展内联汇编包括操作数 要说明这一点 考虑以下示例     内联汇编的基本要素       int a= b;   asm ( movl % %%eax;   movl %%eax % ;    : =r (b) /* output */    : r (a) /* input */   : %eax ); /* clobbered register */      在上例中 我们使用汇编指令使 b 的值等于 a 请注意以下几点      b 是输出操作数 由 % 引用 a 是输入操作数 由 % 引用    r 是操作数的约束 它指定将变量 a 和 b 存储在寄存器中 请注意 输出操作数约束应该带有一个约束修饰符 = 指定它是输出操作数   要在 asm 内使用寄存器 %eax %eax 的前面应该再加一个 % 换句话说就是 %%eax 因为 asm 使用 % % 等来标识变量 任何带有一个 % 的数都看作是输入/输出操作数 而不认为是寄存器   第三个冒号后的修饰寄存器 %eax 告诉将在 asm 中修改 GCC %eax 的值 这样 GCC 就不使用该寄存器存储任何其它的值   movl % %%eax 将 a 的值移到 %eax 中 movl %%eax % 将 %eax 的内容移到 b 中   因为 b 被指定成输出操作数 因此当 asm 的执行完成后 它将反映出更新的值 换句话说 对 asm 内 b 所做的更改将在 asm 外反映出来   现在让我们更详细的了解每一项的含义     汇编程序模板  汇编程序模板是一组插入到 C 程序中的汇编指令(可以是单个指令 也可以是一组指令) 每条指令都应该由双引号括起 或者整组指令应该由双引号括起 每条指令还应该用一个定界符结尾 有效的定界符为新行 (\\n) 和分号 (;) \\n 后可以跟一个 tab(\\t) 作为格式化符号 增加 GCC 在汇编文件中生成的指令的可读性 指令通过数 % % 等来引用 C 表达式(指定为操作数)     如果希望确保编译器不会在 asm 内部优化指令 可以在 asm 后使用关键字 volatile 如果程序必须与 ANSI C 兼容 则应该使用 __asm__ 和 __volatile__ 而不是 asm 和 volatile     操作数  C 表达式用作 asm 内的汇编指令操作数 在汇编指令通过对 C 程序的 C 表达式进行操作来执行有意义的作业的情况下 操作数是内联汇编的主要特性     每个操作数都由操作数约束字符串指定 后面跟用括弧括起的 C 表达式 例如 constraint (C expression) 操作数约束的主要功能是确定操作数的寻址方式     可以在输入和输出部分中同时使用多个操作数 每个操作数由逗号分隔开     在汇编程序模板内部 操作数由数字引用 如果总共有 n 个操作数(包括输入和输出) 那么第一个输出操作数的编号为 逐项递增 最后那个输入操作数的编号为 n 总操作数的数目限制在 如果机器描述中任何指令模式中的最大操作数数目大于 则使用后者作为限制     修饰寄存器列表  如果 asm 中的指令指的是硬件寄存器 可以告诉 GCC 我们将自己使用和修改它们 这样 GCC 就不会假设它装入到这些寄存器中的值是有效值 通常不需要将输入和输出寄存器列为 clobbered 因为 GCC 知道 asm 使用它们(因为它们被明确指定为约束) 不过 如果指令使用任何其它的寄存器 无论是明确的还是隐含的(寄存器不在输入约束列表中出现 也不在输出约束列表中出现) 寄存器都必须被指定为修饰列表 修饰寄存器列在第三个冒号之后 其名称被指定为字符串     至于关键字 如果指令以某些不可预知且不明确的方式修改了内存 则可能将 memory 关键字添加到修饰寄存器列表中 这样就告诉 GCC 不要在不同指令之间将内存值高速缓存在寄存器中     操作数约束  前面提到过 asm 中的每个操作数都应该由操作数约束字符串描述 后面跟用括弧括起的 C 表达式 操作数约束主要是确定指令中操作数的寻址方式 约束也可以指定     是否允许操作数位于寄存器中 以及它可以包括在哪些种类的寄存器中   操作数是否可以是内存引用 以及在这种情况下使用哪些种类的地址   操作数是否可以是立即数   约束还要求两个操作数匹配     常用约束  在可用的操作数约束中 只有一小部分是常用的 下面列出了这些约束以及简要描述 有关操作数约束的完整列表 请参考 GCC 和 GAS 手册     寄存器操作数约束 (r)  使用这种约束指定操作数时 它们存储在通用寄存器中 请看下例     asm ( movl %%cr % \\n : =r (cr val));    这里 变量 cr val 保存在寄存器中 %cr 的值复制到寄存器上 cr val 的值从该寄存器更新到内存中 指定 r 约束时 GCC 可以将变量 cr val 保存在任何可用的 GPR 中 要指定寄存器 必须通过使用特定的寄存器约束直接指定寄存器名     a %eax    b %ebx    c %ecx    d %edx    S %esi    D %edi    内存操作数约束 (m)  当操作数位于内存中时 任何对它们执行的操作都将在内存位置中直接发生 这与寄存器约束正好相反 后者先将值存储在要修改的寄存器中 然后将它写回内存位置中 但寄存器约束通常只在对于指令来说它们是绝对必需的 或者它们可以大大提高进程速度时使用 当需要在 asm 内部更新 C 变量 而您又确实不希望使用寄存器来保存其值时 使用内存约束最为有效 例如 idtr 的值存储在内存位置 loc 中     ( sidt % \\n : : m (loc));    匹配(数字)约束  在某些情况下 一个变量既要充当输入操作数 也要充当输出操作数 可以通过使用匹配约束在 asm 中指定这种情况     asm ( incl % : =a (var): (var));    在匹配约束的示例中 寄存器 %eax 既用作输入变量 也用作输出变量 将 var 输入读取到 %eax 增加后将更新的 %eax 再次存储在 var 中 这里的 指定第 个输出变量相同的约束 即 它指定 var 的输出实例只应该存储在 %eax 中 该约束可以用于以下情况     输入从变量中读取 或者变量被修改后 修改写回到同一变量中   不需要将输入操作数和输出操作数的实例分开   使用匹配约束最重要的意义在于它们可以导致有效地使用可用寄存器     一般内联汇编用法示例  以下示例通过各种不同的操作数约束说明了用法 有如此多的约束以至于无法将它们一一列出 这里只列出了最经常使用的那些约束类型      asm 和寄存器约束 r   让我们先看一下使用寄存器约束 r 的 asm 我们的示例显示了 GCC 如何分配寄存器 以及它如何更 cha138/Article/program/Oracle/201311/17556

相关参考

知识大全 一起学习在linux下使用汇编语言(1)

  作者luster  摘要我开始学习在Linux使用汇编语言了我以前从来没有在Linux下使用过汇编语言我今天看到了一份文档是LinuxAssemblyHOWTO我看了看决定学习学习下面是我的学习笔

知识大全 一起学习在linux下使用汇编语言(3)

  作者luster  摘要:NeideAsseblerProject计划提供了一个非常好用的i汇编器这个汇编器是用C写的可以支持很多种对象文件格式  今天我们接着看看还有其他什么可以选择的汇编编译器

知识大全 一起学习在linux下使用汇编语言(5)

  作者luster  摘要:好吧我们已经铺垫了很多东西了而且看上去用汇编写程序似乎是一个非常恐怖的事情了不过既然我们感兴趣还是应该开始我们的helloworld程序  我们开始写helloworld

知识大全 解析PHP中VC6 X86和VC9 X86的区别及 Non Thread Safe的意思

解析PHP中VC6X86和VC9X86的区别及NonThreadSafe的意思  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,

“头顶马聚源,脚踩内联升,身穿瑞蚨祥,腰缠四大恒”,这首老北京民谣形象地反映了老字号在市场心目中的地位。荣宝斋的字画、享

“头顶马聚源,脚踩内联升,身穿瑞蚨祥,腰缠四大恒”,这首老北京民谣形象地反映了老字号在市场心目中的地位。荣宝斋的字画、享得利的钟表、月盛斋的酱肉、张一元的茶叶、十八街的麻花、狗不理的包子……这些耳熟能

知识大全 SQL联合查询(内联、左联、右联、全联)的语法

SQL联合查询(内联、左联、右联、全联)的语法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  概

知识大全 js获得内联和连接和行内的方式

  varsheet=documentstyleSheets[];  varrules=sheetcssRules||sheetrules;  varrule=rules[];  alert(rule

演员张三从摄影师李四为自己摄影的照片中选择了200张,汇编成摄影影集,并由出版社出版,该汇编作品的作者是演员张三本人。_

演员张三从摄影师李四为自己摄影的照片中选择了200张,汇编成摄影影集,并由出版社出版,该汇编作品的作者是演员张三本人。_____答案:正确解析:《著作权法》第14条规定,汇编若干作品、作品的片段或者不

知识大全 Linux中IP隧道的分析与建议

Linux中IP隧道的分析与建议  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  作者Wing  

知识大全 如何在Linux/390中定义SWAP卷

如何在Linux/390中定义SWAP卷  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  环境:S