Subject: Re: new ldscript and Xen
To: Pavel Cahyna <pavel@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.eu.org>
List: port-i386
Date: 05/28/2006 12:03:25
--n8g4imXOkfNTN/H1
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
On Sun, May 28, 2006 at 01:42:02AM +0200, Pavel Cahyna wrote:
> I bet the
> /local/pop1/bouyer/tmp/i386/obj/local/pop1/bouyer/current/src/tooldir/bin/i386--netbsdelf-ld
> is out of date.
>
> You need to update gnu/dist/binutils/ld and recompile your linker.
Yes, with up-to-date tools it builds fine.
Unfortunably now a Xen3 dom0 kernel fails to load with:
(XEN) *** LOADING DOMAIN 0 ***
(XEN) Malformed ELF image.
Attached is the Xen source file from where this message comes.
Any idea ?
--
Manuel Bouyer <bouyer@antioche.eu.org>
NetBSD: 26 ans d'experience feront toujours la difference
--
--n8g4imXOkfNTN/H1
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="elf.c"
/******************************************************************************
* elf.c
*
* Generic Elf-loading routines.
*/
#include <xen/config.h>
#include <xen/init.h>
#include <xen/lib.h>
#include <xen/mm.h>
#include <xen/elf.h>
#include <xen/sched.h>
static void loadelfsymtab(struct domain_setup_info *dsi, int doload);
static inline int is_loadable_phdr(Elf_Phdr *phdr)
{
return ((phdr->p_type == PT_LOAD) &&
((phdr->p_flags & (PF_W|PF_X)) != 0));
}
int parseelfimage(struct domain_setup_info *dsi)
{
Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr;
Elf_Phdr *phdr;
Elf_Shdr *shdr;
unsigned long kernstart = ~0UL, kernend=0UL;
char *shstrtab, *guestinfo=NULL, *p;
char *elfbase = (char *)dsi->image_addr;
int h;
if ( !elf_sanity_check(ehdr) )
return -EINVAL;
if ( (ehdr->e_phoff + (ehdr->e_phnum*ehdr->e_phentsize)) > dsi->image_len )
{
printk("ELF program headers extend beyond end of image.\n");
return -EINVAL;
}
if ( (ehdr->e_shoff + (ehdr->e_shnum*ehdr->e_shentsize)) > dsi->image_len )
{
printk("ELF section headers extend beyond end of image.\n");
return -EINVAL;
}
/* Find the section-header strings table. */
if ( ehdr->e_shstrndx == SHN_UNDEF )
{
printk("ELF image has no section-header strings table (shstrtab).\n");
return -EINVAL;
}
shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff +
(ehdr->e_shstrndx*ehdr->e_shentsize));
shstrtab = elfbase + shdr->sh_offset;
/* Find the special '__xen_guest' section and check its contents. */
for ( h = 0; h < ehdr->e_shnum; h++ )
{
shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + (h*ehdr->e_shentsize));
if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
continue;
guestinfo = elfbase + shdr->sh_offset;
if ( (strstr(guestinfo, "LOADER=generic") == NULL) &&
(strstr(guestinfo, "GUEST_OS=linux") == NULL) )
{
printk("ERROR: Xen will only load images built for the generic "
"loader or Linux images\n");
return -EINVAL;
}
if ( (strstr(guestinfo, "XEN_VER=xen-3.0") == NULL) )
{
printk("ERROR: Xen will only load images built for Xen v3.0\n");
return -EINVAL;
}
break;
}
dsi->xen_section_string = guestinfo;
for ( h = 0; h < ehdr->e_phnum; h++ )
{
phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
if ( !is_loadable_phdr(phdr) )
continue;
if ( phdr->p_paddr < kernstart )
kernstart = phdr->p_paddr;
if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
kernend = phdr->p_paddr + phdr->p_memsz;
}
if ( (kernstart > kernend) ||
(ehdr->e_entry < kernstart) ||
(ehdr->e_entry > kernend) )
{
printk("Malformed ELF image.\n");
return -EINVAL;
}
dsi->v_start = kernstart;
if ( guestinfo != NULL )
{
if ( (p = strstr(guestinfo, "VIRT_BASE=")) != NULL )
dsi->v_start = simple_strtoul(p+10, &p, 0);
if ( (p = strstr(guestinfo, "BSD_SYMTAB")) != NULL )
dsi->load_symtab = 1;
}
dsi->v_kernstart = kernstart;
dsi->v_kernend = kernend;
dsi->v_kernentry = ehdr->e_entry;
dsi->v_end = dsi->v_kernend;
loadelfsymtab(dsi, 0);
return 0;
}
int loadelfimage(struct domain_setup_info *dsi)
{
char *elfbase = (char *)dsi->image_addr;
Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr;
Elf_Phdr *phdr;
int h;
for ( h = 0; h < ehdr->e_phnum; h++ )
{
phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
if ( !is_loadable_phdr(phdr) )
continue;
if ( phdr->p_filesz != 0 )
memcpy((char *)phdr->p_paddr, elfbase + phdr->p_offset,
phdr->p_filesz);
if ( phdr->p_memsz > phdr->p_filesz )
memset((char *)phdr->p_paddr + phdr->p_filesz, 0,
phdr->p_memsz - phdr->p_filesz);
}
loadelfsymtab(dsi, 1);
return 0;
}
#define ELFROUND (ELFSIZE / 8)
static void loadelfsymtab(struct domain_setup_info *dsi, int doload)
{
Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr, *sym_ehdr;
Elf_Shdr *shdr;
unsigned long maxva, symva;
char *p, *elfbase = (char *)dsi->image_addr;
int h, i;
if ( !dsi->load_symtab )
return;
maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
symva = maxva;
maxva += sizeof(int);
dsi->symtab_addr = maxva;
dsi->symtab_len = 0;
maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
if ( doload )
{
p = (void *)symva;
shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
memcpy(shdr, elfbase + ehdr->e_shoff, ehdr->e_shnum*sizeof(Elf_Shdr));
}
else
{
p = NULL;
shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff);
}
for ( h = 0; h < ehdr->e_shnum; h++ )
{
if ( shdr[h].sh_type == SHT_STRTAB )
{
/* Look for a strtab @i linked to symtab @h. */
for ( i = 0; i < ehdr->e_shnum; i++ )
if ( (shdr[i].sh_type == SHT_SYMTAB) &&
(shdr[i].sh_link == h) )
break;
/* Skip symtab @h if we found no corresponding strtab @i. */
if ( i == ehdr->e_shnum )
{
if (doload) {
shdr[h].sh_offset = 0;
}
continue;
}
}
if ( (shdr[h].sh_type == SHT_STRTAB) ||
(shdr[h].sh_type == SHT_SYMTAB) )
{
if (doload) {
memcpy((void *)maxva, elfbase + shdr[h].sh_offset,
shdr[h].sh_size);
/* Mangled to be based on ELF header location. */
shdr[h].sh_offset = maxva - dsi->symtab_addr;
}
dsi->symtab_len += shdr[h].sh_size;
maxva += shdr[h].sh_size;
maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
}
if ( doload )
shdr[h].sh_name = 0; /* Name is NULL. */
}
if ( dsi->symtab_len == 0 )
{
dsi->symtab_addr = 0;
return;
}
if ( doload )
{
*(int *)p = maxva - dsi->symtab_addr;
sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
sym_ehdr->e_phoff = 0;
sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
sym_ehdr->e_phentsize = 0;
sym_ehdr->e_phnum = 0;
sym_ehdr->e_shstrndx = SHN_UNDEF;
}
dsi->symtab_len = maxva - dsi->symtab_addr;
dsi->v_end = maxva;
}
/*
* Local variables:
* mode: C
* c-set-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
--n8g4imXOkfNTN/H1--