[U-Boot] [PATCH 05/24] SPL: tiny-printf: add "l" modifier
Andre Przywara
andre.przywara at arm.com
Mon Nov 21 16:56:03 CET 2016
Hi Alex,
On 21/11/16 15:42, Alexander Graf wrote:
>
>
> On 20/11/2016 15:56, Andre Przywara wrote:
>> tiny-printf does not know about the "l" modifier so far, which breaks
>> the crash dump on AArch64, because it uses %lx to print the registers.
>> Add an easy way of handling longs correctly.
>>
>> Signed-off-by: Andre Przywara <andre.przywara at arm.com>
>> ---
>> lib/tiny-printf.c | 43 +++++++++++++++++++++++++++++++++----------
>> 1 file changed, 33 insertions(+), 10 deletions(-)
>>
>> diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c
>> index 30ac759..b01099d 100644
>> --- a/lib/tiny-printf.c
>> +++ b/lib/tiny-printf.c
>> @@ -38,8 +38,8 @@ static void out_dgt(struct printf_info *info, char dgt)
>> info->zs = 1;
>> }
>>
>> -static void div_out(struct printf_info *info, unsigned int *num,
>> - unsigned int div)
>> +static void div_out(struct printf_info *info, unsigned long *num,
>> + unsigned long div)
>> {
>> unsigned char dgt = 0;
>>
>> @@ -56,9 +56,9 @@ int _vprintf(struct printf_info *info, const char
>> *fmt, va_list va)
>> {
>> char ch;
>> char *p;
>> - unsigned int num;
>> + unsigned long num;
>> char buf[12];
>> - unsigned int div;
>> + unsigned long div;
>>
>> while ((ch = *(fmt++))) {
>> if (ch != '%') {
>> @@ -66,8 +66,12 @@ int _vprintf(struct printf_info *info, const char
>> *fmt, va_list va)
>> } else {
>> bool lz = false;
>> int width = 0;
>> + bool islong = false;
>>
>> ch = *(fmt++);
>> + if (ch == '-')
>> + ch = *(fmt++);
>> +
>
> What does this do? I don't see '-' mentioned in the patch description.
Argh, apparently the comment in the commit message got lost during a
patch reshuffle. Sorry, will re-add it.
We need it because some SPL printf uses '-', just ignoring it here seems
fine for SPL purposes though.
>
>> if (ch == '0') {
>> ch = *(fmt++);
>> lz = 1;
>> @@ -80,6 +84,11 @@ int _vprintf(struct printf_info *info, const char
>> *fmt, va_list va)
>> ch = *fmt++;
>> }
>> }
>> + if (ch == 'l') {
>> + ch = *(fmt++);
>> + islong = true;
>> + }
>> +
>> info->bf = buf;
>> p = info->bf;
>> info->zs = 0;
>> @@ -89,24 +98,38 @@ int _vprintf(struct printf_info *info, const char
>> *fmt, va_list va)
>> goto abort;
>> case 'u':
>> case 'd':
>> - num = va_arg(va, unsigned int);
>> - if (ch == 'd' && (int)num < 0) {
>> - num = -(int)num;
>> + div = 1000000000;
>> + if (islong) {
>
> Check here if sizeof(long) > 4, so that the whole branch gets optimized
> away on 32bit.
Good idea.
>> + num = va_arg(va, unsigned long);
>> + if (sizeof(long) > 4)
>> + div *= div * 10;
>> + } else {
>> + num = va_arg(va, unsigned int);
>> + }
>> +
>> + if (ch == 'd' && (long)num < 0) {
>> + num = -(long)num;
>
> Num is a long now and before. So if you have a 32bit signed input, it
> will sign extend incorrectly here. You need an additional check
>
> if (islong)
> num = -(long)num;
> else
> num = -(int)num;
>
> Let's hope the compiler on 32bit is smart enough to know that it can
> combine those two cases :).
>
>> out(info, '-');
>> }
>> if (!num) {
>> out_dgt(info, 0);
>> } else {
>> - for (div = 1000000000; div; div /= 10)
>> + for (; div; div /= 10)
>
> Any particular reason for that change?
This algorithm so far only cared for 32-bit values, so it set the start
divider to 1E9. This is not sufficient for 64-bit longs in AA64.
So I compute div above, depending on the actual size of long.
>> div_out(info, &num, div);
>> }
>> break;
>> case 'x':
>> - num = va_arg(va, unsigned int);
>> + if (islong) {
>
> Same comment as above.
Thanks, I will take a look at the rest.
Cheers,
Andre.
>
>> + num = va_arg(va, unsigned long);
>> + div = 1UL << (sizeof(long) * 8 - 4);
>> + } else {
>> + num = va_arg(va, unsigned int);
>> + div = 0x10000000;
>> + }
>> if (!num) {
>> out_dgt(info, 0);
>> } else {
>> - for (div = 0x10000000; div; div /= 0x10)
>> + for (; div; div /= 0x10)
>> div_out(info, &num, div);
>> }
>> break;
>>
More information about the U-Boot
mailing list