将用户输入的字符串/字符与另一个字符串/字符进行比较
因此,我对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出现之前有效。
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到用文字字符,而不是比较全局编译器不能优化成一个常量,并看看你得到了什么。
当我这样做,我得到一个错误,说internal_relocation(类型:OFFSET_IMM)没有修复 – PCRevolt
@PCRevolt:啊,是啊,我想知道如果汇编程序会神奇地照顾使用寻址模式,可以达到的数据。 ARM使用固定宽度的指令,而且它们没有空间存放任意的32位绝对地址。有一个偏移量小的PC相对寻址模式,因此ARM代码通常使用“文字池”从实际代码附近的块中加载数据。看看C编译器的功能:https://godbolt.org/g/xnRrNa。如果你只是为你的缓冲区使用堆栈内存,而不是静态的,你可以避免这种情况。所以你只需要在一个指针和'ldrb r3,[r5]'中获得地址。 –
但是在这种情况下r5会是什么 – PCRevolt