|  | /* Xilinx MicroBlaze-specific support for 32-bit ELF | 
|  |  | 
|  | Copyright (C) 2009-2023 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of BFD, the Binary File Descriptor library. | 
|  |  | 
|  | 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 | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program; if not, write to the | 
|  | Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, | 
|  | Boston, MA 02110-1301, USA.  */ | 
|  |  | 
|  |  | 
|  | #include "sysdep.h" | 
|  | #include "bfd.h" | 
|  | #include "bfdlink.h" | 
|  | #include "libbfd.h" | 
|  | #include "elf-bfd.h" | 
|  | #include "elf/microblaze.h" | 
|  | #include <assert.h> | 
|  |  | 
|  | #define	USE_RELA	/* Only USE_REL is actually significant, but this is | 
|  | here are a reminder...  */ | 
|  | #define INST_WORD_SIZE 4 | 
|  |  | 
|  | static int ro_small_data_pointer = 0; | 
|  | static int rw_small_data_pointer = 0; | 
|  |  | 
|  | static reloc_howto_type * microblaze_elf_howto_table [(int) R_MICROBLAZE_max]; | 
|  |  | 
|  | static reloc_howto_type microblaze_elf_howto_raw[] = | 
|  | { | 
|  | /* This reloc does nothing.  */ | 
|  | HOWTO (R_MICROBLAZE_NONE,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 0,			/* Size.  */ | 
|  | 0,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont,  /* Complain on overflow.  */ | 
|  | NULL,			 /* Special Function.  */ | 
|  | "R_MICROBLAZE_NONE",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0,			/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* A standard 32 bit relocation.  */ | 
|  | HOWTO (R_MICROBLAZE_32,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 32,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_bitfield, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_32",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0xffffffff,		/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* A standard PCREL 32 bit relocation.  */ | 
|  | HOWTO (R_MICROBLAZE_32_PCREL,/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 32,			/* Bitsize.  */ | 
|  | true,			/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_bitfield, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_32_PCREL",	/* Name.  */ | 
|  | true,			/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0xffffffff,		/* Dest Mask.  */ | 
|  | true),		/* PC relative offset?  */ | 
|  |  | 
|  | /* A 64 bit PCREL relocation.  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_64_PCREL,/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | true,			/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_64_PCREL",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | true),		/* PC relative offset?  */ | 
|  |  | 
|  | /* The low half of a PCREL 32 bit relocation.  */ | 
|  | HOWTO (R_MICROBLAZE_32_PCREL_LO,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | true,			/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_signed, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,	/* Special Function.  */ | 
|  | "R_MICROBLAZE_32_PCREL_LO",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | true),		/* PC relative offset?  */ | 
|  |  | 
|  | /* A 64 bit relocation.  Table entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_64,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_64",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* The low half of a 32 bit relocation.  */ | 
|  | HOWTO (R_MICROBLAZE_32_LO,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_signed, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_32_LO", /* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* Read-only small data section relocation.  */ | 
|  | HOWTO (R_MICROBLAZE_SRO32,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_bitfield, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_SRO32", /* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* Read-write small data area relocation.  */ | 
|  | HOWTO (R_MICROBLAZE_SRW32,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_bitfield, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_SRW32", /* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* This reloc does nothing.	Used for relaxation.  */ | 
|  | HOWTO (R_MICROBLAZE_32_NONE,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 2,			/* Size (0 = byte, 1 = short, 2 = long).  */ | 
|  | 32,			/* Bitsize.  */ | 
|  | true,			/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_bitfield, /* Complain on overflow.  */ | 
|  | NULL,			/* Special Function.  */ | 
|  | "R_MICROBLAZE_32_NONE", /* Name.  */ | 
|  | false,			/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0,			/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* This reloc does nothing.	Used for relaxation.  */ | 
|  | HOWTO (R_MICROBLAZE_64_NONE,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 0,			/* Size.  */ | 
|  | 0,			/* Bitsize.  */ | 
|  | true,			/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | NULL,			 /* Special Function.  */ | 
|  | "R_MICROBLAZE_64_NONE",/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0,			/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* Symbol Op Symbol relocation.  */ | 
|  | HOWTO (R_MICROBLAZE_32_SYM_OP_SYM,		/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 32,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_bitfield, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_32_SYM_OP_SYM",		/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0xffffffff,		/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* GNU extension to record C++ vtable hierarchy.  */ | 
|  | HOWTO (R_MICROBLAZE_GNU_VTINHERIT, /* Type.  */ | 
|  | 0,			 /* Rightshift.  */ | 
|  | 4,			 /* Size.  */ | 
|  | 0,			 /* Bitsize.  */ | 
|  | false,		 /* PC_relative.  */ | 
|  | 0,			 /* Bitpos.  */ | 
|  | complain_overflow_dont,/* Complain on overflow.  */ | 
|  | NULL,			 /* Special Function.  */ | 
|  | "R_MICROBLAZE_GNU_VTINHERIT", /* Name.  */ | 
|  | false,		 /* Partial Inplace.  */ | 
|  | 0,			 /* Source Mask.  */ | 
|  | 0,			 /* Dest Mask.  */ | 
|  | false),		 /* PC relative offset?  */ | 
|  |  | 
|  | /* GNU extension to record C++ vtable member usage.  */ | 
|  | HOWTO (R_MICROBLAZE_GNU_VTENTRY,   /* Type.  */ | 
|  | 0,			 /* Rightshift.  */ | 
|  | 4,			 /* Size.  */ | 
|  | 0,			 /* Bitsize.  */ | 
|  | false,		 /* PC_relative.  */ | 
|  | 0,			 /* Bitpos.  */ | 
|  | complain_overflow_dont,/* Complain on overflow.  */ | 
|  | _bfd_elf_rel_vtable_reloc_fn,	 /* Special Function.  */ | 
|  | "R_MICROBLAZE_GNU_VTENTRY", /* Name.  */ | 
|  | false,		 /* Partial Inplace.  */ | 
|  | 0,			 /* Source Mask.  */ | 
|  | 0,			 /* Dest Mask.  */ | 
|  | false),		 /* PC relative offset?  */ | 
|  |  | 
|  | /* A 64 bit GOTPC relocation.  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_GOTPC_64,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | true,			/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,	/* Special Function.  */ | 
|  | "R_MICROBLAZE_GOTPC_64",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | true),		/* PC relative offset?  */ | 
|  |  | 
|  | /* A 64 bit TEXTPCREL relocation.  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_TEXTPCREL_64,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | true,			/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,	/* Special Function.  */ | 
|  | "R_MICROBLAZE_TEXTPCREL_64",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | true),		/* PC relative offset?  */ | 
|  |  | 
|  | /* A 64 bit GOT relocation.  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_GOT_64,  /* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_GOT_64",/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* A 64 bit TEXTREL relocation.  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_TEXTREL_64,  /* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_TEXTREL_64",/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* A 64 bit PLT relocation.  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_PLT_64,  /* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | true,			/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_PLT_64",/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | true),		/* PC relative offset?  */ | 
|  |  | 
|  | /*  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_REL,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | true,			/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_REL",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | true),		/* PC relative offset?  */ | 
|  |  | 
|  | /*  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_JUMP_SLOT,/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | true,			/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_JUMP_SLOT",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | true),		/* PC relative offset?  */ | 
|  |  | 
|  | /*  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_GLOB_DAT,/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | true,			/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_GLOB_DAT",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | true),		/* PC relative offset?  */ | 
|  |  | 
|  | /* A 64 bit GOT relative relocation.  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_GOTOFF_64,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_GOTOFF_64",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* A 32 bit GOT relative relocation.  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_GOTOFF_32,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,	/* Special Function.  */ | 
|  | "R_MICROBLAZE_GOTOFF_32",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* COPY relocation.  Table-entry not really used.  */ | 
|  | HOWTO (R_MICROBLAZE_COPY,	/* Type.  */ | 
|  | 0,			/* Rightshift.  */ | 
|  | 4,			/* Size.  */ | 
|  | 16,			/* Bitsize.  */ | 
|  | false,		/* PC_relative.  */ | 
|  | 0,			/* Bitpos.  */ | 
|  | complain_overflow_dont, /* Complain on overflow.  */ | 
|  | bfd_elf_generic_reloc,/* Special Function.  */ | 
|  | "R_MICROBLAZE_COPY",	/* Name.  */ | 
|  | false,		/* Partial Inplace.  */ | 
|  | 0,			/* Source Mask.  */ | 
|  | 0x0000ffff,		/* Dest Mask.  */ | 
|  | false),		/* PC relative offset?  */ | 
|  |  | 
|  | /* Marker relocs for TLS.  */ | 
|  | HOWTO (R_MICROBLAZE_TLS, | 
|  | 0,			/* rightshift */ | 
|  | 4,			/* size */ | 
|  | 32,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_dont, /* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc,	/* special_function */ | 
|  | "R_MICROBLAZE_TLS",		/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0,			/* src_mask */ | 
|  | 0x0000ffff,			/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | HOWTO (R_MICROBLAZE_TLSGD, | 
|  | 0,			/* rightshift */ | 
|  | 4,			/* size */ | 
|  | 32,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_dont, /* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc, /* special_function */ | 
|  | "R_MICROBLAZE_TLSGD",		/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0,			/* src_mask */ | 
|  | 0x0000ffff,			/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | HOWTO (R_MICROBLAZE_TLSLD, | 
|  | 0,			/* rightshift */ | 
|  | 4,			/* size */ | 
|  | 32,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_dont, /* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc, /* special_function */ | 
|  | "R_MICROBLAZE_TLSLD",		/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0,			/* src_mask */ | 
|  | 0x0000ffff,		/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | /* Computes the load module index of the load module that contains the | 
|  | definition of its TLS sym.  */ | 
|  | HOWTO (R_MICROBLAZE_TLSDTPMOD32, | 
|  | 0,			/* rightshift */ | 
|  | 4,			/* size */ | 
|  | 32,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_dont, /* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc, /* special_function */ | 
|  | "R_MICROBLAZE_TLSDTPMOD32",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0,			/* src_mask */ | 
|  | 0x0000ffff,		/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | /* Computes a dtv-relative displacement, the difference between the value | 
|  | of sym+add and the base address of the thread-local storage block that | 
|  | contains the definition of sym, minus 0x8000.  Used for initializing GOT */ | 
|  | HOWTO (R_MICROBLAZE_TLSDTPREL32, | 
|  | 0,			/* rightshift */ | 
|  | 4,			/* size */ | 
|  | 32,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_dont, /* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc, /* special_function */ | 
|  | "R_MICROBLAZE_TLSDTPREL32",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0,			/* src_mask */ | 
|  | 0x0000ffff,		/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | /* Computes a dtv-relative displacement, the difference between the value | 
|  | of sym+add and the base address of the thread-local storage block that | 
|  | contains the definition of sym, minus 0x8000.  */ | 
|  | HOWTO (R_MICROBLAZE_TLSDTPREL64, | 
|  | 0,			/* rightshift */ | 
|  | 4,			/* size */ | 
|  | 32,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_dont, /* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc, /* special_function */ | 
|  | "R_MICROBLAZE_TLSDTPREL64",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0,			/* src_mask */ | 
|  | 0x0000ffff,		/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | /* Computes a tp-relative displacement, the difference between the value of | 
|  | sym+add and the value of the thread pointer (r13).  */ | 
|  | HOWTO (R_MICROBLAZE_TLSGOTTPREL32, | 
|  | 0,			/* rightshift */ | 
|  | 4,			/* size */ | 
|  | 32,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_dont, /* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc, /* special_function */ | 
|  | "R_MICROBLAZE_TLSGOTTPREL32",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0,			/* src_mask */ | 
|  | 0x0000ffff,		/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | /* Computes a tp-relative displacement, the difference between the value of | 
|  | sym+add and the value of the thread pointer (r13).  */ | 
|  | HOWTO (R_MICROBLAZE_TLSTPREL32, | 
|  | 0,			/* rightshift */ | 
|  | 4,			/* size */ | 
|  | 32,			/* bitsize */ | 
|  | false,			/* pc_relative */ | 
|  | 0,			/* bitpos */ | 
|  | complain_overflow_dont, /* complain_on_overflow */ | 
|  | bfd_elf_generic_reloc, /* special_function */ | 
|  | "R_MICROBLAZE_TLSTPREL32",	/* name */ | 
|  | false,			/* partial_inplace */ | 
|  | 0,			/* src_mask */ | 
|  | 0x0000ffff,		/* dst_mask */ | 
|  | false),		/* pcrel_offset */ | 
|  |  | 
|  | }; | 
|  |  | 
|  | #ifndef NUM_ELEM | 
|  | #define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) | 
|  | #endif | 
|  |  | 
|  | /* Initialize the microblaze_elf_howto_table, so that linear accesses can be done.  */ | 
|  |  | 
|  | static void | 
|  | microblaze_elf_howto_init (void) | 
|  | { | 
|  | unsigned int i; | 
|  |  | 
|  | for (i = NUM_ELEM (microblaze_elf_howto_raw); i--;) | 
|  | { | 
|  | unsigned int type; | 
|  |  | 
|  | type = microblaze_elf_howto_raw[i].type; | 
|  |  | 
|  | BFD_ASSERT (type < NUM_ELEM (microblaze_elf_howto_table)); | 
|  |  | 
|  | microblaze_elf_howto_table [type] = & microblaze_elf_howto_raw [i]; | 
|  | } | 
|  | } | 
|  |  | 
|  | static reloc_howto_type * | 
|  | microblaze_elf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, | 
|  | bfd_reloc_code_real_type code) | 
|  | { | 
|  | enum elf_microblaze_reloc_type microblaze_reloc = R_MICROBLAZE_NONE; | 
|  |  | 
|  | switch (code) | 
|  | { | 
|  | case BFD_RELOC_NONE: | 
|  | microblaze_reloc = R_MICROBLAZE_NONE; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_32_NONE: | 
|  | microblaze_reloc = R_MICROBLAZE_32_NONE; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_NONE: | 
|  | microblaze_reloc = R_MICROBLAZE_64_NONE; | 
|  | break; | 
|  | case BFD_RELOC_32: | 
|  | microblaze_reloc = R_MICROBLAZE_32; | 
|  | break; | 
|  | /* RVA is treated the same as 32 */ | 
|  | case BFD_RELOC_RVA: | 
|  | microblaze_reloc = R_MICROBLAZE_32; | 
|  | break; | 
|  | case BFD_RELOC_32_PCREL: | 
|  | microblaze_reloc = R_MICROBLAZE_32_PCREL; | 
|  | break; | 
|  | case BFD_RELOC_64_PCREL: | 
|  | microblaze_reloc = R_MICROBLAZE_64_PCREL; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_32_LO_PCREL: | 
|  | microblaze_reloc = R_MICROBLAZE_32_PCREL_LO; | 
|  | break; | 
|  | case BFD_RELOC_64: | 
|  | microblaze_reloc = R_MICROBLAZE_64; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_32_LO: | 
|  | microblaze_reloc = R_MICROBLAZE_32_LO; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_32_ROSDA: | 
|  | microblaze_reloc = R_MICROBLAZE_SRO32; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_32_RWSDA: | 
|  | microblaze_reloc = R_MICROBLAZE_SRW32; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM: | 
|  | microblaze_reloc = R_MICROBLAZE_32_SYM_OP_SYM; | 
|  | break; | 
|  | case BFD_RELOC_VTABLE_INHERIT: | 
|  | microblaze_reloc = R_MICROBLAZE_GNU_VTINHERIT; | 
|  | break; | 
|  | case BFD_RELOC_VTABLE_ENTRY: | 
|  | microblaze_reloc = R_MICROBLAZE_GNU_VTENTRY; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_GOTPC: | 
|  | microblaze_reloc = R_MICROBLAZE_GOTPC_64; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_GOT: | 
|  | microblaze_reloc = R_MICROBLAZE_GOT_64; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_TEXTPCREL: | 
|  | microblaze_reloc = R_MICROBLAZE_TEXTPCREL_64; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_TEXTREL: | 
|  | microblaze_reloc = R_MICROBLAZE_TEXTREL_64; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_PLT: | 
|  | microblaze_reloc = R_MICROBLAZE_PLT_64; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_GOTOFF: | 
|  | microblaze_reloc = R_MICROBLAZE_GOTOFF_64; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_32_GOTOFF: | 
|  | microblaze_reloc = R_MICROBLAZE_GOTOFF_32; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_TLSGD: | 
|  | microblaze_reloc = R_MICROBLAZE_TLSGD; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_TLSLD: | 
|  | microblaze_reloc = R_MICROBLAZE_TLSLD; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_32_TLSDTPREL: | 
|  | microblaze_reloc = R_MICROBLAZE_TLSDTPREL32; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_TLSDTPREL: | 
|  | microblaze_reloc = R_MICROBLAZE_TLSDTPREL64; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_32_TLSDTPMOD: | 
|  | microblaze_reloc = R_MICROBLAZE_TLSDTPMOD32; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL: | 
|  | microblaze_reloc = R_MICROBLAZE_TLSGOTTPREL32; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_64_TLSTPREL: | 
|  | microblaze_reloc = R_MICROBLAZE_TLSTPREL32; | 
|  | break; | 
|  | case BFD_RELOC_MICROBLAZE_COPY: | 
|  | microblaze_reloc = R_MICROBLAZE_COPY; | 
|  | break; | 
|  | default: | 
|  | return (reloc_howto_type *) NULL; | 
|  | } | 
|  |  | 
|  | if (!microblaze_elf_howto_table [R_MICROBLAZE_32]) | 
|  | /* Initialize howto table if needed.  */ | 
|  | microblaze_elf_howto_init (); | 
|  |  | 
|  | return microblaze_elf_howto_table [(int) microblaze_reloc]; | 
|  | }; | 
|  |  | 
|  | static reloc_howto_type * | 
|  | microblaze_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | const char *r_name) | 
|  | { | 
|  | unsigned int i; | 
|  |  | 
|  | for (i = 0; i < NUM_ELEM (microblaze_elf_howto_raw); i++) | 
|  | if (microblaze_elf_howto_raw[i].name != NULL | 
|  | && strcasecmp (microblaze_elf_howto_raw[i].name, r_name) == 0) | 
|  | return µblaze_elf_howto_raw[i]; | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* Set the howto pointer for a RCE ELF reloc.  */ | 
|  |  | 
|  | static bool | 
|  | microblaze_elf_info_to_howto (bfd * abfd, | 
|  | arelent * cache_ptr, | 
|  | Elf_Internal_Rela * dst) | 
|  | { | 
|  | unsigned int r_type; | 
|  |  | 
|  | if (!microblaze_elf_howto_table [R_MICROBLAZE_32]) | 
|  | /* Initialize howto table if needed.  */ | 
|  | microblaze_elf_howto_init (); | 
|  |  | 
|  | r_type = ELF32_R_TYPE (dst->r_info); | 
|  | if (r_type >= R_MICROBLAZE_max) | 
|  | { | 
|  | /* xgettext:c-format */ | 
|  | _bfd_error_handler (_("%pB: unsupported relocation type %#x"), | 
|  | abfd, r_type); | 
|  | bfd_set_error (bfd_error_bad_value); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | cache_ptr->howto = microblaze_elf_howto_table [r_type]; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Relax table contains information about instructions which can | 
|  | be removed by relaxation -- replacing a long address with a | 
|  | short address.  */ | 
|  | struct relax_table | 
|  | { | 
|  | /* Address where bytes may be deleted.  */ | 
|  | bfd_vma addr; | 
|  |  | 
|  | /* Number of bytes to be deleted.  */ | 
|  | size_t size; | 
|  | }; | 
|  |  | 
|  | struct _microblaze_elf_section_data | 
|  | { | 
|  | struct bfd_elf_section_data elf; | 
|  | /* Count of used relaxation table entries.  */ | 
|  | size_t relax_count; | 
|  | /* Relaxation table.  */ | 
|  | struct relax_table *relax; | 
|  | }; | 
|  |  | 
|  | #define microblaze_elf_section_data(sec) \ | 
|  | ((struct _microblaze_elf_section_data *) elf_section_data (sec)) | 
|  |  | 
|  | static bool | 
|  | microblaze_elf_new_section_hook (bfd *abfd, asection *sec) | 
|  | { | 
|  | if (!sec->used_by_bfd) | 
|  | { | 
|  | struct _microblaze_elf_section_data *sdata; | 
|  | size_t amt = sizeof (*sdata); | 
|  |  | 
|  | sdata = bfd_zalloc (abfd, amt); | 
|  | if (sdata == NULL) | 
|  | return false; | 
|  | sec->used_by_bfd = sdata; | 
|  | } | 
|  |  | 
|  | return _bfd_elf_new_section_hook (abfd, sec); | 
|  | } | 
|  |  | 
|  | /* Microblaze ELF local labels start with 'L.' or '$L', not '.L'.  */ | 
|  |  | 
|  | static bool | 
|  | microblaze_elf_is_local_label_name (bfd *abfd, const char *name) | 
|  | { | 
|  | if (name[0] == 'L' && name[1] == '.') | 
|  | return true; | 
|  |  | 
|  | if (name[0] == '$' && name[1] == 'L') | 
|  | return true; | 
|  |  | 
|  | /* With gcc, the labels go back to starting with '.', so we accept | 
|  | the generic ELF local label syntax as well.  */ | 
|  | return _bfd_elf_is_local_label_name (abfd, name); | 
|  | } | 
|  |  | 
|  | /* ELF linker hash entry.  */ | 
|  |  | 
|  | struct elf32_mb_link_hash_entry | 
|  | { | 
|  | struct elf_link_hash_entry elf; | 
|  |  | 
|  | /* TLS Reference Types for the symbol; Updated by check_relocs */ | 
|  | #define TLS_GD     1  /* GD reloc. */ | 
|  | #define TLS_LD     2  /* LD reloc. */ | 
|  | #define TLS_TPREL  4  /* TPREL reloc, => IE. */ | 
|  | #define TLS_DTPREL 8  /* DTPREL reloc, => LD. */ | 
|  | #define TLS_TLS    16 /* Any TLS reloc.  */ | 
|  | unsigned char tls_mask; | 
|  |  | 
|  | }; | 
|  |  | 
|  | #define IS_TLS_GD(x)     (x == (TLS_TLS | TLS_GD)) | 
|  | #define IS_TLS_LD(x)     (x == (TLS_TLS | TLS_LD)) | 
|  | #define IS_TLS_DTPREL(x) (x == (TLS_TLS | TLS_DTPREL)) | 
|  | #define IS_TLS_NONE(x)   (x == 0) | 
|  |  | 
|  | #define elf32_mb_hash_entry(ent) ((struct elf32_mb_link_hash_entry *)(ent)) | 
|  |  | 
|  | /* ELF linker hash table.  */ | 
|  |  | 
|  | struct elf32_mb_link_hash_table | 
|  | { | 
|  | struct elf_link_hash_table elf; | 
|  |  | 
|  | /* TLS Local Dynamic GOT Entry */ | 
|  | union { | 
|  | bfd_signed_vma refcount; | 
|  | bfd_vma offset; | 
|  | } tlsld_got; | 
|  | }; | 
|  |  | 
|  | /* Nonzero if this section has TLS related relocations.  */ | 
|  | #define has_tls_reloc sec_flg0 | 
|  |  | 
|  | /* Get the ELF linker hash table from a link_info structure.  */ | 
|  |  | 
|  | #define elf32_mb_hash_table(p) \ | 
|  | ((is_elf_hash_table ((p)->hash)					\ | 
|  | && elf_hash_table_id (elf_hash_table (p)) == MICROBLAZE_ELF_DATA)	\ | 
|  | ? (struct elf32_mb_link_hash_table *) (p)->hash : NULL) | 
|  |  | 
|  | /* Create an entry in a microblaze ELF linker hash table.  */ | 
|  |  | 
|  | static struct bfd_hash_entry * | 
|  | link_hash_newfunc (struct bfd_hash_entry *entry, | 
|  | struct bfd_hash_table *table, | 
|  | const char *string) | 
|  | { | 
|  | /* Allocate the structure if it has not already been allocated by a | 
|  | subclass.  */ | 
|  | if (entry == NULL) | 
|  | { | 
|  | entry = bfd_hash_allocate (table, | 
|  | sizeof (struct elf32_mb_link_hash_entry)); | 
|  | if (entry == NULL) | 
|  | return entry; | 
|  | } | 
|  |  | 
|  | /* Call the allocation method of the superclass.  */ | 
|  | entry = _bfd_elf_link_hash_newfunc (entry, table, string); | 
|  | if (entry != NULL) | 
|  | { | 
|  | struct elf32_mb_link_hash_entry *eh; | 
|  |  | 
|  | eh = (struct elf32_mb_link_hash_entry *) entry; | 
|  | eh->tls_mask = 0; | 
|  | } | 
|  |  | 
|  | return entry; | 
|  | } | 
|  |  | 
|  | /* Create a mb ELF linker hash table.  */ | 
|  |  | 
|  | static struct bfd_link_hash_table * | 
|  | microblaze_elf_link_hash_table_create (bfd *abfd) | 
|  | { | 
|  | struct elf32_mb_link_hash_table *ret; | 
|  | size_t amt = sizeof (struct elf32_mb_link_hash_table); | 
|  |  | 
|  | ret = (struct elf32_mb_link_hash_table *) bfd_zmalloc (amt); | 
|  | if (ret == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc, | 
|  | sizeof (struct elf32_mb_link_hash_entry), | 
|  | MICROBLAZE_ELF_DATA)) | 
|  | { | 
|  | free (ret); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return &ret->elf.root; | 
|  | } | 
|  |  | 
|  | /* Set the values of the small data pointers.  */ | 
|  |  | 
|  | static void | 
|  | microblaze_elf_final_sdp (struct bfd_link_info *info) | 
|  | { | 
|  | struct bfd_link_hash_entry *h; | 
|  |  | 
|  | h = bfd_link_hash_lookup (info->hash, RO_SDA_ANCHOR_NAME, false, false, true); | 
|  | if (h != (struct bfd_link_hash_entry *) NULL | 
|  | && h->type == bfd_link_hash_defined) | 
|  | ro_small_data_pointer = (h->u.def.value | 
|  | + h->u.def.section->output_section->vma | 
|  | + h->u.def.section->output_offset); | 
|  |  | 
|  | h = bfd_link_hash_lookup (info->hash, RW_SDA_ANCHOR_NAME, false, false, true); | 
|  | if (h != (struct bfd_link_hash_entry *) NULL | 
|  | && h->type == bfd_link_hash_defined) | 
|  | rw_small_data_pointer = (h->u.def.value | 
|  | + h->u.def.section->output_section->vma | 
|  | + h->u.def.section->output_offset); | 
|  | } | 
|  |  | 
|  | static bfd_vma | 
|  | dtprel_base (struct bfd_link_info *info) | 
|  | { | 
|  | /* If tls_sec is NULL, we should have signalled an error already.  */ | 
|  | if (elf_hash_table (info)->tls_sec == NULL) | 
|  | return 0; | 
|  | return elf_hash_table (info)->tls_sec->vma; | 
|  | } | 
|  |  | 
|  | /* The size of the thread control block.  */ | 
|  | #define TCB_SIZE	8 | 
|  |  | 
|  | /* Output a simple dynamic relocation into SRELOC.  */ | 
|  |  | 
|  | static void | 
|  | microblaze_elf_output_dynamic_relocation (bfd *output_bfd, | 
|  | asection *sreloc, | 
|  | unsigned long reloc_index, | 
|  | unsigned long indx, | 
|  | int r_type, | 
|  | bfd_vma offset, | 
|  | bfd_vma addend) | 
|  | { | 
|  |  | 
|  | Elf_Internal_Rela rel; | 
|  |  | 
|  | rel.r_info = ELF32_R_INFO (indx, r_type); | 
|  | rel.r_offset = offset; | 
|  | rel.r_addend = addend; | 
|  |  | 
|  | bfd_elf32_swap_reloca_out (output_bfd, &rel, | 
|  | (sreloc->contents + reloc_index * sizeof (Elf32_External_Rela))); | 
|  | } | 
|  |  | 
|  | /* This code is taken from elf32-m32r.c | 
|  | There is some attempt to make this function usable for many architectures, | 
|  | both USE_REL and USE_RELA ['twould be nice if such a critter existed], | 
|  | if only to serve as a learning tool. | 
|  |  | 
|  | 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 adjust 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 int | 
|  | microblaze_elf_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) | 
|  | { | 
|  | struct elf32_mb_link_hash_table *htab; | 
|  | Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; | 
|  | struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); | 
|  | Elf_Internal_Rela *rel, *relend; | 
|  | int endian = (bfd_little_endian (output_bfd)) ? 0 : 2; | 
|  | /* Assume success.  */ | 
|  | bool ret = true; | 
|  | asection *sreloc; | 
|  | bfd_vma *local_got_offsets; | 
|  | unsigned int tls_type; | 
|  |  | 
|  | if (!microblaze_elf_howto_table[R_MICROBLAZE_max-1]) | 
|  | microblaze_elf_howto_init (); | 
|  |  | 
|  | htab = elf32_mb_hash_table (info); | 
|  | if (htab == NULL) | 
|  | return false; | 
|  |  | 
|  | local_got_offsets = elf_local_got_offsets (input_bfd); | 
|  |  | 
|  | sreloc = elf_section_data (input_section)->sreloc; | 
|  |  | 
|  | rel = relocs; | 
|  | relend = relocs + input_section->reloc_count; | 
|  | for (; rel < relend; rel++) | 
|  | { | 
|  | int r_type; | 
|  | reloc_howto_type *howto; | 
|  | unsigned long r_symndx; | 
|  | bfd_vma addend = rel->r_addend; | 
|  | bfd_vma offset = rel->r_offset; | 
|  | struct elf_link_hash_entry *h; | 
|  | Elf_Internal_Sym *sym; | 
|  | asection *sec; | 
|  | const char *sym_name; | 
|  | bfd_reloc_status_type r = bfd_reloc_ok; | 
|  | const char *errmsg = NULL; | 
|  | bool unresolved_reloc = false; | 
|  |  | 
|  | h = NULL; | 
|  | r_type = ELF32_R_TYPE (rel->r_info); | 
|  | tls_type = 0; | 
|  |  | 
|  | if (r_type < 0 || r_type >= (int) R_MICROBLAZE_max) | 
|  | { | 
|  | /* xgettext:c-format */ | 
|  | _bfd_error_handler (_("%pB: unsupported relocation type %#x"), | 
|  | input_bfd, (int) r_type); | 
|  | bfd_set_error (bfd_error_bad_value); | 
|  | ret = false; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | howto = microblaze_elf_howto_table[r_type]; | 
|  | r_symndx = ELF32_R_SYM (rel->r_info); | 
|  |  | 
|  | if (bfd_link_relocatable (info)) | 
|  | { | 
|  | /* This is a relocatable link.  We don't have to change | 
|  | anything, unless the reloc is against a section symbol, | 
|  | in which case we have to adjust according to where the | 
|  | section symbol winds up in the output section.  */ | 
|  | sec = NULL; | 
|  | if (r_symndx >= symtab_hdr->sh_info) | 
|  | /* External symbol.  */ | 
|  | continue; | 
|  |  | 
|  | /* Local symbol.  */ | 
|  | sym = local_syms + r_symndx; | 
|  | sym_name = "<local symbol>"; | 
|  | /* STT_SECTION: symbol is associated with a section.  */ | 
|  | if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) | 
|  | /* Symbol isn't associated with a section.  Nothing to do.  */ | 
|  | continue; | 
|  |  | 
|  | sec = local_sections[r_symndx]; | 
|  | addend += sec->output_offset + sym->st_value; | 
|  | #ifndef USE_REL | 
|  | /* This can't be done for USE_REL because it doesn't mean anything | 
|  | and elf_link_input_bfd asserts this stays zero.  */ | 
|  | /* rel->r_addend = addend; */ | 
|  | #endif | 
|  |  | 
|  | #ifndef USE_REL | 
|  | /* Addends are stored with relocs.  We're done.  */ | 
|  | continue; | 
|  | #else /* USE_REL */ | 
|  | /* If partial_inplace, we need to store any additional addend | 
|  | back in the section.  */ | 
|  | if (!howto->partial_inplace) | 
|  | continue; | 
|  | /* ??? Here is a nice place to call a special_function like handler.  */ | 
|  | r = _bfd_relocate_contents (howto, input_bfd, addend, | 
|  | contents + offset); | 
|  | #endif /* USE_REL */ | 
|  | } | 
|  | else | 
|  | { | 
|  | bfd_vma relocation; | 
|  | bool resolved_to_zero; | 
|  |  | 
|  | /* This is a final link.  */ | 
|  | sym = NULL; | 
|  | sec = NULL; | 
|  | unresolved_reloc = false; | 
|  |  | 
|  | if (r_symndx < symtab_hdr->sh_info) | 
|  | { | 
|  | /* Local symbol.  */ | 
|  | sym = local_syms + r_symndx; | 
|  | sec = local_sections[r_symndx]; | 
|  | if (sec == 0) | 
|  | continue; | 
|  | sym_name = "<local symbol>"; | 
|  | relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); | 
|  | /* r_addend may have changed if the reference section was | 
|  | a merge section.  */ | 
|  | addend = rel->r_addend; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* External symbol.  */ | 
|  | bool warned ATTRIBUTE_UNUSED; | 
|  | bool ignored ATTRIBUTE_UNUSED; | 
|  |  | 
|  | RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, | 
|  | r_symndx, symtab_hdr, sym_hashes, | 
|  | h, sec, relocation, | 
|  | unresolved_reloc, warned, ignored); | 
|  | sym_name = h->root.root.string; | 
|  | } | 
|  |  | 
|  | /* Sanity check the address.  */ | 
|  | if (offset > bfd_get_section_limit (input_bfd, input_section)) | 
|  | { | 
|  | r = bfd_reloc_outofrange; | 
|  | goto check_reloc; | 
|  | } | 
|  |  | 
|  | resolved_to_zero = (h != NULL | 
|  | && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); | 
|  |  | 
|  | switch ((int) r_type) | 
|  | { | 
|  | case (int) R_MICROBLAZE_SRO32 : | 
|  | { | 
|  | const char *name; | 
|  |  | 
|  | /* Only relocate if the symbol is defined.  */ | 
|  | if (sec) | 
|  | { | 
|  | name = bfd_section_name (sec); | 
|  |  | 
|  | if (strcmp (name, ".sdata2") == 0 | 
|  | || strcmp (name, ".sbss2") == 0) | 
|  | { | 
|  | if (ro_small_data_pointer == 0) | 
|  | microblaze_elf_final_sdp (info); | 
|  | if (ro_small_data_pointer == 0) | 
|  | { | 
|  | ret = false; | 
|  | r = bfd_reloc_undefined; | 
|  | goto check_reloc; | 
|  | } | 
|  |  | 
|  | /* At this point `relocation' contains the object's | 
|  | address.  */ | 
|  | relocation -= ro_small_data_pointer; | 
|  | /* Now it contains the offset from _SDA2_BASE_.  */ | 
|  | r = _bfd_final_link_relocate (howto, input_bfd, | 
|  | input_section, | 
|  | contents, offset, | 
|  | relocation, addend); | 
|  | } | 
|  | else | 
|  | { | 
|  | _bfd_error_handler | 
|  | /* xgettext:c-format */ | 
|  | (_("%pB: the target (%s) of an %s relocation" | 
|  | " is in the wrong section (%pA)"), | 
|  | input_bfd, | 
|  | sym_name, | 
|  | microblaze_elf_howto_table[(int) r_type]->name, | 
|  | sec); | 
|  | /*bfd_set_error (bfd_error_bad_value); ??? why? */ | 
|  | ret = false; | 
|  | continue; | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | case (int) R_MICROBLAZE_SRW32 : | 
|  | { | 
|  | const char *name; | 
|  |  | 
|  | /* Only relocate if the symbol is defined.  */ | 
|  | if (sec) | 
|  | { | 
|  | name = bfd_section_name (sec); | 
|  |  | 
|  | if (strcmp (name, ".sdata") == 0 | 
|  | || strcmp (name, ".sbss") == 0) | 
|  | { | 
|  | if (rw_small_data_pointer == 0) | 
|  | microblaze_elf_final_sdp (info); | 
|  | if (rw_small_data_pointer == 0) | 
|  | { | 
|  | ret = false; | 
|  | r = bfd_reloc_undefined; | 
|  | goto check_reloc; | 
|  | } | 
|  |  | 
|  | /* At this point `relocation' contains the object's | 
|  | address.  */ | 
|  | relocation -= rw_small_data_pointer; | 
|  | /* Now it contains the offset from _SDA_BASE_.  */ | 
|  | r = _bfd_final_link_relocate (howto, input_bfd, | 
|  | input_section, | 
|  | contents, offset, | 
|  | relocation, addend); | 
|  | } | 
|  | else | 
|  | { | 
|  | _bfd_error_handler | 
|  | /* xgettext:c-format */ | 
|  | (_("%pB: the target (%s) of an %s relocation" | 
|  | " is in the wrong section (%pA)"), | 
|  | input_bfd, | 
|  | sym_name, | 
|  | microblaze_elf_howto_table[(int) r_type]->name, | 
|  | sec); | 
|  | /*bfd_set_error (bfd_error_bad_value); ??? why? */ | 
|  | ret = false; | 
|  | continue; | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | case (int) R_MICROBLAZE_32_SYM_OP_SYM: | 
|  | break; /* Do nothing.  */ | 
|  |  | 
|  | case (int) R_MICROBLAZE_GOTPC_64: | 
|  | relocation = (htab->elf.sgotplt->output_section->vma | 
|  | + htab->elf.sgotplt->output_offset); | 
|  | relocation -= (input_section->output_section->vma | 
|  | + input_section->output_offset | 
|  | + offset + INST_WORD_SIZE); | 
|  | relocation += addend; | 
|  | bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff, | 
|  | contents + offset + endian); | 
|  | bfd_put_16 (input_bfd, relocation & 0xffff, | 
|  | contents + offset + endian + INST_WORD_SIZE); | 
|  | break; | 
|  |  | 
|  | case (int) R_MICROBLAZE_TEXTPCREL_64: | 
|  | relocation = input_section->output_section->vma; | 
|  | relocation -= (input_section->output_section->vma | 
|  | + input_section->output_offset | 
|  | + offset + INST_WORD_SIZE); | 
|  | relocation += addend; | 
|  | bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff, | 
|  | contents + offset + endian); | 
|  | bfd_put_16 (input_bfd, relocation & 0xffff, | 
|  | contents + offset + endian + INST_WORD_SIZE); | 
|  | break; | 
|  |  | 
|  | case (int) R_MICROBLAZE_PLT_64: | 
|  | { | 
|  | bfd_vma immediate; | 
|  | if (htab->elf.splt != NULL && h != NULL | 
|  | && h->plt.offset != (bfd_vma) -1) | 
|  | { | 
|  | relocation = (htab->elf.splt->output_section->vma | 
|  | + htab->elf.splt->output_offset | 
|  | + h->plt.offset); | 
|  | unresolved_reloc = false; | 
|  | immediate = relocation - (input_section->output_section->vma | 
|  | + input_section->output_offset | 
|  | + offset + INST_WORD_SIZE); | 
|  | bfd_put_16 (input_bfd, (immediate >> 16) & 0xffff, | 
|  | contents + offset + endian); | 
|  | bfd_put_16 (input_bfd, immediate & 0xffff, | 
|  | contents + offset + endian + INST_WORD_SIZE); | 
|  | } | 
|  | else | 
|  | { | 
|  | relocation -= (input_section->output_section->vma | 
|  | + input_section->output_offset | 
|  | + offset + INST_WORD_SIZE); | 
|  | immediate = relocation; | 
|  | bfd_put_16 (input_bfd, (immediate >> 16) & 0xffff, | 
|  | contents + offset + endian); | 
|  | bfd_put_16 (input_bfd, immediate & 0xffff, | 
|  | contents + offset + endian + INST_WORD_SIZE); | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | case (int) R_MICROBLAZE_TLSGD: | 
|  | tls_type = (TLS_TLS | TLS_GD); | 
|  | goto dogot; | 
|  | case (int) R_MICROBLAZE_TLSLD: | 
|  | tls_type = (TLS_TLS | TLS_LD); | 
|  | /* Fall through.  */ | 
|  | dogot: | 
|  | case (int) R_MICROBLAZE_GOT_64: | 
|  | { | 
|  | bfd_vma *offp; | 
|  | bfd_vma off, off2; | 
|  | unsigned long indx; | 
|  | bfd_vma static_value; | 
|  |  | 
|  | bool need_relocs = false; | 
|  | if (htab->elf.sgot == NULL) | 
|  | abort (); | 
|  |  | 
|  | indx = 0; | 
|  | offp = NULL; | 
|  |  | 
|  | /* 1. Identify GOT Offset; | 
|  | 2. Compute Static Values | 
|  | 3. Process Module Id, Process Offset | 
|  | 4. Fixup Relocation with GOT offset value. */ | 
|  |  | 
|  | /* 1. Determine GOT Offset to use : TLS_LD, global, local */ | 
|  | if (IS_TLS_LD (tls_type)) | 
|  | offp = &htab->tlsld_got.offset; | 
|  | else if (h != NULL) | 
|  | { | 
|  | if (htab->elf.sgotplt != NULL | 
|  | && h->got.offset != (bfd_vma) -1) | 
|  | offp = &h->got.offset; | 
|  | else | 
|  | abort (); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (local_got_offsets == NULL) | 
|  | abort (); | 
|  | offp = &local_got_offsets[r_symndx]; | 
|  | } | 
|  |  | 
|  | if (!offp) | 
|  | abort (); | 
|  |  | 
|  | off = (*offp) & ~1; | 
|  | off2 = off; | 
|  |  | 
|  | if (IS_TLS_LD(tls_type) || IS_TLS_GD(tls_type)) | 
|  | off2 = off + 4; | 
|  |  | 
|  | /* Symbol index to use for relocs */ | 
|  | if (h != NULL) | 
|  | { | 
|  | bool dyn = | 
|  | elf_hash_table (info)->dynamic_sections_created; | 
|  |  | 
|  | if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, | 
|  | bfd_link_pic (info), | 
|  | h) | 
|  | && (!bfd_link_pic (info) | 
|  | || !SYMBOL_REFERENCES_LOCAL (info, h))) | 
|  | indx = h->dynindx; | 
|  | } | 
|  |  | 
|  | /* Need to generate relocs ? */ | 
|  | if ((bfd_link_pic (info) || indx != 0) | 
|  | && (h == NULL | 
|  | || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT | 
|  | && !resolved_to_zero) | 
|  | || h->root.type != bfd_link_hash_undefweak)) | 
|  | need_relocs = true; | 
|  |  | 
|  | /* 2. Compute/Emit Static value of r-expression */ | 
|  | static_value = relocation + addend; | 
|  |  | 
|  | /* 3. Process module-id and offset */ | 
|  | if (! ((*offp) & 1) ) | 
|  | { | 
|  | bfd_vma got_offset; | 
|  |  | 
|  | got_offset = (htab->elf.sgot->output_section->vma | 
|  | + htab->elf.sgot->output_offset | 
|  | + off); | 
|  |  | 
|  | /* Process module-id */ | 
|  | if (IS_TLS_LD(tls_type)) | 
|  | { | 
|  | if (! bfd_link_pic (info)) | 
|  | bfd_put_32 (output_bfd, 1, | 
|  | htab->elf.sgot->contents + off); | 
|  | else | 
|  | microblaze_elf_output_dynamic_relocation | 
|  | (output_bfd, | 
|  | htab->elf.srelgot, | 
|  | htab->elf.srelgot->reloc_count++, | 
|  | /* symindex= */ 0, R_MICROBLAZE_TLSDTPMOD32, | 
|  | got_offset, 0); | 
|  | } | 
|  | else if (IS_TLS_GD(tls_type)) | 
|  | { | 
|  | if (! need_relocs) | 
|  | bfd_put_32 (output_bfd, 1, | 
|  | htab->elf.sgot->contents + off); | 
|  | else | 
|  | microblaze_elf_output_dynamic_relocation | 
|  | (output_bfd, | 
|  | htab->elf.srelgot, | 
|  | htab->elf.srelgot->reloc_count++, | 
|  | /* symindex= */ indx, R_MICROBLAZE_TLSDTPMOD32, | 
|  | got_offset, indx ? 0 : static_value); | 
|  | } | 
|  |  | 
|  | /* Process Offset */ | 
|  | if (htab->elf.srelgot == NULL) | 
|  | abort (); | 
|  |  | 
|  | got_offset = (htab->elf.sgot->output_section->vma | 
|  | + htab->elf.sgot->output_offset | 
|  | + off2); | 
|  | if (IS_TLS_LD(tls_type)) | 
|  | { | 
|  | /* For LD, offset should be 0 */ | 
|  | *offp |= 1; | 
|  | bfd_put_32 (output_bfd, 0, | 
|  | htab->elf.sgot->contents + off2); | 
|  | } | 
|  | else if (IS_TLS_GD(tls_type)) | 
|  | { | 
|  | *offp |= 1; | 
|  | static_value -= dtprel_base(info); | 
|  | if (need_relocs) | 
|  | microblaze_elf_output_dynamic_relocation | 
|  | (output_bfd, | 
|  | htab->elf.srelgot, | 
|  | htab->elf.srelgot->reloc_count++, | 
|  | /* symindex= */ indx, R_MICROBLAZE_TLSDTPREL32, | 
|  | got_offset, indx ? 0 : static_value); | 
|  | else | 
|  | bfd_put_32 (output_bfd, static_value, | 
|  | htab->elf.sgot->contents + off2); | 
|  | } | 
|  | else | 
|  | { | 
|  | bfd_put_32 (output_bfd, static_value, | 
|  | htab->elf.sgot->contents + off2); | 
|  |  | 
|  | /* Relocs for dyn symbols generated by | 
|  | finish_dynamic_symbols */ | 
|  | if (bfd_link_pic (info) && h == NULL) | 
|  | { | 
|  | *offp |= 1; | 
|  | microblaze_elf_output_dynamic_relocation | 
|  | (output_bfd, | 
|  | htab->elf.srelgot, | 
|  | htab->elf.srelgot->reloc_count++, | 
|  | /* symindex= */ indx, R_MICROBLAZE_REL, | 
|  | got_offset, static_value); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* 4. Fixup Relocation with GOT offset value | 
|  | Compute relative address of GOT entry for applying | 
|  | the current relocation */ | 
|  | relocation = htab->elf.sgot->output_section->vma | 
|  | + htab->elf.sgot->output_offset | 
|  | + off | 
|  | - htab->elf.sgotplt->output_section->vma | 
|  | - htab->elf.sgotplt->output_offset; | 
|  |  | 
|  | /* Apply Current Relocation */ | 
|  | bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff, | 
|  | contents + offset + endian); | 
|  | bfd_put_16 (input_bfd, relocation & 0xffff, | 
|  | contents + offset + endian + INST_WORD_SIZE); | 
|  |  | 
|  | unresolved_reloc = false; | 
|  | break; | 
|  | } | 
|  |  | 
|  | case (int) R_MICROBLAZE_GOTOFF_64: | 
|  | { | 
|  | bfd_vma immediate; | 
|  | unsigned short lo, high; | 
|  | relocation += addend; | 
|  | relocation -= (htab->elf.sgotplt->output_section->vma | 
|  | + htab->elf.sgotplt->output_offset); | 
|  | /* Write this value into correct location.  */ | 
|  | immediate = relocation; | 
|  | lo = immediate & 0x0000ffff; | 
|  | high = (immediate >> 16) & 0x0000ffff; | 
|  | bfd_put_16 (input_bfd, high, contents + offset + endian); | 
|  | bfd_put_16 (input_bfd, lo, | 
|  | contents + offset + INST_WORD_SIZE + endian); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case (int) R_MICROBLAZE_GOTOFF_32: | 
|  | { | 
|  | relocation += addend; | 
|  | relocation -= (htab->elf.sgotplt->output_section->vma | 
|  | + htab->elf.sgotplt->output_offset); | 
|  | /* Write this value into correct location.  */ | 
|  | bfd_put_32 (input_bfd, relocation, contents + offset); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case (int) R_MICROBLAZE_TLSDTPREL64: | 
|  | relocation += addend; | 
|  | relocation -= dtprel_base(info); | 
|  | bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff, | 
|  | contents + offset + endian); | 
|  | bfd_put_16 (input_bfd, relocation & 0xffff, | 
|  | contents + offset + endian + INST_WORD_SIZE); | 
|  | break; | 
|  | case (int) R_MICROBLAZE_TEXTREL_64: | 
|  | case (int) R_MICROBLAZE_TEXTREL_32_LO: | 
|  | case (int) R_MICROBLAZE_64_PCREL : | 
|  | case (int) R_MICROBLAZE_64: | 
|  | case (int) R_MICROBLAZE_32: | 
|  | { | 
|  | /* r_symndx will be STN_UNDEF (zero) only for relocs against symbols | 
|  | from removed linkonce sections, or sections discarded by | 
|  | a linker script.  */ | 
|  | if (r_symndx == STN_UNDEF || (input_section->flags & SEC_ALLOC) == 0) | 
|  | { | 
|  | relocation += addend; | 
|  | if (r_type == R_MICROBLAZE_32) | 
|  | bfd_put_32 (input_bfd, relocation, contents + offset); | 
|  | else | 
|  | { | 
|  | if (r_type == R_MICROBLAZE_64_PCREL) | 
|  | relocation -= (input_section->output_section->vma | 
|  | + input_section->output_offset | 
|  | + offset + INST_WORD_SIZE); | 
|  | else if (r_type == R_MICROBLAZE_TEXTREL_64 | 
|  | || r_type == R_MICROBLAZE_TEXTREL_32_LO) | 
|  | relocation -= input_section->output_section->vma; | 
|  |  | 
|  | if (r_type == R_MICROBLAZE_TEXTREL_32_LO) | 
|  | bfd_put_16 (input_bfd, relocation & 0xffff, | 
|  | contents + offset + endian); | 
|  |  | 
|  | else | 
|  | { | 
|  | bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff, | 
|  | contents + offset + endian); | 
|  | bfd_put_16 (input_bfd, relocation & 0xffff, | 
|  | contents + offset + endian + INST_WORD_SIZE); | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | if ((bfd_link_pic (info) | 
|  | && (h == NULL | 
|  | || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT | 
|  | && !resolved_to_zero) | 
|  | || h->root.type != bfd_link_hash_undefweak) | 
|  | && (!howto->pc_relative | 
|  | || (h != NULL | 
|  | && h->dynindx != -1 | 
|  | && (!info->symbolic | 
|  | || !h->def_regular)))) | 
|  | || (!bfd_link_pic (info) | 
|  | && h != NULL | 
|  | && h->dynindx != -1 | 
|  | && !h->non_got_ref | 
|  | && ((h->def_dynamic | 
|  | && !h->def_regular) | 
|  | || h->root.type == bfd_link_hash_undefweak | 
|  | || h->root.type == bfd_link_hash_undefined))) | 
|  | { | 
|  | Elf_Internal_Rela outrel; | 
|  | bfd_byte *loc; | 
|  | bool skip; | 
|  |  | 
|  | /* When generating a shared object, these relocations | 
|  | are copied into the output file to be resolved at run | 
|  | time.  */ | 
|  |  | 
|  | BFD_ASSERT (sreloc != NULL); | 
|  |  | 
|  | skip = false; | 
|  |  | 
|  | outrel.r_offset = | 
|  | _bfd_elf_section_offset (output_bfd, info, input_section, | 
|  | rel->r_offset); | 
|  | if (outrel.r_offset == (bfd_vma) -1) | 
|  | skip = true; | 
|  | else if (outrel.r_offset == (bfd_vma) -2) | 
|  | skip = true; | 
|  | outrel.r_offset += (input_section->output_section->vma | 
|  | + input_section->output_offset); | 
|  |  | 
|  | if (skip) | 
|  | memset (&outrel, 0, sizeof outrel); | 
|  | /* h->dynindx may be -1 if the symbol was marked to | 
|  | become local.  */ | 
|  | else if (h != NULL | 
|  | && ((! info->symbolic && h->dynindx != -1) | 
|  | || !h->def_regular)) | 
|  | { | 
|  | BFD_ASSERT (h->dynindx != -1); | 
|  | outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); | 
|  | outrel.r_addend = addend; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (r_type == R_MICROBLAZE_32) | 
|  | { | 
|  | outrel.r_info = ELF32_R_INFO (0, R_MICROBLAZE_REL); | 
|  | outrel.r_addend = relocation + addend; | 
|  | } | 
|  | else | 
|  | { | 
|  | BFD_FAIL (); | 
|  | _bfd_error_handler | 
|  | (_("%pB: probably compiled without -fPIC?"), | 
|  | input_bfd); | 
|  | bfd_set_error (bfd_error_bad_value); | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | loc = sreloc->contents; | 
|  | loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); | 
|  | bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); | 
|  | break; | 
|  | } | 
|  | else | 
|  | { | 
|  | relocation += addend; | 
|  | if (r_type == R_MICROBLAZE_32) | 
|  | bfd_put_32 (input_bfd, relocation, contents + offset); | 
|  | else | 
|  | { | 
|  | if (r_type == R_MICROBLAZE_64_PCREL) | 
|  | relocation -= (input_section->output_section->vma | 
|  | + input_section->output_offset | 
|  | + offset + INST_WORD_SIZE); | 
|  | else if (r_type == R_MICROBLAZE_TEXTREL_64 | 
|  | || r_type == R_MICROBLAZE_TEXTREL_32_LO) | 
|  | relocation -= input_section->output_section->vma; | 
|  |  | 
|  | if (r_type == R_MICROBLAZE_TEXTREL_32_LO) | 
|  | { | 
|  | bfd_put_16 (input_bfd, relocation & 0xffff, | 
|  | contents + offset + endian); | 
|  | } | 
|  | else | 
|  | { | 
|  | bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff, | 
|  | contents + offset + endian); | 
|  | bfd_put_16 (input_bfd, relocation & 0xffff, | 
|  | contents + offset + endian | 
|  | + INST_WORD_SIZE); | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | default : | 
|  | r = _bfd_final_link_relocate (howto, input_bfd, input_section, | 
|  | contents, offset, | 
|  | relocation, addend); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | check_reloc: | 
|  |  | 
|  | if (r != bfd_reloc_ok) | 
|  | { | 
|  | /* FIXME: This should be generic enough to go in a utility.  */ | 
|  | 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 || *name == '\0') | 
|  | name = bfd_section_name (sec); | 
|  | } | 
|  |  | 
|  | if (errmsg != NULL) | 
|  | goto common_error; | 
|  |  | 
|  | switch (r) | 
|  | { | 
|  | case bfd_reloc_overflow: | 
|  | (*info->callbacks->reloc_overflow) | 
|  | (info, (h ? &h->root : NULL), name, howto->name, | 
|  | (bfd_vma) 0, input_bfd, input_section, offset); | 
|  | break; | 
|  |  | 
|  | case bfd_reloc_undefined: | 
|  | (*info->callbacks->undefined_symbol) | 
|  | (info, name, input_bfd, input_section, offset, true); | 
|  | break; | 
|  |  | 
|  | case bfd_reloc_outofrange: | 
|  | errmsg = _("internal error: out of range error"); | 
|  | goto common_error; | 
|  |  | 
|  | case bfd_reloc_notsupported: | 
|  | errmsg = _("internal error: unsupported relocation error"); | 
|  | goto common_error; | 
|  |  | 
|  | case bfd_reloc_dangerous: | 
|  | errmsg = _("internal error: dangerous error"); | 
|  | goto common_error; | 
|  |  | 
|  | default: | 
|  | errmsg = _("internal error: unknown error"); | 
|  | /* Fall through.  */ | 
|  | common_error: | 
|  | (*info->callbacks->warning) (info, errmsg, name, input_bfd, | 
|  | input_section, offset); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Calculate fixup value for reference.  */ | 
|  |  | 
|  | static size_t | 
|  | calc_fixup (bfd_vma start, bfd_vma size, asection *sec) | 
|  | { | 
|  | bfd_vma end = start + size; | 
|  | size_t i, fixup = 0; | 
|  | struct _microblaze_elf_section_data *sdata; | 
|  |  | 
|  | if (sec == NULL || (sdata = microblaze_elf_section_data (sec)) == NULL) | 
|  | return 0; | 
|  |  | 
|  | /* Look for addr in relax table, total fixup value.  */ | 
|  | for (i = 0; i < sdata->relax_count; i++) | 
|  | { | 
|  | if (end <= sdata->relax[i].addr) | 
|  | break; | 
|  | if (end != start && start > sdata->relax[i].addr) | 
|  | continue; | 
|  | fixup += sdata->relax[i].size; | 
|  | } | 
|  | return fixup; | 
|  | } | 
|  |  | 
|  | /* Read-modify-write into the bfd, an immediate value into appropriate fields of | 
|  | a 32-bit instruction.  */ | 
|  | static void | 
|  | microblaze_bfd_write_imm_value_32 (bfd *abfd, bfd_byte *bfd_addr, bfd_vma val) | 
|  | { | 
|  | unsigned long instr = bfd_get_32 (abfd, bfd_addr); | 
|  | instr &= ~0x0000ffff; | 
|  | instr |= (val & 0x0000ffff); | 
|  | bfd_put_32 (abfd, instr, bfd_addr); | 
|  | } | 
|  |  | 
|  | /* Read-modify-write into the bfd, an immediate value into appropriate fields of | 
|  | two consecutive 32-bit instructions.  */ | 
|  | static void | 
|  | microblaze_bfd_write_imm_value_64 (bfd *abfd, bfd_byte *bfd_addr, bfd_vma val) | 
|  | { | 
|  | unsigned long instr_hi; | 
|  | unsigned long instr_lo; | 
|  |  | 
|  | instr_hi = bfd_get_32 (abfd, bfd_addr); | 
|  | instr_hi &= ~0x0000ffff; | 
|  | instr_hi |= ((val >> 16) & 0x0000ffff); | 
|  | bfd_put_32 (abfd, instr_hi, bfd_addr); | 
|  |  | 
|  | instr_lo = bfd_get_32 (abfd, bfd_addr + INST_WORD_SIZE); | 
|  | instr_lo &= ~0x0000ffff; | 
|  | instr_lo |= (val & 0x0000ffff); | 
|  | bfd_put_32 (abfd, instr_lo, bfd_addr + INST_WORD_SIZE); | 
|  | } | 
|  |  | 
|  | static bool | 
|  | microblaze_elf_relax_section (bfd *abfd, | 
|  | asection *sec, | 
|  | struct bfd_link_info *link_info, | 
|  | bool *again) | 
|  | { | 
|  | Elf_Internal_Shdr *symtab_hdr; | 
|  | Elf_Internal_Rela *internal_relocs; | 
|  | Elf_Internal_Rela *free_relocs = NULL; | 
|  | Elf_Internal_Rela *irel, *irelend; | 
|  | bfd_byte *contents = NULL; | 
|  | bfd_byte *free_contents = NULL; | 
|  | int rel_count; | 
|  | unsigned int shndx; | 
|  | size_t i, sym_index; | 
|  | asection *o; | 
|  | struct elf_link_hash_entry *sym_hash; | 
|  | Elf_Internal_Sym *isymbuf, *isymend; | 
|  | Elf_Internal_Sym *isym; | 
|  | size_t symcount; | 
|  | size_t offset; | 
|  | bfd_vma src, dest; | 
|  | struct _microblaze_elf_section_data *sdata; | 
|  |  | 
|  | /* We only do this once per section.  We may be able to delete some code | 
|  | by running multiple passes, but it is not worth it.  */ | 
|  | *again = false; | 
|  |  | 
|  | /* Only do this for a text section.  */ | 
|  | if (bfd_link_relocatable (link_info) | 
|  | || (sec->flags & SEC_RELOC) == 0 | 
|  | || (sec->flags & SEC_CODE) == 0 | 
|  | || sec->reloc_count == 0 | 
|  | || (sdata = microblaze_elf_section_data (sec)) == NULL) | 
|  | return true; | 
|  |  | 
|  | BFD_ASSERT ((sec->size > 0) || (sec->rawsize > 0)); | 
|  |  | 
|  | /* If this is the first time we have been called for this section, | 
|  | initialize the cooked size.  */ | 
|  | if (sec->size == 0) | 
|  | sec->size = sec->rawsize; | 
|  |  | 
|  | /* Get symbols for this section.  */ | 
|  | symtab_hdr = &elf_tdata (abfd)->symtab_hdr; | 
|  | isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; | 
|  | symcount =  symtab_hdr->sh_size / sizeof (Elf32_External_Sym); | 
|  | if (isymbuf == NULL) | 
|  | isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, symcount, | 
|  | 0, NULL, NULL, NULL); | 
|  | BFD_ASSERT (isymbuf != NULL); | 
|  |  | 
|  | internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, link_info->keep_memory); | 
|  | if (internal_relocs == NULL) | 
|  | goto error_return; | 
|  | if (! link_info->keep_memory) | 
|  | free_relocs = internal_relocs; | 
|  |  | 
|  | sdata->relax_count = 0; | 
|  | sdata->relax = (struct relax_table *) bfd_malloc ((sec->reloc_count + 1) | 
|  | * sizeof (*sdata->relax)); | 
|  | if (sdata->relax == NULL) | 
|  | goto error_return; | 
|  |  | 
|  | irelend = internal_relocs + sec->reloc_count; | 
|  | rel_count = 0; | 
|  | for (irel = internal_relocs; irel < irelend; irel++, rel_count++) | 
|  | { | 
|  | bfd_vma symval; | 
|  | if ((ELF32_R_TYPE (irel->r_info) != (int) R_MICROBLAZE_64_PCREL) | 
|  | && (ELF32_R_TYPE (irel->r_info) != (int) R_MICROBLAZE_64) | 
|  | && (ELF32_R_TYPE (irel->r_info) != (int) R_MICROBLAZE_TEXTREL_64)) | 
|  | continue; /* Can't delete this reloc.  */ | 
|  |  | 
|  | /* Get the section contents.  */ | 
|  | if (contents == NULL) | 
|  | { | 
|  | if (elf_section_data (sec)->this_hdr.contents != NULL) | 
|  | contents = elf_section_data (sec)->this_hdr.contents; | 
|  | else | 
|  | { | 
|  | contents = (bfd_byte *) bfd_malloc (sec->size); | 
|  | if (contents == NULL) | 
|  | goto error_return; | 
|  | free_contents = contents; | 
|  |  | 
|  | if (!bfd_get_section_contents (abfd, sec, contents, | 
|  | (file_ptr) 0, sec->size)) | 
|  | goto error_return; | 
|  | elf_section_data (sec)->this_hdr.contents = contents; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Get the value of the symbol referred to by the reloc.  */ | 
|  | if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) | 
|  | { | 
|  | /* A local symbol.  */ | 
|  | asection *sym_sec; | 
|  |  | 
|  | isym = isymbuf + ELF32_R_SYM (irel->r_info); | 
|  | if (isym->st_shndx == SHN_UNDEF) | 
|  | sym_sec = bfd_und_section_ptr; | 
|  | else if (isym->st_shndx == SHN_ABS) | 
|  | sym_sec = bfd_abs_section_ptr; | 
|  | else if (isym->st_shndx == SHN_COMMON) | 
|  | sym_sec = bfd_com_section_ptr; | 
|  | else | 
|  | sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); | 
|  |  | 
|  | symval = _bfd_elf_rela_local_sym (abfd, isym, &sym_sec, irel); | 
|  | } | 
|  | else | 
|  | { | 
|  | unsigned long indx; | 
|  | struct elf_link_hash_entry *h; | 
|  |  | 
|  | indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; | 
|  | h = elf_sym_hashes (abfd)[indx]; | 
|  | BFD_ASSERT (h != NULL); | 
|  |  | 
|  | if (h->root.type != bfd_link_hash_defined | 
|  | && h->root.type != bfd_link_hash_defweak) | 
|  | /* This appears to be a reference to an undefined | 
|  | symbol.  Just ignore it--it will be caught by the | 
|  | regular reloc processing.  */ | 
|  | continue; | 
|  |  | 
|  | symval = (h->root.u.def.value | 
|  | + h->root.u.def.section->output_section->vma | 
|  | + h->root.u.def.section->output_offset); | 
|  | } | 
|  |  | 
|  | /* If this is a PC-relative reloc, subtract the instr offset from | 
|  | the symbol value.  */ | 
|  | if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROBLAZE_64_PCREL) | 
|  | { | 
|  | symval = symval + irel->r_addend | 
|  | - (irel->r_offset | 
|  | + sec->output_section->vma | 
|  | + sec->output_offset); | 
|  | } | 
|  | else if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROBLAZE_TEXTREL_64) | 
|  | { | 
|  | symval = symval + irel->r_addend - (sec->output_section->vma); | 
|  | } | 
|  | else | 
|  | symval += irel->r_addend; | 
|  |  | 
|  | if ((symval & 0xffff8000) == 0 | 
|  | || (symval & 0xffff8000) == 0xffff8000) | 
|  | { | 
|  | /* We can delete this instruction.  */ | 
|  | sdata->relax[sdata->relax_count].addr = irel->r_offset; | 
|  | sdata->relax[sdata->relax_count].size = INST_WORD_SIZE; | 
|  | sdata->relax_count++; | 
|  |  | 
|  | /* Rewrite relocation type.  */ | 
|  | switch ((enum elf_microblaze_reloc_type) ELF32_R_TYPE (irel->r_info)) | 
|  | { | 
|  | case R_MICROBLAZE_64_PCREL: | 
|  | irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), | 
|  | (int) R_MICROBLAZE_32_PCREL_LO); | 
|  | break; | 
|  | case R_MICROBLAZE_64: | 
|  | irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), | 
|  | (int) R_MICROBLAZE_32_LO); | 
|  | break; | 
|  | case R_MICROBLAZE_TEXTREL_64: | 
|  | irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), | 
|  | (int) R_MICROBLAZE_TEXTREL_32_LO); | 
|  | break; | 
|  | default: | 
|  | /* Cannot happen.  */ | 
|  | BFD_ASSERT (false); | 
|  | } | 
|  | } | 
|  | } /* Loop through all relocations.  */ | 
|  |  | 
|  | /* Loop through the relocs again, and see if anything needs to change.  */ | 
|  | if (sdata->relax_count > 0) | 
|  | { | 
|  | shndx = _bfd_elf_section_from_bfd_section (abfd, sec); | 
|  | rel_count = 0; | 
|  | sdata->relax[sdata->relax_count].addr = sec->size; | 
|  |  | 
|  | for (irel = internal_relocs; irel < irelend; irel++, rel_count++) | 
|  | { | 
|  | bfd_vma nraddr; | 
|  |  | 
|  | /* Get the new reloc address.  */ | 
|  | nraddr = irel->r_offset - calc_fixup (irel->r_offset, 0, sec); | 
|  | switch ((enum elf_microblaze_reloc_type) ELF32_R_TYPE (irel->r_info)) | 
|  | { | 
|  | default: | 
|  | break; | 
|  | case R_MICROBLAZE_64_PCREL: | 
|  | break; | 
|  | case R_MICROBLAZE_TEXTREL_64: | 
|  | case R_MICROBLAZE_TEXTREL_32_LO: | 
|  | case R_MICROBLAZE_64: | 
|  | case R_MICROBLAZE_32_LO: | 
|  | /* If this reloc is against a symbol defined in this | 
|  | section, we must check the addend to see it will put the value in | 
|  | range to be adjusted, and hence must be changed.  */ | 
|  | if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) | 
|  | { | 
|  | isym = isymbuf + ELF32_R_SYM (irel->r_info); | 
|  | /* Only handle relocs against .text.  */ | 
|  | if (isym->st_shndx == shndx | 
|  | && ELF32_ST_TYPE (isym->st_info) == STT_SECTION) | 
|  | irel->r_addend -= calc_fixup (irel->r_addend, 0, sec); | 
|  | } | 
|  | break; | 
|  | case R_MICROBLAZE_NONE: | 
|  | case R_MICROBLAZE_32_NONE: | 
|  | { | 
|  | /* This was a PC-relative instruction that was | 
|  | completely resolved.  */ | 
|  | size_t sfix, efix; | 
|  | bfd_vma target_address; | 
|  | target_address = irel->r_addend + irel->r_offset; | 
|  | sfix = calc_fixup (irel->r_offset, 0, sec); | 
|  | efix = calc_fixup (target_address, 0, sec); | 
|  | irel->r_addend -= (efix - sfix); | 
|  | /* Should use HOWTO.  */ | 
|  | microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset, | 
|  | irel->r_addend); | 
|  | } | 
|  | break; | 
|  | case R_MICROBLAZE_64_NONE: | 
|  | { | 
|  | /* This was a PC-relative 64-bit instruction that was | 
|  | completely resolved.  */ | 
|  | size_t sfix, efix; | 
|  | bfd_vma target_address; | 
|  | target_address = irel->r_addend + irel->r_offset + INST_WORD_SIZE; | 
|  | sfix = calc_fixup (irel->r_offset + INST_WORD_SIZE, 0, sec); | 
|  | efix = calc_fixup (target_address, 0, sec); | 
|  | irel->r_addend -= (efix - sfix); | 
|  | microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset | 
|  | + INST_WORD_SIZE, irel->r_addend); | 
|  | } | 
|  | break; | 
|  | } | 
|  | irel->r_offset = nraddr; | 
|  | } /* Change all relocs in this section.  */ | 
|  |  | 
|  | /* Look through all other sections.  */ | 
|  | for (o = abfd->sections; o != NULL; o = o->next) | 
|  | { | 
|  | Elf_Internal_Rela *irelocs; | 
|  | Elf_Internal_Rela *irelscan, *irelscanend; | 
|  | bfd_byte *ocontents; | 
|  |  | 
|  | if (o == sec | 
|  | || (o->flags & SEC_RELOC) == 0 | 
|  | || o->reloc_count == 0) | 
|  | continue; | 
|  |  | 
|  | /* We always cache the relocs.  Perhaps, if info->keep_memory is | 
|  | FALSE, we should free them, if we are permitted to.  */ | 
|  |  | 
|  | irelocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, true); | 
|  | if (irelocs == NULL) | 
|  | goto error_return; | 
|  |  | 
|  | ocontents = NULL; | 
|  | irelscanend = irelocs + o->reloc_count; | 
|  | for (irelscan = irelocs; irelscan < irelscanend; irelscan++) | 
|  | { | 
|  | if ((ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32) | 
|  | || (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32_NONE)) | 
|  | { | 
|  | isym = isymbuf + ELF32_R_SYM (irelscan->r_info); | 
|  |  | 
|  | /* Look at the reloc only if the value has been resolved.  */ | 
|  | if (isym->st_shndx == shndx | 
|  | && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION)) | 
|  | { | 
|  | if (ocontents == NULL) | 
|  | { | 
|  | if (elf_section_data (o)->this_hdr.contents != NULL) | 
|  | ocontents = elf_section_data (o)->this_hdr.contents; | 
|  | else | 
|  | { | 
|  | /* We always cache the section contents. | 
|  | Perhaps, if info->keep_memory is FALSE, we | 
|  | should free them, if we are permitted to.  */ | 
|  | if (o->rawsize == 0) | 
|  | o->rawsize = o->size; | 
|  | ocontents = (bfd_byte *) bfd_malloc (o->rawsize); | 
|  | if (ocontents == NULL) | 
|  | goto error_return; | 
|  | if (!bfd_get_section_contents (abfd, o, ocontents, | 
|  | (file_ptr) 0, | 
|  | o->rawsize)) | 
|  | goto error_return; | 
|  | elf_section_data (o)->this_hdr.contents = ocontents; | 
|  | } | 
|  |  | 
|  | } | 
|  | irelscan->r_addend -= calc_fixup (irelscan->r_addend, 0, sec); | 
|  | } | 
|  | else if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32_SYM_OP_SYM) | 
|  | { | 
|  | isym = isymbuf + ELF32_R_SYM (irelscan->r_info); | 
|  |  | 
|  | /* Look at the reloc only if the value has been resolved.  */ | 
|  | if (ocontents == NULL) | 
|  | { | 
|  | if (elf_section_data (o)->this_hdr.contents != NULL) | 
|  | ocontents = elf_section_data (o)->this_hdr.contents; | 
|  | else | 
|  | { | 
|  | /* We always cache the section contents. | 
|  | Perhaps, if info->keep_memory is FALSE, we | 
|  | should free them, if we are permitted to.  */ | 
|  |  | 
|  | if (o->rawsize == 0) | 
|  | o->rawsize = o->size; | 
|  | ocontents = (bfd_byte *) bfd_malloc (o->rawsize); | 
|  | if (ocontents == NULL) | 
|  | goto error_return; | 
|  | if (!bfd_get_section_contents (abfd, o, ocontents, | 
|  | (file_ptr) 0, | 
|  | o->rawsize)) | 
|  | goto error_return; | 
|  | elf_section_data (o)->this_hdr.contents = ocontents; | 
|  | } | 
|  | } | 
|  | irelscan->r_addend -= calc_fixup (irelscan->r_addend | 
|  | + isym->st_value, | 
|  | 0, | 
|  | sec); | 
|  | } | 
|  | } | 
|  | else if ((ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32_PCREL_LO) | 
|  | || (ELF32_R_TYPE (irelscan->r_info) | 
|  | == (int) R_MICROBLAZE_32_LO) | 
|  | || (ELF32_R_TYPE (irelscan->r_info) | 
|  | == (int) R_MICROBLAZE_TEXTREL_32_LO)) | 
|  | { | 
|  | isym = isymbuf + ELF32_R_SYM (irelscan->r_info); | 
|  |  | 
|  | /* Look at the reloc only if the value has been resolved.  */ | 
|  | if (isym->st_shndx == shndx | 
|  | && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION)) | 
|  | { | 
|  | bfd_vma immediate; | 
|  | bfd_vma target_address; | 
|  |  | 
|  | if (ocontents == NULL) | 
|  | { | 
|  | if (elf_section_data (o)->this_hdr.contents != NULL) | 
|  | ocontents = elf_section_data (o)->this_hdr.contents; | 
|  | else | 
|  | { | 
|  | /* We always cache the section contents. | 
|  | Perhaps, if info->keep_memory is FALSE, we | 
|  | should free them, if we are permitted to.  */ | 
|  | if (o->rawsize == 0) | 
|  | o->rawsize = o->size; | 
|  | ocontents = (bfd_byte *) bfd_malloc (o->rawsize); | 
|  | if (ocontents == NULL) | 
|  | goto error_return; | 
|  | if (!bfd_get_section_contents (abfd, o, ocontents, | 
|  | (file_ptr) 0, | 
|  | o->rawsize)) | 
|  | goto error_return; | 
|  | elf_section_data (o)->this_hdr.contents = ocontents; | 
|  | } | 
|  | } | 
|  |  | 
|  | unsigned long instr = bfd_get_32 (abfd, ocontents + irelscan->r_offset); | 
|  | immediate = instr & 0x0000ffff; | 
|  | target_address = immediate; | 
|  | offset = calc_fixup (target_address, 0, sec); | 
|  | immediate -= offset; | 
|  | irelscan->r_addend -= offset; | 
|  | microblaze_bfd_write_imm_value_32 (abfd, ocontents + irelscan->r_offset, | 
|  | irelscan->r_addend); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_64 | 
|  | || (ELF32_R_TYPE (irelscan->r_info) | 
|  | == (int) R_MICROBLAZE_TEXTREL_64)) | 
|  | { | 
|  | isym = isymbuf + ELF32_R_SYM (irelscan->r_info); | 
|  |  | 
|  | /* Look at the reloc only if the value has been resolved.  */ | 
|  | if (isym->st_shndx == shndx | 
|  | && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION)) | 
|  | { | 
|  | if (ocontents == NULL) | 
|  | { | 
|  | if (elf_section_data (o)->this_hdr.contents != NULL) | 
|  | ocontents = elf_section_data (o)->this_hdr.contents; | 
|  | else | 
|  | { | 
|  | /* We always cache the section contents. | 
|  | Perhaps, if info->keep_memory is FALSE, we | 
|  | should free them, if we are permitted to.  */ | 
|  |  | 
|  | if (o->rawsize == 0) | 
|  | o->rawsize = o->size; | 
|  | ocontents = (bfd_byte *) bfd_malloc (o->rawsize); | 
|  | if (ocontents == NULL) | 
|  | goto error_return; | 
|  | if (!bfd_get_section_contents (abfd, o, ocontents, | 
|  | (file_ptr) 0, | 
|  | o->rawsize)) | 
|  | goto error_return; | 
|  | elf_section_data (o)->this_hdr.contents = ocontents; | 
|  | } | 
|  | } | 
|  | offset = calc_fixup (irelscan->r_addend, 0, sec); | 
|  | irelscan->r_addend -= offset; | 
|  | } | 
|  | } | 
|  | else if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_64_PCREL) | 
|  | { | 
|  | isym = isymbuf + ELF32_R_SYM (irelscan->r_info); | 
|  |  | 
|  | /* Look at the reloc only if the value has been resolved.  */ | 
|  | if (isym->st_shndx == shndx | 
|  | && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION)) | 
|  | { | 
|  | bfd_vma immediate; | 
|  | bfd_vma target_address; | 
|  |  | 
|  | if (ocontents == NULL) | 
|  | { | 
|  | if (elf_section_data (o)->this_hdr.contents != NULL) | 
|  | ocontents = elf_section_data (o)->this_hdr.contents; | 
|  | else | 
|  | { | 
|  | /* We always cache the section contents. | 
|  | Perhaps, if info->keep_memory is FALSE, we | 
|  | should free them, if we are permitted to.  */ | 
|  | if (o->rawsize == 0) | 
|  | o->rawsize = o->size; | 
|  | ocontents = (bfd_byte *) bfd_malloc (o->rawsize); | 
|  | if (ocontents == NULL) | 
|  | goto error_return; | 
|  | if (!bfd_get_section_contents (abfd, o, ocontents, | 
|  | (file_ptr) 0, | 
|  | o->rawsize)) | 
|  | goto error_return; | 
|  | elf_section_data (o)->this_hdr.contents = ocontents; | 
|  | } | 
|  | } | 
|  | unsigned long instr_hi =  bfd_get_32 (abfd, ocontents | 
|  | + irelscan->r_offset); | 
|  | unsigned long instr_lo =  bfd_get_32 (abfd, ocontents | 
|  | + irelscan->r_offset | 
|  | + INST_WORD_SIZE); | 
|  | immediate = (instr_hi & 0x0000ffff) << 16; | 
|  | immediate |= (instr_lo & 0x0000ffff); | 
|  | target_address = immediate; | 
|  | offset = calc_fixup (target_address, 0, sec); | 
|  | immediate -= offset; | 
|  | irelscan->r_addend -= offset; | 
|  | microblaze_bfd_write_imm_value_64 (abfd, ocontents | 
|  | + irelscan->r_offset, immediate); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Adjust the local symbols defined in this section.  */ | 
|  | isymend = isymbuf + symtab_hdr->sh_info; | 
|  | for (isym = isymbuf; isym < isymend; isym++) | 
|  | { | 
|  | if (isym->st_shndx == shndx) | 
|  | { | 
|  | isym->st_value -= calc_fixup (isym->st_value, 0, sec); | 
|  | if (isym->st_size) | 
|  | isym->st_size -= calc_fixup (isym->st_value, isym->st_size, sec); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Now adjust the global symbols defined in this section.  */ | 
|  | isym = isymbuf + symtab_hdr->sh_info; | 
|  | symcount =  (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)) - symtab_hdr->sh_info; | 
|  | for (sym_index = 0; sym_index < symcount; sym_index++) | 
|  | { | 
|  | sym_hash = elf_sym_hashes (abfd)[sym_index]; | 
|  | if ((sym_hash->root.type == bfd_link_hash_defined | 
|  | || sym_hash->root.type == bfd_link_hash_defweak) | 
|  | && sym_hash->root.u.def.section == sec) | 
|  | { | 
|  | sym_hash->root.u.def.value -= calc_fixup (sym_hash->root.u.def.value, | 
|  | 0, sec); | 
|  | if (sym_hash->size) | 
|  | sym_hash->size -= calc_fixup (sym_hash->root.u.def.value, | 
|  | sym_hash->size, sec); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Physically move the code and change the cooked size.  */ | 
|  | dest = sdata->relax[0].addr; | 
|  | for (i = 0; i < sdata->relax_count; i++) | 
|  | { | 
|  | size_t len; | 
|  | src = sdata->relax[i].addr + sdata->relax[i].size; | 
|  | len = (sdata->relax[i+1].addr - sdata->relax[i].addr | 
|  | - sdata->relax[i].size); | 
|  |  | 
|  | memmove (contents + dest, contents + src, len); | 
|  | sec->size -= sdata->relax[i].size; | 
|  | dest += len; | 
|  | } | 
|  |  | 
|  | elf_section_data (sec)->relocs = internal_relocs; | 
|  | free_relocs = NULL; | 
|  |  | 
|  | elf_section_data (sec)->this_hdr.contents = contents; | 
|  | free_contents = NULL; | 
|  |  | 
|  | symtab_hdr->contents = (bfd_byte *) isymbuf; | 
|  | } | 
|  |  | 
|  | free (free_relocs); | 
|  | free_relocs = NULL; | 
|  |  | 
|  | if (free_contents != NULL) | 
|  | { | 
|  | if (!link_info->keep_memory) | 
|  | free (free_contents); | 
|  | else | 
|  | /* Cache the section contents for elf_link_input_bfd.  */ | 
|  | elf_section_data (sec)->this_hdr.contents = contents; | 
|  | free_contents = NULL; | 
|  | } | 
|  |  | 
|  | if (sdata->relax_count == 0) | 
|  | { | 
|  | *again = false; | 
|  | free (sdata->relax); | 
|  | sdata->relax = NULL; | 
|  | } | 
|  | else | 
|  | *again = true; | 
|  | return true; | 
|  |  | 
|  | error_return: | 
|  | free (free_relocs); | 
|  | free (free_contents); | 
|  | free (sdata->relax); | 
|  | sdata->relax = NULL; | 
|  | sdata->relax_count = 0; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Return the section that should be marked against GC for a given | 
|  | relocation.  */ | 
|  |  | 
|  | static asection * | 
|  | microblaze_elf_gc_mark_hook (asection *sec, | 
|  | struct bfd_link_info * info, | 
|  | Elf_Internal_Rela * rel, | 
|  | struct elf_link_hash_entry * h, | 
|  | Elf_Internal_Sym * sym) | 
|  | { | 
|  | if (h != NULL) | 
|  | switch (ELF32_R_TYPE (rel->r_info)) | 
|  | { | 
|  | case R_MICROBLAZE_GNU_VTINHERIT: | 
|  | case R_MICROBLAZE_GNU_VTENTRY: | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); | 
|  | } | 
|  |  | 
|  | /* PIC support.  */ | 
|  |  | 
|  | #define PLT_ENTRY_SIZE 16 | 
|  |  | 
|  | #define PLT_ENTRY_WORD_0  0xb0000000	      /* "imm 0".  */ | 
|  | #define PLT_ENTRY_WORD_1  0xe9940000	      /* "lwi r12,r20,0" - relocated to lwi r12,r20,func@GOT.  */ | 
|  | #define PLT_ENTRY_WORD_1_NOPIC	0xe9800000    /* "lwi r12,r0,0" - non-PIC object.  */ | 
|  | #define PLT_ENTRY_WORD_2  0x98186000	      /* "brad r12".  */ | 
|  | #define PLT_ENTRY_WORD_3  0x80000000	      /* "nop".  */ | 
|  |  | 
|  | static bool | 
|  | update_local_sym_info (bfd *abfd, | 
|  | Elf_Internal_Shdr *symtab_hdr, | 
|  | unsigned long r_symndx, | 
|  | unsigned int tls_type) | 
|  | { | 
|  | bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd); | 
|  | unsigned char *local_got_tls_masks; | 
|  |  | 
|  | if (local_got_refcounts == NULL) | 
|  | { | 
|  | bfd_size_type size = symtab_hdr->sh_info; | 
|  |  | 
|  | size *= (sizeof (*local_got_refcounts) + sizeof (*local_got_tls_masks)); | 
|  | local_got_refcounts = bfd_zalloc (abfd, size); | 
|  | if (local_got_refcounts == NULL) | 
|  | return false; | 
|  | elf_local_got_refcounts (abfd) = local_got_refcounts; | 
|  | } | 
|  |  | 
|  | local_got_tls_masks = | 
|  | (unsigned char *) (local_got_refcounts + symtab_hdr->sh_info); | 
|  | local_got_tls_masks[r_symndx] |= tls_type; | 
|  | local_got_refcounts[r_symndx] += 1; | 
|  |  | 
|  | return true; | 
|  | } | 
|  | /* Look through the relocs for a section during the first phase.  */ | 
|  |  | 
|  | static bool | 
|  | microblaze_elf_check_relocs (bfd * abfd, | 
|  | struct bfd_link_info * info, | 
|  | asection * sec, | 
|  | const Elf_Internal_Rela * relocs) | 
|  | { | 
|  | Elf_Internal_Shdr *		symtab_hdr; | 
|  | struct elf_link_hash_entry ** sym_hashes; | 
|  | const Elf_Internal_Rela *	rel; | 
|  | const Elf_Internal_Rela *	rel_end; | 
|  | struct elf32_mb_link_hash_table *htab; | 
|  | asection *sreloc = NULL; | 
|  |  | 
|  | if (bfd_link_relocatable (info)) | 
|  | return true; | 
|  |  | 
|  | htab = elf32_mb_hash_table (info); | 
|  | if (htab == NULL) | 
|  | return false; | 
|  |  | 
|  | symtab_hdr = & elf_tdata (abfd)->symtab_hdr; | 
|  | sym_hashes = elf_sym_hashes (abfd); | 
|  |  | 
|  | rel_end = relocs + sec->reloc_count; | 
|  |  | 
|  | for (rel = relocs; rel < rel_end; rel++) | 
|  | { | 
|  | unsigned int r_type; | 
|  | struct elf_link_hash_entry * h; | 
|  | unsigned long r_symndx; | 
|  | unsigned char tls_type = 0; | 
|  |  | 
|  | r_symndx = ELF32_R_SYM (rel->r_info); | 
|  | r_type = ELF32_R_TYPE (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; | 
|  | } | 
|  |  | 
|  | switch (r_type) | 
|  | { | 
|  | /* This relocation describes the C++ object vtable hierarchy. | 
|  | Reconstruct it for later use during GC.  */ | 
|  | case R_MICROBLAZE_GNU_VTINHERIT: | 
|  | if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | /* This relocation describes which C++ vtable entries are actually | 
|  | used.  Record for later use during GC.  */ | 
|  | case R_MICROBLAZE_GNU_VTENTRY: | 
|  | if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | /* This relocation requires .plt entry.  */ | 
|  | case R_MICROBLAZE_PLT_64: | 
|  | if (h != NULL) | 
|  | { | 
|  | h->needs_plt = 1; | 
|  | h->plt.refcount += 1; | 
|  | } | 
|  | break; | 
|  |  | 
|  | /* This relocation requires .got entry.  */ | 
|  | case R_MICROBLAZE_TLSGD: | 
|  | tls_type |= (TLS_TLS | TLS_GD); | 
|  | goto dogottls; | 
|  | case R_MICROBLAZE_TLSLD: | 
|  | tls_type |= (TLS_TLS | TLS_LD); | 
|  | /* Fall through.  */ | 
|  | dogottls: | 
|  | sec->has_tls_reloc = 1; | 
|  | /* Fall through.  */ | 
|  | case R_MICROBLAZE_GOT_64: | 
|  | if (htab->elf.sgot == NULL) | 
|  | { | 
|  | if (htab->elf.dynobj == NULL) | 
|  | htab->elf.dynobj = abfd; | 
|  | if (!_bfd_elf_create_got_section (htab->elf.dynobj, info)) | 
|  | return false; | 
|  | } | 
|  | if (h != NULL) | 
|  | { | 
|  | h->got.refcount += 1; | 
|  | elf32_mb_hash_entry (h)->tls_mask |= tls_type; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (! update_local_sym_info(abfd, symtab_hdr, r_symndx, tls_type) ) | 
|  | return false; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case R_MICROBLAZE_GOTOFF_64: | 
|  | case R_MICROBLAZE_GOTOFF_32: | 
|  | if (htab->elf.sgot == NULL) | 
|  | { | 
|  | if (htab->elf.dynobj == NULL) | 
|  | htab->elf.dynobj = abfd; | 
|  | if (!_bfd_elf_create_got_section (htab->elf.dynobj, info)) | 
|  | return false; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case R_MICROBLAZE_64: | 
|  | case R_MICROBLAZE_64_PCREL: | 
|  | case R_MICROBLAZE_32: | 
|  | { | 
|  | if (h != NULL && !bfd_link_pic (info)) | 
|  | { | 
|  | /* we may need a copy reloc.  */ | 
|  | h->non_got_ref = 1; | 
|  |  | 
|  | /* we may also need a .plt entry.  */ | 
|  | h->plt.refcount += 1; | 
|  | if (ELF32_R_TYPE (rel->r_info) != R_MICROBLAZE_64_PCREL) | 
|  | h->pointer_equality_needed = 1; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* If we are creating a shared library, and this is a reloc | 
|  | against a global symbol, or a non PC relative reloc | 
|  | against a local symbol, then we need to copy the reloc | 
|  | into the shared library.  However, if we are linking with | 
|  | -Bsymbolic, we do not need to copy a reloc against a | 
|  | global symbol which is defined in an object we are | 
|  | including in the link (i.e., DEF_REGULAR is set).  At | 
|  | this point we have not seen all the input files, so it is | 
|  | possible that DEF_REGULAR is not set now but will be set | 
|  | later (it is never cleared).  In case of a weak definition, | 
|  | DEF_REGULAR may be cleared later by a strong definition in | 
|  | a shared library.  We account for that possibility below by | 
|  | storing information in the relocs_copied field of the hash | 
|  | table entry.  A similar situation occurs when creating | 
|  | shared libraries and symbol visibility changes render the | 
|  | symbol local. | 
|  |  | 
|  | If on the other hand, we are creating an executable, we | 
|  | may need to keep relocations for symbols satisfied by a | 
|  | dynamic library if we manage to avoid copy relocs for the | 
|  | symbol.  */ | 
|  |  | 
|  | if ((bfd_link_pic (info) | 
|  | && (sec->flags & SEC_ALLOC) != 0 | 
|  | && (r_type != R_MICROBLAZE_64_PCREL | 
|  | || (h != NULL | 
|  | && (! info->symbolic | 
|  | || h->root.type == bfd_link_hash_defweak | 
|  | || !h->def_regular)))) | 
|  | || (!bfd_link_pic (info) | 
|  | && (sec->flags & SEC_ALLOC) != 0 | 
|  | && h != NULL | 
|  | && (h->root.type == bfd_link_hash_defweak | 
|  | || !h->def_regular))) | 
|  | { | 
|  | struct elf_dyn_relocs *p; | 
|  | struct elf_dyn_relocs **head; | 
|  |  | 
|  | /* When creating a shared object, we must copy these | 
|  | relocs into the output file.  We create a reloc | 
|  | section in dynobj and make room for the reloc.  */ | 
|  |  | 
|  | if (sreloc == NULL) | 
|  | { | 
|  | bfd *dynobj; | 
|  |  | 
|  | if (htab->elf.dynobj == NULL) | 
|  | htab->elf.dynobj = abfd; | 
|  | dynobj = htab->elf.dynobj; | 
|  |  | 
|  | sreloc = _bfd_elf_make_dynamic_reloc_section (sec, dynobj, | 
|  | 2, abfd, 1); | 
|  | if (sreloc == NULL) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* If this is a global symbol, we count the number of | 
|  | relocations we need for this symbol.  */ | 
|  | if (h != NULL) | 
|  | head = &h->dyn_relocs; | 
|  | else | 
|  | { | 
|  | /* Track dynamic relocs needed for local syms too. | 
|  | We really need local syms available to do this | 
|  | easily.  Oh well.  */ | 
|  |  | 
|  | asection *s; | 
|  | Elf_Internal_Sym *isym; | 
|  | void *vpp; | 
|  |  | 
|  | isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, | 
|  | abfd, r_symndx); | 
|  | if (isym == NULL) | 
|  | return false; | 
|  |  | 
|  | s = bfd_section_from_elf_index (abfd, isym->st_shndx); | 
|  | if (s == NULL) | 
|  | return false; | 
|  |  | 
|  | vpp = &elf_section_data (s)->local_dynrel; | 
|  | head = (struct elf_dyn_relocs **) vpp; | 
|  | } | 
|  |  | 
|  | p = *head; | 
|  | if (p == NULL || p->sec != sec) | 
|  | { | 
|  | size_t amt = sizeof *p; | 
|  | p = ((struct elf_dyn_relocs *) | 
|  | bfd_alloc (htab->elf.dynobj, amt)); | 
|  | if (p == NULL) | 
|  | return false; | 
|  | p->next = *head; | 
|  | *head = p; | 
|  | p->sec = sec; | 
|  | p->count = 0; | 
|  | p->pc_count = 0; | 
|  | } | 
|  |  | 
|  | p->count += 1; | 
|  | if (r_type == R_MICROBLAZE_64_PCREL) | 
|  | p->pc_count += 1; | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Copy the extra info we tack onto an elf_link_hash_entry.  */ | 
|  |  | 
|  | static void | 
|  | microblaze_elf_copy_indirect_symbol (struct bfd_link_info *info, | 
|  | struct elf_link_hash_entry *dir, | 
|  | struct elf_link_hash_entry *ind) | 
|  | { | 
|  | struct elf32_mb_link_hash_entry *edir, *eind; | 
|  |  | 
|  | edir = (struct elf32_mb_link_hash_entry *) dir; | 
|  | eind = (struct elf32_mb_link_hash_entry *) ind; | 
|  |  | 
|  | edir->tls_mask |= eind->tls_mask; | 
|  |  | 
|  | _bfd_elf_link_hash_copy_indirect (info, dir, ind); | 
|  | } | 
|  |  | 
|  | static bool | 
|  | microblaze_elf_adjust_dynamic_symbol (struct bfd_link_info *info, | 
|  | struct elf_link_hash_entry *h) | 
|  | { | 
|  | struct elf32_mb_link_hash_table *htab; | 
|  | asection *s, *srel; | 
|  | unsigned int power_of_two; | 
|  |  | 
|  | htab = elf32_mb_hash_table (info); | 
|  | if (htab == NULL) | 
|  | return false; | 
|  |  | 
|  | /* If this is a function, put it in the procedure linkage table.  We | 
|  | will fill in the contents of the procedure linkage table later, | 
|  | when we know the address of the .got section.  */ | 
|  | if (h->type == STT_FUNC | 
|  | || h->needs_plt) | 
|  | { | 
|  | if (h->plt.refcount <= 0 | 
|  | || SYMBOL_CALLS_LOCAL (info, h) | 
|  | || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT | 
|  | && h->root.type == bfd_link_hash_undefweak)) | 
|  | { | 
|  | /* This case can occur if we saw a PLT reloc in an input | 
|  | file, but the symbol was never referred to by a dynamic | 
|  | object, or if all references were garbage collected.  In | 
|  | such a case, we don't actually need to build a procedure | 
|  | linkage table, and we can just do a PC32 reloc instead.  */ | 
|  | h->plt.offset = (bfd_vma) -1; | 
|  | h->needs_plt = 0; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  | else | 
|  | /* It's possible that we incorrectly decided a .plt reloc was | 
|  | needed for an R_MICROBLAZE_64_PCREL reloc to a non-function sym in | 
|  | check_relocs.  We can't decide accurately between function and | 
|  | non-function syms in check-relocs;  Objects loaded later in | 
|  | the link may change h->type.  So fix it now.  */ | 
|  | h->plt.offset = (bfd_vma) -1; | 
|  |  | 
|  | /* If this is a weak symbol, and there is a real definition, the | 
|  | processor independent code will have arranged for us to see the | 
|  | real definition first, and we can just use the same value.  */ | 
|  | if (h->is_weakalias) | 
|  | { | 
|  | struct elf_link_hash_entry *def = weakdef (h); | 
|  | BFD_ASSERT (def->root.type == bfd_link_hash_defined); | 
|  | h->root.u.def.section = def->root.u.def.section; | 
|  | h->root.u.def.value = def->root.u.def.value; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* This is a reference to a symbol defined by a dynamic object which | 
|  | is not a function.  */ | 
|  |  | 
|  | /* If we are creating a shared library, we must presume that the | 
|  | only references to the symbol are via the global offset table. | 
|  | For such cases we need not do anything here; the relocations will | 
|  | be handled correctly by relocate_section.  */ | 
|  | if (bfd_link_pic (info)) | 
|  | return true; | 
|  |  | 
|  | /* If there are no references to this symbol that do not use the | 
|  | GOT, we don't need to generate a copy reloc.  */ | 
|  | if (!h->non_got_ref) | 
|  | return true; | 
|  |  | 
|  | /* If -z nocopyreloc was given, we won't generate them either.  */ | 
|  | if (info->nocopyreloc) | 
|  | { | 
|  | h->non_got_ref = 0; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* If we don't find any dynamic relocs in read-only sections, then | 
|  | we'll be keeping the dynamic relocs and avoiding the copy reloc.  */ | 
|  | if (!_bfd_elf_readonly_dynrelocs (h)) | 
|  | { | 
|  | h->non_got_ref = 0; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* We must allocate the symbol in our .dynbss section, which will | 
|  | become part of the .bss section of the executable.  There will be | 
|  | an entry for this symbol in the .dynsym section.  The dynamic | 
|  | object will contain position independent code, so all references | 
|  | from the dynamic object to this symbol will go through the global | 
|  | offset table.  The dynamic linker will use the .dynsym entry to | 
|  | determine the address it must put in the global offset table, so | 
|  | both the dynamic object and the regular object will refer to the | 
|  | same memory location for the variable.  */ | 
|  |  | 
|  | /* We must generate a R_MICROBLAZE_COPY reloc to tell the dynamic linker | 
|  | to copy the initial value out of the dynamic object and into the | 
|  | runtime process image.  */ | 
|  | if ((h->root.u.def.section->flags & SEC_READONLY) != 0) | 
|  | { | 
|  | s = htab->elf.sdynrelro; | 
|  | srel = htab->elf.sreldynrelro; | 
|  | } | 
|  | else | 
|  | { | 
|  | s = htab->elf.sdynbss; | 
|  | srel = htab->elf.srelbss; | 
|  | } | 
|  | if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) | 
|  | { | 
|  | srel->size += sizeof (Elf32_External_Rela); | 
|  | h->needs_copy = 1; | 
|  | } | 
|  |  | 
|  | /* We need to figure out the alignment required for this symbol.  I | 
|  | have no idea how ELF linkers handle this.  */ | 
|  | power_of_two = bfd_log2 (h->size); | 
|  | if (power_of_two > 3) | 
|  | power_of_two = 3; | 
|  |  | 
|  | /* Apply the required alignment.  */ | 
|  | s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two)); | 
|  | if (power_of_two > s->alignment_power) | 
|  | { | 
|  | if (!bfd_set_section_alignment (s, power_of_two)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Define the symbol as being at this point in the section.  */ | 
|  | h->root.u.def.section = s; | 
|  | h->root.u.def.value = s->size; | 
|  |  | 
|  | /* Increment the section size to make room for the symbol.  */ | 
|  | s->size += h->size; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Allocate space in .plt, .got and associated reloc sections for | 
|  | dynamic relocs.  */ | 
|  |  | 
|  | static bool | 
|  | allocate_dynrelocs (struct elf_link_hash_entry *h, void * dat) | 
|  | { | 
|  | struct bfd_link_info *info; | 
|  | struct elf32_mb_link_hash_table *htab; | 
|  | struct elf32_mb_link_hash_entry *eh; | 
|  | struct elf_dyn_relocs *p; | 
|  |  | 
|  | if (h->root.type == bfd_link_hash_indirect) | 
|  | return true; | 
|  |  | 
|  | info = (struct bfd_link_info *) dat; | 
|  | htab = elf32_mb_hash_table (info); | 
|  | if (htab == NULL) | 
|  | return false; | 
|  |  | 
|  | if (htab->elf.dynamic_sections_created | 
|  | && h->plt.refcount > 0) | 
|  | { | 
|  | /* Make sure this symbol is output as a dynamic symbol. | 
|  | Undefined weak syms won't yet be marked as dynamic.  */ | 
|  | if (h->dynindx == -1 | 
|  | && !h->forced_local) | 
|  | { | 
|  | if (! bfd_elf_link_record_dynamic_symbol (info, h)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) | 
|  | { | 
|  | asection *s = htab->elf.splt; | 
|  |  | 
|  | /* The first entry in .plt is reserved.  */ | 
|  | if (s->size == 0) | 
|  | s->size = PLT_ENTRY_SIZE; | 
|  |  | 
|  | h->plt.offset = s->size; | 
|  |  | 
|  | /* If this symbol is not defined in a regular file, and we are | 
|  | not generating a shared library, then set the symbol to this | 
|  | location in the .plt.  This is required to make function | 
|  | pointers compare as equal between the normal executable and | 
|  | the shared library.  */ | 
|  | if (! bfd_link_pic (info) | 
|  | && !h->def_regular) | 
|  | { | 
|  | h->root.u.def.section = s; | 
|  | h->root.u.def.value = h->plt.offset; | 
|  | } | 
|  |  | 
|  | /* Make room for this entry.  */ | 
|  | s->size += PLT_ENTRY_SIZE; | 
|  |  | 
|  | /* We also need to make an entry in the .got.plt section, which | 
|  | will be placed in the .got section by the linker script.  */ | 
|  | htab->elf.sgotplt->size += 4; | 
|  |  | 
|  | /* We also need to make an entry in the .rel.plt section.  */ | 
|  | htab->elf.srelplt->size += sizeof (Elf32_External_Rela); | 
|  | } | 
|  | else | 
|  | { | 
|  | h->plt.offset = (bfd_vma) -1; | 
|  | h->needs_plt = 0; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | h->plt.offset = (bfd_vma) -1; | 
|  | h->needs_plt = 0; | 
|  | } | 
|  |  | 
|  | eh = (struct elf32_mb_link_hash_entry *) h; | 
|  | if (h->got.refcount > 0) | 
|  | { | 
|  | unsigned int need; | 
|  | asection *s; | 
|  |  | 
|  | /* Make sure this symbol is output as a dynamic symbol. | 
|  | Undefined weak syms won't yet be marked as dynamic.  */ | 
|  | if (h->dynindx == -1 | 
|  | && !h->forced_local) | 
|  | { | 
|  | if (! bfd_elf_link_record_dynamic_symbol (info, h)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | need = 0; | 
|  | if ((eh->tls_mask & TLS_TLS) != 0) | 
|  | { | 
|  | /* Handle TLS Symbol */ | 
|  | if ((eh->tls_mask & TLS_LD) != 0) | 
|  | { | 
|  | if (!eh->elf.def_dynamic) | 
|  | /* We'll just use htab->tlsld_got.offset.  This should | 
|  | always be the case.  It's a little odd if we have | 
|  | a local dynamic reloc against a non-local symbol.  */ | 
|  | htab->tlsld_got.refcount += 1; | 
|  | else | 
|  | need += 8; | 
|  | } | 
|  | if ((eh->tls_mask & TLS_GD) != 0) | 
|  | need += 8; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Regular (non-TLS) symbol */ | 
|  | need += 4; | 
|  | } | 
|  | if (need == 0) | 
|  | { | 
|  | h->got.offset = (bfd_vma) -1; | 
|  | } | 
|  | else | 
|  | { | 
|  | s = htab->elf.sgot; | 
|  | h->got.offset = s->size; | 
|  | s->size += need; | 
|  | htab->elf.srelgot->size += need * (sizeof (Elf32_External_Rela) / 4); | 
|  | } | 
|  | } | 
|  | else | 
|  | h->got.offset = (bfd_vma) -1; | 
|  |  | 
|  | if (h->dyn_relocs == NULL) | 
|  | return true; | 
|  |  | 
|  | /* In the shared -Bsymbolic case, discard space allocated for | 
|  | dynamic pc-relative relocs against symbols which turn out to be | 
|  | defined in regular objects.  For the normal shared case, discard | 
|  | space for pc-relative relocs that have become local due to symbol | 
|  | visibility changes.  */ | 
|  |  | 
|  | if (bfd_link_pic (info)) | 
|  | { | 
|  | if (h->def_regular | 
|  | && (h->forced_local | 
|  | || info->symbolic)) | 
|  | { | 
|  | struct elf_dyn_relocs **pp; | 
|  |  | 
|  | for (pp = &h->dyn_relocs; (p = *pp) != NULL; ) | 
|  | { | 
|  | p->count -= p->pc_count; | 
|  | p->pc_count = 0; | 
|  | if (p->count == 0) | 
|  | *pp = p->next; | 
|  | else | 
|  | pp = &p->next; | 
|  | } | 
|  | } | 
|  | else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) | 
|  | h->dyn_relocs = NULL; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* For the non-shared case, discard space for relocs against | 
|  | symbols which turn out to need copy relocs or are not | 
|  | dynamic.  */ | 
|  |  | 
|  | if (!h->non_got_ref | 
|  | && ((h->def_dynamic | 
|  | && !h->def_regular) | 
|  | || (htab->elf.dynamic_sections_created | 
|  | && (h->root.type == bfd_link_hash_undefweak | 
|  | || h->root.type == bfd_link_hash_undefined)))) | 
|  | { | 
|  | /* Make sure this symbol is output as a dynamic symbol. | 
|  | Undefined weak syms won't yet be marked as dynamic.  */ | 
|  | if (h->dynindx == -1 | 
|  | && !h->forced_local) | 
|  | { | 
|  | if (! bfd_elf_link_record_dynamic_symbol (info, h)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* If that succeeded, we know we'll be keeping all the | 
|  | relocs.  */ | 
|  | if (h->dynindx != -1) | 
|  | goto keep; | 
|  | } | 
|  |  | 
|  | h->dyn_relocs = NULL; | 
|  |  | 
|  | keep: ; | 
|  | } | 
|  |  | 
|  | /* Finally, allocate space.  */ | 
|  | for (p = h->dyn_relocs; p != NULL; p = p->next) | 
|  | { | 
|  | asection *sreloc = elf_section_data (p->sec)->sreloc; | 
|  | sreloc->size += p->count * sizeof (Elf32_External_Rela); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Set the sizes of the dynamic sections.  */ | 
|  |  | 
|  | static bool | 
|  | microblaze_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, | 
|  | struct bfd_link_info *info) | 
|  | { | 
|  | struct elf32_mb_link_hash_table *htab; | 
|  | bfd *dynobj; | 
|  | asection *s; | 
|  | bfd *ibfd; | 
|  |  | 
|  | htab = elf32_mb_hash_table (info); | 
|  | if (htab == NULL) | 
|  | return false; | 
|  |  | 
|  | dynobj = htab->elf.dynobj; | 
|  | BFD_ASSERT (dynobj != NULL); | 
|  |  | 
|  | /* Set up .got offsets for local syms, and space for local dynamic | 
|  | relocs.  */ | 
|  | for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) | 
|  | { | 
|  | bfd_signed_vma *local_got; | 
|  | bfd_signed_vma *end_local_got; | 
|  | bfd_size_type locsymcount; | 
|  | Elf_Internal_Shdr *symtab_hdr; | 
|  | unsigned char *lgot_masks; | 
|  | asection *srel; | 
|  |  | 
|  | if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) | 
|  | continue; | 
|  |  | 
|  | for (s = ibfd->sections; s != NULL; s = s->next) | 
|  | { | 
|  | struct elf_dyn_relocs *p; | 
|  |  | 
|  | for (p = ((struct elf_dyn_relocs *) | 
|  | elf_section_data (s)->local_dynrel); | 
|  | p != NULL; | 
|  | p = p->next) | 
|  | { | 
|  | if (!bfd_is_abs_section (p->sec) | 
|  | && bfd_is_abs_section (p->sec->output_section)) | 
|  | { | 
|  | /* Input section has been discarded, either because | 
|  | it is a copy of a linkonce section or due to | 
|  | linker script /DISCARD/, so we'll be discarding | 
|  | the relocs too.  */ | 
|  | } | 
|  | else if (p->count != 0) | 
|  | { | 
|  | srel = elf_section_data (p->sec)->sreloc; | 
|  | srel->size += p->count * sizeof (Elf32_External_Rela); | 
|  | if ((p->sec->output_section->flags & SEC_READONLY) != 0) | 
|  | info->flags |= DF_TEXTREL; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | local_got = elf_local_got_refcounts (ibfd); | 
|  | if (!local_got) | 
|  | continue; | 
|  |  | 
|  | symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; | 
|  | locsymcount = symtab_hdr->sh_info; | 
|  | end_local_got = local_got + locsymcount; | 
|  | lgot_masks = (unsigned char *) end_local_got; | 
|  | s = htab->elf.sgot; | 
|  | srel = htab->elf.srelgot; | 
|  |  | 
|  | for (; local_got < end_local_got; ++local_got, ++lgot_masks) | 
|  | { | 
|  | if (*local_got > 0) | 
|  | { | 
|  | unsigned int need = 0; | 
|  | if ((*lgot_masks & TLS_TLS) != 0) | 
|  | { | 
|  | if ((*lgot_masks & TLS_GD) != 0) | 
|  | need += 8; | 
|  | if ((*lgot_masks & TLS_LD) != 0) | 
|  | htab->tlsld_got.refcount += 1; | 
|  | } | 
|  | else | 
|  | need += 4; | 
|  |  | 
|  | if (need == 0) | 
|  | { | 
|  | *local_got = (bfd_vma) -1; | 
|  | } | 
|  | else | 
|  | { | 
|  | *local_got = s->size; | 
|  | s->size += need; | 
|  | if (bfd_link_pic (info)) | 
|  | srel->size += need * (sizeof (Elf32_External_Rela) / 4); | 
|  | } | 
|  | } | 
|  | else | 
|  | *local_got = (bfd_vma) -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Allocate global sym .plt and .got entries, and space for global | 
|  | sym dynamic relocs.  */ | 
|  | elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info); | 
|  |  | 
|  | if (htab->tlsld_got.refcount > 0) | 
|  | { | 
|  | htab->tlsld_got.offset = htab->elf.sgot->size; | 
|  | htab->elf.sgot->size += 8; | 
|  | if (bfd_link_pic (info)) | 
|  | htab->elf.srelgot->size += sizeof (Elf32_External_Rela); | 
|  | } | 
|  | else | 
|  | htab->tlsld_got.offset = (bfd_vma) -1; | 
|  |  | 
|  | if (elf_hash_table (info)->dynamic_sections_created) | 
|  | { | 
|  | /* Make space for the trailing nop in .plt.  */ | 
|  | if (htab->elf.splt->size > 0) | 
|  | htab->elf.splt->size += 4; | 
|  | } | 
|  |  | 
|  | /* The check_relocs and adjust_dynamic_symbol entry points have | 
|  | determined the sizes of the various dynamic sections.  Allocate | 
|  | memory for them.  */ | 
|  | for (s = dynobj->sections; s != NULL; s = s->next) | 
|  | { | 
|  | const char *name; | 
|  | bool strip = false; | 
|  |  | 
|  | if ((s->flags & SEC_LINKER_CREATED) == 0) | 
|  | continue; | 
|  |  | 
|  | /* It's OK to base decisions on the section name, because none | 
|  | of the dynobj section names depend upon the input files.  */ | 
|  | name = bfd_section_name (s); | 
|  |  | 
|  | if (startswith (name, ".rela")) | 
|  | { | 
|  | if (s->size == 0) | 
|  | { | 
|  | /* If we don't need this section, strip it from the | 
|  | output file.  This is to handle .rela.bss and | 
|  | .rela.plt.  We must create it in | 
|  | create_dynamic_sections, because it must be created | 
|  | before the linker maps input sections to output | 
|  | sections.  The linker does that before | 
|  | adjust_dynamic_symbol is called, and it is that | 
|  | function which decides whether anything needs to go | 
|  | into these sections.  */ | 
|  | strip = true; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* We use the reloc_count field as a counter if we need | 
|  | to copy relocs into the output file.  */ | 
|  | s->reloc_count = 0; | 
|  | } | 
|  | } | 
|  | else if (s != htab->elf.splt | 
|  | && s != htab->elf.sgot | 
|  | && s != htab->elf.sgotplt | 
|  | && s != htab->elf.sdynbss | 
|  | && s != htab->elf.sdynrelro) | 
|  | { | 
|  | /* It's not one of our sections, so don't allocate space.  */ | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (strip) | 
|  | { | 
|  | s->flags |= SEC_EXCLUDE; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* Allocate memory for the section contents.  */ | 
|  | /* FIXME: This should be a call to bfd_alloc not bfd_zalloc. | 
|  | Unused entries should be reclaimed before the section's contents | 
|  | are written out, but at the moment this does not happen.  Thus in | 
|  | order to prevent writing out garbage, we initialise the section's | 
|  | contents to zero.  */ | 
|  | s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); | 
|  | if (s->contents == NULL && s->size != 0) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* ??? Force DF_BIND_NOW?  */ | 
|  | info->flags |= DF_BIND_NOW; | 
|  | return _bfd_elf_add_dynamic_tags (output_bfd, info, true); | 
|  | } | 
|  |  | 
|  | /* Finish up dynamic symbol handling.  We set the contents of various | 
|  | dynamic sections here.  */ | 
|  |  | 
|  | static bool | 
|  | microblaze_elf_finish_dynamic_symbol (bfd *output_bfd, | 
|  | struct bfd_link_info *info, | 
|  | struct elf_link_hash_entry *h, | 
|  | Elf_Internal_Sym *sym) | 
|  | { | 
|  | struct elf32_mb_link_hash_table *htab; | 
|  | struct elf32_mb_link_hash_entry *eh = elf32_mb_hash_entry(h); | 
|  |  | 
|  | htab = elf32_mb_hash_table (info); | 
|  | if (htab == NULL) | 
|  | return false; | 
|  |  | 
|  | if (h->plt.offset != (bfd_vma) -1) | 
|  | { | 
|  | asection *splt; | 
|  | asection *srela; | 
|  | asection *sgotplt; | 
|  | Elf_Internal_Rela rela; | 
|  | bfd_byte *loc; | 
|  | bfd_vma plt_index; | 
|  | bfd_vma got_offset; | 
|  | bfd_vma got_addr; | 
|  |  | 
|  | /* This symbol has an entry in the procedure linkage table.  Set | 
|  | it up.  */ | 
|  | BFD_ASSERT (h->dynindx != -1); | 
|  |  | 
|  | splt = htab->elf.splt; | 
|  | srela = htab->elf.srelplt; | 
|  | sgotplt = htab->elf.sgotplt; | 
|  | BFD_ASSERT (splt != NULL && srela != NULL && sgotplt != NULL); | 
|  |  | 
|  | plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; /* first entry reserved.  */ | 
|  | got_offset = (plt_index + 3) * 4; /* 3 reserved ???  */ | 
|  | got_addr = got_offset; | 
|  |  | 
|  | /* For non-PIC objects we need absolute address of the GOT entry.  */ | 
|  | if (!bfd_link_pic (info)) | 
|  | got_addr += sgotplt->output_section->vma + sgotplt->output_offset; | 
|  |  | 
|  | /* Fill in the entry in the procedure linkage table.  */ | 
|  | bfd_put_32 (output_bfd, PLT_ENTRY_WORD_0 + ((got_addr >> 16) & 0xffff), | 
|  | splt->contents + h->plt.offset); | 
|  | if (bfd_link_pic (info)) | 
|  | bfd_put_32 (output_bfd, PLT_ENTRY_WORD_1 + (got_addr & 0xffff), | 
|  | splt->contents + h->plt.offset + 4); | 
|  | else | 
|  | bfd_put_32 (output_bfd, PLT_ENTRY_WORD_1_NOPIC + (got_addr & 0xffff), | 
|  | splt->contents + h->plt.offset + 4); | 
|  | bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD_2, | 
|  | splt->contents + h->plt.offset + 8); | 
|  | bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD_3, | 
|  | splt->contents + h->plt.offset + 12); | 
|  |  | 
|  | /* Any additions to the .got section??? */ | 
|  | /*      bfd_put_32 (output_bfd, | 
|  | splt->output_section->vma + splt->output_offset + h->plt.offset + 4, | 
|  | sgotplt->contents + got_offset); */ | 
|  |  | 
|  | /* Fill in the entry in the .rela.plt section.  */ | 
|  | rela.r_offset = (sgotplt->output_section->vma | 
|  | + sgotplt->output_offset | 
|  | + got_offset); | 
|  | rela.r_info = ELF32_R_INFO (h->dynindx, R_MICROBLAZE_JUMP_SLOT); | 
|  | rela.r_addend = 0; | 
|  | loc = srela->contents; | 
|  | loc += plt_index * sizeof (Elf32_External_Rela); | 
|  | bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); | 
|  |  | 
|  | if (!h->def_regular) | 
|  | { | 
|  | /* Mark the symbol as undefined, rather than as defined in | 
|  | the .plt section.  Zero the value.  */ | 
|  | sym->st_shndx = SHN_UNDEF; | 
|  | sym->st_value = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* h->got.refcount to be checked ? */ | 
|  | if ((h->got.offset != (bfd_vma) -1) | 
|  | && ! ((h->got.offset & 1) | 
|  | || IS_TLS_LD(eh->tls_mask) || IS_TLS_GD(eh->tls_mask))) | 
|  | { | 
|  | asection *sgot; | 
|  | asection *srela; | 
|  | bfd_vma offset; | 
|  |  | 
|  | /* This symbol has an entry in the global offset table.  Set it | 
|  | up.  */ | 
|  |  | 
|  | sgot = htab->elf.sgot; | 
|  | srela = htab->elf.srelgot; | 
|  | BFD_ASSERT (sgot != NULL && srela != NULL); | 
|  |  | 
|  | offset = (sgot->output_section->vma + sgot->output_offset | 
|  | + (h->got.offset &~ (bfd_vma) 1)); | 
|  |  | 
|  | /* If this is a -Bsymbolic link, and the symbol is defined | 
|  | locally, we just want to emit a RELATIVE reloc.  Likewise if | 
|  | the symbol was forced to be local because of a version file. | 
|  | The entry in the global offset table will already have been | 
|  | initialized in the relocate_section function.  */ | 
|  | if (bfd_link_pic (info) | 
|  | && ((info->symbolic && h->def_regular) | 
|  | || h->dynindx == -1)) | 
|  | { | 
|  | asection *sec = h->root.u.def.section; | 
|  | bfd_vma value; | 
|  |  | 
|  | value = h->root.u.def.value; | 
|  | if (sec->output_section != NULL) | 
|  | /* PR 21180: If the output section is NULL, then the symbol is no | 
|  | longer needed, and in theory the GOT entry is redundant.  But | 
|  | it is too late to change our minds now...  */ | 
|  | value += sec->output_section->vma + sec->output_offset; | 
|  |  | 
|  | microblaze_elf_output_dynamic_relocation (output_bfd, | 
|  | srela, srela->reloc_count++, | 
|  | /* symindex= */ 0, | 
|  | R_MICROBLAZE_REL, offset, | 
|  | value); | 
|  | } | 
|  | else | 
|  | { | 
|  | microblaze_elf_output_dynamic_relocation (output_bfd, | 
|  | srela, srela->reloc_count++, | 
|  | h->dynindx, | 
|  | R_MICROBLAZE_GLOB_DAT, | 
|  | offset, 0); | 
|  | } | 
|  |  | 
|  | bfd_put_32 (output_bfd, (bfd_vma) 0, | 
|  | sgot->contents + (h->got.offset &~ (bfd_vma) 1)); | 
|  | } | 
|  |  | 
|  | if (h->needs_copy) | 
|  | { | 
|  | asection *s; | 
|  | Elf_Internal_Rela rela; | 
|  | bfd_byte *loc; | 
|  |  | 
|  | /* This symbols needs a copy reloc.  Set it up.  */ | 
|  |  | 
|  | BFD_ASSERT (h->dynindx != -1); | 
|  |  | 
|  | rela.r_offset = (h->root.u.def.value | 
|  | + h->root.u.def.section->output_section->vma | 
|  | + h->root.u.def.section->output_offset); | 
|  | rela.r_info = ELF32_R_INFO (h->dynindx, R_MICROBLAZE_COPY); | 
|  | rela.r_addend = 0; | 
|  | if (h->root.u.def.section == htab->elf.sdynrelro) | 
|  | s = htab->elf.sreldynrelro; | 
|  | else | 
|  | s = htab->elf.srelbss; | 
|  | loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); | 
|  | bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); | 
|  | } | 
|  |  | 
|  | /* Mark some specially defined symbols as absolute.  */ | 
|  | if (h == htab->elf.hdynamic | 
|  | || h == htab->elf.hgot | 
|  | || h == htab->elf.hplt) | 
|  | sym->st_shndx = SHN_ABS; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Finish up the dynamic sections.  */ | 
|  |  | 
|  | static bool | 
|  | microblaze_elf_finish_dynamic_sections (bfd *output_bfd, | 
|  | struct bfd_link_info *info) | 
|  | { | 
|  | bfd *dynobj; | 
|  | asection *sdyn, *sgot; | 
|  | struct elf32_mb_link_hash_table *htab; | 
|  |  | 
|  | htab = elf32_mb_hash_table (info); | 
|  | if (htab == NULL) | 
|  | return false; | 
|  |  | 
|  | dynobj = htab->elf.dynobj; | 
|  |  | 
|  | sdyn = bfd_get_linker_section (dynobj, ".dynamic"); | 
|  |  | 
|  | if (htab->elf.dynamic_sections_created) | 
|  | { | 
|  | asection *splt; | 
|  | Elf32_External_Dyn *dyncon, *dynconend; | 
|  |  | 
|  | dyncon = (Elf32_External_Dyn *) sdyn->contents; | 
|  | dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); | 
|  | for (; dyncon < dynconend; dyncon++) | 
|  | { | 
|  | Elf_Internal_Dyn dyn; | 
|  | asection *s; | 
|  | bool size; | 
|  |  | 
|  | bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); | 
|  |  | 
|  | switch (dyn.d_tag) | 
|  | { | 
|  | case DT_PLTGOT: | 
|  | s = htab->elf.sgotplt; | 
|  | size = false; | 
|  | break; | 
|  |  | 
|  | case DT_PLTRELSZ: | 
|  | s = htab->elf.srelplt; | 
|  | size = true; | 
|  | break; | 
|  |  | 
|  | case DT_JMPREL: | 
|  | s = htab->elf.srelplt; | 
|  | size = false; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (s == NULL) | 
|  | dyn.d_un.d_val = 0; | 
|  | else | 
|  | { | 
|  | if (!size) | 
|  | dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; | 
|  | else | 
|  | dyn.d_un.d_val = s->size; | 
|  | } | 
|  | bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); | 
|  | } | 
|  |  | 
|  | splt = htab->elf.splt; | 
|  | BFD_ASSERT (splt != NULL && sdyn != NULL); | 
|  |  | 
|  | /* Clear the first entry in the procedure linkage table, | 
|  | and put a nop in the last four bytes.  */ | 
|  | if (splt->size > 0) | 
|  | { | 
|  | memset (splt->contents, 0, PLT_ENTRY_SIZE); | 
|  | bfd_put_32 (output_bfd, (bfd_vma) 0x80000000 /* nop.  */, | 
|  | splt->contents + splt->size - 4); | 
|  |  | 
|  | if (splt->output_section != bfd_abs_section_ptr) | 
|  | elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Set the first entry in the global offset table to the address of | 
|  | the dynamic section.  */ | 
|  | sgot = htab->elf.sgotplt; | 
|  | if (sgot && sgot->size > 0) | 
|  | { | 
|  | if (sdyn == NULL) | 
|  | bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); | 
|  | else | 
|  | bfd_put_32 (output_bfd, | 
|  | sdyn->output_section->vma + sdyn->output_offset, | 
|  | sgot->contents); | 
|  | elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; | 
|  | } | 
|  |  | 
|  | if (htab->elf.sgot && htab->elf.sgot->size > 0) | 
|  | elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Hook called by the linker routine which adds symbols from an object | 
|  | file.  We use it to put .comm items in .sbss, and not .bss.  */ | 
|  |  | 
|  | static bool | 
|  | microblaze_elf_add_symbol_hook (bfd *abfd, | 
|  | struct bfd_link_info *info, | 
|  | Elf_Internal_Sym *sym, | 
|  | const char **namep ATTRIBUTE_UNUSED, | 
|  | flagword *flagsp ATTRIBUTE_UNUSED, | 
|  | asection **secp, | 
|  | bfd_vma *valp) | 
|  | { | 
|  | if (sym->st_shndx == SHN_COMMON | 
|  | && !bfd_link_relocatable (info) | 
|  | && sym->st_size <= elf_gp_size (abfd)) | 
|  | { | 
|  | /* Common symbols less than or equal to -G nn bytes are automatically | 
|  | put into .sbss.  */ | 
|  | *secp = bfd_make_section_old_way (abfd, ".sbss"); | 
|  | if (*secp == NULL | 
|  | || !bfd_set_section_flags (*secp, SEC_IS_COMMON | SEC_SMALL_DATA)) | 
|  | return false; | 
|  |  | 
|  | *valp = sym->st_size; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | #define TARGET_LITTLE_SYM      microblaze_elf32_le_vec | 
|  | #define TARGET_LITTLE_NAME     "elf32-microblazeel" | 
|  |  | 
|  | #define TARGET_BIG_SYM		microblaze_elf32_vec | 
|  | #define TARGET_BIG_NAME		"elf32-microblaze" | 
|  |  | 
|  | #define ELF_ARCH		bfd_arch_microblaze | 
|  | #define ELF_TARGET_ID		MICROBLAZE_ELF_DATA | 
|  | #define ELF_MACHINE_CODE	EM_MICROBLAZE | 
|  | #define ELF_MACHINE_ALT1	EM_MICROBLAZE_OLD | 
|  | #define ELF_MAXPAGESIZE		0x1000 | 
|  | #define elf_info_to_howto	microblaze_elf_info_to_howto | 
|  | #define elf_info_to_howto_rel	NULL | 
|  |  | 
|  | #define bfd_elf32_bfd_reloc_type_lookup		microblaze_elf_reloc_type_lookup | 
|  | #define bfd_elf32_bfd_is_local_label_name	microblaze_elf_is_local_label_name | 
|  | #define bfd_elf32_new_section_hook		microblaze_elf_new_section_hook | 
|  | #define elf_backend_relocate_section		microblaze_elf_relocate_section | 
|  | #define bfd_elf32_bfd_relax_section		microblaze_elf_relax_section | 
|  | #define bfd_elf32_bfd_merge_private_bfd_data	_bfd_generic_verify_endian_match | 
|  | #define bfd_elf32_bfd_reloc_name_lookup		microblaze_elf_reloc_name_lookup | 
|  |  | 
|  | #define elf_backend_gc_mark_hook		microblaze_elf_gc_mark_hook | 
|  | #define elf_backend_check_relocs		microblaze_elf_check_relocs | 
|  | #define elf_backend_copy_indirect_symbol	microblaze_elf_copy_indirect_symbol | 
|  | #define bfd_elf32_bfd_link_hash_table_create	microblaze_elf_link_hash_table_create | 
|  | #define elf_backend_can_gc_sections		1 | 
|  | #define elf_backend_can_refcount		1 | 
|  | #define elf_backend_want_got_plt		1 | 
|  | #define elf_backend_plt_readonly		1 | 
|  | #define elf_backend_got_header_size		12 | 
|  | #define elf_backend_want_dynrelro		1 | 
|  | #define elf_backend_rela_normal			1 | 
|  | #define elf_backend_dtrel_excludes_plt		1 | 
|  |  | 
|  | #define elf_backend_adjust_dynamic_symbol	microblaze_elf_adjust_dynamic_symbol | 
|  | #define elf_backend_create_dynamic_sections	_bfd_elf_create_dynamic_sections | 
|  | #define elf_backend_finish_dynamic_sections	microblaze_elf_finish_dynamic_sections | 
|  | #define elf_backend_finish_dynamic_symbol	microblaze_elf_finish_dynamic_symbol | 
|  | #define elf_backend_size_dynamic_sections	microblaze_elf_size_dynamic_sections | 
|  | #define elf_backend_add_symbol_hook		microblaze_elf_add_symbol_hook | 
|  |  | 
|  | #include "elf32-target.h" |