Valgrind在树莓派上无法识别memcmp指令。

14

我正在使用Valgrind测试我的应用程序,但我不明白为什么它会在这里的未识别指令上抛出错误:

unsigned char *temp=SearchStartPtr;
unsigned char *NrStartPos=NULL;
unsigned char *Param=(unsigned char*)ParamName; //this is originally *char with "PAR#" inside

if(0==memcmp(temp,Param,4)) 
        {
        NrStartPos=temp;
        break;
        }       

Valgrind会抛出这个错误并退出我的应用程序。

disInstr(arm): unhandled instruction: 0xF1010200
cond=15(0xF) 27:20=16(0x10) 4:4=0 3:0=0(0x0)
==7679== valgrind: Unrecognised instruction at address 0x4843588.
==7679==    at 0x4843588: ??? (in /usr/lib/arm-linux-gnueabihf/libcofi_rpi.so)
Your program just tried to execute an instruction that Valgrind
==7679== did not recognise.  There are two possible reasons for this.
==7679== 1. Your program has a bug and erroneously jumped to a non-code
==7679==    location.  If you are running Memcheck and you just saw a
==7679==    warning about a bad jump, it's probably your program's fault.
==7679== 2. The instruction is legitimate but Valgrind doesn't handle it,
==7679==    i.e. it's Valgrind's fault.  If you think this is the case or
==7679==    you are not sure, please let us know and we'll try to fix it.
==7679== Either way, Valgrind will now raise a SIGILL signal which will
==7679== probably kill your program.
==7679== 
==7679== Process terminating with default action of signal 4 (SIGILL)
==7679==  Illegal opcode at address 0x4843588
==7679==    at 0x4843588: ??? (in /usr/lib/arm-linux-gnueabihf/libcofi_rpi.so)

通常情况下,代码可以正常工作(但我不知道它是否存在一些内存泄漏)。

我确定问题出在memcmp指令上,但我不明白哪里出了问题。

在代码的早期,我有另一个指令也是做同样的事情,但在检查之前我可以将其注释掉:

  memcmp(ReadPtr,ToWritePtr,sizeof(struct termios)

1
如果您仔细阅读消息,它会告诉您发现了非法指令(例如汇编指令)。memcmp是一个函数而不是指令。此外,Valgrind指出这个非法指令是在/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so中发现的,这几乎不可能是您创建的文件。 - Some programmer dude
可能是 https://dev59.com/QGQm5IYBdhLWcg3wrAiX#76258814 的重复问题。 - rsaxvc
3个回答

16

看起来这是树莓派上Valgrind的已知问题

总结一下,在Raspbian中,memcmp的股票版本使用了一个汇编指令,当前版本的Valgrind无法处理。不幸的是,这个特定的指令对于Valgrind来说似乎非常难以支持,所以不太可能发生——在Valgrind跟踪器中提出了一个错误,但已被关闭为WONTFIX。

我唯一能想到的解决方法就是替换自己的memcmp版本,并希望它不会编译成包含有问题的指令。


1
作为解决此问题的可能修复方法,请尝试使用strcmp [如果您查看发布的错误链接下的valgrind跟踪,似乎可以使用strcmp替换]。 - amdixon
/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so 中的函数是用汇编编写的,不太可能有一个 C 版本能够编译成 SETEND 汇编指令 - 因此可以创建一个 C 版本并使用 LD_PRELOAD 来覆盖麻烦的 memcmp。 - nos
12
好的,这很容易。/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so 已经预装了自身。所以只需编辑树莓派上的 /etc/ld.so.preload 文件,并注释掉该行,这将让您使用 glibc 中的 memcmp 函数。 - nos
2
Nigel,你应该把nos最后的评论加到你的答案中,因为它提供了一个非常简单的解决方法。 - Christian Rapp
3
我通过简单地删除“raspi-copies-and-fills”软件包来解决了问题。 - ayke
我的修复已合并到arm-mem:https://github.com/bavison/arm-mem/commit/b836e465c2fd0bb006b428abce99e31607072834 - rsaxvc

3

我和你一样也遇到了这个问题。

我检查了 arm-mem 存储库,它似乎替换了 libc 中的 memcmp 函数。所以我的解决方案是 暂时删除 arm-mem,然后使用 libc 中的原始实现。

尝试这个方法:

$ sudo mv /usr/lib/arm-linux-gnueabihf/libarmmem.so /usr/lib/arm-linux-gnueabihf/libarmmem.so.orig
$ sudo ln -s  /lib/arm-linux-gnueabihf/libc.so.6  /usr/lib/arm-linux-gnueabihf/libarmmem.so
$ sudo ldconfig

现在尝试重新运行valgrind...
稍后,使用以下命令将其移回:
$ sudo rm /usr/lib/arm-linux-gnueabihf/libarmmem.so
$ sudo mv /usr/lib/arm-linux-gnueabihf/libarmmem.so.orig /usr/lib/arm-linux-gnueabihf/libarmmem.so
$ sudo ldconfig

1

libarmmem.so的memcmp()在使用一种名为SWAR的技术搜索缓冲区中的差异时,使用了多字节加载指令。然而,它使用了“setend be”指令将处理器置于大端模式,以便在寄存器不匹配时更容易定位差异,然后在定位差异后,“setend le”恢复字节顺序模式再返回。这在ARM11上运行得很好,但是...

Valgrind没有为Arm处理器实现setend仿真(可能是因为这会使本机字节顺序访问的正常情况变慢),因此它触发了“未识别的指令”。

可以在不使用SETEND的情况下实现SWAR向量化的memcmp(),我已经这样做了,并且已经合并到上游。在相关核心上进行足够大的比较时,额外的rev指令对性能影响大致可以忽略不计。

@user167752 也是正确的,禁用 libarmmem 也可以解决问题,但这将更改 libarmmem 的所有内容,而不仅仅是 memcmp()。要这样做,请卸载 raspi-copies-and-fills 包。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接