Search code examples
c++clinkershared-librariesgot

how to fill off global offset table?


Motivation:

I want to test gcc's limition size of global offset table on my arch(x86).

What I have done:

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:

  • use a decent editor like emacs to generate more functions like these
  • use a decent codegen to generate such codes at preprocess time like macro (but I cannot find a solution with macro)

Of course, there may be more ways to achieve this goal.

Question:

How to reach the limit of the global offset table?


Solution

  • 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.