【问题标题】:In memory copy during execution执行期间在内存中复制
【发布时间】:2021-08-01 07:53:31
【问题描述】:

我正在尝试在程序执行期间进行代码交换的不同方法。使用 QEMU 与 ARM926EJ-S 内核的 VersatilePB 板进行仿真。我找到了一个使用 UART 打印传递的字符串的函数。主要有 3 个函数调用,但这些函数在不同的文件中实现以进行详细说明,每个函数定义都在自己的文件中。函数定义无非就是用不同的字符串调用print_uart0() 来打印。因此使用关键字extern 以便在链接期间,函数将能够找到print_uart0() 定义。

void extern print_uart0(const char *s) {
while(*s != '\0') { /* Loop until end of string */
*UART0DR = (unsigned int)(*s); /* Transmit char */
s++; /* Next char */
 }
}
void main() {
 function_1();
 function_2();
 function_3();
 function_1();
 function_1();
}

我想做的是,例如,如果我有中断信号或更改 GPIO 的状态,则将function_3().text 部分与function_1().text 部分交换 所以基本上所需的输出应该从

"print from function 1"
"print from function 2"
"print from function 3"
"print from function 1"
"print from function 1"

应该是这样的

"print from function 1"
"print from function 2"
"print from function 3"
---------interrupt/code exchange event occurs here ----------
"print from function 3"
"print from function 3"

目的是保持 main 及其函数调用与原来相同,但交换指令本身以执行不同的指令。我发现了一个类似的帖子,讨论了类似的情况 in-memory copying in assembly 但目标架构是 x86,所以如果有人可以指导我寻找替代 ARM 指令或更好的方法,那就太好了。

我对 elf 文件有很好的了解,我可以编写自己的链接描述文件,将每个函数的 .text 部分放在不同的内存地址中

【问题讨论】:

  • 使用函数指针而不是替换函数体。根据您的示例,这是一种更简单的方法。顺便说一句,您仍然可以使用通用的“memcpy”来复制函数体,它不需要是汇编程序实现的函数。但是这种复制需要知道通常通过链接描述文件完成的函数大小以及在复制函数体后正确处理指令缓存。
  • 您是应该复制整个函数,还是应该在函数中查找将字符串地址放入寄存器的一两条指令,然后仅更新它?显然,您正在根据您的措辞方式进行某种练习。在现实生活中(例如在 Linux 内核中),如果您要设置一些用于运行时修改的代码(而不是 func 指针),它通常会以一种更可控的方式进行,您知道自己使用了哪些指令。重新将要改变。 (例如,如果不需要原子 RMW,则将 strex 变成普通的 str。)
  • 如果更改发生的频率大大低于代码执行的频率,您只想修改机器代码,并且使用函数指针而不是直接调用会减慢速度其实是个问题。 (你仍然需要避免内联函数,所以仍然有一个调用)。例如像 Linux 一样,如果在单处理器机器上启动,则修补 x86 lock 前缀,或类似的技巧。如果您想要与此相同的真实行为,您将加载 volatile char* 或 3 个之一,并从中断处理程序更改它指向的内容。

标签: assembly embedded-linux elf qemu linker-scripts


【解决方案1】:

没有必要搞乱函数体复制。 使用函数指针调用正确的函数

void print1()
{
    printf("Function1\n");
}

void print2()
{
    printf("Function2\n");
}

void (*fptr)();// declare function pointer

int main()
{
    fptr = print1; // assign function pointer to 'print1' function
    fptr();        // call 'print1()' by pointer

    fptr = print2; // <-- assign pointer to another function inside interrupt routine

    fptr();        // would call 'print2()'

    return 0;
}

【讨论】:

  • 我明白,但任务是关于动态函数分配,在不同文件中完全分离函数,编译和执行特定函数,并在运行时选择交换其他函数,所以函数指针对我来说不是一个选项
  • “编译并执行特定的”是什么意思?任何随机代码的运行时编译?
  • 正如我之前解释的,我有一个具有特定功能的应用程序,目标不是改变函数调用顺序,目标是保持 main 不变,然后根据中断信号将放置某些功能说明而不是原始说明
  • int main() { fptr(); fptr(); fptr(); }main() 相同,但 fptr 可以分配给不同的功能。所以这就是调用不同的函数而不改变其他任何东西
  • @PeterCordes 我应该复制要替换的函数_3的所有指令,而不是函数_1的指令,假设所有函数都具有相同的签名。所以流程应该是功能未注册,交换代码然后注册
猜你喜欢
  • 2016-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多