第五周IA-32指令系统概述

在线阅读第五周IA-32指令系统概述PDF文档

第1讲 程序转换概述

1. 程序和指令的关系(15分钟)

指令中包含的信息可能包括(ABC )。

A.操作码,用于指出指令的操作性质

B.立即数,即操作数本身

C.寄存器编号,用于指出操作数所在的寄存器

2. 目标代码和ISA(15分钟)

test.c写成下面这样:

int add(int i,int j)
{
        int x = i + j;
        return x;
}

main.c写成下面这样:

#include <stdio.h>
#include "test.c"
int main()
{
        int x = 6, y = 8;
        int sum = add(x,y);
        printf("%d",sum);
        return 0;
}

执行gcc -O1 main.c test.c -o test出现如下的warning

main.c: In function ‘main’:
main.c:5:19: warning: implicit declaration of function ‘add’ [-Wimplicit-function-declaration]
    5 |         int sum = add(x,y);

一般常见错误原因是先调用了主函数,然后在主函数里调用被定义在主函数之后的函数。解决办法就是调整函数顺序或增加函数声明。

经测试gcc -O1 main.c test.c -o testgcc -O1 test.c main.c -o test都会报这个warning。

这里出现这个warning的原因是在需要调用该函数的文件中没有声明该函数或声明格式错误。

main.c修改后如下:

#include <stdio.h>
extern int add(int,int);
int main()
{
        int x = 6, y = 8;
        int sum = add(x,y);
        printf("%d",sum);
        return 0;
}

再执行gcc -O1 main.c test.c -o test./test就能出现14这个正确结果了!!

也可以在相应的.h文件中声明函数(这时不要再加extern了。)

以下是关于用objdump对可重定位目标文件和可执行目标文件反汇编得到结果的叙述,其中错误的是( C )。

A.两者都包含所有的机器指令,用十六进制表示

B.两者都包含机器指令对应的汇编指令,而且汇编指令的形式完全相同

C.可重定位目标文件的反汇编结果中,每条指令的地址是相对于所在函数第一条指令的位移地址

D.可执行目标文件的反汇编结果中,每条指令的地址是一个绝对地址

下面是在WSL2(Ubuntu22.04)上的编译test.c的过程和结果。

gcc -E test.c -o test.i
gcc -S test.i -o test.s

然后执行 cat test.s

        .file   "test.c"
        .text
        .globl  add
        .type   add, @function
add:
.LFB0:
        .cfi_startproc
        endbr64
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    %edi, -20(%rbp)
        movl    %esi, -24(%rbp)
        movl    -20(%rbp), %edx
        movl    -24(%rbp), %eax
        addl    %edx, %eax
        movl    %eax, -4(%rbp)
        movl    -4(%rbp), %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   add, .-add
        .ident  "GCC: (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0"
        .section        .note.GNU-stack,"",@progbits
        .section        .note.gnu.property,"a"
        .align 8
        .long   1f - 0f
        .long   4f - 1f
        .long   5
0:
        .string "GNU"
1:
        .align 8
        .long   0xc0000002
        .long   3f - 2f
2:
        .long   0x3
3:
        .align 8
4:

再执行gcc -c test.s -o test.oobjdump -d test.o出现下面的结果:

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <add>:
   0:   f3 0f 1e fa             endbr64
   4:   55                      push   %rbp
   5:   48 89 e5                mov    %rsp,%rbp
   8:   89 7d ec                mov    %edi,-0x14(%rbp)
   b:   89 75 e8                mov    %esi,-0x18(%rbp)
   e:   8b 55 ec                mov    -0x14(%rbp),%edx
  11:   8b 45 e8                mov    -0x18(%rbp),%eax
  14:   01 d0                   add    %edx,%eax
  16:   89 45 fc                mov    %eax,-0x4(%rbp)
  19:   8b 45 fc                mov    -0x4(%rbp),%eax
  1c:   5d                      pop    %rbp
  1d:   c3                      ret

