github.com/notti/nocgo@v0.0.0-20190619201224-fc443047424c/steps/3_goffi/rewrite.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"debug/elf"
     6  	"encoding/binary"
     7  	"errors"
     8  	"io"
     9  	"log"
    10  	"os"
    11  	"sort"
    12  	"strings"
    13  )
    14  
    15  const (
    16  	in     = "main"
    17  	out    = "dyn"
    18  	interp = "/lib64/ld-linux-x86-64.so.2"
    19  )
    20  
    21  var libs = []string{"libc.so.6", "libpthread.so.0", "libcalltest.so.1"}
    22  
    23  func doCopy() {
    24  	src, err := os.Open(in)
    25  	if err != nil {
    26  		log.Fatal("couldn't open", in, ":", err)
    27  	}
    28  	defer src.Close()
    29  	dst, err := os.OpenFile(out, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0777)
    30  	if err != nil {
    31  		log.Fatal("couldn't create", out, ":", err)
    32  	}
    33  	defer dst.Close()
    34  	_, err = io.Copy(dst, src)
    35  	if err != nil {
    36  		log.Fatal("couldn't copy:", err)
    37  	}
    38  }
    39  
    40  type elfFile struct {
    41  	f         *os.File
    42  	e         *elf.File
    43  	phoff     uint64
    44  	phentsize uint64
    45  	shoff     uint64
    46  	shentsize uint64
    47  	shstrndx  uint64
    48  	buffer    [1024]byte
    49  }
    50  
    51  func openElfFile(name string) (*elfFile, error) {
    52  	ret := &elfFile{}
    53  	var err error
    54  	ret.f, err = os.OpenFile(name, os.O_RDWR, 0777)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	ret.e, err = elf.NewFile(ret.f)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	_, err = ret.Seek(0, io.SeekCurrent)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	switch ret.e.Class {
    69  	case elf.ELFCLASS32:
    70  		var hdr elf.Header32
    71  		err = ret.ReadData(&hdr)
    72  		if err != nil {
    73  			return nil, err
    74  		}
    75  		ret.phoff = uint64(hdr.Phoff)
    76  		ret.phentsize = uint64(hdr.Phentsize)
    77  		ret.shoff = uint64(hdr.Shoff)
    78  		ret.shentsize = uint64(hdr.Shentsize)
    79  		ret.shstrndx = uint64(hdr.Shstrndx)
    80  	case elf.ELFCLASS64:
    81  		var hdr elf.Header64
    82  		err = ret.ReadData(&hdr)
    83  		if err != nil {
    84  			return nil, err
    85  		}
    86  		ret.phoff = hdr.Phoff
    87  		ret.phentsize = uint64(hdr.Phentsize)
    88  		ret.shoff = hdr.Shoff
    89  		ret.shentsize = uint64(hdr.Shentsize)
    90  		ret.shstrndx = uint64(hdr.Shstrndx)
    91  	}
    92  
    93  	return ret, nil
    94  }
    95  
    96  func (e *elfFile) Seek(where int64, whence int) (int64, error) {
    97  	return e.f.Seek(where, whence)
    98  }
    99  
   100  func (e *elfFile) ReadData(data interface{}) error {
   101  	return binary.Read(e.f, e.e.ByteOrder, data)
   102  }
   103  
   104  func (e *elfFile) WriteData(data interface{}) error {
   105  	return binary.Write(e.f, e.e.ByteOrder, data)
   106  }
   107  
   108  func (e *elfFile) Write(b []byte) error {
   109  	_, err := e.f.Write(b)
   110  	return err
   111  }
   112  
   113  func (e *elfFile) WriteAt(b []byte, off uint64) error {
   114  	_, err := e.f.WriteAt(b, int64(off))
   115  	return err
   116  }
   117  
   118  func (e *elfFile) Read8() (uint8, error) {
   119  	_, err := e.f.Read(e.buffer[:1])
   120  	return e.buffer[0], err
   121  }
   122  
   123  func (e *elfFile) Read16() (uint16, error) {
   124  	_, err := e.f.Read(e.buffer[:2])
   125  	return e.e.ByteOrder.Uint16(e.buffer[:]), err
   126  }
   127  
   128  func (e *elfFile) Read32() (uint32, error) {
   129  	_, err := e.f.Read(e.buffer[:4])
   130  	return e.e.ByteOrder.Uint32(e.buffer[:]), err
   131  }
   132  
   133  func (e *elfFile) Read64() (uint64, error) {
   134  	_, err := e.f.Read(e.buffer[:8])
   135  	return e.e.ByteOrder.Uint64(e.buffer[:]), err
   136  }
   137  
   138  func (e *elfFile) Read8At(where int64) (uint8, error) {
   139  	_, err := e.f.ReadAt(e.buffer[:1], where)
   140  	return e.buffer[0], err
   141  }
   142  
   143  func (e *elfFile) Read16At(where int64) (uint16, error) {
   144  	_, err := e.f.ReadAt(e.buffer[:2], where)
   145  	return e.e.ByteOrder.Uint16(e.buffer[:]), err
   146  }
   147  
   148  func (e *elfFile) Read32At(where int64) (uint32, error) {
   149  	_, err := e.f.ReadAt(e.buffer[:4], where)
   150  	return e.e.ByteOrder.Uint32(e.buffer[:]), err
   151  }
   152  
   153  func (e *elfFile) Read64At(where int64) (uint64, error) {
   154  	_, err := e.f.ReadAt(e.buffer[:8], where)
   155  	return e.e.ByteOrder.Uint64(e.buffer[:]), err
   156  }
   157  
   158  func (e *elfFile) Write8(data uint8) error {
   159  	_, err := e.f.Write([]byte{data})
   160  	return err
   161  }
   162  
   163  func (e *elfFile) Write16(data uint16) error {
   164  	e.e.ByteOrder.PutUint16(e.buffer[:], data)
   165  	_, err := e.f.Write(e.buffer[:2])
   166  	return err
   167  }
   168  
   169  func (e *elfFile) Write32(data uint32) error {
   170  	e.e.ByteOrder.PutUint32(e.buffer[:], data)
   171  	_, err := e.f.Write(e.buffer[:4])
   172  	return err
   173  }
   174  
   175  func (e *elfFile) Write64(data uint64) error {
   176  	e.e.ByteOrder.PutUint64(e.buffer[:], data)
   177  	_, err := e.f.Write(e.buffer[:8])
   178  	return err
   179  }
   180  
   181  func (e *elfFile) Write8At(data uint8, where uint64) error {
   182  	return e.WriteAt([]byte{data}, where)
   183  }
   184  
   185  func (e *elfFile) Write16At(data uint16, where uint64) error {
   186  	e.e.ByteOrder.PutUint16(e.buffer[:], data)
   187  	return e.WriteAt(e.buffer[:2], where)
   188  }
   189  
   190  func (e *elfFile) Write32At(data uint32, where uint64) error {
   191  	e.e.ByteOrder.PutUint32(e.buffer[:], data)
   192  	return e.WriteAt(e.buffer[:4], where)
   193  }
   194  
   195  func (e *elfFile) Write64At(data uint64, where uint64) error {
   196  	e.e.ByteOrder.PutUint64(e.buffer[:], data)
   197  	return e.WriteAt(e.buffer[:8], where)
   198  }
   199  
   200  func (e *elfFile) WriteSections() error {
   201  	if _, err := e.f.Seek(int64(e.shoff), io.SeekStart); err != nil {
   202  		return err
   203  	}
   204  	shstrtab := 0
   205  	shstrtabpos := e.shoff
   206  	names := make([]uint64, len(e.e.Sections))
   207  	for i, sec := range e.e.Sections {
   208  		names[i] = e.shoff - shstrtabpos
   209  		if err := e.Write(append([]byte(sec.Name), 0)); err != nil {
   210  			return err
   211  		}
   212  		e.shoff += uint64(len(sec.Name)) + 1
   213  		if sec.Name == ".shstrtab" {
   214  			shstrtab = i
   215  		}
   216  	}
   217  	e.e.Sections[shstrtab].Offset = shstrtabpos
   218  	e.e.Sections[shstrtab].FileSize = e.shoff - shstrtabpos
   219  
   220  	for i, sec := range e.e.Sections {
   221  		if err := e.WriteSection(sec.SectionHeader, names[i]); err != nil {
   222  			return err
   223  		}
   224  	}
   225  	switch e.e.Class {
   226  	case elf.ELFCLASS32:
   227  		if err := e.Write32At(uint32(e.shoff), 0x20); err != nil {
   228  			return err
   229  		}
   230  		if err := e.Write16At(uint16(len(e.e.Sections)), 0x30); err != nil {
   231  			return err
   232  		}
   233  	case elf.ELFCLASS64:
   234  		if err := e.Write64At(e.shoff, 0x28); err != nil {
   235  			return err
   236  		}
   237  		if err := e.Write16At(uint16(len(e.e.Sections)), 0x3C); err != nil {
   238  			return err
   239  		}
   240  	}
   241  	return nil
   242  }
   243  
   244  func (e *elfFile) WriteSection(sh elf.SectionHeader, name uint64) error {
   245  	switch e.e.Class {
   246  	case elf.ELFCLASS32:
   247  		hdr := elf.Section32{
   248  			Name:      uint32(name),
   249  			Type:      uint32(sh.Type),
   250  			Flags:     uint32(sh.Flags),
   251  			Addr:      uint32(sh.Addr),
   252  			Off:       uint32(sh.Offset),
   253  			Size:      uint32(sh.FileSize),
   254  			Link:      sh.Link,
   255  			Info:      sh.Info,
   256  			Addralign: uint32(sh.Addralign),
   257  			Entsize:   uint32(sh.Entsize),
   258  		}
   259  		return e.WriteData(hdr)
   260  	case elf.ELFCLASS64:
   261  		hdr := elf.Section64{
   262  			Name:      uint32(name),
   263  			Type:      uint32(sh.Type),
   264  			Flags:     uint64(sh.Flags),
   265  			Addr:      sh.Addr,
   266  			Off:       sh.Offset,
   267  			Size:      sh.FileSize,
   268  			Link:      sh.Link,
   269  			Info:      sh.Info,
   270  			Addralign: sh.Addralign,
   271  			Entsize:   sh.Entsize,
   272  		}
   273  		return e.WriteData(hdr)
   274  	}
   275  	// compression header not handeled
   276  	return errors.New("Unknown elf bit size")
   277  }
   278  
   279  func (e *elfFile) WritePrograms() error {
   280  	if _, err := e.Seek(int64(e.phoff), io.SeekStart); err != nil {
   281  		return err
   282  	}
   283  	for _, prog := range e.e.Progs {
   284  		if err := e.WriteProgram(prog.ProgHeader); err != nil {
   285  			return err
   286  		}
   287  	}
   288  	switch e.e.Class {
   289  	case elf.ELFCLASS32:
   290  		if err := e.Write32At(uint32(e.phoff), 0x1C); err != nil {
   291  			return err
   292  		}
   293  		if err := e.Write16At(uint16(len(e.e.Progs)), 0x2C); err != nil {
   294  			return err
   295  		}
   296  	case elf.ELFCLASS64:
   297  		if err := e.Write64At(e.phoff, 0x20); err != nil {
   298  			return err
   299  		}
   300  		if err := e.Write16At(uint16(len(e.e.Progs)), 0x38); err != nil {
   301  			return err
   302  		}
   303  	}
   304  	return nil
   305  }
   306  
   307  func (e *elfFile) WriteProgram(ph elf.ProgHeader) error {
   308  	switch e.e.Class {
   309  	case elf.ELFCLASS32:
   310  		hdr := elf.Prog32{
   311  			Type:   uint32(ph.Type),
   312  			Flags:  uint32(ph.Flags),
   313  			Off:    uint32(ph.Off),
   314  			Vaddr:  uint32(ph.Vaddr),
   315  			Paddr:  uint32(ph.Paddr),
   316  			Filesz: uint32(ph.Filesz),
   317  			Memsz:  uint32(ph.Memsz),
   318  			Align:  uint32(ph.Align),
   319  		}
   320  		return e.WriteData(hdr)
   321  	case elf.ELFCLASS64:
   322  		hdr := elf.Prog64{
   323  			Type:   uint32(ph.Type),
   324  			Flags:  uint32(ph.Flags),
   325  			Off:    ph.Off,
   326  			Vaddr:  ph.Vaddr,
   327  			Paddr:  ph.Paddr,
   328  			Filesz: ph.Filesz,
   329  			Memsz:  ph.Memsz,
   330  			Align:  ph.Align,
   331  		}
   332  		return e.WriteData(hdr)
   333  	}
   334  	return errors.New("Unknown elf bit size")
   335  }
   336  
   337  func (e *elfFile) Read(b []byte) error {
   338  	_, err := e.f.Read(b)
   339  	return err
   340  }
   341  
   342  func (e *elfFile) Copy(src, dst int64, length int) error {
   343  	buffer := make([]byte, length)
   344  	_, err := e.Seek(src, io.SeekStart)
   345  	if err != nil {
   346  		return err
   347  	}
   348  	err = e.Read(buffer)
   349  	if err != nil {
   350  		return err
   351  	}
   352  	_, err = e.Seek(dst, io.SeekStart)
   353  	if err != nil {
   354  		return err
   355  	}
   356  	err = e.Write(buffer)
   357  	if err != nil {
   358  		return err
   359  	}
   360  	return nil
   361  }
   362  
   363  func (e *elfFile) Close() error {
   364  	return e.f.Close()
   365  }
   366  
   367  // Dyn contains a single entry of the dynamic table
   368  type Dyn struct {
   369  	Tag elf.DynTag
   370  	Val uint64
   371  }
   372  
   373  func padding(addr, align uint64) uint64 {
   374  	align1 := align - 1
   375  	return (align - (addr & align1)) & align1
   376  }
   377  
   378  // DynSymbol represents a dynamic symbol
   379  type DynSymbol struct {
   380  	Name    string
   381  	Value   uint64
   382  	Size    uint64
   383  	Bind    elf.SymBind
   384  	Type    elf.SymType
   385  	Vis     elf.SymVis
   386  	Section int
   387  }
   388  
   389  func (e *elfFile) makeDynsym(elements []DynSymbol) (dynsym, dynstr []byte) {
   390  	sym := &bytes.Buffer{}
   391  	str := &bytes.Buffer{}
   392  	for _, elem := range elements {
   393  		namei := str.Len()
   394  		str.Write(append([]byte(elem.Name), 0))
   395  		switch e.e.Class {
   396  		case elf.ELFCLASS32:
   397  			binary.Write(sym, e.e.ByteOrder, elf.Sym32{
   398  				Name:  uint32(namei),
   399  				Value: uint32(elem.Value),
   400  				Size:  uint32(elem.Size),
   401  				Info:  byte(elem.Bind)<<4 | byte(elem.Type)&0x0f,
   402  				Other: byte(elem.Vis) & 0x03,
   403  				Shndx: uint16(elem.Section),
   404  			})
   405  		case elf.ELFCLASS64:
   406  			binary.Write(sym, e.e.ByteOrder, elf.Sym64{
   407  				Name:  uint32(namei),
   408  				Value: uint64(elem.Value),
   409  				Size:  uint64(elem.Size),
   410  				Info:  byte(elem.Bind)<<4 | byte(elem.Type)&0x0f,
   411  				Other: byte(elem.Vis) & 0x03,
   412  				Shndx: uint16(elem.Section),
   413  			})
   414  		}
   415  	}
   416  	if str.Len() == 0 {
   417  		str.WriteByte(0)
   418  	}
   419  	return sym.Bytes(), str.Bytes()
   420  }
   421  
   422  func (e *elfFile) makeDynsec(elements []Dyn) []byte {
   423  	ret := &bytes.Buffer{}
   424  	switch e.e.Class {
   425  	case elf.ELFCLASS32:
   426  		var secs []elf.Dyn32
   427  		for _, sec := range elements {
   428  			secs = append(secs, elf.Dyn32{
   429  				Tag: int32(sec.Tag),
   430  				Val: uint32(sec.Val),
   431  			})
   432  		}
   433  		binary.Write(ret, e.e.ByteOrder, secs)
   434  	case elf.ELFCLASS64:
   435  		var secs []elf.Dyn64
   436  		for _, sec := range elements {
   437  			secs = append(secs, elf.Dyn64{
   438  				Tag: int64(sec.Tag),
   439  				Val: uint64(sec.Val),
   440  			})
   441  		}
   442  		binary.Write(ret, e.e.ByteOrder, secs)
   443  	}
   444  	return ret.Bytes()
   445  }
   446  
   447  // RelSymbol represents a symbol in need of relocation
   448  type RelSymbol struct {
   449  	Off   uint64
   450  	SymNo uint64
   451  }
   452  
   453  func (e *elfFile) makeDynRel(symbols []RelSymbol) ([]byte, bool, uint64) {
   454  	ret := &bytes.Buffer{}
   455  	var rela bool
   456  	var relt uint64
   457  	switch e.e.Machine {
   458  	case elf.EM_386:
   459  		rela = false
   460  		relt = uint64(elf.R_386_JMP_SLOT)
   461  	case elf.EM_X86_64:
   462  		rela = true
   463  		relt = uint64(elf.R_X86_64_JMP_SLOT)
   464  	default:
   465  		log.Fatal("Unknown machine type ", e.e.Machine)
   466  	}
   467  
   468  	var relsz uint64
   469  
   470  	switch e.e.Class {
   471  	case elf.ELFCLASS32:
   472  		if rela {
   473  			for _, symbol := range symbols {
   474  				binary.Write(ret, e.e.ByteOrder, elf.Rela32{
   475  					Off:  uint32(symbol.Off),
   476  					Info: uint32(symbol.SymNo<<8 | relt),
   477  				})
   478  			}
   479  			relsz = 12
   480  		} else {
   481  			for _, symbol := range symbols {
   482  
   483  				binary.Write(ret, e.e.ByteOrder, elf.Rel32{
   484  					Off:  uint32(symbol.Off),
   485  					Info: uint32(symbol.SymNo<<8 | relt),
   486  				})
   487  			}
   488  			relsz = 8
   489  		}
   490  	case elf.ELFCLASS64:
   491  		if rela {
   492  			for _, symbol := range symbols {
   493  				binary.Write(ret, e.e.ByteOrder, elf.Rela64{
   494  					Off:  symbol.Off,
   495  					Info: symbol.SymNo<<32 | relt,
   496  				})
   497  			}
   498  			relsz = 24
   499  		} else {
   500  			for _, symbol := range symbols {
   501  				binary.Write(ret, e.e.ByteOrder, elf.Rel64{
   502  					Off:  symbol.Off,
   503  					Info: symbol.SymNo<<32 | relt,
   504  				})
   505  			}
   506  			relsz = 16
   507  		}
   508  	}
   509  	return ret.Bytes(), rela, relsz
   510  }
   511  
   512  func main() {
   513  	doCopy()
   514  	f, err := openElfFile(out)
   515  	if err != nil {
   516  		log.Fatal(err)
   517  	}
   518  
   519  	/*
   520  		        KEEP EXEC (we are not dyn after all)
   521  		        try to put new program headers, dyn, interp into first 4k
   522  		        0  -+-----------------------------------+--
   523  		            | ELF                               |
   524  		            +-----------------------------------+
   525  		            | program headers                   |
   526  		            +-----------------------------------+
   527  		            | interp                            |
   528  		            +-----------------------------------+
   529  		should be   | dyn stuff                         |
   530  		 below 4k ->+-----------------------------------+
   531  		            | other stuff that needs relocation |
   532  		            +-----------------------------------+<- ensure mapping until here
   533  		            +-----------------------------------+
   534  		   entry -> | Everything else (e.g., text)      |
   535  		            +-----------------------------------+
   536  		            | .shstrtab                         |
   537  		            +-----------------------------------+
   538  		            | Section headers                   |
   539  		            +-----------------------------------+
   540  	*/
   541  
   542  	// First some sanity checks - and checks if we can do our meddling, after all we don't support everything in this POC
   543  
   544  	if f.e.Type != elf.ET_EXEC {
   545  		log.Fatal("only static binaries not using an interp supported")
   546  	}
   547  
   548  	var base uint64
   549  	var baseProg int
   550  
   551  	for i, prog := range f.e.Progs {
   552  		if prog.Type == elf.PT_INTERP || prog.Type == elf.PT_DYNAMIC {
   553  			log.Fatal("only static binaries not using an interp supported")
   554  		}
   555  		if prog.Type == elf.PT_LOAD {
   556  			if base == 0 {
   557  				base = prog.Vaddr
   558  				baseProg = i
   559  			} else if prog.Vaddr < base {
   560  				base = prog.Vaddr
   561  				baseProg = i
   562  			}
   563  		}
   564  	}
   565  
   566  	if uint64(f.phoff+f.phentsize*uint64(len(f.e.Progs))) > f.e.Entry {
   567  		log.Fatal("Not enough space before entry point")
   568  	}
   569  
   570  	interpProg := len(f.e.Progs)
   571  
   572  	f.e.Progs = append(f.e.Progs, &elf.Prog{
   573  		ProgHeader: elf.ProgHeader{
   574  			Type:   elf.PT_INTERP,
   575  			Flags:  elf.PF_R,
   576  			Off:    0, // fill later
   577  			Vaddr:  0, // fill later
   578  			Paddr:  0, // fill later
   579  			Filesz: 0, // fill later
   580  			Memsz:  0, // fill later
   581  			Align:  1,
   582  		}})
   583  
   584  	dynsecProg := len(f.e.Progs)
   585  
   586  	f.e.Progs = append(f.e.Progs, &elf.Prog{
   587  		ProgHeader: elf.ProgHeader{
   588  			Type:   elf.PT_DYNAMIC,
   589  			Flags:  elf.PF_R | elf.PF_W,
   590  			Off:    0, // fill later
   591  			Vaddr:  0, // fill later
   592  			Paddr:  0, // fill later
   593  			Filesz: 0, // fill later
   594  			Memsz:  0, // fill later
   595  			Align:  8,
   596  		}})
   597  
   598  	interpPos := f.phoff + f.phentsize*uint64(len(f.e.Progs))
   599  	interpB := append([]byte(interp), 0)
   600  	interpLen := uint64(len(interpB))
   601  
   602  	f.e.Progs[interpProg].Off = interpPos
   603  	f.e.Progs[interpProg].Vaddr = interpPos + base
   604  	f.e.Progs[interpProg].Paddr = interpPos + base
   605  	f.e.Progs[interpProg].Filesz = interpLen
   606  	f.e.Progs[interpProg].Memsz = interpLen
   607  
   608  	hashPos := interpPos + interpLen
   609  	hashPos += padding(hashPos, 8)
   610  	hash := make([]byte, 8*4) // Empty 64bit DT_HASH
   611  	hashLen := uint64(len(hash))
   612  
   613  	var relList []RelSymbol
   614  
   615  	var symsection int
   616  
   617  	symbolList, err := f.e.Symbols()
   618  	if err != nil {
   619  		log.Fatal(err)
   620  	}
   621  
   622  	var symdefs []DynSymbol
   623  
   624  	symdefs = append(symdefs, DynSymbol{
   625  		Name:    "",
   626  		Value:   0,
   627  		Size:    0,
   628  		Bind:    elf.STB_LOCAL,
   629  		Type:    elf.STT_NOTYPE,
   630  		Vis:     elf.STV_DEFAULT,
   631  		Section: int(elf.SHN_UNDEF),
   632  	})
   633  
   634  	x_cgo_init := uint64(0)
   635  	_cgo_init := uint64(0)
   636  	_cgo_size := uint64(0)
   637  
   638  	for _, sym := range symbolList {
   639  		if strings.HasSuffix(sym.Name, "__dynload") {
   640  			parts := strings.Split(sym.Name, ".")
   641  			name := parts[len(parts)-1]
   642  			dynsym := name[:len(name)-9]
   643  
   644  			symsection = int(sym.Section)
   645  			relList = append(relList, RelSymbol{
   646  				Off:   sym.Value,
   647  				SymNo: uint64(len(symdefs)),
   648  			})
   649  			symdefs = append(symdefs, DynSymbol{
   650  				Name:    dynsym,
   651  				Value:   0,
   652  				Size:    0,
   653  				Bind:    elf.STB_GLOBAL,
   654  				Type:    elf.STT_FUNC,
   655  				Vis:     elf.STV_DEFAULT,
   656  				Section: int(elf.SHN_UNDEF),
   657  			})
   658  		}
   659  		if sym.Name == "x_cgo_init" {
   660  			x_cgo_init = sym.Value
   661  		}
   662  		if sym.Name == "_cgo_init" {
   663  			sec := f.e.Sections[sym.Section]
   664  			_cgo_init = sym.Value - sec.Addr + sec.Offset
   665  			_cgo_size = sym.Size
   666  		}
   667  	}
   668  
   669  	if x_cgo_init != 0 && _cgo_init != 0 && _cgo_size != 0 {
   670  		switch _cgo_size {
   671  		case 4:
   672  			f.Write32At(uint32(x_cgo_init), _cgo_init)
   673  		case 8:
   674  			f.Write64At(x_cgo_init, _cgo_init)
   675  		default:
   676  			log.Fatalln("Unknown symbol size", _cgo_size)
   677  		}
   678  	}
   679  
   680  	dynsym, dynstr := f.makeDynsym(symdefs)
   681  
   682  	var libOffsets []uint64
   683  
   684  	for _, l := range libs {
   685  		libOffsets = append(libOffsets, uint64(len(dynstr)))
   686  		dynstr = append(dynstr, []byte(l)...)
   687  		dynstr = append(dynstr, 0)
   688  	}
   689  
   690  	dynsymLocal := 0
   691  	dynstrPos := hashPos + hashLen
   692  	dynstrLen := uint64(len(dynstr))
   693  
   694  	dynsymPos := dynstrPos + dynstrLen
   695  	dynsymPos += padding(dynsymPos, 8)
   696  	dynsymLen := uint64(len(dynsym))
   697  
   698  	// TODO: DT_BIND_NOW?
   699  
   700  	dynrel, rela, relsz := f.makeDynRel(relList)
   701  	dynrelPos := dynsymPos + dynsymLen
   702  	dynrelPos += padding(dynrelPos, 8)
   703  	dynrelLen := uint64(len(dynrel))
   704  
   705  	var dynsecs []Dyn
   706  	for _, offset := range libOffsets {
   707  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_NEEDED, Val: uint64(offset)})
   708  	}
   709  
   710  	if rela {
   711  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_RELA, Val: uint64(base + dynrelPos)})
   712  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_RELASZ, Val: uint64(dynrelLen)})
   713  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_RELAENT, Val: uint64(relsz)})
   714  	} else {
   715  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_REL, Val: uint64(base + dynrelPos)})
   716  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_RELSZ, Val: uint64(dynrelLen)})
   717  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_RELENT, Val: uint64(relsz)})
   718  	}
   719  
   720  	dynsecs = append(dynsecs, []Dyn{
   721  		{Tag: elf.DT_STRTAB, Val: base + dynstrPos},
   722  		{Tag: elf.DT_STRSZ, Val: dynstrLen},
   723  		{Tag: elf.DT_SYMTAB, Val: base + dynsymPos},
   724  		{Tag: elf.DT_SYMENT, Val: dynsymLen},
   725  		{Tag: elf.DT_HASH, Val: hashPos + base},
   726  		{Tag: elf.DT_BIND_NOW, Val: 0},
   727  		{Tag: elf.DT_NULL, Val: 0},
   728  	}...)
   729  
   730  	dynsec := f.makeDynsec(dynsecs)
   731  	dynsecPos := dynrelPos + dynrelLen
   732  	dynsecPos += padding(dynsecPos, 8)
   733  	dynsecLen := uint64(len(dynsec))
   734  
   735  	f.e.Progs[dynsecProg].Off = dynsecPos
   736  	f.e.Progs[dynsecProg].Vaddr = dynsecPos + base
   737  	f.e.Progs[dynsecProg].Paddr = dynsecPos + base
   738  	f.e.Progs[dynsecProg].Filesz = dynsecLen
   739  	f.e.Progs[dynsecProg].Memsz = dynsecLen
   740  
   741  	afterDynsec := dynsecPos + dynsecLen
   742  
   743  	relPos := afterDynsec
   744  	var torelocate []*elf.Section
   745  	relocated := make(map[int]bool)
   746  
   747  	for {
   748  		var newRelocate []*elf.Section
   749  		for i, sec := range f.e.Sections {
   750  			if sec.Type == elf.SHT_NULL {
   751  				continue
   752  			}
   753  			if sec.Offset < relPos && !relocated[i] {
   754  				newRelocate = append(newRelocate, sec)
   755  				relocated[i] = true
   756  			}
   757  		}
   758  		if len(newRelocate) == 0 {
   759  			break
   760  		}
   761  		torelocate = append(torelocate, newRelocate...)
   762  
   763  		sort.Slice(torelocate, func(i, j int) bool { return torelocate[i].Offset < torelocate[j].Offset })
   764  		relPos = afterDynsec
   765  		for _, sec := range torelocate {
   766  			relPos += sec.Size
   767  			if sec.Addralign > 1 {
   768  				relPos += padding(relPos, sec.Addralign)
   769  			}
   770  		}
   771  	}
   772  
   773  	for _, sec := range torelocate {
   774  		data := make([]byte, sec.Size)
   775  		if _, err := f.f.ReadAt(data, int64(sec.Offset)); err != nil {
   776  			log.Fatal(err)
   777  		}
   778  		if sec.Addralign > 1 {
   779  			afterDynsec += padding(afterDynsec, sec.Addralign)
   780  		}
   781  		if err := f.WriteAt(data, afterDynsec); err != nil {
   782  			log.Fatal(err)
   783  		}
   784  		for _, prog := range f.e.Progs {
   785  			if prog.Off == sec.Offset {
   786  				prog.Off = afterDynsec
   787  			}
   788  			if prog.Vaddr == sec.Offset+base {
   789  				prog.Vaddr = afterDynsec + base
   790  				prog.Paddr = afterDynsec + base
   791  			}
   792  		}
   793  
   794  		sec.Addr += afterDynsec - sec.Offset // or base + offset
   795  		sec.Offset, afterDynsec = afterDynsec, afterDynsec+sec.Offset
   796  	}
   797  
   798  	if afterDynsec > f.e.Entry {
   799  		log.Fatal("not enough space before entry point")
   800  	}
   801  
   802  	if f.e.Progs[baseProg].Filesz < afterDynsec {
   803  		f.e.Progs[baseProg].Filesz = afterDynsec
   804  		f.e.Progs[baseProg].Memsz = afterDynsec
   805  	}
   806  
   807  	if err := f.WritePrograms(); err != nil {
   808  		log.Fatal(err)
   809  	}
   810  
   811  	if err := f.WriteAt(interpB, interpPos); err != nil {
   812  		log.Fatal(err)
   813  	}
   814  
   815  	if err := f.WriteAt(hash, hashPos); err != nil {
   816  		log.Fatal(err)
   817  	}
   818  
   819  	if err := f.WriteAt(dynstr, dynstrPos); err != nil {
   820  		log.Fatal(err)
   821  	}
   822  
   823  	if err := f.WriteAt(dynsym, dynsymPos); err != nil {
   824  		log.Fatal(err)
   825  	}
   826  
   827  	if err := f.WriteAt(dynrel, dynrelPos); err != nil {
   828  		log.Fatal(err)
   829  	}
   830  
   831  	if err := f.WriteAt(dynsec, dynsecPos); err != nil {
   832  		log.Fatal(err)
   833  	}
   834  
   835  	f.e.Sections = append(f.e.Sections, &elf.Section{
   836  		SectionHeader: elf.SectionHeader{
   837  			Name:      ".interp",
   838  			Type:      elf.SHT_PROGBITS,
   839  			Flags:     elf.SHF_ALLOC,
   840  			Addr:      base + interpPos,
   841  			Offset:    interpPos,
   842  			FileSize:  interpLen,
   843  			Addralign: 1,
   844  		}})
   845  
   846  	dynstrI := len(f.e.Sections)
   847  
   848  	f.e.Sections = append(f.e.Sections, &elf.Section{
   849  		SectionHeader: elf.SectionHeader{
   850  			Name:      ".dynstr",
   851  			Type:      elf.SHT_STRTAB,
   852  			Flags:     elf.SHF_ALLOC,
   853  			Addr:      base + dynstrPos,
   854  			Offset:    dynstrPos,
   855  			FileSize:  dynstrLen,
   856  			Addralign: 1,
   857  		}})
   858  
   859  	entSize := uint64(24)
   860  	if f.e.Class == elf.ELFCLASS32 {
   861  		entSize = 16
   862  	}
   863  
   864  	dynsymSec := len(f.e.Sections)
   865  
   866  	f.e.Sections = append(f.e.Sections, &elf.Section{
   867  		SectionHeader: elf.SectionHeader{
   868  			Name:      ".dynsym",
   869  			Type:      elf.SHT_DYNSYM,
   870  			Flags:     elf.SHF_ALLOC,
   871  			Addr:      base + dynsymPos,
   872  			Offset:    dynsymPos,
   873  			FileSize:  dynsymLen,
   874  			Addralign: 8,
   875  			Link:      uint32(dynstrI),
   876  			Entsize:   entSize,
   877  			Info:      uint32(dynsymLocal + 1),
   878  		}})
   879  
   880  	entSize = uint64(16)
   881  	if f.e.Class == elf.ELFCLASS32 {
   882  		entSize = 8
   883  	}
   884  
   885  	f.e.Sections = append(f.e.Sections, &elf.Section{
   886  		SectionHeader: elf.SectionHeader{
   887  			Name:      ".dynamic",
   888  			Type:      elf.SHT_DYNAMIC,
   889  			Flags:     elf.SHF_ALLOC | elf.SHF_WRITE,
   890  			Addr:      base + dynsecPos,
   891  			Offset:    dynsecPos,
   892  			FileSize:  dynsecLen,
   893  			Addralign: 8,
   894  			Link:      uint32(dynstrI),
   895  			Entsize:   entSize,
   896  		}})
   897  
   898  	dynname := ".rel"
   899  	if rela {
   900  		dynname = ".rela"
   901  	}
   902  	dynname += f.e.Sections[symsection].Name
   903  
   904  	shtype := elf.SHT_REL
   905  	if rela {
   906  		shtype = elf.SHT_RELA
   907  	}
   908  
   909  	f.e.Sections = append(f.e.Sections, &elf.Section{
   910  		SectionHeader: elf.SectionHeader{
   911  			Name:      dynname,
   912  			Type:      shtype,
   913  			Flags:     elf.SHF_ALLOC,
   914  			Addr:      base + dynrelPos,
   915  			Offset:    dynrelPos,
   916  			FileSize:  dynrelLen,
   917  			Addralign: 8,
   918  			Link:      uint32(dynsymSec),
   919  			Info:      uint32(symsection),
   920  			Entsize:   relsz,
   921  		}})
   922  
   923  	f.e.Sections = append(f.e.Sections, &elf.Section{
   924  		SectionHeader: elf.SectionHeader{
   925  			Name:      ".hash",
   926  			Type:      elf.SHT_HASH,
   927  			Flags:     elf.SHF_ALLOC,
   928  			Addr:      base + hashPos,
   929  			Offset:    hashPos,
   930  			FileSize:  hashLen,
   931  			Addralign: 8,
   932  			Link:      uint32(dynsymSec),
   933  		}})
   934  
   935  	shoff, err := f.f.Seek(0, io.SeekEnd)
   936  	if err != nil {
   937  		log.Fatal(err)
   938  	}
   939  	f.shoff = uint64(shoff)
   940  
   941  	if err := f.WriteSections(); err != nil {
   942  		log.Fatal(err)
   943  	}
   944  
   945  	f.Close()
   946  }