From 4f932b6e669eece19b2adcbb690650a668a67fad Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sat, 23 Feb 2019 19:41:30 +0100 Subject: [PATCH] all: use internal objcopy implementation This lessens the dependency on binutils (e.g. arm-none-eabi-objcopy). --- Gopkg.lock | 9 +++++ main.go | 13 ++------ objcopy.go | 78 +++++++++++++++++++++++++++++++++++++++++++ target.go | 7 ---- targets/avr.json | 1 - targets/cortex-m.json | 1 - 6 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 objcopy.go diff --git a/Gopkg.lock b/Gopkg.lock index 0e0c2773..d59f0ca8 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1,6 +1,14 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. +[[projects]] + branch = "master" + digest = "1:00b45e06c7843541372fc17d982242bd6adfc2fc382b6f2e9ef9ce53d87a50b9" + name = "github.com/marcinbor85/gohex" + packages = ["."] + pruneopts = "UT" + revision = "7a43cd876e46e0f6ddc553f10f91731a78e6e949" + [[projects]] branch = "master" digest = "1:ba70784a3deee74c0ca3c87bcac3c2f93d3b2d27d8f237b768c358b45ba47da8" @@ -25,6 +33,7 @@ analyzer-name = "dep" analyzer-version = 1 input-imports = [ + "github.com/marcinbor85/gohex", "golang.org/x/tools/go/ast/astutil", "golang.org/x/tools/go/ssa", "tinygo.org/x/go-llvm", diff --git a/main.go b/main.go index ca0bd284..88bd72e4 100644 --- a/main.go +++ b/main.go @@ -259,19 +259,12 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act } } + // Get an Intel .hex file or .bin file from the .elf file. if outext == ".hex" || outext == ".bin" { - // Get an Intel .hex file or .bin file from the .elf file. tmppath = filepath.Join(dir, "main"+outext) - format := map[string]string{ - ".hex": "ihex", - ".bin": "binary", - }[outext] - cmd := exec.Command(spec.Objcopy, "-O", format, executable, tmppath) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err = cmd.Run() + err := Objcopy(executable, tmppath) if err != nil { - return &commandError{"failed to extract " + format + " from", executable, err} + return err } } return action(tmppath) diff --git a/objcopy.go b/objcopy.go new file mode 100644 index 00000000..d67bcab5 --- /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") + } +} diff --git a/target.go b/target.go index 562d143e..16970215 100644 --- a/target.go +++ b/target.go @@ -31,7 +31,6 @@ type TargetSpec struct { CFlags []string `json:"cflags"` LDFlags []string `json:"ldflags"` ExtraFiles []string `json:"extra-files"` - Objcopy string `json:"objcopy"` Emulator []string `json:"emulator"` Flasher string `json:"flash"` OCDDaemon []string `json:"ocd-daemon"` @@ -72,9 +71,6 @@ func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) { spec.CFlags = append(spec.CFlags, spec2.CFlags...) spec.LDFlags = append(spec.LDFlags, spec2.LDFlags...) spec.ExtraFiles = append(spec.ExtraFiles, spec2.ExtraFiles...) - if spec2.Objcopy != "" { - spec.Objcopy = spec2.Objcopy - } if len(spec2.Emulator) != 0 { spec.Emulator = spec2.Emulator } @@ -217,7 +213,6 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) { BuildTags: []string{goos, goarch}, Compiler: commands["clang"], Linker: "cc", - Objcopy: "objcopy", GDB: "gdb", GDBCmds: []string{"run"}, } @@ -230,13 +225,11 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) { // Some educated guesses as to how to invoke helper programs. if goarch == "arm" && goos == "linux" { spec.Linker = "arm-linux-gnueabihf-gcc" - spec.Objcopy = "arm-linux-gnueabihf-objcopy" spec.GDB = "arm-linux-gnueabihf-gdb" spec.Emulator = []string{"qemu-arm", "-L", "/usr/arm-linux-gnueabihf"} } if goarch == "arm64" && goos == "linux" { spec.Linker = "aarch64-linux-gnu-gcc" - spec.Objcopy = "aarch64-linux-gnu-objcopy" spec.GDB = "aarch64-linux-gnu-gdb" spec.Emulator = []string{"qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"} } diff --git a/targets/avr.json b/targets/avr.json index e74ed05b..261e4650 100644 --- a/targets/avr.json +++ b/targets/avr.json @@ -4,7 +4,6 @@ "goarch": "wasm", "compiler": "avr-gcc", "linker": "avr-gcc", - "objcopy": "avr-objcopy", "ldflags": [ "-T", "targets/avr.ld", "-Wl,--gc-sections" diff --git a/targets/cortex-m.json b/targets/cortex-m.json index f4f50783..7cae5d9b 100644 --- a/targets/cortex-m.json +++ b/targets/cortex-m.json @@ -16,6 +16,5 @@ "ldflags": [ "--gc-sections" ], - "objcopy": "arm-none-eabi-objcopy", "gdb": "arm-none-eabi-gdb" }