您的位置:首页 > 其它

nasm : test eflags ZF

2015-09-24 12:42 316 查看
看看如何在bochs中查看标志寄存器,当标志寄存器置位和清零0,都是什么样子.



查看eflags的bochs命令 : info eflags

当(0 === ZF)时, ZF标志显示为zf

当(1 == ZF)时,ZF标志显示为ZF

其他标志位也是这样显示.

Next at t=156867343
(0) [0x000000007c39] 0000:7c39 (unk. ctxt): test byte ptr ds:0x7cf7, 0x00 ; f606f77c00
<bochs:13> info eflags
id vip vif ac vm rf nt IOPL=0 of df if tf sf zf AF PF cf
<bochs:14> s
Next at t=156867344
(0) [0x000000007c3e] 0000:7c3e (unk. ctxt): jz .+8 (0x00007c48)       ; 7408
<bochs:15> info eflags
id vip vif ac vm rf nt IOPL=0 of df if tf sf ZF af PF cf


显示物理地址内容的 bochs命令 xp /nuf addr, 示例如下

<bochs:4> xp /10bx 0x7cf7
[bochs]:
0x0000000000007cf7 <bogus+       0>:	0x00	0x7a	0x66	0x20	0x3d	0x3d	0x20	0x30
0x0000000000007cff <bogus+       8>:	0x00	0x7a


第2个参数的含义 10 = 10个显示单位; b = 显示单位为字节; x = 显示为16进制数.

0#扇区为U盘的MBR

实验扇区为1#扇区

nasm 实验代码如下:

; @file ex1-1.asm
; @brief 测试计算机内容是小端序还是大端序排放
; @note 编译命令行 
; cd D:\prj\nasm_prj\boot\boot_dispmsg\ex1-1
; d:
; C:\nasm\nasm.exe ex1-1.asm -o ex1-1.bin -l ex1-1.list
; @note 将ex1-1.bin写U盘1#扇区

; 颜色
%define COLOR_BG_RED_FG_WHITE 47h ; ///< 红底白字

; 函数内临时变量 - 以函数入口处的bp为基准
;Stack address size 2
; | STACK 0xffc6 [0x7ce7] ///< 函数内临时变量2
; | STACK 0xffc8 [0x0000] ///< 函数内临时变量1
; | STACK 0xffca [0xffcc] ///< 入口处的sp值
; | STACK 0xffcc [0x0000] ///< 入口处的bp值
; | STACK 0xffce [0x7c1e] ///< 函数返回地址, 入口处的bp值已经指到了这里

%define FUNCTION_TEMP_VAR_1 [bp - 6]
%define FUNCTION_TEMP_VAR_2 [bp - 8]
%define FUNCTION_TEMP_VAR_3 [bp - 12]
%define FUNCTION_TEMP_VAR_4 [bp - 14]
%define FUNCTION_TEMP_VAR_5 [bp - 16]
%define FUNCTION_TEMP_VAR_6 [bp - 18]
%define FUNCTION_TEMP_VAR_7 [bp - 20]
%define FUNCTION_TEMP_VAR_8 [bp - 22]
%define FUNCTION_TEMP_VAR_9 [bp - 24]

; 栈入参 - 以函数入口处的bp为基准
%define STACK_IN_PARAM_1 [bp + 2]
%define STACK_IN_PARAM_2 [bp + 4]
%define STACK_IN_PARAM_3 [bp + 6]
%define STACK_IN_PARAM_4 [bp + 8]
%define STACK_IN_PARAM_5 [bp + 10]
%define STACK_IN_PARAM_6 [bp + 12]
%define STACK_IN_PARAM_7 [bp + 14]
%define STACK_IN_PARAM_8 [bp + 16]
%define STACK_IN_PARAM_9 [bp + 18]

