最简单的 elf 模块加载 例程

https://blog.youkuaiyun.com/Pedroa/article/details/53842115

 

fun.c

#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>

int main()
{
  int fd;
  int ret;
  unsigned char *buf;
  struct stat stat;
  void *res;
  unsigned long int ImageBase ;
  int rebase[2] = {0x0B, 0x12};
  unsigned char *temp;

  ImageBase = 0x50000000;

  fd = open("hello.bin", O_RDWR);
  if (fd < 0) {
    perror("fd");
    return -1;
  }

  ret = fstat(fd, &stat);
  if (ret < 0) {
    perror("fstat");
    return -1;
  }
  
  buf = (unsigned char *)malloc(stat.st_size);
  if (buf == NULL) {
    perror("allocate");
    return -1;
  }

  ret = read(fd, buf, stat.st_size);
  if (ret < 0 || ret != stat.st_size) {
    perror("read");
    return -1;
  }

  res = mmap((void *)ImageBase, stat.st_size, PROT_EXEC|PROT_WRITE|PROT_READ, MAP_PRIVATE, fd, 0);
  if (res == MAP_FAILED) {
    perror("mmap");
    return -1;
  }
  printf("%p \n", res);

  for (int i = 0; i < 2; i++)
  {
    *(unsigned int *)((char *)res + rebase[i]) += ImageBase;
  }
  
  temp = (unsigned char *)res;
  for (int i = 0; i < 0x100; i++)
    printf("%02X%s", *temp++, (i+1) % 0x10 ? " ": "\n");

  __asm__  volatile ("\n\t"\
             "movl $1 ,%%eax\n\t"\
             "jmp *%0\n\t"\
             ::"mem"(res):
  );


}

 

 

hello.s

.section .data
output:
  .asciz "Hello World 12345678\n"
length:
  .int .-output

.section .text
.global _start
_start:

  movl $4, %eax
  movl $1, %ebx
  movl $output, %ecx
  movl length, %edx
  int $0x80
  
  movl $1, %eax
  movl $0, %ebx
  int $0x80

 

 

makefile

all:hello.bin fun

fun: fun.c
    @echo 1    
    gcc $< -o $@
    @echo 2    

hello.bin:hello.o
    @echo 3    
    @echo "dddeeee$< = $<"     
    ld $< -T test.ld -o hello.elf
    objcopy -j .text -O binary  hello.elf hello.bin

*.o:*.s
    @echo "ddd33333"     
    as $< -o $@
    @echo "ddd$< = $<"     

.PHONY clean:
    -rm *.o *.bin *.elf fun

 

 

test.ld

 

SECTIONS
{
. = 0x00000000;
.text : {
    *(.text) 
    *(.data)
 } 
}
 

 

运行结果:

TEST-master/test1# ./fun
0x50000000 
B8 04 00 00 00 BB 01 00 00 00 B9 24 00 00 50 8B
14 25 3A 00 00 50 CD 80 B8 01 00 00 00 BB 00 00
00 00 CD 80 48 65 6C 6C 6F 20 57 6F 72 6C 64 20
31 32 33 34 35 36 37 38 0A 00 16 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Hello World 12345678

 

 

 

### 控制或配置 LED 灯的方法 要在 Ubuntu 系统中控制或配置 LED 灯,通常可以通过编写嵌入式程序并将其加载到目标硬件上来实现。以下是具体方法: #### 1. **开发环境准备** 为了在 Ubuntu 中完成 LED 的控制,需要安装交叉编译工具链以及必要的调试工具。例如,在引用的内容中提到的 `arm-linux-gnueabihf-gcc` 工具链可以用于 ARM 架构的目标板[^1]。 ```bash sudo apt-get update sudo apt-get install build-essential gcc-arm-linux-gnueabihf ``` #### 2. **Makefile 配置** Makefile 文件定义了构建过程中的命令序列。以下是一个典型的 Makefile 示例,适用于汇编语言编写的 LED 控制程序[^1]: ```makefile led.bin : leds.s arm-linux-gnueabihf-gcc -g -c leds.s -o led.o arm-linux-gnueabihf-ld -Ttext 0x87800000 led.o -o led.elf arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin arm-linux-gnueabihf-objdump -D led.elf > led.dis clean: rm -rf *.o led.bin led.elf led.dis run: cat header led.bin > load.imx sudo ./uuu load.imx ``` 此 Makefile 将源码文件 `leds.s` 编译为目标二进制文件 `led.bin` 并生成反汇编文件 `led.dis`。 #### 3. **GPIO 控制原理** LED 的控制主要依赖于 GPIO(通用输入输出端口)。通过设置特定寄存器来改变引脚的状态,从而控制 LED 的开关状态。这涉及到多个层面的知识点,包括但不限于 GPIO 寄存器操作、字符设备驱动编程、设备树配置等[^2]。 对于 Linux 下的 GPIO 操作,可以直接使用 `/sys/class/gpio/` 接口或者编写内核模块。下面展示了一个简单的 C 程序示例,利用标准库函数访问 GPIO 引脚[^4]: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define GPIO_PATH "/sys/class/gpio/" #define EXPORT_FILE GPIO_PATH"export" #define UNEXPORT_FILE GPIO_PATH"unexport" void export_gpio(int gpio_num) { char buffer[5]; FILE *fp; fp = fopen(EXPORT_FILE, "w"); if (!fp) { perror("Failed to open export file"); exit(EXIT_FAILURE); } sprintf(buffer, "%d", gpio_num); fwrite(buffer, sizeof(char), strlen(buffer), fp); fclose(fp); } void unexport_gpio(int gpio_num) { char buffer[5]; FILE *fp; fp = fopen(UNEXPORT_FILE, "w"); if (!fp) { perror("Failed to open unexport file"); exit(EXIT_FAILURE); } sprintf(buffer, "%d", gpio_num); fwrite(buffer, sizeof(char), strlen(buffer), fp); fclose(fp); } int main() { const int LED_GPIO = 17; char path[64]; snprintf(path, sizeof(path), GPIO_PATH"gpio%d/direction", LED_GPIO); export_gpio(LED_GPIO); // Set direction as output FILE *direction_fp = fopen(path, "wb"); if (!direction_fp) { perror("Failed to set direction"); goto cleanup; } fprintf(direction_fp, "out"); fclose(direction_fp); snprintf(path, sizeof(path), GPIO_PATH"gpio%d/value", LED_GPIO); FILE *value_fp = fopen(path, "wb"); if (!value_fp) { perror("Failed to write value"); goto cleanup; } // Turn on the LED fprintf(value_fp, "1"); fflush(value_fp); sleep(1); // Turn off the LED fprintf(value_fp, "0"); fflush(value_fp); cleanup: fclose(value_fp); unexport_gpio(LED_GPIO); return 0; } ``` 该代码片段展示了如何导出指定编号的 GPIO,并将其方向设为输出模式,最后通过写入数值 `1` 或 `0` 实现 LED 的点亮与熄灭功能。 #### 4. **STM32 开发流程** 如果使用的硬件平台是 STM32 微控制器,则需额外考虑其特有的外设初始化逻辑。例如,针对 STM32F427 芯片,可能涉及如下步骤[^3]: - 使用 CubeMX 自动生成初始项目框架; - 手动调整定时器及时钟分频参数; - 在启动文件中加入自定义中断服务例程。 最终可通过 OpenOCD 和 GDB 结合完成在线调试工作流。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值