Tutorial on the 'BL Trick' (ASM) + Psuedo Ops
#1
Tutorial on the 'BL Trick' (ASM) + Psuedo Ops

NOTICE: For coders who can already write loops but are dealing with a very large amounts of string data that have to be written from 'scratch' before transferring that data to a spot in dynamic memory.

Let's say you are wanting to make a code that changes the Mii names of your entire Friend Roster for MKWii. After finding a Mii name in dynamic memory to breakpoint, you are left with an address with the following instruction...

Code:
lwz r7, 0x0068 (r4)

The instruction loads the first word of the Mii name. So we can conclude that r4+0x68 = The start of the Mii name. Let's say you want to make a code that will edit in a new Mii Name. You also figured out (through manual editing on Dolphin-memory-engine), that you can go past the 10 character limit. In fact after applying a lot of manual edits in Dolphin-memory-engine, yuou conclude you make a Mii Name as large as 29 characters. So you decided you will write a code applying the Mii Name "01230123012301230123456789905". MKWii uses 16 bit ascii, so in hexadecimal form, that would be 0x0030 0031 0032 0033 0030 0031 0032 0033 0030 0031 0032 0033 0030 0031 0032 0033 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 0039 0030 0035, which is 29 halfwords of data.

A beginner/intermediate coder would have probably no idea how to write this new Mii Name from scratch and then transfer it (via a loop) to dynamic memory. He/she would probably write out a source that pushes/pops the stack and uses a crap-ton of lis+ori instructions to write the Mii Name into the registers, and then finally transfer it to dynamic memory.

This is silly and there's a way around it. It's called the BL Trick. The BL Trick allows the coder to write a string of data without using any registers. You are probably wondering "How is this possible"?

Let's take a look at a very simple example of a BL Trick that writes the value 0x12345678 without using any registers.

Code:
#Branch to the Label & Link
bl the_label

#Write out 0x12345678
.long 0x12345678

#Label Name to branch to
the_label:
mflr r12

If you are unfamiliar with the bl instruction, it stands for Branch & Link. Linking meaning that once the branch has been taken, the very next memory address located after where the bl is at is stored in the Link Register. So let's pretend the 'bl the_label' instruction was executed at address 0x80002400. That means the address/value of 0x80002404 is written to the Link Register while simultaneously the branch to the_label is taken.

The ".long" next to our value is called a pseudo-op. These are not instructions but 'keywords' for your ASM compiler to add in values to a code.

Here are a list of commonly used psuedo-ops~

.byte = byte (example: .byte 0xFF)
.short = halfword (example: .short 0x0102)
.long = word (example: .long 0x80456C04)
.llong = doubleword (example: .llong 0x8000150090323C7C)
.float = float value in it's 32-bit single precision form (example: .float 1 will use a value of 0x3F800000)
.string = ASCII write that auto appends a null byte at the end (example: .string "Hello!")
.space X = X bytes of zero (example: .space 8)
.align 2 = Use this for alignment when needed because the BL trick 'amount' must be word divisible. Just place it at the very end of your BL Trick.


The mflr r12 instruction copies the value of the Link Register into r12. Thus r12 is 'pointing' to the address where the value 0x12345678 is located. Still confused? Maybe taking look at the compiled form of the source shown earlier can help (compiled as a C2 code with no address)

Code:
C2000000 00000002
48000009 12345678
7D8802A6 00000000


48000009 = bl 0x8 (bl the_label)
12345678 = Our value written from scratch via pseudo-op
7D8802A6 = mflr r12


The BL Trick allows you to create empty space in memory and then place data inside said space. Now going back to our Mii Name code, we can use the BL Trick to avoid pushing/popping the stack and not having to lis+ori over and over again.

First thing's first, since we are not pushing/popping the stack, we will need to look beyond our default instruction's address to see what registers we can safely use. For this code (which I have already made in the past), here are the following safe registers to use

