From 12a4eb8e05ee242c78389f7beab4398f0e7149df Mon Sep 17 00:00:00 2001 From: renoseven Date: Mon, 12 May 2025 10:59:38 +0800 Subject: [PATCH 1/2] upatch-diff: support text section offset Signed-off-by: renoseven --- upatch-diff/create-diff-object.c | 46 +++++++++++++++++++++++++------- upatch-diff/elf-create.c | 8 ++++-- upatch-diff/elf-create.h | 3 ++- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/upatch-diff/create-diff-object.c b/upatch-diff/create-diff-object.c index c7be45dd..1ffc9f5c 100644 --- a/upatch-diff/create-diff-object.c +++ b/upatch-diff/create-diff-object.c @@ -71,28 +71,42 @@ struct arguments { char *patched_obj; char *running_elf; char *output_obj; + unsigned long text_offset; bool debug; }; static const struct argp_option ARGP_OPTION[] = { - {"source", 's', "", 0, "Source object", 0}, - {"patched", 'p', "", 0, "Patched object", 1}, - {"running", 'r', "", 0, "Running binary file", 2}, - {"output", 'o', "", 0, "Output object", 3}, - {"debug", 'd', NULL, 0, "Show debug output", 4}, + {"source", 's', "", 0, "Source object", 0}, + {"patched", 'p', "", 0, "Patched object", 1}, + {"running", 'r', "", 0, "Running binary file", 2}, + {"output", 'o', "", 0, "Output object", 3}, + {"text-offset", 't', "", 0, "Text section offset", 4}, + {"debug", 'd', NULL, 0, "Show debug output", 5}, {NULL} }; static const char ARGP_DOC[] = "Generate a patch object based on source object"; const char *argp_program_version = PROG_VERSION; +static void parse_text_offset(struct argp_state *state, const char *arg) +{ + errno = 0; + char *endptr = NULL; + + unsigned long offset = strtoul(arg, &endptr, 0); + if ((errno != 0) || (*endptr != '\0') || + ((errno == ERANGE) && (offset == ULONG_MAX))) { + argp_error(state, "ERROR: Invalid text section offset '%s'", arg); + } + + struct arguments *arguments = state->input; + arguments->text_offset = offset; +} + static error_t parse_opt(int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; switch (key) { - case 'd': - arguments->debug = true; - break; case 's': arguments->source_obj = arg; break; @@ -105,6 +119,12 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) case 'o': arguments->output_obj = arg; break; + case 't': + parse_text_offset(state, arg); + break; + case 'd': + arguments->debug = true; + break; default: return ARGP_ERR_UNKNOWN; } @@ -129,6 +149,13 @@ static bool check_args(struct arguments *arguments) log_error("The argument '--output ' requires a value\n"); return false; } + if (arguments->text_offset > UINT32_MAX) { + ERROR("Text section offset 0x%lx overflow", arguments->text_offset); + } + if ((arguments->text_offset & 0xFFF) != 0) { + ERROR("Text section offset 0x%lx is not 4K-aligned", + arguments->text_offset); + } return true; } @@ -141,6 +168,7 @@ static void show_program_info(struct arguments *arguments) log_debug("patched object: %s\n", arguments->patched_obj); log_debug("running binary: %s\n", arguments->running_elf); log_debug("output object: %s\n", arguments->output_obj); + log_debug("text offset: 0x%lx\n", arguments->text_offset); log_debug("------------------------------\n\n"); } @@ -1033,7 +1061,7 @@ int main(int argc, char **argv) upatch_create_strings_elements(&uelf_out); - upatch_create_patches_sections(&uelf_out, &relf); + upatch_create_patches_sections(&uelf_out, &relf, args.text_offset); create_kpatch_arch_section(); diff --git a/upatch-diff/elf-create.c b/upatch-diff/elf-create.c index 964079d1..eea1315a 100644 --- a/upatch-diff/elf-create.c +++ b/upatch-diff/elf-create.c @@ -138,7 +138,7 @@ void upatch_create_strings_elements(struct upatch_elf *uelf) /* create upatch func info section */ void upatch_create_patches_sections(struct upatch_elf *uelf, - struct running_elf *relf) + struct running_elf *relf, unsigned long text_offset) { struct symbol *sym; struct symbol *strsym; @@ -190,7 +190,11 @@ void upatch_create_patches_sections(struct upatch_elf *uelf, sym->name, symbol.symbol->name, symbol.sympos, symbol.symbol->size); /* ATTENTION: kpatch convert global symbols to local symbols here. */ - funcs[index].old_addr = symbol.symbol->addr; + if (symbol.symbol->addr < text_offset) { + ERROR("Text section offset 0x%lx overflow, sym_addr=0x%lx", + text_offset, symbol.symbol->addr); + } + funcs[index].old_addr = symbol.symbol->addr - text_offset; funcs[index].old_size = symbol.symbol->size; funcs[index].new_size = sym->sym.st_size; funcs[index].sympos = symbol.sympos; diff --git a/upatch-diff/elf-create.h b/upatch-diff/elf-create.h index 18778b5a..0c76a46d 100644 --- a/upatch-diff/elf-create.h +++ b/upatch-diff/elf-create.h @@ -29,7 +29,8 @@ void upatch_create_strings_elements(struct upatch_elf *); -void upatch_create_patches_sections(struct upatch_elf *, struct running_elf *); +void upatch_create_patches_sections(struct upatch_elf *, struct running_elf *, + unsigned long); static inline void create_kpatch_arch_section(void) {} -- Gitee From c2f85127c30050dbdf91ca7935c43692a20e3323 Mon Sep 17 00:00:00 2001 From: renoseven Date: Mon, 12 May 2025 11:23:52 +0800 Subject: [PATCH 2/2] upatch-build: support text section offset Signed-off-by: renoseven --- upatch-build/src/main.rs | 49 ++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/upatch-build/src/main.rs b/upatch-build/src/main.rs index 51956d89..6c54374e 100644 --- a/upatch-build/src/main.rs +++ b/upatch-build/src/main.rs @@ -126,6 +126,23 @@ impl UpatchBuild { Ok(()) } + fn parse_text_offset(&self, binary: &Path) -> Result { + const TEXT_SECTION_NAME: &str = ".text"; + + let mmap = fs::mmap(binary)?; + let file = object::File::parse(mmap.as_ref())?; + let text_offset = file + .section_by_name(TEXT_SECTION_NAME) + .map(|section| { + let address = section.address(); + let offset = section.file_range().map(|(start, _)| start).unwrap_or(0); + address - offset + }) + .unwrap_or(0); + + Ok(text_offset) + } + fn build_patch(&self, patch_name: &OsStr, binary: &Path, debuginfo: &Path) -> Result<()> { const NOTES_OBJECT_NAME: &str = "notes.o"; @@ -152,6 +169,9 @@ impl UpatchBuild { .binary_objects(binary) .with_context(|| format!("Failed to find objects of {}", binary.display()))?; + let text_offset = self + .parse_text_offset(binary) + .with_context(|| format!("Failed to parse {} text section offset", binary.display()))?; for (patched_object, original_object) in binary_objects { debug!( "* {}", @@ -160,13 +180,19 @@ impl UpatchBuild { .unwrap_or(patched_object.as_os_str()) .to_string_lossy() ); - Self::create_diff_objs(original_object, patched_object, &debuginfo_file, &temp_dir) - .with_context(|| { - format!( - "Failed to create diff objects for {}", - patch_name.to_string_lossy() - ) - })?; + Self::create_diff_objs( + original_object, + patched_object, + &debuginfo_file, + text_offset, + &temp_dir, + ) + .with_context(|| { + format!( + "Failed to create diff objects for {}", + patch_name.to_string_lossy() + ) + })?; } debug!("- Collecting changes"); @@ -385,6 +411,7 @@ impl UpatchBuild { original_object: &Path, patched_object: &Path, debuginfo: &Path, + text_offset: u64, output_dir: &Path, ) -> Result<()> { let ouput_name = original_object.file_name().with_context(|| { @@ -402,9 +429,11 @@ impl UpatchBuild { .arg("-p") .arg(patched_object) .arg("-r") - .arg(debuginfo) - .arg("-o") - .arg(output_file); + .arg(debuginfo); + if text_offset > 0 { + command.arg("-t").arg(text_offset.to_string()); + } + command.arg("-o").arg(output_file); command.stdout(Level::Trace).run_with_output()?.exit_ok() } -- Gitee