Branch data Line data Source code
1 : : /* PPC specific symbolic name handling.
2 : : Copyright (C) 2004, 2005, 2007, 2014, 2015 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : : Written by Ulrich Drepper <drepper@redhat.com>, 2004.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of either
8 : :
9 : : * the GNU Lesser General Public License as published by the Free
10 : : Software Foundation; either version 3 of the License, or (at
11 : : your option) any later version
12 : :
13 : : or
14 : :
15 : : * the GNU General Public License as published by the Free
16 : : Software Foundation; either version 2 of the License, or (at
17 : : your option) any later version
18 : :
19 : : or both in parallel, as here.
20 : :
21 : : elfutils is distributed in the hope that it will be useful, but
22 : : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : : General Public License for more details.
25 : :
26 : : You should have received copies of the GNU General Public License and
27 : : the GNU Lesser General Public License along with this program. If
28 : : not, see <http://www.gnu.org/licenses/>. */
29 : :
30 : : #ifdef HAVE_CONFIG_H
31 : : # include <config.h>
32 : : #endif
33 : :
34 : : #include <assert.h>
35 : : #include <elf.h>
36 : : #include <stddef.h>
37 : : #include <string.h>
38 : :
39 : : #define BACKEND ppc_
40 : : #include "libebl_CPU.h"
41 : :
42 : :
43 : : /* Check for the simple reloc types. */
44 : : Elf_Type
45 : 0 : ppc_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type,
46 : : int *addsub __attribute__ ((unused)))
47 : : {
48 [ # # # ]: 0 : switch (type)
49 : : {
50 : : case R_PPC_ADDR32:
51 : : case R_PPC_UADDR32:
52 : : return ELF_T_WORD;
53 : 0 : case R_PPC_UADDR16:
54 : 0 : return ELF_T_HALF;
55 : 0 : default:
56 : 0 : return ELF_T_NUM;
57 : : }
58 : : }
59 : :
60 : :
61 : : /* Check whether machine flags are valid. */
62 : : bool
63 : 21 : ppc_machine_flag_check (GElf_Word flags)
64 : : {
65 : 21 : return ((flags &~ (EF_PPC_EMB
66 : : | EF_PPC_RELOCATABLE
67 : 21 : | EF_PPC_RELOCATABLE_LIB)) == 0);
68 : : }
69 : :
70 : :
71 : : const char *
72 : 0 : ppc_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)),
73 : : size_t len __attribute__ ((unused)))
74 : : {
75 [ # # # ]: 0 : switch (tag)
76 : : {
77 : : case DT_PPC_GOT:
78 : : return "PPC_GOT";
79 : 0 : case DT_PPC_OPT:
80 : 0 : return "PPC_OPT";
81 : : default:
82 : 0 : break;
83 : : }
84 : 0 : return NULL;
85 : : }
86 : :
87 : :
88 : : bool
89 : 180 : ppc_dynamic_tag_check (int64_t tag)
90 : : {
91 : 180 : return (tag == DT_PPC_GOT
92 : 180 : || tag == DT_PPC_OPT);
93 : : }
94 : :
95 : :
96 : : /* Look for DT_PPC_GOT. */
97 : : static bool
98 : 18 : find_dyn_got (Elf *elf, GElf_Addr *addr)
99 : : {
100 : 18 : size_t phnum;
101 [ + - ]: 18 : if (elf_getphdrnum (elf, &phnum) != 0)
102 : : return false;
103 : :
104 [ + - ]: 90 : for (size_t i = 0; i < phnum; ++i)
105 : : {
106 : 90 : GElf_Phdr phdr_mem;
107 : 90 : GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
108 [ + - + + ]: 90 : if (phdr == NULL || phdr->p_type != PT_DYNAMIC)
109 : 72 : continue;
110 : :
111 : 18 : Elf_Scn *scn = gelf_offscn (elf, phdr->p_offset);
112 : 18 : GElf_Shdr shdr_mem;
113 : 18 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
114 : 18 : Elf_Data *data = elf_getdata (scn, NULL);
115 [ + - + - : 18 : if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC && data != NULL
+ - ]
116 [ + - ]: 18 : && shdr->sh_entsize != 0)
117 [ + - ]: 324 : for (unsigned int j = 0; j < shdr->sh_size / shdr->sh_entsize; ++j)
118 : : {
119 : 324 : GElf_Dyn dyn_mem;
120 : 324 : GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
121 [ + - + + ]: 324 : if (dyn != NULL && dyn->d_tag == DT_PPC_GOT)
122 : : {
123 : 18 : *addr = dyn->d_un.d_ptr;
124 : 18 : return true;
125 : : }
126 : : }
127 : :
128 : : /* There is only one PT_DYNAMIC entry. */
129 : 0 : break;
130 : : }
131 : :
132 : : return false;
133 : : }
134 : :
135 : :
136 : : /* Check whether given symbol's st_value and st_size are OK despite failing
137 : : normal checks. */
138 : : bool
139 : 600 : ppc_check_special_symbol (Elf *elf, const GElf_Sym *sym,
140 : : const char *name, const GElf_Shdr *destshdr)
141 : : {
142 [ + - ]: 600 : if (name == NULL)
143 : : return false;
144 : :
145 [ + + ]: 600 : if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
146 : : {
147 : : /* In -msecure-plt mode, DT_PPC_GOT is present and must match. */
148 : 12 : GElf_Addr gotaddr;
149 [ + - ]: 12 : if (find_dyn_got (elf, &gotaddr))
150 : 12 : return sym->st_value == gotaddr;
151 : :
152 : : /* In -mbss-plt mode, any place in the section is valid. */
153 : : return true;
154 : : }
155 : :
156 : 588 : size_t shstrndx;
157 [ + - ]: 588 : if (elf_getshdrstrndx (elf, &shstrndx) != 0)
158 : : return false;
159 : 588 : const char *sname = elf_strptr (elf, shstrndx, destshdr->sh_name);
160 [ + - ]: 588 : if (sname == NULL)
161 : : return false;
162 : :
163 : : /* Small data area. Normally points to .sdata, in which case we
164 : : check it is at an offset of 0x8000. It might however fall in the
165 : : .data section, in which case we cannot check the offset. The
166 : : size always should be zero. */
167 [ + + ]: 588 : if (strcmp (name, "_SDA_BASE_") == 0)
168 : 6 : return (((strcmp (sname, ".sdata") == 0
169 [ - + ]: 6 : && sym->st_value == destshdr->sh_addr + 0x8000)
170 [ # # ]: 0 : || strcmp (sname, ".data") == 0)
171 [ + - - + ]: 12 : && sym->st_size == 0);
172 : :
173 [ - + ]: 582 : if (strcmp (name, "_SDA2_BASE_") == 0)
174 : 0 : return (strcmp (sname, ".sdata2") == 0
175 [ # # ]: 0 : && sym->st_value == destshdr->sh_addr + 0x8000
176 [ # # # # ]: 0 : && sym->st_size == 0);
177 : :
178 : : return false;
179 : : }
180 : :
181 : :
182 : : /* Check if backend uses a bss PLT in this file. */
183 : : bool
184 : 6 : ppc_bss_plt_p (Elf *elf)
185 : : {
186 : 6 : GElf_Addr addr;
187 : 6 : return ! find_dyn_got (elf, &addr);
188 : : }
|