Search code examples
assemblyarmstm32

ARM assembly not working without .type macro


I am learning some (ARMv6-M) assembler for an STM32F0 (ARM Cortex M0) microcontroller. For starters, I wrote a script where I initialize register r0 to 0 and r1 to 1, finally, r0 is incremented by 1 in a loop. Using a debugger, i.e. gdb, I can use si to run one step and info reg to output the registers. The assembler code is given below,

.syntax unified
.cpu cortex-m0
.fpu softvfp
.thumb

.global vector_table
.global reset_handler

.type vector_table, %object
vector_table:
    .word _estack
    .word reset_handler

.type reset_handler, %function
reset_handler:
    LDR r0, =0
    LDR r1, =1

    main_loop:
        ADDS r0, r0, 1
    B main_loop

and is based on this excellent tutorial.

When I remove the .type x macros, I don't see any changes in the registers through my debuggers, however according to this stackoverflow post the .type-macro should have no effect.

Why do the register r0 and r1 remain constant when I remove the .type-macros?


Solution

  • .syntax unified
    .cpu cortex-m0
    .fpu softvfp
    .thumb
    
    .global vector_table
    .global reset_handler
    
    .type vector_table, %object
    vector_table:
        .word 0x20001000
        .word reset_handler
    
    .type reset_handler, %function
    reset_handler:
        LDR r0, =0
        LDR r1, =1
    

    with the .type function

    Disassembly of section .text:
    
    00001000 <vector_table>:
        1000:   20001000    andcs   r1, r0, r0
        1004:   00001009    andeq   r1, r0, r9
    
    00001008 <reset_handler>:
        1008:   4800        ldr r0, [pc, #0]    ; (100c <reset_handler+0x4>)
        100a:   4901        ldr r1, [pc, #4]    ; (1010 <reset_handler+0x8>)
        100c:   00000000    andeq   r0, r0, r0
        1010:   00000001    andeq   r0, r0, r1
    

    the vector table for reset has the proper address ORRed with 1 0x1009. If you remove the function declaration

    disassembly of section .text:
    
    00001000 <vector_table>:
        1000:   20001000    andcs   r1, r0, r0
        1004:   00001008    andeq   r1, r0, r8
    
    00001008 <reset_handler>:
        1008:   4800        ldr r0, [pc, #0]    ; (100c <reset_handler+0x4>)
        100a:   4901        ldr r1, [pc, #4]    ; (1010 <reset_handler+0x8>)
        100c:   00000000    andeq   r0, r0, r0
        1010:   00000001    andeq   r0, r0, r1
    

    you get a binary that won't boot on a cortex-m. For thumb you can also use .thumb_func and the next label found is considered a function:

    .thumb_func
    reset_handler:
        LDR r0, =0
        LDR r1, =1
    

    and you are good again, the binary will work:

    so.elf:     file format elf32-littlearm
    
    
    Disassembly of section .text:
    
    00001000 <vector_table>:
        1000:   20001000    andcs   r1, r0, r0
        1004:   00001009    andeq   r1, r0, r9
    
    00001008 <reset_handler>:
        1008:   4800        ldr r0, [pc, #0]    ; (100c <reset_handler+0x4>)
        100a:   4901        ldr r1, [pc, #4]    ; (1010 <reset_handler+0x8>)
        100c:   00000000    andeq   r0, r0, r0
        1010:   00000001    andeq   r0, r0, r1
    

    This is also required for thumb interwork if you want gnu(s linker) to trampoline between functions for you:

    .syntax unified
    .cpu arm7tdmi
    .thumb
    
    .global vector_table
    .global reset_handler
    
    .type vector_table, %object
    vector_table:
        .word 0x20001000
        .word reset_handler
    
    .thumb_func
    reset_handler:
        LDR r0, =0
        LDR r1, =1
        bl hello
    
    .arm
    
    .type hello, %function
    hello:
        b reset_handler
    

    gives

    Disassembly of section .text:
    
    00001000 <vector_table>:
        1000:   20001000    andcs   r1, r0, r0
        1004:   00001009    andeq   r1, r0, r9
    
    00001008 <reset_handler>:
        1008:   4802        ldr r0, [pc, #8]    ; (1014 <hello+0x4>)
        100a:   4903        ldr r1, [pc, #12]   ; (1018 <hello+0x8>)
        100c:   f000 f80e   bl  102c <__hello_from_thumb>
    
    00001010 <hello>:
        1010:   ea000002    b   1020 <__reset_handler_from_arm>
        1014:   00000000    andeq   r0, r0, r0
        1018:   00000001    andeq   r0, r0, r1
        101c:   00000000    andeq   r0, r0, r0
    
    00001020 <__reset_handler_from_arm>:
        1020:   e59fc000    ldr r12, [pc]   ; 1028 <__reset_handler_from_arm+0x8>
        1024:   e12fff1c    bx  r12
        1028:   00001009    andeq   r1, r0, r9
    
    0000102c <__hello_from_thumb>:
        102c:   4778        bx  pc
        102e:   e7fd        b.n 102c <__hello_from_thumb>
        1030:   eafffff6    b   1010 <hello>
        1034:   00000000    andeq   r0, r0, r0
    

    otherwise

    .arm
    
    hello:
        b reset_handler
    

    gives non-functional code

    Disassembly of section .text:
    
    00001000 <vector_table>:
        1000:   20001000    andcs   r1, r0, r0
        1004:   00001009    andeq   r1, r0, r9
    
    00001008 <reset_handler>:
        1008:   4802        ldr r0, [pc, #8]    ; (1014 <hello+0x4>)
        100a:   4903        ldr r1, [pc, #12]   ; (1018 <hello+0x8>)
        100c:   f000 f800   bl  1010 <hello>
    
    00001010 <hello>:
        1010:   ea000002    b   1020 <__reset_handler_from_arm>
        1014:   00000000    andeq   r0, r0, r0
        1018:   00000001    andeq   r0, r0, r1
        101c:   00000000    andeq   r0, r0, r0
    
    00001020 <__reset_handler_from_arm>:
        1020:   e59fc000    ldr r12, [pc]   ; 1028 <__reset_handler_from_arm+0x8>
        1024:   e12fff1c    bx  r12
        1028:   00001009    andeq   r1, r0, r9
        102c:   00000000    andeq   r0, r0, r0
    

    now on a cortex-m you have no arm mode so no interworking, but for the vector table and any other functions in assembly language you want to call from C or other high level you need to have the function declaration.

    The object declaration I have never seen, have been using gnu tools since around the time arm was added and have been doing bare metal boot the chip stuff without needing it...So cant help you there.

    The reason why they are remaining constant is because you hung the chip or forced it into a handler which you didnt define so yet again hung the chip. the processor status should have changed to indicate the fault mode you are in.