From: Nick Clifton Date: Fri, 19 Oct 2007 17:31:31 +0000 (+0000) Subject: Add MN10300 linker relaxation support for symbol differences X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bfff1642494227904c6c9a6c285cbaa6cf615bbb;p=binutils-gdb.git Add MN10300 linker relaxation support for symbol differences --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 6d7fa26d077..55cfb10be25 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +2007-10-19 Nick Clifton + + * config.bfd: Recognise am34-linux-gnu target. + * reloc.c: Add BFD_RELOC_MN10300_SYM_DIFF relocation. + * bfd-in2.h: Regenerate. + * libbfd.h: Regenerate. + * elf-m10300.c (elf_mn10300_howto): Add R_MN10300_SYM_DIFF. + (mn10300_reloc_map): Likewise. + (mn10300_elf_check_relocs): Do not create dynamic relocs for + symbol differences or relocations against absolute symbols. + (mn10300_elf_final_link_relocate): Likewise. + Handle R_MN10300_SYM_DIFF relocs. + (mn10300_elf_relocate_section): Fix for creating local copys of + dynamic relocs. + (mn10300_elf_relax_delete_bytes): Adjust symbols at the end of the + region. Adjust the size of function symbols. + (mn10300_elf_relax_section): Ignore symbols that are in discarded + sections. + 2007-10-19 Nick Clifton * elf-m10300.c: Convert to ISO C. diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index e425db18759..35aad28a5c6 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -2774,6 +2774,11 @@ in the instruction. */ /* Adjust by program base. */ BFD_RELOC_MN10300_RELATIVE, +/* Together with another reloc targeted at the same location, +allows for a value that is the difference of two symbols +in the same section. */ + BFD_RELOC_MN10300_SYM_DIFF, + /* i386/elf relocations */ BFD_RELOC_386_GOT32, diff --git a/bfd/config.bfd b/bfd/config.bfd index 899e18ef696..98183fc0f6b 100644 --- a/bfd/config.bfd +++ b/bfd/config.bfd @@ -71,6 +71,7 @@ esac targ_cpu=`echo $targ | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` case "${targ_cpu}" in alpha*) targ_archs=bfd_alpha_arch ;; +am34*|am33_2.0*) targ_archs=bfd_mn10300_arch ;; arm*) targ_archs=bfd_arm_arch ;; bfin*) targ_archs=bfd_bfin_arch ;; c30*) targ_archs=bfd_tic30_arch ;; @@ -107,7 +108,6 @@ xscale*) targ_archs=bfd_arm_arch ;; xtensa*) targ_archs=bfd_xtensa_arch ;; z80|r800) targ_archs=bfd_z80_arch ;; z8k*) targ_archs=bfd_z8k_arch ;; -am33_2.0) targ_archs=bfd_mn10300_arch ;; *) targ_archs=bfd_${targ_cpu}_arch ;; esac @@ -197,9 +197,10 @@ case "${targ}" in ;; #endif /* BFD64 */ - am33_2.0-*-linux*) + am34-*-linux* | am33_2.0-*-linux*) targ_defvec=bfd_elf32_am33lin_vec ;; + arc-*-elf*) targ_defvec=bfd_elf32_littlearc_vec targ_selvecs=bfd_elf32_bigarc_vec diff --git a/bfd/elf-m10300.c b/bfd/elf-m10300.c index 9aedc06b044..6c688bdcdd2 100644 --- a/bfd/elf-m10300.c +++ b/bfd/elf-m10300.c @@ -446,6 +446,30 @@ static reloc_howto_type elf_mn10300_howto_table[] = 0xffffffff, /* src_mask */ 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (24), + EMPTY_HOWTO (25), + EMPTY_HOWTO (26), + EMPTY_HOWTO (27), + EMPTY_HOWTO (28), + EMPTY_HOWTO (29), + EMPTY_HOWTO (30), + EMPTY_HOWTO (31), + EMPTY_HOWTO (32), + + HOWTO (R_MN10300_SYM_DIFF, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + NULL, /* special handler. */ + "R_MN10300_SYM_DIFF", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE) /* pcrel_offset */ }; struct mn10300_reloc_map @@ -480,6 +504,7 @@ static const struct mn10300_reloc_map mn10300_reloc_map[] = { BFD_RELOC_MN10300_GLOB_DAT, R_MN10300_GLOB_DAT }, { BFD_RELOC_MN10300_JMP_SLOT, R_MN10300_JMP_SLOT }, { BFD_RELOC_MN10300_RELATIVE, R_MN10300_RELATIVE }, + { BFD_RELOC_MN10300_SYM_DIFF, R_MN10300_SYM_DIFF } }; /* Create the GOT section. */ @@ -619,6 +644,7 @@ mn10300_elf_check_relocs (bfd *abfd, asection *sec, const Elf_Internal_Rela *relocs) { + bfd_boolean sym_diff_reloc_seen; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; const Elf_Internal_Rela *rel; @@ -642,6 +668,7 @@ mn10300_elf_check_relocs (bfd *abfd, dynobj = elf_hash_table (info)->dynobj; local_got_offsets = elf_local_got_offsets (abfd); rel_end = relocs + sec->reloc_count; + sym_diff_reloc_seen = FALSE; for (rel = relocs; rel < rel_end; rel++) { @@ -814,53 +841,98 @@ mn10300_elf_check_relocs (bfd *abfd, h->non_got_ref = 1; break; + case R_MN10300_SYM_DIFF: + sym_diff_reloc_seen = TRUE; + break; + case R_MN10300_32: if (h != NULL) h->non_got_ref = 1; - /* If we are creating a shared library, then we need to copy - the reloc into the shared library. */ + /* If we are creating a shared library, then we + need to copy the reloc into the shared library. */ if (info->shared - && (sec->flags & SEC_ALLOC) != 0) + && (sec->flags & SEC_ALLOC) != 0 + /* Do not generate a dynamic reloc for a + reloc associated with a SYM_DIFF operation. */ + && ! sym_diff_reloc_seen) { - /* When creating a shared object, we must copy these - reloc types into the output file. We create a reloc - section in dynobj and make room for this reloc. */ - if (sreloc == NULL) - { - const char * name; - - name = (bfd_elf_string_from_elf_section - (abfd, - elf_elfheader (abfd)->e_shstrndx, - elf_section_data (sec)->rel_hdr.sh_name)); - if (name == NULL) - return FALSE; + asection * sym_section = NULL; - BFD_ASSERT (CONST_STRNEQ (name, ".rela") - && streq (bfd_get_section_name (abfd, sec), name + 5)); + /* Find the section containing the + symbol involved in the relocation. */ + if (h == NULL) + { + Elf_Internal_Sym * isymbuf; + Elf_Internal_Sym * isym; + + isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; + if (isymbuf == NULL) + isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, + symtab_hdr->sh_info, 0, + NULL, NULL, NULL); + if (isymbuf) + { + isym = isymbuf + r_symndx; + /* All we care about is whether this local symbol is absolute. */ + if (isym->st_shndx == SHN_ABS) + sym_section = bfd_abs_section_ptr; + } + } + else + { + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + sym_section = h->root.u.def.section; + } - sreloc = bfd_get_section_by_name (dynobj, name); + /* If the symbol is absolute then the relocation can + be resolved during linking and there is no need for + a dynamic reloc. */ + if (sym_section != bfd_abs_section_ptr) + { + /* When creating a shared object, we must copy these + reloc types into the output file. We create a reloc + section in dynobj and make room for this reloc. */ if (sreloc == NULL) { - flagword flags; + const char * name; - flags = (SEC_HAS_CONTENTS | SEC_READONLY - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - if ((sec->flags & SEC_ALLOC) != 0) - flags |= SEC_ALLOC | SEC_LOAD; - sreloc = bfd_make_section_with_flags (dynobj, name, flags); - if (sreloc == NULL - || ! bfd_set_section_alignment (dynobj, sreloc, 2)) + name = (bfd_elf_string_from_elf_section + (abfd, + elf_elfheader (abfd)->e_shstrndx, + elf_section_data (sec)->rel_hdr.sh_name)); + if (name == NULL) return FALSE; + + BFD_ASSERT (CONST_STRNEQ (name, ".rela") + && streq (bfd_get_section_name (abfd, sec), name + 5)); + + sreloc = bfd_get_section_by_name (dynobj, name); + if (sreloc == NULL) + { + flagword flags; + + flags = (SEC_HAS_CONTENTS | SEC_READONLY + | SEC_IN_MEMORY | SEC_LINKER_CREATED); + if ((sec->flags & SEC_ALLOC) != 0) + flags |= SEC_ALLOC | SEC_LOAD; + sreloc = bfd_make_section_with_flags (dynobj, name, flags); + if (sreloc == NULL + || ! bfd_set_section_alignment (dynobj, sreloc, 2)) + return FALSE; + } } - } - sreloc->size += sizeof (Elf32_External_Rela); + sreloc->size += sizeof (Elf32_External_Rela); + } } break; } + + if (ELF32_R_TYPE (rel->r_info) != R_MN10300_SYM_DIFF) + sym_diff_reloc_seen = FALSE; } return TRUE; @@ -904,6 +976,9 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, asection *sym_sec ATTRIBUTE_UNUSED, int is_local ATTRIBUTE_UNUSED) { + static asection * sym_diff_section; + static bfd_vma sym_diff_value; + bfd_boolean is_sym_diff_reloc; unsigned long r_type = howto->type; bfd_byte * hit_data = contents + offset; bfd * dynobj; @@ -937,13 +1012,54 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, return bfd_reloc_dangerous; } + is_sym_diff_reloc = FALSE; + if (sym_diff_section != NULL) + { + BFD_ASSERT (sym_diff_section == input_section); + + switch (r_type) + { + case R_MN10300_32: + case R_MN10300_24: + case R_MN10300_16: + case R_MN10300_8: + value -= sym_diff_value; + sym_diff_section = NULL; + is_sym_diff_reloc = TRUE; + break; + + default: + sym_diff_section = NULL; + break; + } + } + switch (r_type) { + case R_MN10300_SYM_DIFF: + BFD_ASSERT (addend == 0); + /* Cache the input section and value. + The offset is unreliable, since relaxation may + have reduced the following reloc's offset. */ + sym_diff_section = input_section; + sym_diff_value = value; + return bfd_reloc_ok; + case R_MN10300_NONE: return bfd_reloc_ok; case R_MN10300_32: if (info->shared + /* Do not generate relocs when an R_MN10300_32 has been used + with an R_MN10300_SYM_DIFF to compute a difference of two + symbols. */ + && is_sym_diff_reloc == FALSE + /* Also, do not generate a reloc when the symbol associated + with the R_MN10300_32 reloc is absolute - there is no + need for a run time computation in this case. */ + && sym_sec != bfd_abs_section_ptr + /* If the section is not going to be allocated at load time + then there is no need to generate relocs for it. */ && (input_section->flags & SEC_ALLOC) != 0) { Elf_Internal_Rela outrel; @@ -1370,6 +1486,10 @@ mn10300_elf_relocate_section (bfd *output_bfd, && elf_hash_table (info)->dynamic_sections_created && !SYMBOL_REFERENCES_LOCAL (info, hh)) || (r_type == R_MN10300_32 + /* _32 relocs in executables force _COPY relocs, + such that the address of the symbol ends up + being local. */ + && !info->executable && !SYMBOL_REFERENCES_LOCAL (info, hh) && ((input_section->flags & SEC_ALLOC) != 0 /* DWARF will emit R_MN10300_32 relocations @@ -1551,7 +1671,7 @@ static bfd_boolean elf32_mn10300_count_hash_table_entries (struct bfd_hash_entry *gen_entry ATTRIBUTE_UNUSED, void * in_args) { - int *count = (int *)in_args; + int *count = (int *) in_args; (*count) ++; return TRUE; @@ -1576,9 +1696,9 @@ static int sort_by_value (const void *va, const void *vb) { struct elf32_mn10300_link_hash_entry *a - = *(struct elf32_mn10300_link_hash_entry **)va; + = *(struct elf32_mn10300_link_hash_entry **) va; struct elf32_mn10300_link_hash_entry *b - = *(struct elf32_mn10300_link_hash_entry **)vb; + = *(struct elf32_mn10300_link_hash_entry **) vb; return a->value - b->value; } @@ -1735,8 +1855,14 @@ mn10300_elf_relax_delete_bytes (bfd *abfd, { if (isym->st_shndx == sec_shndx && isym->st_value > addr - && isym->st_value < toaddr) + && isym->st_value <= toaddr) isym->st_value -= count; + /* Adjust the function symbol's size as well. */ + else if (isym->st_shndx == sec_shndx + && ELF_ST_TYPE (isym->st_info) == STT_FUNC + && isym->st_value + isym->st_size > addr + && isym->st_value + isym->st_size <= toaddr) + isym->st_size -= count; } /* Now adjust the global symbols defined in this section. */ @@ -1752,8 +1878,15 @@ mn10300_elf_relax_delete_bytes (bfd *abfd, || sym_hash->root.type == bfd_link_hash_defweak) && sym_hash->root.u.def.section == sec && sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) + && sym_hash->root.u.def.value <= toaddr) sym_hash->root.u.def.value -= count; + /* Adjust the function symbol's size as well. */ + else if (sym_hash->root.type == bfd_link_hash_defined + && sym_hash->root.u.def.section == sec + && sym_hash->type == STT_FUNC + && sym_hash->root.u.def.value + sym_hash->size > addr + && sym_hash->root.u.def.value + sym_hash->size <= toaddr) + sym_hash->size -= count; } return TRUE; @@ -1981,7 +2114,7 @@ mn10300_elf_relax_section (bfd *abfd, local symbol in the global hash table. */ amt = strlen (sym_name) + 10; new_name = bfd_malloc (amt); - if (new_name == 0) + if (new_name == NULL) goto error_return; sprintf (new_name, "%s_%08x", sym_name, sym_sec->id); @@ -2090,7 +2223,7 @@ mn10300_elf_relax_section (bfd *abfd, local symbol in the global hash table. */ amt = strlen (sym_name) + 10; new_name = bfd_malloc (amt); - if (new_name == 0) + if (new_name == NULL) goto error_return; sprintf (new_name, "%s_%08x", sym_name, sym_sec->id); @@ -2302,7 +2435,7 @@ mn10300_elf_relax_section (bfd *abfd, local symbol in the global hash table. */ amt = strlen (sym_name) + 10; new_name = bfd_malloc (amt); - if (new_name == 0) + if (new_name == NULL) goto error_return; sprintf (new_name, "%s_%08x", sym_name, sym_sec->id); sym_name = new_name; @@ -2514,7 +2647,6 @@ mn10300_elf_relax_section (bfd *abfd, asection *sym_sec = NULL; const char *sym_name; char *new_name; - bfd_vma saved_addend; /* A local symbol. */ isym = isymbuf + ELF32_R_SYM (irel->r_info); @@ -2535,22 +2667,22 @@ mn10300_elf_relax_section (bfd *abfd, && ELF_ST_TYPE (isym->st_info) == STT_SECTION && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE) { + bfd_vma saved_addend; + saved_addend = irel->r_addend; - symval = _bfd_elf_rela_local_sym (abfd, isym, &sym_sec, irel); + symval = _bfd_elf_rela_local_sym (abfd, isym, & sym_sec, irel); symval += irel->r_addend; irel->r_addend = saved_addend; } else - { - symval = (isym->st_value - + sym_sec->output_section->vma - + sym_sec->output_offset); - } + symval = (isym->st_value + + sym_sec->output_section->vma + + sym_sec->output_offset); /* Tack on an ID so we can uniquely identify this local symbol in the global hash table. */ new_name = bfd_malloc ((bfd_size_type) strlen (sym_name) + 10); - if (new_name == 0) + if (new_name == NULL) goto error_return; sprintf (new_name, "%s_%08x", sym_name, sym_sec->id); sym_name = new_name; @@ -2576,6 +2708,10 @@ mn10300_elf_relax_section (bfd *abfd, regular reloc processing. */ continue; + /* Check for a reference to a discarded symbol and ignore it. */ + if (h->root.root.u.def.section->output_section == NULL) + continue; + symval = (h->root.root.u.def.value + h->root.root.u.def.section->output_section->vma + h->root.root.u.def.section->output_offset); @@ -3284,7 +3420,7 @@ mn10300_elf_relax_section (bfd *abfd, case 0x93: /* sp-based offsets are zero-extended. */ if (code >= 0x90 && code <= 0x93 - && (long)value < 0) + && (long) value < 0) continue; /* Note that we've changed the relocation contents, etc. */ @@ -3341,7 +3477,7 @@ mn10300_elf_relax_section (bfd *abfd, /* mov imm16, an zero-extends the immediate. */ if (code == 0xdc - && (long)value < 0) + && (long) value < 0) continue; /* Note that we've changed the relocation contents, etc. */ @@ -3422,12 +3558,12 @@ mn10300_elf_relax_section (bfd *abfd, case 0xe3: /* cmp imm16, an zero-extends the immediate. */ if (code == 0xdc - && (long)value < 0) + && (long) value < 0) continue; /* So do sp-based offsets. */ if (code >= 0xb0 && code <= 0xb3 - && (long)value < 0) + && (long) value < 0) continue; /* Note that we've changed the relocation contents, etc. */ diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 7f10f46ed55..18d01caca70 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1046,6 +1046,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_MN10300_GLOB_DAT", "BFD_RELOC_MN10300_JMP_SLOT", "BFD_RELOC_MN10300_RELATIVE", + "BFD_RELOC_MN10300_SYM_DIFF", "BFD_RELOC_386_GOT32", "BFD_RELOC_386_PLT32", diff --git a/bfd/reloc.c b/bfd/reloc.c index 525fe35b633..aa218754bc7 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -2361,6 +2361,12 @@ ENUM BFD_RELOC_MN10300_RELATIVE ENUMDOC Adjust by program base. +ENUM + BFD_RELOC_MN10300_SYM_DIFF +ENUMDOC + Together with another reloc targeted at the same location, + allows for a value that is the difference of two symbols + in the same section. COMMENT ENUM diff --git a/gas/ChangeLog b/gas/ChangeLog index 59112826e38..f53d2aba079 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,24 @@ +2007-10-19 Nick Clifton + + * expr.c (expr): Test md_allow_local_subtract (if defined) before + allowing the evaluation of an expression involving two symbols + defined in the same section. + * doc/internals.texi (md_allow_local_subtract): Document the new + macro. + * config/tc-mn10300.h (md_allow_local_subtract): Define. + (RELAX_EXPANSION_POSSIBLE): Define. + (MAX_RELOC_EXPANSION): Define. + (TC_FRAG_TYPE): Define. + * config/tc-mn10300.c (md_assemble): Mark fragments as containing code. + (tc_gen_reloc): Return an array of relocs. If necessary generate + two relocs to handle an expressions involving the difference of + two symbols. + (mn10300_fix_adjustable): Do not test TC_FORCE_RELOCATION_LOCAL + when then fixup is not pc-relative. + (mn10300_allow_local_subtract): New function. Determine when it + is safe to compute the difference between two symbols at assemble + time. + 2007-10-19 Alan Modra * config/tc-ppc.c (ppc_parse_name): Skip leading '%'. diff --git a/gas/config/tc-mn10300.c b/gas/config/tc-mn10300.c index 671c0089f7f..5ec58bb805e 100644 --- a/gas/config/tc-mn10300.c +++ b/gas/config/tc-mn10300.c @@ -2141,15 +2141,21 @@ keep_going: dwarf2_emit_insn (size); } + + /* Label this frag as one that contains instructions. */ + frag_now->tc_frag_data = TRUE; } /* If while processing a fixup, a reloc really needs to be created then it is done here. */ -arelent * +arelent ** tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) { + static arelent * no_relocs = NULL; + static arelent * relocs[MAX_RELOC_EXPANSION + 1]; arelent *reloc; + reloc = xmalloc (sizeof (arelent)); reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); @@ -2158,9 +2164,13 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) as_bad_where (fixp->fx_file, fixp->fx_line, _("reloc %d not supported by object file format"), (int) fixp->fx_r_type); - return NULL; + free (reloc); + return & no_relocs; } + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + relocs[0] = reloc; + relocs[1] = NULL; if (fixp->fx_subsy && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) @@ -2173,44 +2183,33 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) { reloc->sym_ptr_ptr = NULL; - /* If we got a difference between two symbols, and the - subtracted symbol is in the current section, use a - PC-relative relocation. If both symbols are in the same - section, the difference would have already been simplified - to a constant. */ + /* If we have a difference between two (non-absolute) symbols we must + generate two relocs (one for each symbol) and allow the linker to + resolve them - relaxation may change the distances between symbols, + even local symbols defined in the same segment. */ if (S_GET_SEGMENT (fixp->fx_subsy) == seg) { - reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - reloc->addend = (reloc->address - S_GET_VALUE (fixp->fx_subsy) - + fixp->fx_offset); + arelent * reloc2 = xmalloc (sizeof * reloc); - switch (fixp->fx_r_type) - { - case BFD_RELOC_8: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_8_PCREL); - return reloc; + relocs[0] = reloc2; + relocs[1] = reloc; - case BFD_RELOC_16: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_16_PCREL); - return reloc; + reloc2->address = reloc->address; + reloc2->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_MN10300_SYM_DIFF); + reloc2->addend = - S_GET_VALUE (fixp->fx_subsy); + reloc2->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); + *reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy); - case BFD_RELOC_24: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_24_PCREL); - return reloc; + reloc->addend = fixp->fx_offset; + if (S_GET_SEGMENT (fixp->fx_addsy) == absolute_section) + reloc->addend += S_GET_VALUE (fixp->fx_addsy); - case BFD_RELOC_32: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_32_PCREL); - return reloc; + reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - default: - /* Try to compute the absolute value below. */ - break; - } + fixp->fx_pcrel = 0; + fixp->fx_done = 1; + return relocs; } if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy)) @@ -2247,14 +2246,14 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) default: reloc->sym_ptr_ptr = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr; - return reloc; + return relocs; } } if (reloc->sym_ptr_ptr) free (reloc->sym_ptr_ptr); free (reloc); - return NULL; + return & no_relocs; } else { @@ -2262,7 +2261,7 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->addend = fixp->fx_offset; } - return reloc; + return relocs; } int @@ -2377,11 +2376,14 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg) bfd_boolean mn10300_fix_adjustable (struct fix *fixp) { - if (TC_FORCE_RELOCATION_LOCAL (fixp)) - return FALSE; - - if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + if (fixp->fx_pcrel) + { + if (TC_FORCE_RELOCATION_LOCAL (fixp)) + return FALSE; + } + /* Non-relative relocs can (and must) be adjusted if they do + not meet the criteria below, or the generic criteria. */ + else if (TC_FORCE_RELOCATION (fixp)) return FALSE; /* Do not adjust relocations involving symbols in code sections, @@ -2395,8 +2397,9 @@ mn10300_fix_adjustable (struct fix *fixp) symbols, because they too break relaxation. We do want to adjust other mergable symbols, like .rodata, because code relaxations need section-relative symbols to properly relax them. */ - if (! (S_GET_SEGMENT(fixp->fx_addsy)->flags & SEC_MERGE)) + if (! (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE)) return FALSE; + if (strncmp (S_GET_SEGMENT (fixp->fx_addsy)->name, ".debug", 6) == 0) return FALSE; @@ -2502,3 +2505,60 @@ const pseudo_typeS md_pseudo_table[] = { "mn10300", set_arch_mach, MN103 }, {NULL, 0, 0} }; + +/* Returns FALSE if there is some mn10300 specific reason why the + subtraction of two same-section symbols cannot be computed by + the assembler. */ + +bfd_boolean +mn10300_allow_local_subtract (expressionS * left, expressionS * right, segT section) +{ + bfd_boolean result; + fragS * left_frag; + fragS * right_frag; + fragS * frag; + + /* If we are not performing linker relaxation then we have nothing + to worry about. */ + if (linkrelax == 0) + return TRUE; + + /* If the symbols are not in a code section then they are OK. */ + if ((section->flags & SEC_CODE) == 0) + return TRUE; + + /* Otherwise we have to scan the fragments between the two symbols. + If any instructions are found then we have to assume that linker + relaxation may change their size and so we must delay resolving + the subtraction until the final link. */ + left_frag = symbol_get_frag (left->X_add_symbol); + right_frag = symbol_get_frag (right->X_add_symbol); + + if (left_frag == right_frag) + return ! left_frag->tc_frag_data; + + result = TRUE; + for (frag = left_frag; frag != NULL; frag = frag->fr_next) + { + if (frag->tc_frag_data) + result = FALSE; + if (frag == right_frag) + break; + } + + if (frag == NULL) + for (frag = right_frag; frag != NULL; frag = frag->fr_next) + { + if (frag->tc_frag_data) + result = FALSE; + if (frag == left_frag) + break; + } + + if (frag == NULL) + /* The two symbols are on disjoint fragment chains + - we cannot possibly compute their difference. */ + return FALSE; + + return result; +} diff --git a/gas/config/tc-mn10300.h b/gas/config/tc-mn10300.h index 20de21c5552..af7a6e6d2ce 100644 --- a/gas/config/tc-mn10300.h +++ b/gas/config/tc-mn10300.h @@ -98,13 +98,21 @@ void mn10300_cons_fix_new PARAMS ((fragS *, int, int, expressionS *)); #define md_number_to_chars number_to_chars_littleendian -/* Don't bother to adjust relocs. */ -/* #define tc_fix_adjustable(FIX) 0 */ #define tc_fix_adjustable(FIX) mn10300_fix_adjustable (FIX) -extern bfd_boolean mn10300_fix_adjustable PARAMS ((struct fix *)); +extern bfd_boolean mn10300_fix_adjustable (struct fix *); /* We do relaxing in the assembler as well as the linker. */ extern const struct relax_type md_relax_table[]; #define TC_GENERIC_RELAX_TABLE md_relax_table #define DWARF2_LINE_MIN_INSN_LENGTH 1 + +/* The difference between same-section symbols may be affected by linker + relaxation, so do not resolve such expressions in the assembler. */ +#define md_allow_local_subtract(l,r,s) mn10300_allow_local_subtract (l, r, s) +extern bfd_boolean mn10300_allow_local_subtract (expressionS *, expressionS *, segT); + +#define RELOC_EXPANSION_POSSIBLE +#define MAX_RELOC_EXPANSION 2 + +#define TC_FRAG_TYPE bfd_boolean diff --git a/gas/doc/internals.texi b/gas/doc/internals.texi index ff1df989e53..62f16f7f3d4 100644 --- a/gas/doc/internals.texi +++ b/gas/doc/internals.texi @@ -1535,6 +1535,18 @@ The function should return the debug format that is preferred by the CPU backend. This format will be used when generating assembler specific debug information. +@item md_allow_local_subtract (@var{left}, @var{right}, @var{section}) +If defined, GAS will call this macro when evaluating an expression which is the +difference of two symbols defined in the same section. It takes three +arguments: @code{expressioS * @var{left}} which is the symbolic expression on +the left hand side of the subtraction operation, @code{expressionS * +@var{right}} which is the symbolic expression on the right hand side of the +subtraction, and @code{segT @var{section}} which is the section containing the two +symbols. The macro should return a non-zero value if the expression should be +evaluated. Targets which implement link time relaxation which may change the +position of the two symbols relative to each other should ensure that this +macro returns zero in situations where this can occur. + @end table @node Object format backend diff --git a/gas/expr.c b/gas/expr.c index 4f4d380ff91..285b4381da2 100644 --- a/gas/expr.c +++ b/gas/expr.c @@ -1738,6 +1738,9 @@ expr (int rankarg, /* Larger # is higher rank. */ && right.X_op == O_symbol && resultP->X_op == O_symbol && retval == rightseg +#ifdef md_allow_local_subtract + && md_allow_local_subtract (resultP, & right, rightseg) +#endif && (SEG_NORMAL (rightseg) || right.X_add_symbol == resultP->X_add_symbol) && frag_offset_fixed_p (symbol_get_frag (resultP->X_add_symbol), diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index c180bea02bc..953f096e48a 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2007-10-19 Nick Clifton + + * gas/mn10300/basic.exp: Run pr997 test. + * gas/mn10300/pr997.s: New test. + * gas/mn10300/pr887.l: Expected output. + 2007-10-17 Nathan Sidwell * gas/m68k/mcf-movsr.s: New. diff --git a/gas/testsuite/gas/mn10300/basic.exp b/gas/testsuite/gas/mn10300/basic.exp index 9b1b53bec2c..c74fcf6ff1a 100644 --- a/gas/testsuite/gas/mn10300/basic.exp +++ b/gas/testsuite/gas/mn10300/basic.exp @@ -1801,6 +1801,7 @@ if [istarget mn10300*-*-*] then { do_am33_8 run_list_test "movpc" "" + run_list_test "pr997" "-a" run_dump_test "am33-2" run_dump_test "relax" diff --git a/gas/testsuite/gas/mn10300/pr997.l b/gas/testsuite/gas/mn10300/pr997.l new file mode 100644 index 00000000000..b122095ef42 --- /dev/null +++ b/gas/testsuite/gas/mn10300/pr997.l @@ -0,0 +1,20 @@ +GAS LISTING .*/pr997.s.*page 1 + + + 1.*.data + 2.* + 3 0000 68656C6C.*msg:.*.asciz "hello world.\\n" + 3 6F20776F + 3 726C642E + 3 0A00 + 4.*msglen = .-msg-1 + 5.*msglen=msglen & 0xff + +.*GAS LISTING.*/pr997.s.*page 2 + + +DEFINED SYMBOLS +.*/pr997.s:3.*.data:0+00 msg +.*/pr997.s:4.*\*ABS\*:0+0d msglen + +NO UNDEFINED SYMBOLS diff --git a/gas/testsuite/gas/mn10300/pr997.s b/gas/testsuite/gas/mn10300/pr997.s new file mode 100644 index 00000000000..4a54bbccfc6 --- /dev/null +++ b/gas/testsuite/gas/mn10300/pr997.s @@ -0,0 +1,5 @@ + .data + +msg: .asciz "hello world.\n" +msglen = .-msg-1 +msglen=msglen & 0xff diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index e7ff097cf26..e8e12ac5092 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,7 @@ +2007-10-19 Nick Clifton + + * mn10300.h: Add R_MN10300_SYM_DIFF reloc. + 2007-10-18 Roland McGrath * common.h (NT_PPC_VMX): New macro. diff --git a/include/elf/mn10300.h b/include/elf/mn10300.h index d241e9c61b8..74de473bdcf 100644 --- a/include/elf/mn10300.h +++ b/include/elf/mn10300.h @@ -50,6 +50,7 @@ START_RELOC_NUMBERS (elf_mn10300_reloc_type) RELOC_NUMBER (R_MN10300_GLOB_DAT, 21) RELOC_NUMBER (R_MN10300_JMP_SLOT, 22) RELOC_NUMBER (R_MN10300_RELATIVE, 23) + RELOC_NUMBER (R_MN10300_SYM_DIFF, 33) END_RELOC_NUMBERS (R_MN10300_MAX) /* Machine variant if we know it. This field was invented at Cygnus, diff --git a/ld/ChangeLog b/ld/ChangeLog index 38b0146e3a7..1ecce86934e 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,7 @@ +2007-10-19 Nick Clifton + + * configure.tgt: Add support for am34-linux-gnu target. + 2007-10-17 Zack Weinberg * ldlang.c (lang_check_section_addresses): Also report size of diff --git a/ld/configure.tgt b/ld/configure.tgt index d4f53ef2593..e897d1eae2c 100644 --- a/ld/configure.tgt +++ b/ld/configure.tgt @@ -400,6 +400,7 @@ mips*-*-sysv4*) targ_emul=elf32btsmip mmix-*-*) targ_emul=mmo targ_extra_emuls=elf64mmix ;; +am34-*-linux*) targ_emul=elf32am33lin ;; am33_2.0-*-linux*) targ_emul=elf32am33lin ;; mn10200-*-*) targ_emul=mn10200 ;; mn10300-*-*) targ_emul=mn10300 diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index ffc2296433b..db664305f4e 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,19 @@ +2007-10-19 Nick Clifton + + * ld-mn10300: New test directory. + * ld-mn10300/mn10300.exp: Run the new tests. + * ld-mn10300/i112045-1.s: Linker relaxation test. + * ld-mn10300/i112045-1.d: Expected disassembly. + * ld-mn10300/i112045-2.s: Linker relaxation test. + * ld-mn10300/i112045-2.d: Expected disassembly. + * ld-mn10300/i126256-1.c: Test source. + * ld-mn10300/i126256-2.c: Test source. + * ld-mn10300/i135409.s: Linker relaxation test. + * ld-mn10300/i135409.d: Expected symbol table contents. + * ld-mn10300/i136434.s: Linker string section merge test. + * ld-mn10300/i136434.d: Expected disassembly. + * ld-mn10300/i136434-2.s: Test source file. + 2007-10-17 Zack Weinberg Daniel Jacobowitz Mark Shinwell diff --git a/ld/testsuite/ld-mn10300/i112045-1.d b/ld/testsuite/ld-mn10300/i112045-1.d new file mode 100644 index 00000000000..dcb5a41dcea --- /dev/null +++ b/ld/testsuite/ld-mn10300/i112045-1.d @@ -0,0 +1,22 @@ + +tmpdir/i112045-1.x: file format elf32-.* + +Disassembly of section .text: + +0+0 <_start>: + 0: fc d0 f8 0f[ ]+add 4088,a0 + 4: 00 00 + 6: cb[ ]+nop[ ]+ + 7: cb[ ]+nop[ ]+ + +0+08 : + 8: fc d0 2b 01[ ]+add 299,a0 + c: 00 00 + e: cb[ ]+nop[ ]+ + f: cb[ ]+nop[ ]+ + +0+010 : + 10: fc d0 08 00[ ]+add 8,a0 + 14: 00 00 + 16: cb[ ]+nop[ ]+ + 17: cb[ ]+nop[ ]+ diff --git a/ld/testsuite/ld-mn10300/i112045-1.s b/ld/testsuite/ld-mn10300/i112045-1.s new file mode 100644 index 00000000000..b9e03463942 --- /dev/null +++ b/ld/testsuite/ld-mn10300/i112045-1.s @@ -0,0 +1,14 @@ + .text + .global _start +_start: + add 0x1000 - L01, A0 + nop + nop +L01: + add L01 + 0x123, A0 + nop + nop +L02: + add L02 - L01, A0 + nop + nop diff --git a/ld/testsuite/ld-mn10300/i112045-2.d b/ld/testsuite/ld-mn10300/i112045-2.d new file mode 100644 index 00000000000..9aa2d82290f --- /dev/null +++ b/ld/testsuite/ld-mn10300/i112045-2.d @@ -0,0 +1,6 @@ + +tmpdir/i112045-2.x: file format elf32-.* + +DYNAMIC RELOCATION RECORDS +OFFSET TYPE VALUE +[0-9a-f]+ R_MN10300_RELATIVE \*ABS\*\+0x[0-9a-f]+ diff --git a/ld/testsuite/ld-mn10300/i112045-2.s b/ld/testsuite/ld-mn10300/i112045-2.s new file mode 100644 index 00000000000..90e942d75e1 --- /dev/null +++ b/ld/testsuite/ld-mn10300/i112045-2.s @@ -0,0 +1,12 @@ + .section .data +L01: + .long L04 - L01 +L02: + .long L04 - L02 +L03: + .long L04 - L03 +L04: + .long L04 + .long L00 + .equ L00, 0xff + diff --git a/ld/testsuite/ld-mn10300/i126256-1.c b/ld/testsuite/ld-mn10300/i126256-1.c new file mode 100644 index 00000000000..5907d879a64 --- /dev/null +++ b/ld/testsuite/ld-mn10300/i126256-1.c @@ -0,0 +1,7 @@ +void +sub0 (int i) +{ + extern int sub (int); + + sub (i); +} diff --git a/ld/testsuite/ld-mn10300/i126256-2.c b/ld/testsuite/ld-mn10300/i126256-2.c new file mode 100644 index 00000000000..2948e5b3362 --- /dev/null +++ b/ld/testsuite/ld-mn10300/i126256-2.c @@ -0,0 +1,5 @@ +int +sub (int i) +{ + return i + 10; +} diff --git a/ld/testsuite/ld-mn10300/i135409.d b/ld/testsuite/ld-mn10300/i135409.d new file mode 100644 index 00000000000..2d64a42ca31 --- /dev/null +++ b/ld/testsuite/ld-mn10300/i135409.d @@ -0,0 +1,11 @@ + +Symbol table '.symtab' contains .. entries: + Num: Value Size Type Bind Vis Ndx Name +#... + ..: 0[0-9a-f]+[ ]+7 FUNC LOCAL DEFAULT . _func +#... + ..: 0[0-9a-f]+[ ]+0 NOTYPE LOCAL DEFAULT . A + ..: 0[0-9a-f]+[ ]+7 FUNC GLOBAL DEFAULT . _func2 +#... + ..: 0[0-9a-f]+[ ]+0 NOTYPE GLOBAL DEFAULT . BOTTOM +#... diff --git a/ld/testsuite/ld-mn10300/i135409.s b/ld/testsuite/ld-mn10300/i135409.s new file mode 100644 index 00000000000..b9faaf4117e --- /dev/null +++ b/ld/testsuite/ld-mn10300/i135409.s @@ -0,0 +1,29 @@ + .text + + nop + + .global _start +_start: + .type _func, @function +_func: + mov L001,A1 + nop +A: + mov L001,A1 + .size _func, . - _func + + + .global _func2 +_func2: + .type _func2, @function + mov L001,A1 + nop + mov L001,A1 + .size _func2, . - _func2 + + .global BOTTOM +BOTTOM: + + .data +L001: + diff --git a/ld/testsuite/ld-mn10300/i36434-2.s b/ld/testsuite/ld-mn10300/i36434-2.s new file mode 100644 index 00000000000..cf31ce102ac --- /dev/null +++ b/ld/testsuite/ld-mn10300/i36434-2.s @@ -0,0 +1,16 @@ + .section .text + .global _bar + .type _bar,@function +_bar: + mov .LC1,d0 + mov .LC2,d1 + nop + + .section .rodata.str1.1,"aMS",@progbits,1 +.LC1: + .rept 32768 + .byte 'a' + .endr + .byte 0 +.LC2: + .string "abc\n" diff --git a/ld/testsuite/ld-mn10300/i36434.d b/ld/testsuite/ld-mn10300/i36434.d new file mode 100644 index 00000000000..25cea45bf7e --- /dev/null +++ b/ld/testsuite/ld-mn10300/i36434.d @@ -0,0 +1,16 @@ + +tmpdir/i36434.x: file format elf32-.* + +Disassembly of section .text: + +08000000 <_start>: + 8000000: fc cd 18 80 mov 134250520,d1 + 8000004: 00 08 + 8000006: cb nop + +08000007 <_bar>: + 8000007: fc cc 14 00 mov 134217748,d0 + 800000b: 00 08 + 800000d: fc cd 15 80 mov 134250517,d1 + 8000011: 00 08 + 8000013: cb nop diff --git a/ld/testsuite/ld-mn10300/i36434.s b/ld/testsuite/ld-mn10300/i36434.s new file mode 100644 index 00000000000..84c1d83a199 --- /dev/null +++ b/ld/testsuite/ld-mn10300/i36434.s @@ -0,0 +1,10 @@ + .section .text + .global _start + .type _start,@function +_start: + mov .LC2,d1 + nop + + .section .rodata.str1.1,"aMS",@progbits,1 +.LC2: + .string "\n" diff --git a/ld/testsuite/ld-mn10300/mn10300.exp b/ld/testsuite/ld-mn10300/mn10300.exp new file mode 100644 index 00000000000..14ba85b20ab --- /dev/null +++ b/ld/testsuite/ld-mn10300/mn10300.exp @@ -0,0 +1,94 @@ +# Expect script for ld-mn10300 tests +# Copyright (C) 2007 Free Software Foundation +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +if {!([istarget "am3*-*-*"]) && !([istarget "mn10300*-*-*"]) } { + return +} + +# Set up a list as described in ld-lib.exp + +set am33_tests { + { + "am33 string merging" + "--relax -Ttext 0x8000000" + "" + { "i36434.s" "i36434-2.s" } + { {objdump -dz i36434.d} } + "i36434.x" + } + { + "difference of two symbols" + "-Ttext 0" + "" + { "i112045-1.s" } + { {objdump -d i112045-1.d} } + "i112045-1.x" + } + { + "(shared) difference of two symbols" + "-shared" + "" + { "i112045-2.s" } + { {objdump -R i112045-2.d} } + "i112045-2.x" + } + { + "adjustment of symbols due to relaxation" + "-Tdata 1f -relax" + "" + { "i135409.s" } + { {readelf --syms i135409.d } } + "i135409.x" + } +} + +run_ld_link_tests $am33_tests + +proc i126256-test { } { + global CC + global ld + global srcdir + global subdir + + set tmpdir tmpdir + set testname "Issue 126256 - seg fault whilst linking one shared library into another when relaxation is enabled." + + if { ![ld_compile "$CC -mrelax -fPIC" $srcdir/$subdir/i126256-1.c $tmpdir/i126256-1.o] } { + unresolved $testname + return + } + + if { ![ld_compile "$CC -mrelax -fPIC" $srcdir/$subdir/i126256-2.c $tmpdir/i126256-2.o] } { + unresolved $testname + return + } + + if { ![ld_simple_link $ld $tmpdir/i126256-1.so "-shared $tmpdir/i126256-1.o -e 0"]} { + unresolved $testname + return + } + + if { ![ld_simple_link $ld $tmpdir/i126256-2.so "--relax -shared $tmpdir/i126256-2.o $tmpdir/i126256-1.so -e 0"]} { + fail $testname + return + } + + pass $testname +} + +i126256-test