[RFC PATCH 51/73] x86/tools/relocs: Append relocations into input file

From: Lai Jiangshan
Date: Mon Feb 26 2024 - 09:56:08 EST


From: Hou Wenlong <houwenlong.hwl@xxxxxxxxxxxx>

Add a command line option to append relocations into a reserved section
named ".data.reloc" section of the input file. This is the same as the
implementation in MIPS.

Signed-off-by: Hou Wenlong <houwenlong.hwl@xxxxxxxxxxxx>
Signed-off-by: Lai Jiangshan <jiangshan.ljs@xxxxxxxxxxxx>
---
arch/x86/tools/relocs.c | 62 +++++++++++++++++++++++++++-------
arch/x86/tools/relocs.h | 1 +
arch/x86/tools/relocs_common.c | 11 ++++--
3 files changed, 60 insertions(+), 14 deletions(-)

diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 743e5e44338b..97e0243b9abb 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -912,6 +912,17 @@ static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
strncmp(symname, "init_per_cpu_", 13);
}

+static struct section *sec_lookup(const char *name)
+{
+ int i;
+
+ for (i = 0; i < shnum; i++) {
+ if (!strcmp(sec_name(i), name))
+ return &secs[i];
+ }
+
+ return NULL;
+}

static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
const char *symname)
@@ -1164,12 +1175,13 @@ static int write32_as_text(uint32_t v, FILE *f)
return fprintf(f, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1;
}

-static void emit_relocs(void)
+static void emit_relocs(FILE *f)
{
int i;
int (*write_reloc)(uint32_t, FILE *) = write32;
int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
const char *symname);
+ FILE *outf = stdout;

#if ELF_BITS == 64
if (!opts.use_real_mode)
@@ -1208,37 +1220,63 @@ static void emit_relocs(void)
write_reloc = write32_as_text;
}

+#if ELF_BITS == 64
+ if (opts.keep_relocs) {
+ struct section *sec_reloc;
+ uint32_t size_needed;
+ unsigned long offset;
+
+ sec_reloc = sec_lookup(".data.reloc");
+ if (!sec_reloc)
+ die("Could not find relocation data section\n");
+
+ size_needed = (3 + relocs64.count + relocs32neg.count +
+ relocs32.count) * sizeof(uint32_t);
+ if (size_needed > sec_reloc->shdr.sh_size)
+ die("Relocations overflow available space!\n" \
+ "Please adjust CONFIG_RELOCATION_TABLE_SIZE" \
+ "to at least 0x%08x\n", (size_needed + 0x1000) & ~0xFFF);
+
+ offset = sec_reloc->shdr.sh_offset + sec_reloc->shdr.sh_size -
+ size_needed;
+ if (fseek(f, offset, SEEK_SET) < 0)
+ die("Seek to %ld failed: %s\n", offset, strerror(errno));
+
+ outf = f;
+ }
+#endif
+
if (opts.use_real_mode) {
- write_reloc(relocs16.count, stdout);
+ write_reloc(relocs16.count, outf);
for (i = 0; i < relocs16.count; i++)
- write_reloc(relocs16.offset[i], stdout);
+ write_reloc(relocs16.offset[i], outf);

- write_reloc(relocs32.count, stdout);
+ write_reloc(relocs32.count, outf);
for (i = 0; i < relocs32.count; i++)
- write_reloc(relocs32.offset[i], stdout);
+ write_reloc(relocs32.offset[i], outf);
} else {
#if ELF_BITS == 64
/* Print a stop */
- write_reloc(0, stdout);
+ write_reloc(0, outf);

/* Now print each relocation */
for (i = 0; i < relocs64.count; i++)
- write_reloc(relocs64.offset[i], stdout);
+ write_reloc(relocs64.offset[i], outf);

/* Print a stop */
- write_reloc(0, stdout);
+ write_reloc(0, outf);

/* Now print each inverse 32-bit relocation */
for (i = 0; i < relocs32neg.count; i++)
- write_reloc(relocs32neg.offset[i], stdout);
+ write_reloc(relocs32neg.offset[i], outf);
#endif

/* Print a stop */
- write_reloc(0, stdout);
+ write_reloc(0, outf);

/* Now print each relocation */
for (i = 0; i < relocs32.count; i++)
- write_reloc(relocs32.offset[i], stdout);
+ write_reloc(relocs32.offset[i], outf);
}
}

@@ -1294,5 +1332,5 @@ void process(FILE *fp)
print_reloc_info();
return;
}
- emit_relocs();
+ emit_relocs(fp);
}
diff --git a/arch/x86/tools/relocs.h b/arch/x86/tools/relocs.h
index 1cb0e235ad73..20f729e4579f 100644
--- a/arch/x86/tools/relocs.h
+++ b/arch/x86/tools/relocs.h
@@ -37,6 +37,7 @@ struct opts {
bool show_absolute_syms;
bool show_absolute_relocs;
bool show_reloc_info;
+ bool keep_relocs;
};

extern struct opts opts;
diff --git a/arch/x86/tools/relocs_common.c b/arch/x86/tools/relocs_common.c
index 17d69baee0c3..87d94d9e4b97 100644
--- a/arch/x86/tools/relocs_common.c
+++ b/arch/x86/tools/relocs_common.c
@@ -14,7 +14,7 @@ void die(char *fmt, ...)

static void usage(void)
{
- die("relocs [--abs-syms|--abs-relocs|--reloc-info|--text|--realmode]" \
+ die("relocs [--abs-syms|--abs-relocs|--reloc-info|--text|--realmode|--keep]" \
" vmlinux\n");
}

@@ -49,6 +49,10 @@ int main(int argc, char **argv)
opts.use_real_mode = true;
continue;
}
+ if (strcmp(arg, "--keep") == 0) {
+ opts.keep_relocs = true;
+ continue;
+ }
}
else if (!fname) {
fname = arg;
@@ -59,7 +63,10 @@ int main(int argc, char **argv)
if (!fname) {
usage();
}
- fp = fopen(fname, "r");
+ if (opts.keep_relocs)
+ fp = fopen(fname, "r+");
+ else
+ fp = fopen(fname, "r");
if (!fp) {
die("Cannot open %s: %s\n", fname, strerror(errno));
}
--
2.19.1.6.gb485710b