Kip Irvine 汇编语言 基于x86处理器 Chapter10 代码(含习题)

案例代码

01.AllPoints

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	NumPoints	=		3
	ALIGN		WORD
	AllPoints	COORD	NumPoints	DUP(<0,0>)

.code
	main PROC

		mov		edi,0								;数组索引
		mov		ecx,NumPoints						;循环计数器
		mov		ax ,1								;起始X Y的值

	L1:
		mov		(COORD PTR AllPoints[edi]).X,ax		;引用操作数
		mov		(COORD PTR AllPoints[edi]).Y,ax		;引用操作数
		add		edi,TYPE COORD						;指向下一个顶点坐标位置
		inc		ax
		loop	L1

		exit

		invoke ExitProcess,0
	main ENDP
	END main

02.对齐的结构成员的性能

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

;定义结构
EmployeeBad			STRUCT
	IdNum			BYTE	"000000000"
	LastName		BYTE	30	DUP(0)
	Years			WORD	0
	SalaryHistory	DWORD	0,0,0,0
EmployeeBad			ENDS

Employee			STRUCT
	IdNum			BYTE	"000000000"
	LastName		BYTE	30	DUP(0)
	ALIGN			WORD
	Years			WORD	0
	ALIGN			DWORD
	SalaryHistory	DWORD	0,0,0,0
Employee			ENDS


.data

	ALIGN			DWORD
	startTime		DWORD		0			;对齐startTime
	empGood			Employee	<>			;定义GoodEmployee对象				
	empBad			EmployeeBad	<>			;定义BadEmployee对象

.code
	main PROC
		;10826
		call	GetMSeconds					;获取系统时间
		mov		startTime,eax				;保存开始时间

		mov		ecx,0ffffffffh				;设置循环计数器
	L1:
		mov		empGood.Years,5				;进行任意的赋值操作
		mov		empGood.SalaryHistory,35000
		loop	L1

		call	GetMSeconds
		sub		eax,startTime				;计算并显示所花费的时间
		call	WriteDec			

		call	Crlf

		;11033
		;call	GetMSeconds						;获取系统时间
		;mov		startTime,eax				;保存开始时间

		;mov		ecx,0ffffffffh				;设置循环计数器
	;L2:
		;mov		empBad.Years,5				;进行任意的赋值操作
		;mov		empBad.SalaryHistory,35000
		;loop	L2

		;call	GetMSeconds
		;sub		eax,startTime				;计算并显示所花费的时间
		;call	WriteDec		
		
		;call	Crlf

		invoke ExitProcess,0
	main ENDP
	END main

03.ShowTime

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	sysTime			SYSTEMTIME	<>						;定义系统时间对象
	XYPos			COORD		<10,5>					;定义显示位置对象
	consoleHandle	DWORD		0						;定义控制台标准输出句柄
	consoleStr		BYTE		":",0					;定义时间分隔符

.code
	main PROC

		;获取Win32控制台的标准输出句柄
		invoke		GetStdHandle,STD_OUTPUT_HANDLE
		mov			consoleHandle,eax					;将句柄保存

		;设置光标位置并获取系统时间
		invoke		SetConsoleCursorPosition,
						consoleHandle,XYPos				
		invoke		GetLocalTime,ADDR sysTime

		;显示系统时间
		movzx		eax,sysTime.wHour					;获取小时
		call		WriteDec
		mov			edx,offset consoleStr				;显示冒号:
		call		WriteString

		movzx		eax,sysTime.wMinute					;获取分钟
		call		WriteDec
		mov			edx,offset consoleStr				;显示冒号
		call		WriteString

		movzx		eax,sysTime.wSecond					;获取秒数
		call		WriteDec
		call		Crlf
		call		WaitMsg								;Press any key to
		exit


		invoke ExitProcess,0
	main ENDP
END main

04.结构包含结构

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

Rectangle	STRUCT
	UpperLeft	COORD	<>
	LowerRight	COORD	<>
Rectangle	ENDS

.data

	rect1	Rectangle	< >
	rect2	Rectangle	{ }
	rect3	Rectangle	{ {10,10},{50,20} }
	rect4	Rectangle	< <10,10>,<50,20> >

.code
	main PROC

		;对其中一个的结构字段的直接引用
		mov	rect1.UpperLeft.X,10

		;使用间接操作数访问字段结构
		mov	esi,offset rect1
		mov (Rectangle PTR [esi]).UpperLeft.Y,10

		;offset运算符可以返回单个结构变量的指针包括嵌套字段
		mov edi,offset rect3.LowerRight
		mov (COORD PTR [edi]).X,50
		mov edi,offset rect3.LowerRight.Y
		mov WORD PTR [edi],50

		invoke ExitProcess,0
	main ENDP
END main

05.模拟醉汉随机游走

;随机游走模拟
;模拟醉汉随机游走,醉汉的起点在(25,25),并且在周围徘徊

include irvine32.inc

WalkMax	=	50
StartX	=	25
StartY	=	25

;定义结构体
DrunkardWalk	STRUCT
	path		COORD	WalkMax	DUP(<0,0>)
	pathsUsed	WORD	0
DrunkardWalk	ENDS

DisplayPosition	PROTO	currX:WORD,currY:WORD


.data
	aWalk		DrunkardWalk <>

.code
	main PROC
	mov			esi,OFFSET aWalk
	call		TakeDrunkenWalk
	call		WaitMsg
	exit
	main ENDP

;------------------------------------------
TakeDrunkenWalk PROC
	LOCAL	currX:WORD,currY:WORD				;自定义临时变量
;向随机方向行走(东西南北)
;接收:ESI为DrunkardWalk的结构指针
;返回:结构初始化为随机数						;这里没有传参数所以需要保存寄存器
;------------------------------------------
	pushad
	;用OFFSET运算符获取path-----COORD对象数组的地址,将其复制到EDI
	mov		edi,	esi
	add		edi,	OFFSET DrunkardWalk.path
	mov		ecx,	WalkMax						;循环计数器
	mov		currX,	StartX						;当前X的位置
	mov		currY,	StartY						;当前Y的位置

Again:
	;把当前位置插入数组
	mov		ax,		currX
	mov		(COORD PTR [edi]).X,ax
	mov		ax,		currY
	mov		(COORD PTR [edi]).Y,ax

	invoke	DisplayPosition,currX,currY

	mov		eax,	4							;选择一个方向(0-3)
	call    RandomRange
	.IF		eax==0								;北
	dec		currY
	.ELSEIF	eax==1								;南
	inc		currY
	.ELSEIF eax==2								;西
	dec		currX
	.ELSE	
	inc		currX								;.ENDIF

	add edi,TYPE COORD							;指向下一个COORD
	loop Again

Finish:
	mov (DrunkardWalk PTR [esi]).pathsUsed,WalkMax
	popad
	ret
TakeDrunkenWalk	ENDP

;----------------------------------------------
DisplayPosition PROC currX:WORD,currY:WORD
;显示当前X和Y的位置
;----------------------------------------------
.data
	commaStr	BYTE	",",0
.code
	pushad
	movzx		eax		,currX		;当前X的位置
	call		WriteDec
	mov			edx,OFFSET  commaStr
	call        WriteString
	movzx		eax		,currY
	call		WriteDec
	call		Crlf
	popad
	ret
DisplayPosition ENDP
END main

06.使用简单的宏

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

;在这里定义宏
printX MACRO
	mov		al,'X'
	call	WriteChar
ENDM

.data


.code
	main PROC

		;在这里调用宏
		printX
		invoke ExitProcess,0
	main ENDP
END main

07.mPutChar

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


mPutChar MACRO char
	push eax
	mov  al,char
	call WriteChar
	pop  eax
ENDM

.data


.code
	main PROC

		mPutChar 'A'		;对于一个宏,它仅仅是一段代码并不是函数所以直接把宏的名字卸载某一个位置就等价于函数调用
		invoke	ExitProcess,0
	main ENDP
END main

08.使用宏打印字母表

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

mPutChar MACRO char
	push	eax
	mov		al,char
	call	WriteChar
	pop		eax
ENDM

.data


.code
	main PROC

		mov			ecx,26
		mov			al,'A'
	L:
		mPutChar	al
		mPutChar	' '
		inc			al
		loop		L

		invoke ExitProcess,0
	main ENDP
END main

09.REQ限定符规定形参

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

mPutChar MACRO char:REQ		;REQ限定符表示参数char在宏调用的时候必须被传递
	push	eax
	mov		al,char
	call	WriteChar
	pop		eax
ENDM

.data


.code
	main PROC

		mov			ecx,26
		mov			al,'A'
	L:
		mPutChar	al
		mPutChar	' '
		inc			al
		loop		L

		invoke ExitProcess,0
	main ENDP
END main

10.ECHO伪指令

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

mPutChar	MACRO	char:REQ
	;在使用宏汇编的时候,利用echo指令可以不外加双引号的情况下直接输出字符串
	ECHO	output a character:
	push	eax		;;提示:char必须包含8个比特
	mov		al,char
	call	WriteChar
	pop		eax
ENDM

.data


.code
	main PROC

		mPutChar	'X'
		invoke ExitProcess,0
	main ENDP
END main

11.使用LOCAL伪指令避免宏内部标号重复导致不可以汇编的问题

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

makeString	MACRO text
	LOCAL	string				;使用local做限定的原因是 汇编器不允许有两个标号相同的名称
								;使用了local之后string就会变成宏内部的局部变量,在汇编的
								;时候,汇编器会将这个字符串转化为另外一个唯一的名字,用于
								;区分
	.data
		string	BYTE	text,0	;使用宏参数初始化宏内部的局部变量
	.code
		mov		edx,offset string
		call	WriteString
ENDM

.data

.code
	main PROC

		makeString	"hello world";当时用不含有结束标志的字符串作为参数的时候必须要加上双引号做字符串起止位置的标记
		invoke		ExitProcess,0
	main ENDP
END main

12.使用包含代码和数据的宏

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

mWrite	MACRO	text
		local	string				;;使用local标号
	.data
		string	BYTE	text,0
	.code
		push	edx
		mov		edx,offset string
		call	WriteString
		pop		edx
ENDM

.data


.code
	main PROC

		;调用宏输出字符串
		mWrite	"Hello World"
		invoke ExitProcess,0
	main ENDP
END main

13.MacroTest

;测试Macro.inc库

;本程序说明Macros.inc文件中定义的不同宏的使用方式

include irvine32.inc
include macros.inc

NAME_SIZE = 50

.data
	str1	BYTE	NAME_SIZE DUP(0)
	array	DWORD	5		  DUP(12345678h)

.code
	main	PROC
		call		Clrscr
		mGotoxy		20,0
		mDumpMem	offset array,lengthof array,type array

		mGotoxy		10,8
		mWrite		"Please enter your first name:"
		mReadString	str1

		mGotoxy		10,10
		mWrite		"Your name is:"
		mWriteString str1
		call		Crlf

		exit

	main	ENDP
END main

14.mDumpMem宏的使用

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	array	DWORD	1000h,2000h,3000h,4000h

.code
	main PROC
		;显示数组
		mDumpMem	offset array,lengthof array,type array
		;按照内存存储顺序显示数组
		mDumpMem	offset array,sizeof	  array,type byte

		invoke ExitProcess,0
	main ENDP
END main

15.使用DumpMem显示堆栈

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data


.code
	main PROC
		
		mov		eax,0AAAAAAAAh
		push	eax
		mov		eax,0BBBBBBBBh
		push	eax
		mov		eax,0CCCCCCCCh
		push	eax

		mov		ebx,1
		mov		ecx,2
		mov		esi,3
		;可以看出 mDumpMem的实现利用到了ebx ecx esi三个寄存器
		mDumpMem	esp,8,type dword

		invoke ExitProcess,0
	main ENDP
END main

16.mDump宏的使用

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	diskSize	DWORD	12345h

.code
	main PROC

		mDump	diskSize		;没有标记 
		mDump	diskSize,Y		;含有标记 Variable name:diskSize

		invoke ExitProcess,0
	main ENDP
END main

17.mGotoXY宏的使用

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	buffer	BYTE	"Hello World!",0

.code
	main PROC

		mGotoxy			50,50
		mWriteString	offset buffer

		invoke ExitProcess,0
	main ENDP
END main

18.mReadString宏的使用

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	firstName	BYTE	30 DUP(0)

.code
	main PROC

		mReadString	firstName
		mov			edx,offset firstName
		call		WriteString
		call		Crlf
		invoke ExitProcess,0
	main ENDP
END main

19.mShow宏的使用

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data


.code
	main PROC
		
		mov		ax,4096
		mShow	ax			;默认选项:HIN 十六进制 又符号十进制 换行
		mShow	ax,DBN		;设置显示格式 无符号十进制 二进制 换行

		invoke ExitProcess,0
	main ENDP
END main

20.mShowRegister宏的使用

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	msg1	BYTE	"ESP寄存器:",0
	msg2	BYTE	"EAX寄存器:",0

.code
	main PROC
		
		mov eax,100h

		mov edx,offset msg1
		call	WriteString
		mShowRegister <Stack Pointer>,esp	;显示栈的基址寄存器的值
		call	Crlf

		mov edx,offset msg2
		call	WriteString
		mShowRegister <EAX 寄存器>,eax		;显示EAX寄存器的值

		invoke ExitProcess,0
	main ENDP
END main

21.mWriteSpace

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data
	
	str1	BYTE	"My name is:",0
	str2	BYTE	"Kan Hideo",0


.code
	main PROC

		mov				edx,offset str1
		call			WriteString
		mWriteSpace		10
		mWriteString	str2
		call			Crlf
		call			WaitMsg

		invoke ExitProcess,0
	main ENDP
END main

22.示例程序 封装器

include irvine32.inc
include macros.inc

