Line 1... |
Line 1... |
/* ADI Blackfin BFD support for 32-bit ELF.
|
/* ADI Blackfin BFD support for 32-bit ELF.
|
Copyright 2005, 2006, 2007 Free Software Foundation, Inc.
|
Copyright 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
|
|
This file is part of BFD, the Binary File Descriptor library.
|
This file is part of BFD, the Binary File Descriptor library.
|
|
|
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
Line 21... |
Line 21... |
#include "sysdep.h"
|
#include "sysdep.h"
|
#include "bfd.h"
|
#include "bfd.h"
|
#include "libbfd.h"
|
#include "libbfd.h"
|
#include "elf-bfd.h"
|
#include "elf-bfd.h"
|
#include "elf/bfin.h"
|
#include "elf/bfin.h"
|
#include "elf/dwarf2.h"
|
#include "dwarf2.h"
|
#include "hashtab.h"
|
#include "hashtab.h"
|
|
|
/* FUNCTION : bfin_pltpc_reloc
|
/* FUNCTION : bfin_pltpc_reloc
|
ABSTRACT : TODO : figure out how to handle pltpc relocs. */
|
ABSTRACT : TODO : figure out how to handle pltpc relocs. */
|
static bfd_reloc_status_type
|
static bfd_reloc_status_type
|
Line 419... |
Line 419... |
#define BFIN_ARELOC_MAX 0xF3
|
#define BFIN_ARELOC_MAX 0xF3
|
|
|
static reloc_howto_type bfin_howto_table [] =
|
static reloc_howto_type bfin_howto_table [] =
|
{
|
{
|
/* This reloc does nothing. . */
|
/* This reloc does nothing. . */
|
HOWTO (R_unused0, /* type. */
|
HOWTO (R_BFIN_UNUSED0, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
32, /* bitsize. */
|
32, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_bitfield, /* complain_on_overflow. */
|
complain_overflow_bitfield, /* complain_on_overflow. */
|
bfd_elf_generic_reloc, /* special_function. */
|
bfd_elf_generic_reloc, /* special_function. */
|
"R_unused0", /* name. */
|
"R_BFIN_UNUSED0", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0, /* dst_mask. */
|
0, /* dst_mask. */
|
FALSE), /* pcrel_offset. */
|
FALSE), /* pcrel_offset. */
|
|
|
HOWTO (R_pcrel5m2, /* type. */
|
HOWTO (R_BFIN_PCREL5M2, /* type. */
|
1, /* rightshift. */
|
1, /* rightshift. */
|
1, /* size (0 = byte, 1 = short, 2 = long).. */
|
1, /* size (0 = byte, 1 = short, 2 = long).. */
|
4, /* bitsize. */
|
4, /* bitsize. */
|
TRUE, /* pc_relative. */
|
TRUE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_unsigned, /* complain_on_overflow. */
|
complain_overflow_unsigned, /* complain_on_overflow. */
|
bfin_bfd_reloc, /* special_function. */
|
bfin_bfd_reloc, /* special_function. */
|
"R_pcrel5m2", /* name. */
|
"R_BFIN_PCREL5M2", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x0000000F, /* dst_mask. */
|
0x0000000F, /* dst_mask. */
|
FALSE), /* pcrel_offset. */
|
FALSE), /* pcrel_offset. */
|
|
|
HOWTO (R_unused1, /* type. */
|
HOWTO (R_BFIN_UNUSED1, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
32, /* bitsize. */
|
32, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_bitfield, /* complain_on_overflow. */
|
complain_overflow_bitfield, /* complain_on_overflow. */
|
bfd_elf_generic_reloc, /* special_function. */
|
bfd_elf_generic_reloc, /* special_function. */
|
"R_unused1", /* name. */
|
"R_BFIN_UNUSED1", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0, /* dst_mask. */
|
0, /* dst_mask. */
|
FALSE), /* pcrel_offset. */
|
FALSE), /* pcrel_offset. */
|
|
|
HOWTO (R_pcrel10, /* type. */
|
HOWTO (R_BFIN_PCREL10, /* type. */
|
1, /* rightshift. */
|
1, /* rightshift. */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
10, /* bitsize. */
|
10, /* bitsize. */
|
TRUE, /* pc_relative. */
|
TRUE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
bfin_bfd_reloc, /* special_function. */
|
bfin_bfd_reloc, /* special_function. */
|
"R_pcrel10", /* name. */
|
"R_BFIN_PCREL10", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x000003FF, /* dst_mask. */
|
0x000003FF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_pcrel12_jump, /* type. */
|
HOWTO (R_BFIN_PCREL12_JUMP, /* type. */
|
1, /* rightshift. */
|
1, /* rightshift. */
|
/* the offset is actually 13 bit
|
/* the offset is actually 13 bit
|
aligned on a word boundary so
|
aligned on a word boundary so
|
only 12 bits have to be used.
|
only 12 bits have to be used.
|
Right shift the rightmost bit.. */
|
Right shift the rightmost bit.. */
|
Line 487... |
Line 487... |
12, /* bitsize. */
|
12, /* bitsize. */
|
TRUE, /* pc_relative. */
|
TRUE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
bfin_bfd_reloc, /* special_function. */
|
bfin_bfd_reloc, /* special_function. */
|
"R_pcrel12_jump", /* name. */
|
"R_BFIN_PCREL12_JUMP", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x0FFF, /* dst_mask. */
|
0x0FFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_rimm16, /* type. */
|
HOWTO (R_BFIN_RIMM16, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
16, /* bitsize. */
|
16, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
bfin_imm16_reloc, /* special_function. */
|
bfin_imm16_reloc, /* special_function. */
|
"R_rimm16", /* name. */
|
"R_BFIN_RIMM16", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x0000FFFF, /* dst_mask. */
|
0x0000FFFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_luimm16, /* type. */
|
HOWTO (R_BFIN_LUIMM16, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
16, /* bitsize. */
|
16, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_dont, /* complain_on_overflow. */
|
complain_overflow_dont, /* complain_on_overflow. */
|
bfin_imm16_reloc, /* special_function. */
|
bfin_imm16_reloc, /* special_function. */
|
"R_luimm16", /* name. */
|
"R_BFIN_LUIMM16", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x0000FFFF, /* dst_mask. */
|
0x0000FFFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_huimm16, /* type. */
|
HOWTO (R_BFIN_HUIMM16, /* type. */
|
16, /* rightshift. */
|
16, /* rightshift. */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
16, /* bitsize. */
|
16, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_unsigned, /* complain_on_overflow. */
|
complain_overflow_unsigned, /* complain_on_overflow. */
|
bfin_imm16_reloc, /* special_function. */
|
bfin_imm16_reloc, /* special_function. */
|
"R_huimm16", /* name. */
|
"R_BFIN_HUIMM16", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x0000FFFF, /* dst_mask. */
|
0x0000FFFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_pcrel12_jump_s, /* type. */
|
HOWTO (R_BFIN_PCREL12_JUMP_S, /* type. */
|
1, /* rightshift. */
|
1, /* rightshift. */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
12, /* bitsize. */
|
12, /* bitsize. */
|
TRUE, /* pc_relative. */
|
TRUE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
bfin_bfd_reloc, /* special_function. */
|
bfin_bfd_reloc, /* special_function. */
|
"R_pcrel12_jump_s", /* name. */
|
"R_BFIN_PCREL12_JUMP_S", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x00000FFF, /* dst_mask. */
|
0x00000FFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_pcrel24_jump_x, /* type. */
|
HOWTO (R_BFIN_PCREL24_JUMP_X, /* type. */
|
1, /* rightshift. */
|
1, /* rightshift. */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
24, /* bitsize. */
|
24, /* bitsize. */
|
TRUE, /* pc_relative. */
|
TRUE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
bfin_pcrel24_reloc, /* special_function. */
|
bfin_pcrel24_reloc, /* special_function. */
|
"R_pcrel24_jump_x", /* name. */
|
"R_BFIN_PCREL24_JUMP_X", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x00FFFFFF, /* dst_mask. */
|
0x00FFFFFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_pcrel24, /* type. */
|
HOWTO (R_BFIN_PCREL24, /* type. */
|
1, /* rightshift. */
|
1, /* rightshift. */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
24, /* bitsize. */
|
24, /* bitsize. */
|
TRUE, /* pc_relative. */
|
TRUE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
bfin_pcrel24_reloc, /* special_function. */
|
bfin_pcrel24_reloc, /* special_function. */
|
"R_pcrel24", /* name. */
|
"R_BFIN_PCREL24", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x00FFFFFF, /* dst_mask. */
|
0x00FFFFFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_unusedb, /* type. */
|
HOWTO (R_BFIN_UNUSEDB, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
32, /* bitsize. */
|
32, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_dont, /* complain_on_overflow. */
|
complain_overflow_dont, /* complain_on_overflow. */
|
bfd_elf_generic_reloc, /* special_function. */
|
bfd_elf_generic_reloc, /* special_function. */
|
"R_unusedb", /* name. */
|
"R_BFIN_UNUSEDB", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0, /* dst_mask. */
|
0, /* dst_mask. */
|
FALSE), /* pcrel_offset. */
|
FALSE), /* pcrel_offset. */
|
|
|
HOWTO (R_unusedc, /* type. */
|
HOWTO (R_BFIN_UNUSEDC, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
32, /* bitsize. */
|
32, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_dont, /* complain_on_overflow. */
|
complain_overflow_dont, /* complain_on_overflow. */
|
bfd_elf_generic_reloc, /* special_function. */
|
bfd_elf_generic_reloc, /* special_function. */
|
"R_unusedc", /* name. */
|
"R_BFIN_UNUSEDC", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0, /* dst_mask. */
|
0, /* dst_mask. */
|
FALSE), /* pcrel_offset. */
|
FALSE), /* pcrel_offset. */
|
|
|
HOWTO (R_pcrel24_jump_l, /* type. */
|
HOWTO (R_BFIN_PCREL24_JUMP_L, /* type. */
|
1, /* rightshift. */
|
1, /* rightshift. */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
24, /* bitsize. */
|
24, /* bitsize. */
|
TRUE, /* pc_relative. */
|
TRUE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
bfin_pcrel24_reloc, /* special_function. */
|
bfin_pcrel24_reloc, /* special_function. */
|
"R_pcrel24_jump_l", /* name. */
|
"R_BFIN_PCREL24_JUMP_L", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x00FFFFFF, /* dst_mask. */
|
0x00FFFFFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_pcrel24_call_x, /* type. */
|
HOWTO (R_BFIN_PCREL24_CALL_X, /* type. */
|
1, /* rightshift. */
|
1, /* rightshift. */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
24, /* bitsize. */
|
24, /* bitsize. */
|
TRUE, /* pc_relative. */
|
TRUE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
bfin_pcrel24_reloc, /* special_function. */
|
bfin_pcrel24_reloc, /* special_function. */
|
"R_pcrel24_call_x", /* name. */
|
"R_BFIN_PCREL24_CALL_X", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x00FFFFFF, /* dst_mask. */
|
0x00FFFFFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_var_eq_symb, /* type. */
|
HOWTO (R_BFIN_VAR_EQ_SYMB, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
32, /* bitsize. */
|
32, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_bitfield, /* complain_on_overflow. */
|
complain_overflow_bitfield, /* complain_on_overflow. */
|
bfin_bfd_reloc, /* special_function. */
|
bfin_bfd_reloc, /* special_function. */
|
"R_var_eq_symb", /* name. */
|
"R_BFIN_VAR_EQ_SYMB", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0, /* dst_mask. */
|
0, /* dst_mask. */
|
FALSE), /* pcrel_offset. */
|
FALSE), /* pcrel_offset. */
|
|
|
HOWTO (R_byte_data, /* type. */
|
HOWTO (R_BFIN_BYTE_DATA, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
0, /* size (0 = byte, 1 = short, 2 = long). */
|
0, /* size (0 = byte, 1 = short, 2 = long). */
|
8, /* bitsize. */
|
8, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_unsigned, /* complain_on_overflow. */
|
complain_overflow_unsigned, /* complain_on_overflow. */
|
bfin_bfd_reloc, /* special_function. */
|
bfin_bfd_reloc, /* special_function. */
|
"R_byte_data", /* name. */
|
"R_BFIN_BYTE_DATA", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0xFF, /* dst_mask. */
|
0xFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_byte2_data, /* type. */
|
HOWTO (R_BFIN_BYTE2_DATA, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
16, /* bitsize. */
|
16, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
complain_overflow_signed, /* complain_on_overflow. */
|
bfin_bfd_reloc, /* special_function. */
|
bfin_bfd_reloc, /* special_function. */
|
"R_byte2_data", /* name. */
|
"R_BFIN_BYTE2_DATA", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0xFFFF, /* dst_mask. */
|
0xFFFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_byte4_data, /* type. */
|
HOWTO (R_BFIN_BYTE4_DATA, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
2, /* size (0 = byte, 1 = short, 2 = long). */
|
32, /* bitsize. */
|
32, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_unsigned, /* complain_on_overflow. */
|
complain_overflow_unsigned, /* complain_on_overflow. */
|
bfin_byte4_reloc, /* special_function. */
|
bfin_byte4_reloc, /* special_function. */
|
"R_byte4_data", /* name. */
|
"R_BFIN_BYTE4_DATA", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0xFFFFFFFF, /* dst_mask. */
|
0xFFFFFFFF, /* dst_mask. */
|
TRUE), /* pcrel_offset. */
|
TRUE), /* pcrel_offset. */
|
|
|
HOWTO (R_pcrel11, /* type. */
|
HOWTO (R_BFIN_PCREL11, /* type. */
|
1, /* rightshift. */
|
1, /* rightshift. */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
10, /* bitsize. */
|
10, /* bitsize. */
|
TRUE, /* pc_relative. */
|
TRUE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_unsigned, /* complain_on_overflow. */
|
complain_overflow_unsigned, /* complain_on_overflow. */
|
bfin_bfd_reloc, /* special_function. */
|
bfin_bfd_reloc, /* special_function. */
|
"R_pcrel11", /* name. */
|
"R_BFIN_PCREL11", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0, /* src_mask. */
|
0, /* src_mask. */
|
0x000003FF, /* dst_mask. */
|
0x000003FF, /* dst_mask. */
|
FALSE), /* pcrel_offset. */
|
FALSE), /* pcrel_offset. */
|
|
|
Line 929... |
Line 929... |
FALSE), /* pcrel_offset */
|
FALSE), /* pcrel_offset */
|
};
|
};
|
|
|
static reloc_howto_type bfin_gnuext_howto_table [] =
|
static reloc_howto_type bfin_gnuext_howto_table [] =
|
{
|
{
|
HOWTO (R_pltpc, /* type. */
|
HOWTO (R_BFIN_PLTPC, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
16, /* bitsize. */
|
16, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_bitfield, /* complain_on_overflow. */
|
complain_overflow_bitfield, /* complain_on_overflow. */
|
bfin_pltpc_reloc, /* special_function. */
|
bfin_pltpc_reloc, /* special_function. */
|
"R_pltpc", /* name. */
|
"R_BFIN_PLTPC", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0xffff, /* src_mask. */
|
0xffff, /* src_mask. */
|
0xffff, /* dst_mask. */
|
0xffff, /* dst_mask. */
|
FALSE), /* pcrel_offset. */
|
FALSE), /* pcrel_offset. */
|
|
|
HOWTO (R_got, /* type. */
|
HOWTO (R_BFIN_GOT, /* type. */
|
0, /* rightshift. */
|
0, /* rightshift. */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
1, /* size (0 = byte, 1 = short, 2 = long). */
|
16, /* bitsize. */
|
16, /* bitsize. */
|
FALSE, /* pc_relative. */
|
FALSE, /* pc_relative. */
|
0, /* bitpos. */
|
0, /* bitpos. */
|
complain_overflow_bitfield, /* complain_on_overflow. */
|
complain_overflow_bitfield, /* complain_on_overflow. */
|
bfd_elf_generic_reloc, /* special_function. */
|
bfd_elf_generic_reloc, /* special_function. */
|
"R_got", /* name. */
|
"R_BFIN_GOT", /* name. */
|
FALSE, /* partial_inplace. */
|
FALSE, /* partial_inplace. */
|
0x7fff, /* src_mask. */
|
0x7fff, /* src_mask. */
|
0x7fff, /* dst_mask. */
|
0x7fff, /* dst_mask. */
|
FALSE), /* pcrel_offset. */
|
FALSE), /* pcrel_offset. */
|
|
|
Line 996... |
Line 996... |
unsigned int bfin_reloc_val;
|
unsigned int bfin_reloc_val;
|
};
|
};
|
|
|
static const struct bfin_reloc_map bfin_reloc_map [] =
|
static const struct bfin_reloc_map bfin_reloc_map [] =
|
{
|
{
|
{ BFD_RELOC_NONE, R_unused0 },
|
{ BFD_RELOC_NONE, R_BFIN_UNUSED0 },
|
{ BFD_RELOC_BFIN_5_PCREL, R_pcrel5m2 },
|
{ BFD_RELOC_BFIN_5_PCREL, R_BFIN_PCREL5M2 },
|
{ BFD_RELOC_NONE, R_unused1 },
|
{ BFD_RELOC_NONE, R_BFIN_UNUSED1 },
|
{ BFD_RELOC_BFIN_10_PCREL, R_pcrel10 },
|
{ BFD_RELOC_BFIN_10_PCREL, R_BFIN_PCREL10 },
|
{ BFD_RELOC_BFIN_12_PCREL_JUMP, R_pcrel12_jump },
|
{ BFD_RELOC_BFIN_12_PCREL_JUMP, R_BFIN_PCREL12_JUMP },
|
{ BFD_RELOC_BFIN_16_IMM, R_rimm16 },
|
{ BFD_RELOC_BFIN_16_IMM, R_BFIN_RIMM16 },
|
{ BFD_RELOC_BFIN_16_LOW, R_luimm16 },
|
{ BFD_RELOC_BFIN_16_LOW, R_BFIN_LUIMM16 },
|
{ BFD_RELOC_BFIN_16_HIGH, R_huimm16 },
|
{ BFD_RELOC_BFIN_16_HIGH, R_BFIN_HUIMM16 },
|
{ BFD_RELOC_BFIN_12_PCREL_JUMP_S, R_pcrel12_jump_s },
|
{ BFD_RELOC_BFIN_12_PCREL_JUMP_S, R_BFIN_PCREL12_JUMP_S },
|
{ BFD_RELOC_24_PCREL, R_pcrel24 },
|
{ BFD_RELOC_24_PCREL, R_BFIN_PCREL24 },
|
{ BFD_RELOC_24_PCREL, R_pcrel24 },
|
{ BFD_RELOC_24_PCREL, R_BFIN_PCREL24 },
|
{ BFD_RELOC_BFIN_24_PCREL_JUMP_L, R_pcrel24_jump_l },
|
{ BFD_RELOC_BFIN_24_PCREL_JUMP_L, R_BFIN_PCREL24_JUMP_L },
|
{ BFD_RELOC_NONE, R_unusedb },
|
{ BFD_RELOC_NONE, R_BFIN_UNUSEDB },
|
{ BFD_RELOC_NONE, R_unusedc },
|
{ BFD_RELOC_NONE, R_BFIN_UNUSEDC },
|
{ BFD_RELOC_BFIN_24_PCREL_CALL_X, R_pcrel24_call_x },
|
{ BFD_RELOC_BFIN_24_PCREL_CALL_X, R_BFIN_PCREL24_CALL_X },
|
{ BFD_RELOC_8, R_byte_data },
|
{ BFD_RELOC_8, R_BFIN_BYTE_DATA },
|
{ BFD_RELOC_16, R_byte2_data },
|
{ BFD_RELOC_16, R_BFIN_BYTE2_DATA },
|
{ BFD_RELOC_32, R_byte4_data },
|
{ BFD_RELOC_32, R_BFIN_BYTE4_DATA },
|
{ BFD_RELOC_BFIN_11_PCREL, R_pcrel11 },
|
{ BFD_RELOC_BFIN_11_PCREL, R_BFIN_PCREL11 },
|
{ BFD_RELOC_BFIN_GOT, R_got },
|
{ BFD_RELOC_BFIN_GOT, R_BFIN_GOT },
|
{ BFD_RELOC_BFIN_PLTPC, R_pltpc },
|
{ BFD_RELOC_BFIN_PLTPC, R_BFIN_PLTPC },
|
|
|
{ BFD_RELOC_BFIN_GOT17M4, R_BFIN_GOT17M4 },
|
{ BFD_RELOC_BFIN_GOT17M4, R_BFIN_GOT17M4 },
|
{ BFD_RELOC_BFIN_GOTHI, R_BFIN_GOTHI },
|
{ BFD_RELOC_BFIN_GOTHI, R_BFIN_GOTHI },
|
{ BFD_RELOC_BFIN_GOTLO, R_BFIN_GOTLO },
|
{ BFD_RELOC_BFIN_GOTLO, R_BFIN_GOTLO },
|
{ BFD_RELOC_BFIN_FUNCDESC, R_BFIN_FUNCDESC },
|
{ BFD_RELOC_BFIN_FUNCDESC, R_BFIN_FUNCDESC },
|
Line 1121... |
Line 1121... |
|
|
/* Return TRUE if the name is a local label.
|
/* Return TRUE if the name is a local label.
|
bfin local labels begin with L$. */
|
bfin local labels begin with L$. */
|
static bfd_boolean
|
static bfd_boolean
|
bfin_is_local_label_name (
|
bfin_is_local_label_name (
|
bfd *abfd ATTRIBUTE_UNUSED,
|
bfd *abfd,
|
const char *label)
|
const char *label)
|
{
|
{
|
if (label[0] == 'L' && label[1] == '$' )
|
if (label[0] == 'L' && label[1] == '$' )
|
return TRUE;
|
return TRUE;
|
|
|
return _bfd_elf_is_local_label_name (abfd, label);
|
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;
|
static bfd_boolean
|
#define IS_FDPIC(bfd) ((bfd)->xvec == &bfd_elf32_bfinfdpic_vec)
|
bfin_check_relocs (bfd * abfd,
|
|
struct bfd_link_info *info,
|
/* An extension of the elf hash table data structure, containing some
|
asection *sec,
|
additional Blackfin-specific data. */
|
const Elf_Internal_Rela *relocs)
|
struct bfinfdpic_elf_link_hash_table
|
|
{
|
{
|
struct elf_link_hash_table elf;
|
bfd *dynobj;
|
|
Elf_Internal_Shdr *symtab_hdr;
|
/* A pointer to the .got section. */
|
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;
|
asection *sgot;
|
/* A pointer to the .rel.got section. */
|
asection *srelgot;
|
asection *sgotrel;
|
if (info->relocatable)
|
/* A pointer to the .rofixup section. */
|
return TRUE;
|
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. */
|
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);
|
|
|
#define bfinfdpic_hash_table(info) \
|
sgot = NULL;
|
((struct bfinfdpic_elf_link_hash_table *) ((info)->hash))
|
srelgot = NULL;
|
|
|
#define bfinfdpic_got_section(info) \
|
rel_end = relocs + sec->reloc_count;
|
(bfinfdpic_hash_table (info)->sgot)
|
for (rel = relocs; rel < rel_end; rel++)
|
#define bfinfdpic_gotrel_section(info) \
|
{
|
(bfinfdpic_hash_table (info)->sgotrel)
|
unsigned long r_symndx;
|
#define bfinfdpic_gotfixup_section(info) \
|
struct elf_link_hash_entry *h;
|
(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. */
|
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];
|
|
|
static struct bfd_link_hash_table *
|
switch (ELF32_R_TYPE (rel->r_info))
|
bfinfdpic_elf_link_hash_table_create (bfd *abfd)
|
|
{
|
{
|
struct bfinfdpic_elf_link_hash_table *ret;
|
/* This relocation describes the C++ object vtable hierarchy.
|
bfd_size_type amt = sizeof (struct bfinfdpic_elf_link_hash_table);
|
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;
|
|
|
ret = bfd_zalloc (abfd, amt);
|
/* This relocation describes which C++ vtable entries
|
if (ret == NULL)
|
are actually used. Record for later use during GC. */
|
return NULL;
|
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;
|
|
|
if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
|
case R_BFIN_GOT:
|
_bfd_elf_link_hash_newfunc,
|
if (h != NULL
|
sizeof (struct elf_link_hash_entry)))
|
&& strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
|
|
break;
|
|
/* Fall through. */
|
|
|
|
if (dynobj == NULL)
|
{
|
{
|
free (ret);
|
/* Create the .got section. */
|
return NULL;
|
elf_hash_table (info)->dynobj = dynobj = abfd;
|
|
if (!_bfd_elf_create_got_section (dynobj, info))
|
|
return FALSE;
|
}
|
}
|
|
|
return &ret->elf.root;
|
if (sgot == NULL)
|
|
{
|
|
sgot = bfd_get_section_by_name (dynobj, ".got");
|
|
BFD_ASSERT (sgot != NULL);
|
}
|
}
|
|
|
/* Decide whether a reference to a symbol can be resolved locally or
|
if (srelgot == NULL && (h != NULL || info->shared))
|
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)
|
|
|
|
/* 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
|
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
|
symbol. */
|
if (srelgot == NULL)
|
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 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:1;
|
|
unsigned gothilo:1;
|
|
/* Whether a FUNCDESC relocation references symbol+addend. */
|
|
unsigned fd:1;
|
|
/* Whether a FUNCDESC_GOT relocation references symbol+addend. */
|
|
unsigned fdgot17m4:1;
|
|
unsigned fdgothilo:1;
|
|
/* Whether a FUNCDESC_GOTOFF relocation references symbol+addend. */
|
|
unsigned fdgoff17m4:1;
|
|
unsigned fdgoffhilo:1;
|
|
/* 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:1;
|
|
/* Whether symbol+addend is referenced by a LABEL24 relocation. */
|
|
unsigned call:1;
|
|
/* Whether symbol+addend is referenced by a 32 or FUNCDESC_VALUE
|
|
relocation. */
|
|
unsigned sym:1;
|
|
/* 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;
|
|
|
|
/* The number of R_byte4_data, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE
|
|
relocations referencing the symbol. */
|
|
unsigned relocs32, relocsfd, relocsfdv;
|
|
|
|
/* The number of .rofixups entries and dynamic relocations allocated
|
|
for this symbol, minus any that might have already been used. */
|
|
unsigned fixups, dynrelocs;
|
|
|
|
/* 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;
|
|
};
|
|
|
|
/* 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_;
|
flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
|
|
| SEC_IN_MEMORY | SEC_LINKER_CREATED
|
return (entry->symndx == -1
|
| SEC_READONLY);
|
? (long) entry->d.h->root.root.hash
|
srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
|
: entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend;
|
flags);
|
|
if (srelgot == NULL
|
|
|| !bfd_set_section_alignment (dynobj, srelgot, 2))
|
|
return FALSE;
|
|
}
|
}
|
}
|
|
|
/* Test whether the key fields of two bfinfdpic_relocs_info entries are
|
if (h != NULL)
|
identical. */
|
|
static int
|
|
bfinfdpic_relocs_info_eq (const void *entry1, const void *entry2)
|
|
{
|
{
|
const struct bfinfdpic_relocs_info *e1 = entry1;
|
if (h->got.refcount == 0)
|
const struct bfinfdpic_relocs_info *e2 = entry2;
|
{
|
|
/* 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;
|
|
}
|
|
|
return e1->symndx == e2->symndx && e1->addend == e2->addend
|
/* Allocate space in the .got section. */
|
&& (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd);
|
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;
|
|
|
/* Find or create an entry in a hash table HT that matches the key
|
size = symtab_hdr->sh_info;
|
fields of the given ENTRY. If it's not found, memory for a new
|
size *= sizeof (bfd_signed_vma);
|
entry is allocated in ABFD's obstack. */
|
local_got_refcounts = ((bfd_signed_vma *)
|
static struct bfinfdpic_relocs_info *
|
bfd_zalloc (abfd, size));
|
bfinfdpic_relocs_info_find (struct htab *ht,
|
if (local_got_refcounts == NULL)
|
bfd *abfd,
|
return FALSE;
|
const struct bfinfdpic_relocs_info *entry,
|
elf_local_got_refcounts (abfd) = local_got_refcounts;
|
enum insert_option insert)
|
}
|
|
if (local_got_refcounts[r_symndx] == 0)
|
{
|
{
|
struct bfinfdpic_relocs_info **loc =
|
sgot->size += 4;
|
(struct bfinfdpic_relocs_info **) htab_find_slot (ht, entry, insert);
|
if (info->shared)
|
|
{
|
if (! loc)
|
/* If we are generating a shared object, we need to
|
return NULL;
|
output a R_68K_RELATIVE reloc so that the dynamic
|
|
linker can adjust this GOT entry. */
|
if (*loc)
|
srelgot->size += sizeof (Elf32_External_Rela);
|
return *loc;
|
}
|
|
}
|
*loc = bfd_zalloc (abfd, sizeof (**loc));
|
local_got_refcounts[r_symndx]++;
|
|
}
|
if (! *loc)
|
break;
|
return *loc;
|
|
|
|
(*loc)->symndx = entry->symndx;
|
default:
|
(*loc)->d = entry->d;
|
break;
|
(*loc)->addend = entry->addend;
|
}
|
(*loc)->plt_entry = (bfd_vma)-1;
|
}
|
(*loc)->lzplt_entry = (bfd_vma)-1;
|
|
|
|
return *loc;
|
return TRUE;
|
}
|
}
|
|
|
/* Obtain the address of the entry in HT associated with H's symbol +
|
static enum elf_reloc_type_class
|
addend, creating a new entry if none existed. ABFD is only used
|
elf32_bfin_reloc_type_class (const Elf_Internal_Rela * rela)
|
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;
|
switch ((int) ELF32_R_TYPE (rela->r_info))
|
|
{
|
entry.symndx = -1;
|
default:
|
entry.d.h = h;
|
return reloc_class_normal;
|
entry.addend = addend;
|
}
|
|
|
return bfinfdpic_relocs_info_find (ht, abfd, &entry, 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)
|
|
{
|
|
int r_type = ELF32_R_TYPE (rel->r_info);
|
|
|
/* Obtain the address of the entry in HT associated with the SYMNDXth
|
if (r_type == R_BFIN_PCREL24 || r_type == R_BFIN_PCREL24_JUMP_L)
|
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;
|
bfd_reloc_status_type r = bfd_reloc_ok;
|
|
bfd_vma x;
|
|
|
entry.symndx = symndx;
|
if (address > bfd_get_section_limit (input_bfd, input_section))
|
entry.d.abfd = abfd;
|
return bfd_reloc_outofrange;
|
entry.addend = addend;
|
|
|
|
return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
|
value += addend;
|
}
|
|
|
|
/* Merge fields set by check_relocs() of two entries that end up being
|
/* Perform usual pc-relative correction. */
|
mapped to the same (presumably global) symbol. */
|
value -= input_section->output_section->vma + input_section->output_offset;
|
|
value -= address;
|
|
|
inline static void
|
/* We are getting reloc_entry->address 2 byte off from
|
bfinfdpic_pic_merge_early_relocs_info (struct bfinfdpic_relocs_info *e2,
|
the start of instruction. Assuming absolute postion
|
struct bfinfdpic_relocs_info const *e1)
|
of the reloc data. But, following code had been written assuming
|
{
|
reloc address is starting at begining of instruction.
|
e2->got17m4 |= e1->got17m4;
|
To compensate that I have increased the value of
|
e2->gothilo |= e1->gothilo;
|
relocation by 1 (effectively 2) and used the addr -2 instead of addr. */
|
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;
|
|
}
|
|
|
|
/* Every block of 65535 lazy PLT entries shares a single call to the
|
value += 2;
|
resolver, inserted in the 32768th lazy PLT entry (i.e., entry #
|
address -= 2;
|
32767, counting from 0). All other lazy PLT entries branch to it
|
|
in a single instruction. */
|
|
|
|
#define LZPLT_RESOLVER_EXTRA 10
|
if ((value & 0xFF000000) != 0
|
#define LZPLT_NORMAL_SIZE 6
|
&& (value & 0xFF000000) != 0xFF000000)
|
#define LZPLT_ENTRIES 1362
|
r = bfd_reloc_overflow;
|
|
|
#define BFINFDPIC_LZPLT_BLOCK_SIZE ((bfd_vma) LZPLT_NORMAL_SIZE * LZPLT_ENTRIES + LZPLT_RESOLVER_EXTRA)
|
value >>= 1;
|
#define BFINFDPIC_LZPLT_RESOLV_LOC (LZPLT_NORMAL_SIZE * LZPLT_ENTRIES / 2)
|
|
|
|
/* Add a dynamic relocation to the SRELOC section. */
|
x = bfd_get_16 (input_bfd, contents + address);
|
|
x = (x & 0xff00) | ((value >> 16) & 0xff);
|
|
bfd_put_16 (input_bfd, x, contents + address);
|
|
|
inline static bfd_vma
|
x = bfd_get_16 (input_bfd, contents + address + 2);
|
_bfinfdpic_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset,
|
x = value & 0xFFFF;
|
int reloc_type, long dynindx, bfd_vma addend,
|
bfd_put_16 (input_bfd, x, contents + address + 2);
|
struct bfinfdpic_relocs_info *entry)
|
return r;
|
{
|
}
|
Elf_Internal_Rela outrel;
|
|
bfd_vma reloc_offset;
|
|
|
|
outrel.r_offset = offset;
|
return _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
|
outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
|
rel->r_offset, value, addend);
|
outrel.r_addend = addend;
|
|
|
|
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++;
|
|
|
|
/* If the entry's index is zero, this relocation was probably to a
|
static bfd_boolean
|
linkonce section that got discarded. We reserved a dynamic
|
bfin_relocate_section (bfd * output_bfd,
|
relocation, but it was for another entry than the one we got at
|
struct bfd_link_info *info,
|
the time of emitting the relocation. Unfortunately there's no
|
bfd * input_bfd,
|
simple way for us to catch this situation, since the relocation
|
asection * input_section,
|
is cleared right before calling relocate_section, at which point
|
bfd_byte * contents,
|
we no longer know what the relocation used to point to. */
|
Elf_Internal_Rela * relocs,
|
if (entry->symndx)
|
Elf_Internal_Sym * local_syms,
|
|
asection ** local_sections)
|
{
|
{
|
BFD_ASSERT (entry->dynrelocs > 0);
|
bfd *dynobj;
|
entry->dynrelocs--;
|
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;
|
|
|
return reloc_offset;
|
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);
|
|
|
/* Add a fixup to the ROFIXUP section. */
|
sgot = NULL;
|
|
|
static bfd_vma
|
rel = relocs;
|
_bfinfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset,
|
relend = relocs + input_section->reloc_count;
|
struct bfinfdpic_relocs_info *entry)
|
for (; rel < relend; rel++, i++)
|
{
|
{
|
bfd_vma fixup_offset;
|
int r_type;
|
|
reloc_howto_type *howto;
|
if (rofixup->flags & SEC_EXCLUDE)
|
unsigned long r_symndx;
|
return -1;
|
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;
|
|
|
fixup_offset = rofixup->reloc_count * 4;
|
r_type = ELF32_R_TYPE (rel->r_info);
|
if (rofixup->contents)
|
if (r_type < 0 || r_type >= 243)
|
{
|
{
|
BFD_ASSERT (fixup_offset < rofixup->size);
|
bfd_set_error (bfd_error_bad_value);
|
bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset);
|
return FALSE;
|
}
|
}
|
rofixup->reloc_count++;
|
|
|
|
if (entry && entry->symndx)
|
if (r_type == R_BFIN_GNU_VTENTRY
|
{
|
|| r_type == R_BFIN_GNU_VTINHERIT)
|
/* See discussion about symndx == 0 in _bfinfdpic_add_dyn_reloc
|
continue;
|
above. */
|
|
BFD_ASSERT (entry->fixups > 0);
|
|
entry->fixups--;
|
|
}
|
|
|
|
return fixup_offset;
|
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);
|
|
|
/* Find the segment number in which OSEC, and output section, is
|
h = NULL;
|
located. */
|
sym = NULL;
|
|
sec = NULL;
|
|
unresolved_reloc = FALSE;
|
|
|
static unsigned
|
if (r_symndx < symtab_hdr->sh_info)
|
_bfinfdpic_osec_to_segment (bfd *output_bfd, asection *osec)
|
|
{
|
{
|
Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec);
|
sym = local_syms + r_symndx;
|
|
sec = local_sections[r_symndx];
|
return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1;
|
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
|
}
|
}
|
|
else
|
inline static bfd_boolean
|
|
_bfinfdpic_osec_readonly_p (bfd *output_bfd, asection *osec)
|
|
{
|
{
|
unsigned seg = _bfinfdpic_osec_to_segment (output_bfd, osec);
|
bfd_boolean warned;
|
|
|
return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W);
|
|
}
|
|
|
|
/* Generate relocations for GOT entries, function descriptors, and
|
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
|
code for PLT and lazy PLT entries. */
|
r_symndx, symtab_hdr, sym_hashes,
|
|
h, sec, relocation,
|
|
unresolved_reloc, warned);
|
|
}
|
|
|
inline static bfd_boolean
|
if (sec != NULL && elf_discarded_section (sec))
|
_bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
|
{
|
bfd *output_bfd,
|
/* For relocs against symbols from removed linkonce sections,
|
struct bfd_link_info *info,
|
or sections discarded by a linker script, we just want the
|
asection *sec,
|
section contents zeroed. Avoid any special processing. */
|
Elf_Internal_Sym *sym,
|
_bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
|
bfd_vma addend)
|
rel->r_info = 0;
|
|
rel->r_addend = 0;
|
|
continue;
|
|
}
|
|
|
|
if (info->relocatable)
|
|
continue;
|
|
|
|
address = rel->r_offset;
|
|
|
|
/* Then, process normally. */
|
|
switch (r_type)
|
{
|
{
|
bfd_vma fd_lazy_rel_offset = (bfd_vma)-1;
|
case R_BFIN_GNU_VTINHERIT:
|
int dynindx = -1;
|
case R_BFIN_GNU_VTENTRY:
|
|
return bfd_reloc_ok;
|
|
|
if (entry->done)
|
case R_BFIN_GOT:
|
return TRUE;
|
/* Relocation is to the address of the entry for this symbol
|
entry->done = 1;
|
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 (entry->got_entry || entry->fdgot_entry || entry->fd_entry)
|
|
{
|
{
|
/* If the symbol is dynamic, consider it for dynamic
|
bfd_vma off;
|
relocations, otherwise decay to section + offset. */
|
|
if (entry->symndx == -1 && entry->d.h->dynindx != -1)
|
if (dynobj == NULL)
|
dynindx = entry->d.h->dynindx;
|
|
else
|
|
{
|
{
|
if (sec->output_section
|
/* Create the .got section. */
|
&& ! bfd_is_abs_section (sec->output_section)
|
elf_hash_table (info)->dynobj = dynobj = output_bfd;
|
&& ! bfd_is_und_section (sec->output_section))
|
if (!_bfd_elf_create_got_section (dynobj, info))
|
dynindx = elf_section_data (sec->output_section)->dynindx;
|
return FALSE;
|
else
|
|
dynindx = 0;
|
|
}
|
}
|
|
|
|
if (sgot == NULL)
|
|
{
|
|
sgot = bfd_get_section_by_name (dynobj, ".got");
|
|
BFD_ASSERT (sgot != NULL);
|
}
|
}
|
|
|
/* Generate relocation for GOT entry pointing to the symbol. */
|
if (h != NULL)
|
if (entry->got_entry)
|
|
{
|
{
|
int idx = dynindx;
|
bfd_boolean dyn;
|
bfd_vma ad = addend;
|
|
|
|
/* If the symbol is dynamic but binds locally, use
|
off = h->got.offset;
|
section+offset. */
|
BFD_ASSERT (off != (bfd_vma) - 1);
|
if (sec && (entry->symndx != -1
|
dyn = elf_hash_table (info)->dynamic_sections_created;
|
|| BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
|
|
|
if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
|
|
|| (info->shared
|
|
&& (info->symbolic
|
|
|| h->dynindx == -1
|
|
|| h->forced_local)
|
|
&& h->def_regular))
|
{
|
{
|
if (entry->symndx == -1)
|
/* This is actually a static link, or it is a
|
ad += entry->d.h->root.u.def.value;
|
-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
|
else
|
ad += sym->st_value;
|
{
|
ad += sec->output_offset;
|
bfd_put_32 (output_bfd, relocation,
|
if (sec->output_section && elf_section_data (sec->output_section))
|
sgot->contents + off);
|
idx = elf_section_data (sec->output_section)->dynindx;
|
h->got.offset |= 1;
|
|
}
|
|
}
|
else
|
else
|
idx = 0;
|
unresolved_reloc = FALSE;
|
}
|
}
|
|
else
|
|
{
|
|
BFD_ASSERT (local_got_offsets != NULL);
|
|
off = local_got_offsets[r_symndx];
|
|
BFD_ASSERT (off != (bfd_vma) - 1);
|
|
|
/* If we're linking an executable at a fixed address, we can
|
/* The offset must always be a multiple of 4. We use
|
omit the dynamic relocation as long as the symbol is local to
|
the least significant bit to record whether we have
|
this module. */
|
already generated the necessary reloc. */
|
if (info->executable && !info->pie
|
if ((off & 1) != 0)
|
&& (entry->symndx != -1
|
off &= ~1;
|
|| BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
|
else
|
{
|
{
|
if (sec)
|
bfd_put_32 (output_bfd, relocation, sgot->contents + off);
|
ad += sec->output_section->vma;
|
|
if (entry->symndx != -1
|
if (info->shared)
|
|| entry->d.h->root.type != bfd_link_hash_undefweak)
|
{
|
_bfinfdpic_add_rofixup (output_bfd,
|
asection *s;
|
bfinfdpic_gotfixup_section (info),
|
Elf_Internal_Rela outrel;
|
bfinfdpic_got_section (info)->output_section
|
bfd_byte *loc;
|
->vma
|
|
+ bfinfdpic_got_section (info)->output_offset
|
s = bfd_get_section_by_name (dynobj, ".rela.got");
|
+ bfinfdpic_got_initial_offset (info)
|
BFD_ASSERT (s != NULL);
|
+ entry->got_entry, entry);
|
|
|
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);
|
}
|
}
|
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_put_32 (output_bfd, ad,
|
local_got_offsets[r_symndx] |= 1;
|
bfinfdpic_got_section (info)->contents
|
}
|
+ bfinfdpic_got_initial_offset (info)
|
|
+ entry->got_entry);
|
|
}
|
}
|
|
|
/* Generate relocation for GOT entry pointing to a canonical
|
relocation = sgot->output_offset + off;
|
function descriptor. */
|
rel->r_addend = 0;
|
if (entry->fdgot_entry)
|
/* bfin : preg = [preg + 17bitdiv4offset] relocation is div by 4. */
|
|
relocation /= 4;
|
|
}
|
|
goto do_default;
|
|
|
|
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))
|
{
|
{
|
int reloc, idx;
|
(*_bfd_error_handler)
|
bfd_vma ad = 0;
|
(_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
|
|
input_bfd,
|
|
input_section, (long) rel->r_offset, h->root.root.string);
|
|
return FALSE;
|
|
}
|
|
|
if (! (entry->symndx == -1
|
if (r != bfd_reloc_ok)
|
&& 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
|
const char *name;
|
resolution because we are, or are linked with, a shared
|
|
library, emit a FUNCDESC relocation such that the dynamic
|
if (h != NULL)
|
linker will allocate the function descriptor. If the
|
name = h->root.root.string;
|
symbol needs a non-local function descriptor but binds
|
else
|
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;
|
name = bfd_elf_string_from_elf_section (input_bfd,
|
idx = elf_section_data (entry->d.h->root.u.def.section
|
symtab_hdr->sh_link,
|
->output_section)->dynindx;
|
sym->st_name);
|
ad = entry->d.h->root.u.def.section->output_offset
|
if (name == NULL)
|
+ entry->d.h->root.u.def.value;
|
return FALSE;
|
|
if (*name == '\0')
|
|
name = bfd_section_name (input_bfd, sec);
|
}
|
}
|
else if (entry->symndx == -1
|
|
&& ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h))
|
if (r == bfd_reloc_overflow)
|
{
|
{
|
reloc = R_BFIN_FUNCDESC;
|
if (!(info->callbacks->reloc_overflow
|
idx = dynindx;
|
(info, (h ? &h->root : NULL), name, howto->name,
|
ad = addend;
|
(bfd_vma) 0, input_bfd, input_section, rel->r_offset)))
|
if (ad)
|
|
return FALSE;
|
return FALSE;
|
}
|
}
|
else
|
else
|
{
|
{
|
/* Otherwise, we know we have a private function descriptor,
|
(*_bfd_error_handler)
|
so reference it directly. */
|
(_("%B(%A+0x%lx): reloc against `%s': error %d"),
|
if (elf_hash_table (info)->dynamic_sections_created)
|
input_bfd, input_section,
|
BFD_ASSERT (entry->privfd);
|
(long) rel->r_offset, name, (int) r);
|
reloc = R_byte4_data;
|
return FALSE;
|
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);
|
|
}
|
}
|
|
|
bfd_put_32 (output_bfd, ad,
|
return TRUE;
|
bfinfdpic_got_section (info)->contents
|
|
+ bfinfdpic_got_initial_offset (info)
|
|
+ entry->fdgot_entry);
|
|
}
|
}
|
|
|
/* Generate relocation to fill in a private function descriptor in
|
static asection *
|
the GOT. */
|
bfin_gc_mark_hook (asection * sec,
|
if (entry->fd_entry)
|
struct bfd_link_info *info,
|
|
Elf_Internal_Rela * rel,
|
|
struct elf_link_hash_entry *h,
|
|
Elf_Internal_Sym * sym)
|
{
|
{
|
int idx = dynindx;
|
if (h != NULL)
|
bfd_vma ad = addend;
|
switch (ELF32_R_TYPE (rel->r_info))
|
bfd_vma ofst;
|
|
long lowword, highword;
|
|
|
|
/* 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)
|
case R_BFIN_GNU_VTINHERIT:
|
ad += entry->d.h->root.u.def.value;
|
case R_BFIN_GNU_VTENTRY:
|
else
|
return NULL;
|
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
|
return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
|
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 we've omitted the dynamic relocation, just emit the fixed
|
/* Update the got entry reference counts for the section being removed. */
|
addresses of the symbol and of the local GOT base offset. */
|
|
if (info->executable && !info->pie && sec && sec->output_section)
|
static bfd_boolean
|
{
|
bfin_gc_sweep_hook (bfd * abfd,
|
lowword = ad;
|
struct bfd_link_info *info,
|
highword = bfinfdpic_got_section (info)->output_section->vma
|
asection * sec,
|
+ bfinfdpic_got_section (info)->output_offset
|
const Elf_Internal_Rela * relocs)
|
+ bfinfdpic_got_initial_offset (info);
|
|
}
|
|
else if (entry->lazyplt)
|
|
{
|
{
|
if (ad)
|
Elf_Internal_Shdr *symtab_hdr;
|
return FALSE;
|
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;
|
|
|
fd_lazy_rel_offset = ofst;
|
dynobj = elf_hash_table (info)->dynobj;
|
|
if (dynobj == NULL)
|
|
return TRUE;
|
|
|
/* A function descriptor used for lazy or local resolving is
|
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
initialized such that its high word contains the output
|
sym_hashes = elf_sym_hashes (abfd);
|
section index in which the PLT entries are located, and
|
local_got_refcounts = elf_local_got_refcounts (abfd);
|
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);
|
|
}
|
|
|
|
bfd_put_32 (output_bfd, lowword,
|
sgot = bfd_get_section_by_name (dynobj, ".got");
|
bfinfdpic_got_section (info)->contents
|
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
|
+ 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);
|
|
}
|
|
|
|
/* Generate code for the PLT entry. */
|
relend = relocs + sec->reloc_count;
|
if (entry->plt_entry != (bfd_vma) -1)
|
for (rel = relocs; rel < relend; rel++)
|
{
|
{
|
bfd_byte *plt_code = bfinfdpic_plt_section (info)->contents
|
unsigned long r_symndx;
|
+ entry->plt_entry;
|
struct elf_link_hash_entry *h;
|
|
|
BFD_ASSERT (entry->fd_entry);
|
|
|
|
/* Figure out what kind of PLT entry we need, depending on the
|
switch (ELF32_R_TYPE (rel->r_info))
|
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] */
|
case R_BFIN_GOT:
|
bfd_put_32 (output_bfd,
|
r_symndx = ELF32_R_SYM (rel->r_info);
|
0xe519 | ((entry->fd_entry << 14) & 0xFFFF0000),
|
if (r_symndx >= symtab_hdr->sh_info)
|
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;
|
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
|
P3 = P3 + P1;
|
if (h->got.refcount > 0)
|
P1 = [P3];
|
{
|
P3 = [P3 + 4]; */
|
--h->got.refcount;
|
bfd_put_32 (output_bfd,
|
if (h->got.refcount == 0)
|
0xe109 | (entry->fd_entry << 16),
|
{
|
plt_code);
|
/* We don't need the .got entry any more. */
|
bfd_put_32 (output_bfd,
|
sgot->size -= 4;
|
0xe149 | (entry->fd_entry & 0xFFFF0000),
|
srelgot->size -= sizeof (Elf32_External_Rela);
|
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);
|
|
}
|
}
|
|
}
|
/* Generate code for the lazy PLT entry. */
|
else if (local_got_refcounts != NULL)
|
if (entry->lzplt_entry != (bfd_vma) -1)
|
|
{
|
{
|
bfd_byte *lzplt_code = bfinfdpic_plt_section (info)->contents
|
if (local_got_refcounts[r_symndx] > 0)
|
+ entry->lzplt_entry;
|
|
bfd_vma resolverStub_addr;
|
|
|
|
bfd_put_32 (output_bfd, fd_lazy_rel_offset, lzplt_code);
|
|
lzplt_code += 4;
|
|
|
|
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 (entry->lzplt_entry == resolverStub_addr)
|
|
{
|
{
|
/* This is a lazy PLT entry that includes a resolver call.
|
--local_got_refcounts[r_symndx];
|
P2 = [P3];
|
if (local_got_refcounts[r_symndx] == 0)
|
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 */
|
/* We don't need the .got entry any more. */
|
bfd_put_16 (output_bfd,
|
sgot->size -= 4;
|
0x2000
|
if (info->shared)
|
| (((resolverStub_addr - entry->lzplt_entry)
|
srelgot->size -= sizeof (Elf32_External_Rela);
|
/ 2) & (((bfd_vma)1 << 12) - 1)),
|
}
|
lzplt_code);
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
}
|
}
|
}
|
}
|
|
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
|
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
|
/* Look through the relocs for a section during the first phase, and
|
additional Blackfin-specific data. */
|
allocate space in the global offset table or procedure linkage
|
struct bfinfdpic_elf_link_hash_table
|
table. */
|
|
|
|
static bfd_boolean
|
|
bfin_check_relocs (bfd * abfd,
|
|
struct bfd_link_info *info,
|
|
asection *sec,
|
|
const Elf_Internal_Rela *relocs)
|
|
{
|
{
|
bfd *dynobj;
|
struct elf_link_hash_table elf;
|
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;
|
|
asection *srelgot;
|
|
asection *sreloc;
|
|
if (info->relocatable)
|
|
return TRUE;
|
|
|
|
dynobj = elf_hash_table (info)->dynobj;
|
/* A pointer to the .got section. */
|
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
asection *sgot;
|
sym_hashes = elf_sym_hashes (abfd);
|
/* A pointer to the .rel.got section. */
|
local_got_refcounts = elf_local_got_refcounts (abfd);
|
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;
|
|
};
|
|
|
sgot = NULL;
|
/* Get the Blackfin ELF linker hash table from a link_info structure. */
|
srelgot = NULL;
|
|
sreloc = NULL;
|
|
|
|
rel_end = relocs + sec->reloc_count;
|
#define bfinfdpic_hash_table(info) \
|
for (rel = relocs; rel < rel_end; rel++)
|
((struct bfinfdpic_elf_link_hash_table *) ((info)->hash))
|
{
|
|
unsigned long r_symndx;
|
|
struct elf_link_hash_entry *h;
|
|
|
|
r_symndx = ELF32_R_SYM (rel->r_info);
|
#define bfinfdpic_got_section(info) \
|
if (r_symndx < symtab_hdr->sh_info)
|
(bfinfdpic_hash_table (info)->sgot)
|
h = NULL;
|
#define bfinfdpic_gotrel_section(info) \
|
else
|
(bfinfdpic_hash_table (info)->sgotrel)
|
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
|
#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)
|
|
|
switch (ELF32_R_TYPE (rel->r_info))
|
/* The name of the dynamic interpreter. This is put in the .interp
|
{
|
section. */
|
/* 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
|
#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
|
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:
|
#define DEFAULT_STACK_SIZE 0x20000
|
if (h != NULL
|
|
&& strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
|
|
break;
|
|
/* Fall through. */
|
|
|
|
if (dynobj == NULL)
|
/* This structure is used to collect the number of entries present in
|
|
each addressable range of the got. */
|
|
struct _bfinfdpic_dynamic_got_info
|
{
|
{
|
/* Create the .got section. */
|
/* Several bits of information about the current link. */
|
elf_hash_table (info)->dynobj = dynobj = abfd;
|
struct bfd_link_info *info;
|
if (!_bfd_elf_create_got_section (dynobj, info))
|
/* Total size needed for GOT entries within the 18- or 32-bit
|
return FALSE;
|
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;
|
|
};
|
|
|
if (sgot == NULL)
|
/* Create a Blackfin ELF linker hash table. */
|
{
|
|
sgot = bfd_get_section_by_name (dynobj, ".got");
|
|
BFD_ASSERT (sgot != NULL);
|
|
}
|
|
|
|
if (srelgot == NULL && (h != NULL || info->shared))
|
static struct bfd_link_hash_table *
|
{
|
bfinfdpic_elf_link_hash_table_create (bfd *abfd)
|
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
|
|
if (srelgot == NULL)
|
|
{
|
{
|
flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
|
struct bfinfdpic_elf_link_hash_table *ret;
|
| SEC_IN_MEMORY | SEC_LINKER_CREATED
|
bfd_size_type amt = sizeof (struct bfinfdpic_elf_link_hash_table);
|
| 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)
|
ret = bfd_zalloc (abfd, amt);
|
{
|
if (ret == NULL)
|
if (h->got.refcount == 0)
|
return NULL;
|
{
|
|
/* Make sure this symbol is output as a dynamic symbol. */
|
if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
|
if (h->dynindx == -1 && !h->forced_local)
|
_bfd_elf_link_hash_newfunc,
|
|
sizeof (struct elf_link_hash_entry)))
|
{
|
{
|
if (!bfd_elf_link_record_dynamic_symbol (info, h))
|
free (ret);
|
return FALSE;
|
return NULL;
|
}
|
}
|
|
|
/* Allocate space in the .got section. */
|
return &ret->elf.root;
|
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;
|
|
|
|
size = symtab_hdr->sh_info;
|
/* Decide whether a reference to a symbol can be resolved locally or
|
size *= sizeof (bfd_signed_vma);
|
not. If the symbol is protected, we want the local address, but
|
local_got_refcounts = ((bfd_signed_vma *)
|
its function descriptor must be assigned by the dynamic linker. */
|
bfd_zalloc (abfd, size));
|
#define BFINFDPIC_SYM_LOCAL(INFO, H) \
|
if (local_got_refcounts == NULL)
|
(_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \
|
return FALSE;
|
|| ! elf_hash_table (INFO)->dynamic_sections_created)
|
elf_local_got_refcounts (abfd) = local_got_refcounts;
|
#define BFINFDPIC_FUNCDESC_LOCAL(INFO, H) \
|
}
|
((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created)
|
if (local_got_refcounts[r_symndx] == 0)
|
|
|
/* 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
|
{
|
{
|
sgot->size += 4;
|
/* The index of the symbol, as stored in the relocation r_info, if
|
if (info->shared)
|
we have a local symbol; -1 otherwise. */
|
|
long symndx;
|
|
union
|
{
|
{
|
/* If we are generating a shared object, we need to
|
/* The input bfd in which the symbol is defined, if it's a local
|
output a R_68K_RELATIVE reloc so that the dynamic
|
symbol. */
|
linker can adjust this GOT entry. */
|
bfd *abfd;
|
srelgot->size += sizeof (Elf32_External_Rela);
|
/* 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). */
|
local_got_refcounts[r_symndx]++;
|
struct elf_link_hash_entry *h;
|
}
|
} d;
|
break;
|
/* The addend of the relocation that references the symbol. */
|
|
bfd_vma addend;
|
|
|
default:
|
/* The fields above are used to identify an entry. The fields below
|
break;
|
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;
|
|
|
return TRUE;
|
/* The number of R_BFIN_BYTE4_DATA, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE
|
}
|
relocations referencing the symbol. */
|
|
unsigned relocs32, relocsfd, relocsfdv;
|
|
|
static enum elf_reloc_type_class
|
/* The number of .rofixups entries and dynamic relocations allocated
|
elf32_bfin_reloc_type_class (const Elf_Internal_Rela * rela)
|
for this symbol, minus any that might have already been used. */
|
{
|
unsigned fixups, dynrelocs;
|
switch ((int) ELF32_R_TYPE (rela->r_info))
|
|
|
/* 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;
|
|
};
|
|
|
|
/* Compute a hash with the key fields of an bfinfdpic_relocs_info entry. */
|
|
static hashval_t
|
|
bfinfdpic_relocs_info_hash (const void *entry_)
|
{
|
{
|
default:
|
const struct bfinfdpic_relocs_info *entry = entry_;
|
return reloc_class_normal;
|
|
}
|
return (entry->symndx == -1
|
|
? (long) entry->d.h->root.root.hash
|
|
: entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend;
|
}
|
}
|
|
|
/* Relocate an Blackfin ELF section.
|
|
|
|
The RELOCATE_SECTION function is called by the new ELF backend linker
|
/* Test whether the key fields of two bfinfdpic_relocs_info entries are
|
to handle the relocations for a section.
|
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;
|
|
|
The relocs are always passed as Rela structures; if the section
|
return e1->symndx == e2->symndx && e1->addend == e2->addend
|
actually uses Rel structures, the r_addend field will always be
|
&& (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd);
|
zero.
|
}
|
|
|
This function is responsible for adjusting the section contents as
|
/* Find or create an entry in a hash table HT that matches the key
|
necessary, and (if using Rela relocs and generating a relocatable
|
fields of the given ENTRY. If it's not found, memory for a new
|
output file) adjusting the reloc addend as necessary.
|
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;
|
|
|
This function does not have to worry about setting the reloc
|
if (!ht)
|
address or the reloc symbol index.
|
return NULL;
|
|
|
LOCAL_SYMS is a pointer to the swapped in local symbols.
|
loc = (struct bfinfdpic_relocs_info **) htab_find_slot (ht, entry, insert);
|
|
|
LOCAL_SECTIONS is an array giving the section in the input file
|
if (! loc)
|
corresponding to the st_shndx field of each local symbol.
|
return NULL;
|
|
|
The global hash table entry for the global symbols can be found
|
if (*loc)
|
via elf_sym_hashes (input_bfd).
|
return *loc;
|
|
|
When generating relocatable output, this function must handle
|
*loc = bfd_zalloc (abfd, sizeof (**loc));
|
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
|
if (! *loc)
|
bfinfdpic_relocate_section (bfd * output_bfd,
|
return *loc;
|
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)
|
|
{
|
|
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);
|
|
|
|
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
|
(*loc)->symndx = entry->symndx;
|
sym_hashes = elf_sym_hashes (input_bfd);
|
(*loc)->d = entry->d;
|
relend = relocs + input_section->reloc_count;
|
(*loc)->addend = entry->addend;
|
|
(*loc)->plt_entry = (bfd_vma)-1;
|
|
(*loc)->lzplt_entry = (bfd_vma)-1;
|
|
|
isec_segment = _bfinfdpic_osec_to_segment (output_bfd,
|
return *loc;
|
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;
|
|
|
|
for (rel = relocs; rel < relend; rel ++)
|
/* 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)
|
{
|
{
|
reloc_howto_type *howto;
|
struct bfinfdpic_relocs_info entry;
|
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 (r_type == R_BFIN_GNU_VTINHERIT
|
entry.symndx = -1;
|
|| r_type == R_BFIN_GNU_VTENTRY)
|
entry.d.h = h;
|
continue;
|
entry.addend = addend;
|
|
|
r_symndx = ELF32_R_SYM (rel->r_info);
|
return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
|
howto = bfin_reloc_type_lookup (input_bfd, r_type);
|
|
if (howto == NULL)
|
|
{
|
|
bfd_set_error (bfd_error_bad_value);
|
|
return FALSE;
|
|
}
|
}
|
|
|
h = NULL;
|
/* Obtain the address of the entry in HT associated with the SYMNDXth
|
sym = NULL;
|
local symbol of the input bfd ABFD, plus the addend, creating a new
|
sec = NULL;
|
entry if none existed. */
|
|
inline static struct bfinfdpic_relocs_info *
|
if (r_symndx < symtab_hdr->sh_info)
|
bfinfdpic_relocs_info_for_local (struct htab *ht,
|
|
bfd *abfd,
|
|
long symndx,
|
|
bfd_vma addend,
|
|
enum insert_option insert)
|
{
|
{
|
sym = local_syms + r_symndx;
|
struct bfinfdpic_relocs_info entry;
|
osec = sec = local_sections [r_symndx];
|
|
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
|
|
|
|
name = bfd_elf_string_from_elf_section
|
entry.symndx = symndx;
|
(input_bfd, symtab_hdr->sh_link, sym->st_name);
|
entry.d.abfd = abfd;
|
name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
|
entry.addend = addend;
|
}
|
|
else
|
|
{
|
|
bfd_boolean warned;
|
|
bfd_boolean unresolved_reloc;
|
|
|
|
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
|
return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
|
r_symndx, symtab_hdr, sym_hashes,
|
|
h, sec, relocation,
|
|
unresolved_reloc, warned);
|
|
osec = sec;
|
|
}
|
}
|
|
|
if (sec != NULL && elf_discarded_section (sec))
|
/* 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)
|
{
|
{
|
/* For relocs against symbols from removed linkonce sections,
|
e2->got17m4 |= e1->got17m4;
|
or sections discarded by a linker script, we just want the
|
e2->gothilo |= e1->gothilo;
|
section contents zeroed. Avoid any special processing. */
|
e2->fd |= e1->fd;
|
_bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
|
e2->fdgot17m4 |= e1->fdgot17m4;
|
rel->r_info = 0;
|
e2->fdgothilo |= e1->fdgothilo;
|
rel->r_addend = 0;
|
e2->fdgoff17m4 |= e1->fdgoff17m4;
|
continue;
|
e2->fdgoffhilo |= e1->fdgoffhilo;
|
|
e2->gotoff |= e1->gotoff;
|
|
e2->call |= e1->call;
|
|
e2->sym |= e1->sym;
|
}
|
}
|
|
|
if (info->relocatable)
|
/* Every block of 65535 lazy PLT entries shares a single call to the
|
continue;
|
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. */
|
|
|
if (h != NULL
|
#define LZPLT_RESOLVER_EXTRA 10
|
&& (h->root.type == bfd_link_hash_defined
|
#define LZPLT_NORMAL_SIZE 6
|
|| h->root.type == bfd_link_hash_defweak)
|
#define LZPLT_ENTRIES 1362
|
&& !BFINFDPIC_SYM_LOCAL (info, h))
|
|
{
|
|
osec = sec = NULL;
|
|
relocation = 0;
|
|
}
|
|
|
|
switch (r_type)
|
#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)
|
|
|
|
/* Add a dynamic relocation to the SRELOC section. */
|
|
|
|
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)
|
{
|
{
|
case R_pcrel24:
|
Elf_Internal_Rela outrel;
|
case R_pcrel24_jump_l:
|
bfd_vma reloc_offset;
|
case R_byte4_data:
|
|
if (! IS_FDPIC (output_bfd))
|
|
goto non_fdpic;
|
|
|
|
case R_BFIN_GOT17M4:
|
outrel.r_offset = offset;
|
case R_BFIN_GOTHI:
|
outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
|
case R_BFIN_GOTLO:
|
outrel.r_addend = addend;
|
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,
|
reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rel);
|
osec, sym,
|
BFD_ASSERT (reloc_offset < sreloc->size);
|
rel->r_addend))
|
bfd_elf32_swap_reloc_out (output_bfd, &outrel,
|
|
sreloc->contents + reloc_offset);
|
|
sreloc->reloc_count++;
|
|
|
|
/* 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_error_handler)
|
BFD_ASSERT (entry->dynrelocs > 0);
|
(_("%B: relocation at `%A+0x%x' references symbol `%s' with nonzero addend"),
|
entry->dynrelocs--;
|
input_bfd, input_section, rel->r_offset, name);
|
}
|
return FALSE;
|
|
|
|
|
return reloc_offset;
|
}
|
}
|
|
|
break;
|
/* Add a fixup to the ROFIXUP section. */
|
|
|
default:
|
static bfd_vma
|
non_fdpic:
|
_bfinfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset,
|
picrel = NULL;
|
struct bfinfdpic_relocs_info *entry)
|
if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
|
|
{
|
{
|
info->callbacks->warning
|
bfd_vma fixup_offset;
|
(info, _("relocation references symbol not defined in the module"),
|
|
name, input_bfd, input_section, rel->r_offset);
|
if (rofixup->flags & SEC_EXCLUDE)
|
return FALSE;
|
return -1;
|
}
|
|
break;
|
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++;
|
|
|
switch (r_type)
|
if (entry && entry->symndx)
|
{
|
{
|
case R_pcrel24:
|
/* See discussion about symndx == 0 in _bfinfdpic_add_dyn_reloc
|
case R_pcrel24_jump_l:
|
above. */
|
check_segment[0] = isec_segment;
|
BFD_ASSERT (entry->fixups > 0);
|
if (! IS_FDPIC (output_bfd))
|
entry->fixups--;
|
check_segment[1] = isec_segment;
|
}
|
else if (picrel->plt)
|
|
|
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)
|
{
|
{
|
relocation = bfinfdpic_plt_section (info)->output_section->vma
|
Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec);
|
+ bfinfdpic_plt_section (info)->output_offset
|
|
+ picrel->plt_entry;
|
return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1;
|
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:
|
inline static bfd_boolean
|
case R_BFIN_GOTHI:
|
_bfinfdpic_osec_readonly_p (bfd *output_bfd, asection *osec)
|
case R_BFIN_GOTLO:
|
{
|
relocation = picrel->got_entry;
|
unsigned seg = _bfinfdpic_osec_to_segment (output_bfd, osec);
|
check_segment[0] = check_segment[1] = got_segment;
|
|
break;
|
|
|
|
case R_BFIN_FUNCDESC_GOT17M4:
|
return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W);
|
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:
|
/* Generate relocations for GOT entries, function descriptors, and
|
case R_BFIN_GOTOFF17M4:
|
code for PLT and lazy PLT entries. */
|
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:
|
inline static bfd_boolean
|
case R_BFIN_FUNCDESC_GOTOFFHI:
|
_bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
|
case R_BFIN_FUNCDESC_GOTOFFLO:
|
bfd *output_bfd,
|
relocation = picrel->fd_entry;
|
struct bfd_link_info *info,
|
check_segment[0] = check_segment[1] = got_segment;
|
asection *sec,
|
break;
|
Elf_Internal_Sym *sym,
|
|
bfd_vma addend)
|
|
|
case R_BFIN_FUNCDESC:
|
|
{
|
{
|
int dynindx;
|
bfd_vma fd_lazy_rel_offset = (bfd_vma)-1;
|
bfd_vma addend = rel->r_addend;
|
int dynindx = -1;
|
|
|
if (! (h && h->root.type == bfd_link_hash_undefweak
|
if (entry->done)
|
&& BFINFDPIC_SYM_LOCAL (info, h)))
|
return TRUE;
|
|
entry->done = 1;
|
|
|
|
if (entry->got_entry || entry->fdgot_entry || entry->fd_entry)
|
{
|
{
|
/* If the symbol is dynamic and there may be dynamic
|
/* If the symbol is dynamic, consider it for dynamic
|
symbol resolution because we are or are linked with a
|
relocations, otherwise decay to section + offset. */
|
shared library, emit a FUNCDESC relocation such that
|
if (entry->symndx == -1 && entry->d.h->dynindx != -1)
|
the dynamic linker will allocate the function
|
dynindx = entry->d.h->dynindx;
|
descriptor. If the symbol needs a non-local function
|
else
|
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
|
if (sec
|
->output_section)->dynindx;
|
&& sec->output_section
|
addend += h->root.u.def.section->output_offset
|
&& ! bfd_is_abs_section (sec->output_section)
|
+ h->root.u.def.value;
|
&& ! bfd_is_und_section (sec->output_section))
|
|
dynindx = elf_section_data (sec->output_section)->dynindx;
|
|
else
|
|
dynindx = 0;
|
}
|
}
|
else if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h))
|
}
|
|
|
|
/* Generate relocation for GOT entry pointing to the symbol. */
|
|
if (entry->got_entry)
|
{
|
{
|
if (addend)
|
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)))
|
{
|
{
|
info->callbacks->warning
|
if (entry->symndx == -1)
|
(info, _("R_BFIN_FUNCDESC references dynamic symbol with nonzero addend"),
|
ad += entry->d.h->root.u.def.value;
|
name, input_bfd, input_section, rel->r_offset);
|
|
return FALSE;
|
|
}
|
|
dynindx = h->dynindx;
|
|
}
|
|
else
|
else
|
{
|
ad += sym->st_value;
|
/* Otherwise, we know we have a private function
|
ad += sec->output_offset;
|
descriptor, so reference it directly. */
|
if (sec->output_section && elf_section_data (sec->output_section))
|
BFD_ASSERT (picrel->privfd);
|
idx = elf_section_data (sec->output_section)->dynindx;
|
r_type = R_byte4_data;
|
else
|
dynindx = elf_section_data (bfinfdpic_got_section (info)
|
idx = 0;
|
->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
|
/* If we're linking an executable at a fixed address, we can
|
the dynamic relocation. However, if we're linking an
|
omit the dynamic relocation as long as the symbol is local to
|
executable at a fixed location, we won't have emitted a
|
this module. */
|
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
|
if (info->executable && !info->pie
|
&& (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
|
&& (entry->symndx != -1
|
{
|
|| BFINFDPIC_SYM_LOCAL (info, entry->d.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
|
if (sec)
|
(info,
|
ad += sec->output_section->vma;
|
_("cannot emit fixups in read-only section"),
|
if (entry->symndx != -1
|
name, input_bfd, input_section, rel->r_offset);
|
|| entry->d.h->root.type != bfd_link_hash_undefweak)
|
return FALSE;
|
|
}
|
|
_bfinfdpic_add_rofixup (output_bfd,
|
_bfinfdpic_add_rofixup (output_bfd,
|
bfinfdpic_gotfixup_section
|
bfinfdpic_gotfixup_section (info),
|
(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
|
_bfd_elf_section_offset
|
(output_bfd, info,
|
(output_bfd, info,
|
input_section, rel->r_offset)
|
bfinfdpic_got_section (info),
|
+ input_section
|
bfinfdpic_got_initial_offset (info)
|
|
+ entry->got_entry)
|
|
+ bfinfdpic_got_section (info)
|
->output_section->vma
|
->output_section->vma
|
+ input_section->output_offset,
|
+ bfinfdpic_got_section (info)->output_offset,
|
picrel);
|
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);
|
}
|
}
|
else if ((bfd_get_section_flags (output_bfd,
|
|
input_section->output_section)
|
/* Generate relocation for GOT entry pointing to a canonical
|
& (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
|
function descriptor. */
|
|
if (entry->fdgot_entry)
|
{
|
{
|
bfd_vma offset;
|
int reloc, idx;
|
|
bfd_vma ad = 0;
|
|
|
if (_bfinfdpic_osec_readonly_p (output_bfd,
|
if (! (entry->symndx == -1
|
input_section
|
&& entry->d.h->root.type == bfd_link_hash_undefweak
|
->output_section))
|
&& BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
|
{
|
{
|
info->callbacks->warning
|
/* If the symbol is dynamic and there may be dynamic symbol
|
(info,
|
resolution because we are, or are linked with, a shared
|
_("cannot emit dynamic relocations in read-only section"),
|
library, emit a FUNCDESC relocation such that the dynamic
|
name, input_bfd, input_section, rel->r_offset);
|
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))
|
|
{
|
|
reloc = R_BFIN_FUNCDESC;
|
|
idx = dynindx;
|
|
ad = addend;
|
|
if (ad)
|
return FALSE;
|
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
|
else
|
_bfinfdpic_add_dyn_reloc (output_bfd,
|
{
|
bfinfdpic_gotrel_section (info),
|
/* Otherwise, we know we have a private function descriptor,
|
offset + input_section
|
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;
|
|
}
|
|
|
|
/* 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
|
->output_section->vma
|
+ input_section->output_offset,
|
+ bfinfdpic_got_section (info)
|
r_type,
|
->output_offset
|
dynindx, addend, picrel);
|
+ bfinfdpic_got_initial_offset (info)
|
|
+ entry->fdgot_entry, entry);
|
}
|
}
|
else
|
else
|
addend += bfinfdpic_got_section (info)->output_section->vma;
|
_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);
|
}
|
}
|
|
|
/* We want the addend in-place because dynamic
|
bfd_put_32 (output_bfd, ad,
|
relocations are REL. Setting relocation to it should
|
bfinfdpic_got_section (info)->contents
|
arrange for it to be installed. */
|
+ bfinfdpic_got_initial_offset (info)
|
relocation = addend - rel->r_addend;
|
+ entry->fdgot_entry);
|
}
|
}
|
check_segment[0] = check_segment[1] = got_segment;
|
|
break;
|
|
|
|
case R_byte4_data:
|
/* Generate relocation to fill in a private function descriptor in
|
if (! IS_FDPIC (output_bfd))
|
the GOT. */
|
{
|
if (entry->fd_entry)
|
check_segment[0] = check_segment[1] = -1;
|
|
break;
|
|
}
|
|
/* Fall through. */
|
|
case R_BFIN_FUNCDESC_VALUE:
|
|
{
|
{
|
int dynindx;
|
int idx = dynindx;
|
bfd_vma addend = rel->r_addend;
|
bfd_vma ad = addend;
|
bfd_vma offset;
|
bfd_vma ofst;
|
offset = _bfd_elf_section_offset (output_bfd, info,
|
long lowword, highword;
|
input_section, rel->r_offset);
|
|
|
|
/* If the symbol is dynamic but binds locally, use
|
/* If the symbol is dynamic but binds locally, use
|
section+offset. */
|
section+offset. */
|
if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
|
if (sec && (entry->symndx != -1
|
{
|
|| BFINFDPIC_SYM_LOCAL (info, entry->d.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)
|
if (entry->symndx == -1)
|
addend += h->root.u.def.value;
|
ad += entry->d.h->root.u.def.value;
|
else
|
else
|
addend += sym->st_value;
|
ad += sym->st_value;
|
if (osec)
|
ad += sec->output_offset;
|
addend += osec->output_offset;
|
if (sec->output_section && elf_section_data (sec->output_section))
|
if (osec && osec->output_section
|
idx = elf_section_data (sec->output_section)->dynindx;
|
&& ! bfd_is_abs_section (osec->output_section)
|
|
&& ! bfd_is_und_section (osec->output_section))
|
|
dynindx = elf_section_data (osec->output_section)->dynindx;
|
|
else
|
else
|
dynindx = 0;
|
idx = 0;
|
}
|
}
|
|
|
/* If we're linking an executable at a fixed address, we
|
/* If we're linking an executable at a fixed address, we can
|
can omit the dynamic relocation as long as the symbol
|
omit the dynamic relocation as long as the symbol is local to
|
is defined in the current link unit (which is implied
|
this module. */
|
by its output section not being NULL). */
|
if (info->executable && !info->pie
|
if (info->executable && !info->pie
|
&& (entry->symndx != -1 || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
|
&& (!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
|
if (sec)
|
(info,
|
ad += sec->output_section->vma;
|
_("cannot emit fixups in read-only section"),
|
ofst = 0;
|
name, input_bfd, input_section, rel->r_offset);
|
if (entry->symndx != -1
|
return FALSE;
|
|| entry->d.h->root.type != bfd_link_hash_undefweak)
|
}
|
|
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_add_rofixup (output_bfd,
|
bfinfdpic_gotfixup_section
|
bfinfdpic_gotfixup_section (info),
|
(info), -1, picrel);
|
bfinfdpic_got_section (info)
|
else
|
->output_section->vma
|
|
+ bfinfdpic_got_section (info)
|
|
->output_offset
|
|
+ bfinfdpic_got_initial_offset (info)
|
|
+ entry->fd_entry, entry);
|
_bfinfdpic_add_rofixup (output_bfd,
|
_bfinfdpic_add_rofixup (output_bfd,
|
bfinfdpic_gotfixup_section
|
bfinfdpic_gotfixup_section (info),
|
(info),
|
bfinfdpic_got_section (info)
|
offset + input_section
|
|
->output_section->vma
|
->output_section->vma
|
+ input_section->output_offset,
|
+ bfinfdpic_got_section (info)
|
picrel);
|
->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 (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 && sec && sec->output_section)
|
{
|
{
|
if (offset >= (bfd_vma)-2)
|
lowword = ad;
|
_bfinfdpic_add_rofixup
|
highword = bfinfdpic_got_section (info)->output_section->vma
|
(output_bfd,
|
+ bfinfdpic_got_section (info)->output_offset
|
bfinfdpic_gotfixup_section (info),
|
+ bfinfdpic_got_initial_offset (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 (entry->lazyplt)
|
|
{
|
|
if (ad)
|
|
return FALSE;
|
|
|
|
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);
|
}
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/* 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;
|
|
|
|
BFD_ASSERT (entry->fd_entry);
|
|
|
|
/* 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;
|
}
|
}
|
else
|
else
|
{
|
{
|
if ((bfd_get_section_flags (output_bfd,
|
/* P1.L = fd_entry; P1.H = fd_entry;
|
input_section->output_section)
|
P3 = P3 + P1;
|
& (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
|
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);
|
|
}
|
|
|
|
/* Generate code for the lazy PLT entry. */
|
|
if (entry->lzplt_entry != (bfd_vma) -1)
|
{
|
{
|
if (_bfinfdpic_osec_readonly_p (output_bfd,
|
bfd_byte *lzplt_code = bfinfdpic_plt_section (info)->contents
|
input_section
|
+ entry->lzplt_entry;
|
->output_section))
|
bfd_vma resolverStub_addr;
|
|
|
|
bfd_put_32 (output_bfd, fd_lazy_rel_offset, lzplt_code);
|
|
lzplt_code += 4;
|
|
|
|
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 (entry->lzplt_entry == resolverStub_addr)
|
{
|
{
|
info->callbacks->warning
|
/* This is a lazy PLT entry that includes a resolver call.
|
(info,
|
P2 = [P3];
|
_("cannot emit dynamic relocations in read-only section"),
|
R3 = [P3 + 4];
|
name, input_bfd, input_section, rel->r_offset);
|
JUMP (P2); */
|
return FALSE;
|
bfd_put_32 (output_bfd,
|
|
0xa05b915a,
|
|
lzplt_code);
|
|
bfd_put_16 (output_bfd, 0x0052, lzplt_code + 4);
|
}
|
}
|
/* 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
|
else
|
_bfinfdpic_add_dyn_reloc (output_bfd,
|
{
|
bfinfdpic_gotrel_section (info),
|
/* JUMP.S resolverStub */
|
offset
|
bfd_put_16 (output_bfd,
|
+ input_section
|
0x2000
|
->output_section->vma
|
| (((resolverStub_addr - entry->lzplt_entry)
|
+ input_section->output_offset,
|
/ 2) & (((bfd_vma)1 << 12) - 1)),
|
r_type, dynindx, addend, picrel);
|
lzplt_code);
|
}
|
}
|
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;
|
|
}
|
}
|
|
|
if (r_type == R_BFIN_FUNCDESC_VALUE && offset < (bfd_vma)-2)
|
return TRUE;
|
|
}
|
|
|
|
/* Relocate an Blackfin ELF section.
|
|
|
|
The RELOCATE_SECTION function is called by the new ELF backend linker
|
|
to handle the relocations for a section.
|
|
|
|
The relocs are always passed as Rela structures; if the section
|
|
actually uses Rel structures, the r_addend field will always be
|
|
zero.
|
|
|
|
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.
|
|
|
|
This function does not have to worry about setting the reloc
|
|
address or the reloc symbol index.
|
|
|
|
LOCAL_SYMS is a pointer to the swapped in local symbols.
|
|
|
|
LOCAL_SECTIONS is an array giving the section in the input file
|
|
corresponding to the st_shndx field of each local symbol.
|
|
|
|
The global hash table entry for the global symbols can be found
|
|
via elf_sym_hashes (input_bfd).
|
|
|
|
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
|
|
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)
|
|
{
|
|
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);
|
|
|
|
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
|
|
sym_hashes = elf_sym_hashes (input_bfd);
|
|
relend = relocs + input_section->reloc_count;
|
|
|
|
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;
|
|
|
|
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 (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)
|
{
|
{
|
/* If we've omitted the dynamic relocation, just emit
|
bfd_set_error (bfd_error_bad_value);
|
the fixed addresses of the symbol and of the local
|
return FALSE;
|
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:
|
h = NULL;
|
check_segment[0] = isec_segment;
|
sym = NULL;
|
check_segment[1] = sec
|
sec = NULL;
|
? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
|
|
: (unsigned)-1;
|
|
break;
|
|
}
|
|
|
|
if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd))
|
if (r_symndx < symtab_hdr->sh_info)
|
{
|
{
|
#if 1 /* If you take this out, remove the #error from fdpic-static-6.d
|
sym = local_syms + r_symndx;
|
in the ld testsuite. */
|
osec = sec = local_sections [r_symndx];
|
/* This helps catch problems in GCC while we can't do more
|
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
|
than static linking. The idea is to test whether the
|
|
input file basename is crt0.o only once. */
|
name = bfd_elf_string_from_elf_section
|
if (silence_segment_error == 1)
|
(input_bfd, symtab_hdr->sh_link, sym->st_name);
|
silence_segment_error =
|
name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
|
(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;
|
|
}
|
}
|
|
else
|
|
{
|
|
bfd_boolean warned;
|
|
bfd_boolean unresolved_reloc;
|
|
|
switch (r_type)
|
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))
|
{
|
{
|
case R_BFIN_GOTOFFHI:
|
/* For relocs against symbols from removed linkonce sections,
|
/* We need the addend to be applied before we shift the
|
or sections discarded by a linker script, we just want the
|
value right. */
|
section contents zeroed. Avoid any special processing. */
|
relocation += rel->r_addend;
|
_bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
|
/* Fall through. */
|
rel->r_info = 0;
|
case R_BFIN_GOTHI:
|
rel->r_addend = 0;
|
case R_BFIN_FUNCDESC_GOTHI:
|
continue;
|
case R_BFIN_FUNCDESC_GOTOFFHI:
|
}
|
relocation >>= 16;
|
|
/* Fall through. */
|
|
|
|
case R_BFIN_GOTLO:
|
if (info->relocatable)
|
case R_BFIN_FUNCDESC_GOTLO:
|
continue;
|
case R_BFIN_GOTOFFLO:
|
|
case R_BFIN_FUNCDESC_GOTOFFLO:
|
|
relocation &= 0xffff;
|
|
break;
|
|
|
|
default:
|
if (h != NULL
|
break;
|
&& (h->root.type == bfd_link_hash_defined
|
|
|| h->root.type == bfd_link_hash_defweak)
|
|
&& !BFINFDPIC_SYM_LOCAL (info, h))
|
|
{
|
|
osec = sec = NULL;
|
|
relocation = 0;
|
}
|
}
|
|
|
switch (r_type)
|
switch (r_type)
|
{
|
{
|
case R_pcrel24:
|
case R_BFIN_PCREL24:
|
case R_pcrel24_jump_l:
|
case R_BFIN_PCREL24_JUMP_L:
|
if (! IS_FDPIC (output_bfd) || ! picrel->plt)
|
case R_BFIN_BYTE4_DATA:
|
break;
|
if (! IS_FDPIC (output_bfd))
|
/* Fall through. */
|
goto non_fdpic;
|
|
|
/* 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_GOT17M4:
|
case R_BFIN_GOTHI:
|
case R_BFIN_GOTHI:
|
case R_BFIN_GOTLO:
|
case R_BFIN_GOTLO:
|
case R_BFIN_FUNCDESC_GOT17M4:
|
case R_BFIN_FUNCDESC_GOT17M4:
|
case R_BFIN_FUNCDESC_GOTHI:
|
case R_BFIN_FUNCDESC_GOTHI:
|
case R_BFIN_FUNCDESC_GOTLO:
|
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_GOTOFF17M4:
|
case R_BFIN_FUNCDESC_GOTOFFHI:
|
case R_BFIN_FUNCDESC_GOTOFFHI:
|
case R_BFIN_FUNCDESC_GOTOFFLO:
|
case R_BFIN_FUNCDESC_GOTOFFLO:
|
/* Note that we only want GOTOFFHI, not GOTOFFLO or GOTOFF17M4
|
case R_BFIN_FUNCDESC:
|
here, since we do want to apply the addend to the others.
|
case R_BFIN_FUNCDESC_VALUE:
|
Note that we've applied the addend to GOTOFFHI before we
|
if (h != NULL)
|
shifted it right. */
|
picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info
|
case R_BFIN_GOTOFFHI:
|
(info), input_bfd, h,
|
relocation -= rel->r_addend;
|
orig_addend, INSERT);
|
break;
|
else
|
|
/* In order to find the entry we created before, we must
|
default:
|
use the original addend, not the one that may have been
|
break;
|
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 (r_type == R_pcrel24
|
if (!_bfinfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info,
|
|| r_type == R_pcrel24_jump_l)
|
osec, sym,
|
|
rel->r_addend))
|
{
|
{
|
bfd_vma x;
|
(*_bfd_error_handler)
|
bfd_vma address = rel->r_offset;
|
(_("%B: relocation at `%A+0x%x' references symbol `%s' with nonzero addend"),
|
|
input_bfd, input_section, rel->r_offset, name);
|
relocation += rel->r_addend;
|
return FALSE;
|
|
|
/* Perform usual pc-relative correction. */
|
|
relocation -= input_section->output_section->vma + input_section->output_offset;
|
|
relocation -= address;
|
|
|
|
/* 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. */
|
|
|
|
relocation += 2;
|
|
address -= 2;
|
|
|
|
relocation >>= 1;
|
|
|
|
x = bfd_get_16 (input_bfd, contents + address);
|
|
x = (x & 0xff00) | ((relocation >> 16) & 0xff);
|
|
bfd_put_16 (input_bfd, x, contents + address);
|
|
|
|
x = bfd_get_16 (input_bfd, contents + address + 2);
|
|
x = relocation & 0xFFFF;
|
|
bfd_put_16 (input_bfd, x, contents + address + 2);
|
|
r = bfd_reloc_ok;
|
|
}
|
}
|
else
|
|
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
|
contents, rel->r_offset,
|
|
relocation, rel->r_addend);
|
|
|
|
if (r != bfd_reloc_ok)
|
break;
|
{
|
|
const char * msg = (const char *) NULL;
|
|
|
|
switch (r)
|
default:
|
|
non_fdpic:
|
|
picrel = NULL;
|
|
if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
|
{
|
{
|
case bfd_reloc_overflow:
|
info->callbacks->warning
|
r = info->callbacks->reloc_overflow
|
(info, _("relocation references symbol not defined in the module"),
|
(info, (h ? &h->root : NULL), name, howto->name,
|
name, input_bfd, input_section, rel->r_offset);
|
(bfd_vma) 0, input_bfd, input_section, rel->r_offset);
|
return FALSE;
|
|
}
|
break;
|
break;
|
|
}
|
|
|
case bfd_reloc_undefined:
|
switch (r_type)
|
r = info->callbacks->undefined_symbol
|
{
|
(info, name, input_bfd, input_section, rel->r_offset, TRUE);
|
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;
|
break;
|
|
|
case bfd_reloc_outofrange:
|
case R_BFIN_GOT17M4:
|
msg = _("internal error: out of range error");
|
case R_BFIN_GOTHI:
|
|
case R_BFIN_GOTLO:
|
|
relocation = picrel->got_entry;
|
|
check_segment[0] = check_segment[1] = got_segment;
|
break;
|
break;
|
|
|
case bfd_reloc_notsupported:
|
case R_BFIN_FUNCDESC_GOT17M4:
|
msg = _("internal error: unsupported relocation error");
|
case R_BFIN_FUNCDESC_GOTHI:
|
|
case R_BFIN_FUNCDESC_GOTLO:
|
|
relocation = picrel->fdgot_entry;
|
|
check_segment[0] = check_segment[1] = got_segment;
|
break;
|
break;
|
|
|
case bfd_reloc_dangerous:
|
case R_BFIN_GOTOFFHI:
|
msg = _("internal error: dangerous relocation");
|
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;
|
break;
|
|
|
default:
|
case R_BFIN_FUNCDESC_GOTOFF17M4:
|
msg = _("internal error: unknown error");
|
case R_BFIN_FUNCDESC_GOTOFFHI:
|
|
case R_BFIN_FUNCDESC_GOTOFFLO:
|
|
relocation = picrel->fd_entry;
|
|
check_segment[0] = check_segment[1] = got_segment;
|
break;
|
break;
|
}
|
|
|
|
if (msg)
|
case R_BFIN_FUNCDESC:
|
r = info->callbacks->warning
|
{
|
(info, msg, name, input_bfd, input_section, rel->r_offset);
|
int dynindx;
|
|
bfd_vma addend = rel->r_addend;
|
|
|
if (! r)
|
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;
|
return FALSE;
|
}
|
}
|
|
dynindx = h->dynindx;
|
}
|
}
|
|
else
|
return TRUE;
|
{
|
|
/* 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;
|
}
|
}
|
|
|
static bfd_boolean
|
/* If there is room for dynamic symbol resolution, emit
|
bfin_relocate_section (bfd * output_bfd,
|
the dynamic relocation. However, if we're linking an
|
struct bfd_link_info *info,
|
executable at a fixed location, we won't have emitted a
|
bfd * input_bfd,
|
dynamic symbol entry for the got section, so idx will
|
asection * input_section,
|
be zero, which means we can and should compute the
|
bfd_byte * contents,
|
address of the private descriptor ourselves. */
|
Elf_Internal_Rela * relocs,
|
if (info->executable && !info->pie
|
Elf_Internal_Sym * local_syms,
|
&& (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
|
asection ** local_sections)
|
|
{
|
{
|
bfd *dynobj;
|
bfd_vma offset;
|
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;
|
|
|
|
dynobj = elf_hash_table (info)->dynobj;
|
addend += bfinfdpic_got_section (info)->output_section->vma;
|
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
|
if ((bfd_get_section_flags (output_bfd,
|
sym_hashes = elf_sym_hashes (input_bfd);
|
input_section->output_section)
|
local_got_offsets = elf_local_got_offsets (input_bfd);
|
& (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;
|
|
}
|
|
|
sgot = NULL;
|
offset = _bfd_elf_section_offset
|
sreloc = NULL;
|
(output_bfd, info,
|
|
input_section, rel->r_offset);
|
|
|
rel = relocs;
|
if (offset != (bfd_vma)-1)
|
relend = relocs + input_section->reloc_count;
|
_bfinfdpic_add_rofixup (output_bfd,
|
for (; rel < relend; rel++, i++)
|
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))
|
{
|
{
|
int r_type;
|
bfd_vma offset;
|
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;
|
|
|
|
r_type = ELF32_R_TYPE (rel->r_info);
|
if (_bfinfdpic_osec_readonly_p (output_bfd,
|
if (r_type < 0 || r_type >= 243)
|
input_section
|
|
->output_section))
|
{
|
{
|
bfd_set_error (bfd_error_bad_value);
|
info->callbacks->warning
|
|
(info,
|
|
_("cannot emit dynamic relocations in read-only section"),
|
|
name, input_bfd, input_section, rel->r_offset);
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
offset = _bfd_elf_section_offset (output_bfd, info,
|
|
input_section, rel->r_offset);
|
|
|
if (r_type == R_BFIN_GNU_VTENTRY
|
if (offset != (bfd_vma)-1)
|
|| r_type == R_BFIN_GNU_VTINHERIT)
|
_bfinfdpic_add_dyn_reloc (output_bfd,
|
continue;
|
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;
|
|
}
|
|
|
howto = bfin_reloc_type_lookup (input_bfd, r_type);
|
/* We want the addend in-place because dynamic
|
if (howto == NULL)
|
relocations are REL. Setting relocation to it should
|
{
|
arrange for it to be installed. */
|
bfd_set_error (bfd_error_bad_value);
|
relocation = addend - rel->r_addend;
|
return FALSE;
|
|
}
|
}
|
r_symndx = ELF32_R_SYM (rel->r_info);
|
check_segment[0] = check_segment[1] = got_segment;
|
|
break;
|
|
|
h = NULL;
|
case R_BFIN_BYTE4_DATA:
|
sym = NULL;
|
if (! IS_FDPIC (output_bfd))
|
sec = NULL;
|
{
|
unresolved_reloc = 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 (r_symndx < symtab_hdr->sh_info)
|
/* If the symbol is dynamic but binds locally, use
|
|
section+offset. */
|
|
if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
|
{
|
{
|
sym = local_syms + r_symndx;
|
if (addend && r_type == R_BFIN_FUNCDESC_VALUE)
|
sec = local_sections[r_symndx];
|
{
|
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
|
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
|
else
|
{
|
{
|
bfd_boolean warned;
|
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 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)
|
|
{
|
|
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);
|
|
|
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
|
if (r_type == R_BFIN_FUNCDESC_VALUE)
|
r_symndx, symtab_hdr, sym_hashes,
|
_bfinfdpic_add_rofixup
|
h, sec, relocation,
|
(output_bfd,
|
unresolved_reloc, warned);
|
bfinfdpic_gotfixup_section (info),
|
|
offset + input_section->output_section->vma
|
|
+ input_section->output_offset + 4, picrel);
|
}
|
}
|
|
|
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;
|
|
}
|
}
|
|
}
|
if (info->relocatable)
|
}
|
continue;
|
else
|
|
|
address = rel->r_offset;
|
|
|
|
/* Then, process normally. */
|
|
switch (r_type)
|
|
{
|
{
|
case R_BFIN_GNU_VTINHERIT:
|
if ((bfd_get_section_flags (output_bfd,
|
case R_BFIN_GNU_VTENTRY:
|
input_section->output_section)
|
return bfd_reloc_ok;
|
& (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
|
|
|
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. */
|
|
|
|
{
|
{
|
bfd_vma off;
|
if (_bfinfdpic_osec_readonly_p (output_bfd,
|
|
input_section
|
if (dynobj == NULL)
|
->output_section))
|
{
|
{
|
/* Create the .got section. */
|
info->callbacks->warning
|
elf_hash_table (info)->dynobj = dynobj = output_bfd;
|
(info,
|
if (!_bfd_elf_create_got_section (dynobj, info))
|
_("cannot emit dynamic relocations in read-only section"),
|
|
name, input_bfd, input_section, rel->r_offset);
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
if (sgot == NULL)
|
if (offset != (bfd_vma)-1)
|
{
|
_bfinfdpic_add_dyn_reloc (output_bfd,
|
sgot = bfd_get_section_by_name (dynobj, ".got");
|
bfinfdpic_gotrel_section (info),
|
BFD_ASSERT (sgot != NULL);
|
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;
|
}
|
}
|
|
|
if (h != NULL)
|
if (r_type == R_BFIN_FUNCDESC_VALUE)
|
{
|
|
bfd_boolean dyn;
|
|
|
|
off = h->got.offset;
|
|
BFD_ASSERT (off != (bfd_vma) - 1);
|
|
dyn = elf_hash_table (info)->dynamic_sections_created;
|
|
|
|
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
|
/* If we've omitted the dynamic relocation, just emit
|
-Bsymbolic link and the symbol is defined
|
the fixed addresses of the symbol and of the local
|
locally, or the symbol was forced to be local
|
GOT base offset. */
|
because of a version file.. We must initialize
|
if (info->executable && !info->pie
|
this entry in the global offset table. Since
|
&& (!h || BFINFDPIC_SYM_LOCAL (info, h)))
|
the offset must always be a multiple of 4, we
|
bfd_put_32 (output_bfd,
|
use the least significant bit to record whether
|
bfinfdpic_got_section (info)->output_section->vma
|
we have initialized it already.
|
+ bfinfdpic_got_section (info)->output_offset
|
|
+ bfinfdpic_got_initial_offset (info),
|
When doing a dynamic link, we create a .rela.got
|
contents + rel->r_offset + 4);
|
relocation entry to initialize the value. This
|
|
is done in the finish_dynamic_symbol routine. */
|
|
if ((off & 1) != 0)
|
|
off &= ~1;
|
|
else
|
else
|
{
|
/* A function descriptor used for lazy or local
|
bfd_put_32 (output_bfd, relocation,
|
resolving is initialized such that its high word
|
sgot->contents + off);
|
contains the output section index in which the
|
h->got.offset |= 1;
|
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);
|
}
|
}
|
}
|
}
|
else
|
check_segment[0] = check_segment[1] = got_segment;
|
unresolved_reloc = FALSE;
|
break;
|
|
|
|
default:
|
|
check_segment[0] = isec_segment;
|
|
check_segment[1] = sec
|
|
? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
|
|
: (unsigned)-1;
|
|
break;
|
}
|
}
|
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
|
if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd))
|
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);
|
#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;
|
|
}
|
|
|
if (info->shared)
|
switch (r_type)
|
{
|
{
|
asection *s;
|
case R_BFIN_GOTOFFHI:
|
Elf_Internal_Rela outrel;
|
/* We need the addend to be applied before we shift the
|
bfd_byte *loc;
|
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. */
|
|
|
s = bfd_get_section_by_name (dynobj, ".rela.got");
|
case R_BFIN_GOTLO:
|
BFD_ASSERT (s != NULL);
|
case R_BFIN_FUNCDESC_GOTLO:
|
|
case R_BFIN_GOTOFFLO:
|
|
case R_BFIN_FUNCDESC_GOTOFFLO:
|
|
relocation &= 0xffff;
|
|
break;
|
|
|
outrel.r_offset = (sgot->output_section->vma
|
default:
|
+ sgot->output_offset + off);
|
break;
|
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);
|
|
}
|
}
|
|
|
local_got_offsets[r_symndx] |= 1;
|
switch (r_type)
|
}
|
{
|
|
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;
|
}
|
}
|
|
|
relocation = sgot->output_offset + off;
|
r = bfin_final_link_relocate (rel, howto, input_bfd, input_section,
|
rel->r_addend = 0;
|
contents, rel->r_offset,
|
/* bfin : preg = [preg + 17bitdiv4offset] relocation is div by 4. */
|
relocation, rel->r_addend);
|
relocation /= 4;
|
|
}
|
|
goto do_default;
|
|
|
|
case R_pcrel24:
|
if (r != bfd_reloc_ok)
|
case R_pcrel24_jump_l:
|
|
{
|
{
|
bfd_vma x;
|
const char * msg = (const char *) NULL;
|
|
|
relocation += rel->r_addend;
|
|
|
|
/* Perform usual pc-relative correction. */
|
|
relocation -= input_section->output_section->vma + input_section->output_offset;
|
|
relocation -= address;
|
|
|
|
/* We are getting reloc_entry->address 2 byte off from
|
switch (r)
|
the start of instruction. Assuming absolute postion
|
{
|
of the reloc data. But, following code had been written assuming
|
case bfd_reloc_overflow:
|
reloc address is starting at begining of instruction.
|
r = info->callbacks->reloc_overflow
|
To compensate that I have increased the value of
|
(info, (h ? &h->root : NULL), name, howto->name,
|
relocation by 1 (effectively 2) and used the addr -2 instead of addr. */
|
(bfd_vma) 0, input_bfd, input_section, rel->r_offset);
|
|
break;
|
|
|
relocation += 2;
|
case bfd_reloc_undefined:
|
address -= 2;
|
r = info->callbacks->undefined_symbol
|
|
(info, name, input_bfd, input_section, rel->r_offset, TRUE);
|
|
break;
|
|
|
relocation >>= 1;
|
case bfd_reloc_outofrange:
|
|
msg = _("internal error: out of range error");
|
|
break;
|
|
|
x = bfd_get_16 (input_bfd, contents + address);
|
case bfd_reloc_notsupported:
|
x = (x & 0xff00) | ((relocation >> 16) & 0xff);
|
msg = _("internal error: unsupported relocation error");
|
bfd_put_16 (input_bfd, x, contents + address);
|
break;
|
|
|
x = bfd_get_16 (input_bfd, contents + address + 2);
|
case bfd_reloc_dangerous:
|
x = relocation & 0xFFFF;
|
msg = _("internal error: dangerous relocation");
|
bfd_put_16 (input_bfd, x, contents + address + 2);
|
|
r = bfd_reloc_ok;
|
|
}
|
|
break;
|
break;
|
|
|
default:
|
default:
|
do_default:
|
msg = _("internal error: unknown error");
|
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
|
contents, address,
|
|
relocation, rel->r_addend);
|
|
|
|
break;
|
break;
|
}
|
}
|
|
|
/* Dynamic relocs are not propagated for SEC_DEBUGGING sections
|
if (msg)
|
because such sections are not SEC_ALLOC and thus ld.so will
|
r = info->callbacks->warning
|
not process them. */
|
(info, msg, name, input_bfd, input_section, rel->r_offset);
|
if (unresolved_reloc
|
|
&& !((input_section->flags & SEC_DEBUGGING) != 0 && h->def_dynamic))
|
|
{
|
|
(*_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;
|
|
}
|
|
|
|
if (r != bfd_reloc_ok)
|
|
{
|
|
const char *name;
|
|
|
|
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 (r == bfd_reloc_overflow)
|
if (! r)
|
{
|
|
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 FALSE;
|
}
|
}
|
}
|
}
|
}
|
|
|
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
static asection *
|
/* Update the relocation information for the relocations of the section
|
bfin_gc_mark_hook (asection * sec,
|
being removed. */
|
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 got entry reference counts for the section being removed. */
|
|
|
|
static bfd_boolean
|
static bfd_boolean
|
bfin_gc_sweep_hook (bfd * abfd,
|
bfinfdpic_gc_sweep_hook (bfd *abfd,
|
struct bfd_link_info *info,
|
struct bfd_link_info *info,
|
asection * sec,
|
asection * sec,
|
const Elf_Internal_Rela * relocs)
|
const Elf_Internal_Rela * relocs)
|
{
|
{
|
Elf_Internal_Shdr *symtab_hdr;
|
Elf_Internal_Shdr *symtab_hdr;
|
struct elf_link_hash_entry **sym_hashes;
|
struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
|
bfd_signed_vma *local_got_refcounts;
|
const Elf_Internal_Rela *rel;
|
const Elf_Internal_Rela *rel, *relend;
|
const Elf_Internal_Rela *rel_end;
|
bfd *dynobj;
|
struct bfinfdpic_relocs_info *picrel;
|
asection *sgot;
|
|
asection *srelgot;
|
|
|
|
dynobj = elf_hash_table (info)->dynobj;
|
BFD_ASSERT (IS_FDPIC (abfd));
|
if (dynobj == NULL)
|
|
return TRUE;
|
|
|
|
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
sym_hashes = elf_sym_hashes (abfd);
|
sym_hashes = elf_sym_hashes (abfd);
|
local_got_refcounts = elf_local_got_refcounts (abfd);
|
sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
|
|
if (!elf_bad_symtab (abfd))
|
sgot = bfd_get_section_by_name (dynobj, ".got");
|
sym_hashes_end -= symtab_hdr->sh_info;
|
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
|
|
|
|
relend = relocs + sec->reloc_count;
|
rel_end = relocs + sec->reloc_count;
|
for (rel = relocs; rel < relend; rel++)
|
for (rel = relocs; rel < rel_end; rel++)
|
{
|
{
|
unsigned long r_symndx;
|
|
struct elf_link_hash_entry *h;
|
struct elf_link_hash_entry *h;
|
|
unsigned long r_symndx;
|
|
|
switch (ELF32_R_TYPE (rel->r_info))
|
|
{
|
|
case R_got:
|
|
r_symndx = ELF32_R_SYM (rel->r_info);
|
r_symndx = ELF32_R_SYM (rel->r_info);
|
if (r_symndx >= symtab_hdr->sh_info)
|
if (r_symndx < symtab_hdr->sh_info)
|
{
|
h = NULL;
|
|
else
|
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
|
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
|
if (h->got.refcount > 0)
|
|
{
|
if (h != NULL)
|
--h->got.refcount;
|
picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info (info),
|
if (h->got.refcount == 0)
|
abfd, h,
|
{
|
rel->r_addend, NO_INSERT);
|
/* We don't need the .got entry any more. */
|
else
|
sgot->size -= 4;
|
picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info
|
srelgot->size -= sizeof (Elf32_External_Rela);
|
(info), abfd, r_symndx,
|
}
|
rel->r_addend, NO_INSERT);
|
}
|
|
}
|
if (!picrel)
|
else if (local_got_refcounts != NULL)
|
return TRUE;
|
{
|
|
if (local_got_refcounts[r_symndx] > 0)
|
switch (ELF32_R_TYPE (rel->r_info))
|
{
|
|
--local_got_refcounts[r_symndx];
|
|
if (local_got_refcounts[r_symndx] == 0)
|
|
{
|
{
|
/* We don't need the .got entry any more. */
|
case R_BFIN_PCREL24:
|
sgot->size -= 4;
|
case R_BFIN_PCREL24_JUMP_L:
|
if (info->shared)
|
picrel->call--;
|
srelgot->size -= sizeof (Elf32_External_Rela);
|
break;
|
}
|
|
}
|
case R_BFIN_FUNCDESC_VALUE:
|
}
|
picrel->relocsfdv--;
|
|
if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
|
|
picrel->relocs32++;
|
|
/* Fall through. */
|
|
|
|
case R_BFIN_BYTE4_DATA:
|
|
picrel->sym--;
|
|
if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
|
|
picrel->relocs32--;
|
|
break;
|
|
|
|
case R_BFIN_GOT17M4:
|
|
picrel->got17m4--;
|
|
break;
|
|
|
|
case R_BFIN_GOTHI:
|
|
case R_BFIN_GOTLO:
|
|
picrel->gothilo--;
|
|
break;
|
|
|
|
case R_BFIN_FUNCDESC_GOT17M4:
|
|
picrel->fdgot17m4--;
|
|
break;
|
|
|
|
case R_BFIN_FUNCDESC_GOTHI:
|
|
case R_BFIN_FUNCDESC_GOTLO:
|
|
picrel->fdgothilo--;
|
|
break;
|
|
|
|
case R_BFIN_GOTOFF17M4:
|
|
case R_BFIN_GOTOFFHI:
|
|
case R_BFIN_GOTOFFLO:
|
|
picrel->gotoff--;
|
|
break;
|
|
|
|
case R_BFIN_FUNCDESC_GOTOFF17M4:
|
|
picrel->fdgoff17m4--;
|
|
break;
|
|
|
|
case R_BFIN_FUNCDESC_GOTOFFHI:
|
|
case R_BFIN_FUNCDESC_GOTOFFLO:
|
|
picrel->fdgoffhilo--;
|
break;
|
break;
|
|
|
|
case R_BFIN_FUNCDESC:
|
|
picrel->fd--;
|
|
picrel->relocsfd--;
|
|
break;
|
|
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
/* We need dynamic symbols for every section, since segments can
|
/* We need dynamic symbols for every section, since segments can
|
relocate independently. */
|
relocate independently. */
|
static bfd_boolean
|
static bfd_boolean
|
_bfinfdpic_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
|
_bfinfdpic_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
|
struct bfd_link_info *info
|
struct bfd_link_info *info ATTRIBUTE_UNUSED,
|
ATTRIBUTE_UNUSED,
|
asection *p)
|
asection *p ATTRIBUTE_UNUSED)
|
|
{
|
{
|
switch (elf_section_data (p)->this_hdr.sh_type)
|
switch (elf_section_data (p)->this_hdr.sh_type)
|
{
|
{
|
case SHT_PROGBITS:
|
case SHT_PROGBITS:
|
case SHT_NOBITS:
|
case SHT_NOBITS:
|
Line 3339... |
Line 3455... |
|
|
bfinfdpic_gotfixup_section (info) = s;
|
bfinfdpic_gotfixup_section (info) = s;
|
offset = -2048;
|
offset = -2048;
|
flags = BSF_GLOBAL;
|
flags = BSF_GLOBAL;
|
}
|
}
|
else
|
else
|
{
|
{
|
offset = 2048;
|
offset = 2048;
|
flags = BSF_GLOBAL | BSF_WEAK;
|
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. */
|
|
|
|
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
|
|
| SEC_LINKER_CREATED);
|
|
|
|
pltflags = flags;
|
flags = pltflags;
|
pltflags |= SEC_CODE;
|
pltflags |= SEC_CODE;
|
if (bed->plt_not_loaded)
|
if (bed->plt_not_loaded)
|
pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
|
pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
|
if (bed->plt_readonly)
|
if (bed->plt_readonly)
|
pltflags |= SEC_READONLY;
|
pltflags |= SEC_READONLY;
|
Line 3408... |
Line 3503... |
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
|
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
|
return FALSE;
|
return FALSE;
|
/* Blackfin-specific: remember it. */
|
/* Blackfin-specific: remember it. */
|
bfinfdpic_pltrel_section (info) = s;
|
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. */
|
/* Blackfin-specific: we want to create the GOT in the Blackfin way. */
|
if (! _bfin_create_got_section (abfd, info))
|
if (! _bfin_create_got_section (abfd, info))
|
return FALSE;
|
return FALSE;
|
|
|
/* Blackfin-specific: make sure we created everything we wanted. */
|
/* Blackfin-specific: make sure we created everything we wanted. */
|
Line 3445... |
Line 3561... |
section when generating a shared object, since they do not use
|
section when generating a shared object, since they do not use
|
copy relocs. */
|
copy relocs. */
|
if (! info->shared)
|
if (! info->shared)
|
{
|
{
|
s = bfd_make_section_with_flags (abfd,
|
s = bfd_make_section_with_flags (abfd,
|
(bed->default_use_rela_p
|
".rela.bss",
|
? ".rela.bss" : ".rel.bss"),
|
|
flags | SEC_READONLY);
|
flags | SEC_READONLY);
|
if (s == NULL
|
if (s == NULL
|
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
|
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
|
return FALSE;
|
return FALSE;
|
}
|
}
|
}
|
}
|
|
|
return TRUE;
|
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.
|
/* 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
|
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
|
the symbol, an entry pointing to its function descriptor, and a
|
private function descriptors taking two words. */
|
private function descriptors taking two words. */
|
|
|
static int
|
static void
|
_bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
|
_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. */
|
/* Allocate space for a GOT entry pointing to the symbol. */
|
if (entry->got17m4)
|
if (entry->got17m4)
|
dinfo->got17m4 += 4;
|
dinfo->got17m4 += 4;
|
else if (entry->gothilo)
|
else if (entry->gothilo)
|
dinfo->gothilo += 4;
|
dinfo->gothilo += 4;
|
Line 3547... |
Line 3628... |
entry->relocsfdv--;
|
entry->relocsfdv--;
|
entry->relocsfdv++;
|
entry->relocsfdv++;
|
|
|
if (entry->lazyplt)
|
if (entry->lazyplt)
|
dinfo->lzplt += LZPLT_NORMAL_SIZE;
|
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)
|
if (!dinfo->info->executable || dinfo->info->pie)
|
relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv;
|
relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv;
|
else
|
else
|
{
|
{
|
Line 3572... |
Line 3665... |
}
|
}
|
else
|
else
|
relocs += entry->relocsfd;
|
relocs += entry->relocsfd;
|
}
|
}
|
|
|
|
if (subtract)
|
|
{
|
|
relocs = - relocs;
|
|
fixups = - fixups;
|
|
}
|
|
|
entry->dynrelocs += relocs;
|
entry->dynrelocs += relocs;
|
entry->fixups += fixups;
|
entry->fixups += fixups;
|
dinfo->relocs += relocs;
|
dinfo->relocs += relocs;
|
dinfo->fixups += fixups;
|
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;
|
return 1;
|
}
|
}
|
|
|
/* This structure is used to assign offsets to got entries, function
|
/* This structure is used to assign offsets to got entries, function
|
Line 3871... |
Line 3986... |
}
|
}
|
|
|
return 1;
|
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
|
/* Follow indirect and warning hash entries so that each got entry
|
points to the final symbol definition. P must point to a pointer
|
points to the final symbol definition. P must point to a pointer
|
to the hash table we're traversing. Since this traversal may
|
to the hash table we're traversing. Since this traversal may
|
modify the hash table, we set this pointer to NULL to indicate
|
modify the hash table, we set this pointer to NULL to indicate
|
we've made a potentially-destructive change to the hash table, so
|
we've made a potentially-destructive change to the hash table, so
|
Line 3927... |
Line 4059... |
}
|
}
|
|
|
return 1;
|
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
|
static bfd_boolean
|
elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
|
_bfinfdpic_size_got_plt (bfd *output_bfd,
|
struct bfd_link_info *info)
|
struct _bfinfdpic_dynamic_got_plt_info *gpinfop)
|
{
|
{
|
bfd *dynobj;
|
|
asection *s;
|
|
struct _bfinfdpic_dynamic_got_plt_info gpinfo;
|
|
bfd_signed_vma odd;
|
bfd_signed_vma odd;
|
bfd_vma limit;
|
bfd_vma limit;
|
|
struct bfd_link_info *info = gpinfop->g.info;
|
|
bfd *dynobj = elf_hash_table (info)->dynobj;
|
|
|
dynobj = elf_hash_table (info)->dynobj;
|
memcpy (bfinfdpic_dynamic_got_plt_info (info), &gpinfop->g,
|
BFD_ASSERT (dynobj != NULL);
|
sizeof (gpinfop->g));
|
|
|
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);
|
|
|
|
odd = 12;
|
odd = 12;
|
/* Compute the total size taken by entries in the 18-bit range,
|
/* Compute the total size taken by entries in the 18-bit range,
|
to tell how many PLT function descriptors we can bring into it
|
to tell how many PLT function descriptors we can bring into it
|
without causing it to overflow. */
|
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)
|
if (limit < (bfd_vma)1 << 18)
|
limit = ((bfd_vma)1 << 18) - limit;
|
limit = ((bfd_vma)1 << 18) - limit;
|
else
|
else
|
limit = 0;
|
limit = 0;
|
if (gpinfo.g.fdplt < limit)
|
if (gpinfop->g.fdplt < limit)
|
limit = gpinfo.g.fdplt;
|
limit = gpinfop->g.fdplt;
|
|
|
/* Determine the ranges of GOT offsets that we can use for each
|
/* Determine the ranges of GOT offsets that we can use for each
|
range of addressing modes. */
|
range of addressing modes. */
|
odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.got17m4,
|
odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->got17m4,
|
0,
|
0,
|
odd,
|
odd,
|
16,
|
16,
|
gpinfo.g.got17m4,
|
gpinfop->g.got17m4,
|
gpinfo.g.fd17m4,
|
gpinfop->g.fd17m4,
|
limit,
|
limit,
|
(bfd_vma)1 << (18-1));
|
(bfd_vma)1 << (18-1));
|
odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.gothilo,
|
odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->gothilo,
|
gpinfo.got17m4.min,
|
gpinfop->got17m4.min,
|
odd,
|
odd,
|
gpinfo.got17m4.max,
|
gpinfop->got17m4.max,
|
gpinfo.g.gothilo,
|
gpinfop->g.gothilo,
|
gpinfo.g.fdhilo,
|
gpinfop->g.fdhilo,
|
gpinfo.g.fdplt - gpinfo.got17m4.fdplt,
|
gpinfop->g.fdplt - gpinfop->got17m4.fdplt,
|
(bfd_vma)1 << (32-1));
|
(bfd_vma)1 << (32-1));
|
|
|
/* Now assign (most) GOT offsets. */
|
/* Now assign (most) GOT offsets. */
|
htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_got_entries,
|
htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_got_entries,
|
&gpinfo);
|
gpinfop);
|
|
|
bfinfdpic_got_section (info)->size = gpinfo.gothilo.max
|
bfinfdpic_got_section (info)->size = gpinfop->gothilo.max
|
- gpinfo.gothilo.min
|
- gpinfop->gothilo.min
|
/* If an odd word is the last word of the GOT, we don't need this
|
/* If an odd word is the last word of the GOT, we don't need this
|
word to be part of the GOT. */
|
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)
|
if (bfinfdpic_got_section (info)->size == 0)
|
bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE;
|
bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE;
|
else if (bfinfdpic_got_section (info)->size == 12
|
else if (bfinfdpic_got_section (info)->size == 12
|
&& ! elf_hash_table (info)->dynamic_sections_created)
|
&& ! elf_hash_table (info)->dynamic_sections_created)
|
{
|
{
|
Line 4031... |
Line 4136... |
|
|
if (elf_hash_table (info)->dynamic_sections_created)
|
if (elf_hash_table (info)->dynamic_sections_created)
|
/* Subtract the number of lzplt entries, since those will generate
|
/* Subtract the number of lzplt entries, since those will generate
|
relocations in the pltrel section. */
|
relocations in the pltrel section. */
|
bfinfdpic_gotrel_section (info)->size =
|
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;
|
* get_elf_backend_data (output_bfd)->s->sizeof_rel;
|
else
|
else
|
BFD_ASSERT (gpinfo.g.relocs == 0);
|
BFD_ASSERT (gpinfop->g.relocs == 0);
|
if (bfinfdpic_gotrel_section (info)->size == 0)
|
if (bfinfdpic_gotrel_section (info)->size == 0)
|
bfinfdpic_gotrel_section (info)->flags |= SEC_EXCLUDE;
|
bfinfdpic_gotrel_section (info)->flags |= SEC_EXCLUDE;
|
else
|
else
|
{
|
{
|
bfinfdpic_gotrel_section (info)->contents =
|
bfinfdpic_gotrel_section (info)->contents =
|
Line 4046... |
Line 4151... |
bfinfdpic_gotrel_section (info)->size);
|
bfinfdpic_gotrel_section (info)->size);
|
if (bfinfdpic_gotrel_section (info)->contents == NULL)
|
if (bfinfdpic_gotrel_section (info)->contents == NULL)
|
return FALSE;
|
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)
|
if (bfinfdpic_gotfixup_section (info)->size == 0)
|
bfinfdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE;
|
bfinfdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE;
|
else
|
else
|
{
|
{
|
bfinfdpic_gotfixup_section (info)->contents =
|
bfinfdpic_gotfixup_section (info)->contents =
|
Line 4059... |
Line 4164... |
if (bfinfdpic_gotfixup_section (info)->contents == NULL)
|
if (bfinfdpic_gotfixup_section (info)->contents == NULL)
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
if (elf_hash_table (info)->dynamic_sections_created)
|
if (elf_hash_table (info)->dynamic_sections_created)
|
{
|
|
bfinfdpic_pltrel_section (info)->size =
|
bfinfdpic_pltrel_section (info)->size =
|
gpinfo.g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel;
|
gpinfop->g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel;
|
if (bfinfdpic_pltrel_section (info)->size == 0)
|
if (bfinfdpic_pltrel_section (info)->size == 0)
|
bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE;
|
bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE;
|
else
|
else
|
{
|
{
|
bfinfdpic_pltrel_section (info)->contents =
|
bfinfdpic_pltrel_section (info)->contents =
|
(bfd_byte *) bfd_zalloc (dynobj,
|
(bfd_byte *) bfd_zalloc (dynobj,
|
bfinfdpic_pltrel_section (info)->size);
|
bfinfdpic_pltrel_section (info)->size);
|
if (bfinfdpic_pltrel_section (info)->contents == NULL)
|
if (bfinfdpic_pltrel_section (info)->contents == NULL)
|
return FALSE;
|
return FALSE;
|
}
|
}
|
}
|
|
|
|
/* Add 4 bytes for every block of at most 65535 lazy PLT entries,
|
/* Add 4 bytes for every block of at most 65535 lazy PLT entries,
|
such that there's room for the additional instruction needed to
|
such that there's room for the additional instruction needed to
|
call the resolver. Since _bfinfdpic_assign_got_entries didn't
|
call the resolver. Since _bfinfdpic_assign_got_entries didn't
|
account for them, our block size is 4 bytes smaller than the real
|
account for them, our block size is 4 bytes smaller than the real
|
block size. */
|
block size. */
|
if (elf_hash_table (info)->dynamic_sections_created)
|
if (elf_hash_table (info)->dynamic_sections_created)
|
{
|
{
|
bfinfdpic_plt_section (info)->size = gpinfo.g.lzplt
|
bfinfdpic_plt_section (info)->size = gpinfop->g.lzplt
|
+ ((gpinfo.g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE)
|
+ ((gpinfop->g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE)
|
/ (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) * LZPLT_RESOLVER_EXTRA);
|
/ (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) * LZPLT_RESOLVER_EXTRA);
|
}
|
}
|
|
|
/* Reset it, such that _bfinfdpic_assign_plt_entries() can use it to
|
/* Reset it, such that _bfinfdpic_assign_plt_entries() can use it to
|
actually assign lazy PLT entries addresses. */
|
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
|
/* Save information that we're going to need to generate GOT and PLT
|
entries. */
|
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)
|
if (get_elf_backend_data (output_bfd)->want_got_sym)
|
elf_hash_table (info)->hgot->root.u.def.value
|
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)
|
if (elf_hash_table (info)->dynamic_sections_created)
|
bfinfdpic_plt_initial_offset (info) =
|
bfinfdpic_plt_initial_offset (info) =
|
bfinfdpic_plt_section (info)->size;
|
bfinfdpic_plt_section (info)->size;
|
|
|
htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_plt_entries,
|
htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_plt_entries,
|
&gpinfo);
|
gpinfop);
|
|
|
/* Allocate the PLT section contents only after
|
/* Allocate the PLT section contents only after
|
_bfinfdpic_assign_plt_entries has a chance to add the size of the
|
_bfinfdpic_assign_plt_entries has a chance to add the size of the
|
non-lazy PLT entries. */
|
non-lazy PLT entries. */
|
if (elf_hash_table (info)->dynamic_sections_created)
|
|
{
|
|
if (bfinfdpic_plt_section (info)->size == 0)
|
if (bfinfdpic_plt_section (info)->size == 0)
|
bfinfdpic_plt_section (info)->flags |= SEC_EXCLUDE;
|
bfinfdpic_plt_section (info)->flags |= SEC_EXCLUDE;
|
else
|
else
|
{
|
{
|
bfinfdpic_plt_section (info)->contents =
|
bfinfdpic_plt_section (info)->contents =
|
(bfd_byte *) bfd_zalloc (dynobj,
|
(bfd_byte *) bfd_zalloc (dynobj,
|
bfinfdpic_plt_section (info)->size);
|
bfinfdpic_plt_section (info)->size);
|
if (bfinfdpic_plt_section (info)->contents == NULL)
|
if (bfinfdpic_plt_section (info)->contents == NULL)
|
return FALSE;
|
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)
|
|
{
|
|
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 (elf_hash_table (info)->dynamic_sections_created)
|
{
|
{
|
if (bfinfdpic_got_section (info)->size)
|
if (bfinfdpic_got_section (info)->size)
|
if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0))
|
if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0))
|
return FALSE;
|
return FALSE;
|
Line 4142... |
Line 4295... |
|| !_bfd_elf_add_dynamic_entry (info, DT_RELENT,
|
|| !_bfd_elf_add_dynamic_entry (info, DT_RELENT,
|
sizeof (Elf32_External_Rel)))
|
sizeof (Elf32_External_Rel)))
|
return FALSE;
|
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;
|
return TRUE;
|
}
|
}
|
|
|
static bfd_boolean
|
static bfd_boolean
|
elf32_bfinfdpic_always_size_sections (bfd *output_bfd,
|
elf32_bfinfdpic_always_size_sections (bfd *output_bfd,
|
Line 4182... |
Line 4343... |
}
|
}
|
|
|
return TRUE;
|
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
|
static bfd_boolean
|
elf32_bfinfdpic_modify_program_headers (bfd *output_bfd,
|
elf32_bfinfdpic_modify_program_headers (bfd *output_bfd,
|
struct bfd_link_info *info)
|
struct bfd_link_info *info)
|
{
|
{
|
struct elf_obj_tdata *tdata = elf_tdata (output_bfd);
|
struct elf_obj_tdata *tdata = elf_tdata (output_bfd);
|
Line 4321... |
Line 4598... |
/* Adjust a symbol defined by a dynamic object and referenced by a
|
/* Adjust a symbol defined by a dynamic object and referenced by a
|
regular object. */
|
regular object. */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
elf32_bfinfdpic_adjust_dynamic_symbol
|
elf32_bfinfdpic_adjust_dynamic_symbol
|
(struct bfd_link_info *info ATTRIBUTE_UNUSED,
|
(struct bfd_link_info *info,
|
struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
|
struct elf_link_hash_entry *h)
|
{
|
{
|
bfd * dynobj;
|
bfd * dynobj;
|
|
|
dynobj = elf_hash_table (info)->dynobj;
|
dynobj = elf_hash_table (info)->dynobj;
|
|
|
Line 4560... |
Line 4837... |
case R_BFIN_FUNCDESC:
|
case R_BFIN_FUNCDESC:
|
case R_BFIN_FUNCDESC_VALUE:
|
case R_BFIN_FUNCDESC_VALUE:
|
if (! IS_FDPIC (abfd))
|
if (! IS_FDPIC (abfd))
|
goto bad_reloc;
|
goto bad_reloc;
|
/* Fall through. */
|
/* Fall through. */
|
case R_pcrel24:
|
case R_BFIN_PCREL24:
|
case R_pcrel24_jump_l:
|
case R_BFIN_PCREL24_JUMP_L:
|
case R_byte4_data:
|
case R_BFIN_BYTE4_DATA:
|
if (IS_FDPIC (abfd) && ! dynobj)
|
if (IS_FDPIC (abfd) && ! dynobj)
|
{
|
{
|
elf_hash_table (info)->dynobj = dynobj = abfd;
|
elf_hash_table (info)->dynobj = dynobj = abfd;
|
if (! _bfin_create_got_section (abfd, info))
|
if (! _bfin_create_got_section (abfd, info))
|
return FALSE;
|
return FALSE;
|
Line 4606... |
Line 4883... |
break;
|
break;
|
}
|
}
|
|
|
switch (ELF32_R_TYPE (rel->r_info))
|
switch (ELF32_R_TYPE (rel->r_info))
|
{
|
{
|
case R_pcrel24:
|
case R_BFIN_PCREL24:
|
case R_pcrel24_jump_l:
|
case R_BFIN_PCREL24_JUMP_L:
|
if (IS_FDPIC (abfd))
|
if (IS_FDPIC (abfd))
|
picrel->call = 1;
|
picrel->call++;
|
break;
|
break;
|
|
|
case R_BFIN_FUNCDESC_VALUE:
|
case R_BFIN_FUNCDESC_VALUE:
|
picrel->relocsfdv++;
|
picrel->relocsfdv++;
|
if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
|
if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
|
picrel->relocs32--;
|
picrel->relocs32--;
|
/* Fall through. */
|
/* Fall through. */
|
|
|
case R_byte4_data:
|
case R_BFIN_BYTE4_DATA:
|
if (! IS_FDPIC (abfd))
|
if (! IS_FDPIC (abfd))
|
break;
|
break;
|
|
|
picrel->sym = 1;
|
picrel->sym++;
|
if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
|
if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
|
picrel->relocs32++;
|
picrel->relocs32++;
|
break;
|
break;
|
|
|
case R_BFIN_GOT17M4:
|
case R_BFIN_GOT17M4:
|
picrel->got17m4 = 1;
|
picrel->got17m4++;
|
break;
|
break;
|
|
|
case R_BFIN_GOTHI:
|
case R_BFIN_GOTHI:
|
case R_BFIN_GOTLO:
|
case R_BFIN_GOTLO:
|
picrel->gothilo = 1;
|
picrel->gothilo++;
|
break;
|
break;
|
|
|
case R_BFIN_FUNCDESC_GOT17M4:
|
case R_BFIN_FUNCDESC_GOT17M4:
|
picrel->fdgot17m4 = 1;
|
picrel->fdgot17m4++;
|
break;
|
break;
|
|
|
case R_BFIN_FUNCDESC_GOTHI:
|
case R_BFIN_FUNCDESC_GOTHI:
|
case R_BFIN_FUNCDESC_GOTLO:
|
case R_BFIN_FUNCDESC_GOTLO:
|
picrel->fdgothilo = 1;
|
picrel->fdgothilo++;
|
break;
|
break;
|
|
|
case R_BFIN_GOTOFF17M4:
|
case R_BFIN_GOTOFF17M4:
|
case R_BFIN_GOTOFFHI:
|
case R_BFIN_GOTOFFHI:
|
case R_BFIN_GOTOFFLO:
|
case R_BFIN_GOTOFFLO:
|
picrel->gotoff = 1;
|
picrel->gotoff++;
|
break;
|
break;
|
|
|
case R_BFIN_FUNCDESC_GOTOFF17M4:
|
case R_BFIN_FUNCDESC_GOTOFF17M4:
|
picrel->fdgoff17m4 = 1;
|
picrel->fdgoff17m4++;
|
break;
|
break;
|
|
|
case R_BFIN_FUNCDESC_GOTOFFHI:
|
case R_BFIN_FUNCDESC_GOTOFFHI:
|
case R_BFIN_FUNCDESC_GOTOFFLO:
|
case R_BFIN_FUNCDESC_GOTOFFLO:
|
picrel->fdgoffhilo = 1;
|
picrel->fdgoffhilo++;
|
break;
|
break;
|
|
|
case R_BFIN_FUNCDESC:
|
case R_BFIN_FUNCDESC:
|
picrel->fd = 1;
|
picrel->fd++;
|
picrel->relocsfd++;
|
picrel->relocsfd++;
|
break;
|
break;
|
|
|
/* This relocation describes the C++ object vtable hierarchy.
|
/* This relocation describes the C++ object vtable hierarchy.
|
Reconstruct it for later use during GC. */
|
Reconstruct it for later use during GC. */
|
Line 4681... |
Line 4958... |
if (h != NULL
|
if (h != NULL
|
&& !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
|
&& !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
|
return FALSE;
|
return FALSE;
|
break;
|
break;
|
|
|
case R_huimm16:
|
case R_BFIN_HUIMM16:
|
case R_luimm16:
|
case R_BFIN_LUIMM16:
|
case R_pcrel12_jump_s:
|
case R_BFIN_PCREL12_JUMP_S:
|
case R_pcrel10:
|
case R_BFIN_PCREL10:
|
break;
|
break;
|
|
|
default:
|
default:
|
bad_reloc:
|
bad_reloc:
|
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
Line 4873... |
Line 5150... |
|
|
struct bfin_link_hash_table
|
struct bfin_link_hash_table
|
{
|
{
|
struct elf_link_hash_table root;
|
struct elf_link_hash_table root;
|
|
|
/* Small local sym to section mapping cache. */
|
/* Small local sym cache. */
|
struct sym_sec_cache sym_sec;
|
struct sym_cache sym_cache;
|
};
|
};
|
|
|
#define bfin_hash_entry(ent) ((struct bfin_link_hash_entry *) (ent))
|
#define bfin_hash_entry(ent) ((struct bfin_link_hash_entry *) (ent))
|
|
|
static struct bfd_hash_entry *
|
static struct bfd_hash_entry *
|
Line 4920... |
Line 5197... |
{
|
{
|
free (ret);
|
free (ret);
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
ret->sym_sec.abfd = NULL;
|
ret->sym_cache.abfd = NULL;
|
|
|
return &ret->root.root;
|
return &ret->root.root;
|
}
|
}
|
|
|
/* The size in bytes of an entry in the procedure linkage table. */
|
/* The size in bytes of an entry in the procedure linkage table. */
|
Line 5001... |
Line 5278... |
if (info->shared
|
if (info->shared
|
&& (info->symbolic
|
&& (info->symbolic
|
|| h->dynindx == -1 || h->forced_local) && h->def_regular)
|
|| h->dynindx == -1 || h->forced_local) && h->def_regular)
|
{
|
{
|
fprintf(stderr, "*** check this relocation %s\n", __FUNCTION__);
|
fprintf(stderr, "*** check this relocation %s\n", __FUNCTION__);
|
rela.r_info = ELF32_R_INFO (0, R_pcrel24);
|
rela.r_info = ELF32_R_INFO (0, R_BFIN_PCREL24);
|
rela.r_addend = bfd_get_signed_32 (output_bfd,
|
rela.r_addend = bfd_get_signed_32 (output_bfd,
|
(sgot->contents
|
(sgot->contents
|
+
|
+
|
(h->got.
|
(h->got.
|
offset & ~(bfd_vma) 1)));
|
offset & ~(bfd_vma) 1)));
|
}
|
}
|
else
|
else
|
{
|
{
|
bfd_put_32 (output_bfd, (bfd_vma) 0,
|
bfd_put_32 (output_bfd, (bfd_vma) 0,
|
sgot->contents + (h->got.offset & ~(bfd_vma) 1));
|
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;
|
rela.r_addend = 0;
|
}
|
}
|
|
|
loc = srela->contents;
|
loc = srela->contents;
|
loc += srela->reloc_count++ * sizeof (Elf32_External_Rela);
|
loc += srela->reloc_count++ * sizeof (Elf32_External_Rela);
|
Line 5407... |
Line 5684... |
section which must be relocated. It is followed by the name
|
section which must be relocated. It is followed by the name
|
of the target section NUL-padded or truncated to 8
|
of the target section NUL-padded or truncated to 8
|
characters. */
|
characters. */
|
|
|
/* We can only relocate absolute longword relocs at run time. */
|
/* 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");
|
*errmsg = _("unsupported reloc type");
|
bfd_set_error (bfd_error_bad_value);
|
bfd_set_error (bfd_error_bad_value);
|
goto error_return;
|
goto error_return;
|
}
|
}
|
Line 5472... |
Line 5749... |
if (internal_relocs != NULL
|
if (internal_relocs != NULL
|
&& elf_section_data (datasec)->relocs != internal_relocs)
|
&& elf_section_data (datasec)->relocs != internal_relocs)
|
free (internal_relocs);
|
free (internal_relocs);
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
|
struct bfd_elf_special_section const elf32_bfin_special_sections[] =
|
|
{
|
|
{ ".l1.text", 8, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
|
|
{ ".l1.data", 8, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
|
|
{ NULL, 0, 0, 0, 0 }
|
|
};
|
|
|
|
|
#define TARGET_LITTLE_SYM bfd_elf32_bfin_vec
|
#define TARGET_LITTLE_SYM bfd_elf32_bfin_vec
|
#define TARGET_LITTLE_NAME "elf32-bfin"
|
#define TARGET_LITTLE_NAME "elf32-bfin"
|
#define ELF_ARCH bfd_arch_bfin
|
#define ELF_ARCH bfd_arch_bfin
|
#define ELF_MACHINE_CODE EM_BLACKFIN
|
#define ELF_MACHINE_CODE EM_BLACKFIN
|
Line 5520... |
Line 5805... |
elf32_bfin_set_private_flags
|
elf32_bfin_set_private_flags
|
#define bfd_elf32_bfd_print_private_bfd_data \
|
#define bfd_elf32_bfd_print_private_bfd_data \
|
elf32_bfin_print_private_bfd_data
|
elf32_bfin_print_private_bfd_data
|
#define elf_backend_reloc_type_class elf32_bfin_reloc_type_class
|
#define elf_backend_reloc_type_class elf32_bfin_reloc_type_class
|
#define elf_backend_can_gc_sections 1
|
#define elf_backend_can_gc_sections 1
|
|
#define elf_backend_special_sections elf32_bfin_special_sections
|
#define elf_backend_can_refcount 1
|
#define elf_backend_can_refcount 1
|
#define elf_backend_want_got_plt 0
|
#define elf_backend_want_got_plt 0
|
#define elf_backend_plt_readonly 1
|
#define elf_backend_plt_readonly 1
|
#define elf_backend_want_plt_sym 0
|
#define elf_backend_want_plt_sym 0
|
#define elf_backend_got_header_size 12
|
#define elf_backend_got_header_size 12
|
Line 5537... |
Line 5823... |
#define TARGET_LITTLE_NAME "elf32-bfinfdpic"
|
#define TARGET_LITTLE_NAME "elf32-bfinfdpic"
|
#undef elf32_bed
|
#undef elf32_bed
|
#define elf32_bed elf32_bfinfdpic_bed
|
#define elf32_bed elf32_bfinfdpic_bed
|
|
|
#undef elf_backend_gc_sweep_hook
|
#undef elf_backend_gc_sweep_hook
|
|
#define elf_backend_gc_sweep_hook bfinfdpic_gc_sweep_hook
|
|
|
#undef elf_backend_got_header_size
|
#undef elf_backend_got_header_size
|
#define elf_backend_got_header_size 0
|
#define elf_backend_got_header_size 0
|
|
|
#undef elf_backend_relocate_section
|
#undef elf_backend_relocate_section
|
Line 5575... |
Line 5862... |
elf32_bfinfdpic_finish_dynamic_symbol
|
elf32_bfinfdpic_finish_dynamic_symbol
|
#undef elf_backend_finish_dynamic_sections
|
#undef elf_backend_finish_dynamic_sections
|
#define elf_backend_finish_dynamic_sections \
|
#define elf_backend_finish_dynamic_sections \
|
elf32_bfinfdpic_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
|
#undef elf_backend_can_make_relative_eh_frame
|
#define elf_backend_can_make_relative_eh_frame \
|
#define elf_backend_can_make_relative_eh_frame \
|
bfinfdpic_elf_use_relative_eh_frame
|
bfinfdpic_elf_use_relative_eh_frame
|
#undef elf_backend_can_make_lsda_relative_eh_frame
|
#undef elf_backend_can_make_lsda_relative_eh_frame
|
#define elf_backend_can_make_lsda_relative_eh_frame \
|
#define elf_backend_can_make_lsda_relative_eh_frame \
|