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