X86汇编语言学习

X86汇编语言学习
X86汇编语言学习

X86汇编语言学习手记

X86汇编语言学习手记(1)

1. 编译环境

OS: Solaris 9 X86

Compiler: gcc 3.3.2

Linker: Solaris Link Editors 5.x

Debug Tool: mdb

Editor: vi

注:关于编译环境的安装和设置,可以参考文章:Solaris 上的开发环境安装及设置。

mdb是Solaris提供的kernel debug工具,这里用它做反汇编和汇编语言调试工具。

如果在Linux平台可以用gdb进行反汇编和调试。

2. 最简C代码分析

为简化问题,来分析一下最简的c代码生成的汇编代码:

# vi test1.c

int main()

{

return 0;

}

编译该程序,产生二进制文件:

# gcc test1.c -o test1

# file test1

test1: ELF 32-bit LSB executable 80386 Version 1, dynamically linked, not stripped

test1是一个ELF格式32位小端(Little Endian)的可执行文件,动态链接并且符号表没有去除。

这正是Unix/Linux平台典型的可执行文件格式。

用mdb反汇编可以观察生成的汇编代码:

# mdb test1

Loading modules: [ libc.so.1 ]

> main::dis ; 反汇编main函数,mdb的命令一般格式为 <地址>::dis

main: pushl %ebp ; ebp寄存器内容压栈,即保存main函数的上级调用函数的栈基地址

main+1: movl %esp,%ebp ; esp值赋给ebp,设置main 函数的栈基址

main+3: subl $8,%esp

main+6: andl $0xf0,%esp

main+9: movl $0,%eax

main+0xe: subl %eax,%esp

main+0x10: movl $0,%eax ; 设置函数返回值0

main+0x15: leave ; 将ebp值赋给esp,pop 先前栈内的上级函数栈的基地址给ebp,恢复原栈基址

main+0x16: ret ; main函数返回,回到上级调用

>

注:这里得到的汇编语言语法格式与Intel的手册有很大不同,Unix/Linux采用AT&T 汇编格式作为汇编语言的语法格式

如果想了解AT&T汇编可以参考文章:Linux AT&T 汇编语言开发指南问题:谁调用了 main函数?

在C语言的层面来看,main函数是一个程序的起始入口点,而实际上,ELF可执行文件的入口点并不是main而是_start。

mdb也可以反汇编_start:

> _start::dis ;从_start 的地址开始反汇编

_start: pushl $0

_start+2: pushl $0

_start+4: movl %esp,%ebp

_start+6: pushl %edx

_start+7: movl $0x80504b0,%eax

_start+0xc: testl %eax,%eax

_start+0xe: je +0xf <_ start+0x1d>

_start+0x10: pushl $0x80504b0

_start+0x15: call -0x75

_start+0x1a: addl $4,%esp

_start+0x1d: movl $0x8060710,%eax

_start+0x22: testl %eax,%eax

_start+0x24: je +7 < _start+0x2b>

_start+0x26: call -0x86

_start+0x2b: pushl $0x80506cd

_start+0x30: call -0x90

_start+0x35: movl +8(%ebp),%eax

_start+0x38: leal +0x10(%ebp,%eax,4),%edx

_start+0x3c: movl %edx,0x8060804

_start+0x42: andl $0xf0,%esp

_start+0x45: subl $4,%esp

_start+0x48: pushl %edx

_start+0x49: leal +0xc(%ebp),%edx

_start+0x4c: pushl %edx

_start+0x4d: pushl %eax

_start+0x4e: call +0x152 <_init> _start+0x53: call -0xa3 <__fps tart>

_start+0x58: call +0xfb

;在这里调用了main函数

_start+0x5d: addl $0xc,%esp

_start+0x60: pushl %eax

_start+0x61: call -0xa1 _start+0x66: pushl $0

_start+0x68: movl $1,%eax

_start+0x6d: lcall $7,$0

_start+0x74: hlt

>

问题:为什么用EAX寄存器保存函数返回值?

实际上IA32并没有规定用哪个寄存器来保存返回值。但如果反汇编Solaris/Linux 的二进制文件,就会发现,都用EAX保存函数返回值。

这不是偶然现象,是操作系统的ABI(Application Binary Interface)来决定的。

Solaris/Linux操作系统的ABI就是Sytem V ABI。

概念:SFP (Stack Frame Pointer) 栈框架指针

正确理解SFP必须了解:

IA32 的栈的概念

CPU 中32位寄存器ESP/EBP的作用

PUSH/POP 指令是如何影响栈的

CALL/RET/LEAVE 等指令是如何影响栈的

如我们所知:

1)IA32的栈是用来存放临时数据,而且是LIFO,即后进先出的。栈的增长方向是从高地址向低地址增长,按字节为单位编址。

2) EBP是栈基址的指针,永远指向栈底(高地址),ESP是栈指针,永远指向栈顶(低地址)。

3) PUSH一个long型数据时,以字节为单位将数据压入栈,从高到低按字节依次将数据存入ESP-1、ESP-2、ESP-3、ESP-4的地址单元。

4) POP一个long型数据,过程与PUSH相反,依次将ESP-4、ESP-3、ESP-2、ESP-1从栈内弹出,放入一个32位寄存器。

5) CALL指令用来调用一个函数或过程,此时,下一条指令地址会被压入堆栈,以备返回时能恢复执行下条指令。

6) RET指令用来从一个函数或过程返回,之前CALL保存的下条指令地址会从栈内弹出到EIP寄存器中,程序转到CALL之前下条指令处执行

7) ENTER是建立当前函数的栈框架,即相当于以下两条指令:

pushl %ebp

movl %esp,%ebp

8) LEAVE是释放当前函数或者过程的栈框架,即相当于以下两条指令:

movl ebp esp

popl ebp

如果反汇编一个函数,很多时候会在函数进入和返回处,发现有类似如下形式的汇编语句:

pushl %ebp ; ebp寄存器内容压栈,即保存main函数的上级调用函数的栈基地址

movl %esp,%ebp ; esp值赋给ebp,设置 main函数的栈基址

........... ; 以上两条指令相当于 enter 0,0

...........

leave ; 将ebp值赋给esp,pop 先前栈内的上级函数栈的基地址给ebp,恢复原栈基址

ret ; main函数返回,回到上级调用

这些语句就是用来创建和释放一个函数或者过程的栈框架的。

原来编译器会自动在函数入口和出口处插入创建和释放栈框架的语句。

函数被调用时:

1) EIP/EBP成为新函数栈的边界

函数被调用时,返回时的EIP首先被压入堆栈;创建栈框架时,上级函数栈的EBP 被压入堆栈,与EIP一道行成新函数栈框架的边界

2) EBP成为栈框架指针SFP,用来指示新函数栈的边界

栈框架建立后,EBP指向的栈的内容就是上一级函数栈的EBP,可以想象,通过EBP 就可以把层层调用函数的栈都回朔遍历一遍,调试器就是利用这个特性实现 backtrace功能的

3) ESP总是作为栈指针指向栈顶,用来分配栈空间

栈分配空间给函数局部变量时的语句通常就是给ESP减去一个常数值,例如,分配

一个整型数据就是 ESP-4

4) 函数的参数传递和局部变量访问可以通过SFP即EBP来实现

由于栈框架指针永远指向当前函数的栈基地址,参数和局部变量访问通常为如下形式:

+8+xx(%ebp) ; 函数入口参数的的访问

-xx(%ebp) ; 函数局部变量访问

假如函数A调用函数B,函数B调用函数C ,则函数栈框架及调用关系如下图所示:

[b:771101bbb0]下图有点乱,因此删去部分内容,要看原图可参考我的blog[/b:771101bbb0] +----------------------------+----> 高地址

| EIP (上级函数返回地址) |

+----------------------------+

| EBP (上级函数的EBP) |

+----------------------------+

| Local Variables |

| .......... |

+-----------------------------+

| Arg n(函数B的第n个参数) |

+-----------------------------+

| Arg .(函数B的第.个参数) |

+-----------------------------+

| Arg 1(函数B的第1个参数) |

+-----------------------------+

| Arg 0(函数B的第0个参数) |

+-----------------------------+

EIP (A函数的返回地址) |

+-----------------------------+

| EBP (A函数的EBP) |

+-----------------------------+

| Local Variables |

| .......... |

+-----------------------------+

| Arg n(函数C的第n个参数) |

+-----------------------------+

| Arg .(函数C的第.个参数) |

+-----------------------------+

| Arg 1(函数C的第1个参数) |

+-----------------------------+

