【发布时间】: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