| 1 | /* Motorola 68HC11-specific support for 32-bit ELF
 | 
|---|
| 2 |    Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 | 
|---|
| 3 |    Contributed by Stephane Carrez (stcarrez@nerim.fr)
 | 
|---|
| 4 |    (Heavily copied from the D10V port by Martin Hunt (hunt@cygnus.com))
 | 
|---|
| 5 | 
 | 
|---|
| 6 | This file is part of BFD, the Binary File Descriptor library.
 | 
|---|
| 7 | 
 | 
|---|
| 8 | This program is free software; you can redistribute it and/or modify
 | 
|---|
| 9 | it under the terms of the GNU General Public License as published by
 | 
|---|
| 10 | the Free Software Foundation; either version 2 of the License, or
 | 
|---|
| 11 | (at your option) any later version.
 | 
|---|
| 12 | 
 | 
|---|
| 13 | This program is distributed in the hope that it will be useful,
 | 
|---|
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 16 | GNU General Public License for more details.
 | 
|---|
| 17 | 
 | 
|---|
| 18 | You should have received a copy of the GNU General Public License
 | 
|---|
| 19 | along with this program; if not, write to the Free Software
 | 
|---|
| 20 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 | 
|---|
| 21 | 
 | 
|---|
| 22 | #include "bfd.h"
 | 
|---|
| 23 | #include "sysdep.h"
 | 
|---|
| 24 | #include "bfdlink.h"
 | 
|---|
| 25 | #include "libbfd.h"
 | 
|---|
| 26 | #include "elf-bfd.h"
 | 
|---|
| 27 | #include "elf32-m68hc1x.h"
 | 
|---|
| 28 | #include "elf/m68hc11.h"
 | 
|---|
| 29 | #include "opcode/m68hc11.h"
 | 
|---|
| 30 | 
 | 
|---|
| 31 | /* Relocation functions.  */
 | 
|---|
| 32 | static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
 | 
|---|
| 33 |   PARAMS ((bfd *, bfd_reloc_code_real_type));
 | 
|---|
| 34 | static void m68hc11_info_to_howto_rel
 | 
|---|
| 35 |   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
 | 
|---|
| 36 | 
 | 
|---|
| 37 | /* Trampoline generation.  */
 | 
|---|
| 38 | static bfd_boolean m68hc11_elf_size_one_stub
 | 
|---|
| 39 |   PARAMS((struct bfd_hash_entry *gen_entry, PTR in_arg));
 | 
|---|
| 40 | static bfd_boolean m68hc11_elf_build_one_stub
 | 
|---|
| 41 |   PARAMS((struct bfd_hash_entry *gen_entry, PTR in_arg));
 | 
|---|
| 42 | static struct bfd_link_hash_table* m68hc11_elf_bfd_link_hash_table_create
 | 
|---|
| 43 |   PARAMS ((bfd* abfd));
 | 
|---|
| 44 | 
 | 
|---|
| 45 | /* Linker relaxation.  */
 | 
|---|
| 46 | static bfd_boolean m68hc11_elf_relax_section
 | 
|---|
| 47 |   PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *));
 | 
|---|
| 48 | static void m68hc11_elf_relax_delete_bytes
 | 
|---|
| 49 |   PARAMS ((bfd *, asection *, bfd_vma, int));
 | 
|---|
| 50 | static void m68hc11_relax_group
 | 
|---|
| 51 |   PARAMS ((bfd *, asection *, bfd_byte *, unsigned,
 | 
|---|
| 52 |            unsigned long, unsigned long));
 | 
|---|
| 53 | static int compare_reloc PARAMS ((const void *, const void *));
 | 
|---|
| 54 | 
 | 
|---|
| 55 | /* Use REL instead of RELA to save space */
 | 
|---|
| 56 | #define USE_REL 1
 | 
|---|
| 57 | 
 | 
|---|
| 58 | /* The Motorola 68HC11 microcontroller only addresses 64Kb but we also
 | 
|---|
| 59 |    support a memory bank switching mechanism similar to 68HC12.
 | 
|---|
| 60 |    We must handle 8 and 16-bit relocations.  The 32-bit relocation
 | 
|---|
| 61 |    are used for debugging sections (DWARF2) to represent a virtual
 | 
|---|
| 62 |    address.
 | 
|---|
| 63 |    The 3-bit and 16-bit PC rel relocation is only used by 68HC12.  */
 | 
