how to get the bare bone compiled binary code of a C function?

I'm trying to implement an embedded firmware on an stm32 F4 micro that takes an binary code from the serial and execute it on the micro.

The idea is pretty simple of course the only tricky part is that since on the serial is complicate to send raw binary data I'm going to send everything through base64 encoding.

Here's the code:

#include <Arduino.h>
#include <base64.hpp>

size_t read_serial_line(char *msg, size_t len, size_t timeout = 0) {
  const auto start = millis(); 
  size_t sz = 0;               

  do {
    while (not Serial.available()) {
      if (timeout > 0 and millis() > start + timeout) {
        return -1;
      }
    }

    msg[sz] = Serial.read();

    if (msg[sz] == '\r') {
      msg[sz] = '\0'; // replacing the end line with the end string

      // the next char must be a \n char since the Serial.println of arduino
      // works like that
      while (Serial.read() != '\n')
        ; // I discard it

      // now sz contains the length of the string as returned by strlen
      break; // end of line
    }

    if (timeout > 0 and millis() > start + timeout) {
      return -1;
    }
  } while (++sz < len);

  return sz; 
}

void setup() {
  Serial.begin(9600);

  Serial.println("begin!");
}

void loop() {
  char *msg = new char[2048](); // big line

  auto sz = read_serial_line(msg, 2048);

  Serial.print("\tlooping...");
  Serial.println(sz);
  Serial.print("received: ");
  Serial.println(msg);

  uint8_t *code = new uint8_t[2048]();

  sz = decode_base64(msg, code);

  Serial.println(sz);

  delay(1000);

  int (*code_fn)() = (int (*)())code;

  int c = code_fn();

  Serial.println(c);

  delete code;
  delete msg;
  delay(1000);
}

The next problem is to be able to compile and get the compiled binary code from this simple C function:

int fn() {
   return 3;
}

Here you can see the assembly of this stupid function.

I tried, of course using the same tool chain used for the main code of the micro, to compile it with gcc using the option for the position independent code and then I tried to copy the .text secion with objcopy, to finish I took the text returned from the xxd command, I encoded it in base64 and I sent it to the micro.

here are the commands that I used:

$ arm-none-eabi-gcc -fPIC -c test.c
$ arm-none-eabi-objcopy -j .text test.o test.bin 
$ xxd -p test.bin 

As I expected this idea is not working, my hypothesis is that I'm getting more then just the binary codes of the function from this process. I have this idea because the output file test.bin is pretty big 440 bytes that seems to me a little bit too much for literally 7 assembly instructions.

So that's the reason of my question: How do I get the binary code and only that code?

1 answer

  • answered 2022-05-06 20:29 David Grayson

    You accidentally produced an ELF file instead of a simple BIN file. (You can verify this using the file utility if your system has it.)

    To produce a small BIN file from your code, change your second command to:

    arm-none-eabi-objcopy -j .text test.o -O binary test.bin
    

    Note that there are likely to be tons of complications and security issues when you execute arbitrary machine code received over a serial line. I am not recommending that as a design, just trying to answer the question you asked.

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum