6153 - switch 'main' to use Mu strings

At the SubX level we have to put up with null-terminated kernel strings
for commandline args. But so far we haven't done much with them. Rather
than try to support them we'll just convert them transparently to standard
length-prefixed strings.

In the process I realized that it's not quite right to treat the combination
of argc and argv as an array of kernel strings. Argc counts the number
of elements, whereas the length of an array is usually denominated in bytes.
This commit is contained in:
Kartik Agaram 2020-03-15 21:03:12 -07:00
parent f559236bdf
commit c48ce3c8bf
19 changed files with 170 additions and 18 deletions

View File

@ -234,4 +234,36 @@ $allocate-region:abort:
cd/syscall 0x80/imm8
# never gets here
# Claim the next 'n+4' bytes of memory and initialize the first 4 to n.
# Abort if there isn't enough memory in 'ad'.
allocate-array: # ad: (addr allocation-descriptor), n: int -> result/eax: (addr _)
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
51/push-ecx
52/push-edx
# ecx = n
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+0xc) to ecx
# var size/edx: int = n+4
8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy ecx+4 to edx
# result = allocate(ad, size)
# . . push args
52/push-edx
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
# . . call
e8/call allocate/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# *result = n
89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax
$allocate-array:end:
# . restore registers
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
# . . vim:nowrap:textwidth=0

89
102kernel-string.subx Normal file
View File

