(通过DOSBOX运行程序集x86)
我使用程序加载图像(bmp文件),第一个是加载文件(打开文件):
proc OpenFile
mov ah, 3Dh
xor al, al
mov dx, offset filename
int 21h
jc openerror1
mov [filehandle], ax
ret
openerror1:
mov dx, offset ErrorMsg
mov ah, 9h
int 21h
ret
endp
我希望将filename用作文件名的全局变量 - 其路径的字符串,因此在运行所有过程之前我唯一需要做的就是将正确的路径移动到文件名变量。
filename db ?
img1 db 'img1.bmp',0
img2 db 'img2.bmp',0
我认为它是某种字符串传输,我发现MOVS命令可能会有所帮助,但我没有理解它的工作方式。
答案 0 :(得分:5)
一个简短的例子MOVS
如何工作("字符串"指令系列中的其他人类似)。
首先你需要在内存中占用空间,所以在你的情况下必须扩展filename
。
MAX_FILE_NAME_LENGTH EQU 128
filename db MAX_FILE_NAME_LENGTH dup (?) ; reserving enough space for "string"
img1 db 'img1.bmp',0
img1length equ $-img1
img2 db 'img2.bmp',0
img2length equ $-img2
现在复制img2
" string" into filename
... img2
是内存中的地址,其中以下img2length
字节由上面的db
定义(包括零分隔符)。目标地址是filename
符号。 MOVS
将ds:si
的数据从si
(&{34;来源")复制到es:di
(di
为"目的地&#34 ;)
...
; make sure the DS and ES are set up correctly, if you use data segment, then
; (this can be done just once, if you don't change ds/es in your code any more)
mov ax, @data
mov ds, ax
mov es, ax
cld ; DF=0, if you don't plan to use DF=1 elsewhere
; DF=0 means, that the "string" instructions increment SI/DI
; DF=1 would make them run backwards, decrementing addresses
; (that's handy when implementing "memmove" with overlapping areas)
...
...
; now prepare registers (except ds+es) for `rep movsb` variant
mov cx, img2length ; how many bytes to copy (numeric value)
lea si, [img2] ; offset img2 into SI
lea di, [filename] ; offset filename into DI
rep movsb ; copy "img2length" bytes from ds:si to es:di
; check memory in debugger, the reserved area at "filename" should
; now contain the copied string, including the zero terminator
; WARNING, if you forget about reserved space limitations, and define
; img2 string longer than MAX_FILE_NAME_LENGTH, the code above will
; merrily overwrite more memory than expected, destroying values in memory
; beyond the filename buffer
...
另一个带有指针示例的变体:
通常的做法是将值传递给函数作为参数,在这种情况下,您可以要求调用者在ds:dx
调用之前预先设置OpenFile
,然后您只需省略dx
在程序中设置代码,你就完成了,例如:
; arguments: ds:dx = pointer to ASCIIZ file name
; returns (and modifies): ax = file handle
; in case of file error "..." happens
proc OpenFile
mov ax, 3D00h ; ah = 3D "open file", al = 0 "read-only"
int 21h
jc openerror1
ret
openerror1:
... ; probably terminate app any way in case of error
然后在每个调用之前设置ds:dx,并在存储文件句柄之后:
...
; let's pretend the DS was already set before
mov dx, offset img1
call OpenFile
mov [img1FileHandle],ax
...
数据设置如下:
img1 db 'img1.bmp',0
img1FileHandle dw 2 ; DW, because handle is 16 bit "wide" (AX = 16 bits)
; 2 == STDERR, until the code will run OpenFile and store real handle
也可以将这些东西放入内存中的全局变量中,然后在OpenFile
内的内存中读取它们,但是如果你试着写它,你会看到它相当繁琐的,在寄存器中传递参数更简单......直到你的代码变得复杂到足以忘记什么程序需要什么在哪个寄存器中,突然间它变得有点乱。
从那里开始遵循一些官方调用约定更好,比如cdecl和类似的,但16b / 32b模式的大多数调用约定确实使用堆栈来传递参数,这也是手工编写的有点乏味,并且比通过寄存器传递值更糟糕。对于小型纯asm应用程序,可以随意优化每个过程参数/结果,只需使用明确的描述对每个过程进行注释即可使用哪些寄存器。