| Arg 0(函数C的第0个参数) |

+-----------------------------+

| EIP (B函数的返回地址) |

+-----------------------------+

| EBP (B函数的EBP) |

+-----------------------------+

| Local Variables |

| .......... |

+-----------------------------+---> 低地址

图 1-1

再分析test1反汇编结果中剩余部分语句的含义:

# mdb test1

Loading modules: [ libc.so.1 ]

> main::dis ; 反汇编main 函数

main: pushl %ebp

main+1: movl %esp,%ebp ; 创建Stack Frame(栈框架)

main+3: subl $8,%esp ; 通过ESP-8来分配8字节堆栈空间

main+6: andl $0xf0,%esp ; 使栈地址16字节对齐

main+9: movl $0,%eax ; 无意义

main+0xe: subl %eax,%esp ; 无意义

main+0x10: movl $0,%eax ; 设置main函数返回值

main+0x15: leave ; 撤销Stack Frame(栈框架)

main+0x16: ret ; main 函数返回

>

以下两句似乎是没有意义的,果真是这样吗?

movl $0,%eax

subl %eax,%esp

用gcc的O2级优化来重新编译test1.c:

# gcc -O2 test1.c -o test1

# mdb test1

> main::dis

main: pushl %ebp

main+1: movl %esp,%ebp

main+3: subl $8,%esp

main+6: andl $0xf0,%esp

main+9: xorl %eax,%eax ; 设置main返回值,使

用xorl异或指令来使eax为0

main+0xb: leave

main+0xc: ret

>

新的反汇编结果比最初的结果要简洁一些,果然之前被认为无用的语句被优化掉了,进一步验证了之前的猜测。

提示:编译器产生的某些语句可能在程序实际语义上没有用处,可以用优化选项去掉这些语句。

问题:为什么用xorl来设置eax的值?

注意到优化后的代码中,eax返回值的设置由 movl $0,%eax 变为

xorl %eax,%eax ,这是因为IA32指令中,xorl比movl有更高的运行速度。

概念:Stack aligned 栈对齐

那么,以下语句到底是和作用呢?

subl $8,%esp

andl $0xf0,%esp ; 通过andl使低4位为0,保证栈地址16字节对齐

表面来看,这条语句最直接的后果是使ESP的地址后4位为0,即16字节对齐,那么为什么这么做呢?

原来,IA32 系列CPU的一些指令分别在4、8、16字节对齐时会有更快的运行速度,因此gcc编译器为提高生成代码在IA32上的运行速度,默认对产生的代码进行16字节对齐

andl $0xf0,%esp 的意义很明显,那么 subl $8,%esp 呢,是必须的吗?

这里假设在进入main函数之前,栈是16字节对齐的话,那么,进入main函数后,EIP和EBP被压入堆栈后,栈地址最末4位二进制位必定是 1000,esp -8则恰好使后4位地址二进制位为0000。看来,这也是为保证栈16字节对齐的。

如果查一下gcc的手册,就会发现关于栈对齐的参数设置:

-mpreferred-stack-boundary=n ; 希望栈按照2的n次的字节边界对齐, n 的取值范围是2-12

默认情况下,n是等于4的,也就是说,默认情况下,gcc是16字节对齐,以适应IA32大多数指令的要求。

让我们利用-mpreferred-stack-boundary=2来去除栈对齐指令:

# gcc -mpreferred-stack-boundary=2 test1.c -o test1

> main::dis

main: pushl %ebp

main+1: movl %esp,%ebp

main+3: movl $0,%eax

main+8: leave

main+9: ret

>

可以看到,栈对齐指令没有了,因为,IA32的栈本身就是4字节对齐的,不需要用额外指令进行对齐。

那么,栈框架指针SFP是不是必须的呢?

# gcc -mpreferred-stack-boundary=2 -fomit-frame-pointer test1.c -o test > main::dis

main: movl $0,%eax

main+5: ret

>

由此可知,-fomit-frame-pointer 可以去除SFP。

问题:去除SFP后有什么缺点呢?

1)增加调式难度

由于SFP在调试器backtrace的指令中被使用到,因此没有SFP该调试指令就无法使用。

2)降低汇编代码可读性

函数参数和局部变量的访问,在没有ebp的情况下,都只能通过+xx(esp)的方式访问,而很难区分两种方式,降低了程序的可读性。

问题:去除SFP有什么优点呢?

1)节省栈空间

2)减少建立和撤销栈框架的指令后,简化了代码

3)使ebp空闲出来,使之作为通用寄存器使用,增加通用寄存器的数量

4)以上3点使得程序运行速度更快

概念:Calling Convention 调用约定和 ABI (Application Binary Interface) 应用程序二进制接口

函数如何找到它的参数?

函数如何返回结果?

函数在哪里存放局部变量?

那一个硬件寄存器是起始空间?

那一个硬件寄存器必须预先保留?

Calling Convention 调用约定对以上问题作出了规定。Calling Convention也是ABI的一部分。

因此,遵守相同ABI规范的操作系统,使其相互间实现二进制代码的互操作成为了可能。

例如:由于Solaris、Linux都遵守System V的ABI,Solaris 10就提供了直接运行Linux二进制程序的功能。

详见文章:关注: Solaris 10的10大新变化

3. 小结

本文通过最简的C程序,引入以下概念:

SFP 栈框架指针

Stack aligned 栈对齐

Calling Convention 调用约定和 ABI (Application Binary Interface) 应用程序二进制接口

今后,将通过进一步的实验,来深入了解这些概念。通过掌握这些概念,使在汇编级调试程序产生的core dump、掌握C语言高级调试技巧成为了可能。

X86汇编语言学习手记(2)

这是作者在学习X86汇编过程中的学习笔记,难免有错误和疏漏之处,欢迎指正。作者将随时修改错误并将新的版本发布在自己的Blog站点上。严格说来,本篇文档更侧重于C语言和C编译器方面的知识,如果涉及到基本的汇编语言的内容,可以参考相关文档。

自X86 汇编语言学习手记(1)在作者的Blog上发布以来,得到了很多网友的肯定和鼓励,

并且还有热心网友指出了其中的错误,[b:bea66ddae0]作者已经将文档中已发现的错误修正后更新在Blog上。[/b:bea66ddae0]

上一篇文章通过分析一个最简的C程序,引出了以下概念:

Stack Frame 栈框架和 SFP 栈框架指针

Stack aligned 栈对齐

Calling Convention 调用约定和 ABI (Application Binary Interface) 应用程序二进制接口

本章中,将通过进一步的实验,来深入了解这些概念。如果还不了解这些概念,可以参考 X86汇编语言学习手记(1)。

1. 局部变量的栈分配

上篇文章已经分析过一个最简的C程序,

下面我们分析一下C编译器如何处理局部变量的分配,为此先给出如下程序:

#vi test2.c

int main()

{

int i;

int j=2;

i=3;

i=++i;

return i+j;

}

编译该程序,产生二进制文件,并利用mdb来观察程序运行中的stack的状态:

#gcc test2.c -o test2

#mdb test2

Loading modules: [ libc.so.1 ]

> main::dis

main: pushl %ebp

main+1: movl %esp,%ebp ; main至main+1,创建Stack Frame

main+3: subl $8,%esp ; 为局部变量i,j分配栈空间,并保证栈16字节对齐

main+6: andl $0xf0,%esp

main+9: movl $0,%eax

main+0xe: subl %eax,%esp ; main+6至main+0xe,再次保证栈16字节对齐

main+0x10: movl $2,-8(%ebp) ; 初始化局部变量j的值为2

main+0x17: movl $3,-4(%ebp) ; 给局部变量i 赋值为3

main+0x1e: leal -4(%ebp),%eax ; 将局部变量i的地址装入到EAX寄存器中

main+0x21: incl (%eax) ; i++

main+0x23: movl -8(%ebp),%eax ; 将j的值装入EAX

main+0x26: addl -4(%ebp),%eax ; i+j并将结果存入EAX,作为返回值

main+0x29: leave ; 撤销Stack Frame

main+0x2a: ret ; main函数返回

>

> main+0x10:b ; 在地址 main+0x10处设置断点

> main+0x1e:b ; 在main+0x1e设置断点

> main+0x29:b ; 在main+0x1e设置断点

> main+0x2a:b ; 在main+0x1e设置断点

下面的mdb的4个命令在一行输入,中间用分号间隔开,命令的含义在注释中给出: > :r;

