diff options
author | Ayke van Laethem <[email protected]> | 2019-02-23 19:41:30 +0100 |
---|---|---|
committer | Ron Evans <[email protected]> | 2019-03-04 21:17:56 +0100 |
commit | 4f932b6e669eece19b2adcbb690650a668a67fad (patch) | |
tree | 55d308ffaefba501006b5737b81bf6846b585cc6 /objcopy.go | |
parent | 3538ba943c7abfc6933b72307d1bc24cf581d488 (diff) | |
download | tinygo-4f932b6e669eece19b2adcbb690650a668a67fad.tar.gz tinygo-4f932b6e669eece19b2adcbb690650a668a67fad.zip |
all: use internal objcopy implementation
This lessens the dependency on binutils (e.g. arm-none-eabi-objcopy).
Diffstat (limited to 'objcopy.go')
-rw-r--r-- | objcopy.go | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/objcopy.go b/objcopy.go new file mode 100644 index 000000000..d67bcab57 --- /dev/null +++ b/objcopy.go @@ -0,0 +1,78 @@ +package main + +import ( + "debug/elf" + "os" + "path/filepath" + + "github.com/marcinbor85/gohex" +) + +// ObjcopyError is an error returned by functions that act like objcopy. +type ObjcopyError struct { + Op string + Err error +} + +func (e ObjcopyError) Error() string { + if e.Err == nil { + return e.Op + } + return e.Op + ": " + e.Err.Error() +} + +// ExtractTextSegment returns the .text segment and the first address from the +// ELF file in the given path. +func ExtractTextSegment(path string) (uint64, []byte, error) { + f, err := elf.Open(path) + if err != nil { + return 0, nil, ObjcopyError{"failed to open ELF file to extract text segment", err} + } + defer f.Close() + + text := f.Section(".text") + if text == nil { + return 0, nil, ObjcopyError{"file does not contain .text segment: " + path, nil} + } + data, err := text.Data() + if err != nil { + return 0, nil, ObjcopyError{"failed to extract .text segment from ELF file", err} + } + return text.Addr, data, nil +} + +// Objcopy converts an ELF file to a different (simpler) output file format: +// .bin or .hex. It extracts only the .text section. +func Objcopy(infile, outfile string) error { + f, err := os.OpenFile(outfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) + if err != nil { + return err + } + defer f.Close() + + // Read the .text segment. + addr, data, err := ExtractTextSegment(infile) + if err != nil { + return err + } + + // Write to the file, in the correct format. + switch filepath.Ext(outfile) { + case ".bin": + // The address is not stored in a .bin file (therefore you + // should use .hex files in most cases). + _, err := f.Write(data) + return err + case ".hex": + mem := gohex.NewMemory() + mem.SetStartAddress(uint32(addr)) // ignored in most cases (Intel-specific) + err := mem.AddBinary(uint32(addr), data) + if err != nil { + return ObjcopyError{"failed to create .hex file", err} + } + mem.DumpIntelHex(f, 32) // TODO: handle error + return nil + default: + panic("unreachable") + } +} |