HardenedBSD/lib/libkldelf/ef_i386.c
Ka Ho Ng 968bcca262 libkldelf: add a private library for kernel/kld-related ELF parsing
The libkldelf library was originally a part of kldxref(8). It exposed
ELF parsing helpers specialized in parsing KLDs and the kernel
executable. The library can be used to read metadata such as linker_set,
mod_depend, mod_version and PNP match info, and raw data from the ELF.

To promote the reuse of the facilities the ELF parsing code is separated
from kldxref(8) into a new private library.

For now, libkldelf's source files will be compiled into kldxref(8)
directly if kldxref is built during bootstrapping phase. The reason is
linking kldxref(8) against the libkldelf static library has an unwanted
side effect which renders the linker sets inside the libkldelf
implementation empty if the static library is not build by ld -r all the
.o files into a single .o before producing the static library.

Sponsored by:	Juniper Networks, Inc.
Reviewed by:	markj
Suggested by:	jrtc27, markj
Differential Revision:	https://reviews.freebsd.org/D46719
2024-10-18 20:20:13 +00:00

98 lines
3.0 KiB
C

/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Jake Burkholder.
* Copyright 1996-1998 John D. Polstra.
* 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/endian.h>
#include <err.h>
#include <errno.h>
#include <gelf.h>
#include "kldelf.h"
/*
* Apply relocations to the values obtained from the file. `relbase' is the
* target relocation address of the section, and `dataoff/len' is the region
* that is to be relocated, and has been copied to *dest
*/
static int
ef_i386_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype,
GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
{
char *where;
GElf_Addr addr, addend;
GElf_Size rtype, symidx;
const GElf_Rel *rel;
const GElf_Rela *rela;
switch (reltype) {
case ELF_T_REL:
rel = (const GElf_Rel *)reldata;
where = (char *)dest + (relbase + rel->r_offset - dataoff);
addend = 0;
rtype = GELF_R_TYPE(rel->r_info);
symidx = GELF_R_SYM(rel->r_info);
break;
case ELF_T_RELA:
rela = (const GElf_Rela *)reldata;
where = (char *)dest + (relbase + rela->r_offset - dataoff);
addend = rela->r_addend;
rtype = GELF_R_TYPE(rela->r_info);
symidx = GELF_R_SYM(rela->r_info);
break;
default:
return (EINVAL);
}
if (where < (char *)dest || where >= (char *)dest + len)
return (0);
if (reltype == ELF_T_REL)
addend = le32dec(where);
switch (rtype) {
case R_386_RELATIVE: /* B + A */
addr = relbase + addend;
le32enc(where, addr);
break;
case R_386_32: /* S + A - P */
addr = EF_SYMADDR(ef, symidx) + addend;
le32enc(where, addr);
break;
case R_386_GLOB_DAT: /* S */
addr = EF_SYMADDR(ef, symidx);
le32enc(where, addr);
break;
default:
warnx("unhandled relocation type %d", (int)rtype);
}
return (0);
}
ELF_RELOC(ELFCLASS32, ELFDATA2LSB, EM_386, ef_i386_reloc);