5de34d53cb74574af5939a6e0d1090a4c933fded
[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 struct section_metadata
97 {
98   Elf_Half num_sections;
99   Elf_Shdr *sections;
100   Elf_Addr *addrs;
101   Elf_Addr *vaddrs;
102   Elf_Half section_entsize;
103   Elf_Shdr *symtab;
104   const char *strtab;
105 };
106
107 static int
108 is_relocatable (const struct grub_install_image_target_desc *image_target)
109 {
110   return image_target->id == IMAGE_EFI || image_target->id == IMAGE_UBOOT
111     || (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM);
112 }
113
114 #ifdef MKIMAGE_ELF32
115
116 /*
117  * R_ARM_THM_CALL/THM_JUMP24
118  *
119  * Relocate Thumb (T32) instruction set relative branches:
120  *   B.W, BL and BLX
121  */
122 static grub_err_t
123 grub_arm_reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr)
124 {
125   grub_int32_t offset;
126
127   offset = grub_arm_thm_call_get_offset (target);
128
129   grub_dprintf ("dl", "    sym_addr = 0x%08x", sym_addr);
130
131   offset += sym_addr;
132
133   grub_dprintf("dl", " BL*: target=%p, sym_addr=0x%08x, offset=%d\n",
134                target, sym_addr, offset);
135
136   /* Keep traditional (pre-Thumb2) limits on blx. In any case if the kernel
137      is bigger than 2M  (currently under 150K) then we probably have a problem
138      somewhere else.  */
139   if (offset < -0x200000 || offset >= 0x200000)
140     return grub_error (GRUB_ERR_BAD_MODULE,
141                        "THM_CALL Relocation out of range.");
142
143   grub_dprintf ("dl", "    relative destination = %p",
144                 (char *) target + offset);
145
146   return grub_arm_thm_call_set_offset (target, offset);
147 }
148
149 /*
150  * R_ARM_THM_JUMP19
151  *
152  * Relocate conditional Thumb (T32) B<c>.W
153  */
154 static grub_err_t
155 grub_arm_reloc_thm_jump19 (grub_uint16_t *target, Elf32_Addr sym_addr)
156 {
157   grub_int32_t offset;
158
159   if (!(sym_addr & 1))
160     return grub_error (GRUB_ERR_BAD_MODULE,
161                        "Relocation targeting wrong execution state");
162
163   offset = grub_arm_thm_jump19_get_offset (target);
164
165   /* Adjust and re-truncate offset */
166   offset += sym_addr;
167
168   if (!grub_arm_thm_jump19_check_offset (offset))
169     return grub_error (GRUB_ERR_BAD_MODULE,
170                        "THM_JUMP19 Relocation out of range.");
171
172   grub_arm_thm_jump19_set_offset (target, offset);
173
174   return GRUB_ERR_NONE;
175 }
176
177 /*
178  * R_ARM_JUMP24
179  *
180  * Relocate ARM (A32) B
181  */
182 static grub_err_t
183 grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
184 {
185   grub_int32_t offset;
186
187   if (sym_addr & 1)
188     return grub_error (GRUB_ERR_BAD_MODULE,
189                        "Relocation targeting wrong execution state");
190
191   offset = grub_arm_jump24_get_offset (target);
192   offset += sym_addr;
193
194   if (!grub_arm_jump24_check_offset (offset))
195     return grub_error (GRUB_ERR_BAD_MODULE,
196                        "JUMP24 Relocation out of range.");
197
198
199   grub_arm_jump24_set_offset (target, offset);
200
201   return GRUB_ERR_NONE;
202 }
203
204 #endif
205
206 void
207 SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target,
208                                     int note, char **core_img, size_t *core_size,
209                                     Elf_Addr target_addr,
210                                     struct grub_mkimage_layout *layout)
211 {
212   char *elf_img;
213   size_t program_size;
214   Elf_Ehdr *ehdr;
215   Elf_Phdr *phdr;
216   Elf_Shdr *shdr;
217   int header_size, footer_size = 0;
218   int phnum = 1;
219   int shnum = 4;
220   int string_size = sizeof (".text") + sizeof ("mods") + 1;
221
222   if (image_target->id != IMAGE_LOONGSON_ELF)
223     phnum += 2;
224
225   if (note)
226     {
227       phnum++;
228       footer_size += sizeof (struct grub_ieee1275_note);
229     }
230   if (image_target->id == IMAGE_XEN)
231     {
232       phnum++;
233       shnum++;
234       string_size += sizeof (".xen");
235       footer_size += XEN_NOTE_SIZE;
236     }
237   header_size = ALIGN_UP (sizeof (*ehdr) + phnum * sizeof (*phdr)
238                           + shnum * sizeof (*shdr) + string_size, layout->align);
239
240   program_size = ALIGN_ADDR (*core_size);
241
242   elf_img = xmalloc (program_size + header_size + footer_size);
243   memset (elf_img, 0, program_size + header_size + footer_size);
244   memcpy (elf_img  + header_size, *core_img, *core_size);
245   ehdr = (void *) elf_img;
246   phdr = (void *) (elf_img + sizeof (*ehdr));
247   shdr = (void *) (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr));
248   memcpy (ehdr->e_ident, ELFMAG, SELFMAG);
249   ehdr->e_ident[EI_CLASS] = ELFCLASSXX;
250   if (!image_target->bigendian)
251     ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
252   else
253     ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
254   ehdr->e_ident[EI_VERSION] = EV_CURRENT;
255   ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
256   ehdr->e_type = grub_host_to_target16 (ET_EXEC);
257   ehdr->e_machine = grub_host_to_target16 (image_target->elf_target);
258   ehdr->e_version = grub_host_to_target32 (EV_CURRENT);
259
260   ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr);
261   ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr));
262   ehdr->e_phnum = grub_host_to_target16 (phnum);
263
264   ehdr->e_shoff = grub_host_to_target32 ((grub_uint8_t *) shdr
265                                          - (grub_uint8_t *) ehdr);
266   if (image_target->id == IMAGE_LOONGSON_ELF)
267     ehdr->e_shentsize = grub_host_to_target16 (0);
268   else
269     ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf_Shdr));
270   ehdr->e_shnum = grub_host_to_target16 (shnum);
271   ehdr->e_shstrndx = grub_host_to_target16 (1);
272
273   ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr));
274
275   phdr->p_type = grub_host_to_target32 (PT_LOAD);
276   phdr->p_offset = grub_host_to_target32 (header_size);
277   phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
278
279   ehdr->e_entry = grub_host_to_target32 (target_addr);
280   phdr->p_vaddr = grub_host_to_target32 (target_addr);
281   phdr->p_paddr = grub_host_to_target32 (target_addr);
282   phdr->p_align = grub_host_to_target32 (layout->align > image_target->link_align ?
283                                          layout->align : image_target->link_align);
284   if (image_target->id == IMAGE_LOONGSON_ELF)
285     ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER 
286                                            | EF_MIPS_PIC | EF_MIPS_CPIC);
287   else
288     ehdr->e_flags = 0;
289   if (image_target->id == IMAGE_LOONGSON_ELF)
290     {
291       phdr->p_filesz = grub_host_to_target32 (*core_size);
292       phdr->p_memsz = grub_host_to_target32 (*core_size);
293     }
294   else
295     {
296       grub_uint32_t target_addr_mods;
297       phdr->p_filesz = grub_host_to_target32 (layout->kernel_size);
298       if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM)
299         phdr->p_memsz = grub_host_to_target32 (layout->kernel_size);
300       else
301         phdr->p_memsz = grub_host_to_target32 (layout->kernel_size + layout->bss_size);
302
303       phdr++;
304       phdr->p_type = grub_host_to_target32 (PT_GNU_STACK);
305       phdr->p_offset = grub_host_to_target32 (header_size + layout->kernel_size);
306       phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0;
307       phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
308       phdr->p_align = grub_host_to_target32 (image_target->link_align);
309
310       phdr++;
311       phdr->p_type = grub_host_to_target32 (PT_LOAD);
312       phdr->p_offset = grub_host_to_target32 (header_size + layout->kernel_size);
313       phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
314       phdr->p_filesz = phdr->p_memsz
315         = grub_host_to_target32 (*core_size - layout->kernel_size);
316
317       if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_386)
318         target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
319       else if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM)
320         target_addr_mods = ALIGN_UP (target_addr + layout->end
321                                      + image_target->mod_gap,
322                                      image_target->mod_align);
323       else
324         target_addr_mods = ALIGN_UP (target_addr + layout->kernel_size + layout->bss_size
325                                      + image_target->mod_gap,
326                                      image_target->mod_align);
327       phdr->p_vaddr = grub_host_to_target_addr (target_addr_mods);
328       phdr->p_paddr = grub_host_to_target_addr (target_addr_mods);
329       phdr->p_align = grub_host_to_target32 (image_target->link_align);
330     }
331
332   if (image_target->id == IMAGE_XEN)
333     {
334       char *note_start = (elf_img + program_size + header_size);
335       Elf_Nhdr *note_ptr;
336       char *ptr = (char *) note_start;
337
338       grub_util_info ("adding XEN NOTE segment");
339
340       /* Guest OS.  */
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 (PACKAGE_NAME));
344       note_ptr->n_type = grub_host_to_target32 (6);
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, PACKAGE_NAME, sizeof (PACKAGE_NAME));
349       ptr += ALIGN_UP (sizeof (PACKAGE_NAME), 4);
350
351       /* Loader.  */
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 ("generic"));
355       note_ptr->n_type = grub_host_to_target32 (8);
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, "generic", sizeof ("generic"));
360       ptr += ALIGN_UP (sizeof ("generic"), 4);
361
362       /* Version.  */
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 (sizeof ("xen-3.0"));
366       note_ptr->n_type = grub_host_to_target32 (5);
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       memcpy (ptr, "xen-3.0", sizeof ("xen-3.0"));
371       ptr += ALIGN_UP (sizeof ("xen-3.0"), 4);
372
373       /* Entry.  */
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 (1);
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       /* Virt base.  */
385       note_ptr = (Elf_Nhdr *) ptr;
386       note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
387       note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof);
388       note_ptr->n_type = grub_host_to_target32 (3);
389       ptr += sizeof (Elf_Nhdr);
390       memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
391       ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
392       memset (ptr, 0, image_target->voidp_sizeof);
393       ptr += image_target->voidp_sizeof;
394
395       /* PAE.  */
396       if (image_target->elf_target == EM_386)
397         {
398           note_ptr = (Elf_Nhdr *) ptr;
399           note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
400           note_ptr->n_descsz = grub_host_to_target32 (sizeof ("yes,bimodal"));
401           note_ptr->n_type = grub_host_to_target32 (9);
402           ptr += sizeof (Elf_Nhdr);
403           memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
404           ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
405           memcpy (ptr, "yes", sizeof ("yes"));
406           ptr += ALIGN_UP (sizeof ("yes"), 4);
407         }
408
409       assert (XEN_NOTE_SIZE == (ptr - note_start));
410
411       phdr++;
412       phdr->p_type = grub_host_to_target32 (PT_NOTE);
413       phdr->p_flags = grub_host_to_target32 (PF_R);
414       phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
415       phdr->p_vaddr = 0;
416       phdr->p_paddr = 0;
417       phdr->p_filesz = grub_host_to_target32 (XEN_NOTE_SIZE);
418       phdr->p_memsz = 0;
419       phdr->p_offset = grub_host_to_target32 (header_size + program_size);
420     }
421
422   if (note)
423     {
424       int note_size = sizeof (struct grub_ieee1275_note);
425       struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *) 
426         (elf_img + program_size + header_size);
427
428       grub_util_info ("adding CHRP NOTE segment");
429
430       note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME));
431       note_ptr->header.n_descsz = grub_host_to_target32 (note_size);
432       note_ptr->header.n_type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE);
433       strcpy (note_ptr->name, GRUB_IEEE1275_NOTE_NAME);
434       note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff);
435       note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000);
436       note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff);
437       note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff);
438       note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff);
439       note_ptr->descriptor.load_base = grub_host_to_target32 (0x00004000);
440
441       phdr++;
442       phdr->p_type = grub_host_to_target32 (PT_NOTE);
443       phdr->p_flags = grub_host_to_target32 (PF_R);
444       phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
445       phdr->p_vaddr = 0;
446       phdr->p_paddr = 0;
447       phdr->p_filesz = grub_host_to_target32 (note_size);
448       phdr->p_memsz = 0;
449       phdr->p_offset = grub_host_to_target32 (header_size + program_size);
450     }
451
452   {
453     char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)
454                        + shnum * sizeof (*shdr));
455     char *ptr = str_start + 1;
456
457     shdr++;
458
459     shdr->sh_name = grub_host_to_target32 (0);
460     shdr->sh_type = grub_host_to_target32 (SHT_STRTAB);
461     shdr->sh_addr = grub_host_to_target_addr (0);
462     shdr->sh_offset = grub_host_to_target_addr (str_start - elf_img);
463     shdr->sh_size = grub_host_to_target32 (string_size);
464     shdr->sh_link = grub_host_to_target32 (0);
465     shdr->sh_info = grub_host_to_target32 (0);
466     shdr->sh_addralign = grub_host_to_target32 (layout->align);
467     shdr->sh_entsize = grub_host_to_target32 (0);
468     shdr++;
469
470     memcpy (ptr, ".text", sizeof (".text"));
471
472     shdr->sh_name = grub_host_to_target32 (ptr - str_start);
473     ptr += sizeof (".text");
474     shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
475     shdr->sh_addr = grub_host_to_target_addr (target_addr);
476     shdr->sh_offset = grub_host_to_target_addr (header_size);
477     shdr->sh_size = grub_host_to_target32 (layout->kernel_size);
478     shdr->sh_link = grub_host_to_target32 (0);
479     shdr->sh_info = grub_host_to_target32 (0);
480     shdr->sh_addralign = grub_host_to_target32 (layout->align);
481     shdr->sh_entsize = grub_host_to_target32 (0);
482     shdr++;
483
484     memcpy (ptr, "mods", sizeof ("mods"));
485     shdr->sh_name = grub_host_to_target32 (ptr - str_start);
486     ptr += sizeof ("mods");
487     shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
488     shdr->sh_addr = grub_host_to_target_addr (target_addr + layout->kernel_size);
489     shdr->sh_offset = grub_host_to_target_addr (header_size + layout->kernel_size);
490     shdr->sh_size = grub_host_to_target32 (*core_size - layout->kernel_size);
491     shdr->sh_link = grub_host_to_target32 (0);
492     shdr->sh_info = grub_host_to_target32 (0);
493     shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof);
494     shdr->sh_entsize = grub_host_to_target32 (0);
495     shdr++;
496
497     if (image_target->id == IMAGE_XEN)
498       {
499         memcpy (ptr, ".xen", sizeof (".xen"));
500         shdr->sh_name = grub_host_to_target32 (ptr - str_start);
501         ptr += sizeof (".xen");
502         shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
503         shdr->sh_addr = grub_host_to_target_addr (target_addr + layout->kernel_size);
504         shdr->sh_offset = grub_host_to_target_addr (program_size + header_size);
505         shdr->sh_size = grub_host_to_target32 (XEN_NOTE_SIZE);
506         shdr->sh_link = grub_host_to_target32 (0);
507         shdr->sh_info = grub_host_to_target32 (0);
508         shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof);
509         shdr->sh_entsize = grub_host_to_target32 (0);
510         shdr++;
511       }
512   }
513
514   free (*core_img);
515   *core_img = elf_img;
516   *core_size = program_size + header_size + footer_size;
517 }
518
519 /* Relocate symbols; note that this function overwrites the symbol table.
520    Return the address of a start symbol.  */
521 static Elf_Addr
522 SUFFIX (relocate_symbols) (Elf_Ehdr *e, struct section_metadata *smd,
523                            void *jumpers, Elf_Addr jumpers_addr,
524                            Elf_Addr bss_start, Elf_Addr end,
525                            const struct grub_install_image_target_desc *image_target)
526 {
527   Elf_Word symtab_size, sym_size, num_syms;
528   Elf_Off symtab_offset;
529   Elf_Addr start_address = (Elf_Addr) -1;
530   Elf_Sym *sym;
531   Elf_Word i;
532   Elf_Shdr *symtab_section;
533   const char *symtab;
534   grub_uint64_t *jptr = jumpers;
535
536   symtab_section = (Elf_Shdr *) ((char *) smd->sections
537                                  + grub_target_to_host32 (smd->symtab->sh_link)
538                                    * smd->section_entsize);
539   symtab = (char *) e + grub_target_to_host (symtab_section->sh_offset);
540
541   symtab_size = grub_target_to_host (smd->symtab->sh_size);
542   sym_size = grub_target_to_host (smd->symtab->sh_entsize);
543   symtab_offset = grub_target_to_host (smd->symtab->sh_offset);
544   num_syms = symtab_size / sym_size;
545
546   for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
547        i < num_syms;
548        i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
549     {
550       Elf_Section cur_index;
551       const char *name;
552
553       name = symtab + grub_target_to_host32 (sym->st_name);
554
555       cur_index = grub_target_to_host16 (sym->st_shndx);
556       if (cur_index == STN_ABS)
557         {
558           continue;
559         }
560       else if (cur_index == STN_UNDEF)
561         {
562           if (sym->st_name && grub_strcmp (name, "__bss_start") == 0)
563             sym->st_value = bss_start;
564           else if (sym->st_name && grub_strcmp (name, "_end") == 0)
565             sym->st_value = end;
566           else if (sym->st_name)
567             grub_util_error ("undefined symbol %s", name);
568           else
569             continue;
570         }
571       else if (cur_index >= smd->num_sections)
572         grub_util_error ("section %d does not exist", cur_index);
573       else
574         {
575           sym->st_value = (grub_target_to_host (sym->st_value)
576                            + smd->vaddrs[cur_index]);
577         }
578
579       if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info)
580           == STT_FUNC)
581         {
582           *jptr = grub_host_to_target64 (sym->st_value);
583           sym->st_value = (char *) jptr - (char *) jumpers + jumpers_addr;
584           jptr++;
585           *jptr = 0;
586           jptr++;
587         }
588       grub_util_info ("locating %s at 0x%"  GRUB_HOST_PRIxLONG_LONG
589                       " (0x%"  GRUB_HOST_PRIxLONG_LONG ")", name,
590                       (unsigned long long) sym->st_value,
591                       (unsigned long long) smd->vaddrs[cur_index]);
592
593       if (start_address == (Elf_Addr)-1)
594         if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0)
595           start_address = sym->st_value;
596     }
597
598   return start_address;
599 }
600
601 /* Return the address of a symbol at the index I in the section S.  */
602 static Elf_Addr
603 SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i,
604                              const struct grub_install_image_target_desc *image_target)
605 {
606   Elf_Sym *sym;
607
608   sym = (Elf_Sym *) ((char *) e
609                        + grub_target_to_host (s->sh_offset)
610                        + i * grub_target_to_host (s->sh_entsize));
611   return sym->st_value;
612 }
613
614 /* Return the address of a modified value.  */
615 static Elf_Addr *
616 SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset,
617                     const struct grub_install_image_target_desc *image_target)
618 {
619   return (Elf_Addr *) ((char *) e + grub_target_to_host (s->sh_offset) + offset);
620 }
621
622 #ifdef MKIMAGE_ELF64
623 static Elf_Addr
624 SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section,
625                       const struct grub_install_image_target_desc *image_target)
626 {
627   Elf_Word symtab_size, sym_size, num_syms;
628   Elf_Off symtab_offset;
629   Elf_Sym *sym;
630   Elf_Word i;
631   int ret = 0;
632
633   symtab_size = grub_target_to_host (symtab_section->sh_size);
634   sym_size = grub_target_to_host (symtab_section->sh_entsize);
635   symtab_offset = grub_target_to_host (symtab_section->sh_offset);
636   num_syms = symtab_size / sym_size;
637
638   for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
639        i < num_syms;
640        i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
641     if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
642       ret++;
643
644   return ret;
645 }
646 #endif
647
648 #ifdef MKIMAGE_ELF32
649 /* Deal with relocation information. This function relocates addresses
650    within the virtual address space starting from 0. So only relative
651    addresses can be fully resolved. Absolute addresses must be relocated
652    again by a PE32 relocator when loaded.  */
653 static grub_size_t
654 arm_get_trampoline_size (Elf_Ehdr *e,
655                          Elf_Shdr *sections,
656                          Elf_Half section_entsize,
657                          Elf_Half num_sections,
658                          const struct grub_install_image_target_desc *image_target)
659 {
660   Elf_Half i;
661   Elf_Shdr *s;
662   grub_size_t ret = 0;
663
664   for (i = 0, s = sections;
665        i < num_sections;
666        i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
667     if ((s->sh_type == grub_host_to_target32 (SHT_REL)) ||
668         (s->sh_type == grub_host_to_target32 (SHT_RELA)))
669       {
670         Elf_Rela *r;
671         Elf_Word rtab_size, r_size, num_rs;
672         Elf_Off rtab_offset;
673         Elf_Shdr *symtab_section;
674         Elf_Word j;
675
676         symtab_section = (Elf_Shdr *) ((char *) sections
677                                          + (grub_target_to_host32 (s->sh_link)
678                                             * section_entsize));
679
680         rtab_size = grub_target_to_host (s->sh_size);
681         r_size = grub_target_to_host (s->sh_entsize);
682         rtab_offset = grub_target_to_host (s->sh_offset);
683         num_rs = rtab_size / r_size;
684
685         for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset);
686              j < num_rs;
687              j++, r = (Elf_Rela *) ((char *) r + r_size))
688           {
689             Elf_Addr info;
690             Elf_Addr sym_addr;
691
692             info = grub_target_to_host (r->r_info);
693             sym_addr = SUFFIX (get_symbol_address) (e, symtab_section,
694                                                     ELF_R_SYM (info), image_target);
695
696             sym_addr += (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
697               grub_target_to_host (r->r_addend) : 0;
698
699             switch (ELF_R_TYPE (info))
700               {
701               case R_ARM_ABS32:
702               case R_ARM_V4BX:
703                 break;
704               case R_ARM_THM_CALL:
705               case R_ARM_THM_JUMP24:
706               case R_ARM_THM_JUMP19:
707                 if (!(sym_addr & 1))
708                   ret += 8;
709                 break;
710
711               case R_ARM_CALL:
712               case R_ARM_JUMP24:
713                 if (sym_addr & 1)
714                   ret += 16;
715                 break;
716
717               default:
718                 grub_util_error (_("relocation 0x%x is not implemented yet"),
719                                  (unsigned int) ELF_R_TYPE (info));
720                 break;
721               }
722           }
723       }
724   return ret;
725 }
726 #endif
727
728 /* Deal with relocation information. This function relocates addresses
729    within the virtual address space starting from 0. So only relative
730    addresses can be fully resolved. Absolute addresses must be relocated
731    again by a PE32 relocator when loaded.  */
732 static void
733 SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd,
734                              char *pe_target, Elf_Addr tramp_off, Elf_Addr got_off,
735                              const struct grub_install_image_target_desc *image_target)
736 {
737   Elf_Half i;
738   Elf_Shdr *s;
739 #ifdef MKIMAGE_ELF64
740   struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off);
741   grub_uint64_t *gpptr = (void *) (pe_target + got_off);
742   unsigned unmatched_adr_got_page = 0;
743 #define MASK19 ((1 << 19) - 1)
744 #else
745   grub_uint32_t *tr = (void *) (pe_target + tramp_off);
746 #endif
747
748   for (i = 0, s = smd->sections;
749        i < smd->num_sections;
750        i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
751     if ((s->sh_type == grub_host_to_target32 (SHT_REL)) ||
752         (s->sh_type == grub_host_to_target32 (SHT_RELA)))
753       {
754         Elf_Rela *r;
755         Elf_Word rtab_size, r_size, num_rs;
756         Elf_Off rtab_offset;
757         Elf_Word target_section_index;
758         Elf_Addr target_section_addr;
759         Elf_Shdr *target_section;
760         Elf_Word j;
761
762         target_section_index = grub_target_to_host32 (s->sh_info);
763         target_section_addr = smd->addrs[target_section_index];
764         target_section = (Elf_Shdr *) ((char *) smd->sections
765                                          + (target_section_index
766                                             * smd->section_entsize));
767
768         grub_util_info ("dealing with the relocation section %s for %s",
769                         smd->strtab + grub_target_to_host32 (s->sh_name),
770                         smd->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, smd->symtab,
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 (smd->symtab->sh_offset)
923                                        + ELF_R_SYM (info) * grub_target_to_host (smd->symtab->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 (smd->symtab->sh_offset)
1109                                           + ELF_R_SYM (info) * grub_target_to_host (smd->symtab->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                     struct section_metadata *smd,
1648                     const struct grub_install_image_target_desc *image_target)
1649 {
1650   unsigned i;
1651   Elf_Shdr *s;
1652   struct translate_context ctx;
1653
1654   translate_reloc_start (&ctx, image_target);
1655
1656   for (i = 0, s = smd->sections; i < smd->num_sections;
1657        i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
1658     if ((grub_target_to_host32 (s->sh_type) == SHT_REL) ||
1659         (grub_target_to_host32 (s->sh_type) == SHT_RELA))
1660       {
1661         Elf_Rel *r;
1662         Elf_Word rtab_size, r_size, num_rs;
1663         Elf_Off rtab_offset;
1664         Elf_Addr section_address;
1665         Elf_Word j;
1666
1667         grub_util_info ("translating the relocation section %s",
1668                         smd->strtab + grub_le_to_cpu32 (s->sh_name));
1669
1670         rtab_size = grub_target_to_host (s->sh_size);
1671         r_size = grub_target_to_host (s->sh_entsize);
1672         rtab_offset = grub_target_to_host (s->sh_offset);
1673         num_rs = rtab_size / r_size;
1674
1675         section_address = smd->vaddrs[grub_le_to_cpu32 (s->sh_info)];
1676
1677         for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset);
1678              j < num_rs;
1679              j++, r = (Elf_Rel *) ((char *) r + r_size))
1680           {
1681             Elf_Addr info;
1682             Elf_Addr offset;
1683             Elf_Addr addr;
1684
1685             offset = grub_target_to_host (r->r_offset);
1686             info = grub_target_to_host (r->r_info);
1687
1688             addr = section_address + offset;
1689
1690             translate_relocation (&ctx, addr, info, image_target);
1691           }
1692       }
1693
1694   if (image_target->elf_target == EM_IA_64)
1695     create_u64_fixups (&ctx,
1696                        layout->ia64jmp_off
1697                        + image_target->vaddr_offset,
1698                        2 * layout->ia64jmpnum,
1699                        image_target);
1700   if (image_target->elf_target == EM_IA_64 || image_target->elf_target == EM_AARCH64)
1701     create_u64_fixups (&ctx,
1702                        layout->got_off
1703                        + image_target->vaddr_offset,
1704                        (layout->got_size / 8),
1705                        image_target);
1706
1707   finish_reloc_translation (&ctx, layout, image_target);
1708 }
1709
1710 /* Determine if this section is a text section. Return false if this
1711    section is not allocated.  */
1712 static int
1713 SUFFIX (is_text_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
1714 {
1715   if (!is_relocatable (image_target)
1716       && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
1717     return 0;
1718   return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
1719           == (SHF_EXECINSTR | SHF_ALLOC));
1720 }
1721
1722 /* Determine if this section is a data section.  */
1723 static int
1724 SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
1725 {
1726   if (!is_relocatable (image_target) 
1727       && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
1728     return 0;
1729   return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
1730           == SHF_ALLOC) && !(grub_target_to_host32 (s->sh_type) == SHT_NOBITS);
1731 }
1732
1733 static int
1734 SUFFIX (is_bss_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
1735 {
1736   if (!is_relocatable (image_target))
1737     return 0;
1738   return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
1739           == SHF_ALLOC) && (grub_target_to_host32 (s->sh_type) == SHT_NOBITS);
1740 }
1741
1742 /* Return if the ELF header is valid.  */
1743 static int
1744 SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_image_target_desc *image_target)
1745 {
1746   if (size < sizeof (*e)
1747       || e->e_ident[EI_MAG0] != ELFMAG0
1748       || e->e_ident[EI_MAG1] != ELFMAG1
1749       || e->e_ident[EI_MAG2] != ELFMAG2
1750       || e->e_ident[EI_MAG3] != ELFMAG3
1751       || e->e_ident[EI_VERSION] != EV_CURRENT
1752       || e->e_ident[EI_CLASS] != ELFCLASSXX
1753       || e->e_version != grub_host_to_target32 (EV_CURRENT))
1754     return 0;
1755
1756   return 1;
1757 }
1758
1759 static Elf_Addr
1760 SUFFIX (put_section) (Elf_Shdr *s, int i,
1761                       Elf_Addr current_address,
1762                       struct section_metadata *smd,
1763                       const struct grub_install_image_target_desc *image_target)
1764 {
1765         Elf_Word align = grub_host_to_target_addr (s->sh_addralign);
1766         const char *name = smd->strtab + grub_host_to_target32 (s->sh_name);
1767
1768         if (align)
1769           current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1770                                       align)
1771             - image_target->vaddr_offset;
1772
1773         grub_util_info ("locating the section %s at 0x%"
1774                         GRUB_HOST_PRIxLONG_LONG,
1775                         name, (unsigned long long) current_address);
1776         if (!is_relocatable (image_target))
1777           current_address = grub_host_to_target_addr (s->sh_addr)
1778                             - image_target->link_addr;
1779         smd->addrs[i] = current_address;
1780         current_address += grub_host_to_target_addr (s->sh_size);
1781         return current_address;
1782 }
1783
1784 /*
1785  * Locate section addresses by merging code sections and data sections
1786  * into .text and .data, respectively.
1787  */
1788 static void
1789 SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path,
1790                           struct section_metadata *smd,
1791                           struct grub_mkimage_layout *layout,
1792                           const struct grub_install_image_target_desc *image_target)
1793 {
1794   int i;
1795   Elf_Shdr *s;
1796
1797   layout->align = 1;
1798   /* Page-aligning simplifies relocation handling.  */
1799   if (image_target->elf_target == EM_AARCH64)
1800     layout->align = 4096;
1801
1802   layout->kernel_size = 0;
1803
1804   for (i = 0, s = smd->sections;
1805        i < smd->num_sections;
1806        i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
1807     if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC)
1808         && grub_host_to_target32 (s->sh_addralign) > layout->align)
1809       layout->align = grub_host_to_target32 (s->sh_addralign);
1810
1811   /* .text */
1812   for (i = 0, s = smd->sections;
1813        i < smd->num_sections;
1814        i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
1815     if (SUFFIX (is_text_section) (s, image_target))
1816       {
1817         layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size,
1818                                                 smd, image_target);
1819         if (!is_relocatable (image_target) &&
1820             grub_host_to_target_addr (s->sh_addr) != image_target->link_addr)
1821           {
1822             char *msg
1823               = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx"
1824                                   " instead of 0x%llx: ld.gold bug?"),
1825                                 kernel_path,
1826                                 (unsigned long long) grub_host_to_target_addr (s->sh_addr),
1827                                 (unsigned long long) image_target->link_addr);
1828             grub_util_error ("%s", msg);
1829           }
1830       }
1831
1832   layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset,
1833                               image_target->section_align)
1834     - image_target->vaddr_offset;
1835   layout->exec_size = layout->kernel_size;
1836
1837   /* .data */
1838   for (i = 0, s = smd->sections;
1839        i < smd->num_sections;
1840        i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
1841     if (SUFFIX (is_data_section) (s, image_target))
1842       layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size, smd,
1843                                                   image_target);
1844
1845 #ifdef MKIMAGE_ELF32
1846   if (image_target->elf_target == EM_ARM)
1847     {
1848       grub_size_t tramp;
1849       layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset,
1850                                       image_target->section_align) - image_target->vaddr_offset;
1851
1852       layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
1853
1854       tramp = arm_get_trampoline_size (e, smd->sections, smd->section_entsize,
1855                                        smd->num_sections, image_target);
1856
1857       layout->tramp_off = layout->kernel_size;
1858       layout->kernel_size += ALIGN_UP (tramp, 16);
1859     }
1860 #endif
1861
1862   layout->bss_start = layout->kernel_size;
1863   layout->end = layout->kernel_size;
1864   
1865   /* .bss */
1866   for (i = 0, s = smd->sections;
1867        i < smd->num_sections;
1868        i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
1869     {
1870       if (SUFFIX (is_bss_section) (s, image_target))
1871         layout->end = SUFFIX (put_section) (s, i, layout->end, smd, image_target);
1872
1873       /*
1874        * This must to be in the last time this function passes through the loop.
1875        */
1876       smd->vaddrs[i] = smd->addrs[i] + image_target->vaddr_offset;
1877     }
1878
1879   layout->end = ALIGN_UP (layout->end + image_target->vaddr_offset,
1880                               image_target->section_align) - image_target->vaddr_offset;
1881   /* Explicitly initialize BSS
1882      when producing PE32 to avoid a bug in EFI implementations.
1883      Platforms other than EFI and U-boot shouldn't have .bss in
1884      their binaries as we build with -Wl,-Ttext.
1885   */
1886   if (image_target->id == IMAGE_EFI || !is_relocatable (image_target))
1887     layout->kernel_size = layout->end;
1888 }
1889
1890 char *
1891 SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
1892                                   size_t total_module_size,
1893                                   struct grub_mkimage_layout *layout,
1894                                   const struct grub_install_image_target_desc *image_target)
1895 {
1896   char *kernel_img, *out_img;
1897   struct section_metadata smd = { 0, };
1898   Elf_Ehdr *e;
1899   int i;
1900   Elf_Shdr *s;
1901   Elf_Off section_offset;
1902   grub_size_t kernel_size;
1903
1904   grub_memset (layout, 0, sizeof (*layout));
1905
1906   layout->start_address = 0;
1907
1908   kernel_size = grub_util_get_image_size (kernel_path);
1909   kernel_img = xmalloc (kernel_size);
1910   grub_util_load_image (kernel_path, kernel_img);
1911
1912   e = (Elf_Ehdr *) kernel_img;
1913   if (! SUFFIX (check_elf_header) (e, kernel_size, image_target))
1914     grub_util_error ("invalid ELF header");
1915
1916   section_offset = grub_target_to_host (e->e_shoff);
1917   smd.section_entsize = grub_target_to_host16 (e->e_shentsize);
1918   smd.num_sections = grub_target_to_host16 (e->e_shnum);
1919
1920   if (kernel_size < section_offset
1921                     + (grub_uint32_t) smd.section_entsize * smd.num_sections)
1922     grub_util_error (_("premature end of file %s"), kernel_path);
1923
1924   smd.sections = (Elf_Shdr *) (kernel_img + section_offset);
1925
1926   /* Relocate sections then symbols in the virtual address space.  */
1927   s = (Elf_Shdr *) ((char *) smd.sections
1928                       + grub_host_to_target16 (e->e_shstrndx) * smd.section_entsize);
1929   smd.strtab = (char *) e + grub_host_to_target_addr (s->sh_offset);
1930
1931   smd.addrs = xmalloc (sizeof (*smd.addrs) * smd.num_sections);
1932   memset (smd.addrs, 0, sizeof (*smd.addrs) * smd.num_sections);
1933   smd.vaddrs = xmalloc (sizeof (*smd.vaddrs) * smd.num_sections);
1934   memset (smd.vaddrs, 0, sizeof (*smd.vaddrs) * smd.num_sections);
1935
1936   SUFFIX (locate_sections) (e, kernel_path, &smd, layout, image_target);
1937
1938   if (!is_relocatable (image_target))
1939     {
1940       Elf_Addr current_address = layout->kernel_size;
1941
1942       for (i = 0, s = smd.sections;
1943            i < smd.num_sections;
1944            i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize))
1945         if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
1946           {
1947             Elf_Word sec_align = grub_host_to_target_addr (s->sh_addralign);
1948             const char *name = smd.strtab + grub_host_to_target32 (s->sh_name);
1949
1950             if (sec_align)
1951               current_address = ALIGN_UP (current_address
1952                                           + image_target->vaddr_offset,
1953                                           sec_align)
1954                 - image_target->vaddr_offset;
1955
1956             grub_util_info ("locating the section %s at 0x%"
1957                             GRUB_HOST_PRIxLONG_LONG,
1958                             name, (unsigned long long) current_address);
1959             if (!is_relocatable (image_target))
1960               current_address = grub_host_to_target_addr (s->sh_addr)
1961                 - image_target->link_addr;
1962
1963             smd.vaddrs[i] = current_address
1964               + image_target->vaddr_offset;
1965             current_address += grub_host_to_target_addr (s->sh_size);
1966           }
1967       current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1968                                   image_target->section_align)
1969         - image_target->vaddr_offset;
1970       layout->bss_size = current_address - layout->kernel_size;
1971     }
1972   else
1973     layout->bss_size = 0;
1974
1975   if (image_target->id == IMAGE_SPARC64_AOUT
1976       || image_target->id == IMAGE_SPARC64_RAW
1977       || image_target->id == IMAGE_UBOOT
1978       || image_target->id == IMAGE_COREBOOT
1979       || image_target->id == IMAGE_SPARC64_CDCORE)
1980     layout->kernel_size = ALIGN_UP (layout->kernel_size, image_target->mod_align);
1981
1982   if (is_relocatable (image_target))
1983     {
1984       smd.symtab = NULL;
1985       for (i = 0, s = smd.sections;
1986            i < smd.num_sections;
1987            i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize))
1988         if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB))
1989           {
1990             smd.symtab = s;
1991             break;
1992           }
1993       if (! smd.symtab)
1994         grub_util_error ("%s", _("no symbol table"));
1995 #ifdef MKIMAGE_ELF64
1996       if (image_target->elf_target == EM_IA_64)
1997         {
1998           grub_size_t tramp;
1999
2000           layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
2001
2002           grub_ia64_dl_get_tramp_got_size (e, &tramp, &layout->got_size);
2003
2004           layout->tramp_off = layout->kernel_size;
2005           layout->kernel_size += ALIGN_UP (tramp, 16);
2006
2007           layout->ia64jmp_off = layout->kernel_size;
2008           layout->ia64jmpnum = SUFFIX (count_funcs) (e, smd.symtab,
2009                                                      image_target);
2010           layout->kernel_size += 16 * layout->ia64jmpnum;
2011
2012           layout->got_off = layout->kernel_size;
2013           layout->kernel_size += ALIGN_UP (layout->got_size, 16);
2014         }
2015       if (image_target->elf_target == EM_AARCH64)
2016         {
2017           grub_size_t tramp;
2018
2019           layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
2020
2021           grub_arm64_dl_get_tramp_got_size (e, &tramp, &layout->got_size);
2022
2023           layout->got_off = layout->kernel_size;
2024           layout->kernel_size += ALIGN_UP (layout->got_size, 16);
2025         }
2026 #endif
2027     }
2028   else
2029     {
2030       layout->reloc_size = 0;
2031       layout->reloc_section = NULL;
2032     }
2033
2034   out_img = xmalloc (layout->kernel_size + total_module_size);
2035   memset (out_img, 0, layout->kernel_size + total_module_size);
2036
2037   if (is_relocatable (image_target))
2038     {
2039       layout->start_address = SUFFIX (relocate_symbols) (e, &smd,
2040                                   (char *) out_img + layout->ia64jmp_off,
2041                                   layout->ia64jmp_off + image_target->vaddr_offset,
2042                                   layout->bss_start, layout->end, image_target);
2043
2044       if (layout->start_address == (Elf_Addr) -1)
2045         grub_util_error ("start symbol is not defined");
2046
2047       /* Resolve addrs in the virtual address space.  */
2048       SUFFIX (relocate_addrs) (e, &smd, out_img, layout->tramp_off,
2049                                    layout->got_off, image_target);
2050
2051       make_reloc_section (e, layout, &smd, image_target);
2052       if (image_target->id != IMAGE_EFI)
2053         {
2054           out_img = xrealloc (out_img, layout->kernel_size + total_module_size
2055                               + ALIGN_UP (layout->reloc_size, image_target->mod_align));
2056           memcpy (out_img + layout->kernel_size, layout->reloc_section, layout->reloc_size);
2057           memset (out_img + layout->kernel_size + layout->reloc_size, 0,
2058                   total_module_size + ALIGN_UP (layout->reloc_size, image_target->mod_align) - layout->reloc_size);
2059           layout->kernel_size += ALIGN_UP (layout->reloc_size, image_target->mod_align);
2060         }
2061     }
2062
2063   for (i = 0, s = smd.sections;
2064        i < smd.num_sections;
2065        i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize))
2066     if (SUFFIX (is_data_section) (s, image_target)
2067         /* Explicitly initialize BSS
2068            when producing PE32 to avoid a bug in EFI implementations.
2069            Platforms other than EFI and U-boot shouldn't have .bss in
2070            their binaries as we build with -Wl,-Ttext.
2071         */
2072         || (SUFFIX (is_bss_section) (s, image_target) && (image_target->id == IMAGE_EFI || !is_relocatable (image_target)))
2073         || SUFFIX (is_text_section) (s, image_target))
2074       {
2075         if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
2076           memset (out_img + smd.addrs[i], 0,
2077                   grub_host_to_target_addr (s->sh_size));
2078         else
2079           memcpy (out_img + smd.addrs[i],
2080                   kernel_img + grub_host_to_target_addr (s->sh_offset),
2081                   grub_host_to_target_addr (s->sh_size));
2082       }
2083   free (kernel_img);
2084
2085   free (smd.vaddrs);
2086   smd.vaddrs = NULL;
2087   free (smd.addrs);
2088   smd.addrs = NULL;
2089
2090   return out_img;
2091 }