我正在执行一系列活动,以确保Redis在一组嵌入式系统中运行良好,包括Raspberry PI。为了修复Redis的某些代码路径,其中执行了未对齐的内存访问(由于Redis 3.2中引入的更改),我试图强制PI在未对齐的内存访问上记录消息或向其发送信号这种情况发生的过程。通过这种方式,我可以确保Redis在未对齐访问是违规的情况下运行良好,并且它将在平台中运行得更快,而平台可以执行此类访问但速度较慢。 ARM v6(PI v1中使用的版本)显然能够处理未对齐的内存访问,因此如果我使用以下命令配置Linux以便向执行未对齐访问的进程发送信号:
echo 4 > /proc/cpu/alignment
然后运行以下程序:
#include <stdio.h>
#include <stdint.h>
int main(int argc, char **argv) {
char *buf = "foobareklsjdfklsjdfslkjfskdljfskdfjdslkjfdslkjfsd";
uint32_t *l = (uint32_t*) (buf+1);
printf("%p\n", l);
printf("%d\n", (int)*l);
return 0;
}
我无法看到流程收到的任何信号,或/proc/cpu/alignment
处的计数器递增。
我的猜测是,这是由于ARM v6能够自动处理未对齐的地址,如果设置了给定的CPU配置标志。我的问题是,我的假设是否正确?如果是这样,如果未对齐访问,如何强制PI版本1实际引发异常,以便Linux内核可以捕获它并发送信号,记录访问权限等等,根据/ proc / cpu / alignment设置?
编辑:值得注意的是,即使在ARM v6中,并非所有指令都可以执行未对齐的访问。例如,STMDB,STMFD,LDMDB,LDMEA和类似的多个单词指令确实会引发异常,并将被Linux内核捕获。
答案 0 :(得分:5)
我想我最终找到了答案:
/proc/cpu/alignment
中的陷阱计数器也不会增加。AFAIK我无法强制内核捕获字大小的未对齐访问,因为显然应该配置CPU以便在每种情况下捕获未对齐的地址,但Linux内核确实如此不要那样做AFAIK,可能是因为内核本身内部存在对齐的不安全代码。检查Linux内核源代码确实可以看到:
if (cpu_is_v6_unaligned()) {
set_cr(__clear_cr(CR_A));
ai_usermode = safe_usermode(ai_usermode, false);
}
这意味着SCTLR.A位始终被清除,因此没有陷阱 将为ARM v6可以处理的未对齐访问生成。
当与未对齐地址一起使用时,有大量指令仍然会生成陷阱,例如多存储/加载指令,加载和存储双值。
/proc/cpu/alignment
设置为修复访问权限。所以第4点基本上意味着,修复程序在ARM v6中运行不是一个好主意,只是让Linux内核为我们处理未对齐的地址,即使未对齐的性能影响也是如此地址不是问题:程序仍然可能崩溃,因为并非所有指令都得到处理。
如何可靠地找到程序中所有未对齐的访问仍然是一个悬而未决的问题AFAIK,因为不幸的是,其他很棒的valgrind程序,从未实现过这个功能。在过去,我不得不使用QEMU模拟Sparc,但这是一个非常缓慢的过程。 Valgrind将是这样做的琐碎方式。