Let's step into our instructions from here and examine the orr instruction at 0x1009c:
|-Register group: general------------------------------------------------------------------------------------------------------------------------------------------------| |r0 0x1 1 r1 0x30 48 | |r2 0x15 21 r3 0x0 0 | |r4 0x0 0 r5 0x0 0 | |r6 0x0 0 r7 0x4 4 | |r8 0x0 0 r9 0x0 0 | |r10 0x200ec 131308 r11 0x0 0 | |r12 0x0 0 sp 0x408009c0 0x408009c0 | |lr 0x0 0 pc 0x1009c 0x1009c <print_counter+16> | |cpsr 0x10 16 fpscr 0x0 0 | |fpsid 0x410430f0 1090793712 fpexc 0x40000000 1073741824 | |AFSR0_EL1 0x0 0 AFSR1_EL1 0x0 0 | |DBGDIDR 0x3515f021 890630177 DBGDSAR 0x0 0 | |DBGBVR 0x0 0 DBGBCR 0x0 0 | |DBGWVR 0x0 0 DBGWCR 0x0 0 | |PAR 0x0 0 DBGBVR 0x0 0 | |DBGBCR 0x0 0 DBGWVR 0x0 0 | |DBGWCR 0x0 0 TEECR 0x0 0 | |MIDR_EL1 0x412fc0f1 1093648625 CTR 0x8444c004 -2075869180 | |TCMTR 0x0 0 TTBR0_EL1 0x0 0 | |------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 0x10074 <_start> mov r7, #4 | | 0x10078 <_start+4> mov r0, #1 | | 0x1007c <_start+8> ldr r1, [pc, #96] ; 0x100e4 <exit_normally+12> | | 0x10080 <_start+12> mov r2, #21 | | 0x10084 <_start+16> svc 0x00000000 | | 0x10088 <_start+20> mov r3, #0 | | 0x1008c <print_counter> mov r7, #4 | | 0x10090 <print_counter+4> mov r0, #1 | | 0x10094 <print_counter+8> mov r1, #48 ; 0x30 | | 0x10098 <print_counter+12> add r1, r1, r3 | | > 0x1009c <print_counter+16> orr r1, r1, #2560 ; 0xa00 |
As we step through the instruction we can see that the value of r1 changes from 0x30 to 0x0a30.
It now contains the value for ASCII "0\n"
r1 0xa30 2608
Now lets step to the push instruction:
|-Register group: general------------------------------------------------------------------------------------------------------------------------------------------------|
|r0 0x1 1 r1 0xa30 2608 r2 0x15 21 |
|r3 0x0 0 r4 0x0 0 r5 0x0 0 |
|r6 0x0 0 r7 0x4 4 r8 0x0 0 |
|r9 0x0 0 r10 0x200ec 131308 r11 0x0 0 |
|r12 0x0 0 sp 0x408009c0 0x408009c0 lr 0x0 0 |
|pc 0x100a0 0x100a0 <print_count cpsr 0x10 16 fpscr 0x0 0 |
|fpsid 0x410430f0 1090793712 fpexc 0x40000000 1073741824 AFSR0_EL1 0x0 0 |
|AFSR1_EL1 0x0 0 DBGDIDR 0x3515f021 890630177 DBGDSAR 0x0 0 |
|DBGBVR 0x0 0 DBGBCR 0x0 0 DBGWVR 0x0 0 |
|DBGWCR 0x0 0 PAR 0x0 0 DBGBVR 0x0 0 |
|DBGBCR 0x0 0 DBGWVR 0x0 0 DBGWCR 0x0 0 |
|TEECR 0x0 0 MIDR_EL1 0x412fc0f1 1093648625 CTR 0x8444c004 -2075869180 |
|TCMTR 0x0 0 TTBR0_EL1 0x0 0 PMCCNTR 0x0 0 |
|TLBTR 0x0 0 TTBR1_EL1 0x0 0 MIDR 0x412fc0f1 1093648625 |
|TTBCR 0x0 0 MPIDR_EL1 0x80000000 -2147483648 TTBCR2 0x0 0 |
|REVIDR_EL1 0x0 0 MIDR 0x412fc0f1 1093648625 JIDR 0x0 0 |
|CLIDR 0xa200023 169869347 DFAR 0x0 0 WFAR 0x0 0 |
|IFAR 0x0 0 JMCR 0x0 0 AIDR 0x0 0 |
|CSSELR 0x0 0 ID_PFR2 0x10 16 VBAR 0x0 0 |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 0x10074 <_start> mov r7, #4 |
| 0x10078 <_start+4> mov r0, #1 |
| 0x1007c <_start+8> ldr r1, [pc, #96] ; 0x100e4 <exit_normally+12> |
| 0x10080 <_start+12> mov r2, #21 |
| 0x10084 <_start+16> svc 0x00000000 |
| 0x10088 <_start+20> mov r3, #0 |
| 0x1008c <print_counter> mov r7, #4 |
| 0x10090 <print_counter+4> mov r0, #1 |
| 0x10094 <print_counter+8> mov r1, #48 ; 0x30 |
| 0x10098 <print_counter+12> add r1, r1, r3 |
| 0x1009c <print_counter+16> orr r1, r1, #2560 ; 0xa00 |
| > 0x100a0 <print_counter+20> push {r1} ; (str r1, [sp, #-4]!) |
Notice the value of the sp register before the push:
sp 0x408009c0
Now after the push:
sp 0x408009bc
This is 4 bytes lower than the previous address. Lets examine the data at that address:
(gdb) x /4xb 0x408009bc 0x408009bc: 0x30 0x0a 0x00 0x00
We can see the value of r1 is now at that address.
The instruction mov r1, sp will store that address in r1 to pass to the write syscall.
Let's now examine the cmp instruction at 0x100b4:
The instruction mov r1, sp will store that address in r1 to pass to the write syscall.
Let's now examine the cmp instruction at 0x100b4:
> 0x100b4 <print_counter+40> cmp r3, #9 (gdb) info registers cpsr cpsr 0x10 16 (gdb) si 0x000100b8 in print_counter () (gdb) info registers cpsr cpsr 0x80000010 -2147483632
As we step through the instruction, we can see the value of the flags in cpsr change.
What flags are now set? We could print the value in binary with:
What flags are now set? We could print the value in binary with:
(gdb) print/t 0x80000010 $1 = 10000000000000000000000000010000
This is still difficult to read and determine what flags are set.
We know that the Z, N, C, and V flags are set by the cmp instruction, so let's format the output to show those flags.
Enter the following script to show a formatted output for the flags:
We know that the Z, N, C, and V flags are set by the cmp instruction, so let's format the output to show those flags.
Enter the following script to show a formatted output for the flags:
printf "N=%d Z=%d C=%d V=%d\n", (($cpsr & (1 << 31)) != 0), (($cpsr & (1 << 30)) != 0), (($cpsr & (1 << 29)) != 0), (($cpsr & (1 << 28)) != 0)
This is a script in C-style code which takes the cpsr register value performs a bitwise and operation on a bit that is shifted left
to the position of the corresponding flag bit, if the bit is set, the statement will be non-zero and evaluate true, which will print a 1.
We can see from this script that the negative bit was set by the comparison, because 0 - 9 = -9 which is negative.
We can see from this script that the negative bit was set by the comparison, because 0 - 9 = -9 which is negative.
N=1 Z=0 C=0 V=0
This would be lengthy to type out every time we want to check those flags, so lets open a text editor and save the script as cpsr_cmp.gdb
We can now run the script inside gdb by entering:
We can now run the script inside gdb by entering:
source cpsr_cmp.gdb
This is assuming you placed it in the same path as the current executable.
Otherwise you must use the path to the script.
Otherwise you must use the path to the script.