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
LigangAttachment:
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] |