代码之家  ›  专栏  ›  技术社区  ›  Noè Murr

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

  •  1
  • Noè Murr  · 技术社区  · 3 年前

    我正在尝试在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] = '\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);
    }
    

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

    int fn() {
       return 3;
    }
    

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

    当然,我试着使用与micro主代码相同的工具链,使用位置无关代码的选项用gcc编译它,然后我试着复制。文本secion和objcopy,最后我从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 
    

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

    这就是我的问题的原因:我如何得到二进制代码,并且只得到那个代码?

    1 回复  |  直到 3 年前
        1
  •  1
  •   David Grayson    3 年前

    您意外地生成了一个ELF文件,而不是一个简单的BIN文件。(您可以使用 file 实用程序(如果您的系统有)

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

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

    请注意,当您执行通过串行线接收的任意机器代码时,可能会出现大量复杂问题和安全问题。我并不是建议把它作为一种设计,只是想回答你提出的问题。