|---|
| 64 | static reloc_howto_type elf_m68hc11_howto_table[] = {
 | 
|---|
| 65 |   /* This reloc does nothing.  */
 | 
|---|
| 66 |   HOWTO (R_M68HC11_NONE,        /* type */
 | 
|---|
| 67 |          0,                     /* rightshift */
 | 
|---|
| 68 |          2,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 69 |          32,                    /* bitsize */
 | 
|---|
| 70 |          FALSE,                 /* pc_relative */
 | 
|---|
| 71 |          0,                     /* bitpos */
 | 
|---|
| 72 |          complain_overflow_dont,/* complain_on_overflow */
 | 
|---|
| 73 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 74 |          "R_M68HC11_NONE",      /* name */
 | 
|---|
| 75 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 76 |          0,                     /* src_mask */
 | 
|---|
| 77 |          0,                     /* dst_mask */
 | 
|---|
| 78 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 79 | 
 | 
|---|
| 80 |   /* A 8 bit absolute relocation */
 | 
|---|
| 81 |   HOWTO (R_M68HC11_8,           /* type */
 | 
|---|
| 82 |          0,                     /* rightshift */
 | 
|---|
| 83 |          0,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 84 |          8,                     /* bitsize */
 | 
|---|
| 85 |          FALSE,                 /* pc_relative */
 | 
|---|
| 86 |          0,                     /* bitpos */
 | 
|---|
| 87 |          complain_overflow_bitfield,    /* complain_on_overflow */
 | 
|---|
| 88 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 89 |          "R_M68HC11_8",         /* name */
 | 
|---|
| 90 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 91 |          0x00ff,                /* src_mask */
 | 
|---|
| 92 |          0x00ff,                /* dst_mask */
 | 
|---|
| 93 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 94 | 
 | 
|---|
| 95 |   /* A 8 bit absolute relocation (upper address) */
 | 
|---|
| 96 |   HOWTO (R_M68HC11_HI8,         /* type */
 | 
|---|
| 97 |          8,                     /* rightshift */
 | 
|---|
| 98 |          0,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 99 |          8,                     /* bitsize */
 | 
|---|
| 100 |          FALSE,                 /* pc_relative */
 | 
|---|
| 101 |          0,                     /* bitpos */
 | 
|---|
| 102 |          complain_overflow_bitfield,    /* complain_on_overflow */
 | 
|---|
| 103 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 104 |          "R_M68HC11_HI8",       /* name */
 | 
|---|
| 105 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 106 |          0x00ff,                /* src_mask */
 | 
|---|
| 107 |          0x00ff,                /* dst_mask */
 | 
|---|
| 108 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 109 | 
 | 
|---|
| 110 |   /* A 8 bit absolute relocation (upper address) */
 | 
|---|
| 111 |   HOWTO (R_M68HC11_LO8,         /* type */
 | 
|---|
| 112 |          0,                     /* rightshift */
 | 
|---|
| 113 |          0,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 114 |          8,                     /* bitsize */
 | 
|---|
| 115 |          FALSE,                 /* pc_relative */
 | 
|---|
| 116 |          0,                     /* bitpos */
 | 
|---|
| 117 |          complain_overflow_dont,        /* complain_on_overflow */
 | 
|---|
| 118 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 119 |          "R_M68HC11_LO8",       /* name */
 | 
|---|
| 120 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 121 |          0x00ff,                /* src_mask */
 | 
|---|
| 122 |          0x00ff,                /* dst_mask */
 | 
|---|
| 123 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 124 | 
 | 
|---|
| 125 |   /* A 8 bit PC-rel relocation */
 | 
|---|
| 126 |   HOWTO (R_M68HC11_PCREL_8,     /* type */
 | 
|---|
| 127 |          0,                     /* rightshift */
 | 
|---|
| 128 |          0,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 129 |          8,                     /* bitsize */
 | 
|---|
| 130 |          TRUE,                  /* pc_relative */
 | 
|---|
| 131 |          0,                     /* bitpos */
 | 
|---|
| 132 |          complain_overflow_bitfield,    /* complain_on_overflow */
 | 
|---|
| 133 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 134 |          "R_M68HC11_PCREL_8",   /* name */
 | 
|---|
| 135 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 136 |          0x00ff,                /* src_mask */
 | 
|---|
| 137 |          0x00ff,                /* dst_mask */
 | 
|---|
| 138 |          TRUE),                 /* pcrel_offset */
 | 
|---|
| 139 | 
 | 
|---|
| 140 |   /* A 16 bit absolute relocation */
 | 
|---|
| 141 |   HOWTO (R_M68HC11_16,          /* type */
 | 
|---|
| 142 |          0,                     /* rightshift */
 | 
|---|
| 143 |          1,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 144 |          16,                    /* bitsize */
 | 
|---|
| 145 |          FALSE,                 /* pc_relative */
 | 
|---|
| 146 |          0,                     /* bitpos */
 | 
|---|
| 147 |          complain_overflow_dont /*bitfield */ , /* complain_on_overflow */
 | 
|---|
| 148 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 149 |          "R_M68HC11_16",        /* name */
 | 
|---|
| 150 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 151 |          0xffff,                /* src_mask */
 | 
|---|
| 152 |          0xffff,                /* dst_mask */
 | 
|---|
| 153 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 154 | 
 | 
|---|
| 155 |   /* A 32 bit absolute relocation.  This one is never used for the
 | 
|---|
| 156 |      code relocation.  It's used by gas for -gstabs generation.  */
 | 
|---|
| 157 |   HOWTO (R_M68HC11_32,          /* type */
 | 
|---|
| 158 |          0,                     /* rightshift */
 | 
|---|
| 159 |          2,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 160 |          32,                    /* bitsize */
 | 
|---|
| 161 |          FALSE,                 /* pc_relative */
 | 
|---|
| 162 |          0,                     /* bitpos */
 | 
|---|
| 163 |          complain_overflow_bitfield,    /* complain_on_overflow */
 | 
|---|
| 164 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 165 |          "R_M68HC11_32",        /* name */
 | 
|---|
| 166 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 167 |          0xffffffff,            /* src_mask */
 | 
|---|
| 168 |          0xffffffff,            /* dst_mask */
 | 
|---|
| 169 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 170 | 
 | 
|---|
| 171 |   /* A 3 bit absolute relocation */
 | 
|---|
| 172 |   HOWTO (R_M68HC11_3B,          /* type */
 | 
|---|
| 173 |          0,                     /* rightshift */
 | 
|---|
| 174 |          0,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 175 |          3,                     /* bitsize */
 | 
|---|
| 176 |          FALSE,                 /* pc_relative */
 | 
|---|
| 177 |          0,                     /* bitpos */
 | 
|---|
| 178 |          complain_overflow_bitfield,    /* complain_on_overflow */
 | 
|---|
| 179 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 180 |          "R_M68HC11_4B",        /* name */
 | 
|---|
| 181 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 182 |          0x003,                 /* src_mask */
 | 
|---|
| 183 |          0x003,                 /* dst_mask */
 | 
|---|
| 184 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 185 | 
 | 
|---|
| 186 |   /* A 16 bit PC-rel relocation */
 | 
|---|
| 187 |   HOWTO (R_M68HC11_PCREL_16,    /* type */
 | 
|---|
| 188 |          0,                     /* rightshift */
 | 
|---|
| 189 |          1,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 190 |          16,                    /* bitsize */
 | 
|---|
| 191 |          TRUE,                  /* pc_relative */
 | 
|---|
| 192 |          0,                     /* bitpos */
 | 
|---|
| 193 |          complain_overflow_dont,        /* complain_on_overflow */
 | 
|---|
| 194 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 195 |          "R_M68HC11_PCREL_16",  /* name */
 | 
|---|
| 196 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 197 |          0xffff,                /* src_mask */
 | 
|---|
| 198 |          0xffff,                /* dst_mask */
 | 
|---|
| 199 |          TRUE),                 /* pcrel_offset */
 | 
|---|
| 200 | 
 | 
|---|
| 201 |   /* GNU extension to record C++ vtable hierarchy */
 | 
|---|
| 202 |   HOWTO (R_M68HC11_GNU_VTINHERIT,       /* type */
 | 
|---|
| 203 |          0,                     /* rightshift */
 | 
|---|
| 204 |          1,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 205 |          0,                     /* bitsize */
 | 
|---|
| 206 |          FALSE,                 /* pc_relative */
 | 
|---|
| 207 |          0,                     /* bitpos */
 | 
|---|
| 208 |          complain_overflow_dont,        /* complain_on_overflow */
 | 
|---|
| 209 |          NULL,                  /* special_function */
 | 
|---|
| 210 |          "R_M68HC11_GNU_VTINHERIT",     /* name */
 | 
|---|
| 211 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 212 |          0,                     /* src_mask */
 | 
|---|
| 213 |          0,                     /* dst_mask */
 | 
|---|
| 214 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 215 | 
 | 
|---|
| 216 |   /* GNU extension to record C++ vtable member usage */
 | 
|---|
| 217 |   HOWTO (R_M68HC11_GNU_VTENTRY, /* type */
 | 
|---|
| 218 |          0,                     /* rightshift */
 | 
|---|
| 219 |          1,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 220 |          0,                     /* bitsize */
 | 
|---|
| 221 |          FALSE,                 /* pc_relative */
 | 
|---|
| 222 |          0,                     /* bitpos */
 | 
|---|
| 223 |          complain_overflow_dont,        /* complain_on_overflow */
 | 
|---|
| 224 |          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
 | 
|---|
| 225 |          "R_M68HC11_GNU_VTENTRY",       /* name */
 | 
|---|
| 226 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 227 |          0,                     /* src_mask */
 | 
|---|
| 228 |          0,                     /* dst_mask */
 | 
|---|
| 229 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 230 | 
 | 
|---|
| 231 |   /* A 24 bit relocation */
 | 
|---|
| 232 |   HOWTO (R_M68HC11_24,          /* type */
 | 
|---|
| 233 |          0,                     /* rightshift */
 | 
|---|
| 234 |          1,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 235 |          24,                    /* bitsize */
 | 
|---|
| 236 |          FALSE,                 /* pc_relative */
 | 
|---|
| 237 |          0,                     /* bitpos */
 | 
|---|
| 238 |          complain_overflow_bitfield,    /* complain_on_overflow */
 | 
|---|
| 239 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 240 |          "R_M68HC11_24",        /* name */
 | 
|---|
| 241 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 242 |          0xffffff,              /* src_mask */
 | 
|---|
| 243 |          0xffffff,              /* dst_mask */
 | 
|---|
| 244 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 245 | 
 | 
|---|
| 246 |   /* A 16-bit low relocation */
 | 
|---|
| 247 |   HOWTO (R_M68HC11_LO16,        /* type */
 | 
|---|
| 248 |          0,                     /* rightshift */
 | 
|---|
| 249 |          1,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 250 |          16,                    /* bitsize */
 | 
|---|
| 251 |          FALSE,                 /* pc_relative */
 | 
|---|
| 252 |          0,                     /* bitpos */
 | 
|---|
| 253 |          complain_overflow_bitfield,    /* complain_on_overflow */
 | 
|---|
| 254 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 255 |          "R_M68HC11_LO16",      /* name */
 | 
|---|
| 256 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 257 |          0xffff,                /* src_mask */
 | 
|---|
| 258 |          0xffff,                /* dst_mask */
 | 
|---|
| 259 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 260 | 
 | 
|---|
| 261 |   /* A page relocation */
 | 
|---|
| 262 |   HOWTO (R_M68HC11_PAGE,        /* type */
 | 
|---|
| 263 |          0,                     /* rightshift */
 | 
|---|
| 264 |          0,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 265 |          8,                     /* bitsize */
 | 
|---|
| 266 |          FALSE,                 /* pc_relative */
 | 
|---|
| 267 |          0,                     /* bitpos */
 | 
|---|
| 268 |          complain_overflow_bitfield,    /* complain_on_overflow */
 | 
|---|
| 269 |          bfd_elf_generic_reloc, /* special_function */
 | 
|---|
| 270 |          "R_M68HC11_PAGE",      /* name */
 | 
|---|
| 271 |          FALSE,                 /* partial_inplace */
 | 
|---|
| 272 |          0x00ff,                /* src_mask */
 | 
|---|
| 273 |          0x00ff,                /* dst_mask */
 | 
|---|
| 274 |          FALSE),                /* pcrel_offset */
 | 
|---|
| 275 | 
 | 
|---|
| 276 |   EMPTY_HOWTO (14),
 | 
|---|
| 277 |   EMPTY_HOWTO (15),
 | 
|---|
| 278 |   EMPTY_HOWTO (16),
 | 
|---|
| 279 |   EMPTY_HOWTO (17),
 | 
|---|
| 280 |   EMPTY_HOWTO (18),
 | 
|---|
| 281 |   EMPTY_HOWTO (19),
 | 
|---|
| 282 | 
 | 
|---|
| 283 |   /* Mark beginning of a jump instruction (any form).  */
 | 
|---|
| 284 |   HOWTO (R_M68HC11_RL_JUMP,     /* type */
 | 
|---|
| 285 |          0,                     /* rightshift */
 | 
|---|
| 286 |          1,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 287 |          0,                     /* bitsize */
 | 
|---|
| 288 |          FALSE,                 /* pc_relative */
 | 
|---|
| 289 |          0,                     /* bitpos */
 | 
|---|
| 290 |          complain_overflow_dont,        /* complain_on_overflow */
 | 
|---|
| 291 |          m68hc11_elf_ignore_reloc,      /* special_function */
 | 
|---|
| 292 |          "R_M68HC11_RL_JUMP",   /* name */
 | 
|---|
| 293 |          TRUE,                  /* partial_inplace */
 | 
|---|
| 294 |          0,                     /* src_mask */
 | 
|---|
| 295 |          0,                     /* dst_mask */
 | 
|---|
| 296 |          TRUE),                 /* pcrel_offset */
 | 
|---|
| 297 | 
 | 
|---|
| 298 |   /* Mark beginning of Gcc relaxation group instruction.  */
 | 
|---|
| 299 |   HOWTO (R_M68HC11_RL_GROUP,    /* type */
 | 
|---|
| 300 |          0,                     /* rightshift */
 | 
|---|
| 301 |          1,                     /* size (0 = byte, 1 = short, 2 = long) */
 | 
|---|
| 302 |          0,                     /* bitsize */
 | 
|---|
| 303 |          FALSE,                 /* pc_relative */
 | 
|---|
| 304 |          0,                     /* bitpos */
 | 
|---|
| 305 |          complain_overflow_dont,        /* complain_on_overflow */
 | 
|---|
| 306 |          m68hc11_elf_ignore_reloc,      /* special_function */
 | 
|---|
| 307 |          "R_M68HC11_RL_GROUP",  /* name */
 | 
|---|
| 308 |          TRUE,                  /* partial_inplace */
 | 
|---|
| 309 |          0,                     /* src_mask */
 | 
|---|
| 310 |          0,                     /* dst_mask */
 | 
|---|
| 311 |          TRUE),                 /* pcrel_offset */
 | 
|---|
| 312 | };
 | 
|---|
| 313 | 
 | 
|---|
| 314 | /* Map BFD reloc types to M68HC11 ELF reloc types.  */
 | 
|---|
| 315 | 
 | 
|---|
| 316 | struct m68hc11_reloc_map
 | 
|---|
| 317 | {
 | 
|---|
| 318 |   bfd_reloc_code_real_type bfd_reloc_val;
 | 
|---|
| 319 |   unsigned char elf_reloc_val;
 | 
|---|
| 320 | };
 | 
|---|
| 321 | 
 | 
|---|
| 322 | static const struct m68hc11_reloc_map m68hc11_reloc_map[] = {
 | 
|---|
| 323 |   {BFD_RELOC_NONE, R_M68HC11_NONE,},
 | 
|---|
| 324 |   {BFD_RELOC_8, R_M68HC11_8},
 | 
|---|
| 325 |   {BFD_RELOC_M68HC11_HI8, R_M68HC11_HI8},
 | 
|---|
| 326 |   {BFD_RELOC_M68HC11_LO8, R_M68HC11_LO8},
 | 
|---|
| 327 |   {BFD_RELOC_8_PCREL, R_M68HC11_PCREL_8},
 | 
|---|
| 328 |   {BFD_RELOC_16_PCREL, R_M68HC11_PCREL_16},
 | 
|---|
| 329 |   {BFD_RELOC_16, R_M68HC11_16},
 | 
|---|
| 330 |   {BFD_RELOC_32, R_M68HC11_32},
 | 
|---|
| 331 |   {BFD_RELOC_M68HC11_3B, R_M68HC11_3B},
 | 
|---|
| 332 | 
 | 
|---|
| 333 |   {BFD_RELOC_VTABLE_INHERIT, R_M68HC11_GNU_VTINHERIT},
 | 
|---|
| 334 |   {BFD_RELOC_VTABLE_ENTRY, R_M68HC11_GNU_VTENTRY},
 | 
|---|
| 335 | 
 | 
|---|
| 336 |   {BFD_RELOC_M68HC11_LO16, R_M68HC11_LO16},
 | 
|---|
| 337 |   {BFD_RELOC_M68HC11_PAGE, R_M68HC11_PAGE},
 | 
|---|
| 338 |   {BFD_RELOC_M68HC11_24, R_M68HC11_24},
 | 
|---|
| 339 | 
 | 
|---|
| 340 |   {BFD_RELOC_M68HC11_RL_JUMP, R_M68HC11_RL_JUMP},
 | 
|---|
| 341 |   {BFD_RELOC_M68HC11_RL_GROUP, R_M68HC11_RL_GROUP},
 | 
|---|
| 342 | };
 | 
|---|
| 343 | 
 | 
|---|
| 344 | static reloc_howto_type *
 | 
|---|
| 345 | bfd_elf32_bfd_reloc_type_lookup (abfd, code)
 | 
|---|
| 346 |      bfd *abfd ATTRIBUTE_UNUSED;
 | 
|---|
| 347 |      bfd_reloc_code_real_type code;
 | 
|---|
| 348 | {
 | 
|---|
| 349 |   unsigned int i;
 | 
|---|
| 350 | 
 | 
|---|
| 351 |   for (i = 0;
 | 
|---|
| 352 |        i < sizeof (m68hc11_reloc_map) / sizeof (struct m68hc11_reloc_map);
 | 
|---|
| 353 |        i++)
 | 
|---|
| 354 |     {
 | 
|---|
| 355 |       if (m68hc11_reloc_map[i].bfd_reloc_val == code)
 | 
|---|
| 356 |         return &elf_m68hc11_howto_table[m68hc11_reloc_map[i].elf_reloc_val];
 | 
|---|
| 357 |     }
 | 
|---|
| 358 | 
 | 
|---|
| 359 |   return NULL;
 | 
|---|
| 360 | }
 | 
|---|
| 361 | 
 | 
|---|
| 362 | /* Set the howto pointer for an M68HC11 ELF reloc.  */
 | 
|---|
| 363 | 
 | 
|---|
| 364 | static void
 | 
|---|
| 365 | m68hc11_info_to_howto_rel (abfd, cache_ptr, dst)
 | 
|---|
| 366 |      bfd *abfd ATTRIBUTE_UNUSED;
 | 
|---|
| 367 |      arelent *cache_ptr;
 | 
|---|
| 368 |      Elf_Internal_Rela *dst;
 | 
|---|
| 369 | {
 | 
|---|
| 370 |   unsigned int r_type;
 | 
|---|
| 371 | 
 | 
|---|
| 372 |   r_type = ELF32_R_TYPE (dst->r_info);
 | 
|---|
| 373 |   BFD_ASSERT (r_type < (unsigned int) R_M68HC11_max);
 | 
|---|
| 374 |   cache_ptr->howto = &elf_m68hc11_howto_table[r_type];
 | 
|---|
| 375 | }
 | 
|---|
| 376 | 
 | 
|---|
| 377 |  | 
|---|
| 378 | 
 | 
|---|
| 379 | /* Far trampoline generation.  */
 | 
|---|
| 380 | 
 | 
|---|
| 381 | /* Build a 68HC11 trampoline stub.  */
 | 
|---|
| 382 | static bfd_boolean
 | 
|---|
| 383 | m68hc11_elf_build_one_stub (gen_entry, in_arg)
 | 
|---|
| 384 |      struct bfd_hash_entry *gen_entry;
 | 
|---|
| 385 |      PTR in_arg;
 | 
|---|
| 386 | {
 | 
|---|
| 387 |   struct elf32_m68hc11_stub_hash_entry *stub_entry;
 | 
|---|
| 388 |   struct bfd_link_info *info;
 | 
|---|
| 389 |   struct m68hc11_elf_link_hash_table *htab;
 | 
|---|
| 390 |   asection *stub_sec;
 | 
|---|
| 391 |   bfd *stub_bfd;
 | 
|---|
| 392 |   bfd_byte *loc;
 | 
|---|
| 393 |   bfd_vma sym_value, phys_page, phys_addr;
 | 
|---|
| 394 | 
 | 
|---|
| 395 |   /* Massage our args to the form they really have.  */
 | 
|---|
| 396 |   stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
 | 
|---|
| 397 |   info = (struct bfd_link_info *) in_arg;
 | 
|---|
| 398 | 
 | 
|---|
| 399 |   htab = m68hc11_elf_hash_table (info);
 | 
|---|
| 400 | 
 | 
|---|
| 401 |   stub_sec = stub_entry->stub_sec;
 | 
|---|
| 402 | 
 | 
|---|
| 403 |   /* Make a note of the offset within the stubs for this entry.  */
 | 
|---|
| 404 |   stub_entry->stub_offset = stub_sec->_raw_size;
 | 
|---|
| 405 |   stub_sec->_raw_size += 10;
 | 
|---|
| 406 |   loc = stub_sec->contents + stub_entry->stub_offset;
 | 
|---|
| 407 | 
 | 
|---|
| 408 |   stub_bfd = stub_sec->owner;
 | 
|---|
| 409 | 
 | 
|---|
| 410 |   /* Create the trampoline call stub:
 | 
|---|
| 411 | 
 | 
|---|
| 412 |      pshb
 | 
|---|
| 413 |      ldab #%page(symbol)
 | 
|---|
| 414 |      ldy #%addr(symbol)
 | 
|---|
| 415 |      jmp __trampoline
 | 
|---|
| 416 | 
 | 
|---|
| 417 |   */
 | 
|---|
| 418 |   sym_value = (stub_entry->target_value
 | 
|---|
| 419 |                + stub_entry->target_section->output_offset
 | 
|---|
| 420 |                + stub_entry->target_section->output_section->vma);
 | 
|---|
| 421 |   phys_addr = m68hc11_phys_addr (&htab->pinfo, sym_value);
 | 
|---|
| 422 |   phys_page = m68hc11_phys_page (&htab->pinfo, sym_value);
 | 
|---|
| 423 | 
 | 
|---|
| 424 |   /* pshb; ldab #%page(sym) */
 | 
|---|
| 425 |   bfd_put_8 (stub_bfd, 0x37, loc);
 | 
|---|
| 426 |   bfd_put_8 (stub_bfd, 0xC6, loc + 1);
 | 
|---|
| 427 |   bfd_put_8 (stub_bfd, phys_page, loc + 2);
 | 
|---|
| 428 |   loc += 3;
 | 
|---|
| 429 | 
 | 
|---|
| 430 |   /* ldy #%addr(sym)  */
 | 
|---|
| 431 |   bfd_put_8 (stub_bfd, 0x18, loc);
 | 
|---|
| 432 |   bfd_put_8 (stub_bfd, 0xCE, loc + 1);
 | 
|---|
| 433 |   bfd_put_16 (stub_bfd, phys_addr, loc + 2);
 | 
|---|
| 434 |   loc += 4;
 | 
|---|
| 435 | 
 | 
|---|
| 436 |   /* jmp __trampoline  */
 | 
|---|
| 437 |   bfd_put_8 (stub_bfd, 0x7E, loc);
 | 
|---|
| 438 |   bfd_put_16 (stub_bfd, htab->pinfo.trampoline_addr, loc + 1);
 | 
|---|
| 439 | 
 | 
|---|
| 440 |   return TRUE;
 | 
|---|
| 441 | }
 | 
|---|
| 442 | 
 | 
|---|
| 443 | /* As above, but don't actually build the stub.  Just bump offset so
 | 
|---|
| 444 |    we know stub section sizes.  */
 | 
|---|
| 445 | 
 | 
|---|
| 446 | static bfd_boolean
 | 
|---|
| 447 | m68hc11_elf_size_one_stub (gen_entry, in_arg)
 | 
|---|
| 448 |      struct bfd_hash_entry *gen_entry;
 | 
|---|
| 449 |      PTR in_arg ATTRIBUTE_UNUSED;
 | 
|---|
| 450 | {
 | 
|---|
| 451 |   struct elf32_m68hc11_stub_hash_entry *stub_entry;
 | 
|---|
| 452 | 
 | 
|---|
| 453 |   /* Massage our args to the form they really have.  */
 | 
|---|
| 454 |   stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
 | 
|---|
| 455 | 
 | 
|---|
| 456 |   stub_entry->stub_sec->_raw_size += 10;
 | 
|---|
| 457 |   return TRUE;
 | 
|---|
| 458 | }
 | 
|---|
| 459 | 
 | 
|---|
| 460 | /* Create a 68HC11 ELF linker hash table.  */
 | 
|---|
| 461 | 
 | 
|---|
| 462 | static struct bfd_link_hash_table *
 | 
|---|
| 463 | m68hc11_elf_bfd_link_hash_table_create (abfd)
 | 
|---|
| 464 |      bfd *abfd;
 | 
|---|
| 465 | {
 | 
|---|
| 466 |   struct m68hc11_elf_link_hash_table *ret;
 | 
|---|
| 467 | 
 | 
|---|
| 468 |   ret = m68hc11_elf_hash_table_create (abfd);
 | 
|---|
| 469 |   if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
 | 
|---|
| 470 |     return NULL;
 | 
|---|
| 471 | 
 | 
|---|
| 472 |   ret->size_one_stub = m68hc11_elf_size_one_stub;
 | 
|---|
| 473 |   ret->build_one_stub = m68hc11_elf_build_one_stub;
 | 
|---|
| 474 | 
 | 
|---|
| 475 |   return &ret->root.root;
 | 
|---|
| 476 | }
 | 
|---|
| 477 | 
 | 
|---|
| 478 |  | 
|---|
| 479 | 
 | 
|---|
| 480 | /* 68HC11 Linker Relaxation.  */
 | 
|---|
| 481 | 
 | 
|---|
| 482 | struct m68hc11_direct_relax
 | 
|---|
| 483 | {
 | 
|---|
| 484 |   const char *name;
 | 
|---|
| 485 |   unsigned char code;
 | 
|---|
| 486 |   unsigned char direct_code;
 | 
|---|
| 487 | } m68hc11_direct_relax_table[] = {
 | 
|---|
| 488 |   { "adca", 0xB9, 0x99 },
 | 
|---|
| 489 |   { "adcb", 0xF9, 0xD9 },
 | 
|---|
| 490 |   { "adda", 0xBB, 0x9B },
 | 
|---|
| 491 |   { "addb", 0xFB, 0xDB },
 | 
|---|
| 492 |   { "addd", 0xF3, 0xD3 },
 | 
|---|
| 493 |   { "anda", 0xB4, 0x94 },
 | 
|---|
| 494 |   { "andb", 0xF4, 0xD4 },
 | 
|---|
| 495 |   { "cmpa", 0xB1, 0x91 },
 | 
|---|
| 496 |   { "cmpb", 0xF1, 0xD1 },
 | 
|---|
| 497 |   { "cpd",  0xB3, 0x93 },
 | 
|---|
| 498 |   { "cpxy", 0xBC, 0x9C },
 | 
|---|
| 499 | /* { "cpy",  0xBC, 0x9C }, */
 | 
|---|
| 500 |   { "eora", 0xB8, 0x98 },
 | 
|---|
| 501 |   { "eorb", 0xF8, 0xD8 },
 | 
|---|
| 502 |   { "jsr",  0xBD, 0x9D },
 | 
|---|
| 503 |   { "ldaa", 0xB6, 0x96 },
 | 
|---|
| 504 |   { "ldab", 0xF6, 0xD6 },
 | 
|---|
| 505 |   { "ldd",  0xFC, 0xDC },
 | 
|---|
| 506 |   { "lds",  0xBE, 0x9E },
 | 
|---|
| 507 |   { "ldxy", 0xFE, 0xDE },
 | 
|---|
| 508 |   /*  { "ldy",  0xFE, 0xDE },*/
 | 
|---|
| 509 |   { "oraa", 0xBA, 0x9A },
 | 
|---|
| 510 |   { "orab", 0xFA, 0xDA },
 | 
|---|
| 511 |   { "sbca", 0xB2, 0x92 },
 | 
|---|
| 512 |   { "sbcb", 0xF2, 0xD2 },
 | 
|---|
| 513 |   { "staa", 0xB7, 0x97 },
 | 
|---|
| 514 |   { "stab", 0xF7, 0xD7 },
 | 
|---|
| 515 |   { "std",  0xFD, 0xDD },
 | 
|---|
| 516 |   { "sts",  0xBF, 0x9F },
 | 
|---|
| 517 |   { "stxy", 0xFF, 0xDF },
 | 
|---|
| 518 |   /*  { "sty",  0xFF, 0xDF },*/
 | 
|---|
| 519 |   { "suba", 0xB0, 0x90 },
 | 
|---|
| 520 |   { "subb", 0xF0, 0xD0 },
 | 
|---|
| 521 |   { "subd", 0xB3, 0x93 },
 | 
|---|
| 522 |   { 0, 0, 0 }
 | 
|---|
| 523 | };
 | 
|---|
| 524 | 
 | 
|---|
| 525 | static struct m68hc11_direct_relax *
 | 
|---|
| 526 | find_relaxable_insn (unsigned char code)
 | 
|---|
| 527 | {
 | 
|---|
| 528 |   int i;
 | 
|---|
| 529 | 
 | 
|---|
| 530 |   for (i = 0; m68hc11_direct_relax_table[i].name; i++)
 | 
|---|
| 531 |     if (m68hc11_direct_relax_table[i].code == code)
 | 
|---|
| 532 |       return &m68hc11_direct_relax_table[i];
 | 
|---|
| 533 | 
 | 
|---|
| 534 |   return 0;
 | 
|---|
| 535 | }
 | 
|---|
| 536 | 
 | 
|---|
| 537 | static int
 | 
|---|
| 538 | compare_reloc (e1, e2)
 | 
|---|
| 539 |      const void *e1;
 | 
|---|
| 540 |      const void *e2;
 | 
|---|
| 541 | {
 | 
|---|
| 542 |   const Elf_Internal_Rela *i1 = (const Elf_Internal_Rela *) e1;
 | 
|---|
| 543 |   const Elf_Internal_Rela *i2 = (const Elf_Internal_Rela *) e2;
 | 
|---|
| 544 | 
 | 
|---|
| 545 |   if (i1->r_offset == i2->r_offset)
 | 
|---|
| 546 |     return 0;
 | 
|---|
| 547 |   else
 | 
|---|
| 548 |     return i1->r_offset < i2->r_offset ? -1 : 1;
 | 
|---|
| 549 | }
 | 
|---|
| 550 | 
 | 
|---|
| 551 | #define M6811_OP_LDX_IMMEDIATE (0xCE)
 | 
|---|
| 552 | 
 | 
|---|
| 553 | static void
 | 
|---|
| 554 | m68hc11_relax_group (abfd, sec, contents, value, offset, end_group)
 | 
|---|
| 555 |      bfd *abfd;
 | 
|---|
| 556 |      asection *sec;
 | 
|---|
| 557 |      bfd_byte *contents;
 | 
|---|
| 558 |      unsigned value;
 | 
|---|
| 559 |      unsigned long offset;
 | 
|---|
| 560 |      unsigned long end_group;
 | 
|---|
| 561 | {
 | 
|---|
| 562 |   unsigned char code;
 | 
|---|
| 563 |   unsigned long start_offset;
 | 
|---|
| 564 |   unsigned long ldx_offset = offset;
 | 
|---|
| 565 |   unsigned long ldx_size;
 | 
|---|
| 566 |   int can_delete_ldx;
 | 
|---|
| 567 |   int relax_ldy = 0;
 | 
|---|
| 568 | 
 | 
|---|
| 569 |   /* First instruction of the relax group must be a
 | 
|---|
| 570 |      LDX #value or LDY #value.  If this is not the case,
 | 
|---|
| 571 |      ignore the relax group.  */
 | 
|---|
| 572 |   code = bfd_get_8 (abfd, contents + offset);
 | 
|---|
| 573 |   if (code == 0x18)
 | 
|---|
| 574 |     {
 | 
|---|
| 575 |       relax_ldy++;
 | 
|---|
| 576 |       offset++;
 | 
|---|
| 577 |       code = bfd_get_8 (abfd, contents + offset);
 | 
|---|
| 578 |     }
 | 
|---|
| 579 |   ldx_size = offset - ldx_offset + 3;
 | 
|---|
| 580 |   offset += 3;
 | 
|---|
| 581 |   if (code != M6811_OP_LDX_IMMEDIATE || offset >= end_group)
 | 
|---|
| 582 |     return;
 | 
|---|
| 583 | 
 | 
|---|
| 584 | 
 | 
|---|
| 585 |   /* We can remove the LDX/LDY only when all bset/brclr instructions
 | 
|---|
| 586 |      of the relax group have been converted to use direct addressing
 | 
|---|
| 587 |      mode.  */
 | 
|---|
| 588 |   can_delete_ldx = 1;
 | 
|---|
| 589 |   while (offset < end_group)
 | 
|---|
| 590 |     {
 | 
|---|
| 591 |       unsigned isize;
 | 
|---|
| 592 |       unsigned new_value;
 | 
|---|
| 593 |       int bset_use_y;
 | 
|---|
| 594 | 
 | 
|---|
| 595 |       bset_use_y = 0;
 | 
|---|
| 596 |       start_offset = offset;
 | 
|---|
| 597 |       code = bfd_get_8 (abfd, contents + offset);
 | 
|---|
| 598 |       if (code == 0x18)
 | 
|---|
| 599 |         {
 | 
|---|
| 600 |           bset_use_y++;
 | 
|---|
| 601 |           offset++;
 | 
|---|
| 602 |           code = bfd_get_8 (abfd, contents + offset);
 | 
|---|
| 603 |         }
 | 
|---|
| 604 | 
 | 
|---|
| 605 |       /* Check the instruction and translate to use direct addressing mode.  */
 | 
|---|
| 606 |       switch (code)
 | 
|---|
| 607 |         {
 | 
|---|
| 608 |           /* bset */
 | 
|---|
| 609 |         case 0x1C:
 | 
|---|
| 610 |           code = 0x14;
 | 
|---|
| 611 |           isize = 3;
 | 
|---|
| 612 |           break;
 | 
|---|
| 613 | 
 | 
|---|
| 614 |           /* brclr */
 | 
|---|
| 615 |         case 0x1F:
 | 
|---|
| 616 |           code = 0x13;
 | 
|---|
| 617 |           isize = 4;
 | 
|---|
| 618 |           break;
 | 
|---|
| 619 | 
 | 
|---|
| 620 |           /* brset */
 | 
|---|
| 621 |         case 0x1E:
 | 
|---|
| 622 |           code = 0x12;
 | 
|---|
| 623 |           isize = 4;
 | 
|---|
| 624 |           break;
 | 
|---|
| 625 | 
 | 
|---|
| 626 |           /* bclr */
 | 
|---|
| 627 |         case 0x1D:
 | 
|---|
| 628 |           code = 0x15;
 | 
|---|
| 629 |           isize = 3;
 | 
|---|
| 630 |           break;
 | 
|---|
| 631 | 
 | 
|---|
| 632 |           /* This instruction is not recognized and we are not
 | 
|---|
| 633 |              at end of the relax group.  Ignore and don't remove
 | 
|---|
| 634 |              the first LDX (we don't know what it is used for...).  */
 | 
|---|
| 635 |         default:
 | 
|---|
| 636 |           return;
 | 
|---|
| 637 |         }
 | 
|---|
| 638 |       new_value = (unsigned) bfd_get_8 (abfd, contents + offset + 1);
 | 
|---|
| 639 |       new_value += value;
 | 
|---|
| 640 |       if ((new_value & 0xff00) == 0 && bset_use_y == relax_ldy)
 | 
|---|
| 641 |         {
 | 
|---|
| 642 |           bfd_put_8 (abfd, code, contents + offset);
 | 
|---|
| 643 |           bfd_put_8 (abfd, new_value, contents + offset + 1);
 | 
|---|
| 644 |           if (start_offset != offset)
 | 
|---|
| 645 |             {
 | 
|---|
| 646 |               m68hc11_elf_relax_delete_bytes (abfd, sec, start_offset,
 | 
|---|
| 647 |                                               offset - start_offset);
 | 
|---|
| 648 |               end_group--;
 | 
|---|
| 649 |             }
 | 
|---|
| 650 |         }
 | 
|---|
| 651 |       else
 | 
|---|
| 652 |         {
 | 
|---|
| 653 |           can_delete_ldx = 0;
 | 
|---|
| 654 |         }
 | 
|---|
| 655 |       offset = start_offset + isize;
 | 
|---|
| 656 |     }
 | 
|---|
| 657 |   if (can_delete_ldx)
 | 
|---|
| 658 |     {
 | 
|---|
| 659 |       /* Remove the move instruction (3 or 4 bytes win).  */
 | 
|---|
| 660 |       m68hc11_elf_relax_delete_bytes (abfd, sec, ldx_offset, ldx_size);
 | 
|---|
| 661 |     }
 | 
|---|
| 662 | }
 | 
|---|
| 663 | 
 | 
|---|
| 664 | /* This function handles relaxing for the 68HC11.
 | 
|---|
| 665 | 
 | 
|---|
| 666 | 
 | 
|---|
| 667 |         and somewhat more difficult to support.  */
 | 
|---|
| 668 | 
 | 
|---|
| 669 | static bfd_boolean
 | 
|---|
| 670 | m68hc11_elf_relax_section (abfd, sec, link_info, again)
 | 
|---|
| 671 |      bfd *abfd;
 | 
|---|
| 672 |      asection *sec;
 | 
|---|
| 673 |      struct bfd_link_info *link_info;
 | 
|---|
| 674 |      bfd_boolean *again;
 | 
|---|
| 675 | {
 | 
|---|
| 676 |   Elf_Internal_Shdr *symtab_hdr;
 | 
|---|
| 677 |   Elf_Internal_Shdr *shndx_hdr;
 | 
|---|
| 678 |   Elf_Internal_Rela *internal_relocs;
 | 
|---|
| 679 |   Elf_Internal_Rela *free_relocs = NULL;
 | 
|---|
| 680 |   Elf_Internal_Rela *irel, *irelend;
 | 
|---|
| 681 |   bfd_byte *contents = NULL;
 | 
|---|
| 682 |   bfd_byte *free_contents = NULL;
 | 
|---|
| 683 |   Elf32_External_Sym *free_extsyms = NULL;
 | 
|---|
| 684 |   Elf_Internal_Rela *prev_insn_branch = NULL;
 | 
|---|
| 685 |   Elf_Internal_Rela *prev_insn_group = NULL;
 | 
|---|
| 686 |   unsigned insn_group_value = 0;
 | 
|---|
| 687 |   Elf_Internal_Sym *isymbuf = NULL;
 | 
|---|
| 688 | 
 | 
|---|
| 689 |   /* Assume nothing changes.  */
 | 
|---|
| 690 |   *again = FALSE;
 | 
|---|
| 691 | 
 | 
|---|
| 692 |   /* We don't have to do anything for a relocateable link, if
 | 
|---|
| 693 |      this section does not have relocs, or if this is not a
 | 
|---|
| 694 |      code section.  */
 | 
|---|
| 695 |   if (link_info->relocateable
 | 
|---|
| 696 |       || (sec->flags & SEC_RELOC) == 0
 | 
|---|
| 697 |       || sec->reloc_count == 0
 | 
|---|
| 698 |       || (sec->flags & SEC_CODE) == 0)
 | 
|---|
| 699 |     return TRUE;
 | 
|---|
| 700 | 
 | 
|---|
| 701 |   /* If this is the first time we have been called for this section,
 | 
|---|
| 702 |      initialize the cooked size.  */
 | 
|---|
| 703 |   if (sec->_cooked_size == 0)
 | 
|---|
| 704 |     sec->_cooked_size = sec->_raw_size;
 | 
|---|
| 705 | 
 | 
|---|
| 706 |   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
 | 
|---|
| 707 |   shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
 | 
|---|
| 708 | 
 | 
|---|
| 709 |   /* Get a copy of the native relocations.  */
 | 
|---|
| 710 |   internal_relocs = (_bfd_elf32_link_read_relocs
 | 
|---|
| 711 |                      (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
 | 
|---|
| 712 |                       link_info->keep_memory));
 | 
|---|
| 713 |   if (internal_relocs == NULL)
 | 
|---|
| 714 |     goto error_return;
 | 
|---|
| 715 |   if (! link_info->keep_memory)
 | 
|---|
| 716 |     free_relocs = internal_relocs;
 | 
|---|
| 717 | 
 | 
|---|
| 718 |   /* Checking for branch relaxation relies on the relocations to
 | 
|---|
| 719 |      be sorted on 'r_offset'.  This is not guaranteed so we must sort.  */
 | 
|---|
| 720 |   qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela),
 | 
|---|
| 721 |          compare_reloc);
 | 
|---|
| 722 | 
 | 
|---|
| 723 |   /* Walk through them looking for relaxing opportunities.  */
 | 
|---|
| 724 |   irelend = internal_relocs + sec->reloc_count;
 | 
|---|
| 725 |   for (irel = internal_relocs; irel < irelend; irel++)
 | 
|---|
| 726 |     {
 | 
|---|
| 727 |       bfd_vma symval;
 | 
|---|
| 728 |       bfd_vma value;
 | 
|---|
| 729 |       Elf_Internal_Sym *isym;
 | 
|---|
| 730 |       asection *sym_sec;
 | 
|---|
| 731 |       int is_far = 0;
 | 
|---|
| 732 | 
 | 
|---|
| 733 |       /* If this isn't something that can be relaxed, then ignore
 | 
|---|
| 734 |          this reloc.  */
 | 
|---|
| 735 |       if (ELF32_R_TYPE (irel->r_info) != (int) R_M68HC11_16
 | 
|---|
| 736 |           && ELF32_R_TYPE (irel->r_info) != (int) R_M68HC11_RL_JUMP
 | 
|---|
| 737 |           && ELF32_R_TYPE (irel->r_info) != (int) R_M68HC11_RL_GROUP)
 | 
|---|
| 738 |         {
 | 
|---|
| 739 |           prev_insn_branch = 0;
 | 
|---|
| 740 |           prev_insn_group = 0;
 | 
|---|
| 741 |           continue;
 | 
|---|
| 742 |         }
 | 
|---|
| 743 | 
 | 
|---|
| 744 |       /* Get the section contents if we haven't done so already.  */
 | 
|---|
| 745 |       if (contents == NULL)
 | 
|---|
| 746 |         {
 | 
|---|
| 747 |           /* Get cached copy if it exists.  */
 | 
|---|
| 748 |           if (elf_section_data (sec)->this_hdr.contents != NULL)
 | 
|---|
| 749 |             contents = elf_section_data (sec)->this_hdr.contents;
 | 
|---|
| 750 |           else
 | 
|---|
| 751 |             {
 | 
|---|
| 752 |               /* Go get them off disk.  */
 | 
|---|
| 753 |               contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
 | 
|---|
| 754 |               if (contents == NULL)
 | 
|---|
| 755 |                 goto error_return;
 | 
|---|
| 756 |               free_contents = contents;
 | 
|---|
| 757 | 
 | 
|---|
| 758 |               if (! bfd_get_section_contents (abfd, sec, contents,
 | 
|---|
| 759 |                                               (file_ptr) 0, sec->_raw_size))
 | 
|---|
| 760 |                 goto error_return;
 | 
|---|
| 761 |             }
 | 
|---|
| 762 |         }
 | 
|---|
| 763 | 
 | 
|---|
| 764 |       /* Try to eliminate an unconditional 8 bit pc-relative branch
 | 
|---|
| 765 |          which immediately follows a conditional 8 bit pc-relative
 | 
|---|
| 766 |          branch around the unconditional branch.
 | 
|---|
| 767 | 
 | 
|---|
| 768 |             original:           new:
 | 
|---|
| 769 |             bCC lab1            bCC' lab2
 | 
|---|
| 770 |             bra lab2
 | 
|---|
| 771 |            lab1:               lab1:
 | 
|---|
| 772 | 
 | 
|---|
| 773 |          This happens when the bCC can't reach lab2 at assembly time,
 | 
|---|
| 774 |          but due to other relaxations it can reach at link time.  */
 | 
|---|
| 775 |       if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_RL_JUMP)
 | 
|---|
| 776 |         {
 | 
|---|
| 777 |           Elf_Internal_Rela *nrel;
 | 
|---|
| 778 |           unsigned char code;
 | 
|---|
| 779 |           unsigned char roffset;
 | 
|---|
| 780 | 
 | 
|---|
| 781 |           prev_insn_branch = 0;
 | 
|---|
| 782 |           prev_insn_group = 0;
 | 
|---|
| 783 | 
 | 
|---|
| 784 |           /* Do nothing if this reloc is the last byte in the section.  */
 | 
|---|
| 785 |           if (irel->r_offset + 2 >= sec->_cooked_size)
 | 
|---|
| 786 |             continue;
 | 
|---|
| 787 | 
 | 
|---|
| 788 |           /* See if the next instruction is an unconditional pc-relative
 | 
|---|
| 789 |              branch, more often than not this test will fail, so we
 | 
|---|
| 790 |              test it first to speed things up.  */
 | 
|---|
| 791 |           code = bfd_get_8 (abfd, contents + irel->r_offset + 2);
 | 
|---|
| 792 |           if (code != 0x7e)
 | 
|---|
| 793 |             continue;
 | 
|---|
| 794 | 
 | 
|---|
| 795 |           /* Also make sure the next relocation applies to the next
 | 
|---|
| 796 |              instruction and that it's a pc-relative 8 bit branch.  */
 | 
|---|
| 797 |           nrel = irel + 1;
 | 
|---|
| 798 |           if (nrel == irelend
 | 
|---|
| 799 |               || irel->r_offset + 3 != nrel->r_offset
 | 
|---|
| 800 |               || ELF32_R_TYPE (nrel->r_info) != (int) R_M68HC11_16)
 | 
|---|
| 801 |             continue;
 | 
|---|
| 802 | 
 | 
|---|
| 803 |           /* Make sure our destination immediately follows the
 | 
|---|
| 804 |              unconditional branch.  */
 | 
|---|
| 805 |           roffset = bfd_get_8 (abfd, contents + irel->r_offset + 1);
 | 
|---|
| 806 |           if (roffset != 3)
 | 
|---|
| 807 |             continue;
 | 
|---|
| 808 | 
 | 
|---|
| 809 |           prev_insn_branch = irel;
 | 
|---|
| 810 |           prev_insn_group = 0;
 | 
|---|
| 811 |           continue;
 | 
|---|
| 812 |         }
 | 
|---|
| 813 | 
 | 
|---|
| 814 |       /* Read this BFD's symbols if we haven't done so already.  */
 | 
|---|
| 815 |       if (isymbuf == NULL && symtab_hdr->sh_info != 0)
 | 
|---|
| 816 |         {
 | 
|---|
| 817 |           isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
 | 
|---|
| 818 |           if (isymbuf == NULL)
 | 
|---|
| 819 |             isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
 | 
|---|
| 820 |                                             symtab_hdr->sh_info, 0,
 | 
|---|
| 821 |                                             NULL, NULL, NULL);
 | 
|---|
| 822 |           if (isymbuf == NULL)
 | 
|---|
| 823 |             goto error_return;
 | 
|---|
| 824 |         }
 | 
|---|
| 825 | 
 | 
|---|
| 826 |       /* Get the value of the symbol referred to by the reloc.  */
 | 
|---|
| 827 |       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
 | 
|---|
| 828 |         {
 | 
|---|
| 829 |           /* A local symbol.  */
 | 
|---|
| 830 |           isym = isymbuf + ELF32_R_SYM (irel->r_info);
 | 
|---|
| 831 |           is_far = isym->st_other & STO_M68HC12_FAR;
 | 
|---|
| 832 |           sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
 | 
|---|
| 833 |           symval = (isym->st_value
 | 
|---|
| 834 |                     + sym_sec->output_section->vma
 | 
|---|
| 835 |                     + sym_sec->output_offset);
 | 
|---|
| 836 |         }
 | 
|---|
| 837 |       else
 | 
|---|
| 838 |         {
 | 
|---|
| 839 |           unsigned long indx;
 | 
|---|
| 840 |           struct elf_link_hash_entry *h;
 | 
|---|
| 841 | 
 | 
|---|
| 842 |           /* An external symbol.  */
 | 
|---|
| 843 |           indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
 | 
|---|
| 844 |           h = elf_sym_hashes (abfd)[indx];
 | 
|---|
| 845 |           BFD_ASSERT (h != NULL);
 | 
|---|
| 846 |           if (h->root.type != bfd_link_hash_defined
 | 
|---|
| 847 |               && h->root.type != bfd_link_hash_defweak)
 | 
|---|
| 848 |             {
 | 
|---|
| 849 |               /* This appears to be a reference to an undefined
 | 
|---|
| 850 |                  symbol.  Just ignore it--it will be caught by the
 | 
|---|
| 851 |                  regular reloc processing.  */
 | 
|---|
| 852 |               prev_insn_branch = 0;
 | 
|---|
| 853 |               prev_insn_group = 0;
 | 
|---|
| 854 |               continue;
 | 
|---|
| 855 |             }
 | 
|---|
| 856 | 
 | 
|---|
| 857 |           is_far = h->other & STO_M68HC12_FAR;
 | 
|---|
| 858 |           isym = 0;
 | 
|---|
| 859 |           sym_sec = h->root.u.def.section;
 | 
|---|
| 860 |           symval = (h->root.u.def.value
 | 
|---|
| 861 |                     + sym_sec->output_section->vma
 | 
|---|
| 862 |                     + sym_sec->output_offset);
 | 
|---|
| 863 |         }
 | 
|---|
| 864 | 
 | 
|---|
| 865 |       if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_RL_GROUP)
 | 
|---|
| 866 |         {
 | 
|---|
| 867 |           prev_insn_branch = 0;
 | 
|---|
| 868 |           prev_insn_group = 0;
 | 
|---|
| 869 | 
 | 
|---|
| 870 |           /* Do nothing if this reloc is the last byte in the section.  */
 | 
|---|
| 871 |           if (irel->r_offset == sec->_cooked_size)
 | 
|---|
| 872 |             continue;
 | 
|---|
| 873 | 
 | 
|---|
| 874 |           prev_insn_group = irel;
 | 
|---|
| 875 |           insn_group_value = isym->st_value;
 | 
|---|
| 876 |           continue;
 | 
|---|
| 877 |         }
 | 
|---|
| 878 | 
 | 
|---|
| 879 |       /* When we relax some bytes, the size of our section changes.
 | 
|---|
| 880 |          This affects the layout of next input sections that go in our
 | 
|---|
| 881 |          output section.  When the symbol is part of another section that
 | 
|---|
| 882 |          will go in the same output section as the current one, it's
 | 
|---|
| 883 |          final address may now be incorrect (too far).  We must let the
 | 
|---|
| 884 |          linker re-compute all section offsets before processing this
 | 
|---|
| 885 |          reloc.  Code example:
 | 
|---|
| 886 | 
 | 
|---|
| 887 |                                 Initial             Final
 | 
|---|
| 888 |          .sect .text            section size = 6    section size = 4
 | 
|---|
| 889 |          jmp foo
 | 
|---|
| 890 |          jmp bar
 | 
|---|
| 891 |          .sect .text.foo_bar    output_offset = 6   output_offset = 4
 | 
|---|
| 892 |          foo: rts
 | 
|---|
| 893 |          bar: rts
 | 
|---|
| 894 | 
 | 
|---|
| 895 |          If we process the reloc now, the jmp bar is replaced by a
 | 
|---|
| 896 |          relative branch to the initial bar address (output_offset 6).  */
 | 
|---|
| 897 |       if (*again && sym_sec != sec
 | 
|---|
| 898 |           && sym_sec->output_section == sec->output_section)
 | 
|---|
| 899 |         {
 | 
|---|
| 900 |           prev_insn_group = 0;
 | 
|---|
| 901 |           prev_insn_branch = 0;
 | 
|---|
| 902 |           continue;
 | 
|---|
| 903 |         }
 | 
|---|
| 904 | 
 | 
|---|
| 905 |       value = symval;
 | 
|---|
| 906 |       /* Try to turn a far branch to a near branch.  */
 | 
|---|
| 907 |       if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_16
 | 
|---|
| 908 |           && prev_insn_branch)
 | 
|---|
| 909 |         {
 | 
|---|
| 910 |           bfd_vma offset;
 | 
|---|
| 911 |           unsigned char code;
 | 
|---|
| 912 | 
 | 
|---|
| 913 |           offset = value - (prev_insn_branch->r_offset
 | 
|---|
| 914 |                             + sec->output_section->vma
 | 
|---|
| 915 |                             + sec->output_offset + 2);
 | 
|---|
| 916 | 
 | 
|---|
| 917 |           /* If the offset is still out of -128..+127 range,
 | 
|---|
| 918 |              leave that far branch unchanged.  */
 | 
|---|
| 919 |           if ((offset & 0xff80) != 0 && (offset & 0xff80) != 0xff80)
 | 
|---|
| 920 |             {
 | 
|---|
| 921 |               prev_insn_branch = 0;
 | 
|---|
| 922 |               continue;
 | 
|---|
| 923 |             }
 | 
|---|
| 924 | 
 | 
|---|
| 925 |           /* Shrink the branch.  */
 | 
|---|
| 926 |           code = bfd_get_8 (abfd, contents + prev_insn_branch->r_offset);
 | 
|---|
| 927 |           if (code == 0x7e)
 | 
|---|
| 928 |             {
 | 
|---|
| 929 |               code = 0x20;
 | 
|---|
| 930 |               bfd_put_8 (abfd, code, contents + prev_insn_branch->r_offset);
 | 
|---|
| 931 |               bfd_put_8 (abfd, 0xff,
 | 
|---|
| 932 |                          contents + prev_insn_branch->r_offset + 1);
 | 
|---|
| 933 |               irel->r_offset = prev_insn_branch->r_offset + 1;
 | 
|---|
| 934 |               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
 | 
|---|
| 935 |                                            R_M68HC11_PCREL_8);
 | 
|---|
| 936 |               m68hc11_elf_relax_delete_bytes (abfd, sec,
 | 
|---|
| 937 |                                               irel->r_offset + 1, 1);
 | 
|---|
| 938 |             }
 | 
|---|
| 939 |           else
 | 
|---|
| 940 |             {
 | 
|---|
| 941 |               code ^= 0x1;
 | 
|---|
| 942 |               bfd_put_8 (abfd, code, contents + prev_insn_branch->r_offset);
 | 
|---|
| 943 |               bfd_put_8 (abfd, 0xff,
 | 
|---|
| 944 |                          contents + prev_insn_branch->r_offset + 1);
 | 
|---|
| 945 |               irel->r_offset = prev_insn_branch->r_offset + 1;
 | 
|---|
| 946 |               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
 | 
|---|
| 947 |                                            R_M68HC11_PCREL_8);
 | 
|---|
| 948 |               m68hc11_elf_relax_delete_bytes (abfd, sec,
 | 
|---|
| 949 |                                               irel->r_offset + 1, 3);
 | 
|---|
| 950 |             }
 | 
|---|
| 951 |           prev_insn_branch = 0;
 | 
|---|
| 952 |           *again = TRUE;
 | 
|---|
| 953 |         }
 | 
|---|
| 954 | 
 | 
|---|
| 955 |       /* Try to turn a 16 bit address into a 8 bit page0 address.  */
 | 
|---|
| 956 |       else if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_16
 | 
|---|
| 957 |                && (value & 0xff00) == 0)
 | 
|---|
| 958 |         {
 | 
|---|
| 959 |           unsigned char code;
 | 
|---|
| 960 |           unsigned short offset;
 | 
|---|
| 961 |           struct m68hc11_direct_relax *rinfo;
 | 
|---|
| 962 | 
 | 
|---|
| 963 |           prev_insn_branch = 0;
 | 
|---|
| 964 |           offset = bfd_get_16 (abfd, contents + irel->r_offset);
 | 
|---|
| 965 |           offset += value;
 | 
|---|
| 966 |           if ((offset & 0xff00) != 0)
 | 
|---|
| 967 |             {
 | 
|---|
| 968 |               prev_insn_group = 0;
 | 
|---|
| 969 |               continue;
 | 
|---|
| 970 |             }
 | 
|---|
| 971 | 
 | 
|---|
| 972 |           if (prev_insn_group)
 | 
|---|
| 973 |             {
 | 
|---|
| 974 |               unsigned long old_sec_size = sec->_cooked_size;
 | 
|---|
| 975 | 
 | 
|---|
| 976 |               /* Note that we've changed the reldection contents, etc.  */
 | 
|---|
| 977 |               elf_section_data (sec)->relocs = internal_relocs;
 | 
|---|
| 978 |               free_relocs = NULL;
 | 
|---|
| 979 | 
 | 
|---|
| 980 |               elf_section_data (sec)->this_hdr.contents = contents;
 | 
|---|
| 981 |               free_contents = NULL;
 | 
|---|
| 982 | 
 | 
|---|
| 983 |               symtab_hdr->contents = (bfd_byte *) isymbuf;
 | 
|---|
| 984 |               free_extsyms = NULL;
 | 
|---|
| 985 | 
 | 
|---|
| 986 |               m68hc11_relax_group (abfd, sec, contents, offset,
 | 
|---|
| 987 |                                    prev_insn_group->r_offset,
 | 
|---|
| 988 |                                    insn_group_value);
 | 
|---|
| 989 |               irel = prev_insn_group;
 | 
|---|
| 990 |               prev_insn_group = 0;
 | 
|---|
| 991 |               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
 | 
|---|
| 992 |                                            R_M68HC11_NONE);
 | 
|---|
| 993 |               if (sec->_cooked_size != old_sec_size)
 | 
|---|
| 994 |                 *again = TRUE;
 | 
|---|
| 995 |               continue;
 | 
|---|
| 996 |             }
 | 
|---|
| 997 | 
 | 
|---|
| 998 |           /* Get the opcode.  */
 | 
|---|
| 999 |           code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
 | 
|---|
| 1000 |           rinfo = find_relaxable_insn (code);
 | 
|---|
| 1001 |           if (rinfo == 0)
 | 
|---|
| 1002 |             {
 | 
|---|
| 1003 |               prev_insn_group = 0;
 | 
|---|
| 1004 |               continue;
 | 
|---|
| 1005 |             }
 | 
|---|
| 1006 | 
 | 
|---|
| 1007 |           /* Note that we've changed the reldection contents, etc.  */
 | 
|---|
| 1008 |           elf_section_data (sec)->relocs = internal_relocs;
 | 
|---|
| 1009 |           free_relocs = NULL;
 | 
|---|
| 1010 | 
 | 
|---|
| 1011 |           elf_section_data (sec)->this_hdr.contents = contents;
 | 
|---|
| 1012 |           free_contents = NULL;
 | 
|---|
| 1013 | 
 | 
|---|
| 1014 |           symtab_hdr->contents = (bfd_byte *) isymbuf;
 | 
|---|
| 1015 |           free_extsyms = NULL;
 | 
|---|
| 1016 | 
 | 
|---|
| 1017 |           /* Fix the opcode.  */
 | 
|---|
| 1018 |           /* printf ("A relaxable case : 0x%02x (%s)\n",
 | 
|---|
| 1019 |              code, rinfo->name); */
 | 
|---|
| 1020 |           bfd_put_8 (abfd, rinfo->direct_code,
 | 
|---|
| 1021 |                      contents + irel->r_offset - 1);
 | 
|---|
| 1022 | 
 | 
|---|
| 1023 |           /* Delete one byte of data (upper byte of address).  */
 | 
|---|
| 1024 |           m68hc11_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 1);
 | 
|---|
| 1025 | 
 | 
|---|
| 1026 |           /* Fix the relocation's type.  */
 | 
|---|
| 1027 |           irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
 | 
|---|
| 1028 |                                        R_M68HC11_8);
 | 
|---|
| 1029 | 
 | 
|---|
| 1030 |           /* That will change things, so, we should relax again.  */
 | 
|---|
| 1031 |           *again = TRUE;
 | 
|---|
| 1032 |         }
 | 
|---|
| 1033 |       else if (ELF32_R_TYPE (irel->r_info) == R_M68HC11_16 && !is_far)
 | 
|---|
| 1034 |         {
 | 
|---|
| 1035 |           unsigned char code;
 | 
|---|
| 1036 |           bfd_vma offset;
 | 
|---|
| 1037 | 
 | 
|---|
| 1038 |           prev_insn_branch = 0;
 | 
|---|
| 1039 |           code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
 | 
|---|
| 1040 |           if (code == 0x7e || code == 0xbd)
 | 
|---|
| 1041 |             {
 | 
|---|
| 1042 |               offset = value - (irel->r_offset
 | 
|---|
| 1043 |                                 + sec->output_section->vma
 | 
|---|
| 1044 |                                 + sec->output_offset + 1);
 | 
|---|
| 1045 |               offset += bfd_get_16 (abfd, contents + irel->r_offset);
 | 
|---|
| 1046 | 
 | 
|---|
| 1047 |               /* If the offset is still out of -128..+127 range,
 | 
|---|
| 1048 |                  leave that far branch unchanged.  */
 | 
|---|
| 1049 |               if ((offset & 0xff80) == 0 || (offset & 0xff80) == 0xff80)
 | 
|---|
| 1050 |                 {
 | 
|---|
| 1051 | 
 | 
|---|
| 1052 |                   /* Note that we've changed the reldection contents, etc.  */
 | 
|---|
| 1053 |                   elf_section_data (sec)->relocs = internal_relocs;
 | 
|---|
| 1054 |                   free_relocs = NULL;
 | 
|---|
| 1055 | 
 | 
|---|
| 1056 |                   elf_section_data (sec)->this_hdr.contents = contents;
 | 
|---|
| 1057 |                   free_contents = NULL;
 | 
|---|
| 1058 | 
 | 
|---|
| 1059 |                   symtab_hdr->contents = (bfd_byte *) isymbuf;
 | 
|---|
| 1060 |                   free_extsyms = NULL;
 | 
|---|
| 1061 | 
 | 
|---|
| 1062 |                   /* Shrink the branch.  */
 | 
|---|
| 1063 |                   code = (code == 0x7e) ? 0x20 : 0x8d;
 | 
|---|
| 1064 |                   bfd_put_8 (abfd, code,
 | 
|---|
| 1065 |                              contents + irel->r_offset - 1);
 | 
|---|
| 1066 |                   bfd_put_8 (abfd, 0xff,
 | 
|---|
| 1067 |                              contents + irel->r_offset);
 | 
|---|
| 1068 |                   irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
 | 
|---|
| 1069 |                                                R_M68HC11_PCREL_8);
 | 
|---|
| 1070 |                   m68hc11_elf_relax_delete_bytes (abfd, sec,
 | 
|---|
| 1071 |                                                   irel->r_offset + 1, 1);
 | 
|---|
| 1072 |                   /* That will change things, so, we should relax again.  */
 | 
|---|
| 1073 |                   *again = TRUE;
 | 
|---|
| 1074 |                 }
 | 
|---|
| 1075 |             }
 | 
|---|
| 1076 |         }
 | 
