FreeCalypso > hg > tcs211-patches
diff tool/coff.c @ 6:87e9f30f5f86
ti-libpatch: patching implemented
author | Space Falcon <falcon@ivan.Harhan.ORG> |
---|---|
date | Sat, 06 Jun 2015 04:51:15 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tool/coff.c Sat Jun 06 04:51:15 2015 +0000 @@ -0,0 +1,141 @@ +/* + * This C module implements COFF operations for ti-libpatch. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "coffstruct.h" +#include "patchinfo.h" +#include "globals.h" + +struct external_scnhdr *sections_raw; +unsigned nsections; +unsigned strtab_offset; + +static unsigned +get_u16(ptr) + u_char *ptr; +{ + return ptr[0] | ptr[1] << 8; +} + +static unsigned +get_u32(ptr) + u_char *ptr; +{ + return ptr[0] | ptr[1] << 8 | ptr[2] << 16 | ptr[3] << 24; +} + +parse_coff_hdr() +{ + struct external_filehdr *filehdr_struct; + unsigned symtab_offset; + unsigned nsymtab; + + filehdr_struct = (struct external_filehdr *) member_body; + if (get_u16(filehdr_struct->f_magic) != 0xC2) { + fprintf(stderr, + "error: member \"%s\" is not a TI COFF2 object\n", + member_name); + exit(1); + } + if (get_u16(filehdr_struct->f_target_id) != 0x97) { + fprintf(stderr, "error: member \"%s\" is not a TMS470 object\n", + member_name); + exit(1); + } + if (get_u16(filehdr_struct->f_opthdr)) { + fprintf(stderr, + "error: member \"%s\" has the \"optional\" header present\n", + member_name); + exit(1); + } + sections_raw = (struct external_scnhdr *) + (member_body + sizeof(struct external_filehdr)); + nsections = get_u16(filehdr_struct->f_nscns); + symtab_offset = get_u32(filehdr_struct->f_symptr); + nsymtab = get_u32(filehdr_struct->f_nsyms); + strtab_offset = symtab_offset + + sizeof(struct external_syment) * nsymtab; + return(0); +} + +static struct external_scnhdr * +find_section_shortname(soughtname) + char *soughtname; +{ + unsigned i; + struct external_scnhdr *scnhdr; + + for (i = 0; i < nsections; i++) { + scnhdr = sections_raw + i; + if (!strncmp(scnhdr->s_name, soughtname, 8)) + return(scnhdr); + } + return(0); +} + +static struct external_scnhdr * +find_section_longname(soughtname) + char *soughtname; +{ + unsigned i; + struct external_scnhdr *scnhdr; + u_char *np, *longname; + + for (i = 0; i < nsections; i++) { + scnhdr = sections_raw + i; + np = scnhdr->s_name; + if (np[0] || np[1] || np[2] || np[3]) + continue; + longname = member_body + strtab_offset + get_u32(np + 4); + if (!strcmp(longname, soughtname)) + return(scnhdr); + } + return(0); +} + +static struct external_scnhdr * +find_section(soughtname) + char *soughtname; +{ + if (strlen(soughtname) <= 8) + return find_section_shortname(soughtname); + else + return find_section_longname(soughtname); +} + +apply_patch(patch) + struct patch_desc *patch; +{ + struct external_scnhdr *scnhdr; + unsigned data_offset, section_size; + + scnhdr = find_section(patch->section); + if (!scnhdr) { + fprintf(stderr, + "error: could not find section \"%s\" in member \"%s\"\n", + patch->section, member_name); + exit(1); + } + data_offset = get_u32(scnhdr->s_scnptr); + section_size = get_u32(scnhdr->s_size); + if (data_offset + section_size > member_size) { + fprintf(stderr, + "error: section \"%s\" in member \"%s\" exceeds member size\n", + patch->section, member_name); + exit(1); + } + if (patch->offset >= section_size) { + fprintf(stderr, + "error: patch offset 0x%x in section \"%s\" exceeds section size\n", + patch->offset, patch->section); + exit(1); + } + /* do it! */ + member_body[data_offset + patch->offset] = patch->new_byte; + return(0); +}