I want to test gcc's limition size of global offset table on my arch(x86).
use multiple undeclared functions in a shared library (gcc -nostdlib -shared -o got.so ./got.c
)
// got.c
extern int itestvariable1;
extern int testvariable2;
void test(void)
{
fun1();
...
fun8();
}
and 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
......
As above shows, the global offset table filled by fun1-8
, but to fill reach the limition size, it is far from enough. I can think of two ways:
Of course, there may be more ways to achieve this goal.
How to reach the limit of the global offset table?
Before testing a limit, it is often helpful to know what the limit is. The tricks for declaring thousands of functions would be overkill if all you need is a dozen. So what are the size limitations of a 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."
There are two takeaways from knowing the limits. First, trying to overload the GOT does require a method that can reasonably easily generate thousands of GOT entries. Second, on your architecture (x86), this is a hopeless task as there is no limit.
(For those interested in how I found that link: I just searched the web for "global offset table size restriction".)
For those on other architectures, I suppose an easy way to expand the question's example code is to write another program to generate it.
#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";
}
Compile and run this to generate a got.c
file that calls more functions than will fit in a m68k's global offset table format.