diff --git a/util/cbfstool/rmodule.c b/util/cbfstool/rmodule.c index 03828f77c9..46c9384d50 100644 --- a/util/cbfstool/rmodule.c +++ b/util/cbfstool/rmodule.c @@ -24,39 +24,6 @@ #include "rmodule.h" #include "../../src/include/rmodule-defs.h" -struct rmod_context; - -struct arch_ops { - int arch; - /* Determine if relocation is a valid type for the architecture. */ - int (*valid_type)(Elf64_Rela *rel); - /* Determine if relocation should be emitted. */ - int (*should_emit)(Elf64_Rela *rel); -}; - -struct rmod_context { - /* Ops to process relocations. */ - struct arch_ops *ops; - - /* endian conversion ops */ - struct xdr *xdr; - - /* Parsed ELF sturcture. */ - struct parsed_elf pelf; - /* Program segment. */ - Elf64_Phdr *phdr; - - /* Collection of relocation addresses fixup in the module. */ - Elf64_Xword nrelocs; - Elf64_Addr *emitted_relocs; - - /* The following fields are addresses within the linked program. */ - Elf64_Addr parameters_begin; - Elf64_Addr parameters_end; - Elf64_Addr bss_begin; - Elf64_Addr bss_end; -}; - /* * Architecture specific support operations. */ @@ -130,7 +97,7 @@ static int should_emit_aarch64(Elf64_Rela *rel) return (type == R_AARCH64_ABS64); } -static struct arch_ops reloc_ops[] = { +static const struct arch_ops reloc_ops[] = { { .arch = EM_386, .valid_type = valid_reloc_386, @@ -152,7 +119,8 @@ static struct arch_ops reloc_ops[] = { * Relocation processing loops. */ -static int for_each_reloc(struct rmod_context *ctx, int do_emit) +static int for_each_reloc(struct rmod_context *ctx, struct reloc_filter *f, + int do_emit) { Elf64_Half i; struct parsed_elf *pelf = &ctx->pelf; @@ -173,6 +141,7 @@ static int for_each_reloc(struct rmod_context *ctx, int do_emit) nrelocs = shdr->sh_size / shdr->sh_entsize; for (j = 0; j < nrelocs; j++) { + int filter_emit = 1; Elf64_Rela *r = &relocs[j]; if (!ctx->ops->valid_type(r)) { @@ -181,7 +150,15 @@ static int for_each_reloc(struct rmod_context *ctx, int do_emit) return -1; } - if (ctx->ops->should_emit(r)) { + /* Allow the provided filter to have precedence. */ + if (f != NULL) { + filter_emit = f->filter(f, r); + + if (filter_emit < 0) + return filter_emit; + } + + if (filter_emit && ctx->ops->should_emit(r)) { int n = ctx->nrelocs; if (do_emit) ctx->emitted_relocs[n] = r->r_offset; @@ -303,7 +280,8 @@ static int vaddr_cmp(const void *a, const void *b) return 0; } -static int collect_relocations(struct rmod_context *ctx) +int rmodule_collect_relocations(struct rmod_context *ctx, + struct reloc_filter *f) { Elf64_Xword nrelocs; @@ -312,7 +290,7 @@ static int collect_relocations(struct rmod_context *ctx) * apply to the program. Count the number relocations. Then collect * them into the allocated buffer. */ - if (for_each_reloc(ctx, 0)) + if (for_each_reloc(ctx, f, 0)) return -1; nrelocs = ctx->nrelocs; @@ -324,7 +302,7 @@ static int collect_relocations(struct rmod_context *ctx) ctx->nrelocs = 0; ctx->emitted_relocs = calloc(nrelocs, sizeof(Elf64_Addr)); /* Write out the relocations into the emitted_relocs array. */ - if (for_each_reloc(ctx, 1)) + if (for_each_reloc(ctx, f, 1)) return -1; if (ctx->nrelocs != nrelocs) { @@ -618,7 +596,7 @@ out: return ret; } -static int rmodule_init(struct rmod_context *ctx, const struct buffer *elfin) +int rmodule_init(struct rmod_context *ctx, const struct buffer *elfin) { struct parsed_elf *pelf; int i; @@ -670,7 +648,7 @@ out: return ret; } -static void rmodule_cleanup(struct rmod_context *ctx) +void rmodule_cleanup(struct rmod_context *ctx) { free(ctx->emitted_relocs); parsed_elf_destroy(&ctx->pelf); @@ -684,7 +662,7 @@ int rmodule_create(const struct buffer *elfin, struct buffer *elfout) if (rmodule_init(&ctx, elfin)) goto out; - if (collect_relocations(&ctx)) + if (rmodule_collect_relocations(&ctx, NULL)) goto out; if (populate_rmodule_info(&ctx)) diff --git a/util/cbfstool/rmodule.h b/util/cbfstool/rmodule.h index 4531f8d0b9..9a65677418 100644 --- a/util/cbfstool/rmodule.h +++ b/util/cbfstool/rmodule.h @@ -18,13 +18,74 @@ #ifndef TOOL_RMODULE_H #define TOOL_RMODULE_H -#include "elf.h" +#include "elfparsing.h" #include "common.h" +struct arch_ops { + int arch; + /* Determine if relocation is a valid type for the architecture. */ + int (*valid_type)(Elf64_Rela *rel); + /* Determine if relocation should be emitted. */ + int (*should_emit)(Elf64_Rela *rel); +}; + +/* + * The fields in rmod_context are read-only to the user. These are + * exposed for easy shareability. + */ +struct rmod_context { + /* Ops to process relocations. */ + const struct arch_ops *ops; + + /* endian conversion ops */ + struct xdr *xdr; + + /* Parsed ELF sturcture. */ + struct parsed_elf pelf; + /* Program segment. */ + Elf64_Phdr *phdr; + + /* Collection of relocation addresses fixup in the module. */ + Elf64_Xword nrelocs; + Elf64_Addr *emitted_relocs; + + /* The following fields are addresses within the linked program. */ + Elf64_Addr parameters_begin; + Elf64_Addr parameters_end; + Elf64_Addr bss_begin; + Elf64_Addr bss_end; +}; + +struct reloc_filter { + /* Return < 0 on error. 0 to ignore relocation and 1 to include + * relocation. */ + int (*filter)(struct reloc_filter *f, const Elf64_Rela *r); + /* Pointer for filter provides */ + void *context; +}; + /* * Parse an ELF file within the elfin buffer and fill in the elfout buffer * with a created rmodule in ELF format. Return 0 on success, < 0 on error. */ int rmodule_create(const struct buffer *elfin, struct buffer *elfout); +/* + * Initialize an rmodule context from an ELF buffer. Returns 0 on scucess, < 0 + * on error. + */ +int rmodule_init(struct rmod_context *ctx, const struct buffer *elfin); + +/* + * Collect all the relocations that apply to the program in + * nrelocs/emitted_relocs. One can optionally provide a reloc_filter object + * to help in relocation filtering. The filter function will be called twice: + * once for counting and once for emitting. The same response should be + * provided for each call. Returns 0 on success, < 0 on error. + */ +int rmodule_collect_relocations(struct rmod_context *c, struct reloc_filter *f); + +/* Clean up the memory consumed by the rmdoule context. */ +void rmodule_cleanup(struct rmod_context *ctx); + #endif /* TOOL_RMODULE_H */