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