;过程封装器宏		(Wraps.asm)
;本程序演示宏作为库过程封装器
;内容 mGotoxy mWrite mWriteString mReadString mDumpMem

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data
	
	array		DWORD	1,2,3,4,5,6,7,8
	firstname	BYTE	31	DUP(0)
	lastname	BYTE	31	DUP(0)
	
.code
	main PROC
		
		mGotoxy		0,0
		mWrite		<"Sample Marco Program",0dh,0ah>
		
		;输入用户名
		mGotoxy		0,5
		mWrite		"Please enter your first name:"
		mReadString	firstname
		call		Crlf

		mWrite		"Please enter your last name:"
		mReadString	lastname
		call		Crlf

		;显示用户名
		mWrite		"Your name is:"
		mWriteString firstname
		mWriteSpace
		mWriteString lastname
		call		Crlf

		;显示整数数组
		mDumpMem	offset array,lengthof array,type array
		exit
		invoke		ExitProcess,0
	main ENDP
END main

23.改进版mWriteString

; Useful Macros                  (Macro2.ASM)

; This program demonstrates several useful macros:
; mGotoxy, mWrite, mWriteLn, mWriteStr, mReadStr,
; and mDumpMem.

INCLUDE Irvine32.inc

;-----------------------------------------------------
mWriteStr MACRO buffer
;
; Improved version of mWriteStr that checks for
; a blank argument.
;-----------------------------------------------------
	IFB <buffer>
	  ECHO -----------------------------------------
	  ECHO *  Error: parameter missing in mWriteStr
	  ECHO *  (no code generated)
	  ECHO -----------------------------------------
	  EXITM
	ENDIF
	push edx
	mov  edx,OFFSET buffer
	call WriteString
	pop  edx
ENDM

;-----------------------------------------------------
mWrite MACRO text
;
; No changes to this macro.
;-----------------------------------------------------
	LOCAL string
	.data		;; local data
	string BYTE text,0		;; define the string
	.code
	push edx
	mov  edx,OFFSET string
	call Writestring
	pop  edx
ENDM

;-----------------------------------------------------
; This version supplies a default argument.

mWriteLn MACRO text := < " " >
;-----------------------------------------------------
	mWrite text
	call Crlf
ENDM

;-----------------------------------------------------
mGotoxyConst MACRO X:REQ, Y:REQ
;
; Set the cursor position
; This version checks the ranges of X and Y.
; are not used.
;------------------------------------------------------
	LOCAL ERRS					;; local constant
	ERRS = 0
	IF (X LT 0) OR (X GT 79)
	   ECHO Warning: First argument to mGotoxy (X) is out of range.
	   ECHO ********************************************************
	   ERRS = 1
	ENDIF
	IF (Y LT 0) OR (Y GT 24)
	   ECHO Warning: Second argument to mGotoxy (Y) is out of range.
	   ECHO ********************************************************
	   ERRS = ERRS + 1
	ENDIF
	IF ERRS GT 0				;; if errors found,
	  EXITM						;; exit the macro
	ENDIF
	push edx
	mov  dh,Y
	mov  dl,X
	call Gotoxy
	pop  edx
ENDM

;------------------------------------------------------
mReadStr MACRO bufferPtr, maxChars
;
; Read from standard input into a buffer.
; EDX cannot be the second argument.
;------------------------------------------------------
	IFIDNI <maxChars> , <EDX>
	   ECHO Warning: EDX cannot be second argument to mReadStr.
	   ECHO ***************************************************
	   EXITM
	ENDIF
	push ecx
	push edx
	mov  edx,bufferPtr
	mov  ecx,maxChars
	call ReadString
	pop  edx
	pop  ecx
ENDM

;---------------------------------------------------
ShowRegister MACRO regName
             LOCAL tempStr
;
; Display a register's name and contents.
;---------------------------------------------------
.data
tempStr BYTE "  &regName=",0
.code
	push eax

; Display the register name
	push edx
	mov  edx,offset tempStr
	call WriteString
	pop  edx

; Display the register contents
	mov  eax,regName
	call WriteHex
	pop  eax
ENDM

.data
message BYTE "Hello there",0
buffer BYTE 50 DUP(?)


BadYValue TEXTEQU <Warning: Y-coordinate is !> 24>

ShowWarning MACRO message
	mWrite "&message"
ENDM

count = 4
sumVal TEXTEQU %5 + count        ; sumVal = 9

.code
main PROC
	mGotoxyConst %5 * 10, %3 + 4

	;ShowWarning %BadYValue

	call Crlf
	call Crlf

	ShowRegister ECX

	mReadStr OFFSET buffer,50		; ok

	mov edx,50
	;mReadStr buffer,edx			; generates warning

	mGotoxyConst 10,20

	mWrite "Line one"
	mWriteLn						; missing argument
	mWriteLn "Line two"

	mWrite <"Line three",0dh,0ah>

	;mWriteStr						; missing argument

	exit
main ENDP
END main

24.含有默认参数的宏

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

mWriteln	MACRO	text:=<" ">	;;设置默认参数
	mWrite	text
	call	Crlf
ENDM

.data


.code
	main PROC

		mWriteln
		mWriteln	"上面那句话是空串"
		invoke ExitProcess,0
	main ENDP
END main

25.IFIDN

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


;-----------------------------------------------------------------
mReadBuf	MACRO	bufferPtr,maxChars
;
;将键盘输入读到缓冲区
;接收 缓冲区偏移量 最多可输入字符的数量 第二个参数不能使用edx EDX
;-----------------------------------------------------------------
	ifidni		<maxChars>,<EDX>	;;如果maxChars==edx
		echo	Warning :Second argument to mReadBuf can't be EDX
		echo	***************************************
		EXITM
	endif
		push	ecx
		push	edx
		mov		edx,offset bufferPtr
		mov		ecx,maxChars
		call	ReadString
		pop		edx
		pop		ecx
ENDM


.data

	buffer		BYTE	20 DUP(0),0

.code
	main PROC
		;VS不支持显示IFIDN所表示的错误信息
		mov			eax,15
		mReadBuf	offset buffer,eax

		;输出刚才写入的内容
		mov			edx,offset buffer
		call		WriteString

		invoke ExitProcess,0
	main ENDP

END main

26.矩阵行求和 – version00

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	tableB	BYTE	10h, 20h, 30h, 40h, 50h;0xF0h
			BYTE    60h, 70h, 80h, 90h,0A0h;0280h
			BYTE   0B0h,0C0h,0D0h,0E0h,0F0h;0410h
	RowSize	   =	5
	msg1	BYTE	"Enter a row number:",0
	msg2	BYTE	"The sum is:",0

