nasm : 堆栈平衡的函数调用

更新 disp_char_repeat, 使写入的字符和背景不同

效果图:

; /// 重复显示字符
disp_char_repeat:mov bp, sppush bp;	(9)、功能 09H
;	功能描述:在当前光标处按指定属性显示字符
;	入口参数:AH=09H
;	AL=字符
;	BH=显示页码
;	BL=属性(文本模式)或颜色(图形模式)
;	CX=重复输出字符的次数
;	出口参数:无;	push PAGE_0 ; ///< STACK_PARAM_4
;	push COLOR_BG_READ_FG_WHITE ; ///< STACK_PARAM_3
;	push CHAR_TO_DISP ; ///< STACK_PARAM_2
;	push CHAR_COUNT ; ///< STACK_PARAM_1mov ax, STACK_PARAM_4mov bh, al ; no.0 page mov ax, STACK_PARAM_3mov bl, al ; char color, 红底白字mov ax, STACK_PARAM_1mov cx, ax ; char countmov ax, STACK_PARAM_2 ; char contentmov ah, 09h ; 在当前光标处按指定属性显示字符int 10hpop bpmov sp, bpret

做实验时,发现有时执行的效果不科学。

开始直接烧到U盘0扇区,很麻烦。一直找不到错在哪.

后来用bochsdbg单步,很快发现了问题. 

* 参数传递时, [bp + 2]为栈中参数的开始

* 函数调用完,需要调用者进行堆栈平衡

bochs挺好用的, 调试利器. 写的很人性化,只要用过别的调试器,很快上手,命令不多,10几个. 命令字的助记符也很好记.

显示效果和裸机上相同.

