我刚才有几个关于某些助记符含义的问题,以及我给出的代码中存在的命令。我之前从未与大会合作过。
以下是代码片段:
traverse proc
ldr r0, =21475234
push {r4, r5, lr}
mov r4, r0
ldr r5, [r4]
ldr r0, [r4, #4]
bl traverse
cmp r5, r0
it lt
movlt r5, r0
mov r0,r5
pop {r4,r5,pc}
究竟加载到r5
的内容是什么?按照说明操作,r4
是否被推入堆栈,加载了r0
中的值,然后r5
也加载了它?
加载到r0
的内容是什么? [r4, #4]
是否引用r4
中第五个位置的数字?
bl traverse
由于我们已经在遍历函数中工作,我们是否将分支链接到同一个函数?
我不确定pc
助记符是什么意思。
proc
中traverse proc
的符号是什么?每个功能声明都需要这个吗?
先谢谢你们,我还在努力解决这个问题。
答案 0 :(得分:1)
ldr r0, =21475234
这是一个快捷方式,几乎是伪代码。各种手臂组装者倾向于支持它。
可能打算像这样使用
ldr r0,=hello
ldr r1,[r0]
...
in some other file perhaps
.globl hello
hello:
.word 0x1234
基本上它意味着在等号后加载东西的地址。
ldr r0,hello
...
hello:
.word 0x1234
表示将标签hello中的数据值加载到r0。
在C中就是这个
//ldr r0,=hello
unsigned int r0 = (unsigned int)&hello;
//ldr r0,hello
unsigned int r0 = hello;
因为arm大部分是一个固定长度的指令集,其中指令的大小或小于寄存器,当你使用数字作为项目地址而不是标签
ldr r0,=0x12345678
编码为
ldr r0,temp000
...
temp000: .word 0x12345678
将值0x12345678加载到r0中。汇编程序必须找到一个足够接近ldr的位置,但是在执行路径之外放置该数据字,有时你会得到一个无法找到位置的错误。
所以
ldr r0, =21475234
将值21475234加载到r0。
这推动 推{r4,r5,lr} 将r4,r5和返回寄存器lr保存在堆栈中。常用的调用约定对于arm来说你可以销毁r0-r3,但是你必须保留其他寄存器(这里有一个或两个例外)所以要使用r4我们必须保存它。我假设这是编译后的代码而不是手写的和/或是从编译代码中调用的?所以现在我们可以使用r4,这个值将21475234复制到r4,r0和r4现在保持相同的东西 mov r4,r0 当您将[括号]放在基本上是寄存器间接寻址的寄存器周围时,寄存器的内容不是想要该寄存器的内容,而是您想要的内容的地址,所以这就是读取地址21475234的值并保存r5中的值
ldr r5, [r4]
你是否删除了一些代码来发布这个问题?
这表示读取地址21475234 + 4处的值并将其保存在r0
中ldr r0, [r4, #4]
当立即值在括号内时,意味着将其添加到寄存器并使用从寄存器r4加4中的地址读取的地址。
ldr r0, [r4, #4]
从添加r4 + r5
生成的地址中读取ldr r0, [r4, r5]
这与从r4中的地址读取的情况完全不同,将值放在r0 THEN ADD 4到R4中。
ldr r0, [r4], #4
这类似于C代码
unsigned int r0 = *r4++;
lr是链接寄存器r14,pc是程序计数器r15,当你改变r15时它实际上是一个分支。当调用函数(procedure,proc)时,lr的push保存了返回地址,这样你就可以在函数调用之后立即返回运行代码。为了做到这一点,你基本上需要将程序计数器更改为调用后的地址(bl =分支链接,它基本上是对某个地址的函数调用)。因此,你可以推动lr和pop pc,所以这个
pop {r4,r5,pc}
是push的补充,它将r4和r5恢复为输入函数时的值,然后将返回地址弹出到程序计数器中,以使程序分支到该地址。
traverse是过程的标签或名称(函数)proc是过程的缩写。毫无疑问,汇编助记符更专业,而不仅仅是声明标签。标签应该可以正常工作,但如果你这样做,你可以从汇编程序获得更多帮助。 (我从来没有找到理由在20多年的日常集会中做到这一点,但也许其他人都有)。
bl遍历,这是一个递归调用。不知道你是怎么摆脱这个的,你发布了所有的代码吗?