.code
	main PROC
		
		mov		edx,offset msg1		;显示提示信息
		call	WriteString
		
		call	ReadInt				;读取行号

		mov		ebx,offset tableB
		mov		ecx,RowSize
		call	calc_row_sum		;计算结果

		mov		edx,offset msg2		;显示结果提示信息
		call	WriteString
		call	WriteHex			;以十六进制的形式显示结果

		invoke ExitProcess,0
	main ENDP
	
	calc_row_sum PROC uses ebx ecx esi
	;-------------------------------------
	;接收 ebx 数组偏移量
	;	  eax 行号
	;	  ecx 每行元素字节数
	;-------------------------------------
		mul ecx									;从开始到指定行的字节数
		add	ebx,eax								;指定行的偏移量
		mov eax,0								;累加器清零
		mov esi,0								;偏移地址寄存器清零
	L1:
		movzx edx,byte ptr[ebx+esi*type byte]	;得到一个元素的值 从偏移量处使用间接寻址获得 将数据扩展到32bit
		add	  eax,edx							;累加
		inc   esi								;指向下一个元素
		loop	L1
		ret
	calc_row_sum ENDP
END main

27.矩阵行求和 – version01

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

mCalc_row_sum MACRO						;;宏一定要写在代码段的上面不然编译的时候会出现错误
;-------------------------------------
;接收 ebx 数组偏移量
;	  eax 行号
;	  ecx 每行元素字节数
;-------------------------------------
	push	ebx
	push	ecx
	push	esi

	mul ecx									;从开始到指定行的字节数
	add	ebx,eax								;指定行的偏移量
	mov eax,0								;累加器清零
	mov esi,0								;偏移地址寄存器清零
L1:
	movzx edx,byte ptr[ebx+esi]	;得到一个元素的值 从偏移量处使用间接寻址获得 将数据扩展到32bit
	add	  eax,edx							;累加
	inc   esi								;指向下一个元素
	loop	L1
		
	pop		esi
	pop		ecx
	pop		ebx

ENDM


.data

	tableB	BYTE	10h, 20h, 30h, 40h, 50h;0xF0h
			BYTE    60h, 70h, 80h, 90h,0A0h;0280h
			BYTE   0B0h,0C0h,0D0h,0E0h,0F0h;0410h
	RowSize	   =	5
	msg1	BYTE	"Enter a row number:",0
	msg2	BYTE	"The sum is:",0


.code
	main PROC
		
		mov		edx,offset msg1		;显示提示信息
		call	WriteString
		
		call	ReadInt				;读取行号

		mov		ebx,offset tableB
		mov		ecx,RowSize
		mov     eax,0
		mCalc_row_sum				;计算结果

		mov		edx,offset msg2		;显示结果提示信息
		call	WriteString
		call	WriteHex			;以十六进制的形式显示结果

		invoke ExitProcess,0
	main ENDP
	
	

END main

28.矩阵行求和 – version02

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

mCalc_row_sum MACRO index,arrayOffset,rowSize;;宏一定要写在代码段的上面不然编译的时候会出现错误

	push	ebx
	push	ecx
	push	esi

	mov		eax,index						 ;设置需要的寄存器
	mov		ebx,arrayOffset
	mov		ecx,rowSize

	mul ecx									 ;从开始到指定行的字节数
	add	ebx,eax								 ;指定行的偏移量
	mov eax,0								 ;累加器清零
	mov esi,0								 ;偏移地址寄存器清零
L1:
	movzx edx,byte ptr[ebx+esi]	             ;得到一个元素的值 从偏移量处使用间接寻址获得 将数据扩展到32bit
	add	  eax,edx							 ;累加
	inc   esi								 ;指向下一个元素
	loop	L1
		
	pop		esi								 ;恢复被修改的寄存器
	pop		ecx
	pop		ebx

ENDM


.data

	tableB	BYTE	10h, 20h, 30h, 40h, 50h;0xF0h
			BYTE    60h, 70h, 80h, 90h,0A0h;0280h
			BYTE   0B0h,0C0h,0D0h,0E0h,0F0h;0410h
	RowSize	   =	5
	msg1	BYTE	"Enter a row number:",0
	msg2	BYTE	"The sum is:",0


.code
	main PROC
		
		mov		edx,offset msg1							;显示提示信息
		call	WriteString
		
		call	ReadInt									;读取行号

		mCalc_row_sum eax,offset tableB,RowSize			;计算结果

		mov		edx,offset msg2							;显示结果提示信息
		call	WriteString
		call	WriteHex								;以十六进制的形式显示结果

		invoke ExitProcess,0
	main ENDP
END main

29.矩阵行求和 – version03

include irvine32.inc
include macros.inc

;--------------------------------------------------------------------
mCalc_row_sum	MACRO	index,arrayOffset,rowSize,eltType
;计算二维数组中的一行和数
;
;接收:行索引,数组偏移量,每行的字节数,数组类型(BYTE WORD 或 DWORD)
;返回:EAX=和数
;--------------------------------------------------------------------
local	L1											;在宏中,需要将标号声明为local
	push	ebx										;保存要被修改的寄存器
	push	ecx
	push	esi

	;设置需要被修改的寄存器
	mov		eax,index
	mov		ebx,arrayOffset
	mov		ecx,rowSize

	;计算行偏移量
	mul		ecx										;行索引X行大小
	add		ebx,eax									;行偏移量
	;初始化循环计数器
	shr		ecx,(type eltType/2)					;byte=0 word=1 dword=2
	;初始化累加器和列索引
	mov		eax,0									;累加器
	mov		esi,0									;列索引
L1:
	IFIDNI	<eltType>,<DWORD>
		mov		edx,eltType ptr[ebx+esi*(TYPE eltType)]
	ELSE
		movzx	edx,eltType ptr[ebx+esi*(TYPE eltType)]
	ENDIF
	add		eax,edx
	inc		esi
	loop	L1

	pop		esi
	pop		ecx
	pop		ebx
ENDM

.data
	tableB		BYTE	10h	,20h	,30h	,40h	,50h
	RowSizeB	=		($-tableB)
				BYTE	60h	,70h	,80h	,90h	,0A0h
				BYTE	0B0h,0C0h	,0D0h	,0E0h	,0F0h

	tableW		WORD	10h	,20h	,30h	,40h	,50h
	RowSizeW	=		($-tableW)
				WORD	60h	,70h	,80h	,90h	,0A0h
				WORD	0B0h,0C0h	,0D0h	,0E0h	,0F0h

	tableD		DWORD	10h	,20h	,30h	,40h	,50h
	RowSizeD	=		($-tableD)
				DWORD	60h	,70h	,80h	,90h	,0A0h
				DWORD	0B0h,0C0h	,0D0h	,0E0h	,0F0h

	index		DWORD	0
	msg1		BYTE	"Enter a row number:",0
	msg2		BYTE	"The sum is:",0

