| 1 |
/* 32-bit ELF support for S+core. |
/* 32-bit ELF support for S+core. |
| 2 |
Copyright 2006, 2007 Free Software Foundation, Inc. |
Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. |
| 3 |
Contributed by |
Contributed by |
| 4 |
|
Brain.lin (brain.lin@sunplusct.com) |
| 5 |
Mei Ligang (ligang@sunnorth.com.cn) |
Mei Ligang (ligang@sunnorth.com.cn) |
| 6 |
Pei-Lin Tsai (pltsai@sunplus.com) |
Pei-Lin Tsai (pltsai@sunplus.com) |
| 7 |
|
|
| 31 |
#include "elf/common.h" |
#include "elf/common.h" |
| 32 |
#include "elf/internal.h" |
#include "elf/internal.h" |
| 33 |
#include "hashtab.h" |
#include "hashtab.h" |
| 34 |
|
#include "elf32-score.h" |
| 35 |
|
|
| 36 |
|
|
| 37 |
/* Score ELF linker hash table. */ |
int score3 = 0; |
| 38 |
|
int score7 = 1; |
| 39 |
|
|
| 40 |
|
/* Score ELF linker hash table. */ |
| 41 |
struct score_elf_link_hash_table |
struct score_elf_link_hash_table |
| 42 |
{ |
{ |
| 43 |
/* The main hash table. */ |
/* The main hash table. */ |
| 46 |
|
|
| 47 |
/* The SCORE ELF linker needs additional information for each symbol in |
/* The SCORE ELF linker needs additional information for each symbol in |
| 48 |
the global hash table. */ |
the global hash table. */ |
|
|
|
| 49 |
struct score_elf_link_hash_entry |
struct score_elf_link_hash_entry |
| 50 |
{ |
{ |
| 51 |
struct elf_link_hash_entry root; |
struct elf_link_hash_entry root; |
| 178 |
#define SCORE_ELF_STUB_SECTION_NAME (".SCORE.stub") |
#define SCORE_ELF_STUB_SECTION_NAME (".SCORE.stub") |
| 179 |
#define SCORE_FUNCTION_STUB_SIZE (16) |
#define SCORE_FUNCTION_STUB_SIZE (16) |
| 180 |
|
|
| 181 |
#define STUB_LW 0xc3bcc010 /* lw r29, [r28, -0x3ff0] */ |
#define STUB_LW 0xc3bcc010 /* lw r29, [r28, -0x3ff0] */ |
| 182 |
#define STUB_MOVE 0x8363bc56 /* mv r27, r3 */ |
#define STUB_MOVE 0x8363bc56 /* mv r27, r3 */ |
| 183 |
#define STUB_LI16 0x87548000 /* ori r26, .dynsym_index */ |
#define STUB_LI16 0x87548000 /* ori r26, .dynsym_index */ |
| 184 |
#define STUB_BRL 0x801dbc09 /* brl r29 */ |
#define STUB_BRL 0x801dbc09 /* brl r29 */ |
| 201 |
#define SCORE_ELF_LOG_FILE_ALIGN(abfd)\ |
#define SCORE_ELF_LOG_FILE_ALIGN(abfd)\ |
| 202 |
(get_elf_backend_data (abfd)->s->log_file_align) |
(get_elf_backend_data (abfd)->s->log_file_align) |
| 203 |
|
|
|
#ifndef NUM_ELEM |
|
|
#define NUM_ELEM(a) (sizeof (a) / (sizeof (a)[0])) |
|
|
#endif |
|
|
|
|
| 204 |
static bfd_byte *hi16_rel_addr; |
static bfd_byte *hi16_rel_addr; |
| 205 |
|
|
| 206 |
/* This will be used when we sort the dynamic relocation records. */ |
/* This will be used when we sort the dynamic relocation records. */ |
| 215 |
static asymbol score_elf_scom_symbol; |
static asymbol score_elf_scom_symbol; |
| 216 |
static asymbol *score_elf_scom_symbol_ptr; |
static asymbol *score_elf_scom_symbol_ptr; |
| 217 |
|
|
| 218 |
|
static bfd_vma |
| 219 |
|
score_bfd_get_16 (bfd *abfd, const void *data) |
| 220 |
|
{ |
| 221 |
|
return bfd_get_16 (abfd, data); |
| 222 |
|
} |
| 223 |
|
|
| 224 |
|
static bfd_vma |
| 225 |
|
score3_bfd_getl32 (const void *p) |
| 226 |
|
{ |
| 227 |
|
const bfd_byte *addr = p; |
| 228 |
|
unsigned long v; |
| 229 |
|
|
| 230 |
|
v = (unsigned long) addr[2]; |
| 231 |
|
v |= (unsigned long) addr[3] << 8; |
| 232 |
|
v |= (unsigned long) addr[0] << 16; |
| 233 |
|
v |= (unsigned long) addr[1] << 24; |
| 234 |
|
return v; |
| 235 |
|
} |
| 236 |
|
|
| 237 |
|
static bfd_vma |
| 238 |
|
score3_bfd_getl48 (const void *p) |
| 239 |
|
{ |
| 240 |
|
const bfd_byte *addr = p; |
| 241 |
|
unsigned long long v; |
| 242 |
|
|
| 243 |
|
v = (unsigned long long) addr[4]; |
| 244 |
|
v |= (unsigned long long) addr[5] << 8; |
| 245 |
|
v |= (unsigned long long) addr[2] << 16; |
| 246 |
|
v |= (unsigned long long) addr[3] << 24; |
| 247 |
|
v |= (unsigned long long) addr[0] << 32; |
| 248 |
|
v |= (unsigned long long) addr[1] << 40; |
| 249 |
|
return v; |
| 250 |
|
} |
| 251 |
|
|
| 252 |
|
static bfd_vma |
| 253 |
|
score_bfd_get_32 (bfd *abfd, const void *data) |
| 254 |
|
{ |
| 255 |
|
if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE) |
| 256 |
|
return score3_bfd_getl32 (data); |
| 257 |
|
else |
| 258 |
|
return bfd_get_32 (abfd, data); |
| 259 |
|
} |
| 260 |
|
|
| 261 |
|
static bfd_vma |
| 262 |
|
score_bfd_get_48 (bfd *abfd, const void *p) |
| 263 |
|
{ |
| 264 |
|
if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE) |
| 265 |
|
return score3_bfd_getl48 (p); |
| 266 |
|
else |
| 267 |
|
return bfd_get_bits (p, 48, 1); |
| 268 |
|
} |
| 269 |
|
|
| 270 |
|
static void |
| 271 |
|
score_bfd_put_16 (bfd *abfd, bfd_vma addr, void *data) |
| 272 |
|
{ |
| 273 |
|
return bfd_put_16 (abfd, addr, data); |
| 274 |
|
} |
| 275 |
|
|
| 276 |
|
static void |
| 277 |
|
score3_bfd_putl32 (bfd_vma data, void *p) |
| 278 |
|
{ |
| 279 |
|
bfd_byte *addr = p; |
| 280 |
|
addr[0] = (data >> 16) & 0xff; |
| 281 |
|
addr[1] = (data >> 24) & 0xff; |
| 282 |
|
addr[2] = data & 0xff; |
| 283 |
|
addr[3] = (data >> 8) & 0xff; |
| 284 |
|
} |
| 285 |
|
|
| 286 |
|
static void |
| 287 |
|
score3_bfd_putl48 (bfd_vma data, void *p) |
| 288 |
|
{ |
| 289 |
|
bfd_byte *addr = p; |
| 290 |
|
addr[0] = (data >> 32) & 0xff; |
| 291 |
|
addr[1] = (data >> 40) & 0xff; |
| 292 |
|
addr[2] = (data >> 16) & 0xff; |
| 293 |
|
addr[3] = (data >> 24) & 0xff; |
| 294 |
|
addr[4] = data & 0xff; |
| 295 |
|
addr[5] = (data >> 8) & 0xff; |
| 296 |
|
} |
| 297 |
|
|
| 298 |
|
static void |
| 299 |
|
score_bfd_put_32 (bfd *abfd, bfd_vma addr, void *data) |
| 300 |
|
{ |
| 301 |
|
if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE) |
| 302 |
|
return score3_bfd_putl32 (addr, data); |
| 303 |
|
else |
| 304 |
|
return bfd_put_32 (abfd, addr, data); |
| 305 |
|
} |
| 306 |
|
|
| 307 |
|
static void |
| 308 |
|
score_bfd_put_48 (bfd *abfd, bfd_vma val, void *p) |
| 309 |
|
{ |
| 310 |
|
if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE) |
| 311 |
|
return score3_bfd_putl48 (val, p); |
| 312 |
|
else |
| 313 |
|
return bfd_put_bits (val, p, 48, 1); |
| 314 |
|
} |
| 315 |
|
|
| 316 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
| 317 |
score_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, |
score_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, |
| 318 |
arelent *reloc_entry, |
arelent *reloc_entry, |
| 319 |
asymbol *symbol ATTRIBUTE_UNUSED, |
asymbol *symbol ATTRIBUTE_UNUSED, |
| 320 |
void * data, |
void * data, |
| 321 |
asection *input_section ATTRIBUTE_UNUSED, |
asection *input_section ATTRIBUTE_UNUSED, |
| 322 |
bfd *output_bfd ATTRIBUTE_UNUSED, |
bfd *output_bfd ATTRIBUTE_UNUSED, |
| 323 |
char **error_message ATTRIBUTE_UNUSED) |
char **error_message ATTRIBUTE_UNUSED) |
| 324 |
{ |
{ |
| 325 |
hi16_rel_addr = (bfd_byte *) data + reloc_entry->address; |
hi16_rel_addr = (bfd_byte *) data + reloc_entry->address; |
| 326 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 328 |
|
|
| 329 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
| 330 |
score_elf_lo16_reloc (bfd *abfd, |
score_elf_lo16_reloc (bfd *abfd, |
| 331 |
arelent *reloc_entry, |
arelent *reloc_entry, |
| 332 |
asymbol *symbol ATTRIBUTE_UNUSED, |
asymbol *symbol ATTRIBUTE_UNUSED, |
| 333 |
void * data, |
void * data, |
| 334 |
asection *input_section, |
asection *input_section, |
| 335 |
bfd *output_bfd ATTRIBUTE_UNUSED, |
bfd *output_bfd ATTRIBUTE_UNUSED, |
| 336 |
char **error_message ATTRIBUTE_UNUSED) |
char **error_message ATTRIBUTE_UNUSED) |
| 337 |
{ |
{ |
| 338 |
bfd_vma addend = 0, offset = 0; |
bfd_vma addend = 0, offset = 0; |
| 339 |
unsigned long val; |
unsigned long val; |
| 340 |
unsigned long hi16_offset, hi16_value, uvalue; |
unsigned long hi16_offset, hi16_value, uvalue; |
| 341 |
|
|
| 342 |
hi16_value = bfd_get_32 (abfd, hi16_rel_addr); |
hi16_value = score_bfd_get_32 (abfd, hi16_rel_addr); |
| 343 |
hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; |
hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; |
| 344 |
addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); |
addend = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); |
| 345 |
offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; |
offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; |
| 346 |
val = reloc_entry->addend; |
val = reloc_entry->addend; |
| 347 |
if (reloc_entry->address > input_section->size) |
if (reloc_entry->address > input_section->size) |
| 349 |
uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; |
uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; |
| 350 |
hi16_offset = (uvalue >> 16) << 1; |
hi16_offset = (uvalue >> 16) << 1; |
| 351 |
hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); |
hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); |
| 352 |
bfd_put_32 (abfd, hi16_value, hi16_rel_addr); |
score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr); |
| 353 |
offset = (uvalue & 0xffff) << 1; |
offset = (uvalue & 0xffff) << 1; |
| 354 |
addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); |
addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); |
| 355 |
bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); |
score_bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); |
| 356 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 357 |
} |
} |
| 358 |
|
|
| 381 |
else |
else |
| 382 |
{ |
{ |
| 383 |
for (i = 0; i < count; i++, sym++) |
for (i = 0; i < count; i++, sym++) |
| 384 |
{ |
{ |
| 385 |
const char *name; |
const char *name; |
| 386 |
|
|
| 387 |
name = bfd_asymbol_name (*sym); |
name = bfd_asymbol_name (*sym); |
| 388 |
if (*name == '_' && strcmp (name, "_gp") == 0) |
if (*name == '_' && strcmp (name, "_gp") == 0) |
| 389 |
{ |
{ |
| 390 |
*pgp = bfd_asymbol_value (*sym); |
*pgp = bfd_asymbol_value (*sym); |
| 391 |
_bfd_set_gp_value (output_bfd, *pgp); |
_bfd_set_gp_value (output_bfd, *pgp); |
| 392 |
break; |
break; |
| 393 |
} |
} |
| 394 |
} |
} |
| 395 |
} |
} |
| 396 |
|
|
| 397 |
if (i >= count) |
if (i >= count) |
| 410 |
BFD. If we can't find it, we're stuck. We cache it in the ELF |
BFD. If we can't find it, we're stuck. We cache it in the ELF |
| 411 |
target data. We don't need to adjust the symbol value for an |
target data. We don't need to adjust the symbol value for an |
| 412 |
external symbol if we are producing relocatable output. */ |
external symbol if we are producing relocatable output. */ |
|
|
|
| 413 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
| 414 |
score_elf_final_gp (bfd *output_bfd, |
score_elf_final_gp (bfd *output_bfd, |
| 415 |
asymbol *symbol, |
asymbol *symbol, |
| 416 |
bfd_boolean relocatable, |
bfd_boolean relocatable, |
| 417 |
char **error_message, |
char **error_message, |
| 418 |
bfd_vma *pgp) |
bfd_vma *pgp) |
| 419 |
{ |
{ |
| 420 |
if (bfd_is_und_section (symbol->section) |
if (bfd_is_und_section (symbol->section) |
| 421 |
&& ! relocatable) |
&& ! relocatable) |
| 427 |
*pgp = _bfd_get_gp_value (output_bfd); |
*pgp = _bfd_get_gp_value (output_bfd); |
| 428 |
if (*pgp == 0 |
if (*pgp == 0 |
| 429 |
&& (! relocatable |
&& (! relocatable |
| 430 |
|| (symbol->flags & BSF_SECTION_SYM) != 0)) |
|| (symbol->flags & BSF_SECTION_SYM) != 0)) |
| 431 |
{ |
{ |
| 432 |
if (relocatable) |
if (relocatable) |
| 433 |
{ |
{ |
| 434 |
/* Make up a value. */ |
/* Make up a value. */ |
| 435 |
*pgp = symbol->section->output_section->vma + 0x4000; |
*pgp = symbol->section->output_section->vma + 0x4000; |
| 436 |
_bfd_set_gp_value (output_bfd, *pgp); |
_bfd_set_gp_value (output_bfd, *pgp); |
| 437 |
} |
} |
| 438 |
else if (!score_elf_assign_gp (output_bfd, pgp)) |
else if (!score_elf_assign_gp (output_bfd, pgp)) |
| 439 |
{ |
{ |
| 440 |
*error_message = |
*error_message = |
| 441 |
(char *) _("GP relative relocation when _gp not defined"); |
(char *) _("GP relative relocation when _gp not defined"); |
| 442 |
return bfd_reloc_dangerous; |
return bfd_reloc_dangerous; |
| 443 |
} |
} |
| 444 |
} |
} |
| 445 |
|
|
| 446 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 448 |
|
|
| 449 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
| 450 |
score_elf_gprel15_with_gp (bfd *abfd, |
score_elf_gprel15_with_gp (bfd *abfd, |
| 451 |
asymbol *symbol, |
asymbol *symbol, |
| 452 |
arelent *reloc_entry, |
arelent *reloc_entry, |
| 453 |
asection *input_section, |
asection *input_section, |
| 454 |
bfd_boolean relocateable, |
bfd_boolean relocateable, |
| 455 |
void * data, |
void * data, |
| 456 |
bfd_vma gp ATTRIBUTE_UNUSED) |
bfd_vma gp ATTRIBUTE_UNUSED) |
| 457 |
{ |
{ |
| 458 |
bfd_vma relocation; |
bfd_vma relocation; |
| 459 |
unsigned long insn; |
unsigned long insn; |
| 468 |
if (reloc_entry->address > input_section->size) |
if (reloc_entry->address > input_section->size) |
| 469 |
return bfd_reloc_outofrange; |
return bfd_reloc_outofrange; |
| 470 |
|
|
| 471 |
insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); |
insn = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); |
| 472 |
if (((reloc_entry->addend & 0xffffc000) != 0) |
if (((reloc_entry->addend & 0xffffc000) != 0) |
| 473 |
&& ((reloc_entry->addend & 0xffffc000) != 0xffffc000)) |
&& ((reloc_entry->addend & 0xffffc000) != 0xffffc000)) |
| 474 |
return bfd_reloc_overflow; |
return bfd_reloc_overflow; |
| 475 |
|
|
| 476 |
insn = (insn & ~0x7fff) | (reloc_entry->addend & 0x7fff); |
insn = (insn & ~0x7fff) | (reloc_entry->addend & 0x7fff); |
| 477 |
bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); |
score_bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); |
| 478 |
if (relocateable) |
if (relocateable) |
| 479 |
reloc_entry->address += input_section->output_offset; |
reloc_entry->address += input_section->output_offset; |
| 480 |
|
|
| 483 |
|
|
| 484 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
| 485 |
gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry, |
gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry, |
| 486 |
asection *input_section, bfd_boolean relocatable, |
asection *input_section, bfd_boolean relocatable, |
| 487 |
void *data, bfd_vma gp) |
void *data, bfd_vma gp) |
| 488 |
{ |
{ |
| 489 |
bfd_vma relocation; |
bfd_vma relocation; |
| 490 |
bfd_vma val; |
bfd_vma val; |
| 504 |
val = reloc_entry->addend; |
val = reloc_entry->addend; |
| 505 |
|
|
| 506 |
if (reloc_entry->howto->partial_inplace) |
if (reloc_entry->howto->partial_inplace) |
| 507 |
val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); |
val += score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); |
| 508 |
|
|
| 509 |
/* Adjust val for the final section location and GP value. If we |
/* Adjust val for the final section location and GP value. If we |
| 510 |
are producing relocatable output, we don't want to do this for |
are producing relocatable output, we don't want to do this for |
| 514 |
val += relocation - gp; |
val += relocation - gp; |
| 515 |
|
|
| 516 |
if (reloc_entry->howto->partial_inplace) |
if (reloc_entry->howto->partial_inplace) |
| 517 |
bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); |
score_bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); |
| 518 |
else |
else |
| 519 |
reloc_entry->addend = val; |
reloc_entry->addend = val; |
| 520 |
|
|
| 526 |
|
|
| 527 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
| 528 |
score_elf_gprel15_reloc (bfd *abfd, |
score_elf_gprel15_reloc (bfd *abfd, |
| 529 |
arelent *reloc_entry, |
arelent *reloc_entry, |
| 530 |
asymbol *symbol, |
asymbol *symbol, |
| 531 |
void * data, |
void * data, |
| 532 |
asection *input_section, |
asection *input_section, |
| 533 |
bfd *output_bfd, |
bfd *output_bfd, |
| 534 |
char **error_message) |
char **error_message) |
| 535 |
{ |
{ |
| 536 |
bfd_boolean relocateable; |
bfd_boolean relocateable; |
| 537 |
bfd_reloc_status_type ret; |
bfd_reloc_status_type ret; |
| 538 |
bfd_vma gp; |
bfd_vma gp; |
| 539 |
|
|
| 540 |
if (output_bfd != (bfd *) NULL |
if (output_bfd != NULL |
| 541 |
&& (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0) |
&& (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0) |
| 542 |
{ |
{ |
| 543 |
reloc_entry->address += input_section->output_offset; |
reloc_entry->address += input_section->output_offset; |
| 544 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 545 |
} |
} |
| 546 |
if (output_bfd != (bfd *) NULL) |
if (output_bfd != NULL) |
| 547 |
relocateable = TRUE; |
relocateable = TRUE; |
| 548 |
else |
else |
| 549 |
{ |
{ |
| 564 |
|
|
| 565 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
| 566 |
score_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
score_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
| 567 |
void *data, asection *input_section, bfd *output_bfd, |
void *data, asection *input_section, bfd *output_bfd, |
| 568 |
char **error_message) |
char **error_message) |
| 569 |
{ |
{ |
| 570 |
bfd_boolean relocatable; |
bfd_boolean relocatable; |
| 571 |
bfd_reloc_status_type ret; |
bfd_reloc_status_type ret; |
| 577 |
&& (symbol->flags & BSF_LOCAL) != 0) |
&& (symbol->flags & BSF_LOCAL) != 0) |
| 578 |
{ |
{ |
| 579 |
*error_message = (char *) |
*error_message = (char *) |
| 580 |
_("32bits gp relative relocation occurs for an external symbol"); |
_("32bits gp relative relocation occurs for an external symbol"); |
| 581 |
return bfd_reloc_outofrange; |
return bfd_reloc_outofrange; |
| 582 |
} |
} |
| 583 |
|
|
| 593 |
if (ret != bfd_reloc_ok) |
if (ret != bfd_reloc_ok) |
| 594 |
return ret; |
return ret; |
| 595 |
|
|
| 596 |
gp = 0; /* FIXME. */ |
gp = 0; |
| 597 |
return gprel32_with_gp (abfd, symbol, reloc_entry, input_section, |
return gprel32_with_gp (abfd, symbol, reloc_entry, input_section, |
| 598 |
relocatable, data, gp); |
relocatable, data, gp); |
| 599 |
} |
} |
| 600 |
|
|
| 601 |
/* A howto special_function for R_SCORE_GOT15 relocations. This is just |
/* A howto special_function for R_SCORE_GOT15 relocations. This is just |
| 602 |
like any other 16-bit relocation when applied to global symbols, but is |
like any other 16-bit relocation when applied to global symbols, but is |
| 603 |
treated in the same as R_SCORE_HI16 when applied to local symbols. */ |
treated in the same as R_SCORE_HI16 when applied to local symbols. */ |
|
|
|
| 604 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
| 605 |
score_elf_got15_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
score_elf_got15_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
| 606 |
void *data, asection *input_section, |
void *data, asection *input_section, |
| 607 |
bfd *output_bfd, char **error_message) |
bfd *output_bfd, char **error_message) |
| 608 |
{ |
{ |
| 609 |
if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 |
if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 |
| 610 |
|| bfd_is_und_section (bfd_get_section (symbol)) |
|| bfd_is_und_section (bfd_get_section (symbol)) |
| 611 |
|| bfd_is_com_section (bfd_get_section (symbol))) |
|| bfd_is_com_section (bfd_get_section (symbol))) |
| 612 |
/* The relocation is against a global symbol. */ |
/* The relocation is against a global symbol. */ |
| 613 |
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, |
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, |
| 614 |
input_section, output_bfd, |
input_section, output_bfd, |
| 615 |
error_message); |
error_message); |
| 616 |
|
|
| 617 |
return score_elf_hi16_reloc (abfd, reloc_entry, symbol, data, |
return score_elf_hi16_reloc (abfd, reloc_entry, symbol, data, |
| 618 |
input_section, output_bfd, error_message); |
input_section, output_bfd, error_message); |
| 619 |
} |
} |
| 620 |
|
|
| 621 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
| 622 |
score_elf_got_lo16_reloc (bfd *abfd, |
score_elf_got_lo16_reloc (bfd *abfd, |
| 623 |
arelent *reloc_entry, |
arelent *reloc_entry, |
| 624 |
asymbol *symbol ATTRIBUTE_UNUSED, |
asymbol *symbol ATTRIBUTE_UNUSED, |
| 625 |
void * data, |
void * data, |
| 626 |
asection *input_section, |
asection *input_section, |
| 627 |
bfd *output_bfd ATTRIBUTE_UNUSED, |
bfd *output_bfd ATTRIBUTE_UNUSED, |
| 628 |
char **error_message ATTRIBUTE_UNUSED) |
char **error_message ATTRIBUTE_UNUSED) |
| 629 |
{ |
{ |
| 630 |
bfd_vma addend = 0, offset = 0; |
bfd_vma addend = 0, offset = 0; |
| 631 |
signed long val; |
signed long val; |
| 632 |
signed long hi16_offset, hi16_value, uvalue; |
signed long hi16_offset, hi16_value, uvalue; |
| 633 |
|
|
| 634 |
hi16_value = bfd_get_32 (abfd, hi16_rel_addr); |
hi16_value = score_bfd_get_32 (abfd, hi16_rel_addr); |
| 635 |
hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; |
hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; |
| 636 |
addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); |
addend = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); |
| 637 |
offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; |
offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; |
| 638 |
val = reloc_entry->addend; |
val = reloc_entry->addend; |
| 639 |
if (reloc_entry->address > input_section->size) |
if (reloc_entry->address > input_section->size) |
| 644 |
else |
else |
| 645 |
hi16_offset = (uvalue >> 16) & 0x7fff; |
hi16_offset = (uvalue >> 16) & 0x7fff; |
| 646 |
hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); |
hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); |
| 647 |
bfd_put_32 (abfd, hi16_value, hi16_rel_addr); |
score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr); |
| 648 |
offset = (uvalue & 0xffff) << 1; |
offset = (uvalue & 0xffff) << 1; |
| 649 |
addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); |
addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); |
| 650 |
bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); |
score_bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); |
| 651 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 652 |
} |
} |
| 653 |
|
|
| 676 |
FALSE, /* pc_relative */ |
FALSE, /* pc_relative */ |
| 677 |
1, /* bitpos */ |
1, /* bitpos */ |
| 678 |
complain_overflow_dont,/* complain_on_overflow */ |
complain_overflow_dont,/* complain_on_overflow */ |
| 679 |
score_elf_hi16_reloc, /* special_function */ |
score_elf_hi16_reloc, /* special_function */ |
| 680 |
"R_SCORE_HI16", /* name */ |
"R_SCORE_HI16", /* name */ |
| 681 |
TRUE, /* partial_inplace */ |
TRUE, /* partial_inplace */ |
| 682 |
0x37fff, /* src_mask */ |
0x37fff, /* src_mask */ |
| 698 |
0x37fff, /* dst_mask */ |
0x37fff, /* dst_mask */ |
| 699 |
FALSE), /* pcrel_offset */ |
FALSE), /* pcrel_offset */ |
| 700 |
|
|
| 701 |
/* R_SCORE_DUMMY1 */ |
/* R_SCORE_BCMP */ |
| 702 |
HOWTO (R_SCORE_DUMMY1, /* type */ |
HOWTO (R_SCORE_BCMP, /* type */ |
| 703 |
0, /* rightshift */ |
1, /* rightshift */ |
| 704 |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
| 705 |
16, /* bitsize */ |
16, /* bitsize */ |
| 706 |
FALSE, /* pc_relative */ |
TRUE, /* pc_relative */ |
| 707 |
1, /* bitpos */ |
1, /* bitpos */ |
| 708 |
complain_overflow_dont,/* complain_on_overflow */ |
complain_overflow_dont,/* complain_on_overflow */ |
| 709 |
bfd_elf_generic_reloc, /* special_function */ |
bfd_elf_generic_reloc, /* special_function */ |
| 710 |
"R_SCORE_DUMMY1", /* name */ |
"R_SCORE_BCMP", /* name */ |
| 711 |
TRUE, /* partial_inplace */ |
FALSE, /* partial_inplace */ |
| 712 |
0x0000ffff, /* src_mask */ |
0x03e00381, /* src_mask */ |
| 713 |
0x0000ffff, /* dst_mask */ |
0x03e00381, /* dst_mask */ |
| 714 |
FALSE), /* pcrel_offset */ |
FALSE), /* pcrel_offset */ |
| 715 |
|
|
| 716 |
/*R_SCORE_24 */ |
/*R_SCORE_24 */ |
| 762 |
HOWTO (R_SCORE16_PC8, /* type */ |
HOWTO (R_SCORE16_PC8, /* type */ |
| 763 |
1, /* rightshift */ |
1, /* rightshift */ |
| 764 |
1, /* size (0 = byte, 1 = short, 2 = long) */ |
1, /* size (0 = byte, 1 = short, 2 = long) */ |
| 765 |
8, /* bitsize */ |
9, /* bitsize */ |
| 766 |
TRUE, /* pc_relative */ |
TRUE, /* pc_relative */ |
| 767 |
0, /* bitpos */ |
0, /* bitpos */ |
| 768 |
complain_overflow_dont,/* complain_on_overflow */ |
complain_overflow_dont,/* complain_on_overflow */ |
| 769 |
bfd_elf_generic_reloc, /* special_function */ |
bfd_elf_generic_reloc, /* special_function */ |
| 770 |
"R_SCORE16_PC8", /* name */ |
"R_SCORE16_PC8", /* name */ |
| 771 |
FALSE, /* partial_inplace */ |
FALSE, /* partial_inplace */ |
| 772 |
0x000000ff, /* src_mask */ |
0x000001ff, /* src_mask */ |
| 773 |
0x000000ff, /* dst_mask */ |
0x000001ff, /* dst_mask */ |
| 774 |
FALSE), /* pcrel_offset */ |
FALSE), /* pcrel_offset */ |
| 775 |
|
|
| 776 |
/* 32 bit absolute */ |
/* 32 bit absolute */ |
| 925 |
|
|
| 926 |
/* 32 bit symbol relative relocation. */ |
/* 32 bit symbol relative relocation. */ |
| 927 |
HOWTO (R_SCORE_REL32, /* type */ |
HOWTO (R_SCORE_REL32, /* type */ |
| 928 |
0, /* rightshift */ |
0, /* rightshift */ |
| 929 |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
| 930 |
32, /* bitsize */ |
32, /* bitsize */ |
| 931 |
FALSE, /* pc_relative */ |
FALSE, /* pc_relative */ |
| 932 |
0, /* bitpos */ |
0, /* bitpos */ |
| 933 |
complain_overflow_dont,/* complain_on_overflow */ |
complain_overflow_dont,/* complain_on_overflow */ |
| 934 |
bfd_elf_generic_reloc, /* special_function */ |
bfd_elf_generic_reloc, /* special_function */ |
| 935 |
"R_SCORE_REL32", /* name */ |
"R_SCORE_REL32", /* name */ |
| 936 |
TRUE, /* partial_inplace */ |
TRUE, /* partial_inplace */ |
| 937 |
0xffffffff, /* src_mask */ |
0xffffffff, /* src_mask */ |
| 938 |
0xffffffff, /* dst_mask */ |
0xffffffff, /* dst_mask */ |
| 939 |
FALSE), /* pcrel_offset */ |
FALSE), /* pcrel_offset */ |
| 940 |
|
|
| 941 |
/* R_SCORE_DUMMY_HI16 */ |
/* R_SCORE_DUMMY_HI16 */ |
| 942 |
HOWTO (R_SCORE_DUMMY_HI16, /* type */ |
HOWTO (R_SCORE_DUMMY_HI16, /* type */ |
| 946 |
FALSE, /* pc_relative */ |
FALSE, /* pc_relative */ |
| 947 |
1, /* bitpos */ |
1, /* bitpos */ |
| 948 |
complain_overflow_dont,/* complain_on_overflow */ |
complain_overflow_dont,/* complain_on_overflow */ |
| 949 |
score_elf_hi16_reloc, /* special_function */ |
score_elf_hi16_reloc, /* special_function */ |
| 950 |
"R_SCORE_DUMMY_HI16", /* name */ |
"R_SCORE_DUMMY_HI16", /* name */ |
| 951 |
TRUE, /* partial_inplace */ |
TRUE, /* partial_inplace */ |
| 952 |
0x37fff, /* src_mask */ |
0x37fff, /* src_mask */ |
| 953 |
0x37fff, /* dst_mask */ |
0x37fff, /* dst_mask */ |
| 954 |
FALSE), /* pcrel_offset */ |
FALSE), /* pcrel_offset */ |
| 955 |
|
|
| 956 |
|
/* R_SCORE_IMM30 */ |
| 957 |
|
HOWTO (R_SCORE_IMM30, /* type */ |
| 958 |
|
2, /* rightshift */ |
| 959 |
|
2, /* size (0 = byte, 1 = short, 2 = long) */ |
| 960 |
|
30, /* bitsize */ |
| 961 |
|
FALSE, /* pc_relative */ |
| 962 |
|
7, /* bitpos */ |
| 963 |
|
complain_overflow_dont,/* complain_on_overflow */ |
| 964 |
|
bfd_elf_generic_reloc, /* special_function */ |
| 965 |
|
"R_SCORE_IMM30", /* name */ |
| 966 |
|
FALSE, /* partial_inplace */ |
| 967 |
|
0x7f7fff7f80LL, /* src_mask */ |
| 968 |
|
0x7f7fff7f80LL, /* dst_mask */ |
| 969 |
|
FALSE), /* pcrel_offset */ |
| 970 |
|
|
| 971 |
|
/* R_SCORE_IMM32 */ |
| 972 |
|
HOWTO (R_SCORE_IMM32, /* type */ |
| 973 |
|
0, /* rightshift */ |
| 974 |
|
2, /* size (0 = byte, 1 = short, 2 = long) */ |
| 975 |
|
32, /* bitsize */ |
| 976 |
|
FALSE, /* pc_relative */ |
| 977 |
|
5, /* bitpos */ |
| 978 |
|
complain_overflow_dont,/* complain_on_overflow */ |
| 979 |
|
bfd_elf_generic_reloc, /* special_function */ |
| 980 |
|
"R_SCORE_IMM32", /* name */ |
| 981 |
|
FALSE, /* partial_inplace */ |
| 982 |
|
0x7f7fff7fe0LL, /* src_mask */ |
| 983 |
|
0x7f7fff7fe0LL, /* dst_mask */ |
| 984 |
|
FALSE), /* pcrel_offset */ |
| 985 |
}; |
}; |
| 986 |
|
|
| 987 |
struct score_reloc_map |
struct score_reloc_map |
| 995 |
{BFD_RELOC_NONE, R_SCORE_NONE}, |
{BFD_RELOC_NONE, R_SCORE_NONE}, |
| 996 |
{BFD_RELOC_HI16_S, R_SCORE_HI16}, |
{BFD_RELOC_HI16_S, R_SCORE_HI16}, |
| 997 |
{BFD_RELOC_LO16, R_SCORE_LO16}, |
{BFD_RELOC_LO16, R_SCORE_LO16}, |
| 998 |
{BFD_RELOC_SCORE_DUMMY1, R_SCORE_DUMMY1}, |
{BFD_RELOC_SCORE_BCMP, R_SCORE_BCMP}, |
| 999 |
{BFD_RELOC_SCORE_JMP, R_SCORE_24}, |
{BFD_RELOC_SCORE_JMP, R_SCORE_24}, |
| 1000 |
{BFD_RELOC_SCORE_BRANCH, R_SCORE_PC19}, |
{BFD_RELOC_SCORE_BRANCH, R_SCORE_PC19}, |
| 1001 |
{BFD_RELOC_SCORE16_JMP, R_SCORE16_11}, |
{BFD_RELOC_SCORE16_JMP, R_SCORE16_11}, |
| 1012 |
{BFD_RELOC_GPREL32, R_SCORE_GPREL32}, |
{BFD_RELOC_GPREL32, R_SCORE_GPREL32}, |
| 1013 |
{BFD_RELOC_32_PCREL, R_SCORE_REL32}, |
{BFD_RELOC_32_PCREL, R_SCORE_REL32}, |
| 1014 |
{BFD_RELOC_SCORE_DUMMY_HI16, R_SCORE_DUMMY_HI16}, |
{BFD_RELOC_SCORE_DUMMY_HI16, R_SCORE_DUMMY_HI16}, |
| 1015 |
|
{BFD_RELOC_SCORE_IMM30, R_SCORE_IMM30}, |
| 1016 |
|
{BFD_RELOC_SCORE_IMM32, R_SCORE_IMM32}, |
| 1017 |
}; |
}; |
| 1018 |
|
|
| 1019 |
/* got_entries only match if they're identical, except for gotidx, so |
/* got_entries only match if they're identical, except for gotidx, so |
| 1020 |
use all fields to compute the hash, and compare the appropriate |
use all fields to compute the hash, and compare the appropriate |
| 1021 |
union members. */ |
union members. */ |
|
|
|
| 1022 |
static hashval_t |
static hashval_t |
| 1023 |
score_elf_got_entry_hash (const void *entry_) |
score_elf_got_entry_hash (const void *entry_) |
| 1024 |
{ |
{ |
| 1036 |
|
|
| 1037 |
return e1->abfd == e2->abfd && e1->symndx == e2->symndx |
return e1->abfd == e2->abfd && e1->symndx == e2->symndx |
| 1038 |
&& (! e1->abfd ? e1->d.address == e2->d.address |
&& (! e1->abfd ? e1->d.address == e2->d.address |
| 1039 |
: e1->symndx >= 0 ? e1->d.addend == e2->d.addend |
: e1->symndx >= 0 ? e1->d.addend == e2->d.addend |
| 1040 |
: e1->d.h == e2->d.h); |
: e1->d.h == e2->d.h); |
| 1041 |
} |
} |
| 1042 |
|
|
| 1043 |
/* If H needs a GOT entry, assign it the highest available dynamic |
/* If H needs a GOT entry, assign it the highest available dynamic |
| 1044 |
index. Otherwise, assign it the lowest available dynamic |
index. Otherwise, assign it the lowest available dynamic |
| 1045 |
index. */ |
index. */ |
|
|
|
| 1046 |
static bfd_boolean |
static bfd_boolean |
| 1047 |
score_elf_sort_hash_table_f (struct score_elf_link_hash_entry *h, void *data) |
score_elf_sort_hash_table_f (struct score_elf_link_hash_entry *h, void *data) |
| 1048 |
{ |
{ |
| 1062 |
if (h->root.got.offset == 2) |
if (h->root.got.offset == 2) |
| 1063 |
{ |
{ |
| 1064 |
if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx) |
if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx) |
| 1065 |
hsd->low = (struct elf_link_hash_entry *) h; |
hsd->low = (struct elf_link_hash_entry *) h; |
| 1066 |
h->root.dynindx = hsd->max_unref_got_dynindx++; |
h->root.dynindx = hsd->max_unref_got_dynindx++; |
| 1067 |
} |
} |
| 1068 |
else if (h->root.got.offset != 1) |
else if (h->root.got.offset != 1) |
| 1088 |
|
|
| 1089 |
/* Returns the GOT information associated with the link indicated by |
/* Returns the GOT information associated with the link indicated by |
| 1090 |
INFO. If SGOTP is non-NULL, it is filled in with the GOT section. */ |
INFO. If SGOTP is non-NULL, it is filled in with the GOT section. */ |
|
|
|
| 1091 |
static struct score_got_info * |
static struct score_got_info * |
| 1092 |
score_elf_got_info (bfd *abfd, asection **sgotp) |
score_elf_got_info (bfd *abfd, asection **sgotp) |
| 1093 |
{ |
{ |
| 1109 |
appear towards the end. This reduces the amount of GOT space |
appear towards the end. This reduces the amount of GOT space |
| 1110 |
required. MAX_LOCAL is used to set the number of local symbols |
required. MAX_LOCAL is used to set the number of local symbols |
| 1111 |
known to be in the dynamic symbol table. During |
known to be in the dynamic symbol table. During |
| 1112 |
_bfd_score_elf_size_dynamic_sections, this value is 1. Afterward, the |
s3_bfd_score_elf_size_dynamic_sections, this value is 1. Afterward, the |
| 1113 |
section symbols are added and the count is higher. */ |
section symbols are added and the count is higher. */ |
|
|
|
| 1114 |
static bfd_boolean |
static bfd_boolean |
| 1115 |
score_elf_sort_hash_table (struct bfd_link_info *info, |
score_elf_sort_hash_table (struct bfd_link_info *info, |
| 1116 |
unsigned long max_local) |
unsigned long max_local) |
| 1117 |
{ |
{ |
| 1118 |
struct score_elf_hash_sort_data hsd; |
struct score_elf_hash_sort_data hsd; |
| 1119 |
struct score_got_info *g; |
struct score_got_info *g; |
| 1136 |
- (g->next ? g->assigned_gotno : 0); |
- (g->next ? g->assigned_gotno : 0); |
| 1137 |
hsd.max_non_got_dynindx = max_local; |
hsd.max_non_got_dynindx = max_local; |
| 1138 |
score_elf_link_hash_traverse (((struct score_elf_link_hash_table *) |
score_elf_link_hash_traverse (((struct score_elf_link_hash_table *) |
| 1139 |
elf_hash_table (info)), |
elf_hash_table (info)), |
| 1140 |
score_elf_sort_hash_table_f, |
score_elf_sort_hash_table_f, |
| 1141 |
&hsd); |
&hsd); |
| 1142 |
|
|
| 1143 |
/* There should have been enough room in the symbol table to |
/* There should have been enough room in the symbol table to |
| 1144 |
accommodate both the GOT and non-GOT symbols. */ |
accommodate both the GOT and non-GOT symbols. */ |
| 1145 |
BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx); |
BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx); |
| 1146 |
BFD_ASSERT ((unsigned long)hsd.max_unref_got_dynindx |
BFD_ASSERT ((unsigned long)hsd.max_unref_got_dynindx |
| 1147 |
<= elf_hash_table (info)->dynsymcount); |
<= elf_hash_table (info)->dynsymcount); |
| 1148 |
|
|
| 1149 |
/* Now we know which dynamic symbol has the lowest dynamic symbol |
/* Now we know which dynamic symbol has the lowest dynamic symbol |
| 1150 |
table index in the GOT. */ |
table index in the GOT. */ |
| 1154 |
} |
} |
| 1155 |
|
|
| 1156 |
/* Create an entry in an score ELF linker hash table. */ |
/* Create an entry in an score ELF linker hash table. */ |
|
|
|
| 1157 |
static struct bfd_hash_entry * |
static struct bfd_hash_entry * |
| 1158 |
score_elf_link_hash_newfunc (struct bfd_hash_entry *entry, |
score_elf_link_hash_newfunc (struct bfd_hash_entry *entry, |
| 1159 |
struct bfd_hash_table *table, |
struct bfd_hash_table *table, |
| 1160 |
const char *string) |
const char *string) |
| 1161 |
{ |
{ |
| 1162 |
struct score_elf_link_hash_entry *ret = (struct score_elf_link_hash_entry *)entry; |
struct score_elf_link_hash_entry *ret = (struct score_elf_link_hash_entry *)entry; |
| 1163 |
|
|
| 1184 |
|
|
| 1185 |
/* Returns the first relocation of type r_type found, beginning with |
/* Returns the first relocation of type r_type found, beginning with |
| 1186 |
RELOCATION. RELEND is one-past-the-end of the relocation table. */ |
RELOCATION. RELEND is one-past-the-end of the relocation table. */ |
|
|
|
| 1187 |
static const Elf_Internal_Rela * |
static const Elf_Internal_Rela * |
| 1188 |
score_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type, |
score_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type, |
| 1189 |
const Elf_Internal_Rela *relocation, |
const Elf_Internal_Rela *relocation, |
| 1190 |
const Elf_Internal_Rela *relend) |
const Elf_Internal_Rela *relend) |
| 1191 |
{ |
{ |
| 1192 |
while (relocation < relend) |
while (relocation < relend) |
| 1193 |
{ |
{ |
| 1194 |
if (ELF32_R_TYPE (relocation->r_info) == r_type) |
if (ELF32_R_TYPE (relocation->r_info) == r_type) |
| 1195 |
return relocation; |
return relocation; |
| 1196 |
|
|
| 1197 |
++relocation; |
++relocation; |
| 1198 |
} |
} |
| 1204 |
|
|
| 1205 |
/* This function is called via qsort() to sort the dynamic relocation |
/* This function is called via qsort() to sort the dynamic relocation |
| 1206 |
entries by increasing r_symndx value. */ |
entries by increasing r_symndx value. */ |
|
|
|
| 1207 |
static int |
static int |
| 1208 |
score_elf_sort_dynamic_relocs (const void *arg1, const void *arg2) |
score_elf_sort_dynamic_relocs (const void *arg1, const void *arg2) |
| 1209 |
{ |
{ |
| 1217 |
} |
} |
| 1218 |
|
|
| 1219 |
/* Return whether a relocation is against a local symbol. */ |
/* Return whether a relocation is against a local symbol. */ |
|
|
|
| 1220 |
static bfd_boolean |
static bfd_boolean |
| 1221 |
score_elf_local_relocation_p (bfd *input_bfd, |
score_elf_local_relocation_p (bfd *input_bfd, |
| 1222 |
const Elf_Internal_Rela *relocation, |
const Elf_Internal_Rela *relocation, |
| 1223 |
bfd_boolean check_forced) |
asection **local_sections, |
| 1224 |
|
bfd_boolean check_forced) |
| 1225 |
{ |
{ |
| 1226 |
unsigned long r_symndx; |
unsigned long r_symndx; |
| 1227 |
Elf_Internal_Shdr *symtab_hdr; |
Elf_Internal_Shdr *symtab_hdr; |
| 1230 |
|
|
| 1231 |
r_symndx = ELF32_R_SYM (relocation->r_info); |
r_symndx = ELF32_R_SYM (relocation->r_info); |
| 1232 |
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; |
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; |
| 1233 |
extsymoff = symtab_hdr->sh_info; |
extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info; |
| 1234 |
|
|
| 1235 |
if (r_symndx < extsymoff) |
if (r_symndx < extsymoff) |
| 1236 |
return TRUE; |
return TRUE; |
| 1237 |
|
if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL) |
| 1238 |
|
return TRUE; |
| 1239 |
|
|
| 1240 |
if (check_forced) |
if (check_forced) |
| 1241 |
{ |
{ |
| 1242 |
/* Look up the hash table to check whether the symbol was forced local. */ |
/* Look up the hash table to check whether the symbol was forced local. */ |
| 1243 |
h = (struct score_elf_link_hash_entry *) |
h = (struct score_elf_link_hash_entry *) |
| 1244 |
elf_sym_hashes (input_bfd) [r_symndx - extsymoff]; |
elf_sym_hashes (input_bfd) [r_symndx - extsymoff]; |
| 1245 |
/* Find the real hash-table entry for this symbol. */ |
/* Find the real hash-table entry for this symbol. */ |
| 1246 |
while (h->root.root.type == bfd_link_hash_indirect |
while (h->root.root.type == bfd_link_hash_indirect |
| 1247 |
|| h->root.root.type == bfd_link_hash_warning) |
|| h->root.root.type == bfd_link_hash_warning) |
| 1248 |
h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; |
h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; |
| 1249 |
if (h->root.forced_local) |
if (h->root.forced_local) |
| 1250 |
return TRUE; |
return TRUE; |
| 1251 |
} |
} |
| 1252 |
|
|
| 1253 |
return FALSE; |
return FALSE; |
| 1254 |
} |
} |
| 1255 |
|
|
| 1256 |
/* Returns the dynamic relocation section for DYNOBJ. */ |
/* Returns the dynamic relocation section for DYNOBJ. */ |
|
|
|
| 1257 |
static asection * |
static asection * |
| 1258 |
score_elf_rel_dyn_section (bfd *dynobj, bfd_boolean create_p) |
score_elf_rel_dyn_section (bfd *dynobj, bfd_boolean create_p) |
| 1259 |
{ |
{ |
| 1271 |
| SEC_LINKER_CREATED |
| SEC_LINKER_CREATED |
| 1272 |
| SEC_READONLY)); |
| SEC_READONLY)); |
| 1273 |
if (sreloc == NULL |
if (sreloc == NULL |
| 1274 |
|| ! bfd_set_section_alignment (dynobj, sreloc, |
|| ! bfd_set_section_alignment (dynobj, sreloc, |
| 1275 |
SCORE_ELF_LOG_FILE_ALIGN (dynobj))) |
SCORE_ELF_LOG_FILE_ALIGN (dynobj))) |
| 1276 |
return NULL; |
return NULL; |
| 1277 |
} |
} |
| 1278 |
return sreloc; |
return sreloc; |
| 1279 |
} |
} |
| 1280 |
|
|
| 1281 |
static void |
static void |
| 1299 |
is the original relocation, which is now being transformed into a |
is the original relocation, which is now being transformed into a |
| 1300 |
dynamic relocation. The ADDENDP is adjusted if necessary; the |
dynamic relocation. The ADDENDP is adjusted if necessary; the |
| 1301 |
caller should store the result in place of the original addend. */ |
caller should store the result in place of the original addend. */ |
|
|
|
| 1302 |
static bfd_boolean |
static bfd_boolean |
| 1303 |
score_elf_create_dynamic_relocation (bfd *output_bfd, |
score_elf_create_dynamic_relocation (bfd *output_bfd, |
| 1304 |
struct bfd_link_info *info, |
struct bfd_link_info *info, |
| 1305 |
const Elf_Internal_Rela *rel, |
const Elf_Internal_Rela *rel, |
| 1306 |
struct score_elf_link_hash_entry *h, |
struct score_elf_link_hash_entry *h, |
| 1307 |
bfd_vma symbol, |
bfd_vma symbol, |
| 1308 |
bfd_vma *addendp, asection *input_section) |
bfd_vma *addendp, asection *input_section) |
| 1309 |
{ |
{ |
| 1310 |
Elf_Internal_Rela outrel[3]; |
Elf_Internal_Rela outrel[3]; |
| 1311 |
asection *sreloc; |
asection *sreloc; |
| 1335 |
if (outrel[0].r_offset == MINUS_TWO) |
if (outrel[0].r_offset == MINUS_TWO) |
| 1336 |
{ |
{ |
| 1337 |
/* The relocation field has been converted into a relative value of |
/* The relocation field has been converted into a relative value of |
| 1338 |
some sort. Functions like _bfd_elf_write_section_eh_frame expect |
some sort. Functions like _bfd_elf_write_section_eh_frame expect |
| 1339 |
the field to be fully relocated, so add in the symbol's value. */ |
the field to be fully relocated, so add in the symbol's value. */ |
| 1340 |
*addendp += symbol; |
*addendp += symbol; |
| 1341 |
return TRUE; |
return TRUE; |
| 1342 |
} |
} |
| 1346 |
if (h != NULL |
if (h != NULL |
| 1347 |
&& (! info->symbolic || !h->root.def_regular) |
&& (! info->symbolic || !h->root.def_regular) |
| 1348 |
/* h->root.dynindx may be -1 if this symbol was marked to |
/* h->root.dynindx may be -1 if this symbol was marked to |
| 1349 |
become local. */ |
become local. */ |
| 1350 |
&& h->root.dynindx != -1) |
&& h->root.dynindx != -1) |
| 1351 |
{ |
{ |
| 1352 |
indx = h->root.dynindx; |
indx = h->root.dynindx; |
| 1353 |
/* ??? glibc's ld.so just adds the final GOT entry to the |
/* ??? glibc's ld.so just adds the final GOT entry to the |
| 1354 |
relocation field. It therefore treats relocs against |
relocation field. It therefore treats relocs against |
| 1355 |
defined symbols in the same way as relocs against |
defined symbols in the same way as relocs against |
| 1356 |
undefined symbols. */ |
undefined symbols. */ |
| 1357 |
defined_p = FALSE; |
defined_p = FALSE; |
| 1358 |
} |
} |
| 1359 |
else |
else |
| 1391 |
/* Adjust the output offset of the relocation to reference the |
/* Adjust the output offset of the relocation to reference the |
| 1392 |
correct location in the output file. */ |
correct location in the output file. */ |
| 1393 |
outrel[0].r_offset += (input_section->output_section->vma |
outrel[0].r_offset += (input_section->output_section->vma |
| 1394 |
+ input_section->output_offset); |
+ input_section->output_offset); |
| 1395 |
outrel[1].r_offset += (input_section->output_section->vma |
outrel[1].r_offset += (input_section->output_section->vma |
| 1396 |
+ input_section->output_offset); |
+ input_section->output_offset); |
| 1397 |
outrel[2].r_offset += (input_section->output_section->vma |
outrel[2].r_offset += (input_section->output_section->vma |
| 1398 |
+ input_section->output_offset); |
+ input_section->output_offset); |
| 1399 |
|
|
| 1400 |
/* Put the relocation back out. We have to use the special |
/* Put the relocation back out. We have to use the special |
| 1401 |
relocation outputter in the 64-bit case since the 64-bit |
relocation outputter in the 64-bit case since the 64-bit |
| 1417 |
static bfd_boolean |
static bfd_boolean |
| 1418 |
score_elf_create_got_section (bfd *abfd, |
score_elf_create_got_section (bfd *abfd, |
| 1419 |
struct bfd_link_info *info, |
struct bfd_link_info *info, |
| 1420 |
bfd_boolean maybe_exclude) |
bfd_boolean maybe_exclude) |
| 1421 |
{ |
{ |
| 1422 |
flagword flags; |
flagword flags; |
| 1423 |
asection *s; |
asection *s; |
| 1431 |
if (s) |
if (s) |
| 1432 |
{ |
{ |
| 1433 |
if (! maybe_exclude) |
if (! maybe_exclude) |
| 1434 |
s->flags &= ~SEC_EXCLUDE; |
s->flags &= ~SEC_EXCLUDE; |
| 1435 |
return TRUE; |
return TRUE; |
| 1436 |
} |
} |
| 1437 |
|
|
| 1452 |
are not creating a global offset table. */ |
are not creating a global offset table. */ |
| 1453 |
bh = NULL; |
bh = NULL; |
| 1454 |
if (! (_bfd_generic_link_add_one_symbol |
if (! (_bfd_generic_link_add_one_symbol |
| 1455 |
(info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, |
(info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, |
| 1456 |
0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) |
0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) |
| 1457 |
return FALSE; |
return FALSE; |
| 1458 |
|
|
| 1459 |
h = (struct elf_link_hash_entry *) bh; |
h = (struct elf_link_hash_entry *) bh; |
| 1477 |
g->next = NULL; |
g->next = NULL; |
| 1478 |
|
|
| 1479 |
g->got_entries = htab_try_create (1, score_elf_got_entry_hash, |
g->got_entries = htab_try_create (1, score_elf_got_entry_hash, |
| 1480 |
score_elf_got_entry_eq, NULL); |
score_elf_got_entry_eq, NULL); |
| 1481 |
if (g->got_entries == NULL) |
if (g->got_entries == NULL) |
| 1482 |
return FALSE; |
return FALSE; |
| 1483 |
score_elf_section_data (s)->u.got_info = g; |
score_elf_section_data (s)->u.got_info = g; |
| 1487 |
} |
} |
| 1488 |
|
|
| 1489 |
/* Calculate the %high function. */ |
/* Calculate the %high function. */ |
|
|
|
| 1490 |
static bfd_vma |
static bfd_vma |
| 1491 |
score_elf_high (bfd_vma value) |
score_elf_high (bfd_vma value) |
| 1492 |
{ |
{ |
| 1495 |
|
|
| 1496 |
/* Create a local GOT entry for VALUE. Return the index of the entry, |
/* Create a local GOT entry for VALUE. Return the index of the entry, |
| 1497 |
or -1 if it could not be created. */ |
or -1 if it could not be created. */ |
|
|
|
| 1498 |
static struct score_got_entry * |
static struct score_got_entry * |
| 1499 |
score_elf_create_local_got_entry (bfd *abfd, |
score_elf_create_local_got_entry (bfd *abfd, |
| 1500 |
bfd *ibfd ATTRIBUTE_UNUSED, |
bfd *ibfd ATTRIBUTE_UNUSED, |
| 1501 |
struct score_got_info *gg, |
struct score_got_info *gg, |
| 1502 |
asection *sgot, bfd_vma value, |
asection *sgot, bfd_vma value, |
| 1503 |
unsigned long r_symndx ATTRIBUTE_UNUSED, |
unsigned long r_symndx ATTRIBUTE_UNUSED, |
| 1504 |
struct score_elf_link_hash_entry *h ATTRIBUTE_UNUSED, |
struct score_elf_link_hash_entry *h ATTRIBUTE_UNUSED, |
| 1505 |
int r_type ATTRIBUTE_UNUSED) |
int r_type ATTRIBUTE_UNUSED) |
| 1506 |
{ |
{ |
| 1507 |
struct score_got_entry entry, **loc; |
struct score_got_entry entry, **loc; |
| 1508 |
struct score_got_info *g; |
struct score_got_info *g; |
| 1530 |
(*loc)->gotidx = -1; |
(*loc)->gotidx = -1; |
| 1531 |
/* We didn't allocate enough space in the GOT. */ |
/* We didn't allocate enough space in the GOT. */ |
| 1532 |
(*_bfd_error_handler) |
(*_bfd_error_handler) |
| 1533 |
(_("not enough GOT space for local GOT entries")); |
(_("not enough GOT space for local GOT entries")); |
| 1534 |
bfd_set_error (bfd_error_bad_value); |
bfd_set_error (bfd_error_bad_value); |
| 1535 |
return NULL; |
return NULL; |
| 1536 |
} |
} |
| 1537 |
|
|
| 1538 |
bfd_put_32 (abfd, value, (sgot->contents + entry.gotidx)); |
score_bfd_put_32 (abfd, value, (sgot->contents + entry.gotidx)); |
| 1539 |
|
|
| 1540 |
return *loc; |
return *loc; |
| 1541 |
} |
} |
| 1542 |
|
|
| 1543 |
/* Find a GOT entry whose higher-order 16 bits are the same as those |
/* Find a GOT entry whose higher-order 16 bits are the same as those |
| 1544 |
for value. Return the index into the GOT for this entry. */ |
for value. Return the index into the GOT for this entry. */ |
|
|
|
| 1545 |
static bfd_vma |
static bfd_vma |
| 1546 |
score_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, |
score_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, |
| 1547 |
bfd_vma value, bfd_boolean external) |
bfd_vma value, bfd_boolean external) |
| 1548 |
{ |
{ |
| 1549 |
asection *sgot; |
asection *sgot; |
| 1550 |
struct score_got_info *g; |
struct score_got_info *g; |
| 1553 |
if (!external) |
if (!external) |
| 1554 |
{ |
{ |
| 1555 |
/* Although the ABI says that it is "the high-order 16 bits" that we |
/* Although the ABI says that it is "the high-order 16 bits" that we |
| 1556 |
want, it is really the %high value. The complete value is |
want, it is really the %high value. The complete value is |
| 1557 |
calculated with a `addiu' of a LO16 relocation, just as with a |
calculated with a `addiu' of a LO16 relocation, just as with a |
| 1558 |
HI16/LO16 pair. */ |
HI16/LO16 pair. */ |
| 1559 |
value = score_elf_high (value) << 16; |
value = score_elf_high (value) << 16; |
| 1560 |
} |
} |
| 1561 |
|
|
| 1562 |
g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot); |
g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot); |
| 1563 |
|
|
| 1564 |
entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, 0, NULL, |
entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, 0, NULL, |
| 1565 |
R_SCORE_GOT15); |
R_SCORE_GOT15); |
| 1566 |
if (entry) |
if (entry) |
| 1567 |
return entry->gotidx; |
return entry->gotidx; |
| 1568 |
else |
else |
| 1570 |
} |
} |
| 1571 |
|
|
| 1572 |
static void |
static void |
| 1573 |
_bfd_score_elf_hide_symbol (struct bfd_link_info *info, |
s3_bfd_score_elf_hide_symbol (struct bfd_link_info *info, |
| 1574 |
struct elf_link_hash_entry *entry, |
struct elf_link_hash_entry *entry, |
| 1575 |
bfd_boolean force_local) |
bfd_boolean force_local) |
| 1576 |
{ |
{ |
| 1577 |
bfd *dynobj; |
bfd *dynobj; |
| 1578 |
asection *got; |
asection *got; |
| 1589 |
{ |
{ |
| 1590 |
got = score_elf_got_section (dynobj, FALSE); |
got = score_elf_got_section (dynobj, FALSE); |
| 1591 |
if (got == NULL) |
if (got == NULL) |
| 1592 |
return; |
return; |
| 1593 |
g = score_elf_section_data (got)->u.got_info; |
g = score_elf_section_data (got)->u.got_info; |
| 1594 |
|
|
| 1595 |
if (g->next) |
if (g->next) |
| 1596 |
{ |
{ |
| 1597 |
struct score_got_entry e; |
struct score_got_entry e; |
| 1598 |
struct score_got_info *gg = g; |
struct score_got_info *gg = g; |
| 1599 |
|
|
| 1600 |
/* Since we're turning what used to be a global symbol into a |
/* Since we're turning what used to be a global symbol into a |
| 1601 |
local one, bump up the number of local entries of each GOT |
local one, bump up the number of local entries of each GOT |
| 1602 |
that had an entry for it. This will automatically decrease |
that had an entry for it. This will automatically decrease |
| 1603 |
the number of global entries, since global_gotno is actually |
the number of global entries, since global_gotno is actually |
| 1604 |
the upper limit of global entries. */ |
the upper limit of global entries. */ |
| 1605 |
e.abfd = dynobj; |
e.abfd = dynobj; |
| 1606 |
e.symndx = -1; |
e.symndx = -1; |
| 1607 |
e.d.h = h; |
e.d.h = h; |
| 1608 |
|
|
| 1609 |
for (g = g->next; g != gg; g = g->next) |
for (g = g->next; g != gg; g = g->next) |
| 1610 |
if (htab_find (g->got_entries, &e)) |
if (htab_find (g->got_entries, &e)) |
| 1611 |
{ |
{ |
| 1612 |
BFD_ASSERT (g->global_gotno > 0); |
BFD_ASSERT (g->global_gotno > 0); |
| 1613 |
g->local_gotno++; |
g->local_gotno++; |
| 1614 |
g->global_gotno--; |
g->global_gotno--; |
| 1615 |
} |
} |
| 1616 |
|
|
| 1617 |
/* If this was a global symbol forced into the primary GOT, we |
/* If this was a global symbol forced into the primary GOT, we |
| 1618 |
no longer need an entry for it. We can't release the entry |
no longer need an entry for it. We can't release the entry |
| 1619 |
at this point, but we must at least stop counting it as one |
at this point, but we must at least stop counting it as one |
| 1620 |
of the symbols that required a forced got entry. */ |
of the symbols that required a forced got entry. */ |
| 1621 |
if (h->root.got.offset == 2) |
if (h->root.got.offset == 2) |
| 1622 |
{ |
{ |
| 1623 |
BFD_ASSERT (gg->assigned_gotno > 0); |
BFD_ASSERT (gg->assigned_gotno > 0); |
| 1624 |
gg->assigned_gotno--; |
gg->assigned_gotno--; |
| 1625 |
} |
} |
| 1626 |
} |
} |
| 1627 |
else if (g->global_gotno == 0 && g->global_gotsym == NULL) |
else if (g->global_gotno == 0 && g->global_gotsym == NULL) |
| 1628 |
/* If we haven't got through GOT allocation yet, just bump up the |
/* If we haven't got through GOT allocation yet, just bump up the |
| 1629 |
number of local entries, as this symbol won't be counted as |
number of local entries, as this symbol won't be counted as |
| 1630 |
global. */ |
global. */ |
| 1631 |
g->local_gotno++; |
g->local_gotno++; |
| 1632 |
else if (h->root.got.offset == 1) |
else if (h->root.got.offset == 1) |
| 1633 |
{ |
{ |
| 1634 |
/* If we're past non-multi-GOT allocation and this symbol had |
/* If we're past non-multi-GOT allocation and this symbol had |
| 1635 |
been marked for a global got entry, give it a local entry |
been marked for a global got entry, give it a local entry |
| 1636 |
instead. */ |
instead. */ |
| 1637 |
BFD_ASSERT (g->global_gotno > 0); |
BFD_ASSERT (g->global_gotno > 0); |
| 1638 |
g->local_gotno++; |
g->local_gotno++; |
| 1639 |
g->global_gotno--; |
g->global_gotno--; |
| 1640 |
} |
} |
| 1641 |
} |
} |
| 1642 |
|
|
| 1643 |
_bfd_elf_link_hash_hide_symbol (info, &h->root, force_local); |
_bfd_elf_link_hash_hide_symbol (info, &h->root, force_local); |
| 1646 |
/* If H is a symbol that needs a global GOT entry, but has a dynamic |
/* If H is a symbol that needs a global GOT entry, but has a dynamic |
| 1647 |
symbol table index lower than any we've seen to date, record it for |
symbol table index lower than any we've seen to date, record it for |
| 1648 |
posterity. */ |
posterity. */ |
|
|
|
| 1649 |
static bfd_boolean |
static bfd_boolean |
| 1650 |
score_elf_record_global_got_symbol (struct elf_link_hash_entry *h, |
score_elf_record_global_got_symbol (struct elf_link_hash_entry *h, |
| 1651 |
bfd *abfd, |
bfd *abfd, |
| 1652 |
struct bfd_link_info *info, |
struct bfd_link_info *info, |
| 1653 |
struct score_got_info *g) |
struct score_got_info *g) |
| 1654 |
{ |
{ |
| 1655 |
struct score_got_entry entry, **loc; |
struct score_got_entry entry, **loc; |
| 1656 |
|
|
| 1658 |
if (h->dynindx == -1) |
if (h->dynindx == -1) |
| 1659 |
{ |
{ |
| 1660 |
switch (ELF_ST_VISIBILITY (h->other)) |
switch (ELF_ST_VISIBILITY (h->other)) |
| 1661 |
{ |
{ |
| 1662 |
case STV_INTERNAL: |
case STV_INTERNAL: |
| 1663 |
case STV_HIDDEN: |
case STV_HIDDEN: |
| 1664 |
_bfd_score_elf_hide_symbol (info, h, TRUE); |
s3_bfd_score_elf_hide_symbol (info, h, TRUE); |
| 1665 |
break; |
break; |
| 1666 |
} |
} |
| 1667 |
if (!bfd_elf_link_record_dynamic_symbol (info, h)) |
if (!bfd_elf_link_record_dynamic_symbol (info, h)) |
| 1668 |
return FALSE; |
return FALSE; |
| 1669 |
} |
} |
| 1670 |
|
|
| 1671 |
entry.abfd = abfd; |
entry.abfd = abfd; |
| 1700 |
|
|
| 1701 |
/* Reserve space in G for a GOT entry containing the value of symbol |
/* Reserve space in G for a GOT entry containing the value of symbol |
| 1702 |
SYMNDX in input bfd ABDF, plus ADDEND. */ |
SYMNDX in input bfd ABDF, plus ADDEND. */ |
|
|
|
| 1703 |
static bfd_boolean |
static bfd_boolean |
| 1704 |
score_elf_record_local_got_symbol (bfd *abfd, |
score_elf_record_local_got_symbol (bfd *abfd, |
| 1705 |
long symndx, |
long symndx, |
| 1706 |
bfd_vma addend, |
bfd_vma addend, |
| 1707 |
struct score_got_info *g) |
struct score_got_info *g) |
| 1708 |
{ |
{ |
| 1709 |
struct score_got_entry entry, **loc; |
struct score_got_entry entry, **loc; |
| 1710 |
|
|
| 1730 |
/* Returns the GOT offset at which the indicated address can be found. |
/* Returns the GOT offset at which the indicated address can be found. |
| 1731 |
If there is not yet a GOT entry for this value, create one. |
If there is not yet a GOT entry for this value, create one. |
| 1732 |
Returns -1 if no satisfactory GOT offset can be found. */ |
Returns -1 if no satisfactory GOT offset can be found. */ |
|
|
|
| 1733 |
static bfd_vma |
static bfd_vma |
| 1734 |
score_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, |
score_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, |
| 1735 |
bfd_vma value, unsigned long r_symndx, |
bfd_vma value, unsigned long r_symndx, |
| 1736 |
struct score_elf_link_hash_entry *h, int r_type) |
struct score_elf_link_hash_entry *h, int r_type) |
| 1737 |
{ |
{ |
| 1738 |
asection *sgot; |
asection *sgot; |
| 1739 |
struct score_got_info *g; |
struct score_got_info *g; |
| 1742 |
g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot); |
g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot); |
| 1743 |
|
|
| 1744 |
entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, |
entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, |
| 1745 |
r_symndx, h, r_type); |
r_symndx, h, r_type); |
| 1746 |
if (!entry) |
if (!entry) |
| 1747 |
return MINUS_ONE; |
return MINUS_ONE; |
| 1748 |
|
|
| 1776 |
} |
} |
| 1777 |
|
|
| 1778 |
/* Returns the offset for the entry at the INDEXth position in the GOT. */ |
/* Returns the offset for the entry at the INDEXth position in the GOT. */ |
|
|
|
| 1779 |
static bfd_vma |
static bfd_vma |
| 1780 |
score_elf_got_offset_from_index (bfd *dynobj, bfd *output_bfd, |
score_elf_got_offset_from_index (bfd *dynobj, bfd *output_bfd, |
| 1781 |
bfd *input_bfd ATTRIBUTE_UNUSED, bfd_vma index) |
bfd *input_bfd ATTRIBUTE_UNUSED, bfd_vma index) |
| 1782 |
{ |
{ |
| 1783 |
asection *sgot; |
asection *sgot; |
| 1784 |
bfd_vma gp; |
bfd_vma gp; |
| 1807 |
struct score_elf_link_hash_entry *h = entry->d.h; |
struct score_elf_link_hash_entry *h = entry->d.h; |
| 1808 |
|
|
| 1809 |
while (h->root.root.type == bfd_link_hash_indirect |
while (h->root.root.type == bfd_link_hash_indirect |
| 1810 |
|| h->root.root.type == bfd_link_hash_warning) |
|| h->root.root.type == bfd_link_hash_warning) |
| 1811 |
h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; |
h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; |
| 1812 |
|
|
| 1813 |
if (entry->d.h == h) |
if (entry->d.h == h) |
| 1814 |
return 1; |
return 1; |
| 1815 |
|
|
| 1816 |
entry->d.h = h; |
entry->d.h = h; |
| 1817 |
|
|
| 1818 |
/* If we can't find this entry with the new bfd hash, re-insert |
/* If we can't find this entry with the new bfd hash, re-insert |
| 1819 |
it, and get the traversal restarted. */ |
it, and get the traversal restarted. */ |
| 1820 |
if (! htab_find (got_entries, entry)) |
if (! htab_find (got_entries, entry)) |
| 1821 |
{ |
{ |
| 1822 |
htab_clear_slot (got_entries, entryp); |
htab_clear_slot (got_entries, entryp); |
| 1823 |
entryp = htab_find_slot (got_entries, entry, INSERT); |
entryp = htab_find_slot (got_entries, entry, INSERT); |
| 1824 |
if (! *entryp) |
if (! *entryp) |
| 1825 |
*entryp = entry; |
*entryp = entry; |
| 1826 |
/* Abort the traversal, since the whole table may have |
/* Abort the traversal, since the whole table may have |
| 1827 |
moved, and leave it up to the parent to restart the |
moved, and leave it up to the parent to restart the |
| 1828 |
process. */ |
process. */ |
| 1829 |
*(htab_t *)p = NULL; |
*(htab_t *)p = NULL; |
| 1830 |
return 0; |
return 0; |
| 1831 |
} |
} |
| 1832 |
/* We might want to decrement the global_gotno count, but it's |
/* We might want to decrement the global_gotno count, but it's |
| 1833 |
either too early or too late for that at this point. */ |
either too early or too late for that at this point. */ |
| 1834 |
} |
} |
| 1835 |
|
|
| 1836 |
return 1; |
return 1; |
| 1847 |
got_entries = g->got_entries; |
got_entries = g->got_entries; |
| 1848 |
|
|
| 1849 |
htab_traverse (got_entries, |
htab_traverse (got_entries, |
| 1850 |
score_elf_resolve_final_got_entry, |
score_elf_resolve_final_got_entry, |
| 1851 |
&got_entries); |
&got_entries); |
| 1852 |
} |
} |
| 1853 |
while (got_entries == NULL); |
while (got_entries == NULL); |
| 1854 |
} |
} |
| 1855 |
|
|
| 1856 |
/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. for -r */ |
/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. for -r */ |
|
|
|
| 1857 |
static void |
static void |
| 1858 |
score_elf_add_to_rel (bfd *abfd, |
score_elf_add_to_rel (bfd *abfd, |
| 1859 |
bfd_byte *address, |
bfd_byte *address, |
| 1860 |
reloc_howto_type *howto, |
reloc_howto_type *howto, |
| 1861 |
bfd_signed_vma increment) |
bfd_signed_vma increment) |
| 1862 |
{ |
{ |
| 1863 |
bfd_signed_vma addend; |
bfd_signed_vma addend; |
| 1864 |
bfd_vma contents; |
bfd_vma contents; |
| 1866 |
unsigned long r_type = howto->type; |
unsigned long r_type = howto->type; |
| 1867 |
unsigned long hi16_addend, hi16_offset, hi16_value, uvalue; |
unsigned long hi16_addend, hi16_offset, hi16_value, uvalue; |
| 1868 |
|
|
| 1869 |
contents = bfd_get_32 (abfd, address); |
contents = score_bfd_get_32 (abfd, address); |
| 1870 |
/* Get the (signed) value from the instruction. */ |
/* Get the (signed) value from the instruction. */ |
| 1871 |
addend = contents & howto->src_mask; |
addend = contents & howto->src_mask; |
| 1872 |
if (addend & ((howto->src_mask + 1) >> 1)) |
if (addend & ((howto->src_mask + 1) >> 1)) |
| 1887 |
contents = |
contents = |
| 1888 |
(contents & ~howto-> |
(contents & ~howto-> |
| 1889 |
src_mask) | (((offset << 6) & howto->src_mask) & 0x3ff0000) | (offset & 0x3ff); |
src_mask) | (((offset << 6) & howto->src_mask) & 0x3ff0000) | (offset & 0x3ff); |
| 1890 |
bfd_put_32 (abfd, contents, address); |
score_bfd_put_32 (abfd, contents, address); |
| 1891 |
break; |
break; |
| 1892 |
case R_SCORE_HI16: |
case R_SCORE_HI16: |
| 1893 |
break; |
break; |
| 1894 |
case R_SCORE_LO16: |
case R_SCORE_LO16: |
| 1895 |
hi16_addend = bfd_get_32 (abfd, address - 4); |
hi16_addend = score_bfd_get_32 (abfd, address - 4); |
| 1896 |
hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; |
hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; |
| 1897 |
offset = ((((contents >> 16) & 0x3) << 15) | (contents & 0x7fff)) >> 1; |
offset = ((((contents >> 16) & 0x3) << 15) | (contents & 0x7fff)) >> 1; |
| 1898 |
offset = (hi16_offset << 16) | (offset & 0xffff); |
offset = (hi16_offset << 16) | (offset & 0xffff); |
| 1900 |
hi16_offset = (uvalue >> 16) << 1; |
hi16_offset = (uvalue >> 16) << 1; |
| 1901 |
hi16_value = (hi16_addend & (~(howto->dst_mask))) |
hi16_value = (hi16_addend & (~(howto->dst_mask))) |
| 1902 |
| (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); |
| (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); |
| 1903 |
bfd_put_32 (abfd, hi16_value, address - 4); |
score_bfd_put_32 (abfd, hi16_value, address - 4); |
| 1904 |
offset = (uvalue & 0xffff) << 1; |
offset = (uvalue & 0xffff) << 1; |
| 1905 |
contents = (contents & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000); |
contents = (contents & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000); |
| 1906 |
bfd_put_32 (abfd, contents, address); |
score_bfd_put_32 (abfd, contents, address); |
| 1907 |
break; |
break; |
| 1908 |
case R_SCORE_24: |
case R_SCORE_24: |
| 1909 |
offset = |
offset = |
| 1912 |
contents = |
contents = |
| 1913 |
(contents & ~howto-> |
(contents & ~howto-> |
| 1914 |
src_mask) | (((offset << 1) & howto->src_mask) & 0x3ff0000) | (offset & 0x7fff); |
src_mask) | (((offset << 1) & howto->src_mask) & 0x3ff0000) | (offset & 0x7fff); |
| 1915 |
bfd_put_32 (abfd, contents, address); |
score_bfd_put_32 (abfd, contents, address); |
| 1916 |
break; |
break; |
| 1917 |
|
|
| 1918 |
case R_SCORE16_11: |
case R_SCORE16_11: |
| 1919 |
|
|
| 1920 |
contents = bfd_get_16 (abfd, address); |
contents = score_bfd_get_16 (abfd, address); |
| 1921 |
offset = contents & howto->src_mask; |
offset = contents & howto->src_mask; |
| 1922 |
offset += increment; |
offset += increment; |
| 1923 |
contents = (contents & ~howto->src_mask) | (offset & howto->src_mask); |
contents = (contents & ~howto->src_mask) | (offset & howto->src_mask); |
| 1924 |
bfd_put_16 (abfd, contents, address); |
score_bfd_put_16 (abfd, contents, address); |
| 1925 |
|
|
| 1926 |
break; |
break; |
| 1927 |
case R_SCORE16_PC8: |
case R_SCORE16_PC8: |
| 1928 |
|
|
| 1929 |
contents = bfd_get_16 (abfd, address); |
contents = score_bfd_get_16 (abfd, address); |
| 1930 |
offset = (contents & howto->src_mask) + ((increment >> 1) & 0xff); |
offset = (contents & howto->src_mask) + ((increment >> 1) & 0x1ff); |
| 1931 |
|
contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask); |
| 1932 |
|
score_bfd_put_16 (abfd, contents, address); |
| 1933 |
|
|
| 1934 |
|
break; |
| 1935 |
|
|
| 1936 |
|
case R_SCORE_BCMP: |
| 1937 |
|
contents = score_bfd_get_32 (abfd, address); |
| 1938 |
|
offset = (contents & howto->src_mask); |
| 1939 |
|
offset <<= howto->rightshift; |
| 1940 |
|
offset += increment; |
| 1941 |
|
offset >>= howto->rightshift; |
| 1942 |
|
contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask); |
| 1943 |
|
score_bfd_put_32 (abfd, contents, address); |
| 1944 |
|
break; |
| 1945 |
|
|
| 1946 |
|
case R_SCORE_IMM30: |
| 1947 |
|
contents = score_bfd_get_48 (abfd, address); |
| 1948 |
|
offset = (contents & howto->src_mask); |
| 1949 |
|
offset <<= howto->rightshift; |
| 1950 |
|
offset += increment; |
| 1951 |
|
offset >>= howto->rightshift; |
| 1952 |
contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask); |
contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask); |
| 1953 |
bfd_put_16 (abfd, contents, address); |
score_bfd_put_48 (abfd, contents, address); |
| 1954 |
|
break; |
| 1955 |
|
|
| 1956 |
|
case R_SCORE_IMM32: |
| 1957 |
|
contents = score_bfd_get_48 (abfd, address); |
| 1958 |
|
offset = (contents & howto->src_mask); |
| 1959 |
|
offset += increment; |
| 1960 |
|
contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask); |
| 1961 |
|
score_bfd_put_48 (abfd, contents, address); |
| 1962 |
break; |
break; |
| 1963 |
|
|
| 1964 |
default: |
default: |
| 1965 |
addend += increment; |
addend += increment; |
| 1966 |
contents = (contents & ~howto->dst_mask) | (addend & howto->dst_mask); |
contents = (contents & ~howto->dst_mask) | (addend & howto->dst_mask); |
| 1967 |
bfd_put_32 (abfd, contents, address); |
score_bfd_put_32 (abfd, contents, address); |
| 1968 |
break; |
break; |
| 1969 |
} |
} |
| 1970 |
} |
} |
| 1971 |
|
|
| 1972 |
/* Perform a relocation as part of a final link. */ |
/* Perform a relocation as part of a final link. */ |
|
|
|
| 1973 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
| 1974 |
score_elf_final_link_relocate (reloc_howto_type *howto, |
score_elf_final_link_relocate (reloc_howto_type *howto, |
| 1975 |
bfd *input_bfd, |
bfd *input_bfd, |
| 1976 |
bfd *output_bfd, |
bfd *output_bfd, |
| 1977 |
asection *input_section, |
asection *input_section, |
| 1978 |
bfd_byte *contents, |
bfd_byte *contents, |
| 1979 |
Elf_Internal_Rela *rel, |
Elf_Internal_Rela *rel, |
| 1980 |
Elf_Internal_Rela *relocs, |
Elf_Internal_Rela *relocs, |
| 1981 |
bfd_vma symbol, |
bfd_vma symbol, |
| 1982 |
struct bfd_link_info *info, |
struct bfd_link_info *info, |
| 1983 |
const char *sym_name ATTRIBUTE_UNUSED, |
const char *sym_name ATTRIBUTE_UNUSED, |
| 1984 |
int sym_flags ATTRIBUTE_UNUSED, |
int sym_flags ATTRIBUTE_UNUSED, |
| 1985 |
struct score_elf_link_hash_entry *h, |
struct score_elf_link_hash_entry *h, |
| 1986 |
|
asection **local_sections, |
| 1987 |
bfd_boolean gp_disp_p) |
bfd_boolean gp_disp_p) |
| 1988 |
{ |
{ |
| 1989 |
unsigned long r_type; |
unsigned long r_type; |
| 2006 |
bfd_vma value = symbol; |
bfd_vma value = symbol; |
| 2007 |
unsigned long hi16_addend, hi16_offset, hi16_value, uvalue, offset, abs_value = 0; |
unsigned long hi16_addend, hi16_offset, hi16_value, uvalue, offset, abs_value = 0; |
| 2008 |
|
|
| 2009 |
|
|
| 2010 |
if (elf_gp (output_bfd) == 0) |
if (elf_gp (output_bfd) == 0) |
| 2011 |
{ |
{ |
| 2012 |
struct bfd_link_hash_entry *bh; |
struct bfd_link_hash_entry *bh; |
| 2013 |
asection *o; |
asection *o; |
| 2014 |
|
|
| 2015 |
bh = bfd_link_hash_lookup (info->hash, "_gp", 0, 0, 1); |
bh = bfd_link_hash_lookup (info->hash, "_gp", 0, 0, 1); |
| 2016 |
if (bh != (struct bfd_link_hash_entry *)NULL && bh->type == bfd_link_hash_defined) |
if (bh != NULL && bh->type == bfd_link_hash_defined) |
| 2017 |
elf_gp (output_bfd) = (bh->u.def.value |
elf_gp (output_bfd) = (bh->u.def.value |
| 2018 |
+ bh->u.def.section->output_section->vma |
+ bh->u.def.section->output_section->vma |
| 2019 |
+ bh->u.def.section->output_offset); |
+ bh->u.def.section->output_offset); |
| 2022 |
bfd_vma lo = -1; |
bfd_vma lo = -1; |
| 2023 |
|
|
| 2024 |
/* Find the GP-relative section with the lowest offset. */ |
/* Find the GP-relative section with the lowest offset. */ |
| 2025 |
for (o = output_bfd->sections; o != (asection *) NULL; o = o->next) |
for (o = output_bfd->sections; o != NULL; o = o->next) |
| 2026 |
if (o->vma < lo) |
if (o->vma < lo) |
| 2027 |
lo = o->vma; |
lo = o->vma; |
| 2028 |
/* And calculate GP relative to that. */ |
/* And calculate GP relative to that. */ |
| 2040 |
r_symndx = ELF32_R_SYM (rel->r_info); |
r_symndx = ELF32_R_SYM (rel->r_info); |
| 2041 |
r_type = ELF32_R_TYPE (rel->r_info); |
r_type = ELF32_R_TYPE (rel->r_info); |
| 2042 |
rel_addr = (input_section->output_section->vma + input_section->output_offset + rel->r_offset); |
rel_addr = (input_section->output_section->vma + input_section->output_offset + rel->r_offset); |
| 2043 |
local_p = score_elf_local_relocation_p (input_bfd, rel, TRUE); |
local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, TRUE); |
| 2044 |
|
|
| 2045 |
if (r_type == R_SCORE_GOT15) |
if (r_type == R_SCORE_GOT15) |
| 2046 |
{ |
{ |
| 2053 |
relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel; |
relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel; |
| 2054 |
lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend); |
lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend); |
| 2055 |
if ((local_p) && (lo16_rel != NULL)) |
if ((local_p) && (lo16_rel != NULL)) |
| 2056 |
{ |
{ |
| 2057 |
bfd_vma tmp = 0; |
bfd_vma tmp = 0; |
| 2058 |
tmp = bfd_get_32 (input_bfd, contents + lo16_rel->r_offset); |
tmp = score_bfd_get_32 (input_bfd, contents + lo16_rel->r_offset); |
| 2059 |
lo_value = (((tmp >> 16) & 0x3) << 14) | ((tmp & 0x7fff) >> 1); |
lo_value = (((tmp >> 16) & 0x3) << 14) | ((tmp & 0x7fff) >> 1); |
| 2060 |
} |
} |
| 2061 |
addend = lo_value; |
addend = lo_value; |
| 2062 |
} |
} |
| 2063 |
else |
/* For score3 R_SCORE_ABS32. */ |
| 2064 |
|
else if (r_type == R_SCORE_ABS32 || r_type == R_SCORE_REL32) |
| 2065 |
{ |
{ |
| 2066 |
addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask; |
addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask; |
| 2067 |
} |
} |
| 2068 |
|
else |
| 2069 |
|
{ |
| 2070 |
|
addend = (score_bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask; |
| 2071 |
|
} |
| 2072 |
|
|
| 2073 |
/* If we haven't already determined the GOT offset, or the GP value, |
/* If we haven't already determined the GOT offset, or the GP value, |
| 2074 |
and we're going to need it, get it now. */ |
and we're going to need it, get it now. */ |
| 2090 |
We must initialize this entry in the GOT. */ |
We must initialize this entry in the GOT. */ |
| 2091 |
bfd *tmpbfd = elf_hash_table (info)->dynobj; |
bfd *tmpbfd = elf_hash_table (info)->dynobj; |
| 2092 |
asection *sgot = score_elf_got_section (tmpbfd, FALSE); |
asection *sgot = score_elf_got_section (tmpbfd, FALSE); |
| 2093 |
bfd_put_32 (tmpbfd, value, sgot->contents + g); |
score_bfd_put_32 (tmpbfd, value, sgot->contents + g); |
| 2094 |
} |
} |
| 2095 |
} |
} |
| 2096 |
else if (r_type == R_SCORE_GOT15 || r_type == R_SCORE_CALL15) |
else if (r_type == R_SCORE_GOT15 || r_type == R_SCORE_CALL15) |
| 2097 |
{ |
{ |
| 2098 |
/* There's no need to create a local GOT entry here; the |
/* There's no need to create a local GOT entry here; the |
| 2099 |
calculation for a local GOT15 entry does not involve G. */ |
calculation for a local GOT15 entry does not involve G. */ |
| 2100 |
; |
; |
| 2101 |
} |
} |
| 2102 |
else |
else |
| 2103 |
{ |
{ |
| 2104 |
g = score_elf_local_got_index (output_bfd, input_bfd, info, |
g = score_elf_local_got_index (output_bfd, input_bfd, info, |
| 2105 |
symbol + addend, r_symndx, h, r_type); |
symbol + addend, r_symndx, h, r_type); |
| 2106 |
if (g == MINUS_ONE) |
if (g == MINUS_ONE) |
| 2107 |
return bfd_reloc_outofrange; |
return bfd_reloc_outofrange; |
| 2108 |
} |
} |
| 2109 |
|
|
| 2110 |
/* Convert GOT indices to actual offsets. */ |
/* Convert GOT indices to actual offsets. */ |
| 2111 |
g = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj, |
g = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj, |
| 2112 |
output_bfd, input_bfd, g); |
output_bfd, input_bfd, g); |
| 2113 |
break; |
break; |
| 2114 |
|
|
| 2115 |
case R_SCORE_HI16: |
case R_SCORE_HI16: |
| 2134 |
case R_SCORE_ABS32: |
case R_SCORE_ABS32: |
| 2135 |
case R_SCORE_REL32: |
case R_SCORE_REL32: |
| 2136 |
if ((info->shared |
if ((info->shared |
| 2137 |
|| (elf_hash_table (info)->dynamic_sections_created |
|| (elf_hash_table (info)->dynamic_sections_created |
| 2138 |
&& h != NULL |
&& h != NULL |
| 2139 |
&& h->root.def_dynamic |
&& h->root.def_dynamic |
| 2140 |
&& !h->root.def_regular)) |
&& !h->root.def_regular)) |
| 2141 |
&& r_symndx != 0 |
&& r_symndx != 0 |
| 2142 |
&& (input_section->flags & SEC_ALLOC) != 0) |
&& (input_section->flags & SEC_ALLOC) != 0) |
| 2143 |
{ |
{ |
| 2144 |
/* If we're creating a shared library, or this relocation is against a symbol |
/* If we're creating a shared library, or this relocation is against a symbol |
| 2145 |
in a shared library, then we can't know where the symbol will end up. |
in a shared library, then we can't know where the symbol will end up. |
| 2146 |
So, we create a relocation record in the output, and leave the job up |
So, we create a relocation record in the output, and leave the job up |
| 2147 |
to the dynamic linker. */ |
to the dynamic linker. */ |
| 2148 |
value = addend; |
value = addend; |
| 2149 |
if (!score_elf_create_dynamic_relocation (output_bfd, info, rel, h, |
if (!score_elf_create_dynamic_relocation (output_bfd, info, rel, h, |
| 2150 |
symbol, &value, |
symbol, &value, |
| 2151 |
input_section)) |
input_section)) |
| 2152 |
return bfd_reloc_undefined; |
return bfd_reloc_undefined; |
| 2153 |
} |
} |
| 2154 |
|
else if (r_symndx == 0) |
| 2155 |
|
/* r_symndx will be zero only for relocs against symbols |
| 2156 |
|
from removed linkonce sections, or sections discarded by |
| 2157 |
|
a linker script. */ |
| 2158 |
|
value = 0; |
| 2159 |
else |
else |
| 2160 |
{ |
{ |
| 2161 |
if (r_type != R_SCORE_REL32) |
if (r_type != R_SCORE_REL32) |
| 2162 |
value = symbol + addend; |
value = symbol + addend; |
| 2163 |
else |
else |
| 2164 |
value = addend; |
value = addend; |
| 2165 |
} |
} |
| 2166 |
value &= howto->dst_mask; |
value &= howto->dst_mask; |
| 2167 |
bfd_put_32 (input_bfd, value, hit_data); |
bfd_put_32 (input_bfd, value, hit_data); |
| 2168 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2171 |
value += addend; |
value += addend; |
| 2172 |
if ((long)value > 0x7fff || (long)value < -0x8000) |
if ((long)value > 0x7fff || (long)value < -0x8000) |
| 2173 |
return bfd_reloc_overflow; |
return bfd_reloc_overflow; |
| 2174 |
bfd_put_16 (input_bfd, value, hit_data); |
score_bfd_put_16 (input_bfd, value, hit_data); |
| 2175 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2176 |
|
|
| 2177 |
case R_SCORE_24: |
case R_SCORE_24: |
| 2178 |
addend = bfd_get_32 (input_bfd, hit_data); |
addend = score_bfd_get_32 (input_bfd, hit_data); |
| 2179 |
offset = (((addend & howto->src_mask) >> 1) & 0x1ff8000) | ((addend & howto->src_mask) & 0x7fff); |
offset = (((addend & howto->src_mask) >> 1) & 0x1ff8000) | ((addend & howto->src_mask) & 0x7fff); |
| 2180 |
if ((offset & 0x1000000) != 0) |
if ((offset & 0x1000000) != 0) |
| 2181 |
offset |= 0xfe000000; |
offset |= 0xfe000000; |
| 2182 |
value += offset; |
value += offset; |
| 2183 |
|
abs_value = abs (value - rel_addr); |
| 2184 |
|
if ((abs_value & 0xfe000000) != 0) |
| 2185 |
|
return bfd_reloc_overflow; |
| 2186 |
addend = (addend & ~howto->src_mask) |
addend = (addend & ~howto->src_mask) |
| 2187 |
| (((value << 1) & howto->src_mask) & 0x3ff0000) | (value & 0x7fff); |
| (((value << 1) & howto->src_mask) & 0x3ff0000) | (value & 0x7fff); |
| 2188 |
bfd_put_32 (input_bfd, addend, hit_data); |
score_bfd_put_32 (input_bfd, addend, hit_data); |
| 2189 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2190 |
|
|
| 2191 |
|
/* signed imm32. */ |
| 2192 |
|
case R_SCORE_IMM30: |
| 2193 |
|
{ |
| 2194 |
|
int not_word_align_p = 0; |
| 2195 |
|
bfd_vma imm_offset = 0; |
| 2196 |
|
addend = score_bfd_get_48 (input_bfd, hit_data); |
| 2197 |
|
imm_offset = ((addend >> 7) & 0xff) |
| 2198 |
|
| (((addend >> 16) & 0x7fff) << 8) |
| 2199 |
|
| (((addend >> 32) & 0x7f) << 23); |
| 2200 |
|
imm_offset <<= howto->rightshift; |
| 2201 |
|
value += imm_offset; |
| 2202 |
|
value &= 0xffffffff; |
| 2203 |
|
|
| 2204 |
|
/* Check lw48/sw48 rd, value/label word align. */ |
| 2205 |
|
if ((value & 0x3) != 0) |
| 2206 |
|
not_word_align_p = 1; |
| 2207 |
|
|
| 2208 |
|
value >>= howto->rightshift; |
| 2209 |
|
addend = (addend & ~howto->src_mask) |
| 2210 |
|
| (((value & 0xff) >> 0) << 7) |
| 2211 |
|
| (((value & 0x7fff00) >> 8) << 16) |
| 2212 |
|
| (((value & 0x3f800000) >> 23) << 32); |
| 2213 |
|
score_bfd_put_48 (input_bfd, addend, hit_data); |
| 2214 |
|
if (not_word_align_p) |
| 2215 |
|
return bfd_reloc_other; |
| 2216 |
|
else |
| 2217 |
|
return bfd_reloc_ok; |
| 2218 |
|
} |
| 2219 |
|
|
| 2220 |
|
case R_SCORE_IMM32: |
| 2221 |
|
{ |
| 2222 |
|
bfd_vma imm_offset = 0; |
| 2223 |
|
addend = score_bfd_get_48 (input_bfd, hit_data); |
| 2224 |
|
imm_offset = ((addend >> 5) & 0x3ff) |
| 2225 |
|
| (((addend >> 16) & 0x7fff) << 10) |
| 2226 |
|
| (((addend >> 32) & 0x7f) << 25); |
| 2227 |
|
value += imm_offset; |
| 2228 |
|
value &= 0xffffffff; |
| 2229 |
|
addend = (addend & ~howto->src_mask) |
| 2230 |
|
| ((value & 0x3ff) << 5) |
| 2231 |
|
| (((value >> 10) & 0x7fff) << 16) |
| 2232 |
|
| (((value >> 25) & 0x7f) << 32); |
| 2233 |
|
score_bfd_put_48 (input_bfd, addend, hit_data); |
| 2234 |
|
return bfd_reloc_ok; |
| 2235 |
|
} |
| 2236 |
|
|
| 2237 |
case R_SCORE_PC19: |
case R_SCORE_PC19: |
| 2238 |
addend = bfd_get_32 (input_bfd, hit_data); |
addend = score_bfd_get_32 (input_bfd, hit_data); |
| 2239 |
offset = (((addend & howto->src_mask) & 0x3ff0000) >> 6) | ((addend & howto->src_mask) & 0x3ff); |
offset = (((addend & howto->src_mask) & 0x3ff0000) >> 6) | ((addend & howto->src_mask) & 0x3ff); |
| 2240 |
if ((offset & 0x80000) != 0) |
if ((offset & 0x80000) != 0) |
| 2241 |
offset |= 0xfff00000; |
offset |= 0xfff00000; |
| 2247 |
return bfd_reloc_overflow; |
return bfd_reloc_overflow; |
| 2248 |
addend = (addend & ~howto->src_mask) |
addend = (addend & ~howto->src_mask) |
| 2249 |
| (((value << 6) & howto->src_mask) & 0x3ff0000) | (value & 0x3ff); |
| (((value << 6) & howto->src_mask) & 0x3ff0000) | (value & 0x3ff); |
| 2250 |
bfd_put_32 (input_bfd, addend, hit_data); |
score_bfd_put_32 (input_bfd, addend, hit_data); |
| 2251 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2252 |
|
|
| 2253 |
case R_SCORE16_11: |
case R_SCORE16_11: |
| 2254 |
addend = bfd_get_16 (input_bfd, hit_data); |
addend = score_bfd_get_16 (input_bfd, hit_data); |
| 2255 |
offset = addend & howto->src_mask; |
offset = addend & howto->src_mask; |
| 2256 |
if ((offset & 0x800) != 0) /* Offset is negative. */ |
if ((offset & 0x800) != 0) /* Offset is negative. */ |
| 2257 |
offset |= 0xfffff000; |
offset |= 0xfffff000; |
| 2258 |
value += offset; |
value += offset; |
| 2259 |
|
abs_value = abs (value - rel_addr); |
| 2260 |
|
if ((abs_value & 0xfffff000) != 0) |
| 2261 |
|
return bfd_reloc_overflow; |
| 2262 |
addend = (addend & ~howto->src_mask) | (value & howto->src_mask); |
addend = (addend & ~howto->src_mask) | (value & howto->src_mask); |
| 2263 |
bfd_put_16 (input_bfd, addend, hit_data); |
score_bfd_put_16 (input_bfd, addend, hit_data); |
| 2264 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2265 |
|
|
| 2266 |
case R_SCORE16_PC8: |
case R_SCORE16_PC8: |
| 2267 |
addend = bfd_get_16 (input_bfd, hit_data); |
addend = score_bfd_get_16 (input_bfd, hit_data); |
| 2268 |
offset = (addend & howto->src_mask) << 1; |
offset = (addend & howto->src_mask) << 1; |
| 2269 |
if ((offset & 0x100) != 0) /* Offset is negative. */ |
if ((offset & 0x200) != 0) /* Offset is negative. */ |
| 2270 |
offset |= 0xfffffe00; |
offset |= 0xfffffe00; |
| 2271 |
abs_value = value = value - rel_addr + offset; |
abs_value = value = value - rel_addr + offset; |
| 2272 |
/* Sign bit + exceed 9 bit. */ |
/* Sign bit + exceed 9 bit. */ |
| 2273 |
if (((value & 0xffffff00) != 0) && ((value & 0xffffff00) != 0xffffff00)) |
if (((value & 0xfffffe00) != 0) && ((value & 0xfffffe00) != 0xfffffe00)) |
| 2274 |
return bfd_reloc_overflow; |
return bfd_reloc_overflow; |
| 2275 |
value >>= 1; |
value >>= 1; |
| 2276 |
addend = (addend & ~howto->src_mask) | (value & howto->src_mask); |
addend = (addend & ~howto->src_mask) | (value & howto->src_mask); |
| 2277 |
bfd_put_16 (input_bfd, addend, hit_data); |
score_bfd_put_16 (input_bfd, addend, hit_data); |
| 2278 |
|
return bfd_reloc_ok; |
| 2279 |
|
|
| 2280 |
|
case R_SCORE_BCMP: |
| 2281 |
|
addend = score_bfd_get_32 (input_bfd, hit_data); |
| 2282 |
|
offset = (addend & howto->src_mask) << howto->rightshift; |
| 2283 |
|
if ((offset & 0x200) != 0) /* Offset is negative. */ |
| 2284 |
|
offset |= 0xfffffe00; |
| 2285 |
|
value = value - rel_addr + offset; |
| 2286 |
|
/* Sign bit + exceed 9 bit. */ |
| 2287 |
|
if (((value & 0xfffffe00) != 0) && ((value & 0xfffffe00) != 0xfffffe00)) |
| 2288 |
|
return bfd_reloc_overflow; |
| 2289 |
|
value >>= howto->rightshift; |
| 2290 |
|
addend = (addend & ~howto->src_mask) |
| 2291 |
|
| (value & 0x1) |
| 2292 |
|
| (((value >> 1) & 0x7) << 7) |
| 2293 |
|
| (((value >> 4) & 0x1f) << 21); |
| 2294 |
|
score_bfd_put_32 (input_bfd, addend, hit_data); |
| 2295 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2296 |
|
|
| 2297 |
case R_SCORE_HI16: |
case R_SCORE_HI16: |
| 2298 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2299 |
|
|
| 2300 |
case R_SCORE_LO16: |
case R_SCORE_LO16: |
| 2301 |
hi16_addend = bfd_get_32 (input_bfd, hit_data - 4); |
hi16_addend = score_bfd_get_32 (input_bfd, hit_data - 4); |
| 2302 |
hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; |
hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; |
| 2303 |
addend = bfd_get_32 (input_bfd, hit_data); |
addend = score_bfd_get_32 (input_bfd, hit_data); |
| 2304 |
offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; |
offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; |
| 2305 |
offset = (hi16_offset << 16) | (offset & 0xffff); |
offset = (hi16_offset << 16) | (offset & 0xffff); |
| 2306 |
|
|
| 2307 |
if (!gp_disp_p) |
if (!gp_disp_p) |
| 2308 |
uvalue = value + offset; |
uvalue = value + offset; |
| 2309 |
else |
else |
| 2310 |
uvalue = offset + gp - rel_addr + 4; |
uvalue = offset + gp - rel_addr + 4; |
| 2311 |
|
|
| 2312 |
hi16_offset = (uvalue >> 16) << 1; |
hi16_offset = (uvalue >> 16) << 1; |
| 2313 |
hi16_value = (hi16_addend & (~(howto->dst_mask))) |
hi16_value = (hi16_addend & (~(howto->dst_mask))) |
| 2314 |
| (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); |
| (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); |
| 2315 |
bfd_put_32 (input_bfd, hi16_value, hit_data - 4); |
score_bfd_put_32 (input_bfd, hi16_value, hit_data - 4); |
| 2316 |
offset = (uvalue & 0xffff) << 1; |
offset = (uvalue & 0xffff) << 1; |
| 2317 |
value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000); |
value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000); |
| 2318 |
bfd_put_32 (input_bfd, value, hit_data); |
score_bfd_put_32 (input_bfd, value, hit_data); |
| 2319 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2320 |
|
|
| 2321 |
case R_SCORE_GP15: |
case R_SCORE_GP15: |
| 2322 |
addend = bfd_get_32 (input_bfd, hit_data); |
addend = score_bfd_get_32 (input_bfd, hit_data); |
| 2323 |
offset = addend & 0x7fff; |
offset = addend & 0x7fff; |
| 2324 |
if ((offset & 0x4000) == 0x4000) |
if ((offset & 0x4000) == 0x4000) |
| 2325 |
offset |= 0xffffc000; |
offset |= 0xffffc000; |
| 2327 |
if (((value & 0xffffc000) != 0) && ((value & 0xffffc000) != 0xffffc000)) |
if (((value & 0xffffc000) != 0) && ((value & 0xffffc000) != 0xffffc000)) |
| 2328 |
return bfd_reloc_overflow; |
return bfd_reloc_overflow; |
| 2329 |
value = (addend & ~howto->src_mask) | (value & howto->src_mask); |
value = (addend & ~howto->src_mask) | (value & howto->src_mask); |
| 2330 |
bfd_put_32 (input_bfd, value, hit_data); |
score_bfd_put_32 (input_bfd, value, hit_data); |
| 2331 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2332 |
|
|
| 2333 |
case R_SCORE_GOT15: |
case R_SCORE_GOT15: |
| 2334 |
case R_SCORE_CALL15: |
case R_SCORE_CALL15: |
| 2335 |
if (local_p) |
if (local_p) |
| 2336 |
{ |
{ |
| 2337 |
bfd_boolean forced; |
bfd_boolean forced; |
| 2338 |
|
|
| 2339 |
/* The special case is when the symbol is forced to be local. We need the |
/* The special case is when the symbol is forced to be local. We need the |
| 2340 |
full address in the GOT since no R_SCORE_GOT_LO16 relocation follows. */ |
full address in the GOT since no R_SCORE_GOT_LO16 relocation follows. */ |
| 2341 |
forced = ! score_elf_local_relocation_p (input_bfd, rel, FALSE); |
forced = ! score_elf_local_relocation_p (input_bfd, rel, |
| 2342 |
value = score_elf_got16_entry (output_bfd, input_bfd, info, |
local_sections, FALSE); |
| 2343 |
symbol + addend, forced); |
value = score_elf_got16_entry (output_bfd, input_bfd, info, |
| 2344 |
if (value == MINUS_ONE) |
symbol + addend, forced); |
| 2345 |
return bfd_reloc_outofrange; |
if (value == MINUS_ONE) |
| 2346 |
value = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj, |
return bfd_reloc_outofrange; |
| 2347 |
output_bfd, input_bfd, value); |
value = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj, |
| 2348 |
} |
output_bfd, input_bfd, value); |
| 2349 |
|
} |
| 2350 |
else |
else |
| 2351 |
{ |
{ |
| 2352 |
value = g; |
value = g; |
| 2353 |
} |
} |
| 2354 |
|
|
| 2355 |
if ((long) value > 0x3fff || (long) value < -0x4000) |
if ((long) value > 0x3fff || (long) value < -0x4000) |
| 2356 |
return bfd_reloc_overflow; |
return bfd_reloc_overflow; |
| 2357 |
|
|
| 2358 |
addend = bfd_get_32 (input_bfd, hit_data); |
addend = score_bfd_get_32 (input_bfd, hit_data); |
| 2359 |
value = (addend & ~howto->dst_mask) | (value & howto->dst_mask); |
value = (addend & ~howto->dst_mask) | (value & howto->dst_mask); |
| 2360 |
bfd_put_32 (input_bfd, value, hit_data); |
score_bfd_put_32 (input_bfd, value, hit_data); |
| 2361 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2362 |
|
|
| 2363 |
case R_SCORE_GPREL32: |
case R_SCORE_GPREL32: |
| 2364 |
value = (addend + symbol - gp); |
value = (addend + symbol - gp); |
| 2365 |
value &= howto->dst_mask; |
value &= howto->dst_mask; |
| 2366 |
bfd_put_32 (input_bfd, value, hit_data); |
score_bfd_put_32 (input_bfd, value, hit_data); |
| 2367 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2368 |
|
|
| 2369 |
case R_SCORE_GOT_LO16: |
case R_SCORE_GOT_LO16: |
| 2370 |
addend = bfd_get_32 (input_bfd, hit_data); |
addend = score_bfd_get_32 (input_bfd, hit_data); |
| 2371 |
value = (((addend >> 16) & 0x3) << 14) | ((addend & 0x7fff) >> 1); |
value = (((addend >> 16) & 0x3) << 14) | ((addend & 0x7fff) >> 1); |
| 2372 |
value += symbol; |
value += symbol; |
| 2373 |
value = (addend & (~(howto->dst_mask))) | ((value & 0x3fff) << 1) |
value = (addend & (~(howto->dst_mask))) | ((value & 0x3fff) << 1) |
| 2374 |
| (((value >> 14) & 0x3) << 16); |
| (((value >> 14) & 0x3) << 16); |
| 2375 |
|
|
| 2376 |
bfd_put_32 (input_bfd, value, hit_data); |
score_bfd_put_32 (input_bfd, value, hit_data); |
| 2377 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 2378 |
|
|
| 2379 |
case R_SCORE_DUMMY_HI16: |
case R_SCORE_DUMMY_HI16: |
| 2390 |
} |
} |
| 2391 |
|
|
| 2392 |
/* Score backend functions. */ |
/* Score backend functions. */ |
|
|
|
| 2393 |
static void |
static void |
| 2394 |
_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, |
s3_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, |
| 2395 |
arelent *bfd_reloc, |
arelent *bfd_reloc, |
| 2396 |
Elf_Internal_Rela *elf_reloc) |
Elf_Internal_Rela *elf_reloc) |
| 2397 |
{ |
{ |
| 2398 |
unsigned int r_type; |
unsigned int r_type; |
| 2399 |
|
|
| 2400 |
r_type = ELF32_R_TYPE (elf_reloc->r_info); |
r_type = ELF32_R_TYPE (elf_reloc->r_info); |
| 2401 |
if (r_type >= NUM_ELEM (elf32_score_howto_table)) |
if (r_type >= ARRAY_SIZE (elf32_score_howto_table)) |
| 2402 |
bfd_reloc->howto = NULL; |
bfd_reloc->howto = NULL; |
| 2403 |
else |
else |
| 2404 |
bfd_reloc->howto = &elf32_score_howto_table[r_type]; |
bfd_reloc->howto = &elf32_score_howto_table[r_type]; |
| 2405 |
} |
} |
| 2406 |
|
|
| 2407 |
/* Relocate an score ELF section. */ |
/* Relocate an score ELF section. */ |
|
|
|
| 2408 |
static bfd_boolean |
static bfd_boolean |
| 2409 |
_bfd_score_elf_relocate_section (bfd *output_bfd, |
s3_bfd_score_elf_relocate_section (bfd *output_bfd, |
| 2410 |
struct bfd_link_info *info, |
struct bfd_link_info *info, |
| 2411 |
bfd *input_bfd, |
bfd *input_bfd, |
| 2412 |
asection *input_section, |
asection *input_section, |
| 2413 |
bfd_byte *contents, |
bfd_byte *contents, |
| 2414 |
Elf_Internal_Rela *relocs, |
Elf_Internal_Rela *relocs, |
| 2415 |
Elf_Internal_Sym *local_syms, |
Elf_Internal_Sym *local_syms, |
| 2416 |
asection **local_sections) |
asection **local_sections) |
| 2417 |
{ |
{ |
| 2418 |
Elf_Internal_Shdr *symtab_hdr; |
Elf_Internal_Shdr *symtab_hdr; |
| 2419 |
struct elf_link_hash_entry **sym_hashes; |
struct elf_link_hash_entry **sym_hashes; |
| 2430 |
{ |
{ |
| 2431 |
bfd_size_type dynsecsymcount = 0; |
bfd_size_type dynsecsymcount = 0; |
| 2432 |
if (info->shared) |
if (info->shared) |
| 2433 |
{ |
{ |
| 2434 |
asection * p; |
asection * p; |
| 2435 |
const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); |
const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); |
| 2436 |
|
|
| 2437 |
for (p = output_bfd->sections; p ; p = p->next) |
for (p = output_bfd->sections; p ; p = p->next) |
| 2438 |
if ((p->flags & SEC_EXCLUDE) == 0 |
if ((p->flags & SEC_EXCLUDE) == 0 |
| 2439 |
&& (p->flags & SEC_ALLOC) != 0 |
&& (p->flags & SEC_ALLOC) != 0 |
| 2440 |
&& !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p)) |
&& !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p)) |
| 2441 |
++ dynsecsymcount; |
++ dynsecsymcount; |
| 2442 |
} |
} |
| 2443 |
|
|
| 2444 |
if (!score_elf_sort_hash_table (info, dynsecsymcount + 1)) |
if (!score_elf_sort_hash_table (info, dynsecsymcount + 1)) |
| 2445 |
return FALSE; |
return FALSE; |
| 2446 |
} |
} |
| 2447 |
|
|
| 2448 |
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; |
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; |
| 2449 |
extsymoff = symtab_hdr->sh_info; |
extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info; |
| 2450 |
sym_hashes = elf_sym_hashes (input_bfd); |
sym_hashes = elf_sym_hashes (input_bfd); |
| 2451 |
rel = relocs; |
rel = relocs; |
| 2452 |
relend = relocs + input_section->reloc_count; |
relend = relocs + input_section->reloc_count; |
| 2465 |
r_symndx = ELF32_R_SYM (rel->r_info); |
r_symndx = ELF32_R_SYM (rel->r_info); |
| 2466 |
r_type = ELF32_R_TYPE (rel->r_info); |
r_type = ELF32_R_TYPE (rel->r_info); |
| 2467 |
|
|
| 2468 |
_bfd_score_info_to_howto (input_bfd, &bfd_reloc, (Elf_Internal_Rela *) rel); |
s3_bfd_score_info_to_howto (input_bfd, &bfd_reloc, (Elf_Internal_Rela *) rel); |
| 2469 |
howto = bfd_reloc.howto; |
howto = bfd_reloc.howto; |
| 2470 |
|
|
| 2471 |
h = NULL; |
h = NULL; |
| 2477 |
sym = local_syms + r_symndx; |
sym = local_syms + r_symndx; |
| 2478 |
sec = local_sections[r_symndx]; |
sec = local_sections[r_symndx]; |
| 2479 |
relocation = (sec->output_section->vma |
relocation = (sec->output_section->vma |
| 2480 |
+ sec->output_offset |
+ sec->output_offset |
| 2481 |
+ sym->st_value); |
+ sym->st_value); |
| 2482 |
name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); |
name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); |
| 2483 |
|
|
| 2484 |
if (!info->relocatable |
if (!info->relocatable |
| 2485 |
&& (sec->flags & SEC_MERGE) != 0 |
&& (sec->flags & SEC_MERGE) |
| 2486 |
&& ELF_ST_TYPE (sym->st_info) == STT_SECTION) |
&& ELF_ST_TYPE (sym->st_info) == STT_SECTION) |
| 2487 |
{ |
{ |
| 2488 |
asection *msec; |
asection *msec; |
| 2489 |
bfd_vma addend, value; |
bfd_vma addend, value; |
| 2493 |
case R_SCORE_HI16: |
case R_SCORE_HI16: |
| 2494 |
break; |
break; |
| 2495 |
case R_SCORE_LO16: |
case R_SCORE_LO16: |
| 2496 |
hi16_addend = bfd_get_32 (input_bfd, contents + rel->r_offset - 4); |
hi16_addend = score_bfd_get_32 (input_bfd, contents + rel->r_offset - 4); |
| 2497 |
hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; |
hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; |
| 2498 |
value = bfd_get_32 (input_bfd, contents + rel->r_offset); |
value = score_bfd_get_32 (input_bfd, contents + rel->r_offset); |
| 2499 |
offset = ((((value >> 16) & 0x3) << 15) | (value & 0x7fff)) >> 1; |
offset = ((((value >> 16) & 0x3) << 15) | (value & 0x7fff)) >> 1; |
| 2500 |
addend = (hi16_offset << 16) | (offset & 0xffff); |
addend = (hi16_offset << 16) | (offset & 0xffff); |
| 2501 |
msec = sec; |
msec = sec; |
| 2506 |
hi16_offset = (uvalue >> 16) << 1; |
hi16_offset = (uvalue >> 16) << 1; |
| 2507 |
hi16_value = (hi16_addend & (~(howto->dst_mask))) |
hi16_value = (hi16_addend & (~(howto->dst_mask))) |
| 2508 |
| (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); |
| (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); |
| 2509 |
bfd_put_32 (input_bfd, hi16_value, contents + rel->r_offset - 4); |
score_bfd_put_32 (input_bfd, hi16_value, contents + rel->r_offset - 4); |
| 2510 |
offset = (uvalue & 0xffff) << 1; |
offset = (uvalue & 0xffff) << 1; |
| 2511 |
value = (value & (~(howto->dst_mask))) |
value = (value & (~(howto->dst_mask))) |
| 2512 |
| (offset & 0x7fff) | ((offset << 1) & 0x30000); |
| (offset & 0x7fff) | ((offset << 1) & 0x30000); |
| 2513 |
bfd_put_32 (input_bfd, value, contents + rel->r_offset); |
score_bfd_put_32 (input_bfd, value, contents + rel->r_offset); |
| 2514 |
break; |
break; |
| 2515 |
|
|
| 2516 |
|
case R_SCORE_IMM32: |
| 2517 |
|
{ |
| 2518 |
|
value = score_bfd_get_48 (input_bfd, contents + rel->r_offset); |
| 2519 |
|
addend = ((value >> 5) & 0x3ff) |
| 2520 |
|
| (((value >> 16) & 0x7fff) << 10) |
| 2521 |
|
| (((value >> 32) & 0x7f) << 25); |
| 2522 |
|
msec = sec; |
| 2523 |
|
addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend); |
| 2524 |
|
addend -= relocation; |
| 2525 |
|
addend += msec->output_section->vma + msec->output_offset; |
| 2526 |
|
addend &= 0xffffffff; |
| 2527 |
|
value = (value & ~howto->src_mask) |
| 2528 |
|
| ((addend & 0x3ff) << 5) |
| 2529 |
|
| (((addend >> 10) & 0x7fff) << 16) |
| 2530 |
|
| (((addend >> 25) & 0x7f) << 32); |
| 2531 |
|
score_bfd_put_48 (input_bfd, value, contents + rel->r_offset); |
| 2532 |
|
break; |
| 2533 |
|
} |
| 2534 |
|
|
| 2535 |
|
case R_SCORE_IMM30: |
| 2536 |
|
{ |
| 2537 |
|
int not_word_align_p = 0; |
| 2538 |
|
value = score_bfd_get_48 (input_bfd, contents + rel->r_offset); |
| 2539 |
|
addend = ((value >> 7) & 0xff) |
| 2540 |
|
| (((value >> 16) & 0x7fff) << 8) |
| 2541 |
|
| (((value >> 32) & 0x7f) << 23); |
| 2542 |
|
addend <<= howto->rightshift; |
| 2543 |
|
msec = sec; |
| 2544 |
|
addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend); |
| 2545 |
|
addend -= relocation; |
| 2546 |
|
addend += msec->output_section->vma + msec->output_offset; |
| 2547 |
|
addend &= 0xffffffff; |
| 2548 |
|
|
| 2549 |
|
/* Check lw48/sw48 rd, value/label word align. */ |
| 2550 |
|
if ((addend & 0x3) != 0) |
| 2551 |
|
not_word_align_p = 1; |
| 2552 |
|
|
| 2553 |
|
addend >>= howto->rightshift; |
| 2554 |
|
value = (value & ~howto->src_mask) |
| 2555 |
|
| (((addend & 0xff) >> 0) << 7) |
| 2556 |
|
| (((addend & 0x7fff00) >> 8) << 16) |
| 2557 |
|
| (((addend & 0x3f800000) >> 23) << 32); |
| 2558 |
|
score_bfd_put_48 (input_bfd, value, contents + rel->r_offset); |
| 2559 |
|
|
| 2560 |
|
if (not_word_align_p) |
| 2561 |
|
return bfd_reloc_other; |
| 2562 |
|
else |
| 2563 |
|
break; |
| 2564 |
|
} |
| 2565 |
|
|
| 2566 |
case R_SCORE_GOT_LO16: |
case R_SCORE_GOT_LO16: |
| 2567 |
value = bfd_get_32 (input_bfd, contents + rel->r_offset); |
value = score_bfd_get_32 (input_bfd, contents + rel->r_offset); |
| 2568 |
addend = (((value >> 16) & 0x3) << 14) | ((value & 0x7fff) >> 1); |
addend = (((value >> 16) & 0x3) << 14) | ((value & 0x7fff) >> 1); |
| 2569 |
msec = sec; |
msec = sec; |
| 2570 |
addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; |
addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; |
| 2572 |
value = (value & (~(howto->dst_mask))) | ((addend & 0x3fff) << 1) |
value = (value & (~(howto->dst_mask))) | ((addend & 0x3fff) << 1) |
| 2573 |
| (((addend >> 14) & 0x3) << 16); |
| (((addend >> 14) & 0x3) << 16); |
| 2574 |
|
|
| 2575 |
bfd_put_32 (input_bfd, value, contents + rel->r_offset); |
score_bfd_put_32 (input_bfd, value, contents + rel->r_offset); |
| 2576 |
break; |
break; |
| 2577 |
default: |
|
| 2578 |
|
case R_SCORE_ABS32: |
| 2579 |
|
case R_SCORE_REL32: |
| 2580 |
value = bfd_get_32 (input_bfd, contents + rel->r_offset); |
value = bfd_get_32 (input_bfd, contents + rel->r_offset); |
| 2581 |
/* Get the (signed) value from the instruction. */ |
/* Get the (signed) value from the instruction. */ |
| 2582 |
addend = value & howto->src_mask; |
addend = value & howto->src_mask; |
| 2594 |
value = (value & ~howto->dst_mask) | (addend & howto->dst_mask); |
value = (value & ~howto->dst_mask) | (addend & howto->dst_mask); |
| 2595 |
bfd_put_32 (input_bfd, value, contents + rel->r_offset); |
bfd_put_32 (input_bfd, value, contents + rel->r_offset); |
| 2596 |
break; |
break; |
| 2597 |
|
|
| 2598 |
|
default: |
| 2599 |
|
value = score_bfd_get_32 (input_bfd, contents + rel->r_offset); |
| 2600 |
|
/* Get the (signed) value from the instruction. */ |
| 2601 |
|
addend = value & howto->src_mask; |
| 2602 |
|
if (addend & ((howto->src_mask + 1) >> 1)) |
| 2603 |
|
{ |
| 2604 |
|
bfd_signed_vma mask; |
| 2605 |
|
|
| 2606 |
|
mask = -1; |
| 2607 |
|
mask &= ~howto->src_mask; |
| 2608 |
|
addend |= mask; |
| 2609 |
|
} |
| 2610 |
|
msec = sec; |
| 2611 |
|
addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; |
| 2612 |
|
addend += msec->output_section->vma + msec->output_offset; |
| 2613 |
|
value = (value & ~howto->dst_mask) | (addend & howto->dst_mask); |
| 2614 |
|
score_bfd_put_32 (input_bfd, value, contents + rel->r_offset); |
| 2615 |
|
break; |
| 2616 |
} |
} |
| 2617 |
} |
} |
| 2618 |
} |
} |
| 2619 |
else |
else |
| 2620 |
{ |
{ |
| 2621 |
/* For global symbols we look up the symbol in the hash-table. */ |
/* For global symbols we look up the symbol in the hash-table. */ |
| 2622 |
h = ((struct score_elf_link_hash_entry *) |
h = ((struct score_elf_link_hash_entry *) |
| 2623 |
elf_sym_hashes (input_bfd) [r_symndx - extsymoff]); |
elf_sym_hashes (input_bfd) [r_symndx - extsymoff]); |
| 2624 |
/* Find the real hash-table entry for this symbol. */ |
/* Find the real hash-table entry for this symbol. */ |
| 2625 |
while (h->root.root.type == bfd_link_hash_indirect |
while (h->root.root.type == bfd_link_hash_indirect |
| 2626 |
|| h->root.root.type == bfd_link_hash_warning) |
|| h->root.root.type == bfd_link_hash_warning) |
| 2627 |
h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; |
h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; |
| 2628 |
|
|
| 2629 |
/* Record the name of this symbol, for our caller. */ |
/* Record the name of this symbol, for our caller. */ |
| 2630 |
name = h->root.root.root.string; |
name = h->root.root.root.string; |
| 2631 |
|
|
| 2632 |
/* See if this is the special GP_DISP_LABEL symbol. Note that such a |
/* See if this is the special GP_DISP_LABEL symbol. Note that such a |
| 2633 |
symbol must always be a global symbol. */ |
symbol must always be a global symbol. */ |
| 2634 |
if (strcmp (name, GP_DISP_LABEL) == 0) |
if (strcmp (name, GP_DISP_LABEL) == 0) |
| 2635 |
{ |
{ |
| 2636 |
/* Relocations against GP_DISP_LABEL are permitted only with |
/* Relocations against GP_DISP_LABEL are permitted only with |
| 2637 |
R_SCORE_HI16 and R_SCORE_LO16 relocations. */ |
R_SCORE_HI16 and R_SCORE_LO16 relocations. */ |
| 2638 |
if (r_type != R_SCORE_HI16 && r_type != R_SCORE_LO16) |
if (r_type != R_SCORE_HI16 && r_type != R_SCORE_LO16) |
| 2639 |
return bfd_reloc_notsupported; |
return bfd_reloc_notsupported; |
| 2640 |
|
|
| 2641 |
gp_disp_p = TRUE; |
gp_disp_p = TRUE; |
| 2642 |
} |
} |
| 2643 |
|
|
| 2644 |
/* If this symbol is defined, calculate its address. Note that |
/* If this symbol is defined, calculate its address. Note that |
| 2645 |
GP_DISP_LABEL is a magic symbol, always implicitly defined by the |
GP_DISP_LABEL is a magic symbol, always implicitly defined by the |
| 2646 |
linker, so it's inappropriate to check to see whether or not |
linker, so it's inappropriate to check to see whether or not |
| 2647 |
its defined. */ |
its defined. */ |
| 2648 |
else if ((h->root.root.type == bfd_link_hash_defined |
else if ((h->root.root.type == bfd_link_hash_defined |
| 2649 |
|| h->root.root.type == bfd_link_hash_defweak) |
|| h->root.root.type == bfd_link_hash_defweak) |
| 2650 |
&& h->root.root.u.def.section) |
&& h->root.root.u.def.section) |
| 2651 |
{ |
{ |
| 2652 |
sec = h->root.root.u.def.section; |
sec = h->root.root.u.def.section; |
| 2653 |
if (sec->output_section) |
if (sec->output_section) |
| 2654 |
relocation = (h->root.root.u.def.value |
relocation = (h->root.root.u.def.value |
| 2655 |
+ sec->output_section->vma |
+ sec->output_section->vma |
| 2656 |
+ sec->output_offset); |
+ sec->output_offset); |
| 2657 |
else |
else |
| 2658 |
{ |
{ |
| 2659 |
relocation = h->root.root.u.def.value; |
relocation = h->root.root.u.def.value; |
| 2660 |
} |
} |
| 2661 |
} |
} |
| 2662 |
else if (h->root.root.type == bfd_link_hash_undefweak) |
else if (h->root.root.type == bfd_link_hash_undefweak) |
| 2663 |
/* We allow relocations against undefined weak symbols, giving |
/* We allow relocations against undefined weak symbols, giving |
| 2664 |
it the value zero, so that you can undefined weak functions |
it the value zero, so that you can undefined weak functions |
| 2665 |
and check to see if they exist by looking at their addresses. */ |
and check to see if they exist by looking at their addresses. */ |
| 2666 |
relocation = 0; |
relocation = 0; |
| 2667 |
else if (info->unresolved_syms_in_objects == RM_IGNORE |
else if (info->unresolved_syms_in_objects == RM_IGNORE |
| 2668 |
&& ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT) |
&& ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT) |
| 2669 |
relocation = 0; |
relocation = 0; |
| 2670 |
else if (strcmp (name, "_DYNAMIC_LINK") == 0) |
else if (strcmp (name, "_DYNAMIC_LINK") == 0) |
| 2671 |
{ |
{ |
| 2672 |
/* If this is a dynamic link, we should have created a _DYNAMIC_LINK symbol |
/* If this is a dynamic link, we should have created a _DYNAMIC_LINK symbol |
| 2673 |
in _bfd_score_elf_create_dynamic_sections. Otherwise, we should define |
in s3_bfd_score_elf_create_dynamic_sections. Otherwise, we should define |
| 2674 |
the symbol with a value of 0. */ |
the symbol with a value of 0. */ |
| 2675 |
BFD_ASSERT (! info->shared); |
BFD_ASSERT (! info->shared); |
| 2676 |
BFD_ASSERT (bfd_get_section_by_name (output_bfd, ".dynamic") == NULL); |
BFD_ASSERT (bfd_get_section_by_name (output_bfd, ".dynamic") == NULL); |
| 2677 |
relocation = 0; |
relocation = 0; |
| 2678 |
} |
} |
| 2679 |
else if (!info->relocatable) |
else if (!info->relocatable) |
| 2680 |
{ |
{ |
| 2681 |
if (! ((*info->callbacks->undefined_symbol) |
if (! ((*info->callbacks->undefined_symbol) |
| 2682 |
(info, h->root.root.root.string, input_bfd, |
(info, h->root.root.root.string, input_bfd, |
| 2683 |
input_section, rel->r_offset, |
input_section, rel->r_offset, |
| 2684 |
(info->unresolved_syms_in_objects == RM_GENERATE_ERROR) |
(info->unresolved_syms_in_objects == RM_GENERATE_ERROR) |
| 2685 |
|| ELF_ST_VISIBILITY (h->root.other)))) |
|| ELF_ST_VISIBILITY (h->root.other)))) |
| 2686 |
return bfd_reloc_undefined; |
return bfd_reloc_undefined; |
| 2687 |
relocation = 0; |
relocation = 0; |
| 2688 |
} |
} |
| 2689 |
} |
} |
| 2690 |
|
|
| 2691 |
if (sec != NULL && elf_discarded_section (sec)) |
if (sec != NULL && elf_discarded_section (sec)) |
| 2692 |
{ |
{ |
| 2693 |
/* For relocs against symbols from removed linkonce sections, |
/* For relocs against symbols from removed linkonce sections, |
| 2694 |
or sections discarded by a linker script, we just want the |
or sections discarded by a linker script, we just want the |
| 2695 |
section contents zeroed. Avoid any special processing. */ |
section contents zeroed. Avoid any special processing. */ |
| 2696 |
_bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); |
_bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); |
| 2697 |
rel->r_info = 0; |
rel->r_info = 0; |
| 2698 |
rel->r_addend = 0; |
rel->r_addend = 0; |
| 2699 |
continue; |
continue; |
| 2700 |
} |
} |
| 2701 |
|
|
| 2702 |
if (info->relocatable) |
if (info->relocatable) |
| 2703 |
{ |
{ |
| 2705 |
anything, unless the reloc is against a section symbol, |
anything, unless the reloc is against a section symbol, |
| 2706 |
in which case we have to adjust according to where the |
in which case we have to adjust according to where the |
| 2707 |
section symbol winds up in the output section. */ |
section symbol winds up in the output section. */ |
| 2708 |
if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) |
if (r_symndx < symtab_hdr->sh_info) |
| 2709 |
score_elf_add_to_rel (input_bfd, contents + rel->r_offset, |
{ |
| 2710 |
howto, (bfd_signed_vma) sec->output_offset); |
sym = local_syms + r_symndx; |
| 2711 |
|
if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) |
| 2712 |
|
{ |
| 2713 |
|
sec = local_sections[r_symndx]; |
| 2714 |
|
score_elf_add_to_rel (input_bfd, contents + rel->r_offset, |
| 2715 |
|
howto, (bfd_signed_vma) (sec->output_offset + sym->st_value)); |
| 2716 |
|
} |
| 2717 |
|
} |
| 2718 |
continue; |
continue; |
| 2719 |
} |
} |
| 2720 |
|
|
| 2721 |
|
/* This is a final link. */ |
| 2722 |
r = score_elf_final_link_relocate (howto, input_bfd, output_bfd, |
r = score_elf_final_link_relocate (howto, input_bfd, output_bfd, |
| 2723 |
input_section, contents, rel, relocs, |
input_section, contents, rel, relocs, |
| 2724 |
relocation, info, name, |
relocation, info, name, |
| 2725 |
(h ? ELF_ST_TYPE ((unsigned int)h->root.root.type) : |
(h ? ELF_ST_TYPE ((unsigned int)h->root.root.type) : |
| 2726 |
ELF_ST_TYPE ((unsigned int)sym->st_info)), h, |
ELF_ST_TYPE ((unsigned int)sym->st_info)), h, local_sections, |
| 2727 |
gp_disp_p); |
gp_disp_p); |
| 2728 |
|
|
| 2729 |
if (r != bfd_reloc_ok) |
if (r != bfd_reloc_ok) |
| 2760 |
msg = _("internal error: dangerous error"); |
msg = _("internal error: dangerous error"); |
| 2761 |
goto common_error; |
goto common_error; |
| 2762 |
|
|
| 2763 |
|
/* Use bfd_reloc_other to check lw48, sw48 word align. */ |
| 2764 |
|
case bfd_reloc_other: |
| 2765 |
|
msg = _("address not word align"); |
| 2766 |
|
goto common_error; |
| 2767 |
|
|
| 2768 |
default: |
default: |
| 2769 |
msg = _("internal error: unknown error"); |
msg = _("internal error: unknown error"); |
| 2770 |
/* fall through */ |
/* fall through */ |
| 2783 |
|
|
| 2784 |
/* Look through the relocs for a section during the first phase, and |
/* Look through the relocs for a section during the first phase, and |
| 2785 |
allocate space in the global offset table. */ |
allocate space in the global offset table. */ |
|
|
|
| 2786 |
static bfd_boolean |
static bfd_boolean |
| 2787 |
_bfd_score_elf_check_relocs (bfd *abfd, |
s3_bfd_score_elf_check_relocs (bfd *abfd, |
| 2788 |
struct bfd_link_info *info, |
struct bfd_link_info *info, |
| 2789 |
asection *sec, |
asection *sec, |
| 2790 |
const Elf_Internal_Rela *relocs) |
const Elf_Internal_Rela *relocs) |
| 2791 |
{ |
{ |
| 2792 |
const char *name; |
const char *name; |
| 2793 |
bfd *dynobj; |
bfd *dynobj; |
| 2807 |
dynobj = elf_hash_table (info)->dynobj; |
dynobj = elf_hash_table (info)->dynobj; |
| 2808 |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
| 2809 |
sym_hashes = elf_sym_hashes (abfd); |
sym_hashes = elf_sym_hashes (abfd); |
| 2810 |
extsymoff = symtab_hdr->sh_info; |
extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info; |
| 2811 |
|
|
| 2812 |
name = bfd_get_section_name (abfd, sec); |
name = bfd_get_section_name (abfd, sec); |
| 2813 |
|
|
| 2842 |
r_type = ELF32_R_TYPE (rel->r_info); |
r_type = ELF32_R_TYPE (rel->r_info); |
| 2843 |
|
|
| 2844 |
if (r_symndx < extsymoff) |
if (r_symndx < extsymoff) |
| 2845 |
{ |
{ |
| 2846 |
h = NULL; |
h = NULL; |
| 2847 |
} |
} |
| 2848 |
else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr)) |
else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr)) |
| 2849 |
{ |
{ |
| 2850 |
(*_bfd_error_handler) (_("%s: Malformed reloc detected for section %s"), abfd, name); |
(*_bfd_error_handler) (_("%s: Malformed reloc detected for section %s"), abfd, name); |
| 2888 |
|
|
| 2889 |
if (!h && (r_type == R_SCORE_GOT_LO16)) |
if (!h && (r_type == R_SCORE_GOT_LO16)) |
| 2890 |
{ |
{ |
| 2891 |
if (! score_elf_record_local_got_symbol (abfd, r_symndx, rel->r_addend, g)) |
if (! score_elf_record_local_got_symbol (abfd, r_symndx, rel->r_addend, g)) |
| 2892 |
return FALSE; |
return FALSE; |
| 2893 |
} |
} |
| 2894 |
|
|
| 2895 |
switch (r_type) |
switch (r_type) |
| 2896 |
{ |
{ |
| 2897 |
case R_SCORE_CALL15: |
case R_SCORE_CALL15: |
| 2898 |
if (h == NULL) |
if (h == NULL) |
| 2899 |
{ |
{ |
| 2900 |
(*_bfd_error_handler) |
(*_bfd_error_handler) |
| 2901 |
(_("%B: CALL15 reloc at 0x%lx not against global symbol"), |
(_("%B: CALL15 reloc at 0x%lx not against global symbol"), |
| 2902 |
abfd, (unsigned long) rel->r_offset); |
abfd, (unsigned long) rel->r_offset); |
| 2903 |
bfd_set_error (bfd_error_bad_value); |
bfd_set_error (bfd_error_bad_value); |
| 2904 |
return FALSE; |
return FALSE; |
| 2905 |
} |
} |
| 2906 |
else |
else |
| 2907 |
{ |
{ |
| 2908 |
/* This symbol requires a global offset table entry. */ |
/* This symbol requires a global offset table entry. */ |
| 2909 |
if (! score_elf_record_global_got_symbol (h, abfd, info, g)) |
if (! score_elf_record_global_got_symbol (h, abfd, info, g)) |
| 2910 |
return FALSE; |
return FALSE; |
| 2911 |
|
|
| 2912 |
/* We need a stub, not a plt entry for the undefined function. But we record |
/* We need a stub, not a plt entry for the undefined function. But we record |
| 2913 |
it as if it needs plt. See _bfd_elf_adjust_dynamic_symbol. */ |
it as if it needs plt. See _bfd_elf_adjust_dynamic_symbol. */ |
| 2914 |
h->needs_plt = 1; |
h->needs_plt = 1; |
| 2915 |
h->type = STT_FUNC; |
h->type = STT_FUNC; |
| 2916 |
} |
} |
| 2917 |
|
break; |
| 2918 |
|
case R_SCORE_GOT15: |
| 2919 |
|
if (h && ! score_elf_record_global_got_symbol (h, abfd, info, g)) |
| 2920 |
|
return FALSE; |
| 2921 |
break; |
break; |
|
case R_SCORE_GOT15: |
|
|
if (h && ! score_elf_record_global_got_symbol (h, abfd, info, g)) |
|
|
return FALSE; |
|
|
break; |
|
| 2922 |
case R_SCORE_ABS32: |
case R_SCORE_ABS32: |
| 2923 |
case R_SCORE_REL32: |
case R_SCORE_REL32: |
| 2924 |
if ((info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0) |
if ((info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0) |
| 2925 |
{ |
{ |
| 2926 |
if (sreloc == NULL) |
if (sreloc == NULL) |
| 2927 |
{ |
{ |
| 2928 |
sreloc = score_elf_rel_dyn_section (dynobj, TRUE); |
sreloc = score_elf_rel_dyn_section (dynobj, TRUE); |
| 2929 |
if (sreloc == NULL) |
if (sreloc == NULL) |
| 2930 |
return FALSE; |
return FALSE; |
| 2931 |
} |
} |
| 2932 |
#define SCORE_READONLY_SECTION (SEC_ALLOC | SEC_LOAD | SEC_READONLY) |
#define SCORE_READONLY_SECTION (SEC_ALLOC | SEC_LOAD | SEC_READONLY) |
| 2933 |
if (info->shared) |
if (info->shared) |
| 2934 |
{ |
{ |
| 2935 |
/* When creating a shared object, we must copy these reloc types into |
/* When creating a shared object, we must copy these reloc types into |
| 2936 |
the output file as R_SCORE_REL32 relocs. We make room for this reloc |
the output file as R_SCORE_REL32 relocs. We make room for this reloc |
| 2937 |
in the .rel.dyn reloc section. */ |
in the .rel.dyn reloc section. */ |
| 2938 |
score_elf_allocate_dynamic_relocations (dynobj, 1); |
score_elf_allocate_dynamic_relocations (dynobj, 1); |
| 2939 |
if ((sec->flags & SCORE_READONLY_SECTION) |
if ((sec->flags & SCORE_READONLY_SECTION) |
| 2940 |
== SCORE_READONLY_SECTION) |
== SCORE_READONLY_SECTION) |
| 2941 |
/* We tell the dynamic linker that there are |
/* We tell the dynamic linker that there are |
| 2942 |
relocations against the text segment. */ |
relocations against the text segment. */ |
| 2943 |
info->flags |= DF_TEXTREL; |
info->flags |= DF_TEXTREL; |
| 2944 |
} |
} |
| 2945 |
else |
else |
| 2946 |
{ |
{ |
| 2947 |
struct score_elf_link_hash_entry *hscore; |
struct score_elf_link_hash_entry *hscore; |
| 2948 |
|
|
| 2949 |
/* We only need to copy this reloc if the symbol is |
/* We only need to copy this reloc if the symbol is |
| 2950 |
defined in a dynamic object. */ |
defined in a dynamic object. */ |
| 2951 |
hscore = (struct score_elf_link_hash_entry *)h; |
hscore = (struct score_elf_link_hash_entry *)h; |
| 2952 |
++hscore->possibly_dynamic_relocs; |
++hscore->possibly_dynamic_relocs; |
| 2953 |
if ((sec->flags & SCORE_READONLY_SECTION) |
if ((sec->flags & SCORE_READONLY_SECTION) |
| 2954 |
== SCORE_READONLY_SECTION) |
== SCORE_READONLY_SECTION) |
| 2955 |
/* We need it to tell the dynamic linker if there |
/* We need it to tell the dynamic linker if there |
| 2956 |
are relocations against the text segment. */ |
are relocations against the text segment. */ |
| 2957 |
hscore->readonly_reloc = TRUE; |
hscore->readonly_reloc = TRUE; |
| 2958 |
} |
} |
| 2959 |
|
|
| 2960 |
/* Even though we don't directly need a GOT entry for this symbol, |
/* Even though we don't directly need a GOT entry for this symbol, |
| 2961 |
a symbol must have a dynamic symbol table index greater that |
a symbol must have a dynamic symbol table index greater that |
| 2962 |
DT_SCORE_GOTSYM if there are dynamic relocations against it. */ |
DT_SCORE_GOTSYM if there are dynamic relocations against it. */ |
| 2963 |
if (h != NULL) |
if (h != NULL) |
| 2964 |
{ |
{ |
| 2965 |
if (dynobj == NULL) |
if (dynobj == NULL) |
| 2966 |
elf_hash_table (info)->dynobj = dynobj = abfd; |
elf_hash_table (info)->dynobj = dynobj = abfd; |
| 2967 |
if (! score_elf_create_got_section (dynobj, info, TRUE)) |
if (! score_elf_create_got_section (dynobj, info, TRUE)) |
| 2968 |
return FALSE; |
return FALSE; |
| 2969 |
g = score_elf_got_info (dynobj, &sgot); |
g = score_elf_got_info (dynobj, &sgot); |
| 2970 |
if (! score_elf_record_global_got_symbol (h, abfd, info, g)) |
if (! score_elf_record_global_got_symbol (h, abfd, info, g)) |
| 2971 |
return FALSE; |
return FALSE; |
| 2972 |
} |
} |
| 2973 |
} |
} |
| 2974 |
break; |
break; |
| 2975 |
|
|
| 2976 |
/* This relocation describes the C++ object vtable hierarchy. |
/* This relocation describes the C++ object vtable hierarchy. |
| 2977 |
Reconstruct it for later use during GC. */ |
Reconstruct it for later use during GC. */ |
| 2983 |
/* This relocation describes which C++ vtable entries are actually |
/* This relocation describes which C++ vtable entries are actually |
| 2984 |
used. Record for later use during GC. */ |
used. Record for later use during GC. */ |
| 2985 |
case R_SCORE_GNU_VTENTRY: |
case R_SCORE_GNU_VTENTRY: |
| 2986 |
BFD_ASSERT (h != NULL); |
if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) |
|
if (h != NULL |
|
|
&& !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) |
|
| 2987 |
return FALSE; |
return FALSE; |
| 2988 |
break; |
break; |
| 2989 |
default: |
default: |
| 2993 |
/* We must not create a stub for a symbol that has relocations |
/* We must not create a stub for a symbol that has relocations |
| 2994 |
related to taking the function's address. */ |
related to taking the function's address. */ |
| 2995 |
switch (r_type) |
switch (r_type) |
| 2996 |
{ |
{ |
| 2997 |
default: |
default: |
| 2998 |
if (h != NULL) |
if (h != NULL) |
| 2999 |
{ |
{ |
| 3000 |
struct score_elf_link_hash_entry *sh; |
struct score_elf_link_hash_entry *sh; |
| 3001 |
|
|
| 3002 |
sh = (struct score_elf_link_hash_entry *) h; |
sh = (struct score_elf_link_hash_entry *) h; |
| 3003 |
sh->no_fn_stub = TRUE; |
sh->no_fn_stub = TRUE; |
| 3004 |
} |
} |
| 3005 |
break; |
break; |
| 3006 |
case R_SCORE_CALL15: |
case R_SCORE_CALL15: |
| 3007 |
break; |
break; |
| 3008 |
} |
} |
| 3009 |
} |
} |
| 3010 |
|
|
| 3011 |
return TRUE; |
return TRUE; |
| 3012 |
} |
} |
| 3013 |
|
|
| 3014 |
static bfd_boolean |
static bfd_boolean |
| 3015 |
_bfd_score_elf_add_symbol_hook (bfd *abfd, |
s3_bfd_score_elf_add_symbol_hook (bfd *abfd, |
| 3016 |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
| 3017 |
Elf_Internal_Sym *sym, |
Elf_Internal_Sym *sym, |
| 3018 |
const char **namep ATTRIBUTE_UNUSED, |
const char **namep ATTRIBUTE_UNUSED, |
| 3019 |
flagword *flagsp ATTRIBUTE_UNUSED, |
flagword *flagsp ATTRIBUTE_UNUSED, |
| 3020 |
asection **secp, |
asection **secp, |
| 3021 |
bfd_vma *valp) |
bfd_vma *valp) |
| 3022 |
{ |
{ |
| 3023 |
switch (sym->st_shndx) |
switch (sym->st_shndx) |
| 3024 |
{ |
{ |
| 3037 |
} |
} |
| 3038 |
|
|
| 3039 |
static void |
static void |
| 3040 |
_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym) |
s3_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym) |
| 3041 |
{ |
{ |
| 3042 |
elf_symbol_type *elfsym; |
elf_symbol_type *elfsym; |
| 3043 |
|
|
| 3068 |
} |
} |
| 3069 |
} |
} |
| 3070 |
|
|
| 3071 |
static bfd_boolean |
static int |
| 3072 |
_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
s3_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
| 3073 |
const char *name ATTRIBUTE_UNUSED, |
const char *name ATTRIBUTE_UNUSED, |
| 3074 |
Elf_Internal_Sym *sym, |
Elf_Internal_Sym *sym, |
| 3075 |
asection *input_sec, |
asection *input_sec, |
| 3076 |
struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) |
struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) |
| 3077 |
{ |
{ |
| 3078 |
/* If we see a common symbol, which implies a relocatable link, then |
/* If we see a common symbol, which implies a relocatable link, then |
| 3079 |
if a symbol was small common in an input file, mark it as small |
if a symbol was small common in an input file, mark it as small |
| 3081 |
if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0) |
if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0) |
| 3082 |
sym->st_shndx = SHN_SCORE_SCOMMON; |
sym->st_shndx = SHN_SCORE_SCOMMON; |
| 3083 |
|
|
| 3084 |
return TRUE; |
return 1; |
| 3085 |
} |
} |
| 3086 |
|
|
| 3087 |
static bfd_boolean |
static bfd_boolean |
| 3088 |
_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, |
s3_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, |
| 3089 |
asection *sec, |
asection *sec, |
| 3090 |
int *retval) |
int *retval) |
| 3091 |
{ |
{ |
| 3092 |
if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) |
if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) |
| 3093 |
{ |
{ |
| 3102 |
regular object. The current definition is in some section of the |
regular object. The current definition is in some section of the |
| 3103 |
dynamic object, but we're not including those sections. We have to |
dynamic object, but we're not including those sections. We have to |
| 3104 |
change the definition to something the rest of the link can understand. */ |
change the definition to something the rest of the link can understand. */ |
|
|
|
| 3105 |
static bfd_boolean |
static bfd_boolean |
| 3106 |
_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info, |
s3_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info, |
| 3107 |
struct elf_link_hash_entry *h) |
struct elf_link_hash_entry *h) |
| 3108 |
{ |
{ |
| 3109 |
bfd *dynobj; |
bfd *dynobj; |
| 3110 |
struct score_elf_link_hash_entry *hscore; |
struct score_elf_link_hash_entry *hscore; |
| 3190 |
|
|
| 3191 |
/* This function is called after all the input files have been read, |
/* This function is called after all the input files have been read, |
| 3192 |
and the input sections have been assigned to output sections. */ |
and the input sections have been assigned to output sections. */ |
|
|
|
| 3193 |
static bfd_boolean |
static bfd_boolean |
| 3194 |
_bfd_score_elf_always_size_sections (bfd *output_bfd, |
s3_bfd_score_elf_always_size_sections (bfd *output_bfd, |
| 3195 |
struct bfd_link_info *info) |
struct bfd_link_info *info) |
| 3196 |
{ |
{ |
| 3197 |
bfd *dynobj; |
bfd *dynobj; |
| 3198 |
asection *s; |
asection *s; |
| 3218 |
asection *subsection; |
asection *subsection; |
| 3219 |
|
|
| 3220 |
for (subsection = sub->sections; |
for (subsection = sub->sections; |
| 3221 |
subsection; |
subsection; |
| 3222 |
subsection = subsection->next) |
subsection = subsection->next) |
| 3223 |
{ |
{ |
| 3224 |
if ((subsection->flags & SEC_ALLOC) == 0) |
if ((subsection->flags & SEC_ALLOC) == 0) |
| 3225 |
continue; |
continue; |
| 3226 |
loadable_size += ((subsection->size + 0xf) |
loadable_size += ((subsection->size + 0xf) |
| 3227 |
&~ (bfd_size_type) 0xf); |
&~ (bfd_size_type) 0xf); |
| 3228 |
} |
} |
| 3229 |
} |
} |
| 3230 |
|
|
| 3231 |
/* There has to be a global GOT entry for every symbol with |
/* There has to be a global GOT entry for every symbol with |
| 3267 |
} |
} |
| 3268 |
|
|
| 3269 |
/* Set the sizes of the dynamic sections. */ |
/* Set the sizes of the dynamic sections. */ |
|
|
|
| 3270 |
static bfd_boolean |
static bfd_boolean |
| 3271 |
_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) |
s3_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) |
| 3272 |
{ |
{ |
| 3273 |
bfd *dynobj; |
bfd *dynobj; |
| 3274 |
asection *s; |
asection *s; |
| 3345 |
} |
} |
| 3346 |
else if (CONST_STRNEQ (name, ".got")) |
else if (CONST_STRNEQ (name, ".got")) |
| 3347 |
{ |
{ |
| 3348 |
/* _bfd_score_elf_always_size_sections() has already done |
/* s3_bfd_score_elf_always_size_sections() has already done |
| 3349 |
most of the work, but some symbols may have been mapped |
most of the work, but some symbols may have been mapped |
| 3350 |
to versions that we must now resolve in the got_entries |
to versions that we must now resolve in the got_entries |
| 3351 |
hash tables. */ |
hash tables. */ |
| 3352 |
} |
} |
| 3353 |
else if (strcmp (name, SCORE_ELF_STUB_SECTION_NAME) == 0) |
else if (strcmp (name, SCORE_ELF_STUB_SECTION_NAME) == 0) |
| 3354 |
{ |
{ |
| 3374 |
if (elf_hash_table (info)->dynamic_sections_created) |
if (elf_hash_table (info)->dynamic_sections_created) |
| 3375 |
{ |
{ |
| 3376 |
/* Add some entries to the .dynamic section. We fill in the |
/* Add some entries to the .dynamic section. We fill in the |
| 3377 |
values later, in _bfd_score_elf_finish_dynamic_sections, but we |
values later, in s3_bfd_score_elf_finish_dynamic_sections, but we |
| 3378 |
must add the entries now so that we get the correct size for |
must add the entries now so that we get the correct size for |
| 3379 |
the .dynamic section. The DT_DEBUG entry is filled in by the |
the .dynamic section. The DT_DEBUG entry is filled in by the |
| 3380 |
dynamic linker and used by the debugger. */ |
dynamic linker and used by the debugger. */ |
| 3381 |
|
|
| 3382 |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0)) |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0)) |
| 3383 |
return FALSE; |
return FALSE; |
| 3384 |
|
|
| 3385 |
if (reltext) |
if (reltext) |
| 3386 |
info->flags |= DF_TEXTREL; |
info->flags |= DF_TEXTREL; |
| 3387 |
|
|
| 3388 |
if ((info->flags & DF_TEXTREL) != 0) |
if ((info->flags & DF_TEXTREL) != 0) |
| 3389 |
{ |
{ |
| 3390 |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0)) |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0)) |
| 3391 |
return FALSE; |
return FALSE; |
| 3392 |
} |
} |
| 3393 |
|
|
| 3394 |
if (! SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0)) |
if (! SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0)) |
| 3395 |
return FALSE; |
return FALSE; |
| 3396 |
|
|
| 3397 |
if (score_elf_rel_dyn_section (dynobj, FALSE)) |
if (score_elf_rel_dyn_section (dynobj, FALSE)) |
| 3398 |
{ |
{ |
| 3399 |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0)) |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0)) |
| 3400 |
return FALSE; |
return FALSE; |
| 3401 |
|
|
| 3402 |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0)) |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0)) |
| 3403 |
return FALSE; |
return FALSE; |
| 3404 |
|
|
| 3405 |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0)) |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0)) |
| 3406 |
return FALSE; |
return FALSE; |
| 3407 |
} |
} |
| 3408 |
|
|
| 3409 |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_BASE_ADDRESS, 0)) |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_BASE_ADDRESS, 0)) |
| 3410 |
return FALSE; |
return FALSE; |
| 3422 |
return FALSE; |
return FALSE; |
| 3423 |
|
|
| 3424 |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_HIPAGENO, 0)) |
if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_HIPAGENO, 0)) |
| 3425 |
return FALSE; |
return FALSE; |
| 3426 |
} |
} |
| 3427 |
|
|
| 3428 |
return TRUE; |
return TRUE; |
| 3429 |
} |
} |
| 3430 |
|
|
| 3431 |
static bfd_boolean |
static bfd_boolean |
| 3432 |
_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) |
s3_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) |
| 3433 |
{ |
{ |
| 3434 |
struct elf_link_hash_entry *h; |
struct elf_link_hash_entry *h; |
| 3435 |
struct bfd_link_hash_entry *bh; |
struct bfd_link_hash_entry *bh; |
| 3473 |
bh = NULL; |
bh = NULL; |
| 3474 |
if (!(_bfd_generic_link_add_one_symbol |
if (!(_bfd_generic_link_add_one_symbol |
| 3475 |
(info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, |
(info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, |
| 3476 |
(bfd_vma) 0, (const char *)NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) |
(bfd_vma) 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) |
| 3477 |
return FALSE; |
return FALSE; |
| 3478 |
|
|
| 3479 |
h = (struct elf_link_hash_entry *)bh; |
h = (struct elf_link_hash_entry *)bh; |
| 3491 |
|
|
| 3492 |
/* Finish up dynamic symbol handling. We set the contents of various |
/* Finish up dynamic symbol handling. We set the contents of various |
| 3493 |
dynamic sections here. */ |
dynamic sections here. */ |
|
|
|
| 3494 |
static bfd_boolean |
static bfd_boolean |
| 3495 |
_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd, |
s3_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd, |
| 3496 |
struct bfd_link_info *info, |
struct bfd_link_info *info, |
| 3497 |
struct elf_link_hash_entry *h, |
struct elf_link_hash_entry *h, |
| 3498 |
Elf_Internal_Sym *sym) |
Elf_Internal_Sym *sym) |
| 3499 |
{ |
{ |
| 3500 |
bfd *dynobj; |
bfd *dynobj; |
| 3501 |
asection *sgot; |
asection *sgot; |
| 3517 |
|
|
| 3518 |
/* FIXME: Can h->dynindex be more than 64K? */ |
/* FIXME: Can h->dynindex be more than 64K? */ |
| 3519 |
if (h->dynindx & 0xffff0000) |
if (h->dynindx & 0xffff0000) |
| 3520 |
return FALSE; |
return FALSE; |
| 3521 |
|
|
| 3522 |
/* Fill the stub. */ |
/* Fill the stub. */ |
| 3523 |
bfd_put_32 (output_bfd, STUB_LW, stub); |
score_bfd_put_32 (output_bfd, STUB_LW, stub); |
| 3524 |
bfd_put_32 (output_bfd, STUB_MOVE, stub + 4); |
score_bfd_put_32 (output_bfd, STUB_MOVE, stub + 4); |
| 3525 |
bfd_put_32 (output_bfd, STUB_LI16 | (h->dynindx << 1), stub + 8); |
score_bfd_put_32 (output_bfd, STUB_LI16 | (h->dynindx << 1), stub + 8); |
| 3526 |
bfd_put_32 (output_bfd, STUB_BRL, stub + 12); |
score_bfd_put_32 (output_bfd, STUB_BRL, stub + 12); |
| 3527 |
|
|
| 3528 |
BFD_ASSERT (h->plt.offset <= s->size); |
BFD_ASSERT (h->plt.offset <= s->size); |
| 3529 |
memcpy (s->contents + h->plt.offset, stub, SCORE_FUNCTION_STUB_SIZE); |
memcpy (s->contents + h->plt.offset, stub, SCORE_FUNCTION_STUB_SIZE); |
| 3530 |
|
|
| 3531 |
/* Mark the symbol as undefined. plt.offset != -1 occurs |
/* Mark the symbol as undefined. plt.offset != -1 occurs |
| 3532 |
only for the referenced symbol. */ |
only for the referenced symbol. */ |
| 3533 |
sym->st_shndx = SHN_UNDEF; |
sym->st_shndx = SHN_UNDEF; |
| 3534 |
|
|
| 3535 |
/* The run-time linker uses the st_value field of the symbol |
/* The run-time linker uses the st_value field of the symbol |
| 3536 |
to reset the global offset table entry for this external |
to reset the global offset table entry for this external |
| 3537 |
to its stub address when unlinking a shared object. */ |
to its stub address when unlinking a shared object. */ |
| 3538 |
sym->st_value = (s->output_section->vma + s->output_offset + h->plt.offset); |
sym->st_value = (s->output_section->vma + s->output_offset + h->plt.offset); |
| 3539 |
} |
} |
| 3540 |
|
|
| 3555 |
|
|
| 3556 |
value = sym->st_value; |
value = sym->st_value; |
| 3557 |
offset = score_elf_global_got_index (dynobj, h); |
offset = score_elf_global_got_index (dynobj, h); |
| 3558 |
bfd_put_32 (output_bfd, value, sgot->contents + offset); |
score_bfd_put_32 (output_bfd, value, sgot->contents + offset); |
| 3559 |
} |
} |
| 3560 |
|
|
| 3561 |
/* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ |
/* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ |
| 3579 |
} |
} |
| 3580 |
|
|
| 3581 |
/* Finish up the dynamic sections. */ |
/* Finish up the dynamic sections. */ |
|
|
|
| 3582 |
static bfd_boolean |
static bfd_boolean |
| 3583 |
_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd, |
s3_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd, |
| 3584 |
struct bfd_link_info *info) |
struct bfd_link_info *info) |
| 3585 |
{ |
{ |
| 3586 |
bfd *dynobj; |
bfd *dynobj; |
| 3587 |
asection *sdyn; |
asection *sdyn; |
| 3611 |
BFD_ASSERT (g != NULL); |
BFD_ASSERT (g != NULL); |
| 3612 |
|
|
| 3613 |
for (b = sdyn->contents; |
for (b = sdyn->contents; |
| 3614 |
b < sdyn->contents + sdyn->size; |
b < sdyn->contents + sdyn->size; |
| 3615 |
b += SCORE_ELF_DYN_SIZE (dynobj)) |
b += SCORE_ELF_DYN_SIZE (dynobj)) |
| 3616 |
{ |
{ |
| 3617 |
Elf_Internal_Dyn dyn; |
Elf_Internal_Dyn dyn; |
| 3618 |
const char *name; |
const char *name; |
| 3619 |
size_t elemsize; |
size_t elemsize; |
| 3620 |
bfd_boolean swap_out_p; |
bfd_boolean swap_out_p; |
| 3621 |
|
|
| 3622 |
/* Read in the current dynamic entry. */ |
/* Read in the current dynamic entry. */ |
| 3623 |
(*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn); |
(*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn); |
| 3624 |
|
|
| 3625 |
/* Assume that we're going to modify it and write it out. */ |
/* Assume that we're going to modify it and write it out. */ |
| 3626 |
swap_out_p = TRUE; |
swap_out_p = TRUE; |
| 3627 |
|
|
| 3628 |
switch (dyn.d_tag) |
switch (dyn.d_tag) |
| 3629 |
{ |
{ |
| 3630 |
case DT_RELENT: |
case DT_RELENT: |
| 3631 |
s = score_elf_rel_dyn_section (dynobj, FALSE); |
s = score_elf_rel_dyn_section (dynobj, FALSE); |
| 3632 |
BFD_ASSERT (s != NULL); |
BFD_ASSERT (s != NULL); |
| 3633 |
dyn.d_un.d_val = SCORE_ELF_REL_SIZE (dynobj); |
dyn.d_un.d_val = SCORE_ELF_REL_SIZE (dynobj); |
| 3634 |
break; |
break; |
| 3635 |
|
|
| 3636 |
case DT_STRSZ: |
case DT_STRSZ: |
| 3637 |
/* Rewrite DT_STRSZ. */ |
/* Rewrite DT_STRSZ. */ |
| 3638 |
dyn.d_un.d_val = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); |
dyn.d_un.d_val = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); |
| 3639 |
break; |
break; |
| 3640 |
|
|
| 3641 |
case DT_PLTGOT: |
case DT_PLTGOT: |
| 3642 |
name = ".got"; |
name = ".got"; |
| 3643 |
s = bfd_get_section_by_name (output_bfd, name); |
s = bfd_get_section_by_name (output_bfd, name); |
| 3644 |
BFD_ASSERT (s != NULL); |
BFD_ASSERT (s != NULL); |
| 3645 |
dyn.d_un.d_ptr = s->vma; |
dyn.d_un.d_ptr = s->vma; |
| 3646 |
break; |
break; |
| 3647 |
|
|
| 3648 |
case DT_SCORE_BASE_ADDRESS: |
case DT_SCORE_BASE_ADDRESS: |
| 3649 |
s = output_bfd->sections; |
s = output_bfd->sections; |
| 3650 |
BFD_ASSERT (s != NULL); |
BFD_ASSERT (s != NULL); |
| 3651 |
dyn.d_un.d_ptr = s->vma & ~(bfd_vma) 0xffff; |
dyn.d_un.d_ptr = s->vma & ~(bfd_vma) 0xffff; |
| 3652 |
break; |
break; |
| 3653 |
|
|
| 3654 |
case DT_SCORE_LOCAL_GOTNO: |
case DT_SCORE_LOCAL_GOTNO: |
| 3655 |
dyn.d_un.d_val = g->local_gotno; |
dyn.d_un.d_val = g->local_gotno; |
| 3656 |
break; |
break; |
| 3657 |
|
|
| 3658 |
case DT_SCORE_UNREFEXTNO: |
case DT_SCORE_UNREFEXTNO: |
| 3659 |
/* The index into the dynamic symbol table which is the |
/* The index into the dynamic symbol table which is the |
| 3660 |
entry of the first external symbol that is not |
entry of the first external symbol that is not |
| 3661 |
referenced within the same object. */ |
referenced within the same object. */ |
| 3662 |
dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1; |
dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1; |
| 3663 |
break; |
break; |
| 3664 |
|
|
| 3665 |
case DT_SCORE_GOTSYM: |
case DT_SCORE_GOTSYM: |
| 3666 |
if (g->global_gotsym) |
if (g->global_gotsym) |
| 3667 |
{ |
{ |
| 3668 |
dyn.d_un.d_val = g->global_gotsym->dynindx; |
dyn.d_un.d_val = g->global_gotsym->dynindx; |
| 3669 |
break; |
break; |
| 3670 |
} |
} |
| 3671 |
/* In case if we don't have global got symbols we default |
/* In case if we don't have global got symbols we default |
| 3672 |
to setting DT_SCORE_GOTSYM to the same value as |
to setting DT_SCORE_GOTSYM to the same value as |
| 3673 |
DT_SCORE_SYMTABNO, so we just fall through. */ |
DT_SCORE_SYMTABNO, so we just fall through. */ |
| 3674 |
|
|
| 3675 |
case DT_SCORE_SYMTABNO: |
case DT_SCORE_SYMTABNO: |
| 3676 |
name = ".dynsym"; |
name = ".dynsym"; |
| 3677 |
elemsize = SCORE_ELF_SYM_SIZE (output_bfd); |
elemsize = SCORE_ELF_SYM_SIZE (output_bfd); |
| 3678 |
s = bfd_get_section_by_name (output_bfd, name); |
s = bfd_get_section_by_name (output_bfd, name); |
| 3679 |
BFD_ASSERT (s != NULL); |
BFD_ASSERT (s != NULL); |
| 3680 |
|
|
| 3681 |
dyn.d_un.d_val = s->size / elemsize; |
dyn.d_un.d_val = s->size / elemsize; |
| 3682 |
break; |
break; |
| 3683 |
|
|
| 3684 |
case DT_SCORE_HIPAGENO: |
case DT_SCORE_HIPAGENO: |
| 3685 |
dyn.d_un.d_val = g->local_gotno - SCORE_RESERVED_GOTNO; |
dyn.d_un.d_val = g->local_gotno - SCORE_RESERVED_GOTNO; |
| 3686 |
break; |
break; |
| 3687 |
|
|
| 3688 |
default: |
default: |
| 3689 |
swap_out_p = FALSE; |
swap_out_p = FALSE; |
| 3690 |
break; |
break; |
| 3691 |
} |
} |
| 3692 |
|
|
| 3693 |
if (swap_out_p) |
if (swap_out_p) |
| 3694 |
(*get_elf_backend_data (dynobj)->s->swap_dyn_out) (dynobj, &dyn, b); |
(*get_elf_backend_data (dynobj)->s->swap_dyn_out) (dynobj, &dyn, b); |
| 3695 |
} |
} |
| 3696 |
} |
} |
| 3697 |
|
|
| 3698 |
/* The first entry of the global offset table will be filled at |
/* The first entry of the global offset table will be filled at |
| 3700 |
This isn't the case of IRIX rld. */ |
This isn't the case of IRIX rld. */ |
| 3701 |
if (sgot != NULL && sgot->size > 0) |
if (sgot != NULL && sgot->size > 0) |
| 3702 |
{ |
{ |
| 3703 |
bfd_put_32 (output_bfd, 0, sgot->contents); |
score_bfd_put_32 (output_bfd, 0, sgot->contents); |
| 3704 |
bfd_put_32 (output_bfd, 0x80000000, sgot->contents + SCORE_ELF_GOT_SIZE (output_bfd)); |
score_bfd_put_32 (output_bfd, 0x80000000, sgot->contents + SCORE_ELF_GOT_SIZE (output_bfd)); |
| 3705 |
} |
} |
| 3706 |
|
|
| 3707 |
if (sgot != NULL) |
if (sgot != NULL) |
| 3716 |
{ |
{ |
| 3717 |
reldyn_sorting_bfd = output_bfd; |
reldyn_sorting_bfd = output_bfd; |
| 3718 |
qsort ((Elf32_External_Rel *) s->contents + 1, s->reloc_count - 1, |
qsort ((Elf32_External_Rel *) s->contents + 1, s->reloc_count - 1, |
| 3719 |
sizeof (Elf32_External_Rel), score_elf_sort_dynamic_relocs); |
sizeof (Elf32_External_Rel), score_elf_sort_dynamic_relocs); |
| 3720 |
} |
} |
| 3721 |
|
|
| 3722 |
return TRUE; |
return TRUE; |
| 3724 |
|
|
| 3725 |
/* This function set up the ELF section header for a BFD section in preparation for writing |
/* This function set up the ELF section header for a BFD section in preparation for writing |
| 3726 |
it out. This is where the flags and type fields are set for unusual sections. */ |
it out. This is where the flags and type fields are set for unusual sections. */ |
|
|
|
| 3727 |
static bfd_boolean |
static bfd_boolean |
| 3728 |
_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, |
s3_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, |
| 3729 |
Elf_Internal_Shdr *hdr, |
Elf_Internal_Shdr *hdr, |
| 3730 |
asection *sec) |
asection *sec) |
| 3731 |
{ |
{ |
| 3732 |
const char *name; |
const char *name; |
| 3733 |
|
|
| 3749 |
warning message will be issued. backend_fake_section is called before |
warning message will be issued. backend_fake_section is called before |
| 3750 |
assign_file_positions_except_relocs(); backend_section_processing after it. so, we |
assign_file_positions_except_relocs(); backend_section_processing after it. so, we |
| 3751 |
modify section flag there, but not backend_fake_section. */ |
modify section flag there, but not backend_fake_section. */ |
|
|
|
| 3752 |
static bfd_boolean |
static bfd_boolean |
| 3753 |
_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr) |
s3_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr) |
| 3754 |
{ |
{ |
| 3755 |
if (hdr->bfd_section != NULL) |
if (hdr->bfd_section != NULL) |
| 3756 |
{ |
{ |
| 3757 |
const char *name = bfd_get_section_name (abfd, hdr->bfd_section); |
const char *name = bfd_get_section_name (abfd, hdr->bfd_section); |
| 3758 |
|
|
| 3759 |
if (strcmp (name, ".sdata") == 0) |
if (strcmp (name, ".sdata") == 0) |
| 3760 |
{ |
{ |
| 3761 |
hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; |
hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; |
| 3762 |
hdr->sh_type = SHT_PROGBITS; |
hdr->sh_type = SHT_PROGBITS; |
| 3763 |
} |
} |
| 3764 |
else if (strcmp (name, ".sbss") == 0) |
else if (strcmp (name, ".sbss") == 0) |
| 3765 |
{ |
{ |
| 3766 |
hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; |
hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; |
| 3767 |
hdr->sh_type = SHT_NOBITS; |
hdr->sh_type = SHT_NOBITS; |
| 3768 |
} |
} |
| 3769 |
else if (strcmp (name, ".srdata") == 0) |
else if (strcmp (name, ".srdata") == 0) |
| 3770 |
{ |
{ |
| 3771 |
hdr->sh_flags |= SHF_ALLOC | SHF_SCORE_GPREL; |
hdr->sh_flags |= SHF_ALLOC | SHF_SCORE_GPREL; |
| 3772 |
hdr->sh_type = SHT_PROGBITS; |
hdr->sh_type = SHT_PROGBITS; |
| 3773 |
} |
} |
| 3774 |
} |
} |
| 3775 |
|
|
| 3776 |
return TRUE; |
return TRUE; |
| 3777 |
} |
} |
| 3778 |
|
|
| 3779 |
static bfd_boolean |
static bfd_boolean |
| 3780 |
_bfd_score_elf_write_section (bfd *output_bfd, |
s3_bfd_score_elf_write_section (bfd *output_bfd, asection *sec, bfd_byte *contents) |
|
struct bfd_link_info *link_info ATTRIBUTE_UNUSED, |
|
|
asection *sec, bfd_byte *contents) |
|
| 3781 |
{ |
{ |
| 3782 |
bfd_byte *to, *from, *end; |
bfd_byte *to, *from, *end; |
| 3783 |
int i; |
int i; |
| 3808 |
|
|
| 3809 |
/* Copy data from a SCORE ELF indirect symbol to its direct symbol, hiding the old |
/* Copy data from a SCORE ELF indirect symbol to its direct symbol, hiding the old |
| 3810 |
indirect symbol. Process additional relocation information. */ |
indirect symbol. Process additional relocation information. */ |
|
|
|
| 3811 |
static void |
static void |
| 3812 |
_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info, |
s3_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info, |
| 3813 |
struct elf_link_hash_entry *dir, |
struct elf_link_hash_entry *dir, |
| 3814 |
struct elf_link_hash_entry *ind) |
struct elf_link_hash_entry *ind) |
| 3815 |
{ |
{ |
| 3816 |
struct score_elf_link_hash_entry *dirscore, *indscore; |
struct score_elf_link_hash_entry *dirscore, *indscore; |
| 3817 |
|
|
| 3832 |
} |
} |
| 3833 |
|
|
| 3834 |
/* Remove information about discarded functions from other sections which mention them. */ |
/* Remove information about discarded functions from other sections which mention them. */ |
|
|
|
| 3835 |
static bfd_boolean |
static bfd_boolean |
| 3836 |
_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie, |
s3_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie, |
| 3837 |
struct bfd_link_info *info) |
struct bfd_link_info *info) |
| 3838 |
{ |
{ |
| 3839 |
asection *o; |
asection *o; |
| 3840 |
bfd_boolean ret = FALSE; |
bfd_boolean ret = FALSE; |
| 3885 |
} |
} |
| 3886 |
|
|
| 3887 |
/* Signal that discard_info() has removed the discarded relocations for this section. */ |
/* Signal that discard_info() has removed the discarded relocations for this section. */ |
|
|
|
| 3888 |
static bfd_boolean |
static bfd_boolean |
| 3889 |
_bfd_score_elf_ignore_discarded_relocs (asection *sec) |
s3_bfd_score_elf_ignore_discarded_relocs (asection *sec) |
| 3890 |
{ |
{ |
| 3891 |
if (strcmp (sec->name, ".pdr") == 0) |
if (strcmp (sec->name, ".pdr") == 0) |
| 3892 |
return TRUE; |
return TRUE; |
| 3895 |
|
|
| 3896 |
/* Return the section that should be marked against GC for a given |
/* Return the section that should be marked against GC for a given |
| 3897 |
relocation. */ |
relocation. */ |
|
|
|
| 3898 |
static asection * |
static asection * |
| 3899 |
_bfd_score_elf_gc_mark_hook (asection *sec, |
s3_bfd_score_elf_gc_mark_hook (asection *sec, |
| 3900 |
struct bfd_link_info *info, |
struct bfd_link_info *info, |
| 3901 |
Elf_Internal_Rela *rel, |
Elf_Internal_Rela *rel, |
| 3902 |
struct elf_link_hash_entry *h, |
struct elf_link_hash_entry *h, |
| 3903 |
Elf_Internal_Sym *sym) |
Elf_Internal_Sym *sym) |
| 3904 |
{ |
{ |
| 3905 |
if (h != NULL) |
if (h != NULL) |
| 3906 |
switch (ELF32_R_TYPE (rel->r_info)) |
switch (ELF32_R_TYPE (rel->r_info)) |
| 3907 |
{ |
{ |
| 3908 |
case R_SCORE_GNU_VTINHERIT: |
case R_SCORE_GNU_VTINHERIT: |
| 3909 |
case R_SCORE_GNU_VTENTRY: |
case R_SCORE_GNU_VTENTRY: |
| 3910 |
return NULL; |
return NULL; |
| 3911 |
} |
} |
| 3912 |
|
|
| 3913 |
return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); |
return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); |
| 3916 |
/* Support for core dump NOTE sections. */ |
/* Support for core dump NOTE sections. */ |
| 3917 |
|
|
| 3918 |
static bfd_boolean |
static bfd_boolean |
| 3919 |
_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) |
s3_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) |
| 3920 |
{ |
{ |
| 3921 |
int offset; |
int offset; |
| 3922 |
unsigned int raw_size; |
unsigned int raw_size; |
| 3928 |
|
|
| 3929 |
case 148: /* Linux/Score 32-bit. */ |
case 148: /* Linux/Score 32-bit. */ |
| 3930 |
/* pr_cursig */ |
/* pr_cursig */ |
| 3931 |
elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); |
elf_tdata (abfd)->core_signal = score_bfd_get_16 (abfd, note->descdata + 12); |
| 3932 |
|
|
| 3933 |
/* pr_pid */ |
/* pr_pid */ |
| 3934 |
elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); |
elf_tdata (abfd)->core_pid = score_bfd_get_32 (abfd, note->descdata + 24); |
| 3935 |
|
|
| 3936 |
/* pr_reg */ |
/* pr_reg */ |
| 3937 |
offset = 72; |
offset = 72; |
| 3945 |
} |
} |
| 3946 |
|
|
| 3947 |
static bfd_boolean |
static bfd_boolean |
| 3948 |
_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) |
s3_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) |
| 3949 |
{ |
{ |
| 3950 |
switch (note->descsz) |
switch (note->descsz) |
| 3951 |
{ |
{ |
| 3974 |
|
|
| 3975 |
|
|
| 3976 |
/* Score BFD functions. */ |
/* Score BFD functions. */ |
|
|
|
| 3977 |
static reloc_howto_type * |
static reloc_howto_type * |
| 3978 |
elf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) |
s3_elf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) |
| 3979 |
{ |
{ |
| 3980 |
unsigned int i; |
unsigned int i; |
| 3981 |
|
|
| 3982 |
for (i = 0; i < NUM_ELEM (elf32_score_reloc_map); i++) |
for (i = 0; i < ARRAY_SIZE (elf32_score_reloc_map); i++) |
| 3983 |
if (elf32_score_reloc_map[i].bfd_reloc_val == code) |
if (elf32_score_reloc_map[i].bfd_reloc_val == code) |
| 3984 |
return &elf32_score_howto_table[elf32_score_reloc_map[i].elf_reloc_val]; |
return &elf32_score_howto_table[elf32_score_reloc_map[i].elf_reloc_val]; |
| 3985 |
|
|
| 3988 |
|
|
| 3989 |
static reloc_howto_type * |
static reloc_howto_type * |
| 3990 |
elf32_score_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
elf32_score_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
| 3991 |
const char *r_name) |
const char *r_name) |
| 3992 |
{ |
{ |
| 3993 |
unsigned int i; |
unsigned int i; |
| 3994 |
|
|
| 3995 |
for (i = 0; |
for (i = 0; |
| 3996 |
i < (sizeof (elf32_score_howto_table) |
i < (sizeof (elf32_score_howto_table) |
| 3997 |
/ sizeof (elf32_score_howto_table[0])); |
/ sizeof (elf32_score_howto_table[0])); |
| 3998 |
i++) |
i++) |
| 3999 |
if (elf32_score_howto_table[i].name != NULL |
if (elf32_score_howto_table[i].name != NULL |
| 4000 |
&& strcasecmp (elf32_score_howto_table[i].name, r_name) == 0) |
&& strcasecmp (elf32_score_howto_table[i].name, r_name) == 0) |
| 4001 |
return &elf32_score_howto_table[i]; |
return &elf32_score_howto_table[i]; |
| 4002 |
|
|
| 4003 |
return NULL; |
return NULL; |
| 4006 |
/* Create a score elf linker hash table. */ |
/* Create a score elf linker hash table. */ |
| 4007 |
|
|
| 4008 |
static struct bfd_link_hash_table * |
static struct bfd_link_hash_table * |
| 4009 |
elf32_score_link_hash_table_create (bfd *abfd) |
s3_elf32_score_link_hash_table_create (bfd *abfd) |
| 4010 |
{ |
{ |
| 4011 |
struct score_elf_link_hash_table *ret; |
struct score_elf_link_hash_table *ret; |
| 4012 |
bfd_size_type amt = sizeof (struct score_elf_link_hash_table); |
bfd_size_type amt = sizeof (struct score_elf_link_hash_table); |
| 4016 |
return NULL; |
return NULL; |
| 4017 |
|
|
| 4018 |
if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, score_elf_link_hash_newfunc, |
if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, score_elf_link_hash_newfunc, |
| 4019 |
sizeof (struct score_elf_link_hash_entry))) |
sizeof (struct score_elf_link_hash_entry))) |
| 4020 |
{ |
{ |
| 4021 |
free (ret); |
free (ret); |
| 4022 |
return NULL; |
return NULL; |
| 4026 |
} |
} |
| 4027 |
|
|
| 4028 |
static bfd_boolean |
static bfd_boolean |
| 4029 |
elf32_score_print_private_bfd_data (bfd *abfd, void * ptr) |
s3_elf32_score_print_private_bfd_data (bfd *abfd, void * ptr) |
| 4030 |
{ |
{ |
| 4031 |
FILE *file = (FILE *) ptr; |
FILE *file = (FILE *) ptr; |
| 4032 |
|
|
| 4051 |
} |
} |
| 4052 |
|
|
| 4053 |
static bfd_boolean |
static bfd_boolean |
| 4054 |
elf32_score_merge_private_bfd_data (bfd *ibfd, bfd *obfd) |
s3_elf32_score_merge_private_bfd_data (bfd *ibfd, bfd *obfd) |
| 4055 |
{ |
{ |
| 4056 |
flagword in_flags; |
flagword in_flags; |
| 4057 |
flagword out_flags; |
flagword out_flags; |
| 4075 |
elf_elfheader (obfd)->e_flags = in_flags; |
elf_elfheader (obfd)->e_flags = in_flags; |
| 4076 |
|
|
| 4077 |
if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) |
if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) |
| 4078 |
&& bfd_get_arch_info (obfd)->the_default) |
&& bfd_get_arch_info (obfd)->the_default) |
| 4079 |
{ |
{ |
| 4080 |
return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); |
return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); |
| 4081 |
} |
} |
| 4082 |
|
|
| 4083 |
return TRUE; |
return TRUE; |
| 4084 |
} |
} |
| 4094 |
} |
} |
| 4095 |
|
|
| 4096 |
static bfd_boolean |
static bfd_boolean |
| 4097 |
elf32_score_new_section_hook (bfd *abfd, asection *sec) |
s3_elf32_score_new_section_hook (bfd *abfd, asection *sec) |
| 4098 |
{ |
{ |
| 4099 |
struct _score_elf_section_data *sdata; |
struct _score_elf_section_data *sdata; |
| 4100 |
bfd_size_type amt = sizeof (*sdata); |
bfd_size_type amt = sizeof (*sdata); |
| 4107 |
return _bfd_elf_new_section_hook (abfd, sec); |
return _bfd_elf_new_section_hook (abfd, sec); |
| 4108 |
} |
} |
| 4109 |
|
|
| 4110 |
|
/*****************************************************************************/ |
| 4111 |
|
|
| 4112 |
|
/* s3_s7: backend hooks. */ |
| 4113 |
|
static void |
| 4114 |
|
_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, |
| 4115 |
|
arelent *bfd_reloc, |
| 4116 |
|
Elf_Internal_Rela *elf_reloc) |
| 4117 |
|
{ |
| 4118 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4119 |
|
return s3_bfd_score_info_to_howto (abfd, bfd_reloc, elf_reloc); |
| 4120 |
|
else |
| 4121 |
|
return s7_bfd_score_info_to_howto (abfd, bfd_reloc, elf_reloc); |
| 4122 |
|
} |
| 4123 |
|
|
| 4124 |
|
static bfd_boolean |
| 4125 |
|
_bfd_score_elf_relocate_section (bfd *output_bfd, |
| 4126 |
|
struct bfd_link_info *info, |
| 4127 |
|
bfd *input_bfd, |
| 4128 |
|
asection *input_section, |
| 4129 |
|
bfd_byte *contents, |
| 4130 |
|
Elf_Internal_Rela *relocs, |
| 4131 |
|
Elf_Internal_Sym *local_syms, |
| 4132 |
|
asection **local_sections) |
| 4133 |
|
{ |
| 4134 |
|
if (bfd_get_mach (output_bfd) == bfd_mach_score3) |
| 4135 |
|
return s3_bfd_score_elf_relocate_section (output_bfd, |
| 4136 |
|
info, input_bfd, input_section, contents, relocs, |
| 4137 |
|
local_syms, local_sections); |
| 4138 |
|
else |
| 4139 |
|
return s7_bfd_score_elf_relocate_section (output_bfd, |
| 4140 |
|
info, input_bfd, input_section, contents, relocs, |
| 4141 |
|
local_syms, local_sections); |
| 4142 |
|
} |
| 4143 |
|
|
| 4144 |
|
static bfd_boolean |
| 4145 |
|
_bfd_score_elf_check_relocs (bfd *abfd, |
| 4146 |
|
struct bfd_link_info *info, |
| 4147 |
|
asection *sec, |
| 4148 |
|
const Elf_Internal_Rela *relocs) |
| 4149 |
|
{ |
| 4150 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4151 |
|
return s3_bfd_score_elf_check_relocs (abfd, info, sec, relocs); |
| 4152 |
|
else |
| 4153 |
|
return s7_bfd_score_elf_check_relocs (abfd, info, sec, relocs); |
| 4154 |
|
} |
| 4155 |
|
|
| 4156 |
|
static bfd_boolean |
| 4157 |
|
_bfd_score_elf_add_symbol_hook (bfd *abfd, |
| 4158 |
|
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
| 4159 |
|
Elf_Internal_Sym *sym, |
| 4160 |
|
const char **namep ATTRIBUTE_UNUSED, |
| 4161 |
|
flagword *flagsp ATTRIBUTE_UNUSED, |
| 4162 |
|
asection **secp, |
| 4163 |
|
bfd_vma *valp) |
| 4164 |
|
{ |
| 4165 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4166 |
|
return s3_bfd_score_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, |
| 4167 |
|
secp, valp); |
| 4168 |
|
else |
| 4169 |
|
return s7_bfd_score_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, |
| 4170 |
|
secp, valp); |
| 4171 |
|
} |
| 4172 |
|
|
| 4173 |
|
static void |
| 4174 |
|
_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym) |
| 4175 |
|
{ |
| 4176 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4177 |
|
return s3_bfd_score_elf_symbol_processing (abfd, asym); |
| 4178 |
|
else |
| 4179 |
|
return s7_bfd_score_elf_symbol_processing (abfd, asym); |
| 4180 |
|
} |
| 4181 |
|
|
| 4182 |
|
static int |
| 4183 |
|
_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
| 4184 |
|
const char *name ATTRIBUTE_UNUSED, |
| 4185 |
|
Elf_Internal_Sym *sym, |
| 4186 |
|
asection *input_sec, |
| 4187 |
|
struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) |
| 4188 |
|
{ |
| 4189 |
|
/* If link a empty .o, then this filed is NULL. */ |
| 4190 |
|
if (info->input_bfds == NULL) |
| 4191 |
|
{ |
| 4192 |
|
/* If we see a common symbol, which implies a relocatable link, then |
| 4193 |
|
if a symbol was small common in an input file, mark it as small |
| 4194 |
|
common in the output file. */ |
| 4195 |
|
if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0) |
| 4196 |
|
sym->st_shndx = SHN_SCORE_SCOMMON; |
| 4197 |
|
return 1; |
| 4198 |
|
} |
| 4199 |
|
|
| 4200 |
|
if (bfd_get_mach (info->input_bfds) == bfd_mach_score3) |
| 4201 |
|
return s3_bfd_score_elf_link_output_symbol_hook (info, name, sym, input_sec, h); |
| 4202 |
|
else |
| 4203 |
|
return s7_bfd_score_elf_link_output_symbol_hook (info, name, sym, input_sec, h); |
| 4204 |
|
} |
| 4205 |
|
|
| 4206 |
|
static bfd_boolean |
| 4207 |
|
_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, |
| 4208 |
|
asection *sec, |
| 4209 |
|
int *retval) |
| 4210 |
|
{ |
| 4211 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4212 |
|
return s3_bfd_score_elf_section_from_bfd_section (abfd, sec, retval); |
| 4213 |
|
else |
| 4214 |
|
return s7_bfd_score_elf_section_from_bfd_section (abfd, sec, retval); |
| 4215 |
|
} |
| 4216 |
|
|
| 4217 |
|
static bfd_boolean |
| 4218 |
|
_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info, |
| 4219 |
|
struct elf_link_hash_entry *h) |
| 4220 |
|
{ |
| 4221 |
|
if (bfd_get_mach (info->input_bfds) == bfd_mach_score3) |
| 4222 |
|
return s3_bfd_score_elf_adjust_dynamic_symbol (info, h); |
| 4223 |
|
else |
| 4224 |
|
return s7_bfd_score_elf_adjust_dynamic_symbol (info, h); |
| 4225 |
|
} |
| 4226 |
|
|
| 4227 |
|
static bfd_boolean |
| 4228 |
|
_bfd_score_elf_always_size_sections (bfd *output_bfd, |
| 4229 |
|
struct bfd_link_info *info) |
| 4230 |
|
{ |
| 4231 |
|
if (bfd_get_mach (output_bfd) == bfd_mach_score3) |
| 4232 |
|
return s3_bfd_score_elf_always_size_sections (output_bfd, info); |
| 4233 |
|
else |
| 4234 |
|
return s7_bfd_score_elf_always_size_sections (output_bfd, info); |
| 4235 |
|
} |
| 4236 |
|
|
| 4237 |
|
static bfd_boolean |
| 4238 |
|
_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) |
| 4239 |
|
{ |
| 4240 |
|
if (bfd_get_mach (output_bfd) == bfd_mach_score3) |
| 4241 |
|
return s3_bfd_score_elf_size_dynamic_sections (output_bfd, info); |
| 4242 |
|
else |
| 4243 |
|
return s7_bfd_score_elf_size_dynamic_sections (output_bfd, info); |
| 4244 |
|
} |
| 4245 |
|
|
| 4246 |
|
static bfd_boolean |
| 4247 |
|
_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) |
| 4248 |
|
{ |
| 4249 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4250 |
|
return s3_bfd_score_elf_create_dynamic_sections (abfd, info); |
| 4251 |
|
else |
| 4252 |
|
return s7_bfd_score_elf_create_dynamic_sections (abfd, info); |
| 4253 |
|
} |
| 4254 |
|
|
| 4255 |
|
static bfd_boolean |
| 4256 |
|
_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd, |
| 4257 |
|
struct bfd_link_info *info, |
| 4258 |
|
struct elf_link_hash_entry *h, |
| 4259 |
|
Elf_Internal_Sym *sym) |
| 4260 |
|
{ |
| 4261 |
|
if (bfd_get_mach (output_bfd) == bfd_mach_score3) |
| 4262 |
|
return s3_bfd_score_elf_finish_dynamic_symbol (output_bfd, info, h, sym); |
| 4263 |
|
else |
| 4264 |
|
return s7_bfd_score_elf_finish_dynamic_symbol (output_bfd, info, h, sym); |
| 4265 |
|
} |
| 4266 |
|
|
| 4267 |
|
static bfd_boolean |
| 4268 |
|
_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd, |
| 4269 |
|
struct bfd_link_info *info) |
| 4270 |
|
{ |
| 4271 |
|
if (bfd_get_mach (output_bfd) == bfd_mach_score3) |
| 4272 |
|
return s3_bfd_score_elf_finish_dynamic_sections (output_bfd, info); |
| 4273 |
|
else |
| 4274 |
|
return s7_bfd_score_elf_finish_dynamic_sections (output_bfd, info); |
| 4275 |
|
} |
| 4276 |
|
|
| 4277 |
|
static bfd_boolean |
| 4278 |
|
_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, |
| 4279 |
|
Elf_Internal_Shdr *hdr, |
| 4280 |
|
asection *sec) |
| 4281 |
|
{ |
| 4282 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4283 |
|
return s3_bfd_score_elf_fake_sections (abfd, hdr, sec); |
| 4284 |
|
else |
| 4285 |
|
return s7_bfd_score_elf_fake_sections (abfd, hdr, sec); |
| 4286 |
|
} |
| 4287 |
|
|
| 4288 |
|
static bfd_boolean |
| 4289 |
|
_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr) |
| 4290 |
|
{ |
| 4291 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4292 |
|
return s3_bfd_score_elf_section_processing (abfd, hdr); |
| 4293 |
|
else |
| 4294 |
|
return s7_bfd_score_elf_section_processing (abfd, hdr); |
| 4295 |
|
} |
| 4296 |
|
|
| 4297 |
|
static bfd_boolean |
| 4298 |
|
_bfd_score_elf_write_section (bfd *output_bfd, |
| 4299 |
|
struct bfd_link_info *link_info ATTRIBUTE_UNUSED, |
| 4300 |
|
asection *sec, bfd_byte *contents) |
| 4301 |
|
{ |
| 4302 |
|
if (bfd_get_mach (output_bfd) == bfd_mach_score3) |
| 4303 |
|
return s3_bfd_score_elf_write_section (output_bfd, sec, contents); |
| 4304 |
|
else |
| 4305 |
|
return s7_bfd_score_elf_write_section (output_bfd, sec, contents); |
| 4306 |
|
} |
| 4307 |
|
|
| 4308 |
|
static void |
| 4309 |
|
_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info, |
| 4310 |
|
struct elf_link_hash_entry *dir, |
| 4311 |
|
struct elf_link_hash_entry *ind) |
| 4312 |
|
{ |
| 4313 |
|
if (bfd_get_mach (info->input_bfds) == bfd_mach_score3) |
| 4314 |
|
return s3_bfd_score_elf_copy_indirect_symbol (info, dir, ind); |
| 4315 |
|
else |
| 4316 |
|
return s7_bfd_score_elf_copy_indirect_symbol (info, dir, ind); |
| 4317 |
|
} |
| 4318 |
|
|
| 4319 |
|
static void |
| 4320 |
|
_bfd_score_elf_hide_symbol (struct bfd_link_info *info, |
| 4321 |
|
struct elf_link_hash_entry *entry, |
| 4322 |
|
bfd_boolean force_local) |
| 4323 |
|
{ |
| 4324 |
|
if (bfd_get_mach (info->input_bfds) == bfd_mach_score3) |
| 4325 |
|
return s3_bfd_score_elf_hide_symbol (info, entry, force_local); |
| 4326 |
|
else |
| 4327 |
|
return s7_bfd_score_elf_hide_symbol (info, entry, force_local); |
| 4328 |
|
} |
| 4329 |
|
|
| 4330 |
|
static bfd_boolean |
| 4331 |
|
_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie, |
| 4332 |
|
struct bfd_link_info *info) |
| 4333 |
|
{ |
| 4334 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4335 |
|
return s3_bfd_score_elf_discard_info (abfd, cookie, info); |
| 4336 |
|
else |
| 4337 |
|
return s7_bfd_score_elf_discard_info (abfd, cookie, info); |
| 4338 |
|
} |
| 4339 |
|
|
| 4340 |
|
static bfd_boolean |
| 4341 |
|
_bfd_score_elf_ignore_discarded_relocs (asection *sec) |
| 4342 |
|
{ |
| 4343 |
|
if (bfd_get_mach (sec->owner) == bfd_mach_score3) |
| 4344 |
|
return s3_bfd_score_elf_ignore_discarded_relocs (sec); |
| 4345 |
|
else |
| 4346 |
|
return s7_bfd_score_elf_ignore_discarded_relocs (sec); |
| 4347 |
|
} |
| 4348 |
|
|
| 4349 |
|
static asection * |
| 4350 |
|
_bfd_score_elf_gc_mark_hook (asection *sec, |
| 4351 |
|
struct bfd_link_info *info, |
| 4352 |
|
Elf_Internal_Rela *rel, |
| 4353 |
|
struct elf_link_hash_entry *h, |
| 4354 |
|
Elf_Internal_Sym *sym) |
| 4355 |
|
{ |
| 4356 |
|
if (bfd_get_mach (info->input_bfds) == bfd_mach_score3) |
| 4357 |
|
return s3_bfd_score_elf_gc_mark_hook (sec, info, rel, h, sym); |
| 4358 |
|
else |
| 4359 |
|
return s7_bfd_score_elf_gc_mark_hook (sec, info, rel, h, sym); |
| 4360 |
|
} |
| 4361 |
|
|
| 4362 |
|
static bfd_boolean |
| 4363 |
|
_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) |
| 4364 |
|
{ |
| 4365 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4366 |
|
return s3_bfd_score_elf_grok_prstatus (abfd, note); |
| 4367 |
|
else |
| 4368 |
|
return s7_bfd_score_elf_grok_prstatus (abfd, note); |
| 4369 |
|
} |
| 4370 |
|
|
| 4371 |
|
static bfd_boolean |
| 4372 |
|
_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) |
| 4373 |
|
{ |
| 4374 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4375 |
|
return s3_bfd_score_elf_grok_psinfo (abfd, note); |
| 4376 |
|
else |
| 4377 |
|
return s7_bfd_score_elf_grok_psinfo (abfd, note); |
| 4378 |
|
} |
| 4379 |
|
|
| 4380 |
|
static reloc_howto_type * |
| 4381 |
|
elf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) |
| 4382 |
|
{ |
| 4383 |
|
/* s3: NOTE!!! |
| 4384 |
|
gas will call elf32_score_reloc_type_lookup, and don't write elf file. |
| 4385 |
|
So just using score3, but we don't know ld will call this or not. |
| 4386 |
|
If so, this way can't work. */ |
| 4387 |
|
|
| 4388 |
|
if (score3) |
| 4389 |
|
return s3_elf32_score_reloc_type_lookup (abfd, code); |
| 4390 |
|
else |
| 4391 |
|
return s7_elf32_score_reloc_type_lookup (abfd, code); |
| 4392 |
|
} |
| 4393 |
|
|
| 4394 |
|
static struct bfd_link_hash_table * |
| 4395 |
|
elf32_score_link_hash_table_create (bfd *abfd) |
| 4396 |
|
{ |
| 4397 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4398 |
|
return s3_elf32_score_link_hash_table_create (abfd); |
| 4399 |
|
else |
| 4400 |
|
return s7_elf32_score_link_hash_table_create (abfd); |
| 4401 |
|
} |
| 4402 |
|
|
| 4403 |
|
static bfd_boolean |
| 4404 |
|
elf32_score_print_private_bfd_data (bfd *abfd, void * ptr) |
| 4405 |
|
{ |
| 4406 |
|
if (bfd_get_mach (abfd) == bfd_mach_score3) |
| 4407 |
|
return s3_elf32_score_print_private_bfd_data (abfd, ptr); |
| 4408 |
|
else |
| 4409 |
|
return s7_elf32_score_print_p
| |