]> git.proxmox.com Git - grub2.git/blob - util/grub-mkimagexx.c
* grub-core/genmod.sh.in: Strip before converting to ELF as strip
[grub2.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 #undef ELF_R_SYM
21 #undef ELF_R_TYPE
22
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
64
65 static Elf_Addr SUFFIX (entry_point);
66
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)
72 {
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;
82
83 if (image_target->id != IMAGE_LOONGSON_ELF)
84 phnum += 2;
85
86 if (note)
87 {
88 phnum++;
89 footer_size += sizeof (struct grub_ieee1275_note);
90 }
91 if (image_target->id == IMAGE_XEN)
92 {
93 phnum++;
94 shnum++;
95 string_size += sizeof (".xen");
96 footer_size += XEN_NOTE_SIZE;
97 }
98 header_size = ALIGN_UP (sizeof (*ehdr) + phnum * sizeof (*phdr)
99 + shnum * sizeof (*shdr) + string_size, align);
100
101 program_size = ALIGN_ADDR (*core_size);
102
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);
120
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);
124
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);
133
134 ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr));
135
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);
139
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)
150 {
151 phdr->p_filesz = grub_host_to_target32 (*core_size);
152 phdr->p_memsz = grub_host_to_target32 (*core_size);
153 }
154 else
155 {
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);
159
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);
166
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);
173
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);
183 }
184
185 if (image_target->id == IMAGE_XEN)
186 {
187 char *note_start = (elf_img + program_size + header_size);
188 Elf_Nhdr *note_ptr;
189 char *ptr = (char *) note_start;
190
191 grub_util_info ("adding XEN NOTE segment");
192
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);
203
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);
214
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);
225
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;
236
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;
247
248 /* PAE. */
249 if (image_target->elf_target == EM_386)
250 {
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);
260 }
261
262 assert (XEN_NOTE_SIZE == (ptr - note_start));
263
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);
273 }
274
275 if (note)
276 {
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);
280
281 grub_util_info ("adding CHRP NOTE segment");
282
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);
293
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);
303 }
304
305 {
306 char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)
307 + shnum * sizeof (*shdr));
308 char *ptr = str_start + 1;
309
310 shdr++;
311
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++;
322
323 memcpy (ptr, ".text", sizeof (".text"));
324
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++;
336
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++;
349
350 if (image_target->id == IMAGE_XEN)
351 {
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++;
364 }
365 }
366
367 free (*core_img);
368 *core_img = elf_img;
369 *core_size = program_size + header_size + footer_size;
370 }
371
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)
380 {
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;
389
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);
395
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;
400
401 for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
402 i < num_syms;
403 i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
404 {
405 Elf_Section cur_index;
406 const char *name;
407
408 name = strtab + grub_target_to_host32 (sym->st_name);
409
410 cur_index = grub_target_to_host16 (sym->st_shndx);
411 if (cur_index == STN_ABS)
412 {
413 continue;
414 }
415 else if (cur_index == STN_UNDEF)
416 {
417 if (sym->st_name)
418 grub_util_error ("undefined symbol %s", name);
419 else
420 continue;
421 }
422 else if (cur_index >= num_sections)
423 grub_util_error ("section %d does not exist", cur_index);
424
425 sym->st_value = (grub_target_to_host (sym->st_value)
426 + section_addresses[cur_index]);
427
428 if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info)
429 == STT_FUNC)
430 {
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++;
436 }
437 grub_util_info ("locating %s at 0x%llx (0x%llx)", name,
438 (unsigned long long) sym->st_value,
439 (unsigned long long) section_addresses[cur_index]);
440
441 if (! start_address)
442 if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0)
443 start_address = sym->st_value;
444 }
445
446 return start_address;
447 }
448
449 /* Return the address of a symbol at the index I in the section S. */
450 static Elf_Addr
451 SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i,
452 const struct grub_install_image_target_desc *image_target)
453 {
454 Elf_Sym *sym;
455
456 sym = (Elf_Sym *) ((char *) e
457 + grub_target_to_host (s->sh_offset)
458 + i * grub_target_to_host (s->sh_entsize));
459 return sym->st_value;
460 }
461
462 /* Return the address of a modified value. */
463 static Elf_Addr *
464 SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset,
465 const struct grub_install_image_target_desc *image_target)
466 {
467 return (Elf_Addr *) ((char *) e + grub_target_to_host (s->sh_offset) + offset);
468 }
469
470 #ifdef MKIMAGE_ELF64
471 static Elf_Addr
472 SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section,
473 const struct grub_install_image_target_desc *image_target)
474 {
475 Elf_Word symtab_size, sym_size, num_syms;
476 Elf_Off symtab_offset;
477 Elf_Sym *sym;
478 Elf_Word i;
479 int ret = 0;
480
481 symtab_size = grub_target_to_host (symtab_section->sh_size);
482 sym_size = grub_target_to_host (symtab_section->sh_entsize);
483 symtab_offset = grub_target_to_host (symtab_section->sh_offset);
484 num_syms = symtab_size / sym_size;
485
486 for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
487 i < num_syms;
488 i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
489 if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
490 ret++;
491
492 return ret;
493 }
494 #endif
495
496 #ifdef MKIMAGE_ELF32
497 /* Deal with relocation information. This function relocates addresses
498 within the virtual address space starting from 0. So only relative
499 addresses can be fully resolved. Absolute addresses must be relocated
500 again by a PE32 relocator when loaded. */
501 static grub_size_t
502 arm_get_trampoline_size (Elf_Ehdr *e,
503 Elf_Shdr *sections,
504 Elf_Half section_entsize,
505 Elf_Half num_sections,
506 const struct grub_install_image_target_desc *image_target)
507 {
508 Elf_Half i;
509 Elf_Shdr *s;
510 grub_size_t ret = 0;
511
512 for (i = 0, s = sections;
513 i < num_sections;
514 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
515 if ((s->sh_type == grub_host_to_target32 (SHT_REL)) ||
516 (s->sh_type == grub_host_to_target32 (SHT_RELA)))
517 {
518 Elf_Rela *r;
519 Elf_Word rtab_size, r_size, num_rs;
520 Elf_Off rtab_offset;
521 Elf_Shdr *symtab_section;
522 Elf_Word j;
523
524 symtab_section = (Elf_Shdr *) ((char *) sections
525 + (grub_target_to_host32 (s->sh_link)
526 * section_entsize));
527
528 rtab_size = grub_target_to_host (s->sh_size);
529 r_size = grub_target_to_host (s->sh_entsize);
530 rtab_offset = grub_target_to_host (s->sh_offset);
531 num_rs = rtab_size / r_size;
532
533 for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset);
534 j < num_rs;
535 j++, r = (Elf_Rela *) ((char *) r + r_size))
536 {
537 Elf_Addr info;
538 Elf_Addr sym_addr;
539
540 info = grub_target_to_host (r->r_info);
541 sym_addr = SUFFIX (get_symbol_address) (e, symtab_section,
542 ELF_R_SYM (info), image_target);
543
544 sym_addr += (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
545 grub_target_to_host (r->r_addend) : 0;
546
547 switch (ELF_R_TYPE (info))
548 {
549 case R_ARM_ABS32:
550 case R_ARM_V4BX:
551 break;
552 case R_ARM_THM_CALL:
553 case R_ARM_THM_JUMP24:
554 case R_ARM_THM_JUMP19:
555 if (!(sym_addr & 1))
556 ret += 8;
557 break;
558
559 case R_ARM_CALL:
560 case R_ARM_JUMP24:
561 if (sym_addr & 1)
562 ret += 16;
563 break;
564
565 default:
566 grub_util_error (_("relocation 0x%x is not implemented yet!"), ELF_R_TYPE (info));
567 break;
568 }
569 }
570 }
571 return ret;
572 }
573 #endif
574
575 /* Deal with relocation information. This function relocates addresses
576 within the virtual address space starting from 0. So only relative
577 addresses can be fully resolved. Absolute addresses must be relocated
578 again by a PE32 relocator when loaded. */
579 static void
580 SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
581 Elf_Addr *section_addresses,
582 Elf_Half section_entsize, Elf_Half num_sections,
583 const char *strtab,
584 char *pe_target, Elf_Addr tramp_off,
585 Elf_Addr got_off,
586 const struct grub_install_image_target_desc *image_target)
587 {
588 Elf_Half i;
589 Elf_Shdr *s;
590 #ifdef MKIMAGE_ELF64
591 struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off);
592 grub_uint64_t *gpptr = (void *) (pe_target + got_off);
593 #define MASK19 ((1 << 19) - 1)
594 #else
595 grub_uint32_t *tr = (void *) (pe_target + tramp_off);
596 #endif
597
598 for (i = 0, s = sections;
599 i < num_sections;
600 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
601 if ((s->sh_type == grub_host_to_target32 (SHT_REL)) ||
602 (s->sh_type == grub_host_to_target32 (SHT_RELA)))
603 {
604 Elf_Rela *r;
605 Elf_Word rtab_size, r_size, num_rs;
606 Elf_Off rtab_offset;
607 Elf_Shdr *symtab_section;
608 Elf_Word target_section_index;
609 Elf_Addr target_section_addr;
610 Elf_Shdr *target_section;
611 Elf_Word j;
612
613 symtab_section = (Elf_Shdr *) ((char *) sections
614 + (grub_target_to_host32 (s->sh_link)
615 * section_entsize));
616 target_section_index = grub_target_to_host32 (s->sh_info);
617 target_section_addr = section_addresses[target_section_index];
618 target_section = (Elf_Shdr *) ((char *) sections
619 + (target_section_index
620 * section_entsize));
621
622 grub_util_info ("dealing with the relocation section %s for %s",
623 strtab + grub_target_to_host32 (s->sh_name),
624 strtab + grub_target_to_host32 (target_section->sh_name));
625
626 rtab_size = grub_target_to_host (s->sh_size);
627 r_size = grub_target_to_host (s->sh_entsize);
628 rtab_offset = grub_target_to_host (s->sh_offset);
629 num_rs = rtab_size / r_size;
630
631 for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset);
632 j < num_rs;
633 j++, r = (Elf_Rela *) ((char *) r + r_size))
634 {
635 Elf_Addr info;
636 Elf_Addr offset;
637 Elf_Addr sym_addr;
638 Elf_Addr *target;
639 Elf_Addr addend;
640
641 offset = grub_target_to_host (r->r_offset);
642 target = SUFFIX (get_target_address) (e, target_section,
643 offset, image_target);
644 info = grub_target_to_host (r->r_info);
645 sym_addr = SUFFIX (get_symbol_address) (e, symtab_section,
646 ELF_R_SYM (info), image_target);
647
648 addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
649 grub_target_to_host (r->r_addend) : 0;
650
651 switch (image_target->elf_target)
652 {
653 case EM_386:
654 switch (ELF_R_TYPE (info))
655 {
656 case R_386_NONE:
657 break;
658
659 case R_386_32:
660 /* This is absolute. */
661 *target = grub_host_to_target32 (grub_target_to_host32 (*target)
662 + addend + sym_addr);
663 grub_util_info ("relocating an R_386_32 entry to 0x%llx at the offset 0x%llx",
664 (unsigned long long) *target,
665 (unsigned long long) offset);
666 break;
667
668 case R_386_PC32:
669 /* This is relative. */
670 *target = grub_host_to_target32 (grub_target_to_host32 (*target)
671 + addend + sym_addr
672 - target_section_addr - offset
673 - image_target->vaddr_offset);
674 grub_util_info ("relocating an R_386_PC32 entry to 0x%llx at the offset 0x%llx",
675 (unsigned long long) *target,
676 (unsigned long long) offset);
677 break;
678 default:
679 grub_util_error (_("relocation 0x%llx is not implemented yet"),
680 (unsigned long long) ELF_R_TYPE (info));
681 break;
682 }
683 break;
684 #ifdef MKIMAGE_ELF64
685 case EM_X86_64:
686 switch (ELF_R_TYPE (info))
687 {
688
689 case R_X86_64_NONE:
690 break;
691
692 case R_X86_64_64:
693 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
694 + addend + sym_addr);
695 grub_util_info ("relocating an R_X86_64_64 entry to 0x%llx at the offset 0x%llx",
696 (unsigned long long) *target,
697 (unsigned long long) offset);
698 break;
699
700 case R_X86_64_PC32:
701 {
702 grub_uint32_t *t32 = (grub_uint32_t *) target;
703 *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
704 + addend + sym_addr
705 - target_section_addr - offset
706 - image_target->vaddr_offset);
707 grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%llx",
708 *t32, (unsigned long long) offset);
709 break;
710 }
711
712 case R_X86_64_32:
713 case R_X86_64_32S:
714 {
715 grub_uint32_t *t32 = (grub_uint32_t *) target;
716 *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
717 + addend + sym_addr);
718 grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%llx",
719 *t32, (unsigned long long) offset);
720 break;
721 }
722
723 default:
724 grub_util_error (_("relocation 0x%llx is not implemented yet"),
725 (unsigned long long) ELF_R_TYPE (info));
726 break;
727 }
728 break;
729 case EM_IA_64:
730 switch (ELF_R_TYPE (info))
731 {
732 case R_IA64_PCREL21B:
733 {
734 grub_uint64_t noff;
735 grub_ia64_make_trampoline (tr, addend + sym_addr);
736 noff = ((char *) tr - (char *) pe_target
737 - target_section_addr - (offset & ~3)) >> 4;
738 tr++;
739 if (noff & ~MASK19)
740 grub_util_error ("trampoline offset too big (%"
741 PRIxGRUB_UINT64_T ")", noff);
742 grub_ia64_add_value_to_slot_20b ((grub_addr_t) target, noff);
743 }
744 break;
745
746 case R_IA64_LTOFF22X:
747 case R_IA64_LTOFF22:
748 {
749 Elf_Sym *sym;
750
751 sym = (Elf_Sym *) ((char *) e
752 + grub_target_to_host (symtab_section->sh_offset)
753 + ELF_R_SYM (info) * grub_target_to_host (symtab_section->sh_entsize));
754 if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
755 sym_addr = grub_target_to_host64 (*(grub_uint64_t *) (pe_target
756 + sym->st_value
757 - image_target->vaddr_offset));
758 }
759 case R_IA64_LTOFF_FPTR22:
760 *gpptr = grub_host_to_target64 (addend + sym_addr);
761 grub_ia64_add_value_to_slot_21 ((grub_addr_t) target,
762 (char *) gpptr - (char *) pe_target
763 + image_target->vaddr_offset);
764 gpptr++;
765 break;
766
767 case R_IA64_GPREL22:
768 grub_ia64_add_value_to_slot_21 ((grub_addr_t) target,
769 addend + sym_addr);
770 break;
771 case R_IA64_PCREL64LSB:
772 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
773 + addend + sym_addr
774 - target_section_addr - offset
775 - image_target->vaddr_offset);
776 break;
777
778 case R_IA64_SEGREL64LSB:
779 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
780 + addend + sym_addr - target_section_addr);
781 break;
782 case R_IA64_DIR64LSB:
783 case R_IA64_FPTR64LSB:
784 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
785 + addend + sym_addr);
786 grub_util_info ("relocating a direct entry to 0x%"
787 PRIxGRUB_UINT64_T " at the offset 0x%llx",
788 grub_target_to_host64 (*target),
789 (unsigned long long) offset);
790 break;
791
792 /* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */
793 case R_IA64_LDXMOV:
794 break;
795
796 default:
797 grub_util_error (_("relocation 0x%llx is not implemented yet"),
798 (unsigned long long) ELF_R_TYPE (info));
799 break;
800 }
801 break;
802 case EM_AARCH64:
803 {
804 sym_addr += addend;
805 switch (ELF_R_TYPE (info))
806 {
807 case R_AARCH64_ABS64:
808 {
809 *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr);
810 }
811 break;
812 case R_AARCH64_JUMP26:
813 case R_AARCH64_CALL26:
814 {
815 sym_addr -= offset;
816 sym_addr -= SUFFIX (entry_point);
817 if (!grub_arm_64_check_xxxx26_offset (sym_addr))
818 grub_util_error ("%s", _("CALL26 Relocation out of range"));
819
820 grub_arm64_set_xxxx26_offset((grub_uint32_t *)target,
821 sym_addr);
822 }
823 break;
824 default:
825 grub_util_error (_("relocation %d is not implemented yet"),
826 (unsigned long long) ELF_R_TYPE (info));
827 break;
828 }
829 break;
830 }
831 #endif
832 #if defined(MKIMAGE_ELF32)
833 case EM_ARM:
834 {
835 sym_addr += addend;
836 sym_addr -= SUFFIX (entry_point);
837 switch (ELF_R_TYPE (info))
838 {
839 case R_ARM_ABS32:
840 {
841 grub_util_info (" ABS32:\toffset=%d\t(0x%08x)",
842 (int) sym_addr, (int) sym_addr);
843 /* Data will be naturally aligned */
844 sym_addr += 0x400;
845 *target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr);
846 }
847 break;
848 /* Happens when compiled with -march=armv4.
849 Since currently we need at least armv5, keep bx as-is.
850 */
851 case R_ARM_V4BX:
852 break;
853 case R_ARM_THM_CALL:
854 case R_ARM_THM_JUMP24:
855 case R_ARM_THM_JUMP19:
856 {
857 grub_err_t err;
858 grub_util_info (" THM_JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)",
859 (unsigned long) ((char *) target
860 - (char *) e),
861 sym_addr);
862 if (!(sym_addr & 1))
863 {
864 grub_uint32_t tr_addr;
865 grub_int32_t new_offset;
866 tr_addr = (char *) tr - (char *) pe_target
867 - target_section_addr;
868 new_offset = sym_addr - tr_addr - 12;
869
870 if (!grub_arm_jump24_check_offset (new_offset))
871 return grub_util_error ("jump24 relocation out of range");
872
873 tr[0] = grub_host_to_target32 (0x46c04778); /* bx pc; nop */
874 tr[1] = grub_host_to_target32 (((new_offset >> 2) & 0xffffff) | 0xea000000); /* b new_offset */
875 tr += 2;
876 sym_addr = tr_addr | 1;
877 }
878 sym_addr -= offset;
879 /* Thumb instructions can be 16-bit aligned */
880 if (ELF_R_TYPE (info) == R_ARM_THM_JUMP19)
881 err = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr);
882 else
883 err = grub_arm_reloc_thm_call ((grub_uint16_t *) target,
884 sym_addr);
885 if (err)
886 grub_util_error ("%s", grub_errmsg);
887 }
888 break;
889
890 case R_ARM_CALL:
891 case R_ARM_JUMP24:
892 {
893 grub_err_t err;
894 grub_util_info (" JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", (unsigned long) ((char *) target - (char *) e), sym_addr);
895 if (sym_addr & 1)
896 {
897 grub_uint32_t tr_addr;
898 grub_int32_t new_offset;
899 tr_addr = (char *) tr - (char *) pe_target
900 - target_section_addr;
901 new_offset = sym_addr - tr_addr - 12;
902
903 /* There is no immediate version of bx, only register one... */
904 tr[0] = grub_host_to_target32 (0xe59fc004); /* ldr ip, [pc, #4] */
905 tr[1] = grub_host_to_target32 (0xe08cc00f); /* add ip, ip, pc */
906 tr[2] = grub_host_to_target32 (0xe12fff1c); /* bx ip */
907 tr[3] = grub_host_to_target32 (new_offset | 1);
908 tr += 4;
909 sym_addr = tr_addr;
910 }
911 sym_addr -= offset;
912 err = grub_arm_reloc_jump24 (target,
913 sym_addr);
914 if (err)
915 grub_util_error ("%s", grub_errmsg);
916 }
917 break;
918
919 default:
920 grub_util_error (_("relocation 0x%x is not implemented yet!"), ELF_R_TYPE (info));
921 break;
922 }
923 break;
924 }
925 #endif /* MKIMAGE_ELF32 */
926 default:
927 grub_util_error ("unknown architecture type %d",
928 image_target->elf_target);
929 }
930 }
931 }
932 }
933
934 /* Add a PE32's fixup entry for a relocation. Return the resulting address
935 after having written to the file OUT. */
936 static Elf_Addr
937 SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type,
938 Elf_Addr addr, int flush, Elf_Addr current_address,
939 const struct grub_install_image_target_desc *image_target)
940 {
941 struct grub_pe32_fixup_block *b;
942
943 b = &((*cblock)->b);
944
945 /* First, check if it is necessary to write out the current block. */
946 if ((*cblock)->state)
947 {
948 if (flush || addr < b->page_rva || b->page_rva + 0x1000 <= addr)
949 {
950 grub_uint32_t size;
951
952 if (flush)
953 {
954 /* Add as much padding as necessary to align the address
955 with a section boundary. */
956 Elf_Addr next_address;
957 unsigned padding_size;
958 size_t cur_index;
959
960 next_address = current_address + b->block_size;
961 padding_size = ((ALIGN_UP (next_address, image_target->section_align)
962 - next_address)
963 >> 1);
964 cur_index = ((b->block_size - sizeof (*b)) >> 1);
965 grub_util_info ("adding %d padding fixup entries", padding_size);
966 while (padding_size--)
967 {
968 b->entries[cur_index++] = 0;
969 b->block_size += 2;
970 }
971 }
972 else while (b->block_size & (8 - 1))
973 {
974 /* If not aligned with a 32-bit boundary, add
975 a padding entry. */
976 size_t cur_index;
977
978 grub_util_info ("adding a padding fixup entry");
979 cur_index = ((b->block_size - sizeof (*b)) >> 1);
980 b->entries[cur_index] = 0;
981 b->block_size += 2;
982 }
983
984 /* Flush it. */
985 grub_util_info ("writing %d bytes of a fixup block starting at 0x%x",
986 b->block_size, b->page_rva);
987 size = b->block_size;
988 current_address += size;
989 b->page_rva = grub_host_to_target32 (b->page_rva);
990 b->block_size = grub_host_to_target32 (b->block_size);
991 (*cblock)->next = xmalloc (sizeof (**cblock) + 2 * 0x1000);
992 memset ((*cblock)->next, 0, sizeof (**cblock) + 2 * 0x1000);
993 *cblock = (*cblock)->next;
994 }
995 }
996
997 b = &((*cblock)->b);
998
999 if (! flush)
1000 {
1001 grub_uint16_t entry;
1002 size_t cur_index;
1003
1004 /* If not allocated yet, allocate a block with enough entries. */
1005 if (! (*cblock)->state)
1006 {
1007 (*cblock)->state = 1;
1008
1009 /* The spec does not mention the requirement of a Page RVA.
1010 Here, align the address with a 4K boundary for safety. */
1011 b->page_rva = (addr & ~(0x1000 - 1));
1012 b->block_size = sizeof (*b);
1013 }
1014
1015 /* Sanity check. */
1016 if (b->block_size >= sizeof (*b) + 2 * 0x1000)
1017 grub_util_error ("too many fixup entries");
1018
1019 /* Add a new entry. */
1020 cur_index = ((b->block_size - sizeof (*b)) >> 1);
1021 entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva);
1022 b->entries[cur_index] = grub_host_to_target16 (entry);
1023 b->block_size += 2;
1024 }
1025
1026 return current_address;
1027 }
1028
1029 /* Make a .reloc section. */
1030 static Elf_Addr
1031 SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
1032 Elf_Addr *section_addresses, Elf_Shdr *sections,
1033 Elf_Half section_entsize, Elf_Half num_sections,
1034 const char *strtab,
1035 Elf_Addr jumpers, grub_size_t njumpers,
1036 const struct grub_install_image_target_desc *image_target)
1037 {
1038 unsigned i;
1039 Elf_Shdr *s;
1040 struct fixup_block_list *lst, *lst0;
1041 Elf_Addr current_address = 0;
1042
1043 lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000);
1044 memset (lst, 0, sizeof (*lst) + 2 * 0x1000);
1045
1046 for (i = 0, s = sections; i < num_sections;
1047 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1048 if ((grub_target_to_host32 (s->sh_type) == SHT_REL) ||
1049 (grub_target_to_host32 (s->sh_type) == SHT_RELA))
1050 {
1051 Elf_Rel *r;
1052 Elf_Word rtab_size, r_size, num_rs;
1053 Elf_Off rtab_offset;
1054 Elf_Addr section_address;
1055 Elf_Word j;
1056
1057 grub_util_info ("translating the relocation section %s",
1058 strtab + grub_le_to_cpu32 (s->sh_name));
1059
1060 rtab_size = grub_target_to_host (s->sh_size);
1061 r_size = grub_target_to_host (s->sh_entsize);
1062 rtab_offset = grub_target_to_host (s->sh_offset);
1063 num_rs = rtab_size / r_size;
1064
1065 section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)];
1066
1067 for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset);
1068 j < num_rs;
1069 j++, r = (Elf_Rel *) ((char *) r + r_size))
1070 {
1071 Elf_Addr info;
1072 Elf_Addr offset;
1073
1074 offset = grub_target_to_host (r->r_offset);
1075 info = grub_target_to_host (r->r_info);
1076
1077 /* Necessary to relocate only absolute addresses. */
1078 switch (image_target->elf_target)
1079 {
1080 case EM_386:
1081 if (ELF_R_TYPE (info) == R_386_32)
1082 {
1083 Elf_Addr addr;
1084
1085 addr = section_address + offset;
1086 grub_util_info ("adding a relocation entry for 0x%llx",
1087 (unsigned long long) addr);
1088 current_address
1089 = SUFFIX (add_fixup_entry) (&lst,
1090 GRUB_PE32_REL_BASED_HIGHLOW,
1091 addr, 0, current_address,
1092 image_target);
1093 }
1094 break;
1095 case EM_X86_64:
1096 if ((ELF_R_TYPE (info) == R_X86_64_32) ||
1097 (ELF_R_TYPE (info) == R_X86_64_32S))
1098 {
1099 grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)");
1100 }
1101 else if (ELF_R_TYPE (info) == R_X86_64_64)
1102 {
1103 Elf_Addr addr;
1104
1105 addr = section_address + offset;
1106 grub_util_info ("adding a relocation entry for 0x%llx",
1107 (unsigned long long) addr);
1108 current_address
1109 = SUFFIX (add_fixup_entry) (&lst,
1110 GRUB_PE32_REL_BASED_DIR64,
1111 addr,
1112 0, current_address,
1113 image_target);
1114 }
1115 break;
1116 case EM_IA_64:
1117 switch (ELF_R_TYPE (info))
1118 {
1119 case R_IA64_PCREL64LSB:
1120 case R_IA64_LDXMOV:
1121 case R_IA64_PCREL21B:
1122 case R_IA64_LTOFF_FPTR22:
1123 case R_IA64_LTOFF22X:
1124 case R_IA64_LTOFF22:
1125 case R_IA64_GPREL22:
1126 case R_IA64_SEGREL64LSB:
1127 break;
1128
1129 case R_IA64_FPTR64LSB:
1130 case R_IA64_DIR64LSB:
1131 #if 1
1132 {
1133 Elf_Addr addr;
1134
1135 addr = section_address + offset;
1136 grub_util_info ("adding a relocation entry for 0x%llx",
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);
1144 }
1145 #endif
1146 break;
1147 default:
1148 grub_util_error (_("relocation 0x%llx is not implemented yet"),
1149 (unsigned long long) ELF_R_TYPE (info));
1150 break;
1151 }
1152 break;
1153 case EM_AARCH64:
1154 switch (ELF_R_TYPE (info))
1155 {
1156 case R_AARCH64_ABS64:
1157 {
1158 Elf_Addr addr;
1159
1160 addr = section_address + offset;
1161 current_address
1162 = SUFFIX (add_fixup_entry) (&lst,
1163 GRUB_PE32_REL_BASED_DIR64,
1164 addr, 0, current_address,
1165 image_target);
1166 }
1167 break;
1168 /* Relative relocations do not require fixup entries. */
1169 case R_AARCH64_CALL26:
1170 case R_AARCH64_JUMP26:
1171 break;
1172 default:
1173 grub_util_error (_("fixup for relocation %d is not implemented yet"),
1174 (unsigned long long) ELF_R_TYPE (info));
1175 break;
1176 }
1177 break;
1178 break;
1179 #if defined(MKIMAGE_ELF32)
1180 case EM_ARM:
1181 switch (ELF_R_TYPE (info))
1182 {
1183 case R_ARM_V4BX:
1184 /* Relative relocations do not require fixup entries. */
1185 case R_ARM_JUMP24:
1186 case R_ARM_THM_CALL:
1187 case R_ARM_THM_JUMP19:
1188 case R_ARM_THM_JUMP24:
1189 case R_ARM_CALL:
1190 {
1191 Elf_Addr addr;
1192
1193 addr = section_address + offset;
1194 grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) current_address);
1195 }
1196 break;
1197 /* Create fixup entry for PE/COFF loader */
1198 case R_ARM_ABS32:
1199 {
1200 Elf_Addr addr;
1201
1202 addr = section_address + offset;
1203 current_address
1204 = SUFFIX (add_fixup_entry) (&lst,
1205 GRUB_PE32_REL_BASED_HIGHLOW,
1206 addr, 0, current_address,
1207 image_target);
1208 }
1209 break;
1210 default:
1211 grub_util_error (_("fixup for relocation 0x%x not implemented"), ELF_R_TYPE (info));
1212 break;
1213 }
1214 break;
1215 #endif /* defined(MKIMAGE_ELF32) */
1216 default:
1217 grub_util_error ("unknown machine type 0x%x", image_target->elf_target);
1218 }
1219 }
1220 }
1221
1222 if (image_target->elf_target == EM_IA_64)
1223 for (i = 0; i < njumpers; i++)
1224 current_address = SUFFIX (add_fixup_entry) (&lst,
1225 GRUB_PE32_REL_BASED_DIR64,
1226 jumpers + 8 * i,
1227 0, current_address,
1228 image_target);
1229
1230 current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target);
1231
1232 {
1233 grub_uint8_t *ptr;
1234 ptr = *out = xmalloc (current_address);
1235 for (lst = lst0; lst; lst = lst->next)
1236 if (lst->state)
1237 {
1238 memcpy (ptr, &lst->b, grub_target_to_host32 (lst->b.block_size));
1239 ptr += grub_target_to_host32 (lst->b.block_size);
1240 }
1241 assert ((current_address + (grub_uint8_t *) *out) == ptr);
1242 }
1243
1244 for (lst = lst0; lst; )
1245 {
1246 struct fixup_block_list *next;
1247 next = lst->next;
1248 free (lst);
1249 lst = next;
1250 }
1251
1252 return current_address;
1253 }
1254
1255 /* Determine if this section is a text section. Return false if this
1256 section is not allocated. */
1257 static int
1258 SUFFIX (is_text_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
1259 {
1260 if (image_target->id != IMAGE_EFI
1261 && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
1262 return 0;
1263 return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
1264 == (SHF_EXECINSTR | SHF_ALLOC));
1265 }
1266
1267 /* Determine if this section is a data section. This assumes that
1268 BSS is also a data section, since the converter initializes BSS
1269 when producing PE32 to avoid a bug in EFI implementations. */
1270 static int
1271 SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
1272 {
1273 if (image_target->id != IMAGE_EFI
1274 && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
1275 return 0;
1276 return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
1277 == SHF_ALLOC);
1278 }
1279
1280 /* Return if the ELF header is valid. */
1281 static int
1282 SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_image_target_desc *image_target)
1283 {
1284 if (size < sizeof (*e)
1285 || e->e_ident[EI_MAG0] != ELFMAG0
1286 || e->e_ident[EI_MAG1] != ELFMAG1
1287 || e->e_ident[EI_MAG2] != ELFMAG2
1288 || e->e_ident[EI_MAG3] != ELFMAG3
1289 || e->e_ident[EI_VERSION] != EV_CURRENT
1290 || e->e_ident[EI_CLASS] != ELFCLASSXX
1291 || e->e_version != grub_host_to_target32 (EV_CURRENT))
1292 return 0;
1293
1294 return 1;
1295 }
1296
1297 /* Locate section addresses by merging code sections and data sections
1298 into .text and .data, respectively. Return the array of section
1299 addresses. */
1300 static Elf_Addr *
1301 SUFFIX (locate_sections) (const char *kernel_path,
1302 Elf_Shdr *sections, Elf_Half section_entsize,
1303 Elf_Half num_sections, const char *strtab,
1304 size_t *exec_size, size_t *kernel_sz,
1305 size_t *all_align,
1306 const struct grub_install_image_target_desc *image_target)
1307 {
1308 int i;
1309 Elf_Addr current_address;
1310 Elf_Addr *section_addresses;
1311 Elf_Shdr *s;
1312
1313 *all_align = 1;
1314
1315 section_addresses = xmalloc (sizeof (*section_addresses) * num_sections);
1316 memset (section_addresses, 0, sizeof (*section_addresses) * num_sections);
1317
1318 current_address = 0;
1319
1320 for (i = 0, s = sections;
1321 i < num_sections;
1322 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1323 if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC)
1324 && grub_host_to_target32 (s->sh_addralign) > *all_align)
1325 *all_align = grub_host_to_target32 (s->sh_addralign);
1326
1327
1328 /* .text */
1329 for (i = 0, s = sections;
1330 i < num_sections;
1331 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1332 if (SUFFIX (is_text_section) (s, image_target))
1333 {
1334 Elf_Word align = grub_host_to_target_addr (s->sh_addralign);
1335 const char *name = strtab + grub_host_to_target32 (s->sh_name);
1336 if (align)
1337 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1338 align) - image_target->vaddr_offset;
1339 grub_util_info ("locating the section %s at 0x%llx",
1340 name, (unsigned long long) current_address);
1341 if (image_target->id != IMAGE_EFI)
1342 {
1343 current_address = grub_host_to_target_addr (s->sh_addr)
1344 - image_target->link_addr;
1345 if (grub_host_to_target_addr (s->sh_addr)
1346 != image_target->link_addr)
1347 grub_util_error ("`%s' is miscompiled: it's start address is 0x%llx"
1348 " instead of 0x%llx: ld.gold bug?",
1349 kernel_path,
1350 (unsigned long long) grub_host_to_target_addr (s->sh_addr),
1351 (unsigned long long) image_target->link_addr);
1352 }
1353 section_addresses[i] = current_address;
1354 current_address += grub_host_to_target_addr (s->sh_size);
1355 }
1356
1357 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1358 image_target->section_align)
1359 - image_target->vaddr_offset;
1360 *exec_size = current_address;
1361
1362 /* .data */
1363 for (i = 0, s = sections;
1364 i < num_sections;
1365 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1366 if (SUFFIX (is_data_section) (s, image_target))
1367 {
1368 Elf_Word align = grub_host_to_target_addr (s->sh_addralign);
1369 const char *name = strtab + grub_host_to_target32 (s->sh_name);
1370
1371 if (align)
1372 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1373 align)
1374 - image_target->vaddr_offset;
1375
1376 grub_util_info ("locating the section %s at 0x%llx",
1377 name, (unsigned long long) current_address);
1378 if (image_target->id != IMAGE_EFI)
1379 current_address = grub_host_to_target_addr (s->sh_addr)
1380 - image_target->link_addr;
1381 section_addresses[i] = current_address;
1382 current_address += grub_host_to_target_addr (s->sh_size);
1383 }
1384
1385 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1386 image_target->section_align) - image_target->vaddr_offset;
1387 *kernel_sz = current_address;
1388 return section_addresses;
1389 }
1390
1391 static char *
1392 SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
1393 size_t *kernel_sz, size_t *bss_size,
1394 size_t total_module_size, grub_uint64_t *start,
1395 void **reloc_section, size_t *reloc_size,
1396 size_t *align,
1397 const struct grub_install_image_target_desc *image_target)
1398 {
1399 char *kernel_img, *out_img;
1400 const char *strtab;
1401 Elf_Ehdr *e;
1402 Elf_Shdr *sections;
1403 Elf_Addr *section_addresses;
1404 Elf_Addr *section_vaddresses;
1405 int i;
1406 Elf_Shdr *s;
1407 Elf_Half num_sections;
1408 Elf_Off section_offset;
1409 Elf_Half section_entsize;
1410 grub_size_t kernel_size;
1411 grub_size_t ia64jmp_off = 0, tramp_off = 0, ia64_got_off = 0;
1412 unsigned ia64jmpnum = 0;
1413 Elf_Shdr *symtab_section = 0;
1414 grub_size_t got = 0;
1415
1416 *start = 0;
1417
1418 kernel_size = grub_util_get_image_size (kernel_path);
1419 kernel_img = xmalloc (kernel_size);
1420 grub_util_load_image (kernel_path, kernel_img);
1421
1422 e = (Elf_Ehdr *) kernel_img;
1423 if (! SUFFIX (check_elf_header) (e, kernel_size, image_target))
1424 grub_util_error ("invalid ELF header");
1425
1426 section_offset = grub_target_to_host (e->e_shoff);
1427 section_entsize = grub_target_to_host16 (e->e_shentsize);
1428 num_sections = grub_target_to_host16 (e->e_shnum);
1429
1430 if (kernel_size < section_offset + section_entsize * num_sections)
1431 grub_util_error (_("premature end of file %s"), kernel_path);
1432
1433 sections = (Elf_Shdr *) (kernel_img + section_offset);
1434
1435 /* Relocate sections then symbols in the virtual address space. */
1436 s = (Elf_Shdr *) ((char *) sections
1437 + grub_host_to_target16 (e->e_shstrndx) * section_entsize);
1438 strtab = (char *) e + grub_host_to_target_addr (s->sh_offset);
1439
1440 section_addresses = SUFFIX (locate_sections) (kernel_path,
1441 sections, section_entsize,
1442 num_sections, strtab,
1443 exec_size, kernel_sz, align,
1444 image_target);
1445
1446 section_vaddresses = xmalloc (sizeof (*section_addresses) * num_sections);
1447
1448 for (i = 0; i < num_sections; i++)
1449 section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset;
1450
1451 if (image_target->id != IMAGE_EFI)
1452 {
1453 Elf_Addr current_address = *kernel_sz;
1454
1455 for (i = 0, s = sections;
1456 i < num_sections;
1457 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1458 if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
1459 {
1460 Elf_Word sec_align = grub_host_to_target_addr (s->sh_addralign);
1461 const char *name = strtab + grub_host_to_target32 (s->sh_name);
1462
1463 if (sec_align)
1464 current_address = ALIGN_UP (current_address
1465 + image_target->vaddr_offset,
1466 sec_align)
1467 - image_target->vaddr_offset;
1468
1469 grub_util_info ("locating the section %s at 0x%llx",
1470 name, (unsigned long long) current_address);
1471 if (image_target->id != IMAGE_EFI)
1472 current_address = grub_host_to_target_addr (s->sh_addr)
1473 - image_target->link_addr;
1474
1475 section_vaddresses[i] = current_address
1476 + image_target->vaddr_offset;
1477 current_address += grub_host_to_target_addr (s->sh_size);
1478 }
1479 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
1480 image_target->section_align)
1481 - image_target->vaddr_offset;
1482 *bss_size = current_address - *kernel_sz;
1483 }
1484 else
1485 *bss_size = 0;
1486
1487 if (image_target->id == IMAGE_SPARC64_AOUT
1488 || image_target->id == IMAGE_SPARC64_RAW
1489 || image_target->id == IMAGE_SPARC64_CDCORE)
1490 *kernel_sz = ALIGN_UP (*kernel_sz, image_target->mod_align);
1491
1492 if (image_target->id == IMAGE_EFI)
1493 {
1494 symtab_section = NULL;
1495 for (i = 0, s = sections;
1496 i < num_sections;
1497 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1498 if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB))
1499 {
1500 symtab_section = s;
1501 break;
1502 }
1503
1504 #ifdef MKIMAGE_ELF32
1505 if (image_target->elf_target == EM_ARM)
1506 {
1507 grub_size_t tramp;
1508
1509 *kernel_sz = ALIGN_UP (*kernel_sz, 16);
1510
1511 tramp = arm_get_trampoline_size (e, sections, section_entsize,
1512 num_sections, image_target);
1513
1514 tramp_off = *kernel_sz;
1515 *kernel_sz += ALIGN_UP (tramp, 16);
1516 }
1517 #endif
1518
1519 #ifdef MKIMAGE_ELF64
1520 if (image_target->elf_target == EM_IA_64)
1521 {
1522 grub_size_t tramp;
1523
1524 *kernel_sz = ALIGN_UP (*kernel_sz, 16);
1525
1526 grub_ia64_dl_get_tramp_got_size (e, &tramp, &got);
1527
1528 tramp_off = *kernel_sz;
1529 *kernel_sz += ALIGN_UP (tramp, 16);
1530
1531 ia64jmp_off = *kernel_sz;
1532 ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section,
1533 image_target);
1534 *kernel_sz += 16 * ia64jmpnum;
1535
1536 ia64_got_off = *kernel_sz;
1537 *kernel_sz += ALIGN_UP (got, 16);
1538 }
1539 #endif
1540
1541 if (! symtab_section)
1542 grub_util_error ("%s", _("no symbol table"));
1543 }
1544 else
1545 {
1546 *reloc_size = 0;
1547 *reloc_section = NULL;
1548 }
1549
1550 out_img = xmalloc (*kernel_sz + total_module_size);
1551
1552 if (image_target->id == IMAGE_EFI)
1553 {
1554 *start = SUFFIX (relocate_symbols) (e, sections, symtab_section,
1555 section_vaddresses, section_entsize,
1556 num_sections,
1557 (char *) out_img + ia64jmp_off,
1558 ia64jmp_off
1559 + image_target->vaddr_offset,
1560 image_target);
1561 if (*start == 0)
1562 grub_util_error ("start symbol is not defined");
1563
1564 SUFFIX (entry_point) = (Elf_Addr) *start;
1565
1566 /* Resolve addresses in the virtual address space. */
1567 SUFFIX (relocate_addresses) (e, sections, section_addresses,
1568 section_entsize,
1569 num_sections, strtab,
1570 out_img, tramp_off, ia64_got_off,
1571 image_target);
1572
1573 *reloc_size = SUFFIX (make_reloc_section) (e, reloc_section,
1574 section_vaddresses, sections,
1575 section_entsize, num_sections,
1576 strtab, ia64jmp_off
1577 + image_target->vaddr_offset,
1578 2 * ia64jmpnum + (got / 8),
1579 image_target);
1580 }
1581
1582 for (i = 0, s = sections;
1583 i < num_sections;
1584 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1585 if (SUFFIX (is_data_section) (s, image_target)
1586 || SUFFIX (is_text_section) (s, image_target))
1587 {
1588 if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
1589 memset (out_img + section_addresses[i], 0,
1590 grub_host_to_target_addr (s->sh_size));
1591 else
1592 memcpy (out_img + section_addresses[i],
1593 kernel_img + grub_host_to_target_addr (s->sh_offset),
1594 grub_host_to_target_addr (s->sh_size));
1595 }
1596 free (kernel_img);
1597
1598 free (section_vaddresses);
1599 free (section_addresses);
1600
1601 return out_img;
1602 }
1603
1604
1605 #undef SUFFIX
1606 #undef ELFCLASSXX
1607 #undef Elf_Ehdr
1608 #undef Elf_Phdr
1609 #undef Elf_Nhdr
1610 #undef Elf_Shdr
1611 #undef Elf_Addr
1612 #undef Elf_Sym
1613 #undef Elf_Off
1614 #undef Elf_Rela
1615 #undef Elf_Rel
1616 #undef ELF_R_TYPE
1617 #undef ELF_R_SYM
1618 #undef Elf_Word
1619 #undef Elf_Half
1620 #undef Elf_Section
1621 #undef ELF_ST_TYPE
1622 #undef XEN_NOTE_SIZE