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