From a7985d7382642610f87799e271e3854079eba6b2 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 8 Dec 2005 11:05:36 +0000 Subject: [PATCH] * reloc.c (enum complain_overflow): Correct comments. (bfd_check_overflow): Combine complain_overflow_bitfield and complain_overflow_signed code. (_bfd_relocate_contents): Likewise. (bfd_howto_32): Use complain_overflow_dont. * elf32-d10v.c (elf_d10v_howto_table): Revert 2002-06-17 change. * bfd-in2.h: Regenerate. --- bfd/ChangeLog | 14 +++++- bfd/bfd-in2.h | 7 +-- bfd/elf32-d10v.c | 12 +++--- bfd/reloc.c | 109 +++++++++++++++++------------------------------ 4 files changed, 61 insertions(+), 81 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f76458a9697..1db91701ca9 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,13 @@ +2005-12-08 Alan Modra + + * reloc.c (enum complain_overflow): Correct comments. + (bfd_check_overflow): Combine complain_overflow_bitfield and + complain_overflow_signed code. + (_bfd_relocate_contents): Likewise. + (bfd_howto_32): Use complain_overflow_dont. + * elf32-d10v.c (elf_d10v_howto_table): Revert 2002-06-17 change. + * bfd-in2.h: Regenerate. + 2005-12-07 H.J. Lu * elf.c (assign_section_numbers): Remove extra code in the last @@ -559,7 +569,7 @@ (scan_unit_for_symbols): New locals nested_funcs, nested_funcs_size. Delete code setting funcinfo nesting_level field. Add code to set funcinfo caller_func field. - + 2005-09-20 James E. Wilson * dwarf2.c (find_abstract_instance_name): Don't early exit when name @@ -628,7 +638,7 @@ local symbols and move it to (msp430_elf_relax_adjust_locals): New function - walk over the sections in the bfd and adjust relocations as necessary. - + 2005-08-31 DJ Delorie * elf32-i386.c (elf_i386_check_relocs): Don't cast a unary & diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index fc02ecf96a0..39c15bd2117 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -2073,11 +2073,12 @@ enum complain_overflow /* Do not complain on overflow. */ complain_overflow_dont, - /* Complain if the bitfield overflows, whether it is considered - as signed or unsigned. */ + /* Complain if the value overflows when considered as a signed + number one bit larger than the field. ie. A bitfield of N bits + is allowed to represent -2**n to 2**n-1. */ complain_overflow_bitfield, - /* Complain if the value overflows when considered as signed + /* Complain if the value overflows when considered as a signed number. */ complain_overflow_signed, diff --git a/bfd/elf32-d10v.c b/bfd/elf32-d10v.c index a0e506a8835..293b1419de7 100644 --- a/bfd/elf32-d10v.c +++ b/bfd/elf32-d10v.c @@ -50,10 +50,10 @@ static reloc_howto_type elf_d10v_howto_table[] = HOWTO (R_D10V_10_PCREL_R, /* Type. */ 2, /* Rightshift. */ 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 7, /* Bitsize. */ + 8, /* Bitsize. */ TRUE, /* PC_relative. */ 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain_on_overflow. */ + complain_overflow_signed, /* Complain_on_overflow. */ bfd_elf_generic_reloc, /* Special_function. */ "R_D10V_10_PCREL_R", /* Name. */ FALSE, /* Partial_inplace. */ @@ -65,10 +65,10 @@ static reloc_howto_type elf_d10v_howto_table[] = HOWTO (R_D10V_10_PCREL_L, /* Type. */ 2, /* Rightshift. */ 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 7, /* Bitsize. */ + 8, /* Bitsize. */ TRUE, /* PC_relative. */ 15, /* Bitpos. */ - complain_overflow_bitfield, /* Complain_on_overflow. */ + complain_overflow_signed, /* Complain_on_overflow. */ bfd_elf_generic_reloc, /* Special_function. */ "R_D10V_10_PCREL_L", /* Name. */ FALSE, /* Partial_inplace. */ @@ -110,10 +110,10 @@ static reloc_howto_type elf_d10v_howto_table[] = HOWTO (R_D10V_18_PCREL, /* Type. */ 2, /* Rightshift. */ 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 15, /* Bitsize. */ + 16, /* Bitsize. */ TRUE, /* PC_relative. */ 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain_on_overflow. */ + complain_overflow_signed, /* Complain_on_overflow. */ bfd_elf_generic_reloc, /* Special_function. */ "R_D10V_18_PCREL", /* Name. */ FALSE, /* Partial_inplace. */ diff --git a/bfd/reloc.c b/bfd/reloc.c index d964f1656c1..d5277c0906a 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -255,11 +255,12 @@ CODE_FRAGMENT . {* Do not complain on overflow. *} . complain_overflow_dont, . -. {* Complain if the bitfield overflows, whether it is considered -. as signed or unsigned. *} +. {* Complain if the value overflows when considered as a signed +. number one bit larger than the field. ie. A bitfield of N bits +. is allowed to represent -2**n to 2**n-1. *} . complain_overflow_bitfield, . -. {* Complain if the value overflows when considered as signed +. {* Complain if the value overflows when considered as a signed . number. *} . complain_overflow_signed, . @@ -496,14 +497,14 @@ bfd_check_overflow (enum complain_overflow how, bfd_vma fieldmask, addrmask, signmask, ss, a; bfd_reloc_status_type flag = bfd_reloc_ok; - a = relocation; - /* Note: BITSIZE should always be <= ADDRSIZE, but in case it's not, we'll be permissive: extra bits in the field mask will automatically extend the address mask for purposes of the overflow check. */ fieldmask = N_ONES (bitsize); + signmask = ~fieldmask; addrmask = N_ONES (addrsize) | fieldmask; + a = (relocation & addrmask) >> rightshift;; switch (how) { @@ -513,19 +514,8 @@ bfd_check_overflow (enum complain_overflow how, case complain_overflow_signed: /* If any sign bits are set, all sign bits must be set. That is, A must be a valid negative address after shifting. */ - a = (a & addrmask) >> rightshift; signmask = ~ (fieldmask >> 1); - ss = a & signmask; - if (ss != 0 && ss != ((addrmask >> rightshift) & signmask)) - flag = bfd_reloc_overflow; - break; - - case complain_overflow_unsigned: - /* We have an overflow if the address does not fit in the field. */ - a = (a & addrmask) >> rightshift; - if ((a & ~ fieldmask) != 0) - flag = bfd_reloc_overflow; - break; + /* Fall thru */ case complain_overflow_bitfield: /* Bitfields are sometimes signed, sometimes unsigned. We @@ -533,9 +523,14 @@ bfd_check_overflow (enum complain_overflow how, of n bits is allowed to store -2**n to 2**n-1. Thus overflow if the value has some, but not all, bits set outside the field. */ - a >>= rightshift; - ss = a & ~ fieldmask; - if (ss != 0 && ss != (((bfd_vma) -1 >> rightshift) & ~ fieldmask)) + ss = a & signmask; + if (ss != 0 && ss != ((addrmask >> rightshift) & signmask)) + flag = bfd_reloc_overflow; + break; + + case complain_overflow_unsigned: + /* We have an overflow if the address does not fit in the field. */ + if ((a & signmask) != 0) flag = bfd_reloc_overflow; break; @@ -1437,19 +1432,26 @@ _bfd_relocate_contents (reloc_howto_type *howto, the size of an address. For bitfields, all the bits matter. See also bfd_check_overflow. */ fieldmask = N_ONES (howto->bitsize); + signmask = ~fieldmask; addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask; - a = relocation; - b = x & howto->src_mask; + a = (relocation & addrmask) >> rightshift; + b = (x & howto->src_mask & addrmask) >> bitpos; switch (howto->complain_on_overflow) { case complain_overflow_signed: - a = (a & addrmask) >> rightshift; - /* If any sign bits are set, all sign bits must be set. That is, A must be a valid negative address after shifting. */ - signmask = ~ (fieldmask >> 1); + signmask = ~(fieldmask >> 1); + /* Fall thru */ + + case complain_overflow_bitfield: + /* Much like the signed check, but for a field one bit + wider. We allow a bitfield to represent numbers in the + range -2**n to 2**n-1, where n is the number of bits in the + field. Note that when bfd_vma is 32 bits, a 32-bit reloc + can't overflow, which is exactly what we want. */ ss = a & signmask; if (ss != 0 && ss != ((addrmask >> rightshift) & signmask)) flag = bfd_reloc_overflow; @@ -1460,12 +1462,11 @@ _bfd_relocate_contents (reloc_howto_type *howto, SRC_MASK has more bits than BITSIZE, we can get into trouble; we would need to verify that B is in range, as we do for A above. */ - signmask = ((~ howto->src_mask) >> 1) & howto->src_mask; + ss = ((~howto->src_mask) >> 1) & howto->src_mask; + ss >>= bitpos; /* Set all the bits above the sign bit. */ - b = (b ^ signmask) - signmask; - - b = (b & addrmask) >> bitpos; + b = (b ^ ss) - ss; /* Now we can do the addition. */ sum = a + b; @@ -1477,11 +1478,14 @@ _bfd_relocate_contents (reloc_howto_type *howto, positive inputs. The test below looks only at the sign bits, and it really just SIGN (A) == SIGN (B) && SIGN (A) != SIGN (SUM) - */ - signmask = (fieldmask >> 1) + 1; - if (((~ (a ^ b)) & (a ^ sum)) & signmask) - flag = bfd_reloc_overflow; + We mask with addrmask here to explicitly allow an address + wrap-around. The Linux kernel relies on it, and it is + the only way to write assembler code which can run when + loaded at a location 0x80000000 away from the location at + which it is linked. */ + if (((~(a ^ b)) & (a ^ sum)) & signmask & addrmask) + flag = bfd_reloc_overflow; break; case complain_overflow_unsigned: @@ -1496,44 +1500,9 @@ _bfd_relocate_contents (reloc_howto_type *howto, separate test, we can check for this by or-ing in the operands when testing for the sum overflowing its final field. */ - a = (a & addrmask) >> rightshift; - b = (b & addrmask) >> bitpos; sum = (a + b) & addrmask; - if ((a | b | sum) & ~ fieldmask) - flag = bfd_reloc_overflow; - - break; - - case complain_overflow_bitfield: - /* Much like the signed check, but for a field one bit - wider, and no trimming inputs with addrmask. We allow a - bitfield to represent numbers in the range -2**n to - 2**n-1, where n is the number of bits in the field. - Note that when bfd_vma is 32 bits, a 32-bit reloc can't - overflow, which is exactly what we want. */ - a >>= rightshift; - - signmask = ~ fieldmask; - ss = a & signmask; - if (ss != 0 && ss != (((bfd_vma) -1 >> rightshift) & signmask)) + if ((a | b | sum) & signmask) flag = bfd_reloc_overflow; - - signmask = ((~ howto->src_mask) >> 1) & howto->src_mask; - b = (b ^ signmask) - signmask; - - b >>= bitpos; - - sum = a + b; - - /* We mask with addrmask here to explicitly allow an address - wrap-around. The Linux kernel relies on it, and it is - the only way to write assembler code which can run when - loaded at a location 0x80000000 away from the location at - which it is linked. */ - signmask = fieldmask + 1; - if (((~ (a ^ b)) & (a ^ sum)) & signmask & addrmask) - flag = bfd_reloc_overflow; - break; default: @@ -4625,7 +4594,7 @@ bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code) } static reloc_howto_type bfd_howto_32 = -HOWTO (0, 00, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "VRT32", FALSE, 0xffffffff, 0xffffffff, TRUE); +HOWTO (0, 00, 2, 32, FALSE, 0, complain_overflow_dont, 0, "VRT32", FALSE, 0xffffffff, 0xffffffff, TRUE); /* INTERNAL_FUNCTION -- 2.30.2