|---|
| 1077 |       prev_insn_branch = 0;
 | 
|---|
| 1078 |       prev_insn_group = 0;
 | 
|---|
| 1079 |     }
 | 
|---|
| 1080 | 
 | 
|---|
| 1081 |   if (free_relocs != NULL)
 | 
|---|
| 1082 |     {
 | 
|---|
| 1083 |       free (free_relocs);
 | 
|---|
| 1084 |       free_relocs = NULL;
 | 
|---|
| 1085 |     }
 | 
|---|
| 1086 | 
 | 
|---|
| 1087 |   if (free_contents != NULL)
 | 
|---|
| 1088 |     {
 | 
|---|
| 1089 |       if (! link_info->keep_memory)
 | 
|---|
| 1090 |         free (free_contents);
 | 
|---|
| 1091 |       else
 | 
|---|
| 1092 |         {
 | 
|---|
| 1093 |           /* Cache the section contents for elf_link_input_bfd.  */
 | 
|---|
| 1094 |           elf_section_data (sec)->this_hdr.contents = contents;
 | 
|---|
| 1095 |         }
 | 
|---|
| 1096 |       free_contents = NULL;
 | 
|---|
| 1097 |     }
 | 
|---|
| 1098 | 
 | 
|---|
| 1099 |   if (free_extsyms != NULL)
 | 
|---|
| 1100 |     {
 | 
|---|
| 1101 |       if (! link_info->keep_memory)
 | 
|---|
| 1102 |         free (free_extsyms);
 | 
|---|
| 1103 |       else
 | 
|---|
| 1104 |         {
 | 
|---|
| 1105 |           /* Cache the symbols for elf_link_input_bfd.  */
 | 
|---|
| 1106 |           symtab_hdr->contents = (unsigned char *) isymbuf;
 | 
|---|
| 1107 |         }
 | 
|---|
| 1108 |       free_extsyms = NULL;
 | 
|---|
| 1109 |     }
 | 
|---|
| 1110 | 
 | 
|---|
| 1111 |   return TRUE;
 | 
|---|
| 1112 | 
 | 
|---|
| 1113 |  error_return:
 | 
|---|
| 1114 |   if (free_relocs != NULL)
 | 
|---|
| 1115 |     free (free_relocs);
 | 
|---|
| 1116 |   if (free_contents != NULL)
 | 
|---|
| 1117 |     free (free_contents);
 | 
|---|
| 1118 |   if (free_extsyms != NULL)
 | 
|---|
| 1119 |     free (free_extsyms);
 | 
|---|
| 1120 |   return FALSE;
 | 
|---|
| 1121 | }
 | 
