Introduction

I had some confusion over the semantic of the word “disassembly”. So this is the next part to make up for that.

For more details on the board I’m operating on, please refer to part 1 and the manual repo.

main.c

#define STM32F103xB
#include "stm32f1xx.h"

void delay(volatile uint32_t count) {
    while(count--);
}

int main(void) {
    // Enable GPIOC clock
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;

    // Configure PC13 as output
    GPIOC->CRH = (GPIOC->CRH & ~0xFF000000) | 0x33000000;

    while(1) {
        GPIOC->ODR ^= (1 << 13);  // Toggle
        delay(2000000);
    }
}

Binary Ninja Decompiled Output

08000000    void delay(uint32_t volatile count) __pure
08000000    {
08000000        uint32_t var_c = count;
08000012        uint32_t i;
08000012
08000012        do
08000012        {
0800000a            i = var_c;
0800000e            var_c = i - 1;
08000012        } while (i);
08000000    }

08000020    void main() __noreturn
08000020    {
08000020        *(uint32_t*)0x40021018 |= 0x10;
0800003e        *(uint32_t*)0x40011004 = (
0800003e            *(uint32_t*)0x40011004 & 0xffffff)
0800003e            | 0x33000000;
0800003e
0800004a        while (true)
0800004a            *(uint32_t*)0x4001100c ^= 0x2000;
08000020    }

// Literal pool (constants stored in flash)
08000058  int32_t data_8000058 = 0x40021000  // RCC base
0800005c  int32_t data_800005c = 0x40011000  // GPIOC base
08000060  int32_t data_8000060 = 0x1e8480    // 2000000 decimal

Disassembly

08000000    void delay(uint32_t volatile count) __pure

08000000  80b4       push    {r7} {__saved_r7}         ; save r7 (frame pointer)
08000002  83b0       sub     sp, #0xc                  ; allocate 12 bytes stack 
08000004  00af       add     r7, sp, #0 {var_10}       ; sp = r7
08000006  7860       str     r0, [r7, #4] {var_c}      ; store count at var_c 
08000008  00bf       nop                               

0800000a  7b68       ldr     r3, [r7, #4] {var_c}      ; r3 = var_c (current count)
0800000c  5a1e       subs    r2, r3, #1                ; r2 = r3 - 1
0800000e  7a60       str     r2, [r7, #4] {var_c}      ; r2 = var_c 
08000010  002b       cmp     r3, #0                    ; compare r3 to 0
08000012  fad1       bne     #0x800000a                ; "Branch to <address> if Not Equal"
													   

08000014  00bf       nop
08000016  00bf       nop
08000018  0c37       adds    r7, #0xc {__saved_r7}     ; r7 += 12
0800001a  bd46       mov     sp, r7                    ; sp = r7 (deallocate)
0800001c  80bc       pop     {r7} {__saved_r7}         ; pop out of stack
0800001e  7047       bx      lr                        ; return 


08000020    void main() __noreturn

08000020  80b5       push    {r7, lr} {var_4} {var_8}                         ; save frame pointer + ret addr as var_4 + var_8
08000022  00af       add     r7, sp, #0 {var_8}                               ; frame ptr 

;Enable GPIOC clock
;RCC->APB2ENR |= RCC_APB2ENR_IOPCEN

08000024  0c4b       ldr     r3, [pc, #0x30]  {data_8000058}  {0x40021000}    ; r3 = 0x40021000 (RCC base)
08000026  9b69       ldr     r3, [r3, #0x18]  {0x40021018}                    ; r3 = RCC->APB2ENR
08000028  0b4a       ldr     r2, [pc, #0x2c]  {data_8000058}  {0x40021000}    ; r2 = 0x40021000
0800002a  43f01003   orr     r3, r3, #0x10                                    ; Set bit 4 (IOCPEN)
0800002e  9361       str     r3, [r2, #0x18]  {0x40021018}                    ; Store r3 = r2

;Config PC13 as output
;GPIOC->CRH = (GPIOC->CRH & ~0xFF000000) | 0x33000000
;*(uint32_t*)0x40011004 = (*(uint32_t*)0x40011004 & 0xffffff) | 0x33000000;

08000030  0a4b       ldr     r3, [pc, #0x28]  {data_800005c}  {0x40011000}    
08000032  5b68       ldr     r3, [r3, #4]  {0x40011004}                       
08000034  23f07f43   bic     r3, r3, #0xff000000                              
08000038  084a       ldr     r2, [pc, #0x20]  {data_800005c}  {0x40011000}    
0800003a  43f04c53   orr     r3, r3, #0x33000000                              
0800003e  5360       str     r3, [r2, #4]  {0x40011004}                       

;GPIOC->ODR ^= (1 << 13)

08000040  064b       ldr     r3, [pc, #0x18]  {data_800005c}  {0x40011000}
08000042  db68       ldr     r3, [r3, #0xc]  {0x4001100c}
08000044  054a       ldr     r2, [pc, #0x14]  {data_800005c}  {0x40011000}
08000046  83f40053   eor     r3, r3, #0x2000
0800004a  d360       str     r3, [r2, #0xc]  {0x4001100c}

;delay
0800004c  0448       ldr     r0, [pc, #0x10]  {0x1e8480}  {data_8000060}                  ;r0 = 0x1e8480 (2000000)
0800004e  fff7d7ff   bl      #delay                                                       ;delay(2000000)
08000052  00bf       nop
08000054  f4e7       b       #0x8000040                                                   ;Jump back to loop's start point


08000056                                                                    00 bf         ;nop                                        ..


08000058  int32_t data_8000058 = 0x40021000      ; RCC base
0800005c  int32_t data_800005c = 0x40011000      ; GPIOC base
08000060  int32_t data_8000060 = 0x1e8480        ; decimal of 2000000 (2 sec)

Processor core registers

The variables’ names make more sense when you read the figure below.

For more details, refer to the Programming Manual, which have full details on the Instruction Set.