78 строки
		
	
	
	
		
			1,9 КиБ
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			78 строки
		
	
	
	
		
			1,9 КиБ
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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")
 | |
| 	}
 | |
| }
 | 
