elf2c.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package main
  2. import (
  3. "bufio"
  4. "debug/elf"
  5. "flag"
  6. "fmt"
  7. "io"
  8. "math"
  9. "os"
  10. "path"
  11. )
  12. var dry = flag.Bool("dryrun", true, "don't really do it")
  13. func gencode(w io.Writer, n, t string, m []byte, start, end uint64) {
  14. fmt.Fprintf(os.Stderr, "Write %v %v start %v end %v\n", n, t, start, end)
  15. fmt.Fprintf(w, "int %v_%v_start = %v;\n", n, t, start)
  16. fmt.Fprintf(w, "int %v_%v_end = %v;\n", n, t, end)
  17. fmt.Fprintf(w, "int %v_%v_len = %v;\n", n, t, end-start)
  18. fmt.Fprintf(w, "uint8_t %v_%v_out[] = {\n", n, t)
  19. for i := uint64(start); i < end; i += 16 {
  20. for j := uint64(0); i+j < end && j < 16; j++ {
  21. fmt.Fprintf(w, "0x%02x, ", m[j+i])
  22. }
  23. fmt.Fprintf(w, "\n")
  24. }
  25. fmt.Fprintf(w, "};\n")
  26. }
  27. func main() {
  28. flag.Parse()
  29. a := flag.Args()
  30. for _, n := range a {
  31. f, err := elf.Open(n)
  32. if err != nil {
  33. fmt.Printf("%v %v\n", n, err)
  34. continue
  35. }
  36. var dataend, codeend, end uint64
  37. var datastart, codestart, start uint64
  38. datastart, codestart, start = math.MaxUint64, math.MaxUint64, math.MaxUint64
  39. mem := []byte{}
  40. for _, v := range f.Progs {
  41. if v.Type != elf.PT_LOAD {
  42. continue
  43. }
  44. fmt.Fprintf(os.Stderr, "processing %v\n", v)
  45. // MUST alignt to 2M page boundary.
  46. // then MUST allocate a []byte that
  47. // is the right size. And MUST
  48. // see if by some off chance it
  49. // joins to a pre-existing segment.
  50. // It's easier than it seems. We produce ONE text
  51. // array and ONE data array. So it's a matter of creating
  52. // a virtual memory space with an assumed starting point of
  53. // 0x200000, and filling it. We just grow that as needed.
  54. curstart := v.Vaddr & ^uint64(0xfff) // 0x1fffff)
  55. curend := v.Vaddr + v.Memsz
  56. fmt.Fprintf(os.Stderr, "s %x e %x\n", curstart, curend)
  57. if curend > end {
  58. nmem := make([]byte, curend)
  59. copy(nmem, mem)
  60. mem = nmem
  61. }
  62. if curstart < start {
  63. start = curstart
  64. }
  65. if v.Flags&elf.PF_X == elf.PF_X {
  66. if curstart < codestart {
  67. codestart = curstart
  68. }
  69. if curend > codeend {
  70. codeend = curend
  71. }
  72. fmt.Fprintf(os.Stderr, "code s %v e %v\n", codestart, codeend)
  73. } else {
  74. if curstart < datastart {
  75. datastart = curstart
  76. }
  77. if curend > dataend {
  78. dataend = curend
  79. }
  80. fmt.Fprintf(os.Stderr, "data s %v e %v\n", datastart, dataend)
  81. }
  82. for i := uint64(0); i < v.Filesz; i++ {
  83. if amt, err := v.ReadAt(mem[v.Vaddr+i:], int64(i)); err != nil && err != io.EOF {
  84. fmt.Fprintf(os.Stderr, "%v: %v\n", amt, err)
  85. os.Exit(1)
  86. } else if amt == 0 {
  87. if i < v.Filesz {
  88. fmt.Fprintf(os.Stderr, "%v: Short read: %v of %v\n", v, i, v.Filesz)
  89. os.Exit(1)
  90. }
  91. break
  92. } else {
  93. i = i + uint64(amt)
  94. fmt.Fprintf(os.Stderr, "i now %v\n", i)
  95. }
  96. }
  97. fmt.Fprintf(os.Stderr, "Processed %v\n", v)
  98. }
  99. fmt.Fprintf(os.Stderr, "gencode\n")
  100. // Gen code to stdout. For each file, create an array, a start, and an end variable.
  101. w := bufio.NewWriter(os.Stdout)
  102. _, file := path.Split(n)
  103. gencode(w, file, "code", mem, codestart, codeend)
  104. gencode(w, file, "data", mem, datastart, dataend)
  105. w.Flush()
  106. }
  107. }