Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
liruncong opened this issue Sep 23, 2018 · 3 comments
Closed

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

liruncong opened this issue Sep 23, 2018 · 3 comments

Comments

@liruncong
Copy link
Contributor

liruncong commented Sep 23, 2018

此提交后代码如下:


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;
}

@liruncong
Copy link
Contributor Author

liruncong commented Sep 24, 2018

建议加强测试, 改前是无法正常使用,会跑飞,改完后不会跑飞,但是printf无任何输出(因为第1个字节被写0了).

@BernardXiong
Copy link
Member

手误,应该是

ch[0] = c;

@liruncong
Copy link
Contributor Author

@BernardXiong 看到更正了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants