From nobody Tue Dec 16 12:38:42 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 48E6F2989AF; Fri, 9 May 2025 20:18:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746821893; cv=none; b=MZofZYmTuF92THmJKNaPWOMZSlEF3iI6BmF2Wsj/OYetre1W6dqKsBOOkKP78b1K5q+v7sQ2B6ibXvgjWh3LzMcfVc2YBLB7Ao98qW/Wm3rXzwmcADmR7Ohht2zYZLJBStmo93AzmLttyO28Uod54R9yL1c2eAy1FKi8mF7tsiU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746821893; c=relaxed/simple; bh=g3favnQ2TasT07axjoxQsRRs95xIcj3hy0hj5Qm7MVQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FCd2fJKNOH4suGTPVTYP7CZBjZof/lNzYC0DsxnDGNV1pd2pGOCGC2d6Dd+5w8VcxTcq+B00wgGYw0qBcfRKPNvxkXUk4/gYg4irKgyL3VtR8yFlA/VNT3bq2SK3xN0os4jQRsKoto78wxpSY1IZtZ5bwWXNDPJRvgnHGMW0XP4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=eDMKCPXc; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="eDMKCPXc" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9B6A3C4CEE4; Fri, 9 May 2025 20:18:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1746821893; bh=g3favnQ2TasT07axjoxQsRRs95xIcj3hy0hj5Qm7MVQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eDMKCPXcHmKQq6TFumRtM7si9IejQD31KydsxGJqnYYJ7dR6zkcBAJE5GSP5owKAZ jB2IULLblNQyheueODNyO6Psux44q1+bYDQnH2k6VD8vk/pps5Phx4DdnD/+J8isr6 DutD3ozAjD2KTtr0312Axzu5MXUwgJhc0OP1Ltr/3oTQfMarC6rFUnvFi+Cgykn2H2 frtBQCnoNFwZX3INp+bTtL2TBLRchO4xcMz4CLZXFqs0AiZxSCT3Ln44VmkOL5goNy 1kPdhYd+JO4soKtpMkLOReZYgJ7+8bFQpm1HLNnMAW4MJ57zEWEESIYOe2fnjdfiyH cFUby31vXkvKw== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, Petr Mladek , Miroslav Benes , Joe Lawrence , live-patching@vger.kernel.org, Song Liu , laokz , Jiri Kosina , Marcos Paulo de Souza , Weinan Liu , Fazla Mehrab , Chen Zhongjin , Puranjay Mohan Subject: [PATCH v2 40/62] objtool: Introduce elf_create_reloc() and elf_init_reloc() Date: Fri, 9 May 2025 13:17:04 -0700 Message-ID: <8c045c6e3048507898e9229ddd1aa7eb9ecbd0f6.1746821544.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" elf_create_rela_section() is quite limited in that it requires the caller to know how many relocations need to be allocated up front. In preparation for the objtool klp diff subcommand, allow an arbitrary number of relocations to be created and initialized on demand after section creation. Signed-off-by: Josh Poimboeuf --- tools/objtool/elf.c | 151 +++++++++++++++++++++++++--- tools/objtool/include/objtool/elf.h | 9 ++ 2 files changed, 145 insertions(+), 15 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 1b5528065df7..8fc6e6c75b88 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -22,6 +22,8 @@ #include =20 #define ALIGN_UP(x, align_to) (((x) + ((align_to)-1)) & ~((align_to)-1)) +#define ALIGN_UP_POW2(x) (1U << ((8 * sizeof(x)) - __builtin_clz((x) - 1U)= )) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) =20 static inline u32 str_hash(const char *str) { @@ -897,10 +899,9 @@ elf_create_prefix_symbol(struct elf *elf, struct symbo= l *orig, size_t size) offset, size); } =20 -static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, - unsigned int reloc_idx, - unsigned long offset, struct symbol *sym, - s64 addend, unsigned int type) +struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, + unsigned int reloc_idx, unsigned long offset, + struct symbol *sym, s64 addend, unsigned int type) { struct reloc *reloc, empty =3D { 0 }; =20 @@ -1002,12 +1003,14 @@ static int read_relocs(struct elf *elf) =20 rsec->base->rsec =3D rsec; =20 - nr_reloc =3D 0; - rsec->relocs =3D calloc(sec_num_entries(rsec), sizeof(*reloc)); + rsec->nr_alloc_relocs =3D sec_num_entries(rsec); + rsec->relocs =3D calloc(rsec->nr_alloc_relocs, sizeof(*reloc)); if (!rsec->relocs) { ERROR_GLIBC("calloc"); return -1; } + + nr_reloc =3D 0; for (i =3D 0; i < sec_num_entries(rsec); i++) { reloc =3D &rsec->relocs[i]; =20 @@ -1256,8 +1259,99 @@ struct section *elf_create_section(struct elf *elf, = const char *name, return sec; } =20 +static int elf_alloc_reloc(struct elf *elf, struct section *rsec) +{ + struct reloc *old_relocs, *old_relocs_end, *new_relocs; + unsigned int nr_relocs_old =3D sec_num_entries(rsec); + unsigned int nr_relocs_new =3D nr_relocs_old + 1; + unsigned long nr_alloc; + struct symbol *sym; + + if (!rsec->data) { + rsec->data =3D elf_newdata(elf_getscn(elf->elf, rsec->idx)); + if (!rsec->data) { + ERROR_ELF("elf_newdata"); + return -1; + } + + rsec->data->d_align =3D 1; + rsec->data->d_type =3D ELF_T_RELA; + rsec->data->d_buf =3D NULL; + } + + rsec->data->d_size =3D nr_relocs_new * elf_rela_size(elf); + rsec->sh.sh_size =3D rsec->data->d_size; + + nr_alloc =3D MAX(64, ALIGN_UP_POW2(nr_relocs_new)); + if (nr_alloc <=3D rsec->nr_alloc_relocs) + return 0; + rsec->nr_alloc_relocs =3D nr_alloc; + + rsec->data->d_buf =3D realloc(rsec->data->d_buf, + nr_alloc * elf_rela_size(elf)); + if (!rsec->data->d_buf) { + ERROR_GLIBC("realloc"); + return -1; + } + + old_relocs =3D rsec->relocs; + new_relocs =3D calloc(nr_alloc, sizeof(struct reloc)); + if (!new_relocs) { + ERROR_GLIBC("calloc"); + return -1; + } + + if (!old_relocs) + goto done; + + /* + * The struct reloc's address has changed. Update all the symbols and + * relocs which reference it. + */ + + old_relocs_end =3D &old_relocs[nr_relocs_old]; + for_each_sym(elf, sym) { + struct reloc *reloc; + + reloc =3D sym->relocs; + if (!reloc) + continue; + + if (reloc >=3D old_relocs && reloc < old_relocs_end) + sym->relocs =3D &new_relocs[reloc - old_relocs]; + + while (1) { + struct reloc *next_reloc =3D sym_next_reloc(reloc); + + if (!next_reloc) + break; + + if (next_reloc >=3D old_relocs && next_reloc < old_relocs_end) + set_sym_next_reloc(reloc, &new_relocs[next_reloc - old_relocs]); + + reloc =3D next_reloc; + } + } + + memcpy(new_relocs, old_relocs, nr_relocs_old * sizeof(struct reloc)); + + for (int i =3D 0; i < nr_relocs_old; i++) { + struct reloc *old =3D &old_relocs[i]; + struct reloc *new =3D &new_relocs[i]; + u32 key =3D reloc_hash(old); + + elf_hash_del(reloc, &old->hash, key); + elf_hash_add(reloc, &new->hash, key); + } + + free(old_relocs); +done: + rsec->relocs =3D new_relocs; + return 0; +} + struct section *elf_create_rela_section(struct elf *elf, struct section *s= ec, - unsigned int reloc_nr) + unsigned int nr_relocs) { struct section *rsec; char *rsec_name; @@ -1270,34 +1364,61 @@ struct section *elf_create_rela_section(struct elf = *elf, struct section *sec, strcpy(rsec_name, ".rela"); strcat(rsec_name, sec->name); =20 - rsec =3D elf_create_section(elf, rsec_name, reloc_nr * elf_rela_size(elf), + rsec =3D elf_create_section(elf, rsec_name, nr_relocs * elf_rela_size(elf= ), elf_rela_size(elf), SHT_RELA, elf_addr_size(elf), SHF_INFO_LINK); free(rsec_name); if (!rsec) return NULL; =20 - rsec->sh.sh_link =3D find_section_by_name(elf, ".symtab")->idx; - rsec->sh.sh_info =3D sec->idx; - - if (reloc_nr) { + if (nr_relocs) { rsec->data->d_type =3D ELF_T_RELA; - rsec->relocs =3D calloc(sec_num_entries(rsec), sizeof(struct reloc)); + + rsec->nr_alloc_relocs =3D nr_relocs; + rsec->relocs =3D calloc(nr_relocs, sizeof(struct reloc)); if (!rsec->relocs) { ERROR_GLIBC("calloc"); return NULL; } } =20 + rsec->sh.sh_link =3D find_section_by_name(elf, ".symtab")->idx; + rsec->sh.sh_info =3D sec->idx; + sec->rsec =3D rsec; rsec->base =3D sec; =20 return rsec; } =20 +struct reloc *elf_create_reloc(struct elf *elf, struct section *sec, + unsigned long offset, + struct symbol *sym, s64 addend, + unsigned int type) +{ + struct section *rsec =3D sec->rsec; + + if (!rsec) { + rsec =3D elf_create_rela_section(elf, sec, 0); + if (!rsec) + return NULL; + } + + if (find_reloc_by_dest(elf, sec, offset)) { + ERROR_FUNC(sec, offset, "duplicate reloc"); + return NULL; + } + + if (elf_alloc_reloc(elf, rsec)) + return NULL; + + return elf_init_reloc(elf, rsec, sec_num_entries(rsec) - 1, offset, sym, + addend, type); +} + struct section *elf_create_section_pair(struct elf *elf, const char *name, size_t entsize, unsigned int nr, - unsigned int reloc_nr) + unsigned int nr_relocs) { struct section *sec; =20 @@ -1306,7 +1427,7 @@ struct section *elf_create_section_pair(struct elf *e= lf, const char *name, if (!sec) return NULL; =20 - if (!elf_create_rela_section(elf, sec, reloc_nr)) + if (!elf_create_rela_section(elf, sec, nr_relocs)) return NULL; =20 return sec; diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/ob= jtool/elf.h index fc00f86bedba..5c663e475890 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -47,6 +47,7 @@ struct section { int idx; bool _changed, text, rodata, noinstr, init, truncate; struct reloc *relocs; + unsigned long nr_alloc_relocs; }; =20 struct symbol { @@ -139,6 +140,14 @@ void *elf_add_data(struct elf *elf, struct section *se= c, const void *data, =20 unsigned int elf_add_string(struct elf *elf, struct section *strtab, const= char *str); =20 +struct reloc *elf_create_reloc(struct elf *elf, struct section *sec, + unsigned long offset, struct symbol *sym, + s64 addend, unsigned int type); + +struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, + unsigned int reloc_idx, unsigned long offset, + struct symbol *sym, s64 addend, unsigned int type); + struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, unsigned long offset, unsigned int reloc_idx, --=20 2.49.0