.code
	main PROC
			
			;------------------------------------------------------------------
			mov		edx,offset msg1							;显示提示信息
			call	WriteString
		
			call	ReadInt									;读取行号
			call	Crlf

			mCalc_row_sum eax,offset tableB,RowSizeB,BYTE	;计算结果B
			mov		edx,offset msg2							;显示结果提示信息
			call	WriteString
			call	WriteHex								;以十六进制的形式显示结果
			call	Crlf
			;------------------------------------------------------------------
			mov		edx,offset msg1							;显示提示信息
			call	WriteString
		
			call	ReadInt									;读取行号
			call	Crlf

			mCalc_row_sum eax,offset tableW,RowSizeW,WORD	;计算结果W
			mov		edx,offset msg2							;显示结果提示信息
			call	WriteString
			call	WriteHex								;以十六进制的形式显示结果
			call	Crlf
			;------------------------------------------------------------------
			mov		edx,offset msg1							;显示提示信息
			call	WriteString

			call	ReadInt									;读取行号
			call	Crlf

			mCalc_row_sum eax,offset tableD,RowSizeD,DWORD	;计算结果D
			mov		edx,offset msg2							;显示结果提示信息
			call	WriteString
			call	WriteHex								;以十六进制的形式显示结果
			call	Crlf

			invoke ExitProcess,0
		main ENDP
	END main
	

30.替换运算符

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

mShowRegister	MACRO	regName
	.data
		tempStr	BYTE	" &regName=",0
	.code
		mov		edx,offset tempStr
		call	WriteString
		mov		eax,regName
		call	WriteHex
ENDM

.data


.code
	main PROC

		mov				eax,10
		mshowRegister	eax

		invoke ExitProcess,0
	main ENDP
END main

31.展开运算符

include irvine32.inc
include macros.inc


.data
	
	array		DWORD		1,2,3,4,5,6,7,8
	count		=			5
	sumVal		TEXTEQU		%(5 + count)			;%表示计算
	SIZEARRAY	TEXTEQU		%(sizeof array)			;计算数组所占字节数

	val1		DWORD		1234h
	val2		DWORD		1000h
	val3		DWORD		0

.code
	main PROC

		mGotoxy	%(5*10),%(3+4)					;将光标重新置位
		
		; The following do not evaluate SIZEOF:
		ECHO The array contains (SIZEOF array) bytes
		ECHO The array contains %(SIZEOF array) bytes

		; Using the Expansion (%) operator at the beginning of a line:
		TempStr TEXTEQU %(SIZEOF array)
		%  ECHO The array contains TempStr bytes


		call	WaitMsg

		invoke ExitProcess,0
	main ENDP
	END main

32.显示行号

INCLUDE Irvine32.inc

MUL32 MACRO op1, op2, product
	IFIDNI <op2>,<EAX>
	  LINENUM TEXTEQU %(@LINE)
	  ECHO --------------------------------------------------
%	  ECHO *  Error on line LINENUM: EAX cannot be the second
	  ECHO *  argument when invoking the MUL32 macro.
	  ECHO --------------------------------------------------
	EXITM
	ENDIF
	push eax
	mov  eax,op1
	mul  op2
	mov  product,eax
	pop  eax
ENDM

.data
	val1 DWORD 1234h
	val2 DWORD 1000h
	val3 DWORD ?
	array DWORD 1,2,3,4,5,6,7,8

.code
	main PROC
	; The following do not evaluate SIZEOF:
		ECHO The array contains (SIZEOF array) bytes
		ECHO The array contains %(SIZEOF array) bytes

	; Using the Expansion (%) operator at the beginning of a line:
		TempStr TEXTEQU %(SIZEOF array)
		%  ECHO The array contains TempStr bytes


		;MUL32 val1,val2,val3		; val3 = val1 * val2

		mov eax,val2
		MUL32 val1,EAX,val3			; issues a warning

		exit
	main ENDP
END main

33.文字文本运算符

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data


.code
	main PROC
		mWrite <"Line Three",0dh,0ah>
		mWrite "Line Three",0dh,0ah
		mWrite <0dh,0ah>
		mWrite "Line Three",0dh,0ah		;如果不加上<>那么0dh,0ah会在连接时被忽略
		mWrite <"Line Three",0dh,0ah>

		invoke ExitProcess,0
	main ENDP
END main

34.文字文本运算符

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data


.code
	main PROC

		mWrite <"Hello World!",0dh,0ah>
		invoke ExitProcess,0
	main ENDP
END main

35.文字字符运算符

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	BadValue	TEXTEQU		<"Warning :Y-coordinate is !> 24"> ;;!就相当于C中的转义字符

.code
	main PROC

		mWrite BadValue
		invoke ExitProcess,0
	main ENDP
END main

36.警告信息实例

include irvine32.inc
include macros.inc
;本例演示了 替换运算符& 文字文本运算符<> 文字字符运算符! 展开运算符%  的综合利用
.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

mShowWarning MACRO message
	mWrite	" &message"		;;将message按照参数的值显示
ENDM

.data

	BadYValue	TEXTEQU		<Warning :Y-coordinate is !> 24,0dh,0ah>

.code
	main PROC
		
		mShowWarning % BadYValue
		invoke ExitProcess,0
	main ENDP
END main

37.宏函数使用实例 – 判断一个常量是否被定义

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

IsDefined	MACRO	symbol	;;本宏函数用来判断一个变量是否被定义
	IFDEF	symbol
		EXITM	<1>			;;真
	ELSE	
		EXITM	<0>			;;假
	ENDIF
ENDM

.data

	y	BYTE	"YES",0
	n	BYTE	"NO",0

.code
	main PROC

		IF IsDefined(RealMode)
			mov	edx,offset y
		ELSE
			mov edx,offset n
		ENDIF
		call	WriteString

		invoke ExitProcess,0
	main ENDP
END main

38.HelloNew

include macros.inc

IF IsDefined(RealMode)
	include irvine16.inc		;实模式下的头文件
ELSE
	include irvine32.inc		;保护模式下的头文件
ENDIF

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

;实模式预处理宏
Startup MACRO
	IF IsDefined(RealMode)
		mov ax,@data	;获取数据段的起始地址
		mov ds,ax
	ENDIF
ENDM

.data


.code
	main PROC
		
		Startup
		mWrite <"This program can be assembled to run!",0dh,0ah>
		mWrite <"in both Real mode and Protected mode",0dh,0ah>

		invoke ExitProcess,0
	main ENDP
END main

39.使用while伪指令生成斐波那契数列

include irvine32.inc 
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data
	
	val1 = 1
	val2 = 1
	DWORD	val1		;前两个值
	DWORD	val2
	val3 = val1 + val2
	while	val3 LT 0f0000000h
		DWORD	val3
		val1 = val2
		val2 = val3
		val3 = val1 + val2
	ENDM

.code
	main PROC


		invoke ExitProcess,0
	main ENDP
END main

40.REPEAT伪指令

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	WEEKS_PER_YEAR = 52

	WeatherReading STRUCT
		location	BYTE	50 DUP(0)
		REPEAT		WEEKS_PER_YEAR
			local		rainfall,humidity
			rainfall	DWORD	?
			humidity	DWORD	?
		ENDM
	WeatherReading ENDS

.code
	main PROC


		invoke ExitProcess,0
	main ENDP
END main

41.FOR伪指令的使用

include irvine32.inc
include macros.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

COURSE	STRUCT
	Number	BYTE	9 DUP(10)
	Credits	BYTE	100
COURSE	ENDS

