X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf32-bfin.c;h=8aba7edfe408969e5f3c34683ceb1572e866a4f4;hb=f9a63d49c74b7cc540a0e94d69411676f4332a42;hp=480feb2d30e6d4383b743e53da8aa839f74bba45;hpb=8c6845782707f98080fa789050c9d70afadb1842;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-bfin.c b/bfd/elf32-bfin.c index 480feb2d30..8aba7edfe4 100644 --- a/bfd/elf32-bfin.c +++ b/bfd/elf32-bfin.c @@ -1,5 +1,6 @@ /* ADI Blackfin BFD support for 32-bit ELF. - Copyright 2005, 2006, 2007 Free Software Foundation, Inc. + Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011 + Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -23,7 +24,7 @@ #include "libbfd.h" #include "elf-bfd.h" #include "elf/bfin.h" -#include "elf/dwarf2.h" +#include "dwarf2.h" #include "hashtab.h" /* FUNCTION : bfin_pltpc_reloc @@ -103,7 +104,7 @@ bfin_pcrel24_reloc (bfd *abfd, /* if rightshift is 1 and the number odd, return error. */ if (howto->rightshift && (relocation & 0x01)) { - fprintf(stderr, "relocation should be even number\n"); + (*_bfd_error_handler) (_("relocation should be even number")); return bfd_reloc_overflow; } @@ -359,7 +360,7 @@ bfin_bfd_reloc (bfd *abfd, /* If rightshift is 1 and the number odd, return error. */ if (howto->rightshift && (relocation & 0x01)) { - fprintf(stderr, "relocation should be even number\n"); + (*_bfd_error_handler) (_("relocation should be even number")); return bfd_reloc_overflow; } @@ -421,7 +422,7 @@ bfin_bfd_reloc (bfd *abfd, static reloc_howto_type bfin_howto_table [] = { /* This reloc does nothing. . */ - HOWTO (R_unused0, /* type. */ + HOWTO (R_BFIN_UNUSED0, /* type. */ 0, /* rightshift. */ 2, /* size (0 = byte, 1 = short, 2 = long). */ 32, /* bitsize. */ @@ -429,13 +430,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_bitfield, /* complain_on_overflow. */ bfd_elf_generic_reloc, /* special_function. */ - "R_unused0", /* name. */ + "R_BFIN_UNUSED0", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0, /* dst_mask. */ FALSE), /* pcrel_offset. */ - HOWTO (R_pcrel5m2, /* type. */ + HOWTO (R_BFIN_PCREL5M2, /* type. */ 1, /* rightshift. */ 1, /* size (0 = byte, 1 = short, 2 = long).. */ 4, /* bitsize. */ @@ -443,13 +444,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_unsigned, /* complain_on_overflow. */ bfin_bfd_reloc, /* special_function. */ - "R_pcrel5m2", /* name. */ + "R_BFIN_PCREL5M2", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x0000000F, /* dst_mask. */ FALSE), /* pcrel_offset. */ - HOWTO (R_unused1, /* type. */ + HOWTO (R_BFIN_UNUSED1, /* type. */ 0, /* rightshift. */ 2, /* size (0 = byte, 1 = short, 2 = long). */ 32, /* bitsize. */ @@ -457,13 +458,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_bitfield, /* complain_on_overflow. */ bfd_elf_generic_reloc, /* special_function. */ - "R_unused1", /* name. */ + "R_BFIN_UNUSED1", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0, /* dst_mask. */ FALSE), /* pcrel_offset. */ - HOWTO (R_pcrel10, /* type. */ + HOWTO (R_BFIN_PCREL10, /* type. */ 1, /* rightshift. */ 1, /* size (0 = byte, 1 = short, 2 = long). */ 10, /* bitsize. */ @@ -471,13 +472,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_signed, /* complain_on_overflow. */ bfin_bfd_reloc, /* special_function. */ - "R_pcrel10", /* name. */ + "R_BFIN_PCREL10", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x000003FF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_pcrel12_jump, /* type. */ + HOWTO (R_BFIN_PCREL12_JUMP, /* type. */ 1, /* rightshift. */ /* the offset is actually 13 bit aligned on a word boundary so @@ -489,13 +490,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_signed, /* complain_on_overflow. */ bfin_bfd_reloc, /* special_function. */ - "R_pcrel12_jump", /* name. */ + "R_BFIN_PCREL12_JUMP", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x0FFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_rimm16, /* type. */ + HOWTO (R_BFIN_RIMM16, /* type. */ 0, /* rightshift. */ 1, /* size (0 = byte, 1 = short, 2 = long). */ 16, /* bitsize. */ @@ -503,13 +504,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_signed, /* complain_on_overflow. */ bfin_imm16_reloc, /* special_function. */ - "R_rimm16", /* name. */ + "R_BFIN_RIMM16", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x0000FFFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_luimm16, /* type. */ + HOWTO (R_BFIN_LUIMM16, /* type. */ 0, /* rightshift. */ 1, /* size (0 = byte, 1 = short, 2 = long). */ 16, /* bitsize. */ @@ -517,13 +518,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_dont, /* complain_on_overflow. */ bfin_imm16_reloc, /* special_function. */ - "R_luimm16", /* name. */ + "R_BFIN_LUIMM16", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x0000FFFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_huimm16, /* type. */ + HOWTO (R_BFIN_HUIMM16, /* type. */ 16, /* rightshift. */ 1, /* size (0 = byte, 1 = short, 2 = long). */ 16, /* bitsize. */ @@ -531,13 +532,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_unsigned, /* complain_on_overflow. */ bfin_imm16_reloc, /* special_function. */ - "R_huimm16", /* name. */ + "R_BFIN_HUIMM16", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x0000FFFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_pcrel12_jump_s, /* type. */ + HOWTO (R_BFIN_PCREL12_JUMP_S, /* type. */ 1, /* rightshift. */ 1, /* size (0 = byte, 1 = short, 2 = long). */ 12, /* bitsize. */ @@ -545,13 +546,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_signed, /* complain_on_overflow. */ bfin_bfd_reloc, /* special_function. */ - "R_pcrel12_jump_s", /* name. */ + "R_BFIN_PCREL12_JUMP_S", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x00000FFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_pcrel24_jump_x, /* type. */ + HOWTO (R_BFIN_PCREL24_JUMP_X, /* type. */ 1, /* rightshift. */ 2, /* size (0 = byte, 1 = short, 2 = long). */ 24, /* bitsize. */ @@ -559,13 +560,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_signed, /* complain_on_overflow. */ bfin_pcrel24_reloc, /* special_function. */ - "R_pcrel24_jump_x", /* name. */ + "R_BFIN_PCREL24_JUMP_X", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x00FFFFFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_pcrel24, /* type. */ + HOWTO (R_BFIN_PCREL24, /* type. */ 1, /* rightshift. */ 2, /* size (0 = byte, 1 = short, 2 = long). */ 24, /* bitsize. */ @@ -573,13 +574,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_signed, /* complain_on_overflow. */ bfin_pcrel24_reloc, /* special_function. */ - "R_pcrel24", /* name. */ + "R_BFIN_PCREL24", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x00FFFFFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_unusedb, /* type. */ + HOWTO (R_BFIN_UNUSEDB, /* type. */ 0, /* rightshift. */ 2, /* size (0 = byte, 1 = short, 2 = long). */ 32, /* bitsize. */ @@ -587,13 +588,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_dont, /* complain_on_overflow. */ bfd_elf_generic_reloc, /* special_function. */ - "R_unusedb", /* name. */ + "R_BFIN_UNUSEDB", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0, /* dst_mask. */ FALSE), /* pcrel_offset. */ - HOWTO (R_unusedc, /* type. */ + HOWTO (R_BFIN_UNUSEDC, /* type. */ 0, /* rightshift. */ 2, /* size (0 = byte, 1 = short, 2 = long). */ 32, /* bitsize. */ @@ -601,13 +602,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_dont, /* complain_on_overflow. */ bfd_elf_generic_reloc, /* special_function. */ - "R_unusedc", /* name. */ + "R_BFIN_UNUSEDC", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0, /* dst_mask. */ FALSE), /* pcrel_offset. */ - HOWTO (R_pcrel24_jump_l, /* type. */ + HOWTO (R_BFIN_PCREL24_JUMP_L, /* type. */ 1, /* rightshift. */ 2, /* size (0 = byte, 1 = short, 2 = long). */ 24, /* bitsize. */ @@ -615,13 +616,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_signed, /* complain_on_overflow. */ bfin_pcrel24_reloc, /* special_function. */ - "R_pcrel24_jump_l", /* name. */ + "R_BFIN_PCREL24_JUMP_L", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x00FFFFFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_pcrel24_call_x, /* type. */ + HOWTO (R_BFIN_PCREL24_CALL_X, /* type. */ 1, /* rightshift. */ 2, /* size (0 = byte, 1 = short, 2 = long). */ 24, /* bitsize. */ @@ -629,13 +630,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_signed, /* complain_on_overflow. */ bfin_pcrel24_reloc, /* special_function. */ - "R_pcrel24_call_x", /* name. */ + "R_BFIN_PCREL24_CALL_X", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x00FFFFFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_var_eq_symb, /* type. */ + HOWTO (R_BFIN_VAR_EQ_SYMB, /* type. */ 0, /* rightshift. */ 2, /* size (0 = byte, 1 = short, 2 = long). */ 32, /* bitsize. */ @@ -643,13 +644,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_bitfield, /* complain_on_overflow. */ bfin_bfd_reloc, /* special_function. */ - "R_var_eq_symb", /* name. */ + "R_BFIN_VAR_EQ_SYMB", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0, /* dst_mask. */ FALSE), /* pcrel_offset. */ - HOWTO (R_byte_data, /* type. */ + HOWTO (R_BFIN_BYTE_DATA, /* type. */ 0, /* rightshift. */ 0, /* size (0 = byte, 1 = short, 2 = long). */ 8, /* bitsize. */ @@ -657,13 +658,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_unsigned, /* complain_on_overflow. */ bfin_bfd_reloc, /* special_function. */ - "R_byte_data", /* name. */ + "R_BFIN_BYTE_DATA", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0xFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_byte2_data, /* type. */ + HOWTO (R_BFIN_BYTE2_DATA, /* type. */ 0, /* rightshift. */ 1, /* size (0 = byte, 1 = short, 2 = long). */ 16, /* bitsize. */ @@ -671,13 +672,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_signed, /* complain_on_overflow. */ bfin_bfd_reloc, /* special_function. */ - "R_byte2_data", /* name. */ + "R_BFIN_BYTE2_DATA", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0xFFFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_byte4_data, /* type. */ + HOWTO (R_BFIN_BYTE4_DATA, /* type. */ 0, /* rightshift. */ 2, /* size (0 = byte, 1 = short, 2 = long). */ 32, /* bitsize. */ @@ -685,13 +686,13 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_unsigned, /* complain_on_overflow. */ bfin_byte4_reloc, /* special_function. */ - "R_byte4_data", /* name. */ + "R_BFIN_BYTE4_DATA", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0xFFFFFFFF, /* dst_mask. */ TRUE), /* pcrel_offset. */ - HOWTO (R_pcrel11, /* type. */ + HOWTO (R_BFIN_PCREL11, /* type. */ 1, /* rightshift. */ 1, /* size (0 = byte, 1 = short, 2 = long). */ 10, /* bitsize. */ @@ -699,7 +700,7 @@ static reloc_howto_type bfin_howto_table [] = 0, /* bitpos. */ complain_overflow_unsigned, /* complain_on_overflow. */ bfin_bfd_reloc, /* special_function. */ - "R_pcrel11", /* name. */ + "R_BFIN_PCREL11", /* name. */ FALSE, /* partial_inplace. */ 0, /* src_mask. */ 0x000003FF, /* dst_mask. */ @@ -931,7 +932,7 @@ static reloc_howto_type bfin_howto_table [] = static reloc_howto_type bfin_gnuext_howto_table [] = { - HOWTO (R_pltpc, /* type. */ + HOWTO (R_BFIN_PLTPC, /* type. */ 0, /* rightshift. */ 1, /* size (0 = byte, 1 = short, 2 = long). */ 16, /* bitsize. */ @@ -939,13 +940,13 @@ static reloc_howto_type bfin_gnuext_howto_table [] = 0, /* bitpos. */ complain_overflow_bitfield, /* complain_on_overflow. */ bfin_pltpc_reloc, /* special_function. */ - "R_pltpc", /* name. */ + "R_BFIN_PLTPC", /* name. */ FALSE, /* partial_inplace. */ 0xffff, /* src_mask. */ 0xffff, /* dst_mask. */ FALSE), /* pcrel_offset. */ - HOWTO (R_got, /* type. */ + HOWTO (R_BFIN_GOT, /* type. */ 0, /* rightshift. */ 1, /* size (0 = byte, 1 = short, 2 = long). */ 16, /* bitsize. */ @@ -953,7 +954,7 @@ static reloc_howto_type bfin_gnuext_howto_table [] = 0, /* bitpos. */ complain_overflow_bitfield, /* complain_on_overflow. */ bfd_elf_generic_reloc, /* special_function. */ - "R_got", /* name. */ + "R_BFIN_GOT", /* name. */ FALSE, /* partial_inplace. */ 0x7fff, /* src_mask. */ 0x7fff, /* dst_mask. */ @@ -998,27 +999,27 @@ struct bfin_reloc_map static const struct bfin_reloc_map bfin_reloc_map [] = { - { BFD_RELOC_NONE, R_unused0 }, - { BFD_RELOC_BFIN_5_PCREL, R_pcrel5m2 }, - { BFD_RELOC_NONE, R_unused1 }, - { BFD_RELOC_BFIN_10_PCREL, R_pcrel10 }, - { BFD_RELOC_BFIN_12_PCREL_JUMP, R_pcrel12_jump }, - { BFD_RELOC_BFIN_16_IMM, R_rimm16 }, - { BFD_RELOC_BFIN_16_LOW, R_luimm16 }, - { BFD_RELOC_BFIN_16_HIGH, R_huimm16 }, - { BFD_RELOC_BFIN_12_PCREL_JUMP_S, R_pcrel12_jump_s }, - { BFD_RELOC_24_PCREL, R_pcrel24 }, - { BFD_RELOC_24_PCREL, R_pcrel24 }, - { BFD_RELOC_BFIN_24_PCREL_JUMP_L, R_pcrel24_jump_l }, - { BFD_RELOC_NONE, R_unusedb }, - { BFD_RELOC_NONE, R_unusedc }, - { BFD_RELOC_BFIN_24_PCREL_CALL_X, R_pcrel24_call_x }, - { BFD_RELOC_8, R_byte_data }, - { BFD_RELOC_16, R_byte2_data }, - { BFD_RELOC_32, R_byte4_data }, - { BFD_RELOC_BFIN_11_PCREL, R_pcrel11 }, - { BFD_RELOC_BFIN_GOT, R_got }, - { BFD_RELOC_BFIN_PLTPC, R_pltpc }, + { BFD_RELOC_NONE, R_BFIN_UNUSED0 }, + { BFD_RELOC_BFIN_5_PCREL, R_BFIN_PCREL5M2 }, + { BFD_RELOC_NONE, R_BFIN_UNUSED1 }, + { BFD_RELOC_BFIN_10_PCREL, R_BFIN_PCREL10 }, + { BFD_RELOC_BFIN_12_PCREL_JUMP, R_BFIN_PCREL12_JUMP }, + { BFD_RELOC_BFIN_16_IMM, R_BFIN_RIMM16 }, + { BFD_RELOC_BFIN_16_LOW, R_BFIN_LUIMM16 }, + { BFD_RELOC_BFIN_16_HIGH, R_BFIN_HUIMM16 }, + { BFD_RELOC_BFIN_12_PCREL_JUMP_S, R_BFIN_PCREL12_JUMP_S }, + { BFD_RELOC_24_PCREL, R_BFIN_PCREL24 }, + { BFD_RELOC_24_PCREL, R_BFIN_PCREL24 }, + { BFD_RELOC_BFIN_24_PCREL_JUMP_L, R_BFIN_PCREL24_JUMP_L }, + { BFD_RELOC_NONE, R_BFIN_UNUSEDB }, + { BFD_RELOC_NONE, R_BFIN_UNUSEDC }, + { BFD_RELOC_BFIN_24_PCREL_CALL_X, R_BFIN_PCREL24_CALL_X }, + { BFD_RELOC_8, R_BFIN_BYTE_DATA }, + { BFD_RELOC_16, R_BFIN_BYTE2_DATA }, + { BFD_RELOC_32, R_BFIN_BYTE4_DATA }, + { BFD_RELOC_BFIN_11_PCREL, R_BFIN_PCREL11 }, + { BFD_RELOC_BFIN_GOT, R_BFIN_GOT }, + { BFD_RELOC_BFIN_PLTPC, R_BFIN_PLTPC }, { BFD_RELOC_BFIN_GOT17M4, R_BFIN_GOT17M4 }, { BFD_RELOC_BFIN_GOTHI, R_BFIN_GOTHI }, @@ -1139,7 +1140,7 @@ elf32_bfin_final_write_processing (bfd *abfd, bfin local labels begin with L$. */ static bfd_boolean bfin_is_local_label_name ( - bfd *abfd ATTRIBUTE_UNUSED, + bfd *abfd, const char *label) { if (label[0] == 'L' && label[1] == '$' ) @@ -1147,2012 +1148,2092 @@ bfin_is_local_label_name ( return _bfd_elf_is_local_label_name (abfd, label); } + +/* Look through the relocs for a section during the first phase, and + allocate space in the global offset table or procedure linkage + table. */ -extern const bfd_target bfd_elf32_bfinfdpic_vec; -#define IS_FDPIC(bfd) ((bfd)->xvec == &bfd_elf32_bfinfdpic_vec) - -/* An extension of the elf hash table data structure, containing some - additional Blackfin-specific data. */ -struct bfinfdpic_elf_link_hash_table +static bfd_boolean +bfin_check_relocs (bfd * abfd, + struct bfd_link_info *info, + asection *sec, + const Elf_Internal_Rela *relocs) { - struct elf_link_hash_table elf; - - /* A pointer to the .got section. */ + bfd *dynobj; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_signed_vma *local_got_refcounts; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; asection *sgot; - /* A pointer to the .rel.got section. */ - asection *sgotrel; - /* A pointer to the .rofixup section. */ - asection *sgotfixup; - /* A pointer to the .plt section. */ - asection *splt; - /* A pointer to the .rel.plt section. */ - asection *spltrel; - /* GOT base offset. */ - bfd_vma got0; - /* Location of the first non-lazy PLT entry, i.e., the number of - bytes taken by lazy PLT entries. */ - bfd_vma plt0; - /* A hash table holding information about which symbols were - referenced with which PIC-related relocations. */ - struct htab *relocs_info; -}; - -/* Get the Blackfin ELF linker hash table from a link_info structure. */ - -#define bfinfdpic_hash_table(info) \ - ((struct bfinfdpic_elf_link_hash_table *) ((info)->hash)) - -#define bfinfdpic_got_section(info) \ - (bfinfdpic_hash_table (info)->sgot) -#define bfinfdpic_gotrel_section(info) \ - (bfinfdpic_hash_table (info)->sgotrel) -#define bfinfdpic_gotfixup_section(info) \ - (bfinfdpic_hash_table (info)->sgotfixup) -#define bfinfdpic_plt_section(info) \ - (bfinfdpic_hash_table (info)->splt) -#define bfinfdpic_pltrel_section(info) \ - (bfinfdpic_hash_table (info)->spltrel) -#define bfinfdpic_relocs_info(info) \ - (bfinfdpic_hash_table (info)->relocs_info) -#define bfinfdpic_got_initial_offset(info) \ - (bfinfdpic_hash_table (info)->got0) -#define bfinfdpic_plt_initial_offset(info) \ - (bfinfdpic_hash_table (info)->plt0) - -/* Create a Blackfin ELF linker hash table. */ + asection *srelgot; + if (info->relocatable) + return TRUE; -static struct bfd_link_hash_table * -bfinfdpic_elf_link_hash_table_create (bfd *abfd) -{ - struct bfinfdpic_elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct bfinfdpic_elf_link_hash_table); + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + local_got_refcounts = elf_local_got_refcounts (abfd); - ret = bfd_zalloc (abfd, amt); - if (ret == NULL) - return NULL; + sgot = NULL; + srelgot = NULL; - if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, - _bfd_elf_link_hash_newfunc, - sizeof (struct elf_link_hash_entry))) + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) { - free (ret); - return NULL; - } - - return &ret->elf.root; -} + unsigned long r_symndx; + struct elf_link_hash_entry *h; -/* Decide whether a reference to a symbol can be resolved locally or - not. If the symbol is protected, we want the local address, but - its function descriptor must be assigned by the dynamic linker. */ -#define BFINFDPIC_SYM_LOCAL(INFO, H) \ - (_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \ - || ! elf_hash_table (INFO)->dynamic_sections_created) -#define BFINFDPIC_FUNCDESC_LOCAL(INFO, H) \ - ((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created) + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; -/* This structure collects information on what kind of GOT, PLT or - function descriptors are required by relocations that reference a - certain symbol. */ -struct bfinfdpic_relocs_info -{ - /* The index of the symbol, as stored in the relocation r_info, if - we have a local symbol; -1 otherwise. */ - long symndx; - union - { - /* The input bfd in which the symbol is defined, if it's a local - symbol. */ - bfd *abfd; - /* If symndx == -1, the hash table entry corresponding to a global - symbol (even if it turns out to bind locally, in which case it - should ideally be replaced with section's symndx + addend). */ - struct elf_link_hash_entry *h; - } d; - /* The addend of the relocation that references the symbol. */ - bfd_vma addend; + switch (ELF32_R_TYPE (rel->r_info)) + { + /* This relocation describes the C++ object vtable hierarchy. + Reconstruct it for later use during GC. */ + case R_BFIN_GNU_VTINHERIT: + if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + return FALSE; + break; - /* The fields above are used to identify an entry. The fields below - contain information on how an entry is used and, later on, which - locations it was assigned. */ - /* The following 2 fields record whether the symbol+addend above was - ever referenced with a GOT relocation. The 17M4 suffix indicates a - GOT17M4 relocation; hilo is used for GOTLO/GOTHI pairs. */ - unsigned got17m4; - unsigned gothilo; - /* Whether a FUNCDESC relocation references symbol+addend. */ - unsigned fd; - /* Whether a FUNCDESC_GOT relocation references symbol+addend. */ - unsigned fdgot17m4; - unsigned fdgothilo; - /* Whether a FUNCDESC_GOTOFF relocation references symbol+addend. */ - unsigned fdgoff17m4; - unsigned fdgoffhilo; - /* Whether symbol+addend is referenced with GOTOFF17M4, GOTOFFLO or - GOTOFFHI relocations. The addend doesn't really matter, since we - envision that this will only be used to check whether the symbol - is mapped to the same segment as the got. */ - unsigned gotoff; - /* Whether symbol+addend is referenced by a LABEL24 relocation. */ - unsigned call; - /* Whether symbol+addend is referenced by a 32 or FUNCDESC_VALUE - relocation. */ - unsigned sym; - /* Whether we need a PLT entry for a symbol. Should be implied by - something like: - (call && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h)) */ - unsigned plt:1; - /* Whether a function descriptor should be created in this link unit - for symbol+addend. Should be implied by something like: - (plt || fdgotoff17m4 || fdgotofflohi - || ((fd || fdgot17m4 || fdgothilo) - && (symndx != -1 || BFINFDPIC_FUNCDESC_LOCAL (info, d.h)))) */ - unsigned privfd:1; - /* Whether a lazy PLT entry is needed for this symbol+addend. - Should be implied by something like: - (privfd && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h) - && ! (info->flags & DF_BIND_NOW)) */ - unsigned lazyplt:1; - /* Whether we've already emitted GOT relocations and PLT entries as - needed for this symbol. */ - unsigned done:1; + /* This relocation describes which C++ vtable entries + are actually used. Record for later use during GC. */ + case R_BFIN_GNU_VTENTRY: + BFD_ASSERT (h != NULL); + if (h != NULL + && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + return FALSE; + break; - /* The number of R_byte4_data, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE - relocations referencing the symbol. */ - unsigned relocs32, relocsfd, relocsfdv; + case R_BFIN_GOT: + if (h != NULL + && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0) + break; + /* Fall through. */ - /* The number of .rofixups entries and dynamic relocations allocated - for this symbol, minus any that might have already been used. */ - unsigned fixups, dynrelocs; + if (dynobj == NULL) + { + /* Create the .got section. */ + elf_hash_table (info)->dynobj = dynobj = abfd; + if (!_bfd_elf_create_got_section (dynobj, info)) + return FALSE; + } - /* The offsets of the GOT entries assigned to symbol+addend, to the - function descriptor's address, and to a function descriptor, - respectively. Should be zero if unassigned. The offsets are - counted from the value that will be assigned to the PIC register, - not from the beginning of the .got section. */ - bfd_signed_vma got_entry, fdgot_entry, fd_entry; - /* The offsets of the PLT entries assigned to symbol+addend, - non-lazy and lazy, respectively. If unassigned, should be - (bfd_vma)-1. */ - bfd_vma plt_entry, lzplt_entry; -}; + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + } -/* Compute a hash with the key fields of an bfinfdpic_relocs_info entry. */ -static hashval_t -bfinfdpic_relocs_info_hash (const void *entry_) -{ - const struct bfinfdpic_relocs_info *entry = entry_; + if (srelgot == NULL && (h != NULL || info->shared)) + { + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + if (srelgot == NULL) + { + flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS + | SEC_IN_MEMORY | SEC_LINKER_CREATED + | SEC_READONLY); + srelgot = bfd_make_section_with_flags (dynobj, ".rela.got", + flags); + if (srelgot == NULL + || !bfd_set_section_alignment (dynobj, srelgot, 2)) + return FALSE; + } + } - return (entry->symndx == -1 - ? (long) entry->d.h->root.root.hash - : entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend; -} + if (h != NULL) + { + if (h->got.refcount == 0) + { + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1 && !h->forced_local) + { + if (!bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } -/* Test whether the key fields of two bfinfdpic_relocs_info entries are - identical. */ -static int -bfinfdpic_relocs_info_eq (const void *entry1, const void *entry2) -{ - const struct bfinfdpic_relocs_info *e1 = entry1; - const struct bfinfdpic_relocs_info *e2 = entry2; - - return e1->symndx == e2->symndx && e1->addend == e2->addend - && (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd); -} - -/* Find or create an entry in a hash table HT that matches the key - fields of the given ENTRY. If it's not found, memory for a new - entry is allocated in ABFD's obstack. */ -static struct bfinfdpic_relocs_info * -bfinfdpic_relocs_info_find (struct htab *ht, - bfd *abfd, - const struct bfinfdpic_relocs_info *entry, - enum insert_option insert) -{ - struct bfinfdpic_relocs_info **loc = - (struct bfinfdpic_relocs_info **) htab_find_slot (ht, entry, insert); - - if (! loc) - return NULL; - - if (*loc) - return *loc; - - *loc = bfd_zalloc (abfd, sizeof (**loc)); + /* Allocate space in the .got section. */ + sgot->size += 4; + /* Allocate relocation space. */ + srelgot->size += sizeof (Elf32_External_Rela); + } + h->got.refcount++; + } + else + { + /* This is a global offset table entry for a local symbol. */ + if (local_got_refcounts == NULL) + { + bfd_size_type size; - if (! *loc) - return *loc; + size = symtab_hdr->sh_info; + size *= sizeof (bfd_signed_vma); + local_got_refcounts = ((bfd_signed_vma *) + bfd_zalloc (abfd, size)); + if (local_got_refcounts == NULL) + return FALSE; + elf_local_got_refcounts (abfd) = local_got_refcounts; + } + if (local_got_refcounts[r_symndx] == 0) + { + sgot->size += 4; + if (info->shared) + { + /* If we are generating a shared object, we need to + output a R_68K_RELATIVE reloc so that the dynamic + linker can adjust this GOT entry. */ + srelgot->size += sizeof (Elf32_External_Rela); + } + } + local_got_refcounts[r_symndx]++; + } + break; - (*loc)->symndx = entry->symndx; - (*loc)->d = entry->d; - (*loc)->addend = entry->addend; - (*loc)->plt_entry = (bfd_vma)-1; - (*loc)->lzplt_entry = (bfd_vma)-1; + default: + break; + } + } - return *loc; + return TRUE; } -/* Obtain the address of the entry in HT associated with H's symbol + - addend, creating a new entry if none existed. ABFD is only used - for memory allocation purposes. */ -inline static struct bfinfdpic_relocs_info * -bfinfdpic_relocs_info_for_global (struct htab *ht, - bfd *abfd, - struct elf_link_hash_entry *h, - bfd_vma addend, - enum insert_option insert) +static enum elf_reloc_type_class +elf32_bfin_reloc_type_class (const Elf_Internal_Rela * rela) { - struct bfinfdpic_relocs_info entry; - - entry.symndx = -1; - entry.d.h = h; - entry.addend = addend; - - return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert); + switch ((int) ELF32_R_TYPE (rela->r_info)) + { + default: + return reloc_class_normal; + } } - -/* Obtain the address of the entry in HT associated with the SYMNDXth - local symbol of the input bfd ABFD, plus the addend, creating a new - entry if none existed. */ -inline static struct bfinfdpic_relocs_info * -bfinfdpic_relocs_info_for_local (struct htab *ht, - bfd *abfd, - long symndx, - bfd_vma addend, - enum insert_option insert) + +static bfd_reloc_status_type +bfin_final_link_relocate (Elf_Internal_Rela *rel, reloc_howto_type *howto, + bfd *input_bfd, asection *input_section, + bfd_byte *contents, bfd_vma address, + bfd_vma value, bfd_vma addend) { - struct bfinfdpic_relocs_info entry; - - entry.symndx = symndx; - entry.d.abfd = abfd; - entry.addend = addend; - - return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert); -} + int r_type = ELF32_R_TYPE (rel->r_info); -/* Merge fields set by check_relocs() of two entries that end up being - mapped to the same (presumably global) symbol. */ + if (r_type == R_BFIN_PCREL24 || r_type == R_BFIN_PCREL24_JUMP_L) + { + bfd_reloc_status_type r = bfd_reloc_ok; + bfd_vma x; -inline static void -bfinfdpic_pic_merge_early_relocs_info (struct bfinfdpic_relocs_info *e2, - struct bfinfdpic_relocs_info const *e1) -{ - e2->got17m4 |= e1->got17m4; - e2->gothilo |= e1->gothilo; - e2->fd |= e1->fd; - e2->fdgot17m4 |= e1->fdgot17m4; - e2->fdgothilo |= e1->fdgothilo; - e2->fdgoff17m4 |= e1->fdgoff17m4; - e2->fdgoffhilo |= e1->fdgoffhilo; - e2->gotoff |= e1->gotoff; - e2->call |= e1->call; - e2->sym |= e1->sym; -} + if (address > bfd_get_section_limit (input_bfd, input_section)) + return bfd_reloc_outofrange; -/* Every block of 65535 lazy PLT entries shares a single call to the - resolver, inserted in the 32768th lazy PLT entry (i.e., entry # - 32767, counting from 0). All other lazy PLT entries branch to it - in a single instruction. */ + value += addend; -#define LZPLT_RESOLVER_EXTRA 10 -#define LZPLT_NORMAL_SIZE 6 -#define LZPLT_ENTRIES 1362 + /* Perform usual pc-relative correction. */ + value -= input_section->output_section->vma + input_section->output_offset; + value -= address; -#define BFINFDPIC_LZPLT_BLOCK_SIZE ((bfd_vma) LZPLT_NORMAL_SIZE * LZPLT_ENTRIES + LZPLT_RESOLVER_EXTRA) -#define BFINFDPIC_LZPLT_RESOLV_LOC (LZPLT_NORMAL_SIZE * LZPLT_ENTRIES / 2) + /* We are getting reloc_entry->address 2 byte off from + the start of instruction. Assuming absolute postion + of the reloc data. But, following code had been written assuming + reloc address is starting at begining of instruction. + To compensate that I have increased the value of + relocation by 1 (effectively 2) and used the addr -2 instead of addr. */ -/* Add a dynamic relocation to the SRELOC section. */ + value += 2; + address -= 2; -inline static bfd_vma -_bfinfdpic_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset, - int reloc_type, long dynindx, bfd_vma addend, - struct bfinfdpic_relocs_info *entry) -{ - Elf_Internal_Rela outrel; - bfd_vma reloc_offset; + if ((value & 0xFF000000) != 0 + && (value & 0xFF000000) != 0xFF000000) + r = bfd_reloc_overflow; - outrel.r_offset = offset; - outrel.r_info = ELF32_R_INFO (dynindx, reloc_type); - outrel.r_addend = addend; + value >>= 1; - reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rel); - BFD_ASSERT (reloc_offset < sreloc->size); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, - sreloc->contents + reloc_offset); - sreloc->reloc_count++; + x = bfd_get_16 (input_bfd, contents + address); + x = (x & 0xff00) | ((value >> 16) & 0xff); + bfd_put_16 (input_bfd, x, contents + address); - /* If the entry's index is zero, this relocation was probably to a - linkonce section that got discarded. We reserved a dynamic - relocation, but it was for another entry than the one we got at - the time of emitting the relocation. Unfortunately there's no - simple way for us to catch this situation, since the relocation - is cleared right before calling relocate_section, at which point - we no longer know what the relocation used to point to. */ - if (entry->symndx) - { - BFD_ASSERT (entry->dynrelocs > 0); - entry->dynrelocs--; + x = bfd_get_16 (input_bfd, contents + address + 2); + x = value & 0xFFFF; + bfd_put_16 (input_bfd, x, contents + address + 2); + return r; } - return reloc_offset; -} + return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, + rel->r_offset, value, addend); -/* Add a fixup to the ROFIXUP section. */ +} -static bfd_vma -_bfinfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset, - struct bfinfdpic_relocs_info *entry) +static bfd_boolean +bfin_relocate_section (bfd * output_bfd, + struct bfd_link_info *info, + bfd * input_bfd, + asection * input_section, + bfd_byte * contents, + Elf_Internal_Rela * relocs, + Elf_Internal_Sym * local_syms, + asection ** local_sections) { - bfd_vma fixup_offset; + bfd *dynobj; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_vma *local_got_offsets; + asection *sgot; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + int i = 0; - if (rofixup->flags & SEC_EXCLUDE) - return -1; + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + local_got_offsets = elf_local_got_offsets (input_bfd); - fixup_offset = rofixup->reloc_count * 4; - if (rofixup->contents) - { - BFD_ASSERT (fixup_offset < rofixup->size); - bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset); - } - rofixup->reloc_count++; + sgot = NULL; - if (entry && entry->symndx) + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++, i++) { - /* See discussion about symndx == 0 in _bfinfdpic_add_dyn_reloc - above. */ - BFD_ASSERT (entry->fixups > 0); - entry->fixups--; - } - - return fixup_offset; -} - -/* Find the segment number in which OSEC, and output section, is - located. */ - -static unsigned -_bfinfdpic_osec_to_segment (bfd *output_bfd, asection *osec) -{ - Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec); - - return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1; -} - -inline static bfd_boolean -_bfinfdpic_osec_readonly_p (bfd *output_bfd, asection *osec) -{ - unsigned seg = _bfinfdpic_osec_to_segment (output_bfd, osec); - - return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W); -} - -/* Generate relocations for GOT entries, function descriptors, and - code for PLT and lazy PLT entries. */ - -inline static bfd_boolean -_bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry, - bfd *output_bfd, - struct bfd_link_info *info, - asection *sec, - Elf_Internal_Sym *sym, - bfd_vma addend) - -{ - bfd_vma fd_lazy_rel_offset = (bfd_vma)-1; - int dynindx = -1; - - if (entry->done) - return TRUE; - entry->done = 1; + int r_type; + reloc_howto_type *howto; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sec; + bfd_vma relocation = 0; + bfd_boolean unresolved_reloc; + bfd_reloc_status_type r; + bfd_vma address; - if (entry->got_entry || entry->fdgot_entry || entry->fd_entry) - { - /* If the symbol is dynamic, consider it for dynamic - relocations, otherwise decay to section + offset. */ - if (entry->symndx == -1 && entry->d.h->dynindx != -1) - dynindx = entry->d.h->dynindx; - else + r_type = ELF32_R_TYPE (rel->r_info); + if (r_type < 0 || r_type >= 243) { - if (sec->output_section - && ! bfd_is_abs_section (sec->output_section) - && ! bfd_is_und_section (sec->output_section)) - dynindx = elf_section_data (sec->output_section)->dynindx; - else - dynindx = 0; + bfd_set_error (bfd_error_bad_value); + return FALSE; } - } - /* Generate relocation for GOT entry pointing to the symbol. */ - if (entry->got_entry) - { - int idx = dynindx; - bfd_vma ad = addend; + if (r_type == R_BFIN_GNU_VTENTRY + || r_type == R_BFIN_GNU_VTINHERIT) + continue; - /* If the symbol is dynamic but binds locally, use - section+offset. */ - if (sec && (entry->symndx != -1 - || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) + howto = bfin_reloc_type_lookup (input_bfd, r_type); + if (howto == NULL) { - if (entry->symndx == -1) - ad += entry->d.h->root.u.def.value; - else - ad += sym->st_value; - ad += sec->output_offset; - if (sec->output_section && elf_section_data (sec->output_section)) - idx = elf_section_data (sec->output_section)->dynindx; - else - idx = 0; + bfd_set_error (bfd_error_bad_value); + return FALSE; } + r_symndx = ELF32_R_SYM (rel->r_info); - /* If we're linking an executable at a fixed address, we can - omit the dynamic relocation as long as the symbol is local to - this module. */ - if (info->executable && !info->pie - && (entry->symndx != -1 - || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) + h = NULL; + sym = NULL; + sec = NULL; + unresolved_reloc = FALSE; + + if (r_symndx < symtab_hdr->sh_info) { - if (sec) - ad += sec->output_section->vma; - if (entry->symndx != -1 - || entry->d.h->root.type != bfd_link_hash_undefweak) - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section (info), - bfinfdpic_got_section (info)->output_section - ->vma - + bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info) - + entry->got_entry, entry); + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); } else - _bfinfdpic_add_dyn_reloc (output_bfd, bfinfdpic_gotrel_section (info), - _bfd_elf_section_offset - (output_bfd, info, - bfinfdpic_got_section (info), - bfinfdpic_got_initial_offset (info) - + entry->got_entry) - + bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info)->output_offset, - R_byte4_data, idx, ad, entry); + { + bfd_boolean warned; - bfd_put_32 (output_bfd, ad, - bfinfdpic_got_section (info)->contents - + bfinfdpic_got_initial_offset (info) - + entry->got_entry); - } + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sec, relocation, + unresolved_reloc, warned); + } - /* Generate relocation for GOT entry pointing to a canonical - function descriptor. */ - if (entry->fdgot_entry) - { - int reloc, idx; - bfd_vma ad = 0; + if (sec != NULL && elf_discarded_section (sec)) + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, relend, howto, contents); - if (! (entry->symndx == -1 - && entry->d.h->root.type == bfd_link_hash_undefweak - && BFINFDPIC_SYM_LOCAL (info, entry->d.h))) + if (info->relocatable) + continue; + + address = rel->r_offset; + + /* Then, process normally. */ + switch (r_type) { - /* If the symbol is dynamic and there may be dynamic symbol - resolution because we are, or are linked with, a shared - library, emit a FUNCDESC relocation such that the dynamic - linker will allocate the function descriptor. If the - symbol needs a non-local function descriptor but binds - locally (e.g., its visibility is protected, emit a - dynamic relocation decayed to section+offset. */ - if (entry->symndx == -1 - && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h) - && BFINFDPIC_SYM_LOCAL (info, entry->d.h) - && !(info->executable && !info->pie)) - { - reloc = R_BFIN_FUNCDESC; - idx = elf_section_data (entry->d.h->root.u.def.section - ->output_section)->dynindx; - ad = entry->d.h->root.u.def.section->output_offset - + entry->d.h->root.u.def.value; - } - else if (entry->symndx == -1 - && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h)) + case R_BFIN_GNU_VTINHERIT: + case R_BFIN_GNU_VTENTRY: + return bfd_reloc_ok; + + case R_BFIN_GOT: + /* Relocation is to the address of the entry for this symbol + in the global offset table. */ + if (h != NULL + && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0) + goto do_default; + /* Fall through. */ + /* Relocation is the offset of the entry for this symbol in + the global offset table. */ + + { + bfd_vma off; + + if (dynobj == NULL) { - reloc = R_BFIN_FUNCDESC; - idx = dynindx; - ad = addend; - if (ad) + /* Create the .got section. */ + elf_hash_table (info)->dynobj = dynobj = output_bfd; + if (!_bfd_elf_create_got_section (dynobj, info)) return FALSE; } - else - { - /* Otherwise, we know we have a private function descriptor, - so reference it directly. */ - if (elf_hash_table (info)->dynamic_sections_created) - BFD_ASSERT (entry->privfd); - reloc = R_byte4_data; - idx = elf_section_data (bfinfdpic_got_section (info) - ->output_section)->dynindx; - ad = bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info) + entry->fd_entry; - } - /* If there is room for dynamic symbol resolution, emit the - dynamic relocation. However, if we're linking an - executable at a fixed location, we won't have emitted a - dynamic symbol entry for the got section, so idx will be - zero, which means we can and should compute the address - of the private descriptor ourselves. */ - if (info->executable && !info->pie - && (entry->symndx != -1 - || BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h))) - { - ad += bfinfdpic_got_section (info)->output_section->vma; - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section (info), - bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info) - ->output_offset - + bfinfdpic_got_initial_offset (info) - + entry->fdgot_entry, entry); - } - else - _bfinfdpic_add_dyn_reloc (output_bfd, - bfinfdpic_gotrel_section (info), - _bfd_elf_section_offset - (output_bfd, info, - bfinfdpic_got_section (info), - bfinfdpic_got_initial_offset (info) - + entry->fdgot_entry) - + bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info) - ->output_offset, - reloc, idx, ad, entry); - } + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + } - bfd_put_32 (output_bfd, ad, - bfinfdpic_got_section (info)->contents - + bfinfdpic_got_initial_offset (info) - + entry->fdgot_entry); - } + if (h != NULL) + { + bfd_boolean dyn; - /* Generate relocation to fill in a private function descriptor in - the GOT. */ - if (entry->fd_entry) - { - int idx = dynindx; - bfd_vma ad = addend; - bfd_vma ofst; - long lowword, highword; + off = h->got.offset; + BFD_ASSERT (off != (bfd_vma) - 1); + dyn = elf_hash_table (info)->dynamic_sections_created; - /* If the symbol is dynamic but binds locally, use - section+offset. */ - if (sec && (entry->symndx != -1 - || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (entry->symndx == -1) - ad += entry->d.h->root.u.def.value; - else - ad += sym->st_value; - ad += sec->output_offset; - if (sec->output_section && elf_section_data (sec->output_section)) - idx = elf_section_data (sec->output_section)->dynindx; - else - idx = 0; - } + if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + || (info->shared + && (info->symbolic + || h->dynindx == -1 + || h->forced_local) + && h->def_regular)) + { + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally, or the symbol was forced to be local + because of a version file.. We must initialize + this entry in the global offset table. Since + the offset must always be a multiple of 4, we + use the least significant bit to record whether + we have initialized it already. - /* If we're linking an executable at a fixed address, we can - omit the dynamic relocation as long as the symbol is local to - this module. */ - if (info->executable && !info->pie - && (entry->symndx != -1 || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (sec) - ad += sec->output_section->vma; - ofst = 0; - if (entry->symndx != -1 - || entry->d.h->root.type != bfd_link_hash_undefweak) - { - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section (info), - bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info) - ->output_offset - + bfinfdpic_got_initial_offset (info) - + entry->fd_entry, entry); - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section (info), - bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info) - ->output_offset - + bfinfdpic_got_initial_offset (info) - + entry->fd_entry + 4, entry); - } - } - else - { - ofst - = _bfinfdpic_add_dyn_reloc (output_bfd, - entry->lazyplt - ? bfinfdpic_pltrel_section (info) - : bfinfdpic_gotrel_section (info), - _bfd_elf_section_offset - (output_bfd, info, - bfinfdpic_got_section (info), - bfinfdpic_got_initial_offset (info) - + entry->fd_entry) - + bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info) - ->output_offset, - R_BFIN_FUNCDESC_VALUE, idx, ad, entry); - } + When doing a dynamic link, we create a .rela.got + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, + sgot->contents + off); + h->got.offset |= 1; + } + } + else + unresolved_reloc = FALSE; + } + else + { + BFD_ASSERT (local_got_offsets != NULL); + off = local_got_offsets[r_symndx]; + BFD_ASSERT (off != (bfd_vma) - 1); - /* If we've omitted the dynamic relocation, just emit the fixed - addresses of the symbol and of the local GOT base offset. */ - if (info->executable && !info->pie && sec && sec->output_section) - { - lowword = ad; - highword = bfinfdpic_got_section (info)->output_section->vma - + bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info); - } - else if (entry->lazyplt) - { - if (ad) - return FALSE; + /* The offset must always be a multiple of 4. We use + the least significant bit to record whether we have + already generated the necessary reloc. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, sgot->contents + off); - fd_lazy_rel_offset = ofst; + if (info->shared) + { + asection *s; + Elf_Internal_Rela outrel; + bfd_byte *loc; - /* A function descriptor used for lazy or local resolving is - initialized such that its high word contains the output - section index in which the PLT entries are located, and - the low word contains the address of the lazy PLT entry - entry point, that must be within the memory region - assigned to that section. */ - lowword = entry->lzplt_entry + 4 - + bfinfdpic_plt_section (info)->output_offset - + bfinfdpic_plt_section (info)->output_section->vma; - highword = _bfinfdpic_osec_to_segment - (output_bfd, bfinfdpic_plt_section (info)->output_section); - } - else - { - /* A function descriptor for a local function gets the index - of the section. For a non-local function, it's - disregarded. */ - lowword = ad; - if (entry->symndx == -1 && entry->d.h->dynindx != -1 - && entry->d.h->dynindx == idx) - highword = 0; - else - highword = _bfinfdpic_osec_to_segment - (output_bfd, sec->output_section); - } + s = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (s != NULL); - bfd_put_32 (output_bfd, lowword, - bfinfdpic_got_section (info)->contents - + bfinfdpic_got_initial_offset (info) - + entry->fd_entry); - bfd_put_32 (output_bfd, highword, - bfinfdpic_got_section (info)->contents - + bfinfdpic_got_initial_offset (info) - + entry->fd_entry + 4); - } + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + off); + outrel.r_info = + ELF32_R_INFO (0, R_BFIN_PCREL24); + outrel.r_addend = relocation; + loc = s->contents; + loc += + s->reloc_count++ * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + } - /* Generate code for the PLT entry. */ - if (entry->plt_entry != (bfd_vma) -1) - { - bfd_byte *plt_code = bfinfdpic_plt_section (info)->contents - + entry->plt_entry; + local_got_offsets[r_symndx] |= 1; + } + } - BFD_ASSERT (entry->fd_entry); + relocation = sgot->output_offset + off; + rel->r_addend = 0; + /* bfin : preg = [preg + 17bitdiv4offset] relocation is div by 4. */ + relocation /= 4; + } + goto do_default; - /* Figure out what kind of PLT entry we need, depending on the - location of the function descriptor within the GOT. */ - if (entry->fd_entry >= -(1 << (18 - 1)) - && entry->fd_entry + 4 < (1 << (18 - 1))) - { - /* P1 = [P3 + fd_entry]; P3 = [P3 + fd_entry + 4] */ - bfd_put_32 (output_bfd, - 0xe519 | ((entry->fd_entry << 14) & 0xFFFF0000), - plt_code); - bfd_put_32 (output_bfd, - 0xe51b | (((entry->fd_entry + 4) << 14) & 0xFFFF0000), - plt_code + 4); - plt_code += 8; + default: + do_default: + r = bfin_final_link_relocate (rel, howto, input_bfd, input_section, + contents, address, + relocation, rel->r_addend); + + break; } - else + + /* Dynamic relocs are not propagated for SEC_DEBUGGING sections + because such sections are not SEC_ALLOC and thus ld.so will + not process them. */ + if (unresolved_reloc + && !((input_section->flags & SEC_DEBUGGING) != 0 && h->def_dynamic)) { - /* P1.L = fd_entry; P1.H = fd_entry; - P3 = P3 + P1; - P1 = [P3]; - P3 = [P3 + 4]; */ - bfd_put_32 (output_bfd, - 0xe109 | (entry->fd_entry << 16), - plt_code); - bfd_put_32 (output_bfd, - 0xe149 | (entry->fd_entry & 0xFFFF0000), - plt_code + 4); - bfd_put_16 (output_bfd, 0x5ad9, plt_code + 8); - bfd_put_16 (output_bfd, 0x9159, plt_code + 10); - bfd_put_16 (output_bfd, 0xac5b, plt_code + 12); - plt_code += 14; + (*_bfd_error_handler) + (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"), + input_bfd, + input_section, (long) rel->r_offset, h->root.root.string); + return FALSE; } - /* JUMP (P1) */ - bfd_put_16 (output_bfd, 0x0051, plt_code); - } - - /* Generate code for the lazy PLT entry. */ - if (entry->lzplt_entry != (bfd_vma) -1) - { - bfd_byte *lzplt_code = bfinfdpic_plt_section (info)->contents - + entry->lzplt_entry; - bfd_vma resolverStub_addr; - bfd_put_32 (output_bfd, fd_lazy_rel_offset, lzplt_code); - lzplt_code += 4; + if (r != bfd_reloc_ok) + { + const char *name; - resolverStub_addr = entry->lzplt_entry / BFINFDPIC_LZPLT_BLOCK_SIZE - * BFINFDPIC_LZPLT_BLOCK_SIZE + BFINFDPIC_LZPLT_RESOLV_LOC; - if (resolverStub_addr >= bfinfdpic_plt_initial_offset (info)) - resolverStub_addr = bfinfdpic_plt_initial_offset (info) - LZPLT_NORMAL_SIZE - LZPLT_RESOLVER_EXTRA; + if (h != NULL) + name = h->root.root.string; + else + { + name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); + if (name == NULL) + return FALSE; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } - if (entry->lzplt_entry == resolverStub_addr) - { - /* This is a lazy PLT entry that includes a resolver call. - P2 = [P3]; - R3 = [P3 + 4]; - JUMP (P2); */ - bfd_put_32 (output_bfd, - 0xa05b915a, - lzplt_code); - bfd_put_16 (output_bfd, 0x0052, lzplt_code + 4); - } - else - { - /* JUMP.S resolverStub */ - bfd_put_16 (output_bfd, - 0x2000 - | (((resolverStub_addr - entry->lzplt_entry) - / 2) & (((bfd_vma)1 << 12) - 1)), - lzplt_code); + if (r == bfd_reloc_overflow) + { + if (!(info->callbacks->reloc_overflow + (info, (h ? &h->root : NULL), name, howto->name, + (bfd_vma) 0, input_bfd, input_section, rel->r_offset))) + return FALSE; + } + else + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): reloc against `%s': error %d"), + input_bfd, input_section, + (long) rel->r_offset, name, (int) r); + return FALSE; + } } } return TRUE; } +static asection * +bfin_gc_mark_hook (asection * sec, + struct bfd_link_info *info, + Elf_Internal_Rela * rel, + struct elf_link_hash_entry *h, + Elf_Internal_Sym * sym) +{ + if (h != NULL) + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_BFIN_GNU_VTINHERIT: + case R_BFIN_GNU_VTENTRY: + return NULL; + } -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table or procedure linkage - table. */ + return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); +} + +/* Update the got entry reference counts for the section being removed. */ static bfd_boolean -bfin_check_relocs (bfd * abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) +bfin_gc_sweep_hook (bfd * abfd, + struct bfd_link_info *info, + asection * sec, + const Elf_Internal_Rela * relocs) { - bfd *dynobj; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; bfd_signed_vma *local_got_refcounts; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; + const Elf_Internal_Rela *rel, *relend; + bfd *dynobj; asection *sgot; asection *srelgot; - asection *sreloc; - if (info->relocatable) - return TRUE; dynobj = elf_hash_table (info)->dynobj; + if (dynobj == NULL) + return TRUE; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); local_got_refcounts = elf_local_got_refcounts (abfd); - sgot = NULL; - srelgot = NULL; - sreloc = NULL; + sgot = bfd_get_section_by_name (dynobj, ".got"); + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) + relend = relocs + sec->reloc_count; + for (rel = relocs; rel < relend; rel++) { unsigned long r_symndx; struct elf_link_hash_entry *h; - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - switch (ELF32_R_TYPE (rel->r_info)) { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_BFIN_GNU_VTINHERIT: - if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) - return FALSE; - break; - - /* This relocation describes which C++ vtable entries - are actually used. Record for later use during GC. */ - case R_BFIN_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - case R_got: - if (h != NULL - && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0) - break; - /* Fall through. */ - - if (dynobj == NULL) - { - /* Create the .got section. */ - elf_hash_table (info)->dynobj = dynobj = abfd; - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; - } - - if (sgot == NULL) - { - sgot = bfd_get_section_by_name (dynobj, ".got"); - BFD_ASSERT (sgot != NULL); - } - - if (srelgot == NULL && (h != NULL || info->shared)) - { - srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); - if (srelgot == NULL) - { - flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED - | SEC_READONLY); - srelgot = bfd_make_section_with_flags (dynobj, ".rela.got", - flags); - if (srelgot == NULL - || !bfd_set_section_alignment (dynobj, srelgot, 2)) - return FALSE; - } - } - - if (h != NULL) + case R_BFIN_GOT: + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) { - if (h->got.refcount == 0) + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + if (h->got.refcount > 0) { - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1 && !h->forced_local) + --h->got.refcount; + if (h->got.refcount == 0) { - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; + /* We don't need the .got entry any more. */ + sgot->size -= 4; + srelgot->size -= sizeof (Elf32_External_Rela); } - - /* Allocate space in the .got section. */ - sgot->size += 4; - /* Allocate relocation space. */ - srelgot->size += sizeof (Elf32_External_Rela); } - h->got.refcount++; } - else + else if (local_got_refcounts != NULL) { - /* This is a global offset table entry for a local symbol. */ - if (local_got_refcounts == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= sizeof (bfd_signed_vma); - local_got_refcounts = ((bfd_signed_vma *) - bfd_zalloc (abfd, size)); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - } - if (local_got_refcounts[r_symndx] == 0) + if (local_got_refcounts[r_symndx] > 0) { - sgot->size += 4; - if (info->shared) + --local_got_refcounts[r_symndx]; + if (local_got_refcounts[r_symndx] == 0) { - /* If we are generating a shared object, we need to - output a R_68K_RELATIVE reloc so that the dynamic - linker can adjust this GOT entry. */ - srelgot->size += sizeof (Elf32_External_Rela); + /* We don't need the .got entry any more. */ + sgot->size -= 4; + if (info->shared) + srelgot->size -= sizeof (Elf32_External_Rela); } } - local_got_refcounts[r_symndx]++; } break; - default: break; } } - return TRUE; } - -static enum elf_reloc_type_class -elf32_bfin_reloc_type_class (const Elf_Internal_Rela * rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - default: - return reloc_class_normal; - } -} -static bfd_reloc_status_type -bfin_final_link_relocate (Elf_Internal_Rela *rel, reloc_howto_type *howto, - bfd *input_bfd, asection *input_section, - bfd_byte *contents, bfd_vma address, - bfd_vma value, bfd_vma addend) +extern const bfd_target bfd_elf32_bfinfdpic_vec; +#define IS_FDPIC(bfd) ((bfd)->xvec == &bfd_elf32_bfinfdpic_vec) + +/* An extension of the elf hash table data structure, + containing some additional Blackfin-specific data. */ +struct bfinfdpic_elf_link_hash_table { - int r_type = ELF32_R_TYPE (rel->r_info); + struct elf_link_hash_table elf; - if (r_type == R_pcrel24 || r_type == R_pcrel24_jump_l) - { - bfd_reloc_status_type r = bfd_reloc_ok; - bfd_vma x; + /* A pointer to the .got section. */ + asection *sgot; + /* A pointer to the .rel.got section. */ + asection *sgotrel; + /* A pointer to the .rofixup section. */ + asection *sgotfixup; + /* A pointer to the .plt section. */ + asection *splt; + /* A pointer to the .rel.plt section. */ + asection *spltrel; + /* GOT base offset. */ + bfd_vma got0; + /* Location of the first non-lazy PLT entry, i.e., the number of + bytes taken by lazy PLT entries. */ + bfd_vma plt0; + /* A hash table holding information about which symbols were + referenced with which PIC-related relocations. */ + struct htab *relocs_info; + /* Summary reloc information collected by + _bfinfdpic_count_got_plt_entries. */ + struct _bfinfdpic_dynamic_got_info *g; +}; - if (address > bfd_get_section_limit (input_bfd, input_section)) - return bfd_reloc_outofrange; +/* Get the Blackfin ELF linker hash table from a link_info structure. */ - value += addend; +#define bfinfdpic_hash_table(info) \ + (elf_hash_table_id ((struct elf_link_hash_table *) ((info)->hash)) \ + == BFIN_ELF_DATA ? ((struct bfinfdpic_elf_link_hash_table *) ((info)->hash)) : NULL) - /* Perform usual pc-relative correction. */ - value -= input_section->output_section->vma + input_section->output_offset; - value -= address; +#define bfinfdpic_got_section(info) \ + (bfinfdpic_hash_table (info)->sgot) +#define bfinfdpic_gotrel_section(info) \ + (bfinfdpic_hash_table (info)->sgotrel) +#define bfinfdpic_gotfixup_section(info) \ + (bfinfdpic_hash_table (info)->sgotfixup) +#define bfinfdpic_plt_section(info) \ + (bfinfdpic_hash_table (info)->splt) +#define bfinfdpic_pltrel_section(info) \ + (bfinfdpic_hash_table (info)->spltrel) +#define bfinfdpic_relocs_info(info) \ + (bfinfdpic_hash_table (info)->relocs_info) +#define bfinfdpic_got_initial_offset(info) \ + (bfinfdpic_hash_table (info)->got0) +#define bfinfdpic_plt_initial_offset(info) \ + (bfinfdpic_hash_table (info)->plt0) +#define bfinfdpic_dynamic_got_plt_info(info) \ + (bfinfdpic_hash_table (info)->g) - /* We are getting reloc_entry->address 2 byte off from - the start of instruction. Assuming absolute postion - of the reloc data. But, following code had been written assuming - reloc address is starting at begining of instruction. - To compensate that I have increased the value of - relocation by 1 (effectively 2) and used the addr -2 instead of addr. */ +/* The name of the dynamic interpreter. This is put in the .interp + section. */ - value += 2; - address -= 2; +#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" - if ((value & 0xFF000000) != 0 - && (value & 0xFF000000) != 0xFF000000) - r = bfd_reloc_overflow; +#define DEFAULT_STACK_SIZE 0x20000 - value >>= 1; +/* This structure is used to collect the number of entries present in + each addressable range of the got. */ +struct _bfinfdpic_dynamic_got_info +{ + /* Several bits of information about the current link. */ + struct bfd_link_info *info; + /* Total size needed for GOT entries within the 18- or 32-bit + ranges. */ + bfd_vma got17m4, gothilo; + /* Total size needed for function descriptor entries within the 18- + or 32-bit ranges. */ + bfd_vma fd17m4, fdhilo; + /* Total size needed function descriptor entries referenced in PLT + entries, that would be profitable to place in offsets close to + the PIC register. */ + bfd_vma fdplt; + /* Total size needed by lazy PLT entries. */ + bfd_vma lzplt; + /* Number of relocations carried over from input object files. */ + unsigned long relocs; + /* Number of fixups introduced by relocations in input object files. */ + unsigned long fixups; +}; - x = bfd_get_16 (input_bfd, contents + address); - x = (x & 0xff00) | ((value >> 16) & 0xff); - bfd_put_16 (input_bfd, x, contents + address); +/* Create a Blackfin ELF linker hash table. */ - x = bfd_get_16 (input_bfd, contents + address + 2); - x = value & 0xFFFF; - bfd_put_16 (input_bfd, x, contents + address + 2); - return r; - } +static struct bfd_link_hash_table * +bfinfdpic_elf_link_hash_table_create (bfd *abfd) +{ + struct bfinfdpic_elf_link_hash_table *ret; + bfd_size_type amt = sizeof (struct bfinfdpic_elf_link_hash_table); - return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, - rel->r_offset, value, addend); + ret = bfd_zalloc (abfd, amt); + if (ret == NULL) + return NULL; + + if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, + _bfd_elf_link_hash_newfunc, + sizeof (struct elf_link_hash_entry), + BFIN_ELF_DATA)) + { + free (ret); + return NULL; + } + return &ret->elf.root; } - -/* Relocate an Blackfin ELF section. +/* Decide whether a reference to a symbol can be resolved locally or + not. If the symbol is protected, we want the local address, but + its function descriptor must be assigned by the dynamic linker. */ +#define BFINFDPIC_SYM_LOCAL(INFO, H) \ + (_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \ + || ! elf_hash_table (INFO)->dynamic_sections_created) +#define BFINFDPIC_FUNCDESC_LOCAL(INFO, H) \ + ((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created) - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. +/* This structure collects information on what kind of GOT, PLT or + function descriptors are required by relocations that reference a + certain symbol. */ +struct bfinfdpic_relocs_info +{ + /* The index of the symbol, as stored in the relocation r_info, if + we have a local symbol; -1 otherwise. */ + long symndx; + union + { + /* The input bfd in which the symbol is defined, if it's a local + symbol. */ + bfd *abfd; + /* If symndx == -1, the hash table entry corresponding to a global + symbol (even if it turns out to bind locally, in which case it + should ideally be replaced with section's symndx + addend). */ + struct elf_link_hash_entry *h; + } d; + /* The addend of the relocation that references the symbol. */ + bfd_vma addend; - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. + /* The fields above are used to identify an entry. The fields below + contain information on how an entry is used and, later on, which + locations it was assigned. */ + /* The following 2 fields record whether the symbol+addend above was + ever referenced with a GOT relocation. The 17M4 suffix indicates a + GOT17M4 relocation; hilo is used for GOTLO/GOTHI pairs. */ + unsigned got17m4; + unsigned gothilo; + /* Whether a FUNCDESC relocation references symbol+addend. */ + unsigned fd; + /* Whether a FUNCDESC_GOT relocation references symbol+addend. */ + unsigned fdgot17m4; + unsigned fdgothilo; + /* Whether a FUNCDESC_GOTOFF relocation references symbol+addend. */ + unsigned fdgoff17m4; + unsigned fdgoffhilo; + /* Whether symbol+addend is referenced with GOTOFF17M4, GOTOFFLO or + GOTOFFHI relocations. The addend doesn't really matter, since we + envision that this will only be used to check whether the symbol + is mapped to the same segment as the got. */ + unsigned gotoff; + /* Whether symbol+addend is referenced by a LABEL24 relocation. */ + unsigned call; + /* Whether symbol+addend is referenced by a 32 or FUNCDESC_VALUE + relocation. */ + unsigned sym; + /* Whether we need a PLT entry for a symbol. Should be implied by + something like: + (call && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h)) */ + unsigned plt:1; + /* Whether a function descriptor should be created in this link unit + for symbol+addend. Should be implied by something like: + (plt || fdgotoff17m4 || fdgotofflohi + || ((fd || fdgot17m4 || fdgothilo) + && (symndx != -1 || BFINFDPIC_FUNCDESC_LOCAL (info, d.h)))) */ + unsigned privfd:1; + /* Whether a lazy PLT entry is needed for this symbol+addend. + Should be implied by something like: + (privfd && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h) + && ! (info->flags & DF_BIND_NOW)) */ + unsigned lazyplt:1; + /* Whether we've already emitted GOT relocations and PLT entries as + needed for this symbol. */ + unsigned done:1; - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. + /* The number of R_BFIN_BYTE4_DATA, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE + relocations referencing the symbol. */ + unsigned relocs32, relocsfd, relocsfdv; - This function does not have to worry about setting the reloc - address or the reloc symbol index. + /* The number of .rofixups entries and dynamic relocations allocated + for this symbol, minus any that might have already been used. */ + unsigned fixups, dynrelocs; - LOCAL_SYMS is a pointer to the swapped in local symbols. + /* The offsets of the GOT entries assigned to symbol+addend, to the + function descriptor's address, and to a function descriptor, + respectively. Should be zero if unassigned. The offsets are + counted from the value that will be assigned to the PIC register, + not from the beginning of the .got section. */ + bfd_signed_vma got_entry, fdgot_entry, fd_entry; + /* The offsets of the PLT entries assigned to symbol+addend, + non-lazy and lazy, respectively. If unassigned, should be + (bfd_vma)-1. */ + bfd_vma plt_entry, lzplt_entry; +}; - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. +/* Compute a hash with the key fields of an bfinfdpic_relocs_info entry. */ +static hashval_t +bfinfdpic_relocs_info_hash (const void *entry_) +{ + const struct bfinfdpic_relocs_info *entry = entry_; - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). + return (entry->symndx == -1 + ? (long) entry->d.h->root.root.hash + : entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend; +} - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ +/* Test whether the key fields of two bfinfdpic_relocs_info entries are + identical. */ +static int +bfinfdpic_relocs_info_eq (const void *entry1, const void *entry2) +{ + const struct bfinfdpic_relocs_info *e1 = entry1; + const struct bfinfdpic_relocs_info *e2 = entry2; -static bfd_boolean -bfinfdpic_relocate_section (bfd * output_bfd, - struct bfd_link_info *info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) + return e1->symndx == e2->symndx && e1->addend == e2->addend + && (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd); +} + +/* Find or create an entry in a hash table HT that matches the key + fields of the given ENTRY. If it's not found, memory for a new + entry is allocated in ABFD's obstack. */ +static struct bfinfdpic_relocs_info * +bfinfdpic_relocs_info_find (struct htab *ht, + bfd *abfd, + const struct bfinfdpic_relocs_info *entry, + enum insert_option insert) { - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - unsigned isec_segment, got_segment, plt_segment, - check_segment[2]; - int silence_segment_error = !(info->shared || info->pie); + struct bfinfdpic_relocs_info **loc; - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; + if (!ht) + return NULL; - isec_segment = _bfinfdpic_osec_to_segment (output_bfd, - input_section->output_section); - if (IS_FDPIC (output_bfd) && bfinfdpic_got_section (info)) - got_segment = _bfinfdpic_osec_to_segment (output_bfd, - bfinfdpic_got_section (info) - ->output_section); - else - got_segment = -1; - if (IS_FDPIC (output_bfd) && elf_hash_table (info)->dynamic_sections_created) - plt_segment = _bfinfdpic_osec_to_segment (output_bfd, - bfinfdpic_plt_section (info) - ->output_section); - else - plt_segment = -1; + loc = (struct bfinfdpic_relocs_info **) htab_find_slot (ht, entry, insert); - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - int r_type; - asection *osec; - struct bfinfdpic_relocs_info *picrel; - bfd_vma orig_addend = rel->r_addend; - - r_type = ELF32_R_TYPE (rel->r_info); + if (! loc) + return NULL; - if (r_type == R_BFIN_GNU_VTINHERIT - || r_type == R_BFIN_GNU_VTENTRY) - continue; + if (*loc) + return *loc; - r_symndx = ELF32_R_SYM (rel->r_info); - howto = bfin_reloc_type_lookup (input_bfd, r_type); - if (howto == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } + *loc = bfd_zalloc (abfd, sizeof (**loc)); - h = NULL; - sym = NULL; - sec = NULL; + if (! *loc) + return *loc; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - osec = sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + (*loc)->symndx = entry->symndx; + (*loc)->d = entry->d; + (*loc)->addend = entry->addend; + (*loc)->plt_entry = (bfd_vma)-1; + (*loc)->lzplt_entry = (bfd_vma)-1; - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean warned; - bfd_boolean unresolved_reloc; + return *loc; +} - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned); - osec = sec; - } +/* Obtain the address of the entry in HT associated with H's symbol + + addend, creating a new entry if none existed. ABFD is only used + for memory allocation purposes. */ +inline static struct bfinfdpic_relocs_info * +bfinfdpic_relocs_info_for_global (struct htab *ht, + bfd *abfd, + struct elf_link_hash_entry *h, + bfd_vma addend, + enum insert_option insert) +{ + struct bfinfdpic_relocs_info entry; - if (sec != NULL && elf_discarded_section (sec)) - { - /* For relocs against symbols from removed linkonce sections, - or sections discarded by a linker script, we just want the - section contents zeroed. Avoid any special processing. */ - _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); - rel->r_info = 0; - rel->r_addend = 0; - continue; - } + entry.symndx = -1; + entry.d.h = h; + entry.addend = addend; - if (info->relocatable) - continue; + return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert); +} - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && !BFINFDPIC_SYM_LOCAL (info, h)) - { - osec = sec = NULL; - relocation = 0; - } +/* Obtain the address of the entry in HT associated with the SYMNDXth + local symbol of the input bfd ABFD, plus the addend, creating a new + entry if none existed. */ +inline static struct bfinfdpic_relocs_info * +bfinfdpic_relocs_info_for_local (struct htab *ht, + bfd *abfd, + long symndx, + bfd_vma addend, + enum insert_option insert) +{ + struct bfinfdpic_relocs_info entry; - switch (r_type) - { - case R_pcrel24: - case R_pcrel24_jump_l: - case R_byte4_data: - if (! IS_FDPIC (output_bfd)) - goto non_fdpic; + entry.symndx = symndx; + entry.d.abfd = abfd; + entry.addend = addend; - case R_BFIN_GOT17M4: - case R_BFIN_GOTHI: - case R_BFIN_GOTLO: - case R_BFIN_FUNCDESC_GOT17M4: - case R_BFIN_FUNCDESC_GOTHI: - case R_BFIN_FUNCDESC_GOTLO: - case R_BFIN_GOTOFF17M4: - case R_BFIN_GOTOFFHI: - case R_BFIN_GOTOFFLO: - case R_BFIN_FUNCDESC_GOTOFF17M4: - case R_BFIN_FUNCDESC_GOTOFFHI: - case R_BFIN_FUNCDESC_GOTOFFLO: - case R_BFIN_FUNCDESC: - case R_BFIN_FUNCDESC_VALUE: - if (h != NULL) - picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info - (info), input_bfd, h, - orig_addend, INSERT); - else - /* In order to find the entry we created before, we must - use the original addend, not the one that may have been - modified by _bfd_elf_rela_local_sym(). */ - picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info - (info), input_bfd, r_symndx, - orig_addend, INSERT); - if (! picrel) - return FALSE; + return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert); +} - if (!_bfinfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info, - osec, sym, - rel->r_addend)) - { - (*_bfd_error_handler) - (_("%B: relocation at `%A+0x%x' references symbol `%s' with nonzero addend"), - input_bfd, input_section, rel->r_offset, name); - return FALSE; +/* Merge fields set by check_relocs() of two entries that end up being + mapped to the same (presumably global) symbol. */ - } +inline static void +bfinfdpic_pic_merge_early_relocs_info (struct bfinfdpic_relocs_info *e2, + struct bfinfdpic_relocs_info const *e1) +{ + e2->got17m4 |= e1->got17m4; + e2->gothilo |= e1->gothilo; + e2->fd |= e1->fd; + e2->fdgot17m4 |= e1->fdgot17m4; + e2->fdgothilo |= e1->fdgothilo; + e2->fdgoff17m4 |= e1->fdgoff17m4; + e2->fdgoffhilo |= e1->fdgoffhilo; + e2->gotoff |= e1->gotoff; + e2->call |= e1->call; + e2->sym |= e1->sym; +} - break; +/* Every block of 65535 lazy PLT entries shares a single call to the + resolver, inserted in the 32768th lazy PLT entry (i.e., entry # + 32767, counting from 0). All other lazy PLT entries branch to it + in a single instruction. */ - default: - non_fdpic: - picrel = NULL; - if (h && ! BFINFDPIC_SYM_LOCAL (info, h)) - { - info->callbacks->warning - (info, _("relocation references symbol not defined in the module"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - break; - } +#define LZPLT_RESOLVER_EXTRA 10 +#define LZPLT_NORMAL_SIZE 6 +#define LZPLT_ENTRIES 1362 - switch (r_type) - { - case R_pcrel24: - case R_pcrel24_jump_l: - check_segment[0] = isec_segment; - if (! IS_FDPIC (output_bfd)) - check_segment[1] = isec_segment; - else if (picrel->plt) - { - relocation = bfinfdpic_plt_section (info)->output_section->vma - + bfinfdpic_plt_section (info)->output_offset - + picrel->plt_entry; - check_segment[1] = plt_segment; - } - /* We don't want to warn on calls to undefined weak symbols, - as calls to them must be protected by non-NULL tests - anyway, and unprotected calls would invoke undefined - behavior. */ - else if (picrel->symndx == -1 - && picrel->d.h->root.type == bfd_link_hash_undefweak) - check_segment[1] = check_segment[0]; - else - check_segment[1] = sec - ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section) - : (unsigned)-1; - break; +#define BFINFDPIC_LZPLT_BLOCK_SIZE ((bfd_vma) LZPLT_NORMAL_SIZE * LZPLT_ENTRIES + LZPLT_RESOLVER_EXTRA) +#define BFINFDPIC_LZPLT_RESOLV_LOC (LZPLT_NORMAL_SIZE * LZPLT_ENTRIES / 2) - case R_BFIN_GOT17M4: - case R_BFIN_GOTHI: - case R_BFIN_GOTLO: - relocation = picrel->got_entry; - check_segment[0] = check_segment[1] = got_segment; - break; +/* Add a dynamic relocation to the SRELOC section. */ - case R_BFIN_FUNCDESC_GOT17M4: - case R_BFIN_FUNCDESC_GOTHI: - case R_BFIN_FUNCDESC_GOTLO: - relocation = picrel->fdgot_entry; - check_segment[0] = check_segment[1] = got_segment; - break; +inline static bfd_vma +_bfinfdpic_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset, + int reloc_type, long dynindx, bfd_vma addend, + struct bfinfdpic_relocs_info *entry) +{ + Elf_Internal_Rela outrel; + bfd_vma reloc_offset; - case R_BFIN_GOTOFFHI: - case R_BFIN_GOTOFF17M4: - case R_BFIN_GOTOFFLO: - relocation -= bfinfdpic_got_section (info)->output_section->vma - + bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info); - check_segment[0] = got_segment; - check_segment[1] = sec - ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section) - : (unsigned)-1; - break; + outrel.r_offset = offset; + outrel.r_info = ELF32_R_INFO (dynindx, reloc_type); + outrel.r_addend = addend; - case R_BFIN_FUNCDESC_GOTOFF17M4: - case R_BFIN_FUNCDESC_GOTOFFHI: - case R_BFIN_FUNCDESC_GOTOFFLO: - relocation = picrel->fd_entry; - check_segment[0] = check_segment[1] = got_segment; - break; + reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rel); + BFD_ASSERT (reloc_offset < sreloc->size); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, + sreloc->contents + reloc_offset); + sreloc->reloc_count++; - case R_BFIN_FUNCDESC: - { - int dynindx; - bfd_vma addend = rel->r_addend; + /* If the entry's index is zero, this relocation was probably to a + linkonce section that got discarded. We reserved a dynamic + relocation, but it was for another entry than the one we got at + the time of emitting the relocation. Unfortunately there's no + simple way for us to catch this situation, since the relocation + is cleared right before calling relocate_section, at which point + we no longer know what the relocation used to point to. */ + if (entry->symndx) + { + BFD_ASSERT (entry->dynrelocs > 0); + entry->dynrelocs--; + } - if (! (h && h->root.type == bfd_link_hash_undefweak - && BFINFDPIC_SYM_LOCAL (info, h))) - { - /* If the symbol is dynamic and there may be dynamic - symbol resolution because we are or are linked with a - shared library, emit a FUNCDESC relocation such that - the dynamic linker will allocate the function - descriptor. If the symbol needs a non-local function - descriptor but binds locally (e.g., its visibility is - protected, emit a dynamic relocation decayed to - section+offset. */ - if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h) - && BFINFDPIC_SYM_LOCAL (info, h) - && !(info->executable && !info->pie)) - { - dynindx = elf_section_data (h->root.u.def.section - ->output_section)->dynindx; - addend += h->root.u.def.section->output_offset - + h->root.u.def.value; - } - else if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h)) - { - if (addend) - { - info->callbacks->warning - (info, _("R_BFIN_FUNCDESC references dynamic symbol with nonzero addend"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - dynindx = h->dynindx; - } - else - { - /* Otherwise, we know we have a private function - descriptor, so reference it directly. */ - BFD_ASSERT (picrel->privfd); - r_type = R_byte4_data; - dynindx = elf_section_data (bfinfdpic_got_section (info) - ->output_section)->dynindx; - addend = bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info) - + picrel->fd_entry; - } + return reloc_offset; +} - /* If there is room for dynamic symbol resolution, emit - the dynamic relocation. However, if we're linking an - executable at a fixed location, we won't have emitted a - dynamic symbol entry for the got section, so idx will - be zero, which means we can and should compute the - address of the private descriptor ourselves. */ - if (info->executable && !info->pie - && (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h))) - { - addend += bfinfdpic_got_section (info)->output_section->vma; - if ((bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - if (_bfinfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->warning - (info, - _("cannot emit fixups in read-only section"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section - (info), - _bfd_elf_section_offset - (output_bfd, info, - input_section, rel->r_offset) - + input_section - ->output_section->vma - + input_section->output_offset, - picrel); - } - } - else if ((bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - bfd_vma offset; +/* Add a fixup to the ROFIXUP section. */ - if (_bfinfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->warning - (info, - _("cannot emit dynamic relocations in read-only section"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - offset = _bfd_elf_section_offset (output_bfd, info, - input_section, rel->r_offset); - /* Only output a reloc for a not deleted entry. */ - if (offset >= (bfd_vma) -2) - _bfinfdpic_add_dyn_reloc (output_bfd, - bfinfdpic_gotrel_section (info), - 0, - R_unused0, - dynindx, addend, picrel); - else - _bfinfdpic_add_dyn_reloc (output_bfd, - bfinfdpic_gotrel_section (info), - offset + input_section - ->output_section->vma - + input_section->output_offset, - r_type, - dynindx, addend, picrel); - } - else - addend += bfinfdpic_got_section (info)->output_section->vma; - } +static bfd_vma +_bfinfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset, + struct bfinfdpic_relocs_info *entry) +{ + bfd_vma fixup_offset; - /* We want the addend in-place because dynamic - relocations are REL. Setting relocation to it should - arrange for it to be installed. */ - relocation = addend - rel->r_addend; - } - check_segment[0] = check_segment[1] = got_segment; - break; + if (rofixup->flags & SEC_EXCLUDE) + return -1; - case R_byte4_data: - if (! IS_FDPIC (output_bfd)) + fixup_offset = rofixup->reloc_count * 4; + if (rofixup->contents) + { + BFD_ASSERT (fixup_offset < rofixup->size); + bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset); + } + rofixup->reloc_count++; + + if (entry && entry->symndx) + { + /* See discussion about symndx == 0 in _bfinfdpic_add_dyn_reloc + above. */ + BFD_ASSERT (entry->fixups > 0); + entry->fixups--; + } + + return fixup_offset; +} + +/* Find the segment number in which OSEC, and output section, is + located. */ + +static unsigned +_bfinfdpic_osec_to_segment (bfd *output_bfd, asection *osec) +{ + Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec); + + return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1; +} + +inline static bfd_boolean +_bfinfdpic_osec_readonly_p (bfd *output_bfd, asection *osec) +{ + unsigned seg = _bfinfdpic_osec_to_segment (output_bfd, osec); + + return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W); +} + +/* Generate relocations for GOT entries, function descriptors, and + code for PLT and lazy PLT entries. */ + +inline static bfd_boolean +_bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry, + bfd *output_bfd, + struct bfd_link_info *info, + asection *sec, + Elf_Internal_Sym *sym, + bfd_vma addend) + +{ + bfd_vma fd_lazy_rel_offset = (bfd_vma)-1; + int dynindx = -1; + + if (entry->done) + return TRUE; + entry->done = 1; + + if (entry->got_entry || entry->fdgot_entry || entry->fd_entry) + { + /* If the symbol is dynamic, consider it for dynamic + relocations, otherwise decay to section + offset. */ + if (entry->symndx == -1 && entry->d.h->dynindx != -1) + dynindx = entry->d.h->dynindx; + else + { + if (sec + && sec->output_section + && ! bfd_is_abs_section (sec->output_section) + && ! bfd_is_und_section (sec->output_section)) + dynindx = elf_section_data (sec->output_section)->dynindx; + else + dynindx = 0; + } + } + + /* Generate relocation for GOT entry pointing to the symbol. */ + if (entry->got_entry) + { + int idx = dynindx; + bfd_vma ad = addend; + + /* If the symbol is dynamic but binds locally, use + section+offset. */ + if (sec && (entry->symndx != -1 + || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) + { + if (entry->symndx == -1) + ad += entry->d.h->root.u.def.value; + else + ad += sym->st_value; + ad += sec->output_offset; + if (sec->output_section && elf_section_data (sec->output_section)) + idx = elf_section_data (sec->output_section)->dynindx; + else + idx = 0; + } + + /* If we're linking an executable at a fixed address, we can + omit the dynamic relocation as long as the symbol is local to + this module. */ + if (info->executable && !info->pie + && (entry->symndx != -1 + || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) + { + if (sec) + ad += sec->output_section->vma; + if (entry->symndx != -1 + || entry->d.h->root.type != bfd_link_hash_undefweak) + _bfinfdpic_add_rofixup (output_bfd, + bfinfdpic_gotfixup_section (info), + bfinfdpic_got_section (info)->output_section + ->vma + + bfinfdpic_got_section (info)->output_offset + + bfinfdpic_got_initial_offset (info) + + entry->got_entry, entry); + } + else + _bfinfdpic_add_dyn_reloc (output_bfd, bfinfdpic_gotrel_section (info), + _bfd_elf_section_offset + (output_bfd, info, + bfinfdpic_got_section (info), + bfinfdpic_got_initial_offset (info) + + entry->got_entry) + + bfinfdpic_got_section (info) + ->output_section->vma + + bfinfdpic_got_section (info)->output_offset, + R_BFIN_BYTE4_DATA, idx, ad, entry); + + bfd_put_32 (output_bfd, ad, + bfinfdpic_got_section (info)->contents + + bfinfdpic_got_initial_offset (info) + + entry->got_entry); + } + + /* Generate relocation for GOT entry pointing to a canonical + function descriptor. */ + if (entry->fdgot_entry) + { + int reloc, idx; + bfd_vma ad = 0; + + if (! (entry->symndx == -1 + && entry->d.h->root.type == bfd_link_hash_undefweak + && BFINFDPIC_SYM_LOCAL (info, entry->d.h))) + { + /* If the symbol is dynamic and there may be dynamic symbol + resolution because we are, or are linked with, a shared + library, emit a FUNCDESC relocation such that the dynamic + linker will allocate the function descriptor. If the + symbol needs a non-local function descriptor but binds + locally (e.g., its visibility is protected, emit a + dynamic relocation decayed to section+offset. */ + if (entry->symndx == -1 + && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h) + && BFINFDPIC_SYM_LOCAL (info, entry->d.h) + && !(info->executable && !info->pie)) { - check_segment[0] = check_segment[1] = -1; - break; + reloc = R_BFIN_FUNCDESC; + idx = elf_section_data (entry->d.h->root.u.def.section + ->output_section)->dynindx; + ad = entry->d.h->root.u.def.section->output_offset + + entry->d.h->root.u.def.value; + } + else if (entry->symndx == -1 + && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h)) + { + reloc = R_BFIN_FUNCDESC; + idx = dynindx; + ad = addend; + if (ad) + return FALSE; + } + else + { + /* Otherwise, we know we have a private function descriptor, + so reference it directly. */ + if (elf_hash_table (info)->dynamic_sections_created) + BFD_ASSERT (entry->privfd); + reloc = R_BFIN_BYTE4_DATA; + idx = elf_section_data (bfinfdpic_got_section (info) + ->output_section)->dynindx; + ad = bfinfdpic_got_section (info)->output_offset + + bfinfdpic_got_initial_offset (info) + entry->fd_entry; } - /* Fall through. */ - case R_BFIN_FUNCDESC_VALUE: - { - int dynindx; - bfd_vma addend = rel->r_addend; - bfd_vma offset; - offset = _bfd_elf_section_offset (output_bfd, info, - input_section, rel->r_offset); - /* If the symbol is dynamic but binds locally, use - section+offset. */ - if (h && ! BFINFDPIC_SYM_LOCAL (info, h)) - { - if (addend && r_type == R_BFIN_FUNCDESC_VALUE) - { - info->callbacks->warning - (info, _("R_BFIN_FUNCDESC_VALUE references dynamic symbol with nonzero addend"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - dynindx = h->dynindx; - } - else - { - if (h) - addend += h->root.u.def.value; - else - addend += sym->st_value; - if (osec) - addend += osec->output_offset; - if (osec && osec->output_section - && ! bfd_is_abs_section (osec->output_section) - && ! bfd_is_und_section (osec->output_section)) - dynindx = elf_section_data (osec->output_section)->dynindx; - else - dynindx = 0; - } + /* If there is room for dynamic symbol resolution, emit the + dynamic relocation. However, if we're linking an + executable at a fixed location, we won't have emitted a + dynamic symbol entry for the got section, so idx will be + zero, which means we can and should compute the address + of the private descriptor ourselves. */ + if (info->executable && !info->pie + && (entry->symndx != -1 + || BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h))) + { + ad += bfinfdpic_got_section (info)->output_section->vma; + _bfinfdpic_add_rofixup (output_bfd, + bfinfdpic_gotfixup_section (info), + bfinfdpic_got_section (info) + ->output_section->vma + + bfinfdpic_got_section (info) + ->output_offset + + bfinfdpic_got_initial_offset (info) + + entry->fdgot_entry, entry); + } + else + _bfinfdpic_add_dyn_reloc (output_bfd, + bfinfdpic_gotrel_section (info), + _bfd_elf_section_offset + (output_bfd, info, + bfinfdpic_got_section (info), + bfinfdpic_got_initial_offset (info) + + entry->fdgot_entry) + + bfinfdpic_got_section (info) + ->output_section->vma + + bfinfdpic_got_section (info) + ->output_offset, + reloc, idx, ad, entry); + } - /* If we're linking an executable at a fixed address, we - can omit the dynamic relocation as long as the symbol - is defined in the current link unit (which is implied - by its output section not being NULL). */ - if (info->executable && !info->pie - && (!h || BFINFDPIC_SYM_LOCAL (info, h))) - { - if (osec) - addend += osec->output_section->vma; - if (IS_FDPIC (input_bfd) - && (bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - if (_bfinfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->warning - (info, - _("cannot emit fixups in read-only section"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - if (!h || h->root.type != bfd_link_hash_undefweak) - { - /* Only output a reloc for a not deleted entry. */ - if (offset >= (bfd_vma)-2) - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section - (info), -1, picrel); - else - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section - (info), - offset + input_section - ->output_section->vma - + input_section->output_offset, - picrel); + bfd_put_32 (output_bfd, ad, + bfinfdpic_got_section (info)->contents + + bfinfdpic_got_initial_offset (info) + + entry->fdgot_entry); + } - if (r_type == R_BFIN_FUNCDESC_VALUE) - { - if (offset >= (bfd_vma)-2) - _bfinfdpic_add_rofixup - (output_bfd, - bfinfdpic_gotfixup_section (info), - -1, picrel); - else - _bfinfdpic_add_rofixup - (output_bfd, - bfinfdpic_gotfixup_section (info), - offset + input_section->output_section->vma - + input_section->output_offset + 4, picrel); - } - } - } - } - else - { - if ((bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - if (_bfinfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->warning - (info, - _("cannot emit dynamic relocations in read-only section"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - /* Only output a reloc for a not deleted entry. */ - if (offset >= (bfd_vma)-2) - _bfinfdpic_add_dyn_reloc (output_bfd, - bfinfdpic_gotrel_section (info), - 0, R_unused0, dynindx, addend, picrel); - else - _bfinfdpic_add_dyn_reloc (output_bfd, - bfinfdpic_gotrel_section (info), - offset - + input_section - ->output_section->vma - + input_section->output_offset, - r_type, dynindx, addend, picrel); - } - else if (osec) - addend += osec->output_section->vma; - /* We want the addend in-place because dynamic - relocations are REL. Setting relocation to it - should arrange for it to be installed. */ - relocation = addend - rel->r_addend; - } + /* Generate relocation to fill in a private function descriptor in + the GOT. */ + if (entry->fd_entry) + { + int idx = dynindx; + bfd_vma ad = addend; + bfd_vma ofst; + long lowword, highword; - if (r_type == R_BFIN_FUNCDESC_VALUE && offset < (bfd_vma)-2) - { - /* If we've omitted the dynamic relocation, just emit - the fixed addresses of the symbol and of the local - GOT base offset. */ - if (info->executable && !info->pie - && (!h || BFINFDPIC_SYM_LOCAL (info, h))) - bfd_put_32 (output_bfd, - bfinfdpic_got_section (info)->output_section->vma - + bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info), - contents + rel->r_offset + 4); - else - /* A function descriptor used for lazy or local - resolving is initialized such that its high word - contains the output section index in which the - PLT entries are located, and the low word - contains the offset of the lazy PLT entry entry - point into that section. */ - bfd_put_32 (output_bfd, - h && ! BFINFDPIC_SYM_LOCAL (info, h) - ? 0 - : _bfinfdpic_osec_to_segment (output_bfd, - sec - ->output_section), - contents + rel->r_offset + 4); - } - } - check_segment[0] = check_segment[1] = got_segment; - break; + /* If the symbol is dynamic but binds locally, use + section+offset. */ + if (sec && (entry->symndx != -1 + || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) + { + if (entry->symndx == -1) + ad += entry->d.h->root.u.def.value; + else + ad += sym->st_value; + ad += sec->output_offset; + if (sec->output_section && elf_section_data (sec->output_section)) + idx = elf_section_data (sec->output_section)->dynindx; + else + idx = 0; + } - default: - check_segment[0] = isec_segment; - check_segment[1] = sec - ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section) - : (unsigned)-1; - break; + /* If we're linking an executable at a fixed address, we can + omit the dynamic relocation as long as the symbol is local to + this module. */ + if (info->executable && !info->pie + && (entry->symndx != -1 || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) + { + if (sec) + ad += sec->output_section->vma; + ofst = 0; + if (entry->symndx != -1 + || entry->d.h->root.type != bfd_link_hash_undefweak) + { + _bfinfdpic_add_rofixup (output_bfd, + bfinfdpic_gotfixup_section (info), + bfinfdpic_got_section (info) + ->output_section->vma + + bfinfdpic_got_section (info) + ->output_offset + + bfinfdpic_got_initial_offset (info) + + entry->fd_entry, entry); + _bfinfdpic_add_rofixup (output_bfd, + bfinfdpic_gotfixup_section (info), + bfinfdpic_got_section (info) + ->output_section->vma + + bfinfdpic_got_section (info) + ->output_offset + + bfinfdpic_got_initial_offset (info) + + entry->fd_entry + 4, entry); + } + } + else + { + ofst + = _bfinfdpic_add_dyn_reloc (output_bfd, + entry->lazyplt + ? bfinfdpic_pltrel_section (info) + : bfinfdpic_gotrel_section (info), + _bfd_elf_section_offset + (output_bfd, info, + bfinfdpic_got_section (info), + bfinfdpic_got_initial_offset (info) + + entry->fd_entry) + + bfinfdpic_got_section (info) + ->output_section->vma + + bfinfdpic_got_section (info) + ->output_offset, + R_BFIN_FUNCDESC_VALUE, idx, ad, entry); } - if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd)) + /* If we've omitted the dynamic relocation, just emit the fixed + addresses of the symbol and of the local GOT base offset. */ + if (info->executable && !info->pie && sec && sec->output_section) { -#if 1 /* If you take this out, remove the #error from fdpic-static-6.d - in the ld testsuite. */ - /* This helps catch problems in GCC while we can't do more - than static linking. The idea is to test whether the - input file basename is crt0.o only once. */ - if (silence_segment_error == 1) - silence_segment_error = - (strlen (input_bfd->filename) == 6 - && strcmp (input_bfd->filename, "crt0.o") == 0) - || (strlen (input_bfd->filename) > 6 - && strcmp (input_bfd->filename - + strlen (input_bfd->filename) - 7, - "/crt0.o") == 0) - ? -1 : 0; -#endif - if (!silence_segment_error - /* We don't want duplicate errors for undefined - symbols. */ - && !(picrel && picrel->symndx == -1 - && picrel->d.h->root.type == bfd_link_hash_undefined)) - info->callbacks->warning - (info, - (info->shared || info->pie) - ? _("relocations between different segments are not supported") - : _("warning: relocation references a different segment"), - name, input_bfd, input_section, rel->r_offset); - if (!silence_segment_error && (info->shared || info->pie)) + lowword = ad; + highword = bfinfdpic_got_section (info)->output_section->vma + + bfinfdpic_got_section (info)->output_offset + + bfinfdpic_got_initial_offset (info); + } + else if (entry->lazyplt) + { + if (ad) return FALSE; - elf_elfheader (output_bfd)->e_flags |= EF_BFIN_PIC; + + fd_lazy_rel_offset = ofst; + + /* A function descriptor used for lazy or local resolving is + initialized such that its high word contains the output + section index in which the PLT entries are located, and + the low word contains the address of the lazy PLT entry + entry point, that must be within the memory region + assigned to that section. */ + lowword = entry->lzplt_entry + 4 + + bfinfdpic_plt_section (info)->output_offset + + bfinfdpic_plt_section (info)->output_section->vma; + highword = _bfinfdpic_osec_to_segment + (output_bfd, bfinfdpic_plt_section (info)->output_section); + } + else + { + /* A function descriptor for a local function gets the index + of the section. For a non-local function, it's + disregarded. */ + lowword = ad; + if (sec == NULL + || (entry->symndx == -1 && entry->d.h->dynindx != -1 + && entry->d.h->dynindx == idx)) + highword = 0; + else + highword = _bfinfdpic_osec_to_segment + (output_bfd, sec->output_section); } - switch (r_type) - { - case R_BFIN_GOTOFFHI: - /* We need the addend to be applied before we shift the - value right. */ - relocation += rel->r_addend; - /* Fall through. */ - case R_BFIN_GOTHI: - case R_BFIN_FUNCDESC_GOTHI: - case R_BFIN_FUNCDESC_GOTOFFHI: - relocation >>= 16; - /* Fall through. */ + bfd_put_32 (output_bfd, lowword, + bfinfdpic_got_section (info)->contents + + bfinfdpic_got_initial_offset (info) + + entry->fd_entry); + bfd_put_32 (output_bfd, highword, + bfinfdpic_got_section (info)->contents + + bfinfdpic_got_initial_offset (info) + + entry->fd_entry + 4); + } - case R_BFIN_GOTLO: - case R_BFIN_FUNCDESC_GOTLO: - case R_BFIN_GOTOFFLO: - case R_BFIN_FUNCDESC_GOTOFFLO: - relocation &= 0xffff; - break; + /* Generate code for the PLT entry. */ + if (entry->plt_entry != (bfd_vma) -1) + { + bfd_byte *plt_code = bfinfdpic_plt_section (info)->contents + + entry->plt_entry; - default: - break; - } + BFD_ASSERT (entry->fd_entry); - switch (r_type) + /* Figure out what kind of PLT entry we need, depending on the + location of the function descriptor within the GOT. */ + if (entry->fd_entry >= -(1 << (18 - 1)) + && entry->fd_entry + 4 < (1 << (18 - 1))) { - case R_pcrel24: - case R_pcrel24_jump_l: - if (! IS_FDPIC (output_bfd) || ! picrel->plt) - break; - /* Fall through. */ + /* P1 = [P3 + fd_entry]; P3 = [P3 + fd_entry + 4] */ + bfd_put_32 (output_bfd, + 0xe519 | ((entry->fd_entry << 14) & 0xFFFF0000), + plt_code); + bfd_put_32 (output_bfd, + 0xe51b | (((entry->fd_entry + 4) << 14) & 0xFFFF0000), + plt_code + 4); + plt_code += 8; + } + else + { + /* P1.L = fd_entry; P1.H = fd_entry; + P3 = P3 + P1; + P1 = [P3]; + P3 = [P3 + 4]; */ + bfd_put_32 (output_bfd, + 0xe109 | (entry->fd_entry << 16), + plt_code); + bfd_put_32 (output_bfd, + 0xe149 | (entry->fd_entry & 0xFFFF0000), + plt_code + 4); + bfd_put_16 (output_bfd, 0x5ad9, plt_code + 8); + bfd_put_16 (output_bfd, 0x9159, plt_code + 10); + bfd_put_16 (output_bfd, 0xac5b, plt_code + 12); + plt_code += 14; + } + /* JUMP (P1) */ + bfd_put_16 (output_bfd, 0x0051, plt_code); + } - /* When referencing a GOT entry, a function descriptor or a - PLT, we don't want the addend to apply to the reference, - but rather to the referenced symbol. The actual entry - will have already been created taking the addend into - account, so cancel it out here. */ - case R_BFIN_GOT17M4: - case R_BFIN_GOTHI: - case R_BFIN_GOTLO: - case R_BFIN_FUNCDESC_GOT17M4: - case R_BFIN_FUNCDESC_GOTHI: - case R_BFIN_FUNCDESC_GOTLO: - case R_BFIN_FUNCDESC_GOTOFF17M4: - case R_BFIN_FUNCDESC_GOTOFFHI: - case R_BFIN_FUNCDESC_GOTOFFLO: - /* Note that we only want GOTOFFHI, not GOTOFFLO or GOTOFF17M4 - here, since we do want to apply the addend to the others. - Note that we've applied the addend to GOTOFFHI before we - shifted it right. */ - case R_BFIN_GOTOFFHI: - relocation -= rel->r_addend; - break; + /* Generate code for the lazy PLT entry. */ + if (entry->lzplt_entry != (bfd_vma) -1) + { + bfd_byte *lzplt_code = bfinfdpic_plt_section (info)->contents + + entry->lzplt_entry; + bfd_vma resolverStub_addr; - default: - break; - } + bfd_put_32 (output_bfd, fd_lazy_rel_offset, lzplt_code); + lzplt_code += 4; - r = bfin_final_link_relocate (rel, howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); + resolverStub_addr = entry->lzplt_entry / BFINFDPIC_LZPLT_BLOCK_SIZE + * BFINFDPIC_LZPLT_BLOCK_SIZE + BFINFDPIC_LZPLT_RESOLV_LOC; + if (resolverStub_addr >= bfinfdpic_plt_initial_offset (info)) + resolverStub_addr = bfinfdpic_plt_initial_offset (info) - LZPLT_NORMAL_SIZE - LZPLT_RESOLVER_EXTRA; - if (r != bfd_reloc_ok) + if (entry->lzplt_entry == resolverStub_addr) { - const char * msg = (const char *) NULL; + /* This is a lazy PLT entry that includes a resolver call. + P2 = [P3]; + R3 = [P3 + 4]; + JUMP (P2); */ + bfd_put_32 (output_bfd, + 0xa05b915a, + lzplt_code); + bfd_put_16 (output_bfd, 0x0052, lzplt_code + 4); + } + else + { + /* JUMP.S resolverStub */ + bfd_put_16 (output_bfd, + 0x2000 + | (((resolverStub_addr - entry->lzplt_entry) + / 2) & (((bfd_vma)1 << 12) - 1)), + lzplt_code); + } + } - switch (r) - { - case bfd_reloc_overflow: - r = info->callbacks->reloc_overflow - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; + return TRUE; +} + +/* Relocate an Blackfin ELF section. - case bfd_reloc_undefined: - r = info->callbacks->undefined_symbol - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; + The RELOCATE_SECTION function is called by the new ELF backend linker + to handle the relocations for a section. - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; + The relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; + This function is responsible for adjusting the section contents as + necessary, and (if using Rela relocs and generating a relocatable + output file) adjusting the reloc addend as necessary. - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; + This function does not have to worry about setting the reloc + address or the reloc symbol index. - default: - msg = _("internal error: unknown error"); - break; - } + LOCAL_SYMS is a pointer to the swapped in local symbols. - if (msg) - r = info->callbacks->warning - (info, msg, name, input_bfd, input_section, rel->r_offset); + LOCAL_SECTIONS is an array giving the section in the input file + corresponding to the st_shndx field of each local symbol. - if (! r) - return FALSE; - } - } + The global hash table entry for the global symbols can be found + via elf_sym_hashes (input_bfd). - return TRUE; -} + When generating relocatable output, this function must handle + STB_LOCAL/STT_SECTION symbols specially. The output symbol is + going to be the section symbol corresponding to the output + section, which means that the addend must be adjusted + accordingly. */ static bfd_boolean -bfin_relocate_section (bfd * output_bfd, - struct bfd_link_info *info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) +bfinfdpic_relocate_section (bfd * output_bfd, + struct bfd_link_info *info, + bfd * input_bfd, + asection * input_section, + bfd_byte * contents, + Elf_Internal_Rela * relocs, + Elf_Internal_Sym * local_syms, + asection ** local_sections) { - bfd *dynobj; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; - bfd_vma *local_got_offsets; - asection *sgot; - asection *sreloc; Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; - int i = 0; + unsigned isec_segment, got_segment, plt_segment, + check_segment[2]; + int silence_segment_error = !(info->shared || info->pie); - dynobj = elf_hash_table (info)->dynobj; - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; sym_hashes = elf_sym_hashes (input_bfd); - local_got_offsets = elf_local_got_offsets (input_bfd); + relend = relocs + input_section->reloc_count; - sgot = NULL; - sreloc = NULL; + isec_segment = _bfinfdpic_osec_to_segment (output_bfd, + input_section->output_section); + if (IS_FDPIC (output_bfd) && bfinfdpic_got_section (info)) + got_segment = _bfinfdpic_osec_to_segment (output_bfd, + bfinfdpic_got_section (info) + ->output_section); + else + got_segment = -1; + if (IS_FDPIC (output_bfd) && elf_hash_table (info)->dynamic_sections_created) + plt_segment = _bfinfdpic_osec_to_segment (output_bfd, + bfinfdpic_plt_section (info) + ->output_section); + else + plt_segment = -1; - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++, i++) + for (rel = relocs; rel < relend; rel ++) { - int r_type; reloc_howto_type *howto; unsigned long r_symndx; - struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; asection *sec; - bfd_vma relocation = 0; - bfd_boolean unresolved_reloc; + struct elf_link_hash_entry *h; + bfd_vma relocation; bfd_reloc_status_type r; - bfd_vma address; - - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type < 0 || r_type >= 243) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } + const char * name = NULL; + int r_type; + asection *osec; + struct bfinfdpic_relocs_info *picrel; + bfd_vma orig_addend = rel->r_addend; - if (r_type == R_BFIN_GNU_VTENTRY - || r_type == R_BFIN_GNU_VTINHERIT) + r_type = ELF32_R_TYPE (rel->r_info); + + if (r_type == R_BFIN_GNU_VTINHERIT + || r_type == R_BFIN_GNU_VTENTRY) continue; + r_symndx = ELF32_R_SYM (rel->r_info); howto = bfin_reloc_type_lookup (input_bfd, r_type); if (howto == NULL) { bfd_set_error (bfd_error_bad_value); return FALSE; } - r_symndx = ELF32_R_SYM (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - unresolved_reloc = FALSE; + h = NULL; + sym = NULL; + sec = NULL; if (r_symndx < symtab_hdr->sh_info) { sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; + osec = sec = local_sections [r_symndx]; relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); + name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; } else { bfd_boolean warned; + bfd_boolean unresolved_reloc; RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, r_symndx, symtab_hdr, sym_hashes, h, sec, relocation, unresolved_reloc, warned); + osec = sec; } if (sec != NULL && elf_discarded_section (sec)) - { - /* For relocs against symbols from removed linkonce sections, - or sections discarded by a linker script, we just want the - section contents zeroed. Avoid any special processing. */ - _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); - rel->r_info = 0; - rel->r_addend = 0; - continue; - } + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, relend, howto, contents); if (info->relocatable) continue; - address = rel->r_offset; + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && !BFINFDPIC_SYM_LOCAL (info, h)) + { + osec = sec = NULL; + relocation = 0; + } - /* Then, process normally. */ switch (r_type) { - case R_BFIN_GNU_VTINHERIT: - case R_BFIN_GNU_VTENTRY: - return bfd_reloc_ok; + case R_BFIN_PCREL24: + case R_BFIN_PCREL24_JUMP_L: + case R_BFIN_BYTE4_DATA: + if (! IS_FDPIC (output_bfd)) + goto non_fdpic; + + case R_BFIN_GOT17M4: + case R_BFIN_GOTHI: + case R_BFIN_GOTLO: + case R_BFIN_FUNCDESC_GOT17M4: + case R_BFIN_FUNCDESC_GOTHI: + case R_BFIN_FUNCDESC_GOTLO: + case R_BFIN_GOTOFF17M4: + case R_BFIN_GOTOFFHI: + case R_BFIN_GOTOFFLO: + case R_BFIN_FUNCDESC_GOTOFF17M4: + case R_BFIN_FUNCDESC_GOTOFFHI: + case R_BFIN_FUNCDESC_GOTOFFLO: + case R_BFIN_FUNCDESC: + case R_BFIN_FUNCDESC_VALUE: + if (h != NULL) + picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info + (info), input_bfd, h, + orig_addend, INSERT); + else + /* In order to find the entry we created before, we must + use the original addend, not the one that may have been + modified by _bfd_elf_rela_local_sym(). */ + picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info + (info), input_bfd, r_symndx, + orig_addend, INSERT); + if (! picrel) + return FALSE; + + if (!_bfinfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info, + osec, sym, + rel->r_addend)) + { + (*_bfd_error_handler) + (_("%B: relocation at `%A+0x%x' references symbol `%s' with nonzero addend"), + input_bfd, input_section, rel->r_offset, name); + return FALSE; + + } + + break; + + default: + non_fdpic: + picrel = NULL; + if (h && ! BFINFDPIC_SYM_LOCAL (info, h)) + { + info->callbacks->warning + (info, _("relocation references symbol not defined in the module"), + name, input_bfd, input_section, rel->r_offset); + return FALSE; + } + break; + } + + switch (r_type) + { + case R_BFIN_PCREL24: + case R_BFIN_PCREL24_JUMP_L: + check_segment[0] = isec_segment; + if (! IS_FDPIC (output_bfd)) + check_segment[1] = isec_segment; + else if (picrel->plt) + { + relocation = bfinfdpic_plt_section (info)->output_section->vma + + bfinfdpic_plt_section (info)->output_offset + + picrel->plt_entry; + check_segment[1] = plt_segment; + } + /* We don't want to warn on calls to undefined weak symbols, + as calls to them must be protected by non-NULL tests + anyway, and unprotected calls would invoke undefined + behavior. */ + else if (picrel->symndx == -1 + && picrel->d.h->root.type == bfd_link_hash_undefweak) + check_segment[1] = check_segment[0]; + else + check_segment[1] = sec + ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section) + : (unsigned)-1; + break; + + case R_BFIN_GOT17M4: + case R_BFIN_GOTHI: + case R_BFIN_GOTLO: + relocation = picrel->got_entry; + check_segment[0] = check_segment[1] = got_segment; + break; + + case R_BFIN_FUNCDESC_GOT17M4: + case R_BFIN_FUNCDESC_GOTHI: + case R_BFIN_FUNCDESC_GOTLO: + relocation = picrel->fdgot_entry; + check_segment[0] = check_segment[1] = got_segment; + break; + + case R_BFIN_GOTOFFHI: + case R_BFIN_GOTOFF17M4: + case R_BFIN_GOTOFFLO: + relocation -= bfinfdpic_got_section (info)->output_section->vma + + bfinfdpic_got_section (info)->output_offset + + bfinfdpic_got_initial_offset (info); + check_segment[0] = got_segment; + check_segment[1] = sec + ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section) + : (unsigned)-1; + break; + + case R_BFIN_FUNCDESC_GOTOFF17M4: + case R_BFIN_FUNCDESC_GOTOFFHI: + case R_BFIN_FUNCDESC_GOTOFFLO: + relocation = picrel->fd_entry; + check_segment[0] = check_segment[1] = got_segment; + break; + + case R_BFIN_FUNCDESC: + { + int dynindx; + bfd_vma addend = rel->r_addend; + + if (! (h && h->root.type == bfd_link_hash_undefweak + && BFINFDPIC_SYM_LOCAL (info, h))) + { + /* If the symbol is dynamic and there may be dynamic + symbol resolution because we are or are linked with a + shared library, emit a FUNCDESC relocation such that + the dynamic linker will allocate the function + descriptor. If the symbol needs a non-local function + descriptor but binds locally (e.g., its visibility is + protected, emit a dynamic relocation decayed to + section+offset. */ + if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h) + && BFINFDPIC_SYM_LOCAL (info, h) + && !(info->executable && !info->pie)) + { + dynindx = elf_section_data (h->root.u.def.section + ->output_section)->dynindx; + addend += h->root.u.def.section->output_offset + + h->root.u.def.value; + } + else if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h)) + { + if (addend) + { + info->callbacks->warning + (info, _("R_BFIN_FUNCDESC references dynamic symbol with nonzero addend"), + name, input_bfd, input_section, rel->r_offset); + return FALSE; + } + dynindx = h->dynindx; + } + else + { + /* Otherwise, we know we have a private function + descriptor, so reference it directly. */ + BFD_ASSERT (picrel->privfd); + r_type = R_BFIN_BYTE4_DATA; + dynindx = elf_section_data (bfinfdpic_got_section (info) + ->output_section)->dynindx; + addend = bfinfdpic_got_section (info)->output_offset + + bfinfdpic_got_initial_offset (info) + + picrel->fd_entry; + } + + /* If there is room for dynamic symbol resolution, emit + the dynamic relocation. However, if we're linking an + executable at a fixed location, we won't have emitted a + dynamic symbol entry for the got section, so idx will + be zero, which means we can and should compute the + address of the private descriptor ourselves. */ + if (info->executable && !info->pie + && (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h))) + { + bfd_vma offset; + + addend += bfinfdpic_got_section (info)->output_section->vma; + if ((bfd_get_section_flags (output_bfd, + input_section->output_section) + & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) + { + if (_bfinfdpic_osec_readonly_p (output_bfd, + input_section + ->output_section)) + { + info->callbacks->warning + (info, + _("cannot emit fixups in read-only section"), + name, input_bfd, input_section, rel->r_offset); + return FALSE; + } + + offset = _bfd_elf_section_offset + (output_bfd, info, + input_section, rel->r_offset); + + if (offset != (bfd_vma)-1) + _bfinfdpic_add_rofixup (output_bfd, + bfinfdpic_gotfixup_section + (info), + offset + input_section + ->output_section->vma + + input_section->output_offset, + picrel); + } + } + else if ((bfd_get_section_flags (output_bfd, + input_section->output_section) + & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) + { + bfd_vma offset; + + if (_bfinfdpic_osec_readonly_p (output_bfd, + input_section + ->output_section)) + { + info->callbacks->warning + (info, + _("cannot emit dynamic relocations in read-only section"), + name, input_bfd, input_section, rel->r_offset); + return FALSE; + } + offset = _bfd_elf_section_offset (output_bfd, info, + input_section, rel->r_offset); - case R_got: - /* Relocation is to the address of the entry for this symbol - in the global offset table. */ - if (h != NULL - && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0) - goto do_default; - /* Fall through. */ - /* Relocation is the offset of the entry for this symbol in - the global offset table. */ + if (offset != (bfd_vma)-1) + _bfinfdpic_add_dyn_reloc (output_bfd, + bfinfdpic_gotrel_section (info), + offset + input_section + ->output_section->vma + + input_section->output_offset, + r_type, + dynindx, addend, picrel); + } + else + addend += bfinfdpic_got_section (info)->output_section->vma; + } - { - bfd_vma off; + /* We want the addend in-place because dynamic + relocations are REL. Setting relocation to it should + arrange for it to be installed. */ + relocation = addend - rel->r_addend; + } + check_segment[0] = check_segment[1] = got_segment; + break; - if (dynobj == NULL) + case R_BFIN_BYTE4_DATA: + if (! IS_FDPIC (output_bfd)) { - /* Create the .got section. */ - elf_hash_table (info)->dynobj = dynobj = output_bfd; - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; + check_segment[0] = check_segment[1] = -1; + break; } + /* Fall through. */ + case R_BFIN_FUNCDESC_VALUE: + { + int dynindx; + bfd_vma addend = rel->r_addend; + bfd_vma offset; + offset = _bfd_elf_section_offset (output_bfd, info, + input_section, rel->r_offset); - if (sgot == NULL) + /* If the symbol is dynamic but binds locally, use + section+offset. */ + if (h && ! BFINFDPIC_SYM_LOCAL (info, h)) { - sgot = bfd_get_section_by_name (dynobj, ".got"); - BFD_ASSERT (sgot != NULL); + if (addend && r_type == R_BFIN_FUNCDESC_VALUE) + { + info->callbacks->warning + (info, _("R_BFIN_FUNCDESC_VALUE references dynamic symbol with nonzero addend"), + name, input_bfd, input_section, rel->r_offset); + return FALSE; + } + dynindx = h->dynindx; } - - if (h != NULL) + else { - bfd_boolean dyn; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) - 1); - dyn = elf_hash_table (info)->dynamic_sections_created; + if (h) + addend += h->root.u.def.value; + else + addend += sym->st_value; + if (osec) + addend += osec->output_offset; + if (osec && osec->output_section + && ! bfd_is_abs_section (osec->output_section) + && ! bfd_is_und_section (osec->output_section)) + dynindx = elf_section_data (osec->output_section)->dynindx; + else + dynindx = 0; + } - if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) - || (info->shared - && (info->symbolic - || h->dynindx == -1 - || h->forced_local) - && h->def_regular)) + /* If we're linking an executable at a fixed address, we + can omit the dynamic relocation as long as the symbol + is defined in the current link unit (which is implied + by its output section not being NULL). */ + if (info->executable && !info->pie + && (!h || BFINFDPIC_SYM_LOCAL (info, h))) + { + if (osec) + addend += osec->output_section->vma; + if (IS_FDPIC (input_bfd) + && (bfd_get_section_flags (output_bfd, + input_section->output_section) + & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) { - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file.. We must initialize - this entry in the global offset table. Since - the offset must always be a multiple of 4, we - use the least significant bit to record whether - we have initialized it already. - - When doing a dynamic link, we create a .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else + if (_bfinfdpic_osec_readonly_p (output_bfd, + input_section + ->output_section)) { - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - h->got.offset |= 1; + info->callbacks->warning + (info, + _("cannot emit fixups in read-only section"), + name, input_bfd, input_section, rel->r_offset); + return FALSE; + } + if (!h || h->root.type != bfd_link_hash_undefweak) + { + if (offset != (bfd_vma)-1) + { + _bfinfdpic_add_rofixup (output_bfd, + bfinfdpic_gotfixup_section + (info), + offset + input_section + ->output_section->vma + + input_section->output_offset, + picrel); + + if (r_type == R_BFIN_FUNCDESC_VALUE) + _bfinfdpic_add_rofixup + (output_bfd, + bfinfdpic_gotfixup_section (info), + offset + input_section->output_section->vma + + input_section->output_offset + 4, picrel); + } } } - else - unresolved_reloc = FALSE; } else { - BFD_ASSERT (local_got_offsets != NULL); - off = local_got_offsets[r_symndx]; - BFD_ASSERT (off != (bfd_vma) - 1); - - /* The offset must always be a multiple of 4. We use - the least significant bit to record whether we have - already generated the necessary reloc. */ - if ((off & 1) != 0) - off &= ~1; - else + if ((bfd_get_section_flags (output_bfd, + input_section->output_section) + & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) { - bfd_put_32 (output_bfd, relocation, sgot->contents + off); - - if (info->shared) + if (_bfinfdpic_osec_readonly_p (output_bfd, + input_section + ->output_section)) { - asection *s; - Elf_Internal_Rela outrel; - bfd_byte *loc; + info->callbacks->warning + (info, + _("cannot emit dynamic relocations in read-only section"), + name, input_bfd, input_section, rel->r_offset); + return FALSE; + } - s = bfd_get_section_by_name (dynobj, ".rela.got"); - BFD_ASSERT (s != NULL); + if (offset != (bfd_vma)-1) + _bfinfdpic_add_dyn_reloc (output_bfd, + bfinfdpic_gotrel_section (info), + offset + + input_section->output_section->vma + + input_section->output_offset, + r_type, dynindx, addend, picrel); + } + else if (osec) + addend += osec->output_section->vma; + /* We want the addend in-place because dynamic + relocations are REL. Setting relocation to it + should arrange for it to be installed. */ + relocation = addend - rel->r_addend; + } - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset + off); - outrel.r_info = - ELF32_R_INFO (0, R_pcrel24); - outrel.r_addend = relocation; - loc = s->contents; - loc += - s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } + if (r_type == R_BFIN_FUNCDESC_VALUE) + { + /* If we've omitted the dynamic relocation, just emit + the fixed addresses of the symbol and of the local + GOT base offset. */ + if (info->executable && !info->pie + && (!h || BFINFDPIC_SYM_LOCAL (info, h))) + bfd_put_32 (output_bfd, + bfinfdpic_got_section (info)->output_section->vma + + bfinfdpic_got_section (info)->output_offset + + bfinfdpic_got_initial_offset (info), + contents + rel->r_offset + 4); + else + /* A function descriptor used for lazy or local + resolving is initialized such that its high word + contains the output section index in which the + PLT entries are located, and the low word + contains the offset of the lazy PLT entry entry + point into that section. */ + bfd_put_32 (output_bfd, + h && ! BFINFDPIC_SYM_LOCAL (info, h) + ? 0 + : _bfinfdpic_osec_to_segment (output_bfd, + sec + ->output_section), + contents + rel->r_offset + 4); + } + } + check_segment[0] = check_segment[1] = got_segment; + break; + + default: + check_segment[0] = isec_segment; + check_segment[1] = sec + ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section) + : (unsigned)-1; + break; + } + + if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd)) + { +#if 1 /* If you take this out, remove the #error from fdpic-static-6.d + in the ld testsuite. */ + /* This helps catch problems in GCC while we can't do more + than static linking. The idea is to test whether the + input file basename is crt0.o only once. */ + if (silence_segment_error == 1) + silence_segment_error = + (strlen (input_bfd->filename) == 6 + && strcmp (input_bfd->filename, "crt0.o") == 0) + || (strlen (input_bfd->filename) > 6 + && strcmp (input_bfd->filename + + strlen (input_bfd->filename) - 7, + "/crt0.o") == 0) + ? -1 : 0; +#endif + if (!silence_segment_error + /* We don't want duplicate errors for undefined + symbols. */ + && !(picrel && picrel->symndx == -1 + && picrel->d.h->root.type == bfd_link_hash_undefined)) + info->callbacks->warning + (info, + (info->shared || info->pie) + ? _("relocations between different segments are not supported") + : _("warning: relocation references a different segment"), + name, input_bfd, input_section, rel->r_offset); + if (!silence_segment_error && (info->shared || info->pie)) + return FALSE; + elf_elfheader (output_bfd)->e_flags |= EF_BFIN_PIC; + } - local_got_offsets[r_symndx] |= 1; - } - } + switch (r_type) + { + case R_BFIN_GOTOFFHI: + /* We need the addend to be applied before we shift the + value right. */ + relocation += rel->r_addend; + /* Fall through. */ + case R_BFIN_GOTHI: + case R_BFIN_FUNCDESC_GOTHI: + case R_BFIN_FUNCDESC_GOTOFFHI: + relocation >>= 16; + /* Fall through. */ - relocation = sgot->output_offset + off; - rel->r_addend = 0; - /* bfin : preg = [preg + 17bitdiv4offset] relocation is div by 4. */ - relocation /= 4; - } - goto do_default; + case R_BFIN_GOTLO: + case R_BFIN_FUNCDESC_GOTLO: + case R_BFIN_GOTOFFLO: + case R_BFIN_FUNCDESC_GOTOFFLO: + relocation &= 0xffff; + break; default: - do_default: - r = bfin_final_link_relocate (rel, howto, input_bfd, input_section, - contents, address, - relocation, rel->r_addend); - break; } - /* Dynamic relocs are not propagated for SEC_DEBUGGING sections - because such sections are not SEC_ALLOC and thus ld.so will - not process them. */ - if (unresolved_reloc - && !((input_section->flags & SEC_DEBUGGING) != 0 && h->def_dynamic)) + switch (r_type) { - (*_bfd_error_handler) - (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"), - input_bfd, - input_section, (long) rel->r_offset, h->root.root.string); - return FALSE; + case R_BFIN_PCREL24: + case R_BFIN_PCREL24_JUMP_L: + if (! IS_FDPIC (output_bfd) || ! picrel->plt) + break; + /* Fall through. */ + + /* When referencing a GOT entry, a function descriptor or a + PLT, we don't want the addend to apply to the reference, + but rather to the referenced symbol. The actual entry + will have already been created taking the addend into + account, so cancel it out here. */ + case R_BFIN_GOT17M4: + case R_BFIN_GOTHI: + case R_BFIN_GOTLO: + case R_BFIN_FUNCDESC_GOT17M4: + case R_BFIN_FUNCDESC_GOTHI: + case R_BFIN_FUNCDESC_GOTLO: + case R_BFIN_FUNCDESC_GOTOFF17M4: + case R_BFIN_FUNCDESC_GOTOFFHI: + case R_BFIN_FUNCDESC_GOTOFFLO: + /* Note that we only want GOTOFFHI, not GOTOFFLO or GOTOFF17M4 + here, since we do want to apply the addend to the others. + Note that we've applied the addend to GOTOFFHI before we + shifted it right. */ + case R_BFIN_GOTOFFHI: + relocation -= rel->r_addend; + break; + + default: + break; } + r = bfin_final_link_relocate (rel, howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + if (r != bfd_reloc_ok) { - const char *name; + const char * msg = (const char *) NULL; - if (h != NULL) - name = h->root.root.string; - else + switch (r) { - name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - if (name == NULL) - return FALSE; - if (*name == '\0') - name = bfd_section_name (input_bfd, sec); - } + case bfd_reloc_overflow: + r = info->callbacks->reloc_overflow + (info, (h ? &h->root : NULL), name, howto->name, + (bfd_vma) 0, input_bfd, input_section, rel->r_offset); + break; - if (r == bfd_reloc_overflow) - { - if (!(info->callbacks->reloc_overflow - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset))) - return FALSE; - } - else - { - (*_bfd_error_handler) - (_("%B(%A+0x%lx): reloc against `%s': error %d"), - input_bfd, input_section, - (long) rel->r_offset, name, (int) r); - return FALSE; + case bfd_reloc_undefined: + r = info->callbacks->undefined_symbol + (info, name, input_bfd, input_section, rel->r_offset, TRUE); + break; + + case bfd_reloc_outofrange: + msg = _("internal error: out of range error"); + break; + + case bfd_reloc_notsupported: + msg = _("internal error: unsupported relocation error"); + break; + + case bfd_reloc_dangerous: + msg = _("internal error: dangerous relocation"); + break; + + default: + msg = _("internal error: unknown error"); + break; } + + if (msg) + r = info->callbacks->warning + (info, msg, name, input_bfd, input_section, rel->r_offset); + + if (! r) + return FALSE; } } return TRUE; } -static asection * -bfin_gc_mark_hook (asection * sec, - struct bfd_link_info *info, - Elf_Internal_Rela * rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym * sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_BFIN_GNU_VTINHERIT: - case R_BFIN_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - /* Update the relocation information for the relocations of the section being removed. */ @@ -3202,8 +3283,8 @@ bfinfdpic_gc_sweep_hook (bfd *abfd, switch (ELF32_R_TYPE (rel->r_info)) { - case R_pcrel24: - case R_pcrel24_jump_l: + case R_BFIN_PCREL24: + case R_BFIN_PCREL24_JUMP_L: picrel->call--; break; @@ -3213,7 +3294,7 @@ bfinfdpic_gc_sweep_hook (bfd *abfd, picrel->relocs32++; /* Fall through. */ - case R_byte4_data: + case R_BFIN_BYTE4_DATA: picrel->sym--; if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) picrel->relocs32--; @@ -3265,86 +3346,12 @@ bfinfdpic_gc_sweep_hook (bfd *abfd, return TRUE; } -/* Update the got entry reference counts for the section being removed. */ - -static bfd_boolean -bfin_gc_sweep_hook (bfd * abfd, - struct bfd_link_info *info, - asection * sec, - const Elf_Internal_Rela * relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_signed_vma *local_got_refcounts; - const Elf_Internal_Rela *rel, *relend; - bfd *dynobj; - asection *sgot; - asection *srelgot; - - dynobj = elf_hash_table (info)->dynobj; - if (dynobj == NULL) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - local_got_refcounts = elf_local_got_refcounts (abfd); - - sgot = bfd_get_section_by_name (dynobj, ".got"); - srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); - - relend = relocs + sec->reloc_count; - for (rel = relocs; rel < relend; rel++) - { - unsigned long r_symndx; - struct elf_link_hash_entry *h; - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_got: - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx >= symtab_hdr->sh_info) - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - if (h->got.refcount > 0) - { - --h->got.refcount; - if (h->got.refcount == 0) - { - /* We don't need the .got entry any more. */ - sgot->size -= 4; - srelgot->size -= sizeof (Elf32_External_Rela); - } - } - } - else if (local_got_refcounts != NULL) - { - if (local_got_refcounts[r_symndx] > 0) - { - --local_got_refcounts[r_symndx]; - if (local_got_refcounts[r_symndx] == 0) - { - /* We don't need the .got entry any more. */ - sgot->size -= 4; - if (info->shared) - srelgot->size -= sizeof (Elf32_External_Rela); - } - } - } - break; - default: - break; - } - } - return TRUE; -} - /* We need dynamic symbols for every section, since segments can relocate independently. */ static bfd_boolean _bfinfdpic_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info - ATTRIBUTE_UNUSED, - asection *p ATTRIBUTE_UNUSED) + struct bfd_link_info *info ATTRIBUTE_UNUSED, + asection *p) { switch (elf_section_data (p)->this_hdr.sh_type) { @@ -3374,7 +3381,6 @@ _bfin_create_got_section (bfd *abfd, struct bfd_link_info *info) struct elf_link_hash_entry *h; const struct elf_backend_data *bed = get_elf_backend_data (abfd); int ptralign; - int offset; /* This function may be called more than once. */ s = bfd_get_section_by_name (abfd, ".got"); @@ -3448,41 +3454,12 @@ _bfin_create_got_section (bfd *abfd, struct bfd_link_info *info) s = bfd_make_section_with_flags (abfd, ".rofixup", (flags | SEC_READONLY)); if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - bfinfdpic_gotfixup_section (info) = s; - offset = -2048; - flags = BSF_GLOBAL; - } - else - { - offset = 2048; - flags = BSF_GLOBAL | BSF_WEAK; - } - - return TRUE; -} - -/* Make sure the got and plt sections exist, and that our pointers in - the link hash table point to them. */ - -static bfd_boolean -elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - /* This is mostly copied from - elflink.c:_bfd_elf_create_dynamic_sections(). */ - flagword flags, pltflags; - asection *s; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and - .rel[a].bss sections. */ + || ! bfd_set_section_alignment (abfd, s, 2)) + return FALSE; - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); + bfinfdpic_gotfixup_section (info) = s; + } - pltflags = flags; pltflags |= SEC_CODE; if (bed->plt_not_loaded) pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS); @@ -3500,7 +3477,6 @@ elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) { /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section. */ - struct elf_link_hash_entry *h; struct bfd_link_hash_entry *bh = NULL; if (! (_bfd_generic_link_add_one_symbol @@ -3524,6 +3500,27 @@ elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) /* Blackfin-specific: remember it. */ bfinfdpic_pltrel_section (info) = s; + return TRUE; +} + +/* Make sure the got and plt sections exist, and that our pointers in + the link hash table point to them. */ + +static bfd_boolean +elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) +{ + /* This is mostly copied from + elflink.c:_bfd_elf_create_dynamic_sections(). */ + flagword flags; + asection *s; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); + + /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and + .rel[a].bss sections. */ + /* Blackfin-specific: we want to create the GOT in the Blackfin way. */ if (! _bfin_create_got_section (abfd, info)) return FALSE; @@ -3561,8 +3558,7 @@ elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) if (! info->shared) { s = bfd_make_section_with_flags (abfd, - (bed->default_use_rela_p - ? ".rela.bss" : ".rel.bss"), + ".rela.bss", flags | SEC_READONLY); if (s == NULL || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) @@ -3573,49 +3569,15 @@ elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) return TRUE; } -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" - -#define DEFAULT_STACK_SIZE 0x20000 - -/* This structure is used to collect the number of entries present in - each addressable range of the got. */ -struct _bfinfdpic_dynamic_got_info -{ - /* Several bits of information about the current link. */ - struct bfd_link_info *info; - /* Total size needed for GOT entries within the 18- or 32-bit - ranges. */ - bfd_vma got17m4, gothilo; - /* Total size needed for function descriptor entries within the 18- - or 32-bit ranges. */ - bfd_vma fd17m4, fdhilo; - /* Total size needed function descriptor entries referenced in PLT - entries, that would be profitable to place in offsets close to - the PIC register. */ - bfd_vma fdplt; - /* Total size needed by lazy PLT entries. */ - bfd_vma lzplt; - /* Number of relocations carried over from input object files. */ - unsigned long relocs; - /* Number of fixups introduced by relocations in input object files. */ - unsigned long fixups; -}; - /* Compute the total GOT size required by each symbol in each range. Symbols may require up to 4 words in the GOT: an entry pointing to the symbol, an entry pointing to its function descriptor, and a private function descriptors taking two words. */ -static int -_bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_) +static void +_bfinfdpic_count_nontls_entries (struct bfinfdpic_relocs_info *entry, + struct _bfinfdpic_dynamic_got_info *dinfo) { - struct bfinfdpic_relocs_info *entry = *entryp; - struct _bfinfdpic_dynamic_got_info *dinfo = dinfo_; - unsigned relocs = 0, fixups = 0; - /* Allocate space for a GOT entry pointing to the symbol. */ if (entry->got17m4) dinfo->got17m4 += 4; @@ -3663,6 +3625,18 @@ _bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_) if (entry->lazyplt) dinfo->lzplt += LZPLT_NORMAL_SIZE; +} + +/* Compute the number of dynamic relocations and fixups that a symbol + requires, and add (or subtract) from the grand and per-symbol + totals. */ + +static void +_bfinfdpic_count_relocs_fixups (struct bfinfdpic_relocs_info *entry, + struct _bfinfdpic_dynamic_got_info *dinfo, + bfd_boolean subtract) +{ + bfd_vma relocs = 0, fixups = 0; if (!dinfo->info->executable || dinfo->info->pie) relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv; @@ -3688,10 +3662,32 @@ _bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_) relocs += entry->relocsfd; } + if (subtract) + { + relocs = - relocs; + fixups = - fixups; + } + entry->dynrelocs += relocs; entry->fixups += fixups; dinfo->relocs += relocs; dinfo->fixups += fixups; +} + +/* Compute the total GOT and PLT size required by each symbol in each range. * + Symbols may require up to 4 words in the GOT: an entry pointing to + the symbol, an entry pointing to its function descriptor, and a + private function descriptors taking two words. */ + +static int +_bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_) +{ + struct bfinfdpic_relocs_info *entry = *entryp; + struct _bfinfdpic_dynamic_got_info *dinfo = dinfo_; + + _bfinfdpic_count_nontls_entries (entry, dinfo); + + _bfinfdpic_count_relocs_fixups (entry, dinfo, FALSE); return 1; } @@ -3987,6 +3983,23 @@ _bfinfdpic_assign_plt_entries (void **entryp, void *info_) return 1; } +/* Cancel out any effects of calling _bfinfdpic_assign_got_entries and + _bfinfdpic_assign_plt_entries. */ + +static int +_bfinfdpic_reset_got_plt_entries (void **entryp, void *ignore ATTRIBUTE_UNUSED) +{ + struct bfinfdpic_relocs_info *entry = *entryp; + + entry->got_entry = 0; + entry->fdgot_entry = 0; + entry->fd_entry = 0; + entry->plt_entry = (bfd_vma)-1; + entry->lzplt_entry = (bfd_vma)-1; + + return 1; +} + /* Follow indirect and warning hash entries so that each got entry points to the final symbol definition. P must point to a pointer to the hash table we're traversing. Since this traversal may @@ -4043,89 +4056,62 @@ _bfinfdpic_resolve_final_relocs_info (void **entryp, void *p) return 1; } -/* Set the sizes of the dynamic sections. */ +/* Compute the total size of the GOT, the PLT, the dynamic relocations + section and the rofixup section. Assign locations for GOT and PLT + entries. */ static bfd_boolean -elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) +_bfinfdpic_size_got_plt (bfd *output_bfd, + struct _bfinfdpic_dynamic_got_plt_info *gpinfop) { - bfd *dynobj; - asection *s; - struct _bfinfdpic_dynamic_got_plt_info gpinfo; bfd_signed_vma odd; bfd_vma limit; + struct bfd_link_info *info = gpinfop->g.info; + bfd *dynobj = elf_hash_table (info)->dynobj; - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (info->executable) - { - s = bfd_get_section_by_name (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER; - } - } - - memset (&gpinfo, 0, sizeof (gpinfo)); - gpinfo.g.info = info; - - for (;;) - { - htab_t relocs = bfinfdpic_relocs_info (info); - - htab_traverse (relocs, _bfinfdpic_resolve_final_relocs_info, &relocs); - - if (relocs == bfinfdpic_relocs_info (info)) - break; - } - - htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_count_got_plt_entries, - &gpinfo.g); + memcpy (bfinfdpic_dynamic_got_plt_info (info), &gpinfop->g, + sizeof (gpinfop->g)); odd = 12; /* Compute the total size taken by entries in the 18-bit range, to tell how many PLT function descriptors we can bring into it without causing it to overflow. */ - limit = odd + gpinfo.g.got17m4 + gpinfo.g.fd17m4; + limit = odd + gpinfop->g.got17m4 + gpinfop->g.fd17m4; if (limit < (bfd_vma)1 << 18) limit = ((bfd_vma)1 << 18) - limit; else limit = 0; - if (gpinfo.g.fdplt < limit) - limit = gpinfo.g.fdplt; + if (gpinfop->g.fdplt < limit) + limit = gpinfop->g.fdplt; /* Determine the ranges of GOT offsets that we can use for each range of addressing modes. */ - odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.got17m4, + odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->got17m4, 0, odd, 16, - gpinfo.g.got17m4, - gpinfo.g.fd17m4, + gpinfop->g.got17m4, + gpinfop->g.fd17m4, limit, (bfd_vma)1 << (18-1)); - odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.gothilo, - gpinfo.got17m4.min, + odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->gothilo, + gpinfop->got17m4.min, odd, - gpinfo.got17m4.max, - gpinfo.g.gothilo, - gpinfo.g.fdhilo, - gpinfo.g.fdplt - gpinfo.got17m4.fdplt, + gpinfop->got17m4.max, + gpinfop->g.gothilo, + gpinfop->g.fdhilo, + gpinfop->g.fdplt - gpinfop->got17m4.fdplt, (bfd_vma)1 << (32-1)); /* Now assign (most) GOT offsets. */ htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_got_entries, - &gpinfo); + gpinfop); - bfinfdpic_got_section (info)->size = gpinfo.gothilo.max - - gpinfo.gothilo.min + bfinfdpic_got_section (info)->size = gpinfop->gothilo.max + - gpinfop->gothilo.min /* If an odd word is the last word of the GOT, we don't need this word to be part of the GOT. */ - - (odd + 4 == gpinfo.gothilo.max ? 4 : 0); + - (odd + 4 == gpinfop->gothilo.max ? 4 : 0); if (bfinfdpic_got_section (info)->size == 0) bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE; else if (bfinfdpic_got_section (info)->size == 12 @@ -4147,10 +4133,10 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd, /* Subtract the number of lzplt entries, since those will generate relocations in the pltrel section. */ bfinfdpic_gotrel_section (info)->size = - (gpinfo.g.relocs - gpinfo.g.lzplt / LZPLT_NORMAL_SIZE) + (gpinfop->g.relocs - gpinfop->g.lzplt / LZPLT_NORMAL_SIZE) * get_elf_backend_data (output_bfd)->s->sizeof_rel; else - BFD_ASSERT (gpinfo.g.relocs == 0); + BFD_ASSERT (gpinfop->g.relocs == 0); if (bfinfdpic_gotrel_section (info)->size == 0) bfinfdpic_gotrel_section (info)->flags |= SEC_EXCLUDE; else @@ -4162,7 +4148,7 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd, return FALSE; } - bfinfdpic_gotfixup_section (info)->size = (gpinfo.g.fixups + 1) * 4; + bfinfdpic_gotfixup_section (info)->size = (gpinfop->g.fixups + 1) * 4; if (bfinfdpic_gotfixup_section (info)->size == 0) bfinfdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE; else @@ -4175,19 +4161,17 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd, } if (elf_hash_table (info)->dynamic_sections_created) + bfinfdpic_pltrel_section (info)->size = + gpinfop->g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel; + if (bfinfdpic_pltrel_section (info)->size == 0) + bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE; + else { - bfinfdpic_pltrel_section (info)->size = - gpinfo.g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel; - if (bfinfdpic_pltrel_section (info)->size == 0) - bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE; - else - { - bfinfdpic_pltrel_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - bfinfdpic_pltrel_section (info)->size); - if (bfinfdpic_pltrel_section (info)->contents == NULL) - return FALSE; - } + bfinfdpic_pltrel_section (info)->contents = + (bfd_byte *) bfd_zalloc (dynobj, + bfinfdpic_pltrel_section (info)->size); + if (bfinfdpic_pltrel_section (info)->contents == NULL) + return FALSE; } /* Add 4 bytes for every block of at most 65535 lazy PLT entries, @@ -4197,47 +4181,97 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd, block size. */ if (elf_hash_table (info)->dynamic_sections_created) { - bfinfdpic_plt_section (info)->size = gpinfo.g.lzplt - + ((gpinfo.g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE) + bfinfdpic_plt_section (info)->size = gpinfop->g.lzplt + + ((gpinfop->g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE) / (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) * LZPLT_RESOLVER_EXTRA); } /* Reset it, such that _bfinfdpic_assign_plt_entries() can use it to actually assign lazy PLT entries addresses. */ - gpinfo.g.lzplt = 0; + gpinfop->g.lzplt = 0; /* Save information that we're going to need to generate GOT and PLT entries. */ - bfinfdpic_got_initial_offset (info) = -gpinfo.gothilo.min; + bfinfdpic_got_initial_offset (info) = -gpinfop->gothilo.min; if (get_elf_backend_data (output_bfd)->want_got_sym) elf_hash_table (info)->hgot->root.u.def.value - += bfinfdpic_got_initial_offset (info); + = bfinfdpic_got_initial_offset (info); if (elf_hash_table (info)->dynamic_sections_created) bfinfdpic_plt_initial_offset (info) = bfinfdpic_plt_section (info)->size; htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_plt_entries, - &gpinfo); + gpinfop); /* Allocate the PLT section contents only after _bfinfdpic_assign_plt_entries has a chance to add the size of the non-lazy PLT entries. */ - if (elf_hash_table (info)->dynamic_sections_created) + if (bfinfdpic_plt_section (info)->size == 0) + bfinfdpic_plt_section (info)->flags |= SEC_EXCLUDE; + else { - if (bfinfdpic_plt_section (info)->size == 0) - bfinfdpic_plt_section (info)->flags |= SEC_EXCLUDE; - else + bfinfdpic_plt_section (info)->contents = + (bfd_byte *) bfd_zalloc (dynobj, + bfinfdpic_plt_section (info)->size); + if (bfinfdpic_plt_section (info)->contents == NULL) + return FALSE; + } + + return TRUE; +} + +/* Set the sizes of the dynamic sections. */ + +static bfd_boolean +elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd, + struct bfd_link_info *info) +{ + struct elf_link_hash_table *htab; + bfd *dynobj; + asection *s; + struct _bfinfdpic_dynamic_got_plt_info gpinfo; + + htab = elf_hash_table (info); + dynobj = htab->dynobj; + BFD_ASSERT (dynobj != NULL); + + if (htab->dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (info->executable) { - bfinfdpic_plt_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - bfinfdpic_plt_section (info)->size); - if (bfinfdpic_plt_section (info)->contents == NULL) - return FALSE; + s = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (s != NULL); + s->size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER; } } + memset (&gpinfo, 0, sizeof (gpinfo)); + gpinfo.g.info = info; + + for (;;) + { + htab_t relocs = bfinfdpic_relocs_info (info); + + htab_traverse (relocs, _bfinfdpic_resolve_final_relocs_info, &relocs); + + if (relocs == bfinfdpic_relocs_info (info)) + break; + } + + htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_count_got_plt_entries, + &gpinfo.g); + + /* Allocate space to save the summary information, we're going to + use it if we're doing relaxations. */ + bfinfdpic_dynamic_got_plt_info (info) = bfd_alloc (dynobj, sizeof (gpinfo.g)); + + if (!_bfinfdpic_size_got_plt (output_bfd, &gpinfo)) + return FALSE; + if (elf_hash_table (info)->dynamic_sections_created) { if (bfinfdpic_got_section (info)->size) @@ -4258,6 +4292,14 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd, return FALSE; } + s = bfd_get_section_by_name (dynobj, ".dynbss"); + if (s && s->size == 0) + s->flags |= SEC_EXCLUDE; + + s = bfd_get_section_by_name (dynobj, ".rela.bss"); + if (s && s->size == 0) + s->flags |= SEC_EXCLUDE; + return TRUE; } @@ -4298,6 +4340,122 @@ elf32_bfinfdpic_always_size_sections (bfd *output_bfd, return TRUE; } +/* Check whether any of the relocations was optimized away, and + subtract it from the relocation or fixup count. */ +static bfd_boolean +_bfinfdpic_check_discarded_relocs (bfd *abfd, asection *sec, + struct bfd_link_info *info, + + bfd_boolean *changed) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; + Elf_Internal_Rela *rel, *erel; + + if ((sec->flags & SEC_RELOC) == 0 + || sec->reloc_count == 0) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym); + if (!elf_bad_symtab (abfd)) + sym_hashes_end -= symtab_hdr->sh_info; + + rel = elf_section_data (sec)->relocs; + + /* Now examine each relocation. */ + for (erel = rel + sec->reloc_count; rel < erel; rel++) + { + struct elf_link_hash_entry *h; + unsigned long r_symndx; + struct bfinfdpic_relocs_info *picrel; + struct _bfinfdpic_dynamic_got_info *dinfo; + + if (ELF32_R_TYPE (rel->r_info) != R_BFIN_BYTE4_DATA + && ELF32_R_TYPE (rel->r_info) != R_BFIN_FUNCDESC) + continue; + + if (_bfd_elf_section_offset (sec->output_section->owner, + info, sec, rel->r_offset) + != (bfd_vma)-1) + continue; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *)h->root.u.i.link; + } + + if (h != NULL) + picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info (info), + abfd, h, + rel->r_addend, NO_INSERT); + else + picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info (info), + abfd, r_symndx, + rel->r_addend, NO_INSERT); + + if (! picrel) + return FALSE; + + *changed = TRUE; + dinfo = bfinfdpic_dynamic_got_plt_info (info); + + _bfinfdpic_count_relocs_fixups (picrel, dinfo, TRUE); + if (ELF32_R_TYPE (rel->r_info) == R_BFIN_BYTE4_DATA) + picrel->relocs32--; + else /* we know (ELF32_R_TYPE (rel->r_info) == R_BFIN_FUNCDESC) */ + picrel->relocsfd--; + _bfinfdpic_count_relocs_fixups (picrel, dinfo, FALSE); + } + + return TRUE; +} + +static bfd_boolean +bfinfdpic_elf_discard_info (bfd *ibfd, + struct elf_reloc_cookie *cookie ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + bfd_boolean changed = FALSE; + asection *s; + bfd *obfd = NULL; + + /* Account for relaxation of .eh_frame section. */ + for (s = ibfd->sections; s; s = s->next) + if (s->sec_info_type == ELF_INFO_TYPE_EH_FRAME) + { + if (!_bfinfdpic_check_discarded_relocs (ibfd, s, info, &changed)) + return FALSE; + obfd = s->output_section->owner; + } + + if (changed) + { + struct _bfinfdpic_dynamic_got_plt_info gpinfo; + + memset (&gpinfo, 0, sizeof (gpinfo)); + memcpy (&gpinfo.g, bfinfdpic_dynamic_got_plt_info (info), + sizeof (gpinfo.g)); + + /* Clear GOT and PLT assignments. */ + htab_traverse (bfinfdpic_relocs_info (info), + _bfinfdpic_reset_got_plt_entries, + NULL); + + if (!_bfinfdpic_size_got_plt (obfd, &gpinfo)) + return FALSE; + } + + return TRUE; +} + static bfd_boolean elf32_bfinfdpic_modify_program_headers (bfd *output_bfd, struct bfd_link_info *info) @@ -4437,8 +4595,8 @@ elf32_bfinfdpic_finish_dynamic_sections (bfd *output_bfd, static bfd_boolean elf32_bfinfdpic_adjust_dynamic_symbol -(struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) +(struct bfd_link_info *info, + struct elf_link_hash_entry *h) { bfd * dynobj; @@ -4676,9 +4834,9 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info, if (! IS_FDPIC (abfd)) goto bad_reloc; /* Fall through. */ - case R_pcrel24: - case R_pcrel24_jump_l: - case R_byte4_data: + case R_BFIN_PCREL24: + case R_BFIN_PCREL24_JUMP_L: + case R_BFIN_BYTE4_DATA: if (IS_FDPIC (abfd) && ! dynobj) { elf_hash_table (info)->dynobj = dynobj = abfd; @@ -4722,8 +4880,8 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info, switch (ELF32_R_TYPE (rel->r_info)) { - case R_pcrel24: - case R_pcrel24_jump_l: + case R_BFIN_PCREL24: + case R_BFIN_PCREL24_JUMP_L: if (IS_FDPIC (abfd)) picrel->call++; break; @@ -4734,7 +4892,7 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info, picrel->relocs32--; /* Fall through. */ - case R_byte4_data: + case R_BFIN_BYTE4_DATA: if (! IS_FDPIC (abfd)) break; @@ -4797,10 +4955,10 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info, return FALSE; break; - case R_huimm16: - case R_luimm16: - case R_pcrel12_jump_s: - case R_pcrel10: + case R_BFIN_HUIMM16: + case R_BFIN_LUIMM16: + case R_BFIN_PCREL12_JUMP_S: + case R_BFIN_PCREL10: break; default: @@ -4942,11 +5100,12 @@ elf32_bfin_merge_private_bfd_data (bfd *ibfd, bfd *obfd) if (new_flags & EF_BFIN_FDPIC) new_flags &= ~EF_BFIN_PIC; -#ifdef DEBUG +#ifndef DEBUG + if (0) +#endif (*_bfd_error_handler) ("old_flags = 0x%.8lx, new_flags = 0x%.8lx, init = %s, filename = %s", old_flags, new_flags, elf_flags_init (obfd) ? "yes" : "no", bfd_get_filename (ibfd)); -#endif if (!elf_flags_init (obfd)) /* First call, no flags set. */ { @@ -4989,8 +5148,8 @@ struct bfin_link_hash_table { struct elf_link_hash_table root; - /* Small local sym to section mapping cache. */ - struct sym_sec_cache sym_sec; + /* Small local sym cache. */ + struct sym_cache sym_cache; }; #define bfin_hash_entry(ent) ((struct bfin_link_hash_entry *) (ent)) @@ -5030,13 +5189,14 @@ bfin_link_hash_table_create (bfd * abfd) if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, bfin_link_hash_newfunc, - sizeof (struct elf_link_hash_entry))) + sizeof (struct elf_link_hash_entry), + BFIN_ELF_DATA)) { free (ret); return NULL; } - ret->sym_sec.abfd = NULL; + ret->sym_cache.abfd = NULL; return &ret->root.root; } @@ -5116,8 +5276,9 @@ bfin_finish_dynamic_symbol (bfd * output_bfd, && (info->symbolic || h->dynindx == -1 || h->forced_local) && h->def_regular) { - fprintf(stderr, "*** check this relocation %s\n", __FUNCTION__); - rela.r_info = ELF32_R_INFO (0, R_pcrel24); + (*_bfd_error_handler) (_("*** check this relocation %s"), + __FUNCTION__); + rela.r_info = ELF32_R_INFO (0, R_BFIN_PCREL24); rela.r_addend = bfd_get_signed_32 (output_bfd, (sgot->contents + @@ -5128,7 +5289,7 @@ bfin_finish_dynamic_symbol (bfd * output_bfd, { bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + (h->got.offset & ~(bfd_vma) 1)); - rela.r_info = ELF32_R_INFO (h->dynindx, R_got); + rela.r_info = ELF32_R_INFO (h->dynindx, R_BFIN_GOT); rela.r_addend = 0; } @@ -5523,7 +5684,7 @@ bfd_bfin_elf32_create_embedded_relocs ( characters. */ /* We can only relocate absolute longword relocs at run time. */ - if (ELF32_R_TYPE (irel->r_info) != (int) R_byte4_data) + if (ELF32_R_TYPE (irel->r_info) != (int) R_BFIN_BYTE4_DATA) { *errmsg = _("unsupported reloc type"); bfd_set_error (bfd_error_bad_value); @@ -5600,6 +5761,7 @@ struct bfd_elf_special_section const elf32_bfin_special_sections[] = #define TARGET_LITTLE_SYM bfd_elf32_bfin_vec #define TARGET_LITTLE_NAME "elf32-bfin" #define ELF_ARCH bfd_arch_bfin +#define ELF_TARGET_ID BFIN_ELF_DATA #define ELF_MACHINE_CODE EM_BLACKFIN #define ELF_MAXPAGESIZE 0x1000 #define elf_symbol_leading_char '_' @@ -5643,7 +5805,7 @@ struct bfd_elf_special_section const elf32_bfin_special_sections[] = #define bfd_elf32_bfd_print_private_bfd_data \ elf32_bfin_print_private_bfd_data #define elf_backend_final_write_processing \ - elf32_bfin_final_write_processing + elf32_bfin_final_write_processing #define elf_backend_reloc_type_class elf32_bfin_reloc_type_class #define elf_backend_can_gc_sections 1 #define elf_backend_special_sections elf32_bfin_special_sections @@ -5703,6 +5865,9 @@ struct bfd_elf_special_section const elf32_bfin_special_sections[] = #define elf_backend_finish_dynamic_sections \ elf32_bfinfdpic_finish_dynamic_sections +#undef elf_backend_discard_info +#define elf_backend_discard_info \ + bfinfdpic_elf_discard_info #undef elf_backend_can_make_relative_eh_frame #define elf_backend_can_make_relative_eh_frame \ bfinfdpic_elf_use_relative_eh_frame