1.硬件平台:cortex-m33
2.编译器版本:gcc version 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599] (GNU Tools for Arm Embedded Processors 9-2019-q4-major)
3.代码示例:
static int printf_test(void)
{
long long x = 2121;
printf("x is %lld\n",x);
printf("x+1 is %lld,x is %lld\n",x+1,x);
printf("x+1 is %lld,nouse1 :%ld,nouse2 :%ld,xx is %lld\n",x+1,555,777,x);
printf("x is %lld,nouse1 :%ld,nouse2 :%ld,xx is %lld\n",444,555,777,x);
return 0;
}
MSH_CMD_EXPORT(printf_test, rtc drive test. e.g: printf_test());
结果输出:
x+1 is 2122,x is 2121
x+1 is 2122,nouse1 :555,nouse2 :777,xx is 2121
x is 3337189589547,nouse1 :2121,nouse2 :0,xx is 2121
可以看到明显最后一次输出异常。
由于你libc里的printf是使用apcd-gnu规则的ABI,应用代码又使用的是AAPCS规则的ABI。两边ABI不兼容导致的。
apcd-gnu规则在处理64位传参的时候使用R1和R2来拼。
aapcs规则则遵循偶数寄存器对齐方式来拼,所以就会使用R2,R3来拼。
这也就是反汇编看到printf调用的时候没有使用R1传参的原因。
如果要解决,那么把所有代码库都使用同一种ABI规则。
有个想法,X不要用常量,而改为外部参数输入,不然有可能直接在预编译时给出值。
然后反汇编,并单步调试时看一下内存,以确认一下可变数量参数时的传参规则。
说回重点:
我理解可变数量传参时,参数都放栈里面,然后printf里面根据给的数据类型来从栈里面取对应长度的数据。
而这里的数字默认类型应该是int,而取值时是当成lld取的,自然就错位了。
把 3337189589547和444,555都转成16进制 ,
0x3090000022B
444=1BC
555=22B
我觉得这个22B可以证明我的猜想,但1BC又对不上,我觉得可能和对齐填充有关,因为u64要求8字节对齐。
要是此时能看一下栈,我觉得应该可以找到有填充0x309
帮楼上修正一下
这样就很清晰了。
@aozima 哈哈哈