Como nota inicial, si alguien no tiene una mejor idea de cuál sería la mejor forma de que escriba varios posts como respuestas seguidas, incluso quizás después de varias semanas, pido disculpas si envío respuestas a este tema o abro otros nuevos, porque seguramente va a ser mucha la complejidad a manejar, y repartir las diferentes etapas de descubrimientos es mucho más fácil repartiéndolas en diferentes posts, temas y/o respuestas (que serían continuas a menos que alguien responda o consulte algo, o tenga una idea de qué más averiguar o hacer algo interesante y útil con todo esto desde ya, aparte obviamente de realmente aprender Java).
Me tomo la libertad de escribir sobre la programación en ensamblador, pero en el lenguaje dictado por el bytecode de Java.
Las razones más importantes de esto son:
- Para personas demasiado acostumbradas a trabajar con lenguajes al nivel de C o más bajos, trabajar con un ensamblador en un entorno nativo a la orientación a objetos hace mucho más fácil entender a cabalidad cómo funciona realmente la orientación a objetos, en este caso, de Java.
- Dado que Java es una plataforma unificada sin importar el hardware sobre el que corra, estudiarlo a nivel de ensamblador es una oportunidad excepcionalmente buena para practicar la ingeniería inversa y obtener un nivel de experticia por lo menos intermedio.
- Siendo expertos en el ensamblador de Java y en el formato de archivos de bytecode (.class), así como en el uso de las diferentes APIs y teniendo experticia suficiente para escribir un compilador no optimizador como mínimo, se puede dejar de usar el lenguaje Java para producir programas de Java, y eventualmente es posible usar virtualmente cualquier otro lenguaje de programación (incluso ensamblador de Intel x86, e incluso enmascarando las APIs de Java para usarlas como "alias" de otras plataformas como WinAPI o javascript, y así "recortar" un poco lo que se necesita aprender, y unificar un mismo conocimiento en diferentes ambientes de desarrollo). Esto puede llegar a ser especialmente útil, porque significaría que muchos programas escritos lenguajes que tradicinalmente tienen poca o ninguna portabilidad entre plataformas de hardware pueden reutilizarse, convirtiéndolos en instrucciones de bytecode de Java.
- El ensamblador de Java es extremadamente valioso. Los lenguajes de ensamblador "normales" son evitados por la mayoría de programadores no solo por su complejidad, sino que por el hecho de que no están pensados para ser portables. Con Java, los programas generados son más simples que los ejecutables ELF de Linux, y el ensamblador que se escriba en una plataforma, puede correr en cualquier otra en la que haya una JVM. Eso significa que se pueden hacer tareas interesantes de muy bajo nivel, que al mismo tiempo incluyan programación "moderna" orientada a objetos, con la posibilidad de poder seguir corriendo el mismo código en otras plataformas.
Todo esto suena muy interesante, pero para lograrlo, siendo indistintamente buenos programadores de C/ensamblador por ejemplo, o buenos programadores de Java (aunque a un nivel común y corriente, no a nivel de ensamblador y de la arquitectura central), este proceso puede llevar no menos de un año, durante el que hay que releer cosas como el Tutorial de Java, compilar los programas de ejemplo, hacer ingeniería inversa intensa y desensamblarlos (NO decompilarlos, sino que inspeccionar los archivos binarios a mano si es posible y/o hacer un parser), y leer una y otra vez las partes de las especificaciones que se están aplicando en cada ejemplo compilado.
------------------------------------------------------
------------------------------------------------------
------------------------------------------------------
------------------------------------------------------
Pongo un ejemplo simple de un Hola Mundo, como el del Tutorial de Java, pero en Ensamblador de Java.
No he usado un ensamblador nativo de Java "apropiado" sino que NASM, que entre otras cosas no permite usar Big Endian (Java) sino solo Little Endian (x86), así que se ve rápidamente la necesidad de usar un programa ensamblador ya sea de ARM que use Big Endian por defecto, crear un ensamblador propio para Java (en javascript por ejemplo), o buscar un ensamblador "apropiado" nativo a Java.
Esto debe compilarse con lo siguiente, ya sea en Windows, Linux, etc.:
nasm EHLOWorldApp.asm -o EHLOWorldApp.class
;/*****************************************************************************
;EHLOWorldApp.java
;
; 2012-07-02
;
;
;Demostración inicial de un programa de Java escrito totalmente en ensamblador
;(ensamblador de Java, pero usando NASM para codificar los bytes).
;
;http://devel.cable-modem.org/
;
;Este código es de dominio público (sin derechos de autor).
;Puedes hacer lo que desees con él.
;
;
;*****************************************************************************/
_CLASS_START:
_00000000__magic db 0xCA,0xFE,0xBA,0xBE
_00000004__minor_version dw 0x0000
_00000006__major_version db 0x00,0x33
_00000008__constant_pool_count db 0,29+1
    _0000000A__cp_info_0001:
                           db 0x0A    ;cp_info.tag: CONSTANT_Methodref
                           db 0,0x06  ;cp_info.info.class_index
                           db 0,0x0F  ;cp_info.info.name_and_type_index
    _0000000F__cp_info_00002:
                           db 0x09    ;cp_info.tag: CONSTANT_Fieldref
                           db 0,0x10  ;cp_info.info.class_index
                           db 0,0x11  ;cp_info.info.name_and_type_index
    _00000014__cp_info_0003:
                           db 0x08    ;cp_info.tag: CONSTANT_String
                           db 0,0x12  ;cp_info.info.string_index
    _00000017__cp_info_0004:
                           db 0x0A    ;cp_info.tag: CONSTANT_Methodref
                           db 0,0x13  ;cp_info.info.class_index
                           db 0,0x14  ;cp_info.info.name_and_type_index
    _0000001C__cp_info_0005:
                           db 0x07    ;cp_info.tag: CONSTANT_Class
                           db 0,0x15  ;cp_info.info.name_index
    _0000001F__cp_info_0006:
                           db 0x07    ;cp_info.tag: CONSTANT_Class
                           db 0,0x16  ;cp_info.info.name_index
    _00000022__cp_info_0007:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x06   ;cp_info.info.length
                           db "<init>" ;cp_info.info.bytes[length]
    _0000002B__cp_info_0008:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x03   ;cp_info.info.length
                           db "()V"    ;cp_info.info.bytes[length]
    _00000031__cp_info_0009:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x04   ;cp_info.info.length
                           db "Code"   ;cp_info.info.bytes[length]
    _00000038__cp_info_000A:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x0F   ;cp_info.info.length
                           db "LineNumberTable"   ;cp_info.info.bytes[length]
    _0000004A__cp_info_000B:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x04   ;cp_info.info.length
                           db "main"   ;cp_info.info.bytes[length]
    _00000051__cp_info_000C:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x16   ;cp_info.info.length
                           db "([Ljava/lang/String;)V"   ;cp_info.info.bytes[length]
    _0000006A__cp_info_000D:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x0A   ;cp_info.info.length
                           db "SourceFile"   ;cp_info.info.bytes[length]
    _00000077__cp_info_000E:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x11   ;cp_info.info.length
                           db "EHLOWorldApp.java"   ;cp_info.info.bytes[length]
    _0000008B__cp_info_000F:
                           db 0x0C     ;cp_info.tag: CONSTANT_NameAndType
                           db 0,0x07   ;cp_info.info.name_index
                           db 0,0x08   ;cp_info.info.descriptor_index
    _00000090__cp_info_0010:
                           db 0x07    ;cp_info.tag: CONSTANT_Class
                           db 0,0x17  ;cp_info.info.name_index
    _00000093__cp_info_0011:
                           db 0x0C     ;cp_info.tag: CONSTANT_NameAndType
                           db 0,0x18   ;cp_info.info.name_index
                           db 0,0x19   ;cp_info.info.descriptor_index
    _00000098__cp_info_0012:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x0C   ;cp_info.info.length
                           db "Hello World."   ;cp_info.info.bytes[length]
    _000000A6__cp_info_0013:
                           db 0x07    ;cp_info.tag: CONSTANT_Class
                           db 0,0x1A  ;cp_info.info.name_index
    _000000A9__cp_info_0014:
                           db 0x0C     ;cp_info.tag: CONSTANT_NameAndType
                           db 0,0x1B   ;cp_info.info.name_index
                           db 0,0x1C   ;cp_info.info.descriptor_index
    _000000AE__cp_info_0015:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x0C   ;cp_info.info.length
                           db "EHLOWorldApp"   ;cp_info.info.bytes[length]
    _000000BD__cp_info_0016:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x10   ;cp_info.info.length
                           db "java/lang/Object"   ;cp_info.info.bytes[length]
    _000000D0__cp_info_0017:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x10   ;cp_info.info.length
                           db "java/lang/System"   ;cp_info.info.bytes[length]
    _000000E3__cp_info_0018:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x03   ;cp_info.info.length
                           db "out"   ;cp_info.info.bytes[length]
    _000000E9__cp_info_0019:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x15   ;cp_info.info.length
                           db "Ljava/io/PrintStream;"   ;cp_info.info.bytes[length]
    _00000101__cp_info_001A:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x13   ;cp_info.info.length
                           db "java/io/PrintStream"   ;cp_info.info.bytes[length]
    _00000117__cp_info_001B:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x07   ;cp_info.info.length
                           db "println"   ;cp_info.info.bytes[length]
    _00000121__cp_info_001C:
                           db 0x01     ;cp_info.tag: CONSTANT_Utf8
                           db 0,0x15   ;cp_info.info.length
                           db "(Ljava/lang/String;)V"   ;cp_info.info.bytes[length]
                        __1D:
                           db 0x08    ;cp_info.tag: CONSTANT_String
                           db 0,0x12  ;cp_info.info.string_index
_00000139__access_flags:
                       db 0x00,0x20
_0000013B__this_class:
                       db 0x00,0x05
_0000013D__super_class:
                       db 0x00,0x06
_0000013F__interfaces_count:
                       db 0x00,0x00
;interfaces ------- no interfaces
_00000141__fields_count:
                       db 0x00,0x00
;field_info ------- no fields
_00000143__methods_count:
                       db 0x00,0x02
        _00000145__method_info_0001:
                               db 0x00,0x00     ;access_flags
                               db 0x00,0x07     ;name_index
                               db 0x00,0x08     ;descriptor_index
                               db 0x00,0x01     ;attributes_count
                                   db 0x00,0x09   ;code_attribute/attribute_info[0].attribute_name_index
                                   db 0x00,0x00,0x00,(0x1D)   ;code_attribute/attribute_info[0].attribute_length
                                   db 0X00,0X01       ;code_attribute.max_stack
                                   db 0X00,0X01       ;code_attribute.max_locals
                                   db 0X00,0X00,0X00,0X05   ;code_attribute.code_length
                                      ;INIT: Instructions
                                      ;INIT: Instructions
                                      ;INIT: Instructions
                                      ;INIT: Instructions
                                        db 0X2A         ;aload_0
                                        db 0XB7         ;invokespecial #1
                                        db 0X00
                                        db 0X01
                                        db 0XB1         ;return
                                      ;END: Instructions
                                      ;END: Instructions
                                      ;END: Instructions
                                      ;END: Instructions
                                   db 0X00,0X00    ;code_attribute.exception_table_length
                                   db 0X00,0x01    ;code_attribute.attributes_count       ;1
                                       db 0X00,0X0A             ;LineNumberTable_attribute/attribute_info.attribute_name_index
                                       db 0X00,0X00,0X00,0X06   ;LineNumberTable_attribute/attribute_info.attribute_length
                                           db 0X00,0X01       ;LineNumberTable_attribute.line_number_table_length
                                               db 0X00,0X00       ;line_number_table[0].start_pc
                                               db 0X00,0X05       ;line_number_table[0].line_number
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        _00000170__method_info_0002:
                               db 0x00,0x09     ;access_flags
                               db 0x00,0x0B     ;name_index
                               db 0x00,0x0C     ;descriptor_index
                               db 0x00,0x01     ;attributes_count
                                   db 0x00,0x09   ;code_atribute/attribute_info[0].attribute_name_index
                                   db 0x00,0x00,0x00,(0x25)   ;code_atribute/attribute_info[0].attribute_length
x17E:
                                   db 0x00,0x02      ;code_attribute.max_stack
                                   db 0x00,0x01      ;code_attribute.max_locals
                                   db 0x00,0x00,0x00,(0x09)  ;code_attribute.code_length
                                      ;INIT: Instructions
                                      ;INIT: Instructions
                                      ;INIT: Instructions
                                      ;INIT: Instructions
                                        db 0xB2      ;getstatic #2
                                        db 0x00
                                        db 0x02
                                        db 0x12      ;ldc #3
                                        db 0x1D
                                        db 0xB6      ;invokevirtual #4
                                        db 0x00
                                        db 0x04
                                        db 0xB1      ;return
                                      ;END: Instructions
                                      ;END: Instructions
                                      ;END: Instructions
                                      ;END: Instructions
                                   db 0x00,0x00      ;code_attribute.exception_table_length
                                   db 0x00,0x01      ;code_attribute.attributes_count    ;1
                                       db 0x00,0x0A              ;LineNumberTable_attribute/attrbute_info.attribute_name_index
                                       db 0x00,0x00,0x00,0x0A    ;LineNumberTable_attribute/attribute_info.attribute_length
                                             db 0x00,0x02       ;LineNumberTable_attribute.line_number_table_length
                                                 db 0x00,0x00       ;line_number_table[0].start_pc
                                                 db 0x00,0x07       ;line_number_table[0].line_number
                                                 db 0x00,0x08       ;line_number_table[1].start_pc
                                                 db 0x00,0x08       ;line_number_table[1].line_number
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
f_000001A3__attributes_count db 0x00,0x01     ;attributes_count           ;1
                                db 0x00,0x0D   ;SourceFile_attribute/attribute_info[0].attribute_name_index
                                db 0x00,0x00,0x00,0x02   ;SourceFile_attribute/attribute_info[0].attribute_length
                                db 0x00,0x0E         ;SourceFile_attribute.sourcefile_index
Y el código equivalente en Java normal:
class EHLOWorldApp
{
 public static void main(String[] args)
 {
  System.out.println("Hello World.");
 }
}
Planeo poco a poco documentar y explicar lo que está pasando, aunque ya que he comentado prácticamente todas las líneas en ensamblador, obviamente entiendo lo que está pasando.
Aunque necesito formalizar las explicaciones, porque voy a necesitarlo cuando trate escribir un ensamblador especial para Java y cuando quiera implementar un compilador de un lenguaje que no sea Java, pero que produzca programas para Java.
------------------------------------------------------
------------------------------------------------------
------------------------------------------------------
------------------------------------------------------
Referencias
Seguir las especificaciones es relativamente fácil para quienes, como yo, están acostumbrados a examinar de forma permanente la estructura de todos los archivos en su computadora, a hacer encajar exactamente cada pieza de un programa en ensamblador (lo que permite encontrar mucho más rápidamente la causa de errores causados por dos o más valores interdependientes) y a pensar en términos de cómo las especificaciones combinan los datos requeridos para una tarea en estructuras de todo tipo (y teniendo en mente qué pudieron haber estado pensando los desarrolladores de dichos estándares para hacer las cosas de la forma en que las hicieron de entre muchos diseños posibles e incluso mucho más simplificados).
Como dije, una de las intenciones principales de todo esto es eventualmente poder escribir programas de Java con lenguajes "normales", como C, Visual Basic, Pascal, etc.
Pero para eso se necesita tener gran experticia en el ensamblador de Java, y en la estructura de bajo nivel del lenguaje, las clases, y todos los demás aspectos de la máquina virtual de Java, para poder crear equivalentes para hacer que de un lenguaje no oficial se pueda producir bytecode apropiado y totalmente correcto.
Esta es la lista de lo que hay que empezar a leer, y no hay que olvidar tampoco las referencias de las diferentes APIs, y también el tutorial de Java, que sería extremadamente interesante "remasterizar" en su versión en ensamblador Java, para comprender cada detalle de lo que contiene y hacer posible que se convierta en un libro de alto nivel capaz de volver a un programador en un experto absoluto en Java, ya sea programando en alto nivel o en el nivel más bajo posible:
Especificaciones de bajo nivel de Java (http://docs.oracle.com/javase/specs/)
El capítulo 4 habla específicamente del formato de los archivos .class
Wikipedia: Formato de los archivos .class (http://en.wikipedia.org/wiki/Java_class_file)
Wikipedia: Resumen del bytecode de Java (http://en.wikipedia.org/wiki/Java_bytecode)
Wikipedia: Resumen del conjunto de instrucciones de Java (http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings)
También vale la pena mencionar el comando básico del desensamblador del JDK:
javap -c EHLOWorldApp.class
			
			
			
				Dejo otro ejemplo interesante
Con macros de fasm para poder programar mas facil.
http://board.flatassembler.net/topic.php?t=13961
T_BOOLEAN = 4
T_CHAR	  = 5
T_FLOAT   = 6
T_DOUBLE  = 7
T_BYTE	  = 8
T_SHORT   = 9
T_INT	  = 10
T_LONG	  = 11
macro aaload { db 0x32 }
macro aastore { db 0x53 }
macro aconst_null { db 0x01 }
macro aload index { if index>=0 & index<=3
		      db 0x2a+index
		    else if index<100h
		      db 0x19,index
		    else
		      db 0xc4,0x19,(index) shr 8,(index) and 0FFh
		    end if }
macro anewarray class { db 0xbd,(class) shr 8,(class) and 0FFh }
macro areturn { db 0xb0 }
macro arraylength { db 0xbe }
macro astore index { if index>=0 & index<=3
		       db 0x4b+index
		     else if index<100h
		       db 0x3a,index
		     else
		       db 0xc4,0x3a,(index) shr 8,(index) and 0FFh
		     end if }
macro athrow { db 0xbf }
macro baload { db 0x33 }
macro bastore { db 0x54 }
macro bipush byte { if byte>-1 & byte<=5
		     db 0x03+byte
		    else
		     db 0x10,byte
		    end if }
macro caload { db 0x34 }
macro castore { db 0x55 }
macro checkcast class { db 0xc0,(class) shr 8,(class) and 0FFh }
macro d2f { db 0x90 }
macro d2i { db 0x8e }
macro d2l { db 0x8f }
macro dadd { db 0x63 }
macro daload { db 0x31 }
macro dastore { db 0x52 }
macro dcmpg { db 0x98 }
macro dcmpl { db 0x97 }
macro dconst_0 { db 0x0e }
macro dconst_1 { db 0x0f }
macro ddiv { db 0x6f }
macro dload index { if index>=0 & index<=3
		      db 0x26+index
		    else if index<100h
		      db 0x18,index
		    else
		      db 0xc4,0x18,(index) shr 8,(index) and 0FFh
		    end if }
macro dmul { db 0x6b }
macro dneg { db 0x77 }
macro drem { db 0x73 }
macro dreturn { db 0xaf }
macro dstore index { if index>=0 & index<=3
		       db 0x47+index
		     else if index<100h
		       db 0x39,index
		     else
		       db 0xc4,0x39,(index) shr 8,(index) and 0FFh
		     end if }
macro dsub { db 0x67 }
macro dup { db 0x59 }
macro dup_x1 { db 0x5a }
macro dup_x2 { db 0x5b }
macro dup2 { db 0x5c }
macro dup2_x1 { db 0x5d }
macro dup2_x2 { db 0x5e }
macro f2d { db 0x8d }
macro f2i { db 0x8b }
macro f2l { db 0x8c }
macro fadd { db 0x62 }
macro faload { db 0x30 }
macro fastore { db 0x51 }
macro fcmpg { db 0x96 }
macro fcmpl { db 0x95 }
macro fconst_0 { db 0x0b }
macro fconst_1 { db 0x0c }
macro fconst_2 { db 0x0d }
macro fdiv { db 0x6e }
macro fload index { if index>=0 & index<=3
		      db 0x22+index
		    else if index<100h
		      db 0x17,index
		    else
		      db 0xc4,0x17,(index) shr 8,(index) and 0FFh
		    end if }
macro fmul { db 0x6a }
macro fneg { db 0x76 }
macro frem { db 0x72 }
macro freturn { db 0xae }
macro fstore index { if index>=0 & index<=3
		       db 0x43+index
		     else if index<100h
		       db 0x38,index
		     else
		       db 0xc4,0x38,(index) shr 8,(index) and 0FFh
		     end if }
macro fsub { db 0x66 }
macro getfield index { db 0xb4,(index) shr 8,(index) and 0FFh }
macro getstatic index { db 0xb2,(index) shr 8,(index) and 0FFh }
macro goto branch { if branch-$>=-8000h & branch-$<8000h
		      offset = word branch-$
		      db 0xa7,(offset) shr 8,(offset) and 0FFh
		    else
		      offset = dword branch-$
		      db 0xc8,(offset) shr 24,((offset) shr 16) and 0FFh,((offset) shr 8) and 0FFh,(offset) and 0FFh
		    end if }
macro goto_w branch { offset = dword branch-$
		      db 0xc8,(offset) shr 24,((offset) shr 16) and 0FFh,((offset) shr 8) and 0FFh,(offset) and 0FFh }
macro i2b { db 0x91 }
macro i2c { db 0x92 }
macro i2d { db 0x87 }
macro i2f { db 0x86 }
macro i2l { db 0x85 }
macro i2s { db 0x93 }
macro iadd { db 0x60 }
macro iaload { db 0x2e }
macro iand { db 0x7e }
macro iastore { db 0x4f }
macro iconst_m1 { db 0x02 }
macro iconst_0 { db 0x03 }
macro iconst_1 { db 0x04 }
macro iconst_2 { db 0x05 }
macro iconst_3 { db 0x06 }
macro iconst_4 { db 0x07 }
macro iconst_5 { db 0x08 }
macro idiv { db 0x6c }
macro if_acmpeq branch { offset = word branch-$
			 db 0xa5,(offset) shr 8,(offset) and 0FFh }
macro if_acmpne branch { offset = word branch-$
			 db 0xa6,(offset) shr 8,(offset) and 0FFh }
macro if_icmpeq branch { offset = word branch-$
			 db 0x9f,(offset) shr 8,(offset) and 0FFh }
macro if_icmpne branch { offset = word branch-$
			 db 0xa0,(offset) shr 8,(offset) and 0FFh }
macro if_icmplt branch { offset = word branch-$
			 db 0xa1,(offset) shr 8,(offset) and 0FFh }
macro if_icmpge branch { offset = word branch-$
			 db 0xa2,(offset) shr 8,(offset) and 0FFh }
macro if_icmpgt branch { offset = word branch-$
			 db 0xa3,(offset) shr 8,(offset) and 0FFh }
macro if_icmple branch { offset = word branch-$
			 db 0xa4,(offset) shr 8,(offset) and 0FFh }
macro ifeq branch { offset = word branch-$
		    db 0x99,(offset) shr 8,(offset) and 0FFh }
macro ifne branch { offset = word branch-$
		    db 0x9a,(offset) shr 8,(offset) and 0FFh }
macro iflt branch { offset = word branch-$
		    db 0x9b,(offset) shr 8,(offset) and 0FFh }
macro ifge branch { offset = word branch-$
		    db 0x9c,(offset) shr 8,(offset) and 0FFh }
macro ifgt branch { offset = word branch-$
		    db 0x9d,(offset) shr 8,(offset) and 0FFh }
macro ifle branch { offset = word branch-$
		    db 0x9e,(offset) shr 8,(offset) and 0FFh }
macro ifnonnull branch { offset = word branch-$
			 db 0xc7,(offset) shr 8,(offset) and 0FFh }
macro ifnull branch { offset = word branch-$
		      db 0xc6,(offset) shr 8,(offset) and 0FFh }
macro iinc index,const { if index<100h & const<80h & const>=-80h
			   db 0x84,index,const
			 else
			   db 0xc4,0x84,(index) shr 8,(index) and 0FFh,(const) shr 8,(const) and 0FFh
			 end if }
macro iload index { if index>=0 & index<=3
		      db 0x1a+index
		    else if index<100h
		      db 0x15,index
		    else
		      db 0xc4,0x15,(index) shr 8,(index) and 0FFh
		    end if }
macro imul { db 0x68 }
macro ineg { db 0x74 }
macro instanceof index { db 0xc1,(index) shr 8,(index) and 0FFh }
macro invokedynamic index { db 0xba,(index) shr 8,(index) and 0FFh,0,0 }
macro invokeinterface index,count { db 0xb9,(index) shr 8,(index) and 0FFh,count }
macro invokespecial index { db 0xb7,(index) shr 8,(index) and 0FFh }
macro invokestatic index { db 0xb8,(index) shr 8,(index) and 0FFh }
macro invokevirtual index { db 0xb6,(index) shr 8,(index) and 0FFh }
macro ior { db 0x80 }
macro irem { db 0x70 }
macro ireturn { db 0xac }
macro ishl { db 0x78 }
macro ishr { db 0x7a }
macro istore index { if index>=0 & index<=3
		       db 0x3b+index
		     else if index<100h
		       db 0x36,index
		     else
		       db 0xc4,0x36,(index) shr 8,(index) and 0FFh
		     end if }
macro isub { db 0x64 }
macro iushr { db 0x7c }
macro ixor { db 0x82 }
macro jsr branch { if branch-$>=-8000h & branch-$<8000h
		     offset = word branch-$
		     db 0xa8,(offset) shr 8,(offset) and 0FFh
		   else
		     offset = dword branch-$
		     db 0xc9,(offset) shr 24,((offset) shr 16) and 0FFh,((offset) shr 8) and 0FFh,(offset) and 0FFh
		   end if }
macro jsr_w branch { offset = dword branch-$
		     db 0xc9,(offset) shr 24,((offset) shr 16) and 0FFh,((offset) shr 8) and 0FFh,(offset) and 0FFh }
macro l2d { db 0x8a }
macro l2f { db 0x89 }
macro l2i { db 0x88 }
macro ladd { db 0x61 }
macro laload { db 0x2f }
macro land { db 0x7f }
macro lastore { db 0x50 }
macro lcmp { db 0x94 }
macro lconst_0 { db 0x09 }
macro lconst_1 { db 0x0a }
macro ldc index { if index<100h
		   db 0x12,index
		  else
		   db 0x13,(index) shr 8,(index) and 0FFh
		  end if}
macro ldc_w index { db 0x13,(index) shr 8,(index) and 0FFh }
macro ldc2_w index { db 0x14,(index) shr 8,(index) and 0FFh }
macro ldiv { db 0x6d }
macro lload index { if index>=0 & index<=3
		      db 0x1e+index
		    else if index<100h
		      db 0x16,index
		    else
		      db 0xc4,0x16,(index) shr 8,(index) and 0FFh
		    end if }
macro lmul { db 0x69 }
macro lneg { db 0x75 }
; macro lookupswitch { db 0xab,... }
macro lor { db 0x81 }
macro lrem { db 0x71 }
macro lreturn { db 0xad }
macro lshl { db 0x79 }
macro lshr { db 0x7b }
macro lstore index { if index>=0 & index<=3
		       db 0x3f+index
		     else if index<100h
		       db 0x37,index
		     else
		       db 0xc4,0x37,(index) shr 8,(index) and 0FFh
		     end if }
macro lsub { db 0x65 }
macro lushr { db 0x7d }
macro lxor { db 0x83 }
macro monitorenter { db 0xc2 }
macro monitorexit { db 0xc3 }
macro multianewarray index,dimensions { db 0xc5,(index) shr 8,(index) and 0FFh,dimensions }
macro new index { db 0xbb,(index) shr 8,(index) and 0FFh }
macro newarray atype { db 0xbc,atype }
macro nop { db 0x00 }
macro pop { db 0x57 }
macro pop2 { db 0x58 }
macro putfield index { db 0xb5,(index) shr 8,(index) and 0FFh }
macro putstatic index { db 0xb3,(index) shr 8,(index) and 0FFh }
macro ret index { if index<100h
		    db 0xa9,index
		  else
		    db 0xc4,(index) shr 8,(index) and 0FFh
		  end if }
macro return { db 0xb1 }
macro saload { db 0x35 }
macro sastore { db 0x56 }
macro sipush short { db 0x11,(short) shr 8,(short) and 0FFh }
macro swap { db 0x5f }
; macro tableswitch { db 0xaa,... }
macro breakpoint { db 0xca }
macro impdep1 { db 0xfe }
macro impdep2 { db 0xff }
ACC_PUBLIC	 = 0x0001
ACC_PRIVATE	 = 0x0002
ACC_PROTECTED	 = 0x0004
ACC_STATIC	 = 0x0008
ACC_FINAL	 = 0x0010
ACC_SUPER	 = 0x0020
ACC_SYNCHRONIZED = 0x0020
ACC_NATIVE	 = 0x0200
ACC_INTERFACE	 = 0x0200
ACC_ABSTRACT	 = 0x0400
ACC_STRICT	 = 0x0800
macro u1 [v] { db v }
macro u2 [v] { db (v) shr 8,(v) and 0FFh }
macro u4 [v] { db (v) shr 24,((v) shr 16) and 0FFh,((v) shr 8) and 0FFh,(v) and 0FFh }
macro constant_pool {
  u2 constant_pool_count
  constant_pool_counter = 1
  struc constant_utf8 [string] \{
    common
      . = constant_pool_counter
      constant_pool_counter = constant_pool_counter + 1
      local ..data,..length
      u1 1
      u2 ..length
      ..data: db string
      ..length = $ - ..data
  \}
  struc constant_integer value \{
    . = constant_pool_counter
    constant_pool_counter = constant_pool_counter + 1
    u1 3
    u4 value
  \}
  struc constant_float value \{
    . = constant_pool_counter
    constant_pool_counter = constant_pool_counter + 1
    u1 4
    u4 value
  \}
  struc constant_long value \{
    . = constant_pool_counter
    constant_pool_counter = constant_pool_counter + 1
    u1 5
    u4 value shr 32,value and 0FFFFFFFFh
  \}
  struc constant_double value \{
    . = constant_pool_counter
    constant_pool_counter = constant_pool_counter + 1
    u1 6
    u4 value shr 32,value and 0FFFFFFFFh
  \}
  struc constant_class name_index \{
    . = constant_pool_counter
    constant_pool_counter = constant_pool_counter + 1
    u1 7
    u2 name_index
  \}
  struc constant_string string_index \{
    . = constant_pool_counter
    constant_pool_counter = constant_pool_counter + 1
    u1 8
    u2 string_index
  \}
  struc constant_fieldref class_index,name_and_type_index \{
    . = constant_pool_counter
    constant_pool_counter = constant_pool_counter + 1
    u1 9
    u2 class_index
    u2 name_and_type_index
  \}
  struc constant_methodref class_index,name_and_type_index \{
    . = constant_pool_counter
    constant_pool_counter = constant_pool_counter + 1
    u1 10
    u2 class_index
    u2 name_and_type_index
  \}
  struc constant_interfacemethodref class_index,name_and_type_index \{
    . = constant_pool_counter
    constant_pool_counter = constant_pool_counter + 1
    u1 11
    u2 class_index
    u2 name_and_type_index
  \}
  struc constant_nameandtype name_index,descriptor_index \{
    . = constant_pool_counter
    constant_pool_counter = constant_pool_counter + 1
    u1 12
    u2 name_index
    u2 descriptor_index
  \}
}
macro end_constant_pool {
  constant_pool_count = constant_pool_counter
  restruc constant_utf8,constant_integer,constant_float,constant_long,constant_double
  restruc constant_class,constant_string
  restruc constant_fieldref,constant_methodref,constant_interfacemethodref,constant_nameandtype
}
macro interfaces {
  u2 interfaces_count
  interfaces_counter = 0
  macro interface interface \{
    interfaces_counter = interfaces_counter + 1
    u2 interface
  \}
}
macro end_interfaces {
  interfaces_count = interfaces_counter
  purge interface
}
macro attributes {
  local count,counter
  attributes_count equ count
  attributes_counter equ counter
  u2 attributes_count
  attributes_counter = 0
  macro attribute attribute_name_index \{
    attributes_counter = attributes_counter + 1
    u2 attribute_name_index
    local start,length
    attribute_start equ start
    attribute_length equ length
    u4 attribute_length
    attribute_start = $
  \}
  macro end_attribute \{
    attribute_length = $ - attribute_start
    restore atribute_start,attribute_length
  \}
}
macro end_attributes {
  attributes_count = attributes_counter
  restore attributes_count,attributes_counter
  purge attribute
}
macro fields {
  u2 fields_count
  fields_counter = 0
  macro field_info access_flags,name_index,descriptor_index \{
    fields_counter = fields_counter + 1
    u2 access_flags
    u2 name_index
    u2 descriptor_index
    attributes
  \}
  macro end_field_info \{ end_attributes \}
}
macro end_fields {
  fields_count = fields_counter
  purge field_info,end_field_info
}
macro methods {
  u2 methods_count
  methods_counter = 0
  macro method_info access_flags,name_index,descriptor_index \{
    methods_counter = methods_counter + 1
    u2 access_flags
    u2 name_index
    u2 descriptor_index
    attributes
  \}
  macro end_method_info \{ end_attributes \}
}
macro end_methods {
  methods_count = methods_counter
  purge method_info,end_method_info
}
macro bytecode {
  local length
  bytecode_length equ length
  u4 bytecode_length
  bytecode_offset = $
  org 0
}
macro end_bytecode {
  bytecode_length = $
  org bytecode_offset+bytecode_length
  restore bytecode_length
}
macro exceptions {
  local length
  exception_table_length equ length
  u2 exception_table_length
  exception_counter = 0
  macro exception start_pc,end_pc,handler_pc,catch_type \{
    exception_counter = exception_counter + 1
    u2 start_pc
    u2 end_pc
    u2 handler_pc
    u2 catch_type
  \}
}
macro end_exceptions {
  exception_table_length = exception_counter
  restore exception_table_length
}
include 'bytecode.inc'
include 'jclass.inc'
format binary as 'class'
  u4 0xcafebabe 		; magic
  u2 0,49			; minor and major version
  constant_pool
	_Code			constant_utf8		'Code'
	_init			constant_utf8		'<init>'
	_main			constant_utf8		'main'
	_void_arrstr		constant_utf8		'([Ljava/lang/String;)V'
	Test_class		constant_class		_Test
	_Test			constant_utf8		'Test'
	Object_init		constant_methodref	Object_class,init_method
	Object_class		constant_class		_Object
	_Object 		constant_utf8		'java/lang/Object'
	init_method		constant_nameandtype	_init,_void
	_void			constant_utf8		'()V'
	System.out		constant_fieldref	System_class,out_field
	System_class		constant_class		_System
	_System 		constant_utf8		'java/lang/System'
	out_field		constant_nameandtype	_out,PrintStream_type
	_out			constant_utf8		'out'
	PrintStream_type	constant_utf8		'Ljava/io/PrintStream;'
	PrintStream_println	constant_methodref	PrintStream_class,println_method
	PrintStream_class	constant_class		_PrintStream
	_PrintStream		constant_utf8		'java/io/PrintStream'
	println_method		constant_nameandtype	_println,_void_str
	_println		constant_utf8		'println'
	_void_str		constant_utf8		'(Ljava/lang/String;)V'
	Integer_toString	constant_methodref	Integer_class,toString_method
	Integer_class		constant_class		_Integer
	_Integer		constant_utf8		'java/lang/Integer'
	toString_method 	constant_nameandtype	_toString,_str_int
	_toString		constant_utf8		'toString'
	_str_int		constant_utf8		'(I)Ljava/lang/String;'
	Hello			constant_string 	_main		; re-use some existing UTF-8 sequences
	Hello_again		constant_string 	_void_arrstr	; for demonstration purposes
	number			constant_integer	1234
  end_constant_pool
  u2 ACC_PUBLIC+ACC_SUPER	; access flags
  u2 Test_class 		; this class
  u2 Object_class		; super class
  interfaces
  end_interfaces
  fields
  end_fields
  methods
     method_info ACC_PUBLIC, _init, _void				; public void Test()
       attribute _Code
	 u2 1 ; max_stack
	 u2 1 ; max_locals
	 bytecode
		aload 0
		invokespecial Object_init
		return
	 end_bytecode
	 exceptions
	 end_exceptions
	 attributes
	 end_attributes
       end_attribute
     end_method_info
     method_info ACC_PUBLIC+ACC_STATIC, _main, _void_arrstr		; public static void main(String[] args)
       attribute _Code
	 u2 3 ; max_stack
	 u2 1 ; max_locals
	 bytecode
		getstatic System.out		; load value of System.out on top of the stack
		dup				; duplicate, we are going to use it twice
		ldc Hello
		invokevirtual PrintStream_println
		ldc Hello_again
		invokevirtual PrintStream_println
		return
	 end_bytecode
	 exceptions
	 end_exceptions
	 attributes
	 end_attributes
       end_attribute
     end_method_info
  end_methods
  attributes
  end_attributes