freebsd-src/usr.sbin/kldxref/ef_i386.c
Jessica Clarke 2a622f14e8 kldxref: Reduce divergence between per-architecture files
Note that relbase is always 0 for DSOs so its omission for __KLD_SHARED
architectures was not a bug in practice.

Whilst here, also parenthesise the dest offset for where to avoid
transiently creating an out-of-bounds pointer, which is UB (though even
on CHERI architectures, where capability bounds compression can result
in that creating invalid capabilities that will trap on dereference,
optimisation will reassociate to the correct form in practice and thus
work just fine).
2023-12-14 20:17:20 +00:00

98 lines
3 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 "ef.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);