; 栈出参 - 以函数入口处的sp为基准, 函数出口处的sp必须和入口处相同
; 必须先执行 mov si, sp 因为没有 mov ax, [sp + 4] 这样的指令
; 用完 STACK_OUT_PARAM_X 之后, 执行 pop bp
%define STACK_OUT_PARAM_1 [si + 0]
%define STACK_OUT_PARAM_2 [si + 2]
%define STACK_OUT_PARAM_3 [si + 4]
%define STACK_OUT_PARAM_4 [si + 6]
%define STACK_OUT_PARAM_5 [si + 8]
%define STACK_OUT_PARAM_6 [si + 10]
%define STACK_OUT_PARAM_7 [si + 12]
%define STACK_OUT_PARAM_8 [si + 14]
%define STACK_OUT_PARAM_9 [si + 16]

%define BOOT_CODE_ENTRY_POINT 07c00h ; ///< boot 代码被BIOS加载后的位置

	; /// 这句没用的, 自己用WinHex烧到想要的扇区
	org BOOT_CODE_ENTRY_POINT ; 程序加载到0x7c00

	; /// 0#扇区是 在 UltraISO 中格式化U盘(非快速格式化)后,按照USB-HDD方式写入的MBR
	; /// 0#扇区的MBR已经做了初始处理, 我们在实验中,只需要关心具体的逻辑即可
	
	; /// 清屏
 	call clear_screen

	; --------------------------------------------------------------------------------
	; 在(0,1)显示信息
	; --------------------------------------------------------------------------------
	push 0
	push 1
	call set_cursor
	add sp, 4 ; ///< 堆栈平衡

	; /// 向内存地址中写内容,测试内存排放规则是大端序还是小端序
	; /// mov dword[byte_test], 1 ; ///< 只要向byte以上的空间写1,就可以看出内存排放规则
	mov word[byte_test], 1
	test byte[byte_test], 1
	jnz little_endian
	
big_endian:
	mov si, str_tip_big_endian 
	mov cx, len_str_tip_big_endian
	jmp show_endian

little_endian:
	mov si, str_tip_little_endian 
	mov cx, len_str_tip_little_endian

show_endian:
	call disp_message_by_default_attributes
	
	; --------------------------------------------------------------------------------
	; 在(1,1)显示信息
	; --------------------------------------------------------------------------------
	push 1
	push 1
	call set_cursor
	add sp, 4 ; ///< 堆栈平衡

	; /// 测试位是0还是1, 向看下当 jz时 info eflags 显示的 z位和 jnz时, 有何不同
	mov byte[byte_test], 0
	test byte[byte_test], 0
	jz z_flag

nz_flag:
	mov si, str_zf_is_not_0
	mov cx, len_str_zf_is_not_0
	jmp show_z_flag

z_flag:
	mov si, str_zf_is_0 
	mov cx, len_str_zf_is_0

show_z_flag:
	call disp_message_by_default_attributes
	
	; --------------------------------------------------------------------------------
	; 在(2,1)显示信息
	; --------------------------------------------------------------------------------
	push 2
	push 1
	call set_cursor
	add sp, 4 ; ///< 堆栈平衡

	; --------------------------------------------------------------------------------
	; /// @todo ls for debug
	; --------------------------------------------------------------------------------
 	jmp $ ; 死循环

; /// @fn disp_n_char_by_default_attributes(char* pcMsg, int iLenMsg)
;	si = pcMsg
;	cx = iLenMsg

 disp_message_by_default_attributes:
 	; /// 保护现场 bp和sp
 	push bp
 	push sp

	; /// 使bp回到函数入口处的值
 	mov ax, sp
 	add ax, 4
 	mov bp, ax

 	push cx ; ///< 重复执行次数
 	push bx
	
 	mov bx, 0
disp_message_by_default_attributes_begin:	
 	cmp cx, 0
 	jbe disp_message_by_default_attributes_end ; ///< 执行次数 <= 0, break
 	dec cx

 	mov ax, [si + bx] ; ///< 需要显示的字符
 	inc bx
 	push ax

	; /// disp_one_char_by_default_attributes 必须保护 bx,cx,si
 	call disp_one_char_by_default_attributes
 	add sp, 2 ; ///< 堆栈平衡
	
 	jmp disp_message_by_default_attributes_begin

 disp_message_by_default_attributes_end:

 	pop bx
 	pop cx

	; /// 恢复现场 bp和sp
 	pop sp
 	pop bp
 	ret

