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