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