Assembler ARM32
Assemble first ARM32 program
The program we’ll use is the following:
1 .syntax unified
2 .cpu cortex-m4
3 .thumb
4
5 .word 0x20000400
6 .word 0x08000101
7 .space 0xf8
8
9 .data
10 .word 0xbeefdead
11 .global tic
12 tic: .short 0x1234
13 hello: .ascii "Aabcdefghijklmnopqrstuvwxyz\n"
14
15
16 .text
17 Reset_Handler:
18 movs r0, #7
19 loop:
20 adds r0,r0,#1
21 push {r0}
22 b loop
Remember
The second word
0800 0101(line 6) can be read as 0800 0100 + 1, or Reset_Handler address + 1
space 0xf8is used in order to let sufficient space for the vectors table. More details in Vectors table..global tic and tic: .short 0x1234 will be used to get a global variable, useable in subroutines
Assembler and options
The .s source files are passed to the ARM assembler (arm-none-eabi-as) which creates an object file for each source file.
arm-none-eabi-as fhc.s
This command compiles the assembly file fhc.s into an object file a.out.
We can name the output object file ‘fhc.o’ by using the -o option:
arm-none-eabi-as -o fhc.o fhc.s
The -g option tells the assembler to include debug information.
arm-none-eabi-as -g fhc.s -o fhc.o
When this file is sent to the assembler, it will translate the instructions into binary machine code, with 2 or 4 bytes per instruction.
Dump memory, symbol table
See dump.
Linker
The object files are then passed to the linker (arm-none-eabi-ld). The linker will determine where the object files should be placed in memory on the microcontroller. The output of the linker is an executable binary file called fhc.elf.
Map=fhc.map to instruct the linker to output the memory map file.
To turn this object file into a final program, call the linker like this:
arm-none-eabi-ld -Ttext 0x8000000 -Tdata=0x20000000 fhc.o -o fhc.elf
This creates a file “fhc.elf” that contains the whole generated program.
The ‘-Ttext’ option tells the linker to use 0x800 0000 as the start address of the flash memory.
The ‘-Tdata’ option instructs the linker to use 0x2000 0400 as the address of the first byte of RAM.
The linker will output the following warning:
arm-none-eabi-ld: warning: cannot find entry symbol _start; defaulting to 08000000
It can be ignored.
linker
For a more detailed tutorial on linkers, see Linker.
Debug
From a terminal, do:
$openocd -f /home/fhc/openocd/tcl/board/st_nucleo_l4.cfg
OpenOCD will open only if the Nucleo hardware is seen as a volume NOD_476RG (as a hard disk) containing the two following files:
>>>>
>>
$ openocd -f /home/fhc/openocd/tcl/board/st_nucleo_l4.cfg
Open On-Chip Debugger 0.12.0+dev-01507-g9659a9b5e (2024-02-01-14:42)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 500 kHz
Info : STLINK V2J33M25 (API v2) VID:PID 0483:374B
Info : Target voltage: 3.261417
Info : [stm32l4x.cpu] Cortex-M4 r0p1 processor detected
Info : [stm32l4x.cpu] target has 6 breakpoints, 4 watchpoints
Info : [stm32l4x.cpu] Examination succeed
Info : starting gdb server for stm32l4x.cpu on 3333
Info : Listening on port 3333 for gdb connections
openOCD waits for a gdb connection.
From gdb, let’s do it:
target extended-remote :3333 or tar ext :3333
openocd then responds
Info : accepting 'gdb' connection on tcp/3333
[stm32l4x.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x21000000 pc: 0x0800012a msp: 0x20000400
Info : device idcode = 0x10076415 (STM32L47/L48xx - Rev 4 : 0x1007)
Info : RDP level 0 (0xAA)
Info : flash size = 1024 KiB
Info : flash mode : dual-bank
Info : device idcode = 0x10076415 (STM32L47/L48xx - Rev 4 : 0x1007)
Info : RDP level 0 (0xAA)
Info : OTP size is 1024 bytes, base address is 0x1fff7000
Now it is time to download our program
(gdb) load fhc.elf
Loading section .data, size 0xf lma 0x20000000
Loading section .text, size 0x106 lma 0x8000000
Start address 0x08000000, load size 277
Transfer rate: 746 bytes/sec, 138 bytes/write.
openOCD says:
Info : Unable to match requested speed 500 kHz, using 480 kHz
Info : Unable to match requested speed 500 kHz, using 480 kHz
[stm32l4x.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x080000ec msp: 0x20000400
Info : Unable to match requested speed 500 kHz, using 480 kHz
Info : Unable to match requested speed 500 kHz, using 480 kHz
[stm32l4x.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x080000ec msp: 0x20000400
Info : Padding image section 0 at 0x08000106 with 2 bytes (bank write end alignment)
Info : Unable to match requested speed 500 kHz, using 480 kHz
Info : Unable to match requested speed 500 kHz, using 480 kHz
[stm32l4x.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08000100 msp: 0x20000400
(gdb) file fhc.elf
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Load new symbol table from "fhc.elf"? (y or n) y
Reading symbols from fhc.elf...
(gdb)
openOCD does not need to answer
Set a breakpoint
(gdb) b 18
Breakpoint 1 at 0x8000100: file fhc.s, line 18.
Note: automatically using hardware breakpoints for read-only addresses.
Run the program up to the breakpoint
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/fhc/y/asm_first/fhc.elf
Breakpoint 1, Reset_Handler () at fhc.s:18
18 movs r0, #7
Examine register r0
(gdb) i r r0
r0 0x0 0
Single step
(gdb) s
halted: PC: 0x08000102
loop () at fhc.s:20
20 adds r0,r0,#1
The register r0 now has the value 7
(gdb) i r r0
r0 0x7 7
(gdb) s
halted: PC: 0x08000104
22 b loop
After the add operation, r0 has the value 8
(gdb) i r r0
r0 0x8 8
debugger
For a more detailed tutorial on gdb debugger, see debugger.
Use makefiles
makefiles
See makefiles.
Assemble several files
For example, to assemble the two files fhc.s and init.s, do:
arm-none-eabi-as fhc.s init.s --warn -g -o fhc.o
To turn the object file fhc.o into a final program, call the linker like this:
arm-none-eabi-ld fhc.o -o fhc.elf -Ttext=0x8000000
This way, you link your files to an executable (elf, Executable and Linkable Format)
elf is for debugging and contains much more information. bin is pure program data.
BIN is a byte-by-byte binary image of what goes into the target memory HEX is a text representation of the image; it has addresses and checksums - so it can be “sparse” ELF is the full build output - it contains symbol information, debug information, etc, in addition to the code itself. BIN and HEX are generated from the ELF.
is different from:
To get the object-files simply compile using
$ gcc -c file1.c
this yields file1.o and so on.
Then to link object files do: $ gcc -o output file1.o file2.o