]> git.proxmox.com Git - grub2.git/blob - util/grub-mkimagexx.c
* util/grub-fstest.c: Fix several printf formats.
[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_Addr Elf32_Addr
29 # define Elf_Sym Elf32_Sym
30 # define Elf_Off Elf32_Off
31 # define Elf_Shdr Elf32_Shdr
32 # define Elf_Rela Elf32_Rela
33 # define Elf_Rel Elf32_Rel
34 # define Elf_Word Elf32_Word
35 # define Elf_Half Elf32_Half
36 # define Elf_Section Elf32_Section
37 # define ELF_R_SYM(val) ELF32_R_SYM(val)
38 # define ELF_R_TYPE(val) ELF32_R_TYPE(val)
39 # define ELF_ST_TYPE(val) ELF32_ST_TYPE(val)
40 #elif defined(MKIMAGE_ELF64)
41 # define SUFFIX(x) x ## 64
42 # define ELFCLASSXX ELFCLASS64
43 # define Elf_Ehdr Elf64_Ehdr
44 # define Elf_Phdr Elf64_Phdr
45 # define Elf_Addr Elf64_Addr
46 # define Elf_Sym Elf64_Sym
47 # define Elf_Off Elf64_Off
48 # define Elf_Shdr Elf64_Shdr
49 # define Elf_Rela Elf64_Rela
50 # define Elf_Rel Elf64_Rel
51 # define Elf_Word Elf64_Word
52 # define Elf_Half Elf64_Half
53 # define Elf_Section Elf64_Section
54 # define ELF_R_SYM(val) ELF64_R_SYM(val)
55 # define ELF_R_TYPE(val) ELF64_R_TYPE(val)
56 # define ELF_ST_TYPE(val) ELF64_ST_TYPE(val)
57 #else
58 #error "I'm confused"
59 #endif
60
61 static Elf_Addr SUFFIX (entry_point);
62
63 /* Relocate symbols; note that this function overwrites the symbol table.
64 Return the address of a start symbol. */
65 static Elf_Addr
66 SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
67 Elf_Shdr *symtab_section, Elf_Addr *section_addresses,
68 Elf_Half section_entsize, Elf_Half num_sections,
69 void *jumpers, Elf_Addr jumpers_addr,
70 struct image_target_desc *image_target)
71 {
72 Elf_Word symtab_size, sym_size, num_syms;
73 Elf_Off symtab_offset;
74 Elf_Addr start_address = 0;
75 Elf_Sym *sym;
76 Elf_Word i;
77 Elf_Shdr *strtab_section;
78 const char *strtab;
79 grub_uint64_t *jptr = jumpers;
80
81 strtab_section
82 = (Elf_Shdr *) ((char *) sections
83 + (grub_target_to_host32 (symtab_section->sh_link)
84 * section_entsize));
85 strtab = (char *) e + grub_target_to_host (strtab_section->sh_offset);
86
87 symtab_size = grub_target_to_host (symtab_section->sh_size);
88 sym_size = grub_target_to_host (symtab_section->sh_entsize);
89 symtab_offset = grub_target_to_host (symtab_section->sh_offset);
90 num_syms = symtab_size / sym_size;
91
92 for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
93 i < num_syms;
94 i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
95 {
96 Elf_Section cur_index;
97 const char *name;
98
99 name = strtab + grub_target_to_host32 (sym->st_name);
100
101 cur_index = grub_target_to_host16 (sym->st_shndx);
102 if (cur_index == STN_ABS)
103 {
104 continue;
105 }
106 else if ((cur_index == STN_UNDEF))
107 {
108 if (sym->st_name)
109 grub_util_error ("undefined symbol %s", name);
110 else
111 continue;
112 }
113 else if (cur_index >= num_sections)
114 grub_util_error ("section %d does not exist", cur_index);
115
116 sym->st_value = (grub_target_to_host (sym->st_value)
117 + section_addresses[cur_index]);
118
119 if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info)
120 == STT_FUNC)
121 {
122 *jptr = grub_host_to_target64 (sym->st_value);
123 sym->st_value = (char *) jptr - (char *) jumpers + jumpers_addr;
124 jptr++;
125 *jptr = 0;
126 jptr++;
127 }
128 grub_util_info ("locating %s at 0x%llx (0x%llx)", name,
129 (unsigned long long) sym->st_value,
130 (unsigned long long) section_addresses[cur_index]);
131
132 if (! start_address)
133 if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0)
134 start_address = sym->st_value;
135 }
136
137 return start_address;
138 }
139
140 /* Return the address of a symbol at the index I in the section S. */
141 static Elf_Addr
142 SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i,
143 struct image_target_desc *image_target)
144 {
145 Elf_Sym *sym;
146
147 sym = (Elf_Sym *) ((char *) e
148 + grub_target_to_host (s->sh_offset)
149 + i * grub_target_to_host (s->sh_entsize));
150 return sym->st_value;
151 }
152
153 /* Return the address of a modified value. */
154 static Elf_Addr *
155 SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset,
156 struct image_target_desc *image_target)
157 {
158 return (Elf_Addr *) ((char *) e + grub_target_to_host (s->sh_offset) + offset);
159 }
160
161 #ifdef MKIMAGE_ELF64
162 static Elf_Addr
163 SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section,
164 struct image_target_desc *image_target)
165 {
166 Elf_Word symtab_size, sym_size, num_syms;
167 Elf_Off symtab_offset;
168 Elf_Sym *sym;
169 Elf_Word i;
170 int ret = 0;
171
172 symtab_size = grub_target_to_host (symtab_section->sh_size);
173 sym_size = grub_target_to_host (symtab_section->sh_entsize);
174 symtab_offset = grub_target_to_host (symtab_section->sh_offset);
175 num_syms = symtab_size / sym_size;
176
177 for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
178 i < num_syms;
179 i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
180 if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
181 ret++;
182
183 return ret;
184 }
185 #endif
186
187 /* Deal with relocation information. This function relocates addresses
188 within the virtual address space starting from 0. So only relative
189 addresses can be fully resolved. Absolute addresses must be relocated
190 again by a PE32 relocator when loaded. */
191 static void
192 SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
193 Elf_Addr *section_addresses,
194 Elf_Half section_entsize, Elf_Half num_sections,
195 const char *strtab,
196 char *pe_target, Elf_Addr tramp_off,
197 Elf_Addr got_off,
198 struct image_target_desc *image_target)
199 {
200 Elf_Half i;
201 Elf_Shdr *s;
202 #ifdef MKIMAGE_ELF64
203 struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off);
204 grub_uint64_t *gpptr = (void *) (pe_target + got_off);
205 #define MASK19 ((1 << 19) - 1)
206 #endif
207
208 for (i = 0, s = sections;
209 i < num_sections;
210 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
211 if ((s->sh_type == grub_host_to_target32 (SHT_REL)) ||
212 (s->sh_type == grub_host_to_target32 (SHT_RELA)))
213 {
214 Elf_Rela *r;
215 Elf_Word rtab_size, r_size, num_rs;
216 Elf_Off rtab_offset;
217 Elf_Shdr *symtab_section;
218 Elf_Word target_section_index;
219 Elf_Addr target_section_addr;
220 Elf_Shdr *target_section;
221 Elf_Word j;
222
223 symtab_section = (Elf_Shdr *) ((char *) sections
224 + (grub_target_to_host32 (s->sh_link)
225 * section_entsize));
226 target_section_index = grub_target_to_host32 (s->sh_info);
227 target_section_addr = section_addresses[target_section_index];
228 target_section = (Elf_Shdr *) ((char *) sections
229 + (target_section_index
230 * section_entsize));
231
232 grub_util_info ("dealing with the relocation section %s for %s",
233 strtab + grub_target_to_host32 (s->sh_name),
234 strtab + grub_target_to_host32 (target_section->sh_name));
235
236 rtab_size = grub_target_to_host (s->sh_size);
237 r_size = grub_target_to_host (s->sh_entsize);
238 rtab_offset = grub_target_to_host (s->sh_offset);
239 num_rs = rtab_size / r_size;
240
241 for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset);
242 j < num_rs;
243 j++, r = (Elf_Rela *) ((char *) r + r_size))
244 {
245 Elf_Addr info;
246 Elf_Addr offset;
247 Elf_Addr sym_addr;
248 Elf_Addr *target;
249 Elf_Addr addend;
250
251 offset = grub_target_to_host (r->r_offset);
252 target = SUFFIX (get_target_address) (e, target_section,
253 offset, image_target);
254 info = grub_target_to_host (r->r_info);
255 sym_addr = SUFFIX (get_symbol_address) (e, symtab_section,
256 ELF_R_SYM (info), image_target);
257
258 addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
259 grub_target_to_host (r->r_addend) : 0;
260
261 switch (image_target->elf_target)
262 {
263 case EM_386:
264 switch (ELF_R_TYPE (info))
265 {
266 case R_386_NONE:
267 break;
268
269 case R_386_32:
270 /* This is absolute. */
271 *target = grub_host_to_target32 (grub_target_to_host32 (*target)
272 + addend + sym_addr);
273 grub_util_info ("relocating an R_386_32 entry to 0x%llx at the offset 0x%llx",
274 (unsigned long long) *target,
275 (unsigned long long) offset);
276 break;
277
278 case R_386_PC32:
279 /* This is relative. */
280 *target = grub_host_to_target32 (grub_target_to_host32 (*target)
281 + addend + sym_addr
282 - target_section_addr - offset
283 - image_target->vaddr_offset);
284 grub_util_info ("relocating an R_386_PC32 entry to 0x%llx at the offset 0x%llx",
285 (unsigned long long) *target,
286 (unsigned long long) offset);
287 break;
288 default:
289 grub_util_error (_("relocation 0x%llx is not implemented yet"),
290 (unsigned long long) ELF_R_TYPE (info));
291 break;
292 }
293 break;
294 #ifdef MKIMAGE_ELF64
295 case EM_X86_64:
296 switch (ELF_R_TYPE (info))
297 {
298
299 case R_X86_64_NONE:
300 break;
301
302 case R_X86_64_64:
303 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
304 + addend + sym_addr);
305 grub_util_info ("relocating an R_X86_64_64 entry to 0x%llx at the offset 0x%llx",
306 (unsigned long long) *target,
307 (unsigned long long) offset);
308 break;
309
310 case R_X86_64_PC32:
311 {
312 grub_uint32_t *t32 = (grub_uint32_t *) target;
313 *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
314 + addend + sym_addr
315 - target_section_addr - offset
316 - image_target->vaddr_offset);
317 grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%llx",
318 *t32, (unsigned long long) offset);
319 break;
320 }
321
322 case R_X86_64_32:
323 case R_X86_64_32S:
324 {
325 grub_uint32_t *t32 = (grub_uint32_t *) target;
326 *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
327 + addend + sym_addr);
328 grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%llx",
329 *t32, (unsigned long long) offset);
330 break;
331 }
332
333 default:
334 grub_util_error (_("relocation 0x%llx is not implemented yet"),
335 (unsigned long long) ELF_R_TYPE (info));
336 break;
337 }
338 break;
339 case EM_IA_64:
340 switch (ELF_R_TYPE (info))
341 {
342 case R_IA64_PCREL21B:
343 {
344 grub_uint64_t noff;
345 grub_ia64_make_trampoline (tr, addend + sym_addr);
346 noff = ((char *) tr - (char *) pe_target
347 - target_section_addr - (offset & ~3)) >> 4;
348 tr++;
349 if (noff & ~MASK19)
350 grub_util_error ("trampoline offset too big (%"
351 PRIxGRUB_UINT64_T ")", noff);
352 grub_ia64_add_value_to_slot_20b ((grub_addr_t) target, noff);
353 }
354 break;
355
356 case R_IA64_LTOFF22X:
357 case R_IA64_LTOFF22:
358 {
359 Elf_Sym *sym;
360
361 sym = (Elf_Sym *) ((char *) e
362 + grub_target_to_host (symtab_section->sh_offset)
363 + ELF_R_SYM (info) * grub_target_to_host (symtab_section->sh_entsize));
364 if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
365 sym_addr = grub_target_to_host64 (*(grub_uint64_t *) (pe_target
366 + sym->st_value
367 - image_target->vaddr_offset));
368 }
369 case R_IA64_LTOFF_FPTR22:
370 *gpptr = grub_host_to_target64 (addend + sym_addr);
371 grub_ia64_add_value_to_slot_21 ((grub_addr_t) target,
372 (char *) gpptr - (char *) pe_target
373 + image_target->vaddr_offset);
374 gpptr++;
375 break;
376
377 case R_IA64_GPREL22:
378 grub_ia64_add_value_to_slot_21 ((grub_addr_t) target,
379 addend + sym_addr);
380 break;
381 case R_IA64_PCREL64LSB:
382 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
383 + addend + sym_addr
384 - target_section_addr - offset
385 - image_target->vaddr_offset);
386 break;
387
388 case R_IA64_SEGREL64LSB:
389 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
390 + addend + sym_addr - target_section_addr);
391 break;
392 case R_IA64_DIR64LSB:
393 case R_IA64_FPTR64LSB:
394 *target = grub_host_to_target64 (grub_target_to_host64 (*target)
395 + addend + sym_addr);
396 grub_util_info ("relocating a direct entry to 0x%"
397 PRIxGRUB_UINT64_T " at the offset 0x%llx",
398 grub_target_to_host64 (*target),
399 (unsigned long long) offset);
400 break;
401
402 /* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */
403 case R_IA64_LDXMOV:
404 break;
405
406 default:
407 grub_util_error (_("relocation 0x%llx is not implemented yet"),
408 (unsigned long long) ELF_R_TYPE (info));
409 break;
410 }
411 break;
412 #endif
413 #if defined(MKIMAGE_ELF32)
414 case EM_ARM:
415 {
416 sym_addr += addend;
417 sym_addr -= SUFFIX (entry_point);
418 switch (ELF_R_TYPE (info))
419 {
420 case R_ARM_ABS32:
421 {
422 grub_util_info (" ABS32:\toffset=%d\t(0x%08x)",
423 (int) sym_addr, (int) sym_addr);
424 /* Data will be naturally aligned */
425 sym_addr += 0x400;
426 *target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr);
427 }
428 break;
429 case R_ARM_THM_CALL:
430 case R_ARM_THM_JUMP24:
431 {
432 grub_err_t err;
433 grub_util_info (" THM_JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", (unsigned long) target, sym_addr);
434 sym_addr -= offset;
435 /* Thumb instructions can be 16-bit aligned */
436 err = grub_arm_reloc_thm_call ((grub_uint16_t *) target,
437 sym_addr);
438 if (err)
439 grub_util_error ("%s", grub_errmsg);
440 }
441 break;
442 case R_ARM_THM_JUMP19:
443 {
444 grub_err_t err;
445 grub_util_info (" THM_JUMP19:\toffset=%d\t(0x%08x)",
446 sym_addr, sym_addr);
447 sym_addr -= offset;
448
449 /* Thumb instructions can be 16-bit aligned */
450 err = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr);
451 if (err)
452 grub_util_error ("%s", grub_errmsg);
453 }
454 break;
455 default:
456 grub_util_error (_("relocation 0x%x is not implemented yet!"), ELF_R_TYPE (info));
457 break;
458 }
459 break;
460 }
461 #endif /* MKIMAGE_ELF32 */
462 default:
463 grub_util_error ("unknown architecture type %d",
464 image_target->elf_target);
465 }
466 }
467 }
468 }
469
470 /* Add a PE32's fixup entry for a relocation. Return the resulting address
471 after having written to the file OUT. */
472 static Elf_Addr
473 SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type,
474 Elf_Addr addr, int flush, Elf_Addr current_address,
475 struct image_target_desc *image_target)
476 {
477 struct grub_pe32_fixup_block *b;
478
479 b = &((*cblock)->b);
480
481 /* First, check if it is necessary to write out the current block. */
482 if ((*cblock)->state)
483 {
484 if (flush || addr < b->page_rva || b->page_rva + 0x1000 <= addr)
485 {
486 grub_uint32_t size;
487
488 if (flush)
489 {
490 /* Add as much padding as necessary to align the address
491 with a section boundary. */
492 Elf_Addr next_address;
493 unsigned padding_size;
494 size_t cur_index;
495
496 next_address = current_address + b->block_size;
497 padding_size = ((ALIGN_UP (next_address, image_target->section_align)
498 - next_address)
499 >> 1);
500 cur_index = ((b->block_size - sizeof (*b)) >> 1);
501 grub_util_info ("adding %d padding fixup entries", padding_size);
502 while (padding_size--)
503 {
504 b->entries[cur_index++] = 0;
505 b->block_size += 2;
506 }
507 }
508 else while (b->block_size & (8 - 1))
509 {
510 /* If not aligned with a 32-bit boundary, add
511 a padding entry. */
512 size_t cur_index;
513
514 grub_util_info ("adding a padding fixup entry");
515 cur_index = ((b->block_size - sizeof (*b)) >> 1);
516 b->entries[cur_index] = 0;
517 b->block_size += 2;
518 }
519
520 /* Flush it. */
521 grub_util_info ("writing %d bytes of a fixup block starting at 0x%x",
522 b->block_size, b->page_rva);
523 size = b->block_size;
524 current_address += size;
525 b->page_rva = grub_host_to_target32 (b->page_rva);
526 b->block_size = grub_host_to_target32 (b->block_size);
527 (*cblock)->next = xmalloc (sizeof (**cblock) + 2 * 0x1000);
528 memset ((*cblock)->next, 0, sizeof (**cblock) + 2 * 0x1000);
529 *cblock = (*cblock)->next;
530 }
531 }
532
533 b = &((*cblock)->b);
534
535 if (! flush)
536 {
537 grub_uint16_t entry;
538 size_t cur_index;
539
540 /* If not allocated yet, allocate a block with enough entries. */
541 if (! (*cblock)->state)
542 {
543 (*cblock)->state = 1;
544
545 /* The spec does not mention the requirement of a Page RVA.
546 Here, align the address with a 4K boundary for safety. */
547 b->page_rva = (addr & ~(0x1000 - 1));
548 b->block_size = sizeof (*b);
549 }
550
551 /* Sanity check. */
552 if (b->block_size >= sizeof (*b) + 2 * 0x1000)
553 grub_util_error ("too many fixup entries");
554
555 /* Add a new entry. */
556 cur_index = ((b->block_size - sizeof (*b)) >> 1);
557 entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva);
558 b->entries[cur_index] = grub_host_to_target16 (entry);
559 b->block_size += 2;
560 }
561
562 return current_address;
563 }
564
565 /* Make a .reloc section. */
566 static Elf_Addr
567 SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
568 Elf_Addr *section_addresses, Elf_Shdr *sections,
569 Elf_Half section_entsize, Elf_Half num_sections,
570 const char *strtab,
571 Elf_Addr jumpers, grub_size_t njumpers,
572 struct image_target_desc *image_target)
573 {
574 unsigned i;
575 Elf_Shdr *s;
576 struct fixup_block_list *lst, *lst0;
577 Elf_Addr current_address = 0;
578
579 lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000);
580 memset (lst, 0, sizeof (*lst) + 2 * 0x1000);
581
582 for (i = 0, s = sections; i < num_sections;
583 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
584 if ((grub_target_to_host32 (s->sh_type) == SHT_REL) ||
585 (grub_target_to_host32 (s->sh_type) == SHT_RELA))
586 {
587 Elf_Rel *r;
588 Elf_Word rtab_size, r_size, num_rs;
589 Elf_Off rtab_offset;
590 Elf_Addr section_address;
591 Elf_Word j;
592
593 grub_util_info ("translating the relocation section %s",
594 strtab + grub_le_to_cpu32 (s->sh_name));
595
596 rtab_size = grub_target_to_host (s->sh_size);
597 r_size = grub_target_to_host (s->sh_entsize);
598 rtab_offset = grub_target_to_host (s->sh_offset);
599 num_rs = rtab_size / r_size;
600
601 section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)];
602
603 for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset);
604 j < num_rs;
605 j++, r = (Elf_Rel *) ((char *) r + r_size))
606 {
607 Elf_Addr info;
608 Elf_Addr offset;
609
610 offset = grub_target_to_host (r->r_offset);
611 info = grub_target_to_host (r->r_info);
612
613 /* Necessary to relocate only absolute addresses. */
614 switch (image_target->elf_target)
615 {
616 case EM_386:
617 if (ELF_R_TYPE (info) == R_386_32)
618 {
619 Elf_Addr addr;
620
621 addr = section_address + offset;
622 grub_util_info ("adding a relocation entry for 0x%llx",
623 (unsigned long long) addr);
624 current_address
625 = SUFFIX (add_fixup_entry) (&lst,
626 GRUB_PE32_REL_BASED_HIGHLOW,
627 addr, 0, current_address,
628 image_target);
629 }
630 break;
631 case EM_X86_64:
632 if ((ELF_R_TYPE (info) == R_X86_64_32) ||
633 (ELF_R_TYPE (info) == R_X86_64_32S))
634 {
635 grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)");
636 }
637 else if (ELF_R_TYPE (info) == R_X86_64_64)
638 {
639 Elf_Addr addr;
640
641 addr = section_address + offset;
642 grub_util_info ("adding a relocation entry for 0x%llx",
643 (unsigned long long) addr);
644 current_address
645 = SUFFIX (add_fixup_entry) (&lst,
646 GRUB_PE32_REL_BASED_DIR64,
647 addr,
648 0, current_address,
649 image_target);
650 }
651 break;
652 case EM_IA_64:
653 switch (ELF_R_TYPE (info))
654 {
655 case R_IA64_PCREL64LSB:
656 case R_IA64_LDXMOV:
657 case R_IA64_PCREL21B:
658 case R_IA64_LTOFF_FPTR22:
659 case R_IA64_LTOFF22X:
660 case R_IA64_LTOFF22:
661 case R_IA64_GPREL22:
662 case R_IA64_SEGREL64LSB:
663 break;
664
665 case R_IA64_FPTR64LSB:
666 case R_IA64_DIR64LSB:
667 #if 1
668 {
669 Elf_Addr addr;
670
671 addr = section_address + offset;
672 grub_util_info ("adding a relocation entry for 0x%llx",
673 (unsigned long long) addr);
674 current_address
675 = SUFFIX (add_fixup_entry) (&lst,
676 GRUB_PE32_REL_BASED_DIR64,
677 addr,
678 0, current_address,
679 image_target);
680 }
681 #endif
682 break;
683 default:
684 grub_util_error (_("relocation 0x%llx is not implemented yet"),
685 (unsigned long long) ELF_R_TYPE (info));
686 break;
687 }
688 break;
689 #if defined(MKIMAGE_ELF32)
690 case EM_ARM:
691 switch (ELF_R_TYPE (info))
692 {
693 /* Relative relocations do not require fixup entries. */
694 case R_ARM_JUMP24:
695 case R_ARM_THM_CALL:
696 case R_ARM_THM_JUMP19:
697 case R_ARM_THM_JUMP24:
698 {
699 Elf_Addr addr;
700
701 addr = section_address + offset;
702 grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) current_address);
703 }
704 break;
705 /* Create fixup entry for PE/COFF loader */
706 case R_ARM_ABS32:
707 {
708 Elf_Addr addr;
709
710 addr = section_address + offset;
711 current_address
712 = SUFFIX (add_fixup_entry) (&lst,
713 GRUB_PE32_REL_BASED_HIGHLOW,
714 addr, 0, current_address,
715 image_target);
716 }
717 break;
718 default:
719 grub_util_error (_("fixup for relocation 0x%x not implemented"), ELF_R_TYPE (info));
720 break;
721 }
722 break;
723 #endif /* defined(MKIMAGE_ELF32) */
724 default:
725 grub_util_error ("unknown machine type 0x%x", image_target->elf_target);
726 }
727 }
728 }
729
730 if (image_target->elf_target == EM_IA_64)
731 for (i = 0; i < njumpers; i++)
732 current_address = SUFFIX (add_fixup_entry) (&lst,
733 GRUB_PE32_REL_BASED_DIR64,
734 jumpers + 8 * i,
735 0, current_address,
736 image_target);
737
738 current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target);
739
740 {
741 grub_uint8_t *ptr;
742 ptr = *out = xmalloc (current_address);
743 for (lst = lst0; lst; lst = lst->next)
744 if (lst->state)
745 {
746 memcpy (ptr, &lst->b, grub_target_to_host32 (lst->b.block_size));
747 ptr += grub_target_to_host32 (lst->b.block_size);
748 }
749 assert ((current_address + (grub_uint8_t *) *out) == ptr);
750 }
751
752 return current_address;
753 }
754
755 /* Determine if this section is a text section. Return false if this
756 section is not allocated. */
757 static int
758 SUFFIX (is_text_section) (Elf_Shdr *s, struct image_target_desc *image_target)
759 {
760 if (image_target->id != IMAGE_EFI
761 && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
762 return 0;
763 return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
764 == (SHF_EXECINSTR | SHF_ALLOC));
765 }
766
767 /* Determine if this section is a data section. This assumes that
768 BSS is also a data section, since the converter initializes BSS
769 when producing PE32 to avoid a bug in EFI implementations. */
770 static int
771 SUFFIX (is_data_section) (Elf_Shdr *s, struct image_target_desc *image_target)
772 {
773 if (image_target->id != IMAGE_EFI
774 && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
775 return 0;
776 return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
777 == SHF_ALLOC);
778 }
779
780 /* Return if the ELF header is valid. */
781 static int
782 SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, struct image_target_desc *image_target)
783 {
784 if (size < sizeof (*e)
785 || e->e_ident[EI_MAG0] != ELFMAG0
786 || e->e_ident[EI_MAG1] != ELFMAG1
787 || e->e_ident[EI_MAG2] != ELFMAG2
788 || e->e_ident[EI_MAG3] != ELFMAG3
789 || e->e_ident[EI_VERSION] != EV_CURRENT
790 || e->e_ident[EI_CLASS] != ELFCLASSXX
791 || e->e_version != grub_host_to_target32 (EV_CURRENT))
792 return 0;
793
794 return 1;
795 }
796
797 /* Locate section addresses by merging code sections and data sections
798 into .text and .data, respectively. Return the array of section
799 addresses. */
800 static Elf_Addr *
801 SUFFIX (locate_sections) (Elf_Shdr *sections, Elf_Half section_entsize,
802 Elf_Half num_sections, const char *strtab,
803 grub_size_t *exec_size, grub_size_t *kernel_sz,
804 grub_size_t *all_align,
805 struct image_target_desc *image_target)
806 {
807 int i;
808 Elf_Addr current_address;
809 Elf_Addr *section_addresses;
810 Elf_Shdr *s;
811
812 *all_align = 1;
813
814 section_addresses = xmalloc (sizeof (*section_addresses) * num_sections);
815 memset (section_addresses, 0, sizeof (*section_addresses) * num_sections);
816
817 current_address = 0;
818
819 for (i = 0, s = sections;
820 i < num_sections;
821 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
822 if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC)
823 && grub_host_to_target32 (s->sh_addralign) > *all_align)
824 *all_align = grub_host_to_target32 (s->sh_addralign);
825
826
827 /* .text */
828 for (i = 0, s = sections;
829 i < num_sections;
830 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
831 if (SUFFIX (is_text_section) (s, image_target))
832 {
833 Elf_Word align = grub_host_to_target_addr (s->sh_addralign);
834 const char *name = strtab + grub_host_to_target32 (s->sh_name);
835 if (align)
836 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
837 align) - image_target->vaddr_offset;
838 grub_util_info ("locating the section %s at 0x%llx",
839 name, (unsigned long long) current_address);
840 if (image_target->id != IMAGE_EFI)
841 current_address = grub_host_to_target_addr (s->sh_addr)
842 - image_target->link_addr;
843 section_addresses[i] = current_address;
844 current_address += grub_host_to_target_addr (s->sh_size);
845 }
846
847 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
848 image_target->section_align)
849 - image_target->vaddr_offset;
850 *exec_size = current_address;
851
852 /* .data */
853 for (i = 0, s = sections;
854 i < num_sections;
855 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
856 if (SUFFIX (is_data_section) (s, image_target))
857 {
858 Elf_Word align = grub_host_to_target_addr (s->sh_addralign);
859 const char *name = strtab + grub_host_to_target32 (s->sh_name);
860
861 if (align)
862 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
863 align)
864 - image_target->vaddr_offset;
865
866 grub_util_info ("locating the section %s at 0x%llx",
867 name, (unsigned long long) current_address);
868 if (image_target->id != IMAGE_EFI)
869 current_address = grub_host_to_target_addr (s->sh_addr)
870 - image_target->link_addr;
871 section_addresses[i] = current_address;
872 current_address += grub_host_to_target_addr (s->sh_size);
873 }
874
875 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
876 image_target->section_align) - image_target->vaddr_offset;
877 *kernel_sz = current_address;
878 return section_addresses;
879 }
880
881 static char *
882 SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size,
883 grub_size_t *kernel_sz, grub_size_t *bss_size,
884 grub_size_t total_module_size, grub_uint64_t *start,
885 void **reloc_section, grub_size_t *reloc_size,
886 grub_size_t *align,
887 struct image_target_desc *image_target)
888 {
889 char *kernel_img, *out_img;
890 const char *strtab;
891 Elf_Ehdr *e;
892 Elf_Shdr *sections;
893 Elf_Addr *section_addresses;
894 Elf_Addr *section_vaddresses;
895 int i;
896 Elf_Shdr *s;
897 Elf_Half num_sections;
898 Elf_Off section_offset;
899 Elf_Half section_entsize;
900 grub_size_t kernel_size;
901 grub_size_t ia64jmp_off = 0, ia64_toff = 0, ia64_got_off = 0;
902 unsigned ia64jmpnum = 0;
903 Elf_Shdr *symtab_section = 0;
904 grub_size_t got = 0;
905
906 *start = 0;
907
908 kernel_size = grub_util_get_image_size (kernel_path);
909 kernel_img = xmalloc (kernel_size);
910 grub_util_load_image (kernel_path, kernel_img);
911
912 e = (Elf_Ehdr *) kernel_img;
913 if (! SUFFIX (check_elf_header) (e, kernel_size, image_target))
914 grub_util_error ("invalid ELF header");
915
916 section_offset = grub_target_to_host (e->e_shoff);
917 section_entsize = grub_target_to_host16 (e->e_shentsize);
918 num_sections = grub_target_to_host16 (e->e_shnum);
919
920 if (kernel_size < section_offset + section_entsize * num_sections)
921 grub_util_error (_("premature end of file %s"), kernel_path);
922
923 sections = (Elf_Shdr *) (kernel_img + section_offset);
924
925 /* Relocate sections then symbols in the virtual address space. */
926 s = (Elf_Shdr *) ((char *) sections
927 + grub_host_to_target16 (e->e_shstrndx) * section_entsize);
928 strtab = (char *) e + grub_host_to_target_addr (s->sh_offset);
929
930 section_addresses = SUFFIX (locate_sections) (sections, section_entsize,
931 num_sections, strtab,
932 exec_size, kernel_sz, align,
933 image_target);
934
935 section_vaddresses = xmalloc (sizeof (*section_addresses) * num_sections);
936
937 for (i = 0; i < num_sections; i++)
938 section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset;
939
940 if (image_target->id != IMAGE_EFI)
941 {
942 Elf_Addr current_address = *kernel_sz;
943
944 for (i = 0, s = sections;
945 i < num_sections;
946 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
947 if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
948 {
949 Elf_Word sec_align = grub_host_to_target_addr (s->sh_addralign);
950 const char *name = strtab + grub_host_to_target32 (s->sh_name);
951
952 if (sec_align)
953 current_address = ALIGN_UP (current_address
954 + image_target->vaddr_offset,
955 sec_align)
956 - image_target->vaddr_offset;
957
958 grub_util_info ("locating the section %s at 0x%llx",
959 name, (unsigned long long) current_address);
960 if (image_target->id != IMAGE_EFI)
961 current_address = grub_host_to_target_addr (s->sh_addr)
962 - image_target->link_addr;
963
964 section_vaddresses[i] = current_address
965 + image_target->vaddr_offset;
966 current_address += grub_host_to_target_addr (s->sh_size);
967 }
968 current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
969 image_target->section_align)
970 - image_target->vaddr_offset;
971 *bss_size = current_address - *kernel_sz;
972 }
973 else
974 *bss_size = 0;
975
976 if (image_target->id == IMAGE_EFI)
977 {
978 symtab_section = NULL;
979 for (i = 0, s = sections;
980 i < num_sections;
981 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
982 if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB))
983 {
984 symtab_section = s;
985 break;
986 }
987
988 #ifdef MKIMAGE_ELF64
989 if (image_target->elf_target == EM_IA_64)
990 {
991 grub_size_t tramp;
992
993 *kernel_sz = ALIGN_UP (*kernel_sz, 16);
994
995 grub_ia64_dl_get_tramp_got_size (e, &tramp, &got);
996 tramp *= sizeof (struct grub_ia64_trampoline);
997
998 ia64_toff = *kernel_sz;
999 *kernel_sz += ALIGN_UP (tramp, 16);
1000
1001 ia64jmp_off = *kernel_sz;
1002 ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section,
1003 image_target);
1004 *kernel_sz += 16 * ia64jmpnum;
1005
1006 ia64_got_off = *kernel_sz;
1007 *kernel_sz += ALIGN_UP (got * sizeof (grub_uint64_t), 16);
1008 }
1009 #endif
1010
1011 if (! symtab_section)
1012 grub_util_error ("%s", _("no symbol table"));
1013 }
1014 else
1015 {
1016 *reloc_size = 0;
1017 *reloc_section = NULL;
1018 }
1019
1020 out_img = xmalloc (*kernel_sz + total_module_size);
1021
1022 if (image_target->id == IMAGE_EFI)
1023 {
1024 *start = SUFFIX (relocate_symbols) (e, sections, symtab_section,
1025 section_vaddresses, section_entsize,
1026 num_sections,
1027 (char *) out_img + ia64jmp_off,
1028 ia64jmp_off
1029 + image_target->vaddr_offset,
1030 image_target);
1031 if (*start == 0)
1032 grub_util_error ("start symbol is not defined");
1033
1034 SUFFIX (entry_point) = (Elf_Addr) *start;
1035
1036 /* Resolve addresses in the virtual address space. */
1037 SUFFIX (relocate_addresses) (e, sections, section_addresses,
1038 section_entsize,
1039 num_sections, strtab,
1040 out_img, ia64_toff, ia64_got_off,
1041 image_target);
1042
1043 *reloc_size = SUFFIX (make_reloc_section) (e, reloc_section,
1044 section_vaddresses, sections,
1045 section_entsize, num_sections,
1046 strtab, ia64jmp_off
1047 + image_target->vaddr_offset,
1048 2 * ia64jmpnum + got,
1049 image_target);
1050 }
1051
1052 for (i = 0, s = sections;
1053 i < num_sections;
1054 i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
1055 if (SUFFIX (is_data_section) (s, image_target)
1056 || SUFFIX (is_text_section) (s, image_target))
1057 {
1058 if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
1059 memset (out_img + section_addresses[i], 0,
1060 grub_host_to_target_addr (s->sh_size));
1061 else
1062 memcpy (out_img + section_addresses[i],
1063 kernel_img + grub_host_to_target_addr (s->sh_offset),
1064 grub_host_to_target_addr (s->sh_size));
1065 }
1066 free (kernel_img);
1067
1068 return out_img;
1069 }
1070
1071
1072 #undef SUFFIX
1073 #undef ELFCLASSXX
1074 #undef Elf_Ehdr
1075 #undef Elf_Phdr
1076 #undef Elf_Shdr
1077 #undef Elf_Addr
1078 #undef Elf_Sym
1079 #undef Elf_Off
1080 #undef Elf_Rela
1081 #undef Elf_Rel
1082 #undef ELF_R_TYPE
1083 #undef ELF_R_SYM
1084 #undef Elf_Word
1085 #undef Elf_Half
1086 #undef Elf_Section
1087 #undef ELF_ST_TYPE