| 1 |
/* 32-bit ELF support for ARM |
/* 32-bit ELF support for ARM |
| 2 |
Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, |
Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, |
| 3 |
2008 Free Software Foundation, Inc. |
2008, 2009 Free Software Foundation, Inc. |
| 4 |
|
|
| 5 |
This file is part of BFD, the Binary File Descriptor library. |
This file is part of BFD, the Binary File Descriptor library. |
| 6 |
|
|
| 20 |
MA 02110-1301, USA. */ |
MA 02110-1301, USA. */ |
| 21 |
|
|
| 22 |
#include "sysdep.h" |
#include "sysdep.h" |
| 23 |
|
#include <limits.h> |
| 24 |
|
|
| 25 |
#include "bfd.h" |
#include "bfd.h" |
| 26 |
#include "libiberty.h" |
#include "libiberty.h" |
| 27 |
#include "libbfd.h" |
#include "libbfd.h" |
| 63 |
|
|
| 64 |
static struct elf_backend_data elf32_arm_vxworks_bed; |
static struct elf_backend_data elf32_arm_vxworks_bed; |
| 65 |
|
|
| 66 |
|
static bfd_boolean elf32_arm_write_section (bfd *output_bfd, |
| 67 |
|
struct bfd_link_info *link_info, |
| 68 |
|
asection *sec, |
| 69 |
|
bfd_byte *contents); |
| 70 |
|
|
| 71 |
/* Note: code such as elf32_arm_reloc_type_lookup expect to use e.g. |
/* Note: code such as elf32_arm_reloc_type_lookup expect to use e.g. |
| 72 |
R_ARM_PC24 as an index into this, and find the R_ARM_PC24 HOWTO |
R_ARM_PC24 as an index into this, and find the R_ARM_PC24 HOWTO |
| 73 |
in that slot. */ |
in that slot. */ |
| 1888 |
interworkable. */ |
interworkable. */ |
| 1889 |
#define INTERWORK_FLAG(abfd) \ |
#define INTERWORK_FLAG(abfd) \ |
| 1890 |
(EF_ARM_EABI_VERSION (elf_elfheader (abfd)->e_flags) >= EF_ARM_EABI_VER4 \ |
(EF_ARM_EABI_VERSION (elf_elfheader (abfd)->e_flags) >= EF_ARM_EABI_VER4 \ |
| 1891 |
|| (elf_elfheader (abfd)->e_flags & EF_ARM_INTERWORK)) |
|| (elf_elfheader (abfd)->e_flags & EF_ARM_INTERWORK) \ |
| 1892 |
|
|| ((abfd)->flags & BFD_LINKER_CREATED)) |
| 1893 |
|
|
| 1894 |
/* The linker script knows the section names for placement. |
/* The linker script knows the section names for placement. |
| 1895 |
The entry_names are used to do simple name mangling on the stubs. |
The entry_names are used to do simple name mangling on the stubs. |
| 2018 |
#define THM2_MAX_FWD_BRANCH_OFFSET (((1 << 24) - 2) + 4) |
#define THM2_MAX_FWD_BRANCH_OFFSET (((1 << 24) - 2) + 4) |
| 2019 |
#define THM2_MAX_BWD_BRANCH_OFFSET (-(1 << 24) + 4) |
#define THM2_MAX_BWD_BRANCH_OFFSET (-(1 << 24) + 4) |
| 2020 |
|
|
| 2021 |
static const bfd_vma arm_long_branch_stub[] = |
enum stub_insn_type |
| 2022 |
{ |
{ |
| 2023 |
0xe51ff004, /* ldr pc, [pc, #-4] */ |
THUMB16_TYPE = 1, |
| 2024 |
0x00000000, /* dcd R_ARM_ABS32(X) */ |
THUMB32_TYPE, |
| 2025 |
|
ARM_TYPE, |
| 2026 |
|
DATA_TYPE |
| 2027 |
|
}; |
| 2028 |
|
|
| 2029 |
|
#define THUMB16_INSN(X) {(X), THUMB16_TYPE, R_ARM_NONE, 0} |
| 2030 |
|
/* A bit of a hack. A Thumb conditional branch, in which the proper condition |
| 2031 |
|
is inserted in arm_build_one_stub(). */ |
| 2032 |
|
#define THUMB16_BCOND_INSN(X) {(X), THUMB16_TYPE, R_ARM_NONE, 1} |
| 2033 |
|
#define THUMB32_INSN(X) {(X), THUMB32_TYPE, R_ARM_NONE, 0} |
| 2034 |
|
#define THUMB32_B_INSN(X, Z) {(X), THUMB32_TYPE, R_ARM_THM_JUMP24, (Z)} |
| 2035 |
|
#define ARM_INSN(X) {(X), ARM_TYPE, R_ARM_NONE, 0} |
| 2036 |
|
#define ARM_REL_INSN(X, Z) {(X), ARM_TYPE, R_ARM_JUMP24, (Z)} |
| 2037 |
|
#define DATA_WORD(X,Y,Z) {(X), DATA_TYPE, (Y), (Z)} |
| 2038 |
|
|
| 2039 |
|
typedef struct |
| 2040 |
|
{ |
| 2041 |
|
bfd_vma data; |
| 2042 |
|
enum stub_insn_type type; |
| 2043 |
|
unsigned int r_type; |
| 2044 |
|
int reloc_addend; |
| 2045 |
|
} insn_sequence; |
| 2046 |
|
|
| 2047 |
|
/* Arm/Thumb -> Arm/Thumb long branch stub. On V5T and above, use blx |
| 2048 |
|
to reach the stub if necessary. */ |
| 2049 |
|
static const insn_sequence elf32_arm_stub_long_branch_any_any[] = |
| 2050 |
|
{ |
| 2051 |
|
ARM_INSN(0xe51ff004), /* ldr pc, [pc, #-4] */ |
| 2052 |
|
DATA_WORD(0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
| 2053 |
|
}; |
| 2054 |
|
|
| 2055 |
|
/* V4T Arm -> Thumb long branch stub. Used on V4T where blx is not |
| 2056 |
|
available. */ |
| 2057 |
|
static const insn_sequence elf32_arm_stub_long_branch_v4t_arm_thumb[] = |
| 2058 |
|
{ |
| 2059 |
|
ARM_INSN(0xe59fc000), /* ldr ip, [pc, #0] */ |
| 2060 |
|
ARM_INSN(0xe12fff1c), /* bx ip */ |
| 2061 |
|
DATA_WORD(0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
| 2062 |
|
}; |
| 2063 |
|
|
| 2064 |
|
/* Thumb -> Thumb long branch stub. Used on M-profile architectures. */ |
| 2065 |
|
static const insn_sequence elf32_arm_stub_long_branch_thumb_only[] = |
| 2066 |
|
{ |
| 2067 |
|
THUMB16_INSN(0xb401), /* push {r0} */ |
| 2068 |
|
THUMB16_INSN(0x4802), /* ldr r0, [pc, #8] */ |
| 2069 |
|
THUMB16_INSN(0x4684), /* mov ip, r0 */ |
| 2070 |
|
THUMB16_INSN(0xbc01), /* pop {r0} */ |
| 2071 |
|
THUMB16_INSN(0x4760), /* bx ip */ |
| 2072 |
|
THUMB16_INSN(0xbf00), /* nop */ |
| 2073 |
|
DATA_WORD(0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
| 2074 |
|
}; |
| 2075 |
|
|
| 2076 |
|
/* V4T Thumb -> Thumb long branch stub. Using the stack is not |
| 2077 |
|
allowed. */ |
| 2078 |
|
static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_thumb[] = |
| 2079 |
|
{ |
| 2080 |
|
THUMB16_INSN(0x4778), /* bx pc */ |
| 2081 |
|
THUMB16_INSN(0x46c0), /* nop */ |
| 2082 |
|
ARM_INSN(0xe59fc000), /* ldr ip, [pc, #0] */ |
| 2083 |
|
ARM_INSN(0xe12fff1c), /* bx ip */ |
| 2084 |
|
DATA_WORD(0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
| 2085 |
|
}; |
| 2086 |
|
|
| 2087 |
|
/* V4T Thumb -> ARM long branch stub. Used on V4T where blx is not |
| 2088 |
|
available. */ |
| 2089 |
|
static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_arm[] = |
| 2090 |
|
{ |
| 2091 |
|
THUMB16_INSN(0x4778), /* bx pc */ |
| 2092 |
|
THUMB16_INSN(0x46c0), /* nop */ |
| 2093 |
|
ARM_INSN(0xe51ff004), /* ldr pc, [pc, #-4] */ |
| 2094 |
|
DATA_WORD(0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
| 2095 |
|
}; |
| 2096 |
|
|
| 2097 |
|
/* V4T Thumb -> ARM short branch stub. Shorter variant of the above |
| 2098 |
|
one, when the destination is close enough. */ |
| 2099 |
|
static const insn_sequence elf32_arm_stub_short_branch_v4t_thumb_arm[] = |
| 2100 |
|
{ |
| 2101 |
|
THUMB16_INSN(0x4778), /* bx pc */ |
| 2102 |
|
THUMB16_INSN(0x46c0), /* nop */ |
| 2103 |
|
ARM_REL_INSN(0xea000000, -8), /* b (X-8) */ |
| 2104 |
|
}; |
| 2105 |
|
|
| 2106 |
|
/* ARM/Thumb -> ARM long branch stub, PIC. On V5T and above, use |
| 2107 |
|
blx to reach the stub if necessary. */ |
| 2108 |
|
static const insn_sequence elf32_arm_stub_long_branch_any_arm_pic[] = |
| 2109 |
|
{ |
| 2110 |
|
ARM_INSN(0xe59fc000), /* ldr r12, [pc] */ |
| 2111 |
|
ARM_INSN(0xe08ff00c), /* add pc, pc, ip */ |
| 2112 |
|
DATA_WORD(0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X-4) */ |
| 2113 |
}; |
}; |
| 2114 |
|
|
| 2115 |
static const bfd_vma arm_thumb_v4t_long_branch_stub[] = |
/* ARM/Thumb -> Thumb long branch stub, PIC. On V5T and above, use |
| 2116 |
|
blx to reach the stub if necessary. We can not add into pc; |
| 2117 |
|
it is not guaranteed to mode switch (different in ARMv6 and |
| 2118 |
|
ARMv7). */ |
| 2119 |
|
static const insn_sequence elf32_arm_stub_long_branch_any_thumb_pic[] = |
| 2120 |
{ |
{ |
| 2121 |
0xe59fc000, /* ldr ip, [pc, #0] */ |
ARM_INSN(0xe59fc004), /* ldr r12, [pc, #4] */ |
| 2122 |
0xe12fff1c, /* bx ip */ |
ARM_INSN(0xe08fc00c), /* add ip, pc, ip */ |
| 2123 |
0x00000000, /* dcd R_ARM_ABS32(X) */ |
ARM_INSN(0xe12fff1c), /* bx ip */ |
| 2124 |
|
DATA_WORD(0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ |
| 2125 |
}; |
}; |
| 2126 |
|
|
| 2127 |
static const bfd_vma arm_thumb_thumb_long_branch_stub[] = |
/* V4T ARM -> ARM long branch stub, PIC. */ |
| 2128 |
|
static const insn_sequence elf32_arm_stub_long_branch_v4t_arm_thumb_pic[] = |
| 2129 |
{ |
{ |
| 2130 |
0x4e02b540, /* push {r6, lr} */ |
ARM_INSN(0xe59fc004), /* ldr ip, [pc, #4] */ |
| 2131 |
/* ldr r6, [pc, #8] */ |
ARM_INSN(0xe08fc00c), /* add ip, pc, ip */ |
| 2132 |
0x473046fe, /* mov lr, pc */ |
ARM_INSN(0xe12fff1c), /* bx ip */ |
| 2133 |
/* bx r6 */ |
DATA_WORD(0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ |
|
0xbf00bd40, /* pop {r6, pc} */ |
|
|
/* nop */ |
|
|
0x00000000, /* dcd R_ARM_ABS32(X) */ |
|
| 2134 |
}; |
}; |
| 2135 |
|
|
| 2136 |
static const bfd_vma arm_thumb_arm_v4t_long_branch_stub[] = |
/* V4T Thumb -> ARM long branch stub, PIC. */ |
| 2137 |
|
static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_arm_pic[] = |
| 2138 |
{ |
{ |
| 2139 |
0x4e03b540, /* push {r6, lr} */ |
THUMB16_INSN(0x4778), /* bx pc */ |
| 2140 |
/* ldr r6, [pc, #12] */ |
THUMB16_INSN(0x46c0), /* nop */ |
| 2141 |
0x473046fe, /* mov lr, pc */ |
ARM_INSN(0xe59fc000), /* ldr ip, [pc, #0] */ |
| 2142 |
/* bx r6 */ |
ARM_INSN(0xe08cf00f), /* add pc, ip, pc */ |
| 2143 |
0xe8bd4040, /* pop {r6, pc} */ |
DATA_WORD(0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X) */ |
|
0xe12fff1e, /* bx lr */ |
|
|
0x00000000, /* dcd R_ARM_ABS32(X) */ |
|
| 2144 |
}; |
}; |
| 2145 |
|
|
| 2146 |
static const bfd_vma arm_thumb_arm_v4t_short_branch_stub[] = |
/* Thumb -> Thumb long branch stub, PIC. Used on M-profile |
| 2147 |
|
architectures. */ |
| 2148 |
|
static const insn_sequence elf32_arm_stub_long_branch_thumb_only_pic[] = |
| 2149 |
{ |
{ |
| 2150 |
0x46c04778, /* bx pc */ |
THUMB16_INSN(0xb401), /* push {r0} */ |
| 2151 |
/* nop */ |
THUMB16_INSN(0x4802), /* ldr r0, [pc, #8] */ |
| 2152 |
0xea000000, /* b (X) */ |
THUMB16_INSN(0x46fc), /* mov ip, pc */ |
| 2153 |
|
THUMB16_INSN(0x4484), /* add ip, r0 */ |
| 2154 |
|
THUMB16_INSN(0xbc01), /* pop {r0} */ |
| 2155 |
|
THUMB16_INSN(0x4760), /* bx ip */ |
| 2156 |
|
DATA_WORD(0, R_ARM_REL32, 4), /* dcd R_ARM_REL32(X) */ |
| 2157 |
}; |
}; |
| 2158 |
|
|
| 2159 |
static const bfd_vma arm_pic_long_branch_stub[] = |
/* V4T Thumb -> Thumb long branch stub, PIC. Using the stack is not |
| 2160 |
|
allowed. */ |
| 2161 |
|
static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_thumb_pic[] = |
| 2162 |
{ |
{ |
| 2163 |
0xe59fc000, /* ldr r12, [pc] */ |
THUMB16_INSN(0x4778), /* bx pc */ |
| 2164 |
0xe08ff00c, /* add pc, pc, ip */ |
THUMB16_INSN(0x46c0), /* nop */ |
| 2165 |
0x00000000, /* dcd R_ARM_REL32(X) */ |
ARM_INSN(0xe59fc004), /* ldr ip, [pc, #4] */ |
| 2166 |
|
ARM_INSN(0xe08fc00c), /* add ip, pc, ip */ |
| 2167 |
|
ARM_INSN(0xe12fff1c), /* bx ip */ |
| 2168 |
|
DATA_WORD(0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ |
| 2169 |
|
}; |
| 2170 |
|
|
| 2171 |
|
/* Cortex-A8 erratum-workaround stubs. */ |
| 2172 |
|
|
| 2173 |
|
/* Stub used for conditional branches (which may be beyond +/-1MB away, so we |
| 2174 |
|
can't use a conditional branch to reach this stub). */ |
| 2175 |
|
|
| 2176 |
|
static const insn_sequence elf32_arm_stub_a8_veneer_b_cond[] = |
| 2177 |
|
{ |
| 2178 |
|
THUMB16_BCOND_INSN(0xd001), /* b<cond>.n true. */ |
| 2179 |
|
THUMB32_B_INSN(0xf000b800, -4), /* b.w insn_after_original_branch. */ |
| 2180 |
|
THUMB32_B_INSN(0xf000b800, -4) /* true: b.w original_branch_dest. */ |
| 2181 |
|
}; |
| 2182 |
|
|
| 2183 |
|
/* Stub used for b.w and bl.w instructions. */ |
| 2184 |
|
|
| 2185 |
|
static const insn_sequence elf32_arm_stub_a8_veneer_b[] = |
| 2186 |
|
{ |
| 2187 |
|
THUMB32_B_INSN(0xf000b800, -4) /* b.w original_branch_dest. */ |
| 2188 |
|
}; |
| 2189 |
|
|
| 2190 |
|
static const insn_sequence elf32_arm_stub_a8_veneer_bl[] = |
| 2191 |
|
{ |
| 2192 |
|
THUMB32_B_INSN(0xf000b800, -4) /* b.w original_branch_dest. */ |
| 2193 |
|
}; |
| 2194 |
|
|
| 2195 |
|
/* Stub used for Thumb-2 blx.w instructions. We modified the original blx.w |
| 2196 |
|
instruction (which switches to ARM mode) to point to this stub. Jump to the |
| 2197 |
|
real destination using an ARM-mode branch. */ |
| 2198 |
|
|
| 2199 |
|
static const insn_sequence elf32_arm_stub_a8_veneer_blx[] = |
| 2200 |
|
{ |
| 2201 |
|
ARM_REL_INSN(0xea000000, -8) /* b original_branch_dest. */ |
| 2202 |
}; |
}; |
| 2203 |
|
|
| 2204 |
/* Section name for stubs is the associated section name plus this |
/* Section name for stubs is the associated section name plus this |
| 2205 |
string. */ |
string. */ |
| 2206 |
#define STUB_SUFFIX ".stub" |
#define STUB_SUFFIX ".stub" |
| 2207 |
|
|
| 2208 |
enum elf32_arm_stub_type |
/* One entry per long/short branch stub defined above. */ |
| 2209 |
{ |
#define DEF_STUBS \ |
| 2210 |
|
DEF_STUB(long_branch_any_any) \ |
| 2211 |
|
DEF_STUB(long_branch_v4t_arm_thumb) \ |
| 2212 |
|
DEF_STUB(long_branch_thumb_only) \ |
| 2213 |
|
DEF_STUB(long_branch_v4t_thumb_thumb) \ |
| 2214 |
|
DEF_STUB(long_branch_v4t_thumb_arm) \ |
| 2215 |
|
DEF_STUB(short_branch_v4t_thumb_arm) \ |
| 2216 |
|
DEF_STUB(long_branch_any_arm_pic) \ |
| 2217 |
|
DEF_STUB(long_branch_any_thumb_pic) \ |
| 2218 |
|
DEF_STUB(long_branch_v4t_thumb_thumb_pic) \ |
| 2219 |
|
DEF_STUB(long_branch_v4t_arm_thumb_pic) \ |
| 2220 |
|
DEF_STUB(long_branch_v4t_thumb_arm_pic) \ |
| 2221 |
|
DEF_STUB(long_branch_thumb_only_pic) \ |
| 2222 |
|
DEF_STUB(a8_veneer_b_cond) \ |
| 2223 |
|
DEF_STUB(a8_veneer_b) \ |
| 2224 |
|
DEF_STUB(a8_veneer_bl) \ |
| 2225 |
|
DEF_STUB(a8_veneer_blx) |
| 2226 |
|
|
| 2227 |
|
#define DEF_STUB(x) arm_stub_##x, |
| 2228 |
|
enum elf32_arm_stub_type { |
| 2229 |
arm_stub_none, |
arm_stub_none, |
| 2230 |
arm_stub_long_branch, |
DEF_STUBS |
| 2231 |
arm_thumb_v4t_stub_long_branch, |
}; |
| 2232 |
arm_thumb_thumb_stub_long_branch, |
#undef DEF_STUB |
| 2233 |
arm_thumb_arm_v4t_stub_long_branch, |
|
| 2234 |
arm_thumb_arm_v4t_stub_short_branch, |
typedef struct |
| 2235 |
arm_stub_pic_long_branch, |
{ |
| 2236 |
|
const insn_sequence* template; |
| 2237 |
|
int template_size; |
| 2238 |
|
} stub_def; |
| 2239 |
|
|
| 2240 |
|
#define DEF_STUB(x) {elf32_arm_stub_##x, ARRAY_SIZE(elf32_arm_stub_##x)}, |
| 2241 |
|
static const stub_def stub_definitions[] = { |
| 2242 |
|
{NULL, 0}, |
| 2243 |
|
DEF_STUBS |
| 2244 |
}; |
}; |
| 2245 |
|
|
| 2246 |
struct elf32_arm_stub_hash_entry |
struct elf32_arm_stub_hash_entry |
| 2259 |
bfd_vma target_value; |
bfd_vma target_value; |
| 2260 |
asection *target_section; |
asection *target_section; |
| 2261 |
|
|
| 2262 |
|
/* Offset to apply to relocation referencing target_value. */ |
| 2263 |
|
bfd_vma target_addend; |
| 2264 |
|
|
| 2265 |
|
/* The instruction which caused this stub to be generated (only valid for |
| 2266 |
|
Cortex-A8 erratum workaround stubs at present). */ |
| 2267 |
|
unsigned long orig_insn; |
| 2268 |
|
|
| 2269 |
|
/* The stub type. */ |
| 2270 |
enum elf32_arm_stub_type stub_type; |
enum elf32_arm_stub_type stub_type; |
| 2271 |
|
/* Its encoding size in bytes. */ |
| 2272 |
|
int stub_size; |
| 2273 |
|
/* Its template. */ |
| 2274 |
|
const insn_sequence *stub_template; |
| 2275 |
|
/* The size of the template (number of entries). */ |
| 2276 |
|
int stub_template_size; |
| 2277 |
|
|
| 2278 |
/* The symbol table entry, if any, that this was derived from. */ |
/* The symbol table entry, if any, that this was derived from. */ |
| 2279 |
struct elf32_arm_link_hash_entry *h; |
struct elf32_arm_link_hash_entry *h; |
| 2333 |
} |
} |
| 2334 |
elf32_vfp11_erratum_list; |
elf32_vfp11_erratum_list; |
| 2335 |
|
|
| 2336 |
|
typedef enum |
| 2337 |
|
{ |
| 2338 |
|
DELETE_EXIDX_ENTRY, |
| 2339 |
|
INSERT_EXIDX_CANTUNWIND_AT_END |
| 2340 |
|
} |
| 2341 |
|
arm_unwind_edit_type; |
| 2342 |
|
|
| 2343 |
|
/* A (sorted) list of edits to apply to an unwind table. */ |
| 2344 |
|
typedef struct arm_unwind_table_edit |
| 2345 |
|
{ |
| 2346 |
|
arm_unwind_edit_type type; |
| 2347 |
|
/* Note: we sometimes want to insert an unwind entry corresponding to a |
| 2348 |
|
section different from the one we're currently writing out, so record the |
| 2349 |
|
(text) section this edit relates to here. */ |
| 2350 |
|
asection *linked_section; |
| 2351 |
|
unsigned int index; |
| 2352 |
|
struct arm_unwind_table_edit *next; |
| 2353 |
|
} |
| 2354 |
|
arm_unwind_table_edit; |
| 2355 |
|
|
| 2356 |
typedef struct _arm_elf_section_data |
typedef struct _arm_elf_section_data |
| 2357 |
{ |
{ |
| 2358 |
|
/* Information about mapping symbols. */ |
| 2359 |
struct bfd_elf_section_data elf; |
struct bfd_elf_section_data elf; |
| 2360 |
unsigned int mapcount; |
unsigned int mapcount; |
| 2361 |
unsigned int mapsize; |
unsigned int mapsize; |
| 2362 |
elf32_arm_section_map *map; |
elf32_arm_section_map *map; |
| 2363 |
|
/* Information about CPU errata. */ |
| 2364 |
unsigned int erratumcount; |
unsigned int erratumcount; |
| 2365 |
elf32_vfp11_erratum_list *erratumlist; |
elf32_vfp11_erratum_list *erratumlist; |
| 2366 |
|
/* Information about unwind tables. */ |
| 2367 |
|
union |
| 2368 |
|
{ |
| 2369 |
|
/* Unwind info attached to a text section. */ |
| 2370 |
|
struct |
| 2371 |
|
{ |
| 2372 |
|
asection *arm_exidx_sec; |
| 2373 |
|
} text; |
| 2374 |
|
|
| 2375 |
|
/* Unwind info attached to an .ARM.exidx section. */ |
| 2376 |
|
struct |
| 2377 |
|
{ |
| 2378 |
|
arm_unwind_table_edit *unwind_edit_list; |
| 2379 |
|
arm_unwind_table_edit *unwind_edit_tail; |
| 2380 |
|
} exidx; |
| 2381 |
|
} u; |
| 2382 |
} |
} |
| 2383 |
_arm_elf_section_data; |
_arm_elf_section_data; |
| 2384 |
|
|
| 2385 |
#define elf32_arm_section_data(sec) \ |
#define elf32_arm_section_data(sec) \ |
| 2386 |
((_arm_elf_section_data *) elf_section_data (sec)) |
((_arm_elf_section_data *) elf_section_data (sec)) |
| 2387 |
|
|
| 2388 |
|
/* A fix which might be required for Cortex-A8 Thumb-2 branch/TLB erratum. |
| 2389 |
|
These fixes are subject to a relaxation procedure (in elf32_arm_size_stubs), |
| 2390 |
|
so may be created multiple times: we use an array of these entries whilst |
| 2391 |
|
relaxing which we can refresh easily, then create stubs for each potentially |
| 2392 |
|
erratum-triggering instruction once we've settled on a solution. */ |
| 2393 |
|
|
| 2394 |
|
struct a8_erratum_fix { |
| 2395 |
|
bfd *input_bfd; |
| 2396 |
|
asection *section; |
| 2397 |
|
bfd_vma offset; |
| 2398 |
|
bfd_vma addend; |
| 2399 |
|
unsigned long orig_insn; |
| 2400 |
|
char *stub_name; |
| 2401 |
|
enum elf32_arm_stub_type stub_type; |
| 2402 |
|
}; |
| 2403 |
|
|
| 2404 |
|
/* A table of relocs applied to branches which might trigger Cortex-A8 |
| 2405 |
|
erratum. */ |
| 2406 |
|
|
| 2407 |
|
struct a8_erratum_reloc { |
| 2408 |
|
bfd_vma from; |
| 2409 |
|
bfd_vma destination; |
| 2410 |
|
unsigned int r_type; |
| 2411 |
|
unsigned char st_type; |
| 2412 |
|
const char *sym_name; |
| 2413 |
|
bfd_boolean non_a8_stub; |
| 2414 |
|
}; |
| 2415 |
|
|
| 2416 |
/* The size of the thread control block. */ |
/* The size of the thread control block. */ |
| 2417 |
#define TCB_SIZE 8 |
#define TCB_SIZE 8 |
| 2418 |
|
|
| 2544 |
veneers. */ |
veneers. */ |
| 2545 |
bfd_size_type vfp11_erratum_glue_size; |
bfd_size_type vfp11_erratum_glue_size; |
| 2546 |
|
|
| 2547 |
|
/* A table of fix locations for Cortex-A8 Thumb-2 branch/TLB erratum. This |
| 2548 |
|
holds Cortex-A8 erratum fix locations between elf32_arm_size_stubs() and |
| 2549 |
|
elf32_arm_write_section(). */ |
| 2550 |
|
struct a8_erratum_fix *a8_erratum_fixes; |
| 2551 |
|
unsigned int num_a8_erratum_fixes; |
| 2552 |
|
|
| 2553 |
/* An arbitrary input BFD chosen to hold the glue sections. */ |
/* An arbitrary input BFD chosen to hold the glue sections. */ |
| 2554 |
bfd * bfd_of_glue_owner; |
bfd * bfd_of_glue_owner; |
| 2555 |
|
|
| 2568 |
2 = Generate v4 interworing stubs. */ |
2 = Generate v4 interworing stubs. */ |
| 2569 |
int fix_v4bx; |
int fix_v4bx; |
| 2570 |
|
|
| 2571 |
|
/* Whether we should fix the Cortex-A8 Thumb-2 branch/TLB erratum. */ |
| 2572 |
|
int fix_cortex_a8; |
| 2573 |
|
|
| 2574 |
/* Nonzero if the ARM/Thumb BLX instructions are available for use. */ |
/* Nonzero if the ARM/Thumb BLX instructions are available for use. */ |
| 2575 |
int use_blx; |
int use_blx; |
| 2576 |
|
|
| 2618 |
bfd_vma offset; |
bfd_vma offset; |
| 2619 |
} tls_ldm_got; |
} tls_ldm_got; |
| 2620 |
|
|
| 2621 |
/* Small local sym to section mapping cache. */ |
/* Small local sym cache. */ |
| 2622 |
struct sym_sec_cache sym_sec; |
struct sym_cache sym_cache; |
| 2623 |
|
|
| 2624 |
/* For convenience in allocate_dynrelocs. */ |
/* For convenience in allocate_dynrelocs. */ |
| 2625 |
bfd * obfd; |
bfd * obfd; |
| 2716 |
eh->stub_offset = 0; |
eh->stub_offset = 0; |
| 2717 |
eh->target_value = 0; |
eh->target_value = 0; |
| 2718 |
eh->target_section = NULL; |
eh->target_section = NULL; |
| 2719 |
|
eh->target_addend = 0; |
| 2720 |
|
eh->orig_insn = 0; |
| 2721 |
eh->stub_type = arm_stub_none; |
eh->stub_type = arm_stub_none; |
| 2722 |
|
eh->stub_size = 0; |
| 2723 |
|
eh->stub_template = NULL; |
| 2724 |
|
eh->stub_template_size = 0; |
| 2725 |
eh->h = NULL; |
eh->h = NULL; |
| 2726 |
eh->id_sec = NULL; |
eh->id_sec = NULL; |
| 2727 |
} |
} |
| 2750 |
if (!htab->sgot || !htab->sgotplt) |
if (!htab->sgot || !htab->sgotplt) |
| 2751 |
abort (); |
abort (); |
| 2752 |
|
|
| 2753 |
htab->srelgot = bfd_make_section_with_flags (dynobj, |
htab->srelgot = bfd_get_section_by_name (dynobj, |
| 2754 |
RELOC_SECTION (htab, ".got"), |
RELOC_SECTION (htab, ".got")); |
| 2755 |
(SEC_ALLOC | SEC_LOAD |
if (htab->srelgot == NULL) |
|
| SEC_HAS_CONTENTS |
|
|
| SEC_IN_MEMORY |
|
|
| SEC_LINKER_CREATED |
|
|
| SEC_READONLY)); |
|
|
if (htab->srelgot == NULL |
|
|
|| ! bfd_set_section_alignment (dynobj, htab->srelgot, 2)) |
|
| 2756 |
return FALSE; |
return FALSE; |
| 2757 |
return TRUE; |
return TRUE; |
| 2758 |
} |
} |
| 2906 |
ret->vfp11_fix = BFD_ARM_VFP11_FIX_NONE; |
ret->vfp11_fix = BFD_ARM_VFP11_FIX_NONE; |
| 2907 |
ret->vfp11_erratum_glue_size = 0; |
ret->vfp11_erratum_glue_size = 0; |
| 2908 |
ret->num_vfp11_fixes = 0; |
ret->num_vfp11_fixes = 0; |
| 2909 |
|
ret->fix_cortex_a8 = 0; |
| 2910 |
ret->bfd_of_glue_owner = NULL; |
ret->bfd_of_glue_owner = NULL; |
| 2911 |
ret->byteswap_code = 0; |
ret->byteswap_code = 0; |
| 2912 |
ret->target1_is_rel = 0; |
ret->target1_is_rel = 0; |
| 2923 |
ret->vxworks_p = 0; |
ret->vxworks_p = 0; |
| 2924 |
ret->symbian_p = 0; |
ret->symbian_p = 0; |
| 2925 |
ret->use_rel = 1; |
ret->use_rel = 1; |
| 2926 |
ret->sym_sec.abfd = NULL; |
ret->sym_cache.abfd = NULL; |
| 2927 |
ret->obfd = abfd; |
ret->obfd = abfd; |
| 2928 |
ret->tls_ldm_got.refcount = 0; |
ret->tls_ldm_got.refcount = 0; |
| 2929 |
ret->stub_bfd = NULL; |
ret->stub_bfd = NULL; |
| 2989 |
{ |
{ |
| 2990 |
switch (stub_type) |
switch (stub_type) |
| 2991 |
{ |
{ |
| 2992 |
case arm_thumb_thumb_stub_long_branch: |
case arm_stub_long_branch_thumb_only: |
| 2993 |
case arm_thumb_arm_v4t_stub_long_branch: |
case arm_stub_long_branch_v4t_thumb_arm: |
| 2994 |
case arm_thumb_arm_v4t_stub_short_branch: |
case arm_stub_short_branch_v4t_thumb_arm: |
| 2995 |
|
case arm_stub_long_branch_v4t_thumb_arm_pic: |
| 2996 |
|
case arm_stub_long_branch_thumb_only_pic: |
| 2997 |
return TRUE; |
return TRUE; |
| 2998 |
case arm_stub_none: |
case arm_stub_none: |
| 2999 |
BFD_FAIL (); |
BFD_FAIL (); |
| 3024 |
int thumb2; |
int thumb2; |
| 3025 |
int thumb_only; |
int thumb_only; |
| 3026 |
enum elf32_arm_stub_type stub_type = arm_stub_none; |
enum elf32_arm_stub_type stub_type = arm_stub_none; |
| 3027 |
|
int use_plt = 0; |
| 3028 |
|
|
| 3029 |
/* We don't know the actual type of destination in case it is of |
/* We don't know the actual type of destination in case it is of |
| 3030 |
type STT_SECTION: give up. */ |
type STT_SECTION: give up. */ |
| 3046 |
|
|
| 3047 |
r_type = ELF32_R_TYPE (rel->r_info); |
r_type = ELF32_R_TYPE (rel->r_info); |
| 3048 |
|
|
| 3049 |
/* If the call will go through a PLT entry then we do not need |
/* Keep a simpler condition, for the sake of clarity. */ |
|
glue. */ |
|
| 3050 |
if (globals->splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1) |
if (globals->splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1) |
|
return stub_type; |
|
|
|
|
|
if (r_type == R_ARM_THM_CALL) |
|
| 3051 |
{ |
{ |
| 3052 |
|
use_plt = 1; |
| 3053 |
|
/* Note when dealing with PLT entries: the main PLT stub is in |
| 3054 |
|
ARM mode, so if the branch is in Thumb mode, another |
| 3055 |
|
Thumb->ARM stub will be inserted later just before the ARM |
| 3056 |
|
PLT stub. We don't take this extra distance into account |
| 3057 |
|
here, because if a long branch stub is needed, we'll add a |
| 3058 |
|
Thumb->Arm one and branch directly to the ARM PLT entry |
| 3059 |
|
because it avoids spreading offset corrections in several |
| 3060 |
|
places. */ |
| 3061 |
|
} |
| 3062 |
|
|
| 3063 |
|
if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24) |
| 3064 |
|
{ |
| 3065 |
|
/* Handle cases where: |
| 3066 |
|
- this call goes too far (different Thumb/Thumb2 max |
| 3067 |
|
distance) |
| 3068 |
|
- it's a Thumb->Arm call and blx is not available, or it's a |
| 3069 |
|
Thumb->Arm branch (not bl). A stub is needed in this case, |
| 3070 |
|
but only if this call is not through a PLT entry. Indeed, |
| 3071 |
|
PLT stubs handle mode switching already. |
| 3072 |
|
*/ |
| 3073 |
if ((!thumb2 |
if ((!thumb2 |
| 3074 |
&& (branch_offset > THM_MAX_FWD_BRANCH_OFFSET |
&& (branch_offset > THM_MAX_FWD_BRANCH_OFFSET |
| 3075 |
|| (branch_offset < THM_MAX_BWD_BRANCH_OFFSET))) |
|| (branch_offset < THM_MAX_BWD_BRANCH_OFFSET))) |
| 3076 |
|| (thumb2 |
|| (thumb2 |
| 3077 |
&& (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET |
&& (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET |
| 3078 |
|| (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) |
|| (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) |
| 3079 |
|| ((st_type != STT_ARM_TFUNC) && !globals->use_blx)) |
|| ((st_type != STT_ARM_TFUNC) |
| 3080 |
|
&& (((r_type == R_ARM_THM_CALL) && !globals->use_blx) |
| 3081 |
|
|| (r_type == R_ARM_THM_JUMP24)) |
| 3082 |
|
&& !use_plt)) |
| 3083 |
{ |
{ |
| 3084 |
if (st_type == STT_ARM_TFUNC) |
if (st_type == STT_ARM_TFUNC) |
| 3085 |
{ |
{ |
| 3087 |
if (!thumb_only) |
if (!thumb_only) |
| 3088 |
{ |
{ |
| 3089 |
stub_type = (info->shared | globals->pic_veneer) |
stub_type = (info->shared | globals->pic_veneer) |
| 3090 |
? ((globals->use_blx) |
/* PIC stubs. */ |
| 3091 |
? arm_stub_pic_long_branch |
? ((globals->use_blx |
| 3092 |
: arm_stub_none) |
&& (r_type ==R_ARM_THM_CALL)) |
| 3093 |
: (globals->use_blx) |
/* V5T and above. Stub starts with ARM code, so |
| 3094 |
? arm_stub_long_branch |
we must be able to switch mode before |
| 3095 |
: arm_stub_none; |
reaching it, which is only possible for 'bl' |
| 3096 |
|
(ie R_ARM_THM_CALL relocation). */ |
| 3097 |
|
? arm_stub_long_branch_any_thumb_pic |
| 3098 |
|
/* On V4T, use Thumb code only. */ |
| 3099 |
|
: arm_stub_long_branch_v4t_thumb_thumb_pic) |
| 3100 |
|
|
| 3101 |
|
/* non-PIC stubs. */ |
| 3102 |
|
: ((globals->use_blx |
| 3103 |
|
&& (r_type ==R_ARM_THM_CALL)) |
| 3104 |
|
/* V5T and above. */ |
| 3105 |
|
? arm_stub_long_branch_any_any |
| 3106 |
|
/* V4T. */ |
| 3107 |
|
: arm_stub_long_branch_v4t_thumb_thumb); |
| 3108 |
} |
} |
| 3109 |
else |
else |
| 3110 |
{ |
{ |
| 3111 |
stub_type = (info->shared | globals->pic_veneer) |
stub_type = (info->shared | globals->pic_veneer) |
| 3112 |
? arm_stub_none |
/* PIC stub. */ |
| 3113 |
: (globals->use_blx) |
? arm_stub_long_branch_thumb_only_pic |
| 3114 |
? arm_thumb_thumb_stub_long_branch |
/* non-PIC stub. */ |
| 3115 |
: arm_stub_none; |
: arm_stub_long_branch_thumb_only; |
| 3116 |
} |
} |
| 3117 |
} |
} |
| 3118 |
else |
else |
| 3129 |
} |
} |
| 3130 |
|
|
| 3131 |
stub_type = (info->shared | globals->pic_veneer) |
stub_type = (info->shared | globals->pic_veneer) |
| 3132 |
? ((globals->use_blx) |
/* PIC stubs. */ |
| 3133 |
? arm_stub_pic_long_branch |
? ((globals->use_blx |
| 3134 |
: arm_stub_none) |
&& (r_type ==R_ARM_THM_CALL)) |
| 3135 |
: (globals->use_blx) |
/* V5T and above. */ |
| 3136 |
? arm_stub_long_branch |
? arm_stub_long_branch_any_arm_pic |
| 3137 |
: arm_thumb_arm_v4t_stub_long_branch; |
/* V4T PIC stub. */ |
| 3138 |
|
: arm_stub_long_branch_v4t_thumb_arm_pic) |
| 3139 |
|
|
| 3140 |
|
/* non-PIC stubs. */ |
| 3141 |
|
: ((globals->use_blx |
| 3142 |
|
&& (r_type ==R_ARM_THM_CALL)) |
| 3143 |
|
/* V5T and above. */ |
| 3144 |
|
? arm_stub_long_branch_any_any |
| 3145 |
|
/* V4T. */ |
| 3146 |
|
: arm_stub_long_branch_v4t_thumb_arm); |
| 3147 |
|
|
| 3148 |
/* Handle v4t short branches. */ |
/* Handle v4t short branches. */ |
| 3149 |
if ((stub_type == arm_thumb_arm_v4t_stub_long_branch) |
if ((stub_type == arm_stub_long_branch_v4t_thumb_arm) |
| 3150 |
&& (branch_offset <= THM_MAX_FWD_BRANCH_OFFSET) |
&& (branch_offset <= THM_MAX_FWD_BRANCH_OFFSET) |
| 3151 |
&& (branch_offset >= THM_MAX_BWD_BRANCH_OFFSET)) |
&& (branch_offset >= THM_MAX_BWD_BRANCH_OFFSET)) |
| 3152 |
stub_type = arm_thumb_arm_v4t_stub_short_branch; |
stub_type = arm_stub_short_branch_v4t_thumb_arm; |
| 3153 |
} |
} |
| 3154 |
} |
} |
| 3155 |
} |
} |
| 3156 |
else if (r_type == R_ARM_CALL) |
else if (r_type == R_ARM_CALL || r_type == R_ARM_JUMP24 || r_type == R_ARM_PLT32) |
| 3157 |
{ |
{ |
| 3158 |
if (st_type == STT_ARM_TFUNC) |
if (st_type == STT_ARM_TFUNC) |
| 3159 |
{ |
{ |
| 3165 |
{ |
{ |
| 3166 |
(*_bfd_error_handler) |
(*_bfd_error_handler) |
| 3167 |
(_("%B(%s): warning: interworking not enabled.\n" |
(_("%B(%s): warning: interworking not enabled.\n" |
| 3168 |
" first occurrence: %B: Thumb call to ARM"), |
" first occurrence: %B: ARM call to Thumb"), |
| 3169 |
sym_sec->owner, input_bfd, name); |
sym_sec->owner, input_bfd, name); |
| 3170 |
} |
} |
| 3171 |
|
|
| 3173 |
the mode change (bit 24 (H) of BLX encoding). */ |
the mode change (bit 24 (H) of BLX encoding). */ |
| 3174 |
if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2) |
if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2) |
| 3175 |
|| (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET) |
|| (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET) |
| 3176 |
|| !globals->use_blx) |
|| ((r_type == R_ARM_CALL) && !globals->use_blx) |
| 3177 |
|
|| (r_type == R_ARM_JUMP24) |
| 3178 |
|
|| (r_type == R_ARM_PLT32)) |
| 3179 |
{ |
{ |
| 3180 |
stub_type = (info->shared | globals->pic_veneer) |
stub_type = (info->shared | globals->pic_veneer) |
| 3181 |
? arm_stub_pic_long_branch |
/* PIC stubs. */ |
| 3182 |
: (globals->use_blx) |
? ((globals->use_blx) |
| 3183 |
? arm_stub_long_branch |
/* V5T and above. */ |
| 3184 |
: arm_thumb_v4t_stub_long_branch; |
? arm_stub_long_branch_any_thumb_pic |
| 3185 |
|
/* V4T stub. */ |
| 3186 |
|
: arm_stub_long_branch_v4t_arm_thumb_pic) |
| 3187 |
|
|
| 3188 |
|
/* non-PIC stubs. */ |
| 3189 |
|
: ((globals->use_blx) |
| 3190 |
|
/* V5T and above. */ |
| 3191 |
|
? arm_stub_long_branch_any_any |
| 3192 |
|
/* V4T. */ |
| 3193 |
|
: arm_stub_long_branch_v4t_arm_thumb); |
| 3194 |
} |
} |
| 3195 |
} |
} |
| 3196 |
else |
else |
| 3200 |
|| (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)) |
|| (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)) |
| 3201 |
{ |
{ |
| 3202 |
stub_type = (info->shared | globals->pic_veneer) |
stub_type = (info->shared | globals->pic_veneer) |
| 3203 |
? arm_stub_pic_long_branch |
/* PIC stubs. */ |
| 3204 |
: arm_stub_long_branch; |
? arm_stub_long_branch_any_arm_pic |
| 3205 |
|
/* non-PIC stubs. */ |
| 3206 |
|
: arm_stub_long_branch_any_any; |
| 3207 |
} |
} |
| 3208 |
} |
} |
| 3209 |
} |
} |
| 3296 |
return stub_entry; |
return stub_entry; |
| 3297 |
} |
} |
| 3298 |
|
|
| 3299 |
/* Add a new stub entry to the stub hash. Not all fields of the new |
/* Find or create a stub section. Returns a pointer to the stub section, and |
| 3300 |
stub entry are initialised. */ |
the section to which the stub section will be attached (in *LINK_SEC_P). |
| 3301 |
|
LINK_SEC_P may be NULL. */ |
| 3302 |
|
|
| 3303 |
static struct elf32_arm_stub_hash_entry * |
static asection * |
| 3304 |
elf32_arm_add_stub (const char *stub_name, |
elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section, |
| 3305 |
asection *section, |
struct elf32_arm_link_hash_table *htab) |
|
struct elf32_arm_link_hash_table *htab) |
|
| 3306 |
{ |
{ |
| 3307 |
asection *link_sec; |
asection *link_sec; |
| 3308 |
asection *stub_sec; |
asection *stub_sec; |
|
struct elf32_arm_stub_hash_entry *stub_entry; |
|
| 3309 |
|
|
| 3310 |
link_sec = htab->stub_group[section->id].link_sec; |
link_sec = htab->stub_group[section->id].link_sec; |
| 3311 |
stub_sec = htab->stub_group[section->id].stub_sec; |
stub_sec = htab->stub_group[section->id].stub_sec; |
| 3333 |
} |
} |
| 3334 |
htab->stub_group[section->id].stub_sec = stub_sec; |
htab->stub_group[section->id].stub_sec = stub_sec; |
| 3335 |
} |
} |
| 3336 |
|
|
| 3337 |
|
if (link_sec_p) |
| 3338 |
|
*link_sec_p = link_sec; |
| 3339 |
|
|
| 3340 |
|
return stub_sec; |
| 3341 |
|
} |
| 3342 |
|
|
| 3343 |
|
/* Add a new stub entry to the stub hash. Not all fields of the new |
| 3344 |
|
stub entry are initialised. */ |
| 3345 |
|
|
| 3346 |
|
static struct elf32_arm_stub_hash_entry * |
| 3347 |
|
elf32_arm_add_stub (const char *stub_name, |
| 3348 |
|
asection *section, |
| 3349 |
|
struct elf32_arm_link_hash_table *htab) |
| 3350 |
|
{ |
| 3351 |
|
asection *link_sec; |
| 3352 |
|
asection *stub_sec; |
| 3353 |
|
struct elf32_arm_stub_hash_entry *stub_entry; |
| 3354 |
|
|
| 3355 |
|
stub_sec = elf32_arm_create_or_find_stub_sec (&link_sec, section, htab); |
| 3356 |
|
if (stub_sec == NULL) |
| 3357 |
|
return NULL; |
| 3358 |
|
|
| 3359 |
/* Enter this entry into the linker stub hash table. */ |
/* Enter this entry into the linker stub hash table. */ |
| 3360 |
stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name, |
stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name, |
| 3400 |
bfd_putb16 (val, ptr); |
bfd_putb16 (val, ptr); |
| 3401 |
} |
} |
| 3402 |
|
|
| 3403 |
|
static bfd_reloc_status_type elf32_arm_final_link_relocate |
| 3404 |
|
(reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *, |
| 3405 |
|
Elf_Internal_Rela *, bfd_vma, struct bfd_link_info *, asection *, |
| 3406 |
|
const char *, int, struct elf_link_hash_entry *, bfd_boolean *, char **); |
| 3407 |
|
|
| 3408 |
static bfd_boolean |
static bfd_boolean |
| 3409 |
arm_build_one_stub (struct bfd_hash_entry *gen_entry, |
arm_build_one_stub (struct bfd_hash_entry *gen_entry, |
| 3410 |
void * in_arg) |
void * in_arg) |
| 3411 |
{ |
{ |
| 3412 |
|
#define MAXRELOCS 2 |
| 3413 |
struct elf32_arm_stub_hash_entry *stub_entry; |
struct elf32_arm_stub_hash_entry *stub_entry; |
| 3414 |
struct bfd_link_info *info; |
struct bfd_link_info *info; |
| 3415 |
struct elf32_arm_link_hash_table *htab; |
struct elf32_arm_link_hash_table *htab; |
| 3420 |
bfd_vma sym_value; |
bfd_vma sym_value; |
| 3421 |
int template_size; |
int template_size; |
| 3422 |
int size; |
int size; |
| 3423 |
const bfd_vma *template; |
const insn_sequence *template; |
| 3424 |
int i; |
int i; |
| 3425 |
struct elf32_arm_link_hash_table * globals; |
struct elf32_arm_link_hash_table * globals; |
| 3426 |
|
int stub_reloc_idx[MAXRELOCS] = {-1, -1}; |
| 3427 |
|
int stub_reloc_offset[MAXRELOCS] = {0, 0}; |
| 3428 |
|
int nrelocs = 0; |
| 3429 |
|
|
| 3430 |
/* Massage our args to the form they really have. */ |
/* Massage our args to the form they really have. */ |
| 3431 |
stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; |
stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; |
| 3451 |
+ stub_entry->target_section->output_offset |
+ stub_entry->target_section->output_offset |
| 3452 |
+ stub_entry->target_section->output_section->vma); |
+ stub_entry->target_section->output_section->vma); |
| 3453 |
|
|
| 3454 |
switch (stub_entry->stub_type) |
template = stub_entry->stub_template; |
| 3455 |
{ |
template_size = stub_entry->stub_template_size; |
|
case arm_stub_long_branch: |
|
|
template = arm_long_branch_stub; |
|
|
template_size = (sizeof (arm_long_branch_stub) / sizeof (bfd_vma)) * 4; |
|
|
break; |
|
|
case arm_thumb_v4t_stub_long_branch: |
|
|
template = arm_thumb_v4t_long_branch_stub; |
|
|
template_size = (sizeof (arm_thumb_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4; |
|
|
break; |
|
|
case arm_thumb_thumb_stub_long_branch: |
|
|
template = arm_thumb_thumb_long_branch_stub; |
|
|
template_size = (sizeof (arm_thumb_thumb_long_branch_stub) / sizeof (bfd_vma)) * 4; |
|
|
break; |
|
|
case arm_thumb_arm_v4t_stub_long_branch: |
|
|
template = arm_thumb_arm_v4t_long_branch_stub; |
|
|
template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4; |
|
|
break; |
|
|
case arm_thumb_arm_v4t_stub_short_branch: |
|
|
template = arm_thumb_arm_v4t_short_branch_stub; |
|
|
template_size = (sizeof(arm_thumb_arm_v4t_short_branch_stub) / sizeof (bfd_vma)) * 4; |
|
|
break; |
|
|
case arm_stub_pic_long_branch: |
|
|
template = arm_pic_long_branch_stub; |
|
|
template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4; |
|
|
break; |
|
|
default: |
|
|
BFD_FAIL (); |
|
|
return FALSE; |
|
|
} |
|
| 3456 |
|
|
| 3457 |
size = 0; |
size = 0; |
| 3458 |
for (i = 0; i < (template_size / 4); i++) |
for (i = 0; i < template_size; i++) |
| 3459 |
{ |
{ |
| 3460 |
/* A 0 pattern is a placeholder, every other pattern is an |
switch (template[i].type) |
| 3461 |
instruction. */ |
{ |
| 3462 |
if (template[i] != 0) |
case THUMB16_TYPE: |
| 3463 |
put_arm_insn (globals, stub_bfd, template[i], loc + size); |
{ |
| 3464 |
else |
bfd_vma data = template[i].data; |
| 3465 |
bfd_put_32 (stub_bfd, template[i], loc + size); |
if (template[i].reloc_addend != 0) |
| 3466 |
|
{ |
| 3467 |
|
/* We've borrowed the reloc_addend field to mean we should |
| 3468 |
|
insert a condition code into this (Thumb-1 branch) |
| 3469 |
|
instruction. See THUMB16_BCOND_INSN. */ |
| 3470 |
|
BFD_ASSERT ((data & 0xff00) == 0xd000); |
| 3471 |
|
data |= ((stub_entry->orig_insn >> 22) & 0xf) << 8; |
| 3472 |
|
} |
| 3473 |
|
put_thumb_insn (globals, stub_bfd, data, loc + size); |
| 3474 |
|
size += 2; |
| 3475 |
|
} |
| 3476 |
|
break; |
| 3477 |
|
|
| 3478 |
|
case THUMB32_TYPE: |
| 3479 |
|
put_thumb_insn (globals, stub_bfd, (template[i].data >> 16) & 0xffff, |
| 3480 |
|
loc + size); |
| 3481 |
|
put_thumb_insn (globals, stub_bfd, template[i].data & 0xffff, |
| 3482 |
|
loc + size + 2); |
| 3483 |
|
if (template[i].r_type != R_ARM_NONE) |
| 3484 |
|
{ |
| 3485 |
|
stub_reloc_idx[nrelocs] = i; |
| 3486 |
|
stub_reloc_offset[nrelocs++] = size; |
| 3487 |
|
} |
| 3488 |
|
size += 4; |
| 3489 |
|
break; |
| 3490 |
|
|
| 3491 |
|
case ARM_TYPE: |
| 3492 |
|
put_arm_insn (globals, stub_bfd, template[i].data, loc + size); |
| 3493 |
|
/* Handle cases where the target is encoded within the |
| 3494 |
|
instruction. */ |
| 3495 |
|
if (template[i].r_type == R_ARM_JUMP24) |
| 3496 |
|
{ |
| 3497 |
|
stub_reloc_idx[nrelocs] = i; |
| 3498 |
|
stub_reloc_offset[nrelocs++] = size; |
| 3499 |
|
} |
| 3500 |
|
size += 4; |
| 3501 |
|
break; |
| 3502 |
|
|
| 3503 |
size += 4; |
case DATA_TYPE: |
| 3504 |
|
bfd_put_32 (stub_bfd, template[i].data, loc + size); |
| 3505 |
|
stub_reloc_idx[nrelocs] = i; |
| 3506 |
|
stub_reloc_offset[nrelocs++] = size; |
| 3507 |
|
size += 4; |
| 3508 |
|
break; |
| 3509 |
|
|
| 3510 |
|
default: |
| 3511 |
|
BFD_FAIL (); |
| 3512 |
|
return FALSE; |
| 3513 |
|
} |
| 3514 |
} |
} |
| 3515 |
|
|
| 3516 |
stub_sec->size += size; |
stub_sec->size += size; |
| 3517 |
|
|
| 3518 |
|
/* Stub size has already been computed in arm_size_one_stub. Check |
| 3519 |
|
consistency. */ |
| 3520 |
|
BFD_ASSERT (size == stub_entry->stub_size); |
| 3521 |
|
|
| 3522 |
/* Destination is Thumb. Force bit 0 to 1 to reflect this. */ |
/* Destination is Thumb. Force bit 0 to 1 to reflect this. */ |
| 3523 |
if (stub_entry->st_type == STT_ARM_TFUNC) |
if (stub_entry->st_type == STT_ARM_TFUNC) |
| 3524 |
sym_value |= 1; |
sym_value |= 1; |
| 3525 |
|
|
| 3526 |
switch (stub_entry->stub_type) |
/* Assume there is at least one and at most MAXRELOCS entries to relocate |
| 3527 |
{ |
in each stub. */ |
| 3528 |
case arm_stub_long_branch: |
BFD_ASSERT (nrelocs != 0 && nrelocs <= MAXRELOCS); |
| 3529 |
_bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32), |
|
| 3530 |
stub_bfd, stub_sec, stub_sec->contents, |
for (i = 0; i < nrelocs; i++) |
| 3531 |
stub_entry->stub_offset + 4, sym_value, 0); |
if (template[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP24 |
| 3532 |
break; |
|| template[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP19 |
| 3533 |
case arm_thumb_v4t_stub_long_branch: |
|| template[stub_reloc_idx[i]].r_type == R_ARM_THM_CALL |
| 3534 |
_bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32), |
|| template[stub_reloc_idx[i]].r_type == R_ARM_THM_XPC22) |
| 3535 |
stub_bfd, stub_sec, stub_sec->contents, |
{ |
| 3536 |
stub_entry->stub_offset + 8, sym_value, 0); |
Elf_Internal_Rela rel; |
| 3537 |
break; |
bfd_boolean unresolved_reloc; |
| 3538 |
case arm_thumb_thumb_stub_long_branch: |
char *error_message; |
| 3539 |
_bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32), |
int sym_flags |
| 3540 |
stub_bfd, stub_sec, stub_sec->contents, |
= (template[stub_reloc_idx[i]].r_type != R_ARM_THM_XPC22) |
| 3541 |
stub_entry->stub_offset + 12, sym_value, 0); |
? STT_ARM_TFUNC : 0; |
| 3542 |
break; |
bfd_vma points_to = sym_value + stub_entry->target_addend; |
| 3543 |
case arm_thumb_arm_v4t_stub_long_branch: |
|
| 3544 |
_bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32), |
rel.r_offset = stub_entry->stub_offset + stub_reloc_offset[i]; |
| 3545 |
stub_bfd, stub_sec, stub_sec->contents, |
rel.r_info = ELF32_R_INFO (0, template[stub_reloc_idx[i]].r_type); |
| 3546 |
stub_entry->stub_offset + 16, sym_value, 0); |
rel.r_addend = template[stub_reloc_idx[i]].reloc_addend; |
| 3547 |
break; |
|
| 3548 |
case arm_thumb_arm_v4t_stub_short_branch: |
if (stub_entry->stub_type == arm_stub_a8_veneer_b_cond && i == 0) |
| 3549 |
|
/* The first relocation in the elf32_arm_stub_a8_veneer_b_cond[] |
| 3550 |
|
template should refer back to the instruction after the original |
| 3551 |
|
branch. */ |
| 3552 |
|
points_to = sym_value; |
| 3553 |
|
|
| 3554 |
|
/* There may be unintended consequences if this is not true. */ |
| 3555 |
|
BFD_ASSERT (stub_entry->h == NULL); |
| 3556 |
|
|
| 3557 |
|
/* Note: _bfd_final_link_relocate doesn't handle these relocations |
| 3558 |
|
properly. We should probably use this function unconditionally, |
| 3559 |
|
rather than only for certain relocations listed in the enclosing |
| 3560 |
|
conditional, for the sake of consistency. */ |
| 3561 |
|
elf32_arm_final_link_relocate (elf32_arm_howto_from_type |
| 3562 |
|
(template[stub_reloc_idx[i]].r_type), |
| 3563 |
|
stub_bfd, info->output_bfd, stub_sec, stub_sec->contents, &rel, |
| 3564 |
|
points_to, info, stub_entry->target_section, "", sym_flags, |
| 3565 |
|
(struct elf_link_hash_entry *) stub_entry->h, &unresolved_reloc, |
| 3566 |
|
&error_message); |
| 3567 |
|
} |
| 3568 |
|
else |
| 3569 |
{ |
{ |
| 3570 |
long int rel_offset; |
_bfd_final_link_relocate (elf32_arm_howto_from_type |
| 3571 |
static const insn32 t2a3_b_insn = 0xea000000; |
(template[stub_reloc_idx[i]].r_type), stub_bfd, stub_sec, |
| 3572 |
|
stub_sec->contents, stub_entry->stub_offset + stub_reloc_offset[i], |
| 3573 |
|
sym_value + stub_entry->target_addend, |
| 3574 |
|
template[stub_reloc_idx[i]].reloc_addend); |
| 3575 |
|
} |
| 3576 |
|
|
| 3577 |
rel_offset = sym_value - (stub_addr + 8 + 4); |
return TRUE; |
| 3578 |
|
#undef MAXRELOCS |
| 3579 |
|
} |
| 3580 |
|
|
| 3581 |
put_arm_insn (globals, stub_bfd, |
/* Calculate the template, template size and instruction size for a stub. |
| 3582 |
(bfd_vma) t2a3_b_insn | ((rel_offset >> 2) & 0x00FFFFFF), |
Return value is the instruction size. */ |
|
loc + 4); |
|
|
} |
|
|
break; |
|
| 3583 |
|
|
| 3584 |
case arm_stub_pic_long_branch: |
static unsigned int |
| 3585 |
/* We want the value relative to the address 8 bytes from the |
find_stub_size_and_template (enum elf32_arm_stub_type stub_type, |
| 3586 |
start of the stub. */ |
const insn_sequence **stub_template, |
| 3587 |
_bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_REL32), |
int *stub_template_size) |
| 3588 |
stub_bfd, stub_sec, stub_sec->contents, |
{ |
| 3589 |
stub_entry->stub_offset + 8, sym_value, 0); |
const insn_sequence *template = NULL; |
| 3590 |
break; |
int template_size = 0, i; |
| 3591 |
default: |
unsigned int size; |
| 3592 |
break; |
|
| 3593 |
|
template = stub_definitions[stub_type].template; |
| 3594 |
|
template_size = stub_definitions[stub_type].template_size; |
| 3595 |
|
|
| 3596 |
|
size = 0; |
| 3597 |
|
for (i = 0; i < template_size; i++) |
| 3598 |
|
{ |
| 3599 |
|
switch (template[i].type) |
| 3600 |
|
{ |
| 3601 |
|
case THUMB16_TYPE: |
| 3602 |
|
size += 2; |
| 3603 |
|
break; |
| 3604 |
|
|
| 3605 |
|
case ARM_TYPE: |
| 3606 |
|
case THUMB32_TYPE: |
| 3607 |
|
case DATA_TYPE: |
| 3608 |
|
size += 4; |
| 3609 |
|
break; |
| 3610 |
|
|
| 3611 |
|
default: |
| 3612 |
|
BFD_FAIL (); |
| 3613 |
|
return FALSE; |
| 3614 |
|
} |
| 3615 |
} |
} |
| 3616 |
|
|
| 3617 |
return TRUE; |
if (stub_template) |
| 3618 |
|
*stub_template = template; |
| 3619 |
|
|
| 3620 |
|
if (stub_template_size) |
| 3621 |
|
*stub_template_size = template_size; |
| 3622 |
|
|
| 3623 |
|
return size; |
| 3624 |
} |
} |
| 3625 |
|
|
| 3626 |
/* As above, but don't actually build the stub. Just bump offset so |
/* As above, but don't actually build the stub. Just bump offset so |
| 3632 |
{ |
{ |
| 3633 |
struct elf32_arm_stub_hash_entry *stub_entry; |
struct elf32_arm_stub_hash_entry *stub_entry; |
| 3634 |
struct elf32_arm_link_hash_table *htab; |
struct elf32_arm_link_hash_table *htab; |
| 3635 |
const bfd_vma *template; |
const insn_sequence *template; |
| 3636 |
int template_size; |
int template_size, size; |
|
int size; |
|
|
int i; |
|
| 3637 |
|
|
| 3638 |
/* Massage our args to the form they really have. */ |
/* Massage our args to the form they really have. */ |
| 3639 |
stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; |
stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; |
| 3640 |
htab = (struct elf32_arm_link_hash_table *) in_arg; |
htab = (struct elf32_arm_link_hash_table *) in_arg; |
| 3641 |
|
|
| 3642 |
switch (stub_entry->stub_type) |
BFD_ASSERT((stub_entry->stub_type > arm_stub_none) |
| 3643 |
{ |
&& stub_entry->stub_type < ARRAY_SIZE(stub_definitions)); |
| 3644 |
case arm_stub_long_branch: |
|
| 3645 |
template = arm_long_branch_stub; |
size = find_stub_size_and_template (stub_entry->stub_type, &template, |
| 3646 |
template_size = (sizeof (arm_long_branch_stub) / sizeof (bfd_vma)) * 4; |
&template_size); |
| 3647 |
break; |
|
| 3648 |
case arm_thumb_v4t_stub_long_branch: |
stub_entry->stub_size = size; |
| 3649 |
template = arm_thumb_v4t_long_branch_stub; |
stub_entry->stub_template = template; |
| 3650 |
template_size = (sizeof (arm_thumb_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4; |
stub_entry->stub_template_size = template_size; |
|
break; |
|
|
case arm_thumb_thumb_stub_long_branch: |
|
|
template = arm_thumb_thumb_long_branch_stub; |
|
|
template_size = (sizeof (arm_thumb_thumb_long_branch_stub) / sizeof (bfd_vma)) * 4; |
|
|
break; |
|
|
case arm_thumb_arm_v4t_stub_long_branch: |
|
|
template = arm_thumb_arm_v4t_long_branch_stub; |
|
|
template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4; |
|
|
break; |
|
|
case arm_thumb_arm_v4t_stub_short_branch: |
|
|
template = arm_thumb_arm_v4t_short_branch_stub; |
|
|
template_size = (sizeof(arm_thumb_arm_v4t_short_branch_stub) / sizeof (bfd_vma)) * 4; |
|
|
break; |
|
|
case arm_stub_pic_long_branch: |
|
|
template = arm_pic_long_branch_stub; |
|
|
template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4; |
|
|
break; |
|
|
default: |
|
|
BFD_FAIL (); |
|
|
return FALSE; |
|
|
break; |
|
|
} |
|
| 3651 |
|
|
|
size = 0; |
|
|
for (i = 0; i < (template_size / 4); i++) |
|
|
size += 4; |
|
| 3652 |
size = (size + 7) & ~7; |
size = (size + 7) & ~7; |
| 3653 |
stub_entry->stub_sec->size += size; |
stub_entry->stub_sec->size += size; |
| 3654 |
|
|
| 3655 |
return TRUE; |
return TRUE; |
| 3656 |
} |
} |
| 3657 |
|
|
| 3753 |
/* Steal the link_sec pointer for our list. */ |
/* Steal the link_sec pointer for our list. */ |
| 3754 |
#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec) |
#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec) |
| 3755 |
/* This happens to make the list in reverse order, |
/* This happens to make the list in reverse order, |
| 3756 |
which is what we want. */ |
which we reverse later. */ |
| 3757 |
PREV_SEC (isec) = *list; |
PREV_SEC (isec) = *list; |
| 3758 |
*list = isec; |
*list = isec; |
| 3759 |
} |
} |
| 3762 |
|
|
| 3763 |
/* See whether we can group stub sections together. Grouping stub |
/* See whether we can group stub sections together. Grouping stub |
| 3764 |
sections may result in fewer stubs. More importantly, we need to |
sections may result in fewer stubs. More importantly, we need to |
| 3765 |
put all .init* and .fini* stubs at the beginning of the .init or |
put all .init* and .fini* stubs at the end of the .init or |
| 3766 |
.fini output sections respectively, because glibc splits the |
.fini output sections respectively, because glibc splits the |
| 3767 |
_init and _fini functions into multiple parts. Putting a stub in |
_init and _fini functions into multiple parts. Putting a stub in |
| 3768 |
the middle of a function is not a good idea. */ |
the middle of a function is not a good idea. */ |
| 3770 |
static void |
static void |
| 3771 |
group_sections (struct elf32_arm_link_hash_table *htab, |
group_sections (struct elf32_arm_link_hash_table *htab, |
| 3772 |
bfd_size_type stub_group_size, |
bfd_size_type stub_group_size, |
| 3773 |
bfd_boolean stubs_always_before_branch) |
bfd_boolean stubs_always_after_branch) |
| 3774 |
{ |
{ |
| 3775 |
asection **list = htab->input_list + htab->top_index; |
asection **list = htab->input_list; |
| 3776 |
|
|
| 3777 |
do |
do |
| 3778 |
{ |
{ |
| 3779 |
asection *tail = *list; |
asection *tail = *list; |
| 3780 |
|
asection *head; |
| 3781 |
|
|
| 3782 |
if (tail == bfd_abs_section_ptr) |
if (tail == bfd_abs_section_ptr) |
| 3783 |
continue; |
continue; |
| 3784 |
|
|
| 3785 |
|
/* Reverse the list: we must avoid placing stubs at the |
| 3786 |
|
beginning of the section because the beginning of the text |
| 3787 |
|
section may be required for an interrupt vector in bare metal |
| 3788 |
|
code. */ |
| 3789 |
|
#define NEXT_SEC PREV_SEC |
| 3790 |
|
head = NULL; |
| 3791 |
while (tail != NULL) |
while (tail != NULL) |
| 3792 |
|
{ |
| 3793 |
|
/* Pop from tail. */ |
| 3794 |
|
asection *item = tail; |
| 3795 |
|
tail = PREV_SEC (item); |
| 3796 |
|
|
| 3797 |
|
/* Push on head. */ |
| 3798 |
|
NEXT_SEC (item) = head; |
| 3799 |
|
head = item; |
| 3800 |
|
} |
| 3801 |
|
|
| 3802 |
|
while (head != NULL) |
| 3803 |
{ |
{ |
| 3804 |
asection *curr; |
asection *curr; |
| 3805 |
asection *prev; |
asection *next; |
| 3806 |
bfd_size_type total; |
bfd_vma stub_group_start = head->output_offset; |
| 3807 |
|
bfd_vma end_of_next; |
| 3808 |
curr = tail; |
|
| 3809 |
total = tail->size; |
curr = head; |
| 3810 |
while ((prev = PREV_SEC (curr)) != NULL |
while (NEXT_SEC (curr) != NULL) |
| 3811 |
&& ((total += curr->output_offset - prev->output_offset) |
{ |
| 3812 |
< stub_group_size)) |
next = NEXT_SEC (curr); |
| 3813 |
curr = prev; |
end_of_next = next->output_offset + next->size; |
| 3814 |
|
if (end_of_next - stub_group_start >= stub_group_size) |
| 3815 |
|
/* End of NEXT is too far from start, so stop. */ |
| 3816 |
|
break; |
| 3817 |
|
/* Add NEXT to the group. */ |
| 3818 |
|
curr = next; |
| 3819 |
|
} |
| 3820 |
|
|
| 3821 |
/* OK, the size from the start of CURR to the end is less |
/* OK, the size from the start to the start of CURR is less |
| 3822 |
than stub_group_size and thus can be handled by one stub |
than stub_group_size and thus can be handled by one stub |
| 3823 |
section. (Or the tail section is itself larger than |
section. (Or the head section is itself larger than |
| 3824 |
stub_group_size, in which case we may be toast.) |
stub_group_size, in which case we may be toast.) |
| 3825 |
We should really be keeping track of the total size of |
We should really be keeping track of the total size of |
| 3826 |
stubs added here, as stubs contribute to the final output |
stubs added here, as stubs contribute to the final output |
| 3827 |
section size. */ |
section size. */ |
| 3828 |
do |
do |
| 3829 |
{ |
{ |
| 3830 |
prev = PREV_SEC (tail); |
next = NEXT_SEC (head); |
| 3831 |
/* Set up this stub group. */ |
/* Set up this stub group. */ |
| 3832 |
htab->stub_group[tail->id].link_sec = curr; |
htab->stub_group[head->id].link_sec = curr; |
| 3833 |
} |
} |
| 3834 |
while (tail != curr && (tail = prev) != NULL); |
while (head != curr && (head = next) != NULL); |
| 3835 |
|
|
| 3836 |
/* But wait, there's more! Input sections up to stub_group_size |
/* But wait, there's more! Input sections up to stub_group_size |
| 3837 |
bytes before the stub section can be handled by it too. */ |
bytes after the stub section can be handled by it too. */ |
| 3838 |
if (!stubs_always_before_branch) |
if (!stubs_always_after_branch) |
| 3839 |
{ |
{ |
| 3840 |
total = 0; |
stub_group_start = curr->output_offset + curr->size; |
| 3841 |
while (prev != NULL |
|
| 3842 |
&& ((total += tail->output_offset - prev->output_offset) |
while (next != NULL) |
|
< stub_group_size)) |
|
| 3843 |
{ |
{ |
| 3844 |
tail = prev; |
end_of_next = next->output_offset + next->size; |
| 3845 |
prev = PREV_SEC (tail); |
if (end_of_next - stub_group_start >= stub_group_size) |
| 3846 |
htab->stub_group[tail->id].link_sec = curr; |
/* End of NEXT is too far from stubs, so stop. */ |
| 3847 |
|
break; |
| 3848 |
|
/* Add NEXT to the stub group. */ |
| 3849 |
|
head = next; |
| 3850 |
|
next = NEXT_SEC (head); |
| 3851 |
|
htab->stub_group[head->id].link_sec = curr; |
| 3852 |
} |
} |
| 3853 |
} |
} |
| 3854 |
tail = prev; |
head = next; |
| 3855 |
} |
} |
| 3856 |
} |
} |
| 3857 |
while (list-- != htab->input_list); |
while (list++ != htab->input_list + htab->top_index); |
| 3858 |
|
|
| 3859 |
free (htab->input_list); |
free (htab->input_list); |
| 3860 |
#undef PREV_SEC |
#undef PREV_SEC |
| 3861 |
|
#undef NEXT_SEC |
| 3862 |
|
} |
| 3863 |
|
|
| 3864 |
|
/* Comparison function for sorting/searching relocations relating to Cortex-A8 |
| 3865 |
|
erratum fix. */ |
| 3866 |
|
|
| 3867 |
|
static int |
| 3868 |
|
a8_reloc_compare (const void *a, const void *b) |
| 3869 |
|
{ |
| 3870 |
|
const struct a8_erratum_reloc *ra = a, *rb = b; |
| 3871 |
|
|
| 3872 |
|
if (ra->from < rb->from) |
| 3873 |
|
return -1; |
| 3874 |
|
else if (ra->from > rb->from) |
| 3875 |
|
return 1; |
| 3876 |
|
else |
| 3877 |
|
return 0; |
| 3878 |
|
} |
| 3879 |
|
|
| 3880 |
|
static struct elf_link_hash_entry *find_thumb_glue (struct bfd_link_info *, |
| 3881 |
|
const char *, char **); |
| 3882 |
|
|
| 3883 |
|
/* Helper function to scan code for sequences which might trigger the Cortex-A8 |
| 3884 |
|
branch/TLB erratum. Fill in the table described by A8_FIXES_P, |
| 3885 |
|
NUM_A8_FIXES_P, A8_FIX_TABLE_SIZE_P. Returns true if an error occurs, false |
| 3886 |
|
otherwise. */ |
| 3887 |
|
|
| 3888 |
|
static bfd_boolean |
| 3889 |
|
cortex_a8_erratum_scan (bfd *input_bfd, |
| 3890 |
|
struct bfd_link_info *info, |
| 3891 |
|
struct a8_erratum_fix **a8_fixes_p, |
| 3892 |
|
unsigned int *num_a8_fixes_p, |
| 3893 |
|
unsigned int *a8_fix_table_size_p, |
| 3894 |
|
struct a8_erratum_reloc *a8_relocs, |
| 3895 |
|
unsigned int num_a8_relocs) |
| 3896 |
|
{ |
| 3897 |
|
asection *section; |
| 3898 |
|
struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); |
| 3899 |
|
struct a8_erratum_fix *a8_fixes = *a8_fixes_p; |
| 3900 |
|
unsigned int num_a8_fixes = *num_a8_fixes_p; |
| 3901 |
|
unsigned int a8_fix_table_size = *a8_fix_table_size_p; |
| 3902 |
|
|
| 3903 |
|
for (section = input_bfd->sections; |
| 3904 |
|
section != NULL; |
| 3905 |
|
section = section->next) |
| 3906 |
|
{ |
| 3907 |
|
bfd_byte *contents = NULL; |
| 3908 |
|
struct _arm_elf_section_data *sec_data; |
| 3909 |
|
unsigned int span; |
| 3910 |
|
bfd_vma base_vma; |
| 3911 |
|
|
| 3912 |
|
if (elf_section_type (section) != SHT_PROGBITS |
| 3913 |
|
|| (elf_section_flags (section) & SHF_EXECINSTR) == 0 |
| 3914 |
|
|| (section->flags & SEC_EXCLUDE) != 0 |
| 3915 |
|
|| (section->sec_info_type == ELF_INFO_TYPE_JUST_SYMS) |
| 3916 |
|
|| (section->output_section == bfd_abs_section_ptr)) |
| 3917 |
|
continue; |
| 3918 |
|
|
| 3919 |
|
base_vma = section->output_section->vma + section->output_offset; |
| 3920 |
|
|
| 3921 |
|
if (elf_section_data (section)->this_hdr.contents != NULL) |
| 3922 |
|
contents = elf_section_data (section)->this_hdr.contents; |
| 3923 |
|
else if (! bfd_malloc_and_get_section (input_bfd, section, &contents)) |
| 3924 |
|
return TRUE; |
| 3925 |
|
|
| 3926 |
|
sec_data = elf32_arm_section_data (section); |
| 3927 |
|
|
| 3928 |
|
for (span = 0; span < sec_data->mapcount; span++) |
| 3929 |
|
{ |
| 3930 |
|
unsigned int span_start = sec_data->map[span].vma; |
| 3931 |
|
unsigned int span_end = (span == sec_data->mapcount - 1) |
| 3932 |
|
? section->size : sec_data->map[span + 1].vma; |
| 3933 |
|
unsigned int i; |
| 3934 |
|
char span_type = sec_data->map[span].type; |
| 3935 |
|
bfd_boolean last_was_32bit = FALSE, last_was_branch = FALSE; |
| 3936 |
|
|
| 3937 |
|
if (span_type != 't') |
| 3938 |
|
continue; |
| 3939 |
|
|
| 3940 |
|
/* Span is entirely within a single 4KB region: skip scanning. */ |
| 3941 |
|
if (((base_vma + span_start) & ~0xfff) |
| 3942 |
|
== ((base_vma + span_end) & ~0xfff)) |
| 3943 |
|
continue; |
| 3944 |
|
|
| 3945 |
|
/* Scan for 32-bit Thumb-2 branches which span two 4K regions, where: |
| 3946 |
|
|
| 3947 |
|
* The opcode is BLX.W, BL.W, B.W, Bcc.W |
| 3948 |
|
* The branch target is in the same 4KB region as the |
| 3949 |
|
first half of the branch. |
| 3950 |
|
* The instruction before the branch is a 32-bit |
| 3951 |
|
length non-branch instruction. */ |
| 3952 |
|
for (i = span_start; i < span_end;) |
| 3953 |
|
{ |
| 3954 |
|
unsigned int insn = bfd_getl16 (&contents[i]); |
| 3955 |
|
bfd_boolean insn_32bit = FALSE, is_blx = FALSE, is_b = FALSE; |
| 3956 |
|
bfd_boolean is_bl = FALSE, is_bcc = FALSE, is_32bit_branch; |
| 3957 |
|
|
| 3958 |
|
if ((insn & 0xe000) == 0xe000 && (insn & 0x1800) != 0x0000) |
| 3959 |
|
insn_32bit = TRUE; |
| 3960 |
|
|
| 3961 |
|
if (insn_32bit) |
| 3962 |
|
{ |
| 3963 |
|
/* Load the rest of the insn (in manual-friendly order). */ |
| 3964 |
|
insn = (insn << 16) | bfd_getl16 (&contents[i + 2]); |
| 3965 |
|
|
| 3966 |
|
/* Encoding T4: B<c>.W. */ |
| 3967 |
|
is_b = (insn & 0xf800d000) == 0xf0009000; |
| 3968 |
|
/* Encoding T1: BL<c>.W. */ |
| 3969 |
|
is_bl = (insn & 0xf800d000) == 0xf000d000; |
| 3970 |
|
/* Encoding T2: BLX<c>.W. */ |
| 3971 |
|
is_blx = (insn & 0xf800d000) == 0xf000c000; |
| 3972 |
|
/* Encoding T3: B<c>.W (not permitted in IT block). */ |
| 3973 |
|
is_bcc = (insn & 0xf800d000) == 0xf0008000 |
| 3974 |
|
&& (insn & 0x07f00000) != 0x03800000; |
| 3975 |
|
} |
| 3976 |
|
|
| 3977 |
|
is_32bit_branch = is_b || is_bl || is_blx || is_bcc; |
| 3978 |
|
|
| 3979 |
|
if (((base_vma + i) & 0xfff) == 0xffe |
| 3980 |
|
&& insn_32bit |
| 3981 |
|
&& is_32bit_branch |
| 3982 |
|
&& last_was_32bit |
| 3983 |
|
&& ! last_was_branch) |
| 3984 |
|
{ |
| 3985 |
|
bfd_signed_vma offset; |
| 3986 |
|
bfd_boolean force_target_arm = FALSE; |
| 3987 |
|
bfd_boolean force_target_thumb = FALSE; |
| 3988 |
|
bfd_vma target; |
| 3989 |
|
enum elf32_arm_stub_type stub_type = arm_stub_none; |
| 3990 |
|
struct a8_erratum_reloc key, *found; |
| 3991 |
|
|
| 3992 |
|
key.from = base_vma + i; |
| 3993 |
|
found = bsearch (&key, a8_relocs, num_a8_relocs, |
| 3994 |
|
sizeof (struct a8_erratum_reloc), |
| 3995 |
|
&a8_reloc_compare); |
| 3996 |
|
|
| 3997 |
|
if (found) |
| 3998 |
|
{ |
| 3999 |
|
char *error_message = NULL; |
| 4000 |
|
struct elf_link_hash_entry *entry; |
| 4001 |
|
|
| 4002 |
|
/* We don't care about the error returned from this |
| 4003 |
|
function, only if there is glue or not. */ |
| 4004 |
|
entry = find_thumb_glue (info, found->sym_name, |
| 4005 |
|
&error_message); |
| 4006 |
|
|
| 4007 |
|
if (entry) |
| 4008 |
|
found->non_a8_stub = TRUE; |
| 4009 |
|
|
| 4010 |
|
if (found->r_type == R_ARM_THM_CALL |
| 4011 |
|
&& found->st_type != STT_ARM_TFUNC) |
| 4012 |
|
force_target_arm = TRUE; |
| 4013 |
|
else if (found->r_type == R_ARM_THM_CALL |
| 4014 |
|
&& found->st_type == STT_ARM_TFUNC) |
| 4015 |
|
force_target_thumb = TRUE; |
| 4016 |
|
} |
| 4017 |
|
|
| 4018 |
|
/* Check if we have an offending branch instruction. */ |
| 4019 |
|
|
| 4020 |
|
if (found && found->non_a8_stub) |
| 4021 |
|
/* We've already made a stub for this instruction, e.g. |
| 4022 |
|
it's a long branch or a Thumb->ARM stub. Assume that |
| 4023 |
|
stub will suffice to work around the A8 erratum (see |
| 4024 |
|
setting of always_after_branch above). */ |
| 4025 |
|
; |
| 4026 |
|
else if (is_bcc) |
| 4027 |
|
{ |
| 4028 |
|
offset = (insn & 0x7ff) << 1; |
| 4029 |
|
offset |= (insn & 0x3f0000) >> 4; |
| 4030 |
|
offset |= (insn & 0x2000) ? 0x40000 : 0; |
| 4031 |
|
offset |= (insn & 0x800) ? 0x80000 : 0; |
| 4032 |
|
offset |= (insn & 0x4000000) ? 0x100000 : 0; |
| 4033 |
|
if (offset & 0x100000) |
| 4034 |
|
offset |= ~ ((bfd_signed_vma) 0xfffff); |
| 4035 |
|
stub_type = arm_stub_a8_veneer_b_cond; |
| 4036 |
|
} |
| 4037 |
|
else if (is_b || is_bl || is_blx) |
| 4038 |
|
{ |
| 4039 |
|
int s = (insn & 0x4000000) != 0; |
| 4040 |
|
int j1 = (insn & 0x2000) != 0; |
| 4041 |
|
int j2 = (insn & 0x800) != 0; |
| 4042 |
|
int i1 = !(j1 ^ s); |
| 4043 |
|
int i2 = !(j2 ^ s); |
| 4044 |
|
|
| 4045 |
|
offset = (insn & 0x7ff) << 1; |
| 4046 |
|
offset |= (insn & 0x3ff0000) >> 4; |
| 4047 |
|
offset |= i2 << 22; |
| 4048 |
|
offset |= i1 << 23; |
| 4049 |
|
offset |= s << 24; |
| 4050 |
|
if (offset & 0x1000000) |
| 4051 |
|
offset |= ~ ((bfd_signed_vma) 0xffffff); |
| 4052 |
|
|
| 4053 |
|
if (is_blx) |
| 4054 |
|
offset &= ~ ((bfd_signed_vma) 3); |
| 4055 |
|
|
| 4056 |
|
stub_type = is_blx ? arm_stub_a8_veneer_blx : |
| 4057 |
|
is_bl ? arm_stub_a8_veneer_bl : arm_stub_a8_veneer_b; |
| 4058 |
|
} |
| 4059 |
|
|
| 4060 |
|
if (stub_type != arm_stub_none) |
| 4061 |
|
{ |
| 4062 |
|
bfd_vma pc_for_insn = base_vma + i + 4; |
| 4063 |
|
|
| 4064 |
|
/* The original instruction is a BL, but the target is |
| 4065 |
|
an ARM instruction. If we were not making a stub, |
| 4066 |
|
the BL would have been converted to a BLX. Use the |
| 4067 |
|
BLX stub instead in that case. */ |
| 4068 |
|
if (htab->use_blx && force_target_arm |
| 4069 |
|
&& stub_type == arm_stub_a8_veneer_bl) |
| 4070 |
|
{ |
| 4071 |
|
stub_type = arm_stub_a8_veneer_blx; |
| 4072 |
|
is_blx = TRUE; |
| 4073 |
|
is_bl = FALSE; |
| 4074 |
|
} |
| 4075 |
|
/* Conversely, if the original instruction was |
| 4076 |
|
BLX but the target is Thumb mode, use the BL |
| 4077 |
|
stub. */ |
| 4078 |
|
else if (force_target_thumb |
| 4079 |
|
&& stub_type == arm_stub_a8_veneer_blx) |
| 4080 |
|
{ |
| 4081 |
|
stub_type = arm_stub_a8_veneer_bl; |
| 4082 |
|
is_blx = FALSE; |
| 4083 |
|
is_bl = TRUE; |
| 4084 |
|
} |
| 4085 |
|
|
| 4086 |
|
if (is_blx) |
| 4087 |
|
pc_for_insn &= ~ ((bfd_vma) 3); |
| 4088 |
|
|
| 4089 |
|
/* If we found a relocation, use the proper destination, |
| 4090 |
|
not the offset in the (unrelocated) instruction. |
| 4091 |
|
Note this is always done if we switched the stub type |
| 4092 |
|
above. */ |
| 4093 |
|
if (found) |
| 4094 |
|
offset = |
| 4095 |
|
(bfd_signed_vma) (found->destination - pc_for_insn); |
| 4096 |
|
|
| 4097 |
|
target = pc_for_insn + offset; |
| 4098 |
|
|
| 4099 |
|
/* The BLX stub is ARM-mode code. Adjust the offset to |
| 4100 |
|
take the different PC value (+8 instead of +4) into |
| 4101 |
|
account. */ |
| 4102 |
|
if (stub_type == arm_stub_a8_veneer_blx) |
| 4103 |
|
offset += 4; |
| 4104 |
|
|
| 4105 |
|
if (((base_vma + i) & ~0xfff) == (target & ~0xfff)) |
| 4106 |
|
{ |
| 4107 |
|
char *stub_name; |
| 4108 |
|
|
| 4109 |
|
if (num_a8_fixes == a8_fix_table_size) |
| 4110 |
|
{ |
| 4111 |
|
a8_fix_table_size *= 2; |
| 4112 |
|
a8_fixes = bfd_realloc (a8_fixes, |
| 4113 |
|
sizeof (struct a8_erratum_fix) |
| 4114 |
|
* a8_fix_table_size); |
| 4115 |
|
} |
| 4116 |
|
|
| 4117 |
|
stub_name = bfd_malloc (8 + 1 + 8 + 1); |
| 4118 |
|
if (stub_name != NULL) |
| 4119 |
|
sprintf (stub_name, "%x:%x", section->id, i); |
| 4120 |
|
|
| 4121 |
|
a8_fixes[num_a8_fixes].input_bfd = input_bfd; |
| 4122 |
|
a8_fixes[num_a8_fixes].section = section; |
| 4123 |
|
a8_fixes[num_a8_fixes].offset = i; |
| 4124 |
|
a8_fixes[num_a8_fixes].addend = offset; |
| 4125 |
|
a8_fixes[num_a8_fixes].orig_insn = insn; |
| 4126 |
|
a8_fixes[num_a8_fixes].stub_name = stub_name; |
| 4127 |
|
a8_fixes[num_a8_fixes].stub_type = stub_type; |
| 4128 |
|
|
| 4129 |
|
num_a8_fixes++; |
| 4130 |
|
} |
| 4131 |
|
} |
| 4132 |
|
} |
| 4133 |
|
|
| 4134 |
|
i += insn_32bit ? 4 : 2; |
| 4135 |
|
last_was_32bit = insn_32bit; |
| 4136 |
|
last_was_branch = is_32bit_branch; |
| 4137 |
|
} |
| 4138 |
|
} |
| 4139 |
|
|
| 4140 |
|
if (elf_section_data (section)->this_hdr.contents == NULL) |
| 4141 |
|
free (contents); |
| 4142 |
|
} |
| 4143 |
|
|
| 4144 |
|
*a8_fixes_p = a8_fixes; |
| 4145 |
|
*num_a8_fixes_p = num_a8_fixes; |
| 4146 |
|
*a8_fix_table_size_p = a8_fix_table_size; |
| 4147 |
|
|
| 4148 |
|
return FALSE; |
| 4149 |
} |
} |
| 4150 |
|
|
| 4151 |
/* Determine and set the size of the stub section for a final link. |
/* Determine and set the size of the stub section for a final link. |
| 4163 |
void (*layout_sections_again) (void)) |
void (*layout_sections_again) (void)) |
| 4164 |
{ |
{ |
| 4165 |
bfd_size_type stub_group_size; |
bfd_size_type stub_group_size; |
| 4166 |
bfd_boolean stubs_always_before_branch; |
bfd_boolean stubs_always_after_branch; |
| 4167 |
bfd_boolean stub_changed = 0; |
bfd_boolean stub_changed = 0; |
| 4168 |
struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); |
struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); |
| 4169 |
|
struct a8_erratum_fix *a8_fixes = NULL; |
| 4170 |
|
unsigned int num_a8_fixes = 0, prev_num_a8_fixes = 0, a8_fix_table_size = 10; |
| 4171 |
|
struct a8_erratum_reloc *a8_relocs = NULL; |
| 4172 |
|
unsigned int num_a8_relocs = 0, a8_reloc_table_size = 10, i; |
| 4173 |
|
|
| 4174 |
|
if (htab->fix_cortex_a8) |
| 4175 |
|
{ |
| 4176 |
|
a8_fixes = bfd_zmalloc (sizeof (struct a8_erratum_fix) |
| 4177 |
|
* a8_fix_table_size); |
| 4178 |
|
a8_relocs = bfd_zmalloc (sizeof (struct a8_erratum_reloc) |
| 4179 |
|
* a8_reloc_table_size); |
| 4180 |
|
} |
| 4181 |
|
|
| 4182 |
/* Propagate mach to stub bfd, because it may not have been |
/* Propagate mach to stub bfd, because it may not have been |
| 4183 |
finalized when we created stub_bfd. */ |
finalized when we created stub_bfd. */ |
| 4188 |
htab->stub_bfd = stub_bfd; |
htab->stub_bfd = stub_bfd; |
| 4189 |
htab->add_stub_section = add_stub_section; |
htab->add_stub_section = add_stub_section; |
| 4190 |
htab->layout_sections_again = layout_sections_again; |
htab->layout_sections_again = layout_sections_again; |
| 4191 |
stubs_always_before_branch = group_size < 0; |
stubs_always_after_branch = group_size < 0; |
| 4192 |
|
|
| 4193 |
|
/* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page |
| 4194 |
|
as the first half of a 32-bit branch straddling two 4K pages. This is a |
| 4195 |
|
crude way of enforcing that. */ |
| 4196 |
|
if (htab->fix_cortex_a8) |
| 4197 |
|
stubs_always_after_branch = 1; |
| 4198 |
|
|
| 4199 |
if (group_size < 0) |
if (group_size < 0) |
| 4200 |
stub_group_size = -group_size; |
stub_group_size = -group_size; |
| 4201 |
else |
else |
| 4215 |
stub_group_size = 4170000; |
stub_group_size = 4170000; |
| 4216 |
} |
} |
| 4217 |
|
|
| 4218 |
group_sections (htab, stub_group_size, stubs_always_before_branch); |
group_sections (htab, stub_group_size, stubs_always_after_branch); |
| 4219 |
|
|
| 4220 |
while (1) |
while (1) |
| 4221 |
{ |
{ |
| 4223 |
unsigned int bfd_indx; |
unsigned int bfd_indx; |
| 4224 |
asection *stub_sec; |
asection *stub_sec; |
| 4225 |
|
|
| 4226 |
|
num_a8_fixes = 0; |
| 4227 |
|
|
| 4228 |
for (input_bfd = info->input_bfds, bfd_indx = 0; |
for (input_bfd = info->input_bfds, bfd_indx = 0; |
| 4229 |
input_bfd != NULL; |
input_bfd != NULL; |
| 4230 |
input_bfd = input_bfd->link_next, bfd_indx++) |
input_bfd = input_bfd->link_next, bfd_indx++) |
| 4233 |
asection *section; |
asection *section; |
| 4234 |
Elf_Internal_Sym *local_syms = NULL; |
Elf_Internal_Sym *local_syms = NULL; |
| 4235 |
|
|
| 4236 |
|
num_a8_relocs = 0; |
| 4237 |
|
|
| 4238 |
/* We'll need the symbol table in a second. */ |
/* We'll need the symbol table in a second. */ |
| 4239 |
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; |
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; |
| 4240 |
if (symtab_hdr->sh_info == 0) |
if (symtab_hdr->sh_info == 0) |
| 4283 |
char *stub_name; |
char *stub_name; |
| 4284 |
const asection *id_sec; |
const asection *id_sec; |
| 4285 |
unsigned char st_type; |
unsigned char st_type; |
| 4286 |
|
bfd_boolean created_stub = FALSE; |
| 4287 |
|
|
| 4288 |
r_type = ELF32_R_TYPE (irela->r_info); |
r_type = ELF32_R_TYPE (irela->r_info); |
| 4289 |
r_indx = ELF32_R_SYM (irela->r_info); |
r_indx = ELF32_R_SYM (irela->r_info); |
| 4297 |
goto error_ret_free_local; |
goto error_ret_free_local; |
| 4298 |
} |
} |
| 4299 |
|
|
| 4300 |
/* Only look for stubs on call instructions. */ |
/* Only look for stubs on branch instructions. */ |
| 4301 |
if ((r_type != (unsigned int) R_ARM_CALL) |
if ((r_type != (unsigned int) R_ARM_CALL) |
| 4302 |
&& (r_type != (unsigned int) R_ARM_THM_CALL)) |
&& (r_type != (unsigned int) R_ARM_THM_CALL) |
| 4303 |
|
&& (r_type != (unsigned int) R_ARM_JUMP24) |
| 4304 |
|
&& (r_type != (unsigned int) R_ARM_THM_JUMP19) |
| 4305 |
|
&& (r_type != (unsigned int) R_ARM_THM_XPC22) |
| 4306 |
|
&& (r_type != (unsigned int) R_ARM_THM_JUMP24) |
| 4307 |
|
&& (r_type != (unsigned int) R_ARM_PLT32)) |
| 4308 |
continue; |
continue; |
| 4309 |
|
|
| 4310 |
/* Now determine the call target, its name, value, |
/* Now determine the call target, its name, value, |
| 4366 |
{ |
{ |
| 4367 |
sym_sec = hash->root.root.u.def.section; |
sym_sec = hash->root.root.u.def.section; |
| 4368 |
sym_value = hash->root.root.u.def.value; |
sym_value = hash->root.root.u.def.value; |
| 4369 |
if (sym_sec->output_section != NULL) |
|
| 4370 |
|
struct elf32_arm_link_hash_table *globals = |
| 4371 |
|
elf32_arm_hash_table (info); |
| 4372 |
|
|
| 4373 |
|
/* For a destination in a shared library, |
| 4374 |
|
use the PLT stub as target address to |
| 4375 |
|
decide whether a branch stub is |
| 4376 |
|
needed. */ |
| 4377 |
|
if (globals->splt != NULL && hash != NULL |
| 4378 |
|
&& hash->root.plt.offset != (bfd_vma) -1) |
| 4379 |
|
{ |
| 4380 |
|
sym_sec = globals->splt; |
| 4381 |
|
sym_value = hash->root.plt.offset; |
| 4382 |
|
if (sym_sec->output_section != NULL) |
| 4383 |
|
destination = (sym_value |
| 4384 |
|
+ sym_sec->output_offset |
| 4385 |
|
+ sym_sec->output_section->vma); |
| 4386 |
|
} |
| 4387 |
|
else if (sym_sec->output_section != NULL) |
| 4388 |
destination = (sym_value + irela->r_addend |
destination = (sym_value + irela->r_addend |
| 4389 |
+ sym_sec->output_offset |
+ sym_sec->output_offset |
| 4390 |
+ sym_sec->output_section->vma); |
+ sym_sec->output_section->vma); |
| 4391 |
} |
} |
| 4392 |
else if (hash->root.root.type == bfd_link_hash_undefweak |
else if ((hash->root.root.type == bfd_link_hash_undefined) |
| 4393 |
|| hash->root.root.type == bfd_link_hash_undefined) |
|| (hash->root.root.type == bfd_link_hash_undefweak)) |
| 4394 |
/* For a shared library, these will need a PLT stub, |
{ |
| 4395 |
which is treated separately. |
/* For a shared library, use the PLT stub as |
| 4396 |
For absolute code, they cannot be handled. */ |
target address to decide whether a long |
| 4397 |
continue; |
branch stub is needed. |
| 4398 |
|
For absolute code, they cannot be handled. */ |
| 4399 |
|
struct elf32_arm_link_hash_table *globals = |
| 4400 |
|
elf32_arm_hash_table (info); |
| 4401 |
|
|
| 4402 |
|
if (globals->splt != NULL && hash != NULL |
| 4403 |
|
&& hash->root.plt.offset != (bfd_vma) -1) |
| 4404 |
|
{ |
| 4405 |
|
sym_sec = globals->splt; |
| 4406 |
|
sym_value = hash->root.plt.offset; |
| 4407 |
|
if (sym_sec->output_section != NULL) |
| 4408 |
|
destination = (sym_value |
| 4409 |
|
+ sym_sec->output_offset |
| 4410 |
|
+ sym_sec->output_section->vma); |
| 4411 |
|
} |
| 4412 |
|
else |
| 4413 |
|
continue; |
| 4414 |
|
} |
| 4415 |
else |
else |
| 4416 |
{ |
{ |
| 4417 |
bfd_set_error (bfd_error_bad_value); |
bfd_set_error (bfd_error_bad_value); |
| 4421 |
sym_name = hash->root.root.root.string; |
sym_name = hash->root.root.root.string; |
| 4422 |
} |
} |
| 4423 |
|
|
| 4424 |
/* Determine what (if any) linker stub is needed. */ |
do |
|
stub_type = arm_type_of_stub (info, section, irela, st_type, |
|
|
hash, destination, sym_sec, |
|
|
input_bfd, sym_name); |
|
|
if (stub_type == arm_stub_none) |
|
|
continue; |
|
|
|
|
|
/* Support for grouping stub sections. */ |
|
|
id_sec = htab->stub_group[section->id].link_sec; |
|
|
|
|
|
/* Get the name of this stub. */ |
|
|
stub_name = elf32_arm_stub_name (id_sec, sym_sec, hash, irela); |
|
|
if (!stub_name) |
|
|
goto error_ret_free_internal; |
|
|
|
|
|
stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, |
|
|
stub_name, |
|
|
FALSE, FALSE); |
|
|
if (stub_entry != NULL) |
|
| 4425 |
{ |
{ |
| 4426 |
/* The proper stub has already been created. */ |
/* Determine what (if any) linker stub is needed. */ |
| 4427 |
free (stub_name); |
stub_type = arm_type_of_stub (info, section, irela, |
| 4428 |
continue; |
st_type, hash, |
| 4429 |
} |
destination, sym_sec, |
| 4430 |
|
input_bfd, sym_name); |
| 4431 |
|
if (stub_type == arm_stub_none) |
| 4432 |
|
break; |
| 4433 |
|
|
| 4434 |
|
/* Support for grouping stub sections. */ |
| 4435 |
|
id_sec = htab->stub_group[section->id].link_sec; |
| 4436 |
|
|
| 4437 |
|
/* Get the name of this stub. */ |
| 4438 |
|
stub_name = elf32_arm_stub_name (id_sec, sym_sec, hash, |
| 4439 |
|
irela); |
| 4440 |
|
if (!stub_name) |
| 4441 |
|
goto error_ret_free_internal; |
| 4442 |
|
|
| 4443 |
|
/* We've either created a stub for this reloc already, |
| 4444 |
|
or we are about to. */ |
| 4445 |
|
created_stub = TRUE; |
| 4446 |
|
|
| 4447 |
|
stub_entry = arm_stub_hash_lookup |
| 4448 |
|
(&htab->stub_hash_table, stub_name, |
| 4449 |
|
FALSE, FALSE); |
| 4450 |
|
if (stub_entry != NULL) |
| 4451 |
|
{ |
| 4452 |
|
/* The proper stub has already been created. */ |
| 4453 |
|
free (stub_name); |
| 4454 |
|
break; |
| 4455 |
|
} |
| 4456 |
|
|
| 4457 |
stub_entry = elf32_arm_add_stub (stub_name, section, htab); |
stub_entry = elf32_arm_add_stub (stub_name, section, |
| 4458 |
if (stub_entry == NULL) |
htab); |
| 4459 |
{ |
if (stub_entry == NULL) |
| 4460 |
free (stub_name); |
{ |
| 4461 |
goto error_ret_free_internal; |
free (stub_name); |
| 4462 |
} |
goto error_ret_free_internal; |
| 4463 |
|
} |
| 4464 |
|
|
| 4465 |
stub_entry->target_value = sym_value; |
stub_entry->target_value = sym_value; |
| 4466 |
stub_entry->target_section = sym_sec; |
stub_entry->target_section = sym_sec; |
| 4467 |
stub_entry->stub_type = stub_type; |
stub_entry->stub_type = stub_type; |
| 4468 |
stub_entry->h = hash; |
stub_entry->h = hash; |
| 4469 |
stub_entry->st_type = st_type; |
stub_entry->st_type = st_type; |
| 4470 |
|
|
| 4471 |
if (sym_name == NULL) |
if (sym_name == NULL) |
| 4472 |
sym_name = "unnamed"; |
sym_name = "unnamed"; |
| 4473 |
stub_entry->output_name |
stub_entry->output_name |
| 4474 |
= bfd_alloc (htab->stub_bfd, |
= bfd_alloc (htab->stub_bfd, |
| 4475 |
sizeof (THUMB2ARM_GLUE_ENTRY_NAME) |
sizeof (THUMB2ARM_GLUE_ENTRY_NAME) |
| 4476 |
+ strlen (sym_name)); |
+ strlen (sym_name)); |
| 4477 |
if (stub_entry->output_name == NULL) |
if (stub_entry->output_name == NULL) |
| 4478 |
{ |
{ |
| 4479 |
free (stub_name); |
free (stub_name); |
| 4480 |
goto error_ret_free_internal; |
goto error_ret_free_internal; |
| 4481 |
} |
} |
| 4482 |
|
|
| 4483 |
|
/* For historical reasons, use the existing names for |
| 4484 |
|
ARM-to-Thumb and Thumb-to-ARM stubs. */ |
| 4485 |
|
if ( ((r_type == (unsigned int) R_ARM_THM_CALL) |
| 4486 |
|
|| (r_type == (unsigned int) R_ARM_THM_JUMP24)) |
| 4487 |
|
&& st_type != STT_ARM_TFUNC) |
| 4488 |
|
sprintf (stub_entry->output_name, |
| 4489 |
|
THUMB2ARM_GLUE_ENTRY_NAME, sym_name); |
| 4490 |
|
else if ( ((r_type == (unsigned int) R_ARM_CALL) |
| 4491 |
|
|| (r_type == (unsigned int) R_ARM_JUMP24)) |
| 4492 |
|
&& st_type == STT_ARM_TFUNC) |
| 4493 |
|
sprintf (stub_entry->output_name, |
| 4494 |
|
ARM2THUMB_GLUE_ENTRY_NAME, sym_name); |
| 4495 |
|
else |
| 4496 |
|
sprintf (stub_entry->output_name, STUB_ENTRY_NAME, |
| 4497 |
|
sym_name); |
| 4498 |
|
|
| 4499 |
/* For historical reasons, use the existing names for |
stub_changed = TRUE; |
| 4500 |
ARM-to-Thumb and Thumb-to-ARM stubs. */ |
} |
| 4501 |
if (r_type == (unsigned int) R_ARM_THM_CALL |
while (0); |
|
&& st_type != STT_ARM_TFUNC) |
|
|
sprintf (stub_entry->output_name, THUMB2ARM_GLUE_ENTRY_NAME, |
|
|
sym_name); |
|
|
else if (r_type == (unsigned int) R_ARM_CALL |
|
|
&& st_type == STT_ARM_TFUNC) |
|
|
sprintf (stub_entry->output_name, ARM2THUMB_GLUE_ENTRY_NAME, |
|
|
sym_name); |
|
|
else |
|
|
sprintf (stub_entry->output_name, STUB_ENTRY_NAME, |
|
|
sym_name); |
|
| 4502 |
|
|
| 4503 |
stub_changed = TRUE; |
/* Look for relocations which might trigger Cortex-A8 |
| 4504 |
|
erratum. */ |
| 4505 |
|
if (htab->fix_cortex_a8 |
| 4506 |
|
&& (r_type == (unsigned int) R_ARM_THM_JUMP24 |
| 4507 |
|
|| r_type == (unsigned int) R_ARM_THM_JUMP19 |
| 4508 |
|
|| r_type == (unsigned int) R_ARM_THM_CALL |
| 4509 |
|
|| r_type == (unsigned int) R_ARM_THM_XPC22)) |
| 4510 |
|
{ |
| 4511 |
|
bfd_vma from = section->output_section->vma |
| 4512 |
|
+ section->output_offset |
| 4513 |
|
+ irela->r_offset; |
| 4514 |
|
|
| 4515 |
|
if ((from & 0xfff) == 0xffe) |
| 4516 |
|
{ |
| 4517 |
|
/* Found a candidate. Note we haven't checked the |
| 4518 |
|
destination is within 4K here: if we do so (and |
| 4519 |
|
don't create an entry in a8_relocs) we can't tell |
| 4520 |
|
that a branch should have been relocated when |
| 4521 |
|
scanning later. */ |
| 4522 |
|
if (num_a8_relocs == a8_reloc_table_size) |
| 4523 |
|
{ |
| 4524 |
|
a8_reloc_table_size *= 2; |
| 4525 |
|
a8_relocs = bfd_realloc (a8_relocs, |
| 4526 |
|
sizeof (struct a8_erratum_reloc) |
| 4527 |
|
* a8_reloc_table_size); |
| 4528 |
|
} |
| 4529 |
|
|
| 4530 |
|
a8_relocs[num_a8_relocs].from = from; |
| 4531 |
|
a8_relocs[num_a8_relocs].destination = destination; |
| 4532 |
|
a8_relocs[num_a8_relocs].r_type = r_type; |
| 4533 |
|
a8_relocs[num_a8_relocs].st_type = st_type; |
| 4534 |
|
a8_relocs[num_a8_relocs].sym_name = sym_name; |
| 4535 |
|
a8_relocs[num_a8_relocs].non_a8_stub = created_stub; |
| 4536 |
|
|
| 4537 |
|
num_a8_relocs++; |
| 4538 |
|
} |
| 4539 |
|
} |
| 4540 |
} |
} |
| 4541 |
|
|
| 4542 |
/* We're done with the internal relocs, free them. */ |
/* We're done with the internal relocs, free them. */ |
| 4543 |
if (elf_section_data (section)->relocs == NULL) |
if (elf_section_data (section)->relocs == NULL) |
| 4544 |
free (internal_relocs); |
free (internal_relocs); |
| 4545 |
|
} |
| 4546 |
|
|
| 4547 |
|
if (htab->fix_cortex_a8) |
| 4548 |
|
{ |
| 4549 |
|
/* Sort relocs which might apply to Cortex-A8 erratum. */ |
| 4550 |
|
qsort (a8_relocs, num_a8_relocs, sizeof (struct a8_erratum_reloc), |
| 4551 |
|
&a8_reloc_compare); |
| 4552 |
|
|
| 4553 |
|
/* Scan for branches which might trigger Cortex-A8 erratum. */ |
| 4554 |
|
if (cortex_a8_erratum_scan (input_bfd, info, &a8_fixes, |
| 4555 |
|
&num_a8_fixes, &a8_fix_table_size, |
| 4556 |
|
a8_relocs, num_a8_relocs) != 0) |
| 4557 |
|
goto error_ret_free_local; |
| 4558 |
} |
} |
| 4559 |
} |
} |
| 4560 |
|
|
| 4561 |
|
if (htab->fix_cortex_a8 && num_a8_fixes != prev_num_a8_fixes) |
| 4562 |
|
stub_changed = TRUE; |
| 4563 |
|
|
| 4564 |
if (!stub_changed) |
if (!stub_changed) |
| 4565 |
break; |
break; |
| 4566 |
|
|
| 4569 |
for (stub_sec = htab->stub_bfd->sections; |
for (stub_sec = htab->stub_bfd->sections; |
| 4570 |
stub_sec != NULL; |
stub_sec != NULL; |
| 4571 |
stub_sec = stub_sec->next) |
stub_sec = stub_sec->next) |
| 4572 |
stub_sec->size = 0; |
{ |
| 4573 |
|
/* Ignore non-stub sections. */ |
| 4574 |
|
if (!strstr (stub_sec->name, STUB_SUFFIX)) |
| 4575 |
|
continue; |
| 4576 |
|
|
| 4577 |
|
stub_sec->size = 0; |
| 4578 |
|
} |
| 4579 |
|
|
| 4580 |
bfd_hash_traverse (&htab->stub_hash_table, arm_size_one_stub, htab); |
bfd_hash_traverse (&htab->stub_hash_table, arm_size_one_stub, htab); |
| 4581 |
|
|
| 4582 |
|
/* Add Cortex-A8 erratum veneers to stub section sizes too. */ |
| 4583 |
|
if (htab->fix_cortex_a8) |
| 4584 |
|
for (i = 0; i < num_a8_fixes; i++) |
| 4585 |
|
{ |
| 4586 |
|
stub_sec = elf32_arm_create_or_find_stub_sec (NULL, |
| 4587 |
|
a8_fixes[i].section, htab); |
| 4588 |
|
|
| 4589 |
|
if (stub_sec == NULL) |
| 4590 |
|
goto error_ret_free_local; |
| 4591 |
|
|
| 4592 |
|
stub_sec->size |
| 4593 |
|
+= find_stub_size_and_template (a8_fixes[i].stub_type, NULL, |
| 4594 |
|
NULL); |
| 4595 |
|
} |
| 4596 |
|
|
| 4597 |
|
|
| 4598 |
/* Ask the linker to do its stuff. */ |
/* Ask the linker to do its stuff. */ |
| 4599 |
(*htab->layout_sections_again) (); |
(*htab->layout_sections_again) (); |
| 4600 |
stub_changed = FALSE; |
stub_changed = FALSE; |
| 4601 |
|
prev_num_a8_fixes = num_a8_fixes; |
| 4602 |
} |
} |
| 4603 |
|
|
| 4604 |
|
/* Add stubs for Cortex-A8 erratum fixes now. */ |
| 4605 |
|
if (htab->fix_cortex_a8) |
| 4606 |
|
{ |
| 4607 |
|
for (i = 0; i < num_a8_fixes; i++) |
| 4608 |
|
{ |
| 4609 |
|
struct elf32_arm_stub_hash_entry *stub_entry; |
| 4610 |
|
char *stub_name = a8_fixes[i].stub_name; |
| 4611 |
|
asection *section = a8_fixes[i].section; |
| 4612 |
|
unsigned int section_id = a8_fixes[i].section->id; |
| 4613 |
|
asection *link_sec = htab->stub_group[section_id].link_sec; |
| 4614 |
|
asection *stub_sec = htab->stub_group[section_id].stub_sec; |
| 4615 |
|
const insn_sequence *template; |
| 4616 |
|
int template_size, size = 0; |
| 4617 |
|
|
| 4618 |
|
stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name, |
| 4619 |
|
TRUE, FALSE); |
| 4620 |
|
if (stub_entry == NULL) |
| 4621 |
|
{ |
| 4622 |
|
(*_bfd_error_handler) (_("%s: cannot create stub entry %s"), |
| 4623 |
|
section->owner, |
| 4624 |
|
stub_name); |
| 4625 |
|
return FALSE; |
| 4626 |
|
} |
| 4627 |
|
|
| 4628 |
|
stub_entry->stub_sec = stub_sec; |
| 4629 |
|
stub_entry->stub_offset = 0; |
| 4630 |
|
stub_entry->id_sec = link_sec; |
| 4631 |
|
stub_entry->stub_type = a8_fixes[i].stub_type; |
| 4632 |
|
stub_entry->target_section = a8_fixes[i].section; |
| 4633 |
|
stub_entry->target_value = a8_fixes[i].offset; |
| 4634 |
|
stub_entry->target_addend = a8_fixes[i].addend; |
| 4635 |
|
stub_entry->orig_insn = a8_fixes[i].orig_insn; |
| 4636 |
|
stub_entry->st_type = STT_ARM_TFUNC; |
| 4637 |
|
|
| 4638 |
|
size = find_stub_size_and_template (a8_fixes[i].stub_type, &template, |
| 4639 |
|
&template_size); |
| 4640 |
|
|
| 4641 |
|
stub_entry->stub_size = size; |
| 4642 |
|
stub_entry->stub_template = template; |
| 4643 |
|
stub_entry->stub_template_size = template_size; |
| 4644 |
|
} |
| 4645 |
|
|
| 4646 |
|
/* Stash the Cortex-A8 erratum fix array for use later in |
| 4647 |
|
elf32_arm_write_section(). */ |
| 4648 |
|
htab->a8_erratum_fixes = a8_fixes; |
| 4649 |
|
htab->num_a8_erratum_fixes = num_a8_fixes; |
| 4650 |
|
} |
| 4651 |
|
else |
| 4652 |
|
{ |
| 4653 |
|
htab->a8_erratum_fixes = NULL; |
| 4654 |
|
htab->num_a8_erratum_fixes = 0; |
| 4655 |
|
} |
| 4656 |
return TRUE; |
return TRUE; |
| 4657 |
|
|
| 4658 |
error_ret_free_local: |
error_ret_free_local: |
| 4842 |
bfd_byte * contents; |
bfd_byte * contents; |
| 4843 |
|
|
| 4844 |
if (size == 0) |
if (size == 0) |
| 4845 |
return; |
{ |
| 4846 |
|
/* Do not include empty glue sections in the output. */ |
| 4847 |
|
if (abfd != NULL) |
| 4848 |
|
{ |
| 4849 |
|
s = bfd_get_section_by_name (abfd, name); |
| 4850 |
|
if (s != NULL) |
| 4851 |
|
s->flags |= SEC_EXCLUDE; |
| 4852 |
|
} |
| 4853 |
|
return; |
| 4854 |
|
} |
| 4855 |
|
|
| 4856 |
BFD_ASSERT (abfd != NULL); |
BFD_ASSERT (abfd != NULL); |
| 4857 |
|
|
| 4963 |
return myh; |
return myh; |
| 4964 |
} |
} |
| 4965 |
|
|
|
static void |
|
|
record_thumb_to_arm_glue (struct bfd_link_info *link_info, |
|
|
struct elf_link_hash_entry *h) |
|
|
{ |
|
|
const char *name = h->root.root.string; |
|
|
asection *s; |
|
|
char *tmp_name; |
|
|
struct elf_link_hash_entry *myh; |
|
|
struct bfd_link_hash_entry *bh; |
|
|
struct elf32_arm_link_hash_table *hash_table; |
|
|
bfd_vma val; |
|
|
|
|
|
hash_table = elf32_arm_hash_table (link_info); |
|
|
|
|
|
BFD_ASSERT (hash_table != NULL); |
|
|
BFD_ASSERT (hash_table->bfd_of_glue_owner != NULL); |
|
|
|
|
|
s = bfd_get_section_by_name |
|
|
(hash_table->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME); |
|
|
|
|
|
BFD_ASSERT (s != NULL); |
|
|
|
|
|
tmp_name = bfd_malloc ((bfd_size_type) strlen (name) |
|
|
+ strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1); |
|
|
|
|
|
BFD_ASSERT (tmp_name); |
|
|
|
|
|
sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name); |
|
|
|
|
|
myh = elf_link_hash_lookup |
|
|
(&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE); |
|
|
|
|
|
if (myh != NULL) |
|
|
{ |
|
|
/* We've already seen this guy. */ |
|
|
free (tmp_name); |
|
|
return; |
|
|
} |
|
|
|
|
|
/* The only trick here is using hash_table->thumb_glue_size as the value. |
|
|
Even though the section isn't allocated yet, this is where we will be |
|
|
putting it. The +1 on the value marks that the stub has not been |
|
|
output yet - not that it is a Thumb function. */ |
|
|
bh = NULL; |
|
|
val = hash_table->thumb_glue_size + 1; |
|
|
_bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner, |
|
|
tmp_name, BSF_GLOBAL, s, val, |
|
|
NULL, TRUE, FALSE, &bh); |
|
|
|
|
|
/* If we mark it 'Thumb', the disassembler will do a better job. */ |
|
|
myh = (struct elf_link_hash_entry *) bh; |
|
|
myh->type = ELF_ST_INFO (STB_LOCAL, STT_ARM_TFUNC); |
|
|
myh->forced_local = 1; |
|
|
|
|
|
free (tmp_name); |
|
|
|
|
|
#define CHANGE_TO_ARM "__%s_change_to_arm" |
|
|
#define BACK_FROM_ARM "__%s_back_from_arm" |
|
|
|
|
|
/* Allocate another symbol to mark where we switch to Arm mode. */ |
|
|
tmp_name = bfd_malloc ((bfd_size_type) strlen (name) |
|
|
+ strlen (CHANGE_TO_ARM) + 1); |
|
|
|
|
|
BFD_ASSERT (tmp_name); |
|
|
|
|
|
sprintf (tmp_name, CHANGE_TO_ARM, name); |
|
|
|
|
|
bh = NULL; |
|
|
val = hash_table->thumb_glue_size + 4, |
|
|
_bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner, |
|
|
tmp_name, BSF_LOCAL, s, val, |
|
|
NULL, TRUE, FALSE, &bh); |
|
|
|
|
|
free (tmp_name); |
|
|
|
|
|
s->size += THUMB2ARM_GLUE_SIZE; |
|
|
hash_table->thumb_glue_size += THUMB2ARM_GLUE_SIZE; |
|
|
} |
|
|
|
|
|
|
|
| 4966 |
/* Allocate space for ARMv4 BX veneers. */ |
/* Allocate space for ARMv4 BX veneers. */ |
| 4967 |
|
|
| 4968 |
static void |
static void |
| 5173 |
return val; |
return val; |
| 5174 |
} |
} |
| 5175 |
|
|
|
/* Note: we do not include the flag SEC_LINKER_CREATED, as that |
|
|
would prevent elf_link_input_bfd() from processing the contents |
|
|
of the section. */ |
|
| 5176 |
#define ARM_GLUE_SECTION_FLAGS \ |
#define ARM_GLUE_SECTION_FLAGS \ |
| 5177 |
(SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_CODE | SEC_READONLY) |
(SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_CODE \ |
| 5178 |
|
| SEC_READONLY | SEC_LINKER_CREATED) |
| 5179 |
|
|
| 5180 |
/* Create a fake section for use by the ARM backend of the linker. */ |
/* Create a fake section for use by the ARM backend of the linker. */ |
| 5181 |
|
|
| 5214 |
if (info->relocatable) |
if (info->relocatable) |
| 5215 |
return TRUE; |
return TRUE; |
| 5216 |
|
|
|
/* Linker stubs don't need glue. */ |
|
|
if (!strcmp (abfd->filename, "linker stubs")) |
|
|
return TRUE; |
|
|
|
|
| 5217 |
return arm_make_glue_section (abfd, ARM2THUMB_GLUE_SECTION_NAME) |
return arm_make_glue_section (abfd, ARM2THUMB_GLUE_SECTION_NAME) |
| 5218 |
&& arm_make_glue_section (abfd, THUMB2ARM_GLUE_SECTION_NAME) |
&& arm_make_glue_section (abfd, THUMB2ARM_GLUE_SECTION_NAME) |
| 5219 |
&& arm_make_glue_section (abfd, VFP11_ERRATUM_VENEER_SECTION_NAME) |
&& arm_make_glue_section (abfd, VFP11_ERRATUM_VENEER_SECTION_NAME) |
| 5332 |
|
|
| 5333 |
/* These are the only relocation types we care about. */ |
/* These are the only relocation types we care about. */ |
| 5334 |
if ( r_type != R_ARM_PC24 |
if ( r_type != R_ARM_PC24 |
|
&& r_type != R_ARM_PLT32 |
|
|
&& r_type != R_ARM_JUMP24 |
|
|
&& r_type != R_ARM_THM_JUMP24 |
|
| 5335 |
&& (r_type != R_ARM_V4BX || globals->fix_v4bx < 2)) |
&& (r_type != R_ARM_V4BX || globals->fix_v4bx < 2)) |
| 5336 |
continue; |
continue; |
| 5337 |
|
|
| 5383 |
switch (r_type) |
switch (r_type) |
| 5384 |
{ |
{ |
| 5385 |
case R_ARM_PC24: |
case R_ARM_PC24: |
|
case R_ARM_PLT32: |
|
|
case R_ARM_JUMP24: |
|
| 5386 |
/* This one is a call from arm code. We need to look up |
/* This one is a call from arm code. We need to look up |
| 5387 |
the target of the call. If it is a thumb target, we |
the target of the call. If it is a thumb target, we |
| 5388 |
insert glue. */ |
insert glue. */ |
| 5389 |
if (ELF_ST_TYPE (h->type) == STT_ARM_TFUNC |
if (ELF_ST_TYPE (h->type) == STT_ARM_TFUNC) |
|
&& !(r_type == R_ARM_CALL && globals->use_blx)) |
|
| 5390 |
record_arm_to_thumb_glue (link_info, h); |
record_arm_to_thumb_glue (link_info, h); |
| 5391 |
break; |
break; |
| 5392 |
|
|
|
case R_ARM_THM_JUMP24: |
|
|
/* This one is a call from thumb code. We look |
|
|
up the target of the call. If it is not a thumb |
|
|
target, we insert glue. */ |
|
|
if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC |
|
|
&& !(globals->use_blx && r_type == R_ARM_THM_CALL) |
|
|
&& h->root.type != bfd_link_hash_undefweak) |
|
|
record_thumb_to_arm_glue (link_info, h); |
|
|
break; |
|
|
|
|
| 5393 |
default: |
default: |
| 5394 |
abort (); |
abort (); |
| 5395 |
} |
} |
| 5470 |
} |
} |
| 5471 |
|
|
| 5472 |
|
|
| 5473 |
|
/* Auto-select enabling of Cortex-A8 erratum fix if the user didn't explicitly |
| 5474 |
|
say what they wanted. */ |
| 5475 |
|
|
| 5476 |
|
void |
| 5477 |
|
bfd_elf32_arm_set_cortex_a8_fix (bfd *obfd, struct bfd_link_info *link_info) |
| 5478 |
|
{ |
| 5479 |
|
struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info); |
| 5480 |
|
obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd); |
| 5481 |
|
|
| 5482 |
|
if (globals->fix_cortex_a8 == -1) |
| 5483 |
|
{ |
| 5484 |
|
/* Turn on Cortex-A8 erratum workaround for ARMv7-A. */ |
| 5485 |
|
if (out_attr[Tag_CPU_arch].i == TAG_CPU_ARCH_V7 |
| 5486 |
|
&& (out_attr[Tag_CPU_arch_profile].i == 'A' |
| 5487 |
|
|| out_attr[Tag_CPU_arch_profile].i == 0)) |
| 5488 |
|
globals->fix_cortex_a8 = 1; |
| 5489 |
|
else |
| 5490 |
|
globals->fix_cortex_a8 = 0; |
| 5491 |
|
} |
| 5492 |
|
} |
| 5493 |
|
|
| 5494 |
|
|
| 5495 |
void |
void |
| 5496 |
bfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info) |
bfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info) |
| 5497 |
{ |
{ |
| 5842 |
if (globals->vfp11_fix == BFD_ARM_VFP11_FIX_NONE) |
if (globals->vfp11_fix == BFD_ARM_VFP11_FIX_NONE) |
| 5843 |
return TRUE; |
return TRUE; |
| 5844 |
|
|
| 5845 |
|
/* Skip this BFD if it corresponds to an executable or dynamic object. */ |
| 5846 |
|
if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) |
| 5847 |
|
return TRUE; |
| 5848 |
|
|
| 5849 |
for (sec = abfd->sections; sec != NULL; sec = sec->next) |
for (sec = abfd->sections; sec != NULL; sec = sec->next) |
| 5850 |
{ |
{ |
| 5851 |
unsigned int i, span, first_fmac = 0, veneer_of_insn = 0; |
unsigned int i, span, first_fmac = 0, veneer_of_insn = 0; |
| 5856 |
if (elf_section_type (sec) != SHT_PROGBITS |
if (elf_section_type (sec) != SHT_PROGBITS |
| 5857 |
|| (elf_section_flags (sec) & SHF_EXECINSTR) == 0 |
|| (elf_section_flags (sec) & SHF_EXECINSTR) == 0 |
| 5858 |
|| (sec->flags & SEC_EXCLUDE) != 0 |
|| (sec->flags & SEC_EXCLUDE) != 0 |
| 5859 |
|
|| sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS |
| 5860 |
|
|| sec->output_section == bfd_abs_section_ptr |
| 5861 |
|| strcmp (sec->name, VFP11_ERRATUM_VENEER_SECTION_NAME) == 0) |
|| strcmp (sec->name, VFP11_ERRATUM_VENEER_SECTION_NAME) == 0) |
| 5862 |
continue; |
continue; |
| 5863 |
|
|
| 6101 |
int use_blx, |
int use_blx, |
| 6102 |
bfd_arm_vfp11_fix vfp11_fix, |
bfd_arm_vfp11_fix vfp11_fix, |
| 6103 |
int no_enum_warn, int no_wchar_warn, |
int no_enum_warn, int no_wchar_warn, |
| 6104 |
int pic_veneer) |
int pic_veneer, int fix_cortex_a8) |
| 6105 |
{ |
{ |
| 6106 |
struct elf32_arm_link_hash_table *globals; |
struct elf32_arm_link_hash_table *globals; |
| 6107 |
|
|
| 6123 |
globals->use_blx |= use_blx; |
globals->use_blx |= use_blx; |
| 6124 |
globals->vfp11_fix = vfp11_fix; |
globals->vfp11_fix = vfp11_fix; |
| 6125 |
globals->pic_veneer = pic_veneer; |
globals->pic_veneer = pic_veneer; |
| 6126 |
|
globals->fix_cortex_a8 = fix_cortex_a8; |
| 6127 |
|
|
| 6128 |
BFD_ASSERT (is_arm_elf (output_bfd)); |
BFD_ASSERT (is_arm_elf (output_bfd)); |
| 6129 |
elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn; |
elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn; |
| 6754 |
/* Handle relocations which should use the PLT entry. ABS32/REL32 |
/* Handle relocations which should use the PLT entry. ABS32/REL32 |
| 6755 |
will use the symbol's value, which may point to a PLT entry, but we |
will use the symbol's value, which may point to a PLT entry, but we |
| 6756 |
don't need to handle that here. If we created a PLT entry, all |
don't need to handle that here. If we created a PLT entry, all |
| 6757 |
branches in this object should go to it. */ |
branches in this object should go to it, except if the PLT is too |
| 6758 |
|
far away, in which case a long branch stub should be inserted. */ |
| 6759 |
if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32 |
if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32 |
| 6760 |
&& r_type != R_ARM_ABS32_NOI && r_type != R_ARM_REL32_NOI) |
&& r_type != R_ARM_ABS32_NOI && r_type != R_ARM_REL32_NOI |
| 6761 |
|
&& r_type != R_ARM_CALL |
| 6762 |
|
&& r_type != R_ARM_JUMP24 |
| 6763 |
|
&& r_type != R_ARM_PLT32) |
| 6764 |
&& h != NULL |
&& h != NULL |
| 6765 |
&& splt != NULL |
&& splt != NULL |
| 6766 |
&& h->plt.offset != (bfd_vma) -1) |
&& h->plt.offset != (bfd_vma) -1) |
| 6917 |
bfd_signed_vma branch_offset; |
bfd_signed_vma branch_offset; |
| 6918 |
struct elf32_arm_stub_hash_entry *stub_entry = NULL; |
struct elf32_arm_stub_hash_entry *stub_entry = NULL; |
| 6919 |
|
|
|
from = (input_section->output_section->vma |
|
|
+ input_section->output_offset |
|
|
+ rel->r_offset); |
|
|
branch_offset = (bfd_signed_vma)(value - from); |
|
|
|
|
| 6920 |
if (r_type == R_ARM_XPC25) |
if (r_type == R_ARM_XPC25) |
| 6921 |
{ |
{ |
| 6922 |
/* Check for Arm calling Arm function. */ |
/* Check for Arm calling Arm function. */ |
| 6928 |
input_bfd, |
input_bfd, |
| 6929 |
h ? h->root.root.string : "(local)"); |
h ? h->root.root.string : "(local)"); |
| 6930 |
} |
} |
| 6931 |
else if (r_type != R_ARM_CALL) |
else if (r_type == R_ARM_PC24) |
| 6932 |
{ |
{ |
| 6933 |
/* Check for Arm calling Thumb function. */ |
/* Check for Arm calling Thumb function. */ |
| 6934 |
if (sym_flags == STT_ARM_TFUNC) |
if (sym_flags == STT_ARM_TFUNC) |
| 6946 |
|
|
| 6947 |
/* Check if a stub has to be inserted because the |
/* Check if a stub has to be inserted because the |
| 6948 |
destination is too far or we are changing mode. */ |
destination is too far or we are changing mode. */ |
| 6949 |
if (r_type == R_ARM_CALL) |
if ( r_type == R_ARM_CALL |
| 6950 |
{ |
|| r_type == R_ARM_JUMP24 |
| 6951 |
|
|| r_type == R_ARM_PLT32) |
| 6952 |
|
{ |
| 6953 |
|
/* If the call goes through a PLT entry, make sure to |
| 6954 |
|
check distance to the right destination address. */ |
| 6955 |
|
if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) |
| 6956 |
|
{ |
| 6957 |
|
value = (splt->output_section->vma |
| 6958 |
|
+ splt->output_offset |
| 6959 |
|
+ h->plt.offset); |
| 6960 |
|
*unresolved_reloc_p = FALSE; |
| 6961 |
|
} |
| 6962 |
|
|
| 6963 |
|
from = (input_section->output_section->vma |
| 6964 |
|
+ input_section->output_offset |
| 6965 |
|
+ rel->r_offset); |
| 6966 |
|
branch_offset = (bfd_signed_vma)(value - from); |
| 6967 |
|
|
| 6968 |
if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET |
if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET |
| 6969 |
|| branch_offset < ARM_MAX_BWD_BRANCH_OFFSET |
|| branch_offset < ARM_MAX_BWD_BRANCH_OFFSET |
| 6970 |
|| sym_flags == STT_ARM_TFUNC) |
|| ((sym_flags == STT_ARM_TFUNC) |
| 6971 |
|
&& (((r_type == R_ARM_CALL) && !globals->use_blx) |
| 6972 |
|
|| (r_type == R_ARM_JUMP24) |
| 6973 |
|
|| (r_type == R_ARM_PLT32) )) |
| 6974 |
|
) |
| 6975 |
{ |
{ |
| 6976 |
/* The target is out of reach, so redirect the |
/* The target is out of reach, so redirect the |
| 6977 |
branch to the local stub for this function. */ |
branch to the local stub for this function. */ |
| 7018 |
signed_addend >>= howto->rightshift; |
signed_addend >>= howto->rightshift; |
| 7019 |
|
|
| 7020 |
/* A branch to an undefined weak symbol is turned into a jump to |
/* A branch to an undefined weak symbol is turned into a jump to |
| 7021 |
the next instruction. */ |
the next instruction unless a PLT entry will be created. */ |
| 7022 |
if (h && h->root.type == bfd_link_hash_undefweak) |
if (h && h->root.type == bfd_link_hash_undefweak |
| 7023 |
|
&& !(splt != NULL && h->plt.offset != (bfd_vma) -1)) |
| 7024 |
{ |
{ |
| 7025 |
value = (bfd_get_32 (input_bfd, hit_data) & 0xf0000000) |
value = (bfd_get_32 (input_bfd, hit_data) & 0xf0000000) |
| 7026 |
| 0x0affffff; |
| 0x0affffff; |
| 7037 |
value = (signed_addend & howto->dst_mask) |
value = (signed_addend & howto->dst_mask) |
| 7038 |
| (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask)); |
| (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask)); |
| 7039 |
|
|
|
/* Set the H bit in the BLX instruction. */ |
|
|
if (sym_flags == STT_ARM_TFUNC) |
|
|
{ |
|
|
if (addend) |
|
|
value |= (1 << 24); |
|
|
else |
|
|
value &= ~(bfd_vma)(1 << 24); |
|
|
} |
|
| 7040 |
if (r_type == R_ARM_CALL) |
if (r_type == R_ARM_CALL) |
| 7041 |
{ |
{ |
| 7042 |
|
/* Set the H bit in the BLX instruction. */ |
| 7043 |
|
if (sym_flags == STT_ARM_TFUNC) |
| 7044 |
|
{ |
| 7045 |
|
if (addend) |
| 7046 |
|
value |= (1 << 24); |
| 7047 |
|
else |
| 7048 |
|
value &= ~(bfd_vma)(1 << 24); |
| 7049 |
|
} |
| 7050 |
|
|
| 7051 |
/* Select the correct instruction (BL or BLX). */ |
/* Select the correct instruction (BL or BLX). */ |
| 7052 |
/* Only if we are not handling a BL to a stub. In this |
/* Only if we are not handling a BL to a stub. In this |
| 7053 |
case, mode switching is performed by the stub. */ |
case, mode switching is performed by the stub. */ |
| 7183 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
| 7184 |
} |
} |
| 7185 |
|
|
| 7186 |
|
case R_ARM_THM_PC8: |
| 7187 |
|
/* PR 10073: This reloc is not generated by the GNU toolchain, |
| 7188 |
|
but it is supported for compatibility with third party libraries |
| 7189 |
|
generated by other compilers, specifically the ARM/IAR. */ |
| 7190 |
|
{ |
| 7191 |
|
bfd_vma insn; |
| 7192 |
|
bfd_signed_vma relocation; |
| 7193 |
|
|
| 7194 |
|
insn = bfd_get_16 (input_bfd, hit_data); |
| 7195 |
|
|
| 7196 |
|
if (globals->use_rel) |
| 7197 |
|
addend = (insn & 0x00ff) << 2; |
| 7198 |
|
|
| 7199 |
|
relocation = value + addend; |
| 7200 |
|
relocation -= (input_section->output_section->vma |
| 7201 |
|
+ input_section->output_offset |
| 7202 |
|
+ rel->r_offset); |
| 7203 |
|
|
| 7204 |
|
value = abs (relocation); |
| 7205 |
|
|
| 7206 |
|
/* We do not check for overflow of this reloc. Although strictly |
| 7207 |
|
speaking this is incorrect, it appears to be necessary in order |
| 7208 |
|
to work with IAR generated relocs. Since GCC and GAS do not |
| 7209 |
|
generate R_ARM_THM_PC8 relocs, the lack of a check should not be |
| 7210 |
|
a problem for them. */ |
| 7211 |
|
value &= 0x3fc; |
| 7212 |
|
|
| 7213 |
|
insn = (insn & 0xff00) | (value >> 2); |
| 7214 |
|
|
| 7215 |
|
bfd_put_16 (input_bfd, insn, hit_data); |
| 7216 |
|
|
| 7217 |
|
return bfd_reloc_ok; |
| 7218 |
|
} |
| 7219 |
|
|
| 7220 |
case R_ARM_THM_PC12: |
case R_ARM_THM_PC12: |
| 7221 |
/* Corresponds to: ldr.w reg, [pc, #offset]. */ |
/* Corresponds to: ldr.w reg, [pc, #offset]. */ |
| 7222 |
{ |
{ |
| 7325 |
/* Convert BL to BLX. */ |
/* Convert BL to BLX. */ |
| 7326 |
lower_insn = (lower_insn & ~0x1000) | 0x0800; |
lower_insn = (lower_insn & ~0x1000) | 0x0800; |
| 7327 |
} |
} |
| 7328 |
else if (r_type != R_ARM_THM_CALL) |
else if (( r_type != R_ARM_THM_CALL) |
| 7329 |
|
&& (r_type != R_ARM_THM_JUMP24)) |
| 7330 |
{ |
{ |
| 7331 |
if (elf32_thumb_to_arm_stub |
if (elf32_thumb_to_arm_stub |
| 7332 |
(info, sym_name, input_bfd, output_bfd, input_section, |
(info, sym_name, input_bfd, output_bfd, input_section, |
| 7363 |
*unresolved_reloc_p = FALSE; |
*unresolved_reloc_p = FALSE; |
| 7364 |
} |
} |
| 7365 |
|
|
| 7366 |
if (r_type == R_ARM_THM_CALL) |
if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24) |
| 7367 |
{ |
{ |
| 7368 |
/* Check if a stub has to be inserted because the destination |
/* Check if a stub has to be inserted because the destination |
| 7369 |
is too far. */ |
is too far. */ |
| 7383 |
(thumb2 |
(thumb2 |
| 7384 |
&& (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET |
&& (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET |
| 7385 |
|| (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) |
|| (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) |
| 7386 |
|| ((sym_flags != STT_ARM_TFUNC) && !globals->use_blx)) |
|| ((sym_flags != STT_ARM_TFUNC) |
| 7387 |
|
&& (((r_type == R_ARM_THM_CALL) && !globals->use_blx) |
| 7388 |
|
|| r_type == R_ARM_THM_JUMP24))) |
| 7389 |
{ |
{ |
| 7390 |
/* The target is out of reach or we are changing modes, so |
/* The target is out of reach or we are changing modes, so |
| 7391 |
redirect the branch to the local stub for this |
redirect the branch to the local stub for this |
| 7399 |
+ stub_entry->stub_sec->output_section->vma); |
+ stub_entry->stub_sec->output_section->vma); |
| 7400 |
|
|
| 7401 |
/* If this call becomes a call to Arm, force BLX. */ |
/* If this call becomes a call to Arm, force BLX. */ |
| 7402 |
if (globals->use_blx) |
if (globals->use_blx && (r_type == R_ARM_THM_CALL)) |
| 7403 |
{ |
{ |
| 7404 |
if ((stub_entry |
if ((stub_entry |
| 7405 |
&& !arm_stub_is_thumb (stub_entry->stub_type)) |
&& !arm_stub_is_thumb (stub_entry->stub_type)) |
| 8908 |
return TRUE; |
return TRUE; |
| 8909 |
} |
} |
| 8910 |
|
|
| 8911 |
|
/* Add a new unwind edit to the list described by HEAD, TAIL. If INDEX is zero, |
| 8912 |
|
adds the edit to the start of the list. (The list must be built in order of |
| 8913 |
|
ascending INDEX: the function's callers are primarily responsible for |
| 8914 |
|
maintaining that condition). */ |
| 8915 |
|
|
| 8916 |
|
static void |
| 8917 |
|
add_unwind_table_edit (arm_unwind_table_edit **head, |
| 8918 |
|
arm_unwind_table_edit **tail, |
| 8919 |
|
arm_unwind_edit_type type, |
| 8920 |
|
asection *linked_section, |
| 8921 |
|
unsigned int index) |
| 8922 |
|
{ |
| 8923 |
|
arm_unwind_table_edit *new_edit = xmalloc (sizeof (arm_unwind_table_edit)); |
| 8924 |
|
|
| 8925 |
|
new_edit->type = type; |
| 8926 |
|
new_edit->linked_section = linked_section; |
| 8927 |
|
new_edit->index = index; |
| 8928 |
|
|
| 8929 |
|
if (index > 0) |
| 8930 |
|
{ |
| 8931 |
|
new_edit->next = NULL; |
| 8932 |
|
|
| 8933 |
|
if (*tail) |
| 8934 |
|
(*tail)->next = new_edit; |
| 8935 |
|
|
| 8936 |
|
(*tail) = new_edit; |
| 8937 |
|
|
| 8938 |
|
if (!*head) |
| 8939 |
|
(*head) = new_edit; |
| 8940 |
|
} |
| 8941 |
|
else |
| 8942 |
|
{ |
| 8943 |
|
new_edit->next = *head; |
| 8944 |
|
|
| 8945 |
|
if (!*tail) |
| 8946 |
|
*tail = new_edit; |
| 8947 |
|
|
| 8948 |
|
*head = new_edit; |
| 8949 |
|
} |
| 8950 |
|
} |
| 8951 |
|
|
| 8952 |
|
static _arm_elf_section_data *get_arm_elf_section_data (asection *); |
| 8953 |
|
|
| 8954 |
|
/* Increase the size of EXIDX_SEC by ADJUST bytes. ADJUST mau be negative. */ |
| 8955 |
|
static void |
| 8956 |
|
adjust_exidx_size(asection *exidx_sec, int adjust) |
| 8957 |
|
{ |
| 8958 |
|
asection *out_sec; |
| 8959 |
|
|
| 8960 |
|
if (!exidx_sec->rawsize) |
| 8961 |
|
exidx_sec->rawsize = exidx_sec->size; |
| 8962 |
|
|
| 8963 |
|
bfd_set_section_size (exidx_sec->owner, exidx_sec, exidx_sec->size + adjust); |
| 8964 |
|
out_sec = exidx_sec->output_section; |
| 8965 |
|
/* Adjust size of output section. */ |
| 8966 |
|
bfd_set_section_size (out_sec->owner, out_sec, out_sec->size +adjust); |
| 8967 |
|
} |
| 8968 |
|
|
| 8969 |
|
/* Insert an EXIDX_CANTUNWIND marker at the end of a section. */ |
| 8970 |
|
static void |
| 8971 |
|
insert_cantunwind_after(asection *text_sec, asection *exidx_sec) |
| 8972 |
|
{ |
| 8973 |
|
struct _arm_elf_section_data *exidx_arm_data; |
| 8974 |
|
|
| 8975 |
|
exidx_arm_data = get_arm_elf_section_data (exidx_sec); |
| 8976 |
|
add_unwind_table_edit ( |
| 8977 |
|
&exidx_arm_data->u.exidx.unwind_edit_list, |
| 8978 |
|
&exidx_arm_data->u.exidx.unwind_edit_tail, |
| 8979 |
|
INSERT_EXIDX_CANTUNWIND_AT_END, text_sec, UINT_MAX); |
| 8980 |
|
|
| 8981 |
|
adjust_exidx_size(exidx_sec, 8); |
| 8982 |
|
} |
| 8983 |
|
|
| 8984 |
|
/* Scan .ARM.exidx tables, and create a list describing edits which should be |
| 8985 |
|
made to those tables, such that: |
| 8986 |
|
|
| 8987 |
|
1. Regions without unwind data are marked with EXIDX_CANTUNWIND entries. |
| 8988 |
|
2. Duplicate entries are merged together (EXIDX_CANTUNWIND, or unwind |
| 8989 |
|
codes which have been inlined into the index). |
| 8990 |
|
|
| 8991 |
|
The edits are applied when the tables are written |
| 8992 |
|
(in elf32_arm_write_section). |
| 8993 |
|
*/ |
| 8994 |
|
|
| 8995 |
|
bfd_boolean |
| 8996 |
|
elf32_arm_fix_exidx_coverage (asection **text_section_order, |
| 8997 |
|
unsigned int num_text_sections, |
| 8998 |
|
struct bfd_link_info *info) |
| 8999 |
|
{ |
| 9000 |
|
bfd *inp; |
| 9001 |
|
unsigned int last_second_word = 0, i; |
| 9002 |
|
asection *last_exidx_sec = NULL; |
| 9003 |
|
asection *last_text_sec = NULL; |
| 9004 |
|
int last_unwind_type = -1; |
| 9005 |
|
|
| 9006 |
|
/* Walk over all EXIDX sections, and create backlinks from the corrsponding |
| 9007 |
|
text sections. */ |
| 9008 |
|
for (inp = info->input_bfds; inp != NULL; inp = inp->link_next) |
| 9009 |
|
{ |
| 9010 |
|
asection *sec; |
| 9011 |
|
|
| 9012 |
|
for (sec = inp->sections; sec != NULL; sec = sec->next) |
| 9013 |
|
{ |
| 9014 |
|
struct bfd_elf_section_data *elf_sec = elf_section_data (sec); |
| 9015 |
|
Elf_Internal_Shdr *hdr = &elf_sec->this_hdr; |
| 9016 |
|
|
| 9017 |
|
if (!hdr || hdr->sh_type != SHT_ARM_EXIDX) |
| 9018 |
|
continue; |
| 9019 |
|
|
| 9020 |
|
if (elf_sec->linked_to) |
| 9021 |
|
{ |
| 9022 |
|
Elf_Internal_Shdr *linked_hdr |
| 9023 |
|
= &elf_section_data (elf_sec->linked_to)->this_hdr; |
| 9024 |
|
struct _arm_elf_section_data *linked_sec_arm_data |
| 9025 |
|
= get_arm_elf_section_data (linked_hdr->bfd_section); |
| 9026 |
|
|
| 9027 |
|
if (linked_sec_arm_data == NULL) |
| 9028 |
|
continue; |
| 9029 |
|
|
| 9030 |
|
/* Link this .ARM.exidx section back from the text section it |
| 9031 |
|
describes. */ |
| 9032 |
|
linked_sec_arm_data->u.text.arm_exidx_sec = sec; |
| 9033 |
|
} |
| 9034 |
|
} |
| 9035 |
|
} |
| 9036 |
|
|
| 9037 |
|
/* Walk all text sections in order of increasing VMA. Eilminate duplicate |
| 9038 |
|
index table entries (EXIDX_CANTUNWIND and inlined unwind opcodes), |
| 9039 |
|
and add EXIDX_CANTUNWIND entries for sections with no unwind table data. |
| 9040 |
|
*/ |
| 9041 |
|
|
| 9042 |
|
for (i = 0; i < num_text_sections; i++) |
| 9043 |
|
{ |
| 9044 |
|
asection *sec = text_section_order[i]; |
| 9045 |
|
asection *exidx_sec; |
| 9046 |
|
struct _arm_elf_section_data *arm_data = get_arm_elf_section_data (sec); |
| 9047 |
|
struct _arm_elf_section_data *exidx_arm_data; |
| 9048 |
|
bfd_byte *contents = NULL; |
| 9049 |
|
int deleted_exidx_bytes = 0; |
| 9050 |
|
bfd_vma j; |
| 9051 |
|
arm_unwind_table_edit *unwind_edit_head = NULL; |
| 9052 |
|
arm_unwind_table_edit *unwind_edit_tail = NULL; |
| 9053 |
|
Elf_Internal_Shdr *hdr; |
| 9054 |
|
bfd *ibfd; |
| 9055 |
|
|
| 9056 |
|
if (arm_data == NULL) |
| 9057 |
|
continue; |
| 9058 |
|
|
| 9059 |
|
exidx_sec = arm_data->u.text.arm_exidx_sec; |
| 9060 |
|
if (exidx_sec == NULL) |
| 9061 |
|
{ |
| 9062 |
|
/* Section has no unwind data. */ |
| 9063 |
|
if (last_unwind_type == 0 || !last_exidx_sec) |
| 9064 |
|
continue; |
| 9065 |
|
|
| 9066 |
|
/* Ignore zero sized sections. */ |
| 9067 |
|
if (sec->size == 0) |
| 9068 |
|
continue; |
| 9069 |
|
|
| 9070 |
|
insert_cantunwind_after(last_text_sec, last_exidx_sec); |
| 9071 |
|
last_unwind_type = 0; |
| 9072 |
|
continue; |
| 9073 |
|
} |
| 9074 |
|
|
| 9075 |
|
/* Skip /DISCARD/ sections. */ |
| 9076 |
|
if (bfd_is_abs_section (exidx_sec->output_section)) |
| 9077 |
|
continue; |
| 9078 |
|
|
| 9079 |
|
hdr = &elf_section_data (exidx_sec)->this_hdr; |
| 9080 |
|
if (hdr->sh_type != SHT_ARM_EXIDX) |
| 9081 |
|
continue; |
| 9082 |
|
|
| 9083 |
|
exidx_arm_data = get_arm_elf_section_data (exidx_sec); |
| 9084 |
|
if (exidx_arm_data == NULL) |
| 9085 |
|
continue; |
| 9086 |
|
|
| 9087 |
|
ibfd = exidx_sec->owner; |
| 9088 |
|
|
| 9089 |
|
if (hdr->contents != NULL) |
| 9090 |
|
contents = hdr->contents; |
| 9091 |
|
else if (! bfd_malloc_and_get_section (ibfd, exidx_sec, &contents)) |
| 9092 |
|
/* An error? */ |
| 9093 |
|
continue; |
| 9094 |
|
|
| 9095 |
|
for (j = 0; j < hdr->sh_size; j += 8) |
| 9096 |
|
{ |
| 9097 |
|
unsigned int second_word = bfd_get_32 (ibfd, contents + j + 4); |
| 9098 |
|
int unwind_type; |
| 9099 |
|
int elide = 0; |
| 9100 |
|
|
| 9101 |
|
/* An EXIDX_CANTUNWIND entry. */ |
| 9102 |
|
if (second_word == 1) |
| 9103 |
|
{ |
| 9104 |
|
if (last_unwind_type == 0) |
| 9105 |
|
elide = 1; |
| 9106 |
|
unwind_type = 0; |
| 9107 |
|
} |
| 9108 |
|
/* Inlined unwinding data. Merge if equal to previous. */ |
| 9109 |
|
else if ((second_word & 0x80000000) != 0) |
| 9110 |
|
{ |
| 9111 |
|
if (last_second_word == second_word && last_unwind_type == 1) |
| 9112 |
|
elide = 1; |
| 9113 |
|
unwind_type = 1; |
| 9114 |
|
last_second_word = second_word; |
| 9115 |
|
} |
| 9116 |
|
/* Normal table entry. In theory we could merge these too, |
| 9117 |
|
but duplicate entries are likely to be much less common. */ |
| 9118 |
|
else |
| 9119 |
|
unwind_type = 2; |
| 9120 |
|
|
| 9121 |
|
if (elide) |
| 9122 |
|
{ |
| 9123 |
|
add_unwind_table_edit (&unwind_edit_head, &unwind_edit_tail, |
| 9124 |
|
DELETE_EXIDX_ENTRY, NULL, j / 8); |
| 9125 |
|
|
| 9126 |
|
deleted_exidx_bytes += 8; |
| 9127 |
|
} |
| 9128 |
|
|
| 9129 |
|
last_unwind_type = unwind_type; |
| 9130 |
|
} |
| 9131 |
|
|
| 9132 |
|
/* Free contents if we allocated it ourselves. */ |
| 9133 |
|
if (contents != hdr->contents) |
| 9134 |
|
free (contents); |
| 9135 |
|
|
| 9136 |
|
/* Record edits to be applied later (in elf32_arm_write_section). */ |
| 9137 |
|
exidx_arm_data->u.exidx.unwind_edit_list = unwind_edit_head; |
| 9138 |
|
exidx_arm_data->u.exidx.unwind_edit_tail = unwind_edit_tail; |
| 9139 |
|
|
| 9140 |
|
if (deleted_exidx_bytes > 0) |
| 9141 |
|
adjust_exidx_size(exidx_sec, -deleted_exidx_bytes); |
| 9142 |
|
|
| 9143 |
|
last_exidx_sec = exidx_sec; |
| 9144 |
|
last_text_sec = sec; |
| 9145 |
|
} |
| 9146 |
|
|
| 9147 |
|
/* Add terminating CANTUNWIND entry. */ |
| 9148 |
|
if (last_exidx_sec && last_unwind_type != 0) |
| 9149 |
|
insert_cantunwind_after(last_text_sec, last_exidx_sec); |
| 9150 |
|
|
| 9151 |
|
return TRUE; |
| 9152 |
|
} |
| 9153 |
|
|
| 9154 |
|
static bfd_boolean |
| 9155 |
|
elf32_arm_output_glue_section (struct bfd_link_info *info, bfd *obfd, |
| 9156 |
|
bfd *ibfd, const char *name) |
| 9157 |
|
{ |
| 9158 |
|
asection *sec, *osec; |
| 9159 |
|
|
| 9160 |
|
sec = bfd_get_section_by_name (ibfd, name); |
| 9161 |
|
if (sec == NULL || (sec->flags & SEC_EXCLUDE) != 0) |
| 9162 |
|
return TRUE; |
| 9163 |
|
|
| 9164 |
|
osec = sec->output_section; |
| 9165 |
|
if (elf32_arm_write_section (obfd, info, sec, sec->contents)) |
| 9166 |
|
return TRUE; |
| 9167 |
|
|
| 9168 |
|
if (! bfd_set_section_contents (obfd, osec, sec->contents, |
| 9169 |
|
sec->output_offset, sec->size)) |
| 9170 |
|
return FALSE; |
| 9171 |
|
|
| 9172 |
|
return TRUE; |
| 9173 |
|
} |
| 9174 |
|
|
| 9175 |
|
static bfd_boolean |
| 9176 |
|
elf32_arm_final_link (bfd *abfd, struct bfd_link_info *info) |
| 9177 |
|
{ |
| 9178 |
|
struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (info); |
| 9179 |
|
|
| 9180 |
|
/* Invoke the regular ELF backend linker to do all the work. */ |
| 9181 |
|
if (!bfd_elf_final_link (abfd, info)) |
| 9182 |
|
return FALSE; |
| 9183 |
|
|
| 9184 |
|
/* Write out any glue sections now that we have created all the |
| 9185 |
|
stubs. */ |
| 9186 |
|
if (globals->bfd_of_glue_owner != NULL) |
| 9187 |
|
{ |
| 9188 |
|
if (! elf32_arm_output_glue_section (info, abfd, |
| 9189 |
|
globals->bfd_of_glue_owner, |
| 9190 |
|
ARM2THUMB_GLUE_SECTION_NAME)) |
| 9191 |
|
return FALSE; |
| 9192 |
|
|
| 9193 |
|
if (! elf32_arm_output_glue_section (info, abfd, |
| 9194 |
|
globals->bfd_of_glue_owner, |
| 9195 |
|
THUMB2ARM_GLUE_SECTION_NAME)) |
| 9196 |
|
return FALSE; |
| 9197 |
|
|
| 9198 |
|
if (! elf32_arm_output_glue_section (info, abfd, |
| 9199 |
|
globals->bfd_of_glue_owner, |
| 9200 |
|
VFP11_ERRATUM_VENEER_SECTION_NAME)) |
| 9201 |
|
return FALSE; |
| 9202 |
|
|
| 9203 |
|
if (! elf32_arm_output_glue_section (info, abfd, |
| 9204 |
|
globals->bfd_of_glue_owner, |
| 9205 |
|
ARM_BX_GLUE_SECTION_NAME)) |
| 9206 |
|
return FALSE; |
| 9207 |
|
} |
| 9208 |
|
|
| 9209 |
|
return TRUE; |
| 9210 |
|
} |
| 9211 |
|
|
| 9212 |
/* Set the right machine number. */ |
/* Set the right machine number. */ |
| 9213 |
|
|
| 9214 |
static bfd_boolean |
static bfd_boolean |
| 9349 |
elf32_arm_obj_attrs_arg_type (int tag) |
elf32_arm_obj_attrs_arg_type (int tag) |
| 9350 |
{ |
{ |
| 9351 |
if (tag == Tag_compatibility) |
if (tag == Tag_compatibility) |
| 9352 |
return 3; |
return ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL; |
| 9353 |
else if (tag == 4 || tag == 5) |
else if (tag == Tag_nodefaults) |
| 9354 |
return 2; |
return ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_NO_DEFAULT; |
| 9355 |
|
else if (tag == Tag_CPU_raw_name || tag == Tag_CPU_name) |
| 9356 |
|
return ATTR_TYPE_FLAG_STR_VAL; |
| 9357 |
else if (tag < 32) |
else if (tag < 32) |
| 9358 |
return 1; |
return ATTR_TYPE_FLAG_INT_VAL; |
| 9359 |
else |
else |
| 9360 |
return (tag & 1) != 0 ? 2 : 1; |
return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL; |
| 9361 |
|
} |
| 9362 |
|
|
| 9363 |
|
/* The ABI defines that Tag_conformance should be emitted first, and that |
| 9364 |
|
Tag_nodefaults should be second (if either is defined). This sets those |
| 9365 |
|
two positions, and bumps up the position of all the remaining tags to |
| 9366 |
|
compensate. */ |
| 9367 |
|
static int |
| 9368 |
|
elf32_arm_obj_attrs_order (int num) |
| 9369 |
|
{ |
| 9370 |
|
if (num == 4) |
| 9371 |
|
return Tag_conformance; |
| 9372 |
|
if (num == 5) |
| 9373 |
|
return Tag_nodefaults; |
| 9374 |
|
if ((num - 2) < Tag_nodefaults) |
| 9375 |
|
return num - 2; |
| 9376 |
|
if ((num - 1) < Tag_conformance) |
| 9377 |
|
return num - 1; |
| 9378 |
|
return num; |
| 9379 |
|
} |
| 9380 |
|
|
| 9381 |
|
/* Read the architecture from the Tag_also_compatible_with attribute, if any. |
| 9382 |
|
Returns -1 if no architecture could be read. */ |
| 9383 |
|
|
| 9384 |
|
static int |
| 9385 |
|
get_secondary_compatible_arch (bfd *abfd) |
| 9386 |
|
{ |
| 9387 |
|
obj_attribute *attr = |
| 9388 |
|
&elf_known_obj_attributes_proc (abfd)[Tag_also_compatible_with]; |
| 9389 |
|
|
| 9390 |
|
/* Note: the tag and its argument below are uleb128 values, though |
| 9391 |
|
currently-defined values fit in one byte for each. */ |
| 9392 |
|
if (attr->s |
| 9393 |
|
&& attr->s[0] == Tag_CPU_arch |
| 9394 |
|
&& (attr->s[1] & 128) != 128 |
| 9395 |
|
&& attr->s[2] == 0) |
| 9396 |
|
return attr->s[1]; |
| 9397 |
|
|
| 9398 |
|
/* This tag is "safely ignorable", so don't complain if it looks funny. */ |
| 9399 |
|
return -1; |
| 9400 |
} |
} |
| 9401 |
|
|
| 9402 |
|
/* Set, or unset, the architecture of the Tag_also_compatible_with attribute. |
| 9403 |
|
The tag is removed if ARCH is -1. */ |
| 9404 |
|
|
| 9405 |
static void |
static void |
| 9406 |
elf32_arm_copy_one_eabi_other_attribute (bfd *ibfd, bfd *obfd, obj_attribute_list *in_list) |
set_secondary_compatible_arch (bfd *abfd, int arch) |
| 9407 |
{ |
{ |
| 9408 |
switch (in_list->tag) |
obj_attribute *attr = |
| 9409 |
{ |
&elf_known_obj_attributes_proc (abfd)[Tag_also_compatible_with]; |
|
case Tag_VFP_HP_extension: |
|
|
case Tag_ABI_FP_16bit_format: |
|
|
bfd_elf_add_obj_attr_int (obfd, OBJ_ATTR_PROC, in_list->tag, in_list->attr.i); |
|
|
break; |
|
| 9410 |
|
|
| 9411 |
default: |
if (arch == -1) |
| 9412 |
if ((in_list->tag & 127) < 64) |
{ |
| 9413 |
{ |
attr->s = NULL; |
| 9414 |
_bfd_error_handler |
return; |
|
(_("Warning: %B: Unknown EABI object attribute %d"), ibfd, in_list->tag); |
|
|
break; |
|
|
} |
|
| 9415 |
} |
} |
| 9416 |
|
|
| 9417 |
|
/* Note: the tag and its argument below are uleb128 values, though |
| 9418 |
|
currently-defined values fit in one byte for each. */ |
| 9419 |
|
if (!attr->s) |
| 9420 |
|
attr->s = bfd_alloc (abfd, 3); |
| 9421 |
|
attr->s[0] = Tag_CPU_arch; |
| 9422 |
|
attr->s[1] = arch; |
| 9423 |
|
attr->s[2] = '\0'; |
| 9424 |
} |
} |
| 9425 |
|
|
| 9426 |
static void |
/* Combine two values for Tag_CPU_arch, taking secondary compatibility tags |
| 9427 |
elf32_arm_copy_eabi_other_attribute_list (bfd *ibfd, bfd *obfd, obj_attribute_list *in_list) |
into account. */ |
| 9428 |
|
|
| 9429 |
|
static int |
| 9430 |
|
tag_cpu_arch_combine (bfd *ibfd, int oldtag, int *secondary_compat_out, |
| 9431 |
|
int newtag, int secondary_compat) |
| 9432 |
{ |
{ |
| 9433 |
for (; in_list; in_list = in_list->next ) |
#define T(X) TAG_CPU_ARCH_##X |
| 9434 |
elf32_arm_copy_one_eabi_other_attribute (ibfd, obfd, in_list); |
int tagl, tagh, result; |
| 9435 |
|
const int v6t2[] = |
| 9436 |
|
{ |
| 9437 |
|
T(V6T2), /* PRE_V4. */ |
| 9438 |
|
T(V6T2), /* V4. */ |
| 9439 |
|
T(V6T2), /* V4T. */ |
| 9440 |
|
T(V6T2), /* V5T. */ |
| 9441 |
|
T(V6T2), /* V5TE. */ |
| 9442 |
|
T(V6T2), /* V5TEJ. */ |
| 9443 |
|
T(V6T2), /* V6. */ |
| 9444 |
|
T(V7), /* V6KZ. */ |
| 9445 |
|
T(V6T2) /* V6T2. */ |
| 9446 |
|
}; |
| 9447 |
|
const int v6k[] = |
| 9448 |
|
{ |
| 9449 |
|
T(V6K), /* PRE_V4. */ |
| 9450 |
|
T(V6K), /* V4. */ |
| 9451 |
|
T(V6K), /* V4T. */ |
| 9452 |
|
T(V6K), /* V5T. */ |
| 9453 |
|
T(V6K), /* V5TE. */ |
| 9454 |
|
T(V6K), /* V5TEJ. */ |
| 9455 |
|
T(V6K), /* V6. */ |
| 9456 |
|
T(V6KZ), /* V6KZ. */ |
| 9457 |
|
T(V7), /* V6T2. */ |
| 9458 |
|
T(V6K) /* V6K. */ |
| 9459 |
|
}; |
| 9460 |
|
const int v7[] = |
| 9461 |
|
{ |
| 9462 |
|
T(V7), /* PRE_V4. */ |
| 9463 |
|
T(V7), /* V4. */ |
| 9464 |
|
T(V7), /* V4T. */ |
| 9465 |
|
T(V7), /* V5T. */ |
| 9466 |
|
T(V7), /* V5TE. */ |
| 9467 |
|
T(V7), /* V5TEJ. */ |
| 9468 |
|
T(V7), /* V6. */ |
| 9469 |
|
T(V7), /* V6KZ. */ |
| 9470 |
|
T(V7), /* V6T2. */ |
| 9471 |
|
T(V7), /* V6K. */ |
| 9472 |
|
T(V7) /* V7. */ |
| 9473 |
|
}; |
| 9474 |
|
const int v6_m[] = |
| 9475 |
|
{ |
| 9476 |
|
-1, /* PRE_V4. */ |
| 9477 |
|
-1, /* V4. */ |
| 9478 |
|
T(V6K), /* V4T. */ |
| 9479 |
|
T(V6K), /* V5T. */ |
| 9480 |
|
T(V6K), /* V5TE. */ |
| 9481 |
|
T(V6K), /* V5TEJ. */ |
| 9482 |
|
T(V6K), /* V6. */ |
| 9483 |
|
T(V6KZ), /* V6KZ. */ |
| 9484 |
|
T(V7), /* V6T2. */ |
| 9485 |
|
T(V6K), /* V6K. */ |
| 9486 |
|
T(V7), /* V7. */ |
| 9487 |
|
T(V6_M) /* V6_M. */ |
| 9488 |
|
}; |
| 9489 |
|
const int v6s_m[] = |
| 9490 |
|
{ |
| 9491 |
|
-1, /* PRE_V4. */ |
| 9492 |
|
-1, /* V4. */ |
| 9493 |
|
T(V6K), /* V4T. */ |
| 9494 |
|
T(V6K), /* V5T. */ |
| 9495 |
|
T(V6K), /* V5TE. */ |
| 9496 |
|
T(V6K), /* V5TEJ. */ |
| 9497 |
|
T(V6K), /* V6. */ |
| 9498 |
|
T(V6KZ), /* V6KZ. */ |
| 9499 |
|
T(V7), /* V6T2. */ |
| 9500 |
|
T(V6K), /* V6K. */ |
| 9501 |
|
T(V7), /* V7. */ |
| 9502 |
|
T(V6S_M), /* V6_M. */ |
| 9503 |
|
T(V6S_M) /* V6S_M. */ |
| 9504 |
|
}; |
| 9505 |
|
const int v4t_plus_v6_m[] = |
| 9506 |
|
{ |
| 9507 |
|
-1, /* PRE_V4. */ |
| 9508 |
|
-1, /* V4. */ |
| 9509 |
|
T(V4T), /* V4T. */ |
| 9510 |
|
T(V5T), /* V5T. */ |
| 9511 |
|
T(V5TE), /* V5TE. */ |
| 9512 |
|
T(V5TEJ), /* V5TEJ. */ |
| 9513 |
|
T(V6), /* V6. */ |
| 9514 |
|
T(V6KZ), /* V6KZ. */ |
| 9515 |
|
T(V6T2), /* V6T2. */ |
| 9516 |
|
T(V6K), /* V6K. */ |
| 9517 |
|
T(V7), /* V7. */ |
| 9518 |
|
T(V6_M), /* V6_M. */ |
| 9519 |
|
T(V6S_M), /* V6S_M. */ |
| 9520 |
|
T(V4T_PLUS_V6_M) /* V4T plus V6_M. */ |
| 9521 |
|
}; |
| 9522 |
|
const int *comb[] = |
| 9523 |
|
{ |
| 9524 |
|
v6t2, |
| 9525 |
|
v6k, |
| 9526 |
|
v7, |
| 9527 |
|
v6_m, |
| 9528 |
|
v6s_m, |
| 9529 |
|
/* Pseudo-architecture. */ |
| 9530 |
|
v4t_plus_v6_m |
| 9531 |
|
}; |
| 9532 |
|
|
| 9533 |
|
/* Check we've not got a higher architecture than we know about. */ |
| 9534 |
|
|
| 9535 |
|
if (oldtag >= MAX_TAG_CPU_ARCH || newtag >= MAX_TAG_CPU_ARCH) |
| 9536 |
|
{ |
| 9537 |
|
_bfd_error_handler (_("error: %B: Unknown CPU architecture"), ibfd); |
| 9538 |
|
return -1; |
| 9539 |
|
} |
| 9540 |
|
|
| 9541 |
|
/* Override old tag if we have a Tag_also_compatible_with on the output. */ |
| 9542 |
|
|
| 9543 |
|
if ((oldtag == T(V6_M) && *secondary_compat_out == T(V4T)) |
| 9544 |
|
|| (oldtag == T(V4T) && *secondary_compat_out == T(V6_M))) |
| 9545 |
|
oldtag = T(V4T_PLUS_V6_M); |
| 9546 |
|
|
| 9547 |
|
/* And override the new tag if we have a Tag_also_compatible_with on the |
| 9548 |
|
input. */ |
| 9549 |
|
|
| 9550 |
|
if ((newtag == T(V6_M) && secondary_compat == T(V4T)) |
| 9551 |
|
|| (newtag == T(V4T) && secondary_compat == T(V6_M))) |
| 9552 |
|
newtag = T(V4T_PLUS_V6_M); |
| 9553 |
|
|
| 9554 |
|
tagl = (oldtag < newtag) ? oldtag : newtag; |
| 9555 |
|
result = tagh = (oldtag > newtag) ? oldtag : newtag; |
| 9556 |
|
|
| 9557 |
|
/* Architectures before V6KZ add features monotonically. */ |
| 9558 |
|
if (tagh <= TAG_CPU_ARCH_V6KZ) |
| 9559 |
|
return result; |
| 9560 |
|
|
| 9561 |
|
result = comb[tagh - T(V6T2)][tagl]; |
| 9562 |
|
|
| 9563 |
|
/* Use Tag_CPU_arch == V4T and Tag_also_compatible_with (Tag_CPU_arch V6_M) |
| 9564 |
|
as the canonical version. */ |
| 9565 |
|
if (result == T(V4T_PLUS_V6_M)) |
| 9566 |
|
{ |
| 9567 |
|
result = T(V4T); |
| 9568 |
|
*secondary_compat_out = T(V6_M); |
| 9569 |
|
} |
| 9570 |
|
else |
| 9571 |
|
*secondary_compat_out = -1; |
| 9572 |
|
|
| 9573 |
|
if (result == -1) |
| 9574 |
|
{ |
| 9575 |
|
_bfd_error_handler (_("error: %B: Conflicting CPU architectures %d/%d"), |
| 9576 |
|
ibfd, oldtag, newtag); |
| 9577 |
|
return -1; |
| 9578 |
|
} |
| 9579 |
|
|
| 9580 |
|
return result; |
| 9581 |
|
#undef T |
| 9582 |
} |
} |
| 9583 |
|
|
| 9584 |
/* Merge EABI object attributes from IBFD into OBFD. Raise an error if there |
/* Merge EABI object attributes from IBFD into OBFD. Raise an error if there |
| 9591 |
obj_attribute *out_attr; |
obj_attribute *out_attr; |
| 9592 |
obj_attribute_list *in_list; |
obj_attribute_list *in_list; |
| 9593 |
obj_attribute_list *out_list; |
obj_attribute_list *out_list; |
| 9594 |
|
obj_attribute_list **out_listp; |
| 9595 |
/* Some tags have 0 = don't care, 1 = strong requirement, |
/* Some tags have 0 = don't care, 1 = strong requirement, |
| 9596 |
2 = weak requirement. */ |
2 = weak requirement. */ |
| 9597 |
static const int order_312[3] = {3, 1, 2}; |
static const int order_021[3] = {0, 2, 1}; |
| 9598 |
/* For use with Tag_VFP_arch. */ |
/* For use with Tag_VFP_arch. */ |
| 9599 |
static const int order_01243[5] = {0, 1, 2, 4, 3}; |
static const int order_01243[5] = {0, 1, 2, 4, 3}; |
| 9600 |
int i; |
int i; |
| 9601 |
|
bfd_boolean result = TRUE; |
| 9602 |
|
|
| 9603 |
|
/* Skip the linker stubs file. This preserves previous behavior |
| 9604 |
|
of accepting unknown attributes in the first input file - but |
| 9605 |
|
is that a bug? */ |
| 9606 |
|
if (ibfd->flags & BFD_LINKER_CREATED) |
| 9607 |
|
return TRUE; |
| 9608 |
|
|
| 9609 |
if (!elf_known_obj_attributes_proc (obfd)[0].i) |
if (!elf_known_obj_attributes_proc (obfd)[0].i) |
| 9610 |
{ |
{ |
| 9629 |
else if (in_attr[Tag_ABI_FP_number_model].i != 0) |
else if (in_attr[Tag_ABI_FP_number_model].i != 0) |
| 9630 |
{ |
{ |
| 9631 |
_bfd_error_handler |
_bfd_error_handler |
| 9632 |
(_("ERROR: %B uses VFP register arguments, %B does not"), |
(_("error: %B uses VFP register arguments, %B does not"), |
| 9633 |
ibfd, obfd); |
ibfd, obfd); |
| 9634 |
return FALSE; |
result = FALSE; |
| 9635 |
} |
} |
| 9636 |
} |
} |
| 9637 |
|
|
| 9642 |
{ |
{ |
| 9643 |
case Tag_CPU_raw_name: |
case Tag_CPU_raw_name: |
| 9644 |
case Tag_CPU_name: |
case Tag_CPU_name: |
| 9645 |
/* Use whichever has the greatest architecture requirements. We |
/* These are merged after Tag_CPU_arch. */ |
|
won't necessarily have both the above tags, so make sure input |
|
|
name is non-NULL. */ |
|
|
if (in_attr[Tag_CPU_arch].i > out_attr[Tag_CPU_arch].i |
|
|
&& in_attr[i].s) |
|
|
out_attr[i].s = _bfd_elf_attr_strdup (obfd, in_attr[i].s); |
|
| 9646 |
break; |
break; |
| 9647 |
|
|
| 9648 |
case Tag_ABI_optimization_goals: |
case Tag_ABI_optimization_goals: |
| 9651 |
break; |
break; |
| 9652 |
|
|
| 9653 |
case Tag_CPU_arch: |
case Tag_CPU_arch: |
| 9654 |
|
{ |
| 9655 |
|
int secondary_compat = -1, secondary_compat_out = -1; |
| 9656 |
|
unsigned int saved_out_attr = out_attr[i].i; |
| 9657 |
|
static const char *name_table[] = { |
| 9658 |
|
/* These aren't real CPU names, but we can't guess |
| 9659 |
|
that from the architecture version alone. */ |
| 9660 |
|
"Pre v4", |
| 9661 |
|
"ARM v4", |
| 9662 |
|
"ARM v4T", |
| 9663 |
|
"ARM v5T", |
| 9664 |
|
"ARM v5TE", |
| 9665 |
|
"ARM v5TEJ", |
| 9666 |
|
"ARM v6", |
| 9667 |
|
"ARM v6KZ", |
| 9668 |
|
"ARM v6T2", |
| 9669 |
|
"ARM v6K", |
| 9670 |
|
"ARM v7", |
| 9671 |
|
"ARM v6-M", |
| 9672 |
|
"ARM v6S-M" |
| 9673 |
|
}; |
| 9674 |
|
|
| 9675 |
|
/* Merge Tag_CPU_arch and Tag_also_compatible_with. */ |
| 9676 |
|
secondary_compat = get_secondary_compatible_arch (ibfd); |
| 9677 |
|
secondary_compat_out = get_secondary_compatible_arch (obfd); |
| 9678 |
|
out_attr[i].i = tag_cpu_arch_combine (ibfd, out_attr[i].i, |
| 9679 |
|
&secondary_compat_out, |
| 9680 |
|
in_attr[i].i, |
| 9681 |
|
secondary_compat); |
| 9682 |
|
set_secondary_compatible_arch (obfd, secondary_compat_out); |
| 9683 |
|
|
| 9684 |
|
/* Merge Tag_CPU_name and Tag_CPU_raw_name. */ |
| 9685 |
|
if (out_attr[i].i == saved_out_attr) |
| 9686 |
|
; /* Leave the names alone. */ |
| 9687 |
|
else if (out_attr[i].i == in_attr[i].i) |
| 9688 |
|
{ |
| 9689 |
|
/* The output architecture has been changed to match the |
| 9690 |
|
input architecture. Use the input names. */ |
| 9691 |
|
out_attr[Tag_CPU_name].s = in_attr[Tag_CPU_name].s |
| 9692 |
|
? _bfd_elf_attr_strdup (obfd, in_attr[Tag_CPU_name].s) |
| 9693 |
|
: NULL; |
| 9694 |
|
out_attr[Tag_CPU_raw_name].s = in_attr[Tag_CPU_raw_name].s |
| 9695 |
|
? _bfd_elf_attr_strdup (obfd, in_attr[Tag_CPU_raw_name].s) |
| 9696 |
|
: NULL; |
| 9697 |
|
} |
| 9698 |
|
else |
| 9699 |
|
{ |
| 9700 |
|
out_attr[Tag_CPU_name].s = NULL; |
| 9701 |
|
out_attr[Tag_CPU_raw_name].s = NULL; |
| 9702 |
|
} |
| 9703 |
|
|
| 9704 |
|
/* If we still don't have a value for Tag_CPU_name, |
| 9705 |
|
make one up now. Tag_CPU_raw_name remains blank. */ |
| 9706 |
|
if (out_attr[Tag_CPU_name].s == NULL |
| 9707 |
|
&& out_attr[i].i < ARRAY_SIZE (name_table)) |
| 9708 |
|
out_attr[Tag_CPU_name].s = |
| 9709 |
|
_bfd_elf_attr_strdup (obfd, name_table[out_attr[i].i]); |
| 9710 |
|
} |
| 9711 |
|
break; |
| 9712 |
|
|
| 9713 |
case Tag_ARM_ISA_use: |
case Tag_ARM_ISA_use: |
| 9714 |
case Tag_THUMB_ISA_use: |
case Tag_THUMB_ISA_use: |
| 9715 |
case Tag_WMMX_arch: |
case Tag_WMMX_arch: |
| 9716 |
case Tag_NEON_arch: |
case Tag_Advanced_SIMD_arch: |
| 9717 |
/* ??? Do NEON and WMMX conflict? */ |
/* ??? Do Advanced_SIMD (NEON) and WMMX conflict? */ |
| 9718 |
case Tag_ABI_FP_rounding: |
case Tag_ABI_FP_rounding: |
|
case Tag_ABI_FP_denormal: |
|
| 9719 |
case Tag_ABI_FP_exceptions: |
case Tag_ABI_FP_exceptions: |
| 9720 |
case Tag_ABI_FP_user_exceptions: |
case Tag_ABI_FP_user_exceptions: |
| 9721 |
case Tag_ABI_FP_number_model: |
case Tag_ABI_FP_number_model: |
| 9722 |
case Tag_ABI_align8_preserved: |
case Tag_VFP_HP_extension: |
| 9723 |
case Tag_ABI_HardFP_use: |
case Tag_CPU_unaligned_access: |
| 9724 |
|
case Tag_T2EE_use: |
| 9725 |
|
case Tag_Virtualization_use: |
| 9726 |
|
case Tag_MPextension_use: |
| 9727 |
/* Use the largest value specified. */ |
/* Use the largest value specified. */ |
| 9728 |
if (in_attr[i].i > out_attr[i].i) |
if (in_attr[i].i > out_attr[i].i) |
| 9729 |
out_attr[i].i = in_attr[i].i; |
out_attr[i].i = in_attr[i].i; |
| 9730 |
break; |
break; |
| 9731 |
|
|
| 9732 |
case Tag_CPU_arch_profile: |
case Tag_ABI_align8_preserved: |
| 9733 |
/* Warn if conflicting architecture profiles used. */ |
case Tag_ABI_PCS_RO_data: |
| 9734 |
if (out_attr[i].i && in_attr[i].i && in_attr[i].i != out_attr[i].i) |
/* Use the smallest value specified. */ |
| 9735 |
{ |
if (in_attr[i].i < out_attr[i].i) |
| 9736 |
|
out_attr[i].i = in_attr[i].i; |
| 9737 |
|
break; |
| 9738 |
|
|
| 9739 |
|
case Tag_ABI_align8_needed: |
| 9740 |
|
if ((in_attr[i].i > 0 || out_attr[i].i > 0) |
| 9741 |
|
&& (in_attr[Tag_ABI_align8_preserved].i == 0 |
| 9742 |
|
|| out_attr[Tag_ABI_align8_preserved].i == 0)) |
| 9743 |
|
{ |
| 9744 |
|
/* This error message should be enabled once all non-conformant |
| 9745 |
|
binaries in the toolchain have had the attributes set |
| 9746 |
|
properly. |
| 9747 |
_bfd_error_handler |
_bfd_error_handler |
| 9748 |
(_("ERROR: %B: Conflicting architecture profiles %c/%c"), |
(_("error: %B: 8-byte data alignment conflicts with %B"), |
| 9749 |
ibfd, in_attr[i].i, out_attr[i].i); |
obfd, ibfd); |
| 9750 |
return FALSE; |
result = FALSE; */ |
| 9751 |
} |
} |
| 9752 |
if (in_attr[i].i) |
/* Fall through. */ |
| 9753 |
|
case Tag_ABI_FP_denormal: |
| 9754 |
|
case Tag_ABI_PCS_GOT_use: |
| 9755 |
|
/* Use the "greatest" from the sequence 0, 2, 1, or the largest |
| 9756 |
|
value if greater than 2 (for future-proofing). */ |
| 9757 |
|
if ((in_attr[i].i > 2 && in_attr[i].i > out_attr[i].i) |
| 9758 |
|
|| (in_attr[i].i <= 2 && out_attr[i].i <= 2 |
| 9759 |
|
&& order_021[in_attr[i].i] > order_021[out_attr[i].i])) |
| 9760 |
out_attr[i].i = in_attr[i].i; |
out_attr[i].i = in_attr[i].i; |
| 9761 |
break; |
break; |
| 9762 |
|
|
| 9763 |
|
|
| 9764 |
|
case Tag_CPU_arch_profile: |
| 9765 |
|
if (out_attr[i].i != in_attr[i].i) |
| 9766 |
|
{ |
| 9767 |
|
/* 0 will merge with anything. |
| 9768 |
|
'A' and 'S' merge to 'A'. |
| 9769 |
|
'R' and 'S' merge to 'R'. |
| 9770 |
|
'M' and 'A|R|S' is an error. */ |
| 9771 |
|
if (out_attr[i].i == 0 |
| 9772 |
|
|| (out_attr[i].i == 'S' |
| 9773 |
|
&& (in_attr[i].i == 'A' || in_attr[i].i == 'R'))) |
| 9774 |
|
out_attr[i].i = in_attr[i].i; |
| 9775 |
|
else if (in_attr[i].i == 0 |
| 9776 |
|
|| (in_attr[i].i == 'S' |
| 9777 |
|
&& (out_attr[i].i == 'A' || out_attr[i].i == 'R'))) |
| 9778 |
|
; /* Do nothing. */ |
| 9779 |
|
else |
| 9780 |
|
{ |
| 9781 |
|
_bfd_error_handler |
| 9782 |
|
(_("error: %B: Conflicting architecture profiles %c/%c"), |
| 9783 |
|
ibfd, |
| 9784 |
|
in_attr[i].i ? in_attr[i].i : '0', |
| 9785 |
|
out_attr[i].i ? out_attr[i].i : '0'); |
| 9786 |
|
result = FALSE; |
| 9787 |
|
} |
| 9788 |
|
} |
| 9789 |
|
break; |
| 9790 |
case Tag_VFP_arch: |
case Tag_VFP_arch: |
| 9791 |
if (in_attr[i].i > 4 || out_attr[i].i > 4 |
/* Use the "greatest" from the sequence 0, 1, 2, 4, 3, or the |
| 9792 |
|| order_01243[in_attr[i].i] > order_01243[out_attr[i].i]) |
largest value if greater than 4 (for future-proofing). */ |
| 9793 |
|
if ((in_attr[i].i > 4 && in_attr[i].i > out_attr[i].i) |
| 9794 |
|
|| (in_attr[i].i <= 4 && out_attr[i].i <= 4 |
| 9795 |
|
&& order_01243[in_attr[i].i] > order_01243[out_attr[i].i])) |
| 9796 |
out_attr[i].i = in_attr[i].i; |
out_attr[i].i = in_attr[i].i; |
| 9797 |
break; |
break; |
| 9798 |
case Tag_PCS_config: |
case Tag_PCS_config: |
| 9812 |
&& in_attr[i].i != AEABI_R9_unused) |
&& in_attr[i].i != AEABI_R9_unused) |
| 9813 |
{ |
{ |
| 9814 |
_bfd_error_handler |
_bfd_error_handler |
| 9815 |
(_("ERROR: %B: Conflicting use of R9"), ibfd); |
(_("error: %B: Conflicting use of R9"), ibfd); |
| 9816 |
return FALSE; |
result = FALSE; |
| 9817 |
} |
} |
| 9818 |
if (out_attr[i].i == AEABI_R9_unused) |
if (out_attr[i].i == AEABI_R9_unused) |
| 9819 |
out_attr[i].i = in_attr[i].i; |
out_attr[i].i = in_attr[i].i; |
| 9824 |
&& out_attr[Tag_ABI_PCS_R9_use].i != AEABI_R9_unused) |
&& out_attr[Tag_ABI_PCS_R9_use].i != AEABI_R9_unused) |
| 9825 |
{ |
{ |
| 9826 |
_bfd_error_handler |
_bfd_error_handler |
| 9827 |
(_("ERROR: %B: SB relative addressing conflicts with use of R9"), |
(_("error: %B: SB relative addressing conflicts with use of R9"), |
| 9828 |
ibfd); |
ibfd); |
| 9829 |
return FALSE; |
result = FALSE; |
| 9830 |
} |
} |
| 9831 |
/* Use the smallest value specified. */ |
/* Use the smallest value specified. */ |
| 9832 |
if (in_attr[i].i < out_attr[i].i) |
if (in_attr[i].i < out_attr[i].i) |
| 9833 |
out_attr[i].i = in_attr[i].i; |
out_attr[i].i = in_attr[i].i; |
| 9834 |
break; |
break; |
|
case Tag_ABI_PCS_RO_data: |
|
|
/* Use the smallest value specified. */ |
|
|
if (in_attr[i].i < out_attr[i].i) |
|
|
out_attr[i].i = in_attr[i].i; |
|
|
break; |
|
|
case Tag_ABI_PCS_GOT_use: |
|
|
if (in_attr[i].i > 2 || out_attr[i].i > 2 |
|
|
|| order_312[in_attr[i].i] < order_312[out_attr[i].i]) |
|
|
out_attr[i].i = in_attr[i].i; |
|
|
break; |
|
| 9835 |
case Tag_ABI_PCS_wchar_t: |
case Tag_ABI_PCS_wchar_t: |
| 9836 |
if (out_attr[i].i && in_attr[i].i && out_attr[i].i != in_attr[i].i |
if (out_attr[i].i && in_attr[i].i && out_attr[i].i != in_attr[i].i |
| 9837 |
&& !elf_arm_tdata (obfd)->no_wchar_size_warning) |
&& !elf_arm_tdata (obfd)->no_wchar_size_warning) |
| 9843 |
else if (in_attr[i].i && !out_attr[i].i) |
else if (in_attr[i].i && !out_attr[i].i) |
| 9844 |
out_attr[i].i = in_attr[i].i; |
out_attr[i].i = in_attr[i].i; |
| 9845 |
break; |
break; |
|
case Tag_ABI_align8_needed: |
|
|
/* ??? Check against Tag_ABI_align8_preserved. */ |
|
|
if (in_attr[i].i > 2 || out_attr[i].i > 2 |
|
|
|| order_312[in_attr[i].i] < order_312[out_attr[i].i]) |
|
|
out_attr[i].i = in_attr[i].i; |
|
|
break; |
|
| 9846 |
case Tag_ABI_enum_size: |
case Tag_ABI_enum_size: |
| 9847 |
if (in_attr[i].i != AEABI_enum_unused) |
if (in_attr[i].i != AEABI_enum_unused) |
| 9848 |
{ |
{ |
| 9857 |
&& out_attr[i].i != in_attr[i].i |
&& out_attr[i].i != in_attr[i].i |
| 9858 |
&& !elf_arm_tdata (obfd)->no_enum_size_warning) |
&& !elf_arm_tdata (obfd)->no_enum_size_warning) |
| 9859 |
{ |
{ |
| 9860 |
const char *aeabi_enum_names[] = |
static const char *aeabi_enum_names[] = |
| 9861 |
{ "", "variable-size", "32-bit", "" }; |
{ "", "variable-size", "32-bit", "" }; |
| 9862 |
|
const char *in_name = |
| 9863 |
|
in_attr[i].i < ARRAY_SIZE(aeabi_enum_names) |
| 9864 |
|
? aeabi_enum_names[in_attr[i].i] |
| 9865 |
|
: "<unknown>"; |
| 9866 |
|
const char *out_name = |
| 9867 |
|
out_attr[i].i < ARRAY_SIZE(aeabi_enum_names) |
| 9868 |
|
? aeabi_enum_names[out_attr[i].i] |
| 9869 |
|
: "<unknown>"; |
| 9870 |
_bfd_error_handler |
_bfd_error_handler |
| 9871 |
(_("warning: %B uses %s enums yet the output is to use %s enums; use of enum values across objects may fail"), |
(_("warning: %B uses %s enums yet the output is to use %s enums; use of enum values across objects may fail"), |
| 9872 |
ibfd, aeabi_enum_names[in_attr[i].i], |
ibfd, in_name, out_name); |
|
aeabi_enum_names[out_attr[i].i]); |
|
| 9873 |
} |
} |
| 9874 |
} |
} |
| 9875 |
break; |
break; |
| 9880 |
if (in_attr[i].i != out_attr[i].i) |
if (in_attr[i].i != out_attr[i].i) |
| 9881 |
{ |
{ |
| 9882 |
_bfd_error_handler |
_bfd_error_handler |
| 9883 |
(_("ERROR: %B uses iWMMXt register arguments, %B does not"), |
(_("error: %B uses iWMMXt register arguments, %B does not"), |
| 9884 |
ibfd, obfd); |
ibfd, obfd); |
| 9885 |
return FALSE; |
result = FALSE; |
| 9886 |
} |
} |
| 9887 |
break; |
break; |
| 9888 |
|
case Tag_compatibility: |
| 9889 |
|
/* Merged in target-independent code. */ |
| 9890 |
|
break; |
| 9891 |
|
case Tag_ABI_HardFP_use: |
| 9892 |
|
/* 1 (SP) and 2 (DP) conflict, so combine to 3 (SP & DP). */ |
| 9893 |
|
if ((in_attr[i].i == 1 && out_attr[i].i == 2) |
| 9894 |
|
|| (in_attr[i].i == 2 && out_attr[i].i == 1)) |
| 9895 |
|
out_attr[i].i = 3; |
| 9896 |
|
else if (in_attr[i].i > out_attr[i].i) |
| 9897 |
|
out_attr[i].i = in_attr[i].i; |
| 9898 |
|
break; |
| 9899 |
|
case Tag_ABI_FP_16bit_format: |
| 9900 |
|
if (in_attr[i].i != 0 && out_attr[i].i != 0) |
| 9901 |
|
{ |
| 9902 |
|
if (in_attr[i].i != out_attr[i].i) |
| 9903 |
|
{ |
| 9904 |
|
_bfd_error_handler |
| 9905 |
|
(_("error: fp16 format mismatch between %B and %B"), |
| 9906 |
|
ibfd, obfd); |
| 9907 |
|
result = FALSE; |
| 9908 |
|
} |
| 9909 |
|
} |
| 9910 |
|
if (in_attr[i].i != 0) |
| 9911 |
|
out_attr[i].i = in_attr[i].i; |
| 9912 |
|
break; |
| 9913 |
|
|
| 9914 |
default: /* All known attributes should be explicitly covered. */ |
case Tag_nodefaults: |
| 9915 |
abort (); |
/* This tag is set if it exists, but the value is unused (and is |
| 9916 |
} |
typically zero). We don't actually need to do anything here - |
| 9917 |
|
the merge happens automatically when the type flags are merged |
| 9918 |
|
below. */ |
| 9919 |
|
break; |
| 9920 |
|
case Tag_also_compatible_with: |
| 9921 |
|
/* Already done in Tag_CPU_arch. */ |
| 9922 |
|
break; |
| 9923 |
|
case Tag_conformance: |
| 9924 |
|
/* Keep the attribute if it matches. Throw it away otherwise. |
| 9925 |
|
No attribute means no claim to conform. */ |
| 9926 |
|
if (!in_attr[i].s || !out_attr[i].s |
| 9927 |
|
|| strcmp (in_attr[i].s, out_attr[i].s) != 0) |
| 9928 |
|
out_attr[i].s = NULL; |
| 9929 |
|
break; |
| 9930 |
|
|
| 9931 |
if (in_attr[i].type && !out_attr[i].type) |
default: |
|
switch (in_attr[i].type) |
|
| 9932 |
{ |
{ |
| 9933 |
case 1: |
bfd *err_bfd = NULL; |
|
if (out_attr[i].i) |
|
|
out_attr[i].type = 1; |
|
|
break; |
|
| 9934 |
|
|
| 9935 |
case 2: |
/* The "known_obj_attributes" table does contain some undefined |
| 9936 |
if (out_attr[i].s) |
attributes. Ensure that there are unused. */ |
| 9937 |
out_attr[i].type = 2; |
if (out_attr[i].i != 0 || out_attr[i].s != NULL) |
| 9938 |
break; |
err_bfd = obfd; |
|