簡體   English   中英

x86程序集:Irvine32-獲取數組的最后一個元素

[英]x86 assembly: Irvine32 - Get last element of an array

我是Assembly的新手,我需要有關匯編語言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

首先,您的代碼有一個錯誤: val1[val2]索引的元素數以單詞為單位,而不是以字節數為單位(除非MASM語法比我期望的更神奇)。 由於第一個元素位於val1[0] ,因此它從數組末尾讀取。


為了找到結尾,您要么需要知道長度(顯式長度,如傳遞給memcpy(3)的緩沖區),要么在其中搜索前哨元素(隱式長度,如傳遞給strcpy(3)的C字符串)。

對於我來說,擁有一個可以接受顯式長度作為參數的函數似乎不錯。 顯然,這比循環掃描前哨元素要有效得多,並且顯示的數組不包含一個。 (有關使用'$' (即36 )作為標記值的建議,請參見Jose的答案。 -10可能是更明智的標記/終止符。)

顯然知道長度要好得多,因為不需要循環掃描整個陣列。

如果您編寫val2 = 6或更糟的val2 dw 6 ,而不是在組裝時從數組中計算出來,我只會稱其為硬編碼。 如果要編寫一個可以與非編譯時間常數數組一起使用的函數,則可以讓它接受長度作為內存中的值,而不是將其嵌入到其裝入指令中的立即數。

例如

長度作為內存中的參數

.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

您還可以編寫一個函數,以在堆棧或寄存器中獲取指針和長度arg,並使這些arg main傳遞。

您可以通過接受以字節為單位的長度或起始指針和最后一個指針(如采用.begin().end()迭代器的C ++ STL范圍函數)來保存add (或shl )。 如果有結束指針,則根本不需要開始指針,除非它們相等(大小= 0)時將返回錯誤。

或者,如果您不被過時的16位代碼所困擾,則可以在尋址模式下使用縮放索引,例如[array + esi * 2] 您包括Irvine32.inc ...

我認為您到達最后一個元素的解決方案是最有效的( ($-val1)/2 ),但是@ zx485是正確的,您的老師可能會認為您在作弊,因此,在其他解決方案中,您可以使用循環和指針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 main

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM