-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
此提交后代码如下:
int fputc(int c, FILE *f)
{
char ch[2] = {0};
ch[1] = c;
rt_kprintf(&ch[0]); // 到这里应该是: ch[0] = c, ch[1] = '\0',现在ch[0]和ch[1]反过来了.
return 1;
}
注: 为了跟踪调用fputc时传入c参数.按以下步骤修改测试
- 修改main.c为:
int main(void)
{
/* user app entry */
printf("test"); // 增加,为了调用fputc
return 0;
}
- 在env中通过menuconfig,打开"Enable libc APIs from toolchain". 否则stubs.c等文件不会被编译进去.
- 由于无stm32f4xx板子, 修改stm32_rom.sct中加载和执行地址为我手头上板子内存地址.
- 修改rtconfig.py. armcc平台的LDFLAGS增加"--symdefs=rtthread-stm32.sym --libpath=C:\Keil_v5\ARM\ARMCC\lib"两个选项,第1个用于根据地址查看对应符号.第2个消除链接问题.
- 编译生成rtthread-stm32f4xx.axf.
- 在DS5中加载rtthread-stm32f4xx.axf.
- 找到main反汇编代码
main
0x8020019C : PUSH {r4,lr}
0x8020019E : ADR r0,{pc}+0xa ; 0x802001a8
0x802001A0 : BL __2printf ; 0x8020C2F8 // 这个时printf函数
0x802001A4 : MOVS r0,#0
0x802001A6 : POP {r4,pc}
0x802001A8 : DCD 0x74736574 // 这个是字符串"test"
0x802001AC : DCD 0x00000000
- 找到__2printf反汇编代码
__2printf
0x8020C2F8 : LDR r2,[pc,#4] ; [0x8020C300] = 0x8020C0B9 // 这是fputc地址(+1为thumb指令)
0x8020C2FA : LDR r1,[pc,#8] ; [0x8020C304] = 0x80400218 // 这里是__stdout变量.
0x8020C2FC : B.W _printf_core ; 0x8020C326
0x8020C300 : DCD 0x8020C0B9
0x8020C304 : DCD 0x80400218
- 找到_printf_core反汇编代码
_printf_core
0x8020C326 : PUSH {r4-r8,lr}
0x8020C32A : MOV r6,r2 // fputc
0x8020C32C : MOV r7,r1
0x8020C32E : MOV r4,r0
0x8020C330 : MOVS r5,#0
0x8020C332 : B _printf_core+22 ; 0x8020C33C
0x8020C334 : MOV r1,r7
0x8020C336 : BLX r6 // fputc
0x8020C338 : ADDS r4,r4,#1
0x8020C33A : ADDS r5,r5,#1
0x8020C33C : LDRB r0,[r4,#0] // 读取字符串中一个字符到r0,作为fputc第1个参数c
0x8020C33E : CMP r0,#0
0x8020C340 : BNE _printf_core+14 ; 0x8020C334
0x8020C342 : MOV r0,r5
0x8020C344 : POP {r4-r8,pc}
根据"LDRB r0,[r4,#0] "判断, fputc第1个参数c,只有第1个字节有效,第2/3/4个字节都为0.这个与armclang编译器返汇编结果一致. 因此fputc应该修改如下:
int fputc(int c, FILE f)
{
rt_kprintf((char)&c);
return 1;
}
并且fputc/fgetc的__MICROLIB限定应该取消,对应armcc不使用microlib或armclang的情形,这两个函数都需要,否则printf等函数将不正常.
上面这个更改是最高效的. 下面这种是看不到汇编代码,无法确定传入c的第2~4字节数值时的改动:
int fputc(int c, FILE f)
{
((char)&c)[1] = '\0'; // 各编译器在调这个函数前,准备的字符c,应该都会保证2/3/4字节为0.
rt_kprintf((char*)&c);
return 1;
}