[Intel汇编-NASM]基本指令

1. 过程调用:

    1) 即call和ret指令的组合使用,这里我们先介绍call指令的使用方式;

    2) 16位段内直接相对近调用:

        i. 格式:call near(可省) 标号/立即数;

        ii. near就表示近的意思,但是near可以省了,汇编器会默认为是16位段内直接相对近调用;

        iii. 直接是指:调用的过程的地址直接由立即数(即一个显示的汇编地址)或者标号(符号化的汇编地址)给出;

        iv. 段内:是指只给出了偏移地址而没有给出段地址,因此只能调用同一个段中的过程;

        v. 相对:是指不直接用标号或立即数对IP进行赋值,而是给出(在指令的二进制码中给出)目的地和当前跳转指令的下一条指令的汇编地址之差,即一个位移量,这使得程序的浮动性(灵活性)增强;

        vi. 16位是指位移量是一个16位的有符号数,因此跳转范围为[-32768, 32767],即最多向前跳32768个字节最多向后跳32767个字节;

    3) 16位段内间接绝对近调用:

        i. 格式:call r16/m16,其r16表示16位通用寄存器,m16表示16位内存单元;

        ii. 间接是指:跳转的地址不是直接给出而是存放在后面指定寄存器或内存中;

        iii. 绝对是指:直接将跳转地址值赋给IP而不是计算位移量;

        iv. 16位段内是指:偏移地址由16位单元给出,由于只给出了偏移地址而没有段地址因此只能在段内跳转,挑战范围是整个64KB的段空间界限;

    4) 16位段内直接相对近转移或间接绝对近转移的使用规范:建议不适用near关键字,这样方便记忆;

    5) 16位直接绝对远调用:

        i. 格式:call 立即数:立即数,即直接给出"段地址:偏移地址",立即数可以是标号、宏等;

        ii. 16位主要是约束偏移地址,即偏移地址只能是16位的,这也是理所应当的;

        iii. 直接绝对是指直接给出精确的物理地址(20位物理地址);

        iv. 这里的远调用是指由于给出了段地址,就可以全局地在段之间来换跳转了;

    6) 16位间接绝对远调用:

        i. 格式:call far m32,由于必须给出段地址和偏移地址,同时由于是8086体系不能使用32位寄存器保存地址,因此只能使用32位内存来保存了;

        ii. 16位同样是约束偏移地址的;

        iii. 间接是指调转地址保存在后面指定的内存中;

        iv. 绝对是指直接将内存中的段地址和偏移地址直接赋给cs:ip,同样是低位保存偏移地址高位保存段地址;

        v. 最常使用的手法是将跳转地址保存到一个标号所代表的数据区中,调用时直接取标号所在内存中的地址即可:

func_addr dw 0x1020, 0x2000
call far [func_addr]
    7) ret和retf:这在MASM讲过了,ret对应只给出偏移地址的近调用,retf对应给出全地址的远调用,后者比前者多一个cs的push和pop;


2. 无条件转移指令(和call的格式基本相似):

    1) 相对短转移:

        i. 格式:jmp short 立即数/标号

        ii. 只要是短转移必定都是直接的,即直接给出立即数/标号的偏移地址;

        iii. 短转移比近转移的范围还要小,同样也是相对的,即跳转一个位移量,但是范围只有1字节长度,即[-128, 127];

    2) 16位直接相对近转移:

        i. 格式:jmp near 立即数/标号

        ii. 同样也是段内的、位移量的跳转,范围是[-32768, 32767]的16位长度;

    3) 16位间接绝对近转移:

        i. 格式:jmp near r16/m16

        ii. 同样也是段内的、直接对ip赋值的跳转;

!!!注意:以上的短转移和近转移的short和near都可以省略,如果是标号或者立即数,汇编器会自动根据位移量的大小决定使用短转移还是近转移,如果给出的寄存器或内存则只能是间接绝对近转移了;

!短转移和近转移的使用规范:统一不加关键字short和near,这样简便且方便记忆!

    4) 16位直接绝对远转移:jmp far i16:i16,其中i16就是指16位立即数,也可以是标号或宏,和16位的远call相对应;

    5) 16位简介绝对远转移:jmp far m32,和16位的远call相对应;


3. 对call和jmp越界的检查:

    1) 对于间接近转移:由于给出地址的都是寄存器或内存,本身就已经限制在16位了,因此不可能会超出16位长度的跳转范围,因此没有产生超出范围报错的可能,但是CPU是笨的,并不会检查跳转是否超出了逻辑(人定义的)段的范围,比如虽然是在16位限制以内,但不会检查是否从.text段跳到了.data是不会检查的(也许这两个段相距很短);

    2) 对于short类型的短转移只检查跳跃范围是否超出[-128, 127],其余逻辑层面上的越界不检查;

    3) 对于直接近转移和前面short类型的检查方法一样,只检查跳跃范围处在[-32768, 32767]之内,逻辑层面的不检查;

    4) 对于远跳转则什么都不检查,可以随意、任意、全局地跳,即使跳跃范围是在段内也无所谓;


4. $和$$标记:

    1) 是在转移指令中常用的两个标记;

    2) $表示$所在的当前行的汇编地址,比如jmp $就表示无限循环,即不停地跳转到自己的位置;

    3) $$表示$$标记所在的段的起始位置的汇编地址(如果用户有定义的段的话),如果没有定义任何段则整个汇编程序自成一段;


你可能感兴趣的:(nasm,intel汇编,基本指令)