我需要遍歷每個角色,並且我想通過使用rsi寄存器來使用它。但是每次我嘗試這個時,都會出現分段錯誤。
根據您所顯示的代碼,並RDI
包含字符串的開頭的地址的說法,我可以看到幾個不同的原因,你會得到在負載分段錯誤。
也許問題是RDI
包含一個8字符的ASCII字符串(通過值傳遞),而不是包含該字符串(通過引用傳遞)的內存位置的地址?
另一種更可能的可能性是它在循環的前幾次迭代中工作正常,但是隨後您開始嘗試讀取字符串的末尾,因爲您沒有正確終止循環。您所展示的代碼中沒有dtoi_end
標籤,也沒有您實際跳到convert_end
標籤的地方。這些應該是同一個標籤嗎?如果我傳遞字符串「-2」,會發生什麼?你的循環何時終止?在我看來,它不會!
您需要某種方式來指示整個字符串已被處理。有幾個常用的方法。一種是在字符串末尾使用一個哨兵終結符字符,就像C使用ASCII NUL字符一樣。在你的循環內部,你會檢查正在處理的字符是否爲0(NUL),如果是,跳出循環。另一個選擇是將字符串的長度作爲附加參數傳遞給函數,就像Pascal對計數長度字符串所做的那樣。然後,你需要在循環內部進行測試,以檢查是否已經處理了足夠多的字符,如果是,則跳出循環。
我會盡量不要太講究這個,但你應該已經能夠通過使用調試器自己檢測到這個問題。逐行執行代碼,觀察變量/寄存器的值,並確保您瞭解正在發生的事情。這基本上就是我在分析你的代碼時所做的,除了我的頭腦是調試器,在我自己的腦海裏「執行」了代碼。儘管如此,讓計算機執行它更容易(也更不容易出錯),這就是調試器發明的原因。如果你的代碼不工作,並且你沒有在調試器中逐行執行,你還沒有努力去解決這個問題。事實上,單步穿越你寫的每個功能是一個很好的習慣,因爲(A)它會確保你理解你寫的內容的邏輯,(B)它會幫助你找到錯誤。
組合錯誤無效。我知道這是因爲寄存器是不同的大小,但我失去了如何繼續添加轉換後的ascii值回rax。
您必須使尺寸匹配。你可以做add al, dl
,但是你會限制結果爲8位的字節。這可能不是你想要的。因此,您需要將dl
轉換爲64位QWORD,如rax
。要做到這一點的顯而易見的方法是使用零擴展的MOVZX
指令。換句話說,它將值「擴展」爲更大的大小,用0填充高位。這就是你想要的無符號值。對於帶符號的值,您需要執行符號感知擴展(即將符號位考慮在內),並且要這樣做,您可以使用MOVSX
指令。
在代碼:
movzx rdx, dl
add rax, rdx
別注意,因爲評論者之一指出的,DL
僅僅是RDX
寄存器的最低8位:
| 63 - 32 | 31 - 16 | 15 - 8 | 7 - 0 |
--------------------------------------
| DH | DL |
--------------------------------------
| EDX |
--------------------------------------
| RDX |
因此,它對xor dl, dl
和xor rdx, rdx
是多餘的。後者完成前者。另外,每次修改dl
時,實際上都會修改rdx
的最低8位,這會導致錯誤的結果。提示,提示:這是你用調試器單步執行的其他東西,但你可能已經發現了它(儘管你可能不明白爲什麼!)。
此外,根本不需要做xor rdx, rdx
!您可以通過執行xor edx, edx
完成相同的任務,more efficiently。
只是爲了好玩,這裏是一個可能的實現代碼:
; Parameters: RDI == address of start of character string
; RCX == number of characters in string
; Clobbers: RDX, RSI
; Returns: result is in RAX
xor esi, esi
convert:
; See if we've done enough characters by checking the length of the string
; against our current index.
cmp rsi, rcx
jge convert_end
; Get the next character from the string.
mov dl, BYTE [rdi + rsi]
cmp dl, "-"
je increment
cmp dl, "."
je convert_end
; Efficient way to multiply by 10.
; (Faster and less difficult to write than the MUL instruction.)
add rax, rax
lea rax, [4 * rax + rax]
sub dl, "0"
movzx rdx, dl
add rax, rdx
; (fall through to increment---no reason for redundant instructions!)
increment:
inc rsi ; increment index/counter
jmp convert ; keep looping
convert_end:
ret
(警告:這樣做的邏輯是未經測試我只是改寫了更優化的方式將現有的代碼,而不bug)。
'DL'是'RDX'的一部分。你對'DL'所做的事情你也對'RDX'做了,反之亦然。其次,'mul rdx'採用操作數和'RAX',將它們相乘並將結果存儲在'RDX:RAX'中。這不是你明顯想要的。你必須重新考慮你對寄存器的使用。 – rkhb
當你訪問你不應該訪問的內存時,'mov dl,[rdi + rsi]'崩潰。 rdi指向哪裏?我個人不會添加rdi和rsi,因爲您使用2個寄存器用於一個目的。初始化rsi以指向「字符串」,並用「mov dl,[rsi]'+'inc rsi'加載字節 – Tommylee2k