2017-09-23 166 views
0

因此,我對ARM程序集(一般來說也是一個組裝程序)初學者。現在我正在編寫一個程序,其中最重要的部分之一是用戶需要輸入一個字母,然後我會將該字母與其他預先輸入的字母進行比較,以查看用戶是否輸入了相同的字母事情。將用戶輸入的字符串/字符與另一個字符串/字符進行比較

舉例來說,在我的代碼我有

.balign 4 /* Forces the next data declaration to be on a 4 byte segment */ 
dime: .asciz "D\n" 

在文件的頂部,

addr_dime    : .word dime 

在文件的底部。

此外,基於什麼我已經在網上閱讀,我把

​​

在文件的頂部,並把

inputVal    : .word 0 

在文件的底部。

接近文件的中間(只相信我,有什麼不對的獨立代碼,並且文件在這方面無關緊要的其餘部分)我的代碼塊:

ldr r3, addr_dime 
ldr r2, addr_inputChoice 
cmp r2, r3     /*See if the user entered D*/ 
addeq r5, r5, #10   /*add 10 to the total if so*/ 

我認爲應該將「D」加載到r3中,將用戶輸入的任何字符串或字符加載到r2中,如果它們相同,則將其添加到r5中。

由於某些原因,這不起作用,並且r5,r5,#10代碼僅在addne出現之前有效。

回答

0

addr_dime : .word dime無情地過度複雜。該地址已經是鏈接時間常數。將地址存儲在內存中(在具有自己地址的另一個地方)並不能完全幫助你,它只是增加了另一層間接尋址。 (這實際上是你的問題的根源。)

無論如何,cmp不取消它的寄存器操作數,所以你比較指針。如果您單獨使用調試器,您會看到寄存器中的值是指針。

要在dime加載單個字節,零擴展到R3,做

ldrb r3, dime 

使用ldr做一個32位的負荷也將獲得\n字節,和一個32位的比較將有以匹配eq也是如此。

但是,只有當dime足夠接近PC相對尋址模式才能適用;像大多數RISC機器一樣,ARM不能使用任意的絕對地址,因爲指令寬度是固定的。

對於常量,最容易避免的方法是而不是首先將其存儲在內存中。使用.equ dime, 'D'定義數值常量,那麼你可以使用

cmp r2, dime  @ compare with immediate operand 

或者ldr r3, =dime要求彙編得到不斷的進入你的寄存器。你可以用地址做到這一點,那麼你可以做

ldr r2, =inputVal  @ r2 = &inputVal 
ldrb r2, [r2]   @ load first byte of inputVal 

這是處理來自這可能是太遙遠的PC相對尋址模式的靜態數據加載的通用方法。

你可以通過使用堆棧地址(sub sp, #16/mov r5, sp或其他)來避免這種情況。那麼你已經有了一個寄存器中的地址。


這正是一個C編譯器:

char dime[4] = "D\n"; 
char input[4] = "xyz"; 

int foo(int start) { 
    if (dime[0] == input[0]) 
     start += 10; 
    return start; 
} 

從ARM32 gcc6.3上Godbolt compiler explorer

foo: 
     ldr  r3, .L4   @ load a pointer to the data section at dime/input 
     ldrb r2, [r3] 
     ldrb r3, [r3, #4] 
     cmp  r2, r3 
     addeq r0, r0, #10 
     bx  lr 
.L4: 
     @ gcc greated this "literal pool" next to the code 
     @ holding a pointer it can use to access the data section, 
     @ wherever the linker ends up putting it. 
     .word .LANCHOR0 

.section .data 
.p2align 2 
@@@ These are in a different section, near each other. 
@@@ On Godbolt, click the .text button to see full assembler directives. 

.LANCHOR0:  @ actually defined with a .set directive, but same difference. 
dime: 
     .ascii "D\012\000" 
input: 
     .ascii "xyz\000" 

嘗試改變C到用文字字符,而不是比較全局編譯器不能優化成一個常量,並看看你得到了什麼。

+0

當我這樣做,我得到一個錯誤,說internal_relocation(類型:OFFSET_IMM)沒有修復 – PCRevolt

+0

@PCRevolt:啊,是啊,我想知道如果彙編程序會神奇地照顧使用尋址模式,可以達到的數據。 ARM使用固定寬度的指令,而且它們沒有空間存放任意的32位絕對地址。有一個偏移量小的PC相對尋址模式,因此ARM代碼通常使用「文字池」從實際代碼附近的塊中加載數據。看看C編譯器的功能:https://godbolt.org/g/xnRrNa。如果你只是爲你的緩衝區使用堆棧內存,而不是靜態的,你可以避免這種情況。所以你只需要在一個指針和'ldrb r3,[r5]'中獲得地址。 –

+0

但是在這種情況下r5會是什麼 – PCRevolt

相關問題