Linking in AIX
gcc -o executable -Wl,-blibpath:/usr/local/lib64:/usr/libYou can check the result with dump(1)
$ dump -H -X32_64 executable ... INDEX PATH BASE MEMBER 0 /usr/local/lib64:/usr/lib ...
gcc -o executable -Wl,-brtl,-bipath -la /usr/local/lib/libb.so.2Check:
$ dump -H -X32_64 executable ... INDEX PATH BASE MEMBER ... 1 liba.so 2 /usr/local/lib libb.so.2
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/4.8.3/libgcc_s.a /opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/4.8.3/ppc64/libgcc_s.a /opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/4.8.3/pthread/libgcc_s.a /opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/4.8.3/pthread/ppc64/libgcc_s.a
$ dirname $(gcc -pthread -maix64 -print-file-name=libgcc_s.a) /opt/freeware/lib/gcc/powerpc-ibm-aix6.1.1.0/5.4.0/pthread/ppc64Nontheless I suggest you link/copy your latest/only libgcc_s.a file into directory /usr/local/lib[64] and use that. Here as an example, my libiconv.so file(s):
$ ls -l /usr/local/lib64/libiconv.so* lrwxrwxrwx 1 root system 17 Dec 29 /usr/local/lib64/libiconv.so -> libiconv.so.2.5.1 lrwxrwxrwx 1 root system 17 Dec 29 /usr/local/lib64/libiconv.so.2 -> libiconv.so.2.5.1 -rw-r--r-- 1 root system 1139080 Dec 29 /usr/local/lib64/libiconv.so.2.5.1 $ dump -X32_64 -H /usr/local/lib64/libiconv.so.2 INDEX PATH BASE MEMBER 0 /usr/local/lib64:/usr/lib:/lib 1 /usr/local/lib64 libgcc_s.a shr.o 2 /usr/local/lib64 libcpotlas.so.1 3 /usr/lib libc.a shr_64.o
$ grep fopen64 /usr/include/stdio.h #define fopen fopen64 extern FILE *fopen64(const char *, const char *);Because of this define, if you compile PHP from source, you might end up with a PHP-program that doesn't have a fopen built-in function, only a 'fopen64'.
181 /* Only one for the following should be defined */ 182 #undef SIXTY_FOUR_BIT_LONG 183 #undef SIXTY_FOUR_BIT 184 #undef THIRTY_TWO_BIT 185 #if defined(__64BIT__) 186 # define SIXTY_FOUR_BIT_LONG 187 #else 188 # define THIRTY_TWO_BIT 189 #endif
printf ("major=%llx minor=%llx\n", #if defined(_AIX) && __SIZEOF_POINTER__ == 8 (long long)major64(st.st_dev), (long long)minor64(st.st_dev) #else (long long)major(st.st_dev), (long long)minor(st.st_dev) #endif );
0509-136 Symbol __pthread (number 35) is not exported from dependent module /usr/lib/libpthreads.a[shr_xpg5_64.o].A: You have a program that was created under a newer version of AIX then moved back to version 5.x Mind you, this would work in 32-bit; in that variant this __pthread symbol is exported from /usr/lib/libpthreads.a[shr_xpg5.o]
chdev -l sys0 -a fullcore=true # enabling lsattr -l sys0 -a fullcore -E # verifying
$ dump -X32_64 -H /usr/local/bin/gengetopt INDEX PATH BASE MEMBER 0 /usr/local/lib64:/usr/lib:/lib 1 /usr/local/lib64 libgcc_s.a shr.o 2 /usr/local/lib64 libstdc++.so.6 3 /usr/local/lib64 libcpotlas.so 4 /usr/lib libpthreads.a shr_xpg5_64.o 5 /usr/lib libc.a shr_64.oHere file /usr/local/lib64/libstdc++.so.6 has come from /opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/4.8.3/pthread/ppc64/libstdc++.a Note: I got this name with the following command:
g++ -maix64 -pthread -print-file-name=libstdc++.a
#!/usr/local/bin/bash # bash is important as it has option 'pipefail' export PATH=/usr/local/bin:/opt/freeware/bin:$PATH export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig:$PKG_CONFIG_PATH make distclean || make clean set -e set -o pipefail export CFLAGS='-maix64' export CXXFLAGS='-maix64' export CPPFLAGS='-I/usr/local/include' export LDFLAGS='-maix64 -L/usr/local/lib64 -L/opt/freeware/lib64 -Wl,-brtl,-bipath,-blibpath:/usr/local/lib64:/opt/freeware/lib64:/usr/lib' ./configure \ --prefix=/usr/local \ --libdir=/usr/local/lib64 \ CFLAGS="$CFLAGS" \ CXXFLAGS="$CXXFLAGS" \ CPPFLAGS="$CPPFLAGS" \ LDFLAGS="$LDFLAGS" \ AR='/usr/bin/ar -X64' \ NM='/usr/bin/nm -X64' \ SIZE='/usr/bin/size -X64' \ 2>&1 | tee log.configure make all 2>&1 | tee log.make.all make install 2>&1 | tee log.make.install echo 'Ok(?)'
#!/bin/sh if test $# -ne 2; then echo "usage: $0 script file" exit 1 fi TMPFILE=/tmp/sed_repl.$$ set -e sed -e "$1" <"$2" >"$TMPFILE" cp "$TMPFILE" "$2" rm "$TMPFILE"
# common problem #1 # configure forces '/usr/local/lib' instead of /usr/local/lib64 # insert this before 'configure' find . -name configure -o -name 'config.*' | while read C; do sed_repl 's;/usr/local/lib;/usr/local/lib64;g s;/usr/local/lib6464;/usr/local/lib64;g s;/usr/local/lib64exec;/usr/local/libexec;g ' "$C" done # common problem #2 # configure does funny things with some "hardcoding" that breaks compilation find . -name configure -o -name config.rpath |\ while read C; do sed_repl 's|hardcode_direct=.*$|hardcode_direct=no| s|hardcode_libdir_flag_spec=.*$|hardcode_libdir_flag_spec=| ' "$C" done # common problem #3 # configure ingnores "$AR", so -X32_64 option isn't passed to /usr/bin/ar # insert this between 'configure' and 'make' find . -name Makefile | while read M; do sed_repl 's/^AR = .*$/AR = /usr/bin/ar -X32_64 ' "$M" done # common problem #4 # Makefiles are full with @at-signs so that you couldn't trace problems # insert this between 'configure' and 'make' find . -name Makefile | while read M; do sed_repl "$(printf 's;^\t@;\t;')" "$M" done # common problem #5 # 'configure' checks a static library for an exported symbol, # but it checks for a function while it is actually a variable # # Example: 'configure' of 'php' checks for 'rl_pending_input' # from library 'readline' as if it were a 'function' # # Note: This problem doesn't affect shared libraries; # the reason is realated to this question: # statically linking a foobar function would require the .foobar # symbol, but variables don't have such .dotted versions. sed_repl 's/rl_pending_input ()/rl_pending_input/' configure
$ dump -X32_64 -H libphp5.so ... INDEX PATH BASE MEMBER 0 /opt/lib64:/usr/local/lib64:/usr/lib ... 23 /usr/lib libc.a shr_64.o 24 .A: This module has external symbols that are meant to be resolved from the main program. You can see these symbols with the following command:
$ dump -X32_64 -Tv libphp5.so | grep 'EXTref ' [1224] 0x00000000 undef IMP DS EXTref . ap_mpm_query [1225] 0x00000000 undef IMP DS EXTref . ap_server_root_relative ...The main program is (supposed to be) apache!httpd which exports these symbols:
$ dump -X32_64 -Tv /usr/local/sbin/httpd | grep ap_mpm_query [2261] 0x20007130 .data EXP DS Ldef [noIMid] ap_mpm_query
$ dump -X32_64 -H my_php_plugin.so ... INDEX PATH BASE MEMBER ... 5 /usr/lib libc.a shr_64.o 6 ..A: This module has external symbols that are meant to be resolved loading time, and we cannot tell yet where they will come from. Their list:
$ dump -X32_64 -Tv my_php_plugin.so | fgrep '..' [18] 0x00000000 undef IMP DS EXTref .. php_info_print_table_start [19] 0x00000000 undef IMP DS EXTref .. php_info_print_table_header [20] 0x00000000 undef IMP DS EXTref .. php_info_print_table_end [21] 0x00000000 undef IMP DS EXTref .. zend_parse_parameters [22] 0x00000000 undef IMP DS EXTref .. _estrndup [23] 0x00000000 undef IMP DS EXTref .. zend_register_long_constantThese type of unresolved externs is not welcome in AIX, you should try and avoid them. If you cannot, remember using option -brtlib when linking the main executable (note: in 32-bit mode, /usr/lib/librtl.a will be linked into the program).
# lslpp -l rpm.rte Fileset Level State Description ---------------------------------------------------------------------------- Path: /usr/lib/objrepos rpm.rte 4.15.1.1 COMMITTED RPM Package Manager # updtvpkg Please wait... # rpm -qi AIX-rpm Name : AIX-rpm Version : 7.2.5.0 ... Description : This package contains no files. It is a package which contains information about shared libraries and shell interpreters installed on the operating system.
$ ar -X64 -tv /usr/local/lib64/libiconv.a rw-r--r-- 0/0 1114345 Jul 22 17:12 2015 iconv.o rw-r--r-- 0/0 3346 Jul 22 17:12 2015 localcharset.o rw-r--r-- 0/0 2564 Jul 22 17:12 2015 relocatable.oAlso AIX iconv stores it's shared modules in (another) libiconv.a:
$ ar -X32_64 -tv /usr/lib/libiconv.a r--r--r-- 2/2 117276 Sep 15 21:15 2013 shr4.o r--r--r-- 2/2 117526 Sep 15 21:15 2013 shr.o r--r--r-- 2/2 159410 Sep 15 21:15 2013 shr4_64.oAlso some versions on GNU iconv keep shared objects in (yet another) libiconv.a:
$ ar -X32_64 -tv /opt/freeware/lib/libiconv.a # filtered output rwxr-xr-x 203/1 1100139 Feb 03 08:00 2017 libiconv.so.2 # for 32-bit rwxr-xr-x 203/1 1128141 Feb 03 07:57 2017 libiconv.so.2 # for 64-bitAnother possible source of problems that /usr/lib/libi18n.a(shr*so) depends on libiconv.a(shr*.so) (without path), so if the loading finds a libiconv.a without these shared objects, the loading fails. (It won't search for another libiconv.a archive.)
$ ar -X32_64 -tv /opt/freeware/lib/libiconv.a # complete output rwxr-xr-x 203/1 1100139 Feb 03 08:00 2017 libiconv.so.2 # GNU iconv, 32-bit rwxr-xr-x 203/1 1128141 Feb 03 07:57 2017 libiconv.so.2 # GNU iconv, 64-bit r--r--r-- 0/0 117162 Jul 19 13:04 2017 shr4.o # AIX iconv, 32-bit r--r--r-- 0/0 117412 Jul 19 13:04 2017 shr.o # AIX iconv, 32-bit r--r--r-- 0/0 159296 Jul 19 13:04 2017 shr4_64.o # AIX iconv, 64-bitIf you don't have such file, you can use ar to create something like that; as you have seen, 32- and 64-bit components can be merged in one archive (even with the same name); also the two iconv implementations (GNU and AIX) can be put into the same file without problems.
ar -X64 rcs /usr/local/lib64/libfontconfig.soa /usr/local/lib64/libfontconfig.so.1 ln -sf /usr/local/lib64/libfontconfig.soa /usr/lib/libfontconfig.a ln -sf /usr/local/lib64/libfontconfig.so.1 /usr/lib/libfontconfig.so.1 ls -l /usr/lib/libfontconfig* /usr/lib/libfontconfig.a -> /usr/local/lib64/libfontconfig.soa /usr/lib/libfontconfig.so.1 -> /usr/local/lib64/libfontconfig.so.1
slibclean remove unused shared libraries from memory genld -ld list of processes and the shared libs they use genkld -d list of shared libs loaded into memory procldd <pid> shared libs used by a process dump -X32_64 -H <module> shared libs that the <module> (directly) depends on dump -X32_64 -Tv <module> list of external symbols in <module> nm -Pg <obj> list of external symbols in <obj> ldd <module> list of shared libs <module> (directly or indirectly) depends on module: executable or shared lib obj: object module, executable or shared libBonus:
explist_so <prog> list exported symbols (this script uses 'dump -T')
code address of the first executable statement (in the text-segment) data address of the TOC (the data-area of the module) context (unused in C)The function descriptor exists in the data-segment. The TOC is a section in the object module that contains the function's data.
.globl myhello 'myhello' is a public function .globl .myhello .csect myhello[DS] DS = function descriptor myhello: .long .myhello, TOC[tc0], 0 code, toc, context(unused) .csect .text[PR] PR = code .myhello: mflr 0 actual code of 'myhello' starts here ... .lglobl .smyhello 'smyhello' is a static function .csect smyhello[DS] DS = function descriptor smyhello: .long .smyhello, TOC[tc0], 0 code, toc, context(unused) .csect .text[PR] PR = code .smyhello: mflr 0 actual code of 'smyhello' starts here ... bl .myhello 'main' calls 'myhello'part of "nm hello":
$ nm hello .myhello T 268436440 92 # public text .smyhello t 268436532 92 # local textpart of "nm -g /usr/lib/libc.a"
/usr/lib/libc.a[shr.o]: .puts T 2522688 # code puts D 478040 12 # function destructor
.text 00000164 8062000c lwz 3,LC..7(2) ; par1 .text 00000168 38800001 li 4,1 ; par2 .text 0000016c 38a00027 li 5,39 ; par3 .text 00000170 80c20004 lwz 6,LC..8(2) ; par4 .text 00000174 4bfffe8d bl .fwrite ; the actual call .text 00000178 60000000 nop ; (don't ask)When you call a function via function-pointer (functor), the pointer contains the address of the descriptor:
.text 0000020c 813f0038 lwz 9,56(31) ; r9 := descriptor of the callée .text 00000210 90410014 stw 2,20(1) ; save r2 (our TOC) .text 00000214 81490000 lwz 10,0(9) ; address of the callée .text 00000218 81690008 lwz 11,8(9) ; context of the callée .text 0000021c 7d4903a6 mtctr 10 ; ctr := r10 .text 00000220 80490004 lwz 2,4(9) ; TOC of the callée .text 00000224 4e800421 bctrl ; the actual call .text 00000228 80410014 lwz 2,20(1) ; restore r2 (our TOC)
<caller> 0xd1247334 <+56>: bl 0xd124757c ; call the 'glue code' (and set the link register) 0xd1247338 <+60>: lwz r2,20(r1) ; restore r2 (our TOC) <glue code> 0xd124757c <+0>: lwz r12,36(r2) ; r12 := descriptor of the callée 0xd1247580 <+4>: stw r2,20(r1) ; save r2 (our TOC) 0xd1247584 <+8>: lwz r0,0(r12) ; address of the callée 0xd1247588 <+12>: lwz r2,4(r12) ; TOC of the callée 0xd124758c <+16>: mtctr r0 ; address to the callée 0xd1247590 <+20>: bctr ; jump into the calléeSuch adapter-code is generated for every called function. The code comes form /usr/lib/glink*o
CL TY -- -- PR code (also known as 'text') ER external (to be resolved) RO read only data SD section (also known as 'csect') RW data (writable) LD label (also known as 'entry') BS data (uninitialized, writable) CM common DS function descriptor GL glue code IE T0 header of the TOC -- TC address in TOC I imported symbol TD other data in TOC E exported symbol UA "unclassified" XO "extended operations code"The output consists of two parts: code and data; the TOC resides at the end of the data.
B Global bss symbol D Global data symbol T Global text symbolWe exclude those that begin with .dot, as they are code-pointers that aren't meant to be directly called from other modules.
#!/bin/sh nm -X32_64 -Ppg -- "$@" |\ awk '{ if ((($2 == "T") || ($2 == "D") || ($2 == "B")) && (substr($1,1,1) != ".")) { print $1 } }' |\ sort -uQ: What should I do if I have (poorly written) Assembly sources with .name entries, but without name entries (i.e. without function descriptors). (older versions of OpenSSL had such files, for example.) Can I still export them?
#!/bin/sh nm -X32_64 -Ppg -- "$@" |\ awk '{ if (($2 == "T") || ($2 == "D") || ($2 == "B")) { if (substr($1,1,1) == ".") print substr($1,2); else print $1; } }' |\ sort -u
$ nm -gP libcrypto.so.1.0.2 | egrep '^(str|mem)'| grep ' D ' memmove D 2001aa48 8 strcat D 200238f8 8 strcmp D 200177a0 8 strcpy D 2001e574 8 strncpy D 2001b794 8Another example is Oracle client 12 — it exports tons of symbols it shouldn't, like:
$ dump -Tv /opt/lib32/libclntsh.so.12 |\ grep ' EXP ' |\ egrep ' (BIO_|ERR_|SSLv23_|SSLv3_|TLSv1_|ssl23_|ssl3_|ssl_|tls1_|BZ2_|inflate|deflate)' |\ wc -l 210
cd /somepath/bin mv someexe someexe.bin cat >someexe <<DONE #!/bin/sh export LIBPATH=/somepath/lib:/usr/lib exec /somepath/bin/someexe.bin "$@" DONE chmod 0755 someexe
$ dump -H -X32 /opt/freeware/bin/rpm INDEX PATH BASE MEMBER 0 /opt/freeware/lib:/usr/lib:/lib 1 librpmbuild.so 2 libintl.a libintl.so.1 3 librpm.so 4 libpopt.so 5 libc.a shr.o 6 librtl.a shr.o $ /opt/freeware/bin/rpm # it works $ LIBPATH=/usr/local/lib64 /opt/freeware/bin/rpm # it doesn't work Could not load program /opt/freeware/bin/rpm: Dependent module /usr/local/lib64/libintl.a(libintl.so.1) could not be loaded. Member libintl.so.1 is not found in archive
machine: rs6000 or powerpc -- output of /usr/bin/uname -p vendor: ibm os: aixV.V.V.V -- aix$(/usr/bin/oslevel) example: powerpc-ibm-aix6.1.0.0Q: Are you sure in the last part?
explist_so mylib.so >mylib.exp ld -r -o mylib.o -bnso mylib.so ld -G -bnoentry -bernotok -bE:mylib.exp -o mylib_relinked.so mylib.o foo.so foocommon.so -lc
$ MALLOCDEBUG=catch_overflow ./myexeYou can also try using Electric Fence (next question).
# 64 bit shared: gcc -shared -maix64 -o libefence_sh.a efence.c page.c print.c -pthread # 64 bit static: for i in efence page print; do gcc -maix64 -o $i.o -c $i.c -pthread done ar -X64 rcs libefence.a efence.o page.o print.oWhichever you created, add it into the linkage, and run your program. You should see this message at startup:
Electric Fence 2.1 Copyright (C) 1987-1998 Bruce Perens.Q: And exactly what good will this do for me?
$ cat efence_test.c /* efence_test.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> int main (void) { char *p= malloc (22); memcpy (p, "I've corrupted the heap!!", 25); return 0; } $ gcc -g -maix64 efence_test.c -o efence_test libefence.a -pthread $ gdb ./efence_test (gdb) run Thread 2 received signal SIGSEGV, Segmentation fault. (gdb) bt #0 0x000000000000f470 in ?? () #1 0x0000000100000614 in main () at efence_test.c:11 (gdb) l 11 11 memcpy (p, "I've corrupted the heap!!", 25);
/* dltest.c */ /* gcc -maix32 -o dltest32 dltest.c */ /* gcc -maix64 -o dltest64 dltest.c */ #include <dlfcn.h> #include <stdio.h> #include <stdlib.h> #include <sys/ldr.h> #include <unistd.h> int main (int argc, char **argv) { void *dh; char *args[1024]; if (argc < 2) { fprintf (stderr, "usage: %s sharedobject\n", argv[0]); return 0; } dh= dlopen (argv[1], RTLD_LAZY | RTLD_MEMBER); if (dh) { fprintf (stderr, "dlopen(\"%s\") returned %p\n", argv[1], dh); return 0; } args[0]= "execerror"; args[1]= ""; loadquery (L_GETMESSAGES, &args[2], (sizeof args) - 2*(sizeof args[0])); execvp ("/usr/sbin/execerror", args); fprintf (stderr, "couldn't execute execerror"); return 0; }