[Top][All Lists]
[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;
}