x86-64: Treat R_X86_64_PLT32 as R_X86_64_PC32
[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                 case R_X86_64_PLT32:
845                   {
846                     grub_uint32_t *t32 = (grub_uint32_t *) target;
847                     *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
848                                                   + addend + sym_addr
849                                                   - target_section_addr - offset
850                                                   - image_target->vaddr_offset);
851                     grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%"
852                                     GRUB_HOST_PRIxLONG_LONG,
853                                     *t32, (unsigned long long) offset);
854                     break;
855                   }
856
857                 case R_X86_64_PC64:
858                   {
859                     *target = grub_host_to_target64 (grub_target_to_host64 (*target)
860                                                      + addend + sym_addr
861                                                      - target_section_addr - offset
862                                                      - image_target->vaddr_offset);
863                     grub_util_info ("relocating an R_X86_64_PC64 entry to 0x%"
864                                     GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
865                                     GRUB_HOST_PRIxLONG_LONG,
866                                     (unsigned long long) *target,
867                                     (unsigned long long) offset);
868                     break;
869                   }
870
871                 case R_X86_64_32:
872                 case R_X86_64_32S:
873                   {
874                     grub_uint32_t *t32 = (grub_uint32_t *) target;
875                     *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
876                                                   + addend + sym_addr);
877                     grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%"
878                                     GRUB_HOST_PRIxLONG_LONG,
879                                     *t32, (unsigned long long) offset);
880                     break;
881                   }
882
883                 default:
884                   grub_util_error (_("relocation 0x%x is not implemented yet"),
885                                    (unsigned int) ELF_R_TYPE (info));
886                   break;
887                 }
888               break;
889              case EM_IA_64:
890               switch (ELF_R_TYPE (info))
891                 {
892                 case R_IA64_PCREL21B:
893                   {
894                     grub_uint64_t noff;
895                     grub_ia64_make_trampoline (tr, addend + sym_addr);
896                     noff = ((char *) tr - (char *) pe_target
897                             - target_section_addr - (offset & ~3)) >> 4;
898                     tr++;
899                     if (noff & ~MASK19)
900                       grub_util_error ("trampoline offset too big (%"
901                                        GRUB_HOST_PRIxLONG_LONG ")",
902                                        (unsigned long long) noff);
903                     grub_ia64_add_value_to_slot_20b ((grub_addr_t) target, noff);
904                   }
905                   break;
906
907                 case R_IA64_LTOFF22X:
908                 case R_IA64_LTOFF22:
909                   {
910                     Elf_Sym *sym;
911
912                     sym = (Elf_Sym *) ((char *) e
913                                        + grub_target_to_host (symtab_section->sh_offset)
914                                        + ELF_R_SYM (info) * grub_target_to_host (symtab_section->sh_entsize));
915                     if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
916                       sym_addr = grub_target_to_host64 (*(grub_uint64_t *) (pe_target
917                                                                             + sym->st_value
918                                                                             - image_target->vaddr_offset));
919                   }
920                 /* FALLTHROUGH */
921                 case R_IA64_LTOFF_FPTR22:
922                   *gpptr = grub_host_to_target64 (addend + sym_addr);
923                   grub_ia64_add_value_to_slot_21 ((grub_addr_t) target,
924                                                   (char *) gpptr - (char *) pe_target
925                                                   + image_target->vaddr_offset);
926                   gpptr++;
927                   break;
928
929                 case R_IA64_GPREL22:
930                   grub_ia64_add_value_to_slot_21 ((grub_addr_t) target,
931                                                   addend + sym_addr);
932                   break;
933                 case R_IA64_GPREL64I:
934                   grub_ia64_set_immu64 ((grub_addr_t) target,
935                                         addend + sym_addr);
936                   break;
937                 case R_IA64_PCREL64LSB:
938                   *target = grub_host_to_target64 (grub_target_to_host64 (*target)
939                                                    + addend + sym_addr
940                                                    - target_section_addr - offset
941                                                    - image_target->vaddr_offset);
942                   break;
943
944                 case R_IA64_SEGREL64LSB:
945                   *target = grub_host_to_target64 (grub_target_to_host64 (*target)
946                                                    + addend + sym_addr - target_section_addr);
947                   break;
948                 case R_IA64_DIR64LSB:
949                 case R_IA64_FPTR64LSB:
950                   *target = grub_host_to_target64 (grub_target_to_host64 (*target)
951                                                    + addend + sym_addr);
952                   grub_util_info ("relocating a direct entry to 0x%"
953                                   GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
954                                   GRUB_HOST_PRIxLONG_LONG,
955                                   (unsigned long long)
956                                   grub_target_to_host64 (*target),
957                                   (unsigned long long) offset);
958                   break;
959
960                   /* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV.  */
961                 case R_IA64_LDXMOV:
962                   break;
963
964                 default:
965                   grub_util_error (_("relocation 0x%x is not implemented yet"),
966                                    (unsigned int) ELF_R_TYPE (info));
967                   break;
968                 }
969                break;
970              case EM_AARCH64:
971                {
972                  sym_addr += addend;
973                  switch (ELF_R_TYPE (info))
974                    {
975                    case R_AARCH64_ABS64:
976                      {
977                        *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr);
978                      }
979                      break;
980                    case R_AARCH64_PREL32:
981                      {
982                        grub_uint32_t *t32 = (grub_uint32_t *) target;
983                        *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
984                                                      + sym_addr
985                                                      - target_section_addr - offset
986                                                      - image_target->vaddr_offset);
987                        grub_util_info ("relocating an R_AARCH64_PREL32 entry to 0x%x at the offset 0x%"
988                                        GRUB_HOST_PRIxLONG_LONG,
989                                        *t32, (unsigned long long) offset);
990                        break;
991                      }
992                    case R_AARCH64_ADD_ABS_LO12_NC:
993                      grub_arm64_set_abs_lo12 ((grub_uint32_t *) target,
994                                               sym_addr);
995                      break;
996                    case R_AARCH64_LDST64_ABS_LO12_NC:
997                      grub_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) target,
998                                                      sym_addr);
999                      break;
1000                    case R_AARCH64_JUMP26:
1001                    case R_AARCH64_CALL26:
1002                      {
1003                        sym_addr -= offset;
1004                        sym_addr -= target_section_addr + image_target->vaddr_offset;
1005                        if (!grub_arm_64_check_xxxx26_offset (sym_addr))
1006                          grub_util_error ("%s", "CALL26 Relocation out of range");
1007
1008                        grub_arm64_set_xxxx26_offset((grub_uint32_t *)target,
1009                                                      sym_addr);
1010                      }
1011                      break;
1012                    case R_AARCH64_ADR_GOT_PAGE:
1013                      {
1014                        Elf64_Rela *rel2;
1015                        grub_int64_t gpoffset = (((char *) gpptr - (char *) pe_target + image_target->vaddr_offset) & ~0xfffULL)
1016                          - ((offset + target_section_addr + image_target->vaddr_offset) & ~0xfffULL);
1017                        unsigned k;
1018                        *gpptr = grub_host_to_target64 (sym_addr);
1019                        unmatched_adr_got_page++;
1020                        if (!grub_arm64_check_hi21_signed (gpoffset))
1021                          grub_util_error ("HI21 out of range");
1022                        grub_arm64_set_hi21((grub_uint32_t *)target,
1023                                            gpoffset);
1024                        for (k = 0, rel2 = (Elf_Rela *) ((char *) r + r_size);
1025                             k < num_rs;
1026                             k++, rel2 = (Elf_Rela *) ((char *) rel2 + r_size))
1027                          if (ELF_R_SYM (rel2->r_info)
1028                              == ELF_R_SYM (r->r_info)
1029                              && r->r_addend == rel2->r_addend
1030                              && ELF_R_TYPE (rel2->r_info) == R_AARCH64_LD64_GOT_LO12_NC)
1031                            {
1032                              grub_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) SUFFIX (get_target_address) (e, target_section,
1033                                                                                                             grub_target_to_host (rel2->r_offset), image_target),
1034                                                              ((char *) gpptr - (char *) pe_target + image_target->vaddr_offset));
1035                              break;
1036                            }
1037                        if (k >= num_rs)
1038                          grub_util_error ("ADR_GOT_PAGE without matching LD64_GOT_LO12_NC");
1039                        gpptr++;
1040                      }
1041                      break;
1042                    case R_AARCH64_LD64_GOT_LO12_NC:
1043                      if (unmatched_adr_got_page == 0)
1044                        grub_util_error ("LD64_GOT_LO12_NC without matching ADR_GOT_PAGE");
1045                      unmatched_adr_got_page--;
1046                      break;
1047                    case R_AARCH64_ADR_PREL_PG_HI21:
1048                      {
1049                        sym_addr &= ~0xfffULL;
1050                        sym_addr -= (offset + target_section_addr + image_target->vaddr_offset) & ~0xfffULL;
1051                        if (!grub_arm64_check_hi21_signed (sym_addr))
1052                          grub_util_error ("%s", "CALL26 Relocation out of range");
1053
1054                        grub_arm64_set_hi21((grub_uint32_t *)target,
1055                                            sym_addr);
1056                      }
1057                      break;
1058                    default:
1059                      grub_util_error (_("relocation 0x%x is not implemented yet"),
1060                                       (unsigned int) ELF_R_TYPE (info));
1061                      break;
1062                    }
1063                break;
1064                }
1065 #endif
1066 #if defined(MKIMAGE_ELF32)
1067              case EM_ARM:
1068                {
1069                  sym_addr += addend;
1070                  sym_addr -= image_target->vaddr_offset;
1071                  switch (ELF_R_TYPE (info))
1072                    {
1073                    case R_ARM_ABS32:
1074                      {
1075                        grub_util_info ("  ABS32:\toffset=%d\t(0x%08x)",
1076                                        (int) sym_addr, (int) sym_addr);
1077                        /* Data will be naturally aligned */
1078                        if (image_target->id == IMAGE_EFI)
1079                          sym_addr += 0x400;
1080                        *target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr);
1081                      }
1082                      break;
1083                      /* Happens when compiled with -march=armv4.
1084                         Since currently we need at least armv5, keep bx as-is.
1085                      */
1086                    case R_ARM_V4BX:
1087                      break;
1088                    case R_ARM_THM_CALL:
1089                    case R_ARM_THM_JUMP24:
1090                    case R_ARM_THM_JUMP19:
1091                      {
1092                        grub_err_t err;
1093                        Elf_Sym *sym;
1094                        grub_util_info ("  THM_JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)",
1095                                        (unsigned long) ((char *) target
1096                                                         - (char *) e),
1097                                        sym_addr);
1098                        sym = (Elf_Sym *) ((char *) e
1099                                           + grub_target_to_host (symtab_section->sh_offset)
1100                                           + ELF_R_SYM (info) * grub_target_to_host (symtab_section->sh_entsize));
1101                        if (ELF_ST_TYPE (sym->st_info) != STT_FUNC)
1102                          sym_addr |= 1;
1103                        if (!(sym_addr & 1))
1104                          {
1105                            grub_uint32_t tr_addr;
1106                            grub_int32_t new_offset;
1107                            tr_addr = (char *) tr - (char *) pe_target
1108                              - target_section_addr;
1109                            new_offset = sym_addr - tr_addr - 12;
1110
1111                            if (!grub_arm_jump24_check_offset (new_offset))
1112                              return grub_util_error ("jump24 relocation out of range");
1113
1114                            tr[0] = grub_host_to_target32 (0x46c04778); /* bx pc; nop  */
1115                            tr[1] = grub_host_to_target32 (((new_offset >> 2) & 0xffffff) | 0xea000000); /* b new_offset */
1116                            tr += 2;
1117                            sym_addr = tr_addr | 1;
1118                          }
1119                        sym_addr -= offset;
1120                        /* Thumb instructions can be 16-bit aligned */
1121                        if (ELF_R_TYPE (info) == R_ARM_THM_JUMP19)
1122                          err = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr);
1123                        else
1124                          err = grub_arm_reloc_thm_call ((grub_uint16_t *) target,
1125                                                         sym_addr);
1126                        if (err)
1127                          grub_util_error ("%s", grub_errmsg);
1128                      }
1129                      break;
1130
1131                    case R_ARM_CALL:
1132                    case R_ARM_JUMP24:
1133                      {
1134                        grub_err_t err;
1135                        grub_util_info ("  JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)",  (unsigned long) ((char *) target - (char *) e), sym_addr);
1136                        if (sym_addr & 1)
1137                          {
1138                            grub_uint32_t tr_addr;
1139                            grub_int32_t new_offset;
1140                            tr_addr = (char *) tr - (char *) pe_target
1141                              - target_section_addr;
1142                            new_offset = sym_addr - tr_addr - 12;
1143
1144                            /* There is no immediate version of bx, only register one...  */
1145                            tr[0] = grub_host_to_target32 (0xe59fc004); /* ldr   ip, [pc, #4] */
1146                            tr[1] = grub_host_to_target32 (0xe08cc00f); /* add   ip, ip, pc */
1147                            tr[2] = grub_host_to_target32 (0xe12fff1c); /* bx    ip */
1148                            tr[3] = grub_host_to_target32 (new_offset | 1);
1149                            tr += 4;
1150                            sym_addr = tr_addr;
1151                          }
1152                        sym_addr -= offset;
1153                        err = grub_arm_reloc_jump24 (target,
1154                                                     sym_addr);
1155                        if (err)
1156                          grub_util_error ("%s", grub_errmsg);
1157                      }
1158                      break;
1159
1160                    default:
1161                      grub_util_error (_("relocation 0x%x is not implemented yet"),
1162                                       (unsigned int) ELF_R_TYPE (info));
1163                      break;
1164                    }
1165                  break;
1166                }
1167 #endif /* MKIMAGE_ELF32 */
1168              default:
1169                grub_util_error ("unknown architecture type %d",
1170                                 image_target->elf_target);
1171              }
1172           }
1173       }
1174 }
1175
1176 /* Add a PE32's fixup entry for a relocation. Return the resulting address
1177    after having written to the file OUT.  */
1178 static Elf_Addr
1179 add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type,
1180                  Elf_Addr addr, int flush, Elf_Addr current_address,
1181                  const struct grub_install_image_target_desc *image_target)
1182 {
1183   struct grub_pe32_fixup_block *b;
1184
1185   b = &((*cblock)->b);
1186
1187   /* First, check if it is necessary to write out the current block.  */
1188   if ((*cblock)->state)
1189     {
1190       if (flush || addr < b->page_rva || b->page_rva + 0x1000 <= addr)
1191         {
1192           grub_uint32_t size;
1193
1194           if (flush)
1195             {
1196               /* Add as much padding as necessary to align the address
1197                  with a section boundary.  */
1198               Elf_Addr next_address;
1199               unsigned padding_size;
1200               size_t cur_index;
1201
1202               next_address = current_address + b->block_size;
1203               padding_size = ((ALIGN_UP (next_address, image_target->section_align)
1204                                - next_address)
1205                               >> 1);
1206               cur_index = ((b->block_size - sizeof (*b)) >> 1);
1207               grub_util_info ("adding %d padding fixup entries", padding_size);
1208               while (padding_size--)
1209                 {
1210                   b->entries[cur_index++] = 0;
1211                   b->block_size += 2;
1212                 }
1213             }
1214           else while (b->block_size & (8 - 1))
1215             {
1216               /* If not aligned with a 32-bit boundary, add
1217                  a padding entry.  */
1218               size_t cur_index;
1219
1220               grub_util_info ("adding a padding fixup entry");
1221               cur_index = ((b->block_size - sizeof (*b)) >> 1);
1222               b->entries[cur_index] = 0;
1223               b->block_size += 2;
1224             }
1225
1226           /* Flush it.  */
1227           grub_util_info ("writing %d bytes of a fixup block starting at 0x%x",
1228                           b->block_size, b->page_rva);
1229           size = b->block_size;
1230           current_address += size;
1231           b->page_rva = grub_host_to_target32 (b->page_rva);
1232           b->block_size = grub_host_to_target32 (b->block_size);
1233           (*cblock)->next = xmalloc (sizeof (**cblock) + 2 * 0x1000);
1234           memset ((*cblock)->next, 0, sizeof (**cblock) + 2 * 0x1000);
1235           *cblock = (*cblock)->next;
1236         }
1237     }
1238
1239   b = &((*cblock)->b);
1240
1241   if (! flush)
1242     {
1243       grub_uint16_t entry;
1244       size_t cur_index;
1245
1246       /* If not allocated yet, allocate a block with enough entries.  */
1247       if (! (*cblock)->state)
1248         {
1249           (*cblock)->state = 1;
1250
1251           /* The spec does not mention the requirement of a Page RVA.
1252              Here, align the address with a 4K boundary for safety.  */
1253           b->page_rva = (addr & ~(0x1000 - 1));
1254           b->block_size = sizeof (*b);
1255         }
1256
1257       /* Sanity check.  */
1258       if (b->block_size >= sizeof (*b) + 2 * 0x1000)
1259         grub_util_error ("too many fixup entries");
1260
1261       /* Add a new entry.  */
1262       cur_index = ((b->block_size - sizeof (*b)) >> 1);
1263       entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva);
1264       b->entries[cur_index] = grub_host_to_target16 (entry);
1265       b->block_size += 2;
1266     }
1267
1268   return current_address;
1269 }
1270
1271 struct raw_reloc
1272 {
1273   struct raw_reloc *next;
1274   grub_uint32_t offset;
1275   enum raw_reloc_type {
1276     RAW_RELOC_NONE = -1,
1277     RAW_RELOC_32 = 0,
1278     RAW_RELOC_MAX = 1,
1279   } type;
1280 };
1281
1282 struct translate_context
1283 {
1284   /* PE */
1285   struct fixup_block_list *lst, *lst0;
1286   Elf_Addr current_address;
1287
1288   /* Raw */
1289   struct raw_reloc *raw_relocs;
1290 };
1291
1292 static void
1293 translate_reloc_start (struct translate_context *ctx,
1294                        const struct grub_install_image_target_desc *image_target)
1295 {
1296   grub_memset (ctx, 0, sizeof (*ctx));
1297   if (image_target->id == IMAGE_EFI)
1298     {
1299       ctx->lst = ctx->lst0 = xmalloc (sizeof (*ctx->lst) + 2 * 0x1000);
1300       memset (ctx->lst, 0, sizeof (*ctx->lst) + 2 * 0x1000);
1301       ctx->current_address = 0;
1302     }
1303 }
1304
1305 static void
1306 translate_relocation_pe (struct translate_context *ctx,
1307                          Elf_Addr addr,
1308                          Elf_Addr info,
1309                          const struct grub_install_image_target_desc *image_target)
1310 {
1311   /* Necessary to relocate only absolute addresses.  */
1312   switch (image_target->elf_target)
1313     {
1314     case EM_386:
1315       if (ELF_R_TYPE (info) == R_386_32)
1316         {
1317           grub_util_info ("adding a relocation entry for 0x%"
1318                           GRUB_HOST_PRIxLONG_LONG,
1319                           (unsigned long long) addr);
1320           ctx->current_address
1321             = add_fixup_entry (&ctx->lst,
1322                                GRUB_PE32_REL_BASED_HIGHLOW,
1323                                addr, 0, ctx->current_address,
1324                                image_target);
1325         }
1326       break;
1327     case EM_X86_64:
1328       if ((ELF_R_TYPE (info) == R_X86_64_32) ||
1329           (ELF_R_TYPE (info) == R_X86_64_32S))
1330         {
1331           grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)");
1332         }
1333       else if (ELF_R_TYPE (info) == R_X86_64_64)
1334         {
1335           grub_util_info ("adding a relocation entry for 0x%"
1336                           GRUB_HOST_PRIxLONG_LONG,
1337                           (unsigned long long) addr);
1338           ctx->current_address
1339             = add_fixup_entry (&ctx->lst,
1340                                GRUB_PE32_REL_BASED_DIR64,
1341                                addr,
1342                                0, ctx->current_address,
1343                                image_target);
1344         }
1345       break;
1346     case EM_IA_64:
1347       switch (ELF_R_TYPE (info))
1348         {
1349         case R_IA64_PCREL64LSB:
1350         case R_IA64_LDXMOV:
1351         case R_IA64_PCREL21B:
1352         case R_IA64_LTOFF_FPTR22:
1353         case R_IA64_LTOFF22X:
1354         case R_IA64_LTOFF22:
1355         case R_IA64_GPREL22:
1356         case R_IA64_GPREL64I:
1357         case R_IA64_SEGREL64LSB:
1358           break;
1359
1360         case R_IA64_FPTR64LSB:
1361         case R_IA64_DIR64LSB:
1362 #if 1
1363           {
1364             grub_util_info ("adding a relocation entry for 0x%"
1365                             GRUB_HOST_PRIxLONG_LONG,
1366                             (unsigned long long) addr);
1367             ctx->current_address
1368               = add_fixup_entry (&ctx->lst,
1369                                  GRUB_PE32_REL_BASED_DIR64,
1370                                  addr,
1371                                  0, ctx->current_address,
1372                                  image_target);
1373           }
1374 #endif
1375           break;
1376         default:
1377           grub_util_error (_("relocation 0x%x is not implemented yet"),
1378                            (unsigned int) ELF_R_TYPE (info));
1379           break;
1380         }
1381       break;
1382     case EM_AARCH64:
1383       switch (ELF_R_TYPE (info))
1384         {
1385         case R_AARCH64_ABS64:
1386           {
1387             ctx->current_address
1388               = add_fixup_entry (&ctx->lst,
1389                                  GRUB_PE32_REL_BASED_DIR64,
1390                                  addr, 0, ctx->current_address,
1391                                  image_target);
1392           }
1393           break;
1394           /* Relative relocations do not require fixup entries. */
1395         case R_AARCH64_CALL26:
1396         case R_AARCH64_JUMP26:
1397         case R_AARCH64_PREL32:
1398           break;
1399           /* Page-relative relocations do not require fixup entries. */
1400         case R_AARCH64_ADR_PREL_PG_HI21:
1401           /* We page-align the whole kernel, so no need
1402              for fixup entries.
1403           */
1404         case R_AARCH64_ADD_ABS_LO12_NC:
1405         case R_AARCH64_LDST64_ABS_LO12_NC:
1406           break;
1407
1408           /* GOT is relocated separately.  */
1409         case R_AARCH64_ADR_GOT_PAGE:
1410         case R_AARCH64_LD64_GOT_LO12_NC:
1411           break;
1412
1413         default:
1414           grub_util_error (_("relocation 0x%x is not implemented yet"),
1415                            (unsigned int) ELF_R_TYPE (info));
1416           break;
1417         }
1418       break;
1419       break;
1420 #if defined(MKIMAGE_ELF32)
1421     case EM_ARM:
1422       switch (ELF_R_TYPE (info))
1423         {
1424         case R_ARM_V4BX:
1425           /* Relative relocations do not require fixup entries. */
1426         case R_ARM_JUMP24:
1427         case R_ARM_THM_CALL:
1428         case R_ARM_THM_JUMP19:
1429         case R_ARM_THM_JUMP24:
1430         case R_ARM_CALL:
1431           {
1432             grub_util_info ("  %s:  not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) ctx->current_address);
1433           }
1434           break;
1435           /* Create fixup entry for PE/COFF loader */
1436         case R_ARM_ABS32:
1437           {
1438             ctx->current_address
1439               = add_fixup_entry (&ctx->lst,
1440                                  GRUB_PE32_REL_BASED_HIGHLOW,
1441                                  addr, 0, ctx->current_address,
1442                                  image_target);
1443           }
1444           break;
1445         default:
1446           grub_util_error (_("relocation 0x%x is not implemented yet"),
1447                            (unsigned int) ELF_R_TYPE (info));
1448           break;
1449         }
1450       break;
1451 #endif /* defined(MKIMAGE_ELF32) */
1452     default:
1453       grub_util_error ("unknown machine type 0x%x", image_target->elf_target);
1454     }
1455 }
1456
1457 static enum raw_reloc_type
1458 classify_raw_reloc (Elf_Addr info,
1459                     const struct grub_install_image_target_desc *image_target)
1460 {
1461     /* Necessary to relocate only absolute addresses.  */
1462   switch (image_target->elf_target)
1463     {
1464     case EM_ARM:
1465       switch (ELF_R_TYPE (info))
1466         {
1467         case R_ARM_V4BX:
1468         case R_ARM_JUMP24:
1469         case R_ARM_THM_CALL:
1470         case R_ARM_THM_JUMP19:
1471         case R_ARM_THM_JUMP24:
1472         case R_ARM_CALL:
1473           return RAW_RELOC_NONE;
1474         case R_ARM_ABS32:
1475           return RAW_RELOC_32;
1476         default:
1477           grub_util_error (_("relocation 0x%x is not implemented yet"),
1478                            (unsigned int) ELF_R_TYPE (info));
1479           break;
1480         }
1481       break;
1482     default:
1483       grub_util_error ("unknown machine type 0x%x", image_target->elf_target);
1484     }
1485 }
1486
1487 static void
1488 translate_relocation_raw (struct translate_context *ctx,
1489                           Elf_Addr addr,
1490                           Elf_Addr info,
1491                           const struct grub_install_image_target_desc *image_target)
1492 {
1493   enum raw_reloc_type class = classify_raw_reloc (info, image_target);
1494   struct raw_reloc *rel;
1495   if (class == RAW_RELOC_NONE)
1496     return;
1497   rel = xmalloc (sizeof (*rel));
1498   rel->next = ctx->raw_relocs;
1499   rel->type = class;
1500   rel->offset = addr;
1501   ctx->raw_relocs = rel;
1502 }
1503
1504 static void
1505 translate_relocation (struct translate_context *ctx,
1506                       Elf_Addr addr,
1507                       Elf_Addr info,
1508                       const struct grub_install_image_target_desc *image_target)
1509 {
1510   if (image_target->id == IMAGE_EFI)
1511     translate_relocation_pe (ctx, addr, info, image_target);
1512   else
1513     translate_relocation_raw (ctx, addr, info, image_target);
1514 }
1515
1516 static void
1517 finish_reloc_translation_pe (struct translate_context *ctx, struct grub_mkimage_layout *layout,
1518                              const struct grub_install_image_target_desc *image_target)
1519 {
1520   ctx->current_address = add_fixup_entry (&ctx->lst, 0, 0, 1, ctx->current_address, image_target);
1521
1522   {
1523     grub_uint8_t *ptr;
1524     layout->reloc_section = ptr = xmalloc (ctx->current_address);
1525     for (ctx->lst = ctx->lst0; ctx->lst; ctx->lst = ctx->lst->next)
1526       if (ctx->lst->state)
1527         {
1528           memcpy (ptr, &ctx->lst->b, grub_target_to_host32 (ctx->lst->b.block_size));
1529           ptr += grub_target_to_host32 (ctx->lst->b.block_size);
1530         }
1531     assert ((ctx->current_address + (grub_uint8_t *) layout->reloc_section) == ptr);
1532   }
1533
1534   for (ctx->lst = ctx->lst0; ctx->lst; )
1535     {
1536       struct fixup_block_list *next;
1537       next = ctx->lst->next;
1538       free (ctx->lst);
1539       ctx->lst = next;
1540     }
1541
1542   layout->reloc_size = ctx->current_address;
1543   if (image_target->elf_target == EM_ARM && layout->reloc_size > GRUB_KERNEL_ARM_STACK_SIZE)
1544     grub_util_error ("Reloc section (%d) is bigger than stack size (%d). "
1545                      "This breaks assembly assumptions. Please increase stack size",
1546                      (int) layout->reloc_size,
1547                      (int) GRUB_KERNEL_ARM_STACK_SIZE);
1548 }
1549
1550 /*
1551   Layout:
1552   <type 0 relocations>
1553   <fffffffe>
1554   <type 1 relocations>
1555   <fffffffe>
1556   ...
1557   <type n relocations>
1558   <ffffffff>
1559   each relocation starts with 32-bit offset. Rest depends on relocation.
1560   mkimage stops when it sees first unknown type or end marker.
1561   This allows images to be created with mismatched mkimage and
1562   kernel as long as no relocations are present in kernel that mkimage
1563   isn't aware of (in which case mkimage aborts).
1564   This also allows simple assembly to do the relocs.
1565 */
1566
1567 #define RAW_SEPARATOR 0xfffffffe
1568 #define RAW_END_MARKER 0xffffffff
1569
1570 static void
1571 finish_reloc_translation_raw (struct translate_context *ctx, struct grub_mkimage_layout *layout,
1572                               const struct grub_install_image_target_desc *image_target)
1573 {
1574   size_t count = 0, sz;
1575   enum raw_reloc_type highest = RAW_RELOC_NONE;
1576   enum raw_reloc_type curtype;
1577   struct raw_reloc *cur;
1578   grub_uint32_t *p;
1579   if (!ctx->raw_relocs)
1580     {
1581       layout->reloc_section = p = xmalloc (sizeof (grub_uint32_t));
1582       p[0] = RAW_END_MARKER;
1583       layout->reloc_size = sizeof (grub_uint32_t);
1584       return;
1585     }
1586   for (cur = ctx->raw_relocs; cur; cur = cur->next)
1587     {
1588       count++;
1589       if (cur->type > highest)
1590         highest = cur->type;
1591     }
1592   /* highest separators, count relocations and one end marker.  */
1593   sz = (highest + count + 1) * sizeof (grub_uint32_t);
1594   layout->reloc_section = p = xmalloc (sz);
1595   for (curtype = 0; curtype <= highest; curtype++)
1596     {
1597       /* Support for special cases would go here.  */
1598       for (cur = ctx->raw_relocs; cur; cur = cur->next)
1599         if (cur->type == curtype)
1600           {
1601             *p++ = cur->offset;
1602           }
1603       *p++ = RAW_SEPARATOR;
1604     }
1605   *--p = RAW_END_MARKER;
1606   layout->reloc_size = sz;
1607 }
1608
1609 static void
1610 finish_reloc_translation (struct translate_context *ctx, struct grub_mkimage_layout *layout,
1611                           const struct grub_install_image_target_desc *image_target)
1612 {
1613   if (image_target->id == IMAGE_EFI)
1614     finish_reloc_translation_pe (ctx, layout, image_target);
1615   else
1616     finish_reloc_translation_raw (ctx, layout, image_target);
1617 }
1618
1619
1620 static void
1621 create_u64_fixups (struct translate_context *ctx,
1622                    Elf_Addr jumpers, grub_size_t njumpers,
1623                    const struct grub_install_image_target_desc *image_target)
1624 {
1625   unsigned i;
1626   assert (image_target->id == IMAGE_EFI);
1627   for (i = 0; i < njumpers; i++)
1628     ctx->current_address = add_fixup_entry (&ctx->lst,
1629                                             GRUB_PE32_REL_BASED_DIR64,
1630                                             jumpers + 8 * i,
1631                                             0, ctx->current_address,
1632                                             image_target);
1633 }
1634
1635 /* Make a .reloc section.  */
1636 static void
1637 make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout,
1638                     Elf_Addr *section_addresses, Elf_Shdr *sections,
1639                     Elf_Half section_entsize, Elf_Half num_sections,
1640                     const char *strtab,
1641                     const struct grub_install_image_target_desc *image_target)
1642 {
1643   unsigned i;
1644   Elf_Shdr *s;
1645   struct translate_context ctx;
1646
1647   translate_reloc_start (&ctx, image_target);
1648
1649   for (i = 0, s = sections; i < num_sections;
1650        i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1651     if ((grub_target_to_host32 (s->sh_type) == SHT_REL) ||
1652         (grub_target_to_host32 (s->sh_type) == SHT_RELA))
1653       {
1654         Elf_Rel *r;
1655         Elf_Word rtab_size, r_size, num_rs;
1656         Elf_Off rtab_offset;
1657         Elf_Addr section_address;
1658         Elf_Word j;
1659
1660         grub_util_info ("translating the relocation section %s",
1661                         strtab + grub_le_to_cpu32 (s->sh_name));
1662
1663         rtab_size = grub_target_to_host (s->sh_size);
1664         r_size = grub_target_to_host (s->sh_entsize);
1665         rtab_offset = grub_target_to_host (s->sh_offset);
1666         num_rs = rtab_size / r_size;
1667
1668         section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)];
1669
1670         for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset);
1671              j < num_rs;
1672              j++, r = (Elf_Rel *) ((char *) r + r_size))
1673           {
1674             Elf_Addr info;
1675             Elf_Addr offset;
1676             Elf_Addr addr;
1677
1678             offset = grub_target_to_host (r->r_offset);
1679             info = grub_target_to_host (r->r_info);
1680
1681             addr = section_address + offset;
1682
1683             translate_relocation (&ctx, addr, info, image_target);
1684           }
1685       }
1686
1687   if (image_target->elf_target == EM_IA_64)
1688     create_u64_fixups (&ctx,
1689                        layout->ia64jmp_off
1690                        + image_target->vaddr_offset,
1691                        2 * layout->ia64jmpnum,
1692                        image_target);
1693   if (image_target->elf_target == EM_IA_64 || image_target->elf_target == EM_AARCH64)
1694     create_u64_fixups (&ctx,
1695                        layout->got_off
1696                        + image_target->vaddr_offset,
1697                        (layout->got_size / 8),
1698                        image_target);
1699
1700   finish_reloc_translation (&ctx, layout, image_target);
1701 }
1702
1703 /* Determine if this section is a text section. Return false if this
1704    section is not allocated.  */
1705 static int
1706 SUFFIX (is_text_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
1707 {
1708   if (!is_relocatable (image_target)
1709       && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
1710     return 0;
1711   return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
1712           == (SHF_EXECINSTR | SHF_ALLOC));
1713 }
1714
1715 /* Determine if this section is a data section.  */
1716 static int
1717 SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
1718 {
1719   if (!is_relocatable (image_target) 
1720       && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
1721     return 0;
1722   return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
1723           == SHF_ALLOC) && !(grub_target_to_host32 (s->sh_type) == SHT_NOBITS);
1724 }
1725
1726 static int
1727 SUFFIX (is_bss_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
1728 {
1729   if (!is_relocatable (image_target))
1730     return 0;
1731   return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
1732           == SHF_ALLOC) && (grub_target_to_host32 (s->sh_type) == SHT_NOBITS);
1733 }
1734
1735 /* Return if the ELF header is valid.  */
1736 static int
1737 SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_image_target_desc *image_target)
1738 {
1739   if (size < sizeof (*e)
1740       || e->e_ident[EI_MAG0] != ELFMAG0
1741       || e->e_ident[EI_MAG1] != ELFMAG1
1742       || e->e_ident[EI_MAG2] != ELFMAG2
1743       || e->e_ident[EI_MAG3] != ELFMAG3
1744       || e->e_ident[EI_VERSION] != EV_CURRENT
1745       || e->e_ident[EI_CLASS] != ELFCLASSXX
1746       || e->e_version != grub_host_to_target32 (EV_CURRENT))
1747     return 0;
1748
1749   return 1;
1750 }
1751
1752 static Elf_Addr
1753 SUFFIX (put_section) (Elf_Shdr *s, int i,
1754                       Elf_Addr current_address,
1755                       Elf_Addr *section_addresses,
1756                       const char *strtab,
1757                       const struct grub_install_image_target_desc *image_target)
1758 {
1759         Elf_Word align = grub_host_to_target_addr (s->sh_addralign);
1760         const char *name = strtab + grub_host_to_target32 (s->sh_name);
1761
1762         if (align)
1763           current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1764                                       align)
1765             - image_target->vaddr_offset;
1766
1767         grub_util_info ("locating the section %s at 0x%"
1768                         GRUB_HOST_PRIxLONG_LONG,
1769                         name, (unsigned long long) current_address);
1770         if (!is_relocatable (image_target))
1771           current_address = grub_host_to_target_addr (s->sh_addr)
1772             - image_target->link_addr;
1773         section_addresses[i] = current_address;
1774         current_address += grub_host_to_target_addr (s->sh_size);
1775         return current_address;
1776 }
1777
1778 /* Locate section addresses by merging code sections and data sections
1779    into .text and .data, respectively. Return the array of section
1780    addresses.  */
1781 static Elf_Addr *
1782 SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path,
1783                           Elf_Shdr *sections, Elf_Half section_entsize,
1784                           Elf_Half num_sections, const char *strtab,
1785                           struct grub_mkimage_layout *layout,
1786                           const struct grub_install_image_target_desc *image_target)
1787 {
1788   int i;
1789   Elf_Addr *section_addresses;
1790   Elf_Shdr *s;
1791
1792   layout->align = 1;
1793   /* Page-aligning simplifies relocation handling.  */
1794   if (image_target->elf_target == EM_AARCH64)
1795     layout->align = 4096;
1796
1797   section_addresses = xmalloc (sizeof (*section_addresses) * num_sections);
1798   memset (section_addresses, 0, sizeof (*section_addresses) * num_sections);
1799
1800   layout->kernel_size = 0;
1801
1802   for (i = 0, s = sections;
1803        i < num_sections;
1804        i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1805     if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC) 
1806         && grub_host_to_target32 (s->sh_addralign) > layout->align)
1807       layout->align = grub_host_to_target32 (s->sh_addralign);
1808
1809
1810   /* .text */
1811   for (i = 0, s = sections;
1812        i < num_sections;
1813        i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1814     if (SUFFIX (is_text_section) (s, image_target))
1815       {
1816         layout->kernel_size = SUFFIX (put_section) (s, i,
1817                                                 layout->kernel_size,
1818                                                 section_addresses,
1819                                                 strtab,
1820                                                 image_target);
1821         if (!is_relocatable (image_target) &&
1822             grub_host_to_target_addr (s->sh_addr) != image_target->link_addr)
1823           {
1824             char *msg
1825               = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx"
1826                                   " instead of 0x%llx: ld.gold bug?"),
1827                                 kernel_path,
1828                                 (unsigned long long) grub_host_to_target_addr (s->sh_addr),
1829                                 (unsigned long long) image_target->link_addr);
1830             grub_util_error ("%s", msg);
1831           }
1832       }
1833
1834   layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset,
1835                               image_target->section_align)
1836     - image_target->vaddr_offset;
1837   layout->exec_size = layout->kernel_size;
1838
1839   /* .data */
1840   for (i = 0, s = sections;
1841        i < num_sections;
1842        i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1843     if (SUFFIX (is_data_section) (s, image_target))
1844       layout->kernel_size = SUFFIX (put_section) (s, i,
1845                                               layout->kernel_size,
1846                                               section_addresses,
1847                                               strtab,
1848                                               image_target);
1849
1850 #ifdef MKIMAGE_ELF32
1851   if (image_target->elf_target == EM_ARM)
1852     {
1853       grub_size_t tramp;
1854       layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset,
1855                                       image_target->section_align) - image_target->vaddr_offset;
1856
1857       layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
1858
1859       tramp = arm_get_trampoline_size (e, sections, section_entsize,
1860                                        num_sections, image_target);
1861
1862       layout->tramp_off = layout->kernel_size;
1863       layout->kernel_size += ALIGN_UP (tramp, 16);
1864     }
1865 #endif
1866
1867   layout->bss_start = layout->kernel_size;
1868   layout->end = layout->kernel_size;
1869   
1870   /* .bss */
1871   for (i = 0, s = sections;
1872        i < num_sections;
1873        i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1874     if (SUFFIX (is_bss_section) (s, image_target))
1875       layout->end = SUFFIX (put_section) (s, i,
1876                                           layout->end,
1877                                           section_addresses,
1878                                           strtab,
1879                                           image_target);
1880
1881   layout->end = ALIGN_UP (layout->end + image_target->vaddr_offset,
1882                               image_target->section_align) - image_target->vaddr_offset;
1883   /* Explicitly initialize BSS
1884      when producing PE32 to avoid a bug in EFI implementations.
1885      Platforms other than EFI and U-boot shouldn't have .bss in
1886      their binaries as we build with -Wl,-Ttext.
1887   */
1888   if (image_target->id == IMAGE_EFI || !is_relocatable (image_target))
1889     layout->kernel_size = layout->end;
1890
1891   return section_addresses;
1892 }
1893
1894 char *
1895 SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
1896                                   size_t total_module_size,
1897                                   struct grub_mkimage_layout *layout,
1898                                   const struct grub_install_image_target_desc *image_target)
1899 {
1900   char *kernel_img, *out_img;
1901   const char *strtab;
1902   Elf_Ehdr *e;
1903   Elf_Shdr *sections;
1904   Elf_Addr *section_addresses;
1905   Elf_Addr *section_vaddresses;
1906   int i;
1907   Elf_Shdr *s;
1908   Elf_Half num_sections;
1909   Elf_Off section_offset;
1910   Elf_Half section_entsize;
1911   grub_size_t kernel_size;
1912   Elf_Shdr *symtab_section = 0;
1913
1914   grub_memset (layout, 0, sizeof (*layout));
1915
1916   layout->start_address = 0;
1917
1918   kernel_size = grub_util_get_image_size (kernel_path);
1919   kernel_img = xmalloc (kernel_size);
1920   grub_util_load_image (kernel_path, kernel_img);
1921
1922   e = (Elf_Ehdr *) kernel_img;
1923   if (! SUFFIX (check_elf_header) (e, kernel_size, image_target))
1924     grub_util_error ("invalid ELF header");
1925
1926   section_offset = grub_target_to_host (e->e_shoff);
1927   section_entsize = grub_target_to_host16 (e->e_shentsize);
1928   num_sections = grub_target_to_host16 (e->e_shnum);
1929
1930   if (kernel_size < section_offset + (grub_uint32_t) section_entsize * num_sections)
1931     grub_util_error (_("premature end of file %s"), kernel_path);
1932
1933   sections = (Elf_Shdr *) (kernel_img + section_offset);
1934
1935   /* Relocate sections then symbols in the virtual address space.  */
1936   s = (Elf_Shdr *) ((char *) sections
1937                       + grub_host_to_target16 (e->e_shstrndx) * section_entsize);
1938   strtab = (char *) e + grub_host_to_target_addr (s->sh_offset);
1939
1940   section_addresses = SUFFIX (locate_sections) (e, kernel_path,
1941                                                 sections, section_entsize,
1942                                                 num_sections, strtab,
1943                                                 layout,
1944                                                 image_target);
1945
1946   section_vaddresses = xmalloc (sizeof (*section_addresses) * num_sections);
1947
1948   for (i = 0; i < num_sections; i++)
1949     section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset;
1950
1951   if (!is_relocatable (image_target))
1952     {
1953       Elf_Addr current_address = layout->kernel_size;
1954
1955       for (i = 0, s = sections;
1956            i < num_sections;
1957            i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1958         if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
1959           {
1960             Elf_Word sec_align = grub_host_to_target_addr (s->sh_addralign);
1961             const char *name = strtab + grub_host_to_target32 (s->sh_name);
1962
1963             if (sec_align)
1964               current_address = ALIGN_UP (current_address
1965                                           + image_target->vaddr_offset,
1966                                           sec_align)
1967                 - image_target->vaddr_offset;
1968         
1969             grub_util_info ("locating the section %s at 0x%"
1970                             GRUB_HOST_PRIxLONG_LONG,
1971                             name, (unsigned long long) current_address);
1972             if (!is_relocatable (image_target))
1973               current_address = grub_host_to_target_addr (s->sh_addr)
1974                 - image_target->link_addr;
1975
1976             section_vaddresses[i] = current_address
1977               + image_target->vaddr_offset;
1978             current_address += grub_host_to_target_addr (s->sh_size);
1979           }
1980       current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1981                                   image_target->section_align)
1982         - image_target->vaddr_offset;
1983       layout->bss_size = current_address - layout->kernel_size;
1984     }
1985   else
1986     layout->bss_size = 0;
1987
1988   if (image_target->id == IMAGE_SPARC64_AOUT
1989       || image_target->id == IMAGE_SPARC64_RAW
1990       || image_target->id == IMAGE_UBOOT
1991       || image_target->id == IMAGE_COREBOOT
1992       || image_target->id == IMAGE_SPARC64_CDCORE)
1993     layout->kernel_size = ALIGN_UP (layout->kernel_size, image_target->mod_align);
1994
1995   if (is_relocatable (image_target))
1996     {
1997       symtab_section = NULL;
1998       for (i = 0, s = sections;
1999            i < num_sections;
2000            i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
2001         if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB))
2002           {
2003             symtab_section = s;
2004             break;
2005           }
2006       if (! symtab_section)
2007         grub_util_error ("%s", _("no symbol table"));
2008 #ifdef MKIMAGE_ELF64
2009       if (image_target->elf_target == EM_IA_64)
2010         {
2011           grub_size_t tramp;
2012
2013           layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
2014
2015           grub_ia64_dl_get_tramp_got_size (e, &tramp, &layout->got_size);
2016
2017           layout->tramp_off = layout->kernel_size;
2018           layout->kernel_size += ALIGN_UP (tramp, 16);
2019
2020           layout->ia64jmp_off = layout->kernel_size;
2021           layout->ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section,
2022                                                      image_target);
2023           layout->kernel_size += 16 * layout->ia64jmpnum;
2024
2025           layout->got_off = layout->kernel_size;
2026           layout->kernel_size += ALIGN_UP (layout->got_size, 16);
2027         }
2028       if (image_target->elf_target == EM_AARCH64)
2029         {
2030           grub_size_t tramp;
2031
2032           layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
2033
2034           grub_arm64_dl_get_tramp_got_size (e, &tramp, &layout->got_size);
2035
2036           layout->got_off = layout->kernel_size;
2037           layout->kernel_size += ALIGN_UP (layout->got_size, 16);
2038         }
2039 #endif
2040     }
2041   else
2042     {
2043       layout->reloc_size = 0;
2044       layout->reloc_section = NULL;
2045     }
2046
2047   out_img = xmalloc (layout->kernel_size + total_module_size);
2048   memset (out_img, 0, layout->kernel_size + total_module_size);
2049
2050   if (is_relocatable (image_target))
2051     {
2052       layout->start_address = SUFFIX (relocate_symbols) (e, sections, symtab_section,
2053                                           section_vaddresses, section_entsize,
2054                                           num_sections, 
2055                                           (char *) out_img + layout->ia64jmp_off, 
2056                                           layout->ia64jmp_off 
2057                                           + image_target->vaddr_offset,
2058                                                          layout->bss_start,
2059                                                          layout->end,
2060                                           image_target);
2061       if (layout->start_address == (Elf_Addr) -1)
2062         grub_util_error ("start symbol is not defined");
2063
2064       /* Resolve addresses in the virtual address space.  */
2065       SUFFIX (relocate_addresses) (e, sections, section_addresses, 
2066                                    section_entsize,
2067                                    num_sections, strtab,
2068                                    out_img, layout->tramp_off,
2069                                    layout->got_off,
2070                                    image_target);
2071
2072       make_reloc_section (e, layout,
2073                           section_vaddresses, sections,
2074                           section_entsize, num_sections,
2075                           strtab,
2076                           image_target);
2077       if (image_target->id != IMAGE_EFI)
2078         {
2079           out_img = xrealloc (out_img, layout->kernel_size + total_module_size
2080                               + ALIGN_UP (layout->reloc_size, image_target->mod_align));
2081           memcpy (out_img + layout->kernel_size, layout->reloc_section, layout->reloc_size);
2082           memset (out_img + layout->kernel_size + layout->reloc_size, 0,
2083                   total_module_size + ALIGN_UP (layout->reloc_size, image_target->mod_align) - layout->reloc_size);
2084           layout->kernel_size += ALIGN_UP (layout->reloc_size, image_target->mod_align);
2085         }
2086     }
2087
2088   for (i = 0, s = sections;
2089        i < num_sections;
2090        i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
2091     if (SUFFIX (is_data_section) (s, image_target)
2092         /* Explicitly initialize BSS
2093            when producing PE32 to avoid a bug in EFI implementations.
2094            Platforms other than EFI and U-boot shouldn't have .bss in
2095            their binaries as we build with -Wl,-Ttext.
2096         */
2097         || (SUFFIX (is_bss_section) (s, image_target) && (image_target->id == IMAGE_EFI || !is_relocatable (image_target)))
2098         || SUFFIX (is_text_section) (s, image_target))
2099       {
2100         if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
2101           memset (out_img + section_addresses[i], 0,
2102                   grub_host_to_target_addr (s->sh_size));
2103         else
2104           memcpy (out_img + section_addresses[i],
2105                   kernel_img + grub_host_to_target_addr (s->sh_offset),
2106                   grub_host_to_target_addr (s->sh_size));
2107       }
2108   free (kernel_img);
2109
2110   free (section_vaddresses);
2111   free (section_addresses);
2112
2113   return out_img;
2114 }