Provide __bss_start and _end symbols in grub-mkimage.

For this ensure that all bss sections are merged.

We need this to correctly prelink non-PE relocatable images.
This commit is contained in:
Vladimir Serbinenko 2016-02-18 20:57:21 +01:00
parent 73a9c742fe
commit df21fff504
2 changed files with 89 additions and 50 deletions

View file

@ -33,6 +33,8 @@ struct grub_mkimage_layout
grub_size_t ia64_got_off; grub_size_t ia64_got_off;
grub_size_t got_size; grub_size_t got_size;
unsigned ia64jmpnum; unsigned ia64jmpnum;
Elf_Addr bss_start;
Elf_Addr end;
}; };
/* Private header. Use only in mkimage-related sources. */ /* Private header. Use only in mkimage-related sources. */

View file

@ -490,6 +490,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
Elf_Shdr *symtab_section, Elf_Addr *section_addresses, Elf_Shdr *symtab_section, Elf_Addr *section_addresses,
Elf_Half section_entsize, Elf_Half num_sections, Elf_Half section_entsize, Elf_Half num_sections,
void *jumpers, Elf_Addr jumpers_addr, void *jumpers, Elf_Addr jumpers_addr,
Elf_Addr bss_start, Elf_Addr end,
const struct grub_install_image_target_desc *image_target) const struct grub_install_image_target_desc *image_target)
{ {
Elf_Word symtab_size, sym_size, num_syms; Elf_Word symtab_size, sym_size, num_syms;
@ -528,16 +529,22 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
} }
else if (cur_index == STN_UNDEF) else if (cur_index == STN_UNDEF)
{ {
if (sym->st_name) if (sym->st_name && grub_strcmp (name, "__bss_start"))
sym->st_value = bss_start;
else if (sym->st_name && grub_strcmp (name, "__end"))
sym->st_value = end;
else if (sym->st_name)
grub_util_error ("undefined symbol %s", name); grub_util_error ("undefined symbol %s", name);
else else
continue; continue;
} }
else if (cur_index >= num_sections) else if (cur_index >= num_sections)
grub_util_error ("section %d does not exist", cur_index); grub_util_error ("section %d does not exist", cur_index);
else
sym->st_value = (grub_target_to_host (sym->st_value) {
+ section_addresses[cur_index]); sym->st_value = (grub_target_to_host (sym->st_value)
+ section_addresses[cur_index]);
}
if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info) if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info)
== STT_FUNC) == STT_FUNC)
@ -1462,9 +1469,7 @@ SUFFIX (is_text_section) (Elf_Shdr *s, const struct grub_install_image_target_de
== (SHF_EXECINSTR | SHF_ALLOC)); == (SHF_EXECINSTR | SHF_ALLOC));
} }
/* Determine if this section is a data section. This assumes that /* Determine if this section is a data section. */
BSS is also a data section, since the converter initializes BSS
when producing PE32 to avoid a bug in EFI implementations. */
static int static int
SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
{ {
@ -1472,7 +1477,16 @@ SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_de
&& grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
return 0; return 0;
return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
== SHF_ALLOC); == SHF_ALLOC) && !(grub_target_to_host32 (s->sh_type) == SHT_NOBITS);
}
static int
SUFFIX (is_bss_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
{
if (!is_relocatable (image_target))
return 0;
return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
== SHF_ALLOC) && (grub_target_to_host32 (s->sh_type) == SHT_NOBITS);
} }
/* Return if the ELF header is valid. */ /* Return if the ELF header is valid. */
@ -1492,6 +1506,32 @@ SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_i
return 1; return 1;
} }
static Elf_Addr
SUFFIX (put_section) (Elf_Shdr *s, int i,
Elf_Addr current_address,
Elf_Addr *section_addresses,
const char *strtab,
const struct grub_install_image_target_desc *image_target)
{
Elf_Word align = grub_host_to_target_addr (s->sh_addralign);
const char *name = strtab + grub_host_to_target32 (s->sh_name);
if (align)
current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
align)
- image_target->vaddr_offset;
grub_util_info ("locating the section %s at 0x%"
GRUB_HOST_PRIxLONG_LONG,
name, (unsigned long long) current_address);
if (!is_relocatable (image_target))
current_address = grub_host_to_target_addr (s->sh_addr)
- image_target->link_addr;
section_addresses[i] = current_address;
current_address += grub_host_to_target_addr (s->sh_size);
return current_address;
}
/* Locate section addresses by merging code sections and data sections /* Locate section addresses by merging code sections and data sections
into .text and .data, respectively. Return the array of section into .text and .data, respectively. Return the array of section
addresses. */ addresses. */
@ -1531,32 +1571,22 @@ SUFFIX (locate_sections) (const char *kernel_path,
i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
if (SUFFIX (is_text_section) (s, image_target)) if (SUFFIX (is_text_section) (s, image_target))
{ {
Elf_Word align = grub_host_to_target_addr (s->sh_addralign); current_address = SUFFIX (put_section) (s, i,
const char *name = strtab + grub_host_to_target32 (s->sh_name); current_address,
if (align) section_addresses,
current_address = ALIGN_UP (current_address + image_target->vaddr_offset, strtab,
align) - image_target->vaddr_offset; image_target);
grub_util_info ("locating the section %s at 0x%" if (!is_relocatable (image_target) &&
GRUB_HOST_PRIxLONG_LONG, grub_host_to_target_addr (s->sh_addr) != image_target->link_addr)
name, (unsigned long long) current_address);
if (image_target->id != IMAGE_EFI)
{ {
current_address = grub_host_to_target_addr (s->sh_addr) char *msg
- image_target->link_addr; = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx"
if (grub_host_to_target_addr (s->sh_addr) " instead of 0x%llx: ld.gold bug?"),
!= image_target->link_addr) kernel_path,
{ (unsigned long long) grub_host_to_target_addr (s->sh_addr),
char *msg (unsigned long long) image_target->link_addr);
= grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx" grub_util_error ("%s", msg);
" instead of 0x%llx: ld.gold bug?"),
kernel_path,
(unsigned long long) grub_host_to_target_addr (s->sh_addr),
(unsigned long long) image_target->link_addr);
grub_util_error ("%s", msg);
}
} }
section_addresses[i] = current_address;
current_address += grub_host_to_target_addr (s->sh_size);
} }
current_address = ALIGN_UP (current_address + image_target->vaddr_offset, current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
@ -1569,27 +1599,31 @@ SUFFIX (locate_sections) (const char *kernel_path,
i < num_sections; i < num_sections;
i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
if (SUFFIX (is_data_section) (s, image_target)) if (SUFFIX (is_data_section) (s, image_target))
{ current_address = SUFFIX (put_section) (s, i,
Elf_Word align = grub_host_to_target_addr (s->sh_addralign); current_address,
const char *name = strtab + grub_host_to_target32 (s->sh_name); section_addresses,
strtab,
if (align) image_target);
current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
align)
- image_target->vaddr_offset;
grub_util_info ("locating the section %s at 0x%"
GRUB_HOST_PRIxLONG_LONG,
name, (unsigned long long) current_address);
if (image_target->id != IMAGE_EFI)
current_address = grub_host_to_target_addr (s->sh_addr)
- image_target->link_addr;
section_addresses[i] = current_address;
current_address += grub_host_to_target_addr (s->sh_size);
}
current_address = ALIGN_UP (current_address + image_target->vaddr_offset, current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
image_target->section_align) - image_target->vaddr_offset; image_target->section_align) - image_target->vaddr_offset;
layout->bss_start = current_address;
/* .bss */
for (i = 0, s = sections;
i < num_sections;
i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
if (SUFFIX (is_bss_section) (s, image_target))
current_address = SUFFIX (put_section) (s, i,
current_address,
section_addresses,
strtab,
image_target);
current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
image_target->section_align) - image_target->vaddr_offset;
layout->end = current_address;
layout->kernel_size = current_address; layout->kernel_size = current_address;
return section_addresses; return section_addresses;
} }
@ -1789,8 +1823,11 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
i < num_sections; i < num_sections;
i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
if (SUFFIX (is_data_section) (s, image_target) if (SUFFIX (is_data_section) (s, image_target)
|| SUFFIX (is_bss_section) (s, image_target)
|| SUFFIX (is_text_section) (s, image_target)) || SUFFIX (is_text_section) (s, image_target))
{ {
/* Explicitly initialize BSS
when producing PE32 to avoid a bug in EFI implementations. */
if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
memset (out_img + section_addresses[i], 0, memset (out_img + section_addresses[i], 0,
grub_host_to_target_addr (s->sh_size)); grub_host_to_target_addr (s->sh_size));