Linux 汇编

Linux 汇编语法格式

绝大多数 Linux 程序员以前只接触过DOS/Windows 下的汇编语言,这些汇编代码都是 Intel 风格的。但在 Unix 和 Linux 系统中,更多采用的还是 AT&T 格式,两者在语法格式上有着很大的不同:

  1. 在 AT&T 汇编格式中,寄存器名要加上 ‘%‘ 作为前缀;而在 Intel 汇编格式中,寄存器名不需要加前缀。例如:

    AT&T 格式 Intel 格式
    pushl %eax push eax
  2. 在 AT&T 汇编格式中,用 ‘$‘ 前缀表示一个立即操作数;而在 Intel 汇编格式中,立即数的表示不用带任何前缀。例如:
    AT&T 格式 Intel 格式
    pushl $1 push 1
  3. AT&T 和 Intel 格式中的源操作数和目标操作数的位置正好相反。在 Intel 汇编格式中,目标操作数在源操作数的左边;而在 AT&T 汇编格式中,目标操作数在源操作数的右边。例如:
    AT&T 格式 Intel 格式
    addl $1, %eax add eax, 1
  4. 在 AT&T 汇编格式中,操作数的字长由操作符的最后一个字母决定,后缀‘b‘、‘w‘、‘l‘分别表示操作数为字节(byte,8 比特)、字(word,16 比特)和长字(long,32比特);而在 Intel 汇编格式中,操作数的字长是用 "byte ptr" 和 "word ptr" 等前缀来表示的。例如:
    AT&T 格式 Intel 格式
    movb val, %al mov al, byte ptr val
  5. 在 AT&T 汇编格式中,绝对转移和调用指令(jump/call)的操作数前要加上‘*‘作为前缀,而在 Intel 格式中则不需要。
  6. 远程转移指令和远程子调用指令的操作码,在 AT&T 汇编格式中为 "ljump" 和 "lcall",而在 Intel 汇编格式中则为 "jmp far" 和 "call far",即:
    AT&T 格式 Intel 格式
    ljump $section, $offset jmp far section:offset
    lcall $section, $offset call far section:offset

    与之相应的远程返回指令则为:

    AT&T 格式 Intel 格式
    lret $stack_adjust ret far stack_adjust
  7. 在 AT&T 汇编格式中,内存操作数的寻址方式是
    section:disp(base, index, scale)

    而在 Intel 汇编格式中,内存操作数的寻址方式为:

    section:[base + index*scale + disp]

    由于 Linux 工作在保护模式下,用的是 32 位线性地址,所以在计算地址时不用考虑段基址和偏移量,而是采用如下的地址计算方法:

    disp + base + index * scale

    下面是一些内存操作数的例子:

    AT&T 格式 Intel 格式
    movl -4(%ebp), %eax mov eax, [ebp - 4]
    movl array(, %eax, 4), %eax mov eax, [eax*4 + array]
    movw array(%ebx, %eax, 4), %cx mov cx, [ebx + 4*eax + array]
    movb $4, %fs:(%eax) mov fs:eax, 4