mdb: stop at main+0x10 ; 以ESP寄存器为起始地址,指定格式输出16字节的栈内容(

mdb: target stopped at: ; 在最后输出EBP和EAX寄存器的值(

main+0x10: movl $2,-8(%ebp) ; 程序运行后在main

+0x10处指令执行前中断,此时栈分配后还未初始化

0x8047db0:

0x8047db0: 0xddbebca0 ; 这是变量j,4字节,未初始化,此处为栈顶,ESP的值就是0x8047db0

0x8047db4: 0xddbe137f ; 这是变量i, 4字节,未初始化

0x8047db8: 0x8047dd8 ; 这是_start的SFP(_start的EBP),4字节,由main 的SFP指向它

0x8047dbc: _start+0x5d ; 这是_start调用main之前压栈的下条指令地址,main返回后将恢复给EIP

0x8047dc0: 1

0x8047dc4: 0x8047de4

0x8047dc8: 0x8047dec

0x8047dcc: _start+0x35

0x8047dd0: _fini

0x8047dd4: ld.so.1`atexit_fini

0x8047dd8: 0 ;

_start的SFP指向的内容为0,证明_start是程序的入口

0x8047ddc: 0

0x8047de0: 1

0x8047de4: 0x8047eb4

0x8047de8: 0

0x8047dec: 0x8047eba

8047db8 ; 这是main当前EBP寄存器的值,即main的SFP

0 ; EAX的值,当前为0

> :c;

mdb: stop at main+0x1e

mdb: target stopped at:

main+0x1e: leal -4(%ebp),%eax ; 程序运行到断点

main+0x1e处停止,此时局部变量i,j赋值已完成

0x8047db0:

0x8047db0: 2 ; 这是变量j,4字节,值为2,此处为栈顶,ESP的值就是0x8047db0

0x8047db4: 3 ; 这是变量i,4字节,值为3

0x8047db8: 0x8047dd8 ; 这是_start的SFP,4字节

0x8047dbc: _start+0x5d ; 这是返回_start 后的EIP

0x8047dc0: 1

0x8047dc4: 0x8047de4

0x8047dc8: 0x8047dec

0x8047dcc: _start+0x35

0x8047dd0: _fini

0x8047dd4: ld.so.1`atexit_fini

0x8047dd8: 0

0x8047ddc: 0

0x8047de0: 1

0x8047de4: 0x8047eb4

0x8047de8: 0

0x8047dec: 0x8047eba

8047db8 ; 这是main当前EBP寄存器的值,即main的SFP

0 ; EAX的值,当前为0

> :c;

mdb: stop at main+0x29

mdb: target stopped at:

main+0x29: leave ; 运行到断点main+0x29处停止,计算已经完成,即将撤销Stack Frame

0x8047db0:

0x8047db0: 2 ; 这是变量j,4字节,值为2,此处为栈顶,ESP的值就是0x8047db0

0x8047db4: 4 ; 这是i++以后的变量i,4字节,值为3

0x8047db8: 0x8047dd8 ; 这是_start的SFP,4字节

0x8047dbc: _start+0x5d ; 这是返回_start 后的EIP

0x8047dc0: 1

0x8047dc4: 0x8047de4

0x8047dc8: 0x8047dec

0x8047dcc: _start+0x35

0x8047dd0: _fini

0x8047dd4: ld.so.1`atexit_fini

0x8047dd8: 0

0x8047ddc: 0

0x8047de0: 1

0x8047de4: 0x8047eb4

0x8047de8: 0

0x8047dec: 0x8047eba

8047db8 ; 这是main当前EBP寄存器的值,即main的SFP

6 ; EAX的值,即函数的返回值,当前为6

> :c;

mdb: stop at main+0x2a

mdb: target stopped at:

main+0x2a: ret ; 运行到断点main+0x2a处停止,Stack Frame已被撤销,main即将返回

0x8047dbc:

0x8047dbc: _start+0x5d ; Stack Frame已经被撤销,栈顶是返回_start后的EIP,main的栈已被释放

0x8047dc0: 1

0x8047dc4: 0x8047de4

0x8047dc8: 0x8047dec

0x8047dcc: _start+0x35

0x8047dd0: _fini

0x8047dd4: ld.so.1`atexit_fini

0x8047dd8: 0

0x8047ddc: 0

0x8047de0: 1

0x8047de4: 0x8047eb4

0x8047de8: 0

0x8047dec: 0x8047eba

0x8047df0: 0x8047ed6

0x8047df4: 0x8047edd

0x8047df8: 0x8047ee4

8047dd8 ; _start的SFP,之前存储在地址0x8047db8处,main的Stack Frame撤销时恢

复 6

; EAX的值,即函数的返回值,当前为6

> :s;

mdb: target stopped at:

_start+0x5d: addl $0xc,%esp ; 此时main已经返回,

_start+0x5d曾经存储在地址0x8047dbc处

0x8047dc0:

0x8047dc0: 1 ; main 已经返回,_start +0x5d已经被弹出

0x8047dc4: 0x8047de4

0x8047dc8: 0x8047dec

0x8047dcc: _start+0x35

0x8047dd0: _fini

0x8047dd4: ld.so.1`atexit_fini

0x8047dd8: 0 ;

_start的SFP指向的内容为0,证明_start是程序的入口

0x8047ddc: 0

0x8047de0: 1

0x8047de4: 0x8047eb4

0x8047de8: 0

0x8047dec: 0x8047eba

0x8047df0: 0x8047ed6

0x8047df4: 0x8047edd

0x8047df8: 0x8047ee4

0x8047dfc: 0x8047ef3

8047dd8 ; _start的SFP,之前存储在地址0x8047db8处,main的Stack Frame撤销时恢复

6 ; EAX 的值为6,还是main函数的返回值

>

通过mdb对程序运行时的寄存器和栈的观察和分析,可以得出局部变量在栈中的访问和分配及释放方式:

1.局部变量的分配,可以通过esp减去所需字节数

subl $8,%esp

2.局部变量的释放,可以通过leave指令

leave

3.局部变量的访问,可以通过ebp减去偏移量

movl -8(%ebp),%eax

addl -4(%ebp),%eax

问题:当存在2个以上的局部变量时,如何进行栈对齐?

在上篇文章中,提到subl $8,%esp语句除了分配栈空间外,还有一个作用就是栈对齐。那么本例中,由于i和j正好是8字节,那么如果存在2个以上的局部变量时,如何同时满足空间分配和栈对齐呢?

2. 两个以上的局部变量的栈分配

在之前的C程序中,增加局部变量定义k,程序如下:

# vi test3.c

int main()

{

int i, j=2, k=4;

i=3;

i=++i;

k=i+j+k;

return k;

}

编译该程序后,用mdb反汇编得出如下结果:

# gcc test3.c -o test3

# mdb test3

Loading modules: [ libc.so.1 ]

> main::dis

main: pushl %ebp

main+1: movl %esp,%ebp

; main至main+1,创建Stack Frame

main+3: subl $0x18,%esp ; 为局部变量i,j,k分配栈空间,并保证栈16字节对齐

main+6: andl $0xf0,%esp

main+9: movl $0,%eax

main+0xe: subl %eax,%esp

; main+6至main+0xe,再次保证栈16字节对齐

main+0x10: movl $2,-8(%ebp) ;

j=2

main+0x17: movl $4,-0xc(%ebp) ;

k=4

main+0x1e: movl $3,-4(%ebp) ;

i=3

main+0x25: leal -4(%ebp),%eax ; 将

i的地址装入到EAX

main+0x28: incl (%eax)

; i++

main+0x2a: movl -8(%ebp),%eax ; 将

j的值装入到 EAX

main+0x2d: movl -4(%ebp),%edx ; 将

i的值装入到 EDX

main+0x30: addl %eax,%edx ; j+i,结果存入EDX

main+0x32: leal -0xc(%ebp),%eax ; 将k

的地址装入到EAX

main+0x35: addl %edx,(%eax) ;

i+j+k,结果存入地址ebp-0xc即k中

main+0x37: movl -0xc(%ebp),%eax ; 将k

的值装入EAX,作为返回值

main+0x3a: leave

; 撤销Stack Frame

main+0x3b: ret

; main函数返回

>

问题:为什么3个变量分配了0x18字节的栈空间?

在2个变量的时候,分配栈空间的指令是:subl $8,%esp

而在3个局部变量的时候,分配栈空间的指令是:subl $0x18,%esp

3个整型变量只需要0xc字节,为何实际上分配了0x18字节呢?

答案就是:保持16字节栈对齐。

在X86 汇编语言学习手记(1)里,已经说明过gcc默认的编译是要16字节栈对齐的,subl $8,%esp会使栈16字节对齐,而8字节空间只能满足2个局部变量,如果再分配4字节满足第3个局部变量的话,那栈地址就不再16字节对齐的,而同时满足空间需要而且保持16字节栈对齐的最接近的就是0x18。

如果,各定义一个50字节和100字节的字符数组,在这种情况下,实际分配多少栈空间呢?答案是0x8+0x40+0x70,即184字节。

下面动手验证一下:

# vi test4.c

int main()

{

char str1[50];

char str2[100];

return 0;

}

# mdb test4

Loading modules: [ libc.so.1 ]

> main::dis

main: pushl %ebp

main+1: movl %esp,%ebp

main+3: subl $0xb8,%esp ; 为两个字符数组分配栈空间,同时保证16字节对齐

main+9: andl $0xf0,%esp

main+0xc: movl $0,%eax

main+0x11: subl %eax,%esp

main+0x13: movl $0,%eax

main+0x18: leave

main+0x19: ret

> 0xb8=D ; 16进制换算10进制

184

> 0x40+0x70+0x8=X ; 表达式计算,结果指定为16进制

b8

>

问题:定义了多个局部变量时,栈分配顺序是怎样的?

局部变量栈分配的顺序是按照变量声明先后的顺序,同一行声明的变量是按照从左到右的顺序入栈的,在test2.c中,变量声明如下:

int i, j=2, k=4;

而反汇编的结果中:

movl $2,-8(%ebp) ; j=2

movl $4,-0xc(%ebp) ; k=4

movl $3,-4(%ebp) ; i=3

其中不难看出,i,j,k的栈中的位置如下图:

+--------------------------------+------> 高地址

| EIP (_start函数的返回地址) |

+--------------------------------+

| EBP (_start函数的EBP) | <-- main函数的EBP指针(即SFP框架指针)

+--------------------------------+

| i (EBP-4) |

+--------------------------------+

| j (EBP-8) |

+--------------------------------+

| k (EBP-0xc) |

+--------------------------------+------> 低地址

图 2-1

3. 小结

这次通过几个试验程序,进一步了解了局部变量在栈中的分配和释放以及位置,并再次回顾了上篇文章中涉及到的以下概念:

SFP 栈框架指针

Stack aligned 栈对齐

并且,利用Solaris提供的mdb工具,直观的观察到了栈在程序运行中的动态变化,以及Stack Frame的创建和撤销,根据给出的图例的内容(图 2-1和图 1-1),可以更清晰的了解IA32架构中栈在内存中的布局(Stack Layer)。

相关文档:

X86 汇编语言学习手记(1)

Solaris 上的开发环境安装及设置

Linux AT&T 汇编语言开发指南

ELF动态解析符号过程(修订版)

关注: Solaris 10的10大新变化

汇编语言试题及参考答案

汇编语言试题及参考答案 一,填空题 1.ZF标志位是标志结果是否为零的,若结果,ZF为( 1 ),否则ZF为( 0 ).当ZF为1时,SF为( 0 ) 2.标号可以有两种类型属性.它们是( )和( ) 3.8位无符号整数的表示范围为0--255,写成16进制形式为( ),8位有符号整数的表示范围为-128--+127,写成16进制形式为( ) 4.伪指令DB,GROUP 和NAME 三个标号名字域必须有名字的是( ),不得有名字的是( ),可有可无名字的是( ). 5.循环程序通常由( )( )( )和循环结果外理四部分构成 6.在数值不达式中,各种运算符可可混合使用,其优先次序规则*,/( )于+,-;XOR,OR( )于AND,LT( )于GT 7. 宏指令定义必须由伪指令( )开始,伪指令( )结束,两者之间的语句称为( ) 8.调用程序与子程序之间的参数传递方法有四种,即堆栈法( )( )( ) 9.分别用一条语句实现下述指明的功能 (1)栈顶内容弹出送字变量AYW( ) (2)双字变量AYD存放的地址指针送ES和SI( ) (3)变量AY2类型属性送AH( ) (4)不允许中断即关中断( ) (5)将字符串'HOW ARE YOU!'存入变量AYB( ) (6)子程序返回调用程序( ) (7)地址表达式AYY[4]的偏移地址送字变量ADDR( ) (8)AX的内容加1,要求不影响CF( ) (9)BX的内容加1,要求影响所有标志位( ) (10)若操作结果为零转向短号GOON( ) 二,单选题 1.IBM PC微机中,有符号数是用( )表示的 1.原码 2.补码 3.反码 4.BCD码 2.把汇编源程序变成代码程序的过程是( ) 1.编译 2.汇编 3.编辑 4.链接

基础的汇编语言小程序

基础的汇编语言小程序 1.1 Hello World !程序(完整段) (注:所有的标点符号以及空格回车均为英文输入法状态下的,否则报错!) DATAS SEGMENT STRING DB ‘Hello World !’,13,10,’$’ DATAS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS START: MOV AX,DATAS MOV DS,AX LEA DX,STRING MOV AH,9 INT 21H MOV AH,4CH INT 21H CODES ENDS END START 1.2 Hello World !程序(简化段) .MODEL SMALL .DATA

STRING DB’Hello World !’,13,10,’$’ .STACK .CODE .STARTUP LEA DX,STRING MOV AH,9 INT 21H .EXIT END 2.1完整段的求3+5的和 DATA SEGMENT FIVE DB 5 DATAS ENDS STACKS SEGMENT DB 128 DUP(?) STACKS ENDS CODES SEGMENT ASSUME CD:CODES,DS:DATAS,SS:STACKS START: MOV AX,DATAS MOV DS,AX MOV AL,FIVE

ADD AL,3 ADD AL,30H MOV DL,AL MOV AH,2 MOV AH,4CH INT 21H CODES ENDS END START 2.2;简化段的求3+5的和.MODEL SMALL .DATA FIVE DB 5 .STACK DB 128 DUP (?) .CODE .STARTUP MOV AL,FIVE ADD AL,3 ADD AL,30H MOV DL,AL MOV AH,2 INT 21H

80x86汇编语言程序设计教程》(清华大学出版社,黑色封面,杨季文著)

80x86汇编语言程序设计教程》(清华大学出版社,黑色封面,杨季文著) 《计算机操作系统原理》 《Inside Windows 2000》(微软出版社,我看的是E文版的,中文的书名想必是Windows 2000 技术内幕之类吧)。 《数据结构和算法》——这门课程能够决定一个人程序设计水平的高低,是一门核心课程。我首选的是清华版的(朱战立,刘天时) 《软件工程》——这门课程是越到后来就越发现它的重要,虽然刚开始看时就象看马哲一样不知所云。我的建议是看《实用软件工程》(黄色,清华) 《Windows 程序设计》——《北京大学出版社,Petzold著》我建议任何企图设计Windows 程序的人在学习VC以前仔细的学完它。而且前面的那本 建议:你还可以在CSDN上阅读到许多书评。这些书评能够帮助你决定读什么样的书 关于编程的网站 计算机编程 郭新明-FTP服务器体验式学习课程(张孝祥监制) https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=3997 https://www.360docs.net/doc/df15069108.html,快速开发新闻系统在线播放 https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=4708 数字电路基础[宁波电大] https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=774 计算机组成与汇编语言程序设计(赵丽梅)宁波电大 https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=1242 操作系统(陈访荣)宁波电大(在线播放) https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=4708 计算机网络(马敏飞)宁波电大 https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=1243 https://www.360docs.net/doc/df15069108.html, 2.0快速入门(12)-https://www.360docs.net/doc/df15069108.html, 2.0网站快速导航 https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=2501 Internet和Intranet应用(薛昭旺)宁波电大 https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=1245 2004年电脑硬件安装调试维修视频教学讲授 https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=4825 https://www.360docs.net/doc/df15069108.html, 高级排错技巧 https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=768 SQL Server 2000管理专家系列课程 https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=4832 开心三人行系列(2):使用Atlas 构建AJAX应用 https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=2564 Visual Basic 2005开发技巧系列课程(4): 在Visual Basic 2005中使用.NET Framework 2.0新增功能 https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=2526 SQL Server 2005 系列课程-使用ADO https://www.360docs.net/doc/df15069108.html,开发SQL Server 2005 OLAP应用 https://www.360docs.net/doc/df15069108.html,/so/so138.aspx?id=2535

汇编语言程序设计实验教程

汇编语言程序设计实验教程

目录 第一章上机过程 (4) 1.1编辑源程序 (4) 1.2 汇编源程序 (5) 1.3连接目标程序 (6) 1.4运行程序 (7) 第二章DEBUG命令祥解 (8) 2.1 DEBUG程序使用 (8) 2.2 DEBUG的常用命令 (8) 第三章汇编语言程序设计实验 (13) 3.1实验一顺序与分支程序设计 (13) 3.2 实验二循环与子程序程序设计 (15) 3.3 实验三算术运算与代码转换程序设计 (16) 3.4 实验四字符串的匹配与替换程序设计 (18) 3.5 实验五输入输出程序设计 (19) 第四章部分实验参考答案 (21)

第一章上机过程 1.1编辑源程序 汇编语言源程序:用汇编语句编写的解决应用问题的程序。 汇编程序:将汇编语言源程序翻译成机器语言程序的系统。 汇编:将汇编语言程序翻译成机器语言程序的过程。 在编辑汇编语言源程序时,对计算机硬件工作环境无特殊要求,对软件工作环境要求也很简单,只需用建立ASCII码文本文件的软件即可。 (1)编辑软件 编辑软件:EDIT、QE、WORD、NOTEPAD等。 当输入、建立和修改源程序时,可任选一种编辑软件,不要用格式控制符,要求编辑完成的文件扩展名一定是.ASM。 (2)汇编程序 有汇编ASM.EXE、宏汇编MASM.EXE及TASM等,一般使用宏汇编MASM.EXE,因它比ASM.EXE功能强。TASM适用于8086/8088~Pentium系列指令系统所编写的汇编语言程序,是比较先进的汇编工具。 (3)连接程序 用连接程序LINK.EXE或TLINK.EXE,将MASM.EXE产生的目标代码程序(.OBJ)文件连接成可执行程序.EXE,TLINK比LINK更先进。 (4)辅助工具程序(.EXE) 进行汇编语言程序调试和文件格式转换的程序有: https://www.360docs.net/doc/df15069108.html, 动态调试程序 EXE2BIN.EXE文件格式转换程序

Windows X86-64位汇编语言入门

Windows X86-64位汇编语言入门 Windows X64汇编入门(1) 最近断断续续接触了些64位汇编的知识,这里小结一下,一是阶段学习的回顾,二是希望对64位汇编新手有所帮助。我也是刚接触这方面知识,文中肯定有错误之处,大家多指正。 文章的标题包含了本文的四方面主要内容: (1)Windows:本文是在windows环境下的汇编程序设计,调试环境为Windows Vista 64位版,调用的均为windows API。 (2)X64:本文讨论的是x64汇编,这里的x64表示AMD64和Intel的EM64T,而不包括IA64。至于三者间的区别,可自行搜索。 (3)汇编:顾名思义,本文讨论的编程语言是汇编,其它高级语言的64位编程均不属于讨论范畴。 (4)入门:既是入门,便不会很全。其一,文中有很多知识仅仅点到为止,更深入的学习留待日后努力。其二,便于类似我这样刚接触x64汇编的新手入门。 本文所有代码的调试环境:Windows Vista x64,Intel Core 2 Duo。 1. 建立开发环境 1.1 编译器的选择 对应于不同的x64汇编工具,开发环境也有所不同。最普遍的要算微软的MASM,在x64环境中,相应的编译器已经更名为ml64.exe,随Visual Studio 2005一起发布。因此,如果你是微软的忠实fans,直接安装VS2005既可。运行时,只需打开相应的64位命令行窗口(图1),便可以用ml64进行编译了。

第二个推荐的编译器是GoASM,共包含三个文件:GoASM编译器、GoLINK链接器和GoRC 资源编译器,且自带了Include目录。它的最大好外是小,不用为了学习64位汇编安装几个G 的VS。因此,本文的代码就在GoASM下编译。 第三个Yasm,因为不熟,所以不再赘述,感兴趣的朋友自行测试吧。 不同的编译器,语法会有一定差别,这在下面再说。 1.2 IDE的选择 搜遍了Internet也没有找到支持asm64的IDE,甚至连个Editor都没有。因此,最简单的方法是自行修改EditPlus的masm语法文件,这也是我采用的方法,至少可以得到语法高亮。当然,如果你懒得动手,那就用notepad吧。 没有IDE,每次编译时都要手动输入不少参数和选项,做个批处理就行了。 1.3 硬件与操作系统 硬件要求就是64位的CPU。操作系统也必须是64位的,如果在64位的CPU上安装了

汇编语言复习题(附答案)

汇编语言复习题 注:蓝色标记的为答案,此答案仅供参考,大家自己做一下或看以一下,认为不对的地方,可以提出来一起讨论一下,另外看一下课后老师布置的相应作业。在此文档最后最后附有课 后四、六章的答案,大家抓紧时间复习哦! 一、选择题 1. 把要执行的程序与库文件连接起来形成可执行文件的系统程序是(B )。 A. 汇编程序 B. 连接程序 C. 机器语言程序 D.源代码程序 2. 在8088/8086的寄存器组中,CPU确定下一条指令的物理地址时需要用到的寄存器对是 (C )。 A..SS 和SP B.DS 和DI C.CS 和IP D.ES 和SI 3. 为了使主机访问外设方便起见,外设中的每个寄存器给予一个(C )。 A.物理地址 B. 逻辑地址 C. 端口地址 D. 段地址 4. MOV AX, 3064H,该指令中源操作数采用的寻址方式是(A )。 A.立即 B. 直接 C. 寄存器相对 D. 寄存器间接 5. 换码指令的助记符是(C )。 A. XCHG B. LEAS C.XLAT D. MOV 6. 如果A> B (A、B有符号数)发生转移,应选择的条件转移指令是(JGE )。 7. 下列符号中,可用作标识符的是(C )。 A.MOV B.AX C.MSG1 D.1ABC 8. X DB 10H DUP (1 , 2)内存变量定义语句拥有了( A )个字节的存储空间。 A.20D B.10D C.20H D.10H 9. 当DF=0时,执行串操作指令MOVSB变址寄存器SI、DI的值将(C )。 A.不变 B. 减1 C. 加1 D. 无法确定 10. 如下指令可将AX寄存器内容改变的是(A )。 A. AND AX , BX B . TEST AX , BX C. CMP AX , BX D . XCHG AX , AX 11.16位CPU支持的I/O 地址范围是(D )。 A. 0~0FFFFFH B. 0~0FFFFH C. 0~0FFFH D. 0~0FFH 12. MUL CL指令实现的功能是(A )。 A.无符号乘法:AX AL X CL B.有符号乘法:AX AL X CL C.无符号乘法:DX AL X CL D .有符号乘法:DX AL X CL 13. DOS系统功能调用(INT 21H )中,显示字符串的功能号是(D )。 A.01H B.02H C.08H D. 09H 14. 在16位CPU读取指令时,需要用到的寄存器对是(C )。 A.SS 和SP B.DS 和DI C.CS 和IP D.ES 和SI 15. 下列指令中,源操作数(既第2操作数)属于基址加变址寻址方式是(B )。 A.MOV AX,23H B. MOV AX,[BX+SI] C.SUB AX,[BX] D. ADD AX,BX 16. 有内存变量定义语句:VAR DW 10 DUP(1 , 2), 1234H, VAR的属性TYPE LENGTH和

2位数计算器程序-汇编语言课程设计

信息学院课程设计题目:2位数计算器程序设计 __ 姓名: __ _____ 学号: ____ ___ 班级: 课程:汇编语言 ________ 任课教师:侯艳艳 ____ 2011年12月

课程设计任务书及成绩评定

目录 摘要 (2) 1.设计目的………………………………………………………………………………………………?2 2.概要设计………………………………………………………………………………………………?3 2.1系统总体分析…………………………………………………………………………?3 2.2程序流程图 (3) 3.详细设计......................................................................................................? (4) 3.1主程序及子程序说明 (4) 3.2程序代码编写 (4) 4.程序调试 (6) 4.1运行界面分析 (6) 4.2算法的分析 (6) 4.3调试过程及分析 (6) 5.心得体会 (7) 5.1设计体会...................................................................................................? (7) 5.2系统改进...................................................................................................? (7) 参考文献 (8)

完整版汇编语言试题及答案..doc

一,单项选择题 (每小题 1 分,共 20 分 1-10CCCCAADACB 11-20.ADBBAADDCC 1.指令 JMP FAR PTR DONE 属于 ( C A.段内转移直接寻址 B.段内转移间接寻址 C.段间转移直接寻址 D.段间转移间接寻址 2.下列叙述正确的是 ( A.对两个无符号数进行比较采用CMP 指令 ,对两个有符号数比较用CMP S 指令 B.对两个无符号数进行比较采用CMPS 指令 ,对两个有符号数比较用CM P 指令 C.对无符号数条件转移采用JAE/JNB 指令 ,对有符号数条件转移用JGE/J NL 指令 D.对无符号数条件转移采用JGE/JNL 指令 ,对有符号数条件转移用JAE/J NB 指令 3.一个有 128 个字的数据区 ,它的起始地址为 12ABH:00ABH, 请给出这个数据区最末一个字单元的物理地址是 ( A.12CSBH B.12B6BH

C.12C59H D.12BFEH 4.在下列指令的表示中 ,不正确的是 ( A.MOV AL,[BX+SI] B.JMP SHORT DONI C.DEC [BX] D.MUL CL 5.在进行二重循环程序设计时,下列描述正确的是 ( A.外循环初值应置外循环之外;内循环初值应置内循环之外,外循环之内 B.外循环初值应置外循环之内;内循环初值应置内循环之内 C.内、外循环初值都应置外循环之外 D.内、外循环初值都应置内循环之外,外循环之内 6.条件转移指令 JNE 的测试条件为 ( A.ZF=0 B.CF=0 C.ZF=1 D.CF=1 7.8086CPU在基址加变址的寻址方式中,变址寄存器可以为 ( A.BX 或 CX

汇编语言程序代码详细版

1.1 DATAS SEGMENT x db 6 y db 7 z db ? ;此处输入数据段代码 DATAS ENDS STACKS SEGMENT dw 100 dup(0);此处输入堆栈段代码STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS START: push ds mov ax,0 push ax mov ax,datas mov ds,ax mov dl,x add dl,y mov cl,3 sal dl,cl sub dl,x sar dl,1 mov z , dl ;此处输入代码段代码 MOV AH,4CH INT 21H CODES ENDS END START 1.2DATAS SEGMENT x db 4 dup (0) y db 4 dup (0)

z db 4 dup (0) ;此处输入数据段代码 DATAS ENDS STACKS SEGMENT dw 100 dup(0);此处输入堆栈段代码STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS START: mov x,12h mov [x+1],34h mov [x+2],56h mov [x+3],78h mov bl,78h mov y,34h mov [y+1],56h mov [y+2],87h mov [y+3],64h add bl,64h mov [z+3],bl mov bl,56h adc bl,87h mov [z+2],bl mov bl,34h adc bl,56h mov [z+1],bl mov bl,12h adc bl,34h mov z,bl

x86汇编指令

简明X86汇编语言教程 原创:司徒彦南2002年4月8日 徐远超于2010-02-25收集整理 2010-03-10第2次补充 2010-03-25第3次补充 目录 第Ο章 写在前面 (2) 第一章汇编语言简介 (3) 第二章认识处理器 (4) 2.1 寄存器 (4) 2.2 使用寄存器 (6) 第三章操作内存 (12) 3.1 实模式 (12) 3.2 保护模式 (16) 3.3 操作内存 (19) 3.4 串操作 (21) 3.5 关于保护模式中内存操作的一点说明 (22) 3.6 堆栈 (23) 本章小结 (25) 第四章利用子程序与中断 (25) 4.1 子程序 (25) 4.2 中断 (31) 第五章编译优化概述 (34) 5.1 循环优化:强度削减和代码外提 (36) 5.2 局部优化:表达式预计算和子表达式提取 (37) 5.3 全局寄存器优化 (38) 5.4 x86体系结构上的并行最大化和指令封包 (40) 5.5 存储优化 (42) 第六章 Linux X86汇编程序设计 (46) 6.1编译和链接 (46) 6.2基本示例 (46) 第七章 X86汇编指令集汇总 (47) 一.数据传输指令 (47) 二、算术运算指令 (49) 三、逻辑运算指令 (49) 四、串指令 (50) 五、程序转移指令 (50) 六、伪指令 (52) 七、寄存器 (52) 八、位操作指令,处理器控制指令 (52) 九、FPU instructions (54) 第八章 GCC内联汇编基础 (54) 1. GCC汇编格式 (55) 2.内联汇编基本形式 (56) 3. 扩展形式内联汇编 (56)

汇编语言程序设计(钱晓捷)课后答案

汇编语言程序设计(第二版) 钱晓捷习题答案 第二章(01) 2.1 (1)AX=1200h (2)AX=0100h (3)AX=4C2Ah (4)AX=3412h (5)AX=4C2Ah (6)AX=7856h (7)AX=65B7h 2.2(1) 两操作数类型不匹配 (2) IP指令指针禁止用户访问 (3) 立即数不允许传给段寄存器 (4) 段寄存器之间不允许传送 (5) 两操作数类型不匹配 (6) 目的操作数应为[ BP ] (7) 源操作数应为[BX+DI] (8) 立即数不能作目的操作数 2.3 lea bx,table ;获取table的首地址,BX=200H mov al,8 ;传送欲转换的数字,AL=8 xlat ;转换为格雷码,AL=12H 2.4 堆栈是一种按“先进后出”原则存取数据的存储区域。 堆栈的两种基本操作是压栈和出栈,对应的指令是PUSH和POP。 2.5 mov ax,8057h push ax mov ax,0f79h push ax pop bx ;bx=0f79h pop [bx] ;DS:[0f79h]=8057h 2.6 AL=89h CF ZF SF OF PF AL=12h 1 0 0 1 1 AL=0afh 0 0 1 0 1 AL=0afh 1 0 1 0 1 AL=00h 0 1 0 0 1 AL=0ffh 0 0 1 0 1 AL=00h 0 1 0 0 1 2.7 W=X+Y+24-Z

2.8 (1)ADD DX,BX (2)ADD AL,[BX+SI] (3)ADD [BX+0B2H],CX (4)ADD WORD PTR [0520H],3412H (5)ADD AL,0A0H 2.9;为了避免与操作数地址混淆,将题中X,Y,Z,V 字操作数改为A,B,C,D mov ax,X ;ax=A imul Y ;dx,ax = A*B (将操作数看作符号数,以下同) mov cx,ax mov bx,dx ;bx,ax <-- dx,ax =A*B mov ax,Z ;ax = C cwd ;dx,ax =C (扩展符号后为双字) add cx,ax adc bx,dx ;bx,cx <-- bx,cx+dx,ax=A*B+C sub cx,540 sbb bx,0 ;bx,cx<-- A*B+C-540 mov ax, V ;ax= D cwd ;dx,ax= D (扩展符号后为双字) sub ax, cx sbb dx, bx ;dx,ax = dx,ax - bx,cx = D-(A*B+C-540) idiv X ;运算结果:[D-(A*B+C-540h)]/A ;ax存商,dx存余数 2.10;(1)xchg的操作数不能是立即数 (2不能对CS直接赋值 (3)两个操作数不能都是存储单元 (4)堆栈的操作数不能是字节量 (5)adc的操作数不能是段寄存器 (6)没有确定是字节还是字操作 (7)in不支持超过FFH的直接寻址 (8)out只能以AL/AX为源操作数 第二章(02) 2.11; 指令AX的值CF OF SF ZF PF Mov ax,1407h1470h----- And ax,ax1470h00000 Or ax,ax1470h00000 Xor ax,ax000011 Not ax0ffffh----- Test ax,0f0f0h0ffffh00101 注意: 1. mov, not指令不影响标志位 2. 其他逻辑指令使CF=OF=0, 根据结果影响其他标志位。

汇编语言试题及答案.

一,单项选择题(每小题1分,共20分 1-10CCCCAADACB 11-20.ADBBAADDCC 1.指令JMP FAR PTR DONE属于( C A.段内转移直接寻址 B.段内转移间接寻址 C.段间转移直接寻址 D.段间转移间接寻址 2.下列叙述正确的是( A.对两个无符号数进行比较采用CMP指令,对两个有符号数比较用CMP S指令 B.对两个无符号数进行比较采用CMPS指令,对两个有符号数比较用CM P指令 C.对无符号数条件转移采用JAE/JNB指令,对有符号数条件转移用JGE/J NL指令 D.对无符号数条件转移采用JGE/JNL指令,对有符号数条件转移用JAE/J NB指令 3.一个有128个字的数据区,它的起始地址为12ABH:00ABH,请给出这个数据区最末一个字单元的物理地址是( A.12CSBH B.12B6BH

C.12C59H D.12BFEH 4.在下列指令的表示中,不正确的是( A.MOV AL,[BX+SI] B.JMP SHORT DONI C.DEC [BX] D.MUL CL 5.在进行二重循环程序设计时,下列描述正确的是( A.外循环初值应置外循环之外;内循环初值应置内循环之外,外循环之内 B.外循环初值应置外循环之内;内循环初值应置内循环之内 C.内、外循环初值都应置外循环之外 D.内、外循环初值都应置内循环之外,外循环之内 6.条件转移指令JNE的测试条件为( A.ZF=0 B.CF=0 C.ZF=1 D.CF=1 7.8086CPU在基址加变址的寻址方式中,变址寄存器可以为( A.BX或CX

B.CX或SI C.DX或SI D.SI或DI 8.已知BX=2000H,SI=1234H,则指令MOV AX,[BX+SI+2]的源操作在(中。 A.数据段中偏移量为3236H的字节 B.附加段中偏移量为3234H的字节 C.数据段中偏移量为3234H的字节 D.附加段中偏移量为3236H的字节 9.执行如下程序:( MOV AX,0 MOV AX,0 MOV BX,1 MOV CX,100 A:ADD AX,BX INC BX LOOP A HLT 执行后(BX=( A.99

汇编语言程序的设计试卷与答案

汇编语言程序设计试卷 一、单项选择题(在每小题的四个备选答案中,选出一个正确的答案,并将其号码填在题干后的括号内,每小题1分,共20分) 1.十六进制数88H,可表示成下面几种形式,请找出错误的表示()。 ① 无符号十进制数136 ② 带符号十进制数-120 ③ 压缩型BCD码十进制数88 ④ 8位二进制数-8的补码表示 2.指令指针寄存器是()。 ① IP ② SP ③ BP ④ PSW 3.当执行指令ADD AX,BX后,若AX的内容为2BA0H, 设置的奇偶标志位PF=1,下面的叙述正确的是()。 ① 表示结果中含1的个数为偶数 ② 表示结果中含1的个数为奇数 ③ 表示该数为偶数 ④ 表示结果中低八位含1的个数为偶数 4.完成将累加器AL清零,并使进位标志CF清零, 下面错误的指令是()。 ① MOV AL,00H ② AND AL,00H

③ XOR AL,AL ④ SUB AL,AL 5.下列指令执行后总是使CF=0,OF=0的是()。 ① AND ② NEG ③ NOT ④ INC 6.完成同指令XCHG AX,BX相同功能的指令或指令序列是()。 ① MOV AX,BX ② MOV BX,AX ③ PUSH AX POP BX ④ MOV CX,AX MOV AX,BX MOV BX,CX 7.设AH=0,AL=06H,BL=09H,执行指令 ADD AL,BL AAA 之后,其结果应是()。 ① AH=01,AL=05 ② AH=1 AL=15 ③ AH=0 AL=0FH ④ AH=0 AL=05 8.设AL=0B4H,BL=11H,指令“MUL BL”和指令“IMUL BL”分别执行后OF,CF的值为

汇编语言程序设计教程(第3版 卜艳萍)参考答案

汇编语言程序设计教程(第3版) 习题参考答案 第1章汇编语言基础知识 思考与练习 1.计算机系统分哪几个层次?简述计算机系统的硬件结构。 1)数字逻辑层 2) 微体系结构层 3) 指令系统层 4) 操作系统层 5) 汇编语言层 6) 高级语言层 7) 应用层 硬件系统是指构成计算机系统的物理实体或物理装置。它由控制器、运算器、存储器、输入设备和输出设备等部件构成。 2.简述用汇编语言进行程序设计的必要性。 1)程序要具有较快的执行时间,或者只能占用较小的存储容量。例如,操作系统的核 心程序段,实时控制系统的软件,智能仪器仪表的控制程序等。 2)程序与计算机硬件密切相关,程序要直接、有效地控制硬件。例如,I/O接口电路 的初始化程序段,外部设备的低层驱动程序等。 3)大型软件需要提高性能、优化处理的部分。例如计算机系统频繁调用的子程序、动 态连接库等。 4)没有合适的高级语言或只能采用汇编语言的时候。例如,开发最新的处理器程序时, 暂时没有支持新指令的编译程序。 5)汇编语言还有许多实际应用,例如分析具体系统尤其是该系统的低层软件、加密解 密软件、分析和防治计算机病毒等。 3.汉字编码主要分哪几类?每类的功能如何? 汉字编码主要分为四类:汉字输入码、汉字交换码、汉字机内码和汉字字形码。 1)为了能直接使用西文标准键盘进行输入,就必须为汉字设计相应的编码方法,即用 西文标准键盘上的字母数字串表示汉字的编码。目前,汉字输入编码方法主要有三 种:数字编码、拼音编码和字形编码。 2)汉字交换码:在不同汉字信息处理系统间进行汉字交换时所使用的编码,就是国标 码。无论采用哪种方法输入汉字,一旦输入到计算机中,必须采用统一的国标码标 识每个汉字。 3)汉字机内码是汉字在设备或信息处理系统内部最基本的表达形式,是在设备和信息 处理系统内部存储、处理、传输汉字用的编码。 4)字形编码也称为字模码,是用点阵表示的汉字字形代码,它是汉字的输出形式。4.计算机的字长是怎么定义的,试举例说明。 计算机能同时处理二进制信息的位宽定义为计算机的字长。如8086能同时进行16位二进制数据的运算、存储和传输等操作,该机器的字长为16位。 5.在汇编语言中,如何表示二进制、八进制、十进制和十六进制的数值? 用相应进制的数值加上进制标记即可。

汇编语言试题及答案

一,单项选择题(每小题1分,共20分) 1.指令JMP FAR PTR DONE属于() A.段内转移直接寻址 B.段内转移间接寻址 C.段间转移直接寻址 D.段间转移间接寻址 2.下列叙述正确的是() A.对两个无符号数进行比较采用CMP指令,对两个有符号数比较用CMPS 指令 B.对两个无符号数进行比较采用CMPS指令,对两个有符号数比较用CMP 指令 C.对无符号数条件转移采用JAE/JNB指令,对有符号数条件转移用JGE/JN L指令 D.对无符号数条件转移采用JGE/JNL指令,对有符号数条件转移用JAE/JN B指令 3.一个有128个字的数据区,它的起始地址为12ABH:00ABH,请给出这个数据区最末一个字单元的物理地址是() A.12C5BH B.12B6BH C.12C5AH D.12BFEH 4.在下列指令的表示中,不正确的是() A.MOV AL,[BX+SI] B.JMP SHORT DONI C.DEC [BX] D.MUL CL 5.在进行二重循环程序设计时,下列描述正确的是() A.外循环初值应置外循环之外;内循环初值应置内循环之外,外循环之内B.外循环初值应置外循环之内;内循环初值应置内循环之内 C.内、外循环初值都应置外循环之外 D.内、外循环初值都应置内循环之外,外循环之内 6.条件转移指令JNE的测试条件为() A.ZF=0 B.CF=0 C.ZF=1 D.CF=1 7.8086CPU在基址加变址的寻址方式中,变址寄存器可以为()A.BX或CX B.CX或SI C.DX或SI D.SI或DI 8.已知BX=2000H,SI=1234H,则指令MOV AX,[BX+SI+2]的源操作在()中。 A.数据段中偏移量为3236H的字节 B.附加段中偏移量为3234H的字节 C.数据段中偏移量为3234H的字节 D.附加段中偏移量为3236H的字节 9.执行如下程序:()

汇编语言程序设计习题集111

16.提示下列指令序列执行后的正确结果是( A )。 MOV BX,OFFFCH MOV CL,2 SAR BX,CL A.3FFFH B.0FFFH C.0FFFCH D.0FFF5H 19. 指令SCAS的寻址方式是()。 A 源操作数为寄存器寻址,目的操作数为寄存器间接寻址 B 源操作数为寄存器间接寻址,目的操作数为寄存器间接寻址 C 源操作数为寄存器间接寻址,目的操作数为寄存器寻址 D 源操作数为寄存器寻址,目的操作数为寄存器寻址 22. 下列指令中不合法的指令是(C)。 A IN AX, 03F8H B MOV BX, AX C REP CMPSB D SHR BX, CL 23. 下列指令中正确的是()。 A MOV SS, 2400H B MOV SS, [2400H] C MOV SS, DS D MOV SS, SP 24. 下列指令中正确的是(A)。 A XCHG AH, AL B XCHG AL, 20H C XCHG DS, AX D XCHG SP, [20H] 29. 下列程序段执行完后,BX寄存器中的内容是( C )。 MOV CL, 3 MOV BX, 0B7H ROL BX, 1 ROR BX, CL A 002DH B 00EDH C C02DH D 000DH 30. 执行下列程序: MOV AX, 0 MOV BX, 1 MOV CX, 100 A: ADD AX, BX INC BX LOOP A HLT 执行后的结果为:(AX)= ( C ),(BX)= ( ). A 5050,99 B 2500,100 C 5050,101 D 2550,102 35. 逻辑位移指令SHR用于(D),而算术位移指令SAR用于带符号数除2。

X86汇编(实模式)

前沿:今年的前些时候,在杂志的一篇文章看到如下一句:―掌握汇编,仍是高手必经之路‖。然而在实际的学习中,汇编往往因为其应用太难而被初学者忽视。熟悉汇编语言,将是自己在软件调试时的―倚天剑‖,重要性实不言而喻。也有很多在学习的过程中几次三番,最终退却。希望这一篇文章可以与你一起,重拾汇编这把双刃剑。文档转载请注明―天衣有缝‖原创。 0.本文讲述汇编语言的基础知识,寻址方式,指令系统,宏汇编,结构化程序设计,堆栈,函数,中断等知识 1.汇编简介: 汇编语言是一种符号语言,比机器语言容易理解和掌握,也容易调试和维护。但是,汇编语言源程序要翻译成机器语言程序才可以由计算机执行。这个翻译的过程称为―汇编‖,这种把汇编源程序翻译成目标程序的语言加工程序称为汇编程序。汇编语言虽然较机器语言直观,但仍然烦琐难懂。于是人们研制出了高级程序设计语言。高级程序设计语言接近于人类自然语言的语法习惯,与计算机硬件无关,易被用户掌握和使用。 汇编语言的特点: (1)汇编语言与处理器密切相关。 (2)汇编语言程序效率高。 (3)编写汇编语言源程序比编写高级语言源程序烦琐。 (4)调试汇编语言程序比调试高级语言程序困难。 汇编语言的主要应用场合: (1)程序执行占用较短的时间,或者占用较小存储容量的场合。 (2)程序与计算机硬件密切相关,程序直接控制硬件的场合。 (3)需提高大型软件性能的场合。 (4)没有合适的高级语言的场合。 2.数值数据: 数值数据分为有符号数和无符号数。无符号数最高位表示数值,而有符号数最高位表示符号。有符号数有不同的编码方式,常用的是补码。 n位二进制数能够表示的无符号整数的范围是: 0 ≤I ≤ 2n-1 n位二进制数能够表示的有符号整数的范围是: -2(n-1)≤ I ≤+2(n-1)-1 ASCII码: 标准ASCII码用7位二进制数编码,共有128个。 计算机存储器基本单位为8位,ASCII码的最高位通常为0,通信时,最高位用作奇偶校验位。 ASCII码表中的前32个和最后1个编码是不能显示的控制字符,用于表示某种操作。 ASCII码表中20H后的94个编码是可显示和打印的字符,其中包括数码0~9,英文字母,标点符号等。BCD码: 虽然二进制数实现容易,但不符合人们的使用习惯,且书写阅读不方便,所以在计算机输入输出时通常还是采用十进制来表示数,这就需要实现十进制与二进制间的转换。为了转换方便,常采用二进制编码的十进制,

汇编语言2008秋季期末考试复习题及参考答案

汇编语言2008秋季期末考试复习题及参考答案 一、填空 1. 十进制数369转换成二进制数为()2,转换成十六进制数为()16. 2. 计算机中的指令由()和(地址码)两部分组成。 3. 8086的地址总线有20根,寻址范围为()字节。 4. 下一条将要执行的指令的地址存放在寄存器()中。 5. 写出IBM PC机的三种子程序返回的指令(RET), (IRET),(IRETD)。 6. 汇编语言源程序需经过()程序汇编,()程序连接才能生成可执行文件。 7. 存储器某单元的地址表示为2314H:4132H,则它的偏移地址=(4132),物理地址=() 8. REP指令前缀与()指令配合使用。 9. 在显示器上查看和修改内存单元的内容可以使用DEBUG的()和()命令。 10. (AL)=BFH,要求屏蔽第0,1两位,则要执行指令();如果要求第0,1位变反,可使用指令() 11. 宏汇编适合于(),()的子功能段使用; 二、选择题 1. 设字长N=16,有符号数7AE9H的补码表示为( ) A.9EA7H B. 76C4H C. 8417H D. 7AE9H 2. 比较有符号数3260H与0B425H的大小关系为( ) A. 相等 B. 小于 C. 大于 D. 不能比较 3. 指令JMP WORD PTR [BX][DI]中转移的目标地址为( ) A.16 d x(DS)+(BX)+(DI)B.16d x(ES)+(BX)+(DI) C.16d x(SS)+(BX)+(DI)D.16d x(CS)+(BX)+(DI) 4. 在指令MOV AX,[1000H]中,源操作数的寻址方式为( ) A.立即寻址B.直接寻址C.段内间接寻址D.寄存器寻址 5. 中断矢量表中存放的是( ) A. 中断类型号 B. 断点地址 C. 中断服务程序 D. 中断服务程序入口地址 6. 8086 的汇编语言指令系统中的条件转移指令可以使程序转移到( ) A. 段内的任何地方 B. 距该指令偏移地址为-32768~+32767的地方 C. 距该指令偏移地址为-128~+127的地方. D. 段外 7. 能定义ASCII码字符串的数据定义语句有( ) A. DB,DW,DD,DQ,DT B. DB,DW,DD C. DB, DW D. DB; 8. 若(AL)=87H,执行ADD AL,0F5H后,S,Z,C,O,P的状态为( ) A.SF=0,ZF=0,CF=1,OF=1,PF=0 B.SF=1,ZF=0,CF=1,OF=0,PF=1 C.SF=0,ZF=0,CF=0,OF=1,PF=0 D.SF=1,ZF=0,CF=1,OF=1,PF=1 9. 比较指令CMP( ) A. 专用于有符号数比较 B. 专用于无符号数比较 C. 专用于串比较 D. 不区分比较的对象是有符号数还是无符号数 10. 数据传送指令对标志位的影响为( ) A.都不影响;B.都影响; C.除了SAHF,POPF,其它均不影响. D.除了控制标志位,其它均不影响 三、判断题 ( )31. 段间调用的子程序必须由伪操作FAR说明为远过程。

汇编语言程序设计试题

汇编语言程序设计试题 一、单项选择题(本大题共20小题,每小题1分,共20分) 在每小题列出的四个备选项中只有一个是符合题目要求的,请将其代码填写在题后的括号内。错选、多选或未选均无分。 1.设SS=2050H,SP=0140H,则栈顶存贮单元的物理地址是( A ) A.20640H B.2063EH C.2063FH D.21900H 2.使用DOS功能调用时,子程序编号应放在( B ) A.AL B.AH C.AX D.任意指定 3.没有 ..语法错误的输出指令是( B ) P76 A.OUT AX,30H B.OUT DX,AL C.OUT AL,DX D.OUT 30H,AH 4.用MOV指令将十进制数89以非压缩BCD码格式送入AX,可使用的指令是( B ) A.MOV AX,89 B.MOV AX,0809H C.MOV AX,89H D.MOV AX,0809 5.设AX=8765H,DX=4321H,执行CWD指令后,DX中的内容是( B ) P117 A.4321H B.0FFFFH C.8000H D.0001H 6.设CL=05H,要获得CL=0AH,可选用的指令是( A) A.XOR CL,0FH B.NOT CL C.OR CL,0AH D.AND CL,0FH 7.假设执行ADD指令后AL=8CH,再执行DAA指令,AL中的值是( A ) A.92H B.0104H C.74H D.8CH 8.MOV AL,79H ADD AL,B1H 上面指令执行后,设置的标志位CF和ZF的值是( D ) A.CF=0,ZF=1 B.CF=l,ZF=1 C.CF=0,ZF=0 D.CF=1,ZF=0 9.TEST DL,55H P123 JZ NEXT NEXT:…… … 上述程序段,执行JZ指令时能产生转移的情况是( D ) A.DL>55H B.DL<55H C.DL=55H D.DL中第0、2、4、6位均为0 10.假设AL=28H, 执行ROL AL,1 指令之后的情况是( D ) P125 A.AL=14H, CF=1 B.AL=50H, CF=1 C.AL=14H, CF=0 D.AL=50H, CF=0 11. 98的BCD码是(B) A)10011001 B) 10011000 C) 10011010 D) 10001010 12. –0110110 的补码是(A) A) 11001010 B) 11001001 C) 10110110 D) 00110110

相关文档
最新文档