|---|
| 1122 | 
 | 
|---|
| 1123 | /* Delete some bytes from a section while relaxing.  */
 | 
|---|
| 1124 | 
 | 
|---|
| 1125 | static void
 | 
|---|
| 1126 | m68hc11_elf_relax_delete_bytes (abfd, sec, addr, count)
 | 
|---|
| 1127 |      bfd *abfd;
 | 
|---|
| 1128 |      asection *sec;
 | 
|---|
| 1129 |      bfd_vma addr;
 | 
|---|
| 1130 |      int count;
 | 
|---|
| 1131 | {
 | 
|---|
| 1132 |   Elf_Internal_Shdr *symtab_hdr;
 | 
|---|
| 1133 |   unsigned int sec_shndx;
 | 
|---|
| 1134 |   bfd_byte *contents;
 | 
|---|
| 1135 |   Elf_Internal_Rela *irel, *irelend;
 | 
|---|
| 1136 |   bfd_vma toaddr;
 | 
|---|
| 1137 |   Elf_Internal_Sym *isymbuf, *isym, *isymend;
 | 
|---|
| 1138 |   struct elf_link_hash_entry **sym_hashes;
 | 
|---|
| 1139 |   struct elf_link_hash_entry **end_hashes;
 | 
|---|
| 1140 |   unsigned int symcount;
 | 
|---|
| 1141 | 
 | 
|---|
| 1142 |   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
 | 
|---|
| 1143 |   isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
 | 
|---|
| 1144 | 
 | 
|---|
| 1145 |   sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
 | 
|---|
| 1146 | 
 | 
|---|
| 1147 |   contents = elf_section_data (sec)->this_hdr.contents;
 | 
|---|
| 1148 | 
 | 
|---|
| 1149 |   toaddr = sec->_cooked_size;
 | 
|---|
| 1150 | 
 | 
|---|
| 1151 |   irel = elf_section_data (sec)->relocs;
 | 
|---|
| 1152 |   irelend = irel + sec->reloc_count;
 | 
|---|
| 1153 | 
 | 
|---|
| 1154 |   /* Actually delete the bytes.  */
 | 
|---|
| 1155 |   memmove (contents + addr, contents + addr + count,
 | 
|---|
| 1156 |            (size_t) (toaddr - addr - count));
 | 
|---|
| 1157 | 
 | 
|---|
| 1158 |   sec->_cooked_size -= count;
 | 
|---|
| 1159 | 
 | 
|---|
| 1160 |   /* Adjust all the relocs.  */
 | 
|---|
| 1161 |   for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
 | 
|---|
| 1162 |     {
 | 
|---|
| 1163 |       unsigned char code;
 | 
|---|
| 1164 |       unsigned char offset;
 | 
|---|
| 1165 |       unsigned short raddr;
 | 
|---|
| 1166 |       unsigned long old_offset;
 | 
|---|
| 1167 |       int branch_pos;
 | 
|---|
| 1168 | 
 | 
|---|
| 1169 |       old_offset = irel->r_offset;
 | 
|---|
| 1170 | 
 | 
|---|
| 1171 |       /* See if this reloc was for the bytes we have deleted, in which
 | 
|---|
| 1172 |          case we no longer care about it.  Don't delete relocs which
 | 
|---|
| 1173 |          represent addresses, though.  */
 | 
|---|
| 1174 |       if (ELF32_R_TYPE (irel->r_info) != R_M68HC11_RL_JUMP
 | 
|---|
| 1175 |           && irel->r_offset >= addr && irel->r_offset < addr + count)
 | 
|---|
| 1176 |         irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
 | 
|---|
| 1177 |                                      R_M68HC11_NONE);
 | 
|---|
| 1178 | 
 | 
|---|
| 1179 |       if (ELF32_R_TYPE (irel->r_info) == R_M68HC11_NONE)
 | 
|---|
| 1180 |         continue;
 | 
|---|
| 1181 | 
 | 
|---|
| 1182 |       /* Get the new reloc address.  */
 | 
|---|
| 1183 |       if ((irel->r_offset > addr
 | 
|---|
| 1184 |            && irel->r_offset < toaddr))
 | 
|---|
| 1185 |         irel->r_offset -= count;
 | 
|---|
| 1186 | 
 | 
|---|
| 1187 |       /* If this is a PC relative reloc, see if the range it covers
 | 
|---|
| 1188 |          includes the bytes we have deleted.  */
 | 
|---|
| 1189 |       switch (ELF32_R_TYPE (irel->r_info))
 | 
|---|
| 1190 |         {
 | 
|---|
| 1191 |         default:
 | 
|---|
| 1192 |           break;
 | 
|---|
| 1193 | 
 | 
|---|
| 1194 |         case R_M68HC11_RL_JUMP:
 | 
|---|
| 1195 |           code = bfd_get_8 (abfd, contents + irel->r_offset);
 | 
|---|
| 1196 |           switch (code)
 | 
|---|
| 1197 |             {
 | 
|---|
| 1198 |               /* jsr and jmp instruction are also marked with RL_JUMP
 | 
|---|
| 1199 |                  relocs but no adjustment must be made.  */
 | 
|---|
| 1200 |             case 0x7e:
 | 
|---|
| 1201 |             case 0x9d:
 | 
|---|
| 1202 |             case 0xbd:
 | 
|---|
| 1203 |               continue;
 | 
|---|
| 1204 | 
 | 
|---|
| 1205 |             case 0x12:
 | 
|---|
| 1206 |             case 0x13:
 | 
|---|
| 1207 |               branch_pos = 3;
 | 
|---|
| 1208 |               raddr = 4;
 | 
|---|
| 1209 | 
 | 
|---|
| 1210 |               /* Special case when we translate a brclr N,y into brclr *<addr>
 | 
|---|
| 1211 |                  In this case, the 0x18 page2 prefix is removed.
 | 
|---|
| 1212 |                  The reloc offset is not modified but the instruction
 | 
|---|
| 1213 |                  size is reduced by 1.  */
 | 
|---|
| 1214 |               if (old_offset == addr)
 | 
|---|
| 1215 |                 raddr++;
 | 
|---|
| 1216 |               break;
 | 
|---|
| 1217 | 
 | 
|---|
| 1218 |             case 0x1e:
 | 
|---|
| 1219 |             case 0x1f:
 | 
|---|
| 1220 |               branch_pos = 3;
 | 
|---|
| 1221 |               raddr = 4;
 | 
|---|
| 1222 |               break;
 | 
|---|
| 1223 | 
 | 
|---|
| 1224 |             case 0x18:
 | 
|---|
| 1225 |               branch_pos = 4;
 | 
|---|
| 1226 |               raddr = 5;
 | 
|---|
| 1227 |               break;
 | 
|---|
| 1228 | 
 | 
|---|
| 1229 |             default:
 | 
|---|
| 1230 |               branch_pos = 1;
 | 
|---|
| 1231 |               raddr = 2;
 | 
|---|
| 1232 |               break;
 | 
|---|
| 1233 |             }
 | 
|---|
| 1234 |           offset = bfd_get_8 (abfd, contents + irel->r_offset + branch_pos);
 | 
|---|
| 1235 |           raddr += old_offset;
 | 
|---|
| 1236 |           raddr += ((unsigned short) offset | ((offset & 0x80) ? 0xff00 : 0));
 | 
|---|
| 1237 |           if (irel->r_offset < addr && raddr > addr)
 | 
|---|
| 1238 |             {
 | 
|---|
| 1239 |               offset -= count;
 | 
|---|
| 1240 |               bfd_put_8 (abfd, offset, contents + irel->r_offset + branch_pos);
 | 
|---|
| 1241 |             }
 | 
|---|
| 1242 |           else if (irel->r_offset >= addr && raddr <= addr)
 | 
|---|
| 1243 |             {
 | 
|---|
| 1244 |               offset += count;
 | 
|---|
| 1245 |               bfd_put_8 (abfd, offset, contents + irel->r_offset + branch_pos);
 | 
|---|
| 1246 |             }
 | 
|---|
| 1247 |           else
 | 
|---|
| 1248 |             {
 | 
|---|
| 1249 |               /*printf ("Not adjusted 0x%04x [0x%4x 0x%4x]\n", raddr,
 | 
|---|
| 1250 |                 irel->r_offset, addr);*/
 | 
|---|
| 1251 |             }
 | 
|---|
| 1252 | 
 | 
|---|
| 1253 |           break;
 | 
|---|
| 1254 |         }
 | 
|---|
| 1255 |     }
 | 
