2626#define _FORTIFY_SOURCE 0
2727#endif
2828
29- /* Enable %llu/%llx support on platforms with 64-bit types */
29+ /* Enable %llu/%llx support only on platforms where the 64-bit divide
30+ * is either native (64-bit CPUs) or backed by linked libgcc helpers
31+ * (PPC32 toolchain). The auto-enable deliberately excludes 32-bit
32+ * bare-metal targets (Cortex-M, x86 stage1) -- those would link-fail
33+ * on __aeabi_uldivmod / __udivmoddi4 because they don't pull in libgcc.
34+ * Such targets can still opt-in by defining PRINTF_LONG_LONG manually. */
3035#if !defined(PRINTF_LONG_LONG ) && ( \
3136 defined(__alpha__ ) || defined(__ia64__ ) || defined(_ARCH_PPC64 ) || \
3237 defined(__x86_64__ ) || defined(_M_X64 ) || \
3338 defined(__aarch64__ ) || defined(_M_ARM64 ) || \
3439 defined(__sparc64__ ) || defined(__s390x__ ) || \
3540 defined(__ppc64__ ) || defined(__powerpc64__ ) || defined(__PPC__ ) || \
36- (defined(__riscv_xlen ) && (__riscv_xlen == 64 )) || \
37- defined(__SIZEOF_LONG_LONG__ ))
41+ (defined(__riscv_xlen ) && (__riscv_xlen == 64 )))
3842 #define PRINTF_LONG_LONG
3943#endif
4044
@@ -330,37 +334,82 @@ void *memmove(void *dst, const void *src, size_t n)
330334#endif /* WOLFBOOT_USE_STDLIBC */
331335
332336#if defined(PRINTF_ENABLED ) && defined(DEBUG_UART )
337+ /* Shared digit table -- avoids duplicating the literal in each width's
338+ * formatting loop. */
339+ static const char uart_writenum_digits [] = "0123456789ABCDEF" ;
340+
341+ /* Shared tail for both widths: applies zeropad spacing, slides the digit
342+ * run into place, and emits to UART. Caller has filled digits at the
343+ * tail of `buf` and counted them in `sz`; `i` is the prefix length
344+ * (sign character only). */
345+ static void uart_writenum_emit (char * buf , int bufsize , int i , int sz ,
346+ int zeropad , int maxdigits )
347+ {
348+ if (zeropad && sz < maxdigits ) {
349+ i += maxdigits - sz ;
350+ }
351+ memmove (& buf [i ], & buf [bufsize - sz ], sz );
352+ uart_write (buf , i + sz );
353+ }
354+
333355void uart_writenum (int num , int base , int zeropad , int maxdigits )
334356{
335- int i = 0 ;
336- char buf [sizeof (unsigned long )* 2 + 1 ];
337- const char * kDigitLut = "0123456789ABCDEF" ;
357+ int i = 0 , sz = 0 ;
358+ char buf [sizeof (unsigned int ) * 2 + 2 ];
338359 unsigned int val = (unsigned int )num ;
339- int sz = 0 ;
340360 if (maxdigits == 0 )
341361 maxdigits = 8 ;
342362 if (maxdigits > (int )sizeof (buf ))
343363 maxdigits = (int )sizeof (buf );
344364 memset (buf , 0 , sizeof (buf ));
345- if (base == 10 && num < 0 ) { /* handle negative */
365+ if (base == 10 && num < 0 ) {
346366 buf [i ++ ] = '-' ;
347- val = - num ;
367+ val = ( unsigned int )( - num ) ;
348368 }
349369 if (zeropad ) {
350370 memset (& buf [i ], '0' , maxdigits );
351371 }
372+ /* 32-bit divide: stays out of libgcc 64-bit helpers, which aren't
373+ * linked into freestanding stage1 / Cortex-M builds. */
352374 do {
353- buf [sizeof (buf )- sz - 1 ] = kDigitLut [(val % base )];
375+ buf [sizeof (buf ) - sz - 1 ] =
376+ uart_writenum_digits [(val % (unsigned )base )];
354377 sz ++ ;
355- val /= base ;
378+ val /= ( unsigned ) base ;
356379 } while (val > 0U );
357- if (zeropad && sz < maxdigits ) {
358- i += maxdigits - sz ;
380+ uart_writenum_emit (buf , sizeof (buf ), i , sz , zeropad , maxdigits );
381+ }
382+
383+ #ifdef PRINTF_LONG_LONG
384+ /* 64-bit core for %llu/%lld/%llx. Pulls in libgcc 64-bit divide
385+ * (__udivmoddi4 / __aeabi_uldivmod) so it's only compiled when needed
386+ * and only called from the long-long printf paths -- never from the
387+ * 32-bit uart_writenum() fast path above. */
388+ static void uart_writenum_ll (unsigned long long val , int is_negative ,
389+ int base , int zeropad , int maxdigits )
390+ {
391+ int i = 0 , sz = 0 ;
392+ char buf [sizeof (unsigned long long ) * 2 + 2 ];
393+ if (maxdigits == 0 )
394+ maxdigits = 8 ;
395+ if (maxdigits > (int )sizeof (buf ))
396+ maxdigits = (int )sizeof (buf );
397+ memset (buf , 0 , sizeof (buf ));
398+ if (is_negative ) {
399+ buf [i ++ ] = '-' ;
359400 }
360- memmove (& buf [i ], & buf [sizeof (buf )- sz ], sz );
361- i += sz ;
362- uart_write (buf , i );
401+ if (zeropad ) {
402+ memset (& buf [i ], '0' , maxdigits );
403+ }
404+ do {
405+ buf [sizeof (buf ) - sz - 1 ] =
406+ uart_writenum_digits [(val % (unsigned )base )];
407+ sz ++ ;
408+ val /= (unsigned )base ;
409+ } while (val > 0ULL );
410+ uart_writenum_emit (buf , sizeof (buf ), i , sz , zeropad , maxdigits );
363411}
412+ #endif /* PRINTF_LONG_LONG */
364413
365414void uart_vprintf (const char * fmt , va_list argp )
366415{
@@ -434,9 +483,23 @@ void uart_vprintf(const char* fmt, va_list argp)
434483 {
435484 #ifdef PRINTF_LONG_LONG
436485 if (islong >= 2 ) {
437- /* %llu / %lld: consume 64-bit arg, print low 32 bits */
438- unsigned long long ll = va_arg (argp , unsigned long long);
439- uart_writenum ((int )(unsigned int )ll , 10 , zeropad , maxdigits );
486+ /* %llu / %lld: full 64-bit value */
487+ int is_neg = 0 ;
488+ unsigned long long val ;
489+ if (* fmtp != 'u' ) {
490+ long long sll = va_arg (argp , long long );
491+ if (sll < 0 ) {
492+ is_neg = 1 ;
493+ val = (unsigned long long )(- sll );
494+ }
495+ else {
496+ val = (unsigned long long )sll ;
497+ }
498+ }
499+ else {
500+ val = va_arg (argp , unsigned long long);
501+ }
502+ uart_writenum_ll (val , is_neg , 10 , zeropad , maxdigits );
440503 }
441504 else
442505 #endif
@@ -454,9 +517,10 @@ void uart_vprintf(const char* fmt, va_list argp)
454517 {
455518 #ifdef PRINTF_LONG_LONG
456519 if (islong >= 2 ) {
457- /* %llx: consume 64-bit arg, print low 32 bits */
458- unsigned long long ll = va_arg (argp , unsigned long long);
459- uart_writenum ((int )(unsigned int )ll , 16 , zeropad , maxdigits );
520+ /* %llx: full 64-bit value */
521+ unsigned long long val =
522+ va_arg (argp , unsigned long long);
523+ uart_writenum_ll (val , 0 , 16 , zeropad , maxdigits );
460524 }
461525 else
462526 #endif
0 commit comments