Fix cross compilation (e.g. on Darwin). Following changes to make.tmpl,
[AROS.git] / arch / all-pc / boot / grub2-aros / util / grub-mkimagexx.c
blob3c76d0708cbe6d7047645fe20c85c3770391299b
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.
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.
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.
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/>.
20 #undef ELF_R_SYM
21 #undef ELF_R_TYPE
23 #if defined(MKIMAGE_ELF32)
24 # define SUFFIX(x) x ## 32
25 # define ELFCLASSXX ELFCLASS32
26 # define Elf_Ehdr Elf32_Ehdr
27 # define Elf_Phdr Elf32_Phdr
28 # define Elf_Nhdr Elf32_Nhdr
29 # define Elf_Addr Elf32_Addr
30 # define Elf_Sym Elf32_Sym
31 # define Elf_Off Elf32_Off
32 # define Elf_Shdr Elf32_Shdr
33 # define Elf_Rela Elf32_Rela
34 # define Elf_Rel Elf32_Rel
35 # define Elf_Word Elf32_Word
36 # define Elf_Half Elf32_Half
37 # define Elf_Section Elf32_Section
38 # define ELF_R_SYM(val) ELF32_R_SYM(val)
39 # define ELF_R_TYPE(val) ELF32_R_TYPE(val)
40 # define ELF_ST_TYPE(val) ELF32_ST_TYPE(val)
41 #define XEN_NOTE_SIZE 132
42 #elif defined(MKIMAGE_ELF64)
43 # define SUFFIX(x) x ## 64
44 # define ELFCLASSXX ELFCLASS64
45 # define Elf_Ehdr Elf64_Ehdr
46 # define Elf_Phdr Elf64_Phdr
47 # define Elf_Nhdr Elf64_Nhdr
48 # define Elf_Addr Elf64_Addr
49 # define Elf_Sym Elf64_Sym
50 # define Elf_Off Elf64_Off
51 # define Elf_Shdr Elf64_Shdr
52 # define Elf_Rela Elf64_Rela
53 # define Elf_Rel Elf64_Rel
54 # define Elf_Word Elf64_Word
55 # define Elf_Half Elf64_Half
56 # define Elf_Section Elf64_Section
57 # define ELF_R_SYM(val) ELF64_R_SYM(val)
58 # define ELF_R_TYPE(val) ELF64_R_TYPE(val)
59 # define ELF_ST_TYPE(val) ELF64_ST_TYPE(val)
60 #define XEN_NOTE_SIZE 120
61 #else
62 #error "I'm confused"
63 #endif
65 static Elf_Addr SUFFIX (entry_point);
67 static void
68 SUFFIX (generate_elf) (const struct grub_install_image_target_desc *image_target,
69 int note, char **core_img, size_t *core_size,
70 Elf_Addr target_addr, grub_size_t align,
71 size_t kernel_size, size_t bss_size)
73 char *elf_img;
74 size_t program_size;
75 Elf_Ehdr *ehdr;
76 Elf_Phdr *phdr;
77 Elf_Shdr *shdr;
78 int header_size, footer_size = 0;
79 int phnum = 1;
80 int shnum = 4;
81 int string_size = sizeof (".text") + sizeof ("mods") + 1;
83 if (image_target->id != IMAGE_LOONGSON_ELF)
84 phnum += 2;
86 if (note)
88 phnum++;
89 footer_size += sizeof (struct grub_ieee1275_note);
91 if (image_target->id == IMAGE_XEN)
93 phnum++;
94 shnum++;
95 string_size += sizeof (".xen");
96 footer_size += XEN_NOTE_SIZE;
98 header_size = ALIGN_UP (sizeof (*ehdr) + phnum * sizeof (*phdr)
99 + shnum * sizeof (*shdr) + string_size, align);
101 program_size = ALIGN_ADDR (*core_size);
103 elf_img = xmalloc (program_size + header_size + footer_size);
104 memset (elf_img, 0, program_size + header_size);
105 memcpy (elf_img + header_size, *core_img, *core_size);
106 ehdr = (void *) elf_img;
107 phdr = (void *) (elf_img + sizeof (*ehdr));
108 shdr = (void *) (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr));
109 memcpy (ehdr->e_ident, ELFMAG, SELFMAG);
110 ehdr->e_ident[EI_CLASS] = ELFCLASSXX;
111 if (!image_target->bigendian)
112 ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
113 else
114 ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
115 ehdr->e_ident[EI_VERSION] = EV_CURRENT;
116 ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
117 ehdr->e_type = grub_host_to_target16 (ET_EXEC);
118 ehdr->e_machine = grub_host_to_target16 (image_target->elf_target);
119 ehdr->e_version = grub_host_to_target32 (EV_CURRENT);
121 ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr);
122 ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr));
123 ehdr->e_phnum = grub_host_to_target16 (phnum);
125 ehdr->e_shoff = grub_host_to_target32 ((grub_uint8_t *) shdr
126 - (grub_uint8_t *) ehdr);
127 if (image_target->id == IMAGE_LOONGSON_ELF)
128 ehdr->e_shentsize = grub_host_to_target16 (0);
129 else
130 ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf_Shdr));
131 ehdr->e_shnum = grub_host_to_target16 (shnum);
132 ehdr->e_shstrndx = grub_host_to_target16 (1);
134 ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr));
136 phdr->p_type = grub_host_to_target32 (PT_LOAD);
137 phdr->p_offset = grub_host_to_target32 (header_size);
138 phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
140 ehdr->e_entry = grub_host_to_target32 (target_addr);
141 phdr->p_vaddr = grub_host_to_target32 (target_addr);
142 phdr->p_paddr = grub_host_to_target32 (target_addr);
143 phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align);
144 if (image_target->id == IMAGE_LOONGSON_ELF)
145 ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER
146 | EF_MIPS_PIC | EF_MIPS_CPIC);
147 else
148 ehdr->e_flags = 0;
149 if (image_target->id == IMAGE_LOONGSON_ELF)
151 phdr->p_filesz = grub_host_to_target32 (*core_size);
152 phdr->p_memsz = grub_host_to_target32 (*core_size);
154 else
156 grub_uint32_t target_addr_mods;
157 phdr->p_filesz = grub_host_to_target32 (kernel_size);
158 phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size);
160 phdr++;
161 phdr->p_type = grub_host_to_target32 (PT_GNU_STACK);
162 phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
163 phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0;
164 phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
165 phdr->p_align = grub_host_to_target32 (image_target->link_align);
167 phdr++;
168 phdr->p_type = grub_host_to_target32 (PT_LOAD);
169 phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
170 phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
171 phdr->p_filesz = phdr->p_memsz
172 = grub_host_to_target32 (*core_size - kernel_size);
174 if (image_target->id == IMAGE_COREBOOT)
175 target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
176 else
177 target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size
178 + image_target->mod_gap,
179 image_target->mod_align);
180 phdr->p_vaddr = grub_host_to_target_addr (target_addr_mods);
181 phdr->p_paddr = grub_host_to_target_addr (target_addr_mods);
182 phdr->p_align = grub_host_to_target32 (image_target->link_align);
185 if (image_target->id == IMAGE_XEN)
187 char *note_start = (elf_img + program_size + header_size);
188 Elf_Nhdr *note_ptr;
189 char *ptr = (char *) note_start;
191 grub_util_info ("adding XEN NOTE segment");
193 /* Guest OS. */
194 note_ptr = (Elf_Nhdr *) ptr;
195 note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
196 note_ptr->n_descsz = grub_host_to_target32 (sizeof (PACKAGE_NAME));
197 note_ptr->n_type = grub_host_to_target32 (6);
198 ptr += sizeof (Elf_Nhdr);
199 memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
200 ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
201 memcpy (ptr, PACKAGE_NAME, sizeof (PACKAGE_NAME));
202 ptr += ALIGN_UP (sizeof (PACKAGE_NAME), 4);
204 /* Loader. */
205 note_ptr = (Elf_Nhdr *) ptr;
206 note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
207 note_ptr->n_descsz = grub_host_to_target32 (sizeof ("generic"));
208 note_ptr->n_type = grub_host_to_target32 (8);
209 ptr += sizeof (Elf_Nhdr);
210 memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
211 ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
212 memcpy (ptr, "generic", sizeof ("generic"));
213 ptr += ALIGN_UP (sizeof ("generic"), 4);
215 /* Version. */
216 note_ptr = (Elf_Nhdr *) ptr;
217 note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
218 note_ptr->n_descsz = grub_host_to_target32 (sizeof ("xen-3.0"));
219 note_ptr->n_type = grub_host_to_target32 (5);
220 ptr += sizeof (Elf_Nhdr);
221 memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
222 ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
223 memcpy (ptr, "xen-3.0", sizeof ("xen-3.0"));
224 ptr += ALIGN_UP (sizeof ("xen-3.0"), 4);
226 /* Entry. */
227 note_ptr = (Elf_Nhdr *) ptr;
228 note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
229 note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof);
230 note_ptr->n_type = grub_host_to_target32 (1);
231 ptr += sizeof (Elf_Nhdr);
232 memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
233 ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
234 memset (ptr, 0, image_target->voidp_sizeof);
235 ptr += image_target->voidp_sizeof;
237 /* Virt base. */
238 note_ptr = (Elf_Nhdr *) ptr;
239 note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
240 note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof);
241 note_ptr->n_type = grub_host_to_target32 (3);
242 ptr += sizeof (Elf_Nhdr);
243 memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
244 ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
245 memset (ptr, 0, image_target->voidp_sizeof);
246 ptr += image_target->voidp_sizeof;
248 /* PAE. */
249 if (image_target->elf_target == EM_386)
251 note_ptr = (Elf_Nhdr *) ptr;
252 note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
253 note_ptr->n_descsz = grub_host_to_target32 (sizeof ("yes,bimodal"));
254 note_ptr->n_type = grub_host_to_target32 (9);
255 ptr += sizeof (Elf_Nhdr);
256 memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
257 ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
258 memcpy (ptr, "yes", sizeof ("yes"));
259 ptr += ALIGN_UP (sizeof ("yes"), 4);
262 assert (XEN_NOTE_SIZE == (ptr - note_start));
264 phdr++;
265 phdr->p_type = grub_host_to_target32 (PT_NOTE);
266 phdr->p_flags = grub_host_to_target32 (PF_R);
267 phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
268 phdr->p_vaddr = 0;
269 phdr->p_paddr = 0;
270 phdr->p_filesz = grub_host_to_target32 (XEN_NOTE_SIZE);
271 phdr->p_memsz = 0;
272 phdr->p_offset = grub_host_to_target32 (header_size + program_size);
275 if (note)
277 int note_size = sizeof (struct grub_ieee1275_note);
278 struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *)
279 (elf_img + program_size + header_size);
281 grub_util_info ("adding CHRP NOTE segment");
283 note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME));
284 note_ptr->header.n_descsz = grub_host_to_target32 (note_size);
285 note_ptr->header.n_type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE);
286 strcpy (note_ptr->name, GRUB_IEEE1275_NOTE_NAME);
287 note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff);
288 note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000);
289 note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff);
290 note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff);
291 note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff);
292 note_ptr->descriptor.load_base = grub_host_to_target32 (0x00004000);
294 phdr++;
295 phdr->p_type = grub_host_to_target32 (PT_NOTE);
296 phdr->p_flags = grub_host_to_target32 (PF_R);
297 phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
298 phdr->p_vaddr = 0;
299 phdr->p_paddr = 0;
300 phdr->p_filesz = grub_host_to_target32 (note_size);
301 phdr->p_memsz = 0;
302 phdr->p_offset = grub_host_to_target32 (header_size + program_size);
306 char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)
307 + shnum * sizeof (*shdr));
308 char *ptr = str_start + 1;
310 shdr++;
312 shdr->sh_name = grub_host_to_target32 (0);
313 shdr->sh_type = grub_host_to_target32 (SHT_STRTAB);
314 shdr->sh_addr = grub_host_to_target_addr (0);
315 shdr->sh_offset = grub_host_to_target_addr (str_start - elf_img);
316 shdr->sh_size = grub_host_to_target32 (string_size);
317 shdr->sh_link = grub_host_to_target32 (0);
318 shdr->sh_info = grub_host_to_target32 (0);
319 shdr->sh_addralign = grub_host_to_target32 (align);
320 shdr->sh_entsize = grub_host_to_target32 (0);
321 shdr++;
323 memcpy (ptr, ".text", sizeof (".text"));
325 shdr->sh_name = grub_host_to_target32 (ptr - str_start);
326 ptr += sizeof (".text");
327 shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
328 shdr->sh_addr = grub_host_to_target_addr (target_addr);
329 shdr->sh_offset = grub_host_to_target_addr (header_size);
330 shdr->sh_size = grub_host_to_target32 (kernel_size);
331 shdr->sh_link = grub_host_to_target32 (0);
332 shdr->sh_info = grub_host_to_target32 (0);
333 shdr->sh_addralign = grub_host_to_target32 (align);
334 shdr->sh_entsize = grub_host_to_target32 (0);
335 shdr++;
337 memcpy (ptr, "mods", sizeof ("mods"));
338 shdr->sh_name = grub_host_to_target32 (ptr - str_start);
339 ptr += sizeof ("mods");
340 shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
341 shdr->sh_addr = grub_host_to_target_addr (target_addr + kernel_size);
342 shdr->sh_offset = grub_host_to_target_addr (header_size + kernel_size);
343 shdr->sh_size = grub_host_to_target32 (*core_size - kernel_size);
344 shdr->sh_link = grub_host_to_target32 (0);
345 shdr->sh_info = grub_host_to_target32 (0);
346 shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof);
347 shdr->sh_entsize = grub_host_to_target32 (0);
348 shdr++;
350 if (image_target->id == IMAGE_XEN)
352 memcpy (ptr, ".xen", sizeof (".xen"));
353 shdr->sh_name = grub_host_to_target32 (ptr - str_start);
354 ptr += sizeof (".xen");
355 shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
356 shdr->sh_addr = grub_host_to_target_addr (target_addr + kernel_size);
357 shdr->sh_offset = grub_host_to_target_addr (program_size + header_size);
358 shdr->sh_size = grub_host_to_target32 (XEN_NOTE_SIZE);
359 shdr->sh_link = grub_host_to_target32 (0);
360 shdr->sh_info = grub_host_to_target32 (0);
361 shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof);
362 shdr->sh_entsize = grub_host_to_target32 (0);
363 shdr++;
367 free (*core_img);
368 *core_img = elf_img;
369 *core_size = program_size + header_size + footer_size;
372 /* Relocate symbols; note that this function overwrites the symbol table.
373 Return the address of a start symbol. */
374 static Elf_Addr
375 SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
376 Elf_Shdr *symtab_section, Elf_Addr *section_addresses,
377 Elf_Half section_entsize, Elf_Half num_sections,
378 void *jumpers, Elf_Addr jumpers_addr,
379 const struct grub_install_image_target_desc *image_target)
381 Elf_Word symtab_size, sym_size, num_syms;
382 Elf_Off symtab_offset;
383 Elf_Addr start_address = 0;
384 Elf_Sym *sym;
385 Elf_Word i;
386 Elf_Shdr *strtab_section;
387 const char *strtab;
388 grub_uint64_t *jptr = jumpers;
390 strtab_section
391 = (Elf_Shdr *) ((char *) sections
392 + (grub_target_to_host32 (symtab_section->sh_link)
393 * section_entsize));
394 strtab = (char *) e + grub_target_to_host (strtab_section->sh_offset);
396 symtab_size = grub_target_to_host (symtab_section->sh_size);
397 sym_size = grub_target_to_host (symtab_section->sh_entsize);
398 symtab_offset = grub_target_to_host (symtab_section->sh_offset);
399 num_syms = symtab_size / sym_size;
401 for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
402 i < num_syms;
403 i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
405 Elf_Section cur_index;
406 const char *name;
408 name = strtab + grub_target_to_host32 (sym->st_name);
410 cur_index = grub_target_to_host16 (sym->st_shndx);
411 if (cur_index == STN_ABS)
413 continue;
415 else if (cur_index == STN_UNDEF)
417 if (sym->st_name)
418 grub_util_error ("undefined symbol %s", name);
419 else
420 continue;
422 else if (cur_index >= num_sections)
423 grub_util_error ("section %d does not exist", cur_index);
425 sym->st_value = (grub_target_to_host (sym->st_value)
426 + section_addresses[cur_index]);
428 if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info)
429 == STT_FUNC)
431 *jptr = grub_host_to_target64 (sym->st_value);
432 sym->st_value = (char *) jptr - (char *) jumpers + jumpers_addr;
433 jptr++;
434 *jptr = 0;
435 jptr++;
437 grub_util_info ("locating %s at 0x%" GRUB_HOST_PRIxLONG_LONG
438 " (0x%" GRUB_HOST_PRIxLONG_LONG ")", name,
439 (unsigned long long) sym->st_value,
440 (unsigned long long) section_addresses[cur_index]);
442 if (! start_address)
443 if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0)
444 start_address = sym->st_value;
447 return start_address;
450 /* Return the address of a symbol at the index I in the section S. */
451 static Elf_Addr
452 SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i,
453 const struct grub_install_image_target_desc *image_target)
455 Elf_Sym *sym;
457 sym = (Elf_Sym *) ((char *) e
458 + grub_target_to_host (s->sh_offset)
459 + i * grub_target_to_host (s->sh_entsize));
460 return sym->st_value;
463 /* Return the address of a modified value. */
464 static Elf_Addr *
465 SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset,
466 const struct grub_install_image_target_desc *image_target)
468 return (Elf_Addr *) ((char *) e + grub_target_to_host (s->sh_offset) + offset);
471 #ifdef MKIMAGE_ELF64
472 static Elf_Addr
473 SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section,
474 const struct grub_install_image_target_desc *image_target)
476 Elf_Word symtab_size, sym_size, num_syms;
477 Elf_Off symtab_offset;
478 Elf_Sym *sym;
479 Elf_Word i;
480 int ret = 0;
482 symtab_size = grub_target_to_host (symtab_section->sh_size);
483 sym_size = grub_target_to_host (symtab_section->sh_entsize);
484 symtab_offset = grub_target_to_host (symtab_section->sh_offset);
485 num_syms = symtab_size / sym_size;
487 for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
488 i < num_syms;
489 i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
490 if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
491 ret++;
493 return ret;
495 #endif
497 #ifdef MKIMAGE_ELF32
498 /* Deal with relocation information. This function relocates addresses
499 within the virtual address space starting from 0. So only relative
500 addresses can be fully resolved. Absolute addresses must be relocated
501 again by a PE32 relocator when loaded. */
502 static grub_size_t
503 arm_get_trampoline_size (Elf_Ehdr *e,
504 Elf_Shdr *sections,
505 Elf_Half section_entsize,
506 Elf_Half num_sections,
507 const struct grub_install_image_target_desc *image_target)
509 Elf_Half i;
510 Elf_Shdr *s;
511 grub_size_t ret = 0;
513 for (i = 0, s = sections;
514 i < num_sections;
515 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
516 if ((s->sh_type == grub_host_to_target32 (SHT_REL)) ||
517 (s->sh_type == grub_host_to_target32 (SHT_RELA)))
519 Elf_Rela *r;
520 Elf_Word rtab_size, r_size, num_rs;
521 Elf_Off rtab_offset;
522 Elf_Shdr *symtab_section;
523 Elf_Word j;
525 symtab_section = (Elf_Shdr *) ((char *) sections
526 + (grub_target_to_host32 (s->sh_link)
527 * section_entsize));
529 rtab_size = grub_target_to_host (s->sh_size);
530 r_size = grub_target_to_host (s->sh_entsize);
531 rtab_offset = grub_target_to_host (s->sh_offset);
532 num_rs = rtab_size / r_size;
534 for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset);
535 j < num_rs;
536 j++, r = (Elf_Rela *) ((char *) r + r_size))
538 Elf_Addr info;
539 Elf_Addr sym_addr;
541 info = grub_target_to_host (r->r_info);
542 sym_addr = SUFFIX (get_symbol_address) (e, symtab_section,
543 ELF_R_SYM (info), image_target);
545 sym_addr += (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
546 grub_target_to_host (r->r_addend) : 0;
548 switch (ELF_R_TYPE (info))
550 case R_ARM_ABS32:
551 case R_ARM_V4BX:
552 break;
553 case R_ARM_THM_CALL:
554 case R_ARM_THM_JUMP24:
555 case R_ARM_THM_JUMP19:
556 if (!(sym_addr & 1))
557 ret += 8;
558 break;
560 case R_ARM_CALL:
561 case R_ARM_JUMP24:
562 if (sym_addr & 1)
563 ret += 16;
564 break;
566 default:
567 grub_util_error (_("relocation 0x%x is not implemented yet"),
568 (unsigned int) ELF_R_TYPE (info));
569 break;
573 return ret;
575 #endif
577 /* Deal with relocation information. This function relocates addresses
578 within the virtual address space starting from 0. So only relative
579 addresses can be fully resolved. Absolute addresses must be relocated
580 again by a PE32 relocator when loaded. */
581 static void
582 SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
583 Elf_Addr *section_addresses,
584 Elf_Half section_entsize, Elf_Half num_sections,
585 const char *strtab,
586 char *pe_target, Elf_Addr tramp_off,
587 Elf_Addr got_off,
588 const struct grub_install_image_target_desc *image_target)
590 Elf_Half i;
591 Elf_Shdr *s;
592 #ifdef MKIMAGE_ELF64
593 struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off);
594 grub_uint64_t *gpptr = (void *) (pe_target + got_off);
595 #define MASK19 ((1 << 19) - 1)
596 #else
597 grub_uint32_t *tr = (void *) (pe_target + tramp_off);
598 #endif
600 for (i = 0, s = sections;
601 i < num_sections;
602 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
603 if ((s->sh_type == grub_host_to_target32 (SHT_REL)) ||
604 (s->sh_type == grub_host_to_target32 (SHT_RELA)))
606 Elf_Rela *r;
607 Elf_Word rtab_size, r_size, num_rs;
608 Elf_Off rtab_offset;
609 Elf_Shdr *symtab_section;
610 Elf_Word target_section_index;
611 Elf_Addr target_section_addr;
612 Elf_Shdr *target_section;
613 Elf_Word j;
615 symtab_section = (Elf_Shdr *) ((char *) sections
616 + (grub_target_to_host32 (s->sh_link)
617 * section_entsize));
618 target_section_index = grub_target_to_host32 (s->sh_info);
619 target_section_addr = section_addresses[target_section_index];
620 target_section = (Elf_Shdr *) ((char *) sections
621 + (target_section_index
622 * section_entsize));
624 grub_util_info ("dealing with the relocation section %s for %s",
625 strtab + grub_target_to_host32 (s->sh_name),
626 strtab + grub_target_to_host32 (target_section->sh_name));
628 rtab_size = grub_target_to_host (s->sh_size);
629 r_size = grub_target_to_host (s->sh_entsize);
630 rtab_offset = grub_target_to_host (s->sh_offset);
631 num_rs = rtab_size / r_size;
633 for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset);
634 j < num_rs;
635 j++, r = (Elf_Rela *) ((char *) r + r_size))
637 Elf_Addr info;
638 Elf_Addr offset;
639 Elf_Addr sym_addr;
640 Elf_Addr *target;
641 Elf_Addr addend;
643 offset = grub_target_to_host (r->r_offset);
644 target = SUFFIX (get_target_address) (e, target_section,
645 offset, image_target);
646 info = grub_target_to_host (r->r_info);
647 sym_addr = SUFFIX (get_symbol_address) (e, symtab_section,
648 ELF_R_SYM (info), image_target);
650 addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
651 grub_target_to_host (r->r_addend) : 0;
653 switch (image_target->elf_target)
655 case EM_386:
656 switch (ELF_R_TYPE (info))
658 case R_386_NONE:
659 break;
661 case R_386_32:
662 /* This is absolute. */
663 *target = grub_host_to_target32 (grub_target_to_host32 (*target)
664 + addend + sym_addr);
665 grub_util_info ("relocating an R_386_32 entry to 0x%"
666 GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
667 GRUB_HOST_PRIxLONG_LONG,
668 (unsigned long long) *target,
669 (unsigned long long) offset);
670 break;
672 case R_386_PC32:
673 /* This is relative. */
674 *target = grub_host_to_target32 (grub_target_to_host32 (*target)
675 + addend + sym_addr
676 - target_section_addr - offset
677 - image_target->vaddr_offset);
678 grub_util_info ("relocating an R_386_PC32 entry to 0x%"
679 GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
680 GRUB_HOST_PRIxLONG_LONG,
681 (unsigned long long) *target,
682 (unsigned long long) offset);
683 break;
684 default:
685 grub_util_error (_("relocation 0x%x is not implemented yet"),
686 (unsigned int) ELF_R_TYPE (info));
687 break;
689 break;
690 #ifdef MKIMAGE_ELF64
691 case EM_X86_64:
692 switch (ELF_R_TYPE (info))
695 case R_X86_64_NONE:
696 break;
698 case R_X86_64_64:
699 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
700 + addend + sym_addr);
701 grub_util_info ("relocating an R_X86_64_64 entry to 0x%"
702 GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
703 GRUB_HOST_PRIxLONG_LONG,
704 (unsigned long long) *target,
705 (unsigned long long) offset);
706 break;
708 case R_X86_64_PC32:
710 grub_uint32_t *t32 = (grub_uint32_t *) target;
711 *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
712 + addend + sym_addr
713 - target_section_addr - offset
714 - image_target->vaddr_offset);
715 grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%"
716 GRUB_HOST_PRIxLONG_LONG,
717 *t32, (unsigned long long) offset);
718 break;
721 case R_X86_64_PC64:
723 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
724 + addend + sym_addr
725 - target_section_addr - offset
726 - image_target->vaddr_offset);
727 grub_util_info ("relocating an R_X86_64_PC64 entry to 0x%"
728 GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
729 GRUB_HOST_PRIxLONG_LONG,
730 (unsigned long long) *target,
731 (unsigned long long) offset);
732 break;
735 case R_X86_64_32:
736 case R_X86_64_32S:
738 grub_uint32_t *t32 = (grub_uint32_t *) target;
739 *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
740 + addend + sym_addr);
741 grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%"
742 GRUB_HOST_PRIxLONG_LONG,
743 *t32, (unsigned long long) offset);
744 break;
747 default:
748 grub_util_error (_("relocation 0x%x is not implemented yet"),
749 (unsigned int) ELF_R_TYPE (info));
750 break;
752 break;
753 case EM_IA_64:
754 switch (ELF_R_TYPE (info))
756 case R_IA64_PCREL21B:
758 grub_uint64_t noff;
759 grub_ia64_make_trampoline (tr, addend + sym_addr);
760 noff = ((char *) tr - (char *) pe_target
761 - target_section_addr - (offset & ~3)) >> 4;
762 tr++;
763 if (noff & ~MASK19)
764 grub_util_error ("trampoline offset too big (%"
765 GRUB_HOST_PRIxLONG_LONG ")",
766 (unsigned long long) noff);
767 grub_ia64_add_value_to_slot_20b ((grub_addr_t) target, noff);
769 break;
771 case R_IA64_LTOFF22X:
772 case R_IA64_LTOFF22:
774 Elf_Sym *sym;
776 sym = (Elf_Sym *) ((char *) e
777 + grub_target_to_host (symtab_section->sh_offset)
778 + ELF_R_SYM (info) * grub_target_to_host (symtab_section->sh_entsize));
779 if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
780 sym_addr = grub_target_to_host64 (*(grub_uint64_t *) (pe_target
781 + sym->st_value
782 - image_target->vaddr_offset));
784 case R_IA64_LTOFF_FPTR22:
785 *gpptr = grub_host_to_target64 (addend + sym_addr);
786 grub_ia64_add_value_to_slot_21 ((grub_addr_t) target,
787 (char *) gpptr - (char *) pe_target
788 + image_target->vaddr_offset);
789 gpptr++;
790 break;
792 case R_IA64_GPREL22:
793 grub_ia64_add_value_to_slot_21 ((grub_addr_t) target,
794 addend + sym_addr);
795 break;
796 case R_IA64_PCREL64LSB:
797 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
798 + addend + sym_addr
799 - target_section_addr - offset
800 - image_target->vaddr_offset);
801 break;
803 case R_IA64_SEGREL64LSB:
804 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
805 + addend + sym_addr - target_section_addr);
806 break;
807 case R_IA64_DIR64LSB:
808 case R_IA64_FPTR64LSB:
809 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
810 + addend + sym_addr);
811 grub_util_info ("relocating a direct entry to 0x%"
812 GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
813 GRUB_HOST_PRIxLONG_LONG,
814 (unsigned long long)
815 grub_target_to_host64 (*target),
816 (unsigned long long) offset);
817 break;
819 /* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */
820 case R_IA64_LDXMOV:
821 break;
823 default:
824 grub_util_error (_("relocation 0x%x is not implemented yet"),
825 (unsigned int) ELF_R_TYPE (info));
826 break;
828 break;
829 case EM_AARCH64:
831 sym_addr += addend;
832 switch (ELF_R_TYPE (info))
834 case R_AARCH64_ABS64:
836 *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr);
838 break;
839 case R_AARCH64_JUMP26:
840 case R_AARCH64_CALL26:
842 sym_addr -= offset;
843 sym_addr -= SUFFIX (entry_point);
844 if (!grub_arm_64_check_xxxx26_offset (sym_addr))
845 grub_util_error ("%s", "CALL26 Relocation out of range");
847 grub_arm64_set_xxxx26_offset((grub_uint32_t *)target,
848 sym_addr);
850 break;
851 default:
852 grub_util_error (_("relocation 0x%x is not implemented yet"),
853 (unsigned int) ELF_R_TYPE (info));
854 break;
856 break;
858 #endif
859 #if defined(MKIMAGE_ELF32)
860 case EM_ARM:
862 sym_addr += addend;
863 sym_addr -= SUFFIX (entry_point);
864 switch (ELF_R_TYPE (info))
866 case R_ARM_ABS32:
868 grub_util_info (" ABS32:\toffset=%d\t(0x%08x)",
869 (int) sym_addr, (int) sym_addr);
870 /* Data will be naturally aligned */
871 sym_addr += 0x400;
872 *target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr);
874 break;
875 /* Happens when compiled with -march=armv4.
876 Since currently we need at least armv5, keep bx as-is.
878 case R_ARM_V4BX:
879 break;
880 case R_ARM_THM_CALL:
881 case R_ARM_THM_JUMP24:
882 case R_ARM_THM_JUMP19:
884 grub_err_t err;
885 grub_util_info (" THM_JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)",
886 (unsigned long) ((char *) target
887 - (char *) e),
888 sym_addr);
889 if (!(sym_addr & 1))
891 grub_uint32_t tr_addr;
892 grub_int32_t new_offset;
893 tr_addr = (char *) tr - (char *) pe_target
894 - target_section_addr;
895 new_offset = sym_addr - tr_addr - 12;
897 if (!grub_arm_jump24_check_offset (new_offset))
898 return grub_util_error ("jump24 relocation out of range");
900 tr[0] = grub_host_to_target32 (0x46c04778); /* bx pc; nop */
901 tr[1] = grub_host_to_target32 (((new_offset >> 2) & 0xffffff) | 0xea000000); /* b new_offset */
902 tr += 2;
903 sym_addr = tr_addr | 1;
905 sym_addr -= offset;
906 /* Thumb instructions can be 16-bit aligned */
907 if (ELF_R_TYPE (info) == R_ARM_THM_JUMP19)
908 err = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr);
909 else
910 err = grub_arm_reloc_thm_call ((grub_uint16_t *) target,
911 sym_addr);
912 if (err)
913 grub_util_error ("%s", grub_errmsg);
915 break;
917 case R_ARM_CALL:
918 case R_ARM_JUMP24:
920 grub_err_t err;
921 grub_util_info (" JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", (unsigned long) ((char *) target - (char *) e), sym_addr);
922 if (sym_addr & 1)
924 grub_uint32_t tr_addr;
925 grub_int32_t new_offset;
926 tr_addr = (char *) tr - (char *) pe_target
927 - target_section_addr;
928 new_offset = sym_addr - tr_addr - 12;
930 /* There is no immediate version of bx, only register one... */
931 tr[0] = grub_host_to_target32 (0xe59fc004); /* ldr ip, [pc, #4] */
932 tr[1] = grub_host_to_target32 (0xe08cc00f); /* add ip, ip, pc */
933 tr[2] = grub_host_to_target32 (0xe12fff1c); /* bx ip */
934 tr[3] = grub_host_to_target32 (new_offset | 1);
935 tr += 4;
936 sym_addr = tr_addr;
938 sym_addr -= offset;
939 err = grub_arm_reloc_jump24 (target,
940 sym_addr);
941 if (err)
942 grub_util_error ("%s", grub_errmsg);
944 break;
946 default:
947 grub_util_error (_("relocation 0x%x is not implemented yet"),
948 (unsigned int) ELF_R_TYPE (info));
949 break;
951 break;
953 #endif /* MKIMAGE_ELF32 */
954 default:
955 grub_util_error ("unknown architecture type %d",
956 image_target->elf_target);
962 /* Add a PE32's fixup entry for a relocation. Return the resulting address
963 after having written to the file OUT. */
964 static Elf_Addr
965 SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type,
966 Elf_Addr addr, int flush, Elf_Addr current_address,
967 const struct grub_install_image_target_desc *image_target)
969 struct grub_pe32_fixup_block *b;
971 b = &((*cblock)->b);
973 /* First, check if it is necessary to write out the current block. */
974 if ((*cblock)->state)
976 if (flush || addr < b->page_rva || b->page_rva + 0x1000 <= addr)
978 grub_uint32_t size;
980 if (flush)
982 /* Add as much padding as necessary to align the address
983 with a section boundary. */
984 Elf_Addr next_address;
985 unsigned padding_size;
986 size_t cur_index;
988 next_address = current_address + b->block_size;
989 padding_size = ((ALIGN_UP (next_address, image_target->section_align)
990 - next_address)
991 >> 1);
992 cur_index = ((b->block_size - sizeof (*b)) >> 1);
993 grub_util_info ("adding %d padding fixup entries", padding_size);
994 while (padding_size--)
996 b->entries[cur_index++] = 0;
997 b->block_size += 2;
1000 else while (b->block_size & (8 - 1))
1002 /* If not aligned with a 32-bit boundary, add
1003 a padding entry. */
1004 size_t cur_index;
1006 grub_util_info ("adding a padding fixup entry");
1007 cur_index = ((b->block_size - sizeof (*b)) >> 1);
1008 b->entries[cur_index] = 0;
1009 b->block_size += 2;
1012 /* Flush it. */
1013 grub_util_info ("writing %d bytes of a fixup block starting at 0x%x",
1014 b->block_size, b->page_rva);
1015 size = b->block_size;
1016 current_address += size;
1017 b->page_rva = grub_host_to_target32 (b->page_rva);
1018 b->block_size = grub_host_to_target32 (b->block_size);
1019 (*cblock)->next = xmalloc (sizeof (**cblock) + 2 * 0x1000);
1020 memset ((*cblock)->next, 0, sizeof (**cblock) + 2 * 0x1000);
1021 *cblock = (*cblock)->next;
1025 b = &((*cblock)->b);
1027 if (! flush)
1029 grub_uint16_t entry;
1030 size_t cur_index;
1032 /* If not allocated yet, allocate a block with enough entries. */
1033 if (! (*cblock)->state)
1035 (*cblock)->state = 1;
1037 /* The spec does not mention the requirement of a Page RVA.
1038 Here, align the address with a 4K boundary for safety. */
1039 b->page_rva = (addr & ~(0x1000 - 1));
1040 b->block_size = sizeof (*b);
1043 /* Sanity check. */
1044 if (b->block_size >= sizeof (*b) + 2 * 0x1000)
1045 grub_util_error ("too many fixup entries");
1047 /* Add a new entry. */
1048 cur_index = ((b->block_size - sizeof (*b)) >> 1);
1049 entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva);
1050 b->entries[cur_index] = grub_host_to_target16 (entry);
1051 b->block_size += 2;
1054 return current_address;
1057 /* Make a .reloc section. */
1058 static Elf_Addr
1059 SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
1060 Elf_Addr *section_addresses, Elf_Shdr *sections,
1061 Elf_Half section_entsize, Elf_Half num_sections,
1062 const char *strtab,
1063 Elf_Addr jumpers, grub_size_t njumpers,
1064 const struct grub_install_image_target_desc *image_target)
1066 unsigned i;
1067 Elf_Shdr *s;
1068 struct fixup_block_list *lst, *lst0;
1069 Elf_Addr current_address = 0;
1071 lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000);
1072 memset (lst, 0, sizeof (*lst) + 2 * 0x1000);
1074 for (i = 0, s = sections; i < num_sections;
1075 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1076 if ((grub_target_to_host32 (s->sh_type) == SHT_REL) ||
1077 (grub_target_to_host32 (s->sh_type) == SHT_RELA))
1079 Elf_Rel *r;
1080 Elf_Word rtab_size, r_size, num_rs;
1081 Elf_Off rtab_offset;
1082 Elf_Addr section_address;
1083 Elf_Word j;
1085 grub_util_info ("translating the relocation section %s",
1086 strtab + grub_le_to_cpu32 (s->sh_name));
1088 rtab_size = grub_target_to_host (s->sh_size);
1089 r_size = grub_target_to_host (s->sh_entsize);
1090 rtab_offset = grub_target_to_host (s->sh_offset);
1091 num_rs = rtab_size / r_size;
1093 section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)];
1095 for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset);
1096 j < num_rs;
1097 j++, r = (Elf_Rel *) ((char *) r + r_size))
1099 Elf_Addr info;
1100 Elf_Addr offset;
1102 offset = grub_target_to_host (r->r_offset);
1103 info = grub_target_to_host (r->r_info);
1105 /* Necessary to relocate only absolute addresses. */
1106 switch (image_target->elf_target)
1108 case EM_386:
1109 if (ELF_R_TYPE (info) == R_386_32)
1111 Elf_Addr addr;
1113 addr = section_address + offset;
1114 grub_util_info ("adding a relocation entry for 0x%"
1115 GRUB_HOST_PRIxLONG_LONG,
1116 (unsigned long long) addr);
1117 current_address
1118 = SUFFIX (add_fixup_entry) (&lst,
1119 GRUB_PE32_REL_BASED_HIGHLOW,
1120 addr, 0, current_address,
1121 image_target);
1123 break;
1124 case EM_X86_64:
1125 if ((ELF_R_TYPE (info) == R_X86_64_32) ||
1126 (ELF_R_TYPE (info) == R_X86_64_32S))
1128 grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)");
1130 else if (ELF_R_TYPE (info) == R_X86_64_64)
1132 Elf_Addr addr;
1134 addr = section_address + offset;
1135 grub_util_info ("adding a relocation entry for 0x%"
1136 GRUB_HOST_PRIxLONG_LONG,
1137 (unsigned long long) addr);
1138 current_address
1139 = SUFFIX (add_fixup_entry) (&lst,
1140 GRUB_PE32_REL_BASED_DIR64,
1141 addr,
1142 0, current_address,
1143 image_target);
1145 break;
1146 case EM_IA_64:
1147 switch (ELF_R_TYPE (info))
1149 case R_IA64_PCREL64LSB:
1150 case R_IA64_LDXMOV:
1151 case R_IA64_PCREL21B:
1152 case R_IA64_LTOFF_FPTR22:
1153 case R_IA64_LTOFF22X:
1154 case R_IA64_LTOFF22:
1155 case R_IA64_GPREL22:
1156 case R_IA64_SEGREL64LSB:
1157 break;
1159 case R_IA64_FPTR64LSB:
1160 case R_IA64_DIR64LSB:
1161 #if 1
1163 Elf_Addr addr;
1165 addr = section_address + offset;
1166 grub_util_info ("adding a relocation entry for 0x%"
1167 GRUB_HOST_PRIxLONG_LONG,
1168 (unsigned long long) addr);
1169 current_address
1170 = SUFFIX (add_fixup_entry) (&lst,
1171 GRUB_PE32_REL_BASED_DIR64,
1172 addr,
1173 0, current_address,
1174 image_target);
1176 #endif
1177 break;
1178 default:
1179 grub_util_error (_("relocation 0x%x is not implemented yet"),
1180 (unsigned int) ELF_R_TYPE (info));
1181 break;
1183 break;
1184 case EM_AARCH64:
1185 switch (ELF_R_TYPE (info))
1187 case R_AARCH64_ABS64:
1189 Elf_Addr addr;
1191 addr = section_address + offset;
1192 current_address
1193 = SUFFIX (add_fixup_entry) (&lst,
1194 GRUB_PE32_REL_BASED_DIR64,
1195 addr, 0, current_address,
1196 image_target);
1198 break;
1199 /* Relative relocations do not require fixup entries. */
1200 case R_AARCH64_CALL26:
1201 case R_AARCH64_JUMP26:
1202 break;
1203 default:
1204 grub_util_error (_("relocation 0x%x is not implemented yet"),
1205 (unsigned int) ELF_R_TYPE (info));
1206 break;
1208 break;
1209 break;
1210 #if defined(MKIMAGE_ELF32)
1211 case EM_ARM:
1212 switch (ELF_R_TYPE (info))
1214 case R_ARM_V4BX:
1215 /* Relative relocations do not require fixup entries. */
1216 case R_ARM_JUMP24:
1217 case R_ARM_THM_CALL:
1218 case R_ARM_THM_JUMP19:
1219 case R_ARM_THM_JUMP24:
1220 case R_ARM_CALL:
1222 Elf_Addr addr;
1224 addr = section_address + offset;
1225 grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) current_address);
1227 break;
1228 /* Create fixup entry for PE/COFF loader */
1229 case R_ARM_ABS32:
1231 Elf_Addr addr;
1233 addr = section_address + offset;
1234 current_address
1235 = SUFFIX (add_fixup_entry) (&lst,
1236 GRUB_PE32_REL_BASED_HIGHLOW,
1237 addr, 0, current_address,
1238 image_target);
1240 break;
1241 default:
1242 grub_util_error (_("relocation 0x%x is not implemented yet"),
1243 (unsigned int) ELF_R_TYPE (info));
1244 break;
1246 break;
1247 #endif /* defined(MKIMAGE_ELF32) */
1248 default:
1249 grub_util_error ("unknown machine type 0x%x", image_target->elf_target);
1254 if (image_target->elf_target == EM_IA_64)
1255 for (i = 0; i < njumpers; i++)
1256 current_address = SUFFIX (add_fixup_entry) (&lst,
1257 GRUB_PE32_REL_BASED_DIR64,
1258 jumpers + 8 * i,
1259 0, current_address,
1260 image_target);
1262 current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target);
1265 grub_uint8_t *ptr;
1266 ptr = *out = xmalloc (current_address);
1267 for (lst = lst0; lst; lst = lst->next)
1268 if (lst->state)
1270 memcpy (ptr, &lst->b, grub_target_to_host32 (lst->b.block_size));
1271 ptr += grub_target_to_host32 (lst->b.block_size);
1273 assert ((current_address + (grub_uint8_t *) *out) == ptr);
1276 for (lst = lst0; lst; )
1278 struct fixup_block_list *next;
1279 next = lst->next;
1280 free (lst);
1281 lst = next;
1284 return current_address;
1287 /* Determine if this section is a text section. Return false if this
1288 section is not allocated. */
1289 static int
1290 SUFFIX (is_text_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
1292 if (image_target->id != IMAGE_EFI
1293 && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
1294 return 0;
1295 return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
1296 == (SHF_EXECINSTR | SHF_ALLOC));
1299 /* Determine if this section is a data section. This assumes that
1300 BSS is also a data section, since the converter initializes BSS
1301 when producing PE32 to avoid a bug in EFI implementations. */
1302 static int
1303 SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
1305 if (image_target->id != IMAGE_EFI
1306 && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
1307 return 0;
1308 return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
1309 == SHF_ALLOC);
1312 /* Return if the ELF header is valid. */
1313 static int
1314 SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_image_target_desc *image_target)
1316 if (size < sizeof (*e)
1317 || e->e_ident[EI_MAG0] != ELFMAG0
1318 || e->e_ident[EI_MAG1] != ELFMAG1
1319 || e->e_ident[EI_MAG2] != ELFMAG2
1320 || e->e_ident[EI_MAG3] != ELFMAG3
1321 || e->e_ident[EI_VERSION] != EV_CURRENT
1322 || e->e_ident[EI_CLASS] != ELFCLASSXX
1323 || e->e_version != grub_host_to_target32 (EV_CURRENT))
1324 return 0;
1326 return 1;
1329 /* Locate section addresses by merging code sections and data sections
1330 into .text and .data, respectively. Return the array of section
1331 addresses. */
1332 static Elf_Addr *
1333 SUFFIX (locate_sections) (const char *kernel_path,
1334 Elf_Shdr *sections, Elf_Half section_entsize,
1335 Elf_Half num_sections, const char *strtab,
1336 size_t *exec_size, size_t *kernel_sz,
1337 size_t *all_align,
1338 const struct grub_install_image_target_desc *image_target)
1340 int i;
1341 Elf_Addr current_address;
1342 Elf_Addr *section_addresses;
1343 Elf_Shdr *s;
1345 *all_align = 1;
1347 section_addresses = xmalloc (sizeof (*section_addresses) * num_sections);
1348 memset (section_addresses, 0, sizeof (*section_addresses) * num_sections);
1350 current_address = 0;
1352 for (i = 0, s = sections;
1353 i < num_sections;
1354 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1355 if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC)
1356 && grub_host_to_target32 (s->sh_addralign) > *all_align)
1357 *all_align = grub_host_to_target32 (s->sh_addralign);
1360 /* .text */
1361 for (i = 0, s = sections;
1362 i < num_sections;
1363 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1364 if (SUFFIX (is_text_section) (s, image_target))
1366 Elf_Word align = grub_host_to_target_addr (s->sh_addralign);
1367 const char *name = strtab + grub_host_to_target32 (s->sh_name);
1368 if (align)
1369 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1370 align) - image_target->vaddr_offset;
1371 grub_util_info ("locating the section %s at 0x%"
1372 GRUB_HOST_PRIxLONG_LONG,
1373 name, (unsigned long long) current_address);
1374 if (image_target->id != IMAGE_EFI)
1376 current_address = grub_host_to_target_addr (s->sh_addr)
1377 - image_target->link_addr;
1378 if (grub_host_to_target_addr (s->sh_addr)
1379 != image_target->link_addr)
1381 char *msg
1382 = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx"
1383 " instead of 0x%llx: ld.gold bug?"),
1384 kernel_path,
1385 (unsigned long long) grub_host_to_target_addr (s->sh_addr),
1386 (unsigned long long) image_target->link_addr);
1387 grub_util_error ("%s", msg);
1390 section_addresses[i] = current_address;
1391 current_address += grub_host_to_target_addr (s->sh_size);
1394 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1395 image_target->section_align)
1396 - image_target->vaddr_offset;
1397 *exec_size = current_address;
1399 /* .data */
1400 for (i = 0, s = sections;
1401 i < num_sections;
1402 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1403 if (SUFFIX (is_data_section) (s, image_target))
1405 Elf_Word align = grub_host_to_target_addr (s->sh_addralign);
1406 const char *name = strtab + grub_host_to_target32 (s->sh_name);
1408 if (align)
1409 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1410 align)
1411 - image_target->vaddr_offset;
1413 grub_util_info ("locating the section %s at 0x%"
1414 GRUB_HOST_PRIxLONG_LONG,
1415 name, (unsigned long long) current_address);
1416 if (image_target->id != IMAGE_EFI)
1417 current_address = grub_host_to_target_addr (s->sh_addr)
1418 - image_target->link_addr;
1419 section_addresses[i] = current_address;
1420 current_address += grub_host_to_target_addr (s->sh_size);
1423 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1424 image_target->section_align) - image_target->vaddr_offset;
1425 *kernel_sz = current_address;
1426 return section_addresses;
1429 static char *
1430 SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
1431 size_t *kernel_sz, size_t *bss_size,
1432 size_t total_module_size, grub_uint64_t *start,
1433 void **reloc_section, size_t *reloc_size,
1434 size_t *align,
1435 const struct grub_install_image_target_desc *image_target)
1437 char *kernel_img, *out_img;
1438 const char *strtab;
1439 Elf_Ehdr *e;
1440 Elf_Shdr *sections;
1441 Elf_Addr *section_addresses;
1442 Elf_Addr *section_vaddresses;
1443 int i;
1444 Elf_Shdr *s;
1445 Elf_Half num_sections;
1446 Elf_Off section_offset;
1447 Elf_Half section_entsize;
1448 grub_size_t kernel_size;
1449 grub_size_t ia64jmp_off = 0, tramp_off = 0, ia64_got_off = 0;
1450 unsigned ia64jmpnum = 0;
1451 Elf_Shdr *symtab_section = 0;
1452 grub_size_t got = 0;
1454 *start = 0;
1456 kernel_size = grub_util_get_image_size (kernel_path);
1457 kernel_img = xmalloc (kernel_size);
1458 grub_util_load_image (kernel_path, kernel_img);
1460 e = (Elf_Ehdr *) kernel_img;
1461 if (! SUFFIX (check_elf_header) (e, kernel_size, image_target))
1462 grub_util_error ("invalid ELF header");
1464 section_offset = grub_target_to_host (e->e_shoff);
1465 section_entsize = grub_target_to_host16 (e->e_shentsize);
1466 num_sections = grub_target_to_host16 (e->e_shnum);
1468 if (kernel_size < section_offset + section_entsize * num_sections)
1469 grub_util_error (_("premature end of file %s"), kernel_path);
1471 sections = (Elf_Shdr *) (kernel_img + section_offset);
1473 /* Relocate sections then symbols in the virtual address space. */
1474 s = (Elf_Shdr *) ((char *) sections
1475 + grub_host_to_target16 (e->e_shstrndx) * section_entsize);
1476 strtab = (char *) e + grub_host_to_target_addr (s->sh_offset);
1478 section_addresses = SUFFIX (locate_sections) (kernel_path,
1479 sections, section_entsize,
1480 num_sections, strtab,
1481 exec_size, kernel_sz, align,
1482 image_target);
1484 section_vaddresses = xmalloc (sizeof (*section_addresses) * num_sections);
1486 for (i = 0; i < num_sections; i++)
1487 section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset;
1489 if (image_target->id != IMAGE_EFI)
1491 Elf_Addr current_address = *kernel_sz;
1493 for (i = 0, s = sections;
1494 i < num_sections;
1495 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1496 if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
1498 Elf_Word sec_align = grub_host_to_target_addr (s->sh_addralign);
1499 const char *name = strtab + grub_host_to_target32 (s->sh_name);
1501 if (sec_align)
1502 current_address = ALIGN_UP (current_address
1503 + image_target->vaddr_offset,
1504 sec_align)
1505 - image_target->vaddr_offset;
1507 grub_util_info ("locating the section %s at 0x%"
1508 GRUB_HOST_PRIxLONG_LONG,
1509 name, (unsigned long long) current_address);
1510 if (image_target->id != IMAGE_EFI)
1511 current_address = grub_host_to_target_addr (s->sh_addr)
1512 - image_target->link_addr;
1514 section_vaddresses[i] = current_address
1515 + image_target->vaddr_offset;
1516 current_address += grub_host_to_target_addr (s->sh_size);
1518 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1519 image_target->section_align)
1520 - image_target->vaddr_offset;
1521 *bss_size = current_address - *kernel_sz;
1523 else
1524 *bss_size = 0;
1526 if (image_target->id == IMAGE_SPARC64_AOUT
1527 || image_target->id == IMAGE_SPARC64_RAW
1528 || image_target->id == IMAGE_SPARC64_CDCORE)
1529 *kernel_sz = ALIGN_UP (*kernel_sz, image_target->mod_align);
1531 if (image_target->id == IMAGE_EFI)
1533 symtab_section = NULL;
1534 for (i = 0, s = sections;
1535 i < num_sections;
1536 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1537 if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB))
1539 symtab_section = s;
1540 break;
1542 if (! symtab_section)
1543 grub_util_error ("%s", _("no symbol table"));
1545 #ifdef MKIMAGE_ELF32
1546 if (image_target->elf_target == EM_ARM)
1548 grub_size_t tramp;
1550 *kernel_sz = ALIGN_UP (*kernel_sz, 16);
1552 tramp = arm_get_trampoline_size (e, sections, section_entsize,
1553 num_sections, image_target);
1555 tramp_off = *kernel_sz;
1556 *kernel_sz += ALIGN_UP (tramp, 16);
1558 #endif
1560 #ifdef MKIMAGE_ELF64
1561 if (image_target->elf_target == EM_IA_64)
1563 grub_size_t tramp;
1565 *kernel_sz = ALIGN_UP (*kernel_sz, 16);
1567 grub_ia64_dl_get_tramp_got_size (e, &tramp, &got);
1569 tramp_off = *kernel_sz;
1570 *kernel_sz += ALIGN_UP (tramp, 16);
1572 ia64jmp_off = *kernel_sz;
1573 ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section,
1574 image_target);
1575 *kernel_sz += 16 * ia64jmpnum;
1577 ia64_got_off = *kernel_sz;
1578 *kernel_sz += ALIGN_UP (got, 16);
1580 #endif
1583 else
1585 *reloc_size = 0;
1586 *reloc_section = NULL;
1589 out_img = xmalloc (*kernel_sz + total_module_size);
1591 if (image_target->id == IMAGE_EFI)
1593 *start = SUFFIX (relocate_symbols) (e, sections, symtab_section,
1594 section_vaddresses, section_entsize,
1595 num_sections,
1596 (char *) out_img + ia64jmp_off,
1597 ia64jmp_off
1598 + image_target->vaddr_offset,
1599 image_target);
1600 if (*start == 0)
1601 grub_util_error ("start symbol is not defined");
1603 SUFFIX (entry_point) = (Elf_Addr) *start;
1605 /* Resolve addresses in the virtual address space. */
1606 SUFFIX (relocate_addresses) (e, sections, section_addresses,
1607 section_entsize,
1608 num_sections, strtab,
1609 out_img, tramp_off, ia64_got_off,
1610 image_target);
1612 *reloc_size = SUFFIX (make_reloc_section) (e, reloc_section,
1613 section_vaddresses, sections,
1614 section_entsize, num_sections,
1615 strtab, ia64jmp_off
1616 + image_target->vaddr_offset,
1617 2 * ia64jmpnum + (got / 8),
1618 image_target);
1621 for (i = 0, s = sections;
1622 i < num_sections;
1623 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1624 if (SUFFIX (is_data_section) (s, image_target)
1625 || SUFFIX (is_text_section) (s, image_target))
1627 if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
1628 memset (out_img + section_addresses[i], 0,
1629 grub_host_to_target_addr (s->sh_size));
1630 else
1631 memcpy (out_img + section_addresses[i],
1632 kernel_img + grub_host_to_target_addr (s->sh_offset),
1633 grub_host_to_target_addr (s->sh_size));
1635 free (kernel_img);
1637 free (section_vaddresses);
1638 free (section_addresses);
1640 return out_img;
1644 #undef SUFFIX
1645 #undef ELFCLASSXX
1646 #undef Elf_Ehdr
1647 #undef Elf_Phdr
1648 #undef Elf_Nhdr
1649 #undef Elf_Shdr
1650 #undef Elf_Addr
1651 #undef Elf_Sym
1652 #undef Elf_Off
1653 #undef Elf_Rela
1654 #undef Elf_Rel
1655 #undef ELF_R_TYPE
1656 #undef ELF_R_SYM
1657 #undef Elf_Word
1658 #undef Elf_Half
1659 #undef Elf_Section
1660 #undef ELF_ST_TYPE
1661 #undef XEN_NOTE_SIZE