Kbd*_*man 1 c ssl assembly x86-64 chromium
我正在调试一个带有修改过的boringssl 的chrome。它总是有一个SegmentFault。我发现问题是
EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
Run Code Online (Sandbox Code Playgroud)
反汇编代码:
callq EC_KEY_get0_group
mov %eax,%edi
callq EC_GROUP_get_curve_name
Run Code Online (Sandbox Code Playgroud)
的返回类型EC_KEY_get0_group是一个EC_GROUP*指针,但它是EC_GROUP_get_curve_name由一个 32 位寄存器传递给的。
指针被截断并导致 SegmentFault。为什么编译器会生成这样的代码?是否有任何编译器选项可以避免这种情况?
我可以提供跟踪问题的指导,但不能为您的问题提供具体答案,因为我没有使用 BoringSSL 的修改版本。
如果您没有C函数的原型,那么所有参数和返回值都将默认为一个int类型。该函数将被视为有未指定数量的参数。
让我印象深刻的第一件事是mov $0, %al在每个函数调用之前。这向我表明这些函数要么是可变参数的,要么是无原型的。64 位 Linux 使用的AMD64 System V ABI是这样描述AL寄存器的:
对于可能调用使用 varargs 或 stdargs 的函数的调用(无原型调用或调用在声明中包含省略号 (. . ) 的函数), %al 用作隐藏参数来指定使用的向量寄存器的数量。
我们可以排除它们是可变参数,因为它们的原型应该是这样的:
int EC_GROUP_get_curve_name(const EC_GROUP *group);
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);
Run Code Online (Sandbox Code Playgroud)
由于这些函数不是可变参数(不要使用...),因此您的代码中可能有某些内容没有使这些函数的原型可用。
我们可以通过这些简单的 C 函数调用看到相同的行为:
testfunc.c :
#include <stdlib.h>
typedef struct ec_group_st EC_GROUP;
typedef struct ec_key_st EC_KEY;
int EC_GROUP_get_curve_name(const EC_GROUP *group);
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);
int testfun()
{
EC_KEY *ec = NULL;
return EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
}
Run Code Online (Sandbox Code Playgroud)
如果我使用 GCC 编译gcc -Wall -Wextra -c -O3 testfunc.c -o testfunc.o并使用objdump -D testfunc.o它查看生成的代码,它看起来像:
0000000000000000 <testfun>:
0: 48 83 ec 08 sub $0x8,%rsp
4: 31 ff xor %edi,%edi
6: e8 00 00 00 00 callq b <testfun+0xb>
b: 48 83 c4 08 add $0x8,%rsp
f: 48 89 c7 mov %rax,%rdi
12: e9 00 00 00 00 jmpq 17 <testfun+0x17>
Run Code Online (Sandbox Code Playgroud)
上面的代码似乎是正确的,因为第一个函数调用的 64 位返回值(RAX 中的指针)按预期传递给第二个函数调用。该代码也没有将AL设置为零。
但是,如果我采用相同的代码并注释掉函数的原型,如下所示:
#include <stdlib.h>
typedef struct ec_group_st EC_GROUP;
typedef struct ec_key_st EC_KEY;
/*int EC_GROUP_get_curve_name(const EC_GROUP *group);
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);*/
int testfun()
{
EC_KEY *ec = NULL;
return EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
}
Run Code Online (Sandbox Code Playgroud)
我得到这个生成的代码:
0000000000000000 <testfun>:
0: 48 83 ec 08 sub $0x8,%rsp
4: 31 ff xor %edi,%edi
6: 31 c0 xor %eax,%eax
8: e8 00 00 00 00 callq d <testfun+0xd>
d: 48 83 c4 08 add $0x8,%rsp
11: 89 c7 mov %eax,%edi
13: 31 c0 xor %eax,%eax
15: e9 00 00 00 00 jmpq 1a <testfun+0x1a>
Run Code Online (Sandbox Code Playgroud)
现在我们有RAX(AL是的低8位RAX)被设为零,并从第一个函数调用的返回值被视为32位int,类似于您所看到的行为。我建议至少构建您的C文件-Wall -Wextra以查看更多种类的警告。在没有原型的代码的情况下,我的编译器抛出了这些警告:
testfunc.c: In function ‘testfun’:
testfunc.c:12:12: warning: implicit declaration of function ‘EC_GROUP_get_curve_name’ [-Wimplicit-function-declaratio
]
return EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
^~~~~~~~~~~~~~~~~~~~~~~
testfunc.c:12:36: warning: implicit declaration of function ‘EC_KEY_get0_group’ [-Wimplicit-function-declaration]
return EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
^~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
我会在您的构建输出中寻找关于隐式声明的类似警告,并在您的代码中验证函数原型是否已正确包含。
| 归档时间: |
|
| 查看次数: |
89 次 |
| 最近记录: |