github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/builder/elfpatch.go (about)

     1  package builder
     2  
     3  import (
     4  	"debug/elf"
     5  	"fmt"
     6  	"os"
     7  )
     8  
     9  func getElfSectionData(executable string, sectionName string) ([]byte, elf.FileHeader, error) {
    10  	elfFile, err := elf.Open(executable)
    11  	if err != nil {
    12  		return nil, elf.FileHeader{}, err
    13  	}
    14  	defer elfFile.Close()
    15  
    16  	section := elfFile.Section(sectionName)
    17  	if section == nil {
    18  		return nil, elf.FileHeader{}, fmt.Errorf("could not find %s section", sectionName)
    19  	}
    20  
    21  	data, err := section.Data()
    22  
    23  	return data, elfFile.FileHeader, err
    24  }
    25  
    26  func replaceElfSection(executable string, sectionName string, data []byte) error {
    27  	fp, err := os.OpenFile(executable, os.O_RDWR, 0)
    28  	if err != nil {
    29  		return err
    30  	}
    31  	defer fp.Close()
    32  
    33  	elfFile, err := elf.Open(executable)
    34  	if err != nil {
    35  		return err
    36  	}
    37  	defer elfFile.Close()
    38  
    39  	section := elfFile.Section(sectionName)
    40  	if section == nil {
    41  		return fmt.Errorf("could not find %s section", sectionName)
    42  	}
    43  
    44  	// Implicitly check for compressed sections
    45  	if section.Size != section.FileSize {
    46  		return fmt.Errorf("expected section %s to have identical size and file size, got %d and %d", sectionName, section.Size, section.FileSize)
    47  	}
    48  
    49  	// Only permit complete replacement of section
    50  	if section.Size != uint64(len(data)) {
    51  		return fmt.Errorf("expected section %s to have size %d, was actually %d", sectionName, len(data), section.Size)
    52  	}
    53  
    54  	// Write the replacement section data
    55  	_, err = fp.WriteAt(data, int64(section.Offset))
    56  	return err
    57  }