2017-09-23 175 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

相关问题