I was messing around with Java bytecode today for no particular reason. It’s a fairly simple assembly language — stack based so it takes a little getting used to but not hard for anyone who has used an HP calculator. I installed a copy of jasmin from my apt repository and got to work.
I wanted to make a “Hello, world!” that wasn’t completely obvious at first blush, so the plan of attack was to just push all the ascii codes on the stack in reverse order then call System.out.print() on them in a loop. Each iteration checks the loop count, if ok then pop the next code and print it. Here is where the bytecode verifier is a pain in the ass: apparently, the instructions must be executed each time through a loop with the same stacksize, or else you are branded an evil hacker. Very annoying. I could’ve used an array instead but that also takes a bunch of pushes and stores, so I just unrolled the loop. It works, I guess. Code after the jump.
.class Xyz .super java/lang/Object .method public static zyx(C)V .limit stack 2 getstatic java/lang/System/out Ljava/io/PrintStream; iload 0 invokevirtual java/io/PrintStream/print(C)V return .end method .method public static main([Ljava/lang/String;)V .limit stack 14 bipush 10 bipush 0x21 bipush 100 bipush 0x6c bipush 114 dup bipush -3 iadd bipush 0x77 bipush 32 bipush 44 bipush 0x6f bipush 108 dup bipush 101 bipush 72 invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V invokestatic Xyz/zyx(C)V return .end method