summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--amd64.e49
-rw-r--r--elf.e2
-rw-r--r--execution.e14
-rw-r--r--transform.e117
4 files changed, 165 insertions, 17 deletions
diff --git a/amd64.e b/amd64.e
index ba78bc4..1a5df04 100644
--- a/amd64.e
+++ b/amd64.e
@@ -518,10 +518,24 @@ s" :cc-greater" keyword
     0 4 :rsp reg64 sib
     ~ : drop-subitem
   } if
+
   ~ The displacement byte.
+  ~
+  ~   When addressing-disp8-reg64 references a source, as in
+  ~ lea-reg64-disp8-reg64, the first two parameters of the assembly word
+  ~ calling it are the source register and the source displacement value. When
+  ~ it references a target or destination, as in mov-disp8-reg64-reg64, the
+  ~ LAST two parameters are the target registera and target displacement
+  ~ value.
+  ~
+  ~   In both cases, the register comes first and the displacement value
+  ~ comes second. When these are used in a comment template without any other
+  ~ rearranging going on, whichever is on the top of the stack will be popped
+  ~ off first. So, we swap them here, thus putting the register on the top.
   swap
   ~ : 1 adjust-length
   ~ : provide-hex8
+  ~ : swap-subitems
   pack8 ;
 
 ~ (output point, reg/op field value, reg/mem field register,
@@ -538,10 +552,13 @@ s" :cc-greater" keyword
     0 4 :rsp reg64 sib
     ~ : drop-subitem
   } if
-  ~ The displacement value.
+
+  ~   The displacement value. This is subject to the same considerations as in
+  ~ addressing-disp8-reg64.
   swap
   ~ : 4 adjust-length
   ~ : provide-hex32