|---|
| 1256 | 
 | 
|---|
| 1257 |   /* Adjust the local symbols defined in this section.  */
 | 
|---|
| 1258 |   isymend = isymbuf + symtab_hdr->sh_info;
 | 
|---|
| 1259 |   for (isym = isymbuf; isym < isymend; isym++)
 | 
|---|
| 1260 |     {
 | 
|---|
| 1261 |       if (isym->st_shndx == sec_shndx
 | 
|---|
| 1262 |           && isym->st_value > addr
 | 
|---|
| 1263 |           && isym->st_value <= toaddr)
 | 
|---|
| 1264 |         isym->st_value -= count;
 | 
|---|
| 1265 |     }
 | 
|---|
| 1266 | 
 | 
|---|
| 1267 |   /* Now adjust the global symbols defined in this section.  */
 | 
|---|
| 1268 |   symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
 | 
|---|
| 1269 |               - symtab_hdr->sh_info);
 | 
|---|
| 1270 |   sym_hashes = elf_sym_hashes (abfd);
 | 
|---|
| 1271 |   end_hashes = sym_hashes + symcount;
 | 
|---|
| 1272 |   for (; sym_hashes < end_hashes; sym_hashes++)
 | 
|---|
| 1273 |     {
 | 
|---|
| 1274 |       struct elf_link_hash_entry *sym_hash = *sym_hashes;
 | 
|---|
| 1275 |       if ((sym_hash->root.type == bfd_link_hash_defined
 | 
|---|
| 1276 |            || sym_hash->root.type == bfd_link_hash_defweak)
 | 
|---|
| 1277 |           && sym_hash->root.u.def.section == sec
 | 
|---|
| 1278 |           && sym_hash->root.u.def.value > addr
 | 
|---|
| 1279 |           && sym_hash->root.u.def.value <= toaddr)
 | 
|---|
| 1280 |         {
 | 
|---|
| 1281 |           sym_hash->root.u.def.value -= count;
 | 
|---|
| 1282 |         }
 | 
|---|
| 1283 |     }
 | 
