In my enthusiasm to unleash yet another x86 assembler upon the world,
albeit one embedded in Scheme (because all you compiler writers just
don't have enough to do), I released a less than robust version of Sassy
last night. This release fixes some things:
*MzScheme 209 no longer supported, in favor of v299-alpha
*Proper load paths. Booting Sassy now works as advertised.
*Included a .zip version for Windows users
*All implementations now create _identical_ ELF objects, not just
equally valid ELF objects with their tables in different orders
*All I/O is now handled by write-byte and read-byte.
*This time I made sure all the implementations passed the test-suite!!
By the way, I neglected to mention that Sassy is licensed under the LGPL.
AND...I welcome all questions, comments, criticisms, witticisms...
home: http://home.earthlink.net/~krautj/sassy/sassy.html
tar.gz: http://home.earthlink.net/~krautj/sassy/files/sassy-0.1.1.tar.gz
zip: http://home.earthlink.net/~krautj/sassy/files/sassy-0.1.1.zip
Happy Sassafras!!!
-JK
--
Jonathan Kraut
NYC
ja...@columbia.edu
Cheers,
Brandon Van Every
Hi,
This is really nice. A few comments:
The implicit label definition may be problematic with frequent use
of macros, since a macro can silently overwrite a label. An explicit
label form such as (label _start ...) might be better.
Local labels for use within macros are indispensible. You can do this
implicitly by having all labels introduced within some scope be
replaced by a gensym in the output, or explicitly by naming them in a
scope. For example:
;; Implicit, LOOP becomes a distinct gensym inside the nearest
;; enclosing LOCAL form for each expansion of MY-WHILE.
;; Optional: LAMBDA has an implicit enclosing LOCAL form.
(macro my-while
(lambda (test . body)
`(local
(label loop
(if ,test
(begin ,@body (jmp loop)))))))
;; Explicit, pre-declare LOOP to be a distinct gensym inside the
;; LOCAL block for each expansion of MY-WHILE.
(macro my-while
(lambda (test . body)
`(local loop
(label loop
(if ,test
(begin ,@body (jmp loop)))))))
Also some sort of access to the current assembler state in Scheme
escapes would be nice, for instance so that you can do things like:
(data (str1 (bytes "hello world"))
(str2 (bytes (! (string-upcase (sassy-ref 'the-string1))))))
Do you have any intention of porting to other platforms? How about
supporting 64-bit mode? :)
--
Alex
Thanks! And thanks for your feedback!
> The implicit label definition may be problematic with frequent use
> of macros, since a macro can silently overwrite a label. An explicit
> label form such as (label _start ...) might be better.
Good point. This would also make it easier for Sassy to distinguish
labels and opcode names, so that you could write labels with the same
name as opcodes without confusion (at least on sassy's part).
> Local labels for use within macros are indispensible. You can do this
> implicitly by having all labels introduced within some scope be
> replaced by a gensym in the output, or explicitly by naming them in a
> scope. For example:
>
> ;; Implicit, LOOP becomes a distinct gensym inside the nearest
> ;; enclosing LOCAL form for each expansion of MY-WHILE.
> ;; Optional: LAMBDA has an implicit enclosing LOCAL form.
> (macro my-while
> (lambda (test . body)
> `(local
> (label loop
> (if ,test
> (begin ,@body (jmp loop)))))))
>
> ;; Explicit, pre-declare LOOP to be a distinct gensym inside the
> ;; LOCAL block for each expansion of MY-WHILE.
> (macro my-while
> (lambda (test . body)
> `(local loop
> (label loop
> (if ,test
> (begin ,@body (jmp loop)))))))
I must admit I've been mentally wringing my hands about this issue for
some time, and I keep punting.
The reason I've been punting is this: the whole point of Sassy's (and
COMFY's) control constructs is to make local labels like these, which
are basically throw-away labels you would otherwise care less about,
unnecessary. For instance, the above can be written using sassy's 'iter'
and 'seq' (and 'inv', presuming you want to flip iter's win and lose so
that it wins if its body fails):
(macro my-while
(lambda (test . body)
`(inv (iter (seq ,test
(begin ,@body))))))
which would generate the same code as the above, without declaring a
label (btw, sassy's 'if' form always takes three clauses, unlike
Scheme's).
On the other hand, being a schemer, and since sassy has a lot in it that
looks pretty much like Scheme already, why not take it further, make it
_really_ nice and add full lexical scoping, so you could have for
instance, local data declarations etc. But this means a lot more to
think about and a fair amount of re-design.
> Also some sort of access to the current assembler state in Scheme
> escapes would be nice, for instance so that you can do things like:
>
> (data (str1 (bytes "hello world"))
> (str2 (bytes (! (string-upcase (sassy-ref 'the-string1))))))
A very nice idea! Sassy can be easily rigged to store the contents of
any label declaration, as scheme data. For labels in the data section,
which may have several items, each item can be put in a vector, and some
syntax for either accessing the vector or referencing its contents
introduced.
Hmm...Now that I think about it more, your idea suggests to me a
solution to another issue I've been thinking about: how to get access to
addresses so you can do math on them and use the result as data or an
operand (like NASM's '$' and '$$').
>
> Do you have any intention of porting to other platforms? How about
> supporting 64-bit mode? :)
Yes, eventually I would like Sassy to support 64-bit mode, as well as
basic support for 16-bit mode (probably not for the older style 16-bit
addressing syntax though) so you can say things like "I wrote a new
boot-loader...in Scheme!".
And yeah, I have entertained wild notions of turning Sassy into a
"meta-assembler." The basic framework would stay in place. You would
just (heh, "just") swap out the opcode parsers and re-write a few
internal procedures, set an endian-ness flag etc. With a bit of careful
re-factoring to get all the hooks in the right (easily acessible)
places, I believe it would be do-able, and so there could be
"sassy-x86", "sassy-mips32", "sassy-ppc-whatever", etc, like GNU's 'as',
but written in Scheme, natch!
But neither of these are on my plate right at this moment, since at this
point it I'd like to see Sassy mature and solidify a bit, get put
through its paces as a compiler target, etc, before tackling another ISA
or expanding on the modes of its current one. But yeah, someday...
(assemble-with-ISA
ACME-supercell-9-gazillion-infinity
'((text (start (seq ...))))
Thanks again!
Jon
Well, I used MY-WHILE as an intentionally simple example. There
are plenty of other cases where you really do need local labels.
For example:
(macro defsub
(lambda (name . body)
`(,name
,@body
(ret))))
Now you can define subroutines like:
(defsub say-hello
(mov edx 14)
(mov ecx the-string)
(mov ebx stdout)
(mov eax 4)
(int #x80))
and then call them with
(call say-hello)
The advantage of a subroutine over a macro, of course, is that
the code for it only exists in one place so that you can build
abstractions without exponentially increasing your text size.
Moreover a subroutine can call itself recursively.
This is a simple example using just CALL/RET and not passing
any arguments. You could define your own ABI and write
whole libraries of Sassy code based on it, including Scheme
runtime libraries. If you were to change the ABI you'd only
need to change the DEFSUB definition (and use a complementary
FUNCALL), whereas if you wrote the above directly without a
DEFSUB abstraction you'd have to rewrite every subroutine in
your program for every ABI change.
With a macro assembler leveraging the full power of Lisp macros
you wouldn't even really need a compiler and could program large
projects directly in Sassy.
--
Alex
Indeed. As soon as I sent my previous post I thought of another example
where the control primitives just won't cut it: DFA's, where each label
is a state and the code jmp's around between the states all willy-nilly.
(Say you had written a little DFA compiler that always starts off with
state0. Without local labels, you could only have one of those per Sassy
assembly object.)
So...back to the drawing board I go!
> any arguments. You could define your own ABI and write
> whole libraries of Sassy code based on it, including Scheme
> runtime libraries...
>
> With a macro assembler leveraging the full power of Lisp macros
> you wouldn't even really need a compiler and could program large
> projects directly in Sassy.
I couldn't have said it better.
-Jon
> Alex Shinn wrote:
>
>> With a macro assembler leveraging the full power of Lisp macros
>> you wouldn't even really need a compiler and could program large
>> projects directly in Sassy.
>
>I couldn't have said it better.
That is like scary cool (so cool it is scary).
This creates a lot of interesting possibilities. First and foremost is
a Psyco like dynamic compilation for Scheme:
http://psyco.sourceforge.net/introduction.html
Kudos to Jonathan and everyone involved in the creation of Sassy.
James Graves
Glad you like it, and thanks! I take credit for the man-hours, but it
was through reading Henry Baker's papers that my eyes were opened up to
the possibilities (and in fact the core of the implementation is not
that different from his, and employs some other techniques gleaned from
some of his other publications). Also I re-wrote a couple of procedures
from Alex's SRFI-56 to handle the floating point data.
By the way, I should mention that Felix Winkelmann has been kind enough
to create a chicken .egg for Sassy, so chicken users can install it in
the usual way (ie 'chicken-setup sassy'). Sassy uses a lot of macros so
it takes a while to compile, but works just fine. Thanks Felix!