所以我是ARM Assembly的初学者(一般来说也是程序集)。现在我正在编写一个程序,其中最重要的部分之一是用户需要输入一个字母,然后我会将该字母与其他预先输入的字母进行比较,以查看用户是否输入了相同的字母事情。
例如,在我的代码中我有
.balign 4 /* Forces the next data declaration to be on a 4 byte segment */
dime: .asciz "D\n"
位于文件顶部,
addr_dime : .word dime
位于文件底部。
另外,根据我在线阅读的内容,我提出了
.balign 4
inputChoice: .asciz "%d"
位于文件顶部,然后输入
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中的字符串或字符,然后如果它们相同则将10加到r5。
由于某些原因,这不起作用,并且r5,r5,#10代码仅在addne出现之前有效。
答案 0 :(得分:0)
addr_dime : .word dime
无可救药地过于复杂。地址已经是链接时间常量。将地址存储在内存中(在具有自己地址的另一个位置)根本没有帮助,它只是添加了另一层间接。 (这实际上是你问题的根源。)
无论如何,cmp
不会取消引用它的寄存器操作数,所以你要比较指针。如果单步使用调试器,您将看到寄存器中的值是指针。
要加载dime
的单字节,零扩展到r3,请执行
ldrb r3, dime
使用ldr
执行32位加载也会得到\n
字节,而32位比较也必须与eq
匹配才能成为真。< / p>
但这只能在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;
}
来自Godbolt compiler explorer上的ARM32 gcc6.3:
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以与文字字符进行比较而不是全局编译器无法优化为常量,并看看你得到了什么。