; /// @fn disp_one_char_by_default_attributes(char cDispContent)
disp_one_char_by_default_attributes:        
	; /// 保护现场 bp和sp
 	push bp
 	push sp

	; /// 使bp回到函数入口处的值
 	mov ax, sp
 	add ax, 4
 	mov bp, ax

 	push bx
 	push cx
 	push si

 	xor bh, bh
 	mov ax, STACK_IN_PARAM_1
 	mov ah, 0x0e
 	int 0x10                
	
 	pop si
 	pop cx
 	pop bx

	; /// 恢复现场 bp和sp
 	pop sp
 	pop bp
 	ret

; /// 清屏
clear_screen:
	; /// 保护现场 bp和sp
 	mov ax, bp
 	push ax
 
 	mov ax, sp
 	push ax

	; /// 使bp回到函数入口处的值
	mov ax, sp
	add ax, 4
	mov bp, ax
	
;	(7)、功能 06H 和 07H
;	功能描述:初始化屏幕或滚屏
;	入口参数:AH=06H——向上滚屏,07H——向下滚屏
;	AL=滚动行数(0——清窗口)
;	BH=空白区域的缺省属性
;	(CH、CL)=窗口的左上角位置(Y 坐标,X 坐标)
;	(DH、DL)=窗口的右下角位置(Y 坐标,X 坐标)
;	出口参数:无

 	mov ah, 6h
 	mov al, 0
 	mov bh, 17h ; ///< 蓝底白字,光标闪烁
 	mov cl, 0
 	mov ch, 0
 	mov dl, 79
 	mov dh, 24
 	int 10h

	; --------------------------------------------------------------------------------
	; /// @todo ls for debug
	; --------------------------------------------------------------------------------
; 	jmp $ ; 死循环
	
	; /// 恢复现场 bp和sp
 	pop sp
 	pop bp
 	ret
	
; /// 设置光标位置	
; /// set_cursor(x, y)
set_cursor:
	; /// 保护现场 bp和sp
 	push bp
 	push sp
	; /// 使bp回到函数入口处的值
 	mov ax, sp
 	add ax, 4
 	mov bp, ax
	
	;	push CURSOR_Y_0 ; ///< STACK_PARAM2
	;	push CURSOR_X_0 ; ///< STACK_PARAM1

 	mov ax, 0
 	mov bh, al ; ///< display page number
	
 	mov ax, STACK_IN_PARAM_1
 	mov dl, al ; ///< cursor column, CURSOR_X_N

 	mov ax, STACK_IN_PARAM_2
 	mov dh, al ; ///< cursor row, CURSOR_Y_N
	
 	mov ah, 2
 	mov al, 0
 	int 10h
	
	; /// 恢复现场 bp和sp
 	pop sp
 	pop bp

 	ret	

; /// 得到光标位置	
; /// get_cursor(x, y)
; 调用示例
; push 0 ///< y, STACK_OUT_PARAM_2
; push 0 ///< x, STACK_OUT_PARAM_1
; call get_cursor

get_cursor:
	; /// 保护现场 bp和sp
 	push bp
 	push sp

	; /// 使bp回到函数入口处的值
 	mov ax, sp
 	add ax, 4
 	mov bp, ax
	
	;	push CURSOR_Y_0 ; ///< STACK_PARAM2
	;	push CURSOR_X_0 ; ///< STACK_PARAM1

; (4)、功能 03H
; 功能描述:在文本坐标下,读取光标各种信息
; 入口参数:AH=03H
; BH=显示页码
; 出口参数:CH=光标的起始行
; CL=光标的终止行
; DH=行(Y 坐标)
; DL=列(X 坐标)

 	xor ax, ax
 	mov ah, 3h
 	mov bh, 0
 	int 10h
	
 	mov ax, dx
 	mov STACK_IN_PARAM_1, ax

	; /// 恢复现场 bp和sp
 	pop sp
 	pop bp
	
 	ret	

