linux平台学x86汇编(十八):内联汇编

【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途】

使用汇编语言笔编程最常见的方式是在高级语言(C和C++)程序内编写汇编函数,这种吧汇编语言直接写到C和C++语言程序内的技术称为内联汇编。

GNU的C编译器使用asm关键字指出使用汇编语言编写的源代码段落。asm段的基本格式如下:

asm("as code");

括号中的汇编指令必须在括号,指令超过一条的话必须使用新的行分隔汇编语言代码每一行,因为编译器逐字地取得asm段中汇编代码,并且把它们放在为程序生成的汇编代码中,有时可以使用制表符字符缩进指令以便它们和标签区别开。下面是一个简单的内联汇编的示例:

asm("movl $1, %eax\n\t movl $0,%ebx\n\tint $0x80");

该示例包括3条指令,在使用很多汇编指令时会显得有些混乱,所以一般把指令放在单独的行中。

        asm("movl $1, %eax\n\t"
                "movl $0,%ebx\n\t"
                "int $0x80");

利用C全局变量可以把数据传递进和传递出内联汇编语言,注意不能使用局部变量。

#include <stdio.h>
int     result = 10;
int main(int argc, const char *argv[])
{
    asm("addl $1, result\n\t"
        "subl $2, result\n\t");
    printf("the result is  %d\n", result);
    return 0;
}

使用gcc生成汇编代码如下:

 .file "inline-as.c"
.globl result
.data
.align 4
.type result, @object
.size result, 4
result:
.long 10
.section .rodata
.LC0:
.string "the result is  %d\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
#APP
# 7 "inline-as.c" 1
addl $1, result
subl $2, result

# 0 "" 2
#NO_APP
movl result, %edx
movl $.LC0, %eax
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-3)"
.section .note.GNU-stack,"",@progbits

c文件编译执行结果为:

$ ./inline-as
the result is  9
$

反编译的汇编代码中#APP和#NOAPP之间的代码为asm段指定的内联汇编代码。

ANSI C规范在使用内联汇编语句时使用关键字__asm__替换关键字asm,因为ANSI C 关键字asm用于其他用途。如下:

    __asm__("addl $1, result\n\t"
        "subl $2, result\n\t");

基本的asm格式提供创建汇编代码的简单样式,但是有一些局限性。首先,所有输入值和输出值都必须使用C程序的全局变量,如上示例所见。其次,在内联汇编代码中不去改变任何寄存器的值。GNU编译器提供asm段的扩展格式来帮助解决这些问题。扩展格式采用新的格式,如下:

<span style="font-family:Microsoft YaHei;">asm ("as code": output location : input operands : changed registers);</span>

该格式由4个部分构成,使用冒号分隔:汇编代码、输出位置、输入操作数、改动的寄存器。在扩展asm格式中,不是所有部分必须出现。

大多数程序员把内联汇编代码定义为宏函数,定义方式和C语言类似。定义内联汇编宏函数如下:

    #define CAL ({
            asm("addl $1, result\n\t"
            "subl $2, result\n\t");
            })

这里asm语句必须要在一对花括号中,以便指出语句的开头和结尾,否则编译器会生成错误信息。

如下为使用宏的一个简单示例:

#include <stdio.h>
#define CAL ({     asm("addl $1, result\n\t"        "subl $2, result\n\t");        })
int     result = 10;
int main(int argc, const char *argv[])
{
    CAL;
    printf("the result is  %d\n", result);
    return 0;
}
时间: 2024-08-02 06:57:57

linux平台学x86汇编(十八):内联汇编的相关文章

linux平台学x86汇编(十九):C语言中调用汇编函数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 除了内联汇编以外,还有一种途径可以把汇编代码整合到C/C++语言中,C/C++语言可以直接调用汇编函数,把输入值传递给函数,然后从函数获得输出值. 如果希望汇编语言函数和C/C++程序一起工作,就必须显示地遵守C样式的函数格式,也就是说所有输入变量都必须从堆栈读取,并且大多数输入值都返回到EAX嫁寄存器中.在汇编函数代码中,C样式函数对于可以修改哪些寄存器和函数必须保留哪些寄

linux平台学x86汇编(二十):汇编库的使用

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 汇编语言和C一样,可以通过使用库来简化阻止大量函数的目标文件的问题.GNU C编译器可以不在命令行中独立地包含每个独立地函数目标文件,它允许吧所有目标文件组合在单一存档文件中.在编译C程序时,要做的工作就是包含单一的目标库文件,在编译时,编译器可以从库文件中挑出所需的正确目标文件.在库文件中,经常按照应用程序类型或者函数类型把函数分组在一起,单一应用程序项目可以使用多个库文件

linux平台学x86汇编(八):条件跳转

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 在此之前我们使用的汇编代码示例都是从第一条指令开始,直到最后最后一条指令程序退出.但实际上和高级语言类似,汇编代码也提供指令来改变程序处理数据方式. 正常情况下,程序要执行要执行的下一条指令是在指令指针寄存器中,指令指针确定程序中哪条指令是应该执行的下一条指令. 当指令指针在程序指令中移动时,EIP寄存器会递增.指令长度可能是多个字节,所以指向下一条指令不仅仅是每次是指令指针

linux平台学x86汇编(十五):使用命令行参数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 在高级语言中,程序在命令行上启动时常常带一个或多个参数,在汇编语言中也可以实现这一特性.在实现这一特性之前,我们先了解一下linux如何从命令行执行程序. 每一个应用程序开始执行时,系统都会为该程序分配一块内存区域,并且每个程序都分配相同的虚拟内存地址.虚拟内存地址由操作系统映射到物理内存地址.在Linux中,程序的虚拟内存地址是从0x80480000开始,到地址0xbfff

linux平台学x86汇编(十四):函数的使用

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 和高级语言一样,汇编语言在多个项目之间可能会编写相同的过程和处理,如果使用函数的话就可以不必每次需要时都重复编写实用程序代码,从而在需要它的时候调用它. 函数包含完成特定功能所需的代码,数据从主程序传递给函数,然后结果返回给主程序.调用函数时,程序执行路径被改变,切换到函数代码的第一条指令.处理器从这个位置开始执行指令,直到函数表明它可以把控制返回到主程序中的原始位置. 在汇

linux平台学x86汇编(十六):在汇编语言中调用C库函数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 其实在汇编语言中也是可以使用C库函数的,这一节我们来看一下如何在汇编语言中调用C库函数以使得我们的程序看上去很方便地和用户交互. C库包括C程序通用的喝多函数,如printf和exit等,下面我们紧接着上一节的知识来实现一个两整数想加的计算并输出计算结果的程序. # libc.s .section .data output: .asciz "The result is %d.

linux平台学x86汇编(十):整数运算

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 这一节介绍如何在编语言中上使用整数运算,包括加法.减法.乘法和除法. 加法指令 add指令用于把两个整数想加.格式如下: add src, dest 其中src可以是立即数值.内存地址.寄存器.dest可以是寄存器或内存中的值,不能同时使用内存地址作为源和目标.结果存放在dest中.和其他GNU汇编指令一样,需要在add结尾添加b.w.l来指定操作数长度.如果没有使用整个寄存

linux平台学x86汇编(十二):字符串的存储与加载

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 字符串的存储与加载是指,将字符串的值加载到寄存器和将其传回内存位置中.其使用指令lods指令和stos指令. lods指令用于把内存中的字符串值传送到eax寄存器中,该指令有三种不同格式:lodsb(1字节).lodsw(2字节).lodsl(4字节).lods指令使用esi寄存器作为隐含的源操作数.esi寄存器必须包含要加载的字符串所在的内存地址. 在使用lods指令把字符

linux平台学x86汇编(三):相关开发工具

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 类似于其它高级语言,编写汇编语言,必须有一个开发环境,那么也就需要适当的工具了.搭建汇编语言至少应该有下面这些工具:汇编器.链接器.调试器.下下面看看在汇编语言开发环境中如何使用它们. 汇编器 汇编器用于把汇编语言源代码转换为处理器指令码.选择的汇编器必须能够生成所在系统的处理器系列指令码.汇编语言源代码程序有3个部分:操作码助记符.数据段.命令.但是每种汇编器对于每个部分使