This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Hi all, I fixed some PIC bugs for Score. Please see changelog or attachment. gas/ * config/tc-score.c (build_lw_pic): Rename as build_lwst_pic. Delete the code handling large constant for PIC. Modify some comments. (score_relax_frag): Decrease insn_addr in certain situation. (s_score_cprestore): Change .cprestore syntax from ".cprestore offset" to ".cprestore reg, offset". bfd/ * elf32-score.c (score_elf_got_lo16_reloc): Change some variables type from unsigned to signed. (score_elf_final_link_relocate): Fix bugs of handling relocation type R_SCORE_GOT15, R_SCORE_GOT_LO16, and R_SCORE_REL32. (_bfd_score_elf_relocate_section): Handle R_SCORE_GOT_LO16 specially. Index: bfd/elf32-score.c =================================================================== RCS file: /cvs/src/src/bfd/elf32-score.c,v retrieving revision 1.5 diff -p -u -r1.5 elf32-score.c --- bfd/elf32-score.c 23 Oct 2006 02:41:11 -0000 1.5 +++ bfd/elf32-score.c 25 Dec 2006 08:40:47 -0000 @@ -532,8 +532,8 @@ score_elf_got_lo16_reloc (bfd *abfd, char **error_message ATTRIBUTE_UNUSED) { bfd_vma addend = 0, offset = 0; - unsigned long val; - unsigned long hi16_offset, hi16_value, uvalue; + signed long val; + signed long hi16_offset, hi16_value, uvalue; hi16_value = bfd_get_32 (abfd, hi16_rel_addr); hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; @@ -543,7 +543,10 @@ score_elf_got_lo16_reloc (bfd *abfd, if (reloc_entry->address > input_section->size) return bfd_reloc_outofrange; uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; - hi16_offset = (uvalue >> 16) & 0x7fff; + if ((uvalue > -0x8000) && (uvalue < 0x7fff)) + hi16_offset = 0; + else + hi16_offset = (uvalue >> 16) & 0x7fff; hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); bfd_put_32 (abfd, hi16_value, hi16_rel_addr); offset = (uvalue & 0xffff) << 1; @@ -1897,6 +1900,7 @@ score_elf_final_link_relocate (reloc_how r_symndx = ELF32_R_SYM (rel->r_info); r_type = ELF32_R_TYPE (rel->r_info); rel_addr = (input_section->output_section->vma + input_section->output_offset + rel->r_offset); + local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, TRUE); if (r_type == R_SCORE_GOT15) { @@ -1905,25 +1909,22 @@ score_elf_final_link_relocate (reloc_how const struct elf_backend_data *bed; bfd_vma lo_value = 0; - addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask; - bed = get_elf_backend_data (output_bfd); relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel; lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend); - if (lo16_rel != NULL) + if ((local_p) && (lo16_rel != NULL)) { - lo_value = (bfd_get_32 (input_bfd, contents + lo16_rel->r_offset) >> howto->bitpos) - & howto->src_mask; + bfd_vma tmp = 0; + tmp = bfd_get_32 (input_bfd, contents + lo16_rel->r_offset); + lo_value = (((tmp >> 16) & 0x3) << 14) | ((tmp & 0x7fff) >> 1); } - addend = (addend << 16) + lo_value; + addend = lo_value; } else { addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask; } - local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, TRUE); - /* If we haven't already determined the GOT offset, or the GP value, and we're going to need it, get it now. */ switch (r_type) @@ -1932,9 +1933,21 @@ score_elf_final_link_relocate (reloc_how case R_SCORE_GOT15: if (!local_p) { - g = score_elf_global_got_index (elf_hash_table (info)->dynobj, - (struct elf_link_hash_entry *) h); - } + g = score_elf_global_got_index (elf_hash_table (info)->dynobj, + (struct elf_link_hash_entry *) h); + if ((! elf_hash_table(info)->dynamic_sections_created + || (info->shared + && (info->symbolic || h->root.dynindx == -1) + && h->root.def_regular))) + { + /* This is a static link or a -Bsymbolic link. The + symbol is defined locally, or was forced to be local. + We must initialize this entry in the GOT. */ + bfd *tmpbfd = elf_hash_table (info)->dynobj; + asection *sgot = score_elf_got_section (tmpbfd, FALSE); + bfd_put_32 (tmpbfd, value, sgot->contents + g); + } + } else if (r_type == R_SCORE_GOT15 || r_type == R_SCORE_CALL15) { /* There's no need to create a local GOT entry here; the @@ -1993,6 +2006,11 @@ score_elf_final_link_relocate (reloc_how input_section)) return bfd_reloc_undefined; } + else if (r_symndx == 0) + /* r_symndx will be zero only for relocs against symbols + from removed linkonce sections, or sections discarded by + a linker script. */ + value = 0; else { if (r_type != R_SCORE_REL32) @@ -2122,7 +2140,10 @@ score_elf_final_link_relocate (reloc_how if ((long) value > 0x3fff || (long) value < -0x4000) return bfd_reloc_overflow; - bfd_put_16 (input_bfd, value, hit_data + 2); + + addend = bfd_get_32 (input_bfd, hit_data); + value = (addend & ~howto->dst_mask) | (value & howto->dst_mask); + bfd_put_32 (input_bfd, value, hit_data); return bfd_reloc_ok; case R_SCORE_GPREL32: @@ -2133,10 +2154,10 @@ score_elf_final_link_relocate (reloc_how case R_SCORE_GOT_LO16: addend = bfd_get_32 (input_bfd, hit_data); - value = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; + value = (((addend >> 16) & 0x3) << 14) | ((addend & 0x7fff) >> 1); value += symbol; - offset = (value & 0xffff) << 1; - value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000); + value = (addend & (~(howto->dst_mask))) | ((value & 0x3fff) << 1) + | (((value >> 14) & 0x3) << 16); bfd_put_32 (input_bfd, value, hit_data); return bfd_reloc_ok; @@ -2303,6 +2324,17 @@ _bfd_score_elf_relocate_section (bfd *ou | (offset & 0x7fff) | ((offset << 1) & 0x30000); bfd_put_32 (input_bfd, value, contents + rel->r_offset); break; + case R_SCORE_GOT_LO16: + value = bfd_get_32 (input_bfd, contents + rel->r_offset); + addend = (((value >> 16) & 0x3) << 14) | ((value & 0x7fff) >> 1); + msec = sec; + addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; + addend += msec->output_section->vma + msec->output_offset; + value = (value & (~(howto->dst_mask))) | ((addend & 0x3fff) << 1) + | (((addend >> 14) & 0x3) << 16); + + bfd_put_32 (input_bfd, value, contents + rel->r_offset); + break; default: value = bfd_get_32 (input_bfd, contents + rel->r_offset); /* Get the (signed) value from the instruction. */ Index: gas/config/tc-score.c =================================================================== RCS file: /cvs/src/src/gas/config/tc-score.c,v retrieving revision 1.6 diff -p -u -r1.6 tc-score.c --- gas/config/tc-score.c 16 Nov 2006 04:36:25 -0000 1.6 +++ gas/config/tc-score.c 25 Dec 2006 08:40:50 -0000 @@ -783,7 +783,7 @@ static const struct asm_opcode score_ins {"ldis_pic", 0x0a0c0000, 0x3e0e0000, 0x5000, Insn_internal, do_rdi16_pic}, {"addi_s_pic",0x02000000, 0x3e0e0001, 0x8000, Insn_internal, do_addi_s_pic}, {"addi_u_pic",0x02000000, 0x3e0e0001, 0x8000, Insn_internal, do_addi_u_pic}, - {"lw_pic", 0x20000000, 0x3e000000, 0x2008, Insn_internal, do_lw_pic}, + {"lw_pic", 0x20000000, 0x3e000000, 0x8000, Insn_internal, do_lw_pic}, }; /* Next free entry in the pool. */ @@ -3747,9 +3747,10 @@ build_la_pic (int reg_rd, expressionS ex fix_num = 1; var_num = 2; - /* Insn 1 and Insn 2 */ + /* For an external symbol, only one insn is generated; + For a local symbol, two insns are generated. */ /* Fix part - For an external symbol: lw rD, <sym>($gp) + For an external symbol: lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15 or BFD_RELOC_SCORE_CALL15) */ sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name); if (append_insn (tmp, FALSE) == (int) FAIL) @@ -4149,11 +4150,11 @@ nopic_need_relax (symbolS * sym, int bef return 1; } -/* Build a relax frag for lw instruction when generating PIC, +/* Build a relax frag for lw/st instruction when generating PIC, external symbol first and local symbol second. */ static void -build_lw_pic (int reg_rd, expressionS exp) +build_lwst_pic (int reg_rd, expressionS exp, const char *insn_name) { symbolS *add_symbol = exp.X_add_symbol; int add_number = exp.X_add_number; @@ -4172,13 +4173,14 @@ build_lw_pic (int reg_rd, expressionS ex fix_num = 1; var_num = 2; - /* Insn 1 and Insn 2 */ + /* For an external symbol, two insns are generated; + For a local symbol, three insns are generated. */ /* Fix part - For an external symbol: lw rD, <sym>($gp) + For an external symbol: lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15) */ - sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name); + sprintf (tmp, "lw_pic %s, %s", "r1", add_symbol->bsym->name); if (append_insn (tmp, FALSE) == (int) FAIL) - return; + return; memcpy (&fix_insts[0], &inst, sizeof (struct score_it)); @@ -4188,91 +4190,25 @@ build_lw_pic (int reg_rd, expressionS ex addi rD, <sym> (BFD_RELOC_GOT_LO16) */ inst.reloc.type = BFD_RELOC_SCORE_GOT15; memcpy (&var_insts[0], &inst, sizeof (struct score_it)); - sprintf (tmp, "addi_s_pic r%d, %s", reg_rd, add_symbol->bsym->name); + sprintf (tmp, "addi_s_pic %s, %s", "r1", add_symbol->bsym->name); if (append_insn (tmp, FALSE) == (int) FAIL) - return; + return; memcpy (&var_insts[1], &inst, sizeof (struct score_it)); build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol); - /* Insn 2: lw rD, [rD, constant] */ - sprintf (tmp, "lw r%d, [r%d, %d]", reg_rd, reg_rd, add_number); + /* Insn 2 or Insn 3: lw/st rD, [r1, constant] */ + sprintf (tmp, "%s r%d, [%s, %d]", insn_name, reg_rd, "r1", add_number); if (append_insn (tmp, TRUE) == (int) FAIL) - return; + return; - /* Set bwarn as -1, so macro instruction itself will not be generated frag. */ - inst.bwarn = -1; + /* Set bwarn as -1, so macro instruction itself will not be generated frag. */ + inst.bwarn = -1; } else { - int hi = (add_number >> 16) & 0x0000FFFF; - int lo = add_number & 0x0000FFFF; - - /* Insn 1: lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15) */ - sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name); - if (append_insn (tmp, TRUE) == (int) FAIL) - return; - - /* Insn 2 */ - fix_num = 1; - var_num = 1; - /* Fix part - For an external symbol: ldis r1, HI%<constant> */ - sprintf (tmp, "ldis %s, %d", "r1", hi); - if (append_insn (tmp, FALSE) == (int) FAIL) - return; - - memcpy (&fix_insts[0], &inst, sizeof (struct score_it)); - - /* Var part - For a local symbol: ldis r1, HI%<constant> - but, if lo is outof 16 bit, make hi plus 1 */ - if ((lo < -0x8000) || (lo > 0x7fff)) - { - hi += 1; - } - sprintf (tmp, "ldis_pic %s, %d", "r1", hi); - if (append_insn (tmp, FALSE) == (int) FAIL) - return; - - memcpy (&var_insts[0], &inst, sizeof (struct score_it)); - build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol); - - /* Insn 3 */ - fix_num = 1; - var_num = 1; - /* Fix part - For an external symbol: ori r1, LO%<constant> */ - sprintf (tmp, "ori %s, %d", "r1", lo); - if (append_insn (tmp, FALSE) == (int) FAIL) - return; - - memcpy (&fix_insts[0], &inst, sizeof (struct score_it)); - - /* Var part - For a local symbol: addi r1, <sym>+LO%<constant> (BFD_RELOC_GOT_LO16) */ - sprintf (tmp, "addi_u_pic %s, %s + %d", "r1", add_symbol->bsym->name, lo); - if (append_insn (tmp, FALSE) == (int) FAIL) - return; - - memcpy (&var_insts[0], &inst, sizeof (struct score_it)); - build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol); - - /* Insn 4: add rD, rD, r1 */ - sprintf (tmp, "add r%d, r%d, %s", reg_rd, reg_rd, "r1"); - if (append_insn (tmp, TRUE) == (int) FAIL) - return; - - /* Set bwarn as -1, so macro instruction itself will not be generated frag. */ - inst.bwarn = -1; - - /* Insn 5: lw rD, [rD, 0] */ - sprintf (tmp, "lw r%d, [r%d, 0]", reg_rd, reg_rd); - if (append_insn (tmp, TRUE) == (int) FAIL) - return; - - /* Set bwarn as -1, so macro instruction itself will not be generated frag. */ - inst.bwarn = -1; + inst.error = _("PIC code offset overflow (max 16 signed bits)"); + return; } nor1 = r1_bak; @@ -4354,8 +4290,10 @@ do_macro_ldst_label (char *str) if (score_pic == PIC) { - build_lw_pic (reg_rd, inst.reloc.exp); - return; + int ldst_idx = 0; + ldst_idx = inst.instruction & OPC_PSEUDOLDST_MASK; + build_lwst_pic (reg_rd, inst.reloc.exp, score_ldst_insns[ldst_idx * 3 + 0].template); + return; } else { @@ -5006,9 +4944,17 @@ score_relax_frag (asection * sec ATTRIBU { if (!word_align_p) { - fragp->insn_addr += 2; - grows += 2; - } + if (fragp->insn_addr < 2) + { + fragp->insn_addr += 2; + grows += 2; + } + else + { + fragp->insn_addr -= 2; + grows -= 2; + } + } if (fragp->fr_opcode) fragp->fr_fix = RELAX_NEW (fragp->fr_subtype) + fragp->insn_addr; @@ -6291,7 +6237,7 @@ s_score_cpload (int ignore ATTRIBUTE_UNU static void s_score_cprestore (int ignore ATTRIBUTE_UNUSED) { -#define SCORE_BP_REG 2 + int reg; int cprestore_offset; char insn_str[MAX_LITERAL_POOL_SIZE]; @@ -6302,11 +6248,43 @@ s_score_cprestore (int ignore ATTRIBUTE_ return; } + if ((reg = reg_required_here (&input_line_pointer, -1, REG_TYPE_SCORE)) == (int) FAIL + || skip_past_comma (&input_line_pointer) == (int) FAIL) + { + return; + } + cprestore_offset = get_absolute_expression (); - sprintf (insn_str, "sw r%d, [r%d, %d]", GP, SCORE_BP_REG, cprestore_offset); - if (append_insn (insn_str, TRUE) == (int) FAIL) - return; + if (cprestore_offset <= 0x3fff) + { + sprintf (insn_str, "sw r%d, [r%d, %d]", GP, reg, cprestore_offset); + if (append_insn (insn_str, TRUE) == (int) FAIL) + return; + } + else + { + int r1_bak; + + r1_bak = nor1; + nor1 = 0; + + sprintf (insn_str, "li r1, %d", cprestore_offset); + if (append_insn (insn_str, TRUE) == (int) FAIL) + return; + + sprintf (insn_str, "add r1, r1, r%d", reg); + if (append_insn (insn_str, TRUE) == (int) FAIL) + return; + + sprintf (insn_str, "sw r%d, [r1]", GP); + if (append_insn (insn_str, TRUE) == (int) FAIL) + return; + + nor1 = r1_bak; + } + + demand_empty_rest_of_line (); } /* Handle the .gpword pseudo-op. This is used when generating PIC Best regards Ligang
Attachment:
diffs.tar.bz2
Description: Binary data
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |