X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-arc.c;h=33fff585e404b6e47178201195782a4516125443;hb=1678bd35a35a3bace2d4aee39b64d96c638651f0;hp=22aca81e1e078a8106dece477ec5c86cd5b9a59d;hpb=8a36df4dcfa3cb89779e1a3eaca8067426e9cad6;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-arc.c b/bfd/elf32-arc.c index 22aca81e1e..33fff585e4 100644 --- a/bfd/elf32-arc.c +++ b/bfd/elf32-arc.c @@ -1,5 +1,5 @@ /* ARC-specific support for 32-bit ELF - Copyright (C) 1994-2016 Free Software Foundation, Inc. + Copyright (C) 1994-2018 Free Software Foundation, Inc. Contributed by Cupertino Miranda (cmiranda@synopsys.com). This file is part of BFD, the Binary File Descriptor library. @@ -29,6 +29,10 @@ #include "opcode/arc.h" #include "arc-plt.h" +#define FEATURE_LIST_NAME bfd_feature_list +#define CONFLICT_LIST bfd_conflict_list +#include "opcode/arc-attrs.h" + /* #define ARC_ENABLE_DEBUG 1 */ #ifdef ARC_ENABLE_DEBUG static const char * @@ -51,52 +55,22 @@ name_for_global_symbol (struct elf_link_hash_entry *h) Elf_Internal_Rela _rel; \ bfd_byte * _loc; \ \ - BFD_ASSERT (_htab->srel##SECTION &&_htab->srel##SECTION->contents); \ - _loc = _htab->srel##SECTION->contents \ - + ((_htab->srel##SECTION->reloc_count) \ - * sizeof (Elf32_External_Rela)); \ - _htab->srel##SECTION->reloc_count++; \ - _rel.r_addend = ADDEND; \ - _rel.r_offset = (_htab->s##SECTION)->output_section->vma \ - + (_htab->s##SECTION)->output_offset + OFFSET; \ - BFD_ASSERT ((long) SYM_IDX != -1); \ - _rel.r_info = ELF32_R_INFO (SYM_IDX, TYPE); \ - bfd_elf32_swap_reloca_out (BFD, &_rel, _loc); \ + if (_htab->dynamic_sections_created == TRUE) \ + { \ + BFD_ASSERT (_htab->srel##SECTION &&_htab->srel##SECTION->contents); \ + _loc = _htab->srel##SECTION->contents \ + + ((_htab->srel##SECTION->reloc_count) \ + * sizeof (Elf32_External_Rela)); \ + _htab->srel##SECTION->reloc_count++; \ + _rel.r_addend = ADDEND; \ + _rel.r_offset = (_htab->s##SECTION)->output_section->vma \ + + (_htab->s##SECTION)->output_offset + OFFSET; \ + BFD_ASSERT ((long) SYM_IDX != -1); \ + _rel.r_info = ELF32_R_INFO (SYM_IDX, TYPE); \ + bfd_elf32_swap_reloca_out (BFD, &_rel, _loc); \ + } \ } -struct dynamic_sections -{ - bfd_boolean initialized; - asection * sgot; - asection * srelgot; - asection * sgotplt; - asection * srelgotplt; - asection * sdyn; - asection * splt; - asection * srelplt; -}; - -enum dyn_section_types -{ - got = 0, - relgot, - gotplt, - dyn, - plt, - relplt, - DYN_SECTION_TYPES_END -}; - -const char * dyn_section_names[DYN_SECTION_TYPES_END] = -{ - ".got", - ".rela.got", - ".got.plt", - ".dynamic", - ".plt", - ".rela.plt" -}; - /* The default symbols representing the init and fini dyn values. TODO: Check what is the relation of those strings with arclinux.em @@ -124,6 +98,7 @@ reloc_type_to_name (unsigned int type) break; } } + #undef ARC_RELOC_HOWTO /* Try to minimize the amount of space occupied by relocation tables @@ -186,7 +161,7 @@ struct arc_relocation_data }; /* Should be included at this location due to static declarations - * defined before this point. */ + defined before this point. */ #include "arc-got.h" #define arc_bfd_get_8(A,B,C) bfd_get_8(A,B) @@ -225,11 +200,13 @@ arc_elf_reloc (bfd *abfd ATTRIBUTE_UNUSED, #define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ TYPE = VALUE, + enum howto_list { #include "elf/arc-reloc.def" HOWTO_LIST_LAST }; + #undef ARC_RELOC_HOWTO #define ARC_RELOC_HOWTO(TYPE, VALUE, RSIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ @@ -259,16 +236,17 @@ static struct reloc_howto_struct elf_arc_howto_table[] = }; #undef ARC_RELOC_HOWTO -static void arc_elf_howto_init (void) +static void +arc_elf_howto_init (void) { #define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ - elf_arc_howto_table[TYPE].pc_relative = \ + elf_arc_howto_table[TYPE].pc_relative = \ (strstr (#FORMULA, " P ") != NULL || strstr (#FORMULA, " PDATA ") != NULL); \ - elf_arc_howto_table[TYPE].dst_mask = RELOC_FUNCTION(0, ~0); \ - /* Only 32 bit data relocations should be marked as ME. */ \ - if (strstr (#FORMULA, " ME ") != NULL) \ - { \ - BFD_ASSERT (SIZE == 2); \ + elf_arc_howto_table[TYPE].dst_mask = RELOC_FUNCTION(0, ~0); \ + /* Only 32 bit data relocations should be marked as ME. */ \ + if (strstr (#FORMULA, " ME ") != NULL) \ + { \ + BFD_ASSERT (SIZE == 2); \ } #include "elf/arc-reloc.def" @@ -279,10 +257,12 @@ static void arc_elf_howto_init (void) #define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ [TYPE] = VALUE, + const int howto_table_lookup[] = { #include "elf/arc-reloc.def" }; + #undef ARC_RELOC_HOWTO static reloc_howto_type * @@ -314,9 +294,6 @@ struct elf_arc_link_hash_entry struct elf_arc_link_hash_table { struct elf_link_hash_table elf; - - /* Short-cuts to get to dynamic linker sections. */ - asection *srelbss; }; static struct bfd_hash_entry * @@ -375,8 +352,6 @@ arc_elf_link_hash_table_create (bfd *abfd) return NULL; } - ret->srelbss = NULL; - ret->elf.init_got_refcount.refcount = 0; ret->elf.init_got_refcount.glist = NULL; ret->elf.init_got_offset.offset = 0; @@ -389,6 +364,7 @@ arc_elf_link_hash_table_create (bfd *abfd) #define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ { BFD_RELOC_##TYPE, R_##TYPE }, + static const struct arc_reloc_map arc_reloc_map[] = { #include "elf/arc-reloc.def" @@ -399,6 +375,7 @@ static const struct arc_reloc_map arc_reloc_map[] = {BFD_RELOC_24, R_ARC_24}, {BFD_RELOC_32, R_ARC_32}, }; + #undef ARC_RELOC_HOWTO typedef ATTRIBUTE_UNUSED bfd_vma (*replace_func) (unsigned, int ATTRIBUTE_UNUSED); @@ -407,6 +384,7 @@ typedef ATTRIBUTE_UNUSED bfd_vma (*replace_func) (unsigned, int ATTRIBUTE_UNUSED case TYPE: \ func = (void *) RELOC_FUNCTION; \ break; + static replace_func get_replace_function (bfd *abfd, unsigned int r_type) { @@ -418,7 +396,7 @@ get_replace_function (bfd *abfd, unsigned int r_type) } if (func == replace_bits24 && bfd_big_endian (abfd)) - return (replace_func) replace_bits24_be; + func = replace_bits24_be; return (replace_func) func; } @@ -480,8 +458,9 @@ arc_elf_print_private_bfd_data (bfd *abfd, void * ptr) case E_ARC_OSABI_ORIG : fprintf (file, " (ABI:legacy)"); break; case E_ARC_OSABI_V2 : fprintf (file, " (ABI:v2)"); break; case E_ARC_OSABI_V3 : fprintf (file, " (ABI:v3)"); break; + case E_ARC_OSABI_V4 : fprintf (file, " (ABI:v4)"); break; default: - fprintf (file, "(ABI:unknown)"); + fprintf (file, " (ABI:unknown)"); break; } @@ -526,24 +505,333 @@ bfd_elf32_bfd_reloc_name_lookup (bfd * abfd ATTRIBUTE_UNUSED, /* Set the howto pointer for an ARC ELF reloc. */ -static void -arc_info_to_howto_rel (bfd * abfd ATTRIBUTE_UNUSED, +static bfd_boolean +arc_info_to_howto_rel (bfd * abfd, arelent * cache_ptr, Elf_Internal_Rela * dst) { unsigned int r_type; r_type = ELF32_R_TYPE (dst->r_info); - BFD_ASSERT (r_type < (unsigned int) R_ARC_max); + if (r_type >= (unsigned int) R_ARC_max) + { + /* xgettext:c-format */ + _bfd_error_handler (_("%pB: unsupported relocation type %#x"), + abfd, r_type); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + cache_ptr->howto = arc_elf_howto (r_type); + return TRUE; +} + +/* Extract CPU features from an NTBS. */ + +static unsigned +arc_extract_features (const char *p) +{ + unsigned i, r = 0; + + if (!p) + return 0; + + for (i = 0; i < ARRAY_SIZE (bfd_feature_list); i++) + { + char *t = strstr (p, bfd_feature_list[i].attr); + unsigned l = strlen (bfd_feature_list[i].attr); + if ((t != NULL) + && (t[l] == ',' + || t[l] == '\0')) + r |= bfd_feature_list[i].feature; + } + + return r; +} + +/* Concatenate two strings. s1 can be NULL but not + s2. */ + +static char * +arc_stralloc (char * s1, const char * s2) +{ + char *p; + + /* Only s1 can be null. */ + BFD_ASSERT (s2); + + p = s1 ? concat (s1, ",", s2, NULL) : (char *)s2; + + return p; +} + +/* Merge ARC object attributes from IBFD into OBFD. Raise an error if + there are conflicting attributes. */ + +static bfd_boolean +arc_elf_merge_attributes (bfd *ibfd, struct bfd_link_info *info) +{ + bfd *obfd = info->output_bfd; + obj_attribute *in_attr; + obj_attribute *out_attr; + int i; + bfd_boolean result = TRUE; + const char *sec_name = get_elf_backend_data (ibfd)->obj_attrs_section; + char *tagname = NULL; + + /* Skip the linker stubs file. This preserves previous behavior + of accepting unknown attributes in the first input file - but + is that a bug? */ + if (ibfd->flags & BFD_LINKER_CREATED) + return TRUE; + + /* Skip any input that hasn't attribute section. + This enables to link object files without attribute section with + any others. */ + if (bfd_get_section_by_name (ibfd, sec_name) == NULL) + return TRUE; + + if (!elf_known_obj_attributes_proc (obfd)[0].i) + { + /* This is the first object. Copy the attributes. */ + _bfd_elf_copy_obj_attributes (ibfd, obfd); + + out_attr = elf_known_obj_attributes_proc (obfd); + + /* Use the Tag_null value to indicate the attributes have been + initialized. */ + out_attr[0].i = 1; + + return TRUE; + } + + in_attr = elf_known_obj_attributes_proc (ibfd); + out_attr = elf_known_obj_attributes_proc (obfd); + + for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) + { + /* Merge this attribute with existing attributes. */ + switch (i) + { + case Tag_ARC_PCS_config: + if (out_attr[i].i == 0) + out_attr[i].i = in_attr[i].i; + else if (in_attr[i].i != 0 && out_attr[i].i != in_attr[i].i) + { + const char *tagval[] = { "Absent", "Bare-metal/mwdt", + "Bare-metal/newlib", "Linux/uclibc", + "Linux/glibc" }; + BFD_ASSERT (in_attr[i].i < 5); + BFD_ASSERT (out_attr[i].i < 5); + /* It's sometimes ok to mix different configs, so this is only + a warning. */ + _bfd_error_handler + (_("warning: %pB: conflicting platform configuration " + "%s with %s"), ibfd, + tagval[in_attr[i].i], + tagval[out_attr[i].i]); + } + break; + + case Tag_ARC_CPU_base: + if (out_attr[i].i == 0) + out_attr[i].i = in_attr[i].i; + else if (in_attr[i].i != 0 && out_attr[i].i != in_attr[i].i + && ((out_attr[i].i + in_attr[i].i) < 6)) + { + const char *tagval[] = { "Absent", "ARC6xx", "ARC7xx", + "ARCEM", "ARCHS" }; + BFD_ASSERT (in_attr[i].i < 5); + BFD_ASSERT (out_attr[i].i < 5); + /* We cannot mix code for different CPUs. */ + _bfd_error_handler + (_("error: %pB: unable to merge CPU base attributes " + "%s with %s"), + obfd, + tagval[in_attr[i].i], + tagval[out_attr[i].i]); + result = FALSE; + break; + } + else + { + /* The CPUs may be different, check if we can still mix + the objects against the output choosen CPU. */ + unsigned in_feature = 0; + unsigned out_feature = 0; + char *p1 = in_attr[Tag_ARC_ISA_config].s; + char *p2 = out_attr[Tag_ARC_ISA_config].s; + unsigned j; + unsigned cpu_out; + unsigned opcode_map[] = {0, ARC_OPCODE_ARC600, ARC_OPCODE_ARC700, + ARC_OPCODE_ARCv2EM, ARC_OPCODE_ARCv2HS}; + + BFD_ASSERT (in_attr[i].i < (sizeof (opcode_map) + / sizeof (unsigned))); + BFD_ASSERT (out_attr[i].i < (sizeof (opcode_map) + / sizeof (unsigned))); + cpu_out = opcode_map[out_attr[i].i]; + + in_feature = arc_extract_features (p1); + out_feature = arc_extract_features (p2); + + /* First, check if a feature is compatible with the + output object chosen CPU. */ + for (j = 0; j < ARRAY_SIZE (bfd_feature_list); j++) + if (((in_feature | out_feature) & bfd_feature_list[j].feature) + && (!(cpu_out & bfd_feature_list[j].cpus))) + { + _bfd_error_handler + (_("error: %pB: unable to merge ISA extension attributes " + "%s"), + obfd, bfd_feature_list[j].name); + result = FALSE; + break; + } + /* Second, if we have compatible features with the + chosen CPU, check if they are compatible among + them. */ + for (j = 0; j < ARRAY_SIZE (bfd_conflict_list); j++) + if (((in_feature | out_feature) & bfd_conflict_list[j]) + == bfd_conflict_list[j]) + { + unsigned k; + for (k = 0; k < ARRAY_SIZE (bfd_feature_list); k++) + { + if (in_feature & bfd_feature_list[k].feature + & bfd_conflict_list[j]) + p1 = (char *) bfd_feature_list[k].name; + if (out_feature & bfd_feature_list[k].feature + & bfd_conflict_list[j]) + p2 = (char *) bfd_feature_list[k].name; + } + _bfd_error_handler + (_("error: %pB: conflicting ISA extension attributes " + "%s with %s"), + obfd, p1, p2); + result = FALSE; + break; + } + /* Everithing is alright. */ + out_feature |= in_feature; + p1 = NULL; + for (j = 0; j < ARRAY_SIZE (bfd_feature_list); j++) + if (out_feature & bfd_feature_list[j].feature) + p1 = arc_stralloc (p1, bfd_feature_list[j].attr); + if (p1) + out_attr[Tag_ARC_ISA_config].s = + _bfd_elf_attr_strdup (obfd, p1); + } + /* Fall through. */ + case Tag_ARC_CPU_variation: + case Tag_ARC_ISA_mpy_option: + case Tag_ARC_ABI_osver: + /* Use the largest value specified. */ + if (in_attr[i].i > out_attr[i].i) + out_attr[i].i = in_attr[i].i; + break; + + case Tag_ARC_CPU_name: + break; + + case Tag_ARC_ABI_rf16: + if (out_attr[i].i == 0) + out_attr[i].i = in_attr[i].i; + else if (out_attr[i].i != in_attr[i].i) + { + /* We cannot mix code with rf16 and without. */ + _bfd_error_handler + (_("error: %pB: cannot mix rf16 with full register set %pB"), + obfd, ibfd); + result = FALSE; + } + break; + + case Tag_ARC_ABI_pic: + tagname = "PIC"; + /* fall through */ + case Tag_ARC_ABI_sda: + if (!tagname) + tagname = "SDA"; + /* fall through */ + case Tag_ARC_ABI_tls: + { + const char *tagval[] = { "Absent", "MWDT", "GNU" }; + + if (!tagname) + tagname = "TLS"; + + BFD_ASSERT (in_attr[i].i < 3); + BFD_ASSERT (out_attr[i].i < 3); + if (out_attr[i].i != 0 && in_attr[i].i != 0 + && out_attr[i].i != in_attr[i].i) + { + _bfd_error_handler + (_("error: %pB: conflicting attributes %s: %s with %s"), + obfd, tagname, + tagval[in_attr[i].i], + tagval[out_attr[i].i]); + result = FALSE; + } + tagname = NULL; + break; + } + + case Tag_ARC_ABI_double_size: + tagname = "Double size"; + /* fall through */ + case Tag_ARC_ABI_enumsize: + if (!tagname) + tagname = "Enum size"; + /* fall through */ + case Tag_ARC_ABI_exceptions: + if (!tagname) + tagname = "ABI exceptions"; + + if (out_attr[i].i != 0 && in_attr[i].i != 0 + && out_attr[i].i != in_attr[i].i) + { + _bfd_error_handler + (_("error: %pB: conflicting attributes %s"), + obfd, tagname); + result = FALSE; + } + break; + + case Tag_ARC_ISA_apex: + break; /* Do nothing for APEX attributes. */ + + case Tag_ARC_ISA_config: + /* It is handled in Tag_ARC_CPU_base. */ + break; + + default: + result + = result && _bfd_elf_merge_unknown_attribute_low (ibfd, obfd, i); + } + + /* If out_attr was copied from in_attr then it won't have a type yet. */ + if (in_attr[i].type && !out_attr[i].type) + out_attr[i].type = in_attr[i].type; + } + + /* Merge Tag_compatibility attributes and any common GNU ones. */ + if (!_bfd_elf_merge_object_attributes (ibfd, info)) + return FALSE; + + /* Check for any attributes not known on ARC. */ + result &= _bfd_elf_merge_unknown_attribute_list (ibfd, obfd); + + return result; } /* Merge backend specific data from an object file to the output object file when linking. */ static bfd_boolean -arc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) +arc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) { + bfd *obfd = info->output_bfd; unsigned short mach_ibfd; static unsigned short mach_obfd = EM_NONE; flagword out_flags; @@ -551,13 +839,12 @@ arc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) asection *sec; /* Check if we have the same endianess. */ - if (! _bfd_generic_verify_endian_match (ibfd, obfd)) - { - _bfd_error_handler (_("ERROR: Endian Match failed. Attempting to link " - "%B with binary %s of opposite endian-ness"), - ibfd, bfd_get_filename (obfd)); - return FALSE; - } + if (! _bfd_generic_verify_endian_match (ibfd, info)) + return FALSE; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return TRUE; /* Collect ELF flags. */ in_flags = elf_elfheader (ibfd)->e_flags & EF_ARC_MACH_MSK; @@ -569,9 +856,8 @@ arc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) out_flags = in_flags; } - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; + if (!arc_elf_merge_attributes (ibfd, info)) + return FALSE; /* Check to see if the input BFD actually contains any sections. Do not short-circuit dynamic objects; their section list may be @@ -605,24 +891,35 @@ arc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) { if (mach_ibfd != mach_obfd) { - _bfd_error_handler (_("ERROR: Attempting to link %B " - "with a binary %s of different architecture"), - ibfd, bfd_get_filename (obfd)); + /* xgettext:c-format */ + _bfd_error_handler (_("error: attempting to link %pB " + "with a binary %pB of different architecture"), + ibfd, obfd); return FALSE; } - else if (in_flags != out_flags) + else if ((in_flags != out_flags) + /* If we have object attributes, then we already + checked the objects compatibility, skip it. */ + && !bfd_elf_get_obj_attr_int (ibfd, OBJ_ATTR_PROC, + Tag_ARC_CPU_base)) { /* Warn if different flags. */ - (*_bfd_error_handler) - (_("%s: uses different e_flags (0x%lx) fields than " - "previous modules (0x%lx)"), - bfd_get_filename (ibfd), (long)in_flags, (long)out_flags); + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: uses different e_flags (%#x) fields than " + "previous modules (%#x)"), + ibfd, in_flags, out_flags); if (in_flags && out_flags) return FALSE; /* MWDT doesnt set the eflags hence make sure we choose the eflags set by gcc. */ in_flags = in_flags > out_flags ? in_flags : out_flags; } + else + { + /* Everything is correct; don't change the output flags. */ + in_flags = out_flags; + } } /* Update the flags. */ @@ -636,6 +933,30 @@ arc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) return TRUE; } +/* Return a best guess for the machine number based on the attributes. */ + +static unsigned int +bfd_arc_get_mach_from_attributes (bfd * abfd) +{ + int arch = bfd_elf_get_obj_attr_int (abfd, OBJ_ATTR_PROC, Tag_ARC_CPU_base); + unsigned e_machine = elf_elfheader (abfd)->e_machine; + + switch (arch) + { + case TAG_CPU_ARC6xx: + return bfd_mach_arc_arc600; + case TAG_CPU_ARC7xx: + return bfd_mach_arc_arc700; + case TAG_CPU_ARCEM: + case TAG_CPU_ARCHS: + return bfd_mach_arc_arcv2; + default: + break; + } + return (e_machine == EM_ARC_COMPACT) + ? bfd_mach_arc_arc700 : bfd_mach_arc_arcv2; +} + /* Set the right machine number for an ARC ELF file. */ static bfd_boolean arc_elf_object_p (bfd * abfd) @@ -643,7 +964,7 @@ arc_elf_object_p (bfd * abfd) /* Make sure this is initialised, or you'll have the potential of passing garbage---or misleading values---into the call to bfd_default_set_arch_mach (). */ - int mach = bfd_mach_arc_arc700; + unsigned int mach = bfd_mach_arc_arc700; unsigned long arch = elf_elfheader (abfd)->e_flags & EF_ARC_MACH_MSK; unsigned e_machine = elf_elfheader (abfd)->e_machine; @@ -665,8 +986,7 @@ arc_elf_object_p (bfd * abfd) mach = bfd_mach_arc_arcv2; break; default: - mach = (e_machine == EM_ARC_COMPACT) - ? bfd_mach_arc_arc700 : bfd_mach_arc_arcv2; + mach = bfd_arc_get_mach_from_attributes (abfd); break; } } @@ -674,15 +994,15 @@ arc_elf_object_p (bfd * abfd) { if (e_machine == EM_ARC) { - (*_bfd_error_handler) - (_("Error: The ARC4 architecture is no longer supported.\n")); + _bfd_error_handler + (_("error: the ARC4 architecture is no longer supported")); return FALSE; } else { - (*_bfd_error_handler) - (_("Warning: unset or old architecture flags. \n" - " Use default machine.\n")); + _bfd_error_handler + (_("warning: unset or old architecture flags; " + "use default machine")); } } @@ -697,6 +1017,9 @@ arc_elf_final_write_processing (bfd * abfd, bfd_boolean linker ATTRIBUTE_UNUSED) { unsigned long emf; + int osver = bfd_elf_get_obj_attr_int (abfd, OBJ_ATTR_PROC, + Tag_ARC_ABI_osver); + flagword e_flags = elf_elfheader (abfd)->e_flags & ~EF_ARC_OSABI_MSK; switch (bfd_get_mach (abfd)) { @@ -713,16 +1036,18 @@ arc_elf_final_write_processing (bfd * abfd, emf = EM_ARC_COMPACT2; break; default: - goto DO_NOTHING; + return; } elf_elfheader (abfd)->e_machine = emf; /* Record whatever is the current syscall ABI version. */ - elf_elfheader (abfd)->e_flags |= E_ARC_OSABI_CURRENT; + if (osver) + e_flags |= ((osver & 0x0f) << 8); + else + e_flags |= E_ARC_OSABI_V3; -DO_NOTHING: - return; + elf_elfheader (abfd)->e_flags |= e_flags; } #ifdef ARC_ENABLE_DEBUG @@ -807,26 +1132,28 @@ arc_special_overflow_checks (const struct arc_relocation_data reloc_data, if (((relocation >> 16) & 0xffff) != NPS_CMEM_HIGH_VALUE) { if (reloc_data.reloc_addend == 0) - (*_bfd_error_handler) - (_("%B(%A+0x%lx): CMEM relocation to `%s' is invalid, " - "16 MSB should be 0x%04x (value is 0x%lx)"), + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA+%#" PRIx64 "): CMEM relocation to `%s' is invalid, " + "16 MSB should be %#x (value is %#" PRIx64 ")"), reloc_data.input_section->owner, reloc_data.input_section, - reloc_data.reloc_offset, + (uint64_t) reloc_data.reloc_offset, reloc_data.symbol_name, NPS_CMEM_HIGH_VALUE, - (relocation)); + (uint64_t) relocation); else - (*_bfd_error_handler) - (_("%B(%A+0x%lx): CMEM relocation to `%s+0x%lx' is invalid, " - "16 MSB should be 0x%04x (value is 0x%lx)"), + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA+%#" PRIx64 "): CMEM relocation to `%s+%#" PRIx64 + "' is invalid, 16 MSB should be %#x (value is %#" PRIx64 ")"), reloc_data.input_section->owner, reloc_data.input_section, - reloc_data.reloc_offset, + (uint64_t) reloc_data.reloc_offset, reloc_data.symbol_name, - reloc_data.reloc_addend, + (uint64_t) reloc_data.reloc_addend, NPS_CMEM_HIGH_VALUE, - (relocation)); + (uint64_t) relocation); return bfd_reloc_overflow; } break; @@ -873,12 +1200,11 @@ arc_special_overflow_checks (const struct arc_relocation_data reloc_data, + (reloc_data.reloc_offset)))) #define SECTSTART (bfd_signed_vma) (reloc_data.sym_section->output_section->vma \ + reloc_data.sym_section->output_offset) - +#define JLI (bfd_signed_vma) (reloc_data.sym_section->output_section->vma) #define _SDA_BASE_ (bfd_signed_vma) (reloc_data.sdata_begin_symbol_vma) #define TLS_REL (bfd_signed_vma) \ ((elf_hash_table (info))->tls_sec->output_section->vma) #define TLS_TBSS (8) -#define TCB_SIZE (8) #define none (0) @@ -928,7 +1254,7 @@ arc_special_overflow_checks (const struct arc_relocation_data reloc_data, #else #define PRINT_DEBUG_RELOC_INFO_BEFORE(...) -#define PRINT_DEBUG_RELOC_INFO_AFTER +#define PRINT_DEBUG_RELOC_INFO_AFTER #endif /* ARC_ENABLE_DEBUG */ @@ -957,7 +1283,7 @@ arc_do_relocation (bfd_byte * contents, struct elf_link_hash_table *htab ATTRIBUTE_UNUSED = elf_hash_table (info); bfd_reloc_status_type flag; - if (reloc_data.should_relocate == FALSE) + if (!reloc_data.should_relocate) return bfd_reloc_ok; switch (reloc_data.howto->size) @@ -1051,6 +1377,7 @@ arc_do_relocation (bfd_byte * contents, #undef P #undef SECTSTAR #undef SECTSTART +#undef JLI #undef _SDA_BASE_ #undef none @@ -1072,20 +1399,20 @@ arc_do_relocation (bfd_byte * contents, corresponding to the st_shndx field of each local symbol. */ static bfd_boolean -elf_arc_relocate_section (bfd * output_bfd, +elf_arc_relocate_section (bfd * output_bfd, struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, + bfd * input_bfd, + asection * input_section, + bfd_byte * contents, Elf_Internal_Rela * relocs, Elf_Internal_Sym * local_syms, - asection ** local_sections) + asection ** local_sections) { - Elf_Internal_Shdr * symtab_hdr; + Elf_Internal_Shdr * symtab_hdr; struct elf_link_hash_entry ** sym_hashes; - Elf_Internal_Rela * rel; - Elf_Internal_Rela * wrel; - Elf_Internal_Rela * relend; + Elf_Internal_Rela * rel; + Elf_Internal_Rela * wrel; + Elf_Internal_Rela * relend; struct elf_link_hash_table * htab = elf_hash_table (info); symtab_hdr = &((elf_tdata (input_bfd))->symtab_hdr); @@ -1095,21 +1422,22 @@ elf_arc_relocate_section (bfd * output_bfd, relend = relocs + input_section->reloc_count; for (; rel < relend; wrel++, rel++) { - enum elf_arc_reloc_type r_type; + enum elf_arc_reloc_type r_type; reloc_howto_type * howto; unsigned long r_symndx; struct elf_link_hash_entry * h; Elf_Internal_Sym * sym; asection * sec; struct elf_link_hash_entry * h2; - const char * msg; + const char * msg; + bfd_boolean unresolved_reloc = FALSE; struct arc_relocation_data reloc_data = { .reloc_offset = 0, .reloc_addend = 0, .got_offset_value = 0, - .sym_value = 0, + .sym_value = 0, .sym_section = NULL, .howto = NULL, .input_section = NULL, @@ -1162,9 +1490,9 @@ elf_arc_relocate_section (bfd * output_bfd, h2 = elf_link_hash_lookup (elf_hash_table (info), "__SDATA_BEGIN__", FALSE, FALSE, TRUE); - if (reloc_data.sdata_begin_symbol_vma_set == FALSE - && h2 != NULL && h2->root.type != bfd_link_hash_undefined - && h2->root.u.def.section->output_section != NULL) + if (!reloc_data.sdata_begin_symbol_vma_set + && h2 != NULL && h2->root.type != bfd_link_hash_undefined + && h2->root.u.def.section->output_section != NULL) /* TODO: Verify this condition. */ { reloc_data.sdata_begin_symbol_vma = @@ -1190,6 +1518,14 @@ elf_arc_relocate_section (bfd * output_bfd, } else { + bfd_boolean warned, ignored; + bfd_vma relocation ATTRIBUTE_UNUSED; + + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sec, relocation, + unresolved_reloc, warned, ignored); + /* TODO: This code is repeated from below. We should clean it and remove duplications. Sec is used check for discarded sections. @@ -1216,7 +1552,6 @@ elf_arc_relocate_section (bfd * output_bfd, { _bfd_clear_contents (howto, input_bfd, input_section, contents + rel->r_offset); - rel->r_offset = rel->r_offset; rel->r_info = 0; rel->r_addend = 0; @@ -1279,7 +1614,12 @@ elf_arc_relocate_section (bfd * output_bfd, while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) + { + struct elf_link_hash_entry *h_old = h; h = (struct elf_link_hash_entry *) h->root.u.i.link; + if (h->got.glist == 0 && h_old->got.glist != h->got.glist) + h->got.glist = h_old->got.glist; + } /* TODO: Need to validate what was the intention. */ /* BFD_ASSERT ((h->dynindx == -1) || (h->forced_local != 0)); */ @@ -1374,6 +1714,8 @@ elf_arc_relocate_section (bfd * output_bfd, if ((is_reloc_for_GOT (howto) || is_reloc_for_TLS (howto))) { + reloc_data.should_relocate = TRUE; + struct got_entry **list = get_got_entry_list_for_symbol (output_bfd, r_symndx, h); @@ -1392,21 +1734,27 @@ elf_arc_relocate_section (bfd * output_bfd, { create_got_dynrelocs_for_single_entry ( got_entry_for_type (list, - arc_got_entry_type_for_reloc (howto)), + arc_got_entry_type_for_reloc (howto)), output_bfd, info, NULL); } } + +#define IS_ARC_PCREL_TYPE(TYPE) \ + ( (TYPE == R_ARC_PC32) \ + || (TYPE == R_ARC_32_PCREL)) + switch (r_type) { case R_ARC_32: case R_ARC_32_ME: case R_ARC_PC32: case R_ARC_32_PCREL: - if ((bfd_link_pic (info)) - && ((r_type != R_ARC_PC32 && r_type != R_ARC_32_PCREL) + if (bfd_link_pic (info) + && (!IS_ARC_PCREL_TYPE (r_type) || (h != NULL && h->dynindx != -1 + && !h->def_regular && (!info->symbolic || !h->def_regular)))) { Elf_Internal_Rela outrel; @@ -1423,6 +1771,7 @@ elf_arc_relocate_section (bfd * output_bfd, info, input_section, rel->r_offset); + if (outrel.r_offset == (bfd_vma) -1) skip = TRUE; @@ -1430,10 +1779,6 @@ elf_arc_relocate_section (bfd * output_bfd, outrel.r_offset += (input_section->output_section->vma + input_section->output_offset); -#define IS_ARC_PCREL_TYPE(TYPE) \ - ( (TYPE == R_ARC_PC32) \ - || (TYPE == R_ARC_32_PCREL)) - if (skip) { memset (&outrel, 0, sizeof outrel); @@ -1441,10 +1786,10 @@ elf_arc_relocate_section (bfd * output_bfd, } else if (h != NULL && h->dynindx != -1 - && ((IS_ARC_PCREL_TYPE (r_type)) - || !(bfd_link_executable (info) - || SYMBOLIC_BIND (info, h)) - || ! h->def_regular)) + && (IS_ARC_PCREL_TYPE (r_type) + || !(bfd_link_executable (info) + || SYMBOLIC_BIND (info, h)) + || ! h->def_regular)) { BFD_ASSERT (h != NULL); if ((input_section->flags & SEC_ALLOC) != 0) @@ -1480,7 +1825,7 @@ elf_arc_relocate_section (bfd * output_bfd, bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - if (relocate == FALSE) + if (!relocate) continue; } break; @@ -1489,10 +1834,10 @@ elf_arc_relocate_section (bfd * output_bfd, } if (is_reloc_SDA_relative (howto) - && (reloc_data.sdata_begin_symbol_vma_set == FALSE)) + && !reloc_data.sdata_begin_symbol_vma_set) { - (*_bfd_error_handler) - ("Error: Linker symbol __SDATA_BEGIN__ not found"); + _bfd_error_handler + ("error: linker symbol __SDATA_BEGIN__ not found"); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -1504,8 +1849,8 @@ elf_arc_relocate_section (bfd * output_bfd, if ((is_reloc_for_GOT (howto) || is_reloc_for_PLT (howto)) && reloc_data.sym_section == NULL) { - (*_bfd_error_handler) - (_("GOT and PLT relocations cannot be fixed with a non dynamic linker.")); + _bfd_error_handler + (_("GOT and PLT relocations cannot be fixed with a non dynamic linker")); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -1528,23 +1873,28 @@ elf_arc_relocate_section (bfd * output_bfd, break; case bfd_reloc_other: - msg = _("%B(%A): warning: unaligned access to symbol '%s' in the small data area"); + /* xgettext:c-format */ + msg = _("%pB(%pA): warning: unaligned access to symbol '%s' in the small data area"); break; case bfd_reloc_outofrange: - msg = _("%B(%A): internal error: out of range error"); + /* xgettext:c-format */ + msg = _("%pB(%pA): internal error: out of range error"); break; case bfd_reloc_notsupported: - msg = _("%B(%A): internal error: unsupported relocation error"); + /* xgettext:c-format */ + msg = _("%pB(%pA): internal error: unsupported relocation error"); break; case bfd_reloc_dangerous: - msg = _("%B(%A): internal error: dangerous relocation"); + /* xgettext:c-format */ + msg = _("%pB(%pA): internal error: dangerous relocation"); break; default: - msg = _("%B(%A): internal error: unknown error"); + /* xgettext:c-format */ + msg = _("%pB(%pA): internal error: unknown error"); break; } @@ -1560,97 +1910,6 @@ elf_arc_relocate_section (bfd * output_bfd, (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ == ARC_ELF_DATA ? ((struct elf_arc_link_hash_table *) ((p)->hash)) : NULL) -/* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and - .rela.bss sections in DYNOBJ, and set up shortcuts to them in our - hash table. */ - -static bfd_boolean -arc_elf_create_dynamic_sections (bfd *dynobj, - struct bfd_link_info *info) -{ - struct elf_arc_link_hash_table *htab; - - if (!_bfd_elf_create_dynamic_sections (dynobj, info)) - return FALSE; - - htab = elf_arc_hash_table (info); - if (htab == NULL) - return FALSE; - - if (bfd_link_executable (info)) - { - /* Always allow copy relocs for building executables. */ - asection *s = bfd_get_linker_section (dynobj, ".rela.bss"); - if (s == NULL) - { - const struct elf_backend_data *bed = get_elf_backend_data (dynobj); - s = bfd_make_section_anyway_with_flags (dynobj, - ".rela.bss", - (bed->dynamic_sec_flags - | SEC_READONLY)); - if (s == NULL - || ! bfd_set_section_alignment (dynobj, s, - bed->s->log_file_align)) - return FALSE; - } - htab->srelbss = s; - } - - return TRUE; -} - -static struct dynamic_sections -arc_create_dynamic_sections (bfd * abfd, struct bfd_link_info *info) -{ - struct elf_link_hash_table *htab; - bfd *dynobj; - struct dynamic_sections ds = - { - .initialized = FALSE, - .sgot = NULL, - .srelgot = NULL, - .sgotplt = NULL, - .srelgotplt = NULL, - .sdyn = NULL, - .splt = NULL, - .srelplt = NULL - }; - - htab = elf_hash_table (info); - BFD_ASSERT (htab); - - /* Create dynamic sections for relocatable executables so that we - can copy relocations. */ - if (! htab->dynamic_sections_created && bfd_link_pic (info)) - { - if (! _bfd_elf_link_create_dynamic_sections (abfd, info)) - BFD_ASSERT (0); - } - - dynobj = (elf_hash_table (info))->dynobj; - - if (dynobj) - { - ds.sgot = htab->sgot; - ds.srelgot = htab->srelgot; - - ds.sgotplt = bfd_get_section_by_name (dynobj, ".got.plt"); - ds.srelgotplt = ds.srelplt; - - ds.splt = bfd_get_section_by_name (dynobj, ".plt"); - ds.srelplt = bfd_get_section_by_name (dynobj, ".rela.plt"); - } - - if (htab->dynamic_sections_created) - { - ds.sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); - } - - ds.initialized = TRUE; - - return ds; -} - static bfd_boolean elf_arc_check_relocs (bfd * abfd, struct bfd_link_info * info, @@ -1663,10 +1922,14 @@ elf_arc_check_relocs (bfd * abfd, const Elf_Internal_Rela * rel_end; bfd * dynobj; asection * sreloc = NULL; + struct elf_link_hash_table * htab = elf_hash_table (info); if (bfd_link_relocatable (info)) return TRUE; + if (htab->dynobj == NULL) + htab->dynobj = abfd; + dynobj = (elf_hash_table (info))->dynobj; symtab_hdr = &((elf_tdata (abfd))->symtab_hdr); sym_hashes = elf_sym_hashes (abfd); @@ -1688,15 +1951,6 @@ elf_arc_check_relocs (bfd * abfd, } howto = arc_elf_howto (r_type); - if (dynobj == NULL - && (is_reloc_for_GOT (howto) == TRUE - || is_reloc_for_TLS (howto) == TRUE)) - { - dynobj = elf_hash_table (info)->dynobj = abfd; - if (! _bfd_elf_create_got_section (abfd, info)) - return FALSE; - } - /* Load symbol information. */ r_symndx = ELF32_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) /* Is a local symbol. */ @@ -1713,7 +1967,8 @@ elf_arc_check_relocs (bfd * abfd, and the dynamic linker can not resolve these. However the error should not occur for e.g. debugging or non-readonly sections. */ - if ((bfd_link_dll (info) && !bfd_link_pie (info)) + if (h != NULL + && (bfd_link_dll (info) && !bfd_link_pie (info)) && (sec->flags & SEC_ALLOC) != 0 && (sec->flags & SEC_READONLY) != 0 && ((sec->flags & SEC_CODE) != 0 @@ -1725,12 +1980,13 @@ elf_arc_check_relocs (bfd * abfd, else /* bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL); */ name = "UNKNOWN"; - (*_bfd_error_handler) - (_("\ -%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), - abfd, - arc_elf_howto (r_type)->name, - name); + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: relocation %s against `%s' can not be used" + " when making a shared object; recompile with -fPIC"), + abfd, + arc_elf_howto (r_type)->name, + name); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -1751,6 +2007,10 @@ elf_arc_check_relocs (bfd * abfd, { if (sreloc == NULL) { + if (info->dynamic + && ! htab->dynamic_sections_created + && ! _bfd_elf_link_create_dynamic_sections (abfd, info)) + return FALSE; sreloc = _bfd_elf_make_dynamic_reloc_section (sec, dynobj, 2, abfd, /*rela*/ @@ -1766,7 +2026,7 @@ elf_arc_check_relocs (bfd * abfd, break; } - if (is_reloc_for_PLT (howto) == TRUE) + if (is_reloc_for_PLT (howto)) { if (h == NULL) continue; @@ -1775,9 +2035,12 @@ elf_arc_check_relocs (bfd * abfd, } /* Add info to the symbol got_entry_list. */ - if (is_reloc_for_GOT (howto) == TRUE - || is_reloc_for_TLS (howto) == TRUE) + if (is_reloc_for_GOT (howto) + || is_reloc_for_TLS (howto)) { + if (! _bfd_elf_create_got_section (dynobj, info)) + return FALSE; + arc_fill_got_info_for_reloc ( arc_got_entry_type_for_reloc (howto), get_got_entry_list_for_symbol (abfd, r_symndx, h), @@ -2045,12 +2308,12 @@ elf_arc_adjust_dynamic_symbol (struct bfd_link_info *info, /* If this is a weak symbol, and there is a real definition, the processor independent code will have arranged for us to see the real definition first, and we can just use the same value. */ - if (h->u.weakdef != NULL) + if (h->is_weakalias) { - BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined - || h->u.weakdef->root.type == bfd_link_hash_defweak); - h->root.u.def.section = h->u.weakdef->root.u.def.section; - h->root.u.def.value = h->u.weakdef->root.u.def.value; + struct elf_link_hash_entry *def = weakdef (h); + BFD_ASSERT (def->root.type == bfd_link_hash_defined); + h->root.u.def.section = def->root.u.def.section; + h->root.u.def.value = def->root.u.def.value; return TRUE; } @@ -2097,8 +2360,8 @@ elf_arc_adjust_dynamic_symbol (struct bfd_link_info *info, { struct elf_arc_link_hash_table *arc_htab = elf_arc_hash_table (info); - BFD_ASSERT (arc_htab->srelbss != NULL); - arc_htab->srelbss->size += sizeof (Elf32_External_Rela); + BFD_ASSERT (arc_htab->elf.srelbss != NULL); + arc_htab->elf.srelbss->size += sizeof (Elf32_External_Rela); h->needs_copy = 1; } @@ -2153,16 +2416,16 @@ elf_arc_finish_dynamic_symbol (bfd * output_bfd, if (h->dynindx == -1 || (h->root.type != bfd_link_hash_defined && h->root.type != bfd_link_hash_defweak) - || arc_htab->srelbss == NULL) + || arc_htab->elf.srelbss == NULL) abort (); bfd_vma rel_offset = (h->root.u.def.value + h->root.u.def.section->output_section->vma + h->root.u.def.section->output_offset); - bfd_byte * loc = arc_htab->srelbss->contents - + (arc_htab->srelbss->reloc_count * sizeof (Elf32_External_Rela)); - arc_htab->srelbss->reloc_count++; + bfd_byte * loc = arc_htab->elf.srelbss->contents + + (arc_htab->elf.srelbss->reloc_count * sizeof (Elf32_External_Rela)); + arc_htab->elf.srelbss->reloc_count++; Elf_Internal_Rela rel; rel.r_addend = 0; @@ -2204,17 +2467,17 @@ static bfd_boolean elf_arc_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info *info) { - struct dynamic_sections ds = arc_create_dynamic_sections (output_bfd, info); struct elf_link_hash_table *htab = elf_hash_table (info); bfd *dynobj = (elf_hash_table (info))->dynobj; + asection *sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - if (ds.sdyn) + if (sdyn) { Elf32_External_Dyn *dyncon, *dynconend; - dyncon = (Elf32_External_Dyn *) ds.sdyn->contents; + dyncon = (Elf32_External_Dyn *) sdyn->contents; dynconend - = (Elf32_External_Dyn *) (ds.sdyn->contents + ds.sdyn->size); + = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); for (; dyncon < dynconend; dyncon++) { Elf_Internal_Dyn internal_dyn; @@ -2227,12 +2490,11 @@ elf_arc_finish_dynamic_sections (bfd * output_bfd, switch (internal_dyn.d_tag) { - GET_SYMBOL_OR_SECTION (DT_INIT, "_init", NULL) - GET_SYMBOL_OR_SECTION (DT_FINI, "_fini", NULL) + GET_SYMBOL_OR_SECTION (DT_INIT, info->init_function, NULL) + GET_SYMBOL_OR_SECTION (DT_FINI, info->fini_function, NULL) GET_SYMBOL_OR_SECTION (DT_PLTGOT, NULL, ".plt") GET_SYMBOL_OR_SECTION (DT_JMPREL, NULL, ".rela.plt") GET_SYMBOL_OR_SECTION (DT_PLTRELSZ, NULL, ".rela.plt") - GET_SYMBOL_OR_SECTION (DT_RELASZ, NULL, ".rela.plt") GET_SYMBOL_OR_SECTION (DT_VERSYM, NULL, ".gnu.version") GET_SYMBOL_OR_SECTION (DT_VERDEF, NULL, ".gnu.version_d") GET_SYMBOL_OR_SECTION (DT_VERNEED, NULL, ".gnu.version_r") @@ -2282,12 +2544,6 @@ elf_arc_finish_dynamic_sections (bfd * output_bfd, do_it = TRUE; break; - case DT_RELASZ: - if (s != NULL) - internal_dyn.d_un.d_val -= s->size; - do_it = TRUE; - break; - default: break; } @@ -2303,8 +2559,9 @@ elf_arc_finish_dynamic_sections (bfd * output_bfd, } /* TODO: Validate this. */ - elf_section_data (htab->srelplt->output_section)->this_hdr.sh_entsize - = 0xc; + if (htab->srelplt->output_section != bfd_abs_section_ptr) + elf_section_data (htab->srelplt->output_section) + ->this_hdr.sh_entsize = 12; } /* Fill in the first three entries in the global offset table. */ @@ -2319,12 +2576,12 @@ elf_arc_finish_dynamic_sections (bfd * output_bfd, { asection *sec = h->root.u.def.section; - if (ds.sdyn == NULL) + if (sdyn == NULL) bfd_put_32 (output_bfd, (bfd_vma) 0, sec->contents); else bfd_put_32 (output_bfd, - ds.sdyn->output_section->vma + ds.sdyn->output_offset, + sdyn->output_section->vma + sdyn->output_offset, sec->contents); bfd_put_32 (output_bfd, (bfd_vma) 0, sec->contents + 4); bfd_put_32 (output_bfd, (bfd_vma) 0, sec->contents + 8); @@ -2343,26 +2600,25 @@ elf_arc_finish_dynamic_sections (bfd * output_bfd, /* Set the sizes of the dynamic sections. */ static bfd_boolean -elf_arc_size_dynamic_sections (bfd * output_bfd, +elf_arc_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) { - bfd * dynobj; - asection * s; - bfd_boolean relocs_exist = FALSE; - bfd_boolean reltext_exist = FALSE; - struct dynamic_sections ds = arc_create_dynamic_sections (output_bfd, info); + bfd *dynobj; + asection *s; + bfd_boolean relocs_exist = FALSE; + bfd_boolean reltext_exist = FALSE; struct elf_link_hash_table *htab = elf_hash_table (info); - dynobj = (elf_hash_table (info))->dynobj; + dynobj = htab->dynobj; BFD_ASSERT (dynobj != NULL); - if ((elf_hash_table (info))->dynamic_sections_created) + if (htab->dynamic_sections_created) { struct elf_link_hash_entry *h; /* Set the contents of the .interp section to the interpreter. */ - if (!bfd_link_pic (info)) + if (bfd_link_executable (info) && !info->nointerp) { s = bfd_get_section_by_name (dynobj, ".interp"); BFD_ASSERT (s != NULL); @@ -2376,8 +2632,8 @@ elf_arc_size_dynamic_sections (bfd * output_bfd, section. Checking if the .init section is present. We also create DT_INIT and DT_FINI entries if the init_str has been changed by the user. */ - ADD_DYNAMIC_SYMBOL ("init", DT_INIT); - ADD_DYNAMIC_SYMBOL ("fini", DT_FINI); + ADD_DYNAMIC_SYMBOL (info->init_function, DT_INIT); + ADD_DYNAMIC_SYMBOL (info->fini_function, DT_FINI); } else { @@ -2390,54 +2646,71 @@ elf_arc_size_dynamic_sections (bfd * output_bfd, htab->srelgot->size = 0; } - if (htab->splt != NULL && htab->splt->size == 0) - htab->splt->flags |= SEC_EXCLUDE; for (s = dynobj->sections; s != NULL; s = s->next) { if ((s->flags & SEC_LINKER_CREATED) == 0) continue; - if (strncmp (s->name, ".rela", 5) == 0) + if (s == htab->splt + || s == htab->sgot + || s == htab->sgotplt + || s == htab->sdynbss) { - if (s->size == 0) - { - s->flags |= SEC_EXCLUDE; - } - else + /* Strip this section if we don't need it. */ + } + else if (strncmp (s->name, ".rela", 5) == 0) + { + if (s->size != 0 && s != htab->srelplt) { - if (strcmp (s->name, ".rela.plt") != 0) + if (!reltext_exist) { - const char *outname = - bfd_get_section_name (output_bfd, - htab->srelplt->output_section); - - asection *target = bfd_get_section_by_name (output_bfd, - outname + 4); - - relocs_exist = TRUE; - if (target != NULL && target->size != 0 - && (target->flags & SEC_READONLY) != 0 - && (target->flags & SEC_ALLOC) != 0) - reltext_exist = TRUE; + const char *name = s->name + 5; + bfd *ibfd; + for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next) + if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour + && ibfd->flags & DYNAMIC) + { + asection *target = bfd_get_section_by_name (ibfd, name); + if (target != NULL + && elf_section_data (target)->sreloc == s + && ((target->output_section->flags + & (SEC_READONLY | SEC_ALLOC)) + == (SEC_READONLY | SEC_ALLOC))) + { + reltext_exist = TRUE; + break; + } + } } + relocs_exist = TRUE; } /* We use the reloc_count field as a counter if we need to copy relocs into the output file. */ s->reloc_count = 0; } + else + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } - if (strcmp (s->name, ".dynamic") == 0) - continue; + if (s->size == 0) + { + s->flags |= SEC_EXCLUDE; + continue; + } - if (s->size != 0) - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); + if ((s->flags & SEC_HAS_CONTENTS) == 0) + continue; - if (s->contents == NULL && s->size != 0) + /* Allocate memory for the section contents. */ + s->contents = bfd_zalloc (dynobj, s->size); + if (s->contents == NULL) return FALSE; } - if (ds.sdyn) + if (htab->dynamic_sections_created) { /* TODO: Check if this is needed. */ if (!bfd_link_pic (info)) @@ -2448,19 +2721,17 @@ elf_arc_size_dynamic_sections (bfd * output_bfd, if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0) || !_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0) || !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_RELA) - || !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0) - ) + || !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0)) return FALSE; - if (relocs_exist == TRUE) + if (relocs_exist) if (!_bfd_elf_add_dynamic_entry (info, DT_RELA, 0) || !_bfd_elf_add_dynamic_entry (info, DT_RELASZ, 0) || !_bfd_elf_add_dynamic_entry (info, DT_RELAENT, - sizeof (Elf32_External_Rela)) - ) + sizeof (Elf32_External_Rela))) return FALSE; - if (reltext_exist == TRUE) + if (reltext_exist) if (!_bfd_elf_add_dynamic_entry (info, DT_TEXTREL, 0)) return FALSE; } @@ -2579,6 +2850,69 @@ elf32_arc_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) note->descpos + offset); } +/* Determine whether an object attribute tag takes an integer, a + string or both. */ + +static int +elf32_arc_obj_attrs_arg_type (int tag) +{ + if (tag == Tag_ARC_CPU_name + || tag == Tag_ARC_ISA_config + || tag == Tag_ARC_ISA_apex) + return ATTR_TYPE_FLAG_STR_VAL; + else if (tag < (Tag_ARC_ISA_mpy_option + 1)) + return ATTR_TYPE_FLAG_INT_VAL; + else + return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL; +} + +/* Attribute numbers >=14 can be safely ignored. */ + +static bfd_boolean +elf32_arc_obj_attrs_handle_unknown (bfd *abfd, int tag) +{ + if ((tag & 127) < (Tag_ARC_ISA_mpy_option + 1)) + { + _bfd_error_handler + (_("%pB: unknown mandatory ARC object attribute %d"), + abfd, tag); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + else + { + _bfd_error_handler + (_("warning: %pB: unknown ARC object attribute %d"), + abfd, tag); + return TRUE; + } +} + +/* Handle an ARC specific section when reading an object file. This is + called when bfd_section_from_shdr finds a section with an unknown + type. */ + +static bfd_boolean +elf32_arc_section_from_shdr (bfd *abfd, + Elf_Internal_Shdr * hdr, + const char *name, + int shindex) +{ + switch (hdr->sh_type) + { + case SHT_ARC_ATTRIBUTES: + break; + + default: + return FALSE; + } + + if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) + return FALSE; + + return TRUE; +} + #define TARGET_LITTLE_SYM arc_elf32_le_vec #define TARGET_LITTLE_NAME "elf32-littlearc" #define TARGET_BIG_SYM arc_elf32_be_vec @@ -2603,7 +2937,7 @@ elf32_arc_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) #define elf_backend_relocate_section elf_arc_relocate_section #define elf_backend_check_relocs elf_arc_check_relocs -#define elf_backend_create_dynamic_sections arc_elf_create_dynamic_sections +#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections #define elf_backend_reloc_type_class elf32_arc_reloc_type_class @@ -2620,6 +2954,7 @@ elf32_arc_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) #define elf_backend_rela_plts_and_copies_p 1 #define elf_backend_want_plt_sym 0 #define elf_backend_got_header_size 12 +#define elf_backend_dtrel_excludes_plt 1 #define elf_backend_may_use_rel_p 0 #define elf_backend_may_use_rela_p 1 @@ -2629,4 +2964,16 @@ elf32_arc_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) #define elf_backend_default_execstack 0 +#undef elf_backend_obj_attrs_vendor +#define elf_backend_obj_attrs_vendor "ARC" +#undef elf_backend_obj_attrs_section +#define elf_backend_obj_attrs_section ".ARC.attributes" +#undef elf_backend_obj_attrs_arg_type +#define elf_backend_obj_attrs_arg_type elf32_arc_obj_attrs_arg_type +#undef elf_backend_obj_attrs_section_type +#define elf_backend_obj_attrs_section_type SHT_ARC_ATTRIBUTES +#define elf_backend_obj_attrs_handle_unknown elf32_arc_obj_attrs_handle_unknown + +#define elf_backend_section_from_shdr elf32_arc_section_from_shdr + #include "elf32-target.h"