x86架构汇编指令一般有两种格式:Intel汇编格式和AT&T汇编格式,DOS、Windows使用Intel汇编格式,而Unix、Linux、Mac OS使用AT&T汇编格式。

下面简单列出几个Intel和AT&T汇编格式的区别:

  1. 第一当然是两个操作数的顺序啦:Intel的第一个操作数是目标操作数,第二个操作数是源操作数;AT&T的第一个操作数是源操作数,第二个操作数是目标操作数。
  2. 寄存器的表示:Intel的寄存器直接写寄存器的名字就行(eax);AT&T的寄存器需要在前面加一个百分号%修饰(%eax)。
  3. 立即数表示:Intel的立即数前不用加任何标志(1);AT&T的立即数前需要加$符号修饰($1)。
  4. 括号的使用:Intel中寻址时用的括号是中括号[];AT&T中使用的是小括号()
  5. ......

来源-objdump反汇编对于小白的一个"坑"

objdump默认的汇编格式是AT&T格式。可以通过-M参数来修改反汇编的格式(具体可以参考man objdump)。

执行objdump -d test.o -M intel |less出现下面的结果:


test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <add>:
   0:   f3 0f 1e fa             endbr64
   4:   55                      push   rbp
   5:   48 89 e5                mov    rbp,rsp
   8:   89 7d ec                mov    DWORD PTR [rbp-0x14],edi
   b:   89 75 e8                mov    DWORD PTR [rbp-0x18],esi
   e:   8b 55 ec                mov    edx,DWORD PTR [rbp-0x14]
  11:   8b 45 e8                mov    eax,DWORD PTR [rbp-0x18]
  14:   01 d0                   add    eax,edx
  16:   89 45 fc                mov    DWORD PTR [rbp-0x4],eax
  19:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
  1c:   5d                      pop    rbp
  1d:   c3                      ret
(END)

ISA是计算机组成的抽象

不同ISA规定的指令集不同,如IA-32、MIPS、ARM等

计算机组成必须能够实现ISA规定的功能,如提供GPR、标志、运算电路等

同一种ISA可以有不同的计算机组成,如乘法指令可用ALU或乘法器实现

第2讲 IA-32指令系统概述

1. Intel处理器概述(6分钟)

2. IA-32的寄存器组织(7分钟)

IA-32支持的数据类型及格式如上所示。

ZF 零标志

SF 符号标志

OF 溢出标志

CF 进/借位标志

3. IA-32的寻址方式(8分钟)

4. 高级语言程序中寻址举例(9分钟)

指令集体系结构设计时需要考虑各种寻址方式,这些寻址方式要能够支持高级语言程序的各种数据结构中数据的访问。其中,变址寻址通常用于数组元素的访问。

5. IA-32机器指令格式(10分钟)

IA-32是变长指令字处理器,其中包含操作码、寻址方式、SIB、位移和立即数等字段。SIB字段用于确定操作数的存储地址,其中SS表示比例因子,占两位(00--1B;01--2B;10--4B;11--8B),Index表示3位变址寄存器编号,Base表示3位基址寄存器编号。

第五周小测验

1单选(0.5分)

以下有关指令的叙述中,错误的是(C )。

A. 伪指令是由若干条机器指令构成的一个指令序列,属于软件范畴

B. 机器指令是用二进制表示的一个0/1序列,CPU能直接执行

C. 汇编指令是机器指令的符号表示,CPU能直接执行

D. 微指令是一条机器指令所包含的控制信号的组合,CPU能直接执行

2单选(0.5分)

一条机器指令通常由多个字段构成。以下选项中,通常(D )不显式地包含在机器指令中。

A. 寄存器编号

B. 操作码

C. 寻址方式

D. 下条指令地址

3单选(0.5分)

对于运算类指令或传送类指令,需要在指令中指出操作数或操作数所在的位置。通常,指令中指出的操作数不可能出现在(A )中。

A. 程序计数器

B. 通用寄存器

C. 存储单元

D. 指令

4单选(0.5分)

