bug-gnu-utils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: problem with fill on IA64 linker


From: Alan Modra
Subject: Re: problem with fill on IA64 linker
Date: Fri, 15 Feb 2002 10:41:08 +1030
User-agent: Mutt/1.3.25i

On Wed, Feb 13, 2002 at 01:57:19PM -0800, Lowney, Geoff wrote:
>                                                 2/13/02
> 
> I am using GNU ld version 2.11.2 (with BFD 2.11.2) on a IA64 (Itanium)
> Linux system.  I am writing a binary optimizer for IA64 and have a
> small problem with linker.
> 
> The fill is -1 (0xffffffff), which does not not decode to valid
> instructions.  I would like the fill to be 0, which decodes to a
> series of break instructions.
> 
> There appear to be several problems in processing the fill on IA64.
> 
>   - There is a bug in the parsing of the default linker script.  The
>     fill is set to 0x00300000010070000002000001000400.  However, the
>     lexer uses bfd_scan_vma to read the fill value, and it cannot read
>     a value that is greater than ULONG_MAX.  In a native linker,
>     bfd_scan_vms calls strtoul to lex the string, and it returns -1.
> 
>   - The back end processing (default_fill_link_order) is only prepared
>     to handle a 2-byte fill value.
> 
>   - The string 0x00300000010070000002000001000400 appears to decode to
>     three nops (unless I have made an endian mistake, see example below).
>     I would prefer to use a break, rather than a nop, because the fill
>     code should be unreachable. 

Let's fix this properly.  I'm checking in a patch to fix bfd_scan_vma
to clamp on overflow, and will shortly post a patch to allow
arbitrarily long fill strings.

bfd/ChangeLog
        * bfd.c (bfd_scan_vma): Clamp overflows to max bfd_vma value.
        Correct value returned in "end" for "0x<non-hex>".

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

Index: bfd/bfd.c
===================================================================
RCS file: /cvs/src/src/bfd/bfd.c,v
retrieving revision 1.30
diff -u -p -r1.30 bfd.c
--- bfd.c       2002/01/30 18:12:16     1.30
+++ bfd.c       2002/02/14 23:21:43
@@ -1008,7 +1008,8 @@ DESCRIPTION
        in hex if a leading "0x" or "0X" is found, otherwise
        in octal if a leading zero is found, otherwise in decimal.
 
-       Overflow is not detected.
+       If the value would overflow, the maximum <<bfd_vma>> value is
+       returned.
 */
 
 bfd_vma
@@ -1018,48 +1019,64 @@ bfd_scan_vma (string, end, base)
      int base;
 {
   bfd_vma value;
-  int digit;
+  bfd_vma cutoff;
+  unsigned int cutlim;
+  int overflow;
 
   /* Let the host do it if possible.  */
   if (sizeof (bfd_vma) <= sizeof (unsigned long))
     return (bfd_vma) strtoul (string, (char **) end, base);
 
-  /* A negative base makes no sense, and we only need to go as high as hex.  */
-  if ((base < 0) || (base > 16))
-    return (bfd_vma) 0;
-
   if (base == 0)
     {
       if (string[0] == '0')
        {
          if ((string[1] == 'x') || (string[1] == 'X'))
            base = 16;
-         /* XXX should we also allow "0b" or "0B" to set base to 2?  */
          else
            base = 8;
        }
-      else
-       base = 10;
     }
+
+  if ((base < 2) || (base > 36))
+    base = 10;
+
+  if (base == 16
+      && string[0] == '0'
+      && (string[1] == 'x' || string[1] == 'X')
+      && ISXDIGIT (string[2]))
+    {
+      string += 2;
+    }
+
+  cutoff = (~ (bfd_vma) 0) / (bfd_vma) base;
+  cutlim = (~ (bfd_vma) 0) % (bfd_vma) base;
+  value = 0;
+  overflow = 0;
+  while (1)
+    {
+      unsigned int digit;
 
-  if ((base == 16) &&
-      (string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X')))
-    string += 2;
-  /* XXX should we also skip over "0b" or "0B" if base is 2?  */
-
-/* Speed could be improved with a table like hex_value[] in gas.  */
-#define HEX_VALUE(c) \
-  (ISXDIGIT (c)                                                        \
-   ? (ISDIGIT (c)                                              \
-      ? (c - '0')                                              \
-      : (10 + c - (ISLOWER (c) ? 'a' : 'A')))                  \
-   : 42)
+      digit = *string;
+      if (ISDIGIT (digit))
+       digit = digit - '0';
+      else if (ISALPHA (digit))
+       digit = TOUPPER (digit) - 'A' + 10;
+      else
+       break;
+      if (digit >= (unsigned int) base)
+       break;
+      if (value > cutoff || (value == cutoff && digit > cutlim))
+       overflow = 1;
+      value = value * base + digit;
+      ++string;
+    }
 
-  for (value = 0; (digit = HEX_VALUE (* string)) < base; string ++)
-    value = value * base + digit;
+  if (overflow)
+    value = ~ (bfd_vma) 0;
 
-  if (end)
-    * end = string;
+  if (end != NULL)
+    *end = string;
 
   return value;
 }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]