|---|
| 1284 | }
 | 
|---|
| 1285 | 
 | 
|---|
| 1286 |  | 
|---|
| 1287 | 
 | 
|---|
| 1288 | #define ELF_ARCH                bfd_arch_m68hc11
 | 
|---|
| 1289 | #define ELF_MACHINE_CODE        EM_68HC11
 | 
|---|
| 1290 | #define ELF_MAXPAGESIZE         0x1000
 | 
|---|
| 1291 | 
 | 
|---|
| 1292 | #define TARGET_BIG_SYM          bfd_elf32_m68hc11_vec
 | 
|---|
| 1293 | #define TARGET_BIG_NAME         "elf32-m68hc11"
 | 
|---|
| 1294 | 
 | 
|---|
| 1295 | #define elf_info_to_howto       0
 | 
|---|
| 1296 | #define elf_info_to_howto_rel   m68hc11_info_to_howto_rel
 | 
|---|
| 1297 | #define bfd_elf32_bfd_relax_section  m68hc11_elf_relax_section
 | 
|---|
| 1298 | #define elf_backend_gc_mark_hook     elf32_m68hc11_gc_mark_hook
 | 
|---|
| 1299 | #define elf_backend_gc_sweep_hook    elf32_m68hc11_gc_sweep_hook
 | 
|---|
| 1300 | #define elf_backend_check_relocs     elf32_m68hc11_check_relocs
 | 
|---|
| 1301 | #define elf_backend_relocate_section elf32_m68hc11_relocate_section
 | 
|---|
| 1302 | #define elf_backend_add_symbol_hook  elf32_m68hc11_add_symbol_hook
 | 
|---|
| 1303 | #define elf_backend_object_p    0
 | 
|---|
| 1304 | #define elf_backend_final_write_processing      0
 | 
|---|
| 1305 | #define elf_backend_can_gc_sections             1
 | 
|---|
| 1306 | 
 | 
|---|
| 1307 | #define bfd_elf32_bfd_link_hash_table_create \
 | 
|---|
| 1308 |                                 m68hc11_elf_bfd_link_hash_table_create
 | 
|---|
| 1309 | #define bfd_elf32_bfd_link_hash_table_free \
 | 
|---|
| 1310 |                                 m68hc11_elf_bfd_link_hash_table_free
 | 
|---|
| 1311 | #define bfd_elf32_bfd_merge_private_bfd_data \
 | 
|---|
| 1312 |                                         _bfd_m68hc11_elf_merge_private_bfd_data
 | 
|---|
| 1313 | #define bfd_elf32_bfd_set_private_flags _bfd_m68hc11_elf_set_private_flags
 | 
|---|
| 1314 | #define bfd_elf32_bfd_print_private_bfd_data \
 | 
|---|
| 1315 |                                         _bfd_m68hc11_elf_print_private_bfd_data
 | 
|---|
| 1316 | 
 | 
|---|
| 1317 | #include "elf32-target.h"
 | 
|---|