The short answer to your question is that you should remove the -shared
option in your compilation command. This will produce a "normal" executable that will have a start address and that must have a main function.
While answering your question, I came up with a question myself that I asked on StackOverflow which you can browse at: In shared objects, why does gcc relocate through the GOT for global variables which are defined in the same shared object?.
The main reason for having to remove -shared
is that the -fpie
option is on by default when you compile with gcc. This produces position-independent code that will access the data segment of the executable using RIP-relative addressing. As stated in my own question (linked above), RIP-relative addressing is limited to a 32 bits offset (due to x86-64 machine code limitations). Now I wondered why this is a problem. The problem really lies with symbol interposition. If you redefine a symbol in another shared library or in the main program loaded alongside your own shared library, then this symbol may be "chosen" to be the actual symbol that is going to be used during execution. This is a problem because, if the shared library is farther away than a 32 bits offset from this redefinition, then it will overflow and the code of the shared library will not be able to access that symbol.
This is the cause of the relocation R_X86_64_PC32 against symbol `myglob' can not be used when making a shared object; recompile with -fPIC
error which states that a RIP-relative addressing relocation is illegal in a shared object for accessing a symbol that is exported because that symbol may be interposed.
You can avoid exporting symbols by making the symbol hidden with __attribute__ ((visibility ("hidden")))
. This will prevent gcc from exporting the symbol and thus interposition possibility becomes non-existent. The symbol will thus be accessed using RIP-relative addressing without indirection through the GOT.