;semester 含有一个课程数组
SEMESTER STRUCT
	Courses		COURSE	6 DUP(<>)
	NumCourses	WORD	0
SEMESTER ENDS

.data
	
	for semName ,<Fall2013,Spring2014,Summer2014,Fall2014>
		semName SEMESTER <>
	endm

.code
	main PROC

		
		invoke ExitProcess,0
	main ENDP
END main

42.List

;创建一个链表
include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD

;定义生成链表所需要的宏与结构体
ListNode	STRUCT
	NodeData	DWORD	?
	NextPtr		DWORD	?
ListNode	ENDS

TotalNodeCount = 15
NULL = 0
Counter = 0

.data

	LinkedList	LABEL	PTR	ListNode
	repeat	TotalNodeCount
		Counter = Counter + 1
		ListNode <Counter,($ + Counter * sizeof ListNode)>
	ENDM

.code
	main PROC

		mov		esi,offset LinkedList
	NextNode:
		;显示NodeData域的值
		;检查是否为尾节点
		mov		eax,(ListNode PTR [esi]).NextPtr
		cmp		eax,NULL
		je		quit

		;显示节点数据
		mov		eax,(ListNode PTR[esi]).NodeData
		call	WriteDec
		call	Crlf

		;获得下一个节点的指针
		mov		esi,(ListNode PTR[esi]).NextPtr
		jmp		NextNode
	quit:
		exit

		invoke	ExitProcess,0
	main ENDP
END main

习题

10.8.01

; Chapter 10 Exercise 1              (Ex10_ReadKey.asm)

Comment !
Description: Create a macro that waits for a keystroke and returns
the key that was pressed. The macro should include parameters for the
ASCII code and keyboard scan code. 
!
INCLUDE Irvine32.inc

mReadkey MACRO ascii, scan
	call ReadChar
	mov scan,ah
	mov ascii,al
ENDM

.data
ascii BYTE ?
scan  BYTE ?
str1  BYTE "ASCII code: ",0
str2  BYTE "Scan code:  ",0

.code
main PROC

; Wait for a key; when the macro returns, the two arguments
; contain the ASCII code and scan code of the key.

	mReadkey ascii, scan

; Display the values.
	mov	edx,OFFSET str1
	call WriteString
	movzx eax,ascii
	call WriteHex
	call Crlf

	mov	edx,OFFSET str2
	call WriteString
	movzx eax,scan
	call WriteHex
	call Crlf

	exit
main ENDP
END main

10.8.02

; Chapter 10 Exercise 2			(Ex02_WriteString.asm)

Comment !
Description: Create a macro that writes a null-terminated 
string to the console with a given text color.
!
INCLUDE Irvine32.inc

mWritestringAttr MACRO aString,color
	push eax
	push edx
	mov  eax,color
	call SetTextColor
	mov  edx,OFFSET aString
	call WriteString
	pop  edx
	pop  eax
ENDM

.data
myString BYTE "This string is in color",0

.code
main PROC

	; Blue text on a white background:
	mWritestringAttr myString, (white SHL 4) + blue
	call Crlf

	; White text on a blue background:
	mWritestringAttr myString, (blue SHL 4) + white
	call Crlf

	mov	eax,lightGray		; normal screen color
	call SetTextColor

	exit
main ENDP
END main

10.8.03

; Chapter 10 Exercise 3          (Ex03_Move32.asm)

Comment !
Description: Write a macro named mMove32 that receives two 32-bit
memory operands. The macro should move the source operand to the
destination operand.
!
INCLUDE Irvine32.inc

mMove32 MACRO destination,source
	push eax
	mov	eax,source
	mov	destination,eax
	pop	eax
ENDM

.data
var1 DWORD 12345678h
var2 DWORD 0

.code
main PROC

	mMove32 var2,var1
	
	mov  eax,var2	
	call WriteHex		; display var2
	call Crlf

	exit
main ENDP
END main

10.8.04

; Chapter 10 Exercise 4              (Ex04_Mult32.asm)

Comment !
Description: Create a macro named mMult32 that multiplies two
unsigned 32-bit memory operands and produces a 32-bit product.
!
INCLUDE Irvine32.inc

mMult32 MACRO op1,op2,product
	push eax
	push edx
	mov  eax,op1			;; EAX = destination
	mul  op2				;; EDX:EAX = product
	mov  product,eax		;; discard high 32 bits
	pop  edx
	pop  eax
ENDM

.data
val1 DWORD 1000h
val2 DWORD 200h
prod DWORD ?

.code
main PROC

	mMult32 val1,val2,prod

; Display results
	mov	eax,prod
	call WriteHex
	call Crlf

	exit
main ENDP
END main

10.8.05

; Chapter 10 Exercise 5                     (Ex05_ReadInt.asm)

Comment !
Description: Create a macro named mReadInt that reads a 16- or 32-bit
signed integer from standard input and returns the value in an argument.
Use conditional operators to allow the macro to adapt to the size of
the desired result. Write a program that calls the macro, passing it
operands of various sizes. As an extra feature, we display an error
message during assembly if the operand has an unexpected size.
!

INCLUDE Irvine32.inc

mReadInt MACRO intVal
	push eax
	call ReadInt				;; read 32-bit integer
	IF (TYPE intVal) EQ 2		;; store in 16-bit operand?
	  mov intVal,ax
	ELSEIF (TYPE intVal) EQ 4	;; store in 32-bit operand?
	  mov intVal,eax
	ELSE
	  %OUT ************************************************************************
	  ; (The actual value of intVal is substituted into the following message)
	  %OUT Error: Argument intVal passed to mReadInt must be either 16 or 32 bits.
	  %OUT ************************************************************************
	ENDIF
	pop eax
ENDM

.data
wVal SWORD ?
dVal SDWORD ?
str1 BYTE "Input a 16-bit signed integer: ",0
str2 BYTE "Input a 32-bit signed integer: ",0

.code
main PROC

	mReadInt EAX

; Input and display a 16-bit signed integer

	mov	edx,OFFSET str1
	call WriteString
	mReadInt wVal
	movsx eax,wVal
	call WriteInt
	call Crlf

; Input and display a 32-bit signed integer

	mov	edx,OFFSET str2
	call WriteString
	mReadInt dVal
	mov  eax,dVal
	call WriteInt
	call Crlf

	exit
main ENDP
END main

10.8.06

; Chapter 10 Exercise 6                   (Ex06_WriteInt.asm)

Comment !
Description: Create a macro named mWriteInt that writes a signed integer
to standard output by calling the WriteInt library procedure. The argument
passed to the macro can be a byte, word, or doubleword. Use conditional
operators in the macro so it adapts to the size of the argument. Write a
program that demonstrates the macro, passing it arguments of different sizes.
As an extra feature, we display an error message during assembly if the
operand has an unexpected size.
!

include irvine32.inc

mWriteInt MACRO intVal
	push eax
	IF (TYPE intVal) EQ 1		;; 8-bit operand?
	  movsx eax,intVal
	  call  WriteInt
	ELSEIF (TYPE intVal) EQ 2	;; 16-bit operand?
	  movsx eax,intVal
	  call  WriteInt
	ELSEIF (TYPE intVal) EQ 4	;; 32-bit operand?
	  mov  eax,intVal
	  call WriteInt
	ELSE
	  %OUT ************************************************************************
	  ; (The actual value of intVal is substituted into the following message)
	  %OUT Error: Argument intVal passed to mWriteInt must be 8, 16, or 32 bits.
	  %OUT ************************************************************************
	ENDIF
	pop eax
ENDM

.data
bVal BYTE 26
wVal WORD 12345
dVal DWORD 2332424
qVal QWORD 1

.code
main PROC

	mWriteInt bVal
	call Crlf
	mWriteInt wVal
	call Crlf
	mWriteInt dVal
	call Crlf

	; Test the macro's error message
	;mWriteInt qVal

	exit
main ENDP
END main

10.8.07

; Professor's Lost Phone 			(Ex07_ProfessorsLostPhone.asm)

Comment !
Drunkard's walk program. The professor starts at 
coordinates 25,25 and wanders around the immediate area.
When the professor took the drunkard's walk around campus in Section 10.1.6, 
we discovered that he lost his cell phone somewhere along the path. 
When you simulate the drunken walk, your program must drop the phone 
wherever the professor is standing at some random time interval. 
Each time you run the program, the cell phone will be lost at 
a different time interval (and location).
!

INCLUDE Irvine32.inc
WalkMax = 50
StartX = 25
StartY = 25

DrunkardWalk STRUCT
	path COORD WalkMax DUP(<0,0>)
	pathsUsed WORD 0
DrunkardWalk ENDS

DisplayPosition PROTO currX:WORD, currY:WORD

.data
aWalk DrunkardWalk <>

.code
main PROC
	call  Randomize

	mov	  esi,OFFSET aWalk
	call  TakeDrunkenWalk
	exit
main ENDP

;-------------------------------------------------------
TakeDrunkenWalk PROC
	LOCAL currX:WORD, currY:WORD
;
; Take a walk in random directions (north, south, east,
; west).
; Receives: ESI points to a DrunkardWalk structure
; Returns:  the structure is initialized with random values
;-------------------------------------------------------
	pushad
;---------------------  Prog Challenge #7 ------------------------------
; Choose a random time interval. Choose a number between 1 and WalkMax.
;-----------------------------------------------------------------------
.data
CellPhoneDropTime DWORD ?
DropPhoneMsg BYTE "The professor has dropped a cel phone!",0dh,0ah,0
.code
	mov  eax,WalkMax
	call RandomRange
	inc  eax					; must start at 1
	mov  CellPhoneDropTime,eax
; ----------------------------------------------------------------------

; Use the OFFSET operator to obtain the address of
; path, the array of COORD objects, and copy it to EDI.
	mov	edi,esi
	add	edi,OFFSET DrunkardWalk.path
	mov	ecx,WalkMax			; loop counter
	mov	currX,StartX		; current X-location
	mov	currY,StartY		; current Y-location

Again:
	; Insert current location in array.
	mov	ax,currX
	mov	(COORD PTR [edi]).X,ax
	mov	ax,currY
	mov	(COORD PTR [edi]).Y,ax

	INVOKE DisplayPosition, currX, currY

; --------------------- Prog Challenge #7 ------------------------
; Tell the user if the prof dropped the cel phone during 
; this time interval, i.e. when ECX = WalkMax - CellPhoneDropTime
; ----------------------------------------------------------------
	mov   eax,WalkMax
	sub   eax,CellPhoneDropTime
	cmp   eax,ecx
	jne   L2
	mov	  edx,OFFSET DropPhoneMsg
	call  WriteString
;------------------------------------------------------------------
L2:
	mov	  eax,4			; choose a direction (0-3)
	call  RandomRange

	.IF eax == 0		; North
	  dec currY
	.ELSEIF eax == 1	; South
	  inc currY
	.ELSEIF eax == 2	; West
	  dec currX
	.ELSE			; East (EAX = 3)
	  inc currX
	.ENDIF

	add	edi,TYPE COORD		; point to next COORD
	loop	Again

Finish:
	mov (DrunkardWalk PTR [esi]).pathsUsed, WalkMax
	popad
	ret
TakeDrunkenWalk ENDP

;-------------------------------------------------------
DisplayPosition PROC currX:WORD, currY:WORD
; Display the current X and Y positions.
;-------------------------------------------------------
.data
commaStr BYTE ",",0
.code
	pushad
	movzx eax,currX			; current X position
	call	 WriteDec
	mov	 edx,OFFSET commaStr	; "," string
	call	 WriteString
	movzx eax,currY			; current Y position
	call	 WriteDec
	call	 Crlf
	popad
	ret
DisplayPosition ENDP
END main

10.8.08

; Chapter 10 Exercise 8            (Ex08_DrunkardProbabilities.asm)

Comment !
When testing the Drunkard Walk program, you may have noticed 
that the professor doesn抰 seem to wander very far from the starting 
point. This is no doubt caused by an equal probability of the professor 
moving in any direction. Modify the program so there is a 50% 
probability the professor will continue to walk in the same 
direction as he or she did when taking the previous step. There 
should be a 10% probability that he or she will reverse direction 
and a 20% probability that he or she will turn either right or 
left. Assign a default starting direction before the loop begins
; revised 4/14/2011
!
INCLUDE Irvine32.inc

WalkMax = 100
StartX = 25
StartY = 25

North = 1	
South = 3
West = 2
East = 0

DrunkardWalk STRUCT
	path COORD WalkMax DUP(<0,0>)
	pathsUsed WORD 0
DrunkardWalk ENDS

GetDirection PROTO
DisplayPosition PROTO currX:WORD, currY:WORD

.data
aWalk DrunkardWalk <>
currDirection DWORD ?

.code
main PROC
	call Randomize
	mov esi,offset aWalk
	call TakeDrunkenWalk
	exit
main ENDP

;-------------------------------------------------------
TakeDrunkenWalk PROC
LOCAL currX:SWORD, currY:SWORD
;
; Take a walk in random directions (north, south, east,
; west).
; Receives: ESI points to a DrunkardWalk structure
; Returns:  the structure is initialized with random values
;-------------------------------------------------------
	pushad

; Point EDI to the array of COORD objects.
	mov edi,esi
	add edi,OFFSET DrunkardWalk.path
	mov ecx,WalkMax			; loop counter
	mov currX,StartX			; current X-location
	mov currY,StartY			; current Y-location
	mov currDirection,North		; starting direction

Again:
	; Insert current location in array.
	mov ax,currX
	mov (COORD PTR [edi]).X,ax
	mov ax,currY
	mov (COORD PTR [edi]).Y,ax

	INVOKE DisplayPosition, currX, currY

	call GetDirection			; returns EAX

	;Now that the direction has been chosen, adjust
	;the professor's location in the grid.
	.IF eax == North			; North
	  inc currY
	.ELSEIF eax == South		; South
	  dec currY
	.ELSEIF eax == West			; West
	  dec currX
	.ELSE					; East
	  inc currX
	.ENDIF
		