; @file boot_disp_string_by_call.asm
; @brief 启动后显示一些信息
; @note 编译命令行 
; cd D:\prj\nasm_prj\boot\boot_dispmsg
; d:
; C:\nasm\nasm.exe -f bin -d UBOOT -l boot_disp_string_by_call.list boot_disp_string_by_call.asm -o boot_2015_0919_0833
; @note 将boot_2015_0919_0833写U盘0扇区
; @note 效果 : 显示一句话; /// 栈上的参数
; /// 进入函数后,栈上保存的参数为: 
; /// [sp + 0]返回地址
; /// [sp + 2]参数1(左1)
; /// [sp + 4]参数2(左2)
; /// [sp + 6]参数3(左3)
; /// | STACK 0xffce [0x7c13]
; /// | STACK 0xffd0 [0x0000]
; /// | STACK 0xffd2 [0x0000]
; /// | STACK 0xffd4 [0x0000]
; /// 此时 sp 指向函数返回地址
; /// 函数入口保存现场
; /// mov bp, sp
; /// push bp
; /// 此时 bp 指向函数返回地址
; /// 所以在函数中使用入参时, 
; /// [bp + 0] 是函数返回地址
; /// [bp + 2]参数1(左1)
; /// [bp + 4]参数2(左2)
; /// [bp + 8]参数3(左3) ...
%define STACK_PARAM_1 [bp + 2]
%define STACK_PARAM_2 [bp + 4] ; ///<  对于16位汇编, offset是2,而不是4
%define STACK_PARAM_3 [bp + 6]
%define STACK_PARAM_4 [bp + 8]
%define STACK_PARAM_5 [bp + 10]
%define STACK_PARAM_6 [bp + 12]
%define STACK_PARAM_7 [bp + 14]
%define STACK_PARAM_8 [bp + 16]
%define STACK_PARAM_9 [bp + 18]%define PAGE_0 0 ; ///< 显存页0
%define COLOR_BG_READ_FG_WHITE 47h ; ///< 红底白字
%define CHAR_TO_DISP '=' ; ///< 要显示的字符内容
%define CHAR_COUNT 40 ; ///< 字符个数, 通过实验, 果真能看到一行是80个字符%define CURSOR_X_0 0
%define CURSOR_Y_0 0%define CURSOR_X_1 1
%define CURSOR_Y_1 1%define CURSOR_X_2 2
%define CURSOR_Y_2 2%define CURSOR_X_3 3
%define CURSOR_Y_3 3%define CURSOR_X_4 4
%define CURSOR_Y_4 4%define CURSOR_X_5 5
%define CURSOR_Y_5 5org 0hmov ax, cxmov ds, axmov es, axcall clear_screen ; ///< 清屏nop; /// 将入参从右往左入栈; /// 在调试模式下,单步vs2010中编写的程序反汇编,是这样的; /// 设置光标到(0,0)push CURSOR_Y_0 ; ///< STACK_PARAM_3push CURSOR_X_0 ; ///< STACK_PARAM_2push PAGE_0 ; ///< STACK_PARAM_1call set_cursor ; ///< set_cursor(PAGE_0, CURSOR_X_1, CURSOR_Y_2)pop ax;///< 堆栈平衡pop axpop axcall print_line40; /// 设置光标到(1,1)push CURSOR_Y_1push CURSOR_X_1push PAGE_0call set_cursor ; ///< set_cursor(PAGE_0, CURSOR_X_1, CURSOR_Y_2)pop ax;///< 堆栈平衡pop axpop axcall print_line40; /// 设置光标到(2,2)push CURSOR_Y_2push CURSOR_X_2push PAGE_0call set_cursor ; ///< set_cursor(PAGE_0, CURSOR_X_1, CURSOR_Y_2)pop ax;///< 堆栈平衡pop axpop axcall print_line40; /// 设置光标到(3,3)push CURSOR_Y_3push CURSOR_X_3push PAGE_0call set_cursor ; ///< set_cursor(PAGE_0, CURSOR_X_1, CURSOR_Y_2)pop ax;///< 堆栈平衡pop axpop axcall print_line40; /// >>push CURSOR_Y_4push CURSOR_X_4push PAGE_0call set_cursor ; ///< set_cursor(PAGE_0, CURSOR_X_1, CURSOR_Y_2)pop ax;///< 堆栈平衡pop axpop axcall print_line40; /// >>jmp $ ; 死循环print_line40:mov bp, sppush bppush PAGE_0 ; ///< STACK_PARAM_1push COLOR_BG_READ_FG_WHITE ; ///< STACK_PARAM_2push CHAR_TO_DISP ; ///< STACK_PARAM_3push CHAR_COUNT ; ///< STACK_PARAM_4call disp_char_repeat ; 调用函数-显示字符串pop ax;///< 堆栈平衡pop axpop axpop axpop bpmov sp, bpret; /// 清屏
clear_screen:mov bp, sppush bp;	(7)、功能 06H 和 07H
;	功能描述:初始化屏幕或滚屏
;	入口参数:AH=06H——向上滚屏,07H——向下滚屏
;	AL=滚动行数(0——清窗口)
;	BH=空白区域的缺省属性
;	(CH、CL)=窗口的左上角位置(Y 坐标,X 坐标)
;	(DH、DL)=窗口的右下角位置(Y 坐标,X 坐标)
;	出口参数:无mov ah, 6hmov al, 0mov bh, 17h ; ///< 蓝底白字,光标闪烁mov cl, 0mov ch, 0mov dl, 79mov dh, 24int 10hpop bpmov sp, bpret; /// 设置光标位置	
set_cursor:mov bp, sppush bp;	push CURSOR_Y_0 ; ///< STACK_PARAM_3
;	push CURSOR_X_0 ; ///< STACK_PARAM_2
;	push PAGE_0 ; ///< STACK_PARAM_1mov ax, STACK_PARAM_1mov bh, al ; ///< display page numbermov ax, STACK_PARAM_2mov dl, al ; ///< cursor column, CURSOR_X_Nmov ax, STACK_PARAM_3mov dh, al ; ///< cursor row, CURSOR_Y_Nmov ah, 2mov al, 0int 10hpop bpmov sp, bpret; /// 重复显示字符
disp_char_repeat:mov bp, sppush bp;	push PAGE_0 ; ///< STACK_PARAM_4
;	push COLOR_BG_READ_FG_WHITE ; ///< STACK_PARAM_3
;	push CHAR_TO_DISP ; ///< STACK_PARAM_2
;	push CHAR_COUNT ; ///< STACK_PARAM_1mov ax, STACK_PARAM_4mov bh, al ; no.0 page ; /// 按照原有的属性重复写字符, 这的颜色没用了mov ax, STACK_PARAM_3mov bl, al ; char color, 红底白字mov ax, STACK_PARAM_1mov cx, ax ; char countmov ax, STACK_PARAM_2 ; char contentmov ah, 0ah ; bios 10# function = write char to UIint 10hpop bpmov sp, bpret; /// 做个标记,在拷贝到U盘的前后,都可以确认是否为自己最新的修改
str_build_time db 'build on 2015_0919_1003', 0
len_str_build_time equ ($-str_build_time) ; ///< 串长度times 510-($-$$) db 0 ; 用0填充剩余空间,使该段二进制代码正好为512字节
dw 0aa55h ; 结束标记


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部