【Intel 汇编】寄存器、寻址方式、简单规则

此处汇编仅仅为了看懂Linux下编译、连接、载入过程及原理

Intel 汇编规则:

  在汇编程序中,立即数前面要加$,寄存器名前面要加%,以便跟符号名区分开。

  mov 源 目的(字长用指令的后缀l表示32位)

#PURPOSE: Simple program that exits and returns a
#      status code back to the Linux kernel
#
#INPUT:   none
#
#OUTPUT:  returns a status code. This can be viewed
#      by typing
#
#      echo $?
#
#      after running the program
#
#VARIABLES:
#      %eax holds the system call number
#      %ebx holds the return status
#
 .section .data

 .section .text
 .globl _start
_start:
 movl $1, %eax    # this is the linux kernel command
        # number (system call) for exiting
        # a program

 movl $4, %ebx    # this is the status number we will
        # return to the operating system.
        # Change this around and it will
        # return different things to
        # echo $?

 int $0x80    # this wakes up the kernel to run
        # the exit command

这段汇编代码相当于在C程序的main函数中return 4

.开头的名称称为汇编指示(Assembler Directive)或伪操作(Pseudo-operation),不会被翻译成机器指令,而是给汇编器一些特殊指示。

.section指示把代码划分成若干个段(Section),程序被操作系统加载执行时,每个段被加载到不同的地址,操作系统对不同的页面设置不同的读、写、执行权限。

.data段保存程序的数据,是可读可写的,相当于C程序的全局变量。

.text段保存代码,是只读和可执行的。

_start是一个符号(Symbol),符号在汇编程序中代表一个地址,可以用在指令中,汇编程序经过汇编器的处理之后,所有的符号都被替换成它所代表的地址值。.globl指示告诉汇编器,_start这个符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号。

.globl指示告诉汇编器,_start这个符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号。

movl $1, %eax
movl $4, %ebx
int $0x80
  • int指令称为软中断指令,可以用这条指令故意产生一个异常,异常的处理和中断类似,CPU从用户模式切换到特权模式,然后跳转到内核代码中执行异常处理程序。
  • int指令中的立即数0x80是一个参数,在异常处理程序中要根据这个参数决定如何处理,在Linux内核中int $0x80这种异常称为系统调用(System Call)。内核提供了很多系统服务供用户程序使用,但这些系统服务不能像库函数(比如printf)那样调用,因为在执行用户程序时CPU处于用户模式,不能直接调用内核函数,所以需要通过系统调用切换CPU模式,经由异常处理程序进入内核,用户程序只能通过寄存器传几个参数,之后就要按内核设计好的代码路线走,而不能由用户程序随心所欲,想调哪个内核函数就调哪个内核函数,这样可以保证系统服务被安全地调用。在调用结束之后,CPU再切换回用户模式,继续执行int $0x80的下一条指令,在用户程序看来就像函数调用和返回一样。
  • eaxebx的值是传递给系统调用的两个参数。eax的值是系统调用号,Linux的各种系统调用都是由int $0x80指令引发的,内核需要通过eax判断用户要调哪个系统调用,_exit的系统调用号是1。ebx的值是传给_exit的参数,表示退出状态。大多数系统调用完成之后会返回用户空间继续执行后面的指令,而_exit系统调用比较特殊,它会终止掉当前进程,而不是返回用户空间继续执行。

寻址方式

访问内存时在指令中可以用多种方式表示内存地址,比如可以用数组基地址、元素长度和下标三个量来表示,增加了寻址的灵活性。本节介绍x86常用的几种寻址方式(Addressing Mode)。内存寻址在指令中可以表示成如下的通用格式:

ADDRESS_OR_OFFSET(%BASE_OR_OFFSET,%INDEX,MULTIPLIER)

它所表示的地址可以这样计算出来:

FINAL ADDRESS = ADDRESS_OR_OFFSET + BASE_OR_OFFSET + MULTIPLIER * INDEX

其中ADDRESS_OR_OFFSET和MULTIPLIER必须是常数,BASE_OR_OFFSET和INDEX必须是寄存器。在有些寻址方式中会省略这4项中的某些项,相当于这些项是0。

    • 直接寻址(Direct Addressing Mode)。只使用ADDRESS_OR_OFFSET寻址,例如movl ADDRESS, %eax把ADDRESS地址处的32位数传送到eax寄存器。
    • 变址寻址(Indexed Addressing Mode) 。上一节的movl data_items(,%edi,4), %eax就属于这种寻址方式,用于访问数组元素比较方便。
    • 间接寻址(Indirect Addressing Mode)。只使用BASE_OR_OFFSET寻址,例如movl (%eax), %ebx,把eax寄存器的值看作地址,把内存中这个地址处的32位数传送到ebx寄存器。注意和movl %eax, %ebx区分开。
    • 基址寻址(Base Pointer Addressing Mode)。只使用ADDRESS_OR_OFFSET和BASE_OR_OFFSET寻址,例如movl 4(%eax), %ebx,用于访问结构体成员比较方便,例如一个结构体的基地址保存在eax寄存器中,其中一个成员在结构体内的偏移量是4字节,要把这个成员读上来就可以用这条指令。
    • 立即数寻址(Immediate Mode)。就是指令中有一个操作数是立即数,例如movl $12, %eax中的$12,这其实跟寻址没什么关系,但也算作一种寻址方式。
    • 寄存器寻址(Register Addressing Mode)。就是指令中有一个操作数是寄存器,例如movl $12, %eax中的%eax,这跟内存寻址没什么关系,但也算作一种寻址方式。在汇编程序中寄存器用助记符来表示,在机器指令中则要用几个Bit表示寄存器的编号,这几个Bit也可以看作寄存器的地址,但是和内存地址不在一个地址空间。

x86的寄存器

x86的通用寄存器有eaxebxecxedxediesi。这些寄存器在大多数指令中是可以任意选用的,比如movl指令可以把一个立即数传送到eax中,也可传送到ebx中。但也有一些指令规定只能用其中某个寄存器做某种用途,例如除法指令idivl要求被除数在eax寄存器中,edx寄存器必须是0,而除数可以在任意寄存器中,计算结果的商数保存在eax寄存器中(覆盖原来的被除数),余数保存在edx寄存器中。也就是说,通用寄存器对于某些特殊指令来说也不是通用的。

x86的特殊寄存器有ebpespeipeflagseip是程序计数器,eflags保存着计算过程中产生的标志位,包括进位标志、溢出标志、零标志和负数标志,在intel的手册中这几个标志位分别称为CF、OF、ZF、SF。ebpesp用于维护函数调用的栈帧

原文地址:https://www.cnblogs.com/kelamoyujuzhen/p/9054797.html

时间: 2024-10-10 11:06:37

【Intel 汇编】寄存器、寻址方式、简单规则的相关文章

Linux下AT&T汇编语法格式与Intel汇编语法格式异同

由于绝大多数的国内程序员以前只接触过Intel格式的汇编语言,很少或几乎没有接触过AT&T汇编语言,虽然这些汇编代码都是Intel风格的.但在Unix和Linux系统中,更多采用的还是AT&T格式,两者在语法格式上有着很大的不同,其实完全可以使用原来汇编的思路解决问题,只要掌握下面两者的不同: 一.在AT&T汇编格式中,寄存器名要加上' %'作为前缀:而在Intel汇编格式中,寄存器名不需要加前缀.例如: AT&T格式 Intel格式 pushl %eax push eax

[转]iOS高级调试&逆向技术-汇编寄存器调用

前言 本文翻译自Assembly Register Calling Convention Tutorial 序言 通过本教程,你会可以看到CPU使用的寄存器,并探索和修改传递给函数调用的参数.还将学习常见的苹果计算机架构以及如何在函数中使用寄存器.这就是所谓架构的调用约定. 了解汇编是如何工作的,以及特定架构调用约定是如何工作是一项极其重要的技能.它可以让你在没有源码的情况下,观察和修改传递给函数的参数.此外,因为源码存在不同或未知名称的变量情况,所以有时候更适合使用汇编. 比如说,假设你总想知

AT&T汇编和Intel汇编语法主要区别

AT&T使用$表示立即操作数,而Intel的立即操作数是不需要界定的.因此,使用AT&T语法引用十进制值4时,使用$4,使用Intel语法时只需使用4.   AT&T在寄存器名称前加上前缀%,而Intel不这样做.因此,使用AT&T语法引用EAX寄存器写为%eax.   AT&T语法处理源和目标操作数时使用相反的顺序.把十进制值4传送给EAX寄存器,AT&T的语法是movl $4, %eax,而Intel语法是mov eax, 4.   AT&T语法

IAA32过程调用寄存器的保护规则

由于操作系统中的共享性质,所以,寄存器也就成为了各个进程或者过程共享资源的一种.那么发生过程 调用的时候,如果调用者要用到一个寄存器里面的值,但是这个寄存器的内容很可能在被调用者运行过程中修改,那么我们就要在被调用过程执行之前,对该寄存器里面的内容进行保护,以至于不会出错,寄存器的保护规则也是因为程序的不可再现性而存在的. 在IA32上,实行了一个统一的寄存器保护规则.首先,我们要看一下,计算机中有多少个比较重要的寄存器 (偷偷懒我就不写寄存器前面的百分号了O(∩_∩)O) eax 这个寄存器属

2.汇编代码的简单实现

2.汇编代码的简单实现 使用汇编的原因很简单,就是汇编代码的高效.在机器启动的时候,利用汇编的高效,对硬件进行初始化,为加载内核,提供条件. 目前常用的ARM汇编指令有两种: *ARM标准汇编:适用于ARM公司的汇编器,适合在Windows平台下使用. *GNU汇编:使用与GNU交叉编译工具链中的汇编器,适合于Linux平台开发. 3.汇编程序框架:注意下面的操作环境是Redhat 6.4 + eclipse C/C++ +CDT插件. 汇编代码的基本框架 ? 汇编用到的地方,启动代码,效率要求

《Intel汇编第5版》 Intel CPU小端序

一.MASM汇编器中的数据类型 二.Intel汇编中的立即数类型 三.定义有符号和无符号整数 四.小端序 内存中数据按照字节存储,一个4个字节无符号整数,其高位存储在低地址上,低位存储在高地址上. 比如0x12345678这个整数,在内存中按照内存地址从小往大排列是:0X78 0x56 0x34 0x12 五.汇编代码验证 INCLUDE Irvine32.inc includelib Irvine32.lib includelib kernel32.lib includelib user32.

几个简单规则改进你的SEO效果

教大家几个简单规则,将应该帮助你改善你的结果.前两个规则教你选择如何构建你的技能(不管你的经验或实践的水平高低) 规则1:根据SEO原则,慎重选择获取相关信息声音. 搜索引擎优化,SEO是一个热门话题.如果你问网页设计或Web开发公司,他们可以执行搜索引擎优化,他们通常会告诉你“当然……我们可以排名在所有主要的搜索引擎.“很多人知道如何说话.但实际上很少知道如何获得结果”竞争激烈的“短语.很少经过任何专业培训.因为这篇文章是关于如何学习的技能,最合乎逻辑的问题要问“我可以看到一些示例搜索引擎你是

8.ARM寄存器详细解说ARM寄存器的简单分类:图1-1:

8.ARM寄存器详细解说 ARM寄存器的简单分类:图1-1: 图1-1 ARM微处理器中共有37个32位寄存器,其中31个通用寄存器,6个状态寄存器.但是这些寄存器不能被同时访问,在七种模式中,可以访问的寄存器种类不同.但是,通用寄存器R14--R0.程序计数器PC.一个状态寄存器cpsr都是可以被访问的. 具体的情况如下图1-2所示: 图1-2 寄存器分类: ????1.不分组通用寄存器: R0-R7是不分组寄存器.所谓不分组就是在七种模式下的任意一种模式都访问同一个物理寄存器地址.就是不分组

linux 下gcc生成intel汇编

留作备忘: gcc -S -masm=intel xxxx.c 生成elf可执行文件: gcc -o xxx xxxx.s linux 下gcc生成intel汇编,码迷,mamicode.com