Initialize Tizen 2.3
[external/prelink.git] / src / arch-cris.c
1 /* Copyright (C) 2001, 2002, 2004, 2009 Red Hat, Inc.
2    Written by Jakub Jelinek <jakub@redhat.com>, 2001.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #include <config.h>
19 #include <assert.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <locale.h>
25 #include <error.h>
26 #include <argp.h>
27 #include <stdlib.h>
28
29 #include "prelink.h"
30
31 static int
32 cris_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
33                  GElf_Addr adjust)
34 {
35   if (dyn->d_tag == DT_PLTGOT)
36     {
37       int sec = addr_to_sec (dso, dyn->d_un.d_ptr);
38       Elf32_Addr data;
39
40       if (sec == -1)
41         return 0;
42
43       data = read_ule32 (dso, dyn->d_un.d_ptr);
44       /* If .got[0] points to _DYNAMIC, it needs to be adjusted.  */
45       if (data == dso->shdr[n].sh_addr && data >= start)
46         write_le32 (dso, dyn->d_un.d_ptr, data + adjust);
47
48       data = read_ule32 (dso, dyn->d_un.d_ptr + 4);
49       /* If .got[1] points to .plt + 28, it needs to be adjusted.  */
50       if (data && data >= start)
51         {
52           int i;
53
54           for (i = 1; i < dso->ehdr.e_shnum; i++)
55             if (data == dso->shdr[i].sh_addr + 28
56                 && dso->shdr[i].sh_type == SHT_PROGBITS
57                 && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
58                                         dso->shdr[i].sh_name), ".plt") == 0)
59               {
60                 write_le32 (dso, dyn->d_un.d_ptr + 4, data + adjust);
61                 break;
62               }
63         }
64     }
65   return 0;
66 }
67
68 static int
69 cris_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
70                  GElf_Addr adjust)
71 {
72   error (0, 0, "%s: CRIS doesn't support REL relocs", dso->filename);
73   return 1;
74 }
75
76 static int
77 cris_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
78                   GElf_Addr adjust)
79 {
80   Elf32_Addr data;
81
82   switch (GELF_R_TYPE (rela->r_info))
83     {
84     case R_CRIS_RELATIVE:
85       if ((Elf32_Addr) rela->r_addend >= start)
86         rela->r_addend += (Elf32_Sword) adjust;
87       break;
88     case R_CRIS_JUMP_SLOT:
89       data = read_ule32 (dso, rela->r_offset);
90       if (data >= start)
91         write_le32 (dso, rela->r_offset, data + adjust);
92       break;
93       break;
94     }
95   return 0;
96 }
97
98 static int
99 cris_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
100 {
101   error (0, 0, "%s: CRIS doesn't support REL relocs", info->dso->filename);
102   return 1;
103 }
104
105 static int
106 cris_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
107                    GElf_Addr relaaddr)
108 {
109   DSO *dso;
110   GElf_Addr value;
111
112   dso = info->dso;
113   if (GELF_R_TYPE (rela->r_info) == R_CRIS_NONE)
114     /* Fast path: nothing to do.  */
115     return 0;
116   else if (GELF_R_TYPE (rela->r_info) == R_CRIS_RELATIVE)
117     {
118       write_le32 (dso, rela->r_offset, rela->r_addend);
119       return 0;
120     }
121   value = info->resolve (info, GELF_R_SYM (rela->r_info),
122                          GELF_R_TYPE (rela->r_info));
123   value += rela->r_addend;
124   switch (GELF_R_TYPE (rela->r_info))
125     {
126     case R_CRIS_GLOB_DAT:
127     case R_CRIS_JUMP_SLOT:
128     case R_CRIS_32:
129       write_le32 (dso, rela->r_offset, value);
130       break;
131     case R_CRIS_16:
132       write_le16 (dso, rela->r_offset, value);
133       break;
134     case R_CRIS_8:
135       write_8 (dso, rela->r_offset, value);
136       break;
137     case R_CRIS_32_PCREL:
138       write_le32 (dso, rela->r_offset, value - rela->r_offset - 4);
139       break;
140     case R_CRIS_16_PCREL:
141       write_le16 (dso, rela->r_offset, value - rela->r_offset - 2);
142       break;
143     case R_CRIS_8_PCREL:
144       write_8 (dso, rela->r_offset, value - rela->r_offset - 1);
145       break;
146     case R_CRIS_COPY:
147       if (dso->ehdr.e_type == ET_EXEC)
148         /* COPY relocs are handled specially in generic code.  */
149         return 0;
150       error (0, 0, "%s: R_CRIS_COPY reloc in shared library?", dso->filename);
151       return 1;
152     default:
153       error (0, 0, "%s: Unknown cris relocation type %d", dso->filename,
154              (int) GELF_R_TYPE (rela->r_info));
155       return 1;
156     }
157   return 0;
158 }
159
160 static int
161 cris_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
162                           char *buf, GElf_Addr dest_addr)
163 {
164   switch (GELF_R_TYPE (rela->r_info))
165     {
166     case R_CRIS_GLOB_DAT:
167     case R_CRIS_JUMP_SLOT:
168     case R_CRIS_32:
169       buf_write_le32 (buf, rela->r_addend);
170       break;
171     case R_CRIS_16:
172       buf_write_le16 (buf, rela->r_addend);
173       break;
174     case R_CRIS_8:
175       buf_write_8 (buf, rela->r_addend);
176       break;
177     default:
178       abort ();
179     }
180   return 0;
181 }
182
183 static int
184 cris_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
185 {
186   error (0, 0, "%s: CRIS doesn't support REL relocs", info->dso->filename);
187   return 1;
188 }
189
190 static int
191 cris_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
192 {
193   GElf_Addr value;
194
195   value = info->resolve (info, GELF_R_SYM (rela->r_info),
196                          GELF_R_TYPE (rela->r_info));
197   value += rela->r_addend;
198   switch (GELF_R_TYPE (rela->r_info))
199     {
200     case R_CRIS_NONE:
201       break;
202     case R_CRIS_GLOB_DAT:
203     case R_CRIS_JUMP_SLOT:
204     case R_CRIS_32:
205       buf_write_le32 (buf, value);
206       break;
207     case R_CRIS_16:
208       buf_write_le16 (buf, value);
209       break;
210     case R_CRIS_8:
211       buf_write_8 (buf, value);
212       break;
213     case R_CRIS_32_PCREL:
214       buf_write_le32 (buf, value - rela->r_offset - 4);
215       break;
216     case R_CRIS_16_PCREL:
217       buf_write_le16 (buf, value - rela->r_offset - 2);
218       break;
219     case R_CRIS_8:
220       buf_write_8 (buf, value - rela->r_offset - 1);
221       break;
222     case R_CRIS_COPY:
223       abort ();
224     case R_CRIS_RELATIVE:
225       error (0, 0, "%s: R_CRIS_RELATIVE in ET_EXEC object?", info->dso->filename);
226       return 1;
227     default:
228       return 1;
229     }
230   return 0;
231 }
232
233 static int
234 cris_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
235                            GElf_Addr reladdr)
236 {
237   error (0, 0, "%s: CRIS doesn't support REL relocs", dso->filename);
238   return 1;
239 }
240
241 static int
242 cris_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
243                             GElf_Rela *rela, GElf_Addr relaaddr)
244 {
245   GElf_Addr value;
246   struct prelink_conflict *conflict;
247   GElf_Rela *ret;
248
249   if (GELF_R_TYPE (rela->r_info) == R_CRIS_RELATIVE
250       || GELF_R_TYPE (rela->r_info) == R_CRIS_NONE
251       || info->dso == dso)
252     /* Fast path: nothing to do.  */
253     return 0;
254   conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
255                                GELF_R_TYPE (rela->r_info));
256   if (conflict == NULL)
257     return 0;
258   else if (conflict->ifunc)
259     {
260       error (0, 0, "%s: STT_GNU_IFUNC not handled on CRIS yet",
261              dso->filename);
262       return 1;
263     }
264   value = conflict_lookup_value (conflict);
265   ret = prelink_conflict_add_rela (info);
266   if (ret == NULL)
267     return 1;
268   ret->r_offset = rela->r_offset;
269   ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rela->r_info));
270   value += rela->r_addend;
271   switch (GELF_R_TYPE (rela->r_info))
272     {
273     case R_CRIS_GLOB_DAT:
274     case R_CRIS_JUMP_SLOT:
275     case R_CRIS_32:
276     case R_CRIS_16:
277     case R_CRIS_8:
278       ret->r_addend = (Elf32_Sword) (value + rela->r_addend);
279       break;
280     case R_CRIS_32_PCREL:
281       ret->r_addend = (Elf32_Sword) (value + rela->r_addend
282                                      - rela->r_offset - 4);
283       ret->r_info = GELF_R_INFO (0, R_CRIS_32);
284       break;
285     case R_CRIS_16_PCREL:
286       ret->r_addend = (Elf32_Sword) (value + rela->r_addend
287                                      - rela->r_offset - 2);
288       ret->r_info = GELF_R_INFO (0, R_CRIS_16);
289       break;
290     case R_CRIS_8_PCREL:
291       ret->r_addend = (Elf32_Sword) (value + rela->r_addend
292                                      - rela->r_offset - 1);
293       ret->r_info = GELF_R_INFO (0, R_CRIS_8);
294       break;
295     case R_CRIS_COPY:
296       error (0, 0, "R_CRIS_COPY should not be present in shared libraries");
297       return 1;
298     default:
299       error (0, 0, "%s: Unknown cris relocation type %d", dso->filename,
300              (int) GELF_R_TYPE (rela->r_info));
301       return 1;
302     }
303   return 0;
304 }
305
306 static int
307 cris_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
308 {
309   return 0;
310 }
311
312 static int
313 cris_need_rel_to_rela (DSO *dso, int first, int last)
314 {
315   return 0;
316 }
317
318 static int
319 cris_arch_prelink (struct prelink_info *info)
320 {
321   DSO *dso;
322   int i;
323
324   dso = info->dso;
325   if (dso->info[DT_PLTGOT])
326     {
327       /* Write address of .plt + 28 into got[1].
328          .plt + 28 is what got[3] contains unless prelinking.  */
329       int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
330       Elf32_Addr data;
331
332       if (sec == -1)
333         return 1;
334
335       for (i = 1; i < dso->ehdr.e_shnum; i++)
336         if (dso->shdr[i].sh_type == SHT_PROGBITS
337             && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
338                                  dso->shdr[i].sh_name),
339                          ".plt"))
340         break;
341
342       assert (i < dso->ehdr.e_shnum);
343       data = dso->shdr[i].sh_addr + 28;
344       write_le32 (dso, dso->info[DT_PLTGOT] + 4, data);
345     }
346
347   return 0;
348 }
349
350 static int
351 cris_reloc_size (int reloc_type)
352 {
353   switch (reloc_type)
354     {
355     case R_CRIS_16:
356     case R_CRIS_16_PCREL:
357       return 2;
358     case R_CRIS_8:
359     case R_CRIS_8_PCREL:
360       return 1;
361     default:
362       return 4;
363     }
364 }
365
366 static int
367 cris_reloc_class (int reloc_type)
368 {
369   switch (reloc_type)
370     {
371     case R_CRIS_COPY: return RTYPE_CLASS_COPY;
372     case R_CRIS_JUMP_SLOT: return RTYPE_CLASS_PLT;
373     default: return RTYPE_CLASS_VALID;
374     }
375 }
376
377 PL_ARCH = {
378   .name = "CRIS",
379   .class = ELFCLASS32,
380   .machine = EM_CRIS,
381   .alternate_machine = { EM_NONE },
382   .R_JUMP_SLOT = R_CRIS_JUMP_SLOT,
383   .R_COPY = R_CRIS_COPY,
384   .R_RELATIVE = R_CRIS_RELATIVE,
385   .rtype_class_valid = RTYPE_CLASS_VALID,
386   .dynamic_linker = "/lib/ld.so.1",
387   .adjust_dyn = cris_adjust_dyn,
388   .adjust_rel = cris_adjust_rel,
389   .adjust_rela = cris_adjust_rela,
390   .prelink_rel = cris_prelink_rel,
391   .prelink_rela = cris_prelink_rela,
392   .prelink_conflict_rel = cris_prelink_conflict_rel,
393   .prelink_conflict_rela = cris_prelink_conflict_rela,
394   .apply_conflict_rela = cris_apply_conflict_rela,
395   .apply_rel = cris_apply_rel,
396   .apply_rela = cris_apply_rela,
397   .rel_to_rela = cris_rel_to_rela,
398   .need_rel_to_rela = cris_need_rel_to_rela,
399   .reloc_size = cris_reloc_size,
400   .reloc_class = cris_reloc_class,
401   .max_reloc_size = 4,
402   .arch_prelink = cris_arch_prelink,
403   /* Although TASK_UNMAPPED_BASE is 0x3aaaa000, we leave some
404      area so that mmap of /etc/ld.so.cache and ld.so's malloc
405      does not take some library's VA slot.
406      Also, if this guard area isn't too small, typically
407      even dlopened libraries will get the slots they desire.  */
408   .mmap_base = 0x3c000000,
409   .mmap_end =  0x48000000,
410   .max_page_size = 0x2000,
411   .page_size = 0x2000
412 };