Skip to content

关于"Merge pull request #1836 from RT-Thread/fix_fputc"的问题 #1837

@liruncong

Description

@liruncong

此提交后代码如下:


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参数.按以下步骤修改测试

  1. 修改main.c为:

int main(void)
{
/* user app entry */
printf("test"); // 增加,为了调用fputc
return 0;
}


  1. 在env中通过menuconfig,打开"Enable libc APIs from toolchain". 否则stubs.c等文件不会被编译进去.
  2. 由于无stm32f4xx板子, 修改stm32_rom.sct中加载和执行地址为我手头上板子内存地址.
  3. 修改rtconfig.py. armcc平台的LDFLAGS增加"--symdefs=rtthread-stm32.sym --libpath=C:\Keil_v5\ARM\ARMCC\lib"两个选项,第1个用于根据地址查看对应符号.第2个消除链接问题.
  4. 编译生成rtthread-stm32f4xx.axf.
  5. 在DS5中加载rtthread-stm32f4xx.axf.
  6. 找到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


  1. 找到__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


  1. 找到_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;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions