I'm really hoping we'll be manually writing the least amount of x86-specific code as possible. I think you need to be careful and try to keep the JavaScript code intuitive and "safe".
I'm not sure it's a good idea to define names like $, _, _16, ESP, EAX etc. as global values. Those names are very short and not very distinctive. We probably want something like x86Reg.EAX, or a.regs.EAX (in the assembler object), etc.
Besides that, returning the "this" in each instruction function is a good idea. This is what is done in C++ stream objects (e.g.: iostream).
- Maxime
I've been tinkering with Javascript and x86_64 assembly code and in doing so, I've tried to achieve a syntax in Javascript as close as possible to the AT&T syntax so that writting assembly code feels almost like inline assembly with gcc.
I have not extensively surveyed all instructions yet but here is an example of what it might look like. The javascript notation and the corresponding assembly code in AT&T syntax are shown side-by-side:
var a = new x86_Assembler(); a. add ($(-8), ESP). // addl $-8,%esp maintain 16 byte alignment for Mach!: push (EAX). // push %eax mov (_16(ESP), EAX). // movl 16(%esp),%eax get pointer to handlers call (_12(EAX)). // call *12(%eax) call handlers[1], printf add ($(12), ESP). // addl $12,%esp maintain 16 byte alignment
add ($(-4), ESP). // addl $-4,%esp maintain 16 byte alignment push ($(11)). // push $11 dup (). // MACRO: duplicate top of stack mov (_16(ESP), EAX). // movl 16(%esp),%eax get pointer to handlers call (_16(EAX)). // call *16(%eax) call handlers[2], add add ($(12), ESP). // addl $12,%esp maintain 16 byte alignment
ret ();
The example above covers usage of immediate values, registers, memory accesses on 0,1 and 2 operands instructions. Notice how by having each instruction function return the "this" object, all instructions functions can be chained together. Also notice that "$", "_", "_12" and "_16" are functions which return either and immediate, or a memory access object. Finally, "ESP" and "EAX" are register objects.
One interesting thing to note is the possibility to use "macros" of assembly instructions such as shown by the usage of "dup". Such macros could be installed on the "a" object for a one shot usage, therefore being limited to the scope of the "a" variable, without polluting its prototype. A definition of dup could be:
a.dup = function () { return this. mov (_(ESP), EAX). // movl (%esp), %eax get top of stack value add ($(-4), ESP). // addl $-4, %esp add space on stack for the value mov (EAX, _(ESP)); // movl %eax, (%esp) copy value on top of stack }
Other more useful macros could be promoted to the prototype object.
To achieve that kind of syntax without polluting the global object we could use the following idiom:
function () // A function or method on an object, or an anonymous function { // used as a local namespace
// Definitions of used methods and objects const $ = x86_Assembler.prototype.$; const ESP = x86_Assembler.prototype.register.ESP; const EAX = x86_Assembler.prototype.register.EAX; const _ = x86_Assembler.prototype.memory._; const _12 = x86_Assembler.prototype.memory._12; const _16 = x86_Assembler.prototype.memory._16; var a = new x86_Assembler(); // Can be defined here or outside the
function
// Macro definitions such as "dup" // Some assembly code here
}; // When used as a namespace, it should be called right away I will survey more extensively other instruction usages to see if there are corner cases.
Erick _______________________________________________ Tachyon-list mailing list Tachyon-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/tachyon-list