cbfstool: expose rmodule logic
In order to allow cbfstool to add XIP romstage on x86 without doing the 'cbfstool locate', relink, then 'cbfstool add' dance expose the core logic and of rmodule including proving an optional filter. The filter will be used for ignoring relocations to the .car.global region. BUG=chrome-os-partner:44827 BRANCH=None TEST=Built rambi. Change-Id: I192ae2e2f2e727d3183d32fd3eef8b64aacd92f4 Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/11598 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <pgeorgi@google.com>
This commit is contained in:
parent
051a181f0c
commit
b39a974d75
|
@ -24,39 +24,6 @@
|
||||||
#include "rmodule.h"
|
#include "rmodule.h"
|
||||||
#include "../../src/include/rmodule-defs.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.
|
* Architecture specific support operations.
|
||||||
*/
|
*/
|
||||||
|
@ -130,7 +97,7 @@ static int should_emit_aarch64(Elf64_Rela *rel)
|
||||||
return (type == R_AARCH64_ABS64);
|
return (type == R_AARCH64_ABS64);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct arch_ops reloc_ops[] = {
|
static const struct arch_ops reloc_ops[] = {
|
||||||
{
|
{
|
||||||
.arch = EM_386,
|
.arch = EM_386,
|
||||||
.valid_type = valid_reloc_386,
|
.valid_type = valid_reloc_386,
|
||||||
|
@ -152,7 +119,8 @@ static struct arch_ops reloc_ops[] = {
|
||||||
* Relocation processing loops.
|
* 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;
|
Elf64_Half i;
|
||||||
struct parsed_elf *pelf = &ctx->pelf;
|
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;
|
nrelocs = shdr->sh_size / shdr->sh_entsize;
|
||||||
|
|
||||||
for (j = 0; j < nrelocs; j++) {
|
for (j = 0; j < nrelocs; j++) {
|
||||||
|
int filter_emit = 1;
|
||||||
Elf64_Rela *r = &relocs[j];
|
Elf64_Rela *r = &relocs[j];
|
||||||
|
|
||||||
if (!ctx->ops->valid_type(r)) {
|
if (!ctx->ops->valid_type(r)) {
|
||||||
|
@ -181,7 +150,15 @@ static int for_each_reloc(struct rmod_context *ctx, int do_emit)
|
||||||
return -1;
|
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;
|
int n = ctx->nrelocs;
|
||||||
if (do_emit)
|
if (do_emit)
|
||||||
ctx->emitted_relocs[n] = r->r_offset;
|
ctx->emitted_relocs[n] = r->r_offset;
|
||||||
|
@ -303,7 +280,8 @@ static int vaddr_cmp(const void *a, const void *b)
|
||||||
return 0;
|
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;
|
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
|
* apply to the program. Count the number relocations. Then collect
|
||||||
* them into the allocated buffer.
|
* them into the allocated buffer.
|
||||||
*/
|
*/
|
||||||
if (for_each_reloc(ctx, 0))
|
if (for_each_reloc(ctx, f, 0))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
nrelocs = ctx->nrelocs;
|
nrelocs = ctx->nrelocs;
|
||||||
|
@ -324,7 +302,7 @@ static int collect_relocations(struct rmod_context *ctx)
|
||||||
ctx->nrelocs = 0;
|
ctx->nrelocs = 0;
|
||||||
ctx->emitted_relocs = calloc(nrelocs, sizeof(Elf64_Addr));
|
ctx->emitted_relocs = calloc(nrelocs, sizeof(Elf64_Addr));
|
||||||
/* Write out the relocations into the emitted_relocs array. */
|
/* Write out the relocations into the emitted_relocs array. */
|
||||||
if (for_each_reloc(ctx, 1))
|
if (for_each_reloc(ctx, f, 1))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (ctx->nrelocs != nrelocs) {
|
if (ctx->nrelocs != nrelocs) {
|
||||||
|
@ -618,7 +596,7 @@ out:
|
||||||
return ret;
|
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;
|
struct parsed_elf *pelf;
|
||||||
int i;
|
int i;
|
||||||
|
@ -670,7 +648,7 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rmodule_cleanup(struct rmod_context *ctx)
|
void rmodule_cleanup(struct rmod_context *ctx)
|
||||||
{
|
{
|
||||||
free(ctx->emitted_relocs);
|
free(ctx->emitted_relocs);
|
||||||
parsed_elf_destroy(&ctx->pelf);
|
parsed_elf_destroy(&ctx->pelf);
|
||||||
|
@ -684,7 +662,7 @@ int rmodule_create(const struct buffer *elfin, struct buffer *elfout)
|
||||||
if (rmodule_init(&ctx, elfin))
|
if (rmodule_init(&ctx, elfin))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (collect_relocations(&ctx))
|
if (rmodule_collect_relocations(&ctx, NULL))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (populate_rmodule_info(&ctx))
|
if (populate_rmodule_info(&ctx))
|
||||||
|
|
|
@ -18,13 +18,74 @@
|
||||||
#ifndef TOOL_RMODULE_H
|
#ifndef TOOL_RMODULE_H
|
||||||
#define TOOL_RMODULE_H
|
#define TOOL_RMODULE_H
|
||||||
|
|
||||||
#include "elf.h"
|
#include "elfparsing.h"
|
||||||
#include "common.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
|
* 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.
|
* with a created rmodule in ELF format. Return 0 on success, < 0 on error.
|
||||||
*/
|
*/
|
||||||
int rmodule_create(const struct buffer *elfin, struct buffer *elfout);
|
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 */
|
#endif /* TOOL_RMODULE_H */
|
||||||
|
|
Loading…
Reference in New Issue