1 /* dl.c - arch-dependent part of loadable module support */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2004,2005,2007,2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
22 #include <grub/misc.h>
24 #include <grub/i18n.h>
26 /* Check if EHDR is a valid ELF header. */
28 grub_arch_dl_check_header (void *ehdr
)
32 /* Check the magic numbers. */
33 if (e
->e_ident
[EI_CLASS
] != ELFCLASS32
34 || e
->e_ident
[EI_DATA
] != ELFDATA2MSB
35 || e
->e_machine
!= EM_PPC
)
36 return grub_error (GRUB_ERR_BAD_OS
, N_("invalid arch-dependent ELF magic"));
42 grub_arch_dl_get_tramp_got_size (const void *ehdr
, grub_size_t
*tramp
,
45 const Elf_Ehdr
*e
= ehdr
;
52 /* Find a symbol table. */
53 for (i
= 0, s
= (const Elf_Shdr
*) ((const char *) e
+ e
->e_shoff
);
55 i
++, s
= (const Elf_Shdr
*) ((const char *) s
+ e
->e_shentsize
))
56 if (s
->sh_type
== SHT_SYMTAB
)
62 for (i
= 0, s
= (const Elf_Shdr
*) ((const char *) e
+ e
->e_shoff
);
64 i
++, s
= (const Elf_Shdr
*) ((const char *) s
+ e
->e_shentsize
))
65 if (s
->sh_type
== SHT_RELA
)
67 const Elf_Rela
*rel
, *max
;
69 for (rel
= (const Elf_Rela
*) ((const char *) e
+ s
->sh_offset
),
70 max
= rel
+ s
->sh_size
/ s
->sh_entsize
;
73 if (ELF_R_TYPE (rel
->r_info
) == GRUB_ELF_R_PPC_REL24
)
81 /* For low-endian reverse lis and addr_high as well as ori and addr_low. */
90 static const struct trampoline trampoline_template
=
98 /* Relocate symbols. */
100 grub_arch_dl_relocate_symbols (grub_dl_t mod
, void *ehdr
)
106 struct trampoline
*tptr
= mod
->tramp
;
108 /* Find a symbol table. */
109 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
111 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
112 if (s
->sh_type
== SHT_SYMTAB
)
116 return grub_error (GRUB_ERR_BAD_MODULE
, N_("no symbol table"));
118 entsize
= s
->sh_entsize
;
120 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
122 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
123 if (s
->sh_type
== SHT_RELA
)
125 grub_dl_segment_t seg
;
127 /* Find the target segment. */
128 for (seg
= mod
->segment
; seg
; seg
= seg
->next
)
129 if (seg
->section
== s
->sh_info
)
136 for (rel
= (Elf_Rela
*) ((char *) e
+ s
->sh_offset
),
137 max
= rel
+ s
->sh_size
/ s
->sh_entsize
;
145 if (seg
->size
< rel
->r_offset
)
146 return grub_error (GRUB_ERR_BAD_MODULE
,
147 "reloc offset is out of the segment");
149 addr
= (Elf_Word
*) ((char *) seg
->addr
+ rel
->r_offset
);
150 sym
= (Elf_Sym
*) ((char *) mod
->symtab
151 + entsize
* ELF_R_SYM (rel
->r_info
));
153 /* On the PPC the value does not have an explicit
155 value
= sym
->st_value
+ rel
->r_addend
;
156 switch (ELF_R_TYPE (rel
->r_info
))
158 case GRUB_ELF_R_PPC_ADDR16_LO
:
159 *(Elf_Half
*) addr
= value
;
162 case GRUB_ELF_R_PPC_REL24
:
164 Elf_Sword delta
= value
- (Elf_Word
) addr
;
166 if (delta
<< 6 >> 6 != delta
)
168 COMPILE_TIME_ASSERT (sizeof (struct trampoline
)
169 == GRUB_ARCH_DL_TRAMP_SIZE
);
170 grub_memcpy (tptr
, &trampoline_template
,
172 delta
= (grub_uint8_t
*) tptr
- (grub_uint8_t
*) addr
;
173 tptr
->lis
|= (((value
) >> 16) & 0xffff);
174 tptr
->ori
|= ((value
) & 0xffff);
178 if (delta
<< 6 >> 6 != delta
)
179 return grub_error (GRUB_ERR_BAD_MODULE
,
180 "relocation overflow");
181 *addr
= (*addr
& 0xfc000003) | (delta
& 0x3fffffc);
185 case GRUB_ELF_R_PPC_ADDR16_HA
:
186 *(Elf_Half
*) addr
= (value
+ 0x8000) >> 16;
189 case GRUB_ELF_R_PPC_ADDR32
:
193 case GRUB_ELF_R_PPC_REL32
:
194 *addr
= value
- (Elf_Word
) addr
;
198 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
199 N_("relocation 0x%x is not implemented yet"),
200 ELF_R_TYPE (rel
->r_info
));
206 return GRUB_ERR_NONE
;