byte_test dw 0x1234, 0x5678
	
str_zf_is_0: db "zf == 0", 0
len_str_zf_is_0 equ ($ - str_zf_is_0)
	
str_zf_is_not_0: db "zf != 0", 0
len_str_zf_is_not_0 equ ($ - str_zf_is_not_0)

str_tip_little_endian: db "this computer is little-endian", 0
len_str_tip_little_endian equ ($ - str_tip_little_endian)

str_tip_big_endian: db "this computer is big-endian", 0
len_str_tip_big_endian equ ($ - str_tip_big_endian)

str_build_time: db "2015_0924_1120"

times 510-($-$$) db 0 ; 用0填充剩余空间,使该段二进制代码正好为512字节
dw 0aa55h ; 结束标记


; @file ex1-1.asm
; @brief 测试计算机内容是小端序还是大端序排放
; @note 编译命令行 
; cd D:\prj\nasm_prj\boot\boot_dispmsg\ex1-1
; d:
; C:\nasm\nasm.exe ex1-1.asm -o ex1-1.bin -l ex1-1.list
; @note 将ex1-1.bin写U盘1#扇区

; 颜色
%define COLOR_BG_RED_FG_WHITE 47h ; ///< 红底白字

; 函数内临时变量 - 以函数入口处的bp为基准
;Stack address size 2
; | STACK 0xffc6 [0x7ce7] ///< 函数内临时变量2
; | STACK 0xffc8 [0x0000] ///< 函数内临时变量1
; | STACK 0xffca [0xffcc] ///< 入口处的sp值
; | STACK 0xffcc [0x0000] ///< 入口处的bp值
; | STACK 0xffce [0x7c1e] ///< 函数返回地址, 入口处的bp值已经指到了这里

%define FUNCTION_TEMP_VAR_1 [bp - 6]
%define FUNCTION_TEMP_VAR_2 [bp - 8]
%define FUNCTION_TEMP_VAR_3 [bp - 12]
%define FUNCTION_TEMP_VAR_4 [bp - 14]
%define FUNCTION_TEMP_VAR_5 [bp - 16]
%define FUNCTION_TEMP_VAR_6 [bp - 18]
%define FUNCTION_TEMP_VAR_7 [bp - 20]
%define FUNCTION_TEMP_VAR_8 [bp - 22]
%define FUNCTION_TEMP_VAR_9 [bp - 24]

; 栈入参 - 以函数入口处的bp为基准
%define STACK_IN_PARAM_1 [bp + 2]
%define STACK_IN_PARAM_2 [bp + 4]
%define STACK_IN_PARAM_3 [bp + 6]
%define STACK_IN_PARAM_4 [bp + 8]
%define STACK_IN_PARAM_5 [bp + 10]
%define STACK_IN_PARAM_6 [bp + 12]
%define STACK_IN_PARAM_7 [bp + 14]
%define STACK_IN_PARAM_8 [bp + 16]
%define STACK_IN_PARAM_9 [bp + 18]

; 栈出参 - 以函数入口处的sp为基准, 函数出口处的sp必须和入口处相同
; 必须先执行 mov si, sp 因为没有 mov ax, [sp + 4] 这样的指令
; 用完 STACK_OUT_PARAM_X 之后, 执行 pop bp
%define STACK_OUT_PARAM_1 [si + 0]
%define STACK_OUT_PARAM_2 [si + 2]
%define STACK_OUT_PARAM_3 [si + 4]
%define STACK_OUT_PARAM_4 [si + 6]
%define STACK_OUT_PARAM_5 [si + 8]
%define STACK_OUT_PARAM_6 [si + 10]
%define STACK_OUT_PARAM_7 [si + 12]
%define STACK_OUT_PARAM_8 [si + 14]
%define STACK_OUT_PARAM_9 [si + 16]

