如何填写全局偏移量table?
how to fill off global offset table?
动机:
我想在我的 arch(x86) 上测试 gcc 的全局偏移大小限制 table。
我做了什么:
在共享库中使用多个未声明的函数(gcc -nostdlib -shared -o got.so ./got.c
)
// got.c
extern int itestvariable1;
extern int testvariable2;
void test(void)
{
fun1();
...
fun8();
}
和readelf --relocs ./got.so
:
Relocation section '.rela.plt' at offset 0x3a8 contains 8 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000004018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 fun7 + 0
000000004020 000200000007 R_X86_64_JUMP_SLO 0000000000000000 fun3 + 0
000000004028 000300000007 R_X86_64_JUMP_SLO 0000000000000000 fun4 + 0
000000004030 000400000007 R_X86_64_JUMP_SLO 0000000000000000 fun8 + 0
000000004038 000500000007 R_X86_64_JUMP_SLO 0000000000000000 fun2 + 0
000000004040 000600000007 R_X86_64_JUMP_SLO 0000000000000000 fun6 + 0
000000004048 000700000007 R_X86_64_JUMP_SLO 0000000000000000 fun1 + 0
000000004050 000800000007 R_X86_64_JUMP_SLO 0000000000000000 fun5 + 0
......
如上所示,全局偏移量table由fun1-8
填充,但要填充到极限大小,远远不够。我可以想到两种方法:
- 使用像 emacs 这样的像样的编辑器来生成更多像这样的函数
- 使用像样的代码生成器在预处理时生成这样的代码,比如宏(但我找不到宏的解决方案)
当然,实现这个目标的方法可能更多。
问题:
如何达到全局偏移量的限制table?
在测试限制之前,了解限制是什么通常很有帮助。如果您只需要一打,那么声明数千个函数的技巧就太过分了。那么 GOT 的大小限制是什么? According to Red Hat: "These maximums are 8k on the SPARC and 32k on the m68k and RS/6000. The 386 has no such limit."
了解限制有两个要点。首先,尝试重载 GOT 确实需要一种可以相当轻松地生成数千个 GOT 条目的方法。其次,在您的架构(x86)上,这是一项没有希望的任务,因为没有限制。
(对于那些对我如何发现 link 感兴趣的人:我刚刚在网上搜索 "global offset table size restriction"。)
对于其他架构的人,我认为扩展问题示例代码的一种简单方法是编写另一个程序来生成它。
#include <fstream>
constexpr unsigned NUM_FUN = 70000;
int main()
{
std::ofstream out("got.c");
out << "void test(void)\n{\n";
for ( unsigned i = 0; i < NUM_FUN; ++i )
out << "\tfun" << i << "();\n";
out << "}\n";
}
编译并运行生成一个got.c
文件,该文件调用的函数比适合m68k的全局偏移量table格式的函数多。
动机:
我想在我的 arch(x86) 上测试 gcc 的全局偏移大小限制 table。
我做了什么:
在共享库中使用多个未声明的函数(gcc -nostdlib -shared -o got.so ./got.c
)
// got.c
extern int itestvariable1;
extern int testvariable2;
void test(void)
{
fun1();
...
fun8();
}
和readelf --relocs ./got.so
:
Relocation section '.rela.plt' at offset 0x3a8 contains 8 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000004018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 fun7 + 0
000000004020 000200000007 R_X86_64_JUMP_SLO 0000000000000000 fun3 + 0
000000004028 000300000007 R_X86_64_JUMP_SLO 0000000000000000 fun4 + 0
000000004030 000400000007 R_X86_64_JUMP_SLO 0000000000000000 fun8 + 0
000000004038 000500000007 R_X86_64_JUMP_SLO 0000000000000000 fun2 + 0
000000004040 000600000007 R_X86_64_JUMP_SLO 0000000000000000 fun6 + 0
000000004048 000700000007 R_X86_64_JUMP_SLO 0000000000000000 fun1 + 0
000000004050 000800000007 R_X86_64_JUMP_SLO 0000000000000000 fun5 + 0
......
如上所示,全局偏移量table由fun1-8
填充,但要填充到极限大小,远远不够。我可以想到两种方法:
- 使用像 emacs 这样的像样的编辑器来生成更多像这样的函数
- 使用像样的代码生成器在预处理时生成这样的代码,比如宏(但我找不到宏的解决方案)
当然,实现这个目标的方法可能更多。
问题:
如何达到全局偏移量的限制table?
在测试限制之前,了解限制是什么通常很有帮助。如果您只需要一打,那么声明数千个函数的技巧就太过分了。那么 GOT 的大小限制是什么? According to Red Hat: "These maximums are 8k on the SPARC and 32k on the m68k and RS/6000. The 386 has no such limit."
了解限制有两个要点。首先,尝试重载 GOT 确实需要一种可以相当轻松地生成数千个 GOT 条目的方法。其次,在您的架构(x86)上,这是一项没有希望的任务,因为没有限制。
(对于那些对我如何发现 link 感兴趣的人:我刚刚在网上搜索 "global offset table size restriction"。)
对于其他架构的人,我认为扩展问题示例代码的一种简单方法是编写另一个程序来生成它。
#include <fstream>
constexpr unsigned NUM_FUN = 70000;
int main()
{
std::ofstream out("got.c");
out << "void test(void)\n{\n";
for ( unsigned i = 0; i < NUM_FUN; ++i )
out << "\tfun" << i << "();\n";
out << "}\n";
}
编译并运行生成一个got.c
文件,该文件调用的函数比适合m68k的全局偏移量table格式的函数多。