r0 (fyi: remember the odd rules about r0, we can't use it as a source register in certain instructions like addi; would be treated as literal zero)
r7 (safe as long as default instruction is at end of source)
r10 thru r12

Alright, the first instruction of our source will be backing up the LR to r0

Code:
#Save LR, fyi: r0 good to use for this instruction
mflr r0

When using the BL trick, we will need to take our written-from-scratch Mii name and transfer it to memory (where our default instruction will load up the first word of the name). Thus we need to create a loop

Code:
#Start of Mii Name is at r4+0x68 (where loop writing starts at)
#Mii Name characters are halfword a piece, loop will transfer a halfword at a time
#Thus use r7 to point to r4+0x66
addi r7, r4, 0x66

Alright, r7 is set, let's make a BL Trick with our new extended Mii Name

Code:
#Use BL Trick to write out Mii Name
bl mii_name

.short 0x0000
.llong 0x0030003100320033
.llong 0x0030003100320033
.llong 0x0030003100320033
.llong 0x0030003100320033
.llong 0x0030003100320033
.llong 0x0034003500360037
.llong 0x0038003900390030
.short 0x0035
.short 0x0000
.short 0x0000

mii_name:
mflr r12

At this point you are probably wondering why there are the 4 .short's.

Regarding the first .short, remember that r12 points to the start of our BL Trick. However since we are going to make a loop to transfer the Mii Name to dynamic memory, we would need to setup the first loading address of that loop to be -0x2 in reference to the start of the Mii Name. Instead of writing an instruction like... 'addi r12, r12, -0x2' to setup the first loading address, we can just add a 'gap' of a halfword of null.

The second .short is pretty much self explanatory. It's the last halfword of our Mii name.

The third .short of null will be used to tell the loop to stop. We could use the CTR to tell the loop how many times to load, but if we ever want a person to use this code with being able to use a custom length on the Mii Name, we must set this null to tell the loop to stop, and for MKWii, all Mii Names end in a halfword of null.

The fourth .short is for alignment. .align 2 would have also worked for us. .short is used in this demonstration to give you a better visual representation for the alignment.

Time to write the loop to transfer the Mii Name to dynamic memory. Remember we setup r7 from earlier...

Code:
the_loop:
lhzu r11, 0x2 (r12) #Load Mii Data from BL Trick
sthu r11, 0x2 (r7) #Store Mii Data to dynamic memory
cmpwi r11, 0 #Check for null halfword (end of Mii Data)
bne+ the_loop #If NOT null, keep loop going

Great, the loop has been written. Restore LR's original value, and put in the default instruction at the very end.

Code:
mtlr r0 #Move to Link Register, this copies r0's value (original LR) to the Link Register
lwz r7, 0x0068 (r4) #Default Instruction

And for an overall view, here's the entire source~

Code:
#Save LR, fyi: r0 good to use for this instruction
mflr r0

#Start of Mii Name is at r4+0x68 (where loop writing starts at)
#Mii Name characters are halfword a piece, loop will transfer a halfword at a time
#Thus use r7 to point to r4+0x66
addi r7, r4, 0x66

#Use BL Trick to write out Mii Name
bl mii_name

.short 0x0000
.llong 0x0030003100320033
.llong 0x0030003100320033
.llong 0x0030003100320033
.llong 0x0030003100320033
.llong 0x0030003100320033
.llong 0x0034003500360037
.llong 0x0038003900390030
.short 0x0035
.short 0x0000
.short 0x0000

mii_name:
mflr r12

the_loop:
lhzu r11, 0x2 (r12) #Load Mii Data from BL Trick
sthu r11, 0x2 (r7) #Store Mii Data to dynamic memory
cmpwi r11, 0 #Check for null halfword (end of Mii Data)
bne+ the_loop #If NOT null, keep loop going

mtlr r0 #Move to Link Register, this copies r0's value (original LR) to the Link Register
lwz r7, 0x0068 (r4) #Default Instruction

Conclusion

And that's the BL Trick. It's a good method to use to take written-from-scratch data and transfer it. If you are dealing with around 6 words or more data, try the BL Trick to see if it cuts down on the length of your compiled code. 

Fyi here's the code that you 're-created' - https://mkwii.com/showthread.php?tid=960 Happy coding!
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)