From: Josh Poimboeuf <jpoimboe@kernel.org>
To: x86@kernel.org
Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org,
Peter Zijlstra <peterz@infradead.org>,
Joe Lawrence <joe.lawrence@redhat.com>,
Song Liu <song@kernel.org>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
linux-arm-kernel@lists.infradead.org,
Mark Rutland <mark.rutland@arm.com>,
Miroslav Benes <mbenes@suse.cz>, Petr Mladek <pmladek@suse.com>
Subject: [PATCH v3 12/21] objtool: Refactor elf_add_data() to use a growable data buffer
Date: Tue, 12 May 2026 20:33:46 -0700 [thread overview]
Message-ID: <a0fe2363d017a2833e98ae50de797fe55c2796a4.1778642120.git.jpoimboe@kernel.org> (raw)
In-Reply-To: <cover.1778642120.git.jpoimboe@kernel.org>
Instead of calling elf_newdata() for each new piece of data with its own
separate buffer, keep it all in the same growable buffer so the
section's entire data can be accessed if needed.
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/elf.c | 123 ++++++++++++++--------------
tools/objtool/include/objtool/elf.h | 13 ++-
2 files changed, 71 insertions(+), 65 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 33c95a74a51bd..e09bb0a63be35 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -1134,9 +1134,6 @@ static int read_relocs(struct elf *elf)
rsec->base->rsec = rsec;
- /* nr_alloc_relocs=0: libelf owns d_buf */
- rsec->nr_alloc_relocs = 0;
-
rsec->relocs = calloc(sec_num_entries(rsec), sizeof(*reloc));
if (!rsec->relocs) {
ERROR_GLIBC("calloc");
@@ -1395,7 +1392,7 @@ unsigned int elf_add_string(struct elf *elf, struct section *strtab, const char
void *elf_add_data(struct elf *elf, struct section *sec, const void *data, size_t size)
{
- unsigned long offset;
+ unsigned long offset, size_old, size_new, alloc_size_old, alloc_size_new;
Elf_Scn *s;
if (!sec->sh.sh_addralign) {
@@ -1409,30 +1406,55 @@ void *elf_add_data(struct elf *elf, struct section *sec, const void *data, size_
return NULL;
}
- sec->data = elf_newdata(s);
if (!sec->data) {
- ERROR_ELF("elf_newdata");
- return NULL;
+ sec->data = elf_newdata(s);
+ if (!sec->data) {
+ ERROR_ELF("elf_newdata");
+ return NULL;
+ }
+
+ sec->data->d_align = sec->sh.sh_addralign;
}
- sec->data->d_buf = calloc(1, size);
- if (!sec->data->d_buf) {
- ERROR_GLIBC("calloc");
- return NULL;
+ size_old = sec->data->d_size;
+ offset = ALIGN(size_old, sec->sh.sh_addralign);
+ size_new = offset + size;
+
+ if (!sec->data_overallocated)
+ alloc_size_old = size_old;
+ else
+ alloc_size_old = max(64UL, roundup_pow_of_two(size_old ? : 1));
+
+ alloc_size_new = max(64UL, roundup_pow_of_two(size_new ? : 1));
+
+ if (alloc_size_new > alloc_size_old) {
+ void *orig_buf = sec->data->d_buf;
+
+ sec->data->d_buf = calloc(1, alloc_size_new);
+ if (!sec->data->d_buf) {
+ ERROR_GLIBC("calloc");
+ return NULL;
+ }
+
+ if (size_old)
+ memcpy(sec->data->d_buf, orig_buf, size_old);
+
+ if (orig_buf && sec->data_owned)
+ free(orig_buf);
+
+ sec->data_owned = 1;
+ sec->data_overallocated = 1;
}
if (data)
- memcpy(sec->data->d_buf, data, size);
-
- sec->data->d_size = size;
- sec->data->d_align = sec->sh.sh_addralign;
-
- offset = ALIGN(sec_size(sec), sec->sh.sh_addralign);
- sec->sh.sh_size = offset + size;
+ memcpy(sec->data->d_buf + offset, data, size);
+ else
+ memset(sec->data->d_buf + offset, 0, size);
+ sec->data->d_size = size_new;
+ sec->sh.sh_size = size_new;
mark_sec_changed(elf, sec, true);
-
- return sec->data->d_buf;
+ return sec->data->d_buf + offset;
}
struct section *elf_create_section(struct elf *elf, const char *name,
@@ -1483,6 +1505,8 @@ struct section *elf_create_section(struct elf *elf, const char *name,
ERROR_GLIBC("calloc");
return NULL;
}
+
+ sec->data_owned = 1;
}
if (!gelf_getshdr(s, &sec->sh)) {
@@ -1533,60 +1557,33 @@ 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 = sec_num_entries(rsec);
unsigned int nr_relocs_new = nr_relocs_old + 1;
- unsigned long nr_alloc;
+ unsigned long nr_alloc_old = 0, nr_alloc_new;
struct symbol *sym;
- if (!rsec->data) {
- rsec->data = elf_newdata(elf_getscn(elf->elf, rsec->idx));
- if (!rsec->data) {
- ERROR_ELF("elf_newdata");
- return -1;
- }
+ if (!elf_add_data(elf, rsec, NULL, elf_rela_size(elf)))
+ return -1;
- rsec->data->d_align = 1;
- rsec->data->d_type = ELF_T_RELA;
- rsec->data->d_buf = NULL;
- }
+ rsec->data->d_type = ELF_T_RELA;
- rsec->data->d_size = nr_relocs_new * elf_rela_size(elf);
- rsec->sh.sh_size = rsec->data->d_size;
+ if (rsec->relocs_overallocated)
+ nr_alloc_old = max(64UL, roundup_pow_of_two(nr_relocs_old ? : 1));
+ else
+ nr_alloc_old = nr_relocs_old;
- nr_alloc = max(64UL, roundup_pow_of_two(nr_relocs_new));
- if (nr_alloc <= rsec->nr_alloc_relocs)
+ nr_alloc_new = max(64UL, roundup_pow_of_two(nr_relocs_new ? : 1));
+
+ if (nr_alloc_old == nr_alloc_new)
return 0;
- if (rsec->data->d_buf && !rsec->nr_alloc_relocs) {
- void *orig_buf = rsec->data->d_buf;
-
- /*
- * The original d_buf is owned by libelf so it can't be
- * realloced.
- */
- rsec->data->d_buf = malloc(nr_alloc * elf_rela_size(elf));
- if (!rsec->data->d_buf) {
- ERROR_GLIBC("malloc");
- return -1;
- }
- memcpy(rsec->data->d_buf, orig_buf,
- nr_relocs_old * elf_rela_size(elf));
- } else {
- rsec->data->d_buf = realloc(rsec->data->d_buf,
- nr_alloc * elf_rela_size(elf));
- if (!rsec->data->d_buf) {
- ERROR_GLIBC("realloc");
- return -1;
- }
- }
-
- rsec->nr_alloc_relocs = nr_alloc;
-
- old_relocs = rsec->relocs;
- new_relocs = calloc(nr_alloc, sizeof(struct reloc));
+ new_relocs = calloc(nr_alloc_new, sizeof(struct reloc));
if (!new_relocs) {
ERROR_GLIBC("calloc");
return -1;
}
+ rsec->relocs_overallocated = 1;
+
+ old_relocs = rsec->relocs;
if (!old_relocs)
goto done;
@@ -1631,6 +1628,7 @@ static int elf_alloc_reloc(struct elf *elf, struct section *rsec)
}
free(old_relocs);
+
done:
rsec->relocs = new_relocs;
return 0;
@@ -1660,7 +1658,6 @@ struct section *elf_create_rela_section(struct elf *elf, struct section *sec,
if (nr_relocs) {
rsec->data->d_type = ELF_T_RELA;
- rsec->nr_alloc_relocs = nr_relocs;
rsec->relocs = calloc(nr_relocs, sizeof(struct reloc));
if (!rsec->relocs) {
ERROR_GLIBC("calloc");
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index d9c44df9cc76a..0801fcad516bb 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -58,9 +58,18 @@ struct section {
Elf_Data *data;
const char *name;
int idx;
- bool _changed, text, rodata, noinstr, init, truncate;
+ u32 _changed : 1,
+ text : 1,
+ rodata : 1,
+ noinstr : 1,
+ init : 1,
+ truncate : 1,
+ data_owned : 1,
+ data_overallocated : 1,
+ relocs_overallocated : 1;
+ /* 23 bit hole */
+
struct reloc *relocs;
- unsigned long nr_alloc_relocs;
struct section *twin;
};
--
2.53.0
WARNING: multiple messages have this Message-ID (diff)
From: Josh Poimboeuf <jpoimboe@kernel.org>
To: x86@kernel.org
Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org,
Peter Zijlstra <peterz@infradead.org>,
Joe Lawrence <joe.lawrence@redhat.com>,
Song Liu <song@kernel.org>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
linux-arm-kernel@lists.infradead.org,
Mark Rutland <mark.rutland@arm.com>,
Miroslav Benes <mbenes@suse.cz>, Petr Mladek <pmladek@suse.com>
Subject: [PATCH v3 12/21] objtool: Refactor elf_add_data() to use a growable data buffer
Date: Tue, 12 May 2026 20:34:08 -0700 [thread overview]
Message-ID: <a0fe2363d017a2833e98ae50de797fe55c2796a4.1778642120.git.jpoimboe@kernel.org> (raw)
Message-ID: <20260513033408.1ZFb2x8-oSTFMWeQJYaVS7d61vl60pmihmMFdLyLrG0@z> (raw)
In-Reply-To: <cover.1778642120.git.jpoimboe@kernel.org>
Instead of calling elf_newdata() for each new piece of data with its own
separate buffer, keep it all in the same growable buffer so the
section's entire data can be accessed if needed.
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/elf.c | 123 ++++++++++++++--------------
tools/objtool/include/objtool/elf.h | 13 ++-
2 files changed, 71 insertions(+), 65 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 33c95a74a51bd..e09bb0a63be35 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -1134,9 +1134,6 @@ static int read_relocs(struct elf *elf)
rsec->base->rsec = rsec;
- /* nr_alloc_relocs=0: libelf owns d_buf */
- rsec->nr_alloc_relocs = 0;
-
rsec->relocs = calloc(sec_num_entries(rsec), sizeof(*reloc));
if (!rsec->relocs) {
ERROR_GLIBC("calloc");
@@ -1395,7 +1392,7 @@ unsigned int elf_add_string(struct elf *elf, struct section *strtab, const char
void *elf_add_data(struct elf *elf, struct section *sec, const void *data, size_t size)
{
- unsigned long offset;
+ unsigned long offset, size_old, size_new, alloc_size_old, alloc_size_new;
Elf_Scn *s;
if (!sec->sh.sh_addralign) {
@@ -1409,30 +1406,55 @@ void *elf_add_data(struct elf *elf, struct section *sec, const void *data, size_
return NULL;
}
- sec->data = elf_newdata(s);
if (!sec->data) {
- ERROR_ELF("elf_newdata");
- return NULL;
+ sec->data = elf_newdata(s);
+ if (!sec->data) {
+ ERROR_ELF("elf_newdata");
+ return NULL;
+ }
+
+ sec->data->d_align = sec->sh.sh_addralign;
}
- sec->data->d_buf = calloc(1, size);
- if (!sec->data->d_buf) {
- ERROR_GLIBC("calloc");
- return NULL;
+ size_old = sec->data->d_size;
+ offset = ALIGN(size_old, sec->sh.sh_addralign);
+ size_new = offset + size;
+
+ if (!sec->data_overallocated)
+ alloc_size_old = size_old;
+ else
+ alloc_size_old = max(64UL, roundup_pow_of_two(size_old ? : 1));
+
+ alloc_size_new = max(64UL, roundup_pow_of_two(size_new ? : 1));
+
+ if (alloc_size_new > alloc_size_old) {
+ void *orig_buf = sec->data->d_buf;
+
+ sec->data->d_buf = calloc(1, alloc_size_new);
+ if (!sec->data->d_buf) {
+ ERROR_GLIBC("calloc");
+ return NULL;
+ }
+
+ if (size_old)
+ memcpy(sec->data->d_buf, orig_buf, size_old);
+
+ if (orig_buf && sec->data_owned)
+ free(orig_buf);
+
+ sec->data_owned = 1;
+ sec->data_overallocated = 1;
}
if (data)
- memcpy(sec->data->d_buf, data, size);
-
- sec->data->d_size = size;
- sec->data->d_align = sec->sh.sh_addralign;
-
- offset = ALIGN(sec_size(sec), sec->sh.sh_addralign);
- sec->sh.sh_size = offset + size;
+ memcpy(sec->data->d_buf + offset, data, size);
+ else
+ memset(sec->data->d_buf + offset, 0, size);
+ sec->data->d_size = size_new;
+ sec->sh.sh_size = size_new;
mark_sec_changed(elf, sec, true);
-
- return sec->data->d_buf;
+ return sec->data->d_buf + offset;
}
struct section *elf_create_section(struct elf *elf, const char *name,
@@ -1483,6 +1505,8 @@ struct section *elf_create_section(struct elf *elf, const char *name,
ERROR_GLIBC("calloc");
return NULL;
}
+
+ sec->data_owned = 1;
}
if (!gelf_getshdr(s, &sec->sh)) {
@@ -1533,60 +1557,33 @@ 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 = sec_num_entries(rsec);
unsigned int nr_relocs_new = nr_relocs_old + 1;
- unsigned long nr_alloc;
+ unsigned long nr_alloc_old = 0, nr_alloc_new;
struct symbol *sym;
- if (!rsec->data) {
- rsec->data = elf_newdata(elf_getscn(elf->elf, rsec->idx));
- if (!rsec->data) {
- ERROR_ELF("elf_newdata");
- return -1;
- }
+ if (!elf_add_data(elf, rsec, NULL, elf_rela_size(elf)))
+ return -1;
- rsec->data->d_align = 1;
- rsec->data->d_type = ELF_T_RELA;
- rsec->data->d_buf = NULL;
- }
+ rsec->data->d_type = ELF_T_RELA;
- rsec->data->d_size = nr_relocs_new * elf_rela_size(elf);
- rsec->sh.sh_size = rsec->data->d_size;
+ if (rsec->relocs_overallocated)
+ nr_alloc_old = max(64UL, roundup_pow_of_two(nr_relocs_old ? : 1));
+ else
+ nr_alloc_old = nr_relocs_old;
- nr_alloc = max(64UL, roundup_pow_of_two(nr_relocs_new));
- if (nr_alloc <= rsec->nr_alloc_relocs)
+ nr_alloc_new = max(64UL, roundup_pow_of_two(nr_relocs_new ? : 1));
+
+ if (nr_alloc_old == nr_alloc_new)
return 0;
- if (rsec->data->d_buf && !rsec->nr_alloc_relocs) {
- void *orig_buf = rsec->data->d_buf;
-
- /*
- * The original d_buf is owned by libelf so it can't be
- * realloced.
- */
- rsec->data->d_buf = malloc(nr_alloc * elf_rela_size(elf));
- if (!rsec->data->d_buf) {
- ERROR_GLIBC("malloc");
- return -1;
- }
- memcpy(rsec->data->d_buf, orig_buf,
- nr_relocs_old * elf_rela_size(elf));
- } else {
- rsec->data->d_buf = realloc(rsec->data->d_buf,
- nr_alloc * elf_rela_size(elf));
- if (!rsec->data->d_buf) {
- ERROR_GLIBC("realloc");
- return -1;
- }
- }
-
- rsec->nr_alloc_relocs = nr_alloc;
-
- old_relocs = rsec->relocs;
- new_relocs = calloc(nr_alloc, sizeof(struct reloc));
+ new_relocs = calloc(nr_alloc_new, sizeof(struct reloc));
if (!new_relocs) {
ERROR_GLIBC("calloc");
return -1;
}
+ rsec->relocs_overallocated = 1;
+
+ old_relocs = rsec->relocs;
if (!old_relocs)
goto done;
@@ -1631,6 +1628,7 @@ static int elf_alloc_reloc(struct elf *elf, struct section *rsec)
}
free(old_relocs);
+
done:
rsec->relocs = new_relocs;
return 0;
@@ -1660,7 +1658,6 @@ struct section *elf_create_rela_section(struct elf *elf, struct section *sec,
if (nr_relocs) {
rsec->data->d_type = ELF_T_RELA;
- rsec->nr_alloc_relocs = nr_relocs;
rsec->relocs = calloc(nr_relocs, sizeof(struct reloc));
if (!rsec->relocs) {
ERROR_GLIBC("calloc");
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index d9c44df9cc76a..0801fcad516bb 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -58,9 +58,18 @@ struct section {
Elf_Data *data;
const char *name;
int idx;
- bool _changed, text, rodata, noinstr, init, truncate;
+ u32 _changed : 1,
+ text : 1,
+ rodata : 1,
+ noinstr : 1,
+ init : 1,
+ truncate : 1,
+ data_owned : 1,
+ data_overallocated : 1,
+ relocs_overallocated : 1;
+ /* 23 bit hole */
+
struct reloc *relocs;
- unsigned long nr_alloc_relocs;
struct section *twin;
};
--
2.53.0
next prev parent reply other threads:[~2026-05-13 3:34 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-13 3:33 [PATCH v3 00/21] objtool/arm64: Port klp-build to arm64 Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 01/21] klp-build: Reject patches to init/*.c Josh Poimboeuf
2026-05-13 3:33 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 02/21] arm64: Annotate intra-function calls Josh Poimboeuf
2026-05-13 3:33 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 03/21] arm64: Fix EFI linking with -fdata-sections Josh Poimboeuf
2026-05-13 3:33 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 04/21] arm64: Rename TRAMP_VALIAS -> TRAMP_VALIAS_ASM in asm-offsets Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 05/21] arm64: vdso: Discard .discard.* sections Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 06/21] arm64: Annotate special section entries Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 07/21] crypto: arm64: Move data to .rodata Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 08/21] objtool: Allow setting --mnop without --mcount Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 09/21] kbuild: Only run objtool if there is at least one command Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 10/21] objtool: Ignore jumps to the end of the function for checksum runs Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 7:36 ` Peter Zijlstra
2026-05-13 3:33 ` [PATCH v3 11/21] objtool: Allow empty alternatives Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 7:37 ` Peter Zijlstra
2026-05-13 3:33 ` Josh Poimboeuf [this message]
2026-05-13 3:34 ` [PATCH v3 12/21] objtool: Refactor elf_add_data() to use a growable data buffer Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 13/21] objtool: Reuse string references Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 14/21] objtool: Prevent kCFI hashes from being decoded as instructions Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 15/21] objtool/klp: Add arm64 support for prefix/PFE detection Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 16/21] objtool/klp: Filter arm64 mapping symbols in find_symbol_by_offset() Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 17/21] objtool/klp: Don't correlate arm64 mapping symbols Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 18/21] objtool/klp: Clone inline alternative replacements Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 19/21] objtool/klp: Introduce objtool for arm64 Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 20/21] klp-build: Support cross-compilation Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 21/21] klp-build: Add arm64 syscall patching macro Josh Poimboeuf
2026-05-13 3:34 ` Josh Poimboeuf
2026-05-13 3:33 ` [PATCH v3 00/21] objtool/arm64: Port klp-build to arm64 Josh Poimboeuf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=a0fe2363d017a2833e98ae50de797fe55c2796a4.1778642120.git.jpoimboe@kernel.org \
--to=jpoimboe@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=joe.lawrence@redhat.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=live-patching@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mbenes@suse.cz \
--cc=peterz@infradead.org \
--cc=pmladek@suse.com \
--cc=song@kernel.org \
--cc=will@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox