/* 0. Generate $ g++ generate.cpp $ ./a.out 1. static linking $ $EDITOR generate.cpp # remove "-rpath /usr/local/lib" argument, perform "0. Generate steps" $ make -j8 test time libtool --mode=execute ./program 0,01 real 0,00 user 2. dynamic linking DT_HASH (*) $ make -j8 test time libtool --mode=execute ./program 0,36 real 0,34 user 0,02 sys 3. dynamic linking DT_GNU_HASH (*) $ make LDFLAGS="-Wl,--hash-style=gnu" -j8 test time libtool --mode=execute ./program 0,17 real 0,14 user 0,03 sys (*) Tested exactly the same set of .c and .h files. ----- Tested natively on: $ uname -a NetBSD chieftec 9.99.48 NetBSD 9.99.48 (GENERIC) #0: Wed Feb 26 16:14:54 CET 2020 root@chieftec:/public/netbsd-root/sys/arch/amd64/compile/GENERIC amd64 $ cpuctl identify 0 Cannot bind to target CPU. Output may not accurately describe the target. Run as root to allow binding. cpu0: highest basic info 0000000d cpu0: highest extended info 80000008 cpu0: "Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz" cpu0: Intel Xeon E3-1200v2 and 3rd gen core, Ivy Bridge (686-class), 3392.48 MHz cpu0: family 0x6 model 0x3a stepping 0x9 (id 0x306a9) cpu0: features 0xbfebfbff cpu0: features 0xbfebfbff cpu0: features 0xbfebfbff cpu0: features1 0x7fbae3ff cpu0: features1 0x7fbae3ff cpu0: features1 0x7fbae3ff cpu0: features2 0x28100800 cpu0: features3 0x1 cpu0: features5 0x281 cpu0: xsave features 0x7 cpu0: xsave instructions 0x1 cpu0: xsave area size: current 832, maximum 832, xgetbv enabled cpu0: enabled xsave 0x7 cpu0: I-cache 32KB 64B/line 8-way, D-cache 32KB 64B/line 8-way cpu0: L2 cache 256KB 64B/line 8-way cpu0: L3 cache 8MB 64B/line 16-way cpu0: 64B prefetching cpu0: ITLB 64 4KB entries 4-way, 2M/4M: 8 entries cpu0: DTLB 64 4KB entries 4-way, 2M/4M: 32 entries (L0) cpu0: L2 STLB 512 4KB entries 4-way cpu0: Initial APIC ID 0 cpu0: Cluster/Package ID 0 cpu0: Core ID 0 cpu0: SMT ID 0 cpu0: MONITOR/MWAIT extensions 0x3 cpu0: monitor-line size 64 cpu0: C1 substates 2 cpu0: C2 substates 1 cpu0: C3 substates 1 cpu0: DSPM-eax 0x77 cpu0: DSPM-ecx 0x9 cpu0: SEF highest subleaf 00000000 cpu0: Perfmon-eax 0x7300403 cpu0: Perfmon-eax 0x7300403 cpu0: Perfmon-edx 0x603 cpu0: microcode version 0x15, platform ID 1 */ #include #include #include #include #include #include static const size_t LIBS = 50; static const size_t LENGTH = 25; static const size_t SYMBOLS = 2000; std::string generate_symbol() { std::random_device rd; std::mt19937 engine(rd()); // First character std::string first_characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; std::uniform_int_distribution<> first_dist(0, first_characters.size() - 1); std::string s = ""; s += first_characters[first_dist(engine)]; std::string characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; std::uniform_int_distribution<> dist(0, characters.size() - 1); for (size_t i = 0; i < (LENGTH - 1); i++) s += characters[dist(engine)]; return s; } int main(int argc, char **argv) { std::set symbols; std::ofstream makefile; makefile.open("Makefile", std::ofstream::out); makefile << "CFLAGS?=" << std::endl; makefile << "LDFLAGS?=" << std::endl; makefile << "LIBTOOL?=libtool" << std::endl; makefile << "CC?=gcc" << std::endl; makefile << std::endl; makefile << "all: build" << std::endl; makefile << "build: program" << std::endl; makefile << std::endl; std::ofstream program; program.open("program.c", std::ofstream::out); for (size_t i = 0; i < LIBS; i++) { std::string lib = "bibliotheca" + std::to_string(i); std::string header = lib + ".h"; std::string code = lib + ".c"; std::ofstream hfile; hfile.open (header.c_str(), std::ofstream::out); std::ofstream cfile; cfile.open (code.c_str(), std::ofstream::out); cfile << "#include \"" << header << "\"" << std::endl; program << "#include \"" << header << "\"" << std::endl; for (size_t symbol = 0; symbol < SYMBOLS; symbol++) { std::string s; /* Assure that symbol will be unique */ do { s = generate_symbol(); } while (symbols.find(s) != symbols.end()); symbols.insert(s); hfile << "extern int " << s << "();" << std::endl; cfile << "int " << s << "() {return 0;}" << std::endl; } hfile.close(); cfile.close(); makefile << "lib" << lib << ".la: " << code.substr(0, code.size() - 1) << "o " << header << std::endl; makefile << "\t" << "${LIBTOOL} --mode=link --tag=CC ${CC} -avoid-version ${LDFLAGS} -o $@ " << lib << ".lo -rpath /usr/local/lib" << std::endl; makefile << std::endl; } program << "int main(int argc, char **argv) { return 0 + " << std::endl; std::for_each(symbols.begin(), symbols.end(), [&program](const std::string &str) { program << "+" << str << "()" << std::endl; }); program << ";}" << std::endl; program.close(); makefile << "program: libbibliotheca0.la"; for (size_t i = 1; i < LIBS; i++) { std::string lib = "bibliotheca" + std::to_string(i); makefile << " lib" << lib << ".la"; } makefile << std::endl; makefile << "\t" << "${CC} ${CFLAGS} -o program.o -c program.c" << std::endl; makefile << "\t" << "${LIBTOOL} --mode=link --tag=CC ${CC} ${LDFLAGS} -o $@ program.o libbibliotheca0.la"; for (size_t i = 1; i < LIBS; i++) { std::string lib = "bibliotheca" + std::to_string(i); makefile << " lib" << lib << ".la"; } makefile << std::endl; makefile << std::endl; makefile << "test: program" << std::endl; makefile << "\t" << "time ${LIBTOOL} --mode=execute ./program" << std::endl; makefile << std::endl; makefile << ".SUFFIXES: .c .o " << std::endl; makefile << ".c.o:" << std::endl; makefile << "\t" << "${LIBTOOL} --mode=compile --tag=CC ${CC} ${CFLAGS} -I. -o $@ -c $<" << std::endl; makefile.close(); return 0; }