]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
ld: bring vfinfo() in parity with printf() for format specifiers ll[d|i|x]
authorMatthieu Longo <matthieu.longo@arm.com>
Thu, 22 Jan 2026 17:34:39 +0000 (17:34 +0000)
committerMatthieu Longo <matthieu.longo@arm.com>
Fri, 23 Jan 2026 10:40:10 +0000 (10:40 +0000)
vfinfo() does not currently support the double-'l' ('ll') length
modifier for 'd', 'u', and 'x' conversion specifiers. This caused
incorrect behavior when using PRI[d|u|x][32|64] on some platforms,
and is error-prone for developers who reasonably expect
printf-compatible semantics.

This patch adds support for ll[d|u|x] to align vfinfo() with printf()
and improve portability and robustness.

ld/ldmisc.c

index 8668e55f06db13b17bf5fd3e2068d494e38d2d60..3deceb76719240320c49c3cbd63bfa339d763e08 100644 (file)
@@ -98,6 +98,7 @@ vfinfo (FILE *fp, const char *fmt, va_list ap, bool is_warning)
   {
     int i;
     long l;
+    long long ll;
     void *p;
     bfd_vma v;
     struct {
@@ -110,6 +111,7 @@ vfinfo (FILE *fp, const char *fmt, va_list ap, bool is_warning)
        Bad,
        Int,
        Long,
+       LongLong,
        Ptr,
        Vma,
        RelAddr
@@ -181,10 +183,16 @@ vfinfo (FILE *fp, const char *fmt, va_list ap, bool is_warning)
              break;
 
            case 'l':
+             bool ll_type = false;
+             if (*scan == 'l')
+               {
+                 ll_type = true;
+                 ++scan;
+               }
              if (*scan == 'd' || *scan == 'u' || *scan == 'x')
                {
                  ++scan;
-                 arg_type = Long;
+                 arg_type = (ll_type ? LongLong : Long);
                }
              break;
 
@@ -211,6 +219,9 @@ vfinfo (FILE *fp, const char *fmt, va_list ap, bool is_warning)
        case Long:
          args[arg_no].l = va_arg (ap, long);
          break;
+       case LongLong:
+         args[arg_no].ll = va_arg (ap, long long);
+         break;
        case Ptr:
          args[arg_no].p = va_arg (ap, void *);
          break;
@@ -566,11 +577,21 @@ vfinfo (FILE *fp, const char *fmt, va_list ap, bool is_warning)
              ++arg_count;
              break;
 
-           case 'l': /* (Unsigned) long integer, like printf().  */
+           case 'l': /* (Unsigned) (long) long integer, like printf().  */
+             bool ll_type = false;
+             if (*fmt == 'l')
+               {
+                 fmt++;
+                 ll_type = true;
+               }
              if (*fmt == 'd' || *fmt == 'u' || *fmt == 'x')
                {
-                 cfmt = make_cfmt (fmt - 1 - mods, mods + 2);
-                 fprintf (fp, cfmt, args[arg_no].l);
+                 unsigned int mods_len = (ll_type ? 2 : 1);
+                 cfmt = make_cfmt (fmt - mods_len - mods, mods + mods_len + 1);
+                 if (ll_type)
+                   fprintf (fp, cfmt, args[arg_no].ll);
+                 else
+                   fprintf (fp, cfmt, args[arg_no].l);
                  free (cfmt);
                  ++arg_count;
                  ++fmt;