1 /* grub-mkimage.c - make a bootable image */
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/>.
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)
61 static Elf_Addr
SUFFIX (entry_point
);
63 /* Relocate symbols; note that this function overwrites the symbol table.
64 Return the address of a start symbol. */
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
)
72 Elf_Word symtab_size
, sym_size
, num_syms
;
73 Elf_Off symtab_offset
;
74 Elf_Addr start_address
= 0;
77 Elf_Shdr
*strtab_section
;
79 grub_uint64_t
*jptr
= jumpers
;
82 = (Elf_Shdr
*) ((char *) sections
83 + (grub_target_to_host32 (symtab_section
->sh_link
)
85 strtab
= (char *) e
+ grub_target_to_host (strtab_section
->sh_offset
);
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
;
92 for (i
= 0, sym
= (Elf_Sym
*) ((char *) e
+ symtab_offset
);
94 i
++, sym
= (Elf_Sym
*) ((char *) sym
+ sym_size
))
96 Elf_Section cur_index
;
99 name
= strtab
+ grub_target_to_host32 (sym
->st_name
);
101 cur_index
= grub_target_to_host16 (sym
->st_shndx
);
102 if (cur_index
== STN_ABS
)
106 else if ((cur_index
== STN_UNDEF
))
109 grub_util_error ("undefined symbol %s", name
);
113 else if (cur_index
>= num_sections
)
114 grub_util_error ("section %d does not exist", cur_index
);
116 sym
->st_value
= (grub_target_to_host (sym
->st_value
)
117 + section_addresses
[cur_index
]);
119 if (image_target
->elf_target
== EM_IA_64
&& ELF_ST_TYPE (sym
->st_info
)
122 *jptr
= grub_host_to_target64 (sym
->st_value
);
123 sym
->st_value
= (char *) jptr
- (char *) jumpers
+ jumpers_addr
;
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
]);
133 if (strcmp (name
, "_start") == 0 || strcmp (name
, "start") == 0)
134 start_address
= sym
->st_value
;
137 return start_address
;
140 /* Return the address of a symbol at the index I in the section S. */
142 SUFFIX (get_symbol_address
) (Elf_Ehdr
*e
, Elf_Shdr
*s
, Elf_Word i
,
143 struct image_target_desc
*image_target
)
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
;
153 /* Return the address of a modified value. */
155 SUFFIX (get_target_address
) (Elf_Ehdr
*e
, Elf_Shdr
*s
, Elf_Addr offset
,
156 struct image_target_desc
*image_target
)
158 return (Elf_Addr
*) ((char *) e
+ grub_target_to_host (s
->sh_offset
) + offset
);
163 SUFFIX (count_funcs
) (Elf_Ehdr
*e
, Elf_Shdr
*symtab_section
,
164 struct image_target_desc
*image_target
)
166 Elf_Word symtab_size
, sym_size
, num_syms
;
167 Elf_Off symtab_offset
;
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
;
177 for (i
= 0, sym
= (Elf_Sym
*) ((char *) e
+ symtab_offset
);
179 i
++, sym
= (Elf_Sym
*) ((char *) sym
+ sym_size
))
180 if (ELF_ST_TYPE (sym
->st_info
) == STT_FUNC
)
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. */
192 SUFFIX (relocate_addresses
) (Elf_Ehdr
*e
, Elf_Shdr
*sections
,
193 Elf_Addr
*section_addresses
,
194 Elf_Half section_entsize
, Elf_Half num_sections
,
196 char *pe_target
, Elf_Addr tramp_off
,
198 struct image_target_desc
*image_target
)
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)
208 for (i
= 0, s
= 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
)))
215 Elf_Word rtab_size
, r_size
, num_rs
;
217 Elf_Shdr
*symtab_section
;
218 Elf_Word target_section_index
;
219 Elf_Addr target_section_addr
;
220 Elf_Shdr
*target_section
;
223 symtab_section
= (Elf_Shdr
*) ((char *) sections
224 + (grub_target_to_host32 (s
->sh_link
)
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
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
));
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
;
241 for (j
= 0, r
= (Elf_Rela
*) ((char *) e
+ rtab_offset
);
243 j
++, r
= (Elf_Rela
*) ((char *) r
+ r_size
))
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
);
258 addend
= (s
->sh_type
== grub_target_to_host32 (SHT_RELA
)) ?
259 grub_target_to_host (r
->r_addend
) : 0;
261 switch (image_target
->elf_target
)
264 switch (ELF_R_TYPE (info
))
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
);
279 /* This is relative. */
280 *target
= grub_host_to_target32 (grub_target_to_host32 (*target
)
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
);
289 grub_util_error (_("relocation 0x%llx is not implemented yet"),
290 (unsigned long long) ELF_R_TYPE (info
));
296 switch (ELF_R_TYPE (info
))
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
);
312 grub_uint32_t
*t32
= (grub_uint32_t
*) target
;
313 *t32
= grub_host_to_target64 (grub_target_to_host32 (*t32
)
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
);
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
);
334 grub_util_error (_("relocation 0x%llx is not implemented yet"),
335 (unsigned long long) ELF_R_TYPE (info
));
340 switch (ELF_R_TYPE (info
))
342 case R_IA64_PCREL21B
:
345 grub_ia64_make_trampoline (tr
, addend
+ sym_addr
);
346 noff
= ((char *) tr
- (char *) pe_target
347 - target_section_addr
- (offset
& ~3)) >> 4;
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
);
356 case R_IA64_LTOFF22X
:
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
367 - image_target
->vaddr_offset
));
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
);
378 grub_ia64_add_value_to_slot_21 ((grub_addr_t
) target
,
381 case R_IA64_PCREL64LSB
:
382 *target
= grub_host_to_target64 (grub_target_to_host64 (*target
)
384 - target_section_addr
- offset
385 - image_target
->vaddr_offset
);
388 case R_IA64_SEGREL64LSB
:
389 *target
= grub_host_to_target64 (grub_target_to_host64 (*target
)
390 + addend
+ sym_addr
- target_section_addr
);
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
);
402 /* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */
407 grub_util_error (_("relocation 0x%llx is not implemented yet"),
408 (unsigned long long) ELF_R_TYPE (info
));
413 #if defined(MKIMAGE_ELF32)
417 sym_addr
-= SUFFIX (entry_point
);
418 switch (ELF_R_TYPE (info
))
422 grub_util_info (" ABS32:\toffset=%d\t(0x%08x)",
423 (int) sym_addr
, (int) sym_addr
);
424 /* Data will be naturally aligned */
426 *target
= grub_host_to_target32 (grub_target_to_host32 (*target
) + sym_addr
);
430 case R_ARM_THM_JUMP24
:
433 grub_util_info (" THM_JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", (unsigned long) target
, sym_addr
);
435 /* Thumb instructions can be 16-bit aligned */
436 err
= grub_arm_reloc_thm_call ((grub_uint16_t
*) target
,
439 grub_util_error ("%s", grub_errmsg
);
442 case R_ARM_THM_JUMP19
:
445 grub_util_info (" THM_JUMP19:\toffset=%d\t(0x%08x)",
449 /* Thumb instructions can be 16-bit aligned */
450 err
= grub_arm_reloc_thm_jump19 ((grub_uint16_t
*) target
, sym_addr
);
452 grub_util_error ("%s", grub_errmsg
);
456 grub_util_error (_("relocation 0x%x is not implemented yet!"), ELF_R_TYPE (info
));
461 #endif /* MKIMAGE_ELF32 */
463 grub_util_error ("unknown architecture type %d",
464 image_target
->elf_target
);
470 /* Add a PE32's fixup entry for a relocation. Return the resulting address
471 after having written to the file OUT. */
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
)
477 struct grub_pe32_fixup_block
*b
;
481 /* First, check if it is necessary to write out the current block. */
482 if ((*cblock
)->state
)
484 if (flush
|| addr
< b
->page_rva
|| b
->page_rva
+ 0x1000 <= addr
)
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
;
496 next_address
= current_address
+ b
->block_size
;
497 padding_size
= ((ALIGN_UP (next_address
, image_target
->section_align
)
500 cur_index
= ((b
->block_size
- sizeof (*b
)) >> 1);
501 grub_util_info ("adding %d padding fixup entries", padding_size
);
502 while (padding_size
--)
504 b
->entries
[cur_index
++] = 0;
508 else while (b
->block_size
& (8 - 1))
510 /* If not aligned with a 32-bit boundary, add
514 grub_util_info ("adding a padding fixup entry");
515 cur_index
= ((b
->block_size
- sizeof (*b
)) >> 1);
516 b
->entries
[cur_index
] = 0;
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
;
540 /* If not allocated yet, allocate a block with enough entries. */
541 if (! (*cblock
)->state
)
543 (*cblock
)->state
= 1;
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
);
552 if (b
->block_size
>= sizeof (*b
) + 2 * 0x1000)
553 grub_util_error ("too many fixup entries");
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
);
562 return current_address
;
565 /* Make a .reloc section. */
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
,
571 Elf_Addr jumpers
, grub_size_t njumpers
,
572 struct image_target_desc
*image_target
)
576 struct fixup_block_list
*lst
, *lst0
;
577 Elf_Addr current_address
= 0;
579 lst
= lst0
= xmalloc (sizeof (*lst
) + 2 * 0x1000);
580 memset (lst
, 0, sizeof (*lst
) + 2 * 0x1000);
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
))
588 Elf_Word rtab_size
, r_size
, num_rs
;
590 Elf_Addr section_address
;
593 grub_util_info ("translating the relocation section %s",
594 strtab
+ grub_le_to_cpu32 (s
->sh_name
));
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
;
601 section_address
= section_addresses
[grub_le_to_cpu32 (s
->sh_info
)];
603 for (j
= 0, r
= (Elf_Rel
*) ((char *) e
+ rtab_offset
);
605 j
++, r
= (Elf_Rel
*) ((char *) r
+ r_size
))
610 offset
= grub_target_to_host (r
->r_offset
);
611 info
= grub_target_to_host (r
->r_info
);
613 /* Necessary to relocate only absolute addresses. */
614 switch (image_target
->elf_target
)
617 if (ELF_R_TYPE (info
) == R_386_32
)
621 addr
= section_address
+ offset
;
622 grub_util_info ("adding a relocation entry for 0x%llx",
623 (unsigned long long) addr
);
625 = SUFFIX (add_fixup_entry
) (&lst
,
626 GRUB_PE32_REL_BASED_HIGHLOW
,
627 addr
, 0, current_address
,
632 if ((ELF_R_TYPE (info
) == R_X86_64_32
) ||
633 (ELF_R_TYPE (info
) == R_X86_64_32S
))
635 grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)");
637 else if (ELF_R_TYPE (info
) == R_X86_64_64
)
641 addr
= section_address
+ offset
;
642 grub_util_info ("adding a relocation entry for 0x%llx",
643 (unsigned long long) addr
);
645 = SUFFIX (add_fixup_entry
) (&lst
,
646 GRUB_PE32_REL_BASED_DIR64
,
653 switch (ELF_R_TYPE (info
))
655 case R_IA64_PCREL64LSB
:
657 case R_IA64_PCREL21B
:
658 case R_IA64_LTOFF_FPTR22
:
659 case R_IA64_LTOFF22X
:
662 case R_IA64_SEGREL64LSB
:
665 case R_IA64_FPTR64LSB
:
666 case R_IA64_DIR64LSB
:
671 addr
= section_address
+ offset
;
672 grub_util_info ("adding a relocation entry for 0x%llx",
673 (unsigned long long) addr
);
675 = SUFFIX (add_fixup_entry
) (&lst
,
676 GRUB_PE32_REL_BASED_DIR64
,
684 grub_util_error (_("relocation 0x%llx is not implemented yet"),
685 (unsigned long long) ELF_R_TYPE (info
));
689 #if defined(MKIMAGE_ELF32)
691 switch (ELF_R_TYPE (info
))
693 /* Relative relocations do not require fixup entries. */
696 case R_ARM_THM_JUMP19
:
697 case R_ARM_THM_JUMP24
:
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
);
705 /* Create fixup entry for PE/COFF loader */
710 addr
= section_address
+ offset
;
712 = SUFFIX (add_fixup_entry
) (&lst
,
713 GRUB_PE32_REL_BASED_HIGHLOW
,
714 addr
, 0, current_address
,
719 grub_util_error (_("fixup for relocation 0x%x not implemented"), ELF_R_TYPE (info
));
723 #endif /* defined(MKIMAGE_ELF32) */
725 grub_util_error ("unknown machine type 0x%x", image_target
->elf_target
);
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
,
738 current_address
= SUFFIX (add_fixup_entry
) (&lst
, 0, 0, 1, current_address
, image_target
);
742 ptr
= *out
= xmalloc (current_address
);
743 for (lst
= lst0
; lst
; lst
= lst
->next
)
746 memcpy (ptr
, &lst
->b
, grub_target_to_host32 (lst
->b
.block_size
));
747 ptr
+= grub_target_to_host32 (lst
->b
.block_size
);
749 assert ((current_address
+ (grub_uint8_t
*) *out
) == ptr
);
752 return current_address
;
755 /* Determine if this section is a text section. Return false if this
756 section is not allocated. */
758 SUFFIX (is_text_section
) (Elf_Shdr
*s
, struct image_target_desc
*image_target
)
760 if (image_target
->id
!= IMAGE_EFI
761 && grub_target_to_host32 (s
->sh_type
) != SHT_PROGBITS
)
763 return ((grub_target_to_host (s
->sh_flags
) & (SHF_EXECINSTR
| SHF_ALLOC
))
764 == (SHF_EXECINSTR
| SHF_ALLOC
));
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. */
771 SUFFIX (is_data_section
) (Elf_Shdr
*s
, struct image_target_desc
*image_target
)
773 if (image_target
->id
!= IMAGE_EFI
774 && grub_target_to_host32 (s
->sh_type
) != SHT_PROGBITS
)
776 return ((grub_target_to_host (s
->sh_flags
) & (SHF_EXECINSTR
| SHF_ALLOC
))
780 /* Return if the ELF header is valid. */
782 SUFFIX (check_elf_header
) (Elf_Ehdr
*e
, size_t size
, struct image_target_desc
*image_target
)
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
))
797 /* Locate section addresses by merging code sections and data sections
798 into .text and .data, respectively. Return the array of section
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
)
808 Elf_Addr current_address
;
809 Elf_Addr
*section_addresses
;
814 section_addresses
= xmalloc (sizeof (*section_addresses
) * num_sections
);
815 memset (section_addresses
, 0, sizeof (*section_addresses
) * num_sections
);
819 for (i
= 0, s
= 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
);
828 for (i
= 0, s
= sections
;
830 i
++, s
= (Elf_Shdr
*) ((char *) s
+ section_entsize
))
831 if (SUFFIX (is_text_section
) (s
, image_target
))
833 Elf_Word align
= grub_host_to_target_addr (s
->sh_addralign
);
834 const char *name
= strtab
+ grub_host_to_target32 (s
->sh_name
);
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
);
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
;
853 for (i
= 0, s
= sections
;
855 i
++, s
= (Elf_Shdr
*) ((char *) s
+ section_entsize
))
856 if (SUFFIX (is_data_section
) (s
, image_target
))
858 Elf_Word align
= grub_host_to_target_addr (s
->sh_addralign
);
859 const char *name
= strtab
+ grub_host_to_target32 (s
->sh_name
);
862 current_address
= ALIGN_UP (current_address
+ image_target
->vaddr_offset
,
864 - image_target
->vaddr_offset
;
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
);
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
;
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
,
887 struct image_target_desc
*image_target
)
889 char *kernel_img
, *out_img
;
893 Elf_Addr
*section_addresses
;
894 Elf_Addr
*section_vaddresses
;
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;
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
);
912 e
= (Elf_Ehdr
*) kernel_img
;
913 if (! SUFFIX (check_elf_header
) (e
, kernel_size
, image_target
))
914 grub_util_error ("invalid ELF header");
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
);
920 if (kernel_size
< section_offset
+ section_entsize
* num_sections
)
921 grub_util_error (_("premature end of file %s"), kernel_path
);
923 sections
= (Elf_Shdr
*) (kernel_img
+ section_offset
);
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
);
930 section_addresses
= SUFFIX (locate_sections
) (sections
, section_entsize
,
931 num_sections
, strtab
,
932 exec_size
, kernel_sz
, align
,
935 section_vaddresses
= xmalloc (sizeof (*section_addresses
) * num_sections
);
937 for (i
= 0; i
< num_sections
; i
++)
938 section_vaddresses
[i
] = section_addresses
[i
] + image_target
->vaddr_offset
;
940 if (image_target
->id
!= IMAGE_EFI
)
942 Elf_Addr current_address
= *kernel_sz
;
944 for (i
= 0, s
= sections
;
946 i
++, s
= (Elf_Shdr
*) ((char *) s
+ section_entsize
))
947 if (grub_target_to_host32 (s
->sh_type
) == SHT_NOBITS
)
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
);
953 current_address
= ALIGN_UP (current_address
954 + image_target
->vaddr_offset
,
956 - image_target
->vaddr_offset
;
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
;
964 section_vaddresses
[i
] = current_address
965 + image_target
->vaddr_offset
;
966 current_address
+= grub_host_to_target_addr (s
->sh_size
);
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
;
976 if (image_target
->id
== IMAGE_EFI
)
978 symtab_section
= NULL
;
979 for (i
= 0, s
= sections
;
981 i
++, s
= (Elf_Shdr
*) ((char *) s
+ section_entsize
))
982 if (s
->sh_type
== grub_host_to_target32 (SHT_SYMTAB
))
989 if (image_target
->elf_target
== EM_IA_64
)
993 *kernel_sz
= ALIGN_UP (*kernel_sz
, 16);
995 grub_ia64_dl_get_tramp_got_size (e
, &tramp
, &got
);
996 tramp
*= sizeof (struct grub_ia64_trampoline
);
998 ia64_toff
= *kernel_sz
;
999 *kernel_sz
+= ALIGN_UP (tramp
, 16);
1001 ia64jmp_off
= *kernel_sz
;
1002 ia64jmpnum
= SUFFIX (count_funcs
) (e
, symtab_section
,
1004 *kernel_sz
+= 16 * ia64jmpnum
;
1006 ia64_got_off
= *kernel_sz
;
1007 *kernel_sz
+= ALIGN_UP (got
* sizeof (grub_uint64_t
), 16);
1011 if (! symtab_section
)
1012 grub_util_error ("%s", _("no symbol table"));
1017 *reloc_section
= NULL
;
1020 out_img
= xmalloc (*kernel_sz
+ total_module_size
);
1022 if (image_target
->id
== IMAGE_EFI
)
1024 *start
= SUFFIX (relocate_symbols
) (e
, sections
, symtab_section
,
1025 section_vaddresses
, section_entsize
,
1027 (char *) out_img
+ ia64jmp_off
,
1029 + image_target
->vaddr_offset
,
1032 grub_util_error ("start symbol is not defined");
1034 SUFFIX (entry_point
) = (Elf_Addr
) *start
;
1036 /* Resolve addresses in the virtual address space. */
1037 SUFFIX (relocate_addresses
) (e
, sections
, section_addresses
,
1039 num_sections
, strtab
,
1040 out_img
, ia64_toff
, ia64_got_off
,
1043 *reloc_size
= SUFFIX (make_reloc_section
) (e
, reloc_section
,
1044 section_vaddresses
, sections
,
1045 section_entsize
, num_sections
,
1047 + image_target
->vaddr_offset
,
1048 2 * ia64jmpnum
+ got
,
1052 for (i
= 0, s
= 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
))
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
));
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
));