Reverse Engineering for Beginners

(avery) #1

CHAPTER 6.PRINTF()WITH SEVERAL ARGUMENTS CHAPTER 6.PRINTF()WITH SEVERAL ARGUMENTS


The result is somewhat unusual:


Listing 6.9: Optimizing Keil 6/2013 (ARM mode)

.text:00000014 main
.text:00000014 03 30 A0 E3 MOV R3, #3
.text:00000018 02 20 A0 E3 MOV R2, #2
.text:0000001C 01 10 A0 E3 MOV R1, #1
.text:00000020 1E 0E 8F E2 ADR R0, aADBDCD ; "a=%d; b=%d; c=%d\n"
.text:00000024 CB 18 00 EA B __2printf


This is the optimized (-O3) version for ARM mode and this time we seeBas the last instruction instead of the familiar
BL. Another difference between this optimized version and the previous one (compiled without optimization) is the lack of
function prologue and epilogue (instructions preserving theR0andLRregisters values). TheBinstruction just jumps to
another address, without any manipulation of theLRregister, similar toJMPin x86. Why does it work? Because this code
is, in fact, effectively equivalent to the previous. There are two main reasons: 1) neither the stack norSP(thestack pointer)
is modified; 2) the call toprintf()is the last instruction, so there is nothing going on afterwards. On completion, the
printf()function simply returns the control to the address stored inLR. Since theLRcurrently stores the address of
the point from where our function was called then the control fromprintf()will be returned to that point. Therefore
we do not need to saveLRbecause we do not need to modifyLR. And we do not need to modifyLRbecause there are no
other function calls exceptprintf(). Furthermore, after this call we do not to do anything else! That is the reason such
optimization is possible.


This optimization is often used in functions where the last statement is a call to another function.


A similar example is presented here:13.1.1 on page 144.


ARM64


Non-optimizing GCC (Linaro) 4.9


Listing 6.10: Non-optimizing GCC (Linaro) 4.9

.LC1:
.string "a=%d; b=%d; c=%d"
f2:
; save FP and LR in stack frame:
stp x29, x30, [sp, -16]!
; set stack frame (FP=SP):
add x29, sp, 0
adrp x0, .LC1
add x0, x0, :lo12:.LC1
mov w1, 1
mov w2, 2
mov w3, 3
bl printf
mov w0, 0
; restore FP and LR
ldp x29, x30, [sp], 16
ret


The first instruction STP (Store Pair) savesFP(X29) andLR(X30) in the stack. The secondADD X29, SP, 0instruction
forms the stack frame. It is just writing the value ofSPinto X29.


Next, we see the familiarADRP/ADDinstruction pair, which forms a pointer to the string. lo12meaning low 12 bits, i.e.,
linker will write low 12 bits of LC1 address into the opcode ofADDinstruction.


%dinprintf()string format is a 32-bitint, so the 1, 2 and 3 are loaded into 32-bit register parts.


Optimizing GCC (Linaro) 4.9 generates the same code.


6.2.2 ARM: 8 arguments.


Let’s use again the example with 9 arguments from the previous section:6.1.2 on page 42.


#include <stdio.h>


int main()
{

Free download pdf