Other Features

Comments The Doukutsu Assembler accepts 3 types of comments. They are shown below.
    NOP   ;Assembly style semicolon comments
    NOP   //C++ style double slash comments
    NOP   /* C++ style block
             comments */
Offset Statement Put the word offset somewhere in your code, and follow it up with a numerical address. This determines exactly where you want your code to be written in the game executable (if you choose direct assemble). Direct assemble only overwrites the old code; it does not insert any bytes (i.e. it doesn't increase the size of the executable). You must use the offset statement exactly once in each ASM source file. If you want to compile different pieces of code at multiple offsets, you need to create multiple source files and then do a Multi-File Assemble. Warning: please do not use an offset less than 0x400000, or else bad things may happen to you. Address 0x400000 is considered the first byte of the executable. Decimal Numbers All numbers are assumed to be hex unless otherwise stated. If you want to specify a decimal number, prefix it with a tilde (~).
    ADD EAX,500     ;adds 0x500 to EAX.
    ADD EAX,-500    ;adds 0x-500 to EAX.
    ADD EAX,~500    ;adds 500 (decimal) to EAX.
    ADD EAX,~-500   ;adds -500 (decimal) to EAX.
If you dislike abbreviations, prefixing any number with the word decimal will also work:
    ADD EAX,decimal 500
    ADD EAX,decimal -500
The Data Statement Use the word data followed by hex pairs to insert those hexadecimal bytes directly into your code. Assume you want to NOP out a large area:
    offset 4937F4

    ;fill this space with 256 NOPS (0x90)

    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
    data 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
Or, you can put a null-terminated string into your code:
    offset 4937F4

    ;this says "Profile.dat"
    data 50 72 6f 66 69 6c 65 2e 64 61 74 00
The Pipe Separator The pipe character | is used to write multiple instructions on the same line. This is fairly easy to use. An example follows.
    offset 401030

    push ebp | mov ebp,esp
    push 80
    push 0
    push 499B40
    call 480d30
    add esp,0c
    mov esp,ebp | pop ebp | retn
Note that the indentational editor makes judicious use of pipes to separate instructions and labels. Relativity No, we're not talking about Einstein's theory here. The most common type of jump in x86 assembly is the relative jump. Because of this, all instances of JMP (address), JNE (address), JLE (address), and so on must be converted to relative jumps during the assembling process. OllyDbg does this too. When you enter a jump statement such as JMP 401000, OllyDbg will calculate the distance between the current address and 0x401000 in order to correctly encode the jump statement. Starting from version 1.0 onwards, you can now use relative jumps in your code. Instead of specifying an address or label, you can specify a certain distance (in bytes) and a direction in which to jump. To perform a forward jump of 0x30 bytes, just do JMP ->30. To do a backwards jump of 0x30 bytes, do JMP <-30. As you can see, the forwards arrow operator is -> and the backwards arrow operator is <-. Now, relative jumps will jump a distance relative to the end of the jump, not the beginning of the jump. That means JMP ->0 will jump to the next instruction. It will not jump to itself and perform an infinite loop. The largest possible forward JMP SHORT is 127 bytes forward (0x7F). The largest possible backward JMP SHORT is 128 bytes backwards (0x80). Any jump that travels a longer distance will be a long jump with a 32-bit displacement.
    offset 402000

    jne ->40    ;Jump 0x40 bytes forwards
    jge <-80A   ;Jump 0x80A bytes backwards

    jmp ->7f    ;biggest possible forward JMP SHORT
    jmp <-80    ;biggest possible backwards JMP SHORT

    jmp ->0     ;Jump to next instruction, which is DEC AX
    dec ax

    jmp <-2     ;Jump backwards 2 bytes to the beginning of the JMP instruction,
                ;which creates an infinite loop.
I expect that the feature of relative jumping will not be used very often because it is easier to use JMP (address) or JMP :labelname. Even so, it's good to know that all your direct jumps will eventually be converted to relative jumps anyway. The Prefix Statement Prefixes are special additions to instructions that make them act differently. For example, the REP prefixes will modify how string instructions work. The Doukutsu Assembler now supports the prefix statement. You have to write out the word prefix and then follow it up with the name of the prefix, such as REP or LOCK. Then use a pipe and type in the next command.
    offset 478000

    MOVSB                         ;copies byte from [ESI] to [EDI]
    CMPXCHG8B [4AE000]            ;Typical CMPXCHG8B command.

    prefix REP | MOVSB            ;copies an entire text string.
    prefix LOCK | CMPXCHG8B EAX   ;The infamous F00F
In OllyDbg, prefix REP | MOVSB is simply written as REP MOVSB and prefix LOCK | CMPXCHG8B EAX is written as LOCK CMPXCHG8B EAX. You can also use prefixes to force an instruction with a memory-operand to use a different segment register than the default segment register.
    offset 440500

    MOV EAX,[EBP+8]         //Uses SS register by default.
    MOV EAX,PTR DS:[EBP+8]  //Still uses SS register because
                            //PTR DS: notation is ignored.
    prefix DS | MOV EAX,[EBP+8]   //Forces instruction to use
                                  //segment register DS.
Here is a list of all prefix statements:
Prefix | Equivalent Byte
--- | ---
LOCK | F0
REPNE | F2
REPNZ | F2
REP | F3
REPE | F3
REPZ | F3
SIMD_EXTENSION | 0F
MMX | 0F
SIZE | 66
ADDRESS_SIZE | 67
CS | 2E
DS | 3E
ES | 26
FS | 64
GS | 65
SS | 36
Also, avoid using prefix SIZE because the size-byte is automatically taken care of by the Doukutsu Assembler. Table of Contents