]>
Commit | Line | Data |
---|---|---|
0253aeb7 VS |
1 | /* grub-mkimage.c - make a bootable image */ |
2 | /* | |
3 | * GRUB -- GRand Unified Bootloader | |
4 | * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. | |
5 | * | |
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. | |
10 | * | |
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. | |
15 | * | |
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/>. | |
18 | */ | |
19 | ||
36212460 VS |
20 | #include <config.h> |
21 | #include <grub/types.h> | |
22 | #include <grub/elf.h> | |
23 | #include <grub/aout.h> | |
24 | #include <grub/i18n.h> | |
25 | #include <grub/kernel.h> | |
26 | #include <grub/disk.h> | |
27 | #include <grub/emu/misc.h> | |
28 | #include <grub/util/misc.h> | |
29 | #include <grub/util/resolve.h> | |
30 | #include <grub/misc.h> | |
31 | #include <grub/offsets.h> | |
32 | #include <grub/crypto.h> | |
33 | #include <grub/dl.h> | |
34 | #include <time.h> | |
35 | #include <multiboot.h> | |
36 | ||
37 | #include <stdio.h> | |
38 | #include <unistd.h> | |
39 | #include <string.h> | |
40 | #include <stdlib.h> | |
41 | #include <assert.h> | |
42 | #include <grub/efi/pe32.h> | |
43 | #include <grub/uboot/image.h> | |
44 | #include <grub/arm/reloc.h> | |
45 | #include <grub/arm64/reloc.h> | |
46 | #include <grub/ia64/reloc.h> | |
47 | #include <grub/osdep/hostfile.h> | |
48 | #include <grub/util/install.h> | |
49 | #include <grub/util/mkimage.h> | |
50 | ||
51 | #pragma GCC diagnostic ignored "-Wcast-align" | |
0253aeb7 | 52 | |
36212460 VS |
53 | /* These structures are defined according to the CHRP binding to IEEE1275, |
54 | "Client Program Format" section. */ | |
55 | ||
56 | struct grub_ieee1275_note_desc | |
57 | { | |
58 | grub_uint32_t real_mode; | |
59 | grub_uint32_t real_base; | |
60 | grub_uint32_t real_size; | |
61 | grub_uint32_t virt_base; | |
62 | grub_uint32_t virt_size; | |
63 | grub_uint32_t load_base; | |
64 | }; | |
65 | ||
66 | #define GRUB_IEEE1275_NOTE_NAME "PowerPC" | |
67 | #define GRUB_IEEE1275_NOTE_TYPE 0x1275 | |
68 | ||
69 | struct grub_ieee1275_note | |
70 | { | |
71 | Elf32_Nhdr header; | |
72 | char name[ALIGN_UP(sizeof (GRUB_IEEE1275_NOTE_NAME), 4)]; | |
73 | struct grub_ieee1275_note_desc descriptor; | |
74 | }; | |
75 | ||
76 | #define GRUB_XEN_NOTE_NAME "Xen" | |
77 | ||
78 | struct fixup_block_list | |
79 | { | |
80 | struct fixup_block_list *next; | |
81 | int state; | |
82 | struct grub_pe32_fixup_block b; | |
83 | }; | |
84 | ||
85 | #define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof)) | |
86 | ||
86ef66d9 VS |
87 | static int |
88 | is_relocatable (const struct grub_install_image_target_desc *image_target) | |
89 | { | |
90 | return image_target->id == IMAGE_EFI || image_target->id == IMAGE_UBOOT; | |
91 | } | |
92 | ||
36212460 VS |
93 | #ifdef MKIMAGE_ELF32 |
94 | ||
95 | /* | |
96 | * R_ARM_THM_CALL/THM_JUMP24 | |
97 | * | |
98 | * Relocate Thumb (T32) instruction set relative branches: | |
99 | * B.W, BL and BLX | |
100 | */ | |
101 | static grub_err_t | |
102 | grub_arm_reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr) | |
103 | { | |
104 | grub_int32_t offset; | |
105 | ||
106 | offset = grub_arm_thm_call_get_offset (target); | |
107 | ||
108 | grub_dprintf ("dl", " sym_addr = 0x%08x", sym_addr); | |
109 | ||
110 | offset += sym_addr; | |
111 | ||
112 | grub_dprintf("dl", " BL*: target=%p, sym_addr=0x%08x, offset=%d\n", | |
113 | target, sym_addr, offset); | |
114 | ||
115 | /* Keep traditional (pre-Thumb2) limits on blx. In any case if the kernel | |
116 | is bigger than 2M (currently under 150K) then we probably have a problem | |
117 | somewhere else. */ | |
118 | if (offset < -0x200000 || offset >= 0x200000) | |
119 | return grub_error (GRUB_ERR_BAD_MODULE, | |
120 | "THM_CALL Relocation out of range."); | |
121 | ||
122 | grub_dprintf ("dl", " relative destination = %p", | |
123 | (char *) target + offset); | |
124 | ||
125 | return grub_arm_thm_call_set_offset (target, offset); | |
126 | } | |
127 | ||
128 | /* | |
129 | * R_ARM_THM_JUMP19 | |
130 | * | |
131 | * Relocate conditional Thumb (T32) B<c>.W | |
132 | */ | |
133 | static grub_err_t | |
134 | grub_arm_reloc_thm_jump19 (grub_uint16_t *target, Elf32_Addr sym_addr) | |
135 | { | |
136 | grub_int32_t offset; | |
137 | ||
138 | if (!(sym_addr & 1)) | |
139 | return grub_error (GRUB_ERR_BAD_MODULE, | |
140 | "Relocation targeting wrong execution state"); | |
141 | ||
142 | offset = grub_arm_thm_jump19_get_offset (target); | |
143 | ||
144 | /* Adjust and re-truncate offset */ | |
145 | offset += sym_addr; | |
146 | ||
147 | if (!grub_arm_thm_jump19_check_offset (offset)) | |
148 | return grub_error (GRUB_ERR_BAD_MODULE, | |
149 | "THM_JUMP19 Relocation out of range."); | |
150 | ||
151 | grub_arm_thm_jump19_set_offset (target, offset); | |
152 | ||
153 | return GRUB_ERR_NONE; | |
154 | } | |
155 | ||
156 | /* | |
157 | * R_ARM_JUMP24 | |
158 | * | |
159 | * Relocate ARM (A32) B | |
160 | */ | |
161 | static grub_err_t | |
162 | grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) | |
163 | { | |
164 | grub_int32_t offset; | |
165 | ||
166 | if (sym_addr & 1) | |
167 | return grub_error (GRUB_ERR_BAD_MODULE, | |
168 | "Relocation targeting wrong execution state"); | |
169 | ||
170 | offset = grub_arm_jump24_get_offset (target); | |
171 | offset += sym_addr; | |
172 | ||
173 | if (!grub_arm_jump24_check_offset (offset)) | |
174 | return grub_error (GRUB_ERR_BAD_MODULE, | |
175 | "JUMP24 Relocation out of range."); | |
176 | ||
177 | ||
178 | grub_arm_jump24_set_offset (target, offset); | |
179 | ||
180 | return GRUB_ERR_NONE; | |
181 | } | |
182 | ||
183 | #endif | |
184 | ||
185 | void | |
186 | SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target, | |
187 | int note, char **core_img, size_t *core_size, | |
188 | Elf_Addr target_addr, grub_size_t align, | |
189 | size_t kernel_size, size_t bss_size) | |
9612ebc0 VS |
190 | { |
191 | char *elf_img; | |
192 | size_t program_size; | |
193 | Elf_Ehdr *ehdr; | |
194 | Elf_Phdr *phdr; | |
195 | Elf_Shdr *shdr; | |
196 | int header_size, footer_size = 0; | |
197 | int phnum = 1; | |
198 | int shnum = 4; | |
199 | int string_size = sizeof (".text") + sizeof ("mods") + 1; | |
200 | ||
201 | if (image_target->id != IMAGE_LOONGSON_ELF) | |
202 | phnum += 2; | |
203 | ||
204 | if (note) | |
205 | { | |
206 | phnum++; | |
207 | footer_size += sizeof (struct grub_ieee1275_note); | |
208 | } | |
209 | if (image_target->id == IMAGE_XEN) | |
210 | { | |
211 | phnum++; | |
212 | shnum++; | |
213 | string_size += sizeof (".xen"); | |
214 | footer_size += XEN_NOTE_SIZE; | |
215 | } | |
216 | header_size = ALIGN_UP (sizeof (*ehdr) + phnum * sizeof (*phdr) | |
217 | + shnum * sizeof (*shdr) + string_size, align); | |
218 | ||
219 | program_size = ALIGN_ADDR (*core_size); | |
220 | ||
221 | elf_img = xmalloc (program_size + header_size + footer_size); | |
1018e91d | 222 | memset (elf_img, 0, program_size + header_size + footer_size); |
9612ebc0 VS |
223 | memcpy (elf_img + header_size, *core_img, *core_size); |
224 | ehdr = (void *) elf_img; | |
225 | phdr = (void *) (elf_img + sizeof (*ehdr)); | |
226 | shdr = (void *) (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)); | |
227 | memcpy (ehdr->e_ident, ELFMAG, SELFMAG); | |
228 | ehdr->e_ident[EI_CLASS] = ELFCLASSXX; | |
229 | if (!image_target->bigendian) | |
230 | ehdr->e_ident[EI_DATA] = ELFDATA2LSB; | |
231 | else | |
232 | ehdr->e_ident[EI_DATA] = ELFDATA2MSB; | |
233 | ehdr->e_ident[EI_VERSION] = EV_CURRENT; | |
234 | ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE; | |
235 | ehdr->e_type = grub_host_to_target16 (ET_EXEC); | |
236 | ehdr->e_machine = grub_host_to_target16 (image_target->elf_target); | |
237 | ehdr->e_version = grub_host_to_target32 (EV_CURRENT); | |
238 | ||
239 | ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr); | |
240 | ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr)); | |
241 | ehdr->e_phnum = grub_host_to_target16 (phnum); | |
242 | ||
243 | ehdr->e_shoff = grub_host_to_target32 ((grub_uint8_t *) shdr | |
244 | - (grub_uint8_t *) ehdr); | |
245 | if (image_target->id == IMAGE_LOONGSON_ELF) | |
246 | ehdr->e_shentsize = grub_host_to_target16 (0); | |
247 | else | |
248 | ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf_Shdr)); | |
249 | ehdr->e_shnum = grub_host_to_target16 (shnum); | |
250 | ehdr->e_shstrndx = grub_host_to_target16 (1); | |
251 | ||
252 | ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr)); | |
253 | ||
254 | phdr->p_type = grub_host_to_target32 (PT_LOAD); | |
255 | phdr->p_offset = grub_host_to_target32 (header_size); | |
256 | phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); | |
257 | ||
258 | ehdr->e_entry = grub_host_to_target32 (target_addr); | |
259 | phdr->p_vaddr = grub_host_to_target32 (target_addr); | |
260 | phdr->p_paddr = grub_host_to_target32 (target_addr); | |
261 | phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align); | |
262 | if (image_target->id == IMAGE_LOONGSON_ELF) | |
263 | ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER | |
264 | | EF_MIPS_PIC | EF_MIPS_CPIC); | |
265 | else | |
266 | ehdr->e_flags = 0; | |
267 | if (image_target->id == IMAGE_LOONGSON_ELF) | |
268 | { | |
269 | phdr->p_filesz = grub_host_to_target32 (*core_size); | |
270 | phdr->p_memsz = grub_host_to_target32 (*core_size); | |
271 | } | |
272 | else | |
273 | { | |
274 | grub_uint32_t target_addr_mods; | |
275 | phdr->p_filesz = grub_host_to_target32 (kernel_size); | |
276 | phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size); | |
277 | ||
278 | phdr++; | |
279 | phdr->p_type = grub_host_to_target32 (PT_GNU_STACK); | |
280 | phdr->p_offset = grub_host_to_target32 (header_size + kernel_size); | |
281 | phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0; | |
282 | phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); | |
283 | phdr->p_align = grub_host_to_target32 (image_target->link_align); | |
284 | ||
285 | phdr++; | |
286 | phdr->p_type = grub_host_to_target32 (PT_LOAD); | |
287 | phdr->p_offset = grub_host_to_target32 (header_size + kernel_size); | |
288 | phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); | |
289 | phdr->p_filesz = phdr->p_memsz | |
290 | = grub_host_to_target32 (*core_size - kernel_size); | |
291 | ||
881c6a10 VS |
292 | if (image_target->id == IMAGE_COREBOOT) |
293 | target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR; | |
294 | else | |
295 | target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size | |
296 | + image_target->mod_gap, | |
297 | image_target->mod_align); | |
9612ebc0 VS |
298 | phdr->p_vaddr = grub_host_to_target_addr (target_addr_mods); |
299 | phdr->p_paddr = grub_host_to_target_addr (target_addr_mods); | |
300 | phdr->p_align = grub_host_to_target32 (image_target->link_align); | |
301 | } | |
302 | ||
303 | if (image_target->id == IMAGE_XEN) | |
304 | { | |
305 | char *note_start = (elf_img + program_size + header_size); | |
306 | Elf_Nhdr *note_ptr; | |
307 | char *ptr = (char *) note_start; | |
308 | ||
309 | grub_util_info ("adding XEN NOTE segment"); | |
310 | ||
311 | /* Guest OS. */ | |
312 | note_ptr = (Elf_Nhdr *) ptr; | |
313 | note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); | |
314 | note_ptr->n_descsz = grub_host_to_target32 (sizeof (PACKAGE_NAME)); | |
315 | note_ptr->n_type = grub_host_to_target32 (6); | |
316 | ptr += sizeof (Elf_Nhdr); | |
317 | memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); | |
318 | ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); | |
319 | memcpy (ptr, PACKAGE_NAME, sizeof (PACKAGE_NAME)); | |
320 | ptr += ALIGN_UP (sizeof (PACKAGE_NAME), 4); | |
321 | ||
322 | /* Loader. */ | |
323 | note_ptr = (Elf_Nhdr *) ptr; | |
324 | note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); | |
325 | note_ptr->n_descsz = grub_host_to_target32 (sizeof ("generic")); | |
326 | note_ptr->n_type = grub_host_to_target32 (8); | |
327 | ptr += sizeof (Elf_Nhdr); | |
328 | memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); | |
329 | ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); | |
330 | memcpy (ptr, "generic", sizeof ("generic")); | |
331 | ptr += ALIGN_UP (sizeof ("generic"), 4); | |
332 | ||
333 | /* Version. */ | |
334 | note_ptr = (Elf_Nhdr *) ptr; | |
335 | note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); | |
336 | note_ptr->n_descsz = grub_host_to_target32 (sizeof ("xen-3.0")); | |
337 | note_ptr->n_type = grub_host_to_target32 (5); | |
338 | ptr += sizeof (Elf_Nhdr); | |
339 | memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); | |
340 | ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); | |
341 | memcpy (ptr, "xen-3.0", sizeof ("xen-3.0")); | |
342 | ptr += ALIGN_UP (sizeof ("xen-3.0"), 4); | |
343 | ||
344 | /* Entry. */ | |
345 | note_ptr = (Elf_Nhdr *) ptr; | |
346 | note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); | |
347 | note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof); | |
348 | note_ptr->n_type = grub_host_to_target32 (1); | |
349 | ptr += sizeof (Elf_Nhdr); | |
350 | memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); | |
351 | ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); | |
352 | memset (ptr, 0, image_target->voidp_sizeof); | |
353 | ptr += image_target->voidp_sizeof; | |
354 | ||
355 | /* Virt base. */ | |
356 | note_ptr = (Elf_Nhdr *) ptr; | |
357 | note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); | |
358 | note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof); | |
359 | note_ptr->n_type = grub_host_to_target32 (3); | |
360 | ptr += sizeof (Elf_Nhdr); | |
361 | memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); | |
362 | ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); | |
363 | memset (ptr, 0, image_target->voidp_sizeof); | |
364 | ptr += image_target->voidp_sizeof; | |
365 | ||
366 | /* PAE. */ | |
367 | if (image_target->elf_target == EM_386) | |
368 | { | |
369 | note_ptr = (Elf_Nhdr *) ptr; | |
370 | note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); | |
371 | note_ptr->n_descsz = grub_host_to_target32 (sizeof ("yes,bimodal")); | |
372 | note_ptr->n_type = grub_host_to_target32 (9); | |
373 | ptr += sizeof (Elf_Nhdr); | |
374 | memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); | |
375 | ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); | |
376 | memcpy (ptr, "yes", sizeof ("yes")); | |
377 | ptr += ALIGN_UP (sizeof ("yes"), 4); | |
378 | } | |
379 | ||
380 | assert (XEN_NOTE_SIZE == (ptr - note_start)); | |
381 | ||
382 | phdr++; | |
383 | phdr->p_type = grub_host_to_target32 (PT_NOTE); | |
384 | phdr->p_flags = grub_host_to_target32 (PF_R); | |
385 | phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); | |
386 | phdr->p_vaddr = 0; | |
387 | phdr->p_paddr = 0; | |
388 | phdr->p_filesz = grub_host_to_target32 (XEN_NOTE_SIZE); | |
389 | phdr->p_memsz = 0; | |
390 | phdr->p_offset = grub_host_to_target32 (header_size + program_size); | |
391 | } | |
392 | ||
393 | if (note) | |
394 | { | |
395 | int note_size = sizeof (struct grub_ieee1275_note); | |
396 | struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *) | |
397 | (elf_img + program_size + header_size); | |
398 | ||
399 | grub_util_info ("adding CHRP NOTE segment"); | |
400 | ||
401 | note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME)); | |
402 | note_ptr->header.n_descsz = grub_host_to_target32 (note_size); | |
403 | note_ptr->header.n_type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE); | |
404 | strcpy (note_ptr->name, GRUB_IEEE1275_NOTE_NAME); | |
405 | note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff); | |
406 | note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000); | |
407 | note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff); | |
408 | note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff); | |
409 | note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff); | |
410 | note_ptr->descriptor.load_base = grub_host_to_target32 (0x00004000); | |
411 | ||
412 | phdr++; | |
413 | phdr->p_type = grub_host_to_target32 (PT_NOTE); | |
414 | phdr->p_flags = grub_host_to_target32 (PF_R); | |
415 | phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); | |
416 | phdr->p_vaddr = 0; | |
417 | phdr->p_paddr = 0; | |
418 | phdr->p_filesz = grub_host_to_target32 (note_size); | |
419 | phdr->p_memsz = 0; | |
420 | phdr->p_offset = grub_host_to_target32 (header_size + program_size); | |
421 | } | |
422 | ||
423 | { | |
424 | char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr) | |
425 | + shnum * sizeof (*shdr)); | |
426 | char *ptr = str_start + 1; | |
427 | ||
428 | shdr++; | |
429 | ||
430 | shdr->sh_name = grub_host_to_target32 (0); | |
431 | shdr->sh_type = grub_host_to_target32 (SHT_STRTAB); | |
432 | shdr->sh_addr = grub_host_to_target_addr (0); | |
433 | shdr->sh_offset = grub_host_to_target_addr (str_start - elf_img); | |
434 | shdr->sh_size = grub_host_to_target32 (string_size); | |
435 | shdr->sh_link = grub_host_to_target32 (0); | |
436 | shdr->sh_info = grub_host_to_target32 (0); | |
437 | shdr->sh_addralign = grub_host_to_target32 (align); | |
438 | shdr->sh_entsize = grub_host_to_target32 (0); | |
439 | shdr++; | |
440 | ||
441 | memcpy (ptr, ".text", sizeof (".text")); | |
442 | ||
443 | shdr->sh_name = grub_host_to_target32 (ptr - str_start); | |
444 | ptr += sizeof (".text"); | |
445 | shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS); | |
446 | shdr->sh_addr = grub_host_to_target_addr (target_addr); | |
447 | shdr->sh_offset = grub_host_to_target_addr (header_size); | |
448 | shdr->sh_size = grub_host_to_target32 (kernel_size); | |
449 | shdr->sh_link = grub_host_to_target32 (0); | |
450 | shdr->sh_info = grub_host_to_target32 (0); | |
451 | shdr->sh_addralign = grub_host_to_target32 (align); | |
452 | shdr->sh_entsize = grub_host_to_target32 (0); | |
453 | shdr++; | |
454 | ||
455 | memcpy (ptr, "mods", sizeof ("mods")); | |
456 | shdr->sh_name = grub_host_to_target32 (ptr - str_start); | |
457 | ptr += sizeof ("mods"); | |
458 | shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS); | |
459 | shdr->sh_addr = grub_host_to_target_addr (target_addr + kernel_size); | |
460 | shdr->sh_offset = grub_host_to_target_addr (header_size + kernel_size); | |
461 | shdr->sh_size = grub_host_to_target32 (*core_size - kernel_size); | |
462 | shdr->sh_link = grub_host_to_target32 (0); | |
463 | shdr->sh_info = grub_host_to_target32 (0); | |
464 | shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof); | |
465 | shdr->sh_entsize = grub_host_to_target32 (0); | |
466 | shdr++; | |
467 | ||
468 | if (image_target->id == IMAGE_XEN) | |
469 | { | |
470 | memcpy (ptr, ".xen", sizeof (".xen")); | |
471 | shdr->sh_name = grub_host_to_target32 (ptr - str_start); | |
472 | ptr += sizeof (".xen"); | |
473 | shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS); | |
474 | shdr->sh_addr = grub_host_to_target_addr (target_addr + kernel_size); | |
475 | shdr->sh_offset = grub_host_to_target_addr (program_size + header_size); | |
476 | shdr->sh_size = grub_host_to_target32 (XEN_NOTE_SIZE); | |
477 | shdr->sh_link = grub_host_to_target32 (0); | |
478 | shdr->sh_info = grub_host_to_target32 (0); | |
479 | shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof); | |
480 | shdr->sh_entsize = grub_host_to_target32 (0); | |
481 | shdr++; | |
482 | } | |
483 | } | |
484 | ||
485 | free (*core_img); | |
486 | *core_img = elf_img; | |
487 | *core_size = program_size + header_size + footer_size; | |
488 | } | |
489 | ||
0253aeb7 VS |
490 | /* Relocate symbols; note that this function overwrites the symbol table. |
491 | Return the address of a start symbol. */ | |
492 | static Elf_Addr | |
493 | SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, | |
494 | Elf_Shdr *symtab_section, Elf_Addr *section_addresses, | |
495 | Elf_Half section_entsize, Elf_Half num_sections, | |
5452733f | 496 | void *jumpers, Elf_Addr jumpers_addr, |
df21fff5 | 497 | Elf_Addr bss_start, Elf_Addr end, |
ec16e026 | 498 | const struct grub_install_image_target_desc *image_target) |
0253aeb7 VS |
499 | { |
500 | Elf_Word symtab_size, sym_size, num_syms; | |
501 | Elf_Off symtab_offset; | |
5bcb7d39 | 502 | Elf_Addr start_address = (Elf_Addr) -1; |
0253aeb7 VS |
503 | Elf_Sym *sym; |
504 | Elf_Word i; | |
505 | Elf_Shdr *strtab_section; | |
506 | const char *strtab; | |
5452733f | 507 | grub_uint64_t *jptr = jumpers; |
0253aeb7 VS |
508 | |
509 | strtab_section | |
510 | = (Elf_Shdr *) ((char *) sections | |
511 | + (grub_target_to_host32 (symtab_section->sh_link) | |
512 | * section_entsize)); | |
962b15b4 | 513 | strtab = (char *) e + grub_target_to_host (strtab_section->sh_offset); |
0253aeb7 | 514 | |
962b15b4 VS |
515 | symtab_size = grub_target_to_host (symtab_section->sh_size); |
516 | sym_size = grub_target_to_host (symtab_section->sh_entsize); | |
517 | symtab_offset = grub_target_to_host (symtab_section->sh_offset); | |
0253aeb7 VS |
518 | num_syms = symtab_size / sym_size; |
519 | ||
520 | for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset); | |
521 | i < num_syms; | |
522 | i++, sym = (Elf_Sym *) ((char *) sym + sym_size)) | |
523 | { | |
495fc8c1 | 524 | Elf_Section cur_index; |
0253aeb7 VS |
525 | const char *name; |
526 | ||
527 | name = strtab + grub_target_to_host32 (sym->st_name); | |
528 | ||
495fc8c1 VS |
529 | cur_index = grub_target_to_host16 (sym->st_shndx); |
530 | if (cur_index == STN_ABS) | |
0253aeb7 VS |
531 | { |
532 | continue; | |
533 | } | |
7cb24eb5 | 534 | else if (cur_index == STN_UNDEF) |
0253aeb7 | 535 | { |
86ef66d9 | 536 | if (sym->st_name && grub_strcmp (name, "__bss_start") == 0) |
df21fff5 | 537 | sym->st_value = bss_start; |
86ef66d9 | 538 | else if (sym->st_name && grub_strcmp (name, "_end") == 0) |
df21fff5 VS |
539 | sym->st_value = end; |
540 | else if (sym->st_name) | |
0253aeb7 VS |
541 | grub_util_error ("undefined symbol %s", name); |
542 | else | |
543 | continue; | |
544 | } | |
495fc8c1 VS |
545 | else if (cur_index >= num_sections) |
546 | grub_util_error ("section %d does not exist", cur_index); | |
df21fff5 VS |
547 | else |
548 | { | |
549 | sym->st_value = (grub_target_to_host (sym->st_value) | |
550 | + section_addresses[cur_index]); | |
551 | } | |
5452733f VS |
552 | |
553 | if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info) | |
554 | == STT_FUNC) | |
555 | { | |
d5e2a158 | 556 | *jptr = grub_host_to_target64 (sym->st_value); |
5452733f VS |
557 | sym->st_value = (char *) jptr - (char *) jumpers + jumpers_addr; |
558 | jptr++; | |
559 | *jptr = 0; | |
560 | jptr++; | |
561 | } | |
18e76955 VS |
562 | grub_util_info ("locating %s at 0x%" GRUB_HOST_PRIxLONG_LONG |
563 | " (0x%" GRUB_HOST_PRIxLONG_LONG ")", name, | |
495fc8c1 VS |
564 | (unsigned long long) sym->st_value, |
565 | (unsigned long long) section_addresses[cur_index]); | |
0253aeb7 | 566 | |
5bcb7d39 | 567 | if (start_address == (Elf_Addr)-1) |
0253aeb7 VS |
568 | if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0) |
569 | start_address = sym->st_value; | |
570 | } | |
571 | ||
572 | return start_address; | |
573 | } | |
574 | ||
575 | /* Return the address of a symbol at the index I in the section S. */ | |
576 | static Elf_Addr | |
577 | SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i, | |
ec16e026 | 578 | const struct grub_install_image_target_desc *image_target) |
0253aeb7 VS |
579 | { |
580 | Elf_Sym *sym; | |
581 | ||
582 | sym = (Elf_Sym *) ((char *) e | |
d5e2a158 VS |
583 | + grub_target_to_host (s->sh_offset) |
584 | + i * grub_target_to_host (s->sh_entsize)); | |
0253aeb7 VS |
585 | return sym->st_value; |
586 | } | |
587 | ||
588 | /* Return the address of a modified value. */ | |
589 | static Elf_Addr * | |
590 | SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset, | |
ec16e026 | 591 | const struct grub_install_image_target_desc *image_target) |
0253aeb7 | 592 | { |
d5e2a158 | 593 | return (Elf_Addr *) ((char *) e + grub_target_to_host (s->sh_offset) + offset); |
0253aeb7 VS |
594 | } |
595 | ||
495fc8c1 | 596 | #ifdef MKIMAGE_ELF64 |
5452733f VS |
597 | static Elf_Addr |
598 | SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section, | |
ec16e026 | 599 | const struct grub_install_image_target_desc *image_target) |
5452733f VS |
600 | { |
601 | Elf_Word symtab_size, sym_size, num_syms; | |
602 | Elf_Off symtab_offset; | |
5452733f VS |
603 | Elf_Sym *sym; |
604 | Elf_Word i; | |
605 | int ret = 0; | |
606 | ||
607 | symtab_size = grub_target_to_host (symtab_section->sh_size); | |
608 | sym_size = grub_target_to_host (symtab_section->sh_entsize); | |
609 | symtab_offset = grub_target_to_host (symtab_section->sh_offset); | |
610 | num_syms = symtab_size / sym_size; | |
611 | ||
612 | for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset); | |
613 | i < num_syms; | |
614 | i++, sym = (Elf_Sym *) ((char *) sym + sym_size)) | |
615 | if (ELF_ST_TYPE (sym->st_info) == STT_FUNC) | |
616 | ret++; | |
617 | ||
618 | return ret; | |
619 | } | |
495fc8c1 | 620 | #endif |
5452733f | 621 | |
8c534b85 VS |
622 | #ifdef MKIMAGE_ELF32 |
623 | /* Deal with relocation information. This function relocates addresses | |
624 | within the virtual address space starting from 0. So only relative | |
625 | addresses can be fully resolved. Absolute addresses must be relocated | |
626 | again by a PE32 relocator when loaded. */ | |
627 | static grub_size_t | |
628 | arm_get_trampoline_size (Elf_Ehdr *e, | |
629 | Elf_Shdr *sections, | |
630 | Elf_Half section_entsize, | |
631 | Elf_Half num_sections, | |
632 | const struct grub_install_image_target_desc *image_target) | |
633 | { | |
634 | Elf_Half i; | |
635 | Elf_Shdr *s; | |
636 | grub_size_t ret = 0; | |
637 | ||
638 | for (i = 0, s = sections; | |
639 | i < num_sections; | |
640 | i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) | |
641 | if ((s->sh_type == grub_host_to_target32 (SHT_REL)) || | |
642 | (s->sh_type == grub_host_to_target32 (SHT_RELA))) | |
643 | { | |
644 | Elf_Rela *r; | |
645 | Elf_Word rtab_size, r_size, num_rs; | |
646 | Elf_Off rtab_offset; | |
647 | Elf_Shdr *symtab_section; | |
648 | Elf_Word j; | |
649 | ||
650 | symtab_section = (Elf_Shdr *) ((char *) sections | |
651 | + (grub_target_to_host32 (s->sh_link) | |
652 | * section_entsize)); | |
653 | ||
654 | rtab_size = grub_target_to_host (s->sh_size); | |
655 | r_size = grub_target_to_host (s->sh_entsize); | |
656 | rtab_offset = grub_target_to_host (s->sh_offset); | |
657 | num_rs = rtab_size / r_size; | |
658 | ||
659 | for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); | |
660 | j < num_rs; | |
661 | j++, r = (Elf_Rela *) ((char *) r + r_size)) | |
662 | { | |
663 | Elf_Addr info; | |
664 | Elf_Addr sym_addr; | |
665 | ||
666 | info = grub_target_to_host (r->r_info); | |
667 | sym_addr = SUFFIX (get_symbol_address) (e, symtab_section, | |
668 | ELF_R_SYM (info), image_target); | |
669 | ||
670 | sym_addr += (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? | |
671 | grub_target_to_host (r->r_addend) : 0; | |
672 | ||
673 | switch (ELF_R_TYPE (info)) | |
674 | { | |
675 | case R_ARM_ABS32: | |
676 | case R_ARM_V4BX: | |
677 | break; | |
678 | case R_ARM_THM_CALL: | |
679 | case R_ARM_THM_JUMP24: | |
680 | case R_ARM_THM_JUMP19: | |
681 | if (!(sym_addr & 1)) | |
682 | ret += 8; | |
683 | break; | |
684 | ||
685 | case R_ARM_CALL: | |
686 | case R_ARM_JUMP24: | |
687 | if (sym_addr & 1) | |
688 | ret += 16; | |
689 | break; | |
690 | ||
691 | default: | |
d6c2782a VS |
692 | grub_util_error (_("relocation 0x%x is not implemented yet"), |
693 | (unsigned int) ELF_R_TYPE (info)); | |
8c534b85 VS |
694 | break; |
695 | } | |
696 | } | |
697 | } | |
698 | return ret; | |
699 | } | |
700 | #endif | |
701 | ||
0253aeb7 VS |
702 | /* Deal with relocation information. This function relocates addresses |
703 | within the virtual address space starting from 0. So only relative | |
704 | addresses can be fully resolved. Absolute addresses must be relocated | |
705 | again by a PE32 relocator when loaded. */ | |
706 | static void | |
707 | SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, | |
708 | Elf_Addr *section_addresses, | |
709 | Elf_Half section_entsize, Elf_Half num_sections, | |
5452733f VS |
710 | const char *strtab, |
711 | char *pe_target, Elf_Addr tramp_off, | |
712 | Elf_Addr got_off, | |
ec16e026 | 713 | const struct grub_install_image_target_desc *image_target) |
0253aeb7 VS |
714 | { |
715 | Elf_Half i; | |
716 | Elf_Shdr *s; | |
495fc8c1 | 717 | #ifdef MKIMAGE_ELF64 |
d5e2a158 | 718 | struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off); |
5452733f | 719 | grub_uint64_t *gpptr = (void *) (pe_target + got_off); |
d5e2a158 | 720 | #define MASK19 ((1 << 19) - 1) |
8c534b85 VS |
721 | #else |
722 | grub_uint32_t *tr = (void *) (pe_target + tramp_off); | |
495fc8c1 | 723 | #endif |
0253aeb7 VS |
724 | |
725 | for (i = 0, s = sections; | |
726 | i < num_sections; | |
727 | i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) | |
728 | if ((s->sh_type == grub_host_to_target32 (SHT_REL)) || | |
729 | (s->sh_type == grub_host_to_target32 (SHT_RELA))) | |
730 | { | |
731 | Elf_Rela *r; | |
732 | Elf_Word rtab_size, r_size, num_rs; | |
733 | Elf_Off rtab_offset; | |
734 | Elf_Shdr *symtab_section; | |
735 | Elf_Word target_section_index; | |
736 | Elf_Addr target_section_addr; | |
737 | Elf_Shdr *target_section; | |
738 | Elf_Word j; | |
739 | ||
740 | symtab_section = (Elf_Shdr *) ((char *) sections | |
741 | + (grub_target_to_host32 (s->sh_link) | |
742 | * section_entsize)); | |
743 | target_section_index = grub_target_to_host32 (s->sh_info); | |
744 | target_section_addr = section_addresses[target_section_index]; | |
745 | target_section = (Elf_Shdr *) ((char *) sections | |
746 | + (target_section_index | |
747 | * section_entsize)); | |
748 | ||
749 | grub_util_info ("dealing with the relocation section %s for %s", | |
750 | strtab + grub_target_to_host32 (s->sh_name), | |
751 | strtab + grub_target_to_host32 (target_section->sh_name)); | |
752 | ||
d5e2a158 VS |
753 | rtab_size = grub_target_to_host (s->sh_size); |
754 | r_size = grub_target_to_host (s->sh_entsize); | |
755 | rtab_offset = grub_target_to_host (s->sh_offset); | |
0253aeb7 VS |
756 | num_rs = rtab_size / r_size; |
757 | ||
758 | for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); | |
759 | j < num_rs; | |
760 | j++, r = (Elf_Rela *) ((char *) r + r_size)) | |
761 | { | |
762 | Elf_Addr info; | |
763 | Elf_Addr offset; | |
764 | Elf_Addr sym_addr; | |
765 | Elf_Addr *target; | |
766 | Elf_Addr addend; | |
767 | ||
768 | offset = grub_target_to_host (r->r_offset); | |
769 | target = SUFFIX (get_target_address) (e, target_section, | |
770 | offset, image_target); | |
771 | info = grub_target_to_host (r->r_info); | |
772 | sym_addr = SUFFIX (get_symbol_address) (e, symtab_section, | |
773 | ELF_R_SYM (info), image_target); | |
774 | ||
775 | addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? | |
d5e2a158 | 776 | grub_target_to_host (r->r_addend) : 0; |
0253aeb7 | 777 | |
bea33583 | 778 | switch (image_target->elf_target) |
779 | { | |
780 | case EM_386: | |
0253aeb7 VS |
781 | switch (ELF_R_TYPE (info)) |
782 | { | |
783 | case R_386_NONE: | |
784 | break; | |
785 | ||
786 | case R_386_32: | |
787 | /* This is absolute. */ | |
788 | *target = grub_host_to_target32 (grub_target_to_host32 (*target) | |
789 | + addend + sym_addr); | |
18e76955 VS |
790 | grub_util_info ("relocating an R_386_32 entry to 0x%" |
791 | GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" | |
792 | GRUB_HOST_PRIxLONG_LONG, | |
495fc8c1 VS |
793 | (unsigned long long) *target, |
794 | (unsigned long long) offset); | |
0253aeb7 VS |
795 | break; |
796 | ||
797 | case R_386_PC32: | |
798 | /* This is relative. */ | |
799 | *target = grub_host_to_target32 (grub_target_to_host32 (*target) | |
800 | + addend + sym_addr | |
801 | - target_section_addr - offset | |
802 | - image_target->vaddr_offset); | |
18e76955 VS |
803 | grub_util_info ("relocating an R_386_PC32 entry to 0x%" |
804 | GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" | |
805 | GRUB_HOST_PRIxLONG_LONG, | |
495fc8c1 VS |
806 | (unsigned long long) *target, |
807 | (unsigned long long) offset); | |
0253aeb7 VS |
808 | break; |
809 | default: | |
d6c2782a VS |
810 | grub_util_error (_("relocation 0x%x is not implemented yet"), |
811 | (unsigned int) ELF_R_TYPE (info)); | |
0253aeb7 VS |
812 | break; |
813 | } | |
bea33583 | 814 | break; |
495fc8c1 | 815 | #ifdef MKIMAGE_ELF64 |
bea33583 | 816 | case EM_X86_64: |
0253aeb7 VS |
817 | switch (ELF_R_TYPE (info)) |
818 | { | |
819 | ||
820 | case R_X86_64_NONE: | |
821 | break; | |
822 | ||
823 | case R_X86_64_64: | |
824 | *target = grub_host_to_target64 (grub_target_to_host64 (*target) | |
825 | + addend + sym_addr); | |
18e76955 VS |
826 | grub_util_info ("relocating an R_X86_64_64 entry to 0x%" |
827 | GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" | |
828 | GRUB_HOST_PRIxLONG_LONG, | |
495fc8c1 VS |
829 | (unsigned long long) *target, |
830 | (unsigned long long) offset); | |
0253aeb7 VS |
831 | break; |
832 | ||
833 | case R_X86_64_PC32: | |
834 | { | |
835 | grub_uint32_t *t32 = (grub_uint32_t *) target; | |
836 | *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) | |
837 | + addend + sym_addr | |
838 | - target_section_addr - offset | |
839 | - image_target->vaddr_offset); | |
18e76955 VS |
840 | grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%" |
841 | GRUB_HOST_PRIxLONG_LONG, | |
495fc8c1 | 842 | *t32, (unsigned long long) offset); |
0253aeb7 VS |
843 | break; |
844 | } | |
845 | ||
f4171ebd VS |
846 | case R_X86_64_PC64: |
847 | { | |
848 | *target = grub_host_to_target64 (grub_target_to_host64 (*target) | |
849 | + addend + sym_addr | |
850 | - target_section_addr - offset | |
851 | - image_target->vaddr_offset); | |
18e76955 VS |
852 | grub_util_info ("relocating an R_X86_64_PC64 entry to 0x%" |
853 | GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" | |
854 | GRUB_HOST_PRIxLONG_LONG, | |
f4171ebd VS |
855 | (unsigned long long) *target, |
856 | (unsigned long long) offset); | |
857 | break; | |
858 | } | |
859 | ||
0253aeb7 VS |
860 | case R_X86_64_32: |
861 | case R_X86_64_32S: | |
862 | { | |
863 | grub_uint32_t *t32 = (grub_uint32_t *) target; | |
864 | *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) | |
865 | + addend + sym_addr); | |
18e76955 VS |
866 | grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%" |
867 | GRUB_HOST_PRIxLONG_LONG, | |
495fc8c1 | 868 | *t32, (unsigned long long) offset); |
0253aeb7 VS |
869 | break; |
870 | } | |
871 | ||
872 | default: | |
d6c2782a VS |
873 | grub_util_error (_("relocation 0x%x is not implemented yet"), |
874 | (unsigned int) ELF_R_TYPE (info)); | |
0253aeb7 VS |
875 | break; |
876 | } | |
bea33583 | 877 | break; |
878 | case EM_IA_64: | |
879 | switch (ELF_R_TYPE (info)) | |
880 | { | |
5452733f VS |
881 | case R_IA64_PCREL21B: |
882 | { | |
883 | grub_uint64_t noff; | |
d5e2a158 | 884 | grub_ia64_make_trampoline (tr, addend + sym_addr); |
5452733f | 885 | noff = ((char *) tr - (char *) pe_target |
a988e7aa | 886 | - target_section_addr - (offset & ~3)) >> 4; |
5452733f VS |
887 | tr++; |
888 | if (noff & ~MASK19) | |
0b6225bd | 889 | grub_util_error ("trampoline offset too big (%" |
18e76955 VS |
890 | GRUB_HOST_PRIxLONG_LONG ")", |
891 | (unsigned long long) noff); | |
d5e2a158 | 892 | grub_ia64_add_value_to_slot_20b ((grub_addr_t) target, noff); |
5452733f VS |
893 | } |
894 | break; | |
895 | ||
5452733f VS |
896 | case R_IA64_LTOFF22X: |
897 | case R_IA64_LTOFF22: | |
2679b724 VS |
898 | { |
899 | Elf_Sym *sym; | |
900 | ||
901 | sym = (Elf_Sym *) ((char *) e | |
d5e2a158 VS |
902 | + grub_target_to_host (symtab_section->sh_offset) |
903 | + ELF_R_SYM (info) * grub_target_to_host (symtab_section->sh_entsize)); | |
2679b724 VS |
904 | if (ELF_ST_TYPE (sym->st_info) == STT_FUNC) |
905 | sym_addr = grub_target_to_host64 (*(grub_uint64_t *) (pe_target | |
906 | + sym->st_value | |
907 | - image_target->vaddr_offset)); | |
908 | } | |
909 | case R_IA64_LTOFF_FPTR22: | |
5452733f | 910 | *gpptr = grub_host_to_target64 (addend + sym_addr); |
d5e2a158 VS |
911 | grub_ia64_add_value_to_slot_21 ((grub_addr_t) target, |
912 | (char *) gpptr - (char *) pe_target | |
913 | + image_target->vaddr_offset); | |
5452733f VS |
914 | gpptr++; |
915 | break; | |
916 | ||
917 | case R_IA64_GPREL22: | |
d5e2a158 VS |
918 | grub_ia64_add_value_to_slot_21 ((grub_addr_t) target, |
919 | addend + sym_addr); | |
5452733f | 920 | break; |
a134ef1a VS |
921 | case R_IA64_GPREL64I: |
922 | grub_ia64_set_immu64 ((grub_addr_t) target, | |
923 | addend + sym_addr); | |
924 | break; | |
5452733f VS |
925 | case R_IA64_PCREL64LSB: |
926 | *target = grub_host_to_target64 (grub_target_to_host64 (*target) | |
927 | + addend + sym_addr | |
928 | - target_section_addr - offset | |
929 | - image_target->vaddr_offset); | |
930 | break; | |
931 | ||
932 | case R_IA64_SEGREL64LSB: | |
933 | *target = grub_host_to_target64 (grub_target_to_host64 (*target) | |
934 | + addend + sym_addr - target_section_addr); | |
935 | break; | |
936 | case R_IA64_DIR64LSB: | |
937 | case R_IA64_FPTR64LSB: | |
938 | *target = grub_host_to_target64 (grub_target_to_host64 (*target) | |
939 | + addend + sym_addr); | |
940 | grub_util_info ("relocating a direct entry to 0x%" | |
18e76955 VS |
941 | GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" |
942 | GRUB_HOST_PRIxLONG_LONG, | |
943 | (unsigned long long) | |
d5e2a158 VS |
944 | grub_target_to_host64 (*target), |
945 | (unsigned long long) offset); | |
5452733f VS |
946 | break; |
947 | ||
948 | /* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */ | |
949 | case R_IA64_LDXMOV: | |
950 | break; | |
951 | ||
bea33583 | 952 | default: |
d6c2782a VS |
953 | grub_util_error (_("relocation 0x%x is not implemented yet"), |
954 | (unsigned int) ELF_R_TYPE (info)); | |
bea33583 | 955 | break; |
956 | } | |
957 | break; | |
15a463d7 LL |
958 | case EM_AARCH64: |
959 | { | |
960 | sym_addr += addend; | |
961 | switch (ELF_R_TYPE (info)) | |
962 | { | |
963 | case R_AARCH64_ABS64: | |
964 | { | |
965 | *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr); | |
966 | } | |
967 | break; | |
605eecc9 VS |
968 | case R_AARCH64_ADD_ABS_LO12_NC: |
969 | grub_arm64_set_abs_lo12 ((grub_uint32_t *) target, | |
970 | sym_addr); | |
971 | break; | |
972 | case R_AARCH64_LDST64_ABS_LO12_NC: | |
973 | grub_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) target, | |
974 | sym_addr); | |
975 | break; | |
15a463d7 LL |
976 | case R_AARCH64_JUMP26: |
977 | case R_AARCH64_CALL26: | |
978 | { | |
15a463d7 | 979 | sym_addr -= offset; |
43b444e5 | 980 | sym_addr -= target_section_addr + image_target->vaddr_offset; |
8c534b85 | 981 | if (!grub_arm_64_check_xxxx26_offset (sym_addr)) |
57a691b7 | 982 | grub_util_error ("%s", "CALL26 Relocation out of range"); |
8c534b85 VS |
983 | |
984 | grub_arm64_set_xxxx26_offset((grub_uint32_t *)target, | |
15a463d7 | 985 | sym_addr); |
15a463d7 LL |
986 | } |
987 | break; | |
605eecc9 VS |
988 | case R_AARCH64_ADR_PREL_PG_HI21: |
989 | { | |
990 | sym_addr &= ~0xfffULL; | |
43b444e5 | 991 | sym_addr -= (offset + target_section_addr + image_target->vaddr_offset) & ~0xfffULL; |
605eecc9 VS |
992 | if (!grub_arm64_check_hi21_signed (sym_addr)) |
993 | grub_util_error ("%s", "CALL26 Relocation out of range"); | |
994 | ||
995 | grub_arm64_set_hi21((grub_uint32_t *)target, | |
996 | sym_addr); | |
997 | } | |
998 | break; | |
15a463d7 | 999 | default: |
d6c2782a VS |
1000 | grub_util_error (_("relocation 0x%x is not implemented yet"), |
1001 | (unsigned int) ELF_R_TYPE (info)); | |
15a463d7 LL |
1002 | break; |
1003 | } | |
1004 | break; | |
1005 | } | |
5452733f | 1006 | #endif |
389b31cd LL |
1007 | #if defined(MKIMAGE_ELF32) |
1008 | case EM_ARM: | |
1009 | { | |
1010 | sym_addr += addend; | |
43b444e5 | 1011 | sym_addr -= image_target->vaddr_offset; |
389b31cd LL |
1012 | switch (ELF_R_TYPE (info)) |
1013 | { | |
1014 | case R_ARM_ABS32: | |
1015 | { | |
1016 | grub_util_info (" ABS32:\toffset=%d\t(0x%08x)", | |
1017 | (int) sym_addr, (int) sym_addr); | |
1018 | /* Data will be naturally aligned */ | |
86ef66d9 VS |
1019 | if (image_target->id == IMAGE_EFI) |
1020 | sym_addr += 0x400; | |
389b31cd LL |
1021 | *target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr); |
1022 | } | |
1023 | break; | |
8c534b85 VS |
1024 | /* Happens when compiled with -march=armv4. |
1025 | Since currently we need at least armv5, keep bx as-is. | |
1026 | */ | |
1027 | case R_ARM_V4BX: | |
1028 | break; | |
389b31cd LL |
1029 | case R_ARM_THM_CALL: |
1030 | case R_ARM_THM_JUMP24: | |
8c534b85 | 1031 | case R_ARM_THM_JUMP19: |
389b31cd | 1032 | { |
28af3d86 | 1033 | grub_err_t err; |
e7c418c5 VS |
1034 | grub_util_info (" THM_JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", |
1035 | (unsigned long) ((char *) target | |
1036 | - (char *) e), | |
1037 | sym_addr); | |
8c534b85 VS |
1038 | if (!(sym_addr & 1)) |
1039 | { | |
1040 | grub_uint32_t tr_addr; | |
1041 | grub_int32_t new_offset; | |
1042 | tr_addr = (char *) tr - (char *) pe_target | |
1043 | - target_section_addr; | |
1044 | new_offset = sym_addr - tr_addr - 12; | |
1045 | ||
1046 | if (!grub_arm_jump24_check_offset (new_offset)) | |
1047 | return grub_util_error ("jump24 relocation out of range"); | |
1048 | ||
1049 | tr[0] = grub_host_to_target32 (0x46c04778); /* bx pc; nop */ | |
1050 | tr[1] = grub_host_to_target32 (((new_offset >> 2) & 0xffffff) | 0xea000000); /* b new_offset */ | |
1051 | tr += 2; | |
1052 | sym_addr = tr_addr | 1; | |
1053 | } | |
389b31cd LL |
1054 | sym_addr -= offset; |
1055 | /* Thumb instructions can be 16-bit aligned */ | |
8c534b85 VS |
1056 | if (ELF_R_TYPE (info) == R_ARM_THM_JUMP19) |
1057 | err = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr); | |
1058 | else | |
1059 | err = grub_arm_reloc_thm_call ((grub_uint16_t *) target, | |
1060 | sym_addr); | |
28af3d86 VS |
1061 | if (err) |
1062 | grub_util_error ("%s", grub_errmsg); | |
389b31cd LL |
1063 | } |
1064 | break; | |
8c534b85 VS |
1065 | |
1066 | case R_ARM_CALL: | |
1067 | case R_ARM_JUMP24: | |
389b31cd | 1068 | { |
28af3d86 | 1069 | grub_err_t err; |
e7c418c5 | 1070 | grub_util_info (" JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", (unsigned long) ((char *) target - (char *) e), sym_addr); |
8c534b85 VS |
1071 | if (sym_addr & 1) |
1072 | { | |
1073 | grub_uint32_t tr_addr; | |
1074 | grub_int32_t new_offset; | |
1075 | tr_addr = (char *) tr - (char *) pe_target | |
1076 | - target_section_addr; | |
1077 | new_offset = sym_addr - tr_addr - 12; | |
1078 | ||
1079 | /* There is no immediate version of bx, only register one... */ | |
1080 | tr[0] = grub_host_to_target32 (0xe59fc004); /* ldr ip, [pc, #4] */ | |
1081 | tr[1] = grub_host_to_target32 (0xe08cc00f); /* add ip, ip, pc */ | |
1082 | tr[2] = grub_host_to_target32 (0xe12fff1c); /* bx ip */ | |
1083 | tr[3] = grub_host_to_target32 (new_offset | 1); | |
1084 | tr += 4; | |
1085 | sym_addr = tr_addr; | |
1086 | } | |
389b31cd | 1087 | sym_addr -= offset; |
8c534b85 VS |
1088 | err = grub_arm_reloc_jump24 (target, |
1089 | sym_addr); | |
28af3d86 VS |
1090 | if (err) |
1091 | grub_util_error ("%s", grub_errmsg); | |
389b31cd LL |
1092 | } |
1093 | break; | |
8c534b85 | 1094 | |
389b31cd | 1095 | default: |
d6c2782a VS |
1096 | grub_util_error (_("relocation 0x%x is not implemented yet"), |
1097 | (unsigned int) ELF_R_TYPE (info)); | |
389b31cd LL |
1098 | break; |
1099 | } | |
1100 | break; | |
1101 | } | |
1102 | #endif /* MKIMAGE_ELF32 */ | |
bea33583 | 1103 | default: |
1104 | grub_util_error ("unknown architecture type %d", | |
1105 | image_target->elf_target); | |
1106 | } | |
0253aeb7 VS |
1107 | } |
1108 | } | |
1109 | } | |
1110 | ||
1111 | /* Add a PE32's fixup entry for a relocation. Return the resulting address | |
1112 | after having written to the file OUT. */ | |
1113 | static Elf_Addr | |
dd3969e7 VS |
1114 | add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type, |
1115 | Elf_Addr addr, int flush, Elf_Addr current_address, | |
1116 | const struct grub_install_image_target_desc *image_target) | |
0253aeb7 VS |
1117 | { |
1118 | struct grub_pe32_fixup_block *b; | |
1119 | ||
1120 | b = &((*cblock)->b); | |
1121 | ||
1122 | /* First, check if it is necessary to write out the current block. */ | |
1123 | if ((*cblock)->state) | |
1124 | { | |
1125 | if (flush || addr < b->page_rva || b->page_rva + 0x1000 <= addr) | |
1126 | { | |
1127 | grub_uint32_t size; | |
1128 | ||
1129 | if (flush) | |
1130 | { | |
1131 | /* Add as much padding as necessary to align the address | |
1132 | with a section boundary. */ | |
1133 | Elf_Addr next_address; | |
1134 | unsigned padding_size; | |
495fc8c1 | 1135 | size_t cur_index; |
0253aeb7 VS |
1136 | |
1137 | next_address = current_address + b->block_size; | |
1138 | padding_size = ((ALIGN_UP (next_address, image_target->section_align) | |
1139 | - next_address) | |
1140 | >> 1); | |
495fc8c1 | 1141 | cur_index = ((b->block_size - sizeof (*b)) >> 1); |
0253aeb7 VS |
1142 | grub_util_info ("adding %d padding fixup entries", padding_size); |
1143 | while (padding_size--) | |
1144 | { | |
495fc8c1 | 1145 | b->entries[cur_index++] = 0; |
0253aeb7 VS |
1146 | b->block_size += 2; |
1147 | } | |
1148 | } | |
5452733f | 1149 | else while (b->block_size & (8 - 1)) |
0253aeb7 VS |
1150 | { |
1151 | /* If not aligned with a 32-bit boundary, add | |
1152 | a padding entry. */ | |
495fc8c1 | 1153 | size_t cur_index; |
0253aeb7 VS |
1154 | |
1155 | grub_util_info ("adding a padding fixup entry"); | |
495fc8c1 VS |
1156 | cur_index = ((b->block_size - sizeof (*b)) >> 1); |
1157 | b->entries[cur_index] = 0; | |
0253aeb7 VS |
1158 | b->block_size += 2; |
1159 | } | |
1160 | ||
1161 | /* Flush it. */ | |
1162 | grub_util_info ("writing %d bytes of a fixup block starting at 0x%x", | |
1163 | b->block_size, b->page_rva); | |
1164 | size = b->block_size; | |
1165 | current_address += size; | |
1166 | b->page_rva = grub_host_to_target32 (b->page_rva); | |
1167 | b->block_size = grub_host_to_target32 (b->block_size); | |
1168 | (*cblock)->next = xmalloc (sizeof (**cblock) + 2 * 0x1000); | |
1169 | memset ((*cblock)->next, 0, sizeof (**cblock) + 2 * 0x1000); | |
1170 | *cblock = (*cblock)->next; | |
1171 | } | |
1172 | } | |
1173 | ||
1174 | b = &((*cblock)->b); | |
1175 | ||
1176 | if (! flush) | |
1177 | { | |
1178 | grub_uint16_t entry; | |
495fc8c1 | 1179 | size_t cur_index; |
0253aeb7 VS |
1180 | |
1181 | /* If not allocated yet, allocate a block with enough entries. */ | |
1182 | if (! (*cblock)->state) | |
1183 | { | |
1184 | (*cblock)->state = 1; | |
1185 | ||
1186 | /* The spec does not mention the requirement of a Page RVA. | |
1187 | Here, align the address with a 4K boundary for safety. */ | |
1188 | b->page_rva = (addr & ~(0x1000 - 1)); | |
1189 | b->block_size = sizeof (*b); | |
1190 | } | |
1191 | ||
1192 | /* Sanity check. */ | |
1193 | if (b->block_size >= sizeof (*b) + 2 * 0x1000) | |
1194 | grub_util_error ("too many fixup entries"); | |
1195 | ||
1196 | /* Add a new entry. */ | |
495fc8c1 | 1197 | cur_index = ((b->block_size - sizeof (*b)) >> 1); |
0253aeb7 | 1198 | entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva); |
495fc8c1 | 1199 | b->entries[cur_index] = grub_host_to_target16 (entry); |
0253aeb7 VS |
1200 | b->block_size += 2; |
1201 | } | |
1202 | ||
1203 | return current_address; | |
1204 | } | |
1205 | ||
86ef66d9 VS |
1206 | struct raw_reloc |
1207 | { | |
1208 | struct raw_reloc *next; | |
1209 | grub_uint32_t offset; | |
1210 | enum raw_reloc_type { | |
1211 | RAW_RELOC_NONE = -1, | |
1212 | RAW_RELOC_32 = 0, | |
1213 | RAW_RELOC_MAX = 1, | |
1214 | } type; | |
1215 | }; | |
1216 | ||
dd3969e7 VS |
1217 | struct translate_context |
1218 | { | |
86ef66d9 | 1219 | /* PE */ |
dd3969e7 VS |
1220 | struct fixup_block_list *lst, *lst0; |
1221 | Elf_Addr current_address; | |
86ef66d9 VS |
1222 | |
1223 | /* Raw */ | |
1224 | struct raw_reloc *raw_relocs; | |
dd3969e7 VS |
1225 | }; |
1226 | ||
1227 | static void | |
86ef66d9 VS |
1228 | translate_reloc_start (struct translate_context *ctx, |
1229 | const struct grub_install_image_target_desc *image_target) | |
dd3969e7 | 1230 | { |
86ef66d9 VS |
1231 | grub_memset (ctx, 0, sizeof (*ctx)); |
1232 | if (image_target->id == IMAGE_EFI) | |
1233 | { | |
1234 | ctx->lst = ctx->lst0 = xmalloc (sizeof (*ctx->lst) + 2 * 0x1000); | |
1235 | memset (ctx->lst, 0, sizeof (*ctx->lst) + 2 * 0x1000); | |
1236 | ctx->current_address = 0; | |
1237 | } | |
dd3969e7 VS |
1238 | } |
1239 | ||
1240 | static void | |
86ef66d9 VS |
1241 | translate_relocation_pe (struct translate_context *ctx, |
1242 | Elf_Addr addr, | |
1243 | Elf_Addr info, | |
1244 | const struct grub_install_image_target_desc *image_target) | |
dd3969e7 VS |
1245 | { |
1246 | /* Necessary to relocate only absolute addresses. */ | |
1247 | switch (image_target->elf_target) | |
1248 | { | |
1249 | case EM_386: | |
1250 | if (ELF_R_TYPE (info) == R_386_32) | |
1251 | { | |
1252 | grub_util_info ("adding a relocation entry for 0x%" | |
1253 | GRUB_HOST_PRIxLONG_LONG, | |
1254 | (unsigned long long) addr); | |
1255 | ctx->current_address | |
1256 | = add_fixup_entry (&ctx->lst, | |
1257 | GRUB_PE32_REL_BASED_HIGHLOW, | |
1258 | addr, 0, ctx->current_address, | |
1259 | image_target); | |
1260 | } | |
1261 | break; | |
1262 | case EM_X86_64: | |
1263 | if ((ELF_R_TYPE (info) == R_X86_64_32) || | |
1264 | (ELF_R_TYPE (info) == R_X86_64_32S)) | |
1265 | { | |
1266 | grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)"); | |
1267 | } | |
1268 | else if (ELF_R_TYPE (info) == R_X86_64_64) | |
1269 | { | |
1270 | grub_util_info ("adding a relocation entry for 0x%" | |
1271 | GRUB_HOST_PRIxLONG_LONG, | |
1272 | (unsigned long long) addr); | |
1273 | ctx->current_address | |
1274 | = add_fixup_entry (&ctx->lst, | |
1275 | GRUB_PE32_REL_BASED_DIR64, | |
1276 | addr, | |
1277 | 0, ctx->current_address, | |
1278 | image_target); | |
1279 | } | |
1280 | break; | |
1281 | case EM_IA_64: | |
1282 | switch (ELF_R_TYPE (info)) | |
1283 | { | |
1284 | case R_IA64_PCREL64LSB: | |
1285 | case R_IA64_LDXMOV: | |
1286 | case R_IA64_PCREL21B: | |
1287 | case R_IA64_LTOFF_FPTR22: | |
1288 | case R_IA64_LTOFF22X: | |
1289 | case R_IA64_LTOFF22: | |
1290 | case R_IA64_GPREL22: | |
a134ef1a | 1291 | case R_IA64_GPREL64I: |
dd3969e7 VS |
1292 | case R_IA64_SEGREL64LSB: |
1293 | break; | |
1294 | ||
1295 | case R_IA64_FPTR64LSB: | |
1296 | case R_IA64_DIR64LSB: | |
1297 | #if 1 | |
1298 | { | |
1299 | grub_util_info ("adding a relocation entry for 0x%" | |
1300 | GRUB_HOST_PRIxLONG_LONG, | |
1301 | (unsigned long long) addr); | |
1302 | ctx->current_address | |
1303 | = add_fixup_entry (&ctx->lst, | |
1304 | GRUB_PE32_REL_BASED_DIR64, | |
1305 | addr, | |
1306 | 0, ctx->current_address, | |
1307 | image_target); | |
1308 | } | |
1309 | #endif | |
1310 | break; | |
1311 | default: | |
1312 | grub_util_error (_("relocation 0x%x is not implemented yet"), | |
1313 | (unsigned int) ELF_R_TYPE (info)); | |
1314 | break; | |
1315 | } | |
1316 | break; | |
1317 | case EM_AARCH64: | |
1318 | switch (ELF_R_TYPE (info)) | |
1319 | { | |
1320 | case R_AARCH64_ABS64: | |
1321 | { | |
1322 | ctx->current_address | |
1323 | = add_fixup_entry (&ctx->lst, | |
1324 | GRUB_PE32_REL_BASED_DIR64, | |
1325 | addr, 0, ctx->current_address, | |
1326 | image_target); | |
1327 | } | |
1328 | break; | |
1329 | /* Relative relocations do not require fixup entries. */ | |
1330 | case R_AARCH64_CALL26: | |
1331 | case R_AARCH64_JUMP26: | |
1332 | break; | |
1333 | /* Page-relative relocations do not require fixup entries. */ | |
1334 | case R_AARCH64_ADR_PREL_PG_HI21: | |
1335 | /* We page-align the whole kernel, so no need | |
1336 | for fixup entries. | |
1337 | */ | |
1338 | case R_AARCH64_ADD_ABS_LO12_NC: | |
1339 | case R_AARCH64_LDST64_ABS_LO12_NC: | |
1340 | break; | |
1341 | ||
1342 | default: | |
1343 | grub_util_error (_("relocation 0x%x is not implemented yet"), | |
1344 | (unsigned int) ELF_R_TYPE (info)); | |
1345 | break; | |
1346 | } | |
1347 | break; | |
1348 | break; | |
1349 | #if defined(MKIMAGE_ELF32) | |
1350 | case EM_ARM: | |
1351 | switch (ELF_R_TYPE (info)) | |
1352 | { | |
1353 | case R_ARM_V4BX: | |
1354 | /* Relative relocations do not require fixup entries. */ | |
1355 | case R_ARM_JUMP24: | |
1356 | case R_ARM_THM_CALL: | |
1357 | case R_ARM_THM_JUMP19: | |
1358 | case R_ARM_THM_JUMP24: | |
1359 | case R_ARM_CALL: | |
1360 | { | |
1361 | grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) ctx->current_address); | |
1362 | } | |
1363 | break; | |
1364 | /* Create fixup entry for PE/COFF loader */ | |
1365 | case R_ARM_ABS32: | |
1366 | { | |
1367 | ctx->current_address | |
1368 | = add_fixup_entry (&ctx->lst, | |
1369 | GRUB_PE32_REL_BASED_HIGHLOW, | |
1370 | addr, 0, ctx->current_address, | |
1371 | image_target); | |
1372 | } | |
1373 | break; | |
1374 | default: | |
1375 | grub_util_error (_("relocation 0x%x is not implemented yet"), | |
1376 | (unsigned int) ELF_R_TYPE (info)); | |
1377 | break; | |
1378 | } | |
1379 | break; | |
1380 | #endif /* defined(MKIMAGE_ELF32) */ | |
1381 | default: | |
1382 | grub_util_error ("unknown machine type 0x%x", image_target->elf_target); | |
1383 | } | |
1384 | } | |
1385 | ||
86ef66d9 VS |
1386 | static enum raw_reloc_type |
1387 | classify_raw_reloc (Elf_Addr info, | |
1388 | const struct grub_install_image_target_desc *image_target) | |
1389 | { | |
1390 | /* Necessary to relocate only absolute addresses. */ | |
1391 | switch (image_target->elf_target) | |
1392 | { | |
1393 | case EM_ARM: | |
1394 | switch (ELF_R_TYPE (info)) | |
1395 | { | |
1396 | case R_ARM_V4BX: | |
1397 | case R_ARM_JUMP24: | |
1398 | case R_ARM_THM_CALL: | |
1399 | case R_ARM_THM_JUMP19: | |
1400 | case R_ARM_THM_JUMP24: | |
1401 | case R_ARM_CALL: | |
1402 | return RAW_RELOC_NONE; | |
1403 | case R_ARM_ABS32: | |
1404 | return RAW_RELOC_32; | |
1405 | default: | |
1406 | grub_util_error (_("relocation 0x%x is not implemented yet"), | |
1407 | (unsigned int) ELF_R_TYPE (info)); | |
1408 | break; | |
1409 | } | |
1410 | break; | |
1411 | default: | |
1412 | grub_util_error ("unknown machine type 0x%x", image_target->elf_target); | |
1413 | } | |
1414 | } | |
1415 | ||
73a9c742 | 1416 | static void |
86ef66d9 VS |
1417 | translate_relocation_raw (struct translate_context *ctx, |
1418 | Elf_Addr addr, | |
1419 | Elf_Addr info, | |
dd3969e7 | 1420 | const struct grub_install_image_target_desc *image_target) |
86ef66d9 VS |
1421 | { |
1422 | enum raw_reloc_type class = classify_raw_reloc (info, image_target); | |
1423 | struct raw_reloc *rel; | |
1424 | if (class == RAW_RELOC_NONE) | |
1425 | return; | |
1426 | rel = xmalloc (sizeof (*rel)); | |
1427 | rel->next = ctx->raw_relocs; | |
1428 | rel->type = class; | |
1429 | rel->offset = addr; | |
1430 | ctx->raw_relocs = rel; | |
1431 | } | |
1432 | ||
1433 | static void | |
1434 | translate_relocation (struct translate_context *ctx, | |
1435 | Elf_Addr addr, | |
1436 | Elf_Addr info, | |
1437 | const struct grub_install_image_target_desc *image_target) | |
1438 | { | |
1439 | if (image_target->id == IMAGE_EFI) | |
1440 | translate_relocation_pe (ctx, addr, info, image_target); | |
1441 | else | |
1442 | translate_relocation_raw (ctx, addr, info, image_target); | |
1443 | } | |
1444 | ||
1445 | static void | |
1446 | finish_reloc_translation_pe (struct translate_context *ctx, struct grub_mkimage_layout *layout, | |
1447 | const struct grub_install_image_target_desc *image_target) | |
dd3969e7 VS |
1448 | { |
1449 | ctx->current_address = add_fixup_entry (&ctx->lst, 0, 0, 1, ctx->current_address, image_target); | |
1450 | ||
1451 | { | |
1452 | grub_uint8_t *ptr; | |
73a9c742 | 1453 | layout->reloc_section = ptr = xmalloc (ctx->current_address); |
dd3969e7 VS |
1454 | for (ctx->lst = ctx->lst0; ctx->lst; ctx->lst = ctx->lst->next) |
1455 | if (ctx->lst->state) | |
1456 | { | |
1457 | memcpy (ptr, &ctx->lst->b, grub_target_to_host32 (ctx->lst->b.block_size)); | |
1458 | ptr += grub_target_to_host32 (ctx->lst->b.block_size); | |
1459 | } | |
73a9c742 | 1460 | assert ((ctx->current_address + (grub_uint8_t *) layout->reloc_section) == ptr); |
dd3969e7 VS |
1461 | } |
1462 | ||
1463 | for (ctx->lst = ctx->lst0; ctx->lst; ) | |
1464 | { | |
1465 | struct fixup_block_list *next; | |
1466 | next = ctx->lst->next; | |
1467 | free (ctx->lst); | |
1468 | ctx->lst = next; | |
1469 | } | |
1470 | ||
73a9c742 | 1471 | layout->reloc_size = ctx->current_address; |
86ef66d9 VS |
1472 | if (image_target->elf_target == EM_ARM && layout->reloc_size > GRUB_KERNEL_ARM_STACK_SIZE) |
1473 | grub_util_error ("Reloc section (%d) is bigger than stack size (%d). " | |
1474 | "This breaks assembly assumptions. Please increase stack size", | |
1475 | (int) layout->reloc_size, | |
1476 | (int) GRUB_KERNEL_ARM_STACK_SIZE); | |
dd3969e7 VS |
1477 | } |
1478 | ||
86ef66d9 VS |
1479 | /* |
1480 | Layout: | |
1481 | <type 0 relocations> | |
1482 | <fffffffe> | |
1483 | <type 1 relocations> | |
1484 | <fffffffe> | |
1485 | ... | |
1486 | <type n relocations> | |
1487 | <ffffffff> | |
1488 | each relocation starts with 32-bit offset. Rest depends on relocation. | |
1489 | mkimage stops when it sees first unknown type or end marker. | |
1490 | This allows images to be created with mismatched mkimage and | |
1491 | kernel as long as no relocations are present in kernel that mkimage | |
1492 | isn't aware of (in which case mkimage aborts). | |
1493 | This also allows simple assembly to do the relocs. | |
1494 | */ | |
1495 | ||
1496 | #define RAW_SEPARATOR 0xfffffffe | |
1497 | #define RAW_END_MARKER 0xffffffff | |
1498 | ||
1499 | static void | |
1500 | finish_reloc_translation_raw (struct translate_context *ctx, struct grub_mkimage_layout *layout, | |
1501 | const struct grub_install_image_target_desc *image_target) | |
1502 | { | |
1503 | size_t count = 0, sz; | |
1504 | enum raw_reloc_type highest = RAW_RELOC_NONE; | |
1505 | enum raw_reloc_type curtype; | |
1506 | struct raw_reloc *cur; | |
1507 | grub_uint32_t *p; | |
1508 | if (!ctx->raw_relocs) | |
1509 | { | |
1510 | layout->reloc_section = p = xmalloc (sizeof (grub_uint32_t)); | |
1511 | p[0] = RAW_END_MARKER; | |
1512 | layout->reloc_size = sizeof (grub_uint32_t); | |
1513 | return; | |
1514 | } | |
1515 | for (cur = ctx->raw_relocs; cur; cur = cur->next) | |
1516 | { | |
1517 | count++; | |
1518 | if (cur->type > highest) | |
1519 | highest = cur->type; | |
1520 | } | |
1521 | /* highest separators, count relocations and one end marker. */ | |
1522 | sz = (highest + count + 1) * sizeof (grub_uint32_t); | |
1523 | layout->reloc_section = p = xmalloc (sz); | |
1524 | for (curtype = 0; curtype <= highest; curtype++) | |
1525 | { | |
1526 | /* Support for special cases would go here. */ | |
1527 | for (cur = ctx->raw_relocs; cur; cur = cur->next) | |
1528 | if (cur->type == curtype) | |
1529 | { | |
1530 | *p++ = cur->offset; | |
1531 | } | |
1532 | *p++ = RAW_SEPARATOR; | |
1533 | } | |
1534 | *--p = RAW_END_MARKER; | |
1535 | layout->reloc_size = sz; | |
1536 | } | |
1537 | ||
1538 | static void | |
1539 | finish_reloc_translation (struct translate_context *ctx, struct grub_mkimage_layout *layout, | |
1540 | const struct grub_install_image_target_desc *image_target) | |
1541 | { | |
1542 | if (image_target->id == IMAGE_EFI) | |
1543 | finish_reloc_translation_pe (ctx, layout, image_target); | |
1544 | else | |
1545 | finish_reloc_translation_raw (ctx, layout, image_target); | |
1546 | } | |
1547 | ||
1548 | ||
dd3969e7 VS |
1549 | static void |
1550 | translate_reloc_jumpers (struct translate_context *ctx, | |
1551 | Elf_Addr jumpers, grub_size_t njumpers, | |
1552 | const struct grub_install_image_target_desc *image_target) | |
1553 | { | |
1554 | unsigned i; | |
86ef66d9 | 1555 | assert (image_target->id == IMAGE_EFI); |
dd3969e7 VS |
1556 | for (i = 0; i < njumpers; i++) |
1557 | ctx->current_address = add_fixup_entry (&ctx->lst, | |
1558 | GRUB_PE32_REL_BASED_DIR64, | |
1559 | jumpers + 8 * i, | |
1560 | 0, ctx->current_address, | |
1561 | image_target); | |
1562 | } | |
1563 | ||
0253aeb7 | 1564 | /* Make a .reloc section. */ |
73a9c742 VS |
1565 | static void |
1566 | make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, | |
dd3969e7 VS |
1567 | Elf_Addr *section_addresses, Elf_Shdr *sections, |
1568 | Elf_Half section_entsize, Elf_Half num_sections, | |
1569 | const char *strtab, | |
dd3969e7 | 1570 | const struct grub_install_image_target_desc *image_target) |
0253aeb7 | 1571 | { |
5452733f | 1572 | unsigned i; |
0253aeb7 | 1573 | Elf_Shdr *s; |
dd3969e7 | 1574 | struct translate_context ctx; |
0253aeb7 | 1575 | |
86ef66d9 | 1576 | translate_reloc_start (&ctx, image_target); |
0253aeb7 | 1577 | |
5452733f | 1578 | for (i = 0, s = sections; i < num_sections; |
0253aeb7 | 1579 | i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) |
d5e2a158 VS |
1580 | if ((grub_target_to_host32 (s->sh_type) == SHT_REL) || |
1581 | (grub_target_to_host32 (s->sh_type) == SHT_RELA)) | |
0253aeb7 VS |
1582 | { |
1583 | Elf_Rel *r; | |
1584 | Elf_Word rtab_size, r_size, num_rs; | |
1585 | Elf_Off rtab_offset; | |
1586 | Elf_Addr section_address; | |
1587 | Elf_Word j; | |
1588 | ||
1589 | grub_util_info ("translating the relocation section %s", | |
1590 | strtab + grub_le_to_cpu32 (s->sh_name)); | |
1591 | ||
d5e2a158 VS |
1592 | rtab_size = grub_target_to_host (s->sh_size); |
1593 | r_size = grub_target_to_host (s->sh_entsize); | |
1594 | rtab_offset = grub_target_to_host (s->sh_offset); | |
0253aeb7 VS |
1595 | num_rs = rtab_size / r_size; |
1596 | ||
1597 | section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)]; | |
1598 | ||
1599 | for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset); | |
1600 | j < num_rs; | |
1601 | j++, r = (Elf_Rel *) ((char *) r + r_size)) | |
1602 | { | |
1603 | Elf_Addr info; | |
1604 | Elf_Addr offset; | |
dd3969e7 | 1605 | Elf_Addr addr; |
0253aeb7 | 1606 | |
d5e2a158 VS |
1607 | offset = grub_target_to_host (r->r_offset); |
1608 | info = grub_target_to_host (r->r_info); | |
0253aeb7 | 1609 | |
dd3969e7 | 1610 | addr = section_address + offset; |
0253aeb7 | 1611 | |
dd3969e7 | 1612 | translate_relocation (&ctx, addr, info, image_target); |
0253aeb7 VS |
1613 | } |
1614 | } | |
1615 | ||
5452733f | 1616 | if (image_target->elf_target == EM_IA_64) |
86ef66d9 VS |
1617 | translate_reloc_jumpers (&ctx, |
1618 | layout->ia64jmp_off | |
1619 | + image_target->vaddr_offset, | |
1620 | 2 * layout->ia64jmpnum + (layout->got_size / 8), | |
dd3969e7 | 1621 | image_target); |
5452733f | 1622 | |
73a9c742 | 1623 | finish_reloc_translation (&ctx, layout, image_target); |
0253aeb7 VS |
1624 | } |
1625 | ||
1626 | /* Determine if this section is a text section. Return false if this | |
1627 | section is not allocated. */ | |
1628 | static int | |
ec16e026 | 1629 | SUFFIX (is_text_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) |
0253aeb7 | 1630 | { |
86ef66d9 | 1631 | if (!is_relocatable (image_target) |
0253aeb7 VS |
1632 | && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) |
1633 | return 0; | |
962b15b4 | 1634 | return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) |
0253aeb7 VS |
1635 | == (SHF_EXECINSTR | SHF_ALLOC)); |
1636 | } | |
1637 | ||
df21fff5 | 1638 | /* Determine if this section is a data section. */ |
0253aeb7 | 1639 | static int |
ec16e026 | 1640 | SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) |
0253aeb7 | 1641 | { |
86ef66d9 | 1642 | if (!is_relocatable (image_target) |
0253aeb7 VS |
1643 | && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) |
1644 | return 0; | |
962b15b4 | 1645 | return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) |
df21fff5 VS |
1646 | == SHF_ALLOC) && !(grub_target_to_host32 (s->sh_type) == SHT_NOBITS); |
1647 | } | |
1648 | ||
1649 | static int | |
1650 | SUFFIX (is_bss_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) | |
1651 | { | |
1652 | if (!is_relocatable (image_target)) | |
1653 | return 0; | |
1654 | return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) | |
1655 | == SHF_ALLOC) && (grub_target_to_host32 (s->sh_type) == SHT_NOBITS); | |
0253aeb7 VS |
1656 | } |
1657 | ||
1658 | /* Return if the ELF header is valid. */ | |
1659 | static int | |
ec16e026 | 1660 | SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_image_target_desc *image_target) |
0253aeb7 VS |
1661 | { |
1662 | if (size < sizeof (*e) | |
1663 | || e->e_ident[EI_MAG0] != ELFMAG0 | |
1664 | || e->e_ident[EI_MAG1] != ELFMAG1 | |
1665 | || e->e_ident[EI_MAG2] != ELFMAG2 | |
1666 | || e->e_ident[EI_MAG3] != ELFMAG3 | |
1667 | || e->e_ident[EI_VERSION] != EV_CURRENT | |
1668 | || e->e_ident[EI_CLASS] != ELFCLASSXX | |
1669 | || e->e_version != grub_host_to_target32 (EV_CURRENT)) | |
1670 | return 0; | |
1671 | ||
1672 | return 1; | |
1673 | } | |
1674 | ||
df21fff5 VS |
1675 | static Elf_Addr |
1676 | SUFFIX (put_section) (Elf_Shdr *s, int i, | |
1677 | Elf_Addr current_address, | |
1678 | Elf_Addr *section_addresses, | |
1679 | const char *strtab, | |
1680 | const struct grub_install_image_target_desc *image_target) | |
1681 | { | |
1682 | Elf_Word align = grub_host_to_target_addr (s->sh_addralign); | |
1683 | const char *name = strtab + grub_host_to_target32 (s->sh_name); | |
1684 | ||
1685 | if (align) | |
1686 | current_address = ALIGN_UP (current_address + image_target->vaddr_offset, | |
1687 | align) | |
1688 | - image_target->vaddr_offset; | |
1689 | ||
1690 | grub_util_info ("locating the section %s at 0x%" | |
1691 | GRUB_HOST_PRIxLONG_LONG, | |
1692 | name, (unsigned long long) current_address); | |
1693 | if (!is_relocatable (image_target)) | |
1694 | current_address = grub_host_to_target_addr (s->sh_addr) | |
1695 | - image_target->link_addr; | |
1696 | section_addresses[i] = current_address; | |
1697 | current_address += grub_host_to_target_addr (s->sh_size); | |
1698 | return current_address; | |
1699 | } | |
1700 | ||
0253aeb7 VS |
1701 | /* Locate section addresses by merging code sections and data sections |
1702 | into .text and .data, respectively. Return the array of section | |
1703 | addresses. */ | |
1704 | static Elf_Addr * | |
86ef66d9 | 1705 | SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path, |
a0c9d5c6 | 1706 | Elf_Shdr *sections, Elf_Half section_entsize, |
0253aeb7 | 1707 | Elf_Half num_sections, const char *strtab, |
73a9c742 | 1708 | struct grub_mkimage_layout *layout, |
ec16e026 | 1709 | const struct grub_install_image_target_desc *image_target) |
0253aeb7 VS |
1710 | { |
1711 | int i; | |
0253aeb7 VS |
1712 | Elf_Addr *section_addresses; |
1713 | Elf_Shdr *s; | |
1714 | ||
73a9c742 | 1715 | layout->align = 1; |
605eecc9 VS |
1716 | /* Page-aligning simplifies relocation handling. */ |
1717 | if (image_target->elf_target == EM_AARCH64) | |
73a9c742 | 1718 | layout->align = 4096; |
debaf23f | 1719 | |
0253aeb7 VS |
1720 | section_addresses = xmalloc (sizeof (*section_addresses) * num_sections); |
1721 | memset (section_addresses, 0, sizeof (*section_addresses) * num_sections); | |
1722 | ||
86ef66d9 | 1723 | layout->kernel_size = 0; |
0253aeb7 | 1724 | |
debaf23f VS |
1725 | for (i = 0, s = sections; |
1726 | i < num_sections; | |
1727 | i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) | |
1728 | if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC) | |
73a9c742 VS |
1729 | && grub_host_to_target32 (s->sh_addralign) > layout->align) |
1730 | layout->align = grub_host_to_target32 (s->sh_addralign); | |
debaf23f VS |
1731 | |
1732 | ||
0253aeb7 VS |
1733 | /* .text */ |
1734 | for (i = 0, s = sections; | |
1735 | i < num_sections; | |
1736 | i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) | |
1737 | if (SUFFIX (is_text_section) (s, image_target)) | |
1738 | { | |
86ef66d9 VS |
1739 | layout->kernel_size = SUFFIX (put_section) (s, i, |
1740 | layout->kernel_size, | |
df21fff5 VS |
1741 | section_addresses, |
1742 | strtab, | |
1743 | image_target); | |
1744 | if (!is_relocatable (image_target) && | |
1745 | grub_host_to_target_addr (s->sh_addr) != image_target->link_addr) | |
a0c9d5c6 | 1746 | { |
df21fff5 VS |
1747 | char *msg |
1748 | = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx" | |
1749 | " instead of 0x%llx: ld.gold bug?"), | |
1750 | kernel_path, | |
1751 | (unsigned long long) grub_host_to_target_addr (s->sh_addr), | |
1752 | (unsigned long long) image_target->link_addr); | |
1753 | grub_util_error ("%s", msg); | |
a0c9d5c6 | 1754 | } |
0253aeb7 VS |
1755 | } |
1756 | ||
86ef66d9 | 1757 | layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset, |
0253aeb7 VS |
1758 | image_target->section_align) |
1759 | - image_target->vaddr_offset; | |
86ef66d9 | 1760 | layout->exec_size = layout->kernel_size; |
0253aeb7 VS |
1761 | |
1762 | /* .data */ | |
1763 | for (i = 0, s = sections; | |
1764 | i < num_sections; | |
1765 | i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) | |
1766 | if (SUFFIX (is_data_section) (s, image_target)) | |
86ef66d9 VS |
1767 | layout->kernel_size = SUFFIX (put_section) (s, i, |
1768 | layout->kernel_size, | |
df21fff5 VS |
1769 | section_addresses, |
1770 | strtab, | |
1771 | image_target); | |
0253aeb7 | 1772 | |
86ef66d9 VS |
1773 | #ifdef MKIMAGE_ELF32 |
1774 | if (image_target->elf_target == EM_ARM) | |
1775 | { | |
1776 | grub_size_t tramp; | |
1777 | layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset, | |
1778 | image_target->section_align) - image_target->vaddr_offset; | |
0253aeb7 | 1779 | |
86ef66d9 VS |
1780 | layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); |
1781 | ||
1782 | tramp = arm_get_trampoline_size (e, sections, section_entsize, | |
1783 | num_sections, image_target); | |
1784 | ||
1785 | layout->tramp_off = layout->kernel_size; | |
1786 | layout->kernel_size += ALIGN_UP (tramp, 16); | |
1787 | } | |
1788 | #endif | |
1789 | ||
1790 | layout->bss_start = layout->kernel_size; | |
1791 | layout->end = layout->kernel_size; | |
df21fff5 VS |
1792 | |
1793 | /* .bss */ | |
1794 | for (i = 0, s = sections; | |
1795 | i < num_sections; | |
1796 | i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) | |
1797 | if (SUFFIX (is_bss_section) (s, image_target)) | |
86ef66d9 VS |
1798 | layout->end = SUFFIX (put_section) (s, i, |
1799 | layout->end, | |
1800 | section_addresses, | |
1801 | strtab, | |
1802 | image_target); | |
0253aeb7 | 1803 | |
86ef66d9 | 1804 | layout->end = ALIGN_UP (layout->end + image_target->vaddr_offset, |
0253aeb7 | 1805 | image_target->section_align) - image_target->vaddr_offset; |
86ef66d9 VS |
1806 | /* Explicitly initialize BSS |
1807 | when producing PE32 to avoid a bug in EFI implementations. | |
1808 | Platforms other than EFI and U-boot shouldn't have .bss in | |
1809 | their binaries as we build with -Wl,-Ttext. | |
1810 | */ | |
1811 | if (image_target->id != IMAGE_UBOOT) | |
1812 | layout->kernel_size = layout->end; | |
1813 | ||
0253aeb7 VS |
1814 | return section_addresses; |
1815 | } | |
1816 | ||
36212460 | 1817 | char * |
73a9c742 VS |
1818 | SUFFIX (grub_mkimage_load_image) (const char *kernel_path, |
1819 | size_t total_module_size, | |
1820 | struct grub_mkimage_layout *layout, | |
36212460 | 1821 | const struct grub_install_image_target_desc *image_target) |
0253aeb7 VS |
1822 | { |
1823 | char *kernel_img, *out_img; | |
1824 | const char *strtab; | |
1825 | Elf_Ehdr *e; | |
1826 | Elf_Shdr *sections; | |
1827 | Elf_Addr *section_addresses; | |
1828 | Elf_Addr *section_vaddresses; | |
1829 | int i; | |
1830 | Elf_Shdr *s; | |
1831 | Elf_Half num_sections; | |
1832 | Elf_Off section_offset; | |
1833 | Elf_Half section_entsize; | |
1834 | grub_size_t kernel_size; | |
0b6225bd | 1835 | Elf_Shdr *symtab_section = 0; |
0253aeb7 | 1836 | |
73a9c742 VS |
1837 | grub_memset (layout, 0, sizeof (*layout)); |
1838 | ||
1839 | layout->start_address = 0; | |
0253aeb7 VS |
1840 | |
1841 | kernel_size = grub_util_get_image_size (kernel_path); | |
1842 | kernel_img = xmalloc (kernel_size); | |
1843 | grub_util_load_image (kernel_path, kernel_img); | |
1844 | ||
1845 | e = (Elf_Ehdr *) kernel_img; | |
1846 | if (! SUFFIX (check_elf_header) (e, kernel_size, image_target)) | |
1847 | grub_util_error ("invalid ELF header"); | |
1848 | ||
962b15b4 | 1849 | section_offset = grub_target_to_host (e->e_shoff); |
0253aeb7 VS |
1850 | section_entsize = grub_target_to_host16 (e->e_shentsize); |
1851 | num_sections = grub_target_to_host16 (e->e_shnum); | |
1852 | ||
670c43af | 1853 | if (kernel_size < section_offset + (grub_uint32_t) section_entsize * num_sections) |
d61386e2 | 1854 | grub_util_error (_("premature end of file %s"), kernel_path); |
0253aeb7 VS |
1855 | |
1856 | sections = (Elf_Shdr *) (kernel_img + section_offset); | |
1857 | ||
1858 | /* Relocate sections then symbols in the virtual address space. */ | |
1859 | s = (Elf_Shdr *) ((char *) sections | |
1860 | + grub_host_to_target16 (e->e_shstrndx) * section_entsize); | |
fb53b340 | 1861 | strtab = (char *) e + grub_host_to_target_addr (s->sh_offset); |
0253aeb7 | 1862 | |
86ef66d9 | 1863 | section_addresses = SUFFIX (locate_sections) (e, kernel_path, |
a0c9d5c6 | 1864 | sections, section_entsize, |
0253aeb7 | 1865 | num_sections, strtab, |
73a9c742 | 1866 | layout, |
debaf23f | 1867 | image_target); |
0253aeb7 | 1868 | |
debaf23f | 1869 | section_vaddresses = xmalloc (sizeof (*section_addresses) * num_sections); |
0253aeb7 | 1870 | |
debaf23f VS |
1871 | for (i = 0; i < num_sections; i++) |
1872 | section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset; | |
0253aeb7 | 1873 | |
86ef66d9 | 1874 | if (!is_relocatable (image_target)) |
debaf23f | 1875 | { |
73a9c742 | 1876 | Elf_Addr current_address = layout->kernel_size; |
0253aeb7 | 1877 | |
debaf23f VS |
1878 | for (i = 0, s = sections; |
1879 | i < num_sections; | |
1880 | i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) | |
1881 | if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) | |
1882 | { | |
495fc8c1 | 1883 | Elf_Word sec_align = grub_host_to_target_addr (s->sh_addralign); |
debaf23f | 1884 | const char *name = strtab + grub_host_to_target32 (s->sh_name); |
0253aeb7 | 1885 | |
495fc8c1 | 1886 | if (sec_align) |
debaf23f | 1887 | current_address = ALIGN_UP (current_address |
495fc8c1 VS |
1888 | + image_target->vaddr_offset, |
1889 | sec_align) | |
debaf23f | 1890 | - image_target->vaddr_offset; |
0253aeb7 | 1891 | |
18e76955 VS |
1892 | grub_util_info ("locating the section %s at 0x%" |
1893 | GRUB_HOST_PRIxLONG_LONG, | |
495fc8c1 | 1894 | name, (unsigned long long) current_address); |
86ef66d9 | 1895 | if (!is_relocatable (image_target)) |
9d742bd4 VS |
1896 | current_address = grub_host_to_target_addr (s->sh_addr) |
1897 | - image_target->link_addr; | |
1898 | ||
debaf23f VS |
1899 | section_vaddresses[i] = current_address |
1900 | + image_target->vaddr_offset; | |
1901 | current_address += grub_host_to_target_addr (s->sh_size); | |
1902 | } | |
1903 | current_address = ALIGN_UP (current_address + image_target->vaddr_offset, | |
1904 | image_target->section_align) | |
1905 | - image_target->vaddr_offset; | |
73a9c742 | 1906 | layout->bss_size = current_address - layout->kernel_size; |
debaf23f VS |
1907 | } |
1908 | else | |
73a9c742 | 1909 | layout->bss_size = 0; |
0253aeb7 | 1910 | |
e5ed2f69 VS |
1911 | if (image_target->id == IMAGE_SPARC64_AOUT |
1912 | || image_target->id == IMAGE_SPARC64_RAW | |
86ef66d9 | 1913 | || image_target->id == IMAGE_UBOOT |
e5ed2f69 | 1914 | || image_target->id == IMAGE_SPARC64_CDCORE) |
73a9c742 | 1915 | layout->kernel_size = ALIGN_UP (layout->kernel_size, image_target->mod_align); |
e5ed2f69 | 1916 | |
86ef66d9 | 1917 | if (is_relocatable (image_target)) |
debaf23f | 1918 | { |
0253aeb7 VS |
1919 | symtab_section = NULL; |
1920 | for (i = 0, s = sections; | |
1921 | i < num_sections; | |
1922 | i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) | |
1923 | if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB)) | |
1924 | { | |
1925 | symtab_section = s; | |
1926 | break; | |
1927 | } | |
7aaed664 AB |
1928 | if (! symtab_section) |
1929 | grub_util_error ("%s", _("no symbol table")); | |
5452733f VS |
1930 | #ifdef MKIMAGE_ELF64 |
1931 | if (image_target->elf_target == EM_IA_64) | |
1932 | { | |
1933 | grub_size_t tramp; | |
1934 | ||
73a9c742 | 1935 | layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); |
5452733f | 1936 | |
73a9c742 | 1937 | grub_ia64_dl_get_tramp_got_size (e, &tramp, &layout->got_size); |
5452733f | 1938 | |
73a9c742 VS |
1939 | layout->tramp_off = layout->kernel_size; |
1940 | layout->kernel_size += ALIGN_UP (tramp, 16); | |
5452733f | 1941 | |
73a9c742 VS |
1942 | layout->ia64jmp_off = layout->kernel_size; |
1943 | layout->ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section, | |
86ef66d9 | 1944 | image_target); |
73a9c742 | 1945 | layout->kernel_size += 16 * layout->ia64jmpnum; |
5452733f | 1946 | |
73a9c742 VS |
1947 | layout->ia64_got_off = layout->kernel_size; |
1948 | layout->kernel_size += ALIGN_UP (layout->got_size, 16); | |
5452733f VS |
1949 | } |
1950 | #endif | |
5452733f VS |
1951 | } |
1952 | else | |
1953 | { | |
73a9c742 VS |
1954 | layout->reloc_size = 0; |
1955 | layout->reloc_section = NULL; | |
5452733f VS |
1956 | } |
1957 | ||
73a9c742 VS |
1958 | out_img = xmalloc (layout->kernel_size + total_module_size); |
1959 | memset (out_img, 0, layout->kernel_size + total_module_size); | |
0253aeb7 | 1960 | |
86ef66d9 | 1961 | if (is_relocatable (image_target)) |
5452733f | 1962 | { |
73a9c742 | 1963 | layout->start_address = SUFFIX (relocate_symbols) (e, sections, symtab_section, |
0253aeb7 | 1964 | section_vaddresses, section_entsize, |
5452733f | 1965 | num_sections, |
73a9c742 VS |
1966 | (char *) out_img + layout->ia64jmp_off, |
1967 | layout->ia64jmp_off | |
5452733f | 1968 | + image_target->vaddr_offset, |
86ef66d9 VS |
1969 | layout->bss_start, |
1970 | layout->end, | |
5452733f | 1971 | image_target); |
5bcb7d39 | 1972 | if (layout->start_address == (Elf_Addr) -1) |
0253aeb7 | 1973 | grub_util_error ("start symbol is not defined"); |
15a463d7 | 1974 | |
0253aeb7 | 1975 | /* Resolve addresses in the virtual address space. */ |
5452733f VS |
1976 | SUFFIX (relocate_addresses) (e, sections, section_addresses, |
1977 | section_entsize, | |
1978 | num_sections, strtab, | |
73a9c742 VS |
1979 | out_img, layout->tramp_off, |
1980 | layout->ia64_got_off, | |
5452733f | 1981 | image_target); |
15a463d7 | 1982 | |
73a9c742 VS |
1983 | make_reloc_section (e, layout, |
1984 | section_vaddresses, sections, | |
1985 | section_entsize, num_sections, | |
86ef66d9 | 1986 | strtab, |
73a9c742 | 1987 | image_target); |
86ef66d9 VS |
1988 | if (image_target->id != IMAGE_EFI) |
1989 | { | |
1990 | out_img = xrealloc (out_img, layout->kernel_size + total_module_size | |
1991 | + ALIGN_UP (layout->reloc_size, image_target->mod_align)); | |
1992 | memcpy (out_img + layout->kernel_size, layout->reloc_section, layout->reloc_size); | |
1993 | memset (out_img + layout->kernel_size + layout->reloc_size, 0, | |
1994 | total_module_size + ALIGN_UP (layout->reloc_size, image_target->mod_align) - layout->reloc_size); | |
1995 | layout->kernel_size += ALIGN_UP (layout->reloc_size, image_target->mod_align); | |
1996 | } | |
0253aeb7 VS |
1997 | } |
1998 | ||
0253aeb7 VS |
1999 | for (i = 0, s = sections; |
2000 | i < num_sections; | |
2001 | i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) | |
2002 | if (SUFFIX (is_data_section) (s, image_target) | |
86ef66d9 VS |
2003 | /* Explicitly initialize BSS |
2004 | when producing PE32 to avoid a bug in EFI implementations. | |
2005 | Platforms other than EFI and U-boot shouldn't have .bss in | |
2006 | their binaries as we build with -Wl,-Ttext. | |
2007 | */ | |
2008 | || (SUFFIX (is_bss_section) (s, image_target) && (image_target->id != IMAGE_UBOOT)) | |
0253aeb7 VS |
2009 | || SUFFIX (is_text_section) (s, image_target)) |
2010 | { | |
2011 | if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) | |
2012 | memset (out_img + section_addresses[i], 0, | |
962b15b4 | 2013 | grub_host_to_target_addr (s->sh_size)); |
0253aeb7 VS |
2014 | else |
2015 | memcpy (out_img + section_addresses[i], | |
962b15b4 VS |
2016 | kernel_img + grub_host_to_target_addr (s->sh_offset), |
2017 | grub_host_to_target_addr (s->sh_size)); | |
0253aeb7 VS |
2018 | } |
2019 | free (kernel_img); | |
2020 | ||
663f6eb1 VS |
2021 | free (section_vaddresses); |
2022 | free (section_addresses); | |
2023 | ||
0253aeb7 VS |
2024 | return out_img; |
2025 | } |