next:
	mov  currDirection,eax	; save current direction
	add  edi,TYPE COORD		; point to next COORD
	loop Again

finish:
	mov  ax,WalkMax			; count the steps taken
	sub  ax,cx
	mov  (DrunkardWalk PTR [esi]).pathsUsed, ax
	popad
	ret
TakeDrunkenWalk ENDP

;----------------------------------------------------------
GetDirection PROC USES edx
; Returns: EAX = new direction
;----------------------------------------------------------
LOCAL modDivisor:DWORD

	mov  modDivisor,4
	mov  eax,10
	call RandomRange		

	.IF eax < 5				; keep same direction (50%)
	  mov  eax,currDirection

	.ELSEIF eax < 6			; reverse direction (10%)
	  mov  eax,currDirection		; (D+2) mod 4
	  add  eax,2

	.ELSEIF eax < 8			; turn right (20%)
	  mov  eax,currDirection		; (D+1) mod 4
	  add  eax,1

	.ELSE					; turn left (20%)
	  mov  eax,currDirection		; (D+4-1) mod 4
	  add  eax,4
	  sub  eax,1
	.ENDIF

	; perform MOD 4 operation on eax
	mov  edx,0				; clear upper dividend
	div  modDivisor
	mov  eax,edx				; remainder = new direction

	ret						; return EAX
GetDirection ENDP	

;-------------------------------------------------------
DisplayPosition PROC currX:WORD, currY:WORD
;
; Display the current X and Y positions.
; Optional: used for debugging.
;-------------------------------------------------------
.data
positionMsg BYTE "At ",0
commaStr BYTE ",",0
directionMsg BYTE ", direction = ",0

.code
	pushad
	mov   edx,OFFSET positionMsg	; "At "
	call  WriteString
	movzx eax,currX				; current X position
	call  WriteDec
	mov   edx,OFFSET commaStr		; "," string
	call  WriteString
	movzx eax,currY				; current Y position
	call  WriteDec
	mov   edx,OFFSET directionMsg		; "direction = "
	call  WriteString
	mov	 eax,currDirection
	call	 WriteDec
	call  Crlf
	popad
	ret
DisplayPosition ENDP
END main

10.8.09

; Chapter 10 Exercise 9	  		(Ex09_ShiftingDoublewords.asm)

Comment !
Shifting Multiple Doublewords

Description: Create a macro that shifts an array of 32-bit integers
in either direction, a variable number of bits, using using the SHRD 
instruction. Write a test program that tests your macro by shifting 
the same array in both directions and and displaying the resulting 
values. We assume that the array is in little Endian order.
!

INCLUDE Irvine32.inc

mShiftDoublewords MACRO arrayName, direction, numberOfBits
; Parameters:
;	arrayName         Name of the array
;	direction         Right (R) or Left (L)
;	numberOfBits	   Number of bit positions to shift

LOCAL L1
	mov	bl,numberOfBits		; number of bits to shift
	mov  ecx,(LENGTHOF arrayName) - 1
	mov  esi,OFFSET arrayName

IFIDNI <direction>,<'L'>			; Left shift?

L1:	push	ecx					; save loop counter
	mov  eax,[esi + TYPE DWORD]	; get next lowest doubleword
	mov  cl,bl				; shift count
	shld [esi],eax,cl			; shift EAX into low bits of [esi]	
	add  esi,TYPE DWORD			; point to next doubleword pair
	pop  ecx					; restore loop counter
	loop L1

	shl DWORD PTR [esi],numberOfBits		; shift last doubleword 

ELSE		; Must be a shift to the right

	; point to the last array element
	add	esi,(SIZEOF arrayName) - (TYPE DWORD)

L1:	push	ecx					; save loop counter
	mov  eax,[esi - TYPE DWORD]	; get next highest doubleword
	mov  cl,bl				; shift count
     shrd [esi],eax,cl			; shift EAX into high bits of [esi]
	sub  esi,TYPE DWORD			; point to previous doubleword pair
	pop  ecx					; restore loop counter
	loop L1

	shr DWORD PTR [esi],numberOfBits		; shift last doubleword

ENDIF  
  
ENDM
;----------------------------------------------------------------

.data
array DWORD 008B2165h,8C943A29h,6DFA4B86h,91F76C04h,82AF9857h

.code
main PROC
	call	Display					; original values

	mShiftDoublewords array,'L',4		; shift left 4 bits
	call	Display

; Shift it back to its starting value
	mShiftDoublewords array,'R',4
	call	Display					; same as original values
	
	mShiftDoublewords array,'L',7		; shift left 7 bits
	call	Display
	
	mShiftDoublewords array,'R',7
	call	Display					; same as original values

	
	exit
main ENDP

; Display the array

Display PROC
	mov  esi,OFFSET array
	mov  ecx,LENGTHOF array
	mov  ebx,TYPE array
	call DumpMem
	ret
Display ENDP


END main

10.8.10

; Chapter 10 Exercise 9		(Ex10_ThreeOperandInstructions.asm)

Comment !
Three-Operand Instructions
Some computer instruction sets permit arithmetic instructions with three 
operands. Such operations sometimes appear in simple virtual assemblers 
used to introduce students to the concept of assembly language or using 
intermediate language in compilers. In the following macros, EAX is reserved 
for macro operations and is not preserved. Other registers modified by the 
macros are preserved. All parameters are signed memory doublewords. 
Operations:

a. add3 destination, source1, source2
b. sub3 destination, source1, source2	; destination = source1 - source2
c. mul3 destination, source1, source2
d. div3 destination, source1, source2	; destination = source1 / source2
!

INCLUDE Irvine32.inc

add3 MACRO dest, source1, source2

	mov	eax,source1
	add	eax,source2
	mov	dest,eax
ENDM

sub3 MACRO dest, source1, source2

	mov	eax,source1
	sub	eax,source2
	mov	dest,eax
ENDM


mul3 MACRO dest, source1, source2
	; signed multiplication
	mov	eax,source1
	imul	source2
	mov	dest,eax
ENDM


div3 MACRO dest, source1, source2
	; signed division
	mov	eax,source1
	cdq
	idiv	source2
	mov	dest,eax
ENDM

.data
w SDWORD 1
x SDWORD 2
y SDWORD 3
z SDWORD -4
temp SDWORD ?
temp2 SDWORD ?

.code
main PROC
	; y = Z / x
	div3 y, z, x
	
	; x = (w + y) * z
	add3 temp, w, y
	mul3 x, temp, z

	; y = (z / x) + (y * x)
	mul3 temp, y, x
	div3 y, z, x
	add3	y, y, temp

	; w = (w + x + y) * (z - x)
	add3 temp, x, y
	add3 temp, w, temp
	sub3 temp2, z, x
	mul3 w, temp, temp2
	
	exit
main ENDP

END main
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值