view ticoff/reloc.c @ 118:193926ccd1ec

tiobjd: better handling of section-relative relocs
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Thu, 03 Apr 2014 07:47:03 +0000
parents 2f23301d2f86
children d88f2f40e3ae
line wrap: on
line source

/*
 * Handling of relocation records
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include "filestruct.h"
#include "intstruct.h"
#include "coffconst.h"
#include "globals.h"

extern unsigned get_u16(), get_u32();

cmd_rawrel()
{
	unsigned n, m;
	struct internal_scnhdr *sec;
	struct external_reloc *rel;

	get_int_section_table();
	for (n = 0; n < nsections; n++) {
		sec = sections + n;
		if (!sec->nreloc)
			continue;
		printf("%s:\n\n", sec->name);
		rel = (struct external_reloc *)(filemap + sec->reloc_offset);
		printf("Location  SymIndex  Rsvd  Type\n");
		for (m = 0; m < sec->nreloc; m++, rel++)
			printf("%08X  %08X  %04X  %04X\n",
				get_u32(rel->r_vaddr), get_u32(rel->r_symndx),
				get_u16(rel->r_reserved), get_u16(rel->r_type));
		putchar('\n');
	}
	exit(0);
}

void
get_relocs_of_sec(sec)
	struct internal_scnhdr *sec;
{
	unsigned n;
	struct external_reloc *extrel;
	struct internal_reloc *intrel;
	unsigned lastloc, symidx;

	if (sec->int_relocs)
		return;
	if (!sec->nreloc) {
		fprintf(stderr,
	"BUG: get_relocs_of_sec() called for section \"%s\" w/o relocs\n",
			sec->name);
		exit(1);
	}
	intrel = malloc(sizeof(struct internal_reloc) * sec->nreloc);
	if (!intrel) {
		perror("malloc");
		exit(1);
	}
	sec->int_relocs = intrel;
	extrel = (struct external_reloc *)(filemap + sec->reloc_offset);
	for (n = 0; n < sec->nreloc; n++, extrel++, intrel++) {
		intrel->location = get_u32(extrel->r_vaddr);
		if (n && intrel->location <= lastloc) {
			fprintf(stderr,
			"error: non-increasing reloc order in section \"%s\"\n",
				sec->name);
			exit(1);
		}
		lastloc = intrel->location;
		symidx = get_u32(extrel->r_symndx);
		if (symidx >= nsymtab || !symtab[symidx]) {
			fprintf(stderr,
	"error: reloc references invalid symbol #%u in section \"%s\"\n",
				symidx, sec->name);
			exit(1);
		}
		intrel->sym = symtab[symidx];
		intrel->type = get_u16(extrel->r_type);
		switch (intrel->type) {
		case RTYPE_LONG:
			intrel->typestr = "Word32";
			break;
		case RTYPE_THUMB_BL:
			intrel->typestr = "Thumb_BL";
			break;
		case RTYPE_ARM_B:
			intrel->typestr = "ARM_B";
			break;
		default:
			fprintf(stderr,
		"error: reloc in section \"%s\" of unexpected type 0x%x\n",
				sec->name, intrel->type);
			exit(1);
		}
		if (get_u16(extrel->r_reserved))
			fprintf(stderr,
	"warning: reloc in section \"%s\" has non-zero reserved field\n",
				sec->name);
	}
}

cmd_reloc()
{
	unsigned n, m;
	struct internal_scnhdr *sec;
	struct internal_reloc *rel;

	get_int_section_table();
	get_int_symbol_table();
	for (n = 0; n < nsections; n++) {
		sec = sections + n;
		if (!sec->nreloc)
			continue;
		printf("%s:\n\n", sec->name);
		get_relocs_of_sec(sec);
		rel = sec->int_relocs;
		printf("Location  Type      Symbol relative to\n");
		for (m = 0; m < sec->nreloc; m++, rel++)
			printf("%08X  %-8s  %s\n", rel->location, rel->typestr,
				rel->sym->name);
		putchar('\n');
	}
	exit(0);
}

struct internal_reloc *
find_reloc(sec, loc)
	struct internal_scnhdr *sec;
	unsigned loc;
{
	struct internal_reloc *rel;
	unsigned m;

	rel = sec->int_relocs;
	for (m = 0; m < sec->nreloc; m++, rel++) {
		if (rel->location == loc)
			return(rel);
		if (rel->location > loc)
			return(0);
	}
	return(0);
}

struct internal_reloc *
find_word32_reloc(sec, loc)
	struct internal_scnhdr *sec;
	unsigned loc;
{
	struct internal_reloc *rel;

	rel = find_reloc(sec, loc);
	if (rel && rel->type != RTYPE_LONG)
		rel = 0;
	return(rel);
}