【发布时间】:2017-06-12 10:05:46
【问题描述】:
我有一个这样声明的函数:
void
tesysLog(W16 uid, char *file, int line, int level,
W16 state, W16 event, int error, char *format, ...)
上面还有一个函数会调用tesysLog,例如:
tesysLog(253, __FILE__, __LINE__, 3, 0, 0, result,
"error(code = %d) is %d instead of %d\n",
avp->header.code, decoded, size);
上述调用的相关汇编代码如下:
0x00000000009027e5 <+117>: xor %r9d,%r9d <---- clear r9d, means argv6 event = 0
0x00000000009027e8 <+120>: mov 0x8,%edx <---- absolute address, but 0x8 is in reserved segment, crash here
0x00000000009027ef <+127>: xor %r8d,%r8d
0x00000000009027f2 <+130>: mov $0x3,%ecx
0x00000000009027f7 <+135>: mov $0x995600,%esi
0x00000000009027fc <+140>: mov $0xfd,%edi
0x0000000000902801 <+145>: mov %ebp,0x20(%rsp)
0x0000000000902805 <+149>: mov %eax,0x18(%rsp)
0x0000000000902809 <+153>: xor %eax,%eax
0x000000000090280b <+155>: movq $0x995770,0x8(%rsp)
0x0000000000902814 <+164>: mov %edx,0x10(%rsp)
0x0000000000902818 <+168>: mov $0x8a,%edx
0x000000000090281d <+173>: movl $0xc8e4,(%rsp)
0x0000000000902824 <+180>: callq 0x9136e0 <tesysLog>
我在汇编代码的第二行 mov 0x8,%edx 处收到信号 11,分段错误。看起来这一行是为 tesysLog 调用准备 arg3(int 行)。但是这里,由于使用的是“绝对地址”,并且0x8在进程地址空间的保留段中,依次发出Segmentation fault。
这些代码在 SLES 上运行,并由 gcc 编译。
我想知道为什么要使用“绝对地址”。是 gcc 的 bug,还是有编译选项影响这个?
【问题讨论】:
-
啊,是的,我稍后在您的汇编输出中看到
callq指令调用tesysLog函数。你是正确的关于从绝对地址移动。您能否告诉我们您是如何构建代码的,您为 GCC 提供了哪些标志(用于编译和链接),最重要的是尝试创建一个 Minimal, Complete, and Verifiable Example 向我们展示。 -
我会从我们的客户那里得到这些信息。在此之前,是否有编译选项会影响此行为?喜欢 -fPIC?
-
mov 0x8,%edx会将常量 8 加载到 edx 中,这根本不会崩溃。你能做一个 objdump 来显示使用的指令,只是为了确保? -
您能否向我们展示您的整个程序或从中派生的最小示例?我看不出您发布的 sn-p 是如何导致此错误的,一定是我遗漏了一些东西。
-
它不是 gcc 认为在 0x08 中的“LINE”,它是压入堆栈的第三个最后一个参数,所以很可能是“header.code”(edx 是 - 短在调用之前 - 存储在 rsp+10 中,然后加载 0x8a(第 138 行)。如果您向我们展示了代码,那很可能表明您访问此代码是错误的。 (感谢@CodyGray 解决了关于调用约定的问题)