+  ~ : swap-subitems
   pack32 ;
 
 ~ (output point, reg/op field value,
@@ -552,7 +569,17 @@ s" :cc-greater" keyword
   dup :rbp != {
     ~ Reg/mem value 4 means to use an SIB byte (at least, with this mode).
     5 roll 0 6 roll 4 modrm 4 unroll
-    reg64 3unroll reg64 3unroll scalefield 3unroll sib
+    reg64 3unroll reg64 3unroll scalefield 3unroll
+    ~   We want the scale factor to show after the registers, so we put it
+    ~ last on the stack. We also want the base register to show before the
+    ~ index register, so the base comes first.
+    ~
+    ~   Importantly, we have to do this before the sib so it'll count as being
+    ~ inside the span the assembly word's description attaches to.
+    ~
+    ~ : -3 roll-subitems
+    ~ : swap-subitems
+    sib
     exit
   } if
   ." Base parameter to addressing-indexed-reg64 is :rbp." 1 sys-exit ;
@@ -568,7 +595,21 @@ s" :cc-greater" keyword
   swap
   ~ : 1 adjust-length
   ~ : provide-hex8
-  pack8 ;
+  ~
+  ~   We want the parameters to be shown in the order:
+  ~
+  ~ base register, index register, index scale factor, displacement
+  ~
+  ~   So, we put them on the stack in the opposite of that order.
+  ~
+  ~   Importantly, we have to do this before the pack8 so it'll count as being
+  ~ inside the span the assembly word's description attaches to.
+  ~
+  ~ : -4 roll-subitems
+  ~ : -3 roll-subitems
+  ~ : swap-subitems
+  pack8
+  ;
 
 
 ~ Easy instructions
@@ -687,7 +728,7 @@ s" :cc-greater" keyword
 
 ~ (output point, source register, target register -- output point)
 : mov-reg64-reg64
-  ~ : 1 #swap # # mov-reg64-reg64
+  ~ : 1 # # mov-reg64-reg64
   3roll rex-w 0x89 pack8 3unroll
   swap reg64 swap addressing-reg64 ;
 : mov-indirect-reg64-reg64
diff --git a/elf.e b/elf.e
index 82af2f5..5f0cfc4 100644
--- a/elf.e
+++ b/elf.e
@@ -118,7 +118,7 @@
   L@' total-size pack64               ~ : -8 *size in memory
   ~ : blank-line
 
-  0 pack64                            ~ : 8 segment alignment
+  0 pack64                            ~ : -8 segment alignment
     ~ for relocation, but this doesn't apply to us
 
   ~   As with the file header, we use the label system to keep track of the
diff --git a/execution.e b/execution.e
index c6b6254..20064af 100644
--- a/execution.e
+++ b/execution.e
@@ -251,13 +251,13 @@
   ~ and the kernel would trust us, but this gives us more options for
   ~ interoperating with other runtimes.
   ~
-  9 :rax mov-reg64-imm64                      ~ mmap()
-  log-requested-address :rdi mov-reg64-imm64  ~ address (very arbitrary)
-  log-size :rsi mov-reg64-imm64               ~ size (one meg)
-  0x07 :rdx mov-reg64-imm64                   ~ protection (read+write+exec)
-  0x22 :r10 mov-extrareg64-imm64              ~ flags (private+anonymous)
-  0 :r8 mov-extrareg64-imm64                  ~ file descriptor (ignored)
-  0 :r9 mov-extrareg64-imm64                  ~ offset (ignored)
+  9 :rax mov-reg64-imm64                      ~ : mmap()
+  log-requested-address :rdi mov-reg64-imm64  ~ : address (very arbitrary)
+  log-size :rsi mov-reg64-imm64               ~ : size (one meg)
+  0x07 :rdx mov-reg64-imm64                   ~ : protection (read+write+exec)
+  0x22 :r10 mov-extrareg64-imm64              ~ : flags (private+anonymous)
+  0 :r8 mov-extrareg64-imm64                  ~ : file descriptor (ignored)
+  0 :r9 mov-extrareg64-imm64                  ~ : offset (ignored)
   syscall
 
   ~   The return value of the system call is in rax, we'll use it in a sec.
diff --git a/transform.e b/transform.e
index 9a2cb21..5bec117 100644
--- a/transform.e
+++ b/transform.e
@@ -2786,6 +2786,8 @@ allocate-transformation-state s" transformation-state" variable
 ~   ~ : provide-hex64
 ~   ~ : provide-keyword
 ~   ~ : drop-subitem
+~   ~ : swap-subitems
+~   ~ : 3 roll-subitems
 ~
 ~   By the way, the reason it's possible to write these examples is that
 ~ they're all embedded within an outer comment, the text you're reading, so
@@ -3139,7 +3141,10 @@ allocate-transformation-state s" transformation-state" variable
 ~   With all this context, it likely doesn't need much explanation, but the
 ~ drop-subitem command will create an -entry-type-drop-substring entry. When
 ~ this entry is executed, it will discard an item from the substring entry
-~ stack.
+~ stack. Similarly, swap-subitems creates an -entry-type-swap-substrings,
+~ which swaps the top two items, and roll-subitems creates an
+~ -entry-type-roll-substrings, which rolls them, or unrolls them with a
+~ negative parameter.
 ~
 ~   One more thing: The order in which provide-* commands execute will most
 ~ likely match the order in which the corresponding bytes are output. This may
@@ -3205,6 +3210,8 @@ allocate-transformation-state s" transformation-state" variable
 : hex-output-metadata-entry-type-push-substring-hex64 12 ;
 : hex-output-metadata-entry-type-push-substring-string 13 ;
 : hex-output-metadata-entry-type-drop-substring 14 ;
+: hex-output-metadata-entry-type-swap-substrings 15 ;
+: hex-output-metadata-entry-type-roll-substrings 16 ;
 
 ~   Initialize the contents of the output metadata to all zeroes. This is
 ~ called from hex-transform at its top level, at the very start, to make sure
@@ -3252,7 +3259,8 @@ allocate-transformation-state s" transformation-state" variable
   || ;
 
 : is-push-substring-entry
-  ~ Notably, -entry-type-drop-substring is not a push-substring entry.
+  ~   Notably, the substring swap, drop, and roll entry types are not
+  ~ push-substring entries.
   hex-output-metadata-entry-type @
   dup hex-output-metadata-entry-type-push-substring-decimal = swap
   dup hex-output-metadata-entry-type-push-substring-hex8 = 3roll || swap
@@ -3994,6 +4002,94 @@ allocate-transformation-state s" transformation-state" variable
         hex-output-metadata-entry-type-drop-substring = {
           pop-substring-entry-stack drop
         } if
+
+        dup hex-output-metadata-entry-type @
+        hex-output-metadata-entry-type-swap-substrings = {
+          ~   Just like in hex-emit-template-string, we want to make sure to
+          ~ discard the zeroes we get if we underflow the stack.
+          pop-substring-entry-stack
+          pop-substring-entry-stack
+          swap
+          dup { push-substring-entry-stack } { drop } if-else
+          dup { push-substring-entry-stack } { drop } if-else
+        } if
+
+        dup hex-output-metadata-entry-type @
+        hex-output-metadata-entry-type-roll-substrings = {
+          ~ The parameter giving the amount to roll by is in the string field.
+          dup hex-output-metadata-entry-string @
+          ~ (... amount to roll by)
+
+          ~   We resist the temptation to do the memcopy math. We don't need
+          ~ to, since the regular Forth roll and unroll do it for us.
+          dup 0 < {
+            ~   In this scenario, we're rolling. The amount to roll by is also
+            ~ the number of items.
+
+            0 { 2dup < } { pop-substring-entry-stack 3unroll 1+ } while
+            drop
+            ~ (... items, amount to roll by / number of items)
+
+            ~   Please notice that the items we have popped from the substring
+            ~ entry stack are now, on the value stack, in the reverse of the
+            ~ order they were on the entry stack. They will reverse again when
+            ~ we push them back.
+            ~
+            ~   The amount to roll by is positive, so the desired operation is
+            ~ a regular roll. Since the entries are reversed right now, we
+            ~ unroll them, which will be what we want when we put them back.
+            ~
+            ~   Try it out interactively with a toy example and convince
+            ~ yourself. It's hard to really model in your head, but it's true.
+            ~ The intuition is that, if you're looking at the value stack,
+            ~ the bottommost item there will be the topmost one after
+            ~ re-reversing, so we think of our operations as proceeding
+            ~ up-stack from there, instead of the usual operations that start
+            ~ at the topmost item and proceed downwards.
+            ~
+            ~   Anyway, this little trick does a regular unroll, which acts as
+            ~ a roll, and keeps the value around.
+            dup 3unroll 1+ unroll
+          } if
+          ~ (... items if positive, amount to roll by)
+
+          ~   We did the positive case first, which means the amount to roll
+          ~ by is still its original value, regardless of whether that case
+          ~ ran or not. So, we can check if it's negative to see if we need
+          ~ to do the negative case.
+          dup 0 > {
+            ~   In this scenario, we're unrolling. We negate the amount to
+            ~ roll by to get the amount to unroll by, which is also the number
+            ~ of items.
+            negate
+
+            0 { 2dup < } { pop-substring-entry-stack 3unroll 1+ } while
+            drop
+            ~ (... items, number of items)
+
+            ~   The parameter was negative, so we were asked to do an unroll.
+            ~ This trick does a roll, and keeps the value. Notice that "roll"
+            ~ always needs a positive amount.
+            dup 1+ roll swap
+          } if
+          ~ (... items, number of items)
+
+          ~   Now, regardless of which case ran, we have the items and we have
+          ~ a non-negative count of them. Notice that if we were asked to roll
+          ~ by zero, neither case ran, but that still describes what we have
+          ~ accurately.
+
+          ~ Now we push them back.
+          0 { 2dup < } {
+            3roll
+
+            ~ Again, if we underflowed we got zeros, and we discard them.
+            dup { push-substring-entry-stack } { drop } if-else
+
+            1+
+          } while
+          drop drop
+        } if
       } if
       hex-output-metadata-next-entry
     } while
@@ -4877,9 +4973,20 @@ allocate-transformation-state s" transformation-state" variable
   } if
   dup s" drop-subitem" stringcmp 0 = {
     ~ Create a new "drop substring" entry.
-    drop drop
-    2 pick execution-token-to-entry entry-to-name
-    hex-output-metadata-entry-type-drop-substring swap
+    drop drop hex-output-metadata-entry-type-drop-substring 0
+    add-hex-output-metadata-entry
+    exit
+  } if
+  dup s" swap-subitems" stringcmp 0 = {
+    ~ Create a new "swap substrings" entry.
+    drop drop hex-output-metadata-entry-type-swap-substrings 0
+    add-hex-output-metadata-entry
+    exit
+  } if
+  dup s" roll-subitems" stringcmp 0 = {
+    ~   Create a new "roll substrings" entry. The parameter goes in the string
+    ~ field, and the length is always zero.
+    drop drop 0 swap hex-output-metadata-entry-type-roll-substrings swap
     add-hex-output-metadata-entry
     exit
   } if