我需要从ARM汇编语言例程调用printf。我编写了一个执行相同操作的程序(printf("%d.%d",1,2)
)。我反汇编了编译器输出,但格式字符串的传递方式并不明显。你们中的任何一个都有代码的例子吗?
这是我用来尝试查看如何调用printf的测试例程。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("%d.%d\n",1,2);
return EXIT_SUCCESS;
}
我对主程序的反汇编如下所示:
000081c4 <main>:
81c4: e1a0c00d mov ip, sp
81c8: e92dd800 stmdb sp!, {fp, ip, lr, pc}
81cc: e24cb004 sub fp, ip, #4 ; 0x4
81d0: e59f0014 ldr r0, [pc, #20] ; 81ec <.text+0x11c>
81d4: e3a01001 mov r1, #1 ; 0x1
81d8: e3a02002 mov r2, #2 ; 0x2
81dc: eb000212 bl 8a2c <_IO_printf>
81e0: e3a03000 mov r3, #0 ; 0x0
81e4: e1a00003 mov r0, r3
81e8: e89da800 ldmia sp, {fp, sp, pc}
81ec: 00060120 andeq r0, r6, r0, lsr #2
我看到了_IO_printf例程的分支,但我没有看到如何将格式字符串传递给它。
答案 0 :(得分:2)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("%d.%d\n",1,2);
return EXIT_SUCCESS;
}
编译和反汇编:
0000842c <main>:
842c: e92d4008 push {r3, lr}
8430: e3a01001 mov r1, #1
8434: e3a02002 mov r2, #2
8438: e59f0008 ldr r0, [pc, #8] ; 8448 <main+0x1c>
843c: ebffffcc bl 8374 <_init+0x44>
8440: e3a00000 mov r0, #0
8444: e8bd8008 pop {r3, pc}
8448: 00008524 andeq r8, r0, r4, lsr #10
r0是第一个参数,格式字符串,r1是第二个参数a 1,r2是第三个参数a 2.格式字符串是一个字符串,一个指向字节数组的指针。 r0加载了该指针,一个字节串的地址。在这种情况下,该地址是0x8524。
如果你好奇,你可以去看看0x8524,看看你的字符串,
8524: 252e6425 strcs r6, [lr, #-1061]! ; 0xfffffbdb
8528: 00000a64 andeq r0, r0, r4, ror #20
0x25,0x64,0x2e,0x25,0x64,0x0A,0x00
同样在你的反汇编中,你的字符串的地址是
81d0: e59f0014 ldr r0, [pc, #20] ; 81ec <.text+0x11c>
...
81ec: 00060120 andeq r0, r6, r0, lsr #2
如果您查看地址0x60120的反汇编,您将看到您的字符串。
答案 1 :(得分:1)
在C中,字符串存储为字节序列。将字符串传递给函数时,实际上是在传递字符串中第一个字符的地址。
当您调用printf()
(没有编译器优化)时,参数将以相反的顺序(即从右到左)压入堆栈。然后printf()
弹出第一个参数,它是格式字符串的(指针)。它解析格式字符串以确定每个连续参数弹出的字节数,以及如何根据它们所代表的数据类型(int,string等)来解释它们。
更新:正如其他人所指出的,ARM处理器使用不同的调用约定。它不是使用堆栈,而是传递寄存器中的第一个参数。但是这些参数的内容与它们在堆栈上传递时的内容相同。 R0将包含指向格式字符串的指针,下面的等效代码仍然准确。
感谢那些提供更正的人。
因此,至少就printf()
而言,您的代码与此相同:
const char formatString[] = "%d.%d";
printf(&formatString[0], 1, 2);
答案 2 :(得分:0)
我看到了_IO_printf例程的分支,但我没有看到如何将格式字符串传递给它。
清洁眼镜。寄存器R0是字符串的地址,R1是“1”,R2是“2”。 Adam Liss错了,在ARM中你使用R0-R4作为前4个函数参数。
该行
81d0: e59f0014 ldr r0, [pc, #20] ; 81ec <.text+0x11c>
加载存储在返回R0后面的函数“尾部”的地址。