# # coff_file.py -- read/write COFF files # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # WARNING: This module implements a VERY strict subset of the full COFF file # format. Just enough to read the output of GPASM, perform some # transforms, and write a new COFF file. # # BASIC FILE STRUCTURE # # FILE HEADER (20 bytes) # "OPTIONAL" HEADER (18 bytes) note: always present # SECTION RECORDS (40 bytes each) # SECTION DATA # RELOCATION RECORDS (12 bytes each) # LINENO RECORDS (16 bytes each) # SYMBOL TABLE (20 bytes each) # STRINGS DATA # # import struct # NOTE: we only support v2 _MICROCHIP_MAGIC_v2 = 0x1240 _OPT_HDR_SIZE_v2 = 18 _OPT_MAGIC_v2 = 0x5678 _ASSEMBLER_VERSION = 1 _SYMBOL_SIZE_v2 = 20 _RELOC_SIZE = 12 _LINENO_SIZE = 16 # Symbol storage classes C_NULL = 0 # null C_EXT = 2 # external symbol C_STAT = 3 # static C_LABEL = 6 # label C_FILE = 103 # file name C_EOF = 107 # end of file C_SECTION = 109 # section ### for now, just support 16f688 PIC16F688 = 0x6688 # proc_code def read_file(fname): fp = open(fname, 'rb') magic = _read16(fp) if magic != _MICROCHIP_MAGIC_v2: raise BadMagic() numsec = _read16(fp) tm = _read32(fp) symptr = _read32(fp) numsym = _read32(fp) opthdr = _read16(fp) fileflags = _read16(fp) # Optional header must be present, and v2 sized. if opthdr != _OPT_HDR_SIZE_v2: raise BadOptionalHeaderSize() magic = _read16(fp) if magic != _OPT_MAGIC_v2: raise BadMagic() vstamp = _read32(fp) if vstamp != _ASSEMBLER_VERSION: raise BadAssemblerVersion() proc_code = _read32(fp) if proc_code != PIC16F688: raise UnimplementedFeature() rom_width = _read32(fp) # opcode bit width assert rom_width == 14 ### for 16F688 ram_width = _read32(fp) # RAM bit width assert ram_width == 8 ### for all PIC processors # This is the start of the section headers. It is actually a fixed position, # based on the size of the FILE and OPT headers above. Meh. Use .tell() sechdrs = fp.tell() #print 'SYMPTR:',symptr fp.seek(symptr + _SYMBOL_SIZE_v2 * numsym) strings = fp.read() symbols = [ ] if numsym > 0: fp.seek(symptr) i = 0 while i < numsym: i += 1 # increment now, for clarity. name = _readname(fp, strings) value, secnum, symtyp, cls, numaux = struct.unpack(' 0: ### for now, only accept FILE and SECTION aux records if (cls != C_FILE and cls != C_SECTION) or numaux != 1: raise UnimplementedFeature() # Aux is the next symbol entry. i += 1 if cls == C_FILE: pos = _read32(fp) aux_fname = _readstr(strings, pos) aux_lineno = _read32(fp) aux_flags = _read8(fp) _ = fp.read(11) # skip. 11 unused bytes. #print ' FILE:', aux_fname, aux_lineno, aux_flags symbols.append((name, value, secnum, symtyp, cls, (aux_fname, aux_lineno, aux_flags))) symbols.append(None) # padding, so len(symbols) == numsym else: # Note: this data is duplicated in the section header. aux_len = _read32(fp) aux_nreloc = _read16(fp) aux_nlineno = _read16(fp) _ = fp.read(12) # skip. 12 unused bytes. #print ' SECTION:', aux_len, aux_nreloc, aux_nlineno symbols.append((name, value, secnum, symtyp, cls, (aux_len, aux_nreloc, aux_nlineno))) symbols.append(None) # padding, so len(symbols) == numsym else: symbols.append((name, value, secnum, symtyp, cls, ())) #print len(symbols) # Read in the sections fp.seek(sechdrs) sections = [ ] for i in range(numsec): name = _readname(fp, strings) (addr, virt, size, dataptr, relocptr, linenoptr, nreloc, nlineno, secflags) = struct.unpack('