From 706704c88344314646e4edcc0840cb18a9cb4c82 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Tue, 21 Aug 2018 11:54:29 +0930 Subject: [PATCH] Pack reloc_howto_struct This patch uses bitfields in reloc_howto_struct, reducing its size from 80 to 40 bytes on 64-bit hosts and from 52 to 32 bytes on 32-bit hosts (with a 32-bit bfd_vma). I've also added a new "negate" field rather than making the encoded "size" field do double duty as both a size and a flag. There was just one use of an encoded size of 8, which according to bfd_get_reloc_size meant 16 bytes, in vms-alpha.c ALPHA_R_LINKAGE. See git commit c3d8e071bf adding ALPHA_R_LINKAGE and git commit 8612a388f7 decoding size 8 in bfd_get_reloc_size. Since no other part of BFD handles 16 byte relocs, I've removed that encoding and special cased the ALPHA_R_LINKAGE size in vms-alpha.c. * reloc.c (reloc_howto_type): Typedef. (bfd_symbol): Delete forward declaration. (struct reloc_howto_struct): Add "negate" field. Make "size", "bitsize", "rightshift", "bitpos", "complain_on_overflow", "pc_relative", "partial_inplace", and "pcrel_offset" bitfields. Rearrange for better packing. Revise comments. (HOWTO): Map to rearranged reloc_howto_struct. (bfd_get_reloc_size): Delete now unused cases. (read_reloc, write_reloc): Likewise. (apply_reloc, _bfd_relocate_contents): Test howto->negate rather than howto->size < 0 for negated relocation values. * coff-rs6000.c (xcoff_complain_overflow_bitfield_func): Avoid signed/unsigned warning. (xcoff_ppc_relocate_section): Delete "condition is always false" code. * coff64-rs6000.c (xcoff64_ppc_relocate_section): Likewise. * cpu-ns32k.c (do_ns32k_reloc): Adjust to suit reloc_howto_struct changes. * vms-alpha.c (_bfd_vms_write_etir, alpha_vms_slurp_relocs): Use size 16 for ALPHA_R_LINKAGE. (alpha_howto_table ): Set encoded size and bitsize to zero. * bfd-in.h (reloc_howto_type): Delete. * bfd-in2.h: Regenerate. --- bfd/ChangeLog | 27 +++++++++++ bfd/bfd-in.h | 3 -- bfd/bfd-in2.h | 96 +++++++++++++++++++------------------- bfd/coff-rs6000.c | 6 +-- bfd/coff64-rs6000.c | 4 -- bfd/cpu-ns32k.c | 11 ++--- bfd/reloc.c | 110 ++++++++++++++++++++------------------------ bfd/vms-alpha.c | 12 +++-- 8 files changed, 138 insertions(+), 131 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f6dfda92b06..b51507862df 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,30 @@ +2018-08-21 Alan Modra + + * reloc.c (reloc_howto_type): Typedef. + (bfd_symbol): Delete forward declaration. + (struct reloc_howto_struct): Add "negate" field. Make "size", + "bitsize", "rightshift", "bitpos", "complain_on_overflow", + "pc_relative", "partial_inplace", and "pcrel_offset" bitfields. + Rearrange for better packing. Revise comments. + (HOWTO): Map to rearranged reloc_howto_struct. + (bfd_get_reloc_size): Delete now unused cases. + (read_reloc, write_reloc): Likewise. + (apply_reloc, _bfd_relocate_contents): Test howto->negate + rather than howto->size < 0 for negated relocation values. + * coff-rs6000.c (xcoff_complain_overflow_bitfield_func): Avoid + signed/unsigned warning. + (xcoff_ppc_relocate_section): Delete "condition is always false" + code. + * coff64-rs6000.c (xcoff64_ppc_relocate_section): Likewise. + * cpu-ns32k.c (do_ns32k_reloc): Adjust to suit reloc_howto_struct + changes. + * vms-alpha.c (_bfd_vms_write_etir, alpha_vms_slurp_relocs): Use + size 16 for ALPHA_R_LINKAGE. + (alpha_howto_table ): Set encoded size and + bitsize to zero. + * bfd-in.h (reloc_howto_type): Delete. + * bfd-in2.h: Regenerate. + 2018-08-21 Alan Modra * reloc.c (HOWTO): Revise comment. diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index f00625d832e..47b60bcfbff 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -234,9 +234,6 @@ bfd_format; /* A count of carsyms (canonical archive symbols). */ typedef unsigned long symindex; -/* How to perform a relocation. */ -typedef const struct reloc_howto_struct reloc_howto_type; - #define BFD_NO_MORE_SYMBOLS ((symindex) ~0) /* General purpose part of a symbol X; diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 617f2c9e04d..46a085f29bf 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -241,9 +241,6 @@ bfd_format; /* A count of carsyms (canonical archive symbols). */ typedef unsigned long symindex; -/* How to perform a relocation. */ -typedef const struct reloc_howto_struct reloc_howto_type; - #define BFD_NO_MORE_SYMBOLS ((symindex) ~0) /* General purpose part of a symbol X; @@ -2535,6 +2532,7 @@ typedef enum bfd_reloc_status } bfd_reloc_status_type; +typedef const struct reloc_howto_struct reloc_howto_type; typedef struct reloc_cache_entry { @@ -2572,51 +2570,39 @@ enum complain_overflow unsigned number. */ complain_overflow_unsigned }; -struct bfd_symbol; /* Forward declaration. */ - struct reloc_howto_struct { - /* The type field has mainly a documentary use - the back end can - do what it wants with it, though normally the back end's - external idea of what a reloc number is stored - in this field. For example, a PC relative word relocation - in a coff environment has the type 023 - because that's - what the outside world calls a R_PCRWORD reloc. */ + /* The type field has mainly a documentary use - the back end can + do what it wants with it, though normally the back end's idea of + an external reloc number is stored in this field. */ unsigned int type; - /* The value the final relocation is shifted right by. This drops - unwanted data from the relocation. */ - unsigned int rightshift; + /* The encoded size of the item to be relocated. This is *not* a + power-of-two measure. Use bfd_get_reloc_size to find the size + of the item in bytes. */ + unsigned int size:3; - /* The size of the item to be relocated. This is *not* a - power-of-two measure. To get the number of bytes operated - on by a type of relocation, use bfd_get_reloc_size. */ - int size; + /* The number of bits in the field to be relocated. This is used + when doing overflow checking. */ + unsigned int bitsize:7; - /* The number of bits in the item to be relocated. This is used - when doing overflow checking. */ - unsigned int bitsize; + /* The value the final relocation is shifted right by. This drops + unwanted data from the relocation. */ + unsigned int rightshift:6; - /* The relocation is relative to the field being relocated. */ - bfd_boolean pc_relative; - - /* The bit position of the reloc value in the destination. - The relocated value is left shifted by this amount. */ - unsigned int bitpos; + /* The bit position of the reloc value in the destination. + The relocated value is left shifted by this amount. */ + unsigned int bitpos:6; /* What type of overflow error should be checked for when relocating. */ - enum complain_overflow complain_on_overflow; + ENUM_BITFIELD (complain_overflow) complain_on_overflow:2; - /* If this field is non null, then the supplied function is - called rather than the normal function. This allows really - strange relocation methods to be accommodated. */ - bfd_reloc_status_type (*special_function) - (bfd *, arelent *, struct bfd_symbol *, void *, asection *, - bfd *, char **); + /* The relocation value should be negated before applying. */ + unsigned int negate:1; - /* The textual name of the relocation type. */ - char *name; + /* The relocation is relative to the item being relocated. */ + unsigned int pc_relative:1; /* Some formats record a relocation addend in the section contents rather than with the relocation. For ELF formats this is the @@ -2633,33 +2619,45 @@ struct reloc_howto_struct USE_REL targets set this field to TRUE. Why this is so is peculiar to each particular target. For relocs that aren't used in partial links (e.g. GOT stuff) it doesn't matter what this is set to. */ - bfd_boolean partial_inplace; + unsigned int partial_inplace:1; + + /* When some formats create PC relative instructions, they leave + the value of the pc of the place being relocated in the offset + slot of the instruction, so that a PC relative relocation can + be made just by adding in an ordinary offset (e.g., sun3 a.out). + Some formats leave the displacement part of an instruction + empty (e.g., ELF); this flag signals the fact. */ + unsigned int pcrel_offset:1; /* src_mask selects the part of the instruction (or data) to be used in the relocation sum. If the target relocations don't have an addend in the reloc, eg. ELF USE_REL, src_mask will normally equal dst_mask to extract the addend from the section contents. If relocations do have an addend in the reloc, eg. ELF USE_RELA, this - field should be zero. Non-zero values for ELF USE_RELA targets are - bogus as in those cases the value in the dst_mask part of the - section contents should be treated as garbage. */ + field should normally be zero. Non-zero values for ELF USE_RELA + targets should be viewed with suspicion as normally the value in + the dst_mask part of the section contents should be ignored. */ bfd_vma src_mask; /* dst_mask selects which parts of the instruction (or data) are replaced with a relocated value. */ bfd_vma dst_mask; - /* When some formats create PC relative instructions, they leave - the value of the pc of the place being relocated in the offset - slot of the instruction, so that a PC relative relocation can - be made just by adding in an ordinary offset (e.g., sun3 a.out). - Some formats leave the displacement part of an instruction - empty (e.g., ELF); this flag signals the fact. */ - bfd_boolean pcrel_offset; + /* If this field is non null, then the supplied function is + called rather than the normal function. This allows really + strange relocation methods to be accommodated. */ + bfd_reloc_status_type (*special_function) + (bfd *, arelent *, struct bfd_symbol *, void *, asection *, + bfd *, char **); + + /* The textual name of the relocation type. */ + char *name; }; -#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ - { (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC } +#define HOWTO(type, right, size, bits, pcrel, left, ovf, func, name, \ + inplace, src_mask, dst_mask, pcrel_off) \ + { (unsigned) type, size < 0 ? -size : size, bits, right, left, ovf, \ + size < 0, pcrel, inplace, pcrel_off, src_mask, dst_mask, func, name } #define EMPTY_HOWTO(C) \ HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \ NULL, FALSE, 0, 0, FALSE) diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c index ab282dfef02..edff50daaaf 100644 --- a/bfd/coff-rs6000.c +++ b/bfd/coff-rs6000.c @@ -3090,7 +3090,7 @@ xcoff_complain_overflow_bitfield_func (bfd *input_bfd, 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 (howto->bitsize + howto->rightshift + if ((unsigned) howto->bitsize + howto->rightshift == bfd_arch_bits_per_address (input_bfd)) return FALSE; @@ -3458,10 +3458,6 @@ xcoff_ppc_relocate_section (bfd *output_bfd, operation, which would be tedious, or we must do the computations in a type larger than bfd_vma, which would be inefficient. */ - if ((unsigned int) howto.complain_on_overflow - >= XCOFF_MAX_COMPLAIN_OVERFLOW) - abort (); - if (((*xcoff_complain_overflow[howto.complain_on_overflow]) (input_bfd, value_to_relocate, relocation, &howto))) { diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c index 2135001f191..928a23d4f88 100644 --- a/bfd/coff64-rs6000.c +++ b/bfd/coff64-rs6000.c @@ -1306,10 +1306,6 @@ xcoff64_ppc_relocate_section (bfd *output_bfd, operation, which would be tedious, or we must do the computations in a type larger than bfd_vma, which would be inefficient. */ - if ((unsigned int) howto.complain_on_overflow - >= XCOFF_MAX_COMPLAIN_OVERFLOW) - abort (); - if (((*xcoff_complain_overflow[howto.complain_on_overflow]) (input_bfd, value_to_relocate, relocation, &howto))) { diff --git a/bfd/cpu-ns32k.c b/bfd/cpu-ns32k.c index 2eef0ba7bbe..436cba4c414 100644 --- a/bfd/cpu-ns32k.c +++ b/bfd/cpu-ns32k.c @@ -501,6 +501,9 @@ do_ns32k_reloc (bfd * abfd, ----------------------- R R R R R R R R R R put into bfd_put. */ + if (howto->negate) + relocation = -relocation; + #define DOIT(x) \ x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) @@ -531,14 +534,6 @@ do_ns32k_reloc (bfd * abfd, put_data ((bfd_vma) x, location, 4); } break; - case -2: - { - bfd_vma x = get_data (location, 4); - relocation = -relocation; - DOIT(x); - put_data ((bfd_vma) x, location, 4); - } - break; case 3: /* Do nothing. */ diff --git a/bfd/reloc.c b/bfd/reloc.c index ec58a7e4af9..0dcf2be9a02 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -94,6 +94,7 @@ CODE_FRAGMENT . } . bfd_reloc_status_type; . +.typedef const struct reloc_howto_struct reloc_howto_type; . .typedef struct reloc_cache_entry .{ @@ -279,51 +280,39 @@ SUBSUBSECTION information that libbfd needs to know to tie up a back end's data. CODE_FRAGMENT -.struct bfd_symbol; {* Forward declaration. *} -. .struct reloc_howto_struct .{ -. {* The type field has mainly a documentary use - the back end can -. do what it wants with it, though normally the back end's -. external idea of what a reloc number is stored -. in this field. For example, a PC relative word relocation -. in a coff environment has the type 023 - because that's -. what the outside world calls a R_PCRWORD reloc. *} +. {* The type field has mainly a documentary use - the back end can +. do what it wants with it, though normally the back end's idea of +. an external reloc number is stored in this field. *} . unsigned int type; . -. {* The value the final relocation is shifted right by. This drops -. unwanted data from the relocation. *} -. unsigned int rightshift; -. -. {* The size of the item to be relocated. This is *not* a -. power-of-two measure. To get the number of bytes operated -. on by a type of relocation, use bfd_get_reloc_size. *} -. int size; +. {* The encoded size of the item to be relocated. This is *not* a +. power-of-two measure. Use bfd_get_reloc_size to find the size +. of the item in bytes. *} +. unsigned int size:3; . -. {* The number of bits in the item to be relocated. This is used -. when doing overflow checking. *} -. unsigned int bitsize; +. {* The number of bits in the field to be relocated. This is used +. when doing overflow checking. *} +. unsigned int bitsize:7; . -. {* The relocation is relative to the field being relocated. *} -. bfd_boolean pc_relative; +. {* The value the final relocation is shifted right by. This drops +. unwanted data from the relocation. *} +. unsigned int rightshift:6; . -. {* The bit position of the reloc value in the destination. -. The relocated value is left shifted by this amount. *} -. unsigned int bitpos; +. {* The bit position of the reloc value in the destination. +. The relocated value is left shifted by this amount. *} +. unsigned int bitpos:6; . . {* What type of overflow error should be checked for when . relocating. *} -. enum complain_overflow complain_on_overflow; +. ENUM_BITFIELD (complain_overflow) complain_on_overflow:2; . -. {* If this field is non null, then the supplied function is -. called rather than the normal function. This allows really -. strange relocation methods to be accommodated. *} -. bfd_reloc_status_type (*special_function) -. (bfd *, arelent *, struct bfd_symbol *, void *, asection *, -. bfd *, char **); +. {* The relocation value should be negated before applying. *} +. unsigned int negate:1; . -. {* The textual name of the relocation type. *} -. char *name; +. {* The relocation is relative to the item being relocated. *} +. unsigned int pc_relative:1; . . {* Some formats record a relocation addend in the section contents . rather than with the relocation. For ELF formats this is the @@ -340,29 +329,39 @@ CODE_FRAGMENT . USE_REL targets set this field to TRUE. Why this is so is peculiar . to each particular target. For relocs that aren't used in partial . links (e.g. GOT stuff) it doesn't matter what this is set to. *} -. bfd_boolean partial_inplace; +. unsigned int partial_inplace:1; +. +. {* When some formats create PC relative instructions, they leave +. the value of the pc of the place being relocated in the offset +. slot of the instruction, so that a PC relative relocation can +. be made just by adding in an ordinary offset (e.g., sun3 a.out). +. Some formats leave the displacement part of an instruction +. empty (e.g., ELF); this flag signals the fact. *} +. unsigned int pcrel_offset:1; . . {* src_mask selects the part of the instruction (or data) to be used . in the relocation sum. If the target relocations don't have an . addend in the reloc, eg. ELF USE_REL, src_mask will normally equal . dst_mask to extract the addend from the section contents. If . relocations do have an addend in the reloc, eg. ELF USE_RELA, this -. field should be zero. Non-zero values for ELF USE_RELA targets are -. bogus as in those cases the value in the dst_mask part of the -. section contents should be treated as garbage. *} +. field should normally be zero. Non-zero values for ELF USE_RELA +. targets should be viewed with suspicion as normally the value in +. the dst_mask part of the section contents should be ignored. *} . bfd_vma src_mask; . . {* dst_mask selects which parts of the instruction (or data) are . replaced with a relocated value. *} . bfd_vma dst_mask; . -. {* When some formats create PC relative instructions, they leave -. the value of the pc of the place being relocated in the offset -. slot of the instruction, so that a PC relative relocation can -. be made just by adding in an ordinary offset (e.g., sun3 a.out). -. Some formats leave the displacement part of an instruction -. empty (e.g., ELF); this flag signals the fact. *} -. bfd_boolean pcrel_offset; +. {* If this field is non null, then the supplied function is +. called rather than the normal function. This allows really +. strange relocation methods to be accommodated. *} +. bfd_reloc_status_type (*special_function) +. (bfd *, arelent *, struct bfd_symbol *, void *, asection *, +. bfd *, char **); +. +. {* The textual name of the relocation type. *} +. char *name; .}; . */ @@ -375,8 +374,10 @@ DESCRIPTION The HOWTO macro fills in a reloc_howto_type (a typedef for const struct reloc_howto_struct). -.#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ -. { (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC } +.#define HOWTO(type, right, size, bits, pcrel, left, ovf, func, name, \ +. inplace, src_mask, dst_mask, pcrel_off) \ +. { (unsigned) type, size < 0 ? -size : size, bits, right, left, ovf, \ +. size < 0, pcrel, inplace, pcrel_off, src_mask, dst_mask, func, name } DESCRIPTION This is used to fill in an empty howto entry in an array. @@ -405,14 +406,11 @@ bfd_get_reloc_size (reloc_howto_type *howto) switch (howto->size) { case 0: return 1; - case 1: - case -1: return 2; - case 2: - case -2: return 4; + case 1: return 2; + case 2: return 4; case 3: return 0; case 4: return 8; case 5: return 3; - case 8: return 16; default: abort (); } } @@ -559,11 +557,9 @@ read_reloc (bfd *abfd, bfd_byte *data, reloc_howto_type *howto) return bfd_get_8 (abfd, data); case 1: - case -1: return bfd_get_16 (abfd, data); case 2: - case -2: return bfd_get_32 (abfd, data); case 3: @@ -596,12 +592,10 @@ write_reloc (bfd *abfd, bfd_vma val, bfd_byte *data, reloc_howto_type *howto) break; case 1: - case -1: bfd_put_16 (abfd, val, data); break; case 2: - case -2: bfd_put_32 (abfd, val, data); break; @@ -632,7 +626,7 @@ apply_reloc (bfd *abfd, bfd_byte *data, reloc_howto_type *howto, { bfd_vma val = read_reloc (abfd, data, howto); - if (howto->size < 0) + if (howto->negate) relocation = -relocation; val = ((val & ~howto->dst_mask) @@ -1391,9 +1385,7 @@ _bfd_relocate_contents (reloc_howto_type *howto, unsigned int rightshift = howto->rightshift; unsigned int bitpos = howto->bitpos; - /* If the size is negative, negate RELOCATION. This isn't very - general. */ - if (howto->size < 0) + if (howto->negate) relocation = -relocation; /* Get the value we are going to relocate. */ diff --git a/bfd/vms-alpha.c b/bfd/vms-alpha.c index fc45260e49b..8f22a31ae5d 100644 --- a/bfd/vms-alpha.c +++ b/bfd/vms-alpha.c @@ -4001,6 +4001,7 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED) break; case ALPHA_R_LINKAGE: + size = 16; etir_output_check (abfd, section, curr_addr, 64); _bfd_vms_output_begin_subrec (recwr, ETIR__C_STC_LP_PSB); _bfd_vms_output_long @@ -5157,6 +5158,7 @@ alpha_vms_slurp_relocs (bfd *abfd) asection *sec; struct vms_section_data_struct *vms_sec; arelent *reloc; + bfd_size_type size; /* Get section to which the relocation applies. */ if (cur_psect < 0 || cur_psect > (int)PRIV (section_count)) @@ -5237,7 +5239,11 @@ alpha_vms_slurp_relocs (bfd *abfd) reloc->address = cur_address; reloc->addend = cur_addend; - vaddr += bfd_get_reloc_size (reloc->howto); + if (reloc_code == ALPHA_R_LINKAGE) + size = 16; + else + size = bfd_get_reloc_size (reloc->howto); + vaddr += size; } cur_addend = 0; @@ -5496,8 +5502,8 @@ static reloc_howto_type alpha_howto_table[] = /* Hack. Linkage is done by linker. */ HOWTO (ALPHA_R_LINKAGE, /* Type. */ 0, /* Rightshift. */ - 8, /* Size (0 = byte, 1 = short, 2 = long). */ - 256, /* Bitsize. */ + 0, /* Size (0 = byte, 1 = short, 2 = long). */ + 0, /* Bitsize. */ FALSE, /* PC relative. */ 0, /* Bitpos. */ complain_overflow_dont,/* Complain_on_overflow. */ -- 2.30.2