123d0f849SIan Dowse /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 423d0f849SIan Dowse * Copyright (c) 2003 Jake Burkholder. 523d0f849SIan Dowse * Copyright 1996-1998 John D. Polstra. 623d0f849SIan Dowse * All rights reserved. 723d0f849SIan Dowse * 823d0f849SIan Dowse * Redistribution and use in source and binary forms, with or without 923d0f849SIan Dowse * modification, are permitted provided that the following conditions 1023d0f849SIan Dowse * are met: 1123d0f849SIan Dowse * 1. Redistributions of source code must retain the above copyright 1223d0f849SIan Dowse * notice, this list of conditions and the following disclaimer. 1323d0f849SIan Dowse * 2. Redistributions in binary form must reproduce the above copyright 1423d0f849SIan Dowse * notice, this list of conditions and the following disclaimer in the 1523d0f849SIan Dowse * documentation and/or other materials provided with the distribution. 1623d0f849SIan Dowse * 1723d0f849SIan Dowse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1823d0f849SIan Dowse * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1923d0f849SIan Dowse * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2023d0f849SIan Dowse * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2123d0f849SIan Dowse * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2223d0f849SIan Dowse * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2323d0f849SIan Dowse * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2423d0f849SIan Dowse * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2523d0f849SIan Dowse * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2623d0f849SIan Dowse * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2723d0f849SIan Dowse * SUCH DAMAGE. 2823d0f849SIan Dowse */ 2923d0f849SIan Dowse 300299afdfSJohn Baldwin #include <sys/endian.h> 3123d0f849SIan Dowse 3223d0f849SIan Dowse #include <err.h> 3323d0f849SIan Dowse #include <errno.h> 340299afdfSJohn Baldwin #include <gelf.h> 3523d0f849SIan Dowse 3623d0f849SIan Dowse #include "ef.h" 3723d0f849SIan Dowse 3823d0f849SIan Dowse /* 399dba198bSIan Dowse * Apply relocations to the values we got from the file. `relbase' is the 409dba198bSIan Dowse * target relocation address of the section, and `dataoff' is the target 419dba198bSIan Dowse * relocation address of the data in `dest'. 4223d0f849SIan Dowse */ 430299afdfSJohn Baldwin static int 440299afdfSJohn Baldwin ef_amd64_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype, 450299afdfSJohn Baldwin GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest) 4623d0f849SIan Dowse { 470299afdfSJohn Baldwin char *where; 480299afdfSJohn Baldwin GElf_Addr val; 490299afdfSJohn Baldwin GElf_Addr addend, addr; 500299afdfSJohn Baldwin GElf_Size rtype, symidx; 510299afdfSJohn Baldwin const GElf_Rel *rel; 520299afdfSJohn Baldwin const GElf_Rela *rela; 5323d0f849SIan Dowse 549dba198bSIan Dowse switch (reltype) { 550299afdfSJohn Baldwin case ELF_T_REL: 560299afdfSJohn Baldwin rel = (const GElf_Rel *)reldata; 570299afdfSJohn Baldwin where = (char *)dest + relbase + rel->r_offset - dataoff; 589dba198bSIan Dowse addend = 0; 590299afdfSJohn Baldwin rtype = GELF_R_TYPE(rel->r_info); 600299afdfSJohn Baldwin symidx = GELF_R_SYM(rel->r_info); 6123d0f849SIan Dowse break; 620299afdfSJohn Baldwin case ELF_T_RELA: 630299afdfSJohn Baldwin rela = (const GElf_Rela *)reldata; 640299afdfSJohn Baldwin where = (char *)dest + relbase + rela->r_offset - dataoff; 6523d0f849SIan Dowse addend = rela->r_addend; 660299afdfSJohn Baldwin rtype = GELF_R_TYPE(rela->r_info); 670299afdfSJohn Baldwin symidx = GELF_R_SYM(rela->r_info); 6823d0f849SIan Dowse break; 6923d0f849SIan Dowse default: 7023d0f849SIan Dowse return (EINVAL); 7123d0f849SIan Dowse } 7223d0f849SIan Dowse 730299afdfSJohn Baldwin if (where < (char *)dest || where >= (char *)dest + len) 7423d0f849SIan Dowse return (0); 7523d0f849SIan Dowse 760299afdfSJohn Baldwin if (reltype == ELF_T_REL) { 7723d0f849SIan Dowse /* Addend is 32 bit on 32 bit relocs */ 7823d0f849SIan Dowse switch (rtype) { 7923d0f849SIan Dowse case R_X86_64_PC32: 8023d0f849SIan Dowse case R_X86_64_32S: 810299afdfSJohn Baldwin addend = le32dec(where); 8223d0f849SIan Dowse break; 8323d0f849SIan Dowse default: 840299afdfSJohn Baldwin addend = le64dec(where); 8523d0f849SIan Dowse break; 8623d0f849SIan Dowse } 8723d0f849SIan Dowse } 8823d0f849SIan Dowse 8923d0f849SIan Dowse switch (rtype) { 9023d0f849SIan Dowse case R_X86_64_NONE: /* none */ 9123d0f849SIan Dowse break; 9223d0f849SIan Dowse case R_X86_64_64: /* S + A */ 9323d0f849SIan Dowse addr = EF_SYMADDR(ef, symidx); 9423d0f849SIan Dowse val = addr + addend; 950299afdfSJohn Baldwin le64enc(where, val); 9623d0f849SIan Dowse break; 9723d0f849SIan Dowse case R_X86_64_32S: /* S + A sign extend */ 9823d0f849SIan Dowse addr = EF_SYMADDR(ef, symidx); 990299afdfSJohn Baldwin val = (Elf32_Addr)(addr + addend); 1000299afdfSJohn Baldwin le32enc(where, val); 10123d0f849SIan Dowse break; 10223d0f849SIan Dowse case R_X86_64_GLOB_DAT: /* S */ 10323d0f849SIan Dowse addr = EF_SYMADDR(ef, symidx); 1040299afdfSJohn Baldwin le64enc(where, addr); 10523d0f849SIan Dowse break; 10623d0f849SIan Dowse case R_X86_64_RELATIVE: /* B + A */ 1070299afdfSJohn Baldwin addr = addend + relbase; 10823d0f849SIan Dowse val = addr; 1090299afdfSJohn Baldwin le64enc(where, val); 11023d0f849SIan Dowse break; 11123d0f849SIan Dowse default: 11223d0f849SIan Dowse warnx("unhandled relocation type %d", (int)rtype); 11323d0f849SIan Dowse } 11423d0f849SIan Dowse return (0); 11523d0f849SIan Dowse } 1160299afdfSJohn Baldwin 1170299afdfSJohn Baldwin ELF_RELOC(ELFCLASS64, ELFDATA2LSB, EM_X86_64, ef_amd64_reloc); 118