Machine code (little endian pairs):
a005 22ba 0852 bf2c 2162 2142 de11 de00
d001 de3b d1f6 4770 6675 6166 6f6c 00
Commented assembly:
// Include ThumbGolf wrapper macros
.include "thumbgolf.inc"
.globl main
.thumb_func
main:
// r0 = "uffalo"
adr r0, .Luffalo
// Bitmask representing the case of the B.
// 0 = B, 1 = b, little endian bit order.
// Also allows us to determine the length.
// This fits perfectly into a narrow movs.
// bBbbbBbB
movs r2, #0b10111010
.Lloop:
// Read a bit from the bitmask into the carry flag by shifting right.
// Also detects when we have read all of the bits: lsrs will set the
// zero flag.
lsrs r2, r2, #1
// r1 = (r2 & 1) ? 'b' : 'B'
ite cs
movcs r1, #'b'
movcc r1, #'B'
// print either 'b' or 'B'
putc r1 // udf #0021
// print "uffalo" (w/o newline)
puts r0 // udf #0000
// Yes, none of the output instructions affect the flags despite using
// stdio AND executing the stdio call on the main thread (since stdio in
// signal handlers is unsafe), and this is proof.
//
// If the bitmask is zero, exit.
it eq
bxeq lr
// Use the "put special" instruction to print a space.
putspc ' ' // udf #0073
// More flexing that the flags are preserved, it is just as good to do
// `b .Lloop`.
// The proof is that this won't crash, since the ASCII as code will store
// random garbage to uninitialized registers.
bne .Lloop
// string literal
.Luffalo:
.asciz "uffalo"
Mostly a demo to show how ThumbGolf preserves the condition flags on output instructions.
I could do the same thing with cbz
and an unconditional b
, but this is a nice party trick.
As I explained in the code, I use a bitmask to control whether Buffalo
or buffalo
is printed. It just happens to be a perfect 8-bit constant for movs
.