-------------------------------------------------------------------------------------------------
三、linux内核中ATT汇编实例分析。

 movl %eax,PT_EAX(%esp)  (#define PT_EAX 24)
  --------------->mov [esp+24] ,eax 
将eax寄存器中的值写入到内存地址(esp + 24)中。

时间: 2024-08-08 06:49:29

Linux 汇编的相关文章

Linux汇编与C互相调用

一.简介 C语言调用汇编有两种方式:1.通过内嵌汇编  2.通过编译链接. 二.基础知识 对于C和汇编语言的接口主要有两个问题需要解决 1.调用者与被调用者的参数传递 正常的,定义一个函数总是希望它完成某些功能,一个毫无用处的函数将毫无意义.这些功能有常常是更大的功能的一部分,而函数完成这些功能或多或少都要与外界联系(一个完全不与外界联系的函数也是一个毫无意义的函数)(延时函数也要消耗时间,时间也属于外界的一种资源),比如要传递一些数据给其处理,处理过后返回处理的结果.这种数据的传递可以形象的通

Linux汇编教程01: 基本知识

在我们开始学习Linux汇编之前,需要简单的了解一下计算机的体系结构.我们不需要特别深入的了解,理解了一些基本概念对与我们理解程序会很有帮助.现在计算机的结构体系都是采用冯诺依曼体系结构的基础上发展过来的.而冯诺依曼的体系有两个主要组成部分:CPU和内存.而我们的汇编语言和这两个部分十分密切. 1.1 内存结构 内存的结构就像一排连续的房子,或者是一种矩阵.每个空间的大小是固定的,且每一个存储单元都有自己的地址或者编号.房子的地址是门牌号,而内存的每个单元都有自己的地址. 计算机的内存有数以万计

Linux汇编GAS调用C语言函数实例

Blum的书上只讲了C语言调用汇编,没讲汇编调用C语言.我自己尝试了下. 最终试验成功了,在此写出与大家分享.期间历经无数错误,无数异常,我不是醉了,而是跪了...好在最后好了. 程序实现一个换值功能,在main.s里定义a=10,b=20,然后调用C语言函数把a,b换值. 新建两个文件分别为main.s的汇编文件,还有pro.c的C语言函数文件. main.s的代码如下: .section .data a: .int 10 b: .int 20 .section .text .globl ma

Linux汇编-回忆录一

===汇编基础====汇编语言程序由定义好的段构成,常用三个段:数据段  初始值的数据元素BSS段   使用零初始化的数据元素文本段  程序代码 注明:在BSS段中声明的数据,是不包含在可执行程序中的,但是数据段必然包含在科执行程序中 汇编的编写有如下规则:定义段      使用.section伪指令定义)定义入口点  使用.globl伪指令定义,用于标明程序从哪个            开始执行程序,一般默认为.global _start            如果是GCC编译,定义为.glo

Linux汇编实例讲解(一)

我们使用的平台是Linux系统,具体为CentOS-64位版.下面是第一个汇编程序的源码: # 目的:退出Linux内核并返回一个简单的状态码 # # 输入:无 # # 输出:控制台上没有输出,可以用echo $?来查看状态码 # # 变量: # %eax 保存系统调用号 # %ebx 保存返回状态 # .section .data .section .text .globl _start _start: movl $1, %eax #这是用于退出程序的Linux内核命令号(系统调用) movl

Linux汇编教程02:编写第一个汇编程序

学习一门语言,最好的方式就是在运用中学习,那么在这一章节中,我们开始编写我们的第一个汇编程序.当然作为第一个程序,其实十分的简单,但可以给大家一个基本的轮廓,了解汇编大概是这样的. 我们这个程序实际上没什么作用,只是简单的推出而已.下面就是程序的范例 # 目的: 退出程序并向Linux内核返回一个状态码 # 输入: 无 # 输出: 返回一个状态码.在程序运行结束后可以通过 echo $? 来读取状态码 # 变量: %eax保存系统调用号 %ebx保存返回状态 .section .data .se

linux 汇编函数调用

edi第一个参数 esi第二个参数 edx第三个参数 rax保存结果 C++代码如下: char* demo(char* a,int b){ static char* buf=0; if(!buf)buf=new char[1024]; return buf;}int main(){char* tmp=0;tmp++;tmp=demo(0,1);return 0;} 汇编代码如下:

30>>linux汇编

编辑器就是普通的编辑器,vim,emacs,gedit,kate源文件类型为ascii码的plain text 编译用gcc或者nasm,前者编译AT&T汇编,后者编译intel汇编8086的教材上一般都是用intel,不过区别不大,可以相互转化 链接就是ld,属于gcc工具集 例子: hello.asm 源代码如下: *************************************************************section .textglobal mainmain

Linux汇编教程03:大小比较操作

我们在上一讲中,简单了解了汇编程序大概的样子.接下来我们来了解一下,汇编程序的大小比较操作.所以我们以编写寻找一堆数中的最大值作为学习的载体. 在编写程序之前,先要分析我们的目的,在得出解决方案. 目的:在一堆数中找到最大的数 思路:要实现这个目的,首先,我们一定要对数据进行索引,每一次比较,两个数应该分别占用一个寄存器,得到最大值,所以,我们有一个寄存器一定是存放最大值的.一开始没有最大值,我们不妨设第一个数为最大值,后面一次索引大小比较.得出最大值.索引中还会用到循环结构. 解决方案——代码