%define BOOT_CODE_ENTRY_POINT 07c00h ; ///< boot 代码被BIOS加载后的位置

	; /// 这句没用的, 自己用WinHex烧到想要的扇区
	org BOOT_CODE_ENTRY_POINT ; 程序加载到0x7c00

	; /// 0#扇区是 在 UltraISO 中格式化U盘(非快速格式化)后,按照USB-HDD方式写入的MBR
	; /// 0#扇区的MBR已经做了初始处理, 我们在实验中,只需要关心具体的逻辑即可
	
	; /// 清屏
 	call clear_screen

	; --------------------------------------------------------------------------------
	; 在(0,1)显示信息
	; --------------------------------------------------------------------------------
	push 0
	push 1
	call set_cursor
	add sp, 4 ; ///< 堆栈平衡

	; /// 向内存地址中写内容,测试内存排放规则是大端序还是小端序
	mov dword[byte_test], 1
	test byte[byte_test], 1
	jnz little_endian
	
big_endian:
	mov si, str_tip_big_endian 
	mov cx, len_str_tip_big_endian
	jmp show_endian

little_endian:
	mov si, str_tip_little_endian 
	mov cx, len_str_tip_little_endian

show_endian:
	call disp_message_by_default_attributes
	
	; --------------------------------------------------------------------------------
	; 在(1,1)显示信息
	; --------------------------------------------------------------------------------
	push 1
	push 1
	call set_cursor
	add sp, 4 ; ///< 堆栈平衡

	; /// 测试位是0还是1, 向看下当 jz时 info eflags 显示的 z位和 jnz时, 有何不同
	mov byte[byte_test], 0
	test byte[byte_test], 0
	jz z_flag

nz_flag:
	mov si, str_zf_is_not_0
	mov cx, len_str_zf_is_not_0
	jmp show_z_flag

z_flag:
	mov si, str_zf_is_0 
	mov cx, len_str_zf_is_0

show_z_flag:
	call disp_message_by_default_attributes
	
	; --------------------------------------------------------------------------------
	; 在(2,1)显示信息
	; --------------------------------------------------------------------------------
	push 2
	push 1
	call set_cursor
	add sp, 4 ; ///< 堆栈平衡

	; --------------------------------------------------------------------------------
	; /// @todo ls for debug
	; --------------------------------------------------------------------------------
 	jmp $ ; 死循环

; /// @fn disp_n_char_by_default_attributes(char* pcMsg, int iLenMsg)
;	si = pcMsg
;	cx = iLenMsg

 disp_message_by_default_attributes:
 	; /// 保护现场 bp和sp
 	push bp
 	push sp

	; /// 使bp回到函数入口处的值
 	mov ax, sp
 	add ax, 4
 	mov bp, ax

 	push cx ; ///< 重复执行次数
 	push bx
	
 	mov bx, 0
disp_message_by_default_attributes_begin:	
 	cmp cx, 0
 	jbe disp_message_by_default_attributes_end ; ///< 执行次数 <= 0, break
 	dec cx

 	mov ax, [si + bx] ; ///< 需要显示的字符
 	inc bx
 	push ax

	; /// disp_one_char_by_default_attributes 必须保护 bx,cx,si
 	call disp_one_char_by_default_attributes
 	add sp, 2 ; ///< 堆栈平衡
	
 	jmp disp_message_by_default_attributes_begin

 disp_message_by_default_attributes_end:

 	pop bx
 	pop cx

	; /// 恢复现场 bp和sp
 	pop sp
 	pop bp
 	ret

; /// @fn disp_one_char_by_default_attributes(char cDispContent)
disp_one_char_by_default_attributes:        
	; /// 保护现场 bp和sp
 	push bp
 	push sp

	; /// 使bp回到函数入口处的值
 	mov ax, sp
 	add ax, 4
 	mov bp, ax

 	push bx
 	push cx
 	push si

 	xor bh, bh
 	mov ax, STACK_IN_PARAM_1
 	mov ah, 0x0e
 	int 0x10                
	
 	pop si
 	pop cx
 	pop bx

	; /// 恢复现场 bp和sp
 	pop sp
 	pop bp
 	ret