@ -0,0 +1,89 @@
# We can't really do much with null-terminated kernel strings, and we don't
# want to. Let's turn them into regular length-prefixed strings at the first
# opportunity.
== code
kernel-string-to-string: # ad: (addr allocation-descriptor), in: (addr kernel-string) -> result/eax: (addr array byte)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
52/push-edx
53/push-ebx
56/push-esi
57/push-edi
# var len/ecx: int = length(in)
(kernel-string-length *(ebp+0xc))
89/<- %ecx 0/r32/eax
# result = allocate-array(ad, len)
(allocate-array *(ebp+8) %ecx) # => eax
# var c/edx: byte = 0
ba/copy-to-edx 0/imm32
# var src/esi: (addr byte) = in
8b/-> *(ebp+0xc) 6/r32/esi
# var dest/edi: (addr byte) = result->data
8d/copy-address *(eax+4) 7/r32/edi
{
$kernel-string-to-string:loop:
# c = *src
8a/byte-> *esi 2/r32/edx
# if (c == 0) break
81 7/subop/compare %edx 0/imm32
74/jump-if-= break/disp8
# *dest = c
88/byte<- *edi 2/r32/edx
# ++src
46/increment-esi
# ++dest
47/increment-edi
eb/jump loop/disp8
}
$kernel-string-to-string:end:
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
kernel-string-length: # in: (addr kernel-string) -> result/eax: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
52/push-edx
# result = 0
b8/copy-to-eax 0/imm32
# var c/ecx: byte = 0
b9/copy-to-ecx 0/imm32
# var curr/edx: (addr byte) = in
8b/-> *(ebp+8) 2/r32/edx
{
$kernel-string-length:loop:
# c = *curr
8a/byte-> *edx 1/r32/ecx
# if (c == 0) break
81 7/subop/compare %ecx 0/imm32
74/jump-if-= break/disp8
# ++curr
42/increment-edx
# ++result
40/increment-eax
#
eb/jump loop/disp8
}
$kernel-string-length:end:
# . restore registers
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -31,21 +31,21 @@ fn test-factorial {
check-ints-equal result 0x78 "F - test-factorial"
}
fn main args: (addr array kernel-string) -> exit-status/ebx: int {
var a/eax: (addr array kernel-string) <- copy args
fn main args: (addr array string) -> exit-status/ebx: int {
var a/eax: (addr array string) <- copy args
var tmp/ecx: int <- length a
$main-body: {
compare tmp, 1
# if (len(args) == 1) factorial(5)
# if (len(args) <= 4) factorial(5)
compare tmp, 4
{
break-if-!=
break-if->
var tmp/eax: int <- factorial 5
exit-status <- copy tmp
break $main-body
}
# if (args[1] == "test") run-tests()
var tmp2/ecx: (addr kernel-string) <- index a, 1
var tmp3/eax: boolean <- kernel-string-equal? *tmp2, "test"
var tmp2/ecx: (addr string) <- index a, 1
var tmp3/eax: boolean <- string-equal? *tmp2, "test"
compare tmp3, 0
{
break-if-=

Binary file not shown.

BIN
apps/hex

Binary file not shown.

BIN
apps/mu

Binary file not shown.

BIN
apps/pack

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,10 +1,10 @@
# Just a test stub for mu-init.subx
#
# Try it out like this:
# $ ./translate_subx init.linux 0*.subx mu-init.subx mu-init-test.subx
# $ ./translate_subx init.linux [0-9]*.subx mu-init.subx mu-init-test.subx
# $ ./a.elf # should run all tests
main: # args: (address array kernel-string) -> result/ebx: int
main: # args: (addr array (addr array byte)) -> result/ebx: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
@ -15,10 +15,10 @@ main: # args: (address array kernel-string) -> result/ebx: int
8b/-> *(ebp+8) 6/r32/esi
{
# if (argc <= 1) break
81 7/subop/compare *esi 1/imm32
81 7/subop/compare *esi 4/imm32
7e/jump-if-<= break/disp8
# if (argv[1] != "test") break
(kernel-string-equal? *(esi+8) "test") # => eax
(string-equal? *(esi+8) "test") # => eax
3d/compare-eax-and 0/imm32
74/jump-if-= break/disp8
#

View File

@ -3,7 +3,7 @@
# See translate_mu for how this file is used.
#
# Mu programs start at a function called 'main' with this signature:
# fn main args: (addr array kernel-string) -> exit-status/ebx: int
# fn main args: (addr array (addr array byte)) -> exit-status/ebx: int
# If your program doesn't need commandline arguments you can drop it:
# fn main -> exit-status/ebx: int
#
@ -15,11 +15,42 @@
Entry:
# we don't use ebp in Entry; just initialize it
bd/copy-to-ebp 0/imm32
# var args/eax: (addr array kernel-string)
89/<- %eax 4/r32/esp
# initialize the heap
# - save argc and argv
# var argc-and-argv/esi
89/<- %esi 4/r32/esp
$Entry:initialize-heap:
# - initialize the heap
(new-segment *Heap-size Heap)
# run Mu program
(main %eax)
# exit
$Entry:initialize-args:
# - convert argv from null-terminated 'kernel' strings to length-prefixed Mu strings
# var argc/edx: int
8b/-> *esi 2/r32/edx
# argc is in words; convert it to bytes
c1/shift 4/subop/left %edx 2/imm8
# var args/edi: (addr array (addr array byte))
(allocate-array Heap %edx) # => eax
89/<- %edi 0/r32/eax
# var curr/ecx: (addr kernel-string) = argv
8d/copy-address *(esi+4) 1/r32/ecx
# var max/edx: (addr kernel-string) = argv+4+argc
8d/copy-address *(ecx+edx) 2/r32/edx
# var dest/esi: (addr (addr array byte)) = args+4
8d/copy-address *(edi+4) 6/r32/esi
{
# if (curr >= max) break
39/compare %ecx 2/r32/edx
73/jump-if-addr>= break/disp8
# *dest = kernel-string-to-string(*curr)
(kernel-string-to-string Heap *ecx) # => eax
89/<- *esi 0/r32/eax
# curr += 4
81 0/subop/add %ecx 4/imm32
# dest += 4
81 0/subop/add %esi 4/imm32
#
eb/jump loop/disp8
}
# - run Mu program
(main %edi) # => ebx
# - exit
(syscall_exit)