ca49b3342d
Implement a subset of the multiboot specification in order to boot Xen and a FreeBSD Dom0 from the FreeBSD bootloader. This multiboot implementation is tailored to boot Xen and FreeBSD Dom0, and it will most surely fail to boot any other multiboot compilant kernel. In order to detect and boot the Xen microkernel, two new file formats are added to the bootloader, multiboot and multiboot_obj. Multiboot support must be tested before regular ELF support, since Xen is a multiboot kernel that also uses ELF. After a multiboot kernel is detected, all the other loaded kernels/modules are parsed by the multiboot_obj format. The layout of the loaded objects in memory is the following; first the Xen kernel is loaded as a 32bit ELF into memory (Xen will switch to long mode by itself), after that the FreeBSD kernel is loaded as a RAW file (Xen will parse and load it using it's internal ELF loader), and finally the metadata and the modules are loaded using the native FreeBSD way. After everything is loaded we jump into Xen's entry point using a small trampoline. The order of the multiboot modules passed to Xen is the following, the first module is the RAW FreeBSD kernel, and the second module is the metadata and the FreeBSD modules. Since Xen will relocate the memory position of the second multiboot module (the one that contains the metadata and native FreeBSD modules), we need to stash the original modulep address inside of the metadata itself in order to recalculate its position once booted. This also means the metadata must come before the loaded modules, so after loading the FreeBSD kernel a portion of memory is reserved in order to place the metadata before booting. In order to tell the loader to boot Xen and then the FreeBSD kernel the following has to be added to the /boot/loader.conf file: xen_cmdline="dom0_mem=1024M dom0_max_vcpus=2 dom0pvh=1 console=com1,vga" xen_kernel="/boot/xen" The first argument contains the command line that will be passed to the Xen kernel, while the second argument is the path to the Xen kernel itself. This can also be done manually from the loader command line, by for example typing the following set of commands: OK unload OK load /boot/xen dom0_mem=1024M dom0_max_vcpus=2 dom0pvh=1 console=com1,vga OK load kernel OK load zfs OK load if_tap OK load ... OK boot Sponsored by: Citrix Systems R&D Reviewed by: jhb Differential Revision: https://reviews.freebsd.org/D517 For the Forth bits: Submitted by: Julien Grall <julien.grall AT citrix.com>
537 lines
14 KiB
C
537 lines
14 KiB
C
/*-
|
|
* Copyright (c) 2004 Ian Dowse <iedowse@freebsd.org>
|
|
* Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
|
|
* Copyright (c) 1998 Peter Wemm <peter@freebsd.org>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/exec.h>
|
|
#include <sys/linker.h>
|
|
#include <sys/module.h>
|
|
#include <inttypes.h>
|
|
#include <string.h>
|
|
#include <machine/elf.h>
|
|
#include <stand.h>
|
|
#define FREEBSD_ELF
|
|
#include <link.h>
|
|
|
|
#include "bootstrap.h"
|
|
|
|
#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l)
|
|
|
|
#if defined(__i386__) && __ELF_WORD_SIZE == 64
|
|
#undef ELF_TARG_CLASS
|
|
#undef ELF_TARG_MACH
|
|
#define ELF_TARG_CLASS ELFCLASS64
|
|
#define ELF_TARG_MACH EM_X86_64
|
|
#endif
|
|
|
|
typedef struct elf_file {
|
|
Elf_Ehdr hdr;
|
|
Elf_Shdr *e_shdr;
|
|
|
|
int symtabindex; /* Index of symbol table */
|
|
int shstrindex; /* Index of section name string table */
|
|
|
|
int fd;
|
|
vm_offset_t off;
|
|
} *elf_file_t;
|
|
|
|
static int __elfN(obj_loadimage)(struct preloaded_file *mp, elf_file_t ef,
|
|
u_int64_t loadaddr);
|
|
static int __elfN(obj_lookup_set)(struct preloaded_file *mp, elf_file_t ef,
|
|
const char *name, Elf_Addr *startp, Elf_Addr *stopp, int *countp);
|
|
static int __elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef,
|
|
Elf_Addr p, void *val, size_t len);
|
|
static int __elfN(obj_parse_modmetadata)(struct preloaded_file *mp,
|
|
elf_file_t ef);
|
|
static Elf_Addr __elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx);
|
|
|
|
const char *__elfN(obj_kerneltype) = "elf kernel";
|
|
const char *__elfN(obj_moduletype) = "elf obj module";
|
|
|
|
/*
|
|
* Attempt to load the file (file) as an ELF module. It will be stored at
|
|
* (dest), and a pointer to a module structure describing the loaded object
|
|
* will be saved in (result).
|
|
*/
|
|
int
|
|
__elfN(obj_loadfile)(char *filename, u_int64_t dest,
|
|
struct preloaded_file **result)
|
|
{
|
|
struct preloaded_file *fp, *kfp;
|
|
struct elf_file ef;
|
|
Elf_Ehdr *hdr;
|
|
int err;
|
|
ssize_t bytes_read;
|
|
|
|
fp = NULL;
|
|
bzero(&ef, sizeof(struct elf_file));
|
|
|
|
/*
|
|
* Open the image, read and validate the ELF header
|
|
*/
|
|
if (filename == NULL) /* can't handle nameless */
|
|
return(EFTYPE);
|
|
if ((ef.fd = open(filename, O_RDONLY)) == -1)
|
|
return(errno);
|
|
|
|
hdr = &ef.hdr;
|
|
bytes_read = read(ef.fd, hdr, sizeof(*hdr));
|
|
if (bytes_read != sizeof(*hdr)) {
|
|
err = EFTYPE; /* could be EIO, but may be small file */
|
|
goto oerr;
|
|
}
|
|
|
|
/* Is it ELF? */
|
|
if (!IS_ELF(*hdr)) {
|
|
err = EFTYPE;
|
|
goto oerr;
|
|
}
|
|
if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */
|
|
hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
|
|
hdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */
|
|
hdr->e_version != EV_CURRENT ||
|
|
hdr->e_machine != ELF_TARG_MACH || /* Machine ? */
|
|
hdr->e_type != ET_REL) {
|
|
err = EFTYPE;
|
|
goto oerr;
|
|
}
|
|
|
|
if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 ||
|
|
hdr->e_shentsize != sizeof(Elf_Shdr)) {
|
|
err = EFTYPE;
|
|
goto oerr;
|
|
}
|
|
|
|
kfp = file_findfile(NULL, __elfN(obj_kerneltype));
|
|
if (kfp == NULL) {
|
|
printf("elf" __XSTRING(__ELF_WORD_SIZE)
|
|
"_obj_loadfile: can't load module before kernel\n");
|
|
err = EPERM;
|
|
goto oerr;
|
|
}
|
|
|
|
if (archsw.arch_loadaddr != NULL)
|
|
dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest);
|
|
else
|
|
dest = roundup(dest, PAGE_SIZE);
|
|
|
|
/*
|
|
* Ok, we think we should handle this.
|
|
*/
|
|
fp = file_alloc();
|
|
if (fp == NULL) {
|
|
printf("elf" __XSTRING(__ELF_WORD_SIZE)
|
|
"_obj_loadfile: cannot allocate module info\n");
|
|
err = EPERM;
|
|
goto out;
|
|
}
|
|
fp->f_name = strdup(filename);
|
|
fp->f_type = strdup(__elfN(obj_moduletype));
|
|
|
|
printf("%s ", filename);
|
|
|
|
fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest);
|
|
if (fp->f_size == 0 || fp->f_addr == 0)
|
|
goto ioerr;
|
|
|
|
/* save exec header as metadata */
|
|
file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr);
|
|
|
|
/* Load OK, return module pointer */
|
|
*result = (struct preloaded_file *)fp;
|
|
err = 0;
|
|
goto out;
|
|
|
|
ioerr:
|
|
err = EIO;
|
|
oerr:
|
|
file_discard(fp);
|
|
out:
|
|
close(ef.fd);
|
|
if (ef.e_shdr != NULL)
|
|
free(ef.e_shdr);
|
|
|
|
return(err);
|
|
}
|
|
|
|
/*
|
|
* With the file (fd) open on the image, and (ehdr) containing
|
|
* the Elf header, load the image at (off)
|
|
*/
|
|
static int
|
|
__elfN(obj_loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
|
|
{
|
|
Elf_Ehdr *hdr;
|
|
Elf_Shdr *shdr, *cshdr, *lshdr;
|
|
vm_offset_t firstaddr, lastaddr;
|
|
int i, nsym, res, ret, shdrbytes, symstrindex;
|
|
|
|
ret = 0;
|
|
firstaddr = lastaddr = (vm_offset_t)off;
|
|
hdr = &ef->hdr;
|
|
ef->off = (vm_offset_t)off;
|
|
|
|
/* Read in the section headers. */
|
|
shdrbytes = hdr->e_shnum * hdr->e_shentsize;
|
|
shdr = alloc_pread(ef->fd, (off_t)hdr->e_shoff, shdrbytes);
|
|
if (shdr == NULL) {
|
|
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
|
|
"_obj_loadimage: read section headers failed\n");
|
|
goto out;
|
|
}
|
|
ef->e_shdr = shdr;
|
|
|
|
/*
|
|
* Decide where to load everything, but don't read it yet.
|
|
* We store the load address as a non-zero sh_addr value.
|
|
* Start with the code/data and bss.
|
|
*/
|
|
for (i = 0; i < hdr->e_shnum; i++)
|
|
shdr[i].sh_addr = 0;
|
|
for (i = 0; i < hdr->e_shnum; i++) {
|
|
if (shdr[i].sh_size == 0)
|
|
continue;
|
|
switch (shdr[i].sh_type) {
|
|
case SHT_PROGBITS:
|
|
case SHT_NOBITS:
|
|
lastaddr = roundup(lastaddr, shdr[i].sh_addralign);
|
|
shdr[i].sh_addr = (Elf_Addr)lastaddr;
|
|
lastaddr += shdr[i].sh_size;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Symbols. */
|
|
nsym = 0;
|
|
for (i = 0; i < hdr->e_shnum; i++) {
|
|
switch (shdr[i].sh_type) {
|
|
case SHT_SYMTAB:
|
|
nsym++;
|
|
ef->symtabindex = i;
|
|
shdr[i].sh_addr = (Elf_Addr)lastaddr;
|
|
lastaddr += shdr[i].sh_size;
|
|
break;
|
|
}
|
|
}
|
|
if (nsym != 1) {
|
|
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
|
|
"_obj_loadimage: file has no valid symbol table\n");
|
|
goto out;
|
|
}
|
|
lastaddr = roundup(lastaddr, shdr[ef->symtabindex].sh_addralign);
|
|
shdr[ef->symtabindex].sh_addr = (Elf_Addr)lastaddr;
|
|
lastaddr += shdr[ef->symtabindex].sh_size;
|
|
|
|
symstrindex = shdr[ef->symtabindex].sh_link;
|
|
if (symstrindex < 0 || symstrindex >= hdr->e_shnum ||
|
|
shdr[symstrindex].sh_type != SHT_STRTAB) {
|
|
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
|
|
"_obj_loadimage: file has invalid symbol strings\n");
|
|
goto out;
|
|
}
|
|
lastaddr = roundup(lastaddr, shdr[symstrindex].sh_addralign);
|
|
shdr[symstrindex].sh_addr = (Elf_Addr)lastaddr;
|
|
lastaddr += shdr[symstrindex].sh_size;
|
|
|
|
/* Section names. */
|
|
if (hdr->e_shstrndx == 0 || hdr->e_shstrndx >= hdr->e_shnum ||
|
|
shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) {
|
|
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
|
|
"_obj_loadimage: file has no section names\n");
|
|
goto out;
|
|
}
|
|
ef->shstrindex = hdr->e_shstrndx;
|
|
lastaddr = roundup(lastaddr, shdr[ef->shstrindex].sh_addralign);
|
|
shdr[ef->shstrindex].sh_addr = (Elf_Addr)lastaddr;
|
|
lastaddr += shdr[ef->shstrindex].sh_size;
|
|
|
|
/* Relocation tables. */
|
|
for (i = 0; i < hdr->e_shnum; i++) {
|
|
switch (shdr[i].sh_type) {
|
|
case SHT_REL:
|
|
case SHT_RELA:
|
|
lastaddr = roundup(lastaddr, shdr[i].sh_addralign);
|
|
shdr[i].sh_addr = (Elf_Addr)lastaddr;
|
|
lastaddr += shdr[i].sh_size;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Clear the whole area, including bss regions. */
|
|
kern_bzero(firstaddr, lastaddr - firstaddr);
|
|
|
|
/* Figure section with the lowest file offset we haven't loaded yet. */
|
|
for (cshdr = NULL; /* none */; /* none */)
|
|
{
|
|
/*
|
|
* Find next section to load. The complexity of this loop is
|
|
* O(n^2), but with the number of sections being typically
|
|
* small, we do not care.
|
|
*/
|
|
lshdr = cshdr;
|
|
|
|
for (i = 0; i < hdr->e_shnum; i++) {
|
|
if (shdr[i].sh_addr == 0 ||
|
|
shdr[i].sh_type == SHT_NOBITS)
|
|
continue;
|
|
/* Skip sections that were loaded already. */
|
|
if (lshdr != NULL &&
|
|
lshdr->sh_offset >= shdr[i].sh_offset)
|
|
continue;
|
|
/* Find section with smallest offset. */
|
|
if (cshdr == lshdr ||
|
|
cshdr->sh_offset > shdr[i].sh_offset)
|
|
cshdr = &shdr[i];
|
|
}
|
|
|
|
if (cshdr == lshdr)
|
|
break;
|
|
|
|
if (kern_pread(ef->fd, (vm_offset_t)cshdr->sh_addr,
|
|
cshdr->sh_size, (off_t)cshdr->sh_offset) != 0) {
|
|
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
|
|
"_obj_loadimage: read failed\n");
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
file_addmetadata(fp, MODINFOMD_SHDR, shdrbytes, shdr);
|
|
|
|
res = __elfN(obj_parse_modmetadata)(fp, ef);
|
|
if (res != 0)
|
|
goto out;
|
|
|
|
ret = lastaddr - firstaddr;
|
|
fp->f_addr = firstaddr;
|
|
|
|
printf("size 0x%lx at 0x%lx", (u_long)ret, (u_long)firstaddr);
|
|
|
|
out:
|
|
printf("\n");
|
|
return ret;
|
|
}
|
|
|
|
#if defined(__i386__) && __ELF_WORD_SIZE == 64
|
|
struct mod_metadata64 {
|
|
int md_version; /* structure version MDTV_* */
|
|
int md_type; /* type of entry MDT_* */
|
|
u_int64_t md_data; /* specific data */
|
|
u_int64_t md_cval; /* common string label */
|
|
};
|
|
#endif
|
|
|
|
int
|
|
__elfN(obj_parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef)
|
|
{
|
|
struct mod_metadata md;
|
|
#if defined(__i386__) && __ELF_WORD_SIZE == 64
|
|
struct mod_metadata64 md64;
|
|
#endif
|
|
struct mod_depend *mdepend;
|
|
struct mod_version mver;
|
|
char *s;
|
|
int error, modcnt, minfolen;
|
|
Elf_Addr v, p, p_stop;
|
|
|
|
if (__elfN(obj_lookup_set)(fp, ef, "modmetadata_set", &p, &p_stop,
|
|
&modcnt) != 0)
|
|
return 0;
|
|
|
|
modcnt = 0;
|
|
while (p < p_stop) {
|
|
COPYOUT(p, &v, sizeof(v));
|
|
error = __elfN(obj_reloc_ptr)(fp, ef, p, &v, sizeof(v));
|
|
if (error != 0)
|
|
return (error);
|
|
#if defined(__i386__) && __ELF_WORD_SIZE == 64
|
|
COPYOUT(v, &md64, sizeof(md64));
|
|
error = __elfN(obj_reloc_ptr)(fp, ef, v, &md64, sizeof(md64));
|
|
if (error != 0)
|
|
return (error);
|
|
md.md_version = md64.md_version;
|
|
md.md_type = md64.md_type;
|
|
md.md_cval = (const char *)(uintptr_t)md64.md_cval;
|
|
md.md_data = (void *)(uintptr_t)md64.md_data;
|
|
#else
|
|
COPYOUT(v, &md, sizeof(md));
|
|
error = __elfN(obj_reloc_ptr)(fp, ef, v, &md, sizeof(md));
|
|
if (error != 0)
|
|
return (error);
|
|
#endif
|
|
p += sizeof(Elf_Addr);
|
|
switch(md.md_type) {
|
|
case MDT_DEPEND:
|
|
s = strdupout((vm_offset_t)md.md_cval);
|
|
minfolen = sizeof(*mdepend) + strlen(s) + 1;
|
|
mdepend = malloc(minfolen);
|
|
if (mdepend == NULL)
|
|
return ENOMEM;
|
|
COPYOUT((vm_offset_t)md.md_data, mdepend,
|
|
sizeof(*mdepend));
|
|
strcpy((char*)(mdepend + 1), s);
|
|
free(s);
|
|
file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen,
|
|
mdepend);
|
|
free(mdepend);
|
|
break;
|
|
case MDT_VERSION:
|
|
s = strdupout((vm_offset_t)md.md_cval);
|
|
COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver));
|
|
file_addmodule(fp, s, mver.mv_version, NULL);
|
|
free(s);
|
|
modcnt++;
|
|
break;
|
|
case MDT_MODULE:
|
|
case MDT_PNP_INFO:
|
|
break;
|
|
default:
|
|
printf("unknown type %d\n", md.md_type);
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
__elfN(obj_lookup_set)(struct preloaded_file *fp, elf_file_t ef,
|
|
const char* name, Elf_Addr *startp, Elf_Addr *stopp, int *countp)
|
|
{
|
|
Elf_Ehdr *hdr;
|
|
Elf_Shdr *shdr;
|
|
char *p;
|
|
vm_offset_t shstrtab;
|
|
int i;
|
|
|
|
hdr = &ef->hdr;
|
|
shdr = ef->e_shdr;
|
|
shstrtab = shdr[ef->shstrindex].sh_addr;
|
|
|
|
for (i = 0; i < hdr->e_shnum; i++) {
|
|
if (shdr[i].sh_type != SHT_PROGBITS)
|
|
continue;
|
|
if (shdr[i].sh_name == 0)
|
|
continue;
|
|
p = strdupout(shstrtab + shdr[i].sh_name);
|
|
if (strncmp(p, "set_", 4) == 0 && strcmp(p + 4, name) == 0) {
|
|
*startp = shdr[i].sh_addr;
|
|
*stopp = shdr[i].sh_addr + shdr[i].sh_size;
|
|
*countp = (*stopp - *startp) / sizeof(Elf_Addr);
|
|
free(p);
|
|
return (0);
|
|
}
|
|
free(p);
|
|
}
|
|
|
|
return (ESRCH);
|
|
}
|
|
|
|
/*
|
|
* Apply any intra-module relocations to the value. p is the load address
|
|
* of the value and val/len is the value to be modified. This does NOT modify
|
|
* the image in-place, because this is done by kern_linker later on.
|
|
*/
|
|
static int
|
|
__elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, Elf_Addr p,
|
|
void *val, size_t len)
|
|
{
|
|
Elf_Ehdr *hdr;
|
|
Elf_Shdr *shdr;
|
|
Elf_Addr off = p;
|
|
Elf_Addr base;
|
|
Elf_Rela a, *abase;
|
|
Elf_Rel r, *rbase;
|
|
int error, i, j, nrel, nrela;
|
|
|
|
hdr = &ef->hdr;
|
|
shdr = ef->e_shdr;
|
|
|
|
for (i = 0; i < hdr->e_shnum; i++) {
|
|
if (shdr[i].sh_type != SHT_RELA && shdr[i].sh_type != SHT_REL)
|
|
continue;
|
|
base = shdr[shdr[i].sh_info].sh_addr;
|
|
if (base == 0 || shdr[i].sh_addr == 0)
|
|
continue;
|
|
if (off < base || off + len > base +
|
|
shdr[shdr[i].sh_info].sh_size)
|
|
continue;
|
|
|
|
switch (shdr[i].sh_type) {
|
|
case SHT_RELA:
|
|
abase = (Elf_Rela *)(intptr_t)shdr[i].sh_addr;
|
|
|
|
nrela = shdr[i].sh_size / sizeof(Elf_Rela);
|
|
for (j = 0; j < nrela; j++) {
|
|
COPYOUT(abase + j, &a, sizeof(a));
|
|
|
|
error = __elfN(reloc)(ef, __elfN(obj_symaddr),
|
|
&a, ELF_RELOC_RELA, base, off, val, len);
|
|
if (error != 0)
|
|
return (error);
|
|
}
|
|
break;
|
|
case SHT_REL:
|
|
rbase = (Elf_Rel *)(intptr_t)shdr[i].sh_addr;
|
|
|
|
nrel = shdr[i].sh_size / sizeof(Elf_Rel);
|
|
for (j = 0; j < nrel; j++) {
|
|
COPYOUT(rbase + j, &r, sizeof(r));
|
|
|
|
error = __elfN(reloc)(ef, __elfN(obj_symaddr),
|
|
&r, ELF_RELOC_REL, base, off, val, len);
|
|
if (error != 0)
|
|
return (error);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/* Look up the address of a specified symbol. */
|
|
static Elf_Addr
|
|
__elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx)
|
|
{
|
|
Elf_Sym sym;
|
|
Elf_Addr base;
|
|
int symcnt;
|
|
|
|
symcnt = ef->e_shdr[ef->symtabindex].sh_size / sizeof(Elf_Sym);
|
|
if (symidx >= symcnt)
|
|
return (0);
|
|
COPYOUT(ef->e_shdr[ef->symtabindex].sh_addr + symidx * sizeof(Elf_Sym),
|
|
&sym, sizeof(sym));
|
|
if (sym.st_shndx == SHN_UNDEF || sym.st_shndx >= ef->hdr.e_shnum)
|
|
return (0);
|
|
base = ef->e_shdr[sym.st_shndx].sh_addr;
|
|
if (base == 0)
|
|
return (0);
|
|
return (base + sym.st_value);
|
|
}
|