; /// 清屏
clear_screen:
	; /// 保护现场 bp和sp
 	mov ax, bp
 	push ax
 
 	mov ax, sp
 	push ax

	; /// 使bp回到函数入口处的值
	mov ax, sp
	add ax, 4
	mov bp, ax
	
;	(7)、功能 06H 和 07H
;	功能描述:初始化屏幕或滚屏
;	入口参数:AH=06H——向上滚屏,07H——向下滚屏
;	AL=滚动行数(0——清窗口)
;	BH=空白区域的缺省属性
;	(CH、CL)=窗口的左上角位置(Y 坐标,X 坐标)
;	(DH、DL)=窗口的右下角位置(Y 坐标,X 坐标)
;	出口参数:无

 	mov ah, 6h
 	mov al, 0
 	mov bh, 17h ; ///< 蓝底白字,光标闪烁
 	mov cl, 0
 	mov ch, 0
 	mov dl, 79
 	mov dh, 24
 	int 10h

	; --------------------------------------------------------------------------------
	; /// @todo ls for debug
	; --------------------------------------------------------------------------------
; 	jmp $ ; 死循环
	
	; /// 恢复现场 bp和sp
 	pop sp
 	pop bp
 	ret
	
; /// 设置光标位置	
; /// set_cursor(x, y)
set_cursor:
	; /// 保护现场 bp和sp
 	push bp
 	push sp
	; /// 使bp回到函数入口处的值
 	mov ax, sp
 	add ax, 4
 	mov bp, ax
	
	;	push CURSOR_Y_0 ; ///< STACK_PARAM2
	;	push CURSOR_X_0 ; ///< STACK_PARAM1

 	mov ax, 0
 	mov bh, al ; ///< display page number
	
 	mov ax, STACK_IN_PARAM_1
 	mov dl, al ; ///< cursor column, CURSOR_X_N

 	mov ax, STACK_IN_PARAM_2
 	mov dh, al ; ///< cursor row, CURSOR_Y_N
	
 	mov ah, 2
 	mov al, 0
 	int 10h
	
	; /// 恢复现场 bp和sp
 	pop sp
 	pop bp

 	ret	

; /// 得到光标位置	
; /// get_cursor(x, y)
; 调用示例
; push 0 ///< y, STACK_OUT_PARAM_2
; push 0 ///< x, STACK_OUT_PARAM_1
; call get_cursor

get_cursor:
	; /// 保护现场 bp和sp
 	push bp
 	push sp

	; /// 使bp回到函数入口处的值
 	mov ax, sp
 	add ax, 4
 	mov bp, ax
	
	;	push CURSOR_Y_0 ; ///< STACK_PARAM2
	;	push CURSOR_X_0 ; ///< STACK_PARAM1

; (4)、功能 03H
; 功能描述:在文本坐标下,读取光标各种信息
; 入口参数:AH=03H
; BH=显示页码
; 出口参数:CH=光标的起始行
; CL=光标的终止行
; DH=行(Y 坐标)
; DL=列(X 坐标)

 	xor ax, ax
 	mov ah, 3h
 	mov bh, 0
 	int 10h
	
 	mov ax, dx
 	mov STACK_IN_PARAM_1, ax

	; /// 恢复现场 bp和sp
 	pop sp
 	pop bp
	
 	ret	

byte_test dw 0x1234, 0x5678
	
str_zf_is_0: db "zf == 0", 0
len_str_zf_is_0 equ ($ - str_zf_is_0)
	
str_zf_is_not_0: db "zf != 0", 0
len_str_zf_is_not_0 equ ($ - str_zf_is_not_0)

str_tip_little_endian: db "this computer is little-endian", 0
len_str_tip_little_endian equ ($ - str_tip_little_endian)

str_tip_big_endian: db "this computer is big-endian", 0
len_str_tip_big_endian equ ($ - str_tip_big_endian)

str_build_time: db "2015_0924_1120"

times 510-($-$$) db 0 ; 用0填充剩余空间,使该段二进制代码正好为512字节
dw 0aa55h ; 结束标记
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: