ld --export-dynamic for just one library? - c

It's possible to pass --export-dynamic to ld and this will export symbols in the program (so that they are available to any shared libraries loaded at run-time):
$ cat > test.c
void foo() {}
int main() { foo(); }
^D
$ gcc test.c
$ nm -D a.out | grep foo
...nothing. And now:
$ gcc -Wl,--export-dynamic test.c
$ nm -D a.out | grep foo
0000000000001129 T foo
...works.
This is documented in https://sourceware.org/binutils/docs-2.34/ld/Options.html#Options
Is it possible to just export symbols from one particular static library?
Given like:
$ gcc myprogram.cc lib1.a lib2.a lib3.a
Say I just wanted to export symbols in the program from lib2.a, but not lib1.a or lib3.a?
I tried:
$ gcc myprogram.cc lib1.a -Wl,--export-dynamic lib2.a -Wl,--no-export-dynamic lib3.a
but it doesn't work, it looks like --export-dynamic is global.
(The documentation mentions --dynamic-list=listfile but I didn't understand the format of the file, or how to extract the symbol list from the static library?)

how to extract the symbol list from the static library?
nm staticlib.a | awk 'some parsing here, mostly {print $3}'
didn't understand the format of the file
I also don't, but I've found this link: https://sourceware.org/legacy-ml/binutils/2010-01/msg00416.html . The file should contain:
{
foo;
};
ld --export-dynamic for just one library?
Untested:
gcc myprogram.cc lib1.a lib2.a \
-Wl,--dynamic-list=<(echo '{'; nm lib1.a | awk '{print $3";"}'; echo '};')

Related

Can't link custom shared library with gcc

I'm trying to write my own shared library to link to an executable, but can't get the .so to link.
I'm using a very basic example to try and get it working. The shared library (test_lib.c):
#include "test_lib.h" //stdlib includes and function prototype
char *hello(void) {
char *c = malloc(100);
memcpy(c, "hello\n", 7);
return c;
}
The executable (test.c):
#include "test_lib.h"
int main() {
printf("%s", hello());
return 0;
}
Following all the guides I can find, I compile the .so with gcc -I . -fPIC -shared -o test_lib.so test_lib.c, and then the executable (in the same directory) with gcc -I . -L . test.c -ltest_lib
This gives the error:
/usr/bin/ld: cannot find -ltest_lib
collect2: error: ld returned 1 exit status
As I understand including the path through the -L flag should tell gcc where to find the .so, but this isn't working. What am I missing here?
When linking a library, the library usually has to be named libxxx.a|so for the linker to find it.
Compiling the library:
gcc -I . -fPIC -shared -o libtest.so test_lib.c
Then you can link with:
gcc -I . -L . test.c -ltest

how to hide local symbol for linux static library

I'm going to ship a to static library to a customer.
To maximize the privacy of the library I have restricted symbols for the static library using the technique provided by #ypsu Symbol hiding in static libraries built with Xcode
However, the above mentioned method only restrict the user from calling the hidden functions, the name of the hidden function names are still visible to "nm" or "strings".
The names for hidden function are very sensitive. How do I hide or remove this information from the static library ?
I have lately approached the same problem. I decided to rename all public symbols to it's md5sum so that the names are not visible to the user, including the filenames. A following example tries to demonstrate it:
cat >priv.c <<EOF
#include <stdio.h>
void priv() { printf("Hello, private function\n"); }
EOF
cat >interface.c <<EOF
void priv();
void interface() { priv(); }
EOF
cat >main.c <<EOF
void interface();
int main() {
interface();
}
EOF
cat >compile.sh <<EOF3
#!/bin/bash
namespace="namespace_"
# compile to object files
gcc -c -o priv.o priv.c
gcc -c -o interface.o interface.c
# rename the object file so the names of files are not visible
nofilename="$(echo "nofilenames" | md5sum | cut -d' ' -f1).o"
ld -relocatable priv.o interface.o -o "$nofilename"
# create the static library
ar rcs static.a "$nofilename"
# list of interface symbols
public_symbols=( interface )
# list of private symbols - all symbols except interface symbols
private_symbols=($(
nm static.a | sed '/^[0-9]\+ T /!d; s///' |
sort | comm -13 <(printf "%s\n" "${public_symbols[#]}" | sort) -
))
# strip unused symbols, leave only interface symbols
strip_args=($(printf " -K %s " "${public_symbols[#]}"))
strip --strip-unneeded --strip-debug "${strip_args[#]}" static.a
# rename all private symbols with it's md5sum
objcopy_args=($(
printf "%s\n" "${private_symbols[#]}" |
while IFS= read -r sym; do
new="${namespace}$(echo "$sym" | md5sum | cut -d' ' -f1)"
# replace the symbol with it's md5sum
echo --redefine-sym "$sym=$new"
# make the symbol local
echo -L "$new"
done
))
objcopy "${objcopy_args[#]}" static.a
gcc main.c static.a
# testing
set -x
nm static.a
strings static.a
./a.out
EOF3
The ./compile.sh script would output:
+ nm static.a
b8c84a861a264dfcb24ebf32892484dd.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000013 T interface
0000000000000000 t namespace_6b2f60f631c17ca910498adb47387adf
U puts
+ strings static.a
!<arch>
/ 0 0 0 0 18 `
interface
// 36 `
b8c84a861a264dfcb24ebf32892484dd.o/
/0 0 0 0 644 1744 `
Hello, private function
GCC: (Arch Linux 9.3.0-1) 9.3.0
GCC: (Arch Linux 9.3.0-1) 9.3.0
namespace_6b2f60f631c17ca910498adb47387adf
puts
interface
_GLOBAL_OFFSET_TABLE_
.symtab
.strtab
.shstrtab
.rela.text
.rodata
.rela.eh_frame
.data
.bss
.comment
.note.GNU-stack
+ ./a.out
Hello, private function
The priv symbol was renamed to namespace_6b2f60f631c17ca910498adb47387adf and source files were combined into one b8c84a861a264dfcb24ebf32892484dd.o object file with ld -relocatable. I am open to more suggestions on how to improve such script.
The template shown emerged into a bigger script ,ar_hide_symbols.

Symbol not found when static linking on MacOSX

I am trying to create a static library and link it on MacOS X (several versions):
File foo.c:
char foo[111];
File bar.c:
#include <string.h>
extern char foo[];
int bar(char *src) {
strcpy(foo, src);
return strlen(foo);
}
Create a library:
$ cc -c foo.c bar.c
$ ar r libfoobar.a foo.o bar.o
ar: creating archive libfoobar.a
$ ranlib libfoobar.a
$ nm libfoobar.a
libfoobar.a(foo.o):
000000000000006f C _foo
libfoobar.a(bar.o):
U ___strcpy_chk
0000000000000000 T _bar
U _foo
U _strlen
Create a small test program:
File main.c:
#include <stdio.h>
int bar(char *);
int main(void) {
printf("foobarbar = %i\n", bar("123"));
return 0;
}
Compile and link:
$ cc -c main.c
$ cc -o m main.o -L. -lfoobar
Undefined symbols for architecture x86_64:
"_foo", referenced from:
_bar in libfoobar.a(bar.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Why is the symbol not found? It is defined in foo.c? Shouldn't at least ranlib create an index in the library that allows a random order of the files there?
The same code works well under Linux (gcc), and also when the symbol in foo.c is not a char array, but an int.
There is a similar question: Object files not properly added to archive on mac which has this answer:
Option 1:
ar -rs my_archive.a foo.o bar.o other_object_files.o
ranlib -c my_archive.a
Option 2:
libtool -c -static -o my_archive.a foo.o bar.o other_object_files.o
It is -c flag that makes a difference for both options on ranlib and libtool respectively:
-c
Include common symbols as definitions with respect to the table
of contents. This is seldom the intended behavior for linking
from a library, as it forces the linking of a library member
just because it uses an uninitialized global that is undefined
at that point in the linking. This option is included only
because this was the original behavior of ranlib. This option
is not the default.

C - Print value stored at symbol location

I have a simple command line application (custom dir binary) which I would like to instrument. The debug symbols are enabled, and I can see the global string pointer I'm interested in, the_full_path_name in the output of objdump and nm -D.
Is it possible, in c, to somehow lookup that symbol name/location, and print the contents of the memory which it points at using code injection (ie: LD_PRELOAD library with a custom gcc attribute((constructor)) and additional functions)? I need to accomplish this without having to attach gdb to the process.
Thank you.
I am not really sure if i understood your question but does following help you anyways?
File containing global pointer
$ cat global.c
char mylongstring[] = "myname is nulled pointer";
$ gcc -fPIC -shared global.c -o libglobal.so
Original library
$ cat get_orig.c
#include <stdio.h>
extern char * mylongstring;
char *get()
{
mylongstring = "get from orig";
return mylongstring;
}
$ gcc -fPIC -shared get_orig.c -o libget_orig.so -L. -lglobal
Fake Library
$ cat get_dup.c
#include <stdio.h>
extern char * mylongstring;
char *get()
{
mylongstring = "get from dup";
return mylongstring;
}
$ gcc -fPIC -shared get_dup.c -o libget_dup.so -L. -lglobal
Actual consumer of global variable:
$ cat printglobal.c
#include <stdio.h>
char *get();
int main(void)
{
printf("global value=%s\n",get());
return 0;
}
$ gcc printglobal.c -L. -lglobal -lget_orig -o a.out
otool output
$ otool -L a.out
a.out:
libglobal.so (compatibility version 0.0.0, current version 0.0.0)
libget_orig.so (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
Running a.out
$ DYLD_LIBRARY_PATH=./ ./a.out
global value=get from orig
Replace library
$ cp /tmp/libget_dup.so libget_orig.so
$ DYLD_LIBRARY_PATH=./ ./a.out
global value=get from dup
BTW, i tested this on MAC so .so is really a misnomer for .dylib

C, Linker: How to use weak symbols with static library

I have a large code base which is mainly built as binary. I have changed the Makefile to create a static library and I am creating a binary linking the library.
When I use it as a static library, code doesn't run due to weak symbols undefined reference.
gcc test.c -L . -lasntc -ltc -lresolv -lnetlink -lutil -ltc -lm -o mytc
nm mytc | grep htb_qdisc_util
w htb_qdisc_util
I untared the archives which resulted in .o's and then using those object files, I created a binary and this however works as shown
gcc tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o tc_monitor.o
m_police.o m_estimator.o m_action.o m_ematch.o emp_ematch.yacc.o
emp_ematch.lex.o asn_tc.o asn_global.o q_fifo.o q_sfq.o q_red.o q_prio.o q_tbf.o
q_cbq.o q_rr.o q_multiq.o q_netem.o f_rsvp.o f_u32.o f_route.o f_fw.o f_basic.o
f_flow.o f_cgroup.o q_dsmark.o q_gred.o f_tcindex.o q_ingress.o q_hfsc.o q_htb.o
q_drr.o q_qfq.o m_gact.o m_mirred.o m_nat.o m_pedit.o m_skbedit.o p_ip.o
p_icmp.o p_tcp.o p_udp.o em_nbyte.o em_cmp.o em_u32.o em_meta.o q_mqprio.o static-syms.o tc_core.o tc_red.o tc_cbq.o tc_estimator.o tc_stab.o -lresolv -L. -lnetlink -lutil -L. -lm -o tc
nm tc | grep htb_qdisc_util
0000000000641bc0 D htb_qdisc_util
Just looking at the object files symbol table, following is seen
nm *.o | grep htb_qdisc_util
0000000000000000 D htb_qdisc_util
w htb_qdisc_util
Weak symbols resulting due to
extern char hfsc_qdisc_util[] __attribute__((weak)); if (!strcmp(sym, "hfsc_qdisc_util")) return hfsc_qdisc_util;
extern char htb_qdisc_util[] __attribute__((weak)); if (!strcmp(sym, "htb_qdisc_util")) return htb_qdisc_util;
How do I create a static library and what is happening when I create a binary

Resources