LSO Assembler

From libopenmetaverse - libomv - Developer Wiki

Jump to: navigation, search

A very crude LSO assembler has been created based on the information available on the LSO reverse engineering page. It is created using Ville Helin's WLA assemblers. His macro support is good enough that it is a language of its own and thus allowed the LSO assembler to be built on top of his existing assembler using just macros and constant definitions (I told you it was crude! For those curious, it is actually running on the assembler designed for the Super Nintendo sound processor. heh :) ).

Feel free to download the LSO assembler package and try it out.

Instructions

The package given contains the win32 version of the WLA pieces I needed. WLA is cross platform, and thus you can compile it yourself if you do not use win32. The source is available at: [1].

WLA is more complicated that is necessary for this project and creates object files which need to be linked as defined by a project file. I have included a batch file to allow you to effectively ignore and skip these steps.

So, in short, the instructions are:

  • download and extract LSO assembler package
  • at a command prompt run "asm test" ... this will compile test.asm to test.lso
  • read through the example code along with the LSO documentation and you should be on your way to making your own assembled LSO files!

Known limitations

Because the underlying assembler wasn't designed for this task there are some limitations which should be noted.

  • In some cases, when asking the assembler to do arithmetic with two integers, such as LONG $12345678 + $87654321 you will get the error: "STACK_CALCULATE: Out of 16bit range." In these cases, just do the math for the assembler (in this case replace the command with LONG $99999999).
    • I have not seen this affect any label arithmetic, and the branch command output has been verified for both forward and backwards jumps.
  • The assembler doesn't support outputting IEEE-754 floating point values. Therefore you must specify all floating point values (including those for vectors and rotations) as hex values. Someone could write a quick "pre"-preprocessor to do this for us if people actually intend to use this for writing code instead of reverse-engineering purposes. That wasn't the intent of this assembler though.
    • Many hex editors have a tool to show you what the IEEE-754 hex values of a number are, or if you don't have one, you can use one of the numerous online converters like this [2]. It adds a bit of time to do the conversion, but with comments the code readibility shouldn't be affected much.
  • It appears that WLA stopped supporting address labels in calculations for .DEFINE statements.

"Hello, Avatar!" source

For those curious what the language looks like, here's some example source:

/***************************************************************
As a test this is just the assembly equivalent of some simple
LSL code for which the binary LSO is known.

default
{
    state_entry()
    {
        llSay(0, "Hello, Avatar!");
    }
}

000000  00 00 40 00 00 00 00 00 00 00 02 00 00 00 3f ff  ..@...........?ÿ
000010  00 00 3f ff 00 00 00 af 00 00 00 b6 00 00 00 00  ..?ÿ...¯...¶....
000020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000030  00 00 00 00 00 00 00 00 00 00 00 64 00 00 00 64  ...........d...d
000040  00 00 00 00 00 00 00 00 00 00 00 64 00 00 00 00  ...........d....
000050  00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00  ................
000060  00 00 00 01 00 00 00 01 00 00 00 10 00 00 00 00  ................
000070  00 00 00 01 00 00 00 05 00 00 00 00 08 00 00 00  ................
000080  00 00 00 00 05 00 63 5b 5e 00 00 00 00 60 48 65  ......c[^....`He
000090  6c 6c 6f 2c 20 41 76 61 74 61 72 21 00 66 00 00  llo, Avatar!.f..
0000a0  00 00 5c 5e 00 00 00 08 70 11 08 d1 00 17 95 00  ..\^....p..Ñ....
0000b0  00 40 00 00                                      .@..           
 ... remaining bytes are 00 ...

***************************************************************/
.INCLUDE "LSO.inc"

HeaderBlock:
	LONG $00004000	; Machine memory 
	LONG $00000000	; Program Counter (0 means currently not running)
	LONG $00000200	; version
	LONG LocalFrame
	LONG StackTop
	LONG HeapTop
	LONG HeapBottom
	LONG $00000000
	LONG $00000000	; Current State
	LONG $00000000
	LONG $00000000
	LONG $00000000
	LONG $00000000
	LONG $00000000
	LONG StaticBlock
	LONG FunctionBlock
	LONG $00000000
	LONG $00000000
	LONG StateBlock
	LONG $00000000
	LONG $00000001	; Bit-Encoded Events to run bit31-0
	LONG $00000000
	LONG $00000000
	LONG $00000000	; Bit-Encoded Event Mask bit63-32
	LONG $00000001	; Bit-Encoded Event Mask bit31-0  ... bit0=state_entry

StaticBlock:
FunctionBlock:
StateBlock:
	LONG 1		; Numer of States in script

	;StateEntry
	LONG State0-StateBlock	; Location of State Relative to State Block
	LONG $00000000	; Bit-Encoded Event Mask bit63-32
	LONG $00000001	; Bit-Encoded Event Mask bit31-0  ... bit0=state_entry

State0:
	;State Header
	LONG 5	;Size of Header
	.db 0	;null terminated string
State0_header_end:
	; Pointer to Code Chunk (relative to end of State Block header)
	LONG State0_state_entry-State0_header_end 
	LONG 0	; Call Frame Size

State0_state_entry:
	;Code Chunk Header
	LONG 5	;Size of Code Chunk Header
	.db 0	;Null Terminated String

	PUSH_VOID4 
	PUSH_ARGS_START
	PUSH_INTEGER $00000000
	PUSH_STRING "Hello, Avatar!"
	PUSH_LOCAL_ALLOC $00000000
	PUSH_ARGS_END 
	PUSH_INTEGER $00000008
	MATH_ADD Integer, Integer 
	BUILD_CALL_FRAME 
	CALL_BUILTIN llSay
	RETURN
State0End:


HeapTop:
	;HeapEntry  DataSize(long), Type(byte), Reference count(word)
	
	;marks the end of the heap?
	HeapEntry $4000,Void,0

HeapBottom:

.org $3FFF
StackTop:
LocalFrame: