Assembly Programming and Debugging in Eclipse on Linux

The original article my article is based on is: While being good information to achieve the ultimate goal it is outdated in the year 2020 since Eclipse has changed so much since the article was published.

This article will use the 12-2019 Eclipse for C++ developers and the Linux GCC Toolchain to assemble and debug code within Eclipse.

Basically Eclipse 12-2019 is installed. A C++ project is created. A main.S file is added. The compiler and linker options are adjusted. A debug configuration is created and the sample application is compiled and debugged.

Installing and running Eclipse on Linux

The file eclipse-cpp-2019-12-R-linux-gtk-x86_64.tar.gz is downloaded and extracted.

tar -zxvf eclipse-cpp-2019-12-R-linux-gtk-x86_64.tar.gz

A eclipse folder is created. Eclipse can be run with:

Create a Project

File > New > C++ Project > C++ Managed Build > Executable > Empty Project > Linux GCC > Name: test

Add an Assembly File

File > New > Source File > main.S

The casing of the filename is in fact relevant! There has to be an uppercase S as an extension. The S extension is used by Eclipse to select the correct tools from the toolchain to assemble and link your application! If you use .s it will not work!

Add assembler code to the main.S file.

.section .data
message: .string "Hello World!\n"

.section .text

# this directive allows the linker to see the "main" label
# which is our entry point
.globl main

# this directive allows the eclipse gdb to see a function called "main"
.func main
mov $4, %eax
mov $1, %ebx
mov $message, %ecx
mov $14, %edx
int $0x80
mov $0, %eax
Adjust the Tool Settings

Project > Properties > C/C++ Build > Settings > Tab: Tool Settings > GCC Assembler > Command line pattern append: -g –gstabs immediately following ${COMMAND}


The way Linux, Unix and BSD systems assemble code has changed according to the posts:

Instead of using absolute addresses, the 64 bit way of modern assembly is now relocatable assembly. The code listing above is not moden 64 bit relocatable assembly.

The way to get the Linux GCC toolchain to assemble the code anyways is to add the -no-pie flag to the linker:

Project > Properties > C++ Build > Settings > GCC C++ Linker > Command Line Patter > add -no-pie after ${FLAGS}

Create a Debug Configuration

For eclipse to start an application from within the IDE, you have to supply a Run Configuration for normal execution or a Debug Configuration for debugging the application. Run / Debug Configurations are descriptors of an application run. They contain things such as environment variables and command line parameters to the application amongst other options and parameters.

First make sure your application does in fact build properly. In the next step you have to select your binary, that is why you have to be able to build your project.

In our case, in Eclipse, create a new Debug Configuration. As a type select ‘C/C++ Application’. Click Browser and select your binary for the C/C++ Application input field.

Set a breakpoint into the assembler source code and start the Debug configuration.

Powering the SAM7-LA2 Board

I recently aquired a SAM7-LA2 board. The board apparently is very outdated but it was on sale and it does support the ARM7TDMI instruction set.

The problem with the board is that it does not come with a power supply. The power requirements are specified at several locations in the user manual. Wierdly enough the manual says it need 4.5V DC on one page and 6V DC on another. Also the polarity of the power supply is not specified! It nowhere explicitly states that the polarity does not matter and that the board contains a rectifier. So I did not know which polarity to use.

Here is what worked for me:

I used a 6V DC power supply and as polarity, I used positive center. The board is running without getting fried immediately.

When it comes to power supplies you have four things to worry about:

  1. Amount of supplied voltage
  2. Type of supplied voltage AC / DC
  3. Polarity of supplied voltage (in case of DC)
  4. Amount of supplied current

1. For the amout of Voltage, if the circuit needs 6V you have to supply 6V to not damage the circuit. You have to be exact, when it comes to voltage!

2. The voltage is alternating current (AC) when it is consumed out of your wall socket. If your integrated circuit uses directed current (DC) your power supply has to convert AC to DC and output DC. If your circuit uses AC, the power supply has to output AC. If your circuit does not care, it does not matter what the power supply outputs.

3. Polarity is important because if your circuit can only consume DC and within DC a certain type of polarity and you supply the wrong kind, your circuit will be damaged irreversably. Usually a power supply uses a connector that has a pin in the middle which is surrounded by a metal tube on the outside. The pin in the middle is the inner contact the tube is the outer contact. The contacts have to have opposing polarity. If the pin is positive, the tube has to be negative and vice versa. You have to know which polarity setup your circuit requires. Most modern circuits use a rectifier which automatically converts any polarity to the polarity the circuit wants in order to get rid of problems with incorrect polarity. Older circuits may not contain a rectifier and the user is responsible to plug in a power supply having the correct polarity setup. You have to be precise with polarity in order to not irreversably damage your circuit.

4. For current, you have to make sure that your power supply is capable of supplying at least the required amout of current. If your power supply is capable of more current that is usefull but the circuit will only draw as much current as it actually needs at any point in time. So you cannot damage the circuit if you use a power supply that can supply more current. You can compare this to the situation in your gaming desktop PC. Your PC maybe contains a 500 Watt power supply which does not mean that your PC consumes 500 Watt of power at all times. If your graphics card turns itself off, the power consumption drops to maybe 300 Watts. If you play a CPU and GPU intensive game and your graphics card draws power at its max TDP, your PC will maybe use 480 Watts. If you replace your graphics card with a faster model it may draw more power and your 500 Watt powersupply may not able to supply that power causing your PC to turn off during the gaming session. Time to replace the 500 Watt supply by a 800 Watt supply or an even stronger one. Your PC will not take severe damage when there is not enough power to function, it will just stop to function correctly.



STM32F103C8T6 with Eclipse (OpenSTM32) under Mac OSX


The System Workbench for STM32 (SW4STM32) aka. OpenSTM32 aka. AC6 Tools is a set of plugins for the popular Eclipse IDE. There are two ways to install OpenSTM32. The first is to add the plugins to an existing installation of Eclipse, the other is to download a flavor of the Eclipse IDE from the ST homepage which has all the plugins preinstalled. This article explains what my experience was installing the preconfigured Eclipse on a MAC including debugging the program on a bluepill with openocd, the arm-none-eabi-gdb and a ST Link v2 programmer.

I used this article as a foundation for my article.


A word of advice to everybody wanting to use OpenSTM32 on a mac. Make absolutly sure that you are using the latest software packages available. It will not work with outdated software! There is absolutely no backwards compatibility. If your versions are off, the tools just do not work together. They just fail without usefull error messages!

Use the latest version of

Download and Install OpenSTM32

wget --no-check-certificate
chmod +x
Error: Unrecognized option: -d64

If you get this error:

Unrecognized option: -d64
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

The solution is to run the installer with root priviledges.

sudo ./ -m -f
Opening the OpenSTM32
open -a /Applications/Ac6/
Creating a Project

Create a C project as outlined here.

In Eclipse, select File > New > Project > C Project

As Project Type: Empty Project

As Toolchain: Ac6 STM32 MCU GCC

Keep Debug and Release builds checked.

In the wizard step “Target Configuration” switch to the MCU Tab, select

Series: STM32F1

Mcu: STM32F103C8Tx

In the Firmware Configuration Dialog, choose Hardware Abstraction Layer (Cube HAL). The Standard Peripheral Library (StdPeriph) is discontinued and I was not able to get the StdPeriph working.

Error: The Project Importer fails to install

If you get this error:

'tar' failed to extract /Applications/Ac6/ to /Applications/Ac6/

the solution is to manually untar the file:

cd /Applications/Ac6/
sudo bzip2 -d
sudo tar xopf
sudo cp -R /Applications/Ac6/
Error: The compiler fails to install
Failed to extract '/Applications/Ac6/' to '/Applications/Ac6/' (tar returned '1')

The solution is to install the compiler manually:

cd /Applications/Ac6/
sudo bzip2 -d st-gnu-arm-gcc-7-2018-q2-update_gdb-5_4-2016q3-mac.tar.bz2
sudo tar xopf st-gnu-arm-gcc-7-2018-q2-update_gdb-5_4-2016q3-mac.tar
sudo ln -s ./st-gnu-arm-gcc-7-2018-q2-update_gdb-5_4-2016q3-mac ./compiler
Write a small C Program

In order to test debugging you need a small application which is large enough to place some breakpoints in for testing. My example does not make any sense at all so do not question the application too much.

int main(void)
  int i = 0;

  while (1) {


    if (i == 100)
      i = 0;

  return 0;

The application should now compile in Eclipse without errors.

There are two error messages that are apparently caused by the Eclipse code scanner as explained here.

Program “arm-none-eabi-g++” not found in PATH testf7 Project Properties, C++ Preprocessor Include.../Providers, Ac6 SW4 STM32 MCU Built-in Compiler Settings options C/C++ Scanner Discovery Problem
Program “arm-none-eabi-gcc” not found in PATH testf7 Project Properties, C++ Preprocessor Include.../Providers, Ac6 SW4 STM32 MCU Built-in Compiler Settings options C/C++ Scanner Discovery Problem 

If you get these two errors, you can just select and delete them as they are bogus messages more or less and they do not cause your build to fail.

Install gcc-arm-none-eabi on macos

download and unzip the latest version of gdb

sudo cp -R /Users/<username>/Downloads/gcc-arm-none-eabi-9-2019-q4-major /usr/local/gcc_arm

In eclipse in the debug configuration change the gdb command path
Debugger-Tab > GDB command >

Install OpenOCD

brew install open-ocd

OpenOCD Configuration Script

OpenOCD is used in the OpenSTM32 build sequence to establish a connection to the bluepill. gdb will then be used to debug the application over the connection that openocd has established.

To configure how openocd establishes the connection, you have to write a configuration script. In Eclipse, debugging or running an application is done using so called run configurations.

You will create a debug run configuration and specify the path to openocd and the configuration script in the run configuration.

According to this post, there is a bug in OpenSTM32 were the openocd configuration script is not allowed to be located within the Eclipse project but in some other folder. Because of this bug, create the configuration script in some folder but not in the project folder.

I keep my configuration scripts in the folder:


Here is the script that works for me:

source [find interface/stlink-v2.cfg]
transport select "hla_swd"

# added
set BOARDNAME genericBoard

# added
# Enable debug when in low power modes
# Stop Watchdog counters when halt
# STlink Debug clock frequency
#set CLOCK_FREQ 4000
#set CLOCK_FREQ 1000
set CLOCK_FREQ 950
# We do not connect RESET line to stlink, that's why reset is disabled.
#reset_config none
reset_config none separate
source [find target/stm32f1x.cfg]
Create a Run Configuration for Debugging

Open the pull down menu on the Debug button (Button with a green bug on it) in the toolbar. Select “Debug Configurations…”. A dialog opens. Select Ac6 STM32 Debugging and then click the Document button with the small golder plus symbol on it to create a new Debug Run Configuration of the type Ac6 STM32 Debugging.

Here are the settings to make on the Debugger-Tab:

Start Debugging

A breakpoint causes the debugger to pause the microcontroller as soon as it executes the code the breakpoint was set on. You can set breakpoints everywhere which is a bit misleading as for example you can place a breakpoint on an empty line. Obviously there is no code generated for empty lines and the debugger cannot stop on an empty line. It will only stop on lines that actually translate to code that can be executed by the microcontroller. Eclipse will move breakpoints around before starting the application. If a breakpoint is not on a sensical location, Eclipse will move it to the next sensical location.

To set a breakpoint, double click left of a line number. A small blue dot appears. To get rid of a breakpoint, double click the blue dot and it disapears.

In this example, there is a breakpoint on line 25 of our example application:

Whenever i has been incremented to the value 100, the breakpoint will be hit.

Now that you have an application to debug and a breakpoint that makes sense, you can start the debugging session. To start the session, Select your Run Configuration from the Debugging drop down on the toolbar.

Eclipse will compile your application with debug symbols. It will connect to the board using openocd. It will upload the code via the openocd connection and it will start the gnu debugger gdb and connect it to the openocd server which allows gdb to debug the application on the hardware. Eclipse will switch to the debug perspective and it will break on the breakpoint.

The output during application start should be something similar to this:

Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
none separate
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
none separate
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v29 API v2 SWIM v7 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.132308
Info : STM32F103C8Tx.cpu: hardware has 6 breakpoints, 4 watchpoints

In the debugger you can look at variable values and you can single step through the code. If there are errors and you cannot figure out what the issue is by solely thinking about the issue, you can use a debugger to see what decision your code makes and you can figure out what decision making is happening and where the incorrect decisions are made. You can then fix the issues.

Do not forget to write unit tests for your code! Do not get into bad code-and-fix habits! Maybe, if the problem lends itself to it, give test-driven development a shot.

Error: error in final launch sequence

If you get the “error in final launch sequence” – error, make sure you are using the latest gcc-arm-none-eabi. If the versions of the tools do not match, errors such as this one arise.

Error: dyld: Library not loaded: requires version 3.0.0 or later, but

If you get this error message:

dyld: Library not loaded: /usr/local/opt/libusb/lib/libusb-1.0.0.dylib
  Referenced from: /usr/local/opt/libftdi/lib/libftdi1.2.dylib
  Reason: Incompatible library version: libftdi1.2.dylib requires version 3.0.0 or later, but libusb-1.0.0.dylib provides version 2.0.0

then your libusb versions are out-dated.

For me the libusb files in


are all outdated.

You can check this using the otool command:

otool -L /usr/local/opt/libusb/lib/libusb-1.0.0.dylib

  /usr/local/opt/libusb/lib/libusb-1.0.0.dylib (compatibility version 3.0.0, current version 3.0.0)
  /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
  /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
  /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1575.17.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)

For a correct libusb as outlined above, the output says that the libusb library has a compatibility version of 3.0.0 and a current version of 3.0.0. If your libusb versions deviate, install libusb using brew (brew install libusb) then check where the brew files are (brew list libusb) and then replace the outdated libs with the current libs from brew.

Install a new version of libusb using brew (brew install libusb) then create backups of the four outdated files and copy the new libusb files over

cd /Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/
sudo mv libusb-1.0.0.dylib libusb-1.0.0.dylib.backup
sudo cp /usr/local/lib/libusb-1.0.0.dylib .

cd /Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/
sudo mv libusb-1.0.0.dylib libusb-1.0.0.dylib.backup
sudo cp /usr/local/lib/libusb-1.0.0.dylib .

cd /Applications/Ac6/
sudo mv libusb-1.0.0.dylib libusb-1.0.0.dylib.backup
sudo mv libusb-1.0.dylib libusb-1.0.dylib.backup
sudo cp /usr/local/lib/libusb-1.0.0.dylib .
sudo cp /usr/local/lib/libusb-1.0.dylib .
Make an LED Blink

Making an LED Blink is described here.

For those coming from a high-level application programming background, a word of advice:

The fact that there is a function called HAL_Delay(500); or osDelay(1000); does not automatically mean that this function will work without setup code! In microcontroller programming, you have to first set up the hardware clock before you can make use of it via waiting functions such as the delay functions!

Same goes for LEDs. You have to first setup the LEDs before you can toggle them. The example given in this article shows how to perform the initial setup which is necessary to periodically make an LED blink. I will duplicate the code here for reference.

#include "stm32f1xx.h"

void SystemClock_Config(void) {

  RCC_ClkInitTypeDef clkinitstruct = { 0 };
  RCC_OscInitTypeDef oscinitstruct = { 0 };

  oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  oscinitstruct.HSEState = RCC_HSE_ON;
  oscinitstruct.HSIState = RCC_HSI_OFF;
  oscinitstruct.PLL.PLLState = RCC_PLL_ON;
  oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&oscinitstruct) != HAL_OK) {
    while (1)

  clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK |
  clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
  clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;
  if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2) != HAL_OK) {
    while (1)

int main(void) {



  GPIO_InitTypeDef gpio;
  gpio.Mode = GPIO_MODE_OUTPUT_PP;
  gpio.Pin = GPIO_PIN_13;
  gpio.Pull = GPIO_PULLUP;

  HAL_GPIO_Init(GPIOC, &gpio);

  while (1) {
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);

In order for this code to compile correctly, you have to add the FreeRTOS utility.

Output an Assembler Listing of the Binary

As outlined here, you can add a command to the post build step to call arm-none-eabi-objdump on your binary to disassemble it and output a listing file.

Open the preferences of your project > C / C++ Build > Settings > Tab: Build Steps > PostBuild Steps > Command.

Append to the command:

; arm-none-eabi-objdump -D "${BuildArtifactFileBaseName}.elf" > "${BuildArtifactFileBaseName}.lst"

Do not forget to prefix the semicolon! The semicolon will append a new command to the post build step.

The result is a .lst file in the debug folder that contains the assembly listing.