Raspberry PI版本1未检测到未对齐的访问

ant*_*rez 3 arm memory-alignment raspberry-pi

我正在执行一系列活动,以确保Redis在一组嵌入式系统中运行良好,包括Raspberry PI.为了修复Redis的某些代码路径,其中执行了未对齐的内存访问(由于Redis 3.2中引入的更改),我试图强制PI在未对齐的内存访问上记录消息或者向进程发送信号有时候是这样的.通过这种方式,我可以确保Redis在未对齐访问是违规的情况下运行良好,并且它将在平台中运行得更快,而平台可以执行此类访问但速度较慢.在PI v1中使用的ARM v6显然能够处理未对齐的内存访问,因此如果我使用以下命令配置Linux以便向执行未对齐访问的进程发送信号:

echo 4 > /proc/cpu/alignment
Run Code Online (Sandbox Code Playgroud)

然后运行以下程序:

#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;
}
Run Code Online (Sandbox Code Playgroud)

我看不到进程收到的任何信号,或者/proc/cpu/alignment递增的计数器.

我的猜测是,这是由于ARM v6能够自动处理未对齐的地址,如果设置了给定的CPU配置标志.我的问题是,我的假设是否正确?如果是这样,如果未对齐访问,如何强制PI版本1实际引发异常,以便Linux内核可以捕获它并发送信号,记录访问权限等等,根据/ proc/cpu/alignment设置?

编辑:值得注意的是,即使在ARM v6中,并非所有指令都可以执行未对齐的访问.例如,STMDB,STMFD,LDMDB,LDMEA和类似的多个单词指令确实会引发异常并将被Linux内核捕获.

ant*_*rez 5

我想我最终找到了答案:

  1. 是的我是正确的,直到字大小ARM v6(或更高版本)可以静默处理未对齐的访问,因此不会生成陷阱,并且对Linux内核完全透明.什么都不会被记录,陷阱计数器/proc/cpu/alignment也不会增加.
  2. AFAIK我无法强制内核捕获字大小的未对齐访问,因为显然应该配置CPU以便在每种情况下捕获未对齐的地址,但是Linux内核不会那样做AFAIK,可能因为内核本身内部存在对齐的不安全代码.检查Linux内核源代码确实可以看到:

    if (cpu_is_v6_unaligned()) {
             set_cr(__clear_cr(CR_A));
             ai_usermode = safe_usermode(ai_usermode, false);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这意味着SCTLR.A位始终被清除,因此不会为ARM v6可以处理的未对齐访问生成陷阱.

  3. 当与未对齐地址一起使用时,有大量指令仍将生成陷阱,例如多存储/加载指令,加载和存储双值.

  4. 但是,有一些说明可以很好地生成GCC(默认的Raspberry Linux发行版中提供的版本),而Linux内核无法正确处理,即使/proc/cpu/alignment设置了修复访问权限,也会生成SIGBUS .

所以第4点基本上意味着,修复程序在ARM v6中运行不是一个好主意,只是让Linux内核为我们处理未对齐的地址,即使未对齐地址的性能影响不是问题:程序仍然可以崩溃,因为没有处理所有指令.

如何可靠地找到程序中所有未对齐的访问仍然是一个悬而未决的问题AFAIK,因为不幸的是,其他很棒的valgrind程序,从未实现过这个功能.在过去,我不得不使用QEMU模拟Sparc,但这是一个非常缓慢的过程.Valgrind将是这样做的琐碎方式.