]> git.proxmox.com Git - grub2.git/blame - util/grub-mkimagexx.c
arm/arm64: Fix improper use of start address.
[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
36212460
VS
53/* These structures are defined according to the CHRP binding to IEEE1275,
54 "Client Program Format" section. */
55
56struct 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
69struct 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
78struct 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
87static int
88is_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 */
101static grub_err_t
102grub_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 */
133static grub_err_t
134grub_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 */
161static grub_err_t
162grub_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
185void
186SUFFIX (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. */
492static Elf_Addr
493SUFFIX (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. */
576static Elf_Addr
577SUFFIX (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. */
589static Elf_Addr *
590SUFFIX (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
597static Elf_Addr
598SUFFIX (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. */
627static grub_size_t
628arm_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. */
706static void
707SUFFIX (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. */
1113static Elf_Addr
dd3969e7
VS
1114add_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
1206struct 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
1217struct 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
1227static void
86ef66d9
VS
1228translate_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
1240static void
86ef66d9
VS
1241translate_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
1386static enum raw_reloc_type
1387classify_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 1416static void
86ef66d9
VS
1417translate_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
1433static void
1434translate_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
1445static void
1446finish_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
1499static void
1500finish_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
1538static void
1539finish_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
1549static void
1550translate_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
1565static void
1566make_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. */
1628static int
ec16e026 1629SUFFIX (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 1639static int
ec16e026 1640SUFFIX (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
1649static int
1650SUFFIX (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. */
1659static int
ec16e026 1660SUFFIX (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
1675static Elf_Addr
1676SUFFIX (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. */
1704static Elf_Addr *
86ef66d9 1705SUFFIX (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 1817char *
73a9c742
VS
1818SUFFIX (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}