我是大会新手,我需要帮助完成汇编语言Irvine32的作业。我想知道我哪里出了问题。我相信我的代码是80%正确的,但有一些东西我没有看到或认识到。这是节目的细节。
“编写包含单词数组的汇编语言程序。该程序将数组的最后一个元素加载到适当大小的寄存器中并打印出来。(不要硬编码最后一个元素的索引)。”
INCLUDE Irvine32.inc
.data
val1 word 1,2,3,4,5,6
val2 = ($-val1)/2
.code
main PROC
mov ax, 0
mov ax, val1[val2]
Call WriteDec
Call DumpRegs
exit
main ENDP
END main发布于 2016-05-06 19:10:04
首先,您的代码有一个bug:使用元素计数的val1[val2]索引,而不是以字节为单位的长度(除非MASM语法比我预期的还要神奇)。它读取数组末尾的一个元素,因为第一个元素位于val1[0]。
要找到结尾,您需要知道长度(显式长度,就像传递给memcpy(3)**),的缓冲区一样),或者搜索它的哨兵元素(隐式长度,就像传递给** strcpy(3)**).**的C字符串一样)。
对于我来说,拥有一个接受显式长度作为参数的函数似乎很好。显然,它比循环扫描哨兵元素的效率要高得多,而且所显示的数组不包括一个。(关于使用'$' (即36)作为前哨值的建议,请参见Jose的回答。-1或0可能是更明智的哨兵/终点站。)
显然,知道长度要好得多,因为不需要循环扫描整个数组。
只有当您编写val2 = 6或更糟的val2 dw 6时,我才称其为硬编码,而不是在组装时从数组中计算它。如果您想要编写一个可以使用非编译时间常数数组的函数,可以让它接受长度作为内存中的值,而不是嵌入到其load指令中的即时。
例如:
长度作为内存中的参数
.data
array word 1,2,3,4,5,6
array_len word ($-array)/2 ; some assemblers have syntactic sugar to calc this for you, like a SIZE operator or something.
.code
main PROC ; inputs: array and array_len in static storage
; output: ax = last element of array
; clobbers: si
; mov ax, 0 ; This is useless, the next mov overwrites it.
mov si, [array_len] ; do we need to save/restore si with push/pop in this ABI?
add si,si ; multiply by 2: length in words -> length in bytes
mov ax, [array + si - 2] ; note that the -2 folds into array at assemble time, so it's just a disp16 + index addressing mode
Call WriteDec
Call DumpRegs
exit
main ENDP
END main您还可以编写一个函数来获取堆栈或寄存器中的指针和长度args,并让main传递这些args。
您可以通过接受一个以字节为单位的长度,或者接受一个开始指针和一个经过一个结束指针(比如使用add和.end()迭代器的C++ STL范围函数)来保存C++(或shl)。如果有结束指针,则根本不需要开始指针,除非返回一个错误,如果它们相等(size = 0)。
或者,如果您没有使用过时的16位代码,则可以在寻址模式中使用缩放索引,如[array + esi * 2]。你包括Irvine32.inc..。
发布于 2016-05-06 15:22:49
我认为您访问最后一个元素的解决方案是最有效的(($-val1)/2),但是@ so 485是正确的,您的老师可能认为您在作弊,因此,在其他解决方案中,您可以使用循环和指针SI达到最后一个元素:
INCLUDE Irvine32.inc
.data
val1 word 1,2,3,4,5,6
val2 = ($-val1)/2
.code
main PROC
; mov ax, 0
; mov ax, val1[val2]
mov cx, val2-1 ;COUNTER FOR LOOP (LENGTH-1).
mov si, offset val1 ;SI POINTS TO FIRST WORD IN ARRAY.
repeat:
add si, 2 ;POINT TO NEXT WORD IN ARRAY.
loop repeat ;CX--, IF CX > 0 REPEAT.
mov ax, [ si ] ;LAST WORD!
Call WriteDec
Call DumpRegs
exit
main ENDP
END main一种更短的方法是去掉循环,直接跳到最后一个元素,方法是使用SI指针(并且只稍微更改一下val2 ):
INCLUDE Irvine32.inc
.data
val1 dw 1,2,3,4,5,6
val2 = ($-val1)-2 ;NOW WE GET LENGTH - 2 BYTES.
.code
main PROC
; mov ax, 0
; mov ax, val1[val2]
mov si, offset val1 ;SI POINTS TO FIRST WORD IN ARRAY.
add si, val2 ;SI POINTS TO THE LAST WORD.
mov ax, [ si ] ;LAST WORD!
Call WriteDec
Call DumpRegs
exit
main ENDP
END main“是的”,你可以加入这两行:
mov si, offset val1 ;SI POINTS TO FIRST WORD IN ARRAY.
add si, val2 ;SI POINTS TO THE LAST WORD.我把他们分成一组,互相评论:
mov si, offset val1 + val2如果不能使用val2 = ($-val1)/2,,一个选项是为数组选择一些终止字符,例如,'$',并循环,直到找到为止:
INCLUDE Irvine32.inc
.data
val1 word 1,2,3,4,5,6,'$' ;ARRAY WITH TERMINATING CHARACTER.
;val2 = ($-val1)/2
.code
main PROC
;mov ax, 0
;mov ax, val1[val2]
mov si, offset val1 ;SI POINTS TO VAL1.
mov ax, '$' ;TERMINATING CHARACTER.
repeat:
cmp [ si ], ax
je dollar_found ;IF [ SI ] == '$'
add si, 2 ;NEXT WORD IN ARRAY.
jmp repeat
dollar_found:
sub si, 2 ;PREVIOUS WORD.
mov ax, [ si ] ;FINAL WORD!
Call WriteDec
Call DumpRegs
exit
main ENDP
END mainhttps://stackoverflow.com/questions/37073017
复制相似问题