Arduino vs. embedded C - AVR reversing
As I was teaching some embedded C basics, I was asked what are some benefits of embedded C over the classic Arduino language for an Arduino-based board. This article tries to see what we can do by reversing a really simple program compiled with both methods for the Arduino Uno.
Prerequisites
arduino-cli
: Command Line Interface for Arduino. You will need to install the AVR toolchain as well:arduino-cli core install arduino:avr
- AVR cross compiler:
sudo apt install gcc-avr
- Optional: an Arduino simulator such as SimulIDE
Sample program
We want to create the most simple program which goal is to light on the built-in LED, located at port 13 (or PORT PB5) on the Arduino Uno.
Arduino
|
|
Embedded C
|
|
Codes and compilation
|
|
Binary comparison
Arduino | Embedded C | |
---|---|---|
Storage use | 724 bytes | 144 bytes |
The embedded C code is 5 times smaller than the Arduino one which is a bit “weird” as both codes do the same thing! Let’s find why by reversing binaries and analyzing assembly codes.
arduino-cli
produces the *.elf
binary and the *.hex
file which is just a series of bytes to be loaded in the Arduino.
Reversing binaries
|
|
Arduino binary
|
|
Here is a part of the Arduino objdump. The assembly code is really long for such a program… It is easy to understand when we look at the source code of pinMode()
and digitalWrite()
https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring_digital.c. It does not only write a value into a register…
Garretlab made an analysis of both functions:
- https://garretlab.web.fc2.com/en/arduino/inside/hardware/arduino/avr/cores/arduino/wiring_digital.c/digitalWrite.html
- https://garretlab.web.fc2.com/en/arduino/inside/hardware/arduino/avr/cores/arduino/wiring_digital.c/pinMode.html
Embedded C binary
|
|
At first sight, it’s clearly easier. Step-by-step instruction decoding:
ldi r24, 0x20: according to the AVR ISA [1], ldi
load the value 0x20
in r24
which is a General Purpose Working Register of the Arduino.
out 0x04, r24: this instruction write the value stored in r24
at the address 0x04
(the address of DDRB
according to [2]). 0x20=0b100000
: DDRB5
is set to 1 😉
out 0x05, r24: same thing, for PORTB
.
Conclusion
Embedded C code is usually quicker and smaller as long as we make some effort to study the datasheet. But it’s worth it when we’re working with embedded systems! 😉