Assembler Syntax

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Assembler Syntax

Udo Schneider
This question might seem wrong for this group but I'm thinking of
integrating Assembler into Smalltalk.

As my experience with Assembler comes from a m68k background I'm used to
the source/destination syntax (AT&T style) and not to the Intel style
syntax (destination/source).

On the other hand I assume most people today use MASM (either directly
or through inline assembler).

Which syntax do you prefer?

Regards,

Udo


Reply | Threaded
Open this post in threaded view
|

Re: Assembler Syntax

ChanHong Kim
Oh!! Hat's Good and difficaul project for Smalltalk.
Personally, I prefer and comfortable with Intel sytle because I started
Z80, the advanced over 8080.

IMHO, [Destination/Source] is comfortable and understandable since
almost programming language(inclue Smalltalk) accept assignment is
right to left, not left to right.

Udo, however, Smalltalk is pure-OOPL, so you should consider how embed
assembler in Smalltalk. If you accomplish that, that is so greate way
to spped up Smalltalk like in Delphi's inline assembler.

 Good luck!


Reply | Threaded
Open this post in threaded view
|

Re: Assembler Syntax

Udo Schneider
> Udo, however, Smalltalk is pure-OOPL, so you should consider how embed
 > assembler in Smalltalk. If you accomplish that, that is so greate way
 > to spped up Smalltalk like in Delphi's inline assembler.
The current plann is to provide something like ExternalLibraries with
the difference that the actual methods do not call a function but
instead execute some opcodes.

This would allow me to develop small asm routines in smalltalk without
the "exit DST, make asm change, assemble, start DST, test" cycle.

Another idea is to provide an additional possibility to export all asm
functions once the Library is complete and to make a stand alone dll out
of it .... but that's just food for thought.

Currently I'm getting crazy over this $!ยง&"$% x86 opcodes.

CU,

Udo


ChanHong Kim wrote:

> Oh!! Hat's Good and difficaul project for Smalltalk.
> Personally, I prefer and comfortable with Intel sytle because I started
> Z80, the advanced over 8080.
>
> IMHO, [Destination/Source] is comfortable and understandable since
> almost programming language(inclue Smalltalk) accept assignment is
> right to left, not left to right.
>
> Udo, however, Smalltalk is pure-OOPL, so you should consider how embed
> assembler in Smalltalk. If you accomplish that, that is so greate way
> to spped up Smalltalk like in Delphi's inline assembler.
>
>  Good luck!
>


Reply | Threaded
Open this post in threaded view
|

Re: Assembler Syntax

Schwab,Wilhelm K
Udo,

>  > Udo, however, Smalltalk is pure-OOPL, so you should consider how embed
>  > assembler in Smalltalk. If you accomplish that, that is so greate way
>  > to spped up Smalltalk like in Delphi's inline assembler.
> The current plann is to provide something like ExternalLibraries with
> the difference that the actual methods do not call a function but
> instead execute some opcodes.
>
> This would allow me to develop small asm routines in smalltalk without
> the "exit DST, make asm change, assemble, start DST, test" cycle.

An external library like approach could be very different from "inline
xyz" [*].  I say "inline xyz" vs. "inline asm" because I suspect that if
you go to the trouble of inlining, then it makes sense to make it
generic.  To do that, I suspect one might need to enlist help from OA.

A useful (I think??) start would be a framework for driving compilers.
The result would be useful with mingw, nasm, InnoSetup, MIDL, etc., a
further subclass of it handling the compilers that make callable functions.

Running the compiler and reviewing its output is important.  It would be
ideal to have it able to run reasonably silently, perhaps signalling and
error or simply entering an associated IDE if there are problems during
the build.

Another concept is binding to the functions.  That could be done
manually, by creating IDL and running MIDL and the TLA, etc.

IIRC, Smalltalk/X does something like this???

Have a good one,

Bill


[*] Pardon me, INLine(TM) Visual(R) X#.Net ;)

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Assembler Syntax

Udo Schneider
Bill,

> An external library like approach could be very different from "inline
> xyz" [*].  I say "inline xyz" vs. "inline asm" because I suspect that if
> you go to the trouble of inlining, then it makes sense to make it
> generic.  To do that, I suspect one might need to enlist help from OA.
Actually the concept of "inlining" turned out to be very simple. My
current code emmits ExternalMethods whose address is not determined from
DLL exports (using getProcAddress and friends) but is explicitly set.

I decided to extend (wrap) the Smalltalk compiler to understand a
special asm inline syntax. E.g. something like this:

AsmLibrary asmAdd: add1 with: add2
   _asm{' <stdcall: sdword integerAdd sdword sdword>
        mov eax, add1
        add eax, add2'}
  ^self invalidCall

Please notice that this approach uses a familiar external call
definition and regular smalltalk code (if the "primitive" fails).

The actual Smalltalk code given to the Smalltalk compiler becomes
AsmLibrary asmAdd: add1 with: add2
        <stdcall: sdword integerAdd sdword sdword>
        ^self invalidCall

So the Smalltalk Compiler takes care of creating the ExternalMethod and
call/return type conversions.

As this method was never called yet the ExternalProcAddress is null.
This is  where the Assembler comes in. The code gets's compiled and it's
address is set within the ExternalMethod.

The actual assembler code assembled has a (dynamic) stub for variable
definitions. So the code above becomes:
        equ add1 [ebp+8]
        equ add2 [ebp+12]
        push ebp
        mov ebp, esp
        ----- Start of user routine ---
        mov eax, add1
        add eax, add2
        ------ End of user routine ---
        pop ebp
        ret



Volia!

There is of course more going on behind the scenes. To Dos here are
things like where to store the object code (references),
refresh/clearing during Image Startup, runtim dependencies and so on.

But all these things are more or less (more more than less :-) working
in my workspace with preassembled code.

The *big* thing missing is a "thingy" able to assemble mnenomics to
object code .... That's where I'm stuck now.

I thought about using an external assembler (either as DLL or via a
command) .... but this introduces a lot of dependencies.

So I've decided to write a minimalistic Assembler in Smalltalk. And to
be honest I'm starting to *hate* x86 opcodes (this would be so easy on
ARM :-( ). But that's my problem.




Another idea I'm having is an "automagical" conversion into a stand
alone DLL.

If you are finished with all your AssemblerMethods I'm imagining a tool
which emmits the DLL boilerplate code in asm and appends each inline asm
method as asm proc (including export statements). This file sould then
be assembled using a regular assembler generating a DLL.

As the tool also knows the caller (Dolphin) side it should be possible
to create an ExternalLibrary subclass automagically with complete and
correct method definitions including external call statements.

> A useful (I think??) start would be a framework for driving compilers.
> The result would be useful with mingw, nasm, InnoSetup, MIDL, etc., a
> further subclass of it handling the compilers that make callable functions.
I agree that a more general approach would be desirable. However I
decided to start "small" and to keep everything within the Smalltalk
environment.

I thought about this especially for resources. E.g. building a resoure
dll using rc/link from within Dolphin with all resources needed for
specific packages including some dolpin boilerplate code .... but that's
just in my head at the moment :-(

> Running the compiler and reviewing its output is important.  It would be
> ideal to have it able to run reasonably silently, perhaps signalling and
> error or simply entering an associated IDE if there are problems during
> the build.
My first approach was to integrate an external compiler .... but I found
that dependencies (configuration/path issues) are a problem. In addition
external assemblers are *too* powerfull for inline assembly. I'll never
want to produce a segemented 16 bit binary with it's own heap and other
segments.

The assembler I intended does nothing more than generating _32bit_
object code from mnenomics with alias (equ) and label handling.
Everything else is too much.

> Another concept is binding to the functions.  That could be done
> manually, by creating IDL and running MIDL and the TLA, etc.
Maybe I got you wrong. I intend to keep everything within Dolphin. The
possibilty to create a standalone DLL is just an Add-on.

> IIRC, Smalltalk/X does something like this???
To be honest ... no idea. Maybe I'm totally wrong but AFAIK Smalltalk/X
has something like "inline C". You could however use inline ASM within
inline C .... not sure about that.

CU,

Udo

PS: Please ignore the syntax (st and asm) .... it's just an example.


Reply | Threaded
Open this post in threaded view
|

Re: Assembler Syntax

Udo Schneider
In reply to this post by Schwab,Wilhelm K
Bill,

> An external library like approach could be very different from "inline
> xyz" [*].  I say "inline xyz" vs. "inline asm" because I suspect that if
> you go to the trouble of inlining, then it makes sense to make it
> generic.  To do that, I suspect one might need to enlist help from OA.
I was typing to fast ..... I think I didn't get the sense of what you
were saing.

With my current approach all you need to inline "xyz" is a "thingy"
which produces callable code from xyz code.

Everything else is allready in place (thanks to OA) or can be easily
added. Once you find out that you can easily set the proc address in
ExternalMethods the world becomes yours :-)

To implement an "xyz" inliner you'll have to create your own parser
which seperates xyz from smalltalk code (this is where compilerClass and
friend come in). The Smalltalk code gets compiles by the Smalltalk
Compiler and becomes an ExternalMethod. Your xyz Compiler creates object
code and sets the address in the ExternalMethod.

At the moment I'm seeing on thing where I have to work around OAs
implementation. During Image Startup all addresses of all external
methods of all external libraries are set to null.

If an external method is executed and the address is null than (that's
my assumption) the VM does a getProcAddress to fill in the address. So
it's not possible to catch this in ST and enter the objectcode address
directly.

Instead I choosed to hook up to the cleaning proccess and instead of
setting the address to nul after Startup I'll set it to the actual address.

Regards,

udo


Reply | Threaded
Open this post in threaded view
|

Re: Assembler Syntax

Chris Uppal-3
In reply to this post by Udo Schneider
Udo Schneider wrote:

> The current plann is to provide something like ExternalLibraries with
> the difference that the actual methods do not call a function but
> instead execute some opcodes.

This all sounds very interesting.  I hope it goes well (despite the opcodes).

One suggestion (I hope you don't mind suggestions) would be to expose the
underlying assembler in a form that made it possible to create dynamic code
too.  Something like (assuming that ExternalValuable is a kind of
<*adicValuable>, and based blindly on your own example):

    descriptor := ExternalDescriptor fromString:
                            'stdcall: sdword integerAdd sdword sdword'.
    asm := 'mov eax, add1; add eax, add2'.
    valuable := ExternalValuable
                        asm: asm.
                        descriptor: descriptor.

to create a <triadicValuable> on-the-fly.

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Assembler Syntax

Udo Schneider
Chris Uppal wrote:

> One suggestion (I hope you don't mind suggestions) would be to expose the
> underlying assembler in a form that made it possible to create dynamic code
> too.  Something like (assuming that ExternalValuable is a kind of
> <*adicValuable>, and based blindly on your own example):
>
>     descriptor := ExternalDescriptor fromString:
>                             'stdcall: sdword integerAdd sdword sdword'.
>     asm := 'mov eax, add1; add eax, add2'.
>     valuable := ExternalValuable
>                         asm: asm.
>                         descriptor: descriptor.
>
> to create a <triadicValuable> on-the-fly.

Excellent idea! Thanks for the feedback. I even got this working very
quickly (if you ignore the object code generation ... that's still done
by an external assembler).

I saw that you specified the variables as add1 and add2. My first
thought was "let's name them value1 and value2" .... but then this would
be against the smalltalk style of naming.

So the question I'm having is how to provide meaningfull names to
ExternalValuable. Would something like this be allright for you?

valuable := ExternalValuable asm: asm
        descriptor: descriptor
        variableNames: 'add1 add2'

I even thought of a possible shortcut to use it more like regular blocks:

valuable := ExternalValuable fromString: 'sdword sdword sdword | add1
add2 | mov eax, add1; add eax, add2'.

Remeber that the var names are not neccessary. If you know the stack
layout the call creates you could allways refer to your vars with
something like [ebp+8] etc.

On the other hand I do not think this would be very "smaltalkish".

Please note note that you can ommit the calling convention and the proc
name in this case. I also decided to only support stdcall: for the first
version (So I don't have to care about stack cleaning within asm).

Regards,

Udo


Reply | Threaded
Open this post in threaded view
|

Re: Assembler Syntax

Sergey Philippov
Udo Schneider wrote:
[skip]
> So the question I'm having is how to provide meaningfull names to
> ExternalValuable. Would something like this be allright for you?
>
> valuable := ExternalValuable asm: asm
>     descriptor: descriptor
>     variableNames: 'add1 add2'
>
[skip]
> On the other hand I do not think this would be very "smaltalkish".
>
May be something like .net's System.Reflection.Emit.ILGenerator will be
better?

--
wbr, ps


Reply | Threaded
Open this post in threaded view
|

Re: Assembler Syntax

Chris Uppal-3
In reply to this post by Udo Schneider
Udo,

> I saw that you specified the variables as add1 and add2. My first
> thought was "let's name them value1 and value2" .... but then this would
> be against the smalltalk style of naming.

Actually, I'd just copied that from your example without really thinking about
it....


> So the question I'm having is how to provide meaningfull names to
> ExternalValuable. Would something like this be allright for you?
>
> valuable := ExternalValuable asm: asm
> descriptor: descriptor
> variableNames: 'add1 add2'

Why not make #variableNames: be optional, defaulting to something internally
generated like $1, $2, ... (or arg1, arg2, ... if you prefer).


> I even thought of a possible shortcut to use it more like regular blocks:
>
> valuable := ExternalValuable fromString: 'sdword sdword sdword | add1
> add2 | mov eax, add1; add eax, add2'.

Perhaps that would be a bit misleading; to me it makes add1 and add2 look like
locals rather than parameters.

I think I'd just stick with something that was easy to parse, and not /too/
difficult to use.  The interesting and difficult bit about using this stuff
will be thinking out the assembler code itself.  I don't think that shortcuts
for creating them will actually make much (incremental) difference.  The job of
typing the expression in won't be the bottleneck, if you see what I mean, so
there's not a lot to gain by optimising it.


> Please note note that you can ommit the calling convention and the proc
> name in this case. I also decided to only support stdcall: for the first
> version (So I don't have to care about stack cleaning within asm).

Very reasonable.  The point of having both stdcall and cdecl is to be able to
interface to externally defined APIs, but a block-like construction is
obviously intended for internal use, and so has no need of the distinction.

But, OTOH, it would be nice (as a /further/ enhancement if you happen to feel
like it) to be able to create something like an ExternalCallback that could be
passed to an external API as a "function pointer" (although creating a
BlockCallback that invoked a BlockClosure which in turn invoked the
ExternalValuable would serve as a substitute -- albeit somewhat indirect ;-)

    -- chris


PS, and /completely/ off-topic:

Udo, I noticed a small bug in one of your Treemap layout strategies some time
ago which I've been meaning to tell you about, but never got around to :-(   To
reproduce (unless you've already fixed it) try:
    tm := (TreeModel new)
                 add: 0 asChildOf: nil;
                 add: 10516 asChildOf: 0;
                 add: 2267 asChildOf: 0;
                 add: 71581 asChildOf: 0;
                 yourself.

    p := TreePresenter show: 'Treemap view'.
    p view renderer
             nodeSizeBlock: [:each | each];
             layoutStrategy: OrderedSquarifiedTreeMapStrategy new.
    p model: tm.
Which causes OrderedSquarifiedTreeMapStrategy>>layout:in: to go into an
infinite loop (which can easily be broken out of).

    -- c