令集体系结构(ISA)是计算机系统中必不可少的一个抽象层,它是对硬件的抽象,软件通过它所规定的指令系统规范来使用硬件。以下有关ISA的叙述中,错误的是(D )。

A. ISA规定了指令的操作数类型、寄存器结构、存储空间大小、编址方式和大端/小端方式

B. ISA规定了指令获取操作数的方式,即寻址方式

C. ISA规定了所有指令的集合,包括指令格式和操作类型

D. ISA规定了执行每条指令时所包含的控制信号

5单选(0.5分)

以下选项中,不属于指令集体系结构名称的是(B )。

A. MIPS

B. UNIX

C. IA-32

D. ARM

6单选(0.5分)

以下Intel微处理器中,不兼容IA-32指令集体系结构的是(C )。

A. Pentium (II、III、4)

B. Core(i3、i5、i7)

C. Itanium和Itanium 2

D. 80386和80486

7单选(0.5分)

以下关于IA-32指令格式的叙述中,错误的是(B )。

A. 采用变长指令字格式,指令长度从一个字节到十几个字节不等

B. 指令中给出的操作数所在的通用寄存器的宽度总是32位

C. 采用变长操作码,操作码位数可能是5位到十几位不等

D. 指令中指出的位移量和立即数的长度可以是0、1、2或4个字节

8单选(0.5分)

以下关于IA-32指令寻址方式的叙述中,错误的是( D)。

A. 存储器操作数中最复杂的寻址方式是“基址加比例变址加位移”

B. 操作数可以是指令中的立即数、也可以是通用寄存器或存储单元中的内容

C. 对于寄存器操作数,必须在指令中给出通用寄存器的3位编号

D. 相对寻址的目标地址为“PC内容加位移”,PC内容指当前正在执行指令的地址

9单选(0.5分)(重点)

以下关于IA-32中整数运算指令所支持的操作数的叙述中,错误的是(B )。

A. 参加运算的操作数可以是一个字节(8b)、一个字(16b)或双字(32b)

B. 除乘法指令外,其他运算指令的源操作数和目的操作数的位数相等

C.对于乘除运算指令,操作数一定区分是无符号整数还是带符号整数

D.对于加减运算指令,操作数不区分是无符号整数还是带符号整数

除法运算

10单选(0.5分)(重点)

以下关于IA-32的定点寄存器组织的叙述中,错误的是(C)。

A. 寄存器ESP/SP称为栈指针寄存器,EBP/BP称为基址指针寄存器

B. EIP/IP为指令指针寄存器,即PC;EFLAGS/FLAGS为标志寄存器

C. 每个通用寄存器都可作为32位、16位或8位寄存器使用

D. 寄存器EAX/AX/AL称为累加器,ECX/CX/CL称为计数寄存器

32位处理器中:EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI这8个寄存器通常存放一般性的数据,被称为通用寄存器。它们都有各自的用途。

EAX、ECX、EDX、EBX为数据寄存器;ESP、EBP为指针寄存器;ESI、EDI变址寄存器。

以EAX为例,寄存器的逻辑结构图如图2-3-1所示。

EAX寄存器它本身是一个32位寄存器,那么它可以存储一个32位的数据。EAX寄存器是在32位处理器中工作的,它的上一代处理器是16位处理器,而16位处理器的上一代是8位处理器,为了保证兼容,使之前的处理器经过程序的修改可以在32位处理器上运行。使得EAX寄存器包含了16位、8位的寄存器。

EAX寄存器可分为一个可独立使用的16位寄存器:AX(16位);16位寄存器还可以分为两个可以独立使用的8位寄存器: AH(8位~15位为高8位)、AL(0位~7位为低8位)。

而ESP、EBP、ESI、EDI这四个寄存器是分成了两段。

以ESP为例,寄存器的逻辑结构图如图2-3-2所示。

举例介绍了个别的寄存器逻辑结构,接下来我们来画出32位、16位、8位的通用寄存器逻辑结构图

通用寄存器逻辑结构必须记住,对以后学习有帮助

从这里可以看出,不是每个通用寄存器都可以作为8位寄存器使用