如何获得 C 函数的基本编译二进制代码?

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

我正在尝试在 stm32 F4 micro 上实现一个嵌入式固件,它从串口获取二进制代码并在 micro 上执行它。

这个想法很简单,当然唯一棘手的部分是,因为在串行上发送原始二进制数据很复杂,我将通过 base64 编码发送所有内容。

代码如下:

#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] = '[=10=]'; // 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);
}

下一个问题是能够编译并从这个简单的 C 函数中获取编译后的二进制代码:

int fn() {
   return 3;
}

在这里你可以看到assembly这个愚蠢的功能。

我尝试过,当然是使用用于 micro 主代码的相同工具链,使用与位置无关代码的选项使用 gcc 编译它,然后我尝试使用 objcopy 复制 .​​text 部分,最后,我获取了 xxd 命令返回的文本,将其编码为 base64 并将其发送到 micro。

以下是我使用的命令:

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

如我所料,这个想法行不通,我的假设是我从这个过程中得到的不仅仅是函数的二进制代码。 我有这个想法是因为输出文件 test.bin 相当大,有 440 个字节,在我看来对于 7 条汇编指令来说有点太多了。

这就是我提出问题的原因:如何获取二进制代码并且只获取该代码?

您不小心生成了 ELF 文件而不是简单的 BIN 文件。 (您可以使用 file 实用程序验证这一点,如果您的系统有的话。)

要从您的代码生成一个小的 BIN 文件,请将您的第二个命令更改为:

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

请注意,当您执行通过串行线路接收的任意机器代码时,可能会出现大量复杂情况和安全问题。我不建议将其作为设计,只是尝试回答您提出的问题。