about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xapps/survey_elfbin56302 -> 56440 bytes
-rw-r--r--apps/survey_elf.subx274
2 files changed, 184 insertions, 90 deletions
diff --git a/apps/survey_elf b/apps/survey_elf
index 7af84283..e903f3ee 100755
--- a/apps/survey_elf
+++ b/apps/survey_elf
Binary files differdiff --git a/apps/survey_elf.subx b/apps/survey_elf.subx
index 2b8a47cd..ac2f05b4 100644
--- a/apps/survey_elf.subx
+++ b/apps/survey_elf.subx
@@ -1839,6 +1839,8 @@ emit-segments:  # in: (addr stream byte), out: (addr buffered-file), labels: (ad
     #     read-line(in, line)
     #     if (line->write == 0) break               # end of file
     #     offset-of-next-instruction += num-bytes(line)
+    #     var is-far-jump-or-call? = is-far-jump-or-call?(line)
+    #     rewind-stream(line)
     #     while true
     #       var word-slice = next-word(line)
     #       if slice-empty?(word-slice)             # end of line
@@ -1855,22 +1857,18 @@ emit-segments:  # in: (addr stream byte), out: (addr buffered-file), labels: (ad
     #         continue
     #       var datum: (addr slice) = next-token-from-slice(word-slice->start, word-slice->end, "/")
     #       var info: (addr label-info) = get-slice(labels, datum)
-    #       if !string-equal?(info->segment-name, "code")
-    #         if has-metadata?(word-slice, "disp8")
-    #           abort
-    #         if has-metadata?(word-slice, "imm8")
-    #           abort
-    #         emit(out, info->address, 4)  # global variables always translate to absolute addresses
-    #       # code segment cases
-    #       else if has-metadata?(word-slice, "imm8")
-    #         abort  # label should never go to imm8
+    #       if has-metadata?(word-slice, "imm8")
+    #         abort
     #       else if has-metadata?(word-slice, "imm32")
     #         emit(out, info->address, 4)
     #       else if has-metadata?(word-slice, "disp8")
     #         value = info->offset - offset-of-next-instruction
     #         emit(out, value, 1)
     #       else if has-metadata?(word-slice, "disp32")
-    #         value = info->offset - offset-of-next-instruction
+    #         if is-far-jump-or-call?
+    #           value = info->offset - offset-of-next-instruction
+    #         else
+    #           value = info->address
     #         emit(out, value, 4)
     #       else
     #         abort
@@ -1880,6 +1878,7 @@ emit-segments:  # in: (addr stream byte), out: (addr buffered-file), labels: (ad
     #   line: ecx
     #   word-slice: edx
     #   offset-of-next-instruction: ebx
+    #   is-far-jump-or-call?: edi
     #   info: esi (inner loop only)
     #   temporaries: eax, esi (outer loop)
     #
@@ -1968,6 +1967,20 @@ $emit-segments:check-for-end-of-input:
     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     # . ebx += eax
     01/add                          3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # add eax to ebx
+    # var is-far-jump-or-call?/edi: boolean = is-far-jump-or-call?(line)
+    # . . push args
+    51/push-ecx
+    # . . call
+    e8/call  is-far-jump-or-call?/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+    # rewind-stream(line)
+    # . . push args
+    51/push-ecx
+    # . . call
+    e8/call  rewind-stream/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
 $emit-segments:word-loop:
     # next-word(line, word-slice)
     # . . push args
@@ -2141,66 +2154,7 @@ $emit-segments:check-metadata:
     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
     # . esi = eax
     89/copy                         3/mod/direct    6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy eax to esi
-$emit-segments:check-global-variable:
-    # if string-equal?(info->segment-name, "code") goto code label checks
-    # . eax = lookup(info->segment-name)
-    # . . push args
-    ff          6/subop/push        1/mod/*+disp8   6/rm32/esi    .           .             .           .           4/disp8         .                 # push *(esi+4)
-    ff          6/subop/push        0/mod/indirect  6/rm32/esi    .           .             .           .           .               .                 # push *esi
-    # . . call
-    e8/call  lookup/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . eax = string-equal?(eax, "code")
-    # . . push args
-    68/push  "code"/imm32
-    50/push-eax
-    # . . call
-    e8/call  string-equal?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax != false) goto code label checks
-    3d/compare-eax-and  0/imm32/false
-    0f 85/jump-if-!=  $emit-segments:check-code-label-for-imm8/disp32
-$emit-segments:check-global-variable-for-disp8:
-    # if has-metadata?(word-slice, "disp8") abort
-    # . eax = has-metadata?(word-slice, "disp8")
-    # . . push args
-    68/push  "disp8"/imm32
-    52/push-edx
-    # . . call
-    e8/call  has-metadata?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax != false) abort
-    3d/compare-eax-and  0/imm32/false
-    0f 85/jump-if-!=  $emit-segments:global-variable-abort/disp32
-$emit-segments:check-global-variable-for-imm8:
-    # if has-metadata?(word-slice, "imm8") abort
-    # . eax = has-metadata?(word-slice, "imm8")
-    # . . push args
-    68/push  "imm8"/imm32
-    52/push-edx
-    # . . call
-    e8/call  has-metadata?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax != false) abort
-    3d/compare-eax-and  0/imm32/false
-    0f 85/jump-if-!=  $emit-segments:global-variable-abort/disp32
-$emit-segments:emit-global-variable:
-    # emit-hex(out, info->address, 4)
-    # . . push args
-    68/push  4/imm32
-    ff          6/subop/push        1/mod/*+disp8   6/rm32/esi    .           .             .           .           0xc/disp8       .                 # push *(esi+12)
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-    # . . call
-    e8/call  emit-hex/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # continue
-    e9/jump  $emit-segments:word-loop/disp32
-$emit-segments:check-code-label-for-imm8:
+$emit-segments:check-imm8:
     # if (has-metadata?(word-slice, "imm8")) abort
     # . eax = has-metadata?(edx, "imm8")
     # . . push args
@@ -2213,7 +2167,7 @@ $emit-segments:check-code-label-for-imm8:
     # . if (eax != false) abort
     3d/compare-eax-and  0/imm32/false
     0f 85/jump-if-!=  $emit-segments:imm8-abort/disp32
-$emit-segments:check-code-label-for-imm32:
+$emit-segments:check-imm32:
     # if (!has-metadata?(word-slice, "imm32")) goto next check
     # . eax = has-metadata?(edx, "imm32")
     # . . push args
@@ -2225,7 +2179,7 @@ $emit-segments:check-code-label-for-imm32:
     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     # . if (eax == false) goto next check
     3d/compare-eax-and  0/imm32/false
-    74/jump-if-=  $emit-segments:check-code-label-for-disp8/disp8
+    74/jump-if-=  $emit-segments:check-disp8/disp8
 #?     # dump info->address {{{
 #?     # . write(2/stderr, "info->address: ")
 #?     # . . push args
@@ -2259,7 +2213,7 @@ $emit-segments:check-code-label-for-imm32:
 #?     # . . discard args
 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 #?     # }}}
-$emit-segments:emit-code-label-imm32:
+$emit-segments:emit-imm32:
     # emit-hex(out, info->address, 4)
     # . . push args
     68/push  4/imm32
@@ -2271,7 +2225,7 @@ $emit-segments:emit-code-label-imm32:
     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     # continue
     e9/jump  $emit-segments:word-loop/disp32
-$emit-segments:check-code-label-for-disp8:
+$emit-segments:check-disp8:
     # if (!has-metadata?(word-slice, "disp8")) goto next check
     # . eax = has-metadata?(edx, "disp8")
     # . . push args
@@ -2283,8 +2237,8 @@ $emit-segments:check-code-label-for-disp8:
     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     # . if (eax == false) goto next check
     3d/compare-eax-and  0/imm32/false
-    74/jump-if-=  $emit-segments:check-code-label-for-disp32/disp8
-$emit-segments:emit-code-label-disp8:
+    74/jump-if-=  $emit-segments:check-disp32/disp8
+$emit-segments:emit-disp8:
     # emit-hex(out, info->offset - offset-of-next-instruction, 1)
     # . . push args
     68/push  1/imm32
@@ -2298,7 +2252,7 @@ $emit-segments:emit-code-label-disp8:
     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     # continue
     e9/jump  $emit-segments:word-loop/disp32
-$emit-segments:check-code-label-for-disp32:
+$emit-segments:check-disp32:
     # if (!has-metadata?(word-slice, "disp32")) abort
     # . eax = has-metadata?(edx, "disp32")
     # . . push args
@@ -2311,12 +2265,18 @@ $emit-segments:check-code-label-for-disp32:
     # . if (eax == false) abort
     3d/compare-eax-and  0/imm32/false
     0f 84/jump-if-=  $emit-segments:abort/disp32
-$emit-segments:emit-code-label-disp32:
-    # emit-hex(out, info->offset - offset-of-next-instruction, 4)
-    # . . push args
-    68/push  4/imm32
+$emit-segments:emit-disp32:
+    # var value/eax = info->address
+    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(esi+12) to eax
+    # if (is-far-jump-or-call?) value = info->offset - offset-of-next-instruction
+    81          7/subop/compare     3/mod/direct    7/rm32/edi    .           .             .           .           .               0/imm32/false     # compare edi
+    74/jump-if-=  $emit-segments:really-emit-disp32/disp8
     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   8/disp8         .                 # copy *(esi+8) to eax
     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # subtract ebx from eax
+$emit-segments:really-emit-disp32:
+    # emit-hex(out, value, 4)
+    # . . push args
+    68/push  4/imm32
     50/push-eax
     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
     # . . call
@@ -2409,8 +2369,8 @@ $emit-segments:abort:
     e8/call  syscall_exit/disp32
     # never gets here
 
-test-emit-segments-global-variable:
-    # global variables always convert to absolute addresses, regardless of metadata
+test-emit-segments-non-far-control-flow:
+    # labels turn into absolute addresses if opcodes are not far jumps or calls
     #
     # input:
     #   in:
@@ -2640,7 +2600,7 @@ test-emit-segments-global-variable:
     c3/return
 
 test-emit-segments-code-label:
-    # labels usually convert to displacements
+    # labels turn into PC-relative addresses if opcodes are far jumps or calls
     #
     # input:
     #   in:
@@ -2648,14 +2608,14 @@ test-emit-segments-code-label:
     #     ab cd
     #     l1:
     #       ef gh
-    #       ij l1/disp32
+    #       e8 l1/disp32
     #   labels:
     #     - 'l1': {'code', 2, 0x1056}
     #
     # output:
     #   ab cd
     #   ef gh
-    #   ij f9 ff ff ff  # -7
+    #   e8 f9 ff ff ff  # -7
     #
     # . prologue
     55/push-ebp
@@ -2725,9 +2685,9 @@ test-emit-segments-code-label:
     e8/call  write/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "  ij l1/disp32\n")
+    # . write(_test-input-stream, "  e8 l1/disp32\n")
     # . . push args
-    68/push  "  ij l1/disp32\n"/imm32
+    68/push  "  e8 l1/disp32\n"/imm32
     68/push  _test-input-stream/imm32
     # . . call
     e8/call  write/disp32
@@ -2827,10 +2787,10 @@ test-emit-segments-code-label:
     e8/call  check-next-stream-line-equal/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg)
+    # . check-next-stream-line-equal(_test-output-stream, "e8 f9 ff ff ff ", msg)
     # . . push args
     68/push  "F - test-emit-segments-code-label/2"/imm32
-    68/push  "ij f9 ff ff ff "/imm32
+    68/push  "e8 f9 ff ff ff "/imm32
     68/push  _test-output-stream/imm32
     # . . call
     e8/call  check-next-stream-line-equal/disp32
@@ -3043,6 +3003,140 @@ test-emit-segments-code-label-absolute:
     5d/pop-to-ebp
     c3/return
 
+# reads line to make some checks
+# don't assume the read state of line after calling this function
+is-far-jump-or-call?:  # line: (addr stream byte) -> result/edi: boolean
+    # . prologue
+    55/push-ebp
+    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+    # . save registers
+    50/push-eax
+    51/push-ecx
+    52/push-edx
+    53/push-ebx
+    # ecx = line
+    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+    # var word-slice/edx: slice
+    68/push  0/imm32/end
+    68/push  0/imm32/start
+    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+    # var datum-slice/ebx: slice
+    68/push  0/imm32/end
+    68/push  0/imm32/start
+    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
+    # result = false
+    bf/copy-to-edi  0/imm32/false
+$is-far-jump-or-call?:check-first-word:
+    # next-word(line, word-slice)
+    # . . push args
+    52/push-edx
+    51/push-ecx
+    # . . call
+    e8/call  next-word/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+    # if (slice-empty?(word-slice)) return false
+    # . eax = slice-empty?(word-slice)
+    # . . push args
+    52/push-edx
+    # . . call
+    e8/call  slice-empty?/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+    # . if (eax != 0) return
+    3d/compare-eax-and  0/imm32/false
+    0f 85/jump-if-!=  $is-far-jump-or-call?:end/disp32
+    # datum = next-token-from-slice(word-slice->start, word-slice->end, "/")
+    # . . push args
+    53/push-ebx
+    68/push  0x2f/imm32/slash
+    ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
+    ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
+    # . . call
+    e8/call  next-token-from-slice/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+    # if (datum-slice == "e8") return true
+    # . eax = slice-equal?(datum-slice, "e8")
+    # . . push args
+    68/push  "e8"/imm32
+    53/push-ebx
+    # . . call
+    e8/call  slice-equal?/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+    # . if (eax != false) return true
+    3d/compare-eax-and  0/imm32/false
+    75/jump-if-!=  $is-far-jump-or-call?:return-true/disp8
+    # if (datum-slice == "e9") return true
+    # . eax = slice-equal?(datum-slice, "e9")
+    # . . push args
+    68/push  "e9"/imm32
+    53/push-ebx
+    # . . call
+    e8/call  slice-equal?/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+    # . if (eax != false) return true
+    3d/compare-eax-and  0/imm32/false
+    75/jump-if-!=  $is-far-jump-or-call?:return-true/disp8
+    # if (datum-slice != "0f") return false
+    # . eax = slice-equal?(datum-slice, "0f")
+    # . . push args
+    68/push  "0f"/imm32
+    53/push-ebx
+    # . . call
+    e8/call  slice-equal?/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+    # . if (eax == false) return
+    3d/compare-eax-and  0/imm32/false
+    74/jump-if-=  $is-far-jump-or-call?:end/disp8
+$is-far-jump-or-call?:check-second-word:
+    # next-word(line, word-slice)
+    # . . push args
+    52/push-edx
+    51/push-ecx
+    # . . call
+    e8/call  next-word/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+    # if (slice-empty?(word-slice)) return false
+    # . eax = slice-empty?(word-slice)
+    # . . push args
+    52/push-edx
+    # . . call
+    e8/call  slice-empty?/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+    # . if (eax != 0) return
+    3d/compare-eax-and  0/imm32/false
+    75/jump-if-!=  $is-far-jump-or-call?:end/disp8
+    # if datum of word-slice does not start with "8", return false
+    # . start/eax = word-slice->start
+    8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy *edx to eax
+    # . c/eax = *start
+    8a/copy-byte                    0/mod/indirect  0/rm32/eax    .           .             .           0/r32/AL    .               .                 # copy byte at *eax to AL
+    81          4/subop/and         3/mod/direct    0/rm32/eax    .           .             .           .           .               0xff/imm32        # bitwise and of eax
+    # . if (eax != '8') return
+    3d/compare-eax-and  0x38/imm32/8
+    75/jump-if-!=  $is-far-jump-or-call?:end/disp8
+    # otherwise return true
+$is-far-jump-or-call?:return-true:
+    bf/copy-to-edi  1/imm32/true
+$is-far-jump-or-call?:end:
+    # . reclaim locals
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+    # . restore registers
+    5b/pop-to-ebx
+    5a/pop-to-edx
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilogue
+    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+    5d/pop-to-ebp
+    c3/return
+
 emit-headers:  # out: (addr buffered-file), segments: (addr stream {(handle array byte), segment-info}), labels: (addr stream {(handle array byte), label-info})
     # pseudocode:
     #   emit-elf-header(out, segments, labels)