aboutsummaryrefslogtreecommitdiff
path: root/REORG.TODO/elf
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/elf')
-rw-r--r--REORG.TODO/elf/Makefile1412
-rw-r--r--REORG.TODO/elf/Versions77
-rw-r--r--REORG.TODO/elf/cache.c829
-rw-r--r--REORG.TODO/elf/chroot_canon.c177
-rw-r--r--REORG.TODO/elf/circleload1.c166
-rw-r--r--REORG.TODO/elf/circlemod1.c7
-rw-r--r--REORG.TODO/elf/circlemod1a.c1
-rw-r--r--REORG.TODO/elf/circlemod2.c9
-rw-r--r--REORG.TODO/elf/circlemod2a.c7
-rw-r--r--REORG.TODO/elf/circlemod3.c14
-rw-r--r--REORG.TODO/elf/circlemod3a.c1
-rw-r--r--REORG.TODO/elf/constload1.c32
-rw-r--r--REORG.TODO/elf/constload2.c50
-rw-r--r--REORG.TODO/elf/constload3.c8
-rw-r--r--REORG.TODO/elf/dblload.c53
-rw-r--r--REORG.TODO/elf/dblloadmod1.c8
-rw-r--r--REORG.TODO/elf/dblloadmod2.c15
-rw-r--r--REORG.TODO/elf/dblloadmod3.c8
-rw-r--r--REORG.TODO/elf/dblunload.c53
-rw-r--r--REORG.TODO/elf/dep1.c25
-rw-r--r--REORG.TODO/elf/dep2.c25
-rw-r--r--REORG.TODO/elf/dep3.c23
-rw-r--r--REORG.TODO/elf/dep4.c24
-rw-r--r--REORG.TODO/elf/dl-addr-obj.c75
-rw-r--r--REORG.TODO/elf/dl-addr.c146
-rw-r--r--REORG.TODO/elf/dl-brk.c5
-rw-r--r--REORG.TODO/elf/dl-cache.c325
-rw-r--r--REORG.TODO/elf/dl-caller.c86
-rw-r--r--REORG.TODO/elf/dl-close.c843
-rw-r--r--REORG.TODO/elf/dl-conflict.c74
-rw-r--r--REORG.TODO/elf/dl-debug.c76
-rw-r--r--REORG.TODO/elf/dl-deps.c688
-rw-r--r--REORG.TODO/elf/dl-dst.h74
-rw-r--r--REORG.TODO/elf/dl-environ.c85
-rw-r--r--REORG.TODO/elf/dl-error-minimal.c23
-rw-r--r--REORG.TODO/elf/dl-error-skeleton.c230
-rw-r--r--REORG.TODO/elf/dl-error.c27
-rw-r--r--REORG.TODO/elf/dl-execstack.c31
-rw-r--r--REORG.TODO/elf/dl-fini.c281
-rw-r--r--REORG.TODO/elf/dl-fptr.c322
-rw-r--r--REORG.TODO/elf/dl-hwcaps.c297
-rw-r--r--REORG.TODO/elf/dl-hwcaps.h30
-rw-r--r--REORG.TODO/elf/dl-init.c126
-rw-r--r--REORG.TODO/elf/dl-iteratephdr.c89
-rw-r--r--REORG.TODO/elf/dl-libc.c330
-rw-r--r--REORG.TODO/elf/dl-load.c2307
-rw-r--r--REORG.TODO/elf/dl-load.h135
-rw-r--r--REORG.TODO/elf/dl-lookup.c1129
-rw-r--r--REORG.TODO/elf/dl-machine-reject-phdr.h34
-rw-r--r--REORG.TODO/elf/dl-map-segments.h157
-rw-r--r--REORG.TODO/elf/dl-minimal.c380
-rw-r--r--REORG.TODO/elf/dl-misc.c362
-rw-r--r--REORG.TODO/elf/dl-object.c229
-rw-r--r--REORG.TODO/elf/dl-open.c737
-rw-r--r--REORG.TODO/elf/dl-origin.c50
-rw-r--r--REORG.TODO/elf/dl-profile.c596
-rw-r--r--REORG.TODO/elf/dl-profstub.c41
-rw-r--r--REORG.TODO/elf/dl-reloc.c363
-rw-r--r--REORG.TODO/elf/dl-runtime.c480
-rw-r--r--REORG.TODO/elf/dl-sbrk.c5
-rw-r--r--REORG.TODO/elf/dl-scope.c57
-rw-r--r--REORG.TODO/elf/dl-support.c389
-rw-r--r--REORG.TODO/elf/dl-sym.c274
-rw-r--r--REORG.TODO/elf/dl-symaddr.c33
-rw-r--r--REORG.TODO/elf/dl-sysdep-open.h45
-rw-r--r--REORG.TODO/elf/dl-sysdep.c360
-rw-r--r--REORG.TODO/elf/dl-tls.c953
-rw-r--r--REORG.TODO/elf/dl-trampoline.c1
-rw-r--r--REORG.TODO/elf/dl-tunable-types.h62
-rw-r--r--REORG.TODO/elf/dl-tunables.c490
-rw-r--r--REORG.TODO/elf/dl-tunables.h115
-rw-r--r--REORG.TODO/elf/dl-tunables.list87
-rw-r--r--REORG.TODO/elf/dl-unmap-segments.h35
-rw-r--r--REORG.TODO/elf/dl-version.c389
-rw-r--r--REORG.TODO/elf/dl-writev.h56
-rw-r--r--REORG.TODO/elf/do-rel.h191
-rw-r--r--REORG.TODO/elf/dynamic-link.h203
-rw-r--r--REORG.TODO/elf/elf.h3761
-rw-r--r--REORG.TODO/elf/enbl-secure.c36
-rw-r--r--REORG.TODO/elf/failobj.c10
-rw-r--r--REORG.TODO/elf/filter.c19
-rw-r--r--REORG.TODO/elf/filtmod1.c7
-rw-r--r--REORG.TODO/elf/filtmod2.c7
-rw-r--r--REORG.TODO/elf/firstobj.c10
-rw-r--r--REORG.TODO/elf/gen-trusted-dirs.awk37
-rw-r--r--REORG.TODO/elf/genrtldtbl.awk29
-rw-r--r--REORG.TODO/elf/get-dynamic-info.h184
-rw-r--r--REORG.TODO/elf/global.c7
-rw-r--r--REORG.TODO/elf/globalmod1.c17
-rw-r--r--REORG.TODO/elf/ifuncdep1.c3
-rw-r--r--REORG.TODO/elf/ifuncdep1pic.c3
-rw-r--r--REORG.TODO/elf/ifuncdep2.c59
-rw-r--r--REORG.TODO/elf/ifuncdep2pic.c3
-rw-r--r--REORG.TODO/elf/ifuncdep5.c3
-rw-r--r--REORG.TODO/elf/ifuncdep5pic.c3
-rw-r--r--REORG.TODO/elf/ifuncmain1.c64
-rw-r--r--REORG.TODO/elf/ifuncmain1pic.c3
-rw-r--r--REORG.TODO/elf/ifuncmain1picstatic.c3
-rw-r--r--REORG.TODO/elf/ifuncmain1pie.c3
-rw-r--r--REORG.TODO/elf/ifuncmain1static.c3
-rw-r--r--REORG.TODO/elf/ifuncmain1staticpic.c3
-rw-r--r--REORG.TODO/elf/ifuncmain1staticpie.c3
-rw-r--r--REORG.TODO/elf/ifuncmain1vis.c87
-rw-r--r--REORG.TODO/elf/ifuncmain1vispic.c3
-rw-r--r--REORG.TODO/elf/ifuncmain1vispie.c3
-rw-r--r--REORG.TODO/elf/ifuncmain2.c14
-rw-r--r--REORG.TODO/elf/ifuncmain2pic.c3
-rw-r--r--REORG.TODO/elf/ifuncmain2picstatic.c3
-rw-r--r--REORG.TODO/elf/ifuncmain2static.c3
-rw-r--r--REORG.TODO/elf/ifuncmain3.c129
-rw-r--r--REORG.TODO/elf/ifuncmain4.c4
-rw-r--r--REORG.TODO/elf/ifuncmain4picstatic.c3
-rw-r--r--REORG.TODO/elf/ifuncmain4static.c3
-rw-r--r--REORG.TODO/elf/ifuncmain5.c38
-rw-r--r--REORG.TODO/elf/ifuncmain5pic.c3
-rw-r--r--REORG.TODO/elf/ifuncmain5picstatic.c3
-rw-r--r--REORG.TODO/elf/ifuncmain5pie.c3
-rw-r--r--REORG.TODO/elf/ifuncmain5static.c3
-rw-r--r--REORG.TODO/elf/ifuncmain5staticpic.c3
-rw-r--r--REORG.TODO/elf/ifuncmain6pie.c65
-rw-r--r--REORG.TODO/elf/ifuncmain7.c72
-rw-r--r--REORG.TODO/elf/ifuncmain7pic.c7
-rw-r--r--REORG.TODO/elf/ifuncmain7picstatic.c7
-rw-r--r--REORG.TODO/elf/ifuncmain7pie.c7
-rw-r--r--REORG.TODO/elf/ifuncmain7static.c7
-rw-r--r--REORG.TODO/elf/ifuncmod1.c100
-rw-r--r--REORG.TODO/elf/ifuncmod3.c7
-rw-r--r--REORG.TODO/elf/ifuncmod5.c64
-rw-r--r--REORG.TODO/elf/ifuncmod6.c19
-rw-r--r--REORG.TODO/elf/initfirst.c22
-rw-r--r--REORG.TODO/elf/interp.c22
-rw-r--r--REORG.TODO/elf/lateglobal.c47
-rw-r--r--REORG.TODO/elf/ldconfig.c1418
-rw-r--r--REORG.TODO/elf/ldd.bash.in203
-rw-r--r--REORG.TODO/elf/link.h194
-rw-r--r--REORG.TODO/elf/loadfail.c42
-rw-r--r--REORG.TODO/elf/loadtest.c202
-rw-r--r--REORG.TODO/elf/ltglobmod1.c7
-rw-r--r--REORG.TODO/elf/ltglobmod2.c33
-rw-r--r--REORG.TODO/elf/multiload.c105
-rw-r--r--REORG.TODO/elf/neededobj1.c6
-rw-r--r--REORG.TODO/elf/neededobj2.c8
-rw-r--r--REORG.TODO/elf/neededobj3.c10
-rw-r--r--REORG.TODO/elf/neededobj4.c12
-rw-r--r--REORG.TODO/elf/neededobj5.c5
-rw-r--r--REORG.TODO/elf/neededobj6.c7
-rw-r--r--REORG.TODO/elf/neededtest.c125
-rw-r--r--REORG.TODO/elf/neededtest2.c118
-rw-r--r--REORG.TODO/elf/neededtest3.c129
-rw-r--r--REORG.TODO/elf/neededtest4.c158
-rw-r--r--REORG.TODO/elf/next.c43
-rw-r--r--REORG.TODO/elf/nextmod1.c30
-rw-r--r--REORG.TODO/elf/nextmod2.c10
-rw-r--r--REORG.TODO/elf/nodel2mod1.c19
-rw-r--r--REORG.TODO/elf/nodel2mod2.c7
-rw-r--r--REORG.TODO/elf/nodel2mod3.c1
-rw-r--r--REORG.TODO/elf/nodelete.c210
-rw-r--r--REORG.TODO/elf/nodelete2.c16
-rw-r--r--REORG.TODO/elf/nodelmod1.c9
-rw-r--r--REORG.TODO/elf/nodelmod2.c9
-rw-r--r--REORG.TODO/elf/nodelmod3.c8
-rw-r--r--REORG.TODO/elf/nodelmod4.c9
-rw-r--r--REORG.TODO/elf/nodlopen.c15
-rw-r--r--REORG.TODO/elf/nodlopen2.c15
-rw-r--r--REORG.TODO/elf/nodlopenmod.c1
-rw-r--r--REORG.TODO/elf/nodlopenmod2.c9
-rw-r--r--REORG.TODO/elf/noload.c81
-rw-r--r--REORG.TODO/elf/order.c25
-rw-r--r--REORG.TODO/elf/order2.c45
-rw-r--r--REORG.TODO/elf/order2mod1.c8
-rw-r--r--REORG.TODO/elf/order2mod2.c18
-rw-r--r--REORG.TODO/elf/order2mod3.c14
-rw-r--r--REORG.TODO/elf/order2mod4.c16
-rw-r--r--REORG.TODO/elf/origtest.c39
-rw-r--r--REORG.TODO/elf/pathoptobj.c8
-rw-r--r--REORG.TODO/elf/pldd-xx.c251
-rw-r--r--REORG.TODO/elf/pldd.c344
-rw-r--r--REORG.TODO/elf/preloadtest.c19
-rw-r--r--REORG.TODO/elf/readelflib.c234
-rw-r--r--REORG.TODO/elf/readlib.c212
-rw-r--r--REORG.TODO/elf/reldep.c111
-rw-r--r--REORG.TODO/elf/reldep2.c101
-rw-r--r--REORG.TODO/elf/reldep3.c101
-rw-r--r--REORG.TODO/elf/reldep4.c40
-rw-r--r--REORG.TODO/elf/reldep4mod1.c7
-rw-r--r--REORG.TODO/elf/reldep4mod2.c8
-rw-r--r--REORG.TODO/elf/reldep4mod3.c7
-rw-r--r--REORG.TODO/elf/reldep4mod4.c8
-rw-r--r--REORG.TODO/elf/reldep5.c70
-rw-r--r--REORG.TODO/elf/reldep6.c109
-rw-r--r--REORG.TODO/elf/reldep6mod0.c8
-rw-r--r--REORG.TODO/elf/reldep6mod1.c14
-rw-r--r--REORG.TODO/elf/reldep6mod2.c3
-rw-r--r--REORG.TODO/elf/reldep6mod3.c3
-rw-r--r--REORG.TODO/elf/reldep6mod4.c12
-rw-r--r--REORG.TODO/elf/reldep7.c58
-rw-r--r--REORG.TODO/elf/reldep7mod1.c12
-rw-r--r--REORG.TODO/elf/reldep7mod2.c12
-rw-r--r--REORG.TODO/elf/reldep8.c16
-rw-r--r--REORG.TODO/elf/reldep8mod1.c19
-rw-r--r--REORG.TODO/elf/reldep8mod2.c7
-rw-r--r--REORG.TODO/elf/reldep8mod3.c1
-rw-r--r--REORG.TODO/elf/reldep9.c16
-rw-r--r--REORG.TODO/elf/reldep9mod1.c23
-rw-r--r--REORG.TODO/elf/reldep9mod2.c3
-rw-r--r--REORG.TODO/elf/reldep9mod3.c1
-rw-r--r--REORG.TODO/elf/reldepmod1.c10
-rw-r--r--REORG.TODO/elf/reldepmod2.c8
-rw-r--r--REORG.TODO/elf/reldepmod3.c20
-rw-r--r--REORG.TODO/elf/reldepmod4.c37
-rw-r--r--REORG.TODO/elf/reldepmod5.c7
-rw-r--r--REORG.TODO/elf/reldepmod6.c8
-rw-r--r--REORG.TODO/elf/resolvfail.c31
-rw-r--r--REORG.TODO/elf/restest1.c57
-rw-r--r--REORG.TODO/elf/restest2.c33
-rw-r--r--REORG.TODO/elf/rtld-Rules149
-rw-r--r--REORG.TODO/elf/rtld-debugger-interface.txt122
-rw-r--r--REORG.TODO/elf/rtld.c2652
-rw-r--r--REORG.TODO/elf/setup-vdso.h121
-rw-r--r--REORG.TODO/elf/sln.c202
-rw-r--r--REORG.TODO/elf/sofini.c19
-rw-r--r--REORG.TODO/elf/soinit.c43
-rw-r--r--REORG.TODO/elf/sotruss-lib.c386
-rwxr-xr-xREORG.TODO/elf/sotruss.sh152
-rw-r--r--REORG.TODO/elf/sprof.c1436
-rw-r--r--REORG.TODO/elf/static-stubs.c46
-rw-r--r--REORG.TODO/elf/testobj.h28
-rw-r--r--REORG.TODO/elf/testobj1.c25
-rw-r--r--REORG.TODO/elf/testobj1_1.c7
-rw-r--r--REORG.TODO/elf/testobj2.c32
-rw-r--r--REORG.TODO/elf/testobj3.c26
-rw-r--r--REORG.TODO/elf/testobj4.c25
-rw-r--r--REORG.TODO/elf/testobj5.c26
-rw-r--r--REORG.TODO/elf/testobj6.c19
-rw-r--r--REORG.TODO/elf/tls-macros.h25
-rw-r--r--REORG.TODO/elf/tlsdeschtab.h164
-rw-r--r--REORG.TODO/elf/tst-_dl_addr_inside_object.c222
-rw-r--r--REORG.TODO/elf/tst-addr1.c25
-rw-r--r--REORG.TODO/elf/tst-align.c52
-rw-r--r--REORG.TODO/elf/tst-align2.c155
-rw-r--r--REORG.TODO/elf/tst-alignmod.c52
-rw-r--r--REORG.TODO/elf/tst-alignmod2.c59
-rw-r--r--REORG.TODO/elf/tst-array1-static.c1
-rw-r--r--REORG.TODO/elf/tst-array1.c103
-rw-r--r--REORG.TODO/elf/tst-array1.exp11
-rw-r--r--REORG.TODO/elf/tst-array2.c1
-rw-r--r--REORG.TODO/elf/tst-array2.exp19
-rw-r--r--REORG.TODO/elf/tst-array2dep.c71
-rw-r--r--REORG.TODO/elf/tst-array3.c1
-rw-r--r--REORG.TODO/elf/tst-array4.c18
-rw-r--r--REORG.TODO/elf/tst-array4.exp19
-rw-r--r--REORG.TODO/elf/tst-array5-static.c1
-rw-r--r--REORG.TODO/elf/tst-array5-static.exp2
-rw-r--r--REORG.TODO/elf/tst-array5.c50
-rw-r--r--REORG.TODO/elf/tst-array5.exp3
-rw-r--r--REORG.TODO/elf/tst-array5dep.c23
-rw-r--r--REORG.TODO/elf/tst-audit1.c1
-rw-r--r--REORG.TODO/elf/tst-audit11.c35
-rw-r--r--REORG.TODO/elf/tst-audit11mod1.c24
-rw-r--r--REORG.TODO/elf/tst-audit11mod2.c23
-rw-r--r--REORG.TODO/elf/tst-audit11mod2.map22
-rw-r--r--REORG.TODO/elf/tst-audit12.c48
-rw-r--r--REORG.TODO/elf/tst-audit12mod1.c24
-rw-r--r--REORG.TODO/elf/tst-audit12mod2.c23
-rw-r--r--REORG.TODO/elf/tst-audit12mod2.map22
-rw-r--r--REORG.TODO/elf/tst-audit12mod3.c23
-rw-r--r--REORG.TODO/elf/tst-audit2.c60
-rw-r--r--REORG.TODO/elf/tst-audit8.c1
-rw-r--r--REORG.TODO/elf/tst-audit9.c11
-rw-r--r--REORG.TODO/elf/tst-auditmod1.c135
-rw-r--r--REORG.TODO/elf/tst-auditmod11.c39
-rw-r--r--REORG.TODO/elf/tst-auditmod12.c43
-rw-r--r--REORG.TODO/elf/tst-auditmod9a.c15
-rw-r--r--REORG.TODO/elf/tst-auditmod9b.c6
-rw-r--r--REORG.TODO/elf/tst-auxv.c70
-rw-r--r--REORG.TODO/elf/tst-deep1.c35
-rw-r--r--REORG.TODO/elf/tst-deep1mod1.c14
-rw-r--r--REORG.TODO/elf/tst-deep1mod2.c16
-rw-r--r--REORG.TODO/elf/tst-deep1mod3.c17
-rw-r--r--REORG.TODO/elf/tst-dl-iter-static.c46
-rw-r--r--REORG.TODO/elf/tst-dlmodcount.c108
-rw-r--r--REORG.TODO/elf/tst-dlmopen1.c80
-rw-r--r--REORG.TODO/elf/tst-dlmopen1mod.c59
-rw-r--r--REORG.TODO/elf/tst-dlmopen2.c69
-rw-r--r--REORG.TODO/elf/tst-dlmopen3.c21
-rw-r--r--REORG.TODO/elf/tst-dlopen-aout.c67
-rw-r--r--REORG.TODO/elf/tst-dlopenrpath.c70
-rw-r--r--REORG.TODO/elf/tst-dlopenrpathmod.c35
-rw-r--r--REORG.TODO/elf/tst-dlsym-error.c113
-rw-r--r--REORG.TODO/elf/tst-env-setuid-tunables.c75
-rw-r--r--REORG.TODO/elf/tst-env-setuid.c296
-rw-r--r--REORG.TODO/elf/tst-execstack-mod.c30
-rw-r--r--REORG.TODO/elf/tst-execstack-needed.c34
-rw-r--r--REORG.TODO/elf/tst-execstack-prog.c33
-rw-r--r--REORG.TODO/elf/tst-execstack.c236
-rw-r--r--REORG.TODO/elf/tst-global1.c38
-rw-r--r--REORG.TODO/elf/tst-gnu2-tls1.c51
-rw-r--r--REORG.TODO/elf/tst-gnu2-tls1mod.c56
-rw-r--r--REORG.TODO/elf/tst-initorder.c7
-rw-r--r--REORG.TODO/elf/tst-initorder.exp13
-rw-r--r--REORG.TODO/elf/tst-initorder2.c20
-rw-r--r--REORG.TODO/elf/tst-initorder2.exp9
-rw-r--r--REORG.TODO/elf/tst-initordera1.c16
-rw-r--r--REORG.TODO/elf/tst-initordera2.c16
-rw-r--r--REORG.TODO/elf/tst-initordera3.c16
-rw-r--r--REORG.TODO/elf/tst-initordera4.c16
-rw-r--r--REORG.TODO/elf/tst-initorderb1.c16
-rw-r--r--REORG.TODO/elf/tst-initorderb2.c16
-rw-r--r--REORG.TODO/elf/tst-latepthread.c104
-rw-r--r--REORG.TODO/elf/tst-latepthreadmod.c33
-rw-r--r--REORG.TODO/elf/tst-ldconfig-X.sh62
-rw-r--r--REORG.TODO/elf/tst-leaks1-static.c1
-rw-r--r--REORG.TODO/elf/tst-leaks1.c27
-rw-r--r--REORG.TODO/elf/tst-linkall-static.c52
-rw-r--r--REORG.TODO/elf/tst-nodelete-dlclose-dso.c90
-rw-r--r--REORG.TODO/elf/tst-nodelete-dlclose-plugin.c40
-rw-r--r--REORG.TODO/elf/tst-nodelete-dlclose.c35
-rw-r--r--REORG.TODO/elf/tst-nodelete-opened-lib.c19
-rw-r--r--REORG.TODO/elf/tst-nodelete-opened.c68
-rw-r--r--REORG.TODO/elf/tst-nodelete-rtldmod.cc6
-rw-r--r--REORG.TODO/elf/tst-nodelete-uniquemod.cc14
-rw-r--r--REORG.TODO/elf/tst-nodelete-zmod.cc6
-rw-r--r--REORG.TODO/elf/tst-nodelete.cc50
-rw-r--r--REORG.TODO/elf/tst-nodelete2.c36
-rw-r--r--REORG.TODO/elf/tst-nodelete2mod.c7
-rw-r--r--REORG.TODO/elf/tst-noload.c72
-rw-r--r--REORG.TODO/elf/tst-null-argv-lib.c24
-rw-r--r--REORG.TODO/elf/tst-null-argv.c36
-rw-r--r--REORG.TODO/elf/tst-order-a1.c16
-rw-r--r--REORG.TODO/elf/tst-order-a2.c16
-rw-r--r--REORG.TODO/elf/tst-order-a3.c16
-rw-r--r--REORG.TODO/elf/tst-order-a4.c16
-rw-r--r--REORG.TODO/elf/tst-order-b1.c16
-rw-r--r--REORG.TODO/elf/tst-order-b2.c16
-rw-r--r--REORG.TODO/elf/tst-order-main.c12
-rw-r--r--REORG.TODO/elf/tst-pathopt.c41
-rwxr-xr-xREORG.TODO/elf/tst-pathopt.sh39
-rw-r--r--REORG.TODO/elf/tst-pie1.c5
-rw-r--r--REORG.TODO/elf/tst-pie2.c40
-rw-r--r--REORG.TODO/elf/tst-piemod1.c22
-rw-r--r--REORG.TODO/elf/tst-prelink.c29
-rw-r--r--REORG.TODO/elf/tst-prelink.exp1
-rw-r--r--REORG.TODO/elf/tst-protected1a.c234
-rw-r--r--REORG.TODO/elf/tst-protected1b.c240
-rw-r--r--REORG.TODO/elf/tst-protected1mod.h41
-rw-r--r--REORG.TODO/elf/tst-protected1moda.c92
-rw-r--r--REORG.TODO/elf/tst-protected1modb.c62
-rw-r--r--REORG.TODO/elf/tst-ptrguard1-static.c1
-rw-r--r--REORG.TODO/elf/tst-ptrguard1.c217
-rw-r--r--REORG.TODO/elf/tst-relsort1.c18
-rw-r--r--REORG.TODO/elf/tst-relsort1mod1.c7
-rw-r--r--REORG.TODO/elf/tst-relsort1mod2.c7
-rwxr-xr-xREORG.TODO/elf/tst-rtld-load-self.sh49
-rw-r--r--REORG.TODO/elf/tst-stackguard1-static.c1
-rw-r--r--REORG.TODO/elf/tst-stackguard1.c205
-rw-r--r--REORG.TODO/elf/tst-thrlock.c58
-rw-r--r--REORG.TODO/elf/tst-tls-dlinfo.c85
-rw-r--r--REORG.TODO/elf/tst-tls-manydynamic.c151
-rw-r--r--REORG.TODO/elf/tst-tls-manydynamic.h44
-rw-r--r--REORG.TODO/elf/tst-tls-manydynamicmod.c36
-rw-r--r--REORG.TODO/elf/tst-tls1-static.c1
-rw-r--r--REORG.TODO/elf/tst-tls1.c82
-rw-r--r--REORG.TODO/elf/tst-tls10.c39
-rw-r--r--REORG.TODO/elf/tst-tls10.h32
-rw-r--r--REORG.TODO/elf/tst-tls11.c28
-rw-r--r--REORG.TODO/elf/tst-tls12.c19
-rw-r--r--REORG.TODO/elf/tst-tls13.c28
-rw-r--r--REORG.TODO/elf/tst-tls14.c54
-rw-r--r--REORG.TODO/elf/tst-tls15.c32
-rw-r--r--REORG.TODO/elf/tst-tls16.c52
-rw-r--r--REORG.TODO/elf/tst-tls17.c28
-rw-r--r--REORG.TODO/elf/tst-tls18.c37
-rw-r--r--REORG.TODO/elf/tst-tls19.c26
-rw-r--r--REORG.TODO/elf/tst-tls19mod1.c15
-rw-r--r--REORG.TODO/elf/tst-tls19mod2.c13
-rw-r--r--REORG.TODO/elf/tst-tls19mod3.c16
-rw-r--r--REORG.TODO/elf/tst-tls2-static.c1
-rw-r--r--REORG.TODO/elf/tst-tls2.c82
-rw-r--r--REORG.TODO/elf/tst-tls3.c67
-rw-r--r--REORG.TODO/elf/tst-tls4.c49
-rw-r--r--REORG.TODO/elf/tst-tls5.c65
-rw-r--r--REORG.TODO/elf/tst-tls6.c84
-rw-r--r--REORG.TODO/elf/tst-tls7.c55
-rw-r--r--REORG.TODO/elf/tst-tls8.c167
-rw-r--r--REORG.TODO/elf/tst-tls9-static.c1
-rw-r--r--REORG.TODO/elf/tst-tls9.c36
-rw-r--r--REORG.TODO/elf/tst-tlsalign-extern-static.c1
-rw-r--r--REORG.TODO/elf/tst-tlsalign-extern.c73
-rw-r--r--REORG.TODO/elf/tst-tlsalign-lib.c6
-rw-r--r--REORG.TODO/elf/tst-tlsalign-static.c2
-rw-r--r--REORG.TODO/elf/tst-tlsalign-vars.c28
-rw-r--r--REORG.TODO/elf/tst-tlsalign.c84
-rw-r--r--REORG.TODO/elf/tst-tlsmod1.c62
-rw-r--r--REORG.TODO/elf/tst-tlsmod10.c1
-rw-r--r--REORG.TODO/elf/tst-tlsmod11.c4
-rw-r--r--REORG.TODO/elf/tst-tlsmod12.c12
-rw-r--r--REORG.TODO/elf/tst-tlsmod13.c7
-rw-r--r--REORG.TODO/elf/tst-tlsmod13a.c9
-rw-r--r--REORG.TODO/elf/tst-tlsmod14a.c35
-rw-r--r--REORG.TODO/elf/tst-tlsmod14b.c2
-rw-r--r--REORG.TODO/elf/tst-tlsmod15a.c6
-rw-r--r--REORG.TODO/elf/tst-tlsmod15b.c9
-rw-r--r--REORG.TODO/elf/tst-tlsmod16a.c1
-rw-r--r--REORG.TODO/elf/tst-tlsmod16b.c7
-rw-r--r--REORG.TODO/elf/tst-tlsmod17a.c23
-rw-r--r--REORG.TODO/elf/tst-tlsmod17b.c15
-rw-r--r--REORG.TODO/elf/tst-tlsmod18a.c21
-rw-r--r--REORG.TODO/elf/tst-tlsmod2.c34
-rw-r--r--REORG.TODO/elf/tst-tlsmod3.c37
-rw-r--r--REORG.TODO/elf/tst-tlsmod4.c34
-rw-r--r--REORG.TODO/elf/tst-tlsmod5.c3
-rw-r--r--REORG.TODO/elf/tst-tlsmod6.c3
-rw-r--r--REORG.TODO/elf/tst-tlsmod7.c101
-rw-r--r--REORG.TODO/elf/tst-tlsmod8.c70
-rw-r--r--REORG.TODO/elf/tst-tlsmod9.c99
-rw-r--r--REORG.TODO/elf/tst-unique1.c73
-rw-r--r--REORG.TODO/elf/tst-unique1mod1.c16
-rw-r--r--REORG.TODO/elf/tst-unique1mod2.c15
-rw-r--r--REORG.TODO/elf/tst-unique2.c27
-rw-r--r--REORG.TODO/elf/tst-unique2mod1.c8
-rw-r--r--REORG.TODO/elf/tst-unique2mod2.c15
-rw-r--r--REORG.TODO/elf/tst-unique3.cc24
-rw-r--r--REORG.TODO/elf/tst-unique3.h8
-rw-r--r--REORG.TODO/elf/tst-unique3lib.cc11
-rw-r--r--REORG.TODO/elf/tst-unique3lib2.cc12
-rw-r--r--REORG.TODO/elf/tst-unique4.cc28
-rw-r--r--REORG.TODO/elf/tst-unique4.h7
-rw-r--r--REORG.TODO/elf/tst-unique4lib.cc17
-rw-r--r--REORG.TODO/elf/unload.c91
-rw-r--r--REORG.TODO/elf/unload2.c59
-rw-r--r--REORG.TODO/elf/unload2dep.c6
-rw-r--r--REORG.TODO/elf/unload2mod.c8
-rw-r--r--REORG.TODO/elf/unload3.c41
-rw-r--r--REORG.TODO/elf/unload3mod1.c1
-rw-r--r--REORG.TODO/elf/unload3mod2.c1
-rw-r--r--REORG.TODO/elf/unload3mod3.c8
-rw-r--r--REORG.TODO/elf/unload3mod4.c13
-rw-r--r--REORG.TODO/elf/unload4.c48
-rw-r--r--REORG.TODO/elf/unload4mod1.c10
-rw-r--r--REORG.TODO/elf/unload4mod2.c8
-rw-r--r--REORG.TODO/elf/unload4mod3.c16
-rw-r--r--REORG.TODO/elf/unload4mod4.c16
-rw-r--r--REORG.TODO/elf/unload5.c42
-rw-r--r--REORG.TODO/elf/unload6.c30
-rw-r--r--REORG.TODO/elf/unload6mod1.c16
-rw-r--r--REORG.TODO/elf/unload6mod2.c23
-rw-r--r--REORG.TODO/elf/unload6mod3.c23
-rw-r--r--REORG.TODO/elf/unload7.c39
-rw-r--r--REORG.TODO/elf/unload7mod1.c11
-rw-r--r--REORG.TODO/elf/unload7mod2.c1
-rw-r--r--REORG.TODO/elf/unload8.c33
-rw-r--r--REORG.TODO/elf/unload8mod1.c7
-rw-r--r--REORG.TODO/elf/unload8mod1x.c1
-rw-r--r--REORG.TODO/elf/unload8mod2.c7
-rw-r--r--REORG.TODO/elf/unload8mod3.c27
-rw-r--r--REORG.TODO/elf/unloadmod.c4
-rw-r--r--REORG.TODO/elf/vismain.c260
-rw-r--r--REORG.TODO/elf/vismod.h27
-rw-r--r--REORG.TODO/elf/vismod1.c103
-rw-r--r--REORG.TODO/elf/vismod2.c123
-rw-r--r--REORG.TODO/elf/vismod3.c46
461 files changed, 43439 insertions, 0 deletions
diff --git a/REORG.TODO/elf/Makefile b/REORG.TODO/elf/Makefile
new file mode 100644
index 0000000000..201b328f88
--- /dev/null
+++ b/REORG.TODO/elf/Makefile
@@ -0,0 +1,1412 @@
+# Copyright (C) 1995-2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+# Makefile for elf subdirectory of GNU C Library.
+
+subdir := elf
+
+include ../Makeconfig
+
+headers = elf.h bits/elfclass.h link.h bits/link.h
+routines = $(all-dl-routines) dl-support dl-iteratephdr \
+ dl-addr dl-addr-obj enbl-secure dl-profstub \
+ dl-origin dl-libc dl-sym dl-sysdep dl-error
+
+# The core dynamic linking functions are in libc for the static and
+# profiled libraries.
+dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \
+ runtime init fini debug misc \
+ version profile conflict tls origin scope \
+ execstack caller open close trampoline)
+ifeq (yes,$(use-ldconfig))
+dl-routines += dl-cache
+endif
+
+ifneq (no,$(have-tunables))
+dl-routines += dl-tunables
+tunables-type = $(addprefix TUNABLES_FRONTEND_,$(have-tunables))
+CPPFLAGS-dl-tunables.c = -DTUNABLES_FRONTEND=$(tunables-type)
+
+# Make sure that the compiler does not insert any library calls in tunables
+# code paths.
+ifeq (yes,$(have-loop-to-function))
+CFLAGS-dl-tunables.c = -fno-tree-loop-distribute-patterns
+endif
+endif
+
+all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
+# But they are absent from the shared libc, because that code is in ld.so.
+elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \
+ dl-sysdep
+shared-only-routines += dl-caller
+
+# ld.so uses those routines, plus some special stuff for being the program
+# interpreter and operating independent of libc.
+rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \
+ dl-error-minimal
+all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines)
+
+CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-dl-iterate-phdr.c = $(uses-callbacks)
+
+# Compile rtld itself without stack protection.
+# Also compile all routines in the static library that are elided from
+# the shared libc because they are in libc.a in the same way.
+
+define elide-stack-protector
+$(if $(filter $(@F),$(patsubst %,%$(1),$(2))), $(no-stack-protector))
+endef
+
+CFLAGS-.o += $(call elide-stack-protector,.o,$(elide-routines.os))
+CFLAGS-.op += $(call elide-stack-protector,.op,$(elide-routines.os))
+CFLAGS-.os += $(call elide-stack-protector,.os,$(all-rtld-routines))
+
+ifeq ($(unwind-find-fde),yes)
+routines += unwind-dw2-fde-glibc
+shared-only-routines += unwind-dw2-fde-glibc
+endif
+
+before-compile += $(objpfx)trusted-dirs.h
+generated += trusted-dirs.h trusted-dirs.st for-renamed/renamed.so
+generated-dirs += for-renamed
+
+ifeq ($(build-shared),yes)
+ld-map = $(common-objpfx)ld.map
+endif
+
+ifeq (yes,$(build-shared))
+extra-objs = $(all-rtld-routines:%=%.os) soinit.os sofini.os interp.os
+generated += librtld.os dl-allobjs.os ld.so ldd
+install-others = $(inst_rtlddir)/$(rtld-installed-name)
+install-bin-script = ldd
+endif
+
+others = sprof sln
+install-bin = sprof
+others-static = sln
+install-rootsbin = sln
+sln-modules := static-stubs
+extra-objs += $(sln-modules:=.o)
+
+ifeq (yes,$(use-ldconfig))
+ifeq (yes,$(build-shared))
+others-static += ldconfig
+others += ldconfig
+install-rootsbin += ldconfig
+
+ldconfig-modules := cache readlib xmalloc xstrdup chroot_canon static-stubs
+extra-objs += $(ldconfig-modules:=.o)
+endif
+endif
+
+# To find xmalloc.c and xstrdup.c
+vpath %.c ../locale/programs
+
+ifeq ($(build-shared),yes)
+extra-objs += sotruss-lib.os sotruss-lib.so
+install-others += $(inst_auditdir)/sotruss-lib.so
+install-bin-script += sotruss
+generated += sotruss
+libof-sotruss-lib = extramodules
+$(objpfx)sotruss-lib.so: $(objpfx)sotruss-lib.os
+ $(build-module-asneeded)
+$(objpfx)sotruss-lib.so: $(common-objpfx)libc.so $(objpfx)ld.so \
+ $(common-objpfx)libc_nonshared.a
+
+$(objpfx)sotruss: sotruss.sh $(common-objpfx)config.make
+ sed -e 's%@BASH@%$(BASH)%g' \
+ -e 's%@VERSION@%$(version)%g' \
+ -e 's%@TEXTDOMAINDIR@%$(localedir)%g' \
+ -e 's%@PREFIX@%$(prefix)%g' \
+ -e 's|@PKGVERSION@|$(PKGVERSION)|g' \
+ -e 's|@REPORT_BUGS_TO@|$(REPORT_BUGS_TO)|g' \
+ < $< > $@.new
+ chmod 555 $@.new
+ mv -f $@.new $@
+$(inst_auditdir)/sotruss-lib.so: $(objpfx)sotruss-lib.so $(+force)
+ $(do-install-program)
+endif
+
+tests-static-normal := tst-leaks1-static tst-array1-static tst-array5-static \
+ tst-dl-iter-static \
+ tst-tlsalign-static tst-tlsalign-extern-static \
+ tst-linkall-static tst-env-setuid tst-env-setuid-tunables
+tests-static-internal := tst-tls1-static tst-tls2-static \
+ tst-ptrguard1-static tst-stackguard1-static
+
+tests := tst-tls9 tst-leaks1 \
+ tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \
+ tst-auxv
+tests-internal := tst-tls1 tst-tls2 $(tests-static-internal)
+tests-static := $(tests-static-normal) $(tests-static-internal)
+
+ifeq (yes,$(build-shared))
+tests-static += tst-tls9-static
+tst-tls9-static-ENV = \
+ LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn
+
+tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ constload1 order noload filter \
+ reldep reldep2 reldep3 reldep4 nodelete nodelete2 \
+ nodlopen nodlopen2 lateglobal initfirst global \
+ restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
+ tst-tls4 tst-tls5 \
+ tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \
+ tst-tls16 tst-tls17 tst-tls18 tst-tls19 tst-tls-dlinfo \
+ tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \
+ tst-dlmodcount tst-dlopenrpath tst-deep1 \
+ tst-dlmopen1 tst-dlmopen3 \
+ unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
+ tst-audit1 tst-audit2 tst-audit8 tst-audit9 \
+ tst-addr1 tst-thrlock \
+ tst-unique1 tst-unique2 $(if $(CXX),tst-unique3 tst-unique4 \
+ tst-nodelete) \
+ tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
+ tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \
+ tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
+ tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose
+# reldep9
+tests-internal += loadtest unload unload2 circleload1 \
+ neededtest neededtest2 neededtest3 neededtest4 \
+ tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
+ tst-ptrguard1 tst-stackguard1
+ifeq ($(build-hardcoded-path-in-tests),yes)
+tests += tst-dlopen-aout
+LDFLAGS-tst-dlopen-aout = $(no-pie-ldflag)
+endif
+test-srcs = tst-pathopt
+selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null)
+ifneq ($(selinux-enabled),1)
+tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog
+endif
+endif
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-leaks1-mem.out \
+ $(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out \
+ $(objpfx)tst-ldconfig-X.out
+endif
+tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+tlsmod18a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+tlsmod17a-modules = $(addprefix tst-tlsmod17a, $(tlsmod17a-suffixes))
+tlsmod18a-modules = $(addprefix tst-tlsmod18a, $(tlsmod17a-suffixes))
+one-hundred = $(foreach x,0 1 2 3 4 5 6 7 8 9, \
+ 0$x 1$x 2$x 3$x 4$x 5$x 6$x 7$x 8$x 9$x)
+tst-tls-many-dynamic-modules := \
+ $(foreach n,$(one-hundred),tst-tls-manydynamic$(n)mod)
+extra-test-objs += $(tlsmod17a-modules:=.os) $(tlsmod18a-modules:=.os) \
+ tst-tlsalign-vars.o
+test-extras += tst-tlsmod17a tst-tlsmod18a tst-tlsalign-vars
+modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ testobj1_1 failobj constload2 constload3 unloadmod \
+ dep1 dep2 dep3 dep4 vismod1 vismod2 vismod3 \
+ nodelmod1 nodelmod2 nodelmod3 nodelmod4 \
+ nodel2mod1 nodel2mod2 nodel2mod3 \
+ nodlopenmod nodlopenmod2 filtmod1 filtmod2 \
+ reldepmod1 reldepmod2 reldepmod3 reldepmod4 nextmod1 nextmod2 \
+ reldep4mod1 reldep4mod2 reldep4mod3 reldep4mod4 \
+ neededobj1 neededobj2 neededobj3 neededobj4 \
+ neededobj5 neededobj6 firstobj globalmod1 \
+ unload2mod unload2dep ltglobmod1 ltglobmod2 pathoptobj \
+ dblloadmod1 dblloadmod2 dblloadmod3 reldepmod5 reldepmod6 \
+ reldep6mod0 reldep6mod1 reldep6mod2 reldep6mod3 reldep6mod4 \
+ reldep7mod1 reldep7mod2 \
+ tst-tlsmod1 tst-tlsmod2 tst-tlsmod3 tst-tlsmod4 \
+ tst-tlsmod5 tst-tlsmod6 tst-tlsmod7 tst-tlsmod8 \
+ tst-tlsmod9 tst-tlsmod10 tst-tlsmod11 tst-tlsmod12 \
+ tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \
+ tst-tlsmod15a tst-tlsmod15b tst-tlsmod16a tst-tlsmod16b \
+ $(tlsmod17a-modules) tst-tlsmod17b $(tlsmod18a-modules) \
+ tst-tls19mod1 tst-tls19mod2 tst-tls19mod3 \
+ circlemod1 circlemod1a circlemod2 circlemod2a \
+ circlemod3 circlemod3a \
+ reldep8mod1 reldep8mod2 reldep8mod3 \
+ reldep9mod1 reldep9mod2 reldep9mod3 \
+ tst-alignmod tst-alignmod2 \
+ $(modules-execstack-$(have-z-execstack)) \
+ tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \
+ tst-dlmopen1mod tst-auditmod1 \
+ unload3mod1 unload3mod2 unload3mod3 unload3mod4 \
+ unload4mod1 unload4mod2 unload4mod3 unload4mod4 \
+ unload6mod1 unload6mod2 unload6mod3 \
+ unload7mod1 unload7mod2 \
+ unload8mod1 unload8mod1x unload8mod2 unload8mod3 \
+ order2mod1 order2mod2 order2mod3 order2mod4 \
+ tst-unique1mod1 tst-unique1mod2 \
+ tst-unique2mod1 tst-unique2mod2 \
+ tst-auditmod9a tst-auditmod9b \
+ $(if $(CXX),tst-unique3lib tst-unique3lib2 tst-unique4lib \
+ tst-nodelete-uniquemod tst-nodelete-rtldmod \
+ tst-nodelete-zmod) \
+ tst-initordera1 tst-initorderb1 \
+ tst-initordera2 tst-initorderb2 \
+ tst-initordera3 tst-initordera4 \
+ tst-initorder2a tst-initorder2b tst-initorder2c \
+ tst-initorder2d \
+ tst-relsort1mod1 tst-relsort1mod2 tst-array2dep \
+ tst-array5dep tst-null-argv-lib \
+ tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \
+ tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \
+ tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \
+ tst-latepthreadmod $(tst-tls-many-dynamic-modules) \
+ tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin
+ifeq (yes,$(have-mtls-dialect-gnu2))
+tests += tst-gnu2-tls1
+modules-names += tst-gnu2-tls1mod
+$(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so
+tst-gnu2-tls1mod.so-no-z-defs = yes
+CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2
+endif
+ifeq (yes,$(have-protected-data))
+modules-names += tst-protected1moda tst-protected1modb
+tests += tst-protected1a tst-protected1b
+$(objpfx)tst-protected1a: $(addprefix $(objpfx),tst-protected1moda.so tst-protected1modb.so)
+$(objpfx)tst-protected1b: $(addprefix $(objpfx),tst-protected1modb.so tst-protected1moda.so)
+tst-protected1modb.so-no-z-defs = yes
+# These tests fail with GCC versions prior to 5.1 and with some versions
+# of binutils. See https://sourceware.org/bugzilla/show_bug.cgi?id=17709
+# and https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65248 for details.
+# Perhaps in future we can make these XFAILs conditional on some detection
+# of compiler/linker behavior/version.
+test-xfail-tst-protected1a = yes
+test-xfail-tst-protected1b = yes
+endif
+ifeq (yesyes,$(have-fpie)$(build-shared))
+modules-names += tst-piemod1
+tests += tst-pie1 tst-pie2
+tests-pie += tst-pie1 tst-pie2
+tests += vismain
+tests-pie += vismain
+CFLAGS-vismain.c = $(PIE-ccflag)
+endif
+modules-execstack-yes = tst-execstack-mod
+extra-test-objs += $(addsuffix .os,$(strip $(modules-names)))
+
+# filtmod1.so has a special rule
+modules-names-nobuild := filtmod1
+
+tests += $(tests-static)
+
+ifneq (no,$(multi-arch))
+tests-ifuncstatic := ifuncmain1static ifuncmain1picstatic \
+ ifuncmain2static ifuncmain2picstatic \
+ ifuncmain4static ifuncmain4picstatic \
+ ifuncmain5static ifuncmain5picstatic \
+ ifuncmain7static ifuncmain7picstatic
+tests-static += $(tests-ifuncstatic)
+tests-internal += $(tests-ifuncstatic)
+ifeq (yes,$(build-shared))
+tests-internal += \
+ ifuncmain1 ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
+ ifuncmain1staticpic \
+ ifuncmain2 ifuncmain2pic ifuncmain3 ifuncmain4 \
+ ifuncmain5 ifuncmain5pic ifuncmain5staticpic \
+ ifuncmain7 ifuncmain7pic
+ifunc-test-modules = ifuncdep1 ifuncdep1pic ifuncdep2 ifuncdep2pic \
+ ifuncdep5 ifuncdep5pic
+extra-test-objs += $(ifunc-test-modules:=.o)
+test-internal-extras += $(ifunc-test-modules)
+ifeq (yes,$(have-fpie))
+ifunc-pie-tests = ifuncmain1pie ifuncmain1vispie ifuncmain1staticpie \
+ ifuncmain5pie ifuncmain6pie ifuncmain7pie
+tests-internal += $(ifunc-pie-tests)
+tests-pie += $(ifunc-pie-tests)
+endif
+modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6
+endif
+endif
+
+ifeq (yes,$(build-shared))
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out
+endif
+tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \
+ $(objpfx)check-localplt.out
+endif
+
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)order-cmp.out $(objpfx)tst-array1-cmp.out \
+ $(objpfx)tst-array1-static-cmp.out \
+ $(objpfx)tst-array2-cmp.out $(objpfx)tst-array3-cmp.out \
+ $(objpfx)tst-array4-cmp.out $(objpfx)tst-array5-cmp.out \
+ $(objpfx)tst-array5-static-cmp.out $(objpfx)order2-cmp.out \
+ $(objpfx)tst-initorder-cmp.out \
+ $(objpfx)tst-initorder2-cmp.out $(objpfx)tst-unused-dep.out \
+ $(objpfx)tst-unused-dep-cmp.out
+endif
+
+check-abi: $(objpfx)check-abi-ld.out
+tests-special += $(objpfx)check-abi-ld.out
+update-abi: update-abi-ld
+update-all-abi: update-all-abi-ld
+
+ifeq ($(have-glob-dat-reloc),yes)
+tests += tst-prelink
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-prelink-cmp.out
+endif
+endif
+
+# The test requires shared _and_ PIE because the executable
+# unit test driver must be able to link with the shared object
+# that is going to eventually go into an installed DSO.
+ifeq (yesyes,$(have-fpie)$(build-shared))
+tests-internal += tst-_dl_addr_inside_object
+tests-pie += tst-_dl_addr_inside_object
+$(objpfx)tst-_dl_addr_inside_object: $(objpfx)dl-addr-obj.os
+CFLAGS-tst-_dl_addr_inside_object.c += $(PIE-ccflag)
+endif
+
+# By default tst-linkall-static should try to use crypt routines to test
+# static libcrypt use.
+CFLAGS-tst-linkall-static.c = -DUSE_CRYPT=1
+# However, if we are using NSS crypto and we don't have a static
+# library, then we exclude the use of crypt functions in the test.
+# We similarly exclude libcrypt.a from the static link (see below).
+ifeq (yesno,$(nss-crypt)$(static-nss-crypt))
+CFLAGS-tst-linkall-static.c = -DUSE_CRYPT=0
+endif
+
+include ../Rules
+
+ifeq (yes,$(build-shared))
+# Make sure these things are built in the `make lib' pass so they can be used
+# to run programs during the `make others' pass.
+lib-noranlib: $(objpfx)$(rtld-installed-name) \
+ $(addprefix $(objpfx),$(extra-objs))
+endif
+
+# Command to link into a larger single relocatable object.
+reloc-link = $(LINK.o) -nostdlib -nostartfiles -r
+
+$(objpfx)sotruss-lib.so: $(shlib-lds)
+
+$(objpfx)dl-allobjs.os: $(all-rtld-routines:%=$(objpfx)%.os)
+ $(reloc-link) -o $@ $^
+
+# Link together the dynamic linker into a single relocatable object.
+# First we do a link against libc_pic.a just to get a link map,
+# and discard the object produced by that link. From the link map
+# we can glean all the libc modules that need to go into the dynamic
+# linker. Then we do a recursive make that goes into all the subdirs
+# those modules come from and builds special rtld-foo.os versions that
+# are compiled with special flags, and puts these modules into rtld-libc.a
+# for us. Then we do the real link using rtld-libc.a instead of libc_pic.a.
+
+# If the compiler can do SSP, build the mapfile with dummy __stack_chk_fail
+# and __stack_chk_fail_local symbols defined, to prevent the real things
+# being dragged into rtld even though rtld is never built with stack-
+# protection.
+
+ifeq ($(have-ssp),yes)
+dummy-stack-chk-fail := -Wl,--defsym='__stack_chk_fail=0' \
+ -Wl,--defsym='__stack_chk_fail_local=0'
+else
+dummy-stack-chk-fail :=
+endif
+
+$(objpfx)librtld.map: $(objpfx)dl-allobjs.os $(common-objpfx)libc_pic.a
+ @-rm -f $@T
+ $(reloc-link) -o $@.o $(dummy-stack-chk-fail) \
+ '-Wl,-(' $^ -lgcc '-Wl,-)' -Wl,-Map,$@T
+ rm -f $@.o
+ mv -f $@T $@
+
+$(objpfx)librtld.mk: $(objpfx)librtld.map Makefile
+ LC_ALL=C \
+ sed -n 's@^$(common-objpfx)\([^(]*\)(\([^)]*\.os\)) *.*$$@\1 \2@p' \
+ $< | \
+ while read lib file; do \
+ case $$lib in \
+ libc_pic.a) \
+ LC_ALL=C fgrep -l /$$file \
+ $(common-objpfx)stamp.os $(common-objpfx)*/stamp.os | \
+ LC_ALL=C \
+ sed 's@^$(common-objpfx)\([^/]*\)/stamp\.os$$@rtld-\1'" +=$$file@"\
+ ;; \
+ */*.a) \
+ echo rtld-$${lib%%/*} += $$file ;; \
+ *) echo "Wasn't expecting $$lib($$file)" >&2; exit 1 ;; \
+ esac; \
+ done > $@T
+ echo rtld-subdirs = `LC_ALL=C sed 's/^rtld-\([^ ]*\).*$$/\1/' $@T \
+ | LC_ALL=C sort -u` >> $@T
+ mv -f $@T $@
+
+$(objpfx)rtld-libc.a: $(objpfx)librtld.mk FORCE
+ $(MAKE) -f $< -f rtld-Rules
+
+$(objpfx)librtld.os: $(objpfx)dl-allobjs.os $(objpfx)rtld-libc.a
+ $(LINK.o) -nostdlib -nostartfiles -r -o $@ '-Wl,-(' $^ -lgcc '-Wl,-)' \
+ -Wl,-Map,$@.map
+
+generated += librtld.map librtld.mk rtld-libc.a librtld.os.map
+
+z-now-yes = -Wl,-z,now
+
+$(objpfx)ld.so: $(objpfx)librtld.os $(ld-map)
+# Link into a temporary file so that we don't touch $@ at all
+# if the sanity check below fails.
+ $(LINK.o) -nostdlib -nostartfiles -shared -o $@.new \
+ $(LDFLAGS-rtld) -Wl,-z,defs $(z-now-$(bind-now)) \
+ $(filter-out $(map-file),$^) $(load-map-file) \
+ -Wl,-soname=$(rtld-installed-name) \
+ -Wl,-defsym=_begin=0
+ $(call after-link,$@.new)
+ $(READELF) -s $@.new \
+ | $(AWK) '($$7 ~ /^UND(|EF)$$/ && $$1 != "0:" && $$4 != "REGISTER") { print; p=1 } END { exit p != 0 }'
+ mv -f $@.new $@
+
+ifeq (yes,$(build-shared))
+# interp.c exists just to get the runtime linker path into libc.so.
+$(objpfx)interp.os: $(common-objpfx)runtime-linker.h
+endif
+
+ifneq (ld.so,$(rtld-installed-name))
+# Make sure ld.so.1 exists in the build directory so we can link
+# against it.
+$(objpfx)$(rtld-installed-name): $(objpfx)ld.so
+ $(make-link)
+generated += $(rtld-installed-name)
+endif
+
+# Build a file mentioning all trustworthy directories to look for shared
+# libraries when using LD_LIBRARY_PATH in a setuid program. The user can
+# add directories to the list by defining $(user-defined-trusted-dirs)
+# before starting make.
+$(objpfx)trusted-dirs.h: $(objpfx)trusted-dirs.st; @:
+$(objpfx)trusted-dirs.st: Makefile $(..)Makeconfig
+ $(make-target-directory)
+ echo "$(subst :, ,$(default-rpath) $(user-defined-trusted-dirs))" \
+ | $(AWK) -f gen-trusted-dirs.awk > ${@:st=T};
+ echo '#define DL_DST_LIB "$(notdir $(slibdir))"' >> ${@:st=T}
+ $(move-if-change) ${@:st=T} ${@:st=h}
+ touch $@
+CPPFLAGS-dl-load.c = -I$(objpfx). -I$(csu-objpfx).
+
+ifeq (yes,$(build-shared))
+$(inst_slibdir)/$(rtld-version-installed-name): $(objpfx)ld.so $(+force)
+ $(make-target-directory)
+ $(do-install-program)
+
+$(inst_rtlddir)/$(rtld-installed-name): \
+ $(inst_slibdir)/$(rtld-version-installed-name) \
+ $(inst_slibdir)/libc-$(version).so
+ $(make-target-directory)
+ $(make-shlib-link)
+
+# Special target called by parent to install just the dynamic linker.
+.PHONY: ldso_install
+ldso_install: $(inst_rtlddir)/$(rtld-installed-name)
+endif
+
+
+ldd-rewrite = -e 's%@RTLD@%$(rtlddir)/$(rtld-installed-name)%g' \
+ -e 's%@VERSION@%$(version)%g' \
+ -e 's|@PKGVERSION@|$(PKGVERSION)|g' \
+ -e 's|@REPORT_BUGS_TO@|$(REPORT_BUGS_TO)|g' \
+ -e 's%@BASH@%$(BASH)%g' \
+ -e 's%@TEXTDOMAINDIR@%$(localedir)%g'
+
+ifeq ($(ldd-rewrite-script),no)
+define gen-ldd
+LC_ALL=C sed $(ldd-rewrite) < $< > $@.new
+endef
+else
+define gen-ldd
+LC_ALL=C sed $(ldd-rewrite) < $< \
+| LC_ALL=C sed -f $(patsubst $(..)/%,/%,$(..)$(ldd-rewrite-script)) > $@.new
+endef
+endif
+
+$(objpfx)ldd: ldd.bash.in $(common-objpfx)soversions.mk \
+ $(common-objpfx)config.make
+ $(gen-ldd)
+ chmod 555 $@.new
+ mv -f $@.new $@
+
+$(objpfx)sprof: $(libdl)
+
+$(objpfx)sln: $(sln-modules:%=$(objpfx)%.o)
+
+$(objpfx)ldconfig: $(ldconfig-modules:%=$(objpfx)%.o)
+
+SYSCONF-FLAGS := -D'SYSCONFDIR="$(sysconfdir)"'
+CFLAGS-ldconfig.c = $(SYSCONF-FLAGS) -D'LIBDIR="$(libdir)"' \
+ -D'SLIBDIR="$(slibdir)"'
+libof-ldconfig = ldconfig
+CFLAGS-dl-cache.c = $(SYSCONF-FLAGS)
+CFLAGS-cache.c = $(SYSCONF-FLAGS)
+CFLAGS-rtld.c = $(SYSCONF-FLAGS)
+
+cpp-srcs-left := $(all-rtld-routines:=.os)
+lib := rtld
+include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
+
+test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(strip $(modules-names))))
+generated += $(addsuffix .so,$(strip $(modules-names)))
+
+$(objpfx)testobj1.so: $(libdl)
+$(objpfx)testobj1_1.so: $(objpfx)testobj1.so $(libdl)
+$(objpfx)testobj2.so: $(objpfx)testobj1.so $(libdl)
+$(objpfx)testobj3.so: $(libdl)
+$(objpfx)testobj4.so: $(libdl)
+$(objpfx)testobj5.so: $(libdl)
+$(objpfx)testobj6.so: $(objpfx)testobj1.so $(objpfx)testobj2.so $(libdl)
+$(objpfx)failobj.so: $(objpfx)testobj6.so
+$(objpfx)dep1.so: $(objpfx)dep2.so $(objpfx)dep4.so
+$(objpfx)dep2.so: $(objpfx)dep3.so $(objpfx)dep4.so
+$(objpfx)dep4.so: $(objpfx)dep3.so
+$(objpfx)nodelmod3.so: $(objpfx)nodelmod4.so
+$(objpfx)nextmod1.so: $(libdl)
+$(objpfx)neededobj1.so: $(libdl)
+$(objpfx)neededobj2.so: $(objpfx)neededobj1.so $(libdl)
+$(objpfx)neededobj3.so: $(objpfx)neededobj1.so $(objpfx)neededobj2.so $(libdl)
+$(objpfx)neededobj4.so: $(objpfx)neededobj1.so $(objpfx)neededobj2.so \
+ $(objpfx)neededobj3.so $(libdl)
+$(objpfx)neededobj6.so: $(objpfx)neededobj5.so
+$(objpfx)unload2mod.so: $(objpfx)unload2dep.so
+$(objpfx)ltglobmod2.so: $(libdl)
+$(objpfx)firstobj.so: $(shared-thread-library)
+$(objpfx)globalmod1.so: $(libdl)
+$(objpfx)reldep4mod1.so: $(objpfx)reldep4mod3.so
+$(objpfx)reldep4mod2.so: $(objpfx)reldep4mod4.so
+$(objpfx)dblloadmod1.so: $(objpfx)dblloadmod3.so
+$(objpfx)dblloadmod2.so: $(objpfx)dblloadmod3.so
+$(objpfx)reldepmod5.so: $(objpfx)reldepmod2.so
+$(objpfx)reldepmod6.so: $(objpfx)reldepmod2.so
+$(objpfx)reldep6mod1.so: $(objpfx)reldep6mod0.so
+$(objpfx)reldep6mod2.so: $(objpfx)reldep6mod1.so
+$(objpfx)reldep6mod3.so: $(objpfx)reldep6mod2.so
+$(objpfx)reldep6mod4.so: $(objpfx)reldep6mod1.so
+$(objpfx)tst-tlsmod3.so: $(objpfx)tst-tlsmod2.so
+$(objpfx)tst-tlsmod8.so: $(objpfx)tst-tlsmod7.so
+$(objpfx)tst-tlsmod10.so: $(objpfx)tst-tlsmod9.so
+$(objpfx)tst-tlsmod12.so: $(objpfx)tst-tlsmod11.so
+$(objpfx)tst-tlsmod13a.so: $(objpfx)tst-tlsmod13.so
+# For tst-tls9-static, make sure the modules it dlopens have libc.so in DT_NEEDED
+$(objpfx)tst-tlsmod5.so: $(common-objpfx)libc.so
+$(objpfx)tst-tlsmod6.so: $(common-objpfx)libc.so
+$(objpfx)tst-tls19mod1.so: $(objpfx)tst-tls19mod2.so $(objpfx)tst-tls19mod3.so
+$(objpfx)tst-tls19mod3.so: $(objpfx)ld.so
+$(objpfx)reldep8mod3.so: $(objpfx)reldep8mod1.so $(objpfx)reldep8mod2.so
+$(objpfx)nodel2mod3.so: $(objpfx)nodel2mod1.so $(objpfx)nodel2mod2.so
+$(objpfx)reldep9mod2.so: $(objpfx)reldep9mod1.so
+$(objpfx)reldep9mod3.so: $(objpfx)reldep9mod1.so $(objpfx)reldep9mod2.so
+$(objpfx)unload3mod1.so: $(objpfx)unload3mod3.so
+$(objpfx)unload3mod2.so: $(objpfx)unload3mod3.so
+$(objpfx)unload3mod3.so: $(objpfx)unload3mod4.so
+$(objpfx)unload4mod1.so: $(objpfx)unload4mod2.so $(objpfx)unload4mod3.so
+$(objpfx)unload4mod2.so: $(objpfx)unload4mod4.so $(objpfx)unload4mod3.so
+$(objpfx)unload6mod1.so: $(libdl)
+$(objpfx)unload6mod2.so: $(libdl)
+$(objpfx)unload6mod3.so: $(libdl)
+$(objpfx)unload7mod1.so: $(libdl)
+$(objpfx)unload7mod2.so: $(objpfx)unload7mod1.so
+$(objpfx)unload8mod1.so: $(objpfx)unload8mod2.so
+$(objpfx)unload8mod2.so: $(objpfx)unload8mod3.so
+$(objpfx)unload8mod3.so: $(libdl)
+$(objpfx)tst-initordera2.so: $(objpfx)tst-initordera1.so
+$(objpfx)tst-initorderb2.so: $(objpfx)tst-initorderb1.so $(objpfx)tst-initordera2.so
+$(objpfx)tst-initordera3.so: $(objpfx)tst-initorderb2.so $(objpfx)tst-initorderb1.so
+$(objpfx)tst-initordera4.so: $(objpfx)tst-initordera3.so
+$(objpfx)tst-initorder: $(objpfx)tst-initordera4.so $(objpfx)tst-initordera1.so $(objpfx)tst-initorderb2.so
+$(objpfx)tst-null-argv: $(objpfx)tst-null-argv-lib.so
+$(objpfx)tst-tlsalign: $(objpfx)tst-tlsalign-lib.so
+$(objpfx)tst-nodelete-opened.out: $(objpfx)tst-nodelete-opened-lib.so
+$(objpfx)tst-nodelete-opened: $(libdl)
+$(objpfx)tst-noload: $(libdl)
+
+$(objpfx)tst-tlsalign-extern: $(objpfx)tst-tlsalign-vars.o
+$(objpfx)tst-tlsalign-extern-static: $(objpfx)tst-tlsalign-vars.o
+
+tst-null-argv-ENV = LD_DEBUG=all LD_DEBUG_OUTPUT=$(objpfx)tst-null-argv.debug.out
+LDFLAGS-nodel2mod3.so = $(no-as-needed)
+LDFLAGS-reldepmod5.so = $(no-as-needed)
+LDFLAGS-reldep6mod1.so = $(no-as-needed)
+LDFLAGS-reldep6mod4.so = $(no-as-needed)
+LDFLAGS-reldep8mod3.so = $(no-as-needed)
+LDFLAGS-unload4mod1.so = $(no-as-needed)
+LDFLAGS-unload4mod2.so = $(no-as-needed)
+LDFLAGS-tst-initorder = $(no-as-needed)
+LDFLAGS-tst-initordera2.so = $(no-as-needed)
+LDFLAGS-tst-initordera3.so = $(no-as-needed)
+LDFLAGS-tst-initordera4.so = $(no-as-needed)
+LDFLAGS-tst-initorderb2.so = $(no-as-needed)
+LDFLAGS-tst-tlsmod5.so = -nostdlib $(no-as-needed)
+LDFLAGS-tst-tlsmod6.so = -nostdlib $(no-as-needed)
+
+testobj1.so-no-z-defs = yes
+testobj3.so-no-z-defs = yes
+testobj4.so-no-z-defs = yes
+testobj5.so-no-z-defs = yes
+testobj6.so-no-z-defs = yes
+failobj.so-no-z-defs = yes
+constload2.so-no-z-defs = yes
+constload3.so-no-z-defs = yes
+nodelmod1.so-no-z-defs = yes
+nodelmod2.so-no-z-defs = yes
+nodelmod4.so-no-z-defs = yes
+nodel2mod2.so-no-z-defs = yes
+reldepmod2.so-no-z-defs = yes
+reldepmod3.so-no-z-defs = yes
+reldepmod4.so-no-z-defs = yes
+reldep4mod4.so-no-z-defs = yes
+reldep4mod2.so-no-z-defs = yes
+ltglobmod2.so-no-z-defs = yes
+dblloadmod3.so-no-z-defs = yes
+tst-tlsmod1.so-no-z-defs = yes
+tst-tlsmod2.so-no-z-defs = yes
+tst-tlsmod3.so-no-z-defs = yes
+tst-tlsmod4.so-no-z-defs = yes
+tst-tlsmod7.so-no-z-defs = yes
+tst-tlsmod8.so-no-z-defs = yes
+tst-tlsmod9.so-no-z-defs = yes
+tst-tlsmod10.so-no-z-defs = yes
+tst-tlsmod12.so-no-z-defs = yes
+tst-tlsmod14a.so-no-z-defs = yes
+tst-tlsmod14b.so-no-z-defs = yes
+tst-tlsmod15a.so-no-z-defs = yes
+tst-tlsmod16b.so-no-z-defs = yes
+circlemod2.so-no-z-defs = yes
+circlemod3.so-no-z-defs = yes
+circlemod3a.so-no-z-defs = yes
+reldep8mod2.so-no-z-defs = yes
+reldep9mod1.so-no-z-defs = yes
+unload3mod4.so-no-z-defs = yes
+unload4mod1.so-no-z-defs = yes
+ifuncmod1.so-no-z-defs = yes
+ifuncmod5.so-no-z-defs = yes
+ifuncmod6.so-no-z-defs = yes
+tst-auditmod9a.so-no-z-defs = yes
+tst-auditmod9b.so-no-z-defs = yes
+tst-nodelete-uniquemod.so-no-z-defs = yes
+tst-nodelete-rtldmod.so-no-z-defs = yes
+tst-nodelete-zmod.so-no-z-defs = yes
+tst-nodelete2mod.so-no-z-defs = yes
+
+ifeq ($(build-shared),yes)
+# Build all the modules even when not actually running test programs.
+tests: $(test-modules)
+endif
+
+$(objpfx)loadtest: $(libdl)
+LDFLAGS-loadtest = -rdynamic
+
+$(objpfx)loadtest.out: $(test-modules)
+
+$(objpfx)neededtest: $(libdl)
+$(objpfx)neededtest.out: $(objpfx)neededobj1.so $(objpfx)neededobj2.so \
+ $(objpfx)neededobj3.so
+
+$(objpfx)neededtest2: $(libdl)
+$(objpfx)neededtest2.out: $(objpfx)neededobj1.so $(objpfx)neededobj2.so \
+ $(objpfx)neededobj3.so
+
+$(objpfx)neededtest3: $(libdl)
+$(objpfx)neededtest3.out: $(objpfx)neededobj1.so $(objpfx)neededobj2.so \
+ $(objpfx)neededobj3.so $(objpfx)neededobj4.so
+
+$(objpfx)neededtest4: $(libdl) $(objpfx)neededobj1.so
+$(objpfx)neededtest4.out: $(objpfx)neededobj5.so $(objpfx)neededobj6.so
+
+$(objpfx)restest1: $(objpfx)testobj1.so $(objpfx)testobj1_1.so $(libdl)
+LDFLAGS-restest1 = -rdynamic
+
+$(objpfx)restest2: $(libdl)
+LDFLAGS-restest2 = -rdynamic
+
+$(objpfx)restest1.out: $(test-modules)
+
+preloadtest-preloads = testobj1 testobj2 testobj3 testobj4 testobj5
+$(objpfx)preloadtest: $(objpfx)testobj6.so
+LDFLAGS-preloadtest = -rdynamic
+$(objpfx)preloadtest.out: $(preloadtest-preloads:%=$(objpfx)%.so)
+preloadtest-ENV = \
+ LD_PRELOAD=$(subst $(empty) ,:,$(strip $(preloadtest-preloads:=.so)))
+
+$(objpfx)loadfail: $(libdl)
+LDFLAGS-loadfail = -rdynamic
+
+$(objpfx)loadfail.out: $(objpfx)failobj.so
+
+$(objpfx)multiload: $(libdl)
+LDFLAGS-multiload = -rdynamic
+CFLAGS-multiload.c = -DOBJDIR=\"$(elf-objpfx)\"
+
+$(objpfx)multiload.out: $(objpfx)testobj1.so
+
+$(objpfx)origtest: $(libdl)
+LDFLAGS-origtest = -rdynamic
+$(objpfx)origtest.out: $(objpfx)testobj1.so
+
+ifeq ($(have-thread-library),yes)
+$(objpfx)resolvfail: $(libdl) $(shared-thread-library)
+else
+$(objpfx)resolvfail: $(libdl)
+endif
+
+$(objpfx)constload1: $(libdl)
+$(objpfx)constload1.out: $(objpfx)constload2.so $(objpfx)constload3.so
+
+$(objpfx)circleload1: $(libdl)
+$(objpfx)circleload1.out: $(objpfx)circlemod1.so \
+ $(objpfx)circlemod1a.so
+
+$(objpfx)circlemod1.so: $(objpfx)circlemod2.so
+$(objpfx)circlemod2.so: $(objpfx)circlemod3.so
+$(objpfx)circlemod1a.so: $(objpfx)circlemod2a.so
+$(objpfx)circlemod2a.so: $(objpfx)circlemod3a.so
+
+$(objpfx)order: $(addprefix $(objpfx),dep4.so dep3.so dep2.so dep1.so)
+
+$(objpfx)order-cmp.out: $(objpfx)order.out
+ (echo "0123456789" | cmp $< -) > $@; \
+ $(evaluate-test)
+
+$(objpfx)vismain: $(addprefix $(objpfx),vismod1.so vismod2.so)
+$(objpfx)vismain.out: $(addprefix $(objpfx),vismod3.so)
+vismain-ENV = LD_PRELOAD=$(addprefix $(objpfx),vismod3.so)
+
+$(objpfx)noload: $(objpfx)testobj1.so $(libdl)
+LDFLAGS-noload = -rdynamic $(no-as-needed)
+$(objpfx)noload.out: $(objpfx)testobj5.so
+
+$(objpfx)noload-mem.out: $(objpfx)noload.out
+ $(common-objpfx)malloc/mtrace $(objpfx)noload.mtrace > $@; \
+ $(evaluate-test)
+noload-ENV = MALLOC_TRACE=$(objpfx)noload.mtrace
+
+LDFLAGS-nodelete = -rdynamic
+LDFLAGS-nodelmod1.so = -Wl,--enable-new-dtags,-z,nodelete
+LDFLAGS-nodelmod4.so = -Wl,--enable-new-dtags,-z,nodelete
+$(objpfx)nodelete: $(libdl)
+$(objpfx)nodelete.out: $(objpfx)nodelmod1.so $(objpfx)nodelmod2.so \
+ $(objpfx)nodelmod3.so
+
+LDFLAGS-nodlopenmod.so = -Wl,--enable-new-dtags,-z,nodlopen
+$(objpfx)nodlopen: $(libdl)
+$(objpfx)nodlopen.out: $(objpfx)nodlopenmod.so
+
+$(objpfx)nodlopenmod2.so: $(objpfx)nodlopenmod.so
+$(objpfx)nodlopen2: $(libdl)
+$(objpfx)nodlopen2.out: $(objpfx)nodlopenmod2.so
+
+$(objpfx)filtmod1.so: $(objpfx)filtmod1.os $(objpfx)filtmod2.so
+ $(LINK.o) -shared -o $@ -B$(csu-objpfx) $(LDFLAGS.so) \
+ -L$(subst :, -L,$(rpath-link)) \
+ -Wl,-rpath-link=$(rpath-link) \
+ $< -Wl,-F,$(objpfx)filtmod2.so
+$(objpfx)filter: $(objpfx)filtmod1.so
+
+# This does not link against libc.
+CFLAGS-filtmod1.c = $(no-stack-protector)
+
+$(objpfx)unload: $(libdl)
+$(objpfx)unload.out: $(objpfx)unloadmod.so
+
+$(objpfx)reldep: $(libdl)
+$(objpfx)reldep.out: $(objpfx)reldepmod1.so $(objpfx)reldepmod2.so
+
+$(objpfx)reldep2: $(libdl)
+$(objpfx)reldep2.out: $(objpfx)reldepmod1.so $(objpfx)reldepmod3.so
+
+$(objpfx)reldep3: $(libdl)
+$(objpfx)reldep3.out: $(objpfx)reldepmod1.so $(objpfx)reldepmod4.so
+
+$(objpfx)reldep4: $(libdl)
+$(objpfx)reldep4.out: $(objpfx)reldep4mod1.so $(objpfx)reldep4mod2.so
+
+$(objpfx)next: $(objpfx)nextmod1.so $(objpfx)nextmod2.so $(libdl)
+LDFLAGS-next = $(no-as-needed)
+
+$(objpfx)unload2: $(libdl)
+$(objpfx)unload2.out: $(objpfx)unload2mod.so $(objpfx)unload2dep.so
+
+$(objpfx)lateglobal: $(libdl)
+$(objpfx)lateglobal.out: $(objpfx)ltglobmod1.so $(objpfx)ltglobmod2.so
+
+$(objpfx)tst-pathopt: $(libdl)
+$(objpfx)tst-pathopt.out: tst-pathopt.sh $(objpfx)tst-pathopt \
+ $(objpfx)pathoptobj.so
+ $(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' \
+ '$(run-program-env)'; \
+ $(evaluate-test)
+
+$(objpfx)tst-rtld-load-self.out: tst-rtld-load-self.sh $(objpfx)ld.so
+ $(SHELL) $^ '$(test-wrapper)' '$(test-wrapper-env)' > $@; \
+ $(evaluate-test)
+
+$(objpfx)initfirst: $(libdl)
+$(objpfx)initfirst.out: $(objpfx)firstobj.so
+
+$(objpfx)global: $(objpfx)globalmod1.so
+$(objpfx)global.out: $(objpfx)reldepmod1.so
+
+$(objpfx)dblload: $(libdl)
+$(objpfx)dblload.out: $(objpfx)dblloadmod1.so $(objpfx)dblloadmod2.so
+
+$(objpfx)dblunload: $(libdl)
+$(objpfx)dblunload.out: $(objpfx)dblloadmod1.so $(objpfx)dblloadmod2.so
+
+$(objpfx)reldep5: $(libdl)
+$(objpfx)reldep5.out: $(objpfx)reldepmod5.so $(objpfx)reldepmod6.so
+
+$(objpfx)reldep6: $(libdl)
+$(objpfx)reldep6.out: $(objpfx)reldep6mod3.so $(objpfx)reldep6mod4.so
+
+$(objpfx)reldep7: $(libdl)
+$(objpfx)reldep7.out: $(objpfx)reldep7mod1.so $(objpfx)reldep7mod2.so
+
+$(objpfx)reldep8: $(libdl)
+$(objpfx)reldep8.out: $(objpfx)reldep8mod3.so
+
+LDFLAGS-nodel2mod2.so = -Wl,--enable-new-dtags,-z,nodelete
+$(objpfx)nodelete2: $(libdl)
+$(objpfx)nodelete2.out: $(objpfx)nodel2mod3.so
+
+$(objpfx)reldep9: $(libdl)
+$(objpfx)reldep9.out: $(objpfx)reldep9mod3.so
+
+$(objpfx)tst-tls3: $(objpfx)tst-tlsmod1.so
+
+$(objpfx)tst-tls4: $(libdl)
+$(objpfx)tst-tls4.out: $(objpfx)tst-tlsmod2.so
+
+$(objpfx)tst-tls5: $(libdl)
+$(objpfx)tst-tls5.out: $(objpfx)tst-tlsmod2.so
+
+$(objpfx)tst-tls6: $(libdl)
+$(objpfx)tst-tls6.out: $(objpfx)tst-tlsmod2.so
+
+$(objpfx)tst-tls7: $(libdl)
+$(objpfx)tst-tls7.out: $(objpfx)tst-tlsmod3.so
+
+$(objpfx)tst-tls8: $(libdl)
+$(objpfx)tst-tls8.out: $(objpfx)tst-tlsmod3.so $(objpfx)tst-tlsmod4.so
+
+$(objpfx)tst-tls9: $(libdl)
+$(objpfx)tst-tls9.out: $(objpfx)tst-tlsmod5.so $(objpfx)tst-tlsmod6.so
+
+$(objpfx)tst-tls10: $(objpfx)tst-tlsmod8.so $(objpfx)tst-tlsmod7.so
+
+$(objpfx)tst-tls11: $(objpfx)tst-tlsmod10.so $(objpfx)tst-tlsmod9.so
+
+$(objpfx)tst-tls12: $(objpfx)tst-tlsmod12.so $(objpfx)tst-tlsmod11.so
+
+$(objpfx)tst-tls13: $(libdl)
+$(objpfx)tst-tls13.out: $(objpfx)tst-tlsmod13a.so
+
+$(objpfx)tst-tls14: $(objpfx)tst-tlsmod14a.so $(libdl)
+$(objpfx)tst-tls14.out: $(objpfx)tst-tlsmod14b.so
+
+$(objpfx)tst-tls15: $(libdl)
+$(objpfx)tst-tls15.out: $(objpfx)tst-tlsmod15a.so $(objpfx)tst-tlsmod15b.so
+
+$(objpfx)tst-tls-dlinfo: $(libdl)
+$(objpfx)tst-tls-dlinfo.out: $(objpfx)tst-tlsmod2.so
+
+
+
+$(objpfx)tst-tls16: $(libdl)
+$(objpfx)tst-tls16.out: $(objpfx)tst-tlsmod16a.so $(objpfx)tst-tlsmod16b.so
+
+$(objpfx)tst-tls17: $(libdl)
+$(objpfx)tst-tls17.out: $(objpfx)tst-tlsmod17b.so
+$(patsubst %,$(objpfx)%.os,$(tlsmod17a-modules)): $(objpfx)tst-tlsmod17a%.os: tst-tlsmod17a.c
+ $(compile-command.c) -DN=$*
+$(patsubst %,$(objpfx)%.so,$(tlsmod17a-modules)): $(objpfx)tst-tlsmod17a%.so: $(objpfx)ld.so
+$(objpfx)tst-tlsmod17b.so: $(patsubst %,$(objpfx)%.so,$(tlsmod17a-modules))
+
+$(objpfx)tst-tls18: $(libdl)
+$(objpfx)tst-tls18.out: $(patsubst %,$(objpfx)%.so,$(tlsmod18a-modules))
+$(patsubst %,$(objpfx)%.os,$(tlsmod18a-modules)): $(objpfx)tst-tlsmod18a%.os : tst-tlsmod18a.c
+ $(compile-command.c) -DN=$*
+$(patsubst %,$(objpfx)%.so,$(tlsmod18a-modules)): $(objpfx)tst-tlsmod18a%.so: $(objpfx)ld.so
+
+$(objpfx)tst-tls19: $(libdl)
+$(objpfx)tst-tls19.out: $(objpfx)tst-tls19mod1.so
+
+CFLAGS-tst-align.c = $(stack-align-test-flags)
+CFLAGS-tst-align2.c = $(stack-align-test-flags)
+CFLAGS-tst-alignmod.c = $(stack-align-test-flags)
+CFLAGS-tst-alignmod2.c = $(stack-align-test-flags)
+$(objpfx)tst-align: $(libdl)
+$(objpfx)tst-align.out: $(objpfx)tst-alignmod.so
+$(objpfx)tst-align2: $(objpfx)tst-alignmod2.so
+
+$(objpfx)unload3: $(libdl)
+$(objpfx)unload3.out: $(objpfx)unload3mod1.so $(objpfx)unload3mod2.so \
+ $(objpfx)unload3mod3.so $(objpfx)unload3mod4.so
+
+$(objpfx)unload4: $(libdl)
+$(objpfx)unload4.out: $(objpfx)unload4mod1.so $(objpfx)unload4mod3.so
+
+$(objpfx)unload5: $(libdl)
+$(objpfx)unload5.out: $(objpfx)unload3mod1.so $(objpfx)unload3mod2.so \
+ $(objpfx)unload3mod3.so $(objpfx)unload3mod4.so
+
+$(objpfx)unload6: $(libdl)
+$(objpfx)unload6.out: $(objpfx)unload6mod1.so $(objpfx)unload6mod2.so \
+ $(objpfx)unload6mod3.so
+
+$(objpfx)unload7: $(libdl)
+$(objpfx)unload7.out: $(objpfx)unload7mod1.so $(objpfx)unload7mod2.so
+unload7-ENV = MALLOC_PERTURB_=85
+
+$(objpfx)unload8: $(libdl)
+$(objpfx)unload8.out: $(objpfx)unload8mod1.so $(objpfx)unload8mod1x.so
+
+ifdef libdl
+$(objpfx)tst-tls9-static: $(common-objpfx)dlfcn/libdl.a
+$(objpfx)tst-tls9-static.out: $(objpfx)tst-tlsmod5.so $(objpfx)tst-tlsmod6.so
+endif
+
+ifeq ($(have-z-execstack),yes)
+$(objpfx)tst-execstack: $(libdl)
+$(objpfx)tst-execstack.out: $(objpfx)tst-execstack-mod.so
+CPPFLAGS-tst-execstack.c = -DUSE_PTHREADS=0
+LDFLAGS-tst-execstack = -Wl,-z,noexecstack
+LDFLAGS-tst-execstack-mod = -Wl,-z,execstack
+
+$(objpfx)tst-execstack-needed: $(objpfx)tst-execstack-mod.so
+LDFLAGS-tst-execstack-needed = -Wl,-z,noexecstack
+
+LDFLAGS-tst-execstack-prog = -Wl,-z,execstack
+CFLAGS-tst-execstack-prog.c += -Wno-trampolines
+CFLAGS-tst-execstack-mod.c += -Wno-trampolines
+endif
+
+LDFLAGS-tst-array2 = $(no-as-needed)
+LDFLAGS-tst-array5 = $(no-as-needed)
+
+$(objpfx)tst-array1-cmp.out: tst-array1.exp $(objpfx)tst-array1.out
+ cmp $^ > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-array1-static-cmp.out: tst-array1.exp \
+ $(objpfx)tst-array1-static.out
+ cmp $^ > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-array2: $(objpfx)tst-array2dep.so
+$(objpfx)tst-array2-cmp.out: tst-array2.exp $(objpfx)tst-array2.out
+ cmp $^ > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-array3-cmp.out: tst-array1.exp $(objpfx)tst-array3.out
+ cmp $^ > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-array4: $(libdl)
+$(objpfx)tst-array4.out: $(objpfx)tst-array2dep.so
+$(objpfx)tst-array4-cmp.out: tst-array4.exp $(objpfx)tst-array4.out
+ cmp $^ > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-array5: $(objpfx)tst-array5dep.so
+$(objpfx)tst-array5-cmp.out: tst-array5.exp $(objpfx)tst-array5.out
+ cmp $^ > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-array5-static-cmp.out: tst-array5-static.exp \
+ $(objpfx)tst-array5-static.out
+ cmp $^ > $@; \
+ $(evaluate-test)
+
+CFLAGS-tst-pie1.c += $(pie-ccflag)
+CFLAGS-tst-pie2.c += $(pie-ccflag)
+
+$(objpfx)tst-piemod1.so: $(libsupport)
+$(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
+
+ifeq (yes,$(build-shared))
+all-built-dso := $(common-objpfx)elf/ld.so $(common-objpfx)libc.so \
+ $(filter-out $(common-objpfx)linkobj/libc.so, \
+ $(sort $(wildcard $(addprefix $(common-objpfx), \
+ */lib*.so \
+ iconvdata/*.so))))
+
+$(all-built-dso:=.dyn): %.dyn: %
+ @rm -f $@T
+ LC_ALL=C $(READELF) -W -d $< > $@T
+ test -s $@T
+ mv -f $@T $@
+common-generated += $(all-built-dso:$(common-objpfx)%=%.dyn)
+
+$(objpfx)check-textrel.out: $(..)scripts/check-textrel.awk \
+ $(all-built-dso:=.dyn)
+ LC_ALL=C $(AWK) -f $^ > $@; \
+ $(evaluate-test)
+generated += check-textrel.out
+
+$(objpfx)execstack-default: $(first-word $(wildcard $(sysdirs:%=%/stackinfo.h)))
+ $(make-target-directory)
+ { echo '#include <elf.h>'; \
+ echo '#include <stackinfo.h>'; \
+ echo '#if (DEFAULT_STACK_PERMS & PF_X) == 0'; \
+ echo '@@@execstack-no@@@'; \
+ echo '#else'; \
+ echo '@@@execstack-yes@@@'; \
+ echo '#endif'; } | \
+ $(CC) $(CFLAGS) $(CPPFLAGS) -E -x c-header - | \
+ sed -n -e 's/^@@@\(.*\)@@@/\1/p' > $@T
+ mv -f $@T $@
+generated += execstack-default
+
+$(all-built-dso:=.phdr): %.phdr: %
+ @rm -f $@T
+ LC_ALL=C $(READELF) -W -l $< > $@T
+ test -s $@T
+ mv -f $@T $@
+common-generated += $(all-built-dso:$(common-objpfx)%=%.phdr)
+
+$(objpfx)check-execstack.out: $(..)scripts/check-execstack.awk \
+ $(objpfx)execstack-default \
+ $(all-built-dso:=.phdr)
+ LC_ALL=C $(AWK) -f $^ > $@; \
+ $(evaluate-test)
+generated += check-execstack.out
+
+$(objpfx)tst-dlmodcount: $(libdl)
+$(objpfx)tst-dlmodcount.out: $(test-modules)
+
+$(all-built-dso:=.jmprel): %.jmprel: % Makefile
+ @rm -f $@T
+ LC_ALL=C $(READELF) -W -S -d -r $< > $@T
+ test -s $@T
+ mv -f $@T $@
+common-generated += $(all-built-dso:$(common-objpfx)%=%.jmprel)
+
+localplt-built-dso := $(addprefix $(common-objpfx),\
+ libc.so \
+ elf/ld.so \
+ math/libm.so \
+ rt/librt.so \
+ dlfcn/libdl.so \
+ resolv/libresolv.so \
+ crypt/libcrypt.so \
+ )
+ifeq ($(build-mathvec),yes)
+localplt-built-dso += $(addprefix $(common-objpfx), mathvec/libmvec.so)
+endif
+ifeq ($(have-thread-library),yes)
+localplt-built-dso += $(filter-out %_nonshared.a, $(shared-thread-library))
+endif
+
+vpath localplt.data $(+sysdep_dirs)
+
+$(objpfx)check-localplt.out: $(..)scripts/check-localplt.awk \
+ $(..)scripts/localplt.awk \
+ $(localplt-built-dso:=.jmprel) \
+ localplt.data
+ LC_ALL=C $(AWK) -f $(filter-out $< %localplt.data,$^) | \
+ LC_ALL=C $(AWK) -f $< $(filter %localplt.data,$^) - \
+ > $@; \
+ $(evaluate-test)
+endif
+
+$(objpfx)tst-dlopenrpathmod.so: $(libdl)
+$(objpfx)tst-dlopenrpath: $(objpfx)tst-dlopenrpathmod.so $(libdl)
+CFLAGS-tst-dlopenrpath.c += -DPFX=\"$(objpfx)\"
+LDFLAGS-tst-dlopenrpathmod.so += -Wl,-rpath,\$$ORIGIN/test-subdir
+$(objpfx)tst-dlopenrpath.out: $(objpfx)firstobj.so
+
+$(objpfx)tst-deep1mod2.so: $(objpfx)tst-deep1mod3.so
+$(objpfx)tst-deep1: $(libdl) $(objpfx)tst-deep1mod1.so
+$(objpfx)tst-deep1.out: $(objpfx)tst-deep1mod2.so
+LDFLAGS-tst-deep1 += -rdynamic
+tst-deep1mod3.so-no-z-defs = yes
+
+$(objpfx)tst-dlmopen1mod.so: $(libdl)
+$(objpfx)tst-dlmopen1: $(libdl)
+$(objpfx)tst-dlmopen1.out: $(objpfx)tst-dlmopen1mod.so
+
+$(objpfx)tst-dlmopen2: $(libdl)
+$(objpfx)tst-dlmopen2.out: $(objpfx)tst-dlmopen1mod.so
+
+$(objpfx)tst-dlmopen3: $(libdl)
+$(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
+
+$(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
+tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+
+$(objpfx)tst-audit2: $(libdl)
+$(objpfx)tst-audit2.out: $(objpfx)tst-auditmod1.so $(objpfx)tst-auditmod9b.so
+# Prevent GCC-5 from translating a malloc/memset pair into calloc
+CFLAGS-tst-audit2.c += -fno-builtin
+tst-audit2-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+
+$(objpfx)tst-audit9: $(libdl)
+$(objpfx)tst-audit9.out: $(objpfx)tst-auditmod9a.so $(objpfx)tst-auditmod9b.so
+tst-audit9-ENV = LD_AUDIT=$(objpfx)tst-auditmod9a.so
+
+$(objpfx)tst-audit8: $(libm)
+$(objpfx)tst-audit8.out: $(objpfx)tst-auditmod1.so
+tst-audit8-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+
+$(objpfx)tst-global1: $(libdl)
+$(objpfx)tst-global1.out: $(objpfx)testobj6.so $(objpfx)testobj2.so
+
+$(objpfx)order2: $(libdl)
+$(objpfx)order2.out: $(objpfx)order2mod1.so $(objpfx)order2mod2.so
+$(objpfx)order2-cmp.out: $(objpfx)order2.out
+ (echo "12345" | cmp $< -) > $@; \
+ $(evaluate-test)
+$(objpfx)order2mod1.so: $(objpfx)order2mod4.so
+$(objpfx)order2mod4.so: $(objpfx)order2mod3.so
+$(objpfx)order2mod2.so: $(objpfx)order2mod3.so
+order2mod2.so-no-z-defs = yes
+LDFLAGS-order2mod1.so = $(no-as-needed)
+LDFLAGS-order2mod2.so = $(no-as-needed)
+
+tst-stackguard1-ARGS = --command "$(host-test-program-cmd) --child"
+tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child"
+
+tst-ptrguard1-ARGS = --command "$(host-test-program-cmd) --child"
+# When built statically, the pointer guard interface uses
+# __pointer_chk_guard_local.
+CFLAGS-tst-ptrguard1-static.c = -DPTRGUARD_LOCAL
+tst-ptrguard1-static-ARGS = --command "$(objpfx)tst-ptrguard1-static --child"
+
+$(objpfx)tst-leaks1: $(libdl)
+$(objpfx)tst-leaks1-mem.out: $(objpfx)tst-leaks1.out
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1.mtrace > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-leaks1-static: $(common-objpfx)dlfcn/libdl.a
+$(objpfx)tst-leaks1-static-mem.out: $(objpfx)tst-leaks1-static.out
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1-static.mtrace > $@; \
+ $(evaluate-test)
+
+tst-leaks1-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1.mtrace
+tst-leaks1-static-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1-static.mtrace
+
+$(objpfx)tst-addr1: $(libdl)
+
+$(objpfx)tst-thrlock: $(libdl) $(shared-thread-library)
+$(objpfx)tst-dlopen-aout: $(libdl) $(shared-thread-library)
+
+CFLAGS-ifuncmain1pic.c += $(pic-ccflag)
+CFLAGS-ifuncmain1picstatic.c += $(pic-ccflag)
+CFLAGS-ifuncmain1staticpic.c += $(pic-ccflag)
+CFLAGS-ifuncdep1pic.c += $(pic-ccflag)
+CFLAGS-ifuncmain1vispic.c += $(pic-ccflag)
+CFLAGS-ifuncmain2pic.c += $(pic-ccflag)
+CFLAGS-ifuncmain2picstatic.c += $(pic-ccflag)
+CFLAGS-ifuncdep2pic.c += $(pic-ccflag)
+CFLAGS-ifuncmain4picstatic.c += $(pic-ccflag)
+CFLAGS-ifuncmain5pic.c += $(pic-ccflag)
+CFLAGS-ifuncmain5picstatic.c += $(pic-ccflag)
+CFLAGS-ifuncmain5staticpic.c += $(pic-ccflag)
+CFLAGS-ifuncdep5pic.c += $(pic-ccflag)
+CFLAGS-ifuncmain7pic.c += $(pic-ccflag)
+CFLAGS-ifuncmain7picstatic.c += $(pic-ccflag)
+
+LDFLAGS-ifuncmain3 = -Wl,-export-dynamic
+
+CFLAGS-ifuncmain1pie.c += $(pie-ccflag)
+CFLAGS-ifuncmain1vispie.c += $(pie-ccflag)
+CFLAGS-ifuncmain1staticpie.c += $(pie-ccflag)
+CFLAGS-ifuncmain5pie.c += $(pie-ccflag)
+CFLAGS-ifuncmain6pie.c += $(pie-ccflag)
+CFLAGS-ifuncmain7pie.c += $(pie-ccflag)
+
+$(objpfx)ifuncmain1pie: $(objpfx)ifuncmod1.so
+$(objpfx)ifuncmain1staticpie: $(objpfx)ifuncdep1pic.o
+$(objpfx)ifuncmain1vispie: $(objpfx)ifuncmod1.so
+$(objpfx)ifuncmain5pie: $(objpfx)ifuncmod5.so
+$(objpfx)ifuncmain6pie: $(objpfx)ifuncmod6.so
+
+$(objpfx)ifuncmain1: $(addprefix $(objpfx),ifuncmod1.so)
+$(objpfx)ifuncmain1pic: $(addprefix $(objpfx),ifuncmod1.so)
+$(objpfx)ifuncmain1staticpic: $(addprefix $(objpfx),ifuncdep1pic.o)
+$(objpfx)ifuncmain1static: $(addprefix $(objpfx),ifuncdep1.o)
+$(objpfx)ifuncmain1picstatic: $(addprefix $(objpfx),ifuncdep1pic.o)
+$(objpfx)ifuncmain1vis: $(addprefix $(objpfx),ifuncmod1.so)
+$(objpfx)ifuncmain1vispic: $(addprefix $(objpfx),ifuncmod1.so)
+$(objpfx)ifuncmain2: $(addprefix $(objpfx),ifuncdep2.o)
+$(objpfx)ifuncmain2pic: $(addprefix $(objpfx),ifuncdep2pic.o)
+$(objpfx)ifuncmain2static: $(addprefix $(objpfx),ifuncdep2.o)
+$(objpfx)ifuncmain2picstatic: $(addprefix $(objpfx),ifuncdep2pic.o)
+
+$(objpfx)ifuncmain3: $(libdl)
+$(objpfx)ifuncmain3.out: $(objpfx)ifuncmod3.so
+
+$(objpfx)ifuncmain5: $(addprefix $(objpfx),ifuncmod5.so)
+$(objpfx)ifuncmain5pic: $(addprefix $(objpfx),ifuncmod5.so)
+$(objpfx)ifuncmain5static: $(addprefix $(objpfx),ifuncdep5.o)
+$(objpfx)ifuncmain5staticpic: $(addprefix $(objpfx),ifuncdep5pic.o)
+$(objpfx)ifuncmain5picstatic: $(addprefix $(objpfx),ifuncdep5pic.o)
+
+$(objpfx)tst-unique1: $(libdl)
+$(objpfx)tst-unique1.out: $(objpfx)tst-unique1mod1.so \
+ $(objpfx)tst-unique1mod2.so
+
+$(objpfx)tst-unique2: $(libdl) $(objpfx)tst-unique2mod1.so
+$(objpfx)tst-unique2.out: $(objpfx)tst-unique2mod2.so
+
+$(objpfx)tst-unique3: $(libdl) $(objpfx)tst-unique3lib.so
+$(objpfx)tst-unique3.out: $(objpfx)tst-unique3lib2.so
+
+$(objpfx)tst-unique4: $(objpfx)tst-unique4lib.so
+
+$(objpfx)tst-nodelete: $(libdl)
+$(objpfx)tst-nodelete.out: $(objpfx)tst-nodelete-uniquemod.so \
+ $(objpfx)tst-nodelete-rtldmod.so \
+ $(objpfx)tst-nodelete-zmod.so
+
+LDFLAGS-tst-nodelete = -rdynamic
+LDFLAGS-tst-nodelete-zmod.so = -Wl,--enable-new-dtags,-z,nodelete
+
+$(objpfx)tst-nodelete2: $(libdl)
+$(objpfx)tst-nodelete2.out: $(objpfx)tst-nodelete2mod.so
+
+LDFLAGS-tst-nodelete2 = -rdynamic
+
+$(objpfx)tst-initorder-cmp.out: tst-initorder.exp $(objpfx)tst-initorder.out
+ cmp $^ > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-initorder2: $(objpfx)tst-initorder2a.so $(objpfx)tst-initorder2d.so $(objpfx)tst-initorder2c.so
+$(objpfx)tst-initorder2a.so: $(objpfx)tst-initorder2b.so
+$(objpfx)tst-initorder2b.so: $(objpfx)tst-initorder2c.so
+$(objpfx)tst-initorder2c.so: $(objpfx)tst-initorder2d.so
+LDFLAGS-tst-initorder2 = $(no-as-needed)
+LDFLAGS-tst-initorder2a.so = $(no-as-needed)
+LDFLAGS-tst-initorder2b.so = $(no-as-needed)
+LDFLAGS-tst-initorder2c.so = $(no-as-needed)
+define o-iterator-doit
+$(objpfx)tst-initorder2$o.os: tst-initorder2.c; \
+$$(compile-command.c) -DNAME=\"$o\"
+endef
+object-suffixes-left := a b c d
+include $(o-iterator)
+
+$(objpfx)tst-initorder2-cmp.out: tst-initorder2.exp $(objpfx)tst-initorder2.out
+ cmp $^ > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-relsort1: $(libdl)
+$(objpfx)tst-relsort1mod1.so: $(libm) $(objpfx)tst-relsort1mod2.so
+$(objpfx)tst-relsort1mod2.so: $(libm)
+$(objpfx)tst-relsort1.out: $(objpfx)tst-relsort1mod1.so \
+ $(objpfx)tst-relsort1mod2.so
+
+$(objpfx)tst-unused-dep.out: $(objpfx)testobj1.so
+ $(test-wrapper-env) \
+ LD_TRACE_LOADED_OBJECTS=1 \
+ LD_DEBUG=unused \
+ LD_PRELOAD= \
+ $(rtld-prefix) \
+ $< > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-unused-dep-cmp.out: $(objpfx)tst-unused-dep.out
+ cmp $< /dev/null > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-audit11.out: $(objpfx)tst-auditmod11.so $(objpfx)tst-audit11mod1.so
+$(objpfx)tst-audit11: $(libdl)
+tst-audit11-ENV = LD_AUDIT=$(objpfx)tst-auditmod11.so
+$(objpfx)tst-audit11mod1.so: $(objpfx)tst-audit11mod2.so
+LDFLAGS-tst-audit11mod2.so = -Wl,--version-script=tst-audit11mod2.map,-soname,tst-audit11mod2.so
+
+$(objpfx)tst-audit12.out: $(objpfx)tst-auditmod12.so $(objpfx)tst-audit12mod1.so $(objpfx)tst-audit12mod3.so
+$(objpfx)tst-audit12: $(libdl)
+tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so
+$(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so
+LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map
+
+# Override -z defs, so that we can reference an undefined symbol.
+# Force lazy binding for the same reason.
+LDFLAGS-tst-latepthreadmod.so = \
+ -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all
+# Do not optimize sibling calls as the test relies on a JMP_SLOT relocation for
+# function this_function_is_not_defined.
+CFLAGS-tst-latepthreadmod.c = -fno-optimize-sibling-calls
+$(objpfx)tst-latepthreadmod.so: $(shared-thread-library)
+$(objpfx)tst-latepthread: $(libdl)
+$(objpfx)tst-latepthread.out: $(objpfx)tst-latepthreadmod.so
+
+# The test modules are parameterized by preprocessor macros.
+$(patsubst %,$(objpfx)%.os,$(tst-tls-many-dynamic-modules)): \
+ $(objpfx)tst-tls-manydynamic%mod.os : tst-tls-manydynamicmod.c
+ $(compile-command.c) \
+ -DNAME=tls_global_$* -DSETTER=set_value_$* -DGETTER=get_value_$*
+$(objpfx)tst-tls-manydynamic: $(libdl) $(shared-thread-library)
+$(objpfx)tst-tls-manydynamic.out: \
+ $(patsubst %,$(objpfx)%.so,$(tst-tls-many-dynamic-modules))
+
+tst-prelink-ENV = LD_TRACE_PRELINKING=1
+
+$(objpfx)tst-prelink-conflict.out: $(objpfx)tst-prelink.out
+ grep stdout $< | grep conflict | $(AWK) '{ print $$10, $$11 }' > $@
+
+$(objpfx)tst-prelink-cmp.out: tst-prelink.exp \
+ $(objpfx)tst-prelink-conflict.out
+ cmp $^ > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig
+ $(SHELL) $< '$(common-objpfx)' '$(test-wrapper-env)' \
+ '$(run-program-env)' > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-dlsym-error: $(libdl)
+
+# Test static linking of all the libraries we can possibly link
+# together. Note that in some configurations this may be less than the
+# complete list of libraries we build but we try to maxmimize this list.
+$(objpfx)tst-linkall-static: \
+ $(common-objpfx)math/libm.a \
+ $(common-objpfx)resolv/libresolv.a \
+ $(common-objpfx)dlfcn/libdl.a \
+ $(common-objpfx)login/libutil.a \
+ $(common-objpfx)rt/librt.a \
+ $(common-objpfx)resolv/libanl.a \
+ $(static-thread-library)
+
+# If we are using NSS crypto and we have the ability to link statically
+# then we include libcrypt.a, otherwise we leave out libcrypt.a and
+# link as much as we can into the tst-linkall-static test. This assumes
+# that linking with libcrypt.a does everything required to include the
+# static NSS crypto library.
+ifeq (yesyes,$(nss-crypt)$(static-nss-crypt))
+$(objpfx)tst-linkall-static: \
+ $(common-objpfx)crypt/libcrypt.a
+endif
+# If we are not using NSS crypto then we always have the ability to link
+# with libcrypt.a.
+ifeq (no,$(nss-crypt))
+$(objpfx)tst-linkall-static: \
+ $(common-objpfx)crypt/libcrypt.a
+endif
+
+# The application depends on the DSO, and the DSO loads the plugin.
+# The plugin also depends on the DSO. This creates the circular
+# dependency via dlopen that we're testing to make sure works.
+$(objpfx)tst-nodelete-dlclose-dso.so: $(libdl)
+$(objpfx)tst-nodelete-dlclose-plugin.so: $(objpfx)tst-nodelete-dlclose-dso.so
+$(objpfx)tst-nodelete-dlclose: $(objpfx)tst-nodelete-dlclose-dso.so
+$(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \
+ $(objpfx)tst-nodelete-dlclose-plugin.so
+
+tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \
+ LD_HWCAP_MASK=0x1
+tst-env-setuid-tunables-ENV = \
+ GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096
diff --git a/REORG.TODO/elf/Versions b/REORG.TODO/elf/Versions
new file mode 100644
index 0000000000..c59facdbd7
--- /dev/null
+++ b/REORG.TODO/elf/Versions
@@ -0,0 +1,77 @@
+libc {
+ GLIBC_2.0 {
+%ifdef EXPORT_UNWIND_FIND_FDE
+ __deregister_frame_info; __register_frame_info;
+%endif
+ }
+ GLIBC_2.1 {
+ # functions used in other libraries
+ _dl_mcount_wrapper; _dl_mcount_wrapper_check;
+ }
+ GLIBC_2.2.4 {
+ dl_iterate_phdr;
+ }
+%ifdef EXPORT_UNWIND_FIND_FDE
+ # Needed for SHLIB_COMPAT calls using this version.
+ GLIBC_2.2.5 {
+ }
+ GCC_3.0 {
+ __deregister_frame_info_bases; __register_frame_info_bases;
+ __register_frame_info_table_bases; _Unwind_Find_FDE;
+ }
+%endif
+ GLIBC_PRIVATE {
+ # functions used in other libraries
+ _dl_addr;
+ _dl_open_hook;
+ _dl_sym; _dl_vsym;
+ __libc_dlclose; __libc_dlopen_mode; __libc_dlsym;
+
+ # Internal error handling support. Interposes the functions in ld.so.
+ _dl_signal_error; _dl_catch_error;
+ }
+}
+
+ld {
+ GLIBC_2.0 {
+ # Functions which are interposed from libc.so.
+ calloc; free; malloc; realloc;
+
+ _r_debug;
+ }
+ GLIBC_2.1 {
+ # functions used in other libraries
+ _dl_mcount;
+ # historically used by Garbage Collectors
+ __libc_stack_end;
+ }
+ GLIBC_2.3 {
+ # runtime interface to TLS
+ __tls_get_addr;
+ }
+ GLIBC_2.4 {
+ # stack canary
+ __stack_chk_guard;
+ }
+ GLIBC_PRIVATE {
+ # Those are in the dynamic linker, but used by libc.so.
+ __libc_enable_secure;
+ _dl_allocate_tls; _dl_allocate_tls_init;
+ _dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info;
+ _dl_deallocate_tls; _dl_make_stack_executable; _dl_out_of_memory;
+ _dl_rtld_di_serinfo; _dl_starting_up;
+ _rtld_global; _rtld_global_ro;
+
+ # Only here for gdb while a better method is developed.
+ _dl_debug_state;
+
+ # Pointer protection.
+ __pointer_chk_guard;
+
+ # Internal error handling support. Interposed by libc.so.
+ _dl_signal_error; _dl_catch_error;
+
+ # Set value of a tunable.
+ __tunable_get_val;
+ }
+}
diff --git a/REORG.TODO/elf/cache.c b/REORG.TODO/elf/cache.c
new file mode 100644
index 0000000000..a76f89281d
--- /dev/null
+++ b/REORG.TODO/elf/cache.c
@@ -0,0 +1,829 @@
+/* Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Andreas Jaeger <aj@suse.de>, 1999.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <error.h>
+#include <dirent.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ldconfig.h>
+#include <dl-cache.h>
+
+struct cache_entry
+{
+ char *lib; /* Library name. */
+ char *path; /* Path to find library. */
+ int flags; /* Flags to indicate kind of library. */
+ unsigned int osversion; /* Required OS version. */
+ uint64_t hwcap; /* Important hardware capabilities. */
+ int bits_hwcap; /* Number of bits set in hwcap. */
+ struct cache_entry *next; /* Next entry in list. */
+};
+
+/* List of all cache entries. */
+static struct cache_entry *entries;
+
+static const char *flag_descr[] =
+{ "libc4", "ELF", "libc5", "libc6"};
+
+/* Print a single entry. */
+static void
+print_entry (const char *lib, int flag, unsigned int osversion,
+ uint64_t hwcap, const char *key)
+{
+ printf ("\t%s (", lib);
+ switch (flag & FLAG_TYPE_MASK)
+ {
+ case FLAG_LIBC4:
+ case FLAG_ELF:
+ case FLAG_ELF_LIBC5:
+ case FLAG_ELF_LIBC6:
+ fputs (flag_descr[flag & FLAG_TYPE_MASK], stdout);
+ break;
+ default:
+ fputs (_("unknown"), stdout);
+ break;
+ }
+ switch (flag & FLAG_REQUIRED_MASK)
+ {
+ case FLAG_SPARC_LIB64:
+ fputs (",64bit", stdout);
+ break;
+ case FLAG_IA64_LIB64:
+ fputs (",IA-64", stdout);
+ break;
+ case FLAG_X8664_LIB64:
+ fputs (",x86-64", stdout);
+ break;
+ case FLAG_S390_LIB64:
+ fputs (",64bit", stdout);
+ break;
+ case FLAG_POWERPC_LIB64:
+ fputs (",64bit", stdout);
+ break;
+ case FLAG_MIPS64_LIBN32:
+ fputs (",N32", stdout);
+ break;
+ case FLAG_MIPS64_LIBN64:
+ fputs (",64bit", stdout);
+ break;
+ case FLAG_X8664_LIBX32:
+ fputs (",x32", stdout);
+ break;
+ case FLAG_ARM_LIBHF:
+ fputs (",hard-float", stdout);
+ break;
+ case FLAG_AARCH64_LIB64:
+ fputs (",AArch64", stdout);
+ break;
+ /* Uses the ARM soft-float ABI. */
+ case FLAG_ARM_LIBSF:
+ fputs (",soft-float", stdout);
+ break;
+ case FLAG_MIPS_LIB32_NAN2008:
+ fputs (",nan2008", stdout);
+ break;
+ case FLAG_MIPS64_LIBN32_NAN2008:
+ fputs (",N32,nan2008", stdout);
+ break;
+ case FLAG_MIPS64_LIBN64_NAN2008:
+ fputs (",64bit,nan2008", stdout);
+ break;
+ case 0:
+ break;
+ default:
+ printf (",%d", flag & FLAG_REQUIRED_MASK);
+ break;
+ }
+ if (hwcap != 0)
+ printf (", hwcap: %#.16" PRIx64, hwcap);
+ if (osversion != 0)
+ {
+ static const char *const abi_tag_os[] =
+ {
+ [0] = "Linux",
+ [1] = "Hurd",
+ [2] = "Solaris",
+ [3] = "FreeBSD",
+ [4] = "kNetBSD",
+ [5] = "Syllable",
+ [6] = N_("Unknown OS")
+ };
+#define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
+ unsigned int os = osversion >> 24;
+
+ printf (_(", OS ABI: %s %d.%d.%d"),
+ _(abi_tag_os[os > MAXTAG ? MAXTAG : os]),
+ (osversion >> 16) & 0xff,
+ (osversion >> 8) & 0xff,
+ osversion & 0xff);
+ }
+ printf (") => %s\n", key);
+}
+
+
+/* Print the whole cache file, if a file contains the new cache format
+ hidden in the old one, print the contents of the new format. */
+void
+print_cache (const char *cache_name)
+{
+ int fd = open (cache_name, O_RDONLY);
+ if (fd < 0)
+ error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
+
+ struct stat64 st;
+ if (fstat64 (fd, &st) < 0
+ /* No need to map the file if it is empty. */
+ || st.st_size == 0)
+ {
+ close (fd);
+ return;
+ }
+
+ struct cache_file *cache
+ = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (cache == MAP_FAILED)
+ error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
+
+ size_t cache_size = st.st_size;
+ if (cache_size < sizeof (struct cache_file))
+ error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
+
+ struct cache_file_new *cache_new = NULL;
+ const char *cache_data;
+ int format = 0;
+
+ if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
+ {
+ /* This can only be the new format without the old one. */
+ cache_new = (struct cache_file_new *) cache;
+
+ if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
+ || memcmp (cache_new->version, CACHE_VERSION,
+ sizeof CACHE_VERSION - 1))
+ error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
+ format = 1;
+ /* This is where the strings start. */
+ cache_data = (const char *) cache_new;
+ }
+ else
+ {
+ size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
+ + (cache->nlibs
+ * sizeof (struct file_entry)));
+ /* This is where the strings start. */
+ cache_data = (const char *) &cache->libs[cache->nlibs];
+
+ /* Check for a new cache embedded in the old format. */
+ if (cache_size >
+ (offset + sizeof (struct cache_file_new)))
+ {
+
+ cache_new = (struct cache_file_new *) ((void *)cache + offset);
+
+ if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
+ sizeof CACHEMAGIC_NEW - 1) == 0
+ && memcmp (cache_new->version, CACHE_VERSION,
+ sizeof CACHE_VERSION - 1) == 0)
+ {
+ cache_data = (const char *) cache_new;
+ format = 1;
+ }
+ }
+ }
+
+ if (format == 0)
+ {
+ printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
+
+ /* Print everything. */
+ for (unsigned int i = 0; i < cache->nlibs; i++)
+ print_entry (cache_data + cache->libs[i].key,
+ cache->libs[i].flags, 0, 0,
+ cache_data + cache->libs[i].value);
+ }
+ else if (format == 1)
+ {
+ printf (_("%d libs found in cache `%s'\n"),
+ cache_new->nlibs, cache_name);
+
+ /* Print everything. */
+ for (unsigned int i = 0; i < cache_new->nlibs; i++)
+ print_entry (cache_data + cache_new->libs[i].key,
+ cache_new->libs[i].flags,
+ cache_new->libs[i].osversion,
+ cache_new->libs[i].hwcap,
+ cache_data + cache_new->libs[i].value);
+ }
+ /* Cleanup. */
+ munmap (cache, cache_size);
+ close (fd);
+}
+
+/* Initialize cache data structures. */
+void
+init_cache (void)
+{
+ entries = NULL;
+}
+
+static int
+compare (const struct cache_entry *e1, const struct cache_entry *e2)
+{
+ /* We need to swap entries here to get the correct sort order. */
+ int res = _dl_cache_libcmp (e2->lib, e1->lib);
+ if (res == 0)
+ {
+ if (e1->flags < e2->flags)
+ return 1;
+ else if (e1->flags > e2->flags)
+ return -1;
+ /* Sort by most specific hwcap. */
+ else if (e2->bits_hwcap > e1->bits_hwcap)
+ return 1;
+ else if (e2->bits_hwcap < e1->bits_hwcap)
+ return -1;
+ else if (e2->hwcap > e1->hwcap)
+ return 1;
+ else if (e2->hwcap < e1->hwcap)
+ return -1;
+ if (e2->osversion > e1->osversion)
+ return 1;
+ if (e2->osversion < e1->osversion)
+ return -1;
+ }
+ return res;
+}
+
+/* Save the contents of the cache. */
+void
+save_cache (const char *cache_name)
+{
+ /* The cache entries are sorted already, save them in this order. */
+
+ /* Count the length of all strings. */
+ /* The old format doesn't contain hwcap entries and doesn't contain
+ libraries in subdirectories with hwcaps entries. Count therefore
+ also all entries with hwcap == 0. */
+ size_t total_strlen = 0;
+ struct cache_entry *entry;
+ /* Number of cache entries. */
+ int cache_entry_count = 0;
+ /* Number of normal cache entries. */
+ int cache_entry_old_count = 0;
+
+ for (entry = entries; entry != NULL; entry = entry->next)
+ {
+ /* Account the final NULs. */
+ total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
+ ++cache_entry_count;
+ if (entry->hwcap == 0)
+ ++cache_entry_old_count;
+ }
+
+ /* Create the on disk cache structure. */
+ struct cache_file *file_entries = NULL;
+ size_t file_entries_size = 0;
+
+ if (opt_format != 2)
+ {
+ /* struct cache_file_new is 64-bit aligned on some arches while
+ only 32-bit aligned on other arches. Duplicate last old
+ cache entry so that new cache in ld.so.cache can be used by
+ both. */
+ if (opt_format != 0)
+ cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
+
+ /* And the list of all entries in the old format. */
+ file_entries_size = sizeof (struct cache_file)
+ + cache_entry_old_count * sizeof (struct file_entry);
+ file_entries = xmalloc (file_entries_size);
+
+ /* Fill in the header. */
+ memset (file_entries, '\0', sizeof (struct cache_file));
+ memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
+
+ file_entries->nlibs = cache_entry_old_count;
+ }
+
+ struct cache_file_new *file_entries_new = NULL;
+ size_t file_entries_new_size = 0;
+
+ if (opt_format != 0)
+ {
+ /* And the list of all entries in the new format. */
+ file_entries_new_size = sizeof (struct cache_file_new)
+ + cache_entry_count * sizeof (struct file_entry_new);
+ file_entries_new = xmalloc (file_entries_new_size);
+
+ /* Fill in the header. */
+ memset (file_entries_new, '\0', sizeof (struct cache_file_new));
+ memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
+ sizeof CACHEMAGIC_NEW - 1);
+ memcpy (file_entries_new->version, CACHE_VERSION,
+ sizeof CACHE_VERSION - 1);
+
+ file_entries_new->nlibs = cache_entry_count;
+ file_entries_new->len_strings = total_strlen;
+ }
+
+ /* Pad for alignment of cache_file_new. */
+ size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
+
+ /* If we have both formats, we hide the new format in the strings
+ table, we have to adjust all string indices for this so that
+ old libc5/glibc 2 dynamic linkers just ignore them. */
+ unsigned int str_offset;
+ if (opt_format != 0)
+ str_offset = file_entries_new_size;
+ else
+ str_offset = 0;
+
+ /* An array for all strings. */
+ char *strings = xmalloc (total_strlen);
+ char *str = strings;
+ int idx_old;
+ int idx_new;
+
+ for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
+ entry = entry->next, ++idx_new)
+ {
+ /* First the library. */
+ if (opt_format != 2 && entry->hwcap == 0)
+ {
+ file_entries->libs[idx_old].flags = entry->flags;
+ /* XXX: Actually we can optimize here and remove duplicates. */
+ file_entries->libs[idx_old].key = str_offset + pad;
+ }
+ if (opt_format != 0)
+ {
+ /* We could subtract file_entries_new_size from str_offset -
+ not doing so makes the code easier, the string table
+ always begins at the beginning of the new cache
+ struct. */
+ file_entries_new->libs[idx_new].flags = entry->flags;
+ file_entries_new->libs[idx_new].osversion = entry->osversion;
+ file_entries_new->libs[idx_new].hwcap = entry->hwcap;
+ file_entries_new->libs[idx_new].key = str_offset;
+ }
+
+ size_t len = strlen (entry->lib) + 1;
+ str = mempcpy (str, entry->lib, len);
+ str_offset += len;
+ /* Then the path. */
+ if (opt_format != 2 && entry->hwcap == 0)
+ file_entries->libs[idx_old].value = str_offset + pad;
+ if (opt_format != 0)
+ file_entries_new->libs[idx_new].value = str_offset;
+ len = strlen (entry->path) + 1;
+ str = mempcpy (str, entry->path, len);
+ str_offset += len;
+ /* Ignore entries with hwcap for old format. */
+ if (entry->hwcap == 0)
+ ++idx_old;
+ }
+
+ /* Duplicate last old cache entry if needed. */
+ if (opt_format != 2
+ && idx_old < cache_entry_old_count)
+ file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
+
+ /* Write out the cache. */
+
+ /* Write cache first to a temporary file and rename it later. */
+ char *temp_name = xmalloc (strlen (cache_name) + 2);
+ sprintf (temp_name, "%s~", cache_name);
+
+ /* Create file. */
+ int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
+ S_IRUSR|S_IWUSR);
+ if (fd < 0)
+ error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
+ temp_name);
+
+ /* Write contents. */
+ if (opt_format != 2)
+ {
+ if (write (fd, file_entries, file_entries_size)
+ != (ssize_t) file_entries_size)
+ error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
+ }
+ if (opt_format != 0)
+ {
+ /* Align cache. */
+ if (opt_format != 2)
+ {
+ char zero[pad];
+ memset (zero, '\0', pad);
+ if (write (fd, zero, pad) != (ssize_t) pad)
+ error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
+ }
+ if (write (fd, file_entries_new, file_entries_new_size)
+ != (ssize_t) file_entries_new_size)
+ error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
+ }
+
+ if (write (fd, strings, total_strlen) != (ssize_t) total_strlen
+ || close (fd))
+ error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
+
+ /* Make sure user can always read cache file */
+ if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
+ error (EXIT_FAILURE, errno,
+ _("Changing access rights of %s to %#o failed"), temp_name,
+ S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
+
+ /* Move temporary to its final location. */
+ if (rename (temp_name, cache_name))
+ error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
+ cache_name);
+
+ /* Free all allocated memory. */
+ free (file_entries_new);
+ free (file_entries);
+ free (strings);
+
+ while (entries)
+ {
+ entry = entries;
+ entries = entries->next;
+ free (entry);
+ }
+}
+
+
+/* Add one library to the cache. */
+void
+add_to_cache (const char *path, const char *lib, int flags,
+ unsigned int osversion, uint64_t hwcap)
+{
+ size_t liblen = strlen (lib) + 1;
+ size_t len = liblen + strlen (path) + 1;
+ struct cache_entry *new_entry
+ = xmalloc (sizeof (struct cache_entry) + liblen + len);
+
+ new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
+ new_entry->path = new_entry->lib + liblen;
+ snprintf (new_entry->path, len, "%s/%s", path, lib);
+ new_entry->flags = flags;
+ new_entry->osversion = osversion;
+ new_entry->hwcap = hwcap;
+ new_entry->bits_hwcap = 0;
+
+ /* Count the number of bits set in the masked value. */
+ for (size_t i = 0;
+ (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
+ if ((hwcap & (1ULL << i)) != 0)
+ ++new_entry->bits_hwcap;
+
+
+ /* Keep the list sorted - search for right place to insert. */
+ struct cache_entry *ptr = entries;
+ struct cache_entry *prev = entries;
+ while (ptr != NULL)
+ {
+ if (compare (ptr, new_entry) > 0)
+ break;
+ prev = ptr;
+ ptr = ptr->next;
+ }
+ /* Is this the first entry? */
+ if (ptr == entries)
+ {
+ new_entry->next = entries;
+ entries = new_entry;
+ }
+ else
+ {
+ new_entry->next = prev->next;
+ prev->next = new_entry;
+ }
+}
+
+
+/* Auxiliary cache. */
+
+struct aux_cache_entry_id
+{
+ uint64_t ino;
+ uint64_t ctime;
+ uint64_t size;
+ uint64_t dev;
+};
+
+struct aux_cache_entry
+{
+ struct aux_cache_entry_id id;
+ int flags;
+ unsigned int osversion;
+ int used;
+ char *soname;
+ struct aux_cache_entry *next;
+};
+
+#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
+
+struct aux_cache_file_entry
+{
+ struct aux_cache_entry_id id; /* Unique id of entry. */
+ int32_t flags; /* This is 1 for an ELF library. */
+ uint32_t soname; /* String table indice. */
+ uint32_t osversion; /* Required OS version. */
+ int32_t pad;
+};
+
+/* ldconfig maintains an auxiliary cache file that allows
+ only reading those libraries that have changed since the last iteration.
+ For this for each library some information is cached in the auxiliary
+ cache. */
+struct aux_cache_file
+{
+ char magic[sizeof AUX_CACHEMAGIC - 1];
+ uint32_t nlibs; /* Number of entries. */
+ uint32_t len_strings; /* Size of string table. */
+ struct aux_cache_file_entry libs[0]; /* Entries describing libraries. */
+ /* After this the string table of size len_strings is found. */
+};
+
+static const unsigned int primes[] =
+{
+ 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
+ 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
+ 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
+};
+
+static size_t aux_hash_size;
+static struct aux_cache_entry **aux_hash;
+
+/* Simplistic hash function for aux_cache_entry_id. */
+static unsigned int
+aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
+{
+ uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
+ return ret ^ (ret >> 32);
+}
+
+static size_t nextprime (size_t x)
+{
+ for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
+ if (primes[i] >= x)
+ return primes[i];
+ return x;
+}
+
+void
+init_aux_cache (void)
+{
+ aux_hash_size = primes[3];
+ aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
+}
+
+int
+search_aux_cache (struct stat64 *stat_buf, int *flags,
+ unsigned int *osversion, char **soname)
+{
+ struct aux_cache_entry_id id;
+ id.ino = (uint64_t) stat_buf->st_ino;
+ id.ctime = (uint64_t) stat_buf->st_ctime;
+ id.size = (uint64_t) stat_buf->st_size;
+ id.dev = (uint64_t) stat_buf->st_dev;
+
+ unsigned int hash = aux_cache_entry_id_hash (&id);
+ struct aux_cache_entry *entry;
+ for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
+ if (id.ino == entry->id.ino
+ && id.ctime == entry->id.ctime
+ && id.size == entry->id.size
+ && id.dev == entry->id.dev)
+ {
+ *flags = entry->flags;
+ *osversion = entry->osversion;
+ if (entry->soname != NULL)
+ *soname = xstrdup (entry->soname);
+ else
+ *soname = NULL;
+ entry->used = 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
+ unsigned int osversion, const char *soname, int used)
+{
+ size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
+ struct aux_cache_entry *entry;
+ for (entry = aux_hash[hash]; entry; entry = entry->next)
+ if (id->ino == entry->id.ino
+ && id->ctime == entry->id.ctime
+ && id->size == entry->id.size
+ && id->dev == entry->id.dev)
+ abort ();
+
+ size_t len = soname ? strlen (soname) + 1 : 0;
+ entry = xmalloc (sizeof (struct aux_cache_entry) + len);
+ entry->id = *id;
+ entry->flags = flags;
+ entry->osversion = osversion;
+ entry->used = used;
+ if (soname != NULL)
+ entry->soname = memcpy ((char *) (entry + 1), soname, len);
+ else
+ entry->soname = NULL;
+ entry->next = aux_hash[hash];
+ aux_hash[hash] = entry;
+}
+
+void
+add_to_aux_cache (struct stat64 *stat_buf, int flags,
+ unsigned int osversion, const char *soname)
+{
+ struct aux_cache_entry_id id;
+ id.ino = (uint64_t) stat_buf->st_ino;
+ id.ctime = (uint64_t) stat_buf->st_ctime;
+ id.size = (uint64_t) stat_buf->st_size;
+ id.dev = (uint64_t) stat_buf->st_dev;
+ insert_to_aux_cache (&id, flags, osversion, soname, 1);
+}
+
+/* Load auxiliary cache to search for unchanged entries. */
+void
+load_aux_cache (const char *aux_cache_name)
+{
+ int fd = open (aux_cache_name, O_RDONLY);
+ if (fd < 0)
+ {
+ init_aux_cache ();
+ return;
+ }
+
+ struct stat64 st;
+ if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
+ {
+ close (fd);
+ init_aux_cache ();
+ return;
+ }
+
+ size_t aux_cache_size = st.st_size;
+ struct aux_cache_file *aux_cache
+ = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (aux_cache == MAP_FAILED
+ || aux_cache_size < sizeof (struct aux_cache_file)
+ || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
+ || aux_cache_size != (sizeof(struct aux_cache_file) +
+ aux_cache->nlibs * sizeof(struct aux_cache_file_entry) +
+ aux_cache->len_strings))
+ {
+ close (fd);
+ init_aux_cache ();
+ return;
+ }
+
+ aux_hash_size = nextprime (aux_cache->nlibs);
+ aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
+
+ const char *aux_cache_data
+ = (const char *) &aux_cache->libs[aux_cache->nlibs];
+ for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
+ insert_to_aux_cache (&aux_cache->libs[i].id,
+ aux_cache->libs[i].flags,
+ aux_cache->libs[i].osversion,
+ aux_cache->libs[i].soname == 0
+ ? NULL : aux_cache_data + aux_cache->libs[i].soname,
+ 0);
+
+ munmap (aux_cache, aux_cache_size);
+ close (fd);
+}
+
+/* Save the contents of the auxiliary cache. */
+void
+save_aux_cache (const char *aux_cache_name)
+{
+ /* Count the length of all sonames. We start with empty string. */
+ size_t total_strlen = 1;
+ /* Number of cache entries. */
+ int cache_entry_count = 0;
+
+ for (size_t i = 0; i < aux_hash_size; ++i)
+ for (struct aux_cache_entry *entry = aux_hash[i];
+ entry != NULL; entry = entry->next)
+ if (entry->used)
+ {
+ ++cache_entry_count;
+ if (entry->soname != NULL)
+ total_strlen += strlen (entry->soname) + 1;
+ }
+
+ /* Auxiliary cache. */
+ size_t file_entries_size
+ = sizeof (struct aux_cache_file)
+ + cache_entry_count * sizeof (struct aux_cache_file_entry);
+ struct aux_cache_file *file_entries
+ = xmalloc (file_entries_size + total_strlen);
+
+ /* Fill in the header of the auxiliary cache. */
+ memset (file_entries, '\0', sizeof (struct aux_cache_file));
+ memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
+
+ file_entries->nlibs = cache_entry_count;
+ file_entries->len_strings = total_strlen;
+
+ /* Initial String offset for auxiliary cache is always after the
+ special empty string. */
+ unsigned int str_offset = 1;
+
+ /* An array for all strings. */
+ char *str = (char *) file_entries + file_entries_size;
+ *str++ = '\0';
+
+ size_t idx = 0;
+ for (size_t i = 0; i < aux_hash_size; ++i)
+ for (struct aux_cache_entry *entry = aux_hash[i];
+ entry != NULL; entry = entry->next)
+ if (entry->used)
+ {
+ file_entries->libs[idx].id = entry->id;
+ file_entries->libs[idx].flags = entry->flags;
+ if (entry->soname == NULL)
+ file_entries->libs[idx].soname = 0;
+ else
+ {
+ file_entries->libs[idx].soname = str_offset;
+
+ size_t len = strlen (entry->soname) + 1;
+ str = mempcpy (str, entry->soname, len);
+ str_offset += len;
+ }
+ file_entries->libs[idx].osversion = entry->osversion;
+ file_entries->libs[idx++].pad = 0;
+ }
+
+ /* Write out auxiliary cache file. */
+ /* Write auxiliary cache first to a temporary file and rename it later. */
+
+ char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
+ sprintf (temp_name, "%s~", aux_cache_name);
+
+ /* Check that directory exists and create if needed. */
+ char *dir = strdupa (aux_cache_name);
+ dir = dirname (dir);
+
+ struct stat64 st;
+ if (stat64 (dir, &st) < 0)
+ {
+ if (mkdir (dir, 0700) < 0)
+ goto out_fail;
+ }
+
+ /* Create file. */
+ int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
+ S_IRUSR|S_IWUSR);
+ if (fd < 0)
+ goto out_fail;
+
+ if (write (fd, file_entries, file_entries_size + total_strlen)
+ != (ssize_t) (file_entries_size + total_strlen)
+ || close (fd))
+ {
+ unlink (temp_name);
+ goto out_fail;
+ }
+
+ /* Move temporary to its final location. */
+ if (rename (temp_name, aux_cache_name))
+ unlink (temp_name);
+
+out_fail:
+ /* Free allocated memory. */
+ free (temp_name);
+ free (file_entries);
+}
diff --git a/REORG.TODO/elf/chroot_canon.c b/REORG.TODO/elf/chroot_canon.c
new file mode 100644
index 0000000000..78cd6f4a5e
--- /dev/null
+++ b/REORG.TODO/elf/chroot_canon.c
@@ -0,0 +1,177 @@
+/* Return the canonical absolute name of a given file inside chroot.
+ Copyright (C) 1996-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <eloop-threshold.h>
+#include <ldconfig.h>
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+/* Return the canonical absolute name of file NAME as if chroot(CHROOT) was
+ done first. A canonical name does not contain any `.', `..' components
+ nor any repeated path separators ('/') or symlinks. All path components
+ must exist and NAME must be absolute filename. The result is malloc'd.
+ The returned name includes the CHROOT prefix. */
+
+char *
+chroot_canon (const char *chroot, const char *name)
+{
+ char *rpath;
+ char *dest;
+ char *extra_buf = NULL;
+ char *rpath_root;
+ const char *start;
+ const char *end;
+ const char *rpath_limit;
+ int num_links = 0;
+ size_t chroot_len = strlen (chroot);
+
+ if (chroot_len < 1)
+ {
+ __set_errno (EINVAL);
+ return NULL;
+ }
+
+ rpath = xmalloc (chroot_len + PATH_MAX);
+
+ rpath_limit = rpath + chroot_len + PATH_MAX;
+
+ rpath_root = (char *) mempcpy (rpath, chroot, chroot_len) - 1;
+ if (*rpath_root != '/')
+ *++rpath_root = '/';
+ dest = rpath_root + 1;
+
+ for (start = end = name; *start; start = end)
+ {
+ struct stat64 st;
+
+ /* Skip sequence of multiple path-separators. */
+ while (*start == '/')
+ ++start;
+
+ /* Find end of path component. */
+ for (end = start; *end && *end != '/'; ++end)
+ /* Nothing. */;
+
+ if (end - start == 0)
+ break;
+ else if (end - start == 1 && start[0] == '.')
+ /* nothing */;
+ else if (end - start == 2 && start[0] == '.' && start[1] == '.')
+ {
+ /* Back up to previous component, ignore if at root already. */
+ if (dest > rpath_root + 1)
+ while ((--dest)[-1] != '/');
+ }
+ else
+ {
+ size_t new_size;
+
+ if (dest[-1] != '/')
+ *dest++ = '/';
+
+ if (dest + (end - start) >= rpath_limit)
+ {
+ ptrdiff_t dest_offset = dest - rpath;
+ char *new_rpath;
+
+ new_size = rpath_limit - rpath;
+ if (end - start + 1 > PATH_MAX)
+ new_size += end - start + 1;
+ else
+ new_size += PATH_MAX;
+ new_rpath = (char *) xrealloc (rpath, new_size);
+ rpath = new_rpath;
+ rpath_limit = rpath + new_size;
+
+ dest = rpath + dest_offset;
+ }
+
+ dest = mempcpy (dest, start, end - start);
+ *dest = '\0';
+
+ if (lstat64 (rpath, &st) < 0)
+ {
+ if (*end == '\0')
+ goto done;
+ goto error;
+ }
+
+ if (S_ISLNK (st.st_mode))
+ {
+ char *buf = alloca (PATH_MAX);
+ size_t len;
+
+ if (++num_links > __eloop_threshold ())
+ {
+ __set_errno (ELOOP);
+ goto error;
+ }
+
+ ssize_t n = readlink (rpath, buf, PATH_MAX - 1);
+ if (n < 0)
+ {
+ if (*end == '\0')
+ goto done;
+ goto error;
+ }
+ buf[n] = '\0';
+
+ if (!extra_buf)
+ extra_buf = alloca (PATH_MAX);
+
+ len = strlen (end);
+ if (len >= PATH_MAX - n)
+ {
+ __set_errno (ENAMETOOLONG);
+ goto error;
+ }
+
+ /* Careful here, end may be a pointer into extra_buf... */
+ memmove (&extra_buf[n], end, len + 1);
+ name = end = memcpy (extra_buf, buf, n);
+
+ if (buf[0] == '/')
+ dest = rpath_root + 1; /* It's an absolute symlink */
+ else
+ /* Back up to previous component, ignore if at root already: */
+ if (dest > rpath_root + 1)
+ while ((--dest)[-1] != '/');
+ }
+ }
+ }
+ done:
+ if (dest > rpath_root + 1 && dest[-1] == '/')
+ --dest;
+ *dest = '\0';
+
+ return rpath;
+
+ error:
+ free (rpath);
+ return NULL;
+}
diff --git a/REORG.TODO/elf/circleload1.c b/REORG.TODO/elf/circleload1.c
new file mode 100644
index 0000000000..990ff84a84
--- /dev/null
+++ b/REORG.TODO/elf/circleload1.c
@@ -0,0 +1,166 @@
+#include <dlfcn.h>
+#include <libintl.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
+static int
+check_loaded_objects (const char **loaded)
+{
+ struct link_map *lm;
+ int n;
+ int *found = NULL;
+ int errors = 0;
+
+ for (n = 0; loaded[n]; n++)
+ /* NOTHING */;
+
+ if (n)
+ {
+ found = (int *) alloca (sizeof (int) * n);
+ memset (found, 0, sizeof (int) * n);
+ }
+
+ printf(" Name\n");
+ printf(" --------------------------------------------------------\n");
+ for (lm = MAPS; lm; lm = lm->l_next)
+ {
+ if (lm->l_name && lm->l_name[0])
+ printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
+ if (lm->l_type == lt_loaded && lm->l_name)
+ {
+ int match = 0;
+ for (n = 0; loaded[n] != NULL; n++)
+ {
+ if (strcmp (basename (loaded[n]), basename (lm->l_name)) == 0)
+ {
+ found[n] = 1;
+ match = 1;
+ break;
+ }
+ }
+
+ if (match == 0)
+ {
+ ++errors;
+ printf ("ERRORS: %s is not unloaded\n", lm->l_name);
+ }
+ }
+ }
+
+ for (n = 0; loaded[n] != NULL; n++)
+ {
+ if (found[n] == 0)
+ {
+ ++errors;
+ printf ("ERRORS: %s is not loaded\n", loaded[n]);
+ }
+ }
+
+ return errors;
+}
+
+static int
+load_dso (const char **loading, int undef, int flag)
+{
+ void *obj;
+ const char *loaded[] = { NULL, NULL, NULL, NULL };
+ int errors = 0;
+ const char *errstring;
+
+ printf ("\nThis is what is in memory now:\n");
+ errors += check_loaded_objects (loaded);
+
+ printf ("Loading shared object %s: %s\n", loading[0],
+ flag == RTLD_LAZY ? "RTLD_LAZY" : "RTLD_NOW");
+ obj = dlopen (loading[0], flag);
+ if (obj == NULL)
+ {
+ if (flag == RTLD_LAZY)
+ {
+ ++errors;
+ printf ("ERRORS: dlopen shouldn't fail for RTLD_LAZY\n");
+ }
+
+ errstring = dlerror ();
+ if (strstr (errstring, "undefined symbol") == 0
+ || strstr (errstring, "circlemod2_undefined") == 0)
+ {
+ ++errors;
+ printf ("ERRORS: dlopen: `%s': Invalid error string\n",
+ errstring);
+ }
+ else
+ printf ("dlopen: %s\n", errstring);
+ }
+ else
+ {
+ if (undef && flag == RTLD_NOW)
+ {
+ ++errors;
+ printf ("ERRORS: dlopen shouldn't work for RTLD_NOW\n");
+ }
+
+ if (!undef)
+ {
+ int (*func) (void);
+
+ func = dlsym (obj, "circlemod1");
+ if (func == NULL)
+ {
+ ++errors;
+ printf ("ERRORS: cannot get address of \"circlemod1\": %s\n",
+ dlerror ());
+ }
+ else if (func () != 3)
+ {
+ ++errors;
+ printf ("ERRORS: function \"circlemod1\" returned wrong result\n");
+ }
+ }
+
+ loaded[0] = loading[0];
+ loaded[1] = loading[1];
+ loaded[2] = loading[2];
+ }
+ errors += check_loaded_objects (loaded);
+
+ if (obj)
+ {
+ printf ("UnLoading shared object %s\n", loading[0]);
+ dlclose (obj);
+ loaded[0] = NULL;
+ loaded[1] = NULL;
+ loaded[2] = NULL;
+ errors += check_loaded_objects (loaded);
+ }
+
+ return errors;
+}
+
+int
+main (void)
+{
+ int errors = 0;
+ const char *loading[3];
+
+ loading[0] = "circlemod1a.so";
+ loading[1] = "circlemod2a.so";
+ loading[2] = "circlemod3a.so";
+ errors += load_dso (loading, 0, RTLD_LAZY);
+ errors += load_dso (loading, 0, RTLD_NOW);
+
+ loading[0] = "circlemod1.so";
+ loading[1] = "circlemod2.so";
+ loading[2] = "circlemod3.so";
+ errors += load_dso (loading, 1, RTLD_LAZY);
+ errors += load_dso (loading, 1, RTLD_NOW);
+
+ if (errors != 0)
+ printf ("%d errors found\n", errors);
+
+ return errors;
+}
diff --git a/REORG.TODO/elf/circlemod1.c b/REORG.TODO/elf/circlemod1.c
new file mode 100644
index 0000000000..933ccd3c02
--- /dev/null
+++ b/REORG.TODO/elf/circlemod1.c
@@ -0,0 +1,7 @@
+extern int circlemod2 (void);
+
+int
+circlemod1 (void)
+{
+ return circlemod2 ();
+}
diff --git a/REORG.TODO/elf/circlemod1a.c b/REORG.TODO/elf/circlemod1a.c
new file mode 100644
index 0000000000..45f229136d
--- /dev/null
+++ b/REORG.TODO/elf/circlemod1a.c
@@ -0,0 +1 @@
+#include "circlemod1.c"
diff --git a/REORG.TODO/elf/circlemod2.c b/REORG.TODO/elf/circlemod2.c
new file mode 100644
index 0000000000..ed8c1175fb
--- /dev/null
+++ b/REORG.TODO/elf/circlemod2.c
@@ -0,0 +1,9 @@
+extern void circlemod2_undefined (void);
+extern int circlemod3 (void);
+
+int
+circlemod2 (void)
+{
+ circlemod2_undefined ();
+ return circlemod3 ();
+}
diff --git a/REORG.TODO/elf/circlemod2a.c b/REORG.TODO/elf/circlemod2a.c
new file mode 100644
index 0000000000..dc6410b28b
--- /dev/null
+++ b/REORG.TODO/elf/circlemod2a.c
@@ -0,0 +1,7 @@
+extern int circlemod3 (void);
+
+int
+circlemod2 (void)
+{
+ return circlemod3 ();
+}
diff --git a/REORG.TODO/elf/circlemod3.c b/REORG.TODO/elf/circlemod3.c
new file mode 100644
index 0000000000..8d16fe682f
--- /dev/null
+++ b/REORG.TODO/elf/circlemod3.c
@@ -0,0 +1,14 @@
+extern int circlemod1 (void);
+extern int circlemod2 (void);
+
+int
+circlemod3 (void)
+{
+ return 3;
+}
+
+int
+circlemod3a (void)
+{
+ return circlemod1 () + circlemod2 ();
+}
diff --git a/REORG.TODO/elf/circlemod3a.c b/REORG.TODO/elf/circlemod3a.c
new file mode 100644
index 0000000000..f1b166ef84
--- /dev/null
+++ b/REORG.TODO/elf/circlemod3a.c
@@ -0,0 +1 @@
+#include "circlemod3.c"
diff --git a/REORG.TODO/elf/constload1.c b/REORG.TODO/elf/constload1.c
new file mode 100644
index 0000000000..7381beea88
--- /dev/null
+++ b/REORG.TODO/elf/constload1.c
@@ -0,0 +1,32 @@
+#include <dlfcn.h>
+#include <errno.h>
+#include <error.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ int (*foo) (void);
+ void *h;
+ int ret;
+
+ mtrace ();
+
+ h = dlopen ("constload2.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (h == NULL)
+ error (EXIT_FAILURE, errno, "cannot load module \"constload2.so\"");
+ foo = dlsym (h, "foo");
+ ret = foo ();
+ /* Note that the following dlclose() call cannot unload the objects.
+ Due to the introduced relocation dependency constload2.so depends
+ on constload3.so and the dependencies of constload2.so on constload3.so
+ is not visible to ld.so since it's done using dlopen(). */
+ if (dlclose (h) != 0)
+ {
+ puts ("failed to close");
+ exit (EXIT_FAILURE);
+ }
+ return ret;
+}
diff --git a/REORG.TODO/elf/constload2.c b/REORG.TODO/elf/constload2.c
new file mode 100644
index 0000000000..bf1bf182f3
--- /dev/null
+++ b/REORG.TODO/elf/constload2.c
@@ -0,0 +1,50 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int bar (void);
+extern int baz (void);
+extern int foo (void);
+extern void __attribute__ ((__constructor__)) init (void);
+
+void *h;
+
+int
+foo (void)
+{
+ return 42 + bar ();
+}
+
+int
+baz (void)
+{
+ return -21;
+}
+
+
+void
+__attribute__ ((__constructor__))
+init (void)
+{
+ h = dlopen ("constload3.so", RTLD_GLOBAL | RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("failed to load constload3");
+ exit (1);
+ }
+ else
+ puts ("succeeded loading constload3");
+}
+
+static void
+__attribute__ ((__destructor__))
+fini (void)
+{
+ if (dlclose (h) != 0)
+ {
+ puts ("failed to unload constload3");
+ exit (1);
+ }
+ else
+ puts ("succeeded unloading constload3");
+}
diff --git a/REORG.TODO/elf/constload3.c b/REORG.TODO/elf/constload3.c
new file mode 100644
index 0000000000..9c37620bba
--- /dev/null
+++ b/REORG.TODO/elf/constload3.c
@@ -0,0 +1,8 @@
+extern int baz (void);
+extern int bar (void);
+
+int
+bar (void)
+{
+ return -21 + baz ();
+}
diff --git a/REORG.TODO/elf/dblload.c b/REORG.TODO/elf/dblload.c
new file mode 100644
index 0000000000..52389a60ce
--- /dev/null
+++ b/REORG.TODO/elf/dblload.c
@@ -0,0 +1,53 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int
+main (void)
+{
+ void *p1;
+ void *p2;
+ int (*fp) (void);
+ int result;
+
+ mtrace ();
+
+ p1 = dlopen ("dblloadmod1.so", RTLD_LAZY);
+ if (p1 == NULL)
+ {
+ printf ("cannot open dblloadmod1.so: %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ p2 = dlopen ("dblloadmod2.so", RTLD_LAZY);
+ if (p1 == NULL)
+ {
+ printf ("cannot open dblloadmod2.so: %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ fp = dlsym (p1, "foo");
+ if (fp == NULL)
+ {
+ printf ("cannot get function \"foo\": %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ result = fp ();
+
+ if (dlclose (p1) != 0)
+ {
+ printf ("error while closing dblloadmod1.so: %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ if (dlclose (p2) != 0)
+ {
+ printf ("error while closing dblloadmod2.so: %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ return result;
+}
diff --git a/REORG.TODO/elf/dblloadmod1.c b/REORG.TODO/elf/dblloadmod1.c
new file mode 100644
index 0000000000..ecec29ec63
--- /dev/null
+++ b/REORG.TODO/elf/dblloadmod1.c
@@ -0,0 +1,8 @@
+extern int bar (void);
+extern int foo (void);
+
+int
+foo (void)
+{
+ return 10 + bar ();
+}
diff --git a/REORG.TODO/elf/dblloadmod2.c b/REORG.TODO/elf/dblloadmod2.c
new file mode 100644
index 0000000000..3e20aa941b
--- /dev/null
+++ b/REORG.TODO/elf/dblloadmod2.c
@@ -0,0 +1,15 @@
+extern int bar (void);
+extern int baz (void);
+extern int xyzzy (void);
+
+int
+baz (void)
+{
+ return -42;
+}
+
+int
+xyzzy (void)
+{
+ return 10 + bar ();
+}
diff --git a/REORG.TODO/elf/dblloadmod3.c b/REORG.TODO/elf/dblloadmod3.c
new file mode 100644
index 0000000000..80ac3a6375
--- /dev/null
+++ b/REORG.TODO/elf/dblloadmod3.c
@@ -0,0 +1,8 @@
+extern int bar (void);
+extern int baz (void);
+
+int
+bar (void)
+{
+ return 32 + baz ();
+}
diff --git a/REORG.TODO/elf/dblunload.c b/REORG.TODO/elf/dblunload.c
new file mode 100644
index 0000000000..ab0b2a5e9e
--- /dev/null
+++ b/REORG.TODO/elf/dblunload.c
@@ -0,0 +1,53 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int
+main (void)
+{
+ void *p1;
+ void *p2;
+ int (*fp) (void);
+ int result;
+
+ mtrace ();
+
+ p1 = dlopen ("dblloadmod1.so", RTLD_LAZY);
+ if (p1 == NULL)
+ {
+ printf ("cannot load dblloadmod1.so: %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ p2 = dlopen ("dblloadmod2.so", RTLD_LAZY);
+ if (p2 == NULL)
+ {
+ printf ("cannot load dblloadmod2.so: %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ if (dlclose (p1) != 0)
+ {
+ printf ("error while closing dblloadmod1.so: %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ fp = dlsym (p2, "xyzzy");
+ if (fp == NULL)
+ {
+ printf ("cannot get function \"xyzzy\": %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ result = fp ();
+
+ if (dlclose (p2) != 0)
+ {
+ printf ("error while closing dblloadmod2.so: %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ return result;
+}
diff --git a/REORG.TODO/elf/dep1.c b/REORG.TODO/elf/dep1.c
new file mode 100644
index 0000000000..7ef47adb43
--- /dev/null
+++ b/REORG.TODO/elf/dep1.c
@@ -0,0 +1,25 @@
+#include <unistd.h>
+
+extern int dep1 (void);
+extern int dep2 (void);
+extern int dep4 (void);
+
+static void
+__attribute__ ((constructor))
+init (void)
+{
+ write (1, "3", 1);
+}
+
+static void
+__attribute__ ((destructor))
+fini (void)
+{
+ write (1, "6", 1);
+}
+
+int
+dep1 (void)
+{
+ return dep4 () - dep2 ();
+}
diff --git a/REORG.TODO/elf/dep2.c b/REORG.TODO/elf/dep2.c
new file mode 100644
index 0000000000..749036a4ec
--- /dev/null
+++ b/REORG.TODO/elf/dep2.c
@@ -0,0 +1,25 @@
+#include <unistd.h>
+
+extern int dep2 (void);
+extern int dep3 (void);
+extern int dep4 (void);
+
+static void
+__attribute__ ((constructor))
+init (void)
+{
+ write (1, "2", 1);
+}
+
+static void
+__attribute__ ((destructor))
+fini (void)
+{
+ write (1, "7", 1);
+}
+
+int
+dep2 (void)
+{
+ return dep3 () - dep4 ();
+}
diff --git a/REORG.TODO/elf/dep3.c b/REORG.TODO/elf/dep3.c
new file mode 100644
index 0000000000..3df6282009
--- /dev/null
+++ b/REORG.TODO/elf/dep3.c
@@ -0,0 +1,23 @@
+#include <unistd.h>
+
+extern int dep3 (void);
+
+static void
+__attribute__ ((constructor))
+init (void)
+{
+ write (1, "0", 1);
+}
+
+static void
+__attribute__ ((destructor))
+fini (void)
+{
+ write (1, "9\n", 2);
+}
+
+int
+dep3 (void)
+{
+ return 42;
+}
diff --git a/REORG.TODO/elf/dep4.c b/REORG.TODO/elf/dep4.c
new file mode 100644
index 0000000000..c496d6f531
--- /dev/null
+++ b/REORG.TODO/elf/dep4.c
@@ -0,0 +1,24 @@
+#include <unistd.h>
+
+extern int dep3 (void);
+extern int dep4 (void);
+
+static void
+__attribute__ ((constructor))
+init (void)
+{
+ write (1, "1", 1);
+}
+
+static void
+__attribute__ ((destructor))
+fini (void)
+{
+ write (1, "8", 1);
+}
+
+int
+dep4 (void)
+{
+ return dep3 ();
+}
diff --git a/REORG.TODO/elf/dl-addr-obj.c b/REORG.TODO/elf/dl-addr-obj.c
new file mode 100644
index 0000000000..62aa630ce5
--- /dev/null
+++ b/REORG.TODO/elf/dl-addr-obj.c
@@ -0,0 +1,75 @@
+/* Determine if address is inside object load segments.
+ Copyright (C) 1996-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <link.h>
+#include <elf.h>
+
+/* Return non-zero if ADDR lies within one of L's loadable segments.
+ We have three cases we care about.
+
+ Case 1: addr is above a segment.
+ +==================+<- l_map_end
+ | |<- addr
+ |------------------|<- l_addr + p_vaddr + p_memsz
+ | |
+ | |
+ |------------------|<- l_addr + p_vaddr
+ |------------------|<- l_addr
+ | |
+ +==================+<- l_map_start
+
+ Case 2: addr is within a segments.
+ +==================+<- l_map_end
+ | |
+ |------------------|<- l_addr + p_vaddr + p_memsz
+ | |<- addr
+ | |
+ |------------------|<- l_addr + p_vaddr
+ |------------------|<- l_addr
+ | |
+ +==================+<- l_map_start
+
+ Case 3: addr is below a segments.
+ +==================+<- l_map_end
+ | |
+ |------------------|<- l_addr + p_vaddr + p_memsz
+ | |
+ | |
+ |------------------|<- l_addr + p_vaddr
+ |------------------|<- l_addr
+ | |<- addr
+ +==================+<- l_map_start
+
+ All the arithmetic is unsigned and we shift all the values down by
+ l_addr + p_vaddr and then compare the normalized addr to the range
+ of interest i.e. 0 <= addr < p_memsz.
+
+*/
+int
+internal_function
+_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
+{
+ int n = l->l_phnum;
+ const ElfW(Addr) reladdr = addr - l->l_addr;
+
+ while (--n >= 0)
+ if (l->l_phdr[n].p_type == PT_LOAD
+ && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
+ return 1;
+ return 0;
+}
diff --git a/REORG.TODO/elf/dl-addr.c b/REORG.TODO/elf/dl-addr.c
new file mode 100644
index 0000000000..1fac63d1a9
--- /dev/null
+++ b/REORG.TODO/elf/dl-addr.c
@@ -0,0 +1,146 @@
+/* Locate the shared object symbol nearest a given address.
+ Copyright (C) 1996-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <ldsodefs.h>
+
+
+static inline void
+__attribute ((always_inline))
+determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
+ struct link_map **mapp, const ElfW(Sym) **symbolp)
+{
+ /* Now we know what object the address lies in. */
+ info->dli_fname = match->l_name;
+ info->dli_fbase = (void *) match->l_map_start;
+
+ /* If this is the main program the information is incomplete. */
+ if (__builtin_expect (match->l_name[0], 'a') == '\0'
+ && match->l_type == lt_executable)
+ info->dli_fname = _dl_argv[0];
+
+ const ElfW(Sym) *symtab
+ = (const ElfW(Sym) *) D_PTR (match, l_info[DT_SYMTAB]);
+ const char *strtab = (const char *) D_PTR (match, l_info[DT_STRTAB]);
+
+ ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val;
+
+ const ElfW(Sym) *matchsym = NULL;
+ if (match->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
+ + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] != NULL)
+ {
+ /* We look at all symbol table entries referenced by the hash
+ table. */
+ for (Elf_Symndx bucket = 0; bucket < match->l_nbuckets; ++bucket)
+ {
+ Elf32_Word symndx = match->l_gnu_buckets[bucket];
+ if (symndx != 0)
+ {
+ const Elf32_Word *hasharr = &match->l_gnu_chain_zero[symndx];
+
+ do
+ {
+ /* The hash table never references local symbols so
+ we can omit that test here. */
+ if ((symtab[symndx].st_shndx != SHN_UNDEF
+ || symtab[symndx].st_value != 0)
+ && ELFW(ST_TYPE) (symtab[symndx].st_info) != STT_TLS
+ && DL_ADDR_SYM_MATCH (match, &symtab[symndx],
+ matchsym, addr)
+ && symtab[symndx].st_name < strtabsize)
+ matchsym = (ElfW(Sym) *) &symtab[symndx];
+
+ ++symndx;
+ }
+ while ((*hasharr++ & 1u) == 0);
+ }
+ }
+ }
+ else
+ {
+ const ElfW(Sym) *symtabend;
+ if (match->l_info[DT_HASH] != NULL)
+ symtabend = (symtab
+ + ((Elf_Symndx *) D_PTR (match, l_info[DT_HASH]))[1]);
+ else
+ /* There is no direct way to determine the number of symbols in the
+ dynamic symbol table and no hash table is present. The ELF
+ binary is ill-formed but what shall we do? Use the beginning of
+ the string table which generally follows the symbol table. */
+ symtabend = (const ElfW(Sym) *) strtab;
+
+ for (; (void *) symtab < (void *) symtabend; ++symtab)
+ if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
+ || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)
+ && __glibc_likely (!dl_symbol_visibility_binds_local_p (symtab))
+ && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS
+ && (symtab->st_shndx != SHN_UNDEF
+ || symtab->st_value != 0)
+ && DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr)
+ && symtab->st_name < strtabsize)
+ matchsym = (ElfW(Sym) *) symtab;
+ }
+
+ if (mapp)
+ *mapp = match;
+ if (symbolp)
+ *symbolp = matchsym;
+
+ if (matchsym)
+ {
+ /* We found a symbol close by. Fill in its name and exact
+ address. */
+ lookup_t matchl = LOOKUP_VALUE (match);
+
+ info->dli_sname = strtab + matchsym->st_name;
+ info->dli_saddr = DL_SYMBOL_ADDRESS (matchl, matchsym);
+ }
+ else
+ {
+ /* No symbol matches. We return only the containing object. */
+ info->dli_sname = NULL;
+ info->dli_saddr = NULL;
+ }
+}
+
+
+int
+internal_function
+_dl_addr (const void *address, Dl_info *info,
+ struct link_map **mapp, const ElfW(Sym) **symbolp)
+{
+ const ElfW(Addr) addr = DL_LOOKUP_ADDRESS (address);
+ int result = 0;
+
+ /* Protect against concurrent loads and unloads. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+ struct link_map *l = _dl_find_dso_for_object (addr);
+
+ if (l)
+ {
+ determine_info (addr, l, info, mapp, symbolp);
+ result = 1;
+ }
+
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+ return result;
+}
+libc_hidden_def (_dl_addr)
diff --git a/REORG.TODO/elf/dl-brk.c b/REORG.TODO/elf/dl-brk.c
new file mode 100644
index 0000000000..c37cdfec33
--- /dev/null
+++ b/REORG.TODO/elf/dl-brk.c
@@ -0,0 +1,5 @@
+/* We can use the normal code but we also know the __curbrk is not exported
+ from ld.so. */
+extern void *__curbrk attribute_hidden;
+
+#include <brk.c>
diff --git a/REORG.TODO/elf/dl-cache.c b/REORG.TODO/elf/dl-cache.c
new file mode 100644
index 0000000000..e9632da0b3
--- /dev/null
+++ b/REORG.TODO/elf/dl-cache.c
@@ -0,0 +1,325 @@
+/* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
+ Copyright (C) 1996-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <sys/mman.h>
+#include <dl-cache.h>
+#include <dl-procinfo.h>
+#include <stdint.h>
+#include <_itoa.h>
+#include <dl-hwcaps.h>
+
+#ifndef _DL_PLATFORMS_COUNT
+# define _DL_PLATFORMS_COUNT 0
+#endif
+
+/* This is the starting address and the size of the mmap()ed file. */
+static struct cache_file *cache;
+static struct cache_file_new *cache_new;
+static size_t cachesize;
+
+/* 1 if cache_data + PTR points into the cache. */
+#define _dl_cache_verify_ptr(ptr) (ptr < cache_data_size)
+
+#define SEARCH_CACHE(cache) \
+/* We use binary search since the table is sorted in the cache file. \
+ The first matching entry in the table is returned. \
+ It is important to use the same algorithm as used while generating \
+ the cache file. */ \
+do \
+ { \
+ left = 0; \
+ right = cache->nlibs - 1; \
+ \
+ while (left <= right) \
+ { \
+ __typeof__ (cache->libs[0].key) key; \
+ \
+ middle = (left + right) / 2; \
+ \
+ key = cache->libs[middle].key; \
+ \
+ /* Make sure string table indices are not bogus before using \
+ them. */ \
+ if (! _dl_cache_verify_ptr (key)) \
+ { \
+ cmpres = 1; \
+ break; \
+ } \
+ \
+ /* Actually compare the entry with the key. */ \
+ cmpres = _dl_cache_libcmp (name, cache_data + key); \
+ if (__glibc_unlikely (cmpres == 0)) \
+ { \
+ /* Found it. LEFT now marks the last entry for which we \
+ know the name is correct. */ \
+ left = middle; \
+ \
+ /* There might be entries with this name before the one we \
+ found. So we have to find the beginning. */ \
+ while (middle > 0) \
+ { \
+ __typeof__ (cache->libs[0].key) key; \
+ \
+ key = cache->libs[middle - 1].key; \
+ /* Make sure string table indices are not bogus before \
+ using them. */ \
+ if (! _dl_cache_verify_ptr (key) \
+ /* Actually compare the entry. */ \
+ || _dl_cache_libcmp (name, cache_data + key) != 0) \
+ break; \
+ --middle; \
+ } \
+ \
+ do \
+ { \
+ int flags; \
+ __typeof__ (cache->libs[0]) *lib = &cache->libs[middle]; \
+ \
+ /* Only perform the name test if necessary. */ \
+ if (middle > left \
+ /* We haven't seen this string so far. Test whether the \
+ index is ok and whether the name matches. Otherwise \
+ we are done. */ \
+ && (! _dl_cache_verify_ptr (lib->key) \
+ || (_dl_cache_libcmp (name, cache_data + lib->key) \
+ != 0))) \
+ break; \
+ \
+ flags = lib->flags; \
+ if (_dl_cache_check_flags (flags) \
+ && _dl_cache_verify_ptr (lib->value)) \
+ { \
+ if (best == NULL || flags == GLRO(dl_correct_cache_id)) \
+ { \
+ HWCAP_CHECK; \
+ best = cache_data + lib->value; \
+ \
+ if (flags == GLRO(dl_correct_cache_id)) \
+ /* We've found an exact match for the shared \
+ object and no general `ELF' release. Stop \
+ searching. */ \
+ break; \
+ } \
+ } \
+ } \
+ while (++middle <= right); \
+ break; \
+ } \
+ \
+ if (cmpres < 0) \
+ left = middle + 1; \
+ else \
+ right = middle - 1; \
+ } \
+ } \
+while (0)
+
+
+int
+internal_function
+_dl_cache_libcmp (const char *p1, const char *p2)
+{
+ while (*p1 != '\0')
+ {
+ if (*p1 >= '0' && *p1 <= '9')
+ {
+ if (*p2 >= '0' && *p2 <= '9')
+ {
+ /* Must compare this numerically. */
+ int val1;
+ int val2;
+
+ val1 = *p1++ - '0';
+ val2 = *p2++ - '0';
+ while (*p1 >= '0' && *p1 <= '9')
+ val1 = val1 * 10 + *p1++ - '0';
+ while (*p2 >= '0' && *p2 <= '9')
+ val2 = val2 * 10 + *p2++ - '0';
+ if (val1 != val2)
+ return val1 - val2;
+ }
+ else
+ return 1;
+ }
+ else if (*p2 >= '0' && *p2 <= '9')
+ return -1;
+ else if (*p1 != *p2)
+ return *p1 - *p2;
+ else
+ {
+ ++p1;
+ ++p2;
+ }
+ }
+ return *p1 - *p2;
+}
+
+
+/* Look up NAME in ld.so.cache and return the file name stored there, or null
+ if none is found. The cache is loaded if it was not already. If loading
+ the cache previously failed there will be no more attempts to load it.
+ The caller is responsible for freeing the returned string. The ld.so.cache
+ may be unmapped at any time by a completing recursive dlopen and
+ this function must take care that it does not return references to
+ any data in the mapping. */
+char *
+internal_function
+_dl_load_cache_lookup (const char *name)
+{
+ int left, right, middle;
+ int cmpres;
+ const char *cache_data;
+ uint32_t cache_data_size;
+ const char *best;
+
+ /* Print a message if the loading of libs is traced. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
+ _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
+
+ if (cache == NULL)
+ {
+ /* Read the contents of the file. */
+ void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
+ PROT_READ);
+
+ /* We can handle three different cache file formats here:
+ - the old libc5/glibc2.0/2.1 format
+ - the old format with the new format in it
+ - only the new format
+ The following checks if the cache contains any of these formats. */
+ if (file != MAP_FAILED && cachesize > sizeof *cache
+ && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0)
+ {
+ size_t offset;
+ /* Looks ok. */
+ cache = file;
+
+ /* Check for new version. */
+ offset = ALIGN_CACHE (sizeof (struct cache_file)
+ + cache->nlibs * sizeof (struct file_entry));
+
+ cache_new = (struct cache_file_new *) ((void *) cache + offset);
+ if (cachesize < (offset + sizeof (struct cache_file_new))
+ || memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW,
+ sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
+ cache_new = (void *) -1;
+ }
+ else if (file != MAP_FAILED && cachesize > sizeof *cache_new
+ && memcmp (file, CACHEMAGIC_VERSION_NEW,
+ sizeof CACHEMAGIC_VERSION_NEW - 1) == 0)
+ {
+ cache_new = file;
+ cache = file;
+ }
+ else
+ {
+ if (file != MAP_FAILED)
+ __munmap (file, cachesize);
+ cache = (void *) -1;
+ }
+
+ assert (cache != NULL);
+ }
+
+ if (cache == (void *) -1)
+ /* Previously looked for the cache file and didn't find it. */
+ return NULL;
+
+ best = NULL;
+
+ if (cache_new != (void *) -1)
+ {
+ uint64_t platform;
+
+ /* This is where the strings start. */
+ cache_data = (const char *) cache_new;
+
+ /* Now we can compute how large the string table is. */
+ cache_data_size = (const char *) cache + cachesize - cache_data;
+
+ platform = _dl_string_platform (GLRO(dl_platform));
+ if (platform != (uint64_t) -1)
+ platform = 1ULL << platform;
+
+ uint64_t hwcap_mask = GET_HWCAP_MASK();
+
+#define _DL_HWCAP_TLS_MASK (1LL << 63)
+ uint64_t hwcap_exclude = ~((GLRO(dl_hwcap) & hwcap_mask)
+ | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK);
+
+ /* Only accept hwcap if it's for the right platform. */
+#define HWCAP_CHECK \
+ if (lib->hwcap & hwcap_exclude) \
+ continue; \
+ if (GLRO(dl_osversion) && lib->osversion > GLRO(dl_osversion)) \
+ continue; \
+ if (_DL_PLATFORMS_COUNT \
+ && (lib->hwcap & _DL_HWCAP_PLATFORM) != 0 \
+ && (lib->hwcap & _DL_HWCAP_PLATFORM) != platform) \
+ continue
+ SEARCH_CACHE (cache_new);
+ }
+ else
+ {
+ /* This is where the strings start. */
+ cache_data = (const char *) &cache->libs[cache->nlibs];
+
+ /* Now we can compute how large the string table is. */
+ cache_data_size = (const char *) cache + cachesize - cache_data;
+
+#undef HWCAP_CHECK
+#define HWCAP_CHECK do {} while (0)
+ SEARCH_CACHE (cache);
+ }
+
+ /* Print our result if wanted. */
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0)
+ && best != NULL)
+ _dl_debug_printf (" trying file=%s\n", best);
+
+ if (best == NULL)
+ return NULL;
+
+ /* The double copy is *required* since malloc may be interposed
+ and call dlopen itself whose completion would unmap the data
+ we are accessing. Therefore we must make the copy of the
+ mapping data without using malloc. */
+ char *temp;
+ temp = alloca (strlen (best) + 1);
+ strcpy (temp, best);
+ return __strdup (temp);
+}
+
+#ifndef MAP_COPY
+/* If the system does not support MAP_COPY we cannot leave the file open
+ all the time since this would create problems when the file is replaced.
+ Therefore we provide this function to close the file and open it again
+ once needed. */
+void
+_dl_unload_cache (void)
+{
+ if (cache != NULL && cache != (struct cache_file *) -1)
+ {
+ __munmap (cache, cachesize);
+ cache = NULL;
+ }
+}
+#endif
diff --git a/REORG.TODO/elf/dl-caller.c b/REORG.TODO/elf/dl-caller.c
new file mode 100644
index 0000000000..b4c5335baa
--- /dev/null
+++ b/REORG.TODO/elf/dl-caller.c
@@ -0,0 +1,86 @@
+/* Check whether caller comes from the right place.
+ Copyright (C) 2004-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <ldsodefs.h>
+#include <stddef.h>
+#include <caller.h>
+#include <gnu/lib-names.h>
+
+
+int
+attribute_hidden
+_dl_check_caller (const void *caller, enum allowmask mask)
+{
+ static const char expected1[] = LIBC_SO;
+ static const char expected2[] = LIBDL_SO;
+#ifdef LIBPTHREAD_SO
+ static const char expected3[] = LIBPTHREAD_SO;
+#endif
+ static const char expected4[] = LD_SO;
+
+ for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
+ for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
+ l = l->l_next)
+ if (caller >= (const void *) l->l_map_start
+ && caller < (const void *) l->l_text_end)
+ {
+ /* The address falls into this DSO's address range. Check the
+ name. */
+ if ((mask & allow_libc) && strcmp (expected1, l->l_name) == 0)
+ return 0;
+ if ((mask & allow_libdl) && strcmp (expected2, l->l_name) == 0)
+ return 0;
+#ifdef LIBPTHREAD_SO
+ if ((mask & allow_libpthread) && strcmp (expected3, l->l_name) == 0)
+ return 0;
+#endif
+ if ((mask & allow_ldso) && strcmp (expected4, l->l_name) == 0)
+ return 0;
+
+ struct libname_list *runp = l->l_libname;
+
+ while (runp != NULL)
+ {
+ if ((mask & allow_libc) && strcmp (expected1, runp->name) == 0)
+ return 0;
+ if ((mask & allow_libdl) && strcmp (expected2, runp->name) == 0)
+ return 0;
+#ifdef LIBPTHREAD_SO
+ if ((mask & allow_libpthread)
+ && strcmp (expected3, runp->name) == 0)
+ return 0;
+#endif
+ if ((mask & allow_ldso) && strcmp (expected4, runp->name) == 0)
+ return 0;
+
+ runp = runp->next;
+ }
+
+ break;
+ }
+
+ /* Maybe the dynamic linker is not yet on the list. */
+ if ((mask & allow_ldso) != 0
+ && caller >= (const void *) GL(dl_rtld_map).l_map_start
+ && caller < (const void *) GL(dl_rtld_map).l_text_end)
+ return 0;
+
+ /* No valid caller. */
+ return 1;
+}
diff --git a/REORG.TODO/elf/dl-close.c b/REORG.TODO/elf/dl-close.c
new file mode 100644
index 0000000000..2b46b7cf8b
--- /dev/null
+++ b/REORG.TODO/elf/dl-close.c
@@ -0,0 +1,843 @@
+/* Close a shared object opened by `_dl_open'.
+ Copyright (C) 1996-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libc-lock.h>
+#include <ldsodefs.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sysdep-cancel.h>
+#include <tls.h>
+#include <stap-probe.h>
+
+#include <dl-unmap-segments.h>
+
+
+/* Type of the constructor functions. */
+typedef void (*fini_t) (void);
+
+
+/* Special l_idx value used to indicate which objects remain loaded. */
+#define IDX_STILL_USED -1
+
+
+/* Returns true we an non-empty was found. */
+static bool
+remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
+ bool should_be_there)
+{
+ if (idx - disp >= listp->len)
+ {
+ if (listp->next == NULL)
+ {
+ /* The index is not actually valid in the slotinfo list,
+ because this object was closed before it was fully set
+ up due to some error. */
+ assert (! should_be_there);
+ }
+ else
+ {
+ if (remove_slotinfo (idx, listp->next, disp + listp->len,
+ should_be_there))
+ return true;
+
+ /* No non-empty entry. Search from the end of this element's
+ slotinfo array. */
+ idx = disp + listp->len;
+ }
+ }
+ else
+ {
+ struct link_map *old_map = listp->slotinfo[idx - disp].map;
+
+ /* The entry might still be in its unused state if we are closing an
+ object that wasn't fully set up. */
+ if (__glibc_likely (old_map != NULL))
+ {
+ assert (old_map->l_tls_modid == idx);
+
+ /* Mark the entry as unused. */
+ listp->slotinfo[idx - disp].gen = GL(dl_tls_generation) + 1;
+ listp->slotinfo[idx - disp].map = NULL;
+ }
+
+ /* If this is not the last currently used entry no need to look
+ further. */
+ if (idx != GL(dl_tls_max_dtv_idx))
+ return true;
+ }
+
+ while (idx - disp > (disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0))
+ {
+ --idx;
+
+ if (listp->slotinfo[idx - disp].map != NULL)
+ {
+ /* Found a new last used index. */
+ GL(dl_tls_max_dtv_idx) = idx;
+ return true;
+ }
+ }
+
+ /* No non-entry in this list element. */
+ return false;
+}
+
+
+void
+_dl_close_worker (struct link_map *map, bool force)
+{
+ /* One less direct use. */
+ --map->l_direct_opencount;
+
+ /* If _dl_close is called recursively (some destructor call dlclose),
+ just record that the parent _dl_close will need to do garbage collection
+ again and return. */
+ static enum { not_pending, pending, rerun } dl_close_state;
+
+ if (map->l_direct_opencount > 0 || map->l_type != lt_loaded
+ || dl_close_state != not_pending)
+ {
+ if (map->l_direct_opencount == 0 && map->l_type == lt_loaded)
+ dl_close_state = rerun;
+
+ /* There are still references to this object. Do nothing more. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("\nclosing file=%s; direct_opencount=%u\n",
+ map->l_name, map->l_direct_opencount);
+
+ return;
+ }
+
+ Lmid_t nsid = map->l_ns;
+ struct link_namespaces *ns = &GL(dl_ns)[nsid];
+
+ retry:
+ dl_close_state = pending;
+
+ bool any_tls = false;
+ const unsigned int nloaded = ns->_ns_nloaded;
+ char used[nloaded];
+ char done[nloaded];
+ struct link_map *maps[nloaded];
+
+ /* Clear DF_1_NODELETE to force object deletion. We don't need to touch
+ l_tls_dtor_count because forced object deletion only happens when an
+ error occurs during object load. Destructor registration for TLS
+ non-POD objects should not have happened till then for this
+ object. */
+ if (force)
+ map->l_flags_1 &= ~DF_1_NODELETE;
+
+ /* Run over the list and assign indexes to the link maps and enter
+ them into the MAPS array. */
+ int idx = 0;
+ for (struct link_map *l = ns->_ns_loaded; l != NULL; l = l->l_next)
+ {
+ l->l_idx = idx;
+ maps[idx] = l;
+ ++idx;
+
+ }
+ assert (idx == nloaded);
+
+ /* Prepare the bitmaps. */
+ memset (used, '\0', sizeof (used));
+ memset (done, '\0', sizeof (done));
+
+ /* Keep track of the lowest index link map we have covered already. */
+ int done_index = -1;
+ while (++done_index < nloaded)
+ {
+ struct link_map *l = maps[done_index];
+
+ if (done[done_index])
+ /* Already handled. */
+ continue;
+
+ /* Check whether this object is still used. */
+ if (l->l_type == lt_loaded
+ && l->l_direct_opencount == 0
+ && (l->l_flags_1 & DF_1_NODELETE) == 0
+ /* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why
+ acquire is sufficient and correct. */
+ && atomic_load_acquire (&l->l_tls_dtor_count) == 0
+ && !used[done_index])
+ continue;
+
+ /* We need this object and we handle it now. */
+ done[done_index] = 1;
+ used[done_index] = 1;
+ /* Signal the object is still needed. */
+ l->l_idx = IDX_STILL_USED;
+
+ /* Mark all dependencies as used. */
+ if (l->l_initfini != NULL)
+ {
+ /* We are always the zeroth entry, and since we don't include
+ ourselves in the dependency analysis start at 1. */
+ struct link_map **lp = &l->l_initfini[1];
+ while (*lp != NULL)
+ {
+ if ((*lp)->l_idx != IDX_STILL_USED)
+ {
+ assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded);
+
+ if (!used[(*lp)->l_idx])
+ {
+ used[(*lp)->l_idx] = 1;
+ /* If we marked a new object as used, and we've
+ already processed it, then we need to go back
+ and process again from that point forward to
+ ensure we keep all of its dependencies also. */
+ if ((*lp)->l_idx - 1 < done_index)
+ done_index = (*lp)->l_idx - 1;
+ }
+ }
+
+ ++lp;
+ }
+ }
+ /* And the same for relocation dependencies. */
+ if (l->l_reldeps != NULL)
+ for (unsigned int j = 0; j < l->l_reldeps->act; ++j)
+ {
+ struct link_map *jmap = l->l_reldeps->list[j];
+
+ if (jmap->l_idx != IDX_STILL_USED)
+ {
+ assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded);
+
+ if (!used[jmap->l_idx])
+ {
+ used[jmap->l_idx] = 1;
+ if (jmap->l_idx - 1 < done_index)
+ done_index = jmap->l_idx - 1;
+ }
+ }
+ }
+ }
+
+ /* Sort the entries. */
+ _dl_sort_fini (maps, nloaded, used, nsid);
+
+ /* Call all termination functions at once. */
+#ifdef SHARED
+ bool do_audit = GLRO(dl_naudit) > 0 && !ns->_ns_loaded->l_auditing;
+#endif
+ bool unload_any = false;
+ bool scope_mem_left = false;
+ unsigned int unload_global = 0;
+ unsigned int first_loaded = ~0;
+ for (unsigned int i = 0; i < nloaded; ++i)
+ {
+ struct link_map *imap = maps[i];
+
+ /* All elements must be in the same namespace. */
+ assert (imap->l_ns == nsid);
+
+ if (!used[i])
+ {
+ assert (imap->l_type == lt_loaded
+ && (imap->l_flags_1 & DF_1_NODELETE) == 0);
+
+ /* Call its termination function. Do not do it for
+ half-cooked objects. */
+ if (imap->l_init_called)
+ {
+ /* When debugging print a message first. */
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
+ 0))
+ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
+ imap->l_name, nsid);
+
+ if (imap->l_info[DT_FINI_ARRAY] != NULL)
+ {
+ ElfW(Addr) *array =
+ (ElfW(Addr) *) (imap->l_addr
+ + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
+ unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
+ / sizeof (ElfW(Addr)));
+
+ while (sz-- > 0)
+ ((fini_t) array[sz]) ();
+ }
+
+ /* Next try the old-style destructor. */
+ if (imap->l_info[DT_FINI] != NULL)
+ DL_CALL_DT_FINI (imap, ((void *) imap->l_addr
+ + imap->l_info[DT_FINI]->d_un.d_ptr));
+ }
+
+#ifdef SHARED
+ /* Auditing checkpoint: we remove an object. */
+ if (__glibc_unlikely (do_audit))
+ {
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->objclose != NULL)
+ /* Return value is ignored. */
+ (void) afct->objclose (&imap->l_audit[cnt].cookie);
+
+ afct = afct->next;
+ }
+ }
+#endif
+
+ /* This object must not be used anymore. */
+ imap->l_removed = 1;
+
+ /* We indeed have an object to remove. */
+ unload_any = true;
+
+ if (imap->l_global)
+ ++unload_global;
+
+ /* Remember where the first dynamically loaded object is. */
+ if (i < first_loaded)
+ first_loaded = i;
+ }
+ /* Else used[i]. */
+ else if (imap->l_type == lt_loaded)
+ {
+ struct r_scope_elem *new_list = NULL;
+
+ if (imap->l_searchlist.r_list == NULL && imap->l_initfini != NULL)
+ {
+ /* The object is still used. But one of the objects we are
+ unloading right now is responsible for loading it. If
+ the current object does not have it's own scope yet we
+ have to create one. This has to be done before running
+ the finalizers.
+
+ To do this count the number of dependencies. */
+ unsigned int cnt;
+ for (cnt = 1; imap->l_initfini[cnt] != NULL; ++cnt)
+ ;
+
+ /* We simply reuse the l_initfini list. */
+ imap->l_searchlist.r_list = &imap->l_initfini[cnt + 1];
+ imap->l_searchlist.r_nlist = cnt;
+
+ new_list = &imap->l_searchlist;
+ }
+
+ /* Count the number of scopes which remain after the unload.
+ When we add the local search list count it. Always add
+ one for the terminating NULL pointer. */
+ size_t remain = (new_list != NULL) + 1;
+ bool removed_any = false;
+ for (size_t cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
+ /* This relies on l_scope[] entries being always set either
+ to its own l_symbolic_searchlist address, or some map's
+ l_searchlist address. */
+ if (imap->l_scope[cnt] != &imap->l_symbolic_searchlist)
+ {
+ struct link_map *tmap = (struct link_map *)
+ ((char *) imap->l_scope[cnt]
+ - offsetof (struct link_map, l_searchlist));
+ assert (tmap->l_ns == nsid);
+ if (tmap->l_idx == IDX_STILL_USED)
+ ++remain;
+ else
+ removed_any = true;
+ }
+ else
+ ++remain;
+
+ if (removed_any)
+ {
+ /* Always allocate a new array for the scope. This is
+ necessary since we must be able to determine the last
+ user of the current array. If possible use the link map's
+ memory. */
+ size_t new_size;
+ struct r_scope_elem **newp;
+
+#define SCOPE_ELEMS(imap) \
+ (sizeof (imap->l_scope_mem) / sizeof (imap->l_scope_mem[0]))
+
+ if (imap->l_scope != imap->l_scope_mem
+ && remain < SCOPE_ELEMS (imap))
+ {
+ new_size = SCOPE_ELEMS (imap);
+ newp = imap->l_scope_mem;
+ }
+ else
+ {
+ new_size = imap->l_scope_max;
+ newp = (struct r_scope_elem **)
+ malloc (new_size * sizeof (struct r_scope_elem *));
+ if (newp == NULL)
+ _dl_signal_error (ENOMEM, "dlclose", NULL,
+ N_("cannot create scope list"));
+ }
+
+ /* Copy over the remaining scope elements. */
+ remain = 0;
+ for (size_t cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
+ {
+ if (imap->l_scope[cnt] != &imap->l_symbolic_searchlist)
+ {
+ struct link_map *tmap = (struct link_map *)
+ ((char *) imap->l_scope[cnt]
+ - offsetof (struct link_map, l_searchlist));
+ if (tmap->l_idx != IDX_STILL_USED)
+ {
+ /* Remove the scope. Or replace with own map's
+ scope. */
+ if (new_list != NULL)
+ {
+ newp[remain++] = new_list;
+ new_list = NULL;
+ }
+ continue;
+ }
+ }
+
+ newp[remain++] = imap->l_scope[cnt];
+ }
+ newp[remain] = NULL;
+
+ struct r_scope_elem **old = imap->l_scope;
+
+ imap->l_scope = newp;
+
+ /* No user anymore, we can free it now. */
+ if (old != imap->l_scope_mem)
+ {
+ if (_dl_scope_free (old))
+ /* If _dl_scope_free used THREAD_GSCOPE_WAIT (),
+ no need to repeat it. */
+ scope_mem_left = false;
+ }
+ else
+ scope_mem_left = true;
+
+ imap->l_scope_max = new_size;
+ }
+ else if (new_list != NULL)
+ {
+ /* We didn't change the scope array, so reset the search
+ list. */
+ imap->l_searchlist.r_list = NULL;
+ imap->l_searchlist.r_nlist = 0;
+ }
+
+ /* The loader is gone, so mark the object as not having one.
+ Note: l_idx != IDX_STILL_USED -> object will be removed. */
+ if (imap->l_loader != NULL
+ && imap->l_loader->l_idx != IDX_STILL_USED)
+ imap->l_loader = NULL;
+
+ /* Remember where the first dynamically loaded object is. */
+ if (i < first_loaded)
+ first_loaded = i;
+ }
+ }
+
+ /* If there are no objects to unload, do nothing further. */
+ if (!unload_any)
+ goto out;
+
+#ifdef SHARED
+ /* Auditing checkpoint: we will start deleting objects. */
+ if (__glibc_unlikely (do_audit))
+ {
+ struct link_map *head = ns->_ns_loaded;
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ /* Do not call the functions for any auditing object. */
+ if (head->l_auditing == 0)
+ {
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->activity != NULL)
+ afct->activity (&head->l_audit[cnt].cookie, LA_ACT_DELETE);
+
+ afct = afct->next;
+ }
+ }
+ }
+#endif
+
+ /* Notify the debugger we are about to remove some loaded objects. */
+ struct r_debug *r = _dl_debug_initialize (0, nsid);
+ r->r_state = RT_DELETE;
+ _dl_debug_state ();
+ LIBC_PROBE (unmap_start, 2, nsid, r);
+
+ if (unload_global)
+ {
+ /* Some objects are in the global scope list. Remove them. */
+ struct r_scope_elem *ns_msl = ns->_ns_main_searchlist;
+ unsigned int i;
+ unsigned int j = 0;
+ unsigned int cnt = ns_msl->r_nlist;
+
+ while (cnt > 0 && ns_msl->r_list[cnt - 1]->l_removed)
+ --cnt;
+
+ if (cnt + unload_global == ns_msl->r_nlist)
+ /* Speed up removing most recently added objects. */
+ j = cnt;
+ else
+ for (i = 0; i < cnt; i++)
+ if (ns_msl->r_list[i]->l_removed == 0)
+ {
+ if (i != j)
+ ns_msl->r_list[j] = ns_msl->r_list[i];
+ j++;
+ }
+ ns_msl->r_nlist = j;
+ }
+
+ if (!RTLD_SINGLE_THREAD_P
+ && (unload_global
+ || scope_mem_left
+ || (GL(dl_scope_free_list) != NULL
+ && GL(dl_scope_free_list)->count)))
+ {
+ THREAD_GSCOPE_WAIT ();
+
+ /* Now we can free any queued old scopes. */
+ struct dl_scope_free_list *fsl = GL(dl_scope_free_list);
+ if (fsl != NULL)
+ while (fsl->count > 0)
+ free (fsl->list[--fsl->count]);
+ }
+
+ size_t tls_free_start;
+ size_t tls_free_end;
+ tls_free_start = tls_free_end = NO_TLS_OFFSET;
+
+ /* We modify the list of loaded objects. */
+ __rtld_lock_lock_recursive (GL(dl_load_write_lock));
+
+ /* Check each element of the search list to see if all references to
+ it are gone. */
+ for (unsigned int i = first_loaded; i < nloaded; ++i)
+ {
+ struct link_map *imap = maps[i];
+ if (!used[i])
+ {
+ assert (imap->l_type == lt_loaded);
+
+ /* That was the last reference, and this was a dlopen-loaded
+ object. We can unmap it. */
+
+ /* Remove the object from the dtv slotinfo array if it uses TLS. */
+ if (__glibc_unlikely (imap->l_tls_blocksize > 0))
+ {
+ any_tls = true;
+
+ if (GL(dl_tls_dtv_slotinfo_list) != NULL
+ && ! remove_slotinfo (imap->l_tls_modid,
+ GL(dl_tls_dtv_slotinfo_list), 0,
+ imap->l_init_called))
+ /* All dynamically loaded modules with TLS are unloaded. */
+ GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
+
+ if (imap->l_tls_offset != NO_TLS_OFFSET
+ && imap->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)
+ {
+ /* Collect a contiguous chunk built from the objects in
+ this search list, going in either direction. When the
+ whole chunk is at the end of the used area then we can
+ reclaim it. */
+#if TLS_TCB_AT_TP
+ if (tls_free_start == NO_TLS_OFFSET
+ || (size_t) imap->l_tls_offset == tls_free_start)
+ {
+ /* Extend the contiguous chunk being reclaimed. */
+ tls_free_start
+ = imap->l_tls_offset - imap->l_tls_blocksize;
+
+ if (tls_free_end == NO_TLS_OFFSET)
+ tls_free_end = imap->l_tls_offset;
+ }
+ else if (imap->l_tls_offset - imap->l_tls_blocksize
+ == tls_free_end)
+ /* Extend the chunk backwards. */
+ tls_free_end = imap->l_tls_offset;
+ else
+ {
+ /* This isn't contiguous with the last chunk freed.
+ One of them will be leaked unless we can free
+ one block right away. */
+ if (tls_free_end == GL(dl_tls_static_used))
+ {
+ GL(dl_tls_static_used) = tls_free_start;
+ tls_free_end = imap->l_tls_offset;
+ tls_free_start
+ = tls_free_end - imap->l_tls_blocksize;
+ }
+ else if ((size_t) imap->l_tls_offset
+ == GL(dl_tls_static_used))
+ GL(dl_tls_static_used)
+ = imap->l_tls_offset - imap->l_tls_blocksize;
+ else if (tls_free_end < (size_t) imap->l_tls_offset)
+ {
+ /* We pick the later block. It has a chance to
+ be freed. */
+ tls_free_end = imap->l_tls_offset;
+ tls_free_start
+ = tls_free_end - imap->l_tls_blocksize;
+ }
+ }
+#elif TLS_DTV_AT_TP
+ if (tls_free_start == NO_TLS_OFFSET)
+ {
+ tls_free_start = imap->l_tls_firstbyte_offset;
+ tls_free_end = (imap->l_tls_offset
+ + imap->l_tls_blocksize);
+ }
+ else if (imap->l_tls_firstbyte_offset == tls_free_end)
+ /* Extend the contiguous chunk being reclaimed. */
+ tls_free_end = imap->l_tls_offset + imap->l_tls_blocksize;
+ else if (imap->l_tls_offset + imap->l_tls_blocksize
+ == tls_free_start)
+ /* Extend the chunk backwards. */
+ tls_free_start = imap->l_tls_firstbyte_offset;
+ /* This isn't contiguous with the last chunk freed.
+ One of them will be leaked unless we can free
+ one block right away. */
+ else if (imap->l_tls_offset + imap->l_tls_blocksize
+ == GL(dl_tls_static_used))
+ GL(dl_tls_static_used) = imap->l_tls_firstbyte_offset;
+ else if (tls_free_end == GL(dl_tls_static_used))
+ {
+ GL(dl_tls_static_used) = tls_free_start;
+ tls_free_start = imap->l_tls_firstbyte_offset;
+ tls_free_end = imap->l_tls_offset + imap->l_tls_blocksize;
+ }
+ else if (tls_free_end < imap->l_tls_firstbyte_offset)
+ {
+ /* We pick the later block. It has a chance to
+ be freed. */
+ tls_free_start = imap->l_tls_firstbyte_offset;
+ tls_free_end = imap->l_tls_offset + imap->l_tls_blocksize;
+ }
+#else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+#endif
+ }
+ }
+
+ /* Reset unique symbols if forced. */
+ if (force)
+ {
+ struct unique_sym_table *tab = &ns->_ns_unique_sym_table;
+ __rtld_lock_lock_recursive (tab->lock);
+ struct unique_sym *entries = tab->entries;
+ if (entries != NULL)
+ {
+ size_t idx, size = tab->size;
+ for (idx = 0; idx < size; ++idx)
+ {
+ /* Clear unique symbol entries that belong to this
+ object. */
+ if (entries[idx].name != NULL
+ && entries[idx].map == imap)
+ {
+ entries[idx].name = NULL;
+ entries[idx].hashval = 0;
+ tab->n_elements--;
+ }
+ }
+ }
+ __rtld_lock_unlock_recursive (tab->lock);
+ }
+
+ /* We can unmap all the maps at once. We determined the
+ start address and length when we loaded the object and
+ the `munmap' call does the rest. */
+ DL_UNMAP (imap);
+
+ /* Finally, unlink the data structure and free it. */
+#if DL_NNS == 1
+ /* The assert in the (imap->l_prev == NULL) case gives
+ the compiler license to warn that NS points outside
+ the dl_ns array bounds in that case (as nsid != LM_ID_BASE
+ is tantamount to nsid >= DL_NNS). That should be impossible
+ in this configuration, so just assert about it instead. */
+ assert (nsid == LM_ID_BASE);
+ assert (imap->l_prev != NULL);
+#else
+ if (imap->l_prev == NULL)
+ {
+ assert (nsid != LM_ID_BASE);
+ ns->_ns_loaded = imap->l_next;
+
+ /* Update the pointer to the head of the list
+ we leave for debuggers to examine. */
+ r->r_map = (void *) ns->_ns_loaded;
+ }
+ else
+#endif
+ imap->l_prev->l_next = imap->l_next;
+
+ --ns->_ns_nloaded;
+ if (imap->l_next != NULL)
+ imap->l_next->l_prev = imap->l_prev;
+
+ free (imap->l_versions);
+ if (imap->l_origin != (char *) -1)
+ free ((char *) imap->l_origin);
+
+ free (imap->l_reldeps);
+
+ /* Print debugging message. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("\nfile=%s [%lu]; destroying link map\n",
+ imap->l_name, imap->l_ns);
+
+ /* This name always is allocated. */
+ free (imap->l_name);
+ /* Remove the list with all the names of the shared object. */
+
+ struct libname_list *lnp = imap->l_libname;
+ do
+ {
+ struct libname_list *this = lnp;
+ lnp = lnp->next;
+ if (!this->dont_free)
+ free (this);
+ }
+ while (lnp != NULL);
+
+ /* Remove the searchlists. */
+ free (imap->l_initfini);
+
+ /* Remove the scope array if we allocated it. */
+ if (imap->l_scope != imap->l_scope_mem)
+ free (imap->l_scope);
+
+ if (imap->l_phdr_allocated)
+ free ((void *) imap->l_phdr);
+
+ if (imap->l_rpath_dirs.dirs != (void *) -1)
+ free (imap->l_rpath_dirs.dirs);
+ if (imap->l_runpath_dirs.dirs != (void *) -1)
+ free (imap->l_runpath_dirs.dirs);
+
+ free (imap);
+ }
+ }
+
+ __rtld_lock_unlock_recursive (GL(dl_load_write_lock));
+
+ /* If we removed any object which uses TLS bump the generation counter. */
+ if (any_tls)
+ {
+ if (__glibc_unlikely (++GL(dl_tls_generation) == 0))
+ _dl_fatal_printf ("TLS generation counter wrapped! Please report as described in "REPORT_BUGS_TO".\n");
+
+ if (tls_free_end == GL(dl_tls_static_used))
+ GL(dl_tls_static_used) = tls_free_start;
+ }
+
+#ifdef SHARED
+ /* Auditing checkpoint: we have deleted all objects. */
+ if (__glibc_unlikely (do_audit))
+ {
+ struct link_map *head = ns->_ns_loaded;
+ /* Do not call the functions for any auditing object. */
+ if (head->l_auditing == 0)
+ {
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->activity != NULL)
+ afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
+
+ afct = afct->next;
+ }
+ }
+ }
+#endif
+
+ if (__builtin_expect (ns->_ns_loaded == NULL, 0)
+ && nsid == GL(dl_nns) - 1)
+ do
+ --GL(dl_nns);
+ while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL);
+
+ /* Notify the debugger those objects are finalized and gone. */
+ r->r_state = RT_CONSISTENT;
+ _dl_debug_state ();
+ LIBC_PROBE (unmap_complete, 2, nsid, r);
+
+ /* Recheck if we need to retry, release the lock. */
+ out:
+ if (dl_close_state == rerun)
+ goto retry;
+
+ dl_close_state = not_pending;
+}
+
+
+void
+_dl_close (void *_map)
+{
+ struct link_map *map = _map;
+
+ /* We must take the lock to examine the contents of map and avoid
+ concurrent dlopens. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+ /* At this point we are guaranteed nobody else is touching the list of
+ loaded maps, but a concurrent dlclose might have freed our map
+ before we took the lock. There is no way to detect this (see below)
+ so we proceed assuming this isn't the case. First see whether we
+ can remove the object at all. */
+ if (__glibc_unlikely (map->l_flags_1 & DF_1_NODELETE))
+ {
+ /* Nope. Do nothing. */
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ return;
+ }
+
+ /* At present this is an unreliable check except in the case where the
+ caller has recursively called dlclose and we are sure the link map
+ has not been freed. In a non-recursive dlclose the map itself
+ might have been freed and this access is potentially a data race
+ with whatever other use this memory might have now, or worse we
+ might silently corrupt memory if it looks enough like a link map.
+ POSIX has language in dlclose that appears to guarantee that this
+ should be a detectable case and given that dlclose should be threadsafe
+ we need this to be a reliable detection.
+ This is bug 20990. */
+ if (__builtin_expect (map->l_direct_opencount, 1) == 0)
+ {
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ _dl_signal_error (0, map->l_name, NULL, N_("shared object not open"));
+ }
+
+ _dl_close_worker (map, false);
+
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+}
diff --git a/REORG.TODO/elf/dl-conflict.c b/REORG.TODO/elf/dl-conflict.c
new file mode 100644
index 0000000000..3cbd07435e
--- /dev/null
+++ b/REORG.TODO/elf/dl-conflict.c
@@ -0,0 +1,74 @@
+/* Resolve conflicts against already prelinked libraries.
+ Copyright (C) 2001-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include "dynamic-link.h"
+
+void
+_dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict,
+ ElfW(Rela) *conflictend)
+{
+#if ! ELF_MACHINE_NO_RELA
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_RELOC))
+ _dl_debug_printf ("\nconflict processing: %s\n", DSO_FILENAME (l->l_name));
+
+ {
+ /* Do the conflict relocation of the object and library GOT and other
+ data. */
+
+ /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */
+#define RESOLVE_MAP(ref, version, flags) (*ref = NULL, NULL)
+#define RESOLVE(ref, version, flags) (*ref = NULL, 0)
+#define RESOLVE_CONFLICT_FIND_MAP(map, r_offset) \
+ do { \
+ while ((resolve_conflict_map->l_map_end < (ElfW(Addr)) (r_offset)) \
+ || (resolve_conflict_map->l_map_start > (ElfW(Addr)) (r_offset))) \
+ resolve_conflict_map = resolve_conflict_map->l_next; \
+ \
+ (map) = resolve_conflict_map; \
+ } while (0)
+
+ /* Prelinking makes no sense for anything but the main namespace. */
+ assert (l->l_ns == LM_ID_BASE);
+ struct link_map *resolve_conflict_map __attribute__ ((__unused__))
+ = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+
+#include "dynamic-link.h"
+
+ /* Override these, defined in dynamic-link.h. */
+#undef CHECK_STATIC_TLS
+#define CHECK_STATIC_TLS(ref_map, sym_map) ((void) 0)
+#undef TRY_STATIC_TLS
+#define TRY_STATIC_TLS(ref_map, sym_map) (0)
+
+ GL(dl_num_cache_relocations) += conflictend - conflict;
+
+ for (; conflict < conflictend; ++conflict)
+ elf_machine_rela (l, conflict, NULL, NULL, (void *) conflict->r_offset,
+ 0);
+ }
+#endif
+}
diff --git a/REORG.TODO/elf/dl-debug.c b/REORG.TODO/elf/dl-debug.c
new file mode 100644
index 0000000000..f3957044f6
--- /dev/null
+++ b/REORG.TODO/elf/dl-debug.c
@@ -0,0 +1,76 @@
+/* Communicate dynamic linker state to the debugger at runtime.
+ Copyright (C) 1996-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <ldsodefs.h>
+
+
+/* These are the members in the public `struct link_map' type.
+ Sanity check that the internal type and the public type match. */
+#define VERIFY_MEMBER(name) \
+ (offsetof (struct link_map_public, name) == offsetof (struct link_map, name))
+extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
+ && VERIFY_MEMBER (l_name)
+ && VERIFY_MEMBER (l_ld)
+ && VERIFY_MEMBER (l_next)
+ && VERIFY_MEMBER (l_prev))
+ ? 1 : -1];
+
+/* This structure communicates dl state to the debugger. The debugger
+ normally finds it via the DT_DEBUG entry in the dynamic section, but in
+ a statically-linked program there is no dynamic section for the debugger
+ to examine and it looks for this particular symbol name. */
+struct r_debug _r_debug;
+
+
+/* Initialize _r_debug if it has not already been done. The argument is
+ the run-time load address of the dynamic linker, to be put in
+ _r_debug.r_ldbase. Returns the address of _r_debug. */
+
+struct r_debug *
+internal_function
+_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
+{
+ struct r_debug *r;
+
+ if (ns == LM_ID_BASE)
+ r = &_r_debug;
+ else
+ r = &GL(dl_ns)[ns]._ns_debug;
+
+ if (r->r_map == NULL || ldbase != 0)
+ {
+ /* Tell the debugger where to find the map of loaded objects. */
+ r->r_version = 1 /* R_DEBUG_VERSION XXX */;
+ r->r_ldbase = ldbase ?: _r_debug.r_ldbase;
+ r->r_map = (void *) GL(dl_ns)[ns]._ns_loaded;
+ r->r_brk = (ElfW(Addr)) &_dl_debug_state;
+ }
+
+ return r;
+}
+
+
+/* This function exists solely to have a breakpoint set on it by the
+ debugger. The debugger is supposed to find this function's address by
+ examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks
+ for this particular symbol name in the PT_INTERP file. */
+void
+_dl_debug_state (void)
+{
+}
+rtld_hidden_def (_dl_debug_state)
diff --git a/REORG.TODO/elf/dl-deps.c b/REORG.TODO/elf/dl-deps.c
new file mode 100644
index 0000000000..1b8bac6593
--- /dev/null
+++ b/REORG.TODO/elf/dl-deps.c
@@ -0,0 +1,688 @@
+/* Load the dependencies of a mapped object.
+ Copyright (C) 1996-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <atomic.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <ldsodefs.h>
+
+#include <dl-dst.h>
+
+/* Whether an shared object references one or more auxiliary objects
+ is signaled by the AUXTAG entry in l_info. */
+#define AUXTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ + DT_EXTRATAGIDX (DT_AUXILIARY))
+/* Whether an shared object references one or more auxiliary objects
+ is signaled by the AUXTAG entry in l_info. */
+#define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ + DT_EXTRATAGIDX (DT_FILTER))
+
+
+/* When loading auxiliary objects we must ignore errors. It's ok if
+ an object is missing. */
+struct openaux_args
+ {
+ /* The arguments to openaux. */
+ struct link_map *map;
+ int trace_mode;
+ int open_mode;
+ const char *strtab;
+ const char *name;
+
+ /* The return value of openaux. */
+ struct link_map *aux;
+ };
+
+static void
+openaux (void *a)
+{
+ struct openaux_args *args = (struct openaux_args *) a;
+
+ args->aux = _dl_map_object (args->map, args->name,
+ (args->map->l_type == lt_executable
+ ? lt_library : args->map->l_type),
+ args->trace_mode, args->open_mode,
+ args->map->l_ns);
+}
+
+static ptrdiff_t
+internal_function
+_dl_build_local_scope (struct link_map **list, struct link_map *map)
+{
+ struct link_map **p = list;
+ struct link_map **q;
+
+ *p++ = map;
+ map->l_reserved = 1;
+ if (map->l_initfini)
+ for (q = map->l_initfini + 1; *q; ++q)
+ if (! (*q)->l_reserved)
+ p += _dl_build_local_scope (p, *q);
+ return p - list;
+}
+
+
+/* We use a very special kind of list to track the path
+ through the list of loaded shared objects. We have to
+ produce a flat list with unique members of all involved objects.
+*/
+struct list
+ {
+ int done; /* Nonzero if this map was processed. */
+ struct link_map *map; /* The data. */
+ struct list *next; /* Elements for normal list. */
+ };
+
+
+/* Macro to expand DST. It is an macro since we use `alloca'. */
+#define expand_dst(l, str, fatal) \
+ ({ \
+ const char *__str = (str); \
+ const char *__result = __str; \
+ size_t __dst_cnt = DL_DST_COUNT (__str, 0); \
+ \
+ if (__dst_cnt != 0) \
+ { \
+ char *__newp; \
+ \
+ /* DST must not appear in SUID/SGID programs. */ \
+ if (__libc_enable_secure) \
+ _dl_signal_error (0, __str, NULL, N_("\
+DST not allowed in SUID/SGID programs")); \
+ \
+ __newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str), \
+ __dst_cnt)); \
+ \
+ __result = _dl_dst_substitute (l, __str, __newp, 0); \
+ \
+ if (*__result == '\0') \
+ { \
+ /* The replacement for the DST is not known. We can't \
+ processed. */ \
+ if (fatal) \
+ _dl_signal_error (0, __str, NULL, N_("\
+empty dynamic string token substitution")); \
+ else \
+ { \
+ /* This is for DT_AUXILIARY. */ \
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) \
+ _dl_debug_printf (N_("\
+cannot load auxiliary `%s' because of empty dynamic string token " \
+ "substitution\n"), __str); \
+ continue; \
+ } \
+ } \
+ } \
+ \
+ __result; })
+
+static void
+preload (struct list *known, unsigned int *nlist, struct link_map *map)
+{
+ known[*nlist].done = 0;
+ known[*nlist].map = map;
+ known[*nlist].next = &known[*nlist + 1];
+
+ ++*nlist;
+ /* We use `l_reserved' as a mark bit to detect objects we have
+ already put in the search list and avoid adding duplicate
+ elements later in the list. */
+ map->l_reserved = 1;
+}
+
+void
+internal_function
+_dl_map_object_deps (struct link_map *map,
+ struct link_map **preloads, unsigned int npreloads,
+ int trace_mode, int open_mode)
+{
+ struct list *known = __alloca (sizeof *known * (1 + npreloads + 1));
+ struct list *runp, *tail;
+ unsigned int nlist, i;
+ /* Object name. */
+ const char *name;
+ int errno_saved;
+ int errno_reason;
+ const char *errstring;
+ const char *objname;
+
+ /* No loaded object so far. */
+ nlist = 0;
+
+ /* First load MAP itself. */
+ preload (known, &nlist, map);
+
+ /* Add the preloaded items after MAP but before any of its dependencies. */
+ for (i = 0; i < npreloads; ++i)
+ preload (known, &nlist, preloads[i]);
+
+ /* Terminate the lists. */
+ known[nlist - 1].next = NULL;
+
+ /* Pointer to last unique object. */
+ tail = &known[nlist - 1];
+
+ /* No alloca'd space yet. */
+ struct link_map **needed_space = NULL;
+ size_t needed_space_bytes = 0;
+
+ /* Process each element of the search list, loading each of its
+ auxiliary objects and immediate dependencies. Auxiliary objects
+ will be added in the list before the object itself and
+ dependencies will be appended to the list as we step through it.
+ This produces a flat, ordered list that represents a
+ breadth-first search of the dependency tree.
+
+ The whole process is complicated by the fact that we better
+ should use alloca for the temporary list elements. But using
+ alloca means we cannot use recursive function calls. */
+ errno_saved = errno;
+ errno_reason = 0;
+ errstring = NULL;
+ errno = 0;
+ name = NULL;
+ for (runp = known; runp; )
+ {
+ struct link_map *l = runp->map;
+ struct link_map **needed = NULL;
+ unsigned int nneeded = 0;
+
+ /* Unless otherwise stated, this object is handled. */
+ runp->done = 1;
+
+ /* Allocate a temporary record to contain the references to the
+ dependencies of this object. */
+ if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
+ && l != map && l->l_ldnum > 0)
+ {
+ size_t new_size = l->l_ldnum * sizeof (struct link_map *);
+
+ if (new_size > needed_space_bytes)
+ needed_space
+ = extend_alloca (needed_space, needed_space_bytes, new_size);
+
+ needed = needed_space;
+ }
+
+ if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
+ {
+ const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
+ struct openaux_args args;
+ struct list *orig;
+ const ElfW(Dyn) *d;
+
+ args.strtab = strtab;
+ args.map = l;
+ args.trace_mode = trace_mode;
+ args.open_mode = open_mode;
+ orig = runp;
+
+ for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
+ if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED)
+ {
+ /* Map in the needed object. */
+ struct link_map *dep;
+
+ /* Recognize DSTs. */
+ name = expand_dst (l, strtab + d->d_un.d_val, 0);
+ /* Store the tag in the argument structure. */
+ args.name = name;
+
+ bool malloced;
+ int err = _dl_catch_error (&objname, &errstring, &malloced,
+ openaux, &args);
+ if (__glibc_unlikely (errstring != NULL))
+ {
+ char *new_errstring = strdupa (errstring);
+ objname = strdupa (objname);
+ if (malloced)
+ free ((char *) errstring);
+ errstring = new_errstring;
+
+ if (err)
+ errno_reason = err;
+ else
+ errno_reason = -1;
+ goto out;
+ }
+ else
+ dep = args.aux;
+
+ if (! dep->l_reserved)
+ {
+ /* Allocate new entry. */
+ struct list *newp;
+
+ newp = alloca (sizeof (struct list));
+
+ /* Append DEP to the list. */
+ newp->map = dep;
+ newp->done = 0;
+ newp->next = NULL;
+ tail->next = newp;
+ tail = newp;
+ ++nlist;
+ /* Set the mark bit that says it's already in the list. */
+ dep->l_reserved = 1;
+ }
+
+ /* Remember this dependency. */
+ if (needed != NULL)
+ needed[nneeded++] = dep;
+ }
+ else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER)
+ {
+ struct list *newp;
+
+ /* Recognize DSTs. */
+ name = expand_dst (l, strtab + d->d_un.d_val,
+ d->d_tag == DT_AUXILIARY);
+ /* Store the tag in the argument structure. */
+ args.name = name;
+
+ /* Say that we are about to load an auxiliary library. */
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
+ 0))
+ _dl_debug_printf ("load auxiliary object=%s"
+ " requested by file=%s\n",
+ name,
+ DSO_FILENAME (l->l_name));
+
+ /* We must be prepared that the addressed shared
+ object is not available. For filter objects the dependency
+ must be available. */
+ bool malloced;
+ int err = _dl_catch_error (&objname, &errstring, &malloced,
+ openaux, &args);
+
+ if (__glibc_unlikely (errstring != NULL))
+ {
+ if (d->d_tag == DT_AUXILIARY)
+ {
+ /* We are not interested in the error message. */
+ assert (errstring != NULL);
+ if (malloced)
+ free ((char *) errstring);
+
+ /* Simply ignore this error and continue the work. */
+ continue;
+ }
+ else
+ {
+
+ char *new_errstring = strdupa (errstring);
+ objname = strdupa (objname);
+ if (malloced)
+ free ((char *) errstring);
+ errstring = new_errstring;
+
+ if (err)
+ errno_reason = err;
+ else
+ errno_reason = -1;
+ goto out;
+ }
+ }
+
+ /* The auxiliary object is actually available.
+ Incorporate the map in all the lists. */
+
+ /* Allocate new entry. This always has to be done. */
+ newp = alloca (sizeof (struct list));
+
+ /* We want to insert the new map before the current one,
+ but we have no back links. So we copy the contents of
+ the current entry over. Note that ORIG and NEWP now
+ have switched their meanings. */
+ memcpy (newp, orig, sizeof (*newp));
+
+ /* Initialize new entry. */
+ orig->done = 0;
+ orig->map = args.aux;
+
+ /* Remember this dependency. */
+ if (needed != NULL)
+ needed[nneeded++] = args.aux;
+
+ /* We must handle two situations here: the map is new,
+ so we must add it in all three lists. If the map
+ is already known, we have two further possibilities:
+ - if the object is before the current map in the
+ search list, we do nothing. It is already found
+ early
+ - if the object is after the current one, we must
+ move it just before the current map to make sure
+ the symbols are found early enough
+ */
+ if (args.aux->l_reserved)
+ {
+ /* The object is already somewhere in the list.
+ Locate it first. */
+ struct list *late;
+
+ /* This object is already in the search list we
+ are building. Don't add a duplicate pointer.
+ Just added by _dl_map_object. */
+ for (late = newp; late->next != NULL; late = late->next)
+ if (late->next->map == args.aux)
+ break;
+
+ if (late->next != NULL)
+ {
+ /* The object is somewhere behind the current
+ position in the search path. We have to
+ move it to this earlier position. */
+ orig->next = newp;
+
+ /* Now remove the later entry from the list
+ and adjust the tail pointer. */
+ if (tail == late->next)
+ tail = late;
+ late->next = late->next->next;
+
+ /* We must move the object earlier in the chain. */
+ if (args.aux->l_prev != NULL)
+ args.aux->l_prev->l_next = args.aux->l_next;
+ if (args.aux->l_next != NULL)
+ args.aux->l_next->l_prev = args.aux->l_prev;
+
+ args.aux->l_prev = newp->map->l_prev;
+ newp->map->l_prev = args.aux;
+ if (args.aux->l_prev != NULL)
+ args.aux->l_prev->l_next = args.aux;
+ args.aux->l_next = newp->map;
+ }
+ else
+ {
+ /* The object must be somewhere earlier in the
+ list. Undo to the current list element what
+ we did above. */
+ memcpy (orig, newp, sizeof (*newp));
+ continue;
+ }
+ }
+ else
+ {
+ /* This is easy. We just add the symbol right here. */
+ orig->next = newp;
+ ++nlist;
+ /* Set the mark bit that says it's already in the list. */
+ args.aux->l_reserved = 1;
+
+ /* The only problem is that in the double linked
+ list of all objects we don't have this new
+ object at the correct place. Correct this here. */
+ if (args.aux->l_prev)
+ args.aux->l_prev->l_next = args.aux->l_next;
+ if (args.aux->l_next)
+ args.aux->l_next->l_prev = args.aux->l_prev;
+
+ args.aux->l_prev = newp->map->l_prev;
+ newp->map->l_prev = args.aux;
+ if (args.aux->l_prev != NULL)
+ args.aux->l_prev->l_next = args.aux;
+ args.aux->l_next = newp->map;
+ }
+
+ /* Move the tail pointer if necessary. */
+ if (orig == tail)
+ tail = newp;
+
+ /* Move on the insert point. */
+ orig = newp;
+ }
+ }
+
+ /* Terminate the list of dependencies and store the array address. */
+ if (needed != NULL)
+ {
+ needed[nneeded++] = NULL;
+
+ struct link_map **l_initfini = (struct link_map **)
+ malloc ((2 * nneeded + 1) * sizeof needed[0]);
+ if (l_initfini == NULL)
+ _dl_signal_error (ENOMEM, map->l_name, NULL,
+ N_("cannot allocate dependency list"));
+ l_initfini[0] = l;
+ memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
+ memcpy (&l_initfini[nneeded + 1], l_initfini,
+ nneeded * sizeof needed[0]);
+ atomic_write_barrier ();
+ l->l_initfini = l_initfini;
+ l->l_free_initfini = 1;
+ }
+
+ /* If we have no auxiliary objects just go on to the next map. */
+ if (runp->done)
+ do
+ runp = runp->next;
+ while (runp != NULL && runp->done);
+ }
+
+ out:
+ if (errno == 0 && errno_saved != 0)
+ __set_errno (errno_saved);
+
+ struct link_map **old_l_initfini = NULL;
+ if (map->l_initfini != NULL && map->l_type == lt_loaded)
+ {
+ /* This object was previously loaded as a dependency and we have
+ a separate l_initfini list. We don't need it anymore. */
+ assert (map->l_searchlist.r_list == NULL);
+ old_l_initfini = map->l_initfini;
+ }
+
+ /* Store the search list we built in the object. It will be used for
+ searches in the scope of this object. */
+ struct link_map **l_initfini =
+ (struct link_map **) malloc ((2 * nlist + 1)
+ * sizeof (struct link_map *));
+ if (l_initfini == NULL)
+ _dl_signal_error (ENOMEM, map->l_name, NULL,
+ N_("cannot allocate symbol search list"));
+
+
+ map->l_searchlist.r_list = &l_initfini[nlist + 1];
+ map->l_searchlist.r_nlist = nlist;
+
+ for (nlist = 0, runp = known; runp; runp = runp->next)
+ {
+ if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
+ /* This can happen when we trace the loading. */
+ --map->l_searchlist.r_nlist;
+ else
+ map->l_searchlist.r_list[nlist++] = runp->map;
+
+ /* Now clear all the mark bits we set in the objects on the search list
+ to avoid duplicates, so the next call starts fresh. */
+ runp->map->l_reserved = 0;
+ }
+
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
+ && map == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
+ {
+ /* If we are to compute conflicts, we have to build local scope
+ for each library, not just the ultimate loader. */
+ for (i = 0; i < nlist; ++i)
+ {
+ struct link_map *l = map->l_searchlist.r_list[i];
+ unsigned int j, cnt;
+
+ /* The local scope has been already computed. */
+ if (l == map
+ || (l->l_local_scope[0]
+ && l->l_local_scope[0]->r_nlist) != 0)
+ continue;
+
+ if (l->l_info[AUXTAG] || l->l_info[FILTERTAG])
+ {
+ /* As current DT_AUXILIARY/DT_FILTER implementation needs to be
+ rewritten, no need to bother with prelinking the old
+ implementation. */
+ _dl_signal_error (EINVAL, l->l_name, NULL, N_("\
+Filters not supported with LD_TRACE_PRELINKING"));
+ }
+
+ cnt = _dl_build_local_scope (l_initfini, l);
+ assert (cnt <= nlist);
+ for (j = 0; j < cnt; j++)
+ {
+ l_initfini[j]->l_reserved = 0;
+ if (j && __builtin_expect (l_initfini[j]->l_info[DT_SYMBOLIC]
+ != NULL, 0))
+ l->l_symbolic_in_local_scope = true;
+ }
+
+ l->l_local_scope[0] =
+ (struct r_scope_elem *) malloc (sizeof (struct r_scope_elem)
+ + (cnt
+ * sizeof (struct link_map *)));
+ if (l->l_local_scope[0] == NULL)
+ _dl_signal_error (ENOMEM, map->l_name, NULL,
+ N_("cannot allocate symbol search list"));
+ l->l_local_scope[0]->r_nlist = cnt;
+ l->l_local_scope[0]->r_list =
+ (struct link_map **) (l->l_local_scope[0] + 1);
+ memcpy (l->l_local_scope[0]->r_list, l_initfini,
+ cnt * sizeof (struct link_map *));
+ }
+ }
+
+ /* Maybe we can remove some relocation dependencies now. */
+ assert (map->l_searchlist.r_list[0] == map);
+ struct link_map_reldeps *l_reldeps = NULL;
+ if (map->l_reldeps != NULL)
+ {
+ for (i = 1; i < nlist; ++i)
+ map->l_searchlist.r_list[i]->l_reserved = 1;
+
+ struct link_map **list = &map->l_reldeps->list[0];
+ for (i = 0; i < map->l_reldeps->act; ++i)
+ if (list[i]->l_reserved)
+ {
+ /* Need to allocate new array of relocation dependencies. */
+ l_reldeps = malloc (sizeof (*l_reldeps)
+ + map->l_reldepsmax
+ * sizeof (struct link_map *));
+ if (l_reldeps == NULL)
+ /* Bad luck, keep the reldeps duplicated between
+ map->l_reldeps->list and map->l_initfini lists. */
+ ;
+ else
+ {
+ unsigned int j = i;
+ memcpy (&l_reldeps->list[0], &list[0],
+ i * sizeof (struct link_map *));
+ for (i = i + 1; i < map->l_reldeps->act; ++i)
+ if (!list[i]->l_reserved)
+ l_reldeps->list[j++] = list[i];
+ l_reldeps->act = j;
+ }
+ }
+
+ for (i = 1; i < nlist; ++i)
+ map->l_searchlist.r_list[i]->l_reserved = 0;
+ }
+
+ /* Sort the initializer list to take dependencies into account. The binary
+ itself will always be initialize last. */
+ memcpy (l_initfini, map->l_searchlist.r_list,
+ nlist * sizeof (struct link_map *));
+ if (__glibc_likely (nlist > 1))
+ {
+ /* We can skip looking for the binary itself which is at the front
+ of the search list. */
+ i = 1;
+ uint16_t seen[nlist];
+ memset (seen, 0, nlist * sizeof (seen[0]));
+ while (1)
+ {
+ /* Keep track of which object we looked at this round. */
+ ++seen[i];
+ struct link_map *thisp = l_initfini[i];
+
+ /* Find the last object in the list for which the current one is
+ a dependency and move the current object behind the object
+ with the dependency. */
+ unsigned int k = nlist - 1;
+ while (k > i)
+ {
+ struct link_map **runp = l_initfini[k]->l_initfini;
+ if (runp != NULL)
+ /* Look through the dependencies of the object. */
+ while (*runp != NULL)
+ if (__glibc_unlikely (*runp++ == thisp))
+ {
+ /* Move the current object to the back past the last
+ object with it as the dependency. */
+ memmove (&l_initfini[i], &l_initfini[i + 1],
+ (k - i) * sizeof (l_initfini[0]));
+ l_initfini[k] = thisp;
+
+ if (seen[i + 1] > nlist - i)
+ {
+ ++i;
+ goto next_clear;
+ }
+
+ uint16_t this_seen = seen[i];
+ memmove (&seen[i], &seen[i + 1],
+ (k - i) * sizeof (seen[0]));
+ seen[k] = this_seen;
+
+ goto next;
+ }
+
+ --k;
+ }
+
+ if (++i == nlist)
+ break;
+ next_clear:
+ memset (&seen[i], 0, (nlist - i) * sizeof (seen[0]));
+
+ next:;
+ }
+ }
+
+ /* Terminate the list of dependencies. */
+ l_initfini[nlist] = NULL;
+ atomic_write_barrier ();
+ map->l_initfini = l_initfini;
+ map->l_free_initfini = 1;
+ if (l_reldeps != NULL)
+ {
+ atomic_write_barrier ();
+ void *old_l_reldeps = map->l_reldeps;
+ map->l_reldeps = l_reldeps;
+ _dl_scope_free (old_l_reldeps);
+ }
+ if (old_l_initfini != NULL)
+ _dl_scope_free (old_l_initfini);
+
+ if (errno_reason)
+ _dl_signal_error (errno_reason == -1 ? 0 : errno_reason, objname,
+ NULL, errstring);
+}
diff --git a/REORG.TODO/elf/dl-dst.h b/REORG.TODO/elf/dl-dst.h
new file mode 100644
index 0000000000..a96513d4dc
--- /dev/null
+++ b/REORG.TODO/elf/dl-dst.h
@@ -0,0 +1,74 @@
+/* Handling of dynamic sring tokens.
+ Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "trusted-dirs.h"
+
+/* Determine the number of DST elements in the name. Only if IS_PATH is
+ nonzero paths are recognized (i.e., multiple, ':' separated filenames). */
+#define DL_DST_COUNT(name, is_path) \
+ ({ \
+ size_t __cnt = 0; \
+ const char *__sf = strchr (name, '$'); \
+ \
+ if (__glibc_unlikely (__sf != NULL)) \
+ __cnt = _dl_dst_count (__sf, is_path); \
+ \
+ __cnt; })
+
+
+#ifdef SHARED
+# define IS_RTLD(l) (l) == &GL(dl_rtld_map)
+#else
+# define IS_RTLD(l) 0
+#endif
+/* Guess from the number of DSTs the length of the result string. */
+#define DL_DST_REQUIRED(l, name, len, cnt) \
+ ({ \
+ size_t __len = (len); \
+ size_t __cnt = (cnt); \
+ \
+ if (__cnt > 0) \
+ { \
+ size_t dst_len; \
+ /* Now we make a guess how many extra characters on top of the \
+ length of S we need to represent the result. We know that \
+ we have CNT replacements. Each at most can use \
+ MAX (MAX (strlen (ORIGIN), strlen (_dl_platform)), \
+ strlen (DL_DST_LIB)) \
+ minus 4 (which is the length of "$LIB"). \
+ \
+ First get the origin string if it is not available yet. \
+ This can only happen for the map of the executable or, when \
+ auditing, in ld.so. */ \
+ if ((l)->l_origin == NULL) \
+ { \
+ assert ((l)->l_name[0] == '\0' || IS_RTLD (l)); \
+ (l)->l_origin = _dl_get_origin (); \
+ dst_len = ((l)->l_origin && (l)->l_origin != (char *) -1 \
+ ? strlen ((l)->l_origin) : 0); \
+ } \
+ else \
+ dst_len = (l)->l_origin == (char *) -1 \
+ ? 0 : strlen ((l)->l_origin); \
+ dst_len = MAX (MAX (dst_len, GLRO(dl_platformlen)), \
+ strlen (DL_DST_LIB)); \
+ if (dst_len > 4) \
+ __len += __cnt * (dst_len - 4); \
+ } \
+ \
+ __len; })
diff --git a/REORG.TODO/elf/dl-environ.c b/REORG.TODO/elf/dl-environ.c
new file mode 100644
index 0000000000..cbffec8808
--- /dev/null
+++ b/REORG.TODO/elf/dl-environ.c
@@ -0,0 +1,85 @@
+/* Environment handling for dynamic loader.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+
+/* Walk through the environment of the process and return all entries
+ starting with `LD_'. */
+char *
+internal_function
+_dl_next_ld_env_entry (char ***position)
+{
+ char **current = *position;
+ char *result = NULL;
+
+ while (*current != NULL)
+ {
+ if (__builtin_expect ((*current)[0] == 'L', 0)
+ && (*current)[1] == 'D' && (*current)[2] == '_')
+ {
+ result = &(*current)[3];
+
+ /* Save current position for next visit. */
+ *position = ++current;
+
+ break;
+ }
+
+ ++current;
+ }
+
+ return result;
+}
+
+
+/* In ld.so __environ is not exported. */
+extern char **__environ attribute_hidden;
+
+int
+unsetenv (const char *name)
+{
+ char **ep;
+
+ ep = __environ;
+ while (*ep != NULL)
+ {
+ size_t cnt = 0;
+
+ while ((*ep)[cnt] == name[cnt] && name[cnt] != '\0')
+ ++cnt;
+
+ if (name[cnt] == '\0' && (*ep)[cnt] == '=')
+ {
+ /* Found it. Remove this pointer by moving later ones to
+ the front. */
+ char **dp = ep;
+
+ do
+ dp[0] = dp[1];
+ while (*dp++);
+ /* Continue the loop in case NAME appears again. */
+ }
+ else
+ ++ep;
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/dl-error-minimal.c b/REORG.TODO/elf/dl-error-minimal.c
new file mode 100644
index 0000000000..384c9b0edc
--- /dev/null
+++ b/REORG.TODO/elf/dl-error-minimal.c
@@ -0,0 +1,23 @@
+/* Error handling for runtime dynamic linker, minimal version.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This version does lives in ld.so, does not use thread-local data
+ and supports _dl_signal_cerror and _dl_receive_error. */
+
+#define DL_ERROR_BOOTSTRAP 1
+#include "dl-error-skeleton.c"
diff --git a/REORG.TODO/elf/dl-error-skeleton.c b/REORG.TODO/elf/dl-error-skeleton.c
new file mode 100644
index 0000000000..8e5888d4bd
--- /dev/null
+++ b/REORG.TODO/elf/dl-error-skeleton.c
@@ -0,0 +1,230 @@
+/* Template for error handling for runtime dynamic linker.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* The following macro needs to be defined before including this
+ skeleton file:
+
+ DL_ERROR_BOOTSTRAP
+
+ If 1, do not use TLS and implement _dl_signal_cerror and
+ _dl_receive_error. If 0, TLS is used, and the variants with
+ error callbacks are not provided. */
+
+
+#include <libintl.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <stdio.h>
+
+/* This structure communicates state between _dl_catch_error and
+ _dl_signal_error. */
+struct catch
+ {
+ const char **objname; /* Object/File name. */
+ const char **errstring; /* Error detail filled in here. */
+ bool *malloced; /* Nonzero if the string is malloced
+ by the libc malloc. */
+ volatile int *errcode; /* Return value of _dl_signal_error. */
+ jmp_buf env; /* longjmp here on error. */
+ };
+
+/* Multiple threads at once can use the `_dl_catch_error' function. The
+ calls can come from `_dl_map_object_deps', `_dlerror_run', or from
+ any of the libc functionality which loads dynamic objects (NSS, iconv).
+ Therefore we have to be prepared to save the state in thread-local
+ memory. */
+#if !DL_ERROR_BOOTSTRAP
+static __thread struct catch *catch_hook attribute_tls_model_ie;
+#else
+/* The version of this code in ld.so cannot use thread-local variables
+ and is used during bootstrap only. */
+static struct catch *catch_hook;
+#endif
+
+/* This message we return as a last resort. We define the string in a
+ variable since we have to avoid freeing it and so have to enable
+ a pointer comparison. See below and in dlfcn/dlerror.c. */
+static const char _dl_out_of_memory[] = "out of memory";
+
+#if DL_ERROR_BOOTSTRAP
+/* This points to a function which is called when an continuable error is
+ received. Unlike the handling of `catch' this function may return.
+ The arguments will be the `errstring' and `objname'.
+
+ Since this functionality is not used in normal programs (only in ld.so)
+ we do not care about multi-threaded programs here. We keep this as a
+ global variable. */
+static receiver_fct receiver;
+#endif /* DL_ERROR_BOOTSTRAP */
+
+void
+internal_function
+_dl_signal_error (int errcode, const char *objname, const char *occation,
+ const char *errstring)
+{
+ struct catch *lcatch = catch_hook;
+
+ if (! errstring)
+ errstring = N_("DYNAMIC LINKER BUG!!!");
+
+ if (objname == NULL)
+ objname = "";
+ if (lcatch != NULL)
+ {
+ /* We are inside _dl_catch_error. Return to it. We have to
+ duplicate the error string since it might be allocated on the
+ stack. The object name is always a string constant. */
+ size_t len_objname = strlen (objname) + 1;
+ size_t len_errstring = strlen (errstring) + 1;
+
+ char *errstring_copy = malloc (len_objname + len_errstring);
+ if (errstring_copy != NULL)
+ {
+ /* Make a copy of the object file name and the error string. */
+ *lcatch->objname = memcpy (__mempcpy (errstring_copy,
+ errstring, len_errstring),
+ objname, len_objname);
+ *lcatch->errstring = errstring_copy;
+
+ /* If the main executable is relocated it means the libc's malloc
+ is used. */
+ bool malloced = true;
+#ifdef SHARED
+ malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
+ && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0));
+#endif
+ *lcatch->malloced = malloced;
+ }
+ else
+ {
+ /* This is better than nothing. */
+ *lcatch->objname = "";
+ *lcatch->errstring = _dl_out_of_memory;
+ *lcatch->malloced = false;
+ }
+
+ *lcatch->errcode = errcode;
+
+ /* We do not restore the signal mask because none was saved. */
+ __longjmp (lcatch->env[0].__jmpbuf, 1);
+ }
+ else
+ {
+ /* Lossage while resolving the program's own symbols is always fatal. */
+ char buffer[1024];
+ _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n",
+ RTLD_PROGNAME,
+ occation ?: N_("error while loading shared libraries"),
+ objname, *objname ? ": " : "",
+ errstring, errcode ? ": " : "",
+ (errcode
+ ? __strerror_r (errcode, buffer, sizeof buffer)
+ : ""));
+ }
+}
+libc_hidden_def (_dl_signal_error)
+
+
+#if DL_ERROR_BOOTSTRAP
+void
+internal_function
+_dl_signal_cerror (int errcode, const char *objname, const char *occation,
+ const char *errstring)
+{
+ if (__builtin_expect (GLRO(dl_debug_mask)
+ & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
+ _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
+ errstring, receiver ? "continued" : "fatal");
+
+ if (receiver)
+ {
+ /* We are inside _dl_receive_error. Call the user supplied
+ handler and resume the work. The receiver will still be
+ installed. */
+ (*receiver) (errcode, objname, errstring);
+ }
+ else
+ _dl_signal_error (errcode, objname, occation, errstring);
+}
+#endif /* DL_ERROR_BOOTSTRAP */
+
+
+int
+internal_function
+_dl_catch_error (const char **objname, const char **errstring,
+ bool *mallocedp, void (*operate) (void *), void *args)
+{
+ /* We need not handle `receiver' since setting a `catch' is handled
+ before it. */
+
+ /* Only this needs to be marked volatile, because it is the only local
+ variable that gets changed between the setjmp invocation and the
+ longjmp call. All others are just set here (before setjmp) and read
+ in _dl_signal_error (before longjmp). */
+ volatile int errcode;
+
+ struct catch c;
+ /* Don't use an initializer since we don't need to clear C.env. */
+ c.objname = objname;
+ c.errstring = errstring;
+ c.malloced = mallocedp;
+ c.errcode = &errcode;
+
+ struct catch *const old = catch_hook;
+ catch_hook = &c;
+
+ /* Do not save the signal mask. */
+ if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0)
+ {
+ (*operate) (args);
+ catch_hook = old;
+ *objname = NULL;
+ *errstring = NULL;
+ *mallocedp = false;
+ return 0;
+ }
+
+ /* We get here only if we longjmp'd out of OPERATE. _dl_signal_error has
+ already stored values into *OBJNAME, *ERRSTRING, and *MALLOCEDP. */
+ catch_hook = old;
+ return errcode;
+}
+libc_hidden_def (_dl_catch_error)
+
+#if DL_ERROR_BOOTSTRAP
+void
+internal_function
+_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
+{
+ struct catch *old_catch = catch_hook;
+ receiver_fct old_receiver = receiver;
+
+ /* Set the new values. */
+ catch_hook = NULL;
+ receiver = fct;
+
+ (*operate) (args);
+
+ catch_hook = old_catch;
+ receiver = old_receiver;
+}
+#endif /* DL_ERROR_BOOTSTRAP */
diff --git a/REORG.TODO/elf/dl-error.c b/REORG.TODO/elf/dl-error.c
new file mode 100644
index 0000000000..bfcbd5358b
--- /dev/null
+++ b/REORG.TODO/elf/dl-error.c
@@ -0,0 +1,27 @@
+/* Error handling for runtime dynamic linker, full version.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This implementation lives in libc.so because it uses thread-local
+ data, which is not available in ld.so. It interposes the version
+ in dl-error-minimal.c after ld.so bootstrap.
+
+ The signal/catch mechanism is used by the audit framework, which
+ means that even in ld.so, not all errors are fatal. */
+
+#define DL_ERROR_BOOTSTRAP 0
+#include "dl-error-skeleton.c"
diff --git a/REORG.TODO/elf/dl-execstack.c b/REORG.TODO/elf/dl-execstack.c
new file mode 100644
index 0000000000..875338bea5
--- /dev/null
+++ b/REORG.TODO/elf/dl-execstack.c
@@ -0,0 +1,31 @@
+/* Stack executability handling for GNU dynamic linker. Stub version.
+ Copyright (C) 2003-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <ldsodefs.h>
+#include <errno.h>
+
+/* There is no portable way to know the bounds of the initial thread's stack
+ so as to mprotect it. */
+
+int
+internal_function
+_dl_make_stack_executable (void **stack_endp)
+{
+ return ENOSYS;
+}
+rtld_hidden_def (_dl_make_stack_executable)
diff --git a/REORG.TODO/elf/dl-fini.c b/REORG.TODO/elf/dl-fini.c
new file mode 100644
index 0000000000..93b337bea1
--- /dev/null
+++ b/REORG.TODO/elf/dl-fini.c
@@ -0,0 +1,281 @@
+/* Call the termination functions of loaded shared objects.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <string.h>
+#include <ldsodefs.h>
+
+
+/* Type of the constructor functions. */
+typedef void (*fini_t) (void);
+
+
+void
+internal_function
+_dl_sort_fini (struct link_map **maps, size_t nmaps, char *used, Lmid_t ns)
+{
+ /* A list of one element need not be sorted. */
+ if (nmaps == 1)
+ return;
+
+ /* We can skip looking for the binary itself which is at the front
+ of the search list for the main namespace. */
+ unsigned int i = ns == LM_ID_BASE;
+ uint16_t seen[nmaps];
+ memset (seen, 0, nmaps * sizeof (seen[0]));
+ while (1)
+ {
+ /* Keep track of which object we looked at this round. */
+ ++seen[i];
+ struct link_map *thisp = maps[i];
+
+ /* Do not handle ld.so in secondary namespaces and object which
+ are not removed. */
+ if (thisp != thisp->l_real || thisp->l_idx == -1)
+ goto skip;
+
+ /* Find the last object in the list for which the current one is
+ a dependency and move the current object behind the object
+ with the dependency. */
+ unsigned int k = nmaps - 1;
+ while (k > i)
+ {
+ struct link_map **runp = maps[k]->l_initfini;
+ if (runp != NULL)
+ /* Look through the dependencies of the object. */
+ while (*runp != NULL)
+ if (__glibc_unlikely (*runp++ == thisp))
+ {
+ move:
+ /* Move the current object to the back past the last
+ object with it as the dependency. */
+ memmove (&maps[i], &maps[i + 1],
+ (k - i) * sizeof (maps[0]));
+ maps[k] = thisp;
+
+ if (used != NULL)
+ {
+ char here_used = used[i];
+ memmove (&used[i], &used[i + 1],
+ (k - i) * sizeof (used[0]));
+ used[k] = here_used;
+ }
+
+ if (seen[i + 1] > nmaps - i)
+ {
+ ++i;
+ goto next_clear;
+ }
+
+ uint16_t this_seen = seen[i];
+ memmove (&seen[i], &seen[i + 1], (k - i) * sizeof (seen[0]));
+ seen[k] = this_seen;
+
+ goto next;
+ }
+
+ if (__glibc_unlikely (maps[k]->l_reldeps != NULL))
+ {
+ unsigned int m = maps[k]->l_reldeps->act;
+ struct link_map **relmaps = &maps[k]->l_reldeps->list[0];
+
+ /* Look through the relocation dependencies of the object. */
+ while (m-- > 0)
+ if (__glibc_unlikely (relmaps[m] == thisp))
+ {
+ /* If a cycle exists with a link time dependency,
+ preserve the latter. */
+ struct link_map **runp = thisp->l_initfini;
+ if (runp != NULL)
+ while (*runp != NULL)
+ if (__glibc_unlikely (*runp++ == maps[k]))
+ goto ignore;
+ goto move;
+ }
+ ignore:;
+ }
+
+ --k;
+ }
+
+ skip:
+ if (++i == nmaps)
+ break;
+ next_clear:
+ memset (&seen[i], 0, (nmaps - i) * sizeof (seen[0]));
+
+ next:;
+ }
+}
+
+
+void
+internal_function
+_dl_fini (void)
+{
+ /* Lots of fun ahead. We have to call the destructors for all still
+ loaded objects, in all namespaces. The problem is that the ELF
+ specification now demands that dependencies between the modules
+ are taken into account. I.e., the destructor for a module is
+ called before the ones for any of its dependencies.
+
+ To make things more complicated, we cannot simply use the reverse
+ order of the constructors. Since the user might have loaded objects
+ using `dlopen' there are possibly several other modules with its
+ dependencies to be taken into account. Therefore we have to start
+ determining the order of the modules once again from the beginning. */
+
+ /* We run the destructors of the main namespaces last. As for the
+ other namespaces, we pick run the destructors in them in reverse
+ order of the namespace ID. */
+#ifdef SHARED
+ int do_audit = 0;
+ again:
+#endif
+ for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns)
+ {
+ /* Protect against concurrent loads and unloads. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+ unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
+ /* No need to do anything for empty namespaces or those used for
+ auditing DSOs. */
+ if (nloaded == 0
+#ifdef SHARED
+ || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
+#endif
+ )
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ else
+ {
+ /* Now we can allocate an array to hold all the pointers and
+ copy the pointers in. */
+ struct link_map *maps[nloaded];
+
+ unsigned int i;
+ struct link_map *l;
+ assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
+ for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
+ /* Do not handle ld.so in secondary namespaces. */
+ if (l == l->l_real)
+ {
+ assert (i < nloaded);
+
+ maps[i] = l;
+ l->l_idx = i;
+ ++i;
+
+ /* Bump l_direct_opencount of all objects so that they
+ are not dlclose()ed from underneath us. */
+ ++l->l_direct_opencount;
+ }
+ assert (ns != LM_ID_BASE || i == nloaded);
+ assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
+ unsigned int nmaps = i;
+
+ /* Now we have to do the sorting. */
+ _dl_sort_fini (maps, nmaps, NULL, ns);
+
+ /* We do not rely on the linked list of loaded object anymore
+ from this point on. We have our own list here (maps). The
+ various members of this list cannot vanish since the open
+ count is too high and will be decremented in this loop. So
+ we release the lock so that some code which might be called
+ from a destructor can directly or indirectly access the
+ lock. */
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+ /* 'maps' now contains the objects in the right order. Now
+ call the destructors. We have to process this array from
+ the front. */
+ for (i = 0; i < nmaps; ++i)
+ {
+ struct link_map *l = maps[i];
+
+ if (l->l_init_called)
+ {
+ /* Make sure nothing happens if we are called twice. */
+ l->l_init_called = 0;
+
+ /* Is there a destructor function? */
+ if (l->l_info[DT_FINI_ARRAY] != NULL
+ || l->l_info[DT_FINI] != NULL)
+ {
+ /* When debugging print a message first. */
+ if (__builtin_expect (GLRO(dl_debug_mask)
+ & DL_DEBUG_IMPCALLS, 0))
+ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
+ DSO_FILENAME (l->l_name),
+ ns);
+
+ /* First see whether an array is given. */
+ if (l->l_info[DT_FINI_ARRAY] != NULL)
+ {
+ ElfW(Addr) *array =
+ (ElfW(Addr) *) (l->l_addr
+ + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
+ unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
+ / sizeof (ElfW(Addr)));
+ while (i-- > 0)
+ ((fini_t) array[i]) ();
+ }
+
+ /* Next try the old-style destructor. */
+ if (l->l_info[DT_FINI] != NULL)
+ DL_CALL_DT_FINI
+ (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr);
+ }
+
+#ifdef SHARED
+ /* Auditing checkpoint: another object closed. */
+ if (!do_audit && __builtin_expect (GLRO(dl_naudit) > 0, 0))
+ {
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->objclose != NULL)
+ /* Return value is ignored. */
+ (void) afct->objclose (&l->l_audit[cnt].cookie);
+
+ afct = afct->next;
+ }
+ }
+#endif
+ }
+
+ /* Correct the previous increment. */
+ --l->l_direct_opencount;
+ }
+ }
+ }
+
+#ifdef SHARED
+ if (! do_audit && GLRO(dl_naudit) > 0)
+ {
+ do_audit = 1;
+ goto again;
+ }
+
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
+ _dl_debug_printf ("\nruntime linker statistics:\n"
+ " final number of relocations: %lu\n"
+ "final number of relocations from cache: %lu\n",
+ GL(dl_num_relocations),
+ GL(dl_num_cache_relocations));
+#endif
+}
diff --git a/REORG.TODO/elf/dl-fptr.c b/REORG.TODO/elf/dl-fptr.c
new file mode 100644
index 0000000000..bf8ae43b51
--- /dev/null
+++ b/REORG.TODO/elf/dl-fptr.c
@@ -0,0 +1,322 @@
+/* Manage function descriptors. Generic version.
+ Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <libintl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <link.h>
+#include <ldsodefs.h>
+#include <elf/dynamic-link.h>
+#include <dl-fptr.h>
+#include <dl-unmap-segments.h>
+#include <atomic.h>
+
+#ifndef ELF_MACHINE_BOOT_FPTR_TABLE_LEN
+/* ELF_MACHINE_BOOT_FPTR_TABLE_LEN should be greater than the number of
+ dynamic symbols in ld.so. */
+# define ELF_MACHINE_BOOT_FPTR_TABLE_LEN 256
+#endif
+
+#ifndef ELF_MACHINE_LOAD_ADDRESS
+# error "ELF_MACHINE_LOAD_ADDRESS is not defined."
+#endif
+
+#ifndef COMPARE_AND_SWAP
+# define COMPARE_AND_SWAP(ptr, old, new) \
+ (catomic_compare_and_exchange_bool_acq (ptr, new, old) == 0)
+#endif
+
+ElfW(Addr) _dl_boot_fptr_table [ELF_MACHINE_BOOT_FPTR_TABLE_LEN];
+
+static struct local
+ {
+ struct fdesc_table *root;
+ struct fdesc *free_list;
+ unsigned int npages; /* # of pages to allocate */
+ /* the next to members MUST be consecutive! */
+ struct fdesc_table boot_table;
+ struct fdesc boot_fdescs[1024];
+ }
+local =
+ {
+ .root = &local.boot_table,
+ .npages = 2,
+ .boot_table =
+ {
+ .len = sizeof (local.boot_fdescs) / sizeof (local.boot_fdescs[0]),
+ .first_unused = 0
+ }
+ };
+
+/* Create a new fdesc table and return a pointer to the first fdesc
+ entry. The fdesc lock must have been acquired already. */
+
+static struct fdesc_table *
+new_fdesc_table (struct local *l, size_t *size)
+{
+ size_t old_npages = l->npages;
+ size_t new_npages = old_npages + old_npages;
+ struct fdesc_table *new_table;
+
+ /* If someone has just created a new table, we return NULL to tell
+ the caller to use the new table. */
+ if (! COMPARE_AND_SWAP (&l->npages, old_npages, new_npages))
+ return (struct fdesc_table *) NULL;
+
+ *size = old_npages * GLRO(dl_pagesize);
+ new_table = __mmap (NULL, *size,
+ PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+ if (new_table == MAP_FAILED)
+ _dl_signal_error (errno, NULL, NULL,
+ N_("cannot map pages for fdesc table"));
+
+ new_table->len
+ = (*size - sizeof (*new_table)) / sizeof (struct fdesc);
+ new_table->first_unused = 1;
+ return new_table;
+}
+
+
+static ElfW(Addr)
+make_fdesc (ElfW(Addr) ip, ElfW(Addr) gp)
+{
+ struct fdesc *fdesc = NULL;
+ struct fdesc_table *root;
+ unsigned int old;
+ struct local *l;
+
+ ELF_MACHINE_LOAD_ADDRESS (l, local);
+
+ retry:
+ root = l->root;
+ while (1)
+ {
+ old = root->first_unused;
+ if (old >= root->len)
+ break;
+ else if (COMPARE_AND_SWAP (&root->first_unused, old, old + 1))
+ {
+ fdesc = &root->fdesc[old];
+ goto install;
+ }
+ }
+
+ if (l->free_list)
+ {
+ /* Get it from free-list. */
+ do
+ {
+ fdesc = l->free_list;
+ if (fdesc == NULL)
+ goto retry;
+ }
+ while (! COMPARE_AND_SWAP ((ElfW(Addr) *) &l->free_list,
+ (ElfW(Addr)) fdesc, fdesc->ip));
+ }
+ else
+ {
+ /* Create a new fdesc table. */
+ size_t size;
+ struct fdesc_table *new_table = new_fdesc_table (l, &size);
+
+ if (new_table == NULL)
+ goto retry;
+
+ new_table->next = root;
+ if (! COMPARE_AND_SWAP ((ElfW(Addr) *) &l->root,
+ (ElfW(Addr)) root,
+ (ElfW(Addr)) new_table))
+ {
+ /* Someone has just installed a new table. Return NULL to
+ tell the caller to use the new table. */
+ __munmap (new_table, size);
+ goto retry;
+ }
+
+ /* Note that the first entry was reserved while allocating the
+ memory for the new page. */
+ fdesc = &new_table->fdesc[0];
+ }
+
+ install:
+ fdesc->ip = ip;
+ fdesc->gp = gp;
+
+ return (ElfW(Addr)) fdesc;
+}
+
+
+static inline ElfW(Addr) * __attribute__ ((always_inline))
+make_fptr_table (struct link_map *map)
+{
+ const ElfW(Sym) *symtab
+ = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+ ElfW(Addr) *fptr_table;
+ size_t size;
+ size_t len;
+
+ /* XXX Apparently the only way to find out the size of the dynamic
+ symbol section is to assume that the string table follows right
+ afterwards... */
+ len = ((strtab - (char *) symtab)
+ / map->l_info[DT_SYMENT]->d_un.d_val);
+ size = ((len * sizeof (fptr_table[0]) + GLRO(dl_pagesize) - 1)
+ & -GLRO(dl_pagesize));
+ /* XXX We don't support here in the moment systems without MAP_ANON.
+ There probably are none for IA-64. In case this is proven wrong
+ we will have to open /dev/null here and use the file descriptor
+ instead of the hard-coded -1. */
+ fptr_table = __mmap (NULL, size,
+ PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
+ -1, 0);
+ if (fptr_table == MAP_FAILED)
+ _dl_signal_error (errno, NULL, NULL,
+ N_("cannot map pages for fptr table"));
+
+ if (COMPARE_AND_SWAP ((ElfW(Addr) *) &map->l_mach.fptr_table,
+ (ElfW(Addr)) NULL, (ElfW(Addr)) fptr_table))
+ map->l_mach.fptr_table_len = len;
+ else
+ __munmap (fptr_table, len * sizeof (fptr_table[0]));
+
+ return map->l_mach.fptr_table;
+}
+
+
+ElfW(Addr)
+_dl_make_fptr (struct link_map *map, const ElfW(Sym) *sym,
+ ElfW(Addr) ip)
+{
+ ElfW(Addr) *ftab = map->l_mach.fptr_table;
+ const ElfW(Sym) *symtab;
+ Elf_Symndx symidx;
+ struct local *l;
+
+ if (__glibc_unlikely (ftab == NULL))
+ ftab = make_fptr_table (map);
+
+ symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+ symidx = sym - symtab;
+
+ if (symidx >= map->l_mach.fptr_table_len)
+ _dl_signal_error (0, NULL, NULL,
+ N_("internal error: symidx out of range of fptr table"));
+
+ while (ftab[symidx] == 0)
+ {
+ /* GOT has already been relocated in elf_get_dynamic_info -
+ don't try to relocate it again. */
+ ElfW(Addr) fdesc
+ = make_fdesc (ip, map->l_info[DT_PLTGOT]->d_un.d_ptr);
+
+ if (__builtin_expect (COMPARE_AND_SWAP (&ftab[symidx], (ElfW(Addr)) NULL,
+ fdesc), 1))
+ {
+ /* Noone has updated the entry and the new function
+ descriptor has been installed. */
+#if 0
+ const char *strtab
+ = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+
+ ELF_MACHINE_LOAD_ADDRESS (l, local);
+ if (l->root != &l->boot_table
+ || l->boot_table.first_unused > 20)
+ _dl_debug_printf ("created fdesc symbol `%s' at %lx\n",
+ strtab + sym->st_name, ftab[symidx]);
+#endif
+ break;
+ }
+ else
+ {
+ /* We created a duplicated function descriptor. We put it on
+ free-list. */
+ struct fdesc *f = (struct fdesc *) fdesc;
+
+ ELF_MACHINE_LOAD_ADDRESS (l, local);
+
+ do
+ f->ip = (ElfW(Addr)) l->free_list;
+ while (! COMPARE_AND_SWAP ((ElfW(Addr) *) &l->free_list,
+ f->ip, fdesc));
+ }
+ }
+
+ return ftab[symidx];
+}
+
+
+void
+_dl_unmap (struct link_map *map)
+{
+ ElfW(Addr) *ftab = map->l_mach.fptr_table;
+ struct fdesc *head = NULL, *tail = NULL;
+ size_t i;
+
+ _dl_unmap_segments (map);
+
+ if (ftab == NULL)
+ return;
+
+ /* String together the fdesc structures that are being freed. */
+ for (i = 0; i < map->l_mach.fptr_table_len; ++i)
+ {
+ if (ftab[i])
+ {
+ *(struct fdesc **) ftab[i] = head;
+ head = (struct fdesc *) ftab[i];
+ if (tail == NULL)
+ tail = head;
+ }
+ }
+
+ /* Prepend the new list to the free_list: */
+ if (tail)
+ do
+ tail->ip = (ElfW(Addr)) local.free_list;
+ while (! COMPARE_AND_SWAP ((ElfW(Addr) *) &local.free_list,
+ tail->ip, (ElfW(Addr)) head));
+
+ __munmap (ftab, (map->l_mach.fptr_table_len
+ * sizeof (map->l_mach.fptr_table[0])));
+
+ map->l_mach.fptr_table = NULL;
+}
+
+
+ElfW(Addr)
+_dl_lookup_address (const void *address)
+{
+ ElfW(Addr) addr = (ElfW(Addr)) address;
+ struct fdesc_table *t;
+ unsigned long int i;
+
+ for (t = local.root; t != NULL; t = t->next)
+ {
+ i = (struct fdesc *) addr - &t->fdesc[0];
+ if (i < t->first_unused && addr == (ElfW(Addr)) &t->fdesc[i])
+ {
+ addr = t->fdesc[i].ip;
+ break;
+ }
+ }
+
+ return addr;
+}
diff --git a/REORG.TODO/elf/dl-hwcaps.c b/REORG.TODO/elf/dl-hwcaps.c
new file mode 100644
index 0000000000..ac50fd2c38
--- /dev/null
+++ b/REORG.TODO/elf/dl-hwcaps.c
@@ -0,0 +1,297 @@
+/* Hardware capability support for run-time dynamic loader.
+ Copyright (C) 2012-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <elf.h>
+#include <errno.h>
+#include <libintl.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+
+#include <dl-procinfo.h>
+#include <dl-hwcaps.h>
+
+#ifdef _DL_FIRST_PLATFORM
+# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
+#else
+# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT
+#endif
+
+/* Return an array of useful/necessary hardware capability names. */
+const struct r_strlenpair *
+internal_function
+_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
+ size_t *max_capstrlen)
+{
+ uint64_t hwcap_mask = GET_HWCAP_MASK();
+ /* Determine how many important bits are set. */
+ uint64_t masked = GLRO(dl_hwcap) & hwcap_mask;
+ size_t cnt = platform != NULL;
+ size_t n, m;
+ size_t total;
+ struct r_strlenpair *result;
+ struct r_strlenpair *rp;
+ char *cp;
+
+ /* Count the number of bits set in the masked value. */
+ for (n = 0; (~((1ULL << n) - 1) & masked) != 0; ++n)
+ if ((masked & (1ULL << n)) != 0)
+ ++cnt;
+
+#ifdef NEED_DL_SYSINFO_DSO
+ /* The system-supplied DSO can contain a note of type 2, vendor "GNU".
+ This gives us a list of names to treat as fake hwcap bits. */
+
+ const char *dsocaps = NULL;
+ size_t dsocapslen = 0;
+ if (GLRO(dl_sysinfo_map) != NULL)
+ {
+ const ElfW(Phdr) *const phdr = GLRO(dl_sysinfo_map)->l_phdr;
+ const ElfW(Word) phnum = GLRO(dl_sysinfo_map)->l_phnum;
+ for (uint_fast16_t i = 0; i < phnum; ++i)
+ if (phdr[i].p_type == PT_NOTE)
+ {
+ const ElfW(Addr) start = (phdr[i].p_vaddr
+ + GLRO(dl_sysinfo_map)->l_addr);
+ /* The standard ELF note layout is exactly as the anonymous struct.
+ The next element is a variable length vendor name of length
+ VENDORLEN (with a real length rounded to ElfW(Word)), followed
+ by the data of length DATALEN (with a real length rounded to
+ ElfW(Word)). */
+ const struct
+ {
+ ElfW(Word) vendorlen;
+ ElfW(Word) datalen;
+ ElfW(Word) type;
+ } *note = (const void *) start;
+ while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz)
+ {
+#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
+ /* The layout of the type 2, vendor "GNU" note is as follows:
+ .long <Number of capabilities enabled by this note>
+ .long <Capabilities mask> (as mask >> _DL_FIRST_EXTRA).
+ .byte <The bit number for the next capability>
+ .asciz <The name of the capability>. */
+ if (note->type == NT_GNU_HWCAP
+ && note->vendorlen == sizeof "GNU"
+ && !memcmp ((note + 1), "GNU", sizeof "GNU")
+ && note->datalen > 2 * sizeof (ElfW(Word)) + 2)
+ {
+ const ElfW(Word) *p = ((const void *) (note + 1)
+ + ROUND (sizeof "GNU"));
+ cnt += *p++;
+ ++p; /* Skip mask word. */
+ dsocaps = (const char *) p; /* Pseudo-string "<b>name" */
+ dsocapslen = note->datalen - sizeof *p * 2;
+ break;
+ }
+ note = ((const void *) (note + 1)
+ + ROUND (note->vendorlen) + ROUND (note->datalen));
+#undef ROUND
+ }
+ if (dsocaps != NULL)
+ break;
+ }
+ }
+#endif
+
+ /* For TLS enabled builds always add 'tls'. */
+ ++cnt;
+
+ /* Create temporary data structure to generate result table. */
+ struct r_strlenpair temp[cnt];
+ m = 0;
+#ifdef NEED_DL_SYSINFO_DSO
+ if (dsocaps != NULL)
+ {
+ /* dsocaps points to the .asciz string, and -1 points to the mask
+ .long just before the string. */
+ const ElfW(Word) mask = ((const ElfW(Word) *) dsocaps)[-1];
+ GLRO(dl_hwcap) |= (uint64_t) mask << _DL_FIRST_EXTRA;
+ /* Note that we add the dsocaps to the set already chosen by the
+ LD_HWCAP_MASK environment variable (or default HWCAP_IMPORTANT).
+ So there is no way to request ignoring an OS-supplied dsocap
+ string and bit like you can ignore an OS-supplied HWCAP bit. */
+ hwcap_mask |= (uint64_t) mask << _DL_FIRST_EXTRA;
+#if HAVE_TUNABLES
+ TUNABLE_SET (glibc, tune, hwcap_mask, uint64_t, hwcap_mask);
+#else
+ GLRO(dl_hwcap_mask) = hwcap_mask;
+#endif
+ size_t len;
+ for (const char *p = dsocaps; p < dsocaps + dsocapslen; p += len + 1)
+ {
+ uint_fast8_t bit = *p++;
+ len = strlen (p);
+
+ /* Skip entries that are not enabled in the mask word. */
+ if (__glibc_likely (mask & ((ElfW(Word)) 1 << bit)))
+ {
+ temp[m].str = p;
+ temp[m].len = len;
+ ++m;
+ }
+ else
+ --cnt;
+ }
+ }
+#endif
+ for (n = 0; masked != 0; ++n)
+ if ((masked & (1ULL << n)) != 0)
+ {
+ temp[m].str = _dl_hwcap_string (n);
+ temp[m].len = strlen (temp[m].str);
+ masked ^= 1ULL << n;
+ ++m;
+ }
+ if (platform != NULL)
+ {
+ temp[m].str = platform;
+ temp[m].len = platform_len;
+ ++m;
+ }
+
+ temp[m].str = "tls";
+ temp[m].len = 3;
+ ++m;
+
+ assert (m == cnt);
+
+ /* Determine the total size of all strings together. */
+ if (cnt == 1)
+ total = temp[0].len + 1;
+ else
+ {
+ total = temp[0].len + temp[cnt - 1].len + 2;
+ if (cnt > 2)
+ {
+ total <<= 1;
+ for (n = 1; n + 1 < cnt; ++n)
+ total += temp[n].len + 1;
+ if (cnt > 3
+ && (cnt >= sizeof (size_t) * 8
+ || total + (sizeof (*result) << 3)
+ >= (1UL << (sizeof (size_t) * 8 - cnt + 3))))
+ _dl_signal_error (ENOMEM, NULL, NULL,
+ N_("cannot create capability list"));
+
+ total <<= cnt - 3;
+ }
+ }
+
+ /* The result structure: we use a very compressed way to store the
+ various combinations of capability names. */
+ *sz = 1 << cnt;
+ result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total);
+ if (result == NULL)
+ _dl_signal_error (ENOMEM, NULL, NULL,
+ N_("cannot create capability list"));
+
+ if (cnt == 1)
+ {
+ result[0].str = (char *) (result + *sz);
+ result[0].len = temp[0].len + 1;
+ result[1].str = (char *) (result + *sz);
+ result[1].len = 0;
+ cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len);
+ *cp = '/';
+ *sz = 2;
+ *max_capstrlen = result[0].len;
+
+ return result;
+ }
+
+ /* Fill in the information. This follows the following scheme
+ (indices from TEMP for four strings):
+ entry #0: 0, 1, 2, 3 binary: 1111
+ #1: 0, 1, 3 1101
+ #2: 0, 2, 3 1011
+ #3: 0, 3 1001
+ This allows the representation of all possible combinations of
+ capability names in the string. First generate the strings. */
+ result[1].str = result[0].str = cp = (char *) (result + *sz);
+#define add(idx) \
+ cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
+ if (cnt == 2)
+ {
+ add (1);
+ add (0);
+ }
+ else
+ {
+ n = 1 << (cnt - 1);
+ do
+ {
+ n -= 2;
+
+ /* We always add the last string. */
+ add (cnt - 1);
+
+ /* Add the strings which have the bit set in N. */
+ for (m = cnt - 2; m > 0; --m)
+ if ((n & (1 << m)) != 0)
+ add (m);
+
+ /* Always add the first string. */
+ add (0);
+ }
+ while (n != 0);
+ }
+#undef add
+
+ /* Now we are ready to install the string pointers and length. */
+ for (n = 0; n < (1UL << cnt); ++n)
+ result[n].len = 0;
+ n = cnt;
+ do
+ {
+ size_t mask = 1 << --n;
+
+ rp = result;
+ for (m = 1 << cnt; m > 0; ++rp)
+ if ((--m & mask) != 0)
+ rp->len += temp[n].len + 1;
+ }
+ while (n != 0);
+
+ /* The first half of the strings all include the first string. */
+ n = (1 << cnt) - 2;
+ rp = &result[2];
+ while (n != (1UL << (cnt - 1)))
+ {
+ if ((--n & 1) != 0)
+ rp[0].str = rp[-2].str + rp[-2].len;
+ else
+ rp[0].str = rp[-1].str;
+ ++rp;
+ }
+
+ /* The second half starts right after the first part of the string of
+ the corresponding entry in the first half. */
+ do
+ {
+ rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1;
+ ++rp;
+ }
+ while (--n != 0);
+
+ /* The maximum string length. */
+ *max_capstrlen = result[0].len;
+
+ return result;
+}
diff --git a/REORG.TODO/elf/dl-hwcaps.h b/REORG.TODO/elf/dl-hwcaps.h
new file mode 100644
index 0000000000..2c4fa3db02
--- /dev/null
+++ b/REORG.TODO/elf/dl-hwcaps.h
@@ -0,0 +1,30 @@
+/* Hardware capability support for run-time dynamic loader.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <elf/dl-tunables.h>
+
+#if HAVE_TUNABLES
+# define GET_HWCAP_MASK() TUNABLE_GET (glibc, tune, hwcap_mask, uint64_t, NULL)
+#else
+# ifdef SHARED
+# define GET_HWCAP_MASK() GLRO(dl_hwcap_mask)
+# else
+/* HWCAP_MASK is ignored in static binaries when built without tunables. */
+# define GET_HWCAP_MASK() (0)
+# endif
+#endif
diff --git a/REORG.TODO/elf/dl-init.c b/REORG.TODO/elf/dl-init.c
new file mode 100644
index 0000000000..5c5f3de365
--- /dev/null
+++ b/REORG.TODO/elf/dl-init.c
@@ -0,0 +1,126 @@
+/* Run initializers for newly loaded objects.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stddef.h>
+#include <ldsodefs.h>
+
+
+/* Type of the initializer. */
+typedef void (*init_t) (int, char **, char **);
+
+
+static void
+call_init (struct link_map *l, int argc, char **argv, char **env)
+{
+ if (l->l_init_called)
+ /* This object is all done. */
+ return;
+
+ /* Avoid handling this constructor again in case we have a circular
+ dependency. */
+ l->l_init_called = 1;
+
+ /* Check for object which constructors we do not run here. */
+ if (__builtin_expect (l->l_name[0], 'a') == '\0'
+ && l->l_type == lt_executable)
+ return;
+
+ /* Are there any constructors? */
+ if (l->l_info[DT_INIT] == NULL
+ && __builtin_expect (l->l_info[DT_INIT_ARRAY] == NULL, 1))
+ return;
+
+ /* Print a debug message if wanted. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
+ _dl_debug_printf ("\ncalling init: %s\n\n",
+ DSO_FILENAME (l->l_name));
+
+ /* Now run the local constructors. There are two forms of them:
+ - the one named by DT_INIT
+ - the others in the DT_INIT_ARRAY.
+ */
+ if (l->l_info[DT_INIT] != NULL)
+ DL_CALL_DT_INIT(l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr, argc, argv, env);
+
+ /* Next see whether there is an array with initialization functions. */
+ ElfW(Dyn) *init_array = l->l_info[DT_INIT_ARRAY];
+ if (init_array != NULL)
+ {
+ unsigned int j;
+ unsigned int jm;
+ ElfW(Addr) *addrs;
+
+ jm = l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr));
+
+ addrs = (ElfW(Addr) *) (init_array->d_un.d_ptr + l->l_addr);
+ for (j = 0; j < jm; ++j)
+ ((init_t) addrs[j]) (argc, argv, env);
+ }
+}
+
+
+void
+internal_function
+_dl_init (struct link_map *main_map, int argc, char **argv, char **env)
+{
+ ElfW(Dyn) *preinit_array = main_map->l_info[DT_PREINIT_ARRAY];
+ ElfW(Dyn) *preinit_array_size = main_map->l_info[DT_PREINIT_ARRAYSZ];
+ unsigned int i;
+
+ if (__glibc_unlikely (GL(dl_initfirst) != NULL))
+ {
+ call_init (GL(dl_initfirst), argc, argv, env);
+ GL(dl_initfirst) = NULL;
+ }
+
+ /* Don't do anything if there is no preinit array. */
+ if (__builtin_expect (preinit_array != NULL, 0)
+ && preinit_array_size != NULL
+ && (i = preinit_array_size->d_un.d_val / sizeof (ElfW(Addr))) > 0)
+ {
+ ElfW(Addr) *addrs;
+ unsigned int cnt;
+
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
+ _dl_debug_printf ("\ncalling preinit: %s\n\n",
+ DSO_FILENAME (main_map->l_name));
+
+ addrs = (ElfW(Addr) *) (preinit_array->d_un.d_ptr + main_map->l_addr);
+ for (cnt = 0; cnt < i; ++cnt)
+ ((init_t) addrs[cnt]) (argc, argv, env);
+ }
+
+ /* Stupid users forced the ELF specification to be changed. It now
+ says that the dynamic loader is responsible for determining the
+ order in which the constructors have to run. The constructors
+ for all dependencies of an object must run before the constructor
+ for the object itself. Circular dependencies are left unspecified.
+
+ This is highly questionable since it puts the burden on the dynamic
+ loader which has to find the dependencies at runtime instead of
+ letting the user do it right. Stupidity rules! */
+
+ i = main_map->l_searchlist.r_nlist;
+ while (i-- > 0)
+ call_init (main_map->l_initfini[i], argc, argv, env);
+
+#ifndef HAVE_INLINED_SYSCALLS
+ /* Finished starting up. */
+ _dl_starting_up = 0;
+#endif
+}
diff --git a/REORG.TODO/elf/dl-iteratephdr.c b/REORG.TODO/elf/dl-iteratephdr.c
new file mode 100644
index 0000000000..ddd5bde831
--- /dev/null
+++ b/REORG.TODO/elf/dl-iteratephdr.c
@@ -0,0 +1,89 @@
+/* Get loaded objects program headers.
+ Copyright (C) 2001-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <ldsodefs.h>
+#include <stddef.h>
+#include <libc-lock.h>
+
+static void
+cancel_handler (void *arg __attribute__((unused)))
+{
+ __rtld_lock_unlock_recursive (GL(dl_load_write_lock));
+}
+
+hidden_proto (__dl_iterate_phdr)
+int
+__dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
+ size_t size, void *data), void *data)
+{
+ struct link_map *l;
+ struct dl_phdr_info info;
+ int ret = 0;
+
+ /* Make sure nobody modifies the list of loaded objects. */
+ __rtld_lock_lock_recursive (GL(dl_load_write_lock));
+ __libc_cleanup_push (cancel_handler, NULL);
+
+ /* We have to determine the namespace of the caller since this determines
+ which namespace is reported. */
+ size_t nloaded = GL(dl_ns)[0]._ns_nloaded;
+ Lmid_t ns = 0;
+#ifdef SHARED
+ const void *caller = RETURN_ADDRESS (0);
+ for (Lmid_t cnt = GL(dl_nns) - 1; cnt > 0; --cnt)
+ for (struct link_map *l = GL(dl_ns)[cnt]._ns_loaded; l; l = l->l_next)
+ {
+ /* We have to count the total number of loaded objects. */
+ nloaded += GL(dl_ns)[cnt]._ns_nloaded;
+
+ if (caller >= (const void *) l->l_map_start
+ && caller < (const void *) l->l_map_end
+ && (l->l_contiguous
+ || _dl_addr_inside_object (l, (ElfW(Addr)) caller)))
+ ns = cnt;
+ }
+#endif
+
+ for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
+ {
+ info.dlpi_addr = l->l_real->l_addr;
+ info.dlpi_name = l->l_real->l_name;
+ info.dlpi_phdr = l->l_real->l_phdr;
+ info.dlpi_phnum = l->l_real->l_phnum;
+ info.dlpi_adds = GL(dl_load_adds);
+ info.dlpi_subs = GL(dl_load_adds) - nloaded;
+ info.dlpi_tls_data = NULL;
+ info.dlpi_tls_modid = l->l_real->l_tls_modid;
+ if (info.dlpi_tls_modid != 0)
+ info.dlpi_tls_data = GLRO(dl_tls_get_addr_soft) (l->l_real);
+ ret = callback (&info, sizeof (struct dl_phdr_info), data);
+ if (ret)
+ break;
+ }
+
+ /* Release the lock. */
+ __libc_cleanup_pop (0);
+ __rtld_lock_unlock_recursive (GL(dl_load_write_lock));
+
+ return ret;
+}
+hidden_def (__dl_iterate_phdr)
+
+weak_alias (__dl_iterate_phdr, dl_iterate_phdr);
diff --git a/REORG.TODO/elf/dl-libc.c b/REORG.TODO/elf/dl-libc.c
new file mode 100644
index 0000000000..9fdc8b1130
--- /dev/null
+++ b/REORG.TODO/elf/dl-libc.c
@@ -0,0 +1,330 @@
+/* Handle loading and unloading shared objects for internal libc purposes.
+ Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Zack Weinberg <zack@rabi.columbia.edu>, 1999.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <ldsodefs.h>
+
+extern int __libc_argc attribute_hidden;
+extern char **__libc_argv attribute_hidden;
+
+extern char **__environ;
+
+/* The purpose of this file is to provide wrappers around the dynamic
+ linker error mechanism (similar to dlopen() et al in libdl) which
+ are usable from within libc. Generally we want to throw away the
+ string that dlerror() would return and just pass back a null pointer
+ for errors. This also lets the rest of libc not know about the error
+ handling mechanism.
+
+ Much of this code came from gconv_dl.c with slight modifications. */
+
+static int
+internal_function
+dlerror_run (void (*operate) (void *), void *args)
+{
+ const char *objname;
+ const char *last_errstring = NULL;
+ bool malloced;
+
+ int result = (_dl_catch_error (&objname, &last_errstring, &malloced,
+ operate, args)
+ ?: last_errstring != NULL);
+
+ if (result && malloced)
+ free ((char *) last_errstring);
+
+ return result;
+}
+
+/* These functions are called by dlerror_run... */
+
+struct do_dlopen_args
+{
+ /* Argument to do_dlopen. */
+ const char *name;
+ /* Opening mode. */
+ int mode;
+ /* This is the caller of the dlopen() function. */
+ const void *caller_dlopen;
+
+ /* Return from do_dlopen. */
+ struct link_map *map;
+};
+
+struct do_dlsym_args
+{
+ /* Arguments to do_dlsym. */
+ struct link_map *map;
+ const char *name;
+
+ /* Return values of do_dlsym. */
+ lookup_t loadbase;
+ const ElfW(Sym) *ref;
+};
+
+static void
+do_dlopen (void *ptr)
+{
+ struct do_dlopen_args *args = (struct do_dlopen_args *) ptr;
+ /* Open and relocate the shared object. */
+ args->map = GLRO(dl_open) (args->name, args->mode, args->caller_dlopen,
+ __LM_ID_CALLER, __libc_argc, __libc_argv,
+ __environ);
+}
+
+static void
+do_dlsym (void *ptr)
+{
+ struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
+ args->ref = NULL;
+ args->loadbase = GLRO(dl_lookup_symbol_x) (args->name, args->map, &args->ref,
+ args->map->l_local_scope, NULL, 0,
+ DL_LOOKUP_RETURN_NEWEST, NULL);
+}
+
+static void
+do_dlclose (void *ptr)
+{
+ GLRO(dl_close) ((struct link_map *) ptr);
+}
+
+/* This code is to support __libc_dlopen from __libc_dlopen'ed shared
+ libraries. We need to ensure the statically linked __libc_dlopen
+ etc. functions are used instead of the dynamically loaded. */
+struct dl_open_hook
+{
+ void *(*dlopen_mode) (const char *name, int mode);
+ void *(*dlsym) (void *map, const char *name);
+ int (*dlclose) (void *map);
+};
+
+#ifdef SHARED
+extern struct dl_open_hook *_dl_open_hook;
+libc_hidden_proto (_dl_open_hook);
+struct dl_open_hook *_dl_open_hook __attribute__ ((nocommon));
+libc_hidden_data_def (_dl_open_hook);
+#else
+static void
+do_dlsym_private (void *ptr)
+{
+ lookup_t l;
+ struct r_found_version vers;
+ vers.name = "GLIBC_PRIVATE";
+ vers.hidden = 1;
+ /* vers.hash = _dl_elf_hash (vers.name); */
+ vers.hash = 0x0963cf85;
+ vers.filename = NULL;
+
+ struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
+ args->ref = NULL;
+ l = GLRO(dl_lookup_symbol_x) (args->name, args->map, &args->ref,
+ args->map->l_scope, &vers, 0, 0, NULL);
+ args->loadbase = l;
+}
+
+static struct dl_open_hook _dl_open_hook =
+ {
+ .dlopen_mode = __libc_dlopen_mode,
+ .dlsym = __libc_dlsym,
+ .dlclose = __libc_dlclose
+ };
+#endif
+
+/* ... and these functions call dlerror_run. */
+
+void *
+__libc_dlopen_mode (const char *name, int mode)
+{
+ struct do_dlopen_args args;
+ args.name = name;
+ args.mode = mode;
+ args.caller_dlopen = RETURN_ADDRESS (0);
+
+#ifdef SHARED
+ if (__glibc_unlikely (_dl_open_hook != NULL))
+ return _dl_open_hook->dlopen_mode (name, mode);
+ return (dlerror_run (do_dlopen, &args) ? NULL : (void *) args.map);
+#else
+ if (dlerror_run (do_dlopen, &args))
+ return NULL;
+
+ __libc_register_dl_open_hook (args.map);
+ __libc_register_dlfcn_hook (args.map);
+ return (void *) args.map;
+#endif
+}
+libc_hidden_def (__libc_dlopen_mode)
+
+#ifndef SHARED
+void *
+__libc_dlsym_private (struct link_map *map, const char *name)
+{
+ struct do_dlsym_args sargs;
+ sargs.map = map;
+ sargs.name = name;
+
+ if (! dlerror_run (do_dlsym_private, &sargs))
+ return DL_SYMBOL_ADDRESS (sargs.loadbase, sargs.ref);
+ return NULL;
+}
+
+void
+__libc_register_dl_open_hook (struct link_map *map)
+{
+ struct dl_open_hook **hook;
+
+ hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook");
+ if (hook != NULL)
+ *hook = &_dl_open_hook;
+}
+#endif
+
+void *
+__libc_dlsym (void *map, const char *name)
+{
+ struct do_dlsym_args args;
+ args.map = map;
+ args.name = name;
+
+#ifdef SHARED
+ if (__glibc_unlikely (_dl_open_hook != NULL))
+ return _dl_open_hook->dlsym (map, name);
+#endif
+ return (dlerror_run (do_dlsym, &args) ? NULL
+ : (void *) (DL_SYMBOL_ADDRESS (args.loadbase, args.ref)));
+}
+libc_hidden_def (__libc_dlsym)
+
+int
+__libc_dlclose (void *map)
+{
+#ifdef SHARED
+ if (__glibc_unlikely (_dl_open_hook != NULL))
+ return _dl_open_hook->dlclose (map);
+#endif
+ return dlerror_run (do_dlclose, map);
+}
+libc_hidden_def (__libc_dlclose)
+
+
+static bool __libc_freeres_fn_section
+free_slotinfo (struct dtv_slotinfo_list **elemp)
+{
+ size_t cnt;
+
+ if (*elemp == NULL)
+ /* Nothing here, all is removed (or there never was anything). */
+ return true;
+
+ if (!free_slotinfo (&(*elemp)->next))
+ /* We cannot free the entry. */
+ return false;
+
+ /* That cleared our next pointer for us. */
+
+ for (cnt = 0; cnt < (*elemp)->len; ++cnt)
+ if ((*elemp)->slotinfo[cnt].map != NULL)
+ /* Still used. */
+ return false;
+
+ /* We can remove the list element. */
+ free (*elemp);
+ *elemp = NULL;
+
+ return true;
+}
+
+
+libc_freeres_fn (free_mem)
+{
+ struct link_map *l;
+ struct r_search_path_elem *d;
+
+ /* Remove all search directories. */
+ d = GL(dl_all_dirs);
+ while (d != GLRO(dl_init_all_dirs))
+ {
+ struct r_search_path_elem *old = d;
+ d = d->next;
+ free (old);
+ }
+
+ for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
+ {
+ for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
+ {
+ struct libname_list *lnp = l->l_libname->next;
+
+ l->l_libname->next = NULL;
+
+ /* Remove all additional names added to the objects. */
+ while (lnp != NULL)
+ {
+ struct libname_list *old = lnp;
+ lnp = lnp->next;
+ if (! old->dont_free)
+ free (old);
+ }
+
+ /* Free the initfini dependency list. */
+ if (l->l_free_initfini)
+ free (l->l_initfini);
+ l->l_initfini = NULL;
+ }
+
+ if (__builtin_expect (GL(dl_ns)[ns]._ns_global_scope_alloc, 0) != 0
+ && (GL(dl_ns)[ns]._ns_main_searchlist->r_nlist
+ // XXX Check whether we need NS-specific initial_searchlist
+ == GLRO(dl_initial_searchlist).r_nlist))
+ {
+ /* All object dynamically loaded by the program are unloaded. Free
+ the memory allocated for the global scope variable. */
+ struct link_map **old = GL(dl_ns)[ns]._ns_main_searchlist->r_list;
+
+ /* Put the old map in. */
+ GL(dl_ns)[ns]._ns_main_searchlist->r_list
+ // XXX Check whether we need NS-specific initial_searchlist
+ = GLRO(dl_initial_searchlist).r_list;
+ /* Signal that the original map is used. */
+ GL(dl_ns)[ns]._ns_global_scope_alloc = 0;
+
+ /* Now free the old map. */
+ free (old);
+ }
+ }
+
+ /* Free the memory allocated for the dtv slotinfo array. We can do
+ this only if all modules which used this memory are unloaded. */
+#ifdef SHARED
+ if (GL(dl_initial_dtv) == NULL)
+ /* There was no initial TLS setup, it was set up later when
+ it used the normal malloc. */
+ free_slotinfo (&GL(dl_tls_dtv_slotinfo_list));
+ else
+#endif
+ /* The first element of the list does not have to be deallocated.
+ It was allocated in the dynamic linker (i.e., with a different
+ malloc), and in the static library it's in .bss space. */
+ free_slotinfo (&GL(dl_tls_dtv_slotinfo_list)->next);
+
+ void *scope_free_list = GL(dl_scope_free_list);
+ GL(dl_scope_free_list) = NULL;
+ free (scope_free_list);
+}
diff --git a/REORG.TODO/elf/dl-load.c b/REORG.TODO/elf/dl-load.c
new file mode 100644
index 0000000000..c1b6d4ba0f
--- /dev/null
+++ b/REORG.TODO/elf/dl-load.c
@@ -0,0 +1,2307 @@
+/* Map in a shared object's segments from the file.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <bits/wordsize.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "dynamic-link.h"
+#include <abi-tag.h>
+#include <stackinfo.h>
+#include <caller.h>
+#include <sysdep.h>
+#include <stap-probe.h>
+#include <libc-pointer-arith.h>
+
+#include <dl-dst.h>
+#include <dl-load.h>
+#include <dl-map-segments.h>
+#include <dl-unmap-segments.h>
+#include <dl-machine-reject-phdr.h>
+#include <dl-sysdep-open.h>
+
+
+#include <endian.h>
+#if BYTE_ORDER == BIG_ENDIAN
+# define byteorder ELFDATA2MSB
+#elif BYTE_ORDER == LITTLE_ENDIAN
+# define byteorder ELFDATA2LSB
+#else
+# error "Unknown BYTE_ORDER " BYTE_ORDER
+# define byteorder ELFDATANONE
+#endif
+
+#define STRING(x) __STRING (x)
+
+
+int __stack_prot attribute_hidden attribute_relro
+#if _STACK_GROWS_DOWN && defined PROT_GROWSDOWN
+ = PROT_GROWSDOWN;
+#elif _STACK_GROWS_UP && defined PROT_GROWSUP
+ = PROT_GROWSUP;
+#else
+ = 0;
+#endif
+
+
+/* Type for the buffer we put the ELF header and hopefully the program
+ header. This buffer does not really have to be too large. In most
+ cases the program header follows the ELF header directly. If this
+ is not the case all bets are off and we can make the header
+ arbitrarily large and still won't get it read. This means the only
+ question is how large are the ELF and program header combined. The
+ ELF header 32-bit files is 52 bytes long and in 64-bit files is 64
+ bytes long. Each program header entry is again 32 and 56 bytes
+ long respectively. I.e., even with a file which has 10 program
+ header entries we only have to read 372B/624B respectively. Add to
+ this a bit of margin for program notes and reading 512B and 832B
+ for 32-bit and 64-bit files respecitvely is enough. If this
+ heuristic should really fail for some file the code in
+ `_dl_map_object_from_fd' knows how to recover. */
+struct filebuf
+{
+ ssize_t len;
+#if __WORDSIZE == 32
+# define FILEBUF_SIZE 512
+#else
+# define FILEBUF_SIZE 832
+#endif
+ char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr)))));
+};
+
+/* This is the decomposed LD_LIBRARY_PATH search path. */
+static struct r_search_path_struct env_path_list attribute_relro;
+
+/* List of the hardware capabilities we might end up using. */
+static const struct r_strlenpair *capstr attribute_relro;
+static size_t ncapstr attribute_relro;
+static size_t max_capstrlen attribute_relro;
+
+
+/* Get the generated information about the trusted directories. */
+#include "trusted-dirs.h"
+
+static const char system_dirs[] = SYSTEM_DIRS;
+static const size_t system_dirs_len[] =
+{
+ SYSTEM_DIRS_LEN
+};
+#define nsystem_dirs_len \
+ (sizeof (system_dirs_len) / sizeof (system_dirs_len[0]))
+
+
+static bool
+is_trusted_path (const char *path, size_t len)
+{
+ const char *trun = system_dirs;
+
+ for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
+ {
+ if (len == system_dirs_len[idx] && memcmp (trun, path, len) == 0)
+ /* Found it. */
+ return true;
+
+ trun += system_dirs_len[idx] + 1;
+ }
+
+ return false;
+}
+
+
+static bool
+is_trusted_path_normalize (const char *path, size_t len)
+{
+ if (len == 0)
+ return false;
+
+ if (*path == ':')
+ {
+ ++path;
+ --len;
+ }
+
+ char *npath = (char *) alloca (len + 2);
+ char *wnp = npath;
+ while (*path != '\0')
+ {
+ if (path[0] == '/')
+ {
+ if (path[1] == '.')
+ {
+ if (path[2] == '.' && (path[3] == '/' || path[3] == '\0'))
+ {
+ while (wnp > npath && *--wnp != '/')
+ ;
+ path += 3;
+ continue;
+ }
+ else if (path[2] == '/' || path[2] == '\0')
+ {
+ path += 2;
+ continue;
+ }
+ }
+
+ if (wnp > npath && wnp[-1] == '/')
+ {
+ ++path;
+ continue;
+ }
+ }
+
+ *wnp++ = *path++;
+ }
+
+ if (wnp == npath || wnp[-1] != '/')
+ *wnp++ = '/';
+
+ const char *trun = system_dirs;
+
+ for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
+ {
+ if (wnp - npath >= system_dirs_len[idx]
+ && memcmp (trun, npath, system_dirs_len[idx]) == 0)
+ /* Found it. */
+ return true;
+
+ trun += system_dirs_len[idx] + 1;
+ }
+
+ return false;
+}
+
+
+static size_t
+is_dst (const char *start, const char *name, const char *str,
+ int is_path, int secure)
+{
+ size_t len;
+ bool is_curly = false;
+
+ if (name[0] == '{')
+ {
+ is_curly = true;
+ ++name;
+ }
+
+ len = 0;
+ while (name[len] == str[len] && name[len] != '\0')
+ ++len;
+
+ if (is_curly)
+ {
+ if (name[len] != '}')
+ return 0;
+
+ /* Point again at the beginning of the name. */
+ --name;
+ /* Skip over closing curly brace and adjust for the --name. */
+ len += 2;
+ }
+ else if (name[len] != '\0' && name[len] != '/'
+ && (!is_path || name[len] != ':'))
+ return 0;
+
+ if (__glibc_unlikely (secure)
+ && ((name[len] != '\0' && name[len] != '/'
+ && (!is_path || name[len] != ':'))
+ || (name != start + 1 && (!is_path || name[-2] != ':'))))
+ return 0;
+
+ return len;
+}
+
+
+size_t
+_dl_dst_count (const char *name, int is_path)
+{
+ const char *const start = name;
+ size_t cnt = 0;
+
+ do
+ {
+ size_t len;
+
+ /* $ORIGIN is not expanded for SUID/GUID programs (except if it
+ is $ORIGIN alone) and it must always appear first in path. */
+ ++name;
+ if ((len = is_dst (start, name, "ORIGIN", is_path,
+ __libc_enable_secure)) != 0
+ || (len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0
+ || (len = is_dst (start, name, "LIB", is_path, 0)) != 0)
+ ++cnt;
+
+ name = strchr (name + len, '$');
+ }
+ while (name != NULL);
+
+ return cnt;
+}
+
+
+char *
+_dl_dst_substitute (struct link_map *l, const char *name, char *result,
+ int is_path)
+{
+ const char *const start = name;
+
+ /* Now fill the result path. While copying over the string we keep
+ track of the start of the last path element. When we come across
+ a DST we copy over the value or (if the value is not available)
+ leave the entire path element out. */
+ char *wp = result;
+ char *last_elem = result;
+ bool check_for_trusted = false;
+
+ do
+ {
+ if (__glibc_unlikely (*name == '$'))
+ {
+ const char *repl = NULL;
+ size_t len;
+
+ ++name;
+ if ((len = is_dst (start, name, "ORIGIN", is_path,
+ __libc_enable_secure)) != 0)
+ {
+ repl = l->l_origin;
+ check_for_trusted = (__libc_enable_secure
+ && l->l_type == lt_executable);
+ }
+ else if ((len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0)
+ repl = GLRO(dl_platform);
+ else if ((len = is_dst (start, name, "LIB", is_path, 0)) != 0)
+ repl = DL_DST_LIB;
+
+ if (repl != NULL && repl != (const char *) -1)
+ {
+ wp = __stpcpy (wp, repl);
+ name += len;
+ }
+ else if (len > 1)
+ {
+ /* We cannot use this path element, the value of the
+ replacement is unknown. */
+ wp = last_elem;
+ name += len;
+ while (*name != '\0' && (!is_path || *name != ':'))
+ ++name;
+ /* Also skip following colon if this is the first rpath
+ element, but keep an empty element at the end. */
+ if (wp == result && is_path && *name == ':' && name[1] != '\0')
+ ++name;
+ }
+ else
+ /* No DST we recognize. */
+ *wp++ = '$';
+ }
+ else
+ {
+ *wp++ = *name++;
+ if (is_path && *name == ':')
+ {
+ /* In SUID/SGID programs, after $ORIGIN expansion the
+ normalized path must be rooted in one of the trusted
+ directories. */
+ if (__glibc_unlikely (check_for_trusted)
+ && !is_trusted_path_normalize (last_elem, wp - last_elem))
+ wp = last_elem;
+ else
+ last_elem = wp;
+
+ check_for_trusted = false;
+ }
+ }
+ }
+ while (*name != '\0');
+
+ /* In SUID/SGID programs, after $ORIGIN expansion the normalized
+ path must be rooted in one of the trusted directories. */
+ if (__glibc_unlikely (check_for_trusted)
+ && !is_trusted_path_normalize (last_elem, wp - last_elem))
+ wp = last_elem;
+
+ *wp = '\0';
+
+ return result;
+}
+
+
+/* Return copy of argument with all recognized dynamic string tokens
+ ($ORIGIN and $PLATFORM for now) replaced. On some platforms it
+ might not be possible to determine the path from which the object
+ belonging to the map is loaded. In this case the path element
+ containing $ORIGIN is left out. */
+static char *
+expand_dynamic_string_token (struct link_map *l, const char *s, int is_path)
+{
+ /* We make two runs over the string. First we determine how large the
+ resulting string is and then we copy it over. Since this is no
+ frequently executed operation we are looking here not for performance
+ but rather for code size. */
+ size_t cnt;
+ size_t total;
+ char *result;
+
+ /* Determine the number of DST elements. */
+ cnt = DL_DST_COUNT (s, is_path);
+
+ /* If we do not have to replace anything simply copy the string. */
+ if (__glibc_likely (cnt == 0))
+ return __strdup (s);
+
+ /* Determine the length of the substituted string. */
+ total = DL_DST_REQUIRED (l, s, strlen (s), cnt);
+
+ /* Allocate the necessary memory. */
+ result = (char *) malloc (total + 1);
+ if (result == NULL)
+ return NULL;
+
+ return _dl_dst_substitute (l, s, result, is_path);
+}
+
+
+/* Add `name' to the list of names for a particular shared object.
+ `name' is expected to have been allocated with malloc and will
+ be freed if the shared object already has this name.
+ Returns false if the object already had this name. */
+static void
+internal_function
+add_name_to_object (struct link_map *l, const char *name)
+{
+ struct libname_list *lnp, *lastp;
+ struct libname_list *newname;
+ size_t name_len;
+
+ lastp = NULL;
+ for (lnp = l->l_libname; lnp != NULL; lastp = lnp, lnp = lnp->next)
+ if (strcmp (name, lnp->name) == 0)
+ return;
+
+ name_len = strlen (name) + 1;
+ newname = (struct libname_list *) malloc (sizeof *newname + name_len);
+ if (newname == NULL)
+ {
+ /* No more memory. */
+ _dl_signal_error (ENOMEM, name, NULL, N_("cannot allocate name record"));
+ return;
+ }
+ /* The object should have a libname set from _dl_new_object. */
+ assert (lastp != NULL);
+
+ newname->name = memcpy (newname + 1, name, name_len);
+ newname->next = NULL;
+ newname->dont_free = 0;
+ lastp->next = newname;
+}
+
+/* Standard search directories. */
+static struct r_search_path_struct rtld_search_dirs attribute_relro;
+
+static size_t max_dirnamelen;
+
+static struct r_search_path_elem **
+fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
+ int check_trusted, const char *what, const char *where,
+ struct link_map *l)
+{
+ char *cp;
+ size_t nelems = 0;
+ char *to_free;
+
+ while ((cp = __strsep (&rpath, sep)) != NULL)
+ {
+ struct r_search_path_elem *dirp;
+
+ to_free = cp = expand_dynamic_string_token (l, cp, 1);
+
+ size_t len = strlen (cp);
+
+ /* `strsep' can pass an empty string. This has to be
+ interpreted as `use the current directory'. */
+ if (len == 0)
+ {
+ static const char curwd[] = "./";
+ cp = (char *) curwd;
+ }
+
+ /* Remove trailing slashes (except for "/"). */
+ while (len > 1 && cp[len - 1] == '/')
+ --len;
+
+ /* Now add one if there is none so far. */
+ if (len > 0 && cp[len - 1] != '/')
+ cp[len++] = '/';
+
+ /* Make sure we don't use untrusted directories if we run SUID. */
+ if (__glibc_unlikely (check_trusted) && !is_trusted_path (cp, len))
+ {
+ free (to_free);
+ continue;
+ }
+
+ /* See if this directory is already known. */
+ for (dirp = GL(dl_all_dirs); dirp != NULL; dirp = dirp->next)
+ if (dirp->dirnamelen == len && memcmp (cp, dirp->dirname, len) == 0)
+ break;
+
+ if (dirp != NULL)
+ {
+ /* It is available, see whether it's on our own list. */
+ size_t cnt;
+ for (cnt = 0; cnt < nelems; ++cnt)
+ if (result[cnt] == dirp)
+ break;
+
+ if (cnt == nelems)
+ result[nelems++] = dirp;
+ }
+ else
+ {
+ size_t cnt;
+ enum r_dir_status init_val;
+ size_t where_len = where ? strlen (where) + 1 : 0;
+
+ /* It's a new directory. Create an entry and add it. */
+ dirp = (struct r_search_path_elem *)
+ malloc (sizeof (*dirp) + ncapstr * sizeof (enum r_dir_status)
+ + where_len + len + 1);
+ if (dirp == NULL)
+ _dl_signal_error (ENOMEM, NULL, NULL,
+ N_("cannot create cache for search path"));
+
+ dirp->dirname = ((char *) dirp + sizeof (*dirp)
+ + ncapstr * sizeof (enum r_dir_status));
+ *((char *) __mempcpy ((char *) dirp->dirname, cp, len)) = '\0';
+ dirp->dirnamelen = len;
+
+ if (len > max_dirnamelen)
+ max_dirnamelen = len;
+
+ /* We have to make sure all the relative directories are
+ never ignored. The current directory might change and
+ all our saved information would be void. */
+ init_val = cp[0] != '/' ? existing : unknown;
+ for (cnt = 0; cnt < ncapstr; ++cnt)
+ dirp->status[cnt] = init_val;
+
+ dirp->what = what;
+ if (__glibc_likely (where != NULL))
+ dirp->where = memcpy ((char *) dirp + sizeof (*dirp) + len + 1
+ + (ncapstr * sizeof (enum r_dir_status)),
+ where, where_len);
+ else
+ dirp->where = NULL;
+
+ dirp->next = GL(dl_all_dirs);
+ GL(dl_all_dirs) = dirp;
+
+ /* Put it in the result array. */
+ result[nelems++] = dirp;
+ }
+ free (to_free);
+ }
+
+ /* Terminate the array. */
+ result[nelems] = NULL;
+
+ return result;
+}
+
+
+static bool
+internal_function
+decompose_rpath (struct r_search_path_struct *sps,
+ const char *rpath, struct link_map *l, const char *what)
+{
+ /* Make a copy we can work with. */
+ const char *where = l->l_name;
+ char *copy;
+ char *cp;
+ struct r_search_path_elem **result;
+ size_t nelems;
+ /* Initialize to please the compiler. */
+ const char *errstring = NULL;
+
+ /* First see whether we must forget the RUNPATH and RPATH from this
+ object. */
+ if (__glibc_unlikely (GLRO(dl_inhibit_rpath) != NULL)
+ && !__libc_enable_secure)
+ {
+ const char *inhp = GLRO(dl_inhibit_rpath);
+
+ do
+ {
+ const char *wp = where;
+
+ while (*inhp == *wp && *wp != '\0')
+ {
+ ++inhp;
+ ++wp;
+ }
+
+ if (*wp == '\0' && (*inhp == '\0' || *inhp == ':'))
+ {
+ /* This object is on the list of objects for which the
+ RUNPATH and RPATH must not be used. */
+ sps->dirs = (void *) -1;
+ return false;
+ }
+
+ while (*inhp != '\0')
+ if (*inhp++ == ':')
+ break;
+ }
+ while (*inhp != '\0');
+ }
+
+ /* Make a writable copy. */
+ copy = __strdup (rpath);
+ if (copy == NULL)
+ {
+ errstring = N_("cannot create RUNPATH/RPATH copy");
+ goto signal_error;
+ }
+
+ /* Ignore empty rpaths. */
+ if (*copy == 0)
+ {
+ free (copy);
+ sps->dirs = (struct r_search_path_elem **) -1;
+ return false;
+ }
+
+ /* Count the number of necessary elements in the result array. */
+ nelems = 0;
+ for (cp = copy; *cp != '\0'; ++cp)
+ if (*cp == ':')
+ ++nelems;
+
+ /* Allocate room for the result. NELEMS + 1 is an upper limit for the
+ number of necessary entries. */
+ result = (struct r_search_path_elem **) malloc ((nelems + 1 + 1)
+ * sizeof (*result));
+ if (result == NULL)
+ {
+ free (copy);
+ errstring = N_("cannot create cache for search path");
+ signal_error:
+ _dl_signal_error (ENOMEM, NULL, NULL, errstring);
+ }
+
+ fillin_rpath (copy, result, ":", 0, what, where, l);
+
+ /* Free the copied RPATH string. `fillin_rpath' make own copies if
+ necessary. */
+ free (copy);
+
+ sps->dirs = result;
+ /* The caller will change this value if we haven't used a real malloc. */
+ sps->malloced = 1;
+ return true;
+}
+
+/* Make sure cached path information is stored in *SP
+ and return true if there are any paths to search there. */
+static bool
+cache_rpath (struct link_map *l,
+ struct r_search_path_struct *sp,
+ int tag,
+ const char *what)
+{
+ if (sp->dirs == (void *) -1)
+ return false;
+
+ if (sp->dirs != NULL)
+ return true;
+
+ if (l->l_info[tag] == NULL)
+ {
+ /* There is no path. */
+ sp->dirs = (void *) -1;
+ return false;
+ }
+
+ /* Make sure the cache information is available. */
+ return decompose_rpath (sp, (const char *) (D_PTR (l, l_info[DT_STRTAB])
+ + l->l_info[tag]->d_un.d_val),
+ l, what);
+}
+
+
+void
+internal_function
+_dl_init_paths (const char *llp)
+{
+ size_t idx;
+ const char *strp;
+ struct r_search_path_elem *pelem, **aelem;
+ size_t round_size;
+ struct link_map __attribute__ ((unused)) *l = NULL;
+ /* Initialize to please the compiler. */
+ const char *errstring = NULL;
+
+ /* Fill in the information about the application's RPATH and the
+ directories addressed by the LD_LIBRARY_PATH environment variable. */
+
+ /* Get the capabilities. */
+ capstr = _dl_important_hwcaps (GLRO(dl_platform), GLRO(dl_platformlen),
+ &ncapstr, &max_capstrlen);
+
+ /* First set up the rest of the default search directory entries. */
+ aelem = rtld_search_dirs.dirs = (struct r_search_path_elem **)
+ malloc ((nsystem_dirs_len + 1) * sizeof (struct r_search_path_elem *));
+ if (rtld_search_dirs.dirs == NULL)
+ {
+ errstring = N_("cannot create search path array");
+ signal_error:
+ _dl_signal_error (ENOMEM, NULL, NULL, errstring);
+ }
+
+ round_size = ((2 * sizeof (struct r_search_path_elem) - 1
+ + ncapstr * sizeof (enum r_dir_status))
+ / sizeof (struct r_search_path_elem));
+
+ rtld_search_dirs.dirs[0] = (struct r_search_path_elem *)
+ malloc ((sizeof (system_dirs) / sizeof (system_dirs[0]))
+ * round_size * sizeof (struct r_search_path_elem));
+ if (rtld_search_dirs.dirs[0] == NULL)
+ {
+ errstring = N_("cannot create cache for search path");
+ goto signal_error;
+ }
+
+ rtld_search_dirs.malloced = 0;
+ pelem = GL(dl_all_dirs) = rtld_search_dirs.dirs[0];
+ strp = system_dirs;
+ idx = 0;
+
+ do
+ {
+ size_t cnt;
+
+ *aelem++ = pelem;
+
+ pelem->what = "system search path";
+ pelem->where = NULL;
+
+ pelem->dirname = strp;
+ pelem->dirnamelen = system_dirs_len[idx];
+ strp += system_dirs_len[idx] + 1;
+
+ /* System paths must be absolute. */
+ assert (pelem->dirname[0] == '/');
+ for (cnt = 0; cnt < ncapstr; ++cnt)
+ pelem->status[cnt] = unknown;
+
+ pelem->next = (++idx == nsystem_dirs_len ? NULL : (pelem + round_size));
+
+ pelem += round_size;
+ }
+ while (idx < nsystem_dirs_len);
+
+ max_dirnamelen = SYSTEM_DIRS_MAX_LEN;
+ *aelem = NULL;
+
+#ifdef SHARED
+ /* This points to the map of the main object. */
+ l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+ if (l != NULL)
+ {
+ assert (l->l_type != lt_loaded);
+
+ if (l->l_info[DT_RUNPATH])
+ {
+ /* Allocate room for the search path and fill in information
+ from RUNPATH. */
+ decompose_rpath (&l->l_runpath_dirs,
+ (const void *) (D_PTR (l, l_info[DT_STRTAB])
+ + l->l_info[DT_RUNPATH]->d_un.d_val),
+ l, "RUNPATH");
+ /* During rtld init the memory is allocated by the stub malloc,
+ prevent any attempt to free it by the normal malloc. */
+ l->l_runpath_dirs.malloced = 0;
+
+ /* The RPATH is ignored. */
+ l->l_rpath_dirs.dirs = (void *) -1;
+ }
+ else
+ {
+ l->l_runpath_dirs.dirs = (void *) -1;
+
+ if (l->l_info[DT_RPATH])
+ {
+ /* Allocate room for the search path and fill in information
+ from RPATH. */
+ decompose_rpath (&l->l_rpath_dirs,
+ (const void *) (D_PTR (l, l_info[DT_STRTAB])
+ + l->l_info[DT_RPATH]->d_un.d_val),
+ l, "RPATH");
+ /* During rtld init the memory is allocated by the stub
+ malloc, prevent any attempt to free it by the normal
+ malloc. */
+ l->l_rpath_dirs.malloced = 0;
+ }
+ else
+ l->l_rpath_dirs.dirs = (void *) -1;
+ }
+ }
+#endif /* SHARED */
+
+ if (llp != NULL && *llp != '\0')
+ {
+ size_t nllp;
+ const char *cp = llp;
+ char *llp_tmp;
+
+#ifdef SHARED
+ /* Expand DSTs. */
+ size_t cnt = DL_DST_COUNT (llp, 1);
+ if (__glibc_likely (cnt == 0))
+ llp_tmp = strdupa (llp);
+ else
+ {
+ /* Determine the length of the substituted string. */
+ size_t total = DL_DST_REQUIRED (l, llp, strlen (llp), cnt);
+
+ /* Allocate the necessary memory. */
+ llp_tmp = (char *) alloca (total + 1);
+ llp_tmp = _dl_dst_substitute (l, llp, llp_tmp, 1);
+ }
+#else
+ llp_tmp = strdupa (llp);
+#endif
+
+ /* Decompose the LD_LIBRARY_PATH contents. First determine how many
+ elements it has. */
+ nllp = 1;
+ while (*cp)
+ {
+ if (*cp == ':' || *cp == ';')
+ ++nllp;
+ ++cp;
+ }
+
+ env_path_list.dirs = (struct r_search_path_elem **)
+ malloc ((nllp + 1) * sizeof (struct r_search_path_elem *));
+ if (env_path_list.dirs == NULL)
+ {
+ errstring = N_("cannot create cache for search path");
+ goto signal_error;
+ }
+
+ (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;",
+ __libc_enable_secure, "LD_LIBRARY_PATH",
+ NULL, l);
+
+ if (env_path_list.dirs[0] == NULL)
+ {
+ free (env_path_list.dirs);
+ env_path_list.dirs = (void *) -1;
+ }
+
+ env_path_list.malloced = 0;
+ }
+ else
+ env_path_list.dirs = (void *) -1;
+}
+
+
+static void
+__attribute__ ((noreturn, noinline))
+lose (int code, int fd, const char *name, char *realname, struct link_map *l,
+ const char *msg, struct r_debug *r, Lmid_t nsid)
+{
+ /* The file might already be closed. */
+ if (fd != -1)
+ (void) __close (fd);
+ if (l != NULL && l->l_origin != (char *) -1l)
+ free ((char *) l->l_origin);
+ free (l);
+ free (realname);
+
+ if (r != NULL)
+ {
+ r->r_state = RT_CONSISTENT;
+ _dl_debug_state ();
+ LIBC_PROBE (map_failed, 2, nsid, r);
+ }
+
+ _dl_signal_error (code, name, NULL, msg);
+}
+
+
+/* Map in the shared object NAME, actually located in REALNAME, and already
+ opened on FD. */
+
+#ifndef EXTERNAL_MAP_FROM_FD
+static
+#endif
+struct link_map *
+_dl_map_object_from_fd (const char *name, const char *origname, int fd,
+ struct filebuf *fbp, char *realname,
+ struct link_map *loader, int l_type, int mode,
+ void **stack_endp, Lmid_t nsid)
+{
+ struct link_map *l = NULL;
+ const ElfW(Ehdr) *header;
+ const ElfW(Phdr) *phdr;
+ const ElfW(Phdr) *ph;
+ size_t maplength;
+ int type;
+ /* Initialize to keep the compiler happy. */
+ const char *errstring = NULL;
+ int errval = 0;
+ struct r_debug *r = _dl_debug_initialize (0, nsid);
+ bool make_consistent = false;
+
+ /* Get file information. */
+ struct r_file_id id;
+ if (__glibc_unlikely (!_dl_get_file_id (fd, &id)))
+ {
+ errstring = N_("cannot stat shared object");
+ call_lose_errno:
+ errval = errno;
+ call_lose:
+ lose (errval, fd, name, realname, l, errstring,
+ make_consistent ? r : NULL, nsid);
+ }
+
+ /* Look again to see if the real name matched another already loaded. */
+ for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
+ if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id))
+ {
+ /* The object is already loaded.
+ Just bump its reference count and return it. */
+ __close (fd);
+
+ /* If the name is not in the list of names for this object add
+ it. */
+ free (realname);
+ add_name_to_object (l, name);
+
+ return l;
+ }
+
+#ifdef SHARED
+ /* When loading into a namespace other than the base one we must
+ avoid loading ld.so since there can only be one copy. Ever. */
+ if (__glibc_unlikely (nsid != LM_ID_BASE)
+ && (_dl_file_id_match_p (&id, &GL(dl_rtld_map).l_file_id)
+ || _dl_name_match_p (name, &GL(dl_rtld_map))))
+ {
+ /* This is indeed ld.so. Create a new link_map which refers to
+ the real one for almost everything. */
+ l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
+ if (l == NULL)
+ goto fail_new;
+
+ /* Refer to the real descriptor. */
+ l->l_real = &GL(dl_rtld_map);
+
+ /* No need to bump the refcount of the real object, ld.so will
+ never be unloaded. */
+ __close (fd);
+
+ /* Add the map for the mirrored object to the object list. */
+ _dl_add_to_namespace_list (l, nsid);
+
+ return l;
+ }
+#endif
+
+ if (mode & RTLD_NOLOAD)
+ {
+ /* We are not supposed to load the object unless it is already
+ loaded. So return now. */
+ free (realname);
+ __close (fd);
+ return NULL;
+ }
+
+ /* Print debugging message. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("file=%s [%lu]; generating link map\n", name, nsid);
+
+ /* This is the ELF header. We read it in `open_verify'. */
+ header = (void *) fbp->buf;
+
+#ifndef MAP_ANON
+# define MAP_ANON 0
+ if (_dl_zerofd == -1)
+ {
+ _dl_zerofd = _dl_sysdep_open_zero_fill ();
+ if (_dl_zerofd == -1)
+ {
+ free (realname);
+ __close (fd);
+ _dl_signal_error (errno, NULL, NULL,
+ N_("cannot open zero fill device"));
+ }
+ }
+#endif
+
+ /* Signal that we are going to add new objects. */
+ if (r->r_state == RT_CONSISTENT)
+ {
+#ifdef SHARED
+ /* Auditing checkpoint: we are going to add new objects. */
+ if ((mode & __RTLD_AUDIT) == 0
+ && __glibc_unlikely (GLRO(dl_naudit) > 0))
+ {
+ struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
+ /* Do not call the functions for any auditing object. */
+ if (head->l_auditing == 0)
+ {
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->activity != NULL)
+ afct->activity (&head->l_audit[cnt].cookie, LA_ACT_ADD);
+
+ afct = afct->next;
+ }
+ }
+ }
+#endif
+
+ /* Notify the debugger we have added some objects. We need to
+ call _dl_debug_initialize in a static program in case dynamic
+ linking has not been used before. */
+ r->r_state = RT_ADD;
+ _dl_debug_state ();
+ LIBC_PROBE (map_start, 2, nsid, r);
+ make_consistent = true;
+ }
+ else
+ assert (r->r_state == RT_ADD);
+
+ /* Enter the new object in the list of loaded objects. */
+ l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
+ if (__glibc_unlikely (l == NULL))
+ {
+#ifdef SHARED
+ fail_new:
+#endif
+ errstring = N_("cannot create shared object descriptor");
+ goto call_lose_errno;
+ }
+
+ /* Extract the remaining details we need from the ELF header
+ and then read in the program header table. */
+ l->l_entry = header->e_entry;
+ type = header->e_type;
+ l->l_phnum = header->e_phnum;
+
+ maplength = header->e_phnum * sizeof (ElfW(Phdr));
+ if (header->e_phoff + maplength <= (size_t) fbp->len)
+ phdr = (void *) (fbp->buf + header->e_phoff);
+ else
+ {
+ phdr = alloca (maplength);
+ __lseek (fd, header->e_phoff, SEEK_SET);
+ if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength)
+ {
+ errstring = N_("cannot read file data");
+ goto call_lose_errno;
+ }
+ }
+
+ /* On most platforms presume that PT_GNU_STACK is absent and the stack is
+ * executable. Other platforms default to a nonexecutable stack and don't
+ * need PT_GNU_STACK to do so. */
+ uint_fast16_t stack_flags = DEFAULT_STACK_PERMS;
+
+ {
+ /* Scan the program header table, collecting its load commands. */
+ struct loadcmd loadcmds[l->l_phnum];
+ size_t nloadcmds = 0;
+ bool has_holes = false;
+
+ /* The struct is initialized to zero so this is not necessary:
+ l->l_ld = 0;
+ l->l_phdr = 0;
+ l->l_addr = 0; */
+ for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph)
+ switch (ph->p_type)
+ {
+ /* These entries tell us where to find things once the file's
+ segments are mapped in. We record the addresses it says
+ verbatim, and later correct for the run-time load address. */
+ case PT_DYNAMIC:
+ l->l_ld = (void *) ph->p_vaddr;
+ l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+ break;
+
+ case PT_PHDR:
+ l->l_phdr = (void *) ph->p_vaddr;
+ break;
+
+ case PT_LOAD:
+ /* A load command tells us to map in part of the file.
+ We record the load commands and process them all later. */
+ if (__glibc_unlikely ((ph->p_align & (GLRO(dl_pagesize) - 1)) != 0))
+ {
+ errstring = N_("ELF load command alignment not page-aligned");
+ goto call_lose;
+ }
+ if (__glibc_unlikely (((ph->p_vaddr - ph->p_offset)
+ & (ph->p_align - 1)) != 0))
+ {
+ errstring
+ = N_("ELF load command address/offset not properly aligned");
+ goto call_lose;
+ }
+
+ struct loadcmd *c = &loadcmds[nloadcmds++];
+ c->mapstart = ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize));
+ c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize));
+ c->dataend = ph->p_vaddr + ph->p_filesz;
+ c->allocend = ph->p_vaddr + ph->p_memsz;
+ c->mapoff = ALIGN_DOWN (ph->p_offset, GLRO(dl_pagesize));
+
+ /* Determine whether there is a gap between the last segment
+ and this one. */
+ if (nloadcmds > 1 && c[-1].mapend != c->mapstart)
+ has_holes = true;
+
+ /* Optimize a common case. */
+#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7
+ c->prot = (PF_TO_PROT
+ >> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf;
+#else
+ c->prot = 0;
+ if (ph->p_flags & PF_R)
+ c->prot |= PROT_READ;
+ if (ph->p_flags & PF_W)
+ c->prot |= PROT_WRITE;
+ if (ph->p_flags & PF_X)
+ c->prot |= PROT_EXEC;
+#endif
+ break;
+
+ case PT_TLS:
+ if (ph->p_memsz == 0)
+ /* Nothing to do for an empty segment. */
+ break;
+
+ l->l_tls_blocksize = ph->p_memsz;
+ l->l_tls_align = ph->p_align;
+ if (ph->p_align == 0)
+ l->l_tls_firstbyte_offset = 0;
+ else
+ l->l_tls_firstbyte_offset = ph->p_vaddr & (ph->p_align - 1);
+ l->l_tls_initimage_size = ph->p_filesz;
+ /* Since we don't know the load address yet only store the
+ offset. We will adjust it later. */
+ l->l_tls_initimage = (void *) ph->p_vaddr;
+
+ /* If not loading the initial set of shared libraries,
+ check whether we should permit loading a TLS segment. */
+ if (__glibc_likely (l->l_type == lt_library)
+ /* If GL(dl_tls_dtv_slotinfo_list) == NULL, then rtld.c did
+ not set up TLS data structures, so don't use them now. */
+ || __glibc_likely (GL(dl_tls_dtv_slotinfo_list) != NULL))
+ {
+ /* Assign the next available module ID. */
+ l->l_tls_modid = _dl_next_tls_modid ();
+ break;
+ }
+
+#ifdef SHARED
+ /* We are loading the executable itself when the dynamic
+ linker was executed directly. The setup will happen
+ later. Otherwise, the TLS data structures are already
+ initialized, and we assigned a TLS modid above. */
+ assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0);
+#else
+ assert (false && "TLS not initialized in static application");
+#endif
+ break;
+
+ case PT_GNU_STACK:
+ stack_flags = ph->p_flags;
+ break;
+
+ case PT_GNU_RELRO:
+ l->l_relro_addr = ph->p_vaddr;
+ l->l_relro_size = ph->p_memsz;
+ break;
+ }
+
+ if (__glibc_unlikely (nloadcmds == 0))
+ {
+ /* This only happens for a bogus object that will be caught with
+ another error below. But we don't want to go through the
+ calculations below using NLOADCMDS - 1. */
+ errstring = N_("object file has no loadable segments");
+ goto call_lose;
+ }
+
+ if (__glibc_unlikely (type != ET_DYN)
+ && __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0))
+ {
+ /* This object is loaded at a fixed address. This must never
+ happen for objects loaded with dlopen. */
+ errstring = N_("cannot dynamically load executable");
+ goto call_lose;
+ }
+
+ /* Length of the sections to be loaded. */
+ maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart;
+
+ /* Now process the load commands and map segments into memory.
+ This is responsible for filling in:
+ l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr
+ */
+ errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds,
+ maplength, has_holes, loader);
+ if (__glibc_unlikely (errstring != NULL))
+ goto call_lose;
+ }
+
+ if (l->l_ld == 0)
+ {
+ if (__glibc_unlikely (type == ET_DYN))
+ {
+ errstring = N_("object file has no dynamic section");
+ goto call_lose;
+ }
+ }
+ else
+ l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
+
+ elf_get_dynamic_info (l, NULL);
+
+ /* Make sure we are not dlopen'ing an object that has the
+ DF_1_NOOPEN flag set. */
+ if (__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)
+ && (mode & __RTLD_DLOPEN))
+ {
+ /* We are not supposed to load this object. Free all resources. */
+ _dl_unmap_segments (l);
+
+ if (!l->l_libname->dont_free)
+ free (l->l_libname);
+
+ if (l->l_phdr_allocated)
+ free ((void *) l->l_phdr);
+
+ errstring = N_("shared object cannot be dlopen()ed");
+ goto call_lose;
+ }
+
+ if (l->l_phdr == NULL)
+ {
+ /* The program header is not contained in any of the segments.
+ We have to allocate memory ourself and copy it over from out
+ temporary place. */
+ ElfW(Phdr) *newp = (ElfW(Phdr) *) malloc (header->e_phnum
+ * sizeof (ElfW(Phdr)));
+ if (newp == NULL)
+ {
+ errstring = N_("cannot allocate memory for program header");
+ goto call_lose_errno;
+ }
+
+ l->l_phdr = memcpy (newp, phdr,
+ (header->e_phnum * sizeof (ElfW(Phdr))));
+ l->l_phdr_allocated = 1;
+ }
+ else
+ /* Adjust the PT_PHDR value by the runtime load address. */
+ l->l_phdr = (ElfW(Phdr) *) ((ElfW(Addr)) l->l_phdr + l->l_addr);
+
+ if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_flags)) & PF_X))
+ {
+ if (__glibc_unlikely (__check_caller (RETURN_ADDRESS (0), allow_ldso) != 0))
+ {
+ errstring = N_("invalid caller");
+ goto call_lose;
+ }
+
+ /* The stack is presently not executable, but this module
+ requires that it be executable. We must change the
+ protection of the variable which contains the flags used in
+ the mprotect calls. */
+#ifdef SHARED
+ if ((mode & (__RTLD_DLOPEN | __RTLD_AUDIT)) == __RTLD_DLOPEN)
+ {
+ const uintptr_t p = (uintptr_t) &__stack_prot & -GLRO(dl_pagesize);
+ const size_t s = (uintptr_t) (&__stack_prot + 1) - p;
+
+ struct link_map *const m = &GL(dl_rtld_map);
+ const uintptr_t relro_end = ((m->l_addr + m->l_relro_addr
+ + m->l_relro_size)
+ & -GLRO(dl_pagesize));
+ if (__glibc_likely (p + s <= relro_end))
+ {
+ /* The variable lies in the region protected by RELRO. */
+ if (__mprotect ((void *) p, s, PROT_READ|PROT_WRITE) < 0)
+ {
+ errstring = N_("cannot change memory protections");
+ goto call_lose_errno;
+ }
+ __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
+ __mprotect ((void *) p, s, PROT_READ);
+ }
+ else
+ __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
+ }
+ else
+#endif
+ __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
+
+#ifdef check_consistency
+ check_consistency ();
+#endif
+
+ errval = (*GL(dl_make_stack_executable_hook)) (stack_endp);
+ if (errval)
+ {
+ errstring = N_("\
+cannot enable executable stack as shared object requires");
+ goto call_lose;
+ }
+ }
+
+ /* Adjust the address of the TLS initialization image. */
+ if (l->l_tls_initimage != NULL)
+ l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr;
+
+ /* We are done mapping in the file. We no longer need the descriptor. */
+ if (__glibc_unlikely (__close (fd) != 0))
+ {
+ errstring = N_("cannot close file descriptor");
+ goto call_lose_errno;
+ }
+ /* Signal that we closed the file. */
+ fd = -1;
+
+ /* If this is ET_EXEC, we should have loaded it as lt_executable. */
+ assert (type != ET_EXEC || l->l_type == lt_executable);
+
+ l->l_entry += l->l_addr;
+
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("\
+ dynamic: 0x%0*lx base: 0x%0*lx size: 0x%0*Zx\n\
+ entry: 0x%0*lx phdr: 0x%0*lx phnum: %*u\n\n",
+ (int) sizeof (void *) * 2,
+ (unsigned long int) l->l_ld,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) l->l_addr,
+ (int) sizeof (void *) * 2, maplength,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) l->l_entry,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) l->l_phdr,
+ (int) sizeof (void *) * 2, l->l_phnum);
+
+ /* Set up the symbol hash table. */
+ _dl_setup_hash (l);
+
+ /* If this object has DT_SYMBOLIC set modify now its scope. We don't
+ have to do this for the main map. */
+ if ((mode & RTLD_DEEPBIND) == 0
+ && __glibc_unlikely (l->l_info[DT_SYMBOLIC] != NULL)
+ && &l->l_searchlist != l->l_scope[0])
+ {
+ /* Create an appropriate searchlist. It contains only this map.
+ This is the definition of DT_SYMBOLIC in SysVr4. */
+ l->l_symbolic_searchlist.r_list[0] = l;
+ l->l_symbolic_searchlist.r_nlist = 1;
+
+ /* Now move the existing entries one back. */
+ memmove (&l->l_scope[1], &l->l_scope[0],
+ (l->l_scope_max - 1) * sizeof (l->l_scope[0]));
+
+ /* Now add the new entry. */
+ l->l_scope[0] = &l->l_symbolic_searchlist;
+ }
+
+ /* Remember whether this object must be initialized first. */
+ if (l->l_flags_1 & DF_1_INITFIRST)
+ GL(dl_initfirst) = l;
+
+ /* Finally the file information. */
+ l->l_file_id = id;
+
+#ifdef SHARED
+ /* When auditing is used the recorded names might not include the
+ name by which the DSO is actually known. Add that as well. */
+ if (__glibc_unlikely (origname != NULL))
+ add_name_to_object (l, origname);
+#else
+ /* Audit modules only exist when linking is dynamic so ORIGNAME
+ cannot be non-NULL. */
+ assert (origname == NULL);
+#endif
+
+ /* When we profile the SONAME might be needed for something else but
+ loading. Add it right away. */
+ if (__glibc_unlikely (GLRO(dl_profile) != NULL)
+ && l->l_info[DT_SONAME] != NULL)
+ add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB])
+ + l->l_info[DT_SONAME]->d_un.d_val));
+
+#ifdef DL_AFTER_LOAD
+ DL_AFTER_LOAD (l);
+#endif
+
+ /* Now that the object is fully initialized add it to the object list. */
+ _dl_add_to_namespace_list (l, nsid);
+
+#ifdef SHARED
+ /* Auditing checkpoint: we have a new object. */
+ if (__glibc_unlikely (GLRO(dl_naudit) > 0)
+ && !GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
+ {
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->objopen != NULL)
+ {
+ l->l_audit[cnt].bindflags
+ = afct->objopen (l, nsid, &l->l_audit[cnt].cookie);
+
+ l->l_audit_any_plt |= l->l_audit[cnt].bindflags != 0;
+ }
+
+ afct = afct->next;
+ }
+ }
+#endif
+
+ return l;
+}
+
+/* Print search path. */
+static void
+print_search_path (struct r_search_path_elem **list,
+ const char *what, const char *name)
+{
+ char buf[max_dirnamelen + max_capstrlen];
+ int first = 1;
+
+ _dl_debug_printf (" search path=");
+
+ while (*list != NULL && (*list)->what == what) /* Yes, ==. */
+ {
+ char *endp = __mempcpy (buf, (*list)->dirname, (*list)->dirnamelen);
+ size_t cnt;
+
+ for (cnt = 0; cnt < ncapstr; ++cnt)
+ if ((*list)->status[cnt] != nonexisting)
+ {
+ char *cp = __mempcpy (endp, capstr[cnt].str, capstr[cnt].len);
+ if (cp == buf || (cp == buf + 1 && buf[0] == '/'))
+ cp[0] = '\0';
+ else
+ cp[-1] = '\0';
+
+ _dl_debug_printf_c (first ? "%s" : ":%s", buf);
+ first = 0;
+ }
+
+ ++list;
+ }
+
+ if (name != NULL)
+ _dl_debug_printf_c ("\t\t(%s from file %s)\n", what,
+ DSO_FILENAME (name));
+ else
+ _dl_debug_printf_c ("\t\t(%s)\n", what);
+}
+
+/* Open a file and verify it is an ELF file for this architecture. We
+ ignore only ELF files for other architectures. Non-ELF files and
+ ELF files with different header information cause fatal errors since
+ this could mean there is something wrong in the installation and the
+ user might want to know about this.
+
+ If FD is not -1, then the file is already open and FD refers to it.
+ In that case, FD is consumed for both successful and error returns. */
+static int
+open_verify (const char *name, int fd,
+ struct filebuf *fbp, struct link_map *loader,
+ int whatcode, int mode, bool *found_other_class, bool free_name)
+{
+ /* This is the expected ELF header. */
+#define ELF32_CLASS ELFCLASS32
+#define ELF64_CLASS ELFCLASS64
+#ifndef VALID_ELF_HEADER
+# define VALID_ELF_HEADER(hdr,exp,size) (memcmp (hdr, exp, size) == 0)
+# define VALID_ELF_OSABI(osabi) (osabi == ELFOSABI_SYSV)
+# define VALID_ELF_ABIVERSION(osabi,ver) (ver == 0)
+#elif defined MORE_ELF_HEADER_DATA
+ MORE_ELF_HEADER_DATA;
+#endif
+ static const unsigned char expected[EI_NIDENT] =
+ {
+ [EI_MAG0] = ELFMAG0,
+ [EI_MAG1] = ELFMAG1,
+ [EI_MAG2] = ELFMAG2,
+ [EI_MAG3] = ELFMAG3,
+ [EI_CLASS] = ELFW(CLASS),
+ [EI_DATA] = byteorder,
+ [EI_VERSION] = EV_CURRENT,
+ [EI_OSABI] = ELFOSABI_SYSV,
+ [EI_ABIVERSION] = 0
+ };
+ static const struct
+ {
+ ElfW(Word) vendorlen;
+ ElfW(Word) datalen;
+ ElfW(Word) type;
+ char vendor[4];
+ } expected_note = { 4, 16, 1, "GNU" };
+ /* Initialize it to make the compiler happy. */
+ const char *errstring = NULL;
+ int errval = 0;
+
+#ifdef SHARED
+ /* Give the auditing libraries a chance. */
+ if (__glibc_unlikely (GLRO(dl_naudit) > 0) && whatcode != 0
+ && loader->l_auditing == 0)
+ {
+ const char *original_name = name;
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->objsearch != NULL)
+ {
+ name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
+ whatcode);
+ if (name == NULL)
+ /* Ignore the path. */
+ return -1;
+ }
+
+ afct = afct->next;
+ }
+
+ if (fd != -1 && name != original_name && strcmp (name, original_name))
+ {
+ /* An audit library changed what we're supposed to open,
+ so FD no longer matches it. */
+ __close (fd);
+ fd = -1;
+ }
+ }
+#endif
+
+ if (fd == -1)
+ /* Open the file. We always open files read-only. */
+ fd = __open (name, O_RDONLY | O_CLOEXEC);
+
+ if (fd != -1)
+ {
+ ElfW(Ehdr) *ehdr;
+ ElfW(Phdr) *phdr, *ph;
+ ElfW(Word) *abi_note;
+ unsigned int osversion;
+ size_t maplength;
+
+ /* We successfully opened the file. Now verify it is a file
+ we can use. */
+ __set_errno (0);
+ fbp->len = 0;
+ assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr)));
+ /* Read in the header. */
+ do
+ {
+ ssize_t retlen = __libc_read (fd, fbp->buf + fbp->len,
+ sizeof (fbp->buf) - fbp->len);
+ if (retlen <= 0)
+ break;
+ fbp->len += retlen;
+ }
+ while (__glibc_unlikely (fbp->len < sizeof (ElfW(Ehdr))));
+
+ /* This is where the ELF header is loaded. */
+ ehdr = (ElfW(Ehdr) *) fbp->buf;
+
+ /* Now run the tests. */
+ if (__glibc_unlikely (fbp->len < (ssize_t) sizeof (ElfW(Ehdr))))
+ {
+ errval = errno;
+ errstring = (errval == 0
+ ? N_("file too short") : N_("cannot read file data"));
+ call_lose:
+ if (free_name)
+ {
+ char *realname = (char *) name;
+ name = strdupa (realname);
+ free (realname);
+ }
+ lose (errval, fd, name, NULL, NULL, errstring, NULL, 0);
+ }
+
+ /* See whether the ELF header is what we expect. */
+ if (__glibc_unlikely (! VALID_ELF_HEADER (ehdr->e_ident, expected,
+ EI_ABIVERSION)
+ || !VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI],
+ ehdr->e_ident[EI_ABIVERSION])
+ || memcmp (&ehdr->e_ident[EI_PAD],
+ &expected[EI_PAD],
+ EI_NIDENT - EI_PAD) != 0))
+ {
+ /* Something is wrong. */
+ const Elf32_Word *magp = (const void *) ehdr->e_ident;
+ if (*magp !=
+#if BYTE_ORDER == LITTLE_ENDIAN
+ ((ELFMAG0 << (EI_MAG0 * 8)) |
+ (ELFMAG1 << (EI_MAG1 * 8)) |
+ (ELFMAG2 << (EI_MAG2 * 8)) |
+ (ELFMAG3 << (EI_MAG3 * 8)))
+#else
+ ((ELFMAG0 << (EI_MAG3 * 8)) |
+ (ELFMAG1 << (EI_MAG2 * 8)) |
+ (ELFMAG2 << (EI_MAG1 * 8)) |
+ (ELFMAG3 << (EI_MAG0 * 8)))
+#endif
+ )
+ errstring = N_("invalid ELF header");
+ else if (ehdr->e_ident[EI_CLASS] != ELFW(CLASS))
+ {
+ /* This is not a fatal error. On architectures where
+ 32-bit and 64-bit binaries can be run this might
+ happen. */
+ *found_other_class = true;
+ goto close_and_out;
+ }
+ else if (ehdr->e_ident[EI_DATA] != byteorder)
+ {
+ if (BYTE_ORDER == BIG_ENDIAN)
+ errstring = N_("ELF file data encoding not big-endian");
+ else
+ errstring = N_("ELF file data encoding not little-endian");
+ }
+ else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT)
+ errstring
+ = N_("ELF file version ident does not match current one");
+ /* XXX We should be able so set system specific versions which are
+ allowed here. */
+ else if (!VALID_ELF_OSABI (ehdr->e_ident[EI_OSABI]))
+ errstring = N_("ELF file OS ABI invalid");
+ else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI],
+ ehdr->e_ident[EI_ABIVERSION]))
+ errstring = N_("ELF file ABI version invalid");
+ else if (memcmp (&ehdr->e_ident[EI_PAD], &expected[EI_PAD],
+ EI_NIDENT - EI_PAD) != 0)
+ errstring = N_("nonzero padding in e_ident");
+ else
+ /* Otherwise we don't know what went wrong. */
+ errstring = N_("internal error");
+
+ goto call_lose;
+ }
+
+ if (__glibc_unlikely (ehdr->e_version != EV_CURRENT))
+ {
+ errstring = N_("ELF file version does not match current one");
+ goto call_lose;
+ }
+ if (! __glibc_likely (elf_machine_matches_host (ehdr)))
+ goto close_and_out;
+ else if (__glibc_unlikely (ehdr->e_type != ET_DYN
+ && ehdr->e_type != ET_EXEC))
+ {
+ errstring = N_("only ET_DYN and ET_EXEC can be loaded");
+ goto call_lose;
+ }
+ else if (__glibc_unlikely (ehdr->e_type == ET_EXEC
+ && (mode & __RTLD_OPENEXEC) == 0))
+ {
+ /* BZ #16634. It is an error to dlopen ET_EXEC (unless
+ __RTLD_OPENEXEC is explicitly set). We return error here
+ so that code in _dl_map_object_from_fd does not try to set
+ l_tls_modid for this module. */
+
+ errstring = N_("cannot dynamically load executable");
+ goto call_lose;
+ }
+ else if (__glibc_unlikely (ehdr->e_phentsize != sizeof (ElfW(Phdr))))
+ {
+ errstring = N_("ELF file's phentsize not the expected size");
+ goto call_lose;
+ }
+
+ maplength = ehdr->e_phnum * sizeof (ElfW(Phdr));
+ if (ehdr->e_phoff + maplength <= (size_t) fbp->len)
+ phdr = (void *) (fbp->buf + ehdr->e_phoff);
+ else
+ {
+ phdr = alloca (maplength);
+ __lseek (fd, ehdr->e_phoff, SEEK_SET);
+ if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength)
+ {
+ read_error:
+ errval = errno;
+ errstring = N_("cannot read file data");
+ goto call_lose;
+ }
+ }
+
+ if (__glibc_unlikely (elf_machine_reject_phdr_p
+ (phdr, ehdr->e_phnum, fbp->buf, fbp->len,
+ loader, fd)))
+ goto close_and_out;
+
+ /* Check .note.ABI-tag if present. */
+ for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph)
+ if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4)
+ {
+ ElfW(Addr) size = ph->p_filesz;
+
+ if (ph->p_offset + size <= (size_t) fbp->len)
+ abi_note = (void *) (fbp->buf + ph->p_offset);
+ else
+ {
+ abi_note = alloca (size);
+ __lseek (fd, ph->p_offset, SEEK_SET);
+ if (__libc_read (fd, (void *) abi_note, size) != size)
+ goto read_error;
+ }
+
+ while (memcmp (abi_note, &expected_note, sizeof (expected_note)))
+ {
+#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
+ ElfW(Addr) note_size = 3 * sizeof (ElfW(Word))
+ + ROUND (abi_note[0])
+ + ROUND (abi_note[1]);
+
+ if (size - 32 < note_size)
+ {
+ size = 0;
+ break;
+ }
+ size -= note_size;
+ abi_note = (void *) abi_note + note_size;
+ }
+
+ if (size == 0)
+ continue;
+
+ osversion = (abi_note[5] & 0xff) * 65536
+ + (abi_note[6] & 0xff) * 256
+ + (abi_note[7] & 0xff);
+ if (abi_note[4] != __ABI_TAG_OS
+ || (GLRO(dl_osversion) && GLRO(dl_osversion) < osversion))
+ {
+ close_and_out:
+ __close (fd);
+ __set_errno (ENOENT);
+ fd = -1;
+ }
+
+ break;
+ }
+ }
+
+ return fd;
+}
+
+/* Try to open NAME in one of the directories in *DIRSP.
+ Return the fd, or -1. If successful, fill in *REALNAME
+ with the malloc'd full directory name. If it turns out
+ that none of the directories in *DIRSP exists, *DIRSP is
+ replaced with (void *) -1, and the old value is free()d
+ if MAY_FREE_DIRS is true. */
+
+static int
+open_path (const char *name, size_t namelen, int mode,
+ struct r_search_path_struct *sps, char **realname,
+ struct filebuf *fbp, struct link_map *loader, int whatcode,
+ bool *found_other_class)
+{
+ struct r_search_path_elem **dirs = sps->dirs;
+ char *buf;
+ int fd = -1;
+ const char *current_what = NULL;
+ int any = 0;
+
+ if (__glibc_unlikely (dirs == NULL))
+ /* We're called before _dl_init_paths when loading the main executable
+ given on the command line when rtld is run directly. */
+ return -1;
+
+ buf = alloca (max_dirnamelen + max_capstrlen + namelen);
+ do
+ {
+ struct r_search_path_elem *this_dir = *dirs;
+ size_t buflen = 0;
+ size_t cnt;
+ char *edp;
+ int here_any = 0;
+ int err;
+
+ /* If we are debugging the search for libraries print the path
+ now if it hasn't happened now. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)
+ && current_what != this_dir->what)
+ {
+ current_what = this_dir->what;
+ print_search_path (dirs, current_what, this_dir->where);
+ }
+
+ edp = (char *) __mempcpy (buf, this_dir->dirname, this_dir->dirnamelen);
+ for (cnt = 0; fd == -1 && cnt < ncapstr; ++cnt)
+ {
+ /* Skip this directory if we know it does not exist. */
+ if (this_dir->status[cnt] == nonexisting)
+ continue;
+
+ buflen =
+ ((char *) __mempcpy (__mempcpy (edp, capstr[cnt].str,
+ capstr[cnt].len),
+ name, namelen)
+ - buf);
+
+ /* Print name we try if this is wanted. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
+ _dl_debug_printf (" trying file=%s\n", buf);
+
+ fd = open_verify (buf, -1, fbp, loader, whatcode, mode,
+ found_other_class, false);
+ if (this_dir->status[cnt] == unknown)
+ {
+ if (fd != -1)
+ this_dir->status[cnt] = existing;
+ /* Do not update the directory information when loading
+ auditing code. We must try to disturb the program as
+ little as possible. */
+ else if (loader == NULL
+ || GL(dl_ns)[loader->l_ns]._ns_loaded->l_auditing == 0)
+ {
+ /* We failed to open machine dependent library. Let's
+ test whether there is any directory at all. */
+ struct stat64 st;
+
+ buf[buflen - namelen - 1] = '\0';
+
+ if (__xstat64 (_STAT_VER, buf, &st) != 0
+ || ! S_ISDIR (st.st_mode))
+ /* The directory does not exist or it is no directory. */
+ this_dir->status[cnt] = nonexisting;
+ else
+ this_dir->status[cnt] = existing;
+ }
+ }
+
+ /* Remember whether we found any existing directory. */
+ here_any |= this_dir->status[cnt] != nonexisting;
+
+ if (fd != -1 && __glibc_unlikely (mode & __RTLD_SECURE)
+ && __libc_enable_secure)
+ {
+ /* This is an extra security effort to make sure nobody can
+ preload broken shared objects which are in the trusted
+ directories and so exploit the bugs. */
+ struct stat64 st;
+
+ if (__fxstat64 (_STAT_VER, fd, &st) != 0
+ || (st.st_mode & S_ISUID) == 0)
+ {
+ /* The shared object cannot be tested for being SUID
+ or this bit is not set. In this case we must not
+ use this object. */
+ __close (fd);
+ fd = -1;
+ /* We simply ignore the file, signal this by setting
+ the error value which would have been set by `open'. */
+ errno = ENOENT;
+ }
+ }
+ }
+
+ if (fd != -1)
+ {
+ *realname = (char *) malloc (buflen);
+ if (*realname != NULL)
+ {
+ memcpy (*realname, buf, buflen);
+ return fd;
+ }
+ else
+ {
+ /* No memory for the name, we certainly won't be able
+ to load and link it. */
+ __close (fd);
+ return -1;
+ }
+ }
+ if (here_any && (err = errno) != ENOENT && err != EACCES)
+ /* The file exists and is readable, but something went wrong. */
+ return -1;
+
+ /* Remember whether we found anything. */
+ any |= here_any;
+ }
+ while (*++dirs != NULL);
+
+ /* Remove the whole path if none of the directories exists. */
+ if (__glibc_unlikely (! any))
+ {
+ /* Paths which were allocated using the minimal malloc() in ld.so
+ must not be freed using the general free() in libc. */
+ if (sps->malloced)
+ free (sps->dirs);
+
+ /* rtld_search_dirs and env_path_list are attribute_relro, therefore
+ avoid writing into it. */
+ if (sps != &rtld_search_dirs && sps != &env_path_list)
+ sps->dirs = (void *) -1;
+ }
+
+ return -1;
+}
+
+/* Map in the shared object file NAME. */
+
+struct link_map *
+internal_function
+_dl_map_object (struct link_map *loader, const char *name,
+ int type, int trace_mode, int mode, Lmid_t nsid)
+{
+ int fd;
+ const char *origname = NULL;
+ char *realname;
+ char *name_copy;
+ struct link_map *l;
+ struct filebuf fb;
+
+ assert (nsid >= 0);
+ assert (nsid < GL(dl_nns));
+
+ /* Look for this name among those already loaded. */
+ for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
+ {
+ /* If the requested name matches the soname of a loaded object,
+ use that object. Elide this check for names that have not
+ yet been opened. */
+ if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0))
+ continue;
+ if (!_dl_name_match_p (name, l))
+ {
+ const char *soname;
+
+ if (__glibc_likely (l->l_soname_added)
+ || l->l_info[DT_SONAME] == NULL)
+ continue;
+
+ soname = ((const char *) D_PTR (l, l_info[DT_STRTAB])
+ + l->l_info[DT_SONAME]->d_un.d_val);
+ if (strcmp (name, soname) != 0)
+ continue;
+
+ /* We have a match on a new name -- cache it. */
+ add_name_to_object (l, soname);
+ l->l_soname_added = 1;
+ }
+
+ /* We have a match. */
+ return l;
+ }
+
+ /* Display information if we are debugging. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
+ && loader != NULL)
+ _dl_debug_printf ((mode & __RTLD_CALLMAP) == 0
+ ? "\nfile=%s [%lu]; needed by %s [%lu]\n"
+ : "\nfile=%s [%lu]; dynamically loaded by %s [%lu]\n",
+ name, nsid, DSO_FILENAME (loader->l_name), loader->l_ns);
+
+#ifdef SHARED
+ /* Give the auditing libraries a chance to change the name before we
+ try anything. */
+ if (__glibc_unlikely (GLRO(dl_naudit) > 0)
+ && (loader == NULL || loader->l_auditing == 0))
+ {
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->objsearch != NULL)
+ {
+ const char *before = name;
+ name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
+ LA_SER_ORIG);
+ if (name == NULL)
+ {
+ /* Do not try anything further. */
+ fd = -1;
+ goto no_file;
+ }
+ if (before != name && strcmp (before, name) != 0)
+ {
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("audit changed filename %s -> %s\n",
+ before, name);
+
+ if (origname == NULL)
+ origname = before;
+ }
+ }
+
+ afct = afct->next;
+ }
+ }
+#endif
+
+ /* Will be true if we found a DSO which is of the other ELF class. */
+ bool found_other_class = false;
+
+ if (strchr (name, '/') == NULL)
+ {
+ /* Search for NAME in several places. */
+
+ size_t namelen = strlen (name) + 1;
+
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
+ _dl_debug_printf ("find library=%s [%lu]; searching\n", name, nsid);
+
+ fd = -1;
+
+ /* When the object has the RUNPATH information we don't use any
+ RPATHs. */
+ if (loader == NULL || loader->l_info[DT_RUNPATH] == NULL)
+ {
+ /* This is the executable's map (if there is one). Make sure that
+ we do not look at it twice. */
+ struct link_map *main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+ bool did_main_map = false;
+
+ /* First try the DT_RPATH of the dependent object that caused NAME
+ to be loaded. Then that object's dependent, and on up. */
+ for (l = loader; l; l = l->l_loader)
+ if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
+ {
+ fd = open_path (name, namelen, mode,
+ &l->l_rpath_dirs,
+ &realname, &fb, loader, LA_SER_RUNPATH,
+ &found_other_class);
+ if (fd != -1)
+ break;
+
+ did_main_map |= l == main_map;
+ }
+
+ /* If dynamically linked, try the DT_RPATH of the executable
+ itself. NB: we do this for lookups in any namespace. */
+ if (fd == -1 && !did_main_map
+ && main_map != NULL && main_map->l_type != lt_loaded
+ && cache_rpath (main_map, &main_map->l_rpath_dirs, DT_RPATH,
+ "RPATH"))
+ fd = open_path (name, namelen, mode,
+ &main_map->l_rpath_dirs,
+ &realname, &fb, loader ?: main_map, LA_SER_RUNPATH,
+ &found_other_class);
+ }
+
+ /* Try the LD_LIBRARY_PATH environment variable. */
+ if (fd == -1 && env_path_list.dirs != (void *) -1)
+ fd = open_path (name, namelen, mode, &env_path_list,
+ &realname, &fb,
+ loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
+ LA_SER_LIBPATH, &found_other_class);
+
+ /* Look at the RUNPATH information for this binary. */
+ if (fd == -1 && loader != NULL
+ && cache_rpath (loader, &loader->l_runpath_dirs,
+ DT_RUNPATH, "RUNPATH"))
+ fd = open_path (name, namelen, mode,
+ &loader->l_runpath_dirs, &realname, &fb, loader,
+ LA_SER_RUNPATH, &found_other_class);
+
+ if (fd == -1)
+ {
+ realname = _dl_sysdep_open_object (name, namelen, &fd);
+ if (realname != NULL)
+ {
+ fd = open_verify (realname, fd,
+ &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
+ LA_SER_CONFIG, mode, &found_other_class,
+ false);
+ if (fd == -1)
+ free (realname);
+ }
+ }
+
+#ifdef USE_LDCONFIG
+ if (fd == -1
+ && (__glibc_likely ((mode & __RTLD_SECURE) == 0)
+ || ! __libc_enable_secure)
+ && __glibc_likely (GLRO(dl_inhibit_cache) == 0))
+ {
+ /* Check the list of libraries in the file /etc/ld.so.cache,
+ for compatibility with Linux's ldconfig program. */
+ char *cached = _dl_load_cache_lookup (name);
+
+ if (cached != NULL)
+ {
+ // XXX Correct to unconditionally default to namespace 0?
+ l = (loader
+ ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded
+# ifdef SHARED
+ ?: &GL(dl_rtld_map)
+# endif
+ );
+
+ /* If the loader has the DF_1_NODEFLIB flag set we must not
+ use a cache entry from any of these directories. */
+ if (__glibc_unlikely (l->l_flags_1 & DF_1_NODEFLIB))
+ {
+ const char *dirp = system_dirs;
+ unsigned int cnt = 0;
+
+ do
+ {
+ if (memcmp (cached, dirp, system_dirs_len[cnt]) == 0)
+ {
+ /* The prefix matches. Don't use the entry. */
+ free (cached);
+ cached = NULL;
+ break;
+ }
+
+ dirp += system_dirs_len[cnt] + 1;
+ ++cnt;
+ }
+ while (cnt < nsystem_dirs_len);
+ }
+
+ if (cached != NULL)
+ {
+ fd = open_verify (cached, -1,
+ &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
+ LA_SER_CONFIG, mode, &found_other_class,
+ false);
+ if (__glibc_likely (fd != -1))
+ realname = cached;
+ else
+ free (cached);
+ }
+ }
+ }
+#endif
+
+ /* Finally, try the default path. */
+ if (fd == -1
+ && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
+ || __glibc_likely (!(l->l_flags_1 & DF_1_NODEFLIB)))
+ && rtld_search_dirs.dirs != (void *) -1)
+ fd = open_path (name, namelen, mode, &rtld_search_dirs,
+ &realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
+
+ /* Add another newline when we are tracing the library loading. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
+ _dl_debug_printf ("\n");
+ }
+ else
+ {
+ /* The path may contain dynamic string tokens. */
+ realname = (loader
+ ? expand_dynamic_string_token (loader, name, 0)
+ : __strdup (name));
+ if (realname == NULL)
+ fd = -1;
+ else
+ {
+ fd = open_verify (realname, -1, &fb,
+ loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, mode,
+ &found_other_class, true);
+ if (__glibc_unlikely (fd == -1))
+ free (realname);
+ }
+ }
+
+#ifdef SHARED
+ no_file:
+#endif
+ /* In case the LOADER information has only been provided to get to
+ the appropriate RUNPATH/RPATH information we do not need it
+ anymore. */
+ if (mode & __RTLD_CALLMAP)
+ loader = NULL;
+
+ if (__glibc_unlikely (fd == -1))
+ {
+ if (trace_mode
+ && __glibc_likely ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) == 0))
+ {
+ /* We haven't found an appropriate library. But since we
+ are only interested in the list of libraries this isn't
+ so severe. Fake an entry with all the information we
+ have. */
+ static const Elf_Symndx dummy_bucket = STN_UNDEF;
+
+ /* Allocate a new object map. */
+ if ((name_copy = __strdup (name)) == NULL
+ || (l = _dl_new_object (name_copy, name, type, loader,
+ mode, nsid)) == NULL)
+ {
+ free (name_copy);
+ _dl_signal_error (ENOMEM, name, NULL,
+ N_("cannot create shared object descriptor"));
+ }
+ /* Signal that this is a faked entry. */
+ l->l_faked = 1;
+ /* Since the descriptor is initialized with zero we do not
+ have do this here.
+ l->l_reserved = 0; */
+ l->l_buckets = &dummy_bucket;
+ l->l_nbuckets = 1;
+ l->l_relocated = 1;
+
+ /* Enter the object in the object list. */
+ _dl_add_to_namespace_list (l, nsid);
+
+ return l;
+ }
+ else if (found_other_class)
+ _dl_signal_error (0, name, NULL,
+ ELFW(CLASS) == ELFCLASS32
+ ? N_("wrong ELF class: ELFCLASS64")
+ : N_("wrong ELF class: ELFCLASS32"));
+ else
+ _dl_signal_error (errno, name, NULL,
+ N_("cannot open shared object file"));
+ }
+
+ void *stack_end = __libc_stack_end;
+ return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader,
+ type, mode, &stack_end, nsid);
+}
+
+struct add_path_state
+{
+ bool counting;
+ unsigned int idx;
+ Dl_serinfo *si;
+ char *allocptr;
+};
+
+static void
+add_path (struct add_path_state *p, const struct r_search_path_struct *sps,
+ unsigned int flags)
+{
+ if (sps->dirs != (void *) -1)
+ {
+ struct r_search_path_elem **dirs = sps->dirs;
+ do
+ {
+ const struct r_search_path_elem *const r = *dirs++;
+ if (p->counting)
+ {
+ p->si->dls_cnt++;
+ p->si->dls_size += MAX (2, r->dirnamelen);
+ }
+ else
+ {
+ Dl_serpath *const sp = &p->si->dls_serpath[p->idx++];
+ sp->dls_name = p->allocptr;
+ if (r->dirnamelen < 2)
+ *p->allocptr++ = r->dirnamelen ? '/' : '.';
+ else
+ p->allocptr = __mempcpy (p->allocptr,
+ r->dirname, r->dirnamelen - 1);
+ *p->allocptr++ = '\0';
+ sp->dls_flags = flags;
+ }
+ }
+ while (*dirs != NULL);
+ }
+}
+
+void
+internal_function
+_dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
+{
+ if (counting)
+ {
+ si->dls_cnt = 0;
+ si->dls_size = 0;
+ }
+
+ struct add_path_state p =
+ {
+ .counting = counting,
+ .idx = 0,
+ .si = si,
+ .allocptr = (char *) &si->dls_serpath[si->dls_cnt]
+ };
+
+# define add_path(p, sps, flags) add_path(p, sps, 0) /* XXX */
+
+ /* When the object has the RUNPATH information we don't use any RPATHs. */
+ if (loader->l_info[DT_RUNPATH] == NULL)
+ {
+ /* First try the DT_RPATH of the dependent object that caused NAME
+ to be loaded. Then that object's dependent, and on up. */
+
+ struct link_map *l = loader;
+ do
+ {
+ if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
+ add_path (&p, &l->l_rpath_dirs, XXX_RPATH);
+ l = l->l_loader;
+ }
+ while (l != NULL);
+
+ /* If dynamically linked, try the DT_RPATH of the executable itself. */
+ if (loader->l_ns == LM_ID_BASE)
+ {
+ l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+ if (l != NULL && l->l_type != lt_loaded && l != loader)
+ if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
+ add_path (&p, &l->l_rpath_dirs, XXX_RPATH);
+ }
+ }
+
+ /* Try the LD_LIBRARY_PATH environment variable. */
+ add_path (&p, &env_path_list, XXX_ENV);
+
+ /* Look at the RUNPATH information for this binary. */
+ if (cache_rpath (loader, &loader->l_runpath_dirs, DT_RUNPATH, "RUNPATH"))
+ add_path (&p, &loader->l_runpath_dirs, XXX_RUNPATH);
+
+ /* XXX
+ Here is where ld.so.cache gets checked, but we don't have
+ a way to indicate that in the results for Dl_serinfo. */
+
+ /* Finally, try the default path. */
+ if (!(loader->l_flags_1 & DF_1_NODEFLIB))
+ add_path (&p, &rtld_search_dirs, XXX_default);
+
+ if (counting)
+ /* Count the struct size before the string area, which we didn't
+ know before we completed dls_cnt. */
+ si->dls_size += (char *) &si->dls_serpath[si->dls_cnt] - (char *) si;
+}
diff --git a/REORG.TODO/elf/dl-load.h b/REORG.TODO/elf/dl-load.h
new file mode 100644
index 0000000000..7cd6214d4e
--- /dev/null
+++ b/REORG.TODO/elf/dl-load.h
@@ -0,0 +1,135 @@
+/* Map in a shared object's segments from the file.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _DL_LOAD_H
+#define _DL_LOAD_H 1
+
+#include <link.h>
+#include <sys/mman.h>
+
+
+/* On some systems, no flag bits are given to specify file mapping. */
+#ifndef MAP_FILE
+# define MAP_FILE 0
+#endif
+
+/* The right way to map in the shared library files is MAP_COPY, which
+ makes a virtual copy of the data at the time of the mmap call; this
+ guarantees the mapped pages will be consistent even if the file is
+ overwritten. Some losing VM systems like Linux's lack MAP_COPY. All we
+ get is MAP_PRIVATE, which copies each page when it is modified; this
+ means if the file is overwritten, we may at some point get some pages
+ from the new version after starting with pages from the old version.
+
+ To make up for the lack and avoid the overwriting problem,
+ what Linux does have is MAP_DENYWRITE. This prevents anyone
+ from modifying the file while we have it mapped. */
+#ifndef MAP_COPY
+# ifdef MAP_DENYWRITE
+# define MAP_COPY (MAP_PRIVATE | MAP_DENYWRITE)
+# else
+# define MAP_COPY MAP_PRIVATE
+# endif
+#endif
+
+/* Some systems link their relocatable objects for another base address
+ than 0. We want to know the base address for these such that we can
+ subtract this address from the segment addresses during mapping.
+ This results in a more efficient address space usage. Defaults to
+ zero for almost all systems. */
+#ifndef MAP_BASE_ADDR
+# define MAP_BASE_ADDR(l) 0
+#endif
+
+
+/* Handle situations where we have a preferred location in memory for
+ the shared objects. */
+#ifdef ELF_PREFERRED_ADDRESS_DATA
+ELF_PREFERRED_ADDRESS_DATA;
+#endif
+#ifndef ELF_PREFERRED_ADDRESS
+# define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref)
+#endif
+#ifndef ELF_FIXED_ADDRESS
+# define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0)
+#endif
+
+
+/* This structure describes one PT_LOAD command.
+ Its details have been expanded out and converted. */
+struct loadcmd
+{
+ ElfW(Addr) mapstart, mapend, dataend, allocend;
+ ElfW(Off) mapoff;
+ int prot; /* PROT_* bits. */
+};
+
+
+/* This is a subroutine of _dl_map_segments. It should be called for each
+ load command, some time after L->l_addr has been set correctly. It is
+ responsible for setting up the l_text_end and l_phdr fields. */
+static void __always_inline
+_dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header,
+ const struct loadcmd *c)
+{
+ if (c->prot & PROT_EXEC)
+ l->l_text_end = l->l_addr + c->mapend;
+
+ if (l->l_phdr == 0
+ && c->mapoff <= header->e_phoff
+ && ((size_t) (c->mapend - c->mapstart + c->mapoff)
+ >= header->e_phoff + header->e_phnum * sizeof (ElfW(Phdr))))
+ /* Found the program header in this segment. */
+ l->l_phdr = (void *) (uintptr_t) (c->mapstart + header->e_phoff
+ - c->mapoff);
+}
+
+
+/* This is a subroutine of _dl_map_object_from_fd. It is responsible
+ for filling in several fields in *L: l_map_start, l_map_end, l_addr,
+ l_contiguous, l_text_end, l_phdr. On successful return, all the
+ segments are mapped (or copied, or whatever) from the file into their
+ final places in the address space, with the correct page permissions,
+ and any bss-like regions already zeroed. It returns a null pointer
+ on success, or an error message string (to be translated) on error
+ (having also set errno).
+
+ The file <dl-map-segments.h> defines this function. The canonical
+ implementation in elf/dl-map-segments.h might be replaced by a sysdeps
+ version. */
+static const char *_dl_map_segments (struct link_map *l, int fd,
+ const ElfW(Ehdr) *header, int type,
+ const struct loadcmd loadcmds[],
+ size_t nloadcmds,
+ const size_t maplength,
+ bool has_holes,
+ struct link_map *loader);
+
+/* All the error message strings _dl_map_segments might return are
+ listed here so that different implementations in different sysdeps
+ dl-map-segments.h files all use consistent strings that are
+ guaranteed to have translations. */
+#define DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT \
+ N_("failed to map segment from shared object")
+#define DL_MAP_SEGMENTS_ERROR_MPROTECT \
+ N_("cannot change memory protections")
+#define DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL \
+ N_("cannot map zero-fill pages")
+
+
+#endif /* dl-load.h */
diff --git a/REORG.TODO/elf/dl-lookup.c b/REORG.TODO/elf/dl-lookup.c
new file mode 100644
index 0000000000..3d2369dbf2
--- /dev/null
+++ b/REORG.TODO/elf/dl-lookup.c
@@ -0,0 +1,1129 @@
+/* Look up a symbol in the loaded objects.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <alloca.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <dl-hash.h>
+#include <dl-machine.h>
+#include <sysdep-cancel.h>
+#include <libc-lock.h>
+#include <tls.h>
+#include <atomic.h>
+
+#include <assert.h>
+
+/* Return nonzero if check_match should consider SYM to fail to match a
+ symbol reference for some machine-specific reason. */
+#ifndef ELF_MACHINE_SYM_NO_MATCH
+# define ELF_MACHINE_SYM_NO_MATCH(sym) 0
+#endif
+
+#define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
+
+
+struct sym_val
+ {
+ const ElfW(Sym) *s;
+ struct link_map *m;
+ };
+
+
+#define make_string(string, rest...) \
+ ({ \
+ const char *all[] = { string, ## rest }; \
+ size_t len, cnt; \
+ char *result, *cp; \
+ \
+ len = 1; \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ len += strlen (all[cnt]); \
+ \
+ cp = result = alloca (len); \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ cp = __stpcpy (cp, all[cnt]); \
+ \
+ result; \
+ })
+
+/* Statistics function. */
+#ifdef SHARED
+# define bump_num_relocations() ++GL(dl_num_relocations)
+#else
+# define bump_num_relocations() ((void) 0)
+#endif
+
+/* Utility function for do_lookup_x. The caller is called with undef_name,
+ ref, version, flags and type_class, and those are passed as the first
+ five arguments. The caller then computes sym, symidx, strtab, and map
+ and passes them as the next four arguments. Lastly the caller passes in
+ versioned_sym and num_versions which are modified by check_match during
+ the checking process. */
+static const ElfW(Sym) *
+check_match (const char *const undef_name,
+ const ElfW(Sym) *const ref,
+ const struct r_found_version *const version,
+ const int flags,
+ const int type_class,
+ const ElfW(Sym) *const sym,
+ const Elf_Symndx symidx,
+ const char *const strtab,
+ const struct link_map *const map,
+ const ElfW(Sym) **const versioned_sym,
+ int *const num_versions)
+{
+ unsigned int stt = ELFW(ST_TYPE) (sym->st_info);
+ assert (ELF_RTYPE_CLASS_PLT == 1);
+ if (__glibc_unlikely ((sym->st_value == 0 /* No value. */
+ && stt != STT_TLS)
+ || ELF_MACHINE_SYM_NO_MATCH (sym)
+ || (type_class & (sym->st_shndx == SHN_UNDEF))))
+ return NULL;
+
+ /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC,
+ STT_COMMON, STT_TLS, and STT_GNU_IFUNC since these are no
+ code/data definitions. */
+#define ALLOWED_STT \
+ ((1 << STT_NOTYPE) | (1 << STT_OBJECT) | (1 << STT_FUNC) \
+ | (1 << STT_COMMON) | (1 << STT_TLS) | (1 << STT_GNU_IFUNC))
+ if (__glibc_unlikely (((1 << stt) & ALLOWED_STT) == 0))
+ return NULL;
+
+ if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
+ /* Not the symbol we are looking for. */
+ return NULL;
+
+ const ElfW(Half) *verstab = map->l_versyms;
+ if (version != NULL)
+ {
+ if (__glibc_unlikely (verstab == NULL))
+ {
+ /* We need a versioned symbol but haven't found any. If
+ this is the object which is referenced in the verneed
+ entry it is a bug in the library since a symbol must
+ not simply disappear.
+
+ It would also be a bug in the object since it means that
+ the list of required versions is incomplete and so the
+ tests in dl-version.c haven't found a problem.*/
+ assert (version->filename == NULL
+ || ! _dl_name_match_p (version->filename, map));
+
+ /* Otherwise we accept the symbol. */
+ }
+ else
+ {
+ /* We can match the version information or use the
+ default one if it is not hidden. */
+ ElfW(Half) ndx = verstab[symidx] & 0x7fff;
+ if ((map->l_versions[ndx].hash != version->hash
+ || strcmp (map->l_versions[ndx].name, version->name))
+ && (version->hidden || map->l_versions[ndx].hash
+ || (verstab[symidx] & 0x8000)))
+ /* It's not the version we want. */
+ return NULL;
+ }
+ }
+ else
+ {
+ /* No specific version is selected. There are two ways we
+ can got here:
+
+ - a binary which does not include versioning information
+ is loaded
+
+ - dlsym() instead of dlvsym() is used to get a symbol which
+ might exist in more than one form
+
+ If the library does not provide symbol version information
+ there is no problem at all: we simply use the symbol if it
+ is defined.
+
+ These two lookups need to be handled differently if the
+ library defines versions. In the case of the old
+ unversioned application the oldest (default) version
+ should be used. In case of a dlsym() call the latest and
+ public interface should be returned. */
+ if (verstab != NULL)
+ {
+ if ((verstab[symidx] & 0x7fff)
+ >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3))
+ {
+ /* Don't accept hidden symbols. */
+ if ((verstab[symidx] & 0x8000) == 0
+ && (*num_versions)++ == 0)
+ /* No version so far. */
+ *versioned_sym = sym;
+
+ return NULL;
+ }
+ }
+ }
+
+ /* There cannot be another entry for this symbol so stop here. */
+ return sym;
+}
+
+/* Utility function for do_lookup_unique. Add a symbol to TABLE. */
+static void
+enter_unique_sym (struct unique_sym *table, size_t size,
+ unsigned int hash, const char *name,
+ const ElfW(Sym) *sym, const struct link_map *map)
+{
+ size_t idx = hash % size;
+ size_t hash2 = 1 + hash % (size - 2);
+ while (table[idx].name != NULL)
+ {
+ idx += hash2;
+ if (idx >= size)
+ idx -= size;
+ }
+
+ table[idx].hashval = hash;
+ table[idx].name = name;
+ table[idx].sym = sym;
+ table[idx].map = map;
+}
+
+/* Utility function for do_lookup_x. Lookup an STB_GNU_UNIQUE symbol
+ in the unique symbol table, creating a new entry if necessary.
+ Return the matching symbol in RESULT. */
+static void
+do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
+ const struct link_map *map, struct sym_val *result,
+ int type_class, const ElfW(Sym) *sym, const char *strtab,
+ const ElfW(Sym) *ref, const struct link_map *undef_map)
+{
+ /* We have to determine whether we already found a symbol with this
+ name before. If not then we have to add it to the search table.
+ If we already found a definition we have to use it. */
+
+ struct unique_sym_table *tab
+ = &GL(dl_ns)[map->l_ns]._ns_unique_sym_table;
+
+ __rtld_lock_lock_recursive (tab->lock);
+
+ struct unique_sym *entries = tab->entries;
+ size_t size = tab->size;
+ if (entries != NULL)
+ {
+ size_t idx = new_hash % size;
+ size_t hash2 = 1 + new_hash % (size - 2);
+ while (1)
+ {
+ if (entries[idx].hashval == new_hash
+ && strcmp (entries[idx].name, undef_name) == 0)
+ {
+ if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
+ {
+ /* We possibly have to initialize the central
+ copy from the copy addressed through the
+ relocation. */
+ result->s = sym;
+ result->m = (struct link_map *) map;
+ }
+ else
+ {
+ result->s = entries[idx].sym;
+ result->m = (struct link_map *) entries[idx].map;
+ }
+ __rtld_lock_unlock_recursive (tab->lock);
+ return;
+ }
+
+ if (entries[idx].name == NULL)
+ break;
+
+ idx += hash2;
+ if (idx >= size)
+ idx -= size;
+ }
+
+ if (size * 3 <= tab->n_elements * 4)
+ {
+ /* Expand the table. */
+#ifdef RTLD_CHECK_FOREIGN_CALL
+ /* This must not happen during runtime relocations. */
+ assert (!RTLD_CHECK_FOREIGN_CALL);
+#endif
+ size_t newsize = _dl_higher_prime_number (size + 1);
+ struct unique_sym *newentries
+ = calloc (sizeof (struct unique_sym), newsize);
+ if (newentries == NULL)
+ {
+ nomem:
+ __rtld_lock_unlock_recursive (tab->lock);
+ _dl_fatal_printf ("out of memory\n");
+ }
+
+ for (idx = 0; idx < size; ++idx)
+ if (entries[idx].name != NULL)
+ enter_unique_sym (newentries, newsize, entries[idx].hashval,
+ entries[idx].name, entries[idx].sym,
+ entries[idx].map);
+
+ tab->free (entries);
+ tab->size = newsize;
+ size = newsize;
+ entries = tab->entries = newentries;
+ tab->free = free;
+ }
+ }
+ else
+ {
+#ifdef RTLD_CHECK_FOREIGN_CALL
+ /* This must not happen during runtime relocations. */
+ assert (!RTLD_CHECK_FOREIGN_CALL);
+#endif
+
+#ifdef SHARED
+ /* If tab->entries is NULL, but tab->size is not, it means
+ this is the second, conflict finding, lookup for
+ LD_TRACE_PRELINKING in _dl_debug_bindings. Don't
+ allocate anything and don't enter anything into the
+ hash table. */
+ if (__glibc_unlikely (tab->size))
+ {
+ assert (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK);
+ goto success;
+ }
+#endif
+
+#define INITIAL_NUNIQUE_SYM_TABLE 31
+ size = INITIAL_NUNIQUE_SYM_TABLE;
+ entries = calloc (sizeof (struct unique_sym), size);
+ if (entries == NULL)
+ goto nomem;
+
+ tab->entries = entries;
+ tab->size = size;
+ tab->free = free;
+ }
+
+ if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
+ enter_unique_sym (entries, size, new_hash, strtab + sym->st_name, ref,
+ undef_map);
+ else
+ {
+ enter_unique_sym (entries, size,
+ new_hash, strtab + sym->st_name, sym, map);
+
+ if (map->l_type == lt_loaded)
+ /* Make sure we don't unload this object by
+ setting the appropriate flag. */
+ ((struct link_map *) map)->l_flags_1 |= DF_1_NODELETE;
+ }
+ ++tab->n_elements;
+
+#ifdef SHARED
+ success:
+#endif
+ __rtld_lock_unlock_recursive (tab->lock);
+
+ result->s = sym;
+ result->m = (struct link_map *) map;
+}
+
+/* Inner part of the lookup functions. We return a value > 0 if we
+ found the symbol, the value 0 if nothing is found and < 0 if
+ something bad happened. */
+static int
+__attribute_noinline__
+do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
+ unsigned long int *old_hash, const ElfW(Sym) *ref,
+ struct sym_val *result, struct r_scope_elem *scope, size_t i,
+ const struct r_found_version *const version, int flags,
+ struct link_map *skip, int type_class, struct link_map *undef_map)
+{
+ size_t n = scope->r_nlist;
+ /* Make sure we read the value before proceeding. Otherwise we
+ might use r_list pointing to the initial scope and r_nlist being
+ the value after a resize. That is the only path in dl-open.c not
+ protected by GSCOPE. A read barrier here might be to expensive. */
+ __asm volatile ("" : "+r" (n), "+m" (scope->r_list));
+ struct link_map **list = scope->r_list;
+
+ do
+ {
+ const struct link_map *map = list[i]->l_real;
+
+ /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
+ if (map == skip)
+ continue;
+
+ /* Don't search the executable when resolving a copy reloc. */
+ if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable)
+ continue;
+
+ /* Do not look into objects which are going to be removed. */
+ if (map->l_removed)
+ continue;
+
+ /* Print some debugging info if wanted. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS))
+ _dl_debug_printf ("symbol=%s; lookup in file=%s [%lu]\n",
+ undef_name, DSO_FILENAME (map->l_name),
+ map->l_ns);
+
+ /* If the hash table is empty there is nothing to do here. */
+ if (map->l_nbuckets == 0)
+ continue;
+
+ Elf_Symndx symidx;
+ int num_versions = 0;
+ const ElfW(Sym) *versioned_sym = NULL;
+
+ /* The tables for this map. */
+ const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+
+ const ElfW(Sym) *sym;
+ const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
+ if (__glibc_likely (bitmask != NULL))
+ {
+ ElfW(Addr) bitmask_word
+ = bitmask[(new_hash / __ELF_NATIVE_CLASS)
+ & map->l_gnu_bitmask_idxbits];
+
+ unsigned int hashbit1 = new_hash & (__ELF_NATIVE_CLASS - 1);
+ unsigned int hashbit2 = ((new_hash >> map->l_gnu_shift)
+ & (__ELF_NATIVE_CLASS - 1));
+
+ if (__glibc_unlikely ((bitmask_word >> hashbit1)
+ & (bitmask_word >> hashbit2) & 1))
+ {
+ Elf32_Word bucket = map->l_gnu_buckets[new_hash
+ % map->l_nbuckets];
+ if (bucket != 0)
+ {
+ const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
+
+ do
+ if (((*hasharr ^ new_hash) >> 1) == 0)
+ {
+ symidx = hasharr - map->l_gnu_chain_zero;
+ sym = check_match (undef_name, ref, version, flags,
+ type_class, &symtab[symidx], symidx,
+ strtab, map, &versioned_sym,
+ &num_versions);
+ if (sym != NULL)
+ goto found_it;
+ }
+ while ((*hasharr++ & 1u) == 0);
+ }
+ }
+ /* No symbol found. */
+ symidx = SHN_UNDEF;
+ }
+ else
+ {
+ if (*old_hash == 0xffffffff)
+ *old_hash = _dl_elf_hash (undef_name);
+
+ /* Use the old SysV-style hash table. Search the appropriate
+ hash bucket in this object's symbol table for a definition
+ for the same symbol name. */
+ for (symidx = map->l_buckets[*old_hash % map->l_nbuckets];
+ symidx != STN_UNDEF;
+ symidx = map->l_chain[symidx])
+ {
+ sym = check_match (undef_name, ref, version, flags,
+ type_class, &symtab[symidx], symidx,
+ strtab, map, &versioned_sym,
+ &num_versions);
+ if (sym != NULL)
+ goto found_it;
+ }
+ }
+
+ /* If we have seen exactly one versioned symbol while we are
+ looking for an unversioned symbol and the version is not the
+ default version we still accept this symbol since there are
+ no possible ambiguities. */
+ sym = num_versions == 1 ? versioned_sym : NULL;
+
+ if (sym != NULL)
+ {
+ found_it:
+ /* When UNDEF_MAP is NULL, which indicates we are called from
+ do_lookup_x on relocation against protected data, we skip
+ the data definion in the executable from copy reloc. */
+ if (ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA
+ && undef_map == NULL
+ && map->l_type == lt_executable
+ && type_class == ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA)
+ {
+ const ElfW(Sym) *s;
+ unsigned int i;
+
+#if ! ELF_MACHINE_NO_RELA
+ if (map->l_info[DT_RELA] != NULL
+ && map->l_info[DT_RELASZ] != NULL
+ && map->l_info[DT_RELASZ]->d_un.d_val != 0)
+ {
+ const ElfW(Rela) *rela
+ = (const ElfW(Rela) *) D_PTR (map, l_info[DT_RELA]);
+ unsigned int rela_count
+ = map->l_info[DT_RELASZ]->d_un.d_val / sizeof (*rela);
+
+ for (i = 0; i < rela_count; i++, rela++)
+ if (elf_machine_type_class (ELFW(R_TYPE) (rela->r_info))
+ == ELF_RTYPE_CLASS_COPY)
+ {
+ s = &symtab[ELFW(R_SYM) (rela->r_info)];
+ if (!strcmp (strtab + s->st_name, undef_name))
+ goto skip;
+ }
+ }
+#endif
+#if ! ELF_MACHINE_NO_REL
+ if (map->l_info[DT_REL] != NULL
+ && map->l_info[DT_RELSZ] != NULL
+ && map->l_info[DT_RELSZ]->d_un.d_val != 0)
+ {
+ const ElfW(Rel) *rel
+ = (const ElfW(Rel) *) D_PTR (map, l_info[DT_REL]);
+ unsigned int rel_count
+ = map->l_info[DT_RELSZ]->d_un.d_val / sizeof (*rel);
+
+ for (i = 0; i < rel_count; i++, rel++)
+ if (elf_machine_type_class (ELFW(R_TYPE) (rel->r_info))
+ == ELF_RTYPE_CLASS_COPY)
+ {
+ s = &symtab[ELFW(R_SYM) (rel->r_info)];
+ if (!strcmp (strtab + s->st_name, undef_name))
+ goto skip;
+ }
+ }
+#endif
+ }
+
+ /* Hidden and internal symbols are local, ignore them. */
+ if (__glibc_unlikely (dl_symbol_visibility_binds_local_p (sym)))
+ goto skip;
+
+ switch (ELFW(ST_BIND) (sym->st_info))
+ {
+ case STB_WEAK:
+ /* Weak definition. Use this value if we don't find another. */
+ if (__glibc_unlikely (GLRO(dl_dynamic_weak)))
+ {
+ if (! result->s)
+ {
+ result->s = sym;
+ result->m = (struct link_map *) map;
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+ case STB_GLOBAL:
+ /* Global definition. Just what we need. */
+ result->s = sym;
+ result->m = (struct link_map *) map;
+ return 1;
+
+ case STB_GNU_UNIQUE:;
+ do_lookup_unique (undef_name, new_hash, map, result, type_class,
+ sym, strtab, ref, undef_map);
+ return 1;
+
+ default:
+ /* Local symbols are ignored. */
+ break;
+ }
+ }
+
+skip:
+ /* If this current map is the one mentioned in the verneed entry
+ and we have not found a weak entry, it is a bug. */
+ if (symidx == STN_UNDEF && version != NULL && version->filename != NULL
+ && __glibc_unlikely (_dl_name_match_p (version->filename, map)))
+ return -1;
+ }
+ while (++i < n);
+
+ /* We have not found anything until now. */
+ return 0;
+}
+
+
+static uint_fast32_t
+dl_new_hash (const char *s)
+{
+ uint_fast32_t h = 5381;
+ for (unsigned char c = *s; c != '\0'; c = *++s)
+ h = h * 33 + c;
+ return h & 0xffffffff;
+}
+
+
+/* Add extra dependency on MAP to UNDEF_MAP. */
+static int
+internal_function
+add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
+{
+ struct link_map *runp;
+ unsigned int i;
+ int result = 0;
+
+ /* Avoid self-references and references to objects which cannot be
+ unloaded anyway. */
+ if (undef_map == map)
+ return 0;
+
+ /* Avoid references to objects which cannot be unloaded anyway. */
+ assert (map->l_type == lt_loaded);
+ if ((map->l_flags_1 & DF_1_NODELETE) != 0)
+ return 0;
+
+ struct link_map_reldeps *l_reldeps
+ = atomic_forced_read (undef_map->l_reldeps);
+
+ /* Make sure l_reldeps is read before l_initfini. */
+ atomic_read_barrier ();
+
+ /* Determine whether UNDEF_MAP already has a reference to MAP. First
+ look in the normal dependencies. */
+ struct link_map **l_initfini = atomic_forced_read (undef_map->l_initfini);
+ if (l_initfini != NULL)
+ {
+ for (i = 0; l_initfini[i] != NULL; ++i)
+ if (l_initfini[i] == map)
+ return 0;
+ }
+
+ /* No normal dependency. See whether we already had to add it
+ to the special list of dynamic dependencies. */
+ unsigned int l_reldepsact = 0;
+ if (l_reldeps != NULL)
+ {
+ struct link_map **list = &l_reldeps->list[0];
+ l_reldepsact = l_reldeps->act;
+ for (i = 0; i < l_reldepsact; ++i)
+ if (list[i] == map)
+ return 0;
+ }
+
+ /* Save serial number of the target MAP. */
+ unsigned long long serial = map->l_serial;
+
+ /* Make sure nobody can unload the object while we are at it. */
+ if (__glibc_unlikely (flags & DL_LOOKUP_GSCOPE_LOCK))
+ {
+ /* We can't just call __rtld_lock_lock_recursive (GL(dl_load_lock))
+ here, that can result in ABBA deadlock. */
+ THREAD_GSCOPE_RESET_FLAG ();
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+ /* While MAP value won't change, after THREAD_GSCOPE_RESET_FLAG ()
+ it can e.g. point to unallocated memory. So avoid the optimizer
+ treating the above read from MAP->l_serial as ensurance it
+ can safely dereference it. */
+ map = atomic_forced_read (map);
+
+ /* From this point on it is unsafe to dereference MAP, until it
+ has been found in one of the lists. */
+
+ /* Redo the l_initfini check in case undef_map's l_initfini
+ changed in the mean time. */
+ if (undef_map->l_initfini != l_initfini
+ && undef_map->l_initfini != NULL)
+ {
+ l_initfini = undef_map->l_initfini;
+ for (i = 0; l_initfini[i] != NULL; ++i)
+ if (l_initfini[i] == map)
+ goto out_check;
+ }
+
+ /* Redo the l_reldeps check if undef_map's l_reldeps changed in
+ the mean time. */
+ if (undef_map->l_reldeps != NULL)
+ {
+ if (undef_map->l_reldeps != l_reldeps)
+ {
+ struct link_map **list = &undef_map->l_reldeps->list[0];
+ l_reldepsact = undef_map->l_reldeps->act;
+ for (i = 0; i < l_reldepsact; ++i)
+ if (list[i] == map)
+ goto out_check;
+ }
+ else if (undef_map->l_reldeps->act > l_reldepsact)
+ {
+ struct link_map **list
+ = &undef_map->l_reldeps->list[0];
+ i = l_reldepsact;
+ l_reldepsact = undef_map->l_reldeps->act;
+ for (; i < l_reldepsact; ++i)
+ if (list[i] == map)
+ goto out_check;
+ }
+ }
+ }
+ else
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+ /* The object is not yet in the dependency list. Before we add
+ it make sure just one more time the object we are about to
+ reference is still available. There is a brief period in
+ which the object could have been removed since we found the
+ definition. */
+ runp = GL(dl_ns)[undef_map->l_ns]._ns_loaded;
+ while (runp != NULL && runp != map)
+ runp = runp->l_next;
+
+ if (runp != NULL)
+ {
+ /* The object is still available. */
+
+ /* MAP could have been dlclosed, freed and then some other dlopened
+ library could have the same link_map pointer. */
+ if (map->l_serial != serial)
+ goto out_check;
+
+ /* Redo the NODELETE check, as when dl_load_lock wasn't held
+ yet this could have changed. */
+ if ((map->l_flags_1 & DF_1_NODELETE) != 0)
+ goto out;
+
+ /* If the object with the undefined reference cannot be removed ever
+ just make sure the same is true for the object which contains the
+ definition. */
+ if (undef_map->l_type != lt_loaded
+ || (undef_map->l_flags_1 & DF_1_NODELETE) != 0)
+ {
+ map->l_flags_1 |= DF_1_NODELETE;
+ goto out;
+ }
+
+ /* Add the reference now. */
+ if (__glibc_unlikely (l_reldepsact >= undef_map->l_reldepsmax))
+ {
+ /* Allocate more memory for the dependency list. Since this
+ can never happen during the startup phase we can use
+ `realloc'. */
+ struct link_map_reldeps *newp;
+ unsigned int max
+ = undef_map->l_reldepsmax ? undef_map->l_reldepsmax * 2 : 10;
+
+#ifdef RTLD_PREPARE_FOREIGN_CALL
+ RTLD_PREPARE_FOREIGN_CALL;
+#endif
+
+ newp = malloc (sizeof (*newp) + max * sizeof (struct link_map *));
+ if (newp == NULL)
+ {
+ /* If we didn't manage to allocate memory for the list this is
+ no fatal problem. We simply make sure the referenced object
+ cannot be unloaded. This is semantically the correct
+ behavior. */
+ map->l_flags_1 |= DF_1_NODELETE;
+ goto out;
+ }
+ else
+ {
+ if (l_reldepsact)
+ memcpy (&newp->list[0], &undef_map->l_reldeps->list[0],
+ l_reldepsact * sizeof (struct link_map *));
+ newp->list[l_reldepsact] = map;
+ newp->act = l_reldepsact + 1;
+ atomic_write_barrier ();
+ void *old = undef_map->l_reldeps;
+ undef_map->l_reldeps = newp;
+ undef_map->l_reldepsmax = max;
+ if (old)
+ _dl_scope_free (old);
+ }
+ }
+ else
+ {
+ undef_map->l_reldeps->list[l_reldepsact] = map;
+ atomic_write_barrier ();
+ undef_map->l_reldeps->act = l_reldepsact + 1;
+ }
+
+ /* Display information if we are debugging. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("\
+\nfile=%s [%lu]; needed by %s [%lu] (relocation dependency)\n\n",
+ DSO_FILENAME (map->l_name),
+ map->l_ns,
+ DSO_FILENAME (undef_map->l_name),
+ undef_map->l_ns);
+ }
+ else
+ /* Whoa, that was bad luck. We have to search again. */
+ result = -1;
+
+ out:
+ /* Release the lock. */
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+ if (__glibc_unlikely (flags & DL_LOOKUP_GSCOPE_LOCK))
+ THREAD_GSCOPE_SET_FLAG ();
+
+ return result;
+
+ out_check:
+ if (map->l_serial != serial)
+ result = -1;
+ goto out;
+}
+
+static void
+internal_function
+_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
+ const ElfW(Sym) **ref, struct sym_val *value,
+ const struct r_found_version *version, int type_class,
+ int protected);
+
+
+/* Search loaded objects' symbol tables for a definition of the symbol
+ UNDEF_NAME, perhaps with a requested version for the symbol.
+
+ We must never have calls to the audit functions inside this function
+ or in any function which gets called. If this would happen the audit
+ code might create a thread which can throw off all the scope locking. */
+lookup_t
+internal_function
+_dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
+ const ElfW(Sym) **ref,
+ struct r_scope_elem *symbol_scope[],
+ const struct r_found_version *version,
+ int type_class, int flags, struct link_map *skip_map)
+{
+ const uint_fast32_t new_hash = dl_new_hash (undef_name);
+ unsigned long int old_hash = 0xffffffff;
+ struct sym_val current_value = { NULL, NULL };
+ struct r_scope_elem **scope = symbol_scope;
+
+ bump_num_relocations ();
+
+ /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK
+ is allowed if we look up a versioned symbol. */
+ assert (version == NULL
+ || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK))
+ == 0);
+
+ size_t i = 0;
+ if (__glibc_unlikely (skip_map != NULL))
+ /* Search the relevant loaded objects for a definition. */
+ while ((*scope)->r_list[i] != skip_map)
+ ++i;
+
+ /* Search the relevant loaded objects for a definition. */
+ for (size_t start = i; *scope != NULL; start = 0, ++scope)
+ {
+ int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ &current_value, *scope, start, version, flags,
+ skip_map, type_class, undef_map);
+ if (res > 0)
+ break;
+
+ if (__glibc_unlikely (res < 0) && skip_map == NULL)
+ {
+ /* Oh, oh. The file named in the relocation entry does not
+ contain the needed symbol. This code is never reached
+ for unversioned lookups. */
+ assert (version != NULL);
+ const char *reference_name = undef_map ? undef_map->l_name : "";
+
+ /* XXX We cannot translate the message. */
+ _dl_signal_cerror (0, DSO_FILENAME (reference_name),
+ N_("relocation error"),
+ make_string ("symbol ", undef_name, ", version ",
+ version->name,
+ " not defined in file ",
+ version->filename,
+ " with link time reference",
+ res == -2
+ ? " (no version symbols)" : ""));
+ *ref = NULL;
+ return 0;
+ }
+ }
+
+ if (__glibc_unlikely (current_value.s == NULL))
+ {
+ if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
+ && !(GLRO(dl_debug_mask) & DL_DEBUG_UNUSED))
+ {
+ /* We could find no value for a strong reference. */
+ const char *reference_name = undef_map ? undef_map->l_name : "";
+ const char *versionstr = version ? ", version " : "";
+ const char *versionname = (version && version->name
+ ? version->name : "");
+
+ /* XXX We cannot translate the message. */
+ _dl_signal_cerror (0, DSO_FILENAME (reference_name),
+ N_("symbol lookup error"),
+ make_string ("undefined symbol: ", undef_name,
+ versionstr, versionname));
+ }
+ *ref = NULL;
+ return 0;
+ }
+
+ int protected = (*ref
+ && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED);
+ if (__glibc_unlikely (protected != 0))
+ {
+ /* It is very tricky. We need to figure out what value to
+ return for the protected symbol. */
+ if (type_class == ELF_RTYPE_CLASS_PLT)
+ {
+ if (current_value.s != NULL && current_value.m != undef_map)
+ {
+ current_value.s = *ref;
+ current_value.m = undef_map;
+ }
+ }
+ else
+ {
+ struct sym_val protected_value = { NULL, NULL };
+
+ for (scope = symbol_scope; *scope != NULL; i = 0, ++scope)
+ if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ &protected_value, *scope, i, version, flags,
+ skip_map,
+ (ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA
+ && ELFW(ST_TYPE) ((*ref)->st_info) == STT_OBJECT
+ && type_class == ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA)
+ ? ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA
+ : ELF_RTYPE_CLASS_PLT, NULL) != 0)
+ break;
+
+ if (protected_value.s != NULL && protected_value.m != undef_map)
+ {
+ current_value.s = *ref;
+ current_value.m = undef_map;
+ }
+ }
+ }
+
+ /* We have to check whether this would bind UNDEF_MAP to an object
+ in the global scope which was dynamically loaded. In this case
+ we have to prevent the latter from being unloaded unless the
+ UNDEF_MAP object is also unloaded. */
+ if (__glibc_unlikely (current_value.m->l_type == lt_loaded)
+ /* Don't do this for explicit lookups as opposed to implicit
+ runtime lookups. */
+ && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0
+ /* Add UNDEF_MAP to the dependencies. */
+ && add_dependency (undef_map, current_value.m, flags) < 0)
+ /* Something went wrong. Perhaps the object we tried to reference
+ was just removed. Try finding another definition. */
+ return _dl_lookup_symbol_x (undef_name, undef_map, ref,
+ (flags & DL_LOOKUP_GSCOPE_LOCK)
+ ? undef_map->l_scope : symbol_scope,
+ version, type_class, flags, skip_map);
+
+ /* The object is used. */
+ if (__glibc_unlikely (current_value.m->l_used == 0))
+ current_value.m->l_used = 1;
+
+ if (__glibc_unlikely (GLRO(dl_debug_mask)
+ & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK)))
+ _dl_debug_bindings (undef_name, undef_map, ref,
+ &current_value, version, type_class, protected);
+
+ *ref = current_value.s;
+ return LOOKUP_VALUE (current_value.m);
+}
+
+
+/* Cache the location of MAP's hash table. */
+
+void
+internal_function
+_dl_setup_hash (struct link_map *map)
+{
+ Elf_Symndx *hash;
+
+ if (__glibc_likely (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM] != NULL))
+ {
+ Elf32_Word *hash32
+ = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM]);
+ map->l_nbuckets = *hash32++;
+ Elf32_Word symbias = *hash32++;
+ Elf32_Word bitmask_nwords = *hash32++;
+ /* Must be a power of two. */
+ assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0);
+ map->l_gnu_bitmask_idxbits = bitmask_nwords - 1;
+ map->l_gnu_shift = *hash32++;
+
+ map->l_gnu_bitmask = (ElfW(Addr) *) hash32;
+ hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords;
+
+ map->l_gnu_buckets = hash32;
+ hash32 += map->l_nbuckets;
+ map->l_gnu_chain_zero = hash32 - symbias;
+ return;
+ }
+
+ if (!map->l_info[DT_HASH])
+ return;
+ hash = (void *) D_PTR (map, l_info[DT_HASH]);
+
+ map->l_nbuckets = *hash++;
+ /* Skip nchain. */
+ hash++;
+ map->l_buckets = hash;
+ hash += map->l_nbuckets;
+ map->l_chain = hash;
+}
+
+
+static void
+internal_function
+_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
+ const ElfW(Sym) **ref, struct sym_val *value,
+ const struct r_found_version *version, int type_class,
+ int protected)
+{
+ const char *reference_name = undef_map->l_name;
+
+ if (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)
+ {
+ _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
+ DSO_FILENAME (reference_name),
+ undef_map->l_ns,
+ DSO_FILENAME (value->m->l_name),
+ value->m->l_ns,
+ protected ? "protected" : "normal", undef_name);
+ if (version)
+ _dl_debug_printf_c (" [%s]\n", version->name);
+ else
+ _dl_debug_printf_c ("\n");
+ }
+#ifdef SHARED
+ if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
+ {
+/* ELF_RTYPE_CLASS_XXX must match RTYPE_CLASS_XXX used by prelink with
+ LD_TRACE_PRELINKING. */
+#define RTYPE_CLASS_VALID 8
+#define RTYPE_CLASS_PLT (8|1)
+#define RTYPE_CLASS_COPY (8|2)
+#define RTYPE_CLASS_TLS (8|4)
+#if ELF_RTYPE_CLASS_PLT != 0 && ELF_RTYPE_CLASS_PLT != 1
+# error ELF_RTYPE_CLASS_PLT must be 0 or 1!
+#endif
+#if ELF_RTYPE_CLASS_COPY != 0 && ELF_RTYPE_CLASS_COPY != 2
+# error ELF_RTYPE_CLASS_COPY must be 0 or 2!
+#endif
+ int conflict = 0;
+ struct sym_val val = { NULL, NULL };
+
+ if ((GLRO(dl_trace_prelink_map) == NULL
+ || GLRO(dl_trace_prelink_map) == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
+ && undef_map != GL(dl_ns)[LM_ID_BASE]._ns_loaded)
+ {
+ const uint_fast32_t new_hash = dl_new_hash (undef_name);
+ unsigned long int old_hash = 0xffffffff;
+ struct unique_sym *saved_entries
+ = GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries;
+
+ GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries = NULL;
+ do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val,
+ undef_map->l_local_scope[0], 0, version, 0, NULL,
+ type_class, undef_map);
+ if (val.s != value->s || val.m != value->m)
+ conflict = 1;
+ else if (__glibc_unlikely (undef_map->l_symbolic_in_local_scope)
+ && val.s
+ && __glibc_unlikely (ELFW(ST_BIND) (val.s->st_info)
+ == STB_GNU_UNIQUE))
+ {
+ /* If it is STB_GNU_UNIQUE and undef_map's l_local_scope
+ contains any DT_SYMBOLIC libraries, unfortunately there
+ can be conflicts even if the above is equal. As symbol
+ resolution goes from the last library to the first and
+ if a STB_GNU_UNIQUE symbol is found in some late DT_SYMBOLIC
+ library, it would be the one that is looked up. */
+ struct sym_val val2 = { NULL, NULL };
+ size_t n;
+ struct r_scope_elem *scope = undef_map->l_local_scope[0];
+
+ for (n = 0; n < scope->r_nlist; n++)
+ if (scope->r_list[n] == val.m)
+ break;
+
+ for (n++; n < scope->r_nlist; n++)
+ if (scope->r_list[n]->l_info[DT_SYMBOLIC] != NULL
+ && do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ &val2,
+ &scope->r_list[n]->l_symbolic_searchlist,
+ 0, version, 0, NULL, type_class,
+ undef_map) > 0)
+ {
+ conflict = 1;
+ val = val2;
+ break;
+ }
+ }
+ GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries = saved_entries;
+ }
+
+ if (value->s)
+ {
+ /* Keep only ELF_RTYPE_CLASS_PLT and ELF_RTYPE_CLASS_COPY
+ bits since since prelink only uses them. */
+ type_class &= ELF_RTYPE_CLASS_PLT | ELF_RTYPE_CLASS_COPY;
+ if (__glibc_unlikely (ELFW(ST_TYPE) (value->s->st_info)
+ == STT_TLS))
+ /* Clear the RTYPE_CLASS_VALID bit in RTYPE_CLASS_TLS. */
+ type_class = RTYPE_CLASS_TLS & ~RTYPE_CLASS_VALID;
+ else if (__glibc_unlikely (ELFW(ST_TYPE) (value->s->st_info)
+ == STT_GNU_IFUNC))
+ /* Set the RTYPE_CLASS_VALID bit. */
+ type_class |= RTYPE_CLASS_VALID;
+ }
+
+ if (conflict
+ || GLRO(dl_trace_prelink_map) == undef_map
+ || GLRO(dl_trace_prelink_map) == NULL
+ || type_class >= 4)
+ {
+ _dl_printf ("%s 0x%0*Zx 0x%0*Zx -> 0x%0*Zx 0x%0*Zx ",
+ conflict ? "conflict" : "lookup",
+ (int) sizeof (ElfW(Addr)) * 2,
+ (size_t) undef_map->l_map_start,
+ (int) sizeof (ElfW(Addr)) * 2,
+ (size_t) (((ElfW(Addr)) *ref) - undef_map->l_map_start),
+ (int) sizeof (ElfW(Addr)) * 2,
+ (size_t) (value->s ? value->m->l_map_start : 0),
+ (int) sizeof (ElfW(Addr)) * 2,
+ (size_t) (value->s ? value->s->st_value : 0));
+
+ if (conflict)
+ _dl_printf ("x 0x%0*Zx 0x%0*Zx ",
+ (int) sizeof (ElfW(Addr)) * 2,
+ (size_t) (val.s ? val.m->l_map_start : 0),
+ (int) sizeof (ElfW(Addr)) * 2,
+ (size_t) (val.s ? val.s->st_value : 0));
+
+ _dl_printf ("/%x %s\n", type_class, undef_name);
+ }
+ }
+#endif
+}
diff --git a/REORG.TODO/elf/dl-machine-reject-phdr.h b/REORG.TODO/elf/dl-machine-reject-phdr.h
new file mode 100644
index 0000000000..57253deb52
--- /dev/null
+++ b/REORG.TODO/elf/dl-machine-reject-phdr.h
@@ -0,0 +1,34 @@
+/* Machine-dependent program header inspection for the ELF loader.
+ Copyright (C) 2014-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _DL_MACHINE_REJECT_PHDR_H
+#define _DL_MACHINE_REJECT_PHDR_H 1
+
+#include <stdbool.h>
+
+/* Return true iff ELF program headers are incompatible with the running
+ host. */
+static inline bool
+elf_machine_reject_phdr_p (const ElfW(Phdr) *phdr, uint_fast16_t phnum,
+ const char *buf, size_t len, struct link_map *map,
+ int fd)
+{
+ return false;
+}
+
+#endif /* dl-machine-reject-phdr.h */
diff --git a/REORG.TODO/elf/dl-map-segments.h b/REORG.TODO/elf/dl-map-segments.h
new file mode 100644
index 0000000000..d36f9bd2f6
--- /dev/null
+++ b/REORG.TODO/elf/dl-map-segments.h
@@ -0,0 +1,157 @@
+/* Map in a shared object's segments. Generic version.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dl-load.h>
+
+/* This implementation assumes (as does the corresponding implementation
+ of _dl_unmap_segments, in dl-unmap-segments.h) that shared objects
+ are always laid out with all segments contiguous (or with gaps
+ between them small enough that it's preferable to reserve all whole
+ pages inside the gaps with PROT_NONE mappings rather than permitting
+ other use of those parts of the address space). */
+
+static __always_inline const char *
+_dl_map_segments (struct link_map *l, int fd,
+ const ElfW(Ehdr) *header, int type,
+ const struct loadcmd loadcmds[], size_t nloadcmds,
+ const size_t maplength, bool has_holes,
+ struct link_map *loader)
+{
+ const struct loadcmd *c = loadcmds;
+
+ if (__glibc_likely (type == ET_DYN))
+ {
+ /* This is a position-independent shared object. We can let the
+ kernel map it anywhere it likes, but we must have space for all
+ the segments in their specified positions relative to the first.
+ So we map the first segment without MAP_FIXED, but with its
+ extent increased to cover all the segments. Then we remove
+ access from excess portion, and there is known sufficient space
+ there to remap from the later segments.
+
+ As a refinement, sometimes we have an address that we would
+ prefer to map such objects at; but this is only a preference,
+ the OS can do whatever it likes. */
+ ElfW(Addr) mappref
+ = (ELF_PREFERRED_ADDRESS (loader, maplength,
+ c->mapstart & GLRO(dl_use_load_bias))
+ - MAP_BASE_ADDR (l));
+
+ /* Remember which part of the address space this object uses. */
+ l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength,
+ c->prot,
+ MAP_COPY|MAP_FILE,
+ fd, c->mapoff);
+ if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED))
+ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
+
+ l->l_map_end = l->l_map_start + maplength;
+ l->l_addr = l->l_map_start - c->mapstart;
+
+ if (has_holes)
+ {
+ /* Change protection on the excess portion to disallow all access;
+ the portions we do not remap later will be inaccessible as if
+ unallocated. Then jump into the normal segment-mapping loop to
+ handle the portion of the segment past the end of the file
+ mapping. */
+ if (__glibc_unlikely
+ (__mprotect ((caddr_t) (l->l_addr + c->mapend),
+ loadcmds[nloadcmds - 1].mapstart - c->mapend,
+ PROT_NONE) < 0))
+ return DL_MAP_SEGMENTS_ERROR_MPROTECT;
+ }
+
+ l->l_contiguous = 1;
+
+ goto postmap;
+ }
+
+ /* Remember which part of the address space this object uses. */
+ l->l_map_start = c->mapstart + l->l_addr;
+ l->l_map_end = l->l_map_start + maplength;
+ l->l_contiguous = !has_holes;
+
+ while (c < &loadcmds[nloadcmds])
+ {
+ if (c->mapend > c->mapstart
+ /* Map the segment contents from the file. */
+ && (__mmap ((void *) (l->l_addr + c->mapstart),
+ c->mapend - c->mapstart, c->prot,
+ MAP_FIXED|MAP_COPY|MAP_FILE,
+ fd, c->mapoff)
+ == MAP_FAILED))
+ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
+
+ postmap:
+ _dl_postprocess_loadcmd (l, header, c);
+
+ if (c->allocend > c->dataend)
+ {
+ /* Extra zero pages should appear at the end of this segment,
+ after the data mapped from the file. */
+ ElfW(Addr) zero, zeroend, zeropage;
+
+ zero = l->l_addr + c->dataend;
+ zeroend = l->l_addr + c->allocend;
+ zeropage = ((zero + GLRO(dl_pagesize) - 1)
+ & ~(GLRO(dl_pagesize) - 1));
+
+ if (zeroend < zeropage)
+ /* All the extra data is in the last page of the segment.
+ We can just zero it. */
+ zeropage = zeroend;
+
+ if (zeropage > zero)
+ {
+ /* Zero the final part of the last page of the segment. */
+ if (__glibc_unlikely ((c->prot & PROT_WRITE) == 0))
+ {
+ /* Dag nab it. */
+ if (__mprotect ((caddr_t) (zero
+ & ~(GLRO(dl_pagesize) - 1)),
+ GLRO(dl_pagesize), c->prot|PROT_WRITE) < 0)
+ return DL_MAP_SEGMENTS_ERROR_MPROTECT;
+ }
+ memset ((void *) zero, '\0', zeropage - zero);
+ if (__glibc_unlikely ((c->prot & PROT_WRITE) == 0))
+ __mprotect ((caddr_t) (zero & ~(GLRO(dl_pagesize) - 1)),
+ GLRO(dl_pagesize), c->prot);
+ }
+
+ if (zeroend > zeropage)
+ {
+ /* Map the remaining zero pages in from the zero fill FD. */
+ caddr_t mapat;
+ mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage,
+ c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
+ -1, 0);
+ if (__glibc_unlikely (mapat == MAP_FAILED))
+ return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL;
+ }
+ }
+
+ ++c;
+ }
+
+ /* Notify ELF_PREFERRED_ADDRESS that we have to load this one
+ fixed. */
+ ELF_FIXED_ADDRESS (loader, c->mapstart);
+
+ return NULL;
+}
diff --git a/REORG.TODO/elf/dl-minimal.c b/REORG.TODO/elf/dl-minimal.c
new file mode 100644
index 0000000000..1a35baff2e
--- /dev/null
+++ b/REORG.TODO/elf/dl-minimal.c
@@ -0,0 +1,380 @@
+/* Minimal replacements for basic facilities used in the dynamic linker.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <tls.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <ldsodefs.h>
+#include <_itoa.h>
+#include <malloc/malloc-internal.h>
+
+#include <assert.h>
+
+/* Minimal malloc allocator for used during initial link. After the
+ initial link, a full malloc implementation is interposed, either
+ the one in libc, or a different one supplied by the user through
+ interposition. */
+
+static void *alloc_ptr, *alloc_end, *alloc_last_block;
+
+/* Declarations of global functions. */
+extern void weak_function free (void *ptr);
+extern void * weak_function realloc (void *ptr, size_t n);
+extern unsigned long int weak_function __strtoul_internal (const char *nptr,
+ char **endptr,
+ int base,
+ int group);
+extern unsigned long int weak_function strtoul (const char *nptr,
+ char **endptr, int base);
+
+
+/* Allocate an aligned memory block. */
+void * weak_function
+malloc (size_t n)
+{
+ if (alloc_end == 0)
+ {
+ /* Consume any unused space in the last page of our data segment. */
+ extern int _end attribute_hidden;
+ alloc_ptr = &_end;
+ alloc_end = (void *) 0 + (((alloc_ptr - (void *) 0)
+ + GLRO(dl_pagesize) - 1)
+ & ~(GLRO(dl_pagesize) - 1));
+ }
+
+ /* Make sure the allocation pointer is ideally aligned. */
+ alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + MALLOC_ALIGNMENT - 1)
+ & ~(MALLOC_ALIGNMENT - 1));
+
+ if (alloc_ptr + n >= alloc_end || n >= -(uintptr_t) alloc_ptr)
+ {
+ /* Insufficient space left; allocate another page plus one extra
+ page to reduce number of mmap calls. */
+ caddr_t page;
+ size_t nup = (n + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
+ if (__glibc_unlikely (nup == 0 && n != 0))
+ return NULL;
+ nup += GLRO(dl_pagesize);
+ page = __mmap (0, nup, PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, -1, 0);
+ if (page == MAP_FAILED)
+ return NULL;
+ if (page != alloc_end)
+ alloc_ptr = page;
+ alloc_end = page + nup;
+ }
+
+ alloc_last_block = (void *) alloc_ptr;
+ alloc_ptr += n;
+ return alloc_last_block;
+}
+
+/* We use this function occasionally since the real implementation may
+ be optimized when it can assume the memory it returns already is
+ set to NUL. */
+void * weak_function
+calloc (size_t nmemb, size_t size)
+{
+ /* New memory from the trivial malloc above is always already cleared.
+ (We make sure that's true in the rare occasion it might not be,
+ by clearing memory in free, below.) */
+ size_t bytes = nmemb * size;
+
+#define HALF_SIZE_T (((size_t) 1) << (8 * sizeof (size_t) / 2))
+ if (__builtin_expect ((nmemb | size) >= HALF_SIZE_T, 0)
+ && size != 0 && bytes / size != nmemb)
+ return NULL;
+
+ return malloc (bytes);
+}
+
+/* This will rarely be called. */
+void weak_function
+free (void *ptr)
+{
+ /* We can free only the last block allocated. */
+ if (ptr == alloc_last_block)
+ {
+ /* Since this is rare, we clear the freed block here
+ so that calloc can presume malloc returns cleared memory. */
+ memset (alloc_last_block, '\0', alloc_ptr - alloc_last_block);
+ alloc_ptr = alloc_last_block;
+ }
+}
+
+/* This is only called with the most recent block returned by malloc. */
+void * weak_function
+realloc (void *ptr, size_t n)
+{
+ if (ptr == NULL)
+ return malloc (n);
+ assert (ptr == alloc_last_block);
+ size_t old_size = alloc_ptr - alloc_last_block;
+ alloc_ptr = alloc_last_block;
+ void *new = malloc (n);
+ return new != ptr ? memcpy (new, ptr, old_size) : new;
+}
+
+/* Avoid signal frobnication in setjmp/longjmp. Keeps things smaller. */
+
+#include <setjmp.h>
+
+int weak_function
+__sigjmp_save (sigjmp_buf env, int savemask __attribute__ ((unused)))
+{
+ env[0].__mask_was_saved = 0;
+ return 0;
+}
+
+/* Define our own version of the internal function used by strerror. We
+ only provide the messages for some common errors. This avoids pulling
+ in the whole error list. */
+
+char * weak_function
+__strerror_r (int errnum, char *buf, size_t buflen)
+{
+ char *msg;
+
+ switch (errnum)
+ {
+ case ENOMEM:
+ msg = (char *) "Cannot allocate memory";
+ break;
+ case EINVAL:
+ msg = (char *) "Invalid argument";
+ break;
+ case ENOENT:
+ msg = (char *) "No such file or directory";
+ break;
+ case EPERM:
+ msg = (char *) "Operation not permitted";
+ break;
+ case EIO:
+ msg = (char *) "Input/output error";
+ break;
+ case EACCES:
+ msg = (char *) "Permission denied";
+ break;
+ default:
+ /* No need to check buffer size, all calls in the dynamic linker
+ provide enough space. */
+ buf[buflen - 1] = '\0';
+ msg = _itoa (errnum, buf + buflen - 1, 10, 0);
+ msg = memcpy (msg - (sizeof ("Error ") - 1), "Error ",
+ sizeof ("Error ") - 1);
+ break;
+ }
+
+ return msg;
+}
+
+void
+__libc_fatal (const char *message)
+{
+ _dl_fatal_printf ("%s", message);
+}
+rtld_hidden_def (__libc_fatal)
+
+void
+__attribute__ ((noreturn))
+__chk_fail (void)
+{
+ _exit (127);
+}
+rtld_hidden_def (__chk_fail)
+
+#ifndef NDEBUG
+/* Define (weakly) our own assert failure function which doesn't use stdio.
+ If we are linked into the user program (-ldl), the normal __assert_fail
+ defn can override this one. */
+
+void weak_function
+__assert_fail (const char *assertion,
+ const char *file, unsigned int line, const char *function)
+{
+ _dl_fatal_printf ("\
+Inconsistency detected by ld.so: %s: %u: %s%sAssertion `%s' failed!\n",
+ file, line, function ?: "", function ? ": " : "",
+ assertion);
+
+}
+rtld_hidden_weak (__assert_fail)
+
+void weak_function
+__assert_perror_fail (int errnum,
+ const char *file, unsigned int line,
+ const char *function)
+{
+ char errbuf[400];
+ _dl_fatal_printf ("\
+Inconsistency detected by ld.so: %s: %u: %s%sUnexpected error: %s.\n",
+ file, line, function ?: "", function ? ": " : "",
+ __strerror_r (errnum, errbuf, sizeof errbuf));
+
+}
+rtld_hidden_weak (__assert_perror_fail)
+#endif
+
+unsigned long int weak_function
+__strtoul_internal (const char *nptr, char **endptr, int base, int group)
+{
+ unsigned long int result = 0;
+ long int sign = 1;
+ unsigned max_digit;
+
+ while (*nptr == ' ' || *nptr == '\t')
+ ++nptr;
+
+ if (*nptr == '-')
+ {
+ sign = -1;
+ ++nptr;
+ }
+ else if (*nptr == '+')
+ ++nptr;
+
+ if (*nptr < '0' || *nptr > '9')
+ {
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+ return 0UL;
+ }
+
+ assert (base == 0);
+ base = 10;
+ max_digit = 9;
+ if (*nptr == '0')
+ {
+ if (nptr[1] == 'x' || nptr[1] == 'X')
+ {
+ base = 16;
+ nptr += 2;
+ }
+ else
+ {
+ base = 8;
+ max_digit = 7;
+ }
+ }
+
+ while (1)
+ {
+ unsigned long int digval;
+ if (*nptr >= '0' && *nptr <= '0' + max_digit)
+ digval = *nptr - '0';
+ else if (base == 16)
+ {
+ if (*nptr >= 'a' && *nptr <= 'f')
+ digval = *nptr - 'a' + 10;
+ else if (*nptr >= 'A' && *nptr <= 'F')
+ digval = *nptr - 'A' + 10;
+ else
+ break;
+ }
+ else
+ break;
+
+ if (result > ULONG_MAX / base
+ || (result == ULONG_MAX / base && digval > ULONG_MAX % base))
+ {
+ errno = ERANGE;
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+ return ULONG_MAX;
+ }
+ result *= base;
+ result += digval;
+ ++nptr;
+ }
+
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+ return result * sign;
+}
+
+
+#undef _itoa
+/* We always use _itoa instead of _itoa_word in ld.so since the former
+ also has to be present and it is never about speed when these
+ functions are used. */
+char *
+_itoa (unsigned long long int value, char *buflim, unsigned int base,
+ int upper_case)
+{
+ assert (! upper_case);
+
+ do
+ *--buflim = _itoa_lower_digits[value % base];
+ while ((value /= base) != 0);
+
+ return buflim;
+}
+
+/* The '_itoa_lower_digits' variable in libc.so is able to handle bases
+ up to 36. We don't need this here. */
+const char _itoa_lower_digits[16] = "0123456789abcdef";
+rtld_hidden_data_def (_itoa_lower_digits)
+
+/* The following is not a complete strsep implementation. It cannot
+ handle empty delimiter strings. But this isn't necessary for the
+ execution of ld.so. */
+#undef strsep
+#undef __strsep
+char *
+__strsep (char **stringp, const char *delim)
+{
+ char *begin;
+
+ assert (delim[0] != '\0');
+
+ begin = *stringp;
+ if (begin != NULL)
+ {
+ char *end = begin;
+
+ while (*end != '\0' || (end = NULL))
+ {
+ const char *dp = delim;
+
+ do
+ if (*dp == *end)
+ break;
+ while (*++dp != '\0');
+
+ if (*dp != '\0')
+ {
+ *end++ = '\0';
+ break;
+ }
+
+ ++end;
+ }
+
+ *stringp = end;
+ }
+
+ return begin;
+}
+weak_alias (__strsep, strsep)
+strong_alias (__strsep, __strsep_g)
diff --git a/REORG.TODO/elf/dl-misc.c b/REORG.TODO/elf/dl-misc.c
new file mode 100644
index 0000000000..c5d3e0e7c5
--- /dev/null
+++ b/REORG.TODO/elf/dl-misc.c
@@ -0,0 +1,362 @@
+/* Miscellaneous support functions for dynamic linker
+ Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <ldsodefs.h>
+#include <limits.h>
+#include <link.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sysdep.h>
+#include <_itoa.h>
+#include <dl-writev.h>
+
+
+/* Read the whole contents of FILE into new mmap'd space with given
+ protections. *SIZEP gets the size of the file. On error MAP_FAILED
+ is returned. */
+
+void *
+internal_function
+_dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot)
+{
+ void *result = MAP_FAILED;
+ struct stat64 st;
+ int fd = __open (file, O_RDONLY | O_CLOEXEC);
+ if (fd >= 0)
+ {
+ if (__fxstat64 (_STAT_VER, fd, &st) >= 0)
+ {
+ *sizep = st.st_size;
+
+ /* No need to map the file if it is empty. */
+ if (*sizep != 0)
+ /* Map a copy of the file contents. */
+ result = __mmap (NULL, *sizep, prot,
+#ifdef MAP_COPY
+ MAP_COPY
+#else
+ MAP_PRIVATE
+#endif
+#ifdef MAP_FILE
+ | MAP_FILE
+#endif
+ , fd, 0);
+ }
+ __close (fd);
+ }
+ return result;
+}
+
+
+/* Bare-bones printf implementation. This function only knows about
+ the formats and flags needed and can handle only up to 64 stripes in
+ the output. */
+static void
+_dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
+{
+# define NIOVMAX 64
+ struct iovec iov[NIOVMAX];
+ int niov = 0;
+ pid_t pid = 0;
+ char pidbuf[12];
+
+ while (*fmt != '\0')
+ {
+ const char *startp = fmt;
+
+ if (tag_p > 0)
+ {
+ /* Generate the tag line once. It consists of the PID and a
+ colon followed by a tab. */
+ if (pid == 0)
+ {
+ char *p;
+ pid = __getpid ();
+ assert (pid >= 0 && sizeof (pid_t) <= 4);
+ p = _itoa (pid, &pidbuf[10], 10, 0);
+ while (p > pidbuf)
+ *--p = ' ';
+ pidbuf[10] = ':';
+ pidbuf[11] = '\t';
+ }
+
+ /* Append to the output. */
+ assert (niov < NIOVMAX);
+ iov[niov].iov_len = 12;
+ iov[niov++].iov_base = pidbuf;
+
+ /* No more tags until we see the next newline. */
+ tag_p = -1;
+ }
+
+ /* Skip everything except % and \n (if tags are needed). */
+ while (*fmt != '\0' && *fmt != '%' && (! tag_p || *fmt != '\n'))
+ ++fmt;
+
+ /* Append constant string. */
+ assert (niov < NIOVMAX);
+ if ((iov[niov].iov_len = fmt - startp) != 0)
+ iov[niov++].iov_base = (char *) startp;
+
+ if (*fmt == '%')
+ {
+ /* It is a format specifier. */
+ char fill = ' ';
+ int width = -1;
+ int prec = -1;
+#if LONG_MAX != INT_MAX
+ int long_mod = 0;
+#endif
+
+ /* Recognize zero-digit fill flag. */
+ if (*++fmt == '0')
+ {
+ fill = '0';
+ ++fmt;
+ }
+
+ /* See whether with comes from a parameter. Note that no other
+ way to specify the width is implemented. */
+ if (*fmt == '*')
+ {
+ width = va_arg (arg, int);
+ ++fmt;
+ }
+
+ /* Handle precision. */
+ if (*fmt == '.' && fmt[1] == '*')
+ {
+ prec = va_arg (arg, int);
+ fmt += 2;
+ }
+
+ /* Recognize the l modifier. It is only important on some
+ platforms where long and int have a different size. We
+ can use the same code for size_t. */
+ if (*fmt == 'l' || *fmt == 'Z')
+ {
+#if LONG_MAX != INT_MAX
+ long_mod = 1;
+#endif
+ ++fmt;
+ }
+
+ switch (*fmt)
+ {
+ /* Integer formatting. */
+ case 'u':
+ case 'x':
+ {
+ /* We have to make a difference if long and int have a
+ different size. */
+#if LONG_MAX != INT_MAX
+ unsigned long int num = (long_mod
+ ? va_arg (arg, unsigned long int)
+ : va_arg (arg, unsigned int));
+#else
+ unsigned long int num = va_arg (arg, unsigned int);
+#endif
+ /* We use alloca() to allocate the buffer with the most
+ pessimistic guess for the size. Using alloca() allows
+ having more than one integer formatting in a call. */
+ char *buf = (char *) alloca (3 * sizeof (unsigned long int));
+ char *endp = &buf[3 * sizeof (unsigned long int)];
+ char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0);
+
+ /* Pad to the width the user specified. */
+ if (width != -1)
+ while (endp - cp < width)
+ *--cp = fill;
+
+ iov[niov].iov_base = cp;
+ iov[niov].iov_len = endp - cp;
+ ++niov;
+ }
+ break;
+
+ case 's':
+ /* Get the string argument. */
+ iov[niov].iov_base = va_arg (arg, char *);
+ iov[niov].iov_len = strlen (iov[niov].iov_base);
+ if (prec != -1)
+ iov[niov].iov_len = MIN ((size_t) prec, iov[niov].iov_len);
+ ++niov;
+ break;
+
+ case '%':
+ iov[niov].iov_base = (void *) fmt;
+ iov[niov].iov_len = 1;
+ ++niov;
+ break;
+
+ default:
+ assert (! "invalid format specifier");
+ }
+ ++fmt;
+ }
+ else if (*fmt == '\n')
+ {
+ /* See whether we have to print a single newline character. */
+ if (fmt == startp)
+ {
+ iov[niov].iov_base = (char *) startp;
+ iov[niov++].iov_len = 1;
+ }
+ else
+ /* No, just add it to the rest of the string. */
+ ++iov[niov - 1].iov_len;
+
+ /* Next line, print a tag again. */
+ tag_p = 1;
+ ++fmt;
+ }
+ }
+
+ /* Finally write the result. */
+ _dl_writev (fd, iov, niov);
+}
+
+
+/* Write to debug file. */
+void
+_dl_debug_printf (const char *fmt, ...)
+{
+ va_list arg;
+
+ va_start (arg, fmt);
+ _dl_debug_vdprintf (GLRO(dl_debug_fd), 1, fmt, arg);
+ va_end (arg);
+}
+
+
+/* Write to debug file but don't start with a tag. */
+void
+_dl_debug_printf_c (const char *fmt, ...)
+{
+ va_list arg;
+
+ va_start (arg, fmt);
+ _dl_debug_vdprintf (GLRO(dl_debug_fd), -1, fmt, arg);
+ va_end (arg);
+}
+
+
+/* Write the given file descriptor. */
+void
+_dl_dprintf (int fd, const char *fmt, ...)
+{
+ va_list arg;
+
+ va_start (arg, fmt);
+ _dl_debug_vdprintf (fd, 0, fmt, arg);
+ va_end (arg);
+}
+
+
+/* Test whether given NAME matches any of the names of the given object. */
+int
+internal_function
+_dl_name_match_p (const char *name, const struct link_map *map)
+{
+ if (strcmp (name, map->l_name) == 0)
+ return 1;
+
+ struct libname_list *runp = map->l_libname;
+
+ while (runp != NULL)
+ if (strcmp (name, runp->name) == 0)
+ return 1;
+ else
+ runp = runp->next;
+
+ return 0;
+}
+
+
+unsigned long int
+internal_function
+_dl_higher_prime_number (unsigned long int n)
+{
+ /* These are primes that are near, but slightly smaller than, a
+ power of two. */
+ static const uint32_t primes[] = {
+ UINT32_C (7),
+ UINT32_C (13),
+ UINT32_C (31),
+ UINT32_C (61),
+ UINT32_C (127),
+ UINT32_C (251),
+ UINT32_C (509),
+ UINT32_C (1021),
+ UINT32_C (2039),
+ UINT32_C (4093),
+ UINT32_C (8191),
+ UINT32_C (16381),
+ UINT32_C (32749),
+ UINT32_C (65521),
+ UINT32_C (131071),
+ UINT32_C (262139),
+ UINT32_C (524287),
+ UINT32_C (1048573),
+ UINT32_C (2097143),
+ UINT32_C (4194301),
+ UINT32_C (8388593),
+ UINT32_C (16777213),
+ UINT32_C (33554393),
+ UINT32_C (67108859),
+ UINT32_C (134217689),
+ UINT32_C (268435399),
+ UINT32_C (536870909),
+ UINT32_C (1073741789),
+ UINT32_C (2147483647),
+ /* 4294967291L */
+ UINT32_C (2147483647) + UINT32_C (2147483644)
+ };
+
+ const uint32_t *low = &primes[0];
+ const uint32_t *high = &primes[sizeof (primes) / sizeof (primes[0])];
+
+ while (low != high)
+ {
+ const uint32_t *mid = low + (high - low) / 2;
+ if (n > *mid)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+
+#if 0
+ /* If we've run out of primes, abort. */
+ if (n > *low)
+ {
+ fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
+ abort ();
+ }
+#endif
+
+ return *low;
+}
diff --git a/REORG.TODO/elf/dl-object.c b/REORG.TODO/elf/dl-object.c
new file mode 100644
index 0000000000..4c43235148
--- /dev/null
+++ b/REORG.TODO/elf/dl-object.c
@@ -0,0 +1,229 @@
+/* Storage management for the chain of loaded shared objects.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+
+#include <assert.h>
+
+
+/* Add the new link_map NEW to the end of the namespace list. */
+void
+internal_function
+_dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
+{
+ /* We modify the list of loaded objects. */
+ __rtld_lock_lock_recursive (GL(dl_load_write_lock));
+
+ if (GL(dl_ns)[nsid]._ns_loaded != NULL)
+ {
+ struct link_map *l = GL(dl_ns)[nsid]._ns_loaded;
+ while (l->l_next != NULL)
+ l = l->l_next;
+ new->l_prev = l;
+ /* new->l_next = NULL; Would be necessary but we use calloc. */
+ l->l_next = new;
+ }
+ else
+ GL(dl_ns)[nsid]._ns_loaded = new;
+ ++GL(dl_ns)[nsid]._ns_nloaded;
+ new->l_serial = GL(dl_load_adds);
+ ++GL(dl_load_adds);
+
+ __rtld_lock_unlock_recursive (GL(dl_load_write_lock));
+}
+
+
+/* Allocate a `struct link_map' for a new object being loaded,
+ and enter it into the _dl_loaded list. */
+struct link_map *
+internal_function
+_dl_new_object (char *realname, const char *libname, int type,
+ struct link_map *loader, int mode, Lmid_t nsid)
+{
+ size_t libname_len = strlen (libname) + 1;
+ struct link_map *new;
+ struct libname_list *newname;
+#ifdef SHARED
+ /* We create the map for the executable before we know whether we have
+ auditing libraries and if yes, how many. Assume the worst. */
+ unsigned int naudit = GLRO(dl_naudit) ?: ((mode & __RTLD_OPENEXEC)
+ ? DL_NNS : 0);
+ size_t audit_space = naudit * sizeof (new->l_audit[0]);
+#else
+# define audit_space 0
+#endif
+
+ new = (struct link_map *) calloc (sizeof (*new) + audit_space
+ + sizeof (struct link_map *)
+ + sizeof (*newname) + libname_len, 1);
+ if (new == NULL)
+ return NULL;
+
+ new->l_real = new;
+ new->l_symbolic_searchlist.r_list = (struct link_map **) ((char *) (new + 1)
+ + audit_space);
+
+ new->l_libname = newname
+ = (struct libname_list *) (new->l_symbolic_searchlist.r_list + 1);
+ newname->name = (char *) memcpy (newname + 1, libname, libname_len);
+ /* newname->next = NULL; We use calloc therefore not necessary. */
+ newname->dont_free = 1;
+
+ /* When we create the executable link map, or a VDSO link map, we start
+ with "" for the l_name. In these cases "" points to ld.so rodata
+ and won't get dumped during core file generation. Therefore to assist
+ gdb and to create more self-contained core files we adjust l_name to
+ point at the newly allocated copy (which will get dumped) instead of
+ the ld.so rodata copy. */
+ new->l_name = *realname ? realname : (char *) newname->name + libname_len - 1;
+ new->l_type = type;
+ /* If we set the bit now since we know it is never used we avoid
+ dirtying the cache line later. */
+ if ((GLRO(dl_debug_mask) & DL_DEBUG_UNUSED) == 0)
+ new->l_used = 1;
+ new->l_loader = loader;
+#if NO_TLS_OFFSET != 0
+ new->l_tls_offset = NO_TLS_OFFSET;
+#endif
+ new->l_ns = nsid;
+
+#ifdef SHARED
+ for (unsigned int cnt = 0; cnt < naudit; ++cnt)
+ {
+ new->l_audit[cnt].cookie = (uintptr_t) new;
+ /* new->l_audit[cnt].bindflags = 0; */
+ }
+#endif
+
+ /* new->l_global = 0; We use calloc therefore not necessary. */
+
+ /* Use the 'l_scope_mem' array by default for the 'l_scope'
+ information. If we need more entries we will allocate a large
+ array dynamically. */
+ new->l_scope = new->l_scope_mem;
+ new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]);
+
+ /* Counter for the scopes we have to handle. */
+ int idx = 0;
+
+ if (GL(dl_ns)[nsid]._ns_loaded != NULL)
+ /* Add the global scope. */
+ new->l_scope[idx++] = &GL(dl_ns)[nsid]._ns_loaded->l_searchlist;
+
+ /* If we have no loader the new object acts as it. */
+ if (loader == NULL)
+ loader = new;
+ else
+ /* Determine the local scope. */
+ while (loader->l_loader != NULL)
+ loader = loader->l_loader;
+
+ /* Insert the scope if it isn't the global scope we already added. */
+ if (idx == 0 || &loader->l_searchlist != new->l_scope[0])
+ {
+ if ((mode & RTLD_DEEPBIND) != 0 && idx != 0)
+ {
+ new->l_scope[1] = new->l_scope[0];
+ idx = 0;
+ }
+
+ new->l_scope[idx] = &loader->l_searchlist;
+ }
+
+ new->l_local_scope[0] = &new->l_searchlist;
+
+ /* Don't try to find the origin for the main map which has the name "". */
+ if (realname[0] != '\0')
+ {
+ size_t realname_len = strlen (realname) + 1;
+ char *origin;
+ char *cp;
+
+ if (realname[0] == '/')
+ {
+ /* It is an absolute path. Use it. But we have to make a
+ copy since we strip out the trailing slash. */
+ cp = origin = (char *) malloc (realname_len);
+ if (origin == NULL)
+ {
+ origin = (char *) -1;
+ goto out;
+ }
+ }
+ else
+ {
+ size_t len = realname_len;
+ char *result = NULL;
+
+ /* Get the current directory name. */
+ origin = NULL;
+ do
+ {
+ char *new_origin;
+
+ len += 128;
+ new_origin = (char *) realloc (origin, len);
+ if (new_origin == NULL)
+ /* We exit the loop. Note that result == NULL. */
+ break;
+ origin = new_origin;
+ }
+ while ((result = __getcwd (origin, len - realname_len)) == NULL
+ && errno == ERANGE);
+
+ if (result == NULL)
+ {
+ /* We were not able to determine the current directory.
+ Note that free(origin) is OK if origin == NULL. */
+ free (origin);
+ origin = (char *) -1;
+ goto out;
+ }
+
+ /* Find the end of the path and see whether we have to add a
+ slash. We could use rawmemchr but this need not be
+ fast. */
+ cp = (strchr) (origin, '\0');
+ if (cp[-1] != '/')
+ *cp++ = '/';
+ }
+
+ /* Add the real file name. */
+ cp = __mempcpy (cp, realname, realname_len);
+
+ /* Now remove the filename and the slash. Leave the slash if
+ the name is something like "/foo". */
+ do
+ --cp;
+ while (*cp != '/');
+
+ if (cp == origin)
+ /* Keep the only slash which is the first character. */
+ ++cp;
+ *cp = '\0';
+
+ out:
+ new->l_origin = origin;
+ }
+
+ return new;
+}
diff --git a/REORG.TODO/elf/dl-open.c b/REORG.TODO/elf/dl-open.c
new file mode 100644
index 0000000000..cec54db413
--- /dev/null
+++ b/REORG.TODO/elf/dl-open.c
@@ -0,0 +1,737 @@
+/* Load a shared object at runtime, relocate it, and run its initializer.
+ Copyright (C) 1996-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h> /* Check whether MAP_COPY is defined. */
+#include <sys/param.h>
+#include <libc-lock.h>
+#include <ldsodefs.h>
+#include <caller.h>
+#include <sysdep-cancel.h>
+#include <tls.h>
+#include <stap-probe.h>
+#include <atomic.h>
+
+#include <dl-dst.h>
+
+
+extern int __libc_multiple_libcs; /* Defined in init-first.c. */
+
+/* We must be careful not to leave us in an inconsistent state. Thus we
+ catch any error and re-raise it after cleaning up. */
+
+struct dl_open_args
+{
+ const char *file;
+ int mode;
+ /* This is the caller of the dlopen() function. */
+ const void *caller_dlopen;
+ /* This is the caller of _dl_open(). */
+ const void *caller_dl_open;
+ struct link_map *map;
+ /* Namespace ID. */
+ Lmid_t nsid;
+ /* Original parameters to the program and the current environment. */
+ int argc;
+ char **argv;
+ char **env;
+};
+
+
+static int
+add_to_global (struct link_map *new)
+{
+ struct link_map **new_global;
+ unsigned int to_add = 0;
+ unsigned int cnt;
+
+ /* Count the objects we have to put in the global scope. */
+ for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
+ if (new->l_searchlist.r_list[cnt]->l_global == 0)
+ ++to_add;
+
+ /* The symbols of the new objects and its dependencies are to be
+ introduced into the global scope that will be used to resolve
+ references from other dynamically-loaded objects.
+
+ The global scope is the searchlist in the main link map. We
+ extend this list if necessary. There is one problem though:
+ since this structure was allocated very early (before the libc
+ is loaded) the memory it uses is allocated by the malloc()-stub
+ in the ld.so. When we come here these functions are not used
+ anymore. Instead the malloc() implementation of the libc is
+ used. But this means the block from the main map cannot be used
+ in an realloc() call. Therefore we allocate a completely new
+ array the first time we have to add something to the locale scope. */
+
+ struct link_namespaces *ns = &GL(dl_ns)[new->l_ns];
+ if (ns->_ns_global_scope_alloc == 0)
+ {
+ /* This is the first dynamic object given global scope. */
+ ns->_ns_global_scope_alloc
+ = ns->_ns_main_searchlist->r_nlist + to_add + 8;
+ new_global = (struct link_map **)
+ malloc (ns->_ns_global_scope_alloc * sizeof (struct link_map *));
+ if (new_global == NULL)
+ {
+ ns->_ns_global_scope_alloc = 0;
+ nomem:
+ _dl_signal_error (ENOMEM, new->l_libname->name, NULL,
+ N_("cannot extend global scope"));
+ return 1;
+ }
+
+ /* Copy over the old entries. */
+ ns->_ns_main_searchlist->r_list
+ = memcpy (new_global, ns->_ns_main_searchlist->r_list,
+ (ns->_ns_main_searchlist->r_nlist
+ * sizeof (struct link_map *)));
+ }
+ else if (ns->_ns_main_searchlist->r_nlist + to_add
+ > ns->_ns_global_scope_alloc)
+ {
+ /* We have to extend the existing array of link maps in the
+ main map. */
+ struct link_map **old_global
+ = GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list;
+ size_t new_nalloc = ((ns->_ns_global_scope_alloc + to_add) * 2);
+
+ new_global = (struct link_map **)
+ malloc (new_nalloc * sizeof (struct link_map *));
+ if (new_global == NULL)
+ goto nomem;
+
+ memcpy (new_global, old_global,
+ ns->_ns_global_scope_alloc * sizeof (struct link_map *));
+
+ ns->_ns_global_scope_alloc = new_nalloc;
+ ns->_ns_main_searchlist->r_list = new_global;
+
+ if (!RTLD_SINGLE_THREAD_P)
+ THREAD_GSCOPE_WAIT ();
+
+ free (old_global);
+ }
+
+ /* Now add the new entries. */
+ unsigned int new_nlist = ns->_ns_main_searchlist->r_nlist;
+ for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
+ {
+ struct link_map *map = new->l_searchlist.r_list[cnt];
+
+ if (map->l_global == 0)
+ {
+ map->l_global = 1;
+ ns->_ns_main_searchlist->r_list[new_nlist++] = map;
+
+ /* We modify the global scope. Report this. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
+ _dl_debug_printf ("\nadd %s [%lu] to global scope\n",
+ map->l_name, map->l_ns);
+ }
+ }
+ atomic_write_barrier ();
+ ns->_ns_main_searchlist->r_nlist = new_nlist;
+
+ return 0;
+}
+
+/* Search link maps in all namespaces for the DSO that contains the object at
+ address ADDR. Returns the pointer to the link map of the matching DSO, or
+ NULL if a match is not found. */
+struct link_map *
+internal_function
+_dl_find_dso_for_object (const ElfW(Addr) addr)
+{
+ struct link_map *l;
+
+ /* Find the highest-addressed object that ADDR is not below. */
+ for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
+ for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
+ if (addr >= l->l_map_start && addr < l->l_map_end
+ && (l->l_contiguous
+ || _dl_addr_inside_object (l, (ElfW(Addr)) addr)))
+ {
+ assert (ns == l->l_ns);
+ return l;
+ }
+ return NULL;
+}
+rtld_hidden_def (_dl_find_dso_for_object);
+
+static void
+dl_open_worker (void *a)
+{
+ struct dl_open_args *args = a;
+ const char *file = args->file;
+ int mode = args->mode;
+ struct link_map *call_map = NULL;
+
+ /* Check whether _dl_open() has been called from a valid DSO. */
+ if (__check_caller (args->caller_dl_open,
+ allow_libc|allow_libdl|allow_ldso) != 0)
+ _dl_signal_error (0, "dlopen", NULL, N_("invalid caller"));
+
+ /* Determine the caller's map if necessary. This is needed in case
+ we have a DST, when we don't know the namespace ID we have to put
+ the new object in, or when the file name has no path in which
+ case we need to look along the RUNPATH/RPATH of the caller. */
+ const char *dst = strchr (file, '$');
+ if (dst != NULL || args->nsid == __LM_ID_CALLER
+ || strchr (file, '/') == NULL)
+ {
+ const void *caller_dlopen = args->caller_dlopen;
+
+ /* We have to find out from which object the caller is calling.
+ By default we assume this is the main application. */
+ call_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+
+ struct link_map *l = _dl_find_dso_for_object ((ElfW(Addr)) caller_dlopen);
+
+ if (l)
+ call_map = l;
+
+ if (args->nsid == __LM_ID_CALLER)
+ args->nsid = call_map->l_ns;
+ }
+
+ /* One might be tempted to assert that we are RT_CONSISTENT at this point, but that
+ may not be true if this is a recursive call to dlopen. */
+ _dl_debug_initialize (0, args->nsid);
+
+ /* Load the named object. */
+ struct link_map *new;
+ args->map = new = _dl_map_object (call_map, file, lt_loaded, 0,
+ mode | __RTLD_CALLMAP, args->nsid);
+
+ /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
+ set and the object is not already loaded. */
+ if (new == NULL)
+ {
+ assert (mode & RTLD_NOLOAD);
+ return;
+ }
+
+ /* Mark the object as not deletable if the RTLD_NODELETE flags was passed.
+ Do this early so that we don't skip marking the object if it was
+ already loaded. */
+ if (__glibc_unlikely (mode & RTLD_NODELETE))
+ new->l_flags_1 |= DF_1_NODELETE;
+
+ if (__glibc_unlikely (mode & __RTLD_SPROF))
+ /* This happens only if we load a DSO for 'sprof'. */
+ return;
+
+ /* This object is directly loaded. */
+ ++new->l_direct_opencount;
+
+ /* It was already open. */
+ if (__glibc_unlikely (new->l_searchlist.r_list != NULL))
+ {
+ /* Let the user know about the opencount. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_direct_opencount);
+
+ /* If the user requested the object to be in the global namespace
+ but it is not so far, add it now. */
+ if ((mode & RTLD_GLOBAL) && new->l_global == 0)
+ (void) add_to_global (new);
+
+ assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
+
+ return;
+ }
+
+ /* Load that object's dependencies. */
+ _dl_map_object_deps (new, NULL, 0, 0,
+ mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT));
+
+ /* So far, so good. Now check the versions. */
+ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
+ if (new->l_searchlist.r_list[i]->l_real->l_versions == NULL)
+ (void) _dl_check_map_versions (new->l_searchlist.r_list[i]->l_real,
+ 0, 0);
+
+#ifdef SHARED
+ /* Auditing checkpoint: we have added all objects. */
+ if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ {
+ struct link_map *head = GL(dl_ns)[new->l_ns]._ns_loaded;
+ /* Do not call the functions for any auditing object. */
+ if (head->l_auditing == 0)
+ {
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->activity != NULL)
+ afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
+
+ afct = afct->next;
+ }
+ }
+ }
+#endif
+
+ /* Notify the debugger all new objects are now ready to go. */
+ struct r_debug *r = _dl_debug_initialize (0, args->nsid);
+ r->r_state = RT_CONSISTENT;
+ _dl_debug_state ();
+ LIBC_PROBE (map_complete, 3, args->nsid, r, new);
+
+ /* Print scope information. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
+ _dl_show_scope (new, 0);
+
+ /* Only do lazy relocation if `LD_BIND_NOW' is not set. */
+ int reloc_mode = mode & __RTLD_AUDIT;
+ if (GLRO(dl_lazy))
+ reloc_mode |= mode & RTLD_LAZY;
+
+ /* Sort the objects by dependency for the relocation process. This
+ allows IFUNC relocations to work and it also means copy
+ relocation of dependencies are if necessary overwritten. */
+ size_t nmaps = 0;
+ struct link_map *l = new;
+ do
+ {
+ if (! l->l_real->l_relocated)
+ ++nmaps;
+ l = l->l_next;
+ }
+ while (l != NULL);
+ struct link_map *maps[nmaps];
+ nmaps = 0;
+ l = new;
+ do
+ {
+ if (! l->l_real->l_relocated)
+ maps[nmaps++] = l;
+ l = l->l_next;
+ }
+ while (l != NULL);
+ if (nmaps > 1)
+ {
+ uint16_t seen[nmaps];
+ memset (seen, '\0', sizeof (seen));
+ size_t i = 0;
+ while (1)
+ {
+ ++seen[i];
+ struct link_map *thisp = maps[i];
+
+ /* Find the last object in the list for which the current one is
+ a dependency and move the current object behind the object
+ with the dependency. */
+ size_t k = nmaps - 1;
+ while (k > i)
+ {
+ struct link_map **runp = maps[k]->l_initfini;
+ if (runp != NULL)
+ /* Look through the dependencies of the object. */
+ while (*runp != NULL)
+ if (__glibc_unlikely (*runp++ == thisp))
+ {
+ /* Move the current object to the back past the last
+ object with it as the dependency. */
+ memmove (&maps[i], &maps[i + 1],
+ (k - i) * sizeof (maps[0]));
+ maps[k] = thisp;
+
+ if (seen[i + 1] > nmaps - i)
+ {
+ ++i;
+ goto next_clear;
+ }
+
+ uint16_t this_seen = seen[i];
+ memmove (&seen[i], &seen[i + 1],
+ (k - i) * sizeof (seen[0]));
+ seen[k] = this_seen;
+
+ goto next;
+ }
+
+ --k;
+ }
+
+ if (++i == nmaps)
+ break;
+ next_clear:
+ memset (&seen[i], 0, (nmaps - i) * sizeof (seen[0]));
+ next:;
+ }
+ }
+
+ int relocation_in_progress = 0;
+
+ for (size_t i = nmaps; i-- > 0; )
+ {
+ l = maps[i];
+
+ if (! relocation_in_progress)
+ {
+ /* Notify the debugger that relocations are about to happen. */
+ LIBC_PROBE (reloc_start, 2, args->nsid, r);
+ relocation_in_progress = 1;
+ }
+
+#ifdef SHARED
+ if (__glibc_unlikely (GLRO(dl_profile) != NULL))
+ {
+ /* If this here is the shared object which we want to profile
+ make sure the profile is started. We can find out whether
+ this is necessary or not by observing the `_dl_profile_map'
+ variable. If it was NULL but is not NULL afterwards we must
+ start the profiling. */
+ struct link_map *old_profile_map = GL(dl_profile_map);
+
+ _dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1);
+
+ if (old_profile_map == NULL && GL(dl_profile_map) != NULL)
+ {
+ /* We must prepare the profiling. */
+ _dl_start_profile ();
+
+ /* Prevent unloading the object. */
+ GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
+ }
+ }
+ else
+#endif
+ _dl_relocate_object (l, l->l_scope, reloc_mode, 0);
+ }
+
+ /* If the file is not loaded now as a dependency, add the search
+ list of the newly loaded object to the scope. */
+ bool any_tls = false;
+ unsigned int first_static_tls = new->l_searchlist.r_nlist;
+ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
+ {
+ struct link_map *imap = new->l_searchlist.r_list[i];
+ int from_scope = 0;
+
+ /* If the initializer has been called already, the object has
+ not been loaded here and now. */
+ if (imap->l_init_called && imap->l_type == lt_loaded)
+ {
+ struct r_scope_elem **runp = imap->l_scope;
+ size_t cnt = 0;
+
+ while (*runp != NULL)
+ {
+ if (*runp == &new->l_searchlist)
+ break;
+ ++cnt;
+ ++runp;
+ }
+
+ if (*runp != NULL)
+ /* Avoid duplicates. */
+ continue;
+
+ if (__glibc_unlikely (cnt + 1 >= imap->l_scope_max))
+ {
+ /* The 'r_scope' array is too small. Allocate a new one
+ dynamically. */
+ size_t new_size;
+ struct r_scope_elem **newp;
+
+#define SCOPE_ELEMS(imap) \
+ (sizeof (imap->l_scope_mem) / sizeof (imap->l_scope_mem[0]))
+
+ if (imap->l_scope != imap->l_scope_mem
+ && imap->l_scope_max < SCOPE_ELEMS (imap))
+ {
+ new_size = SCOPE_ELEMS (imap);
+ newp = imap->l_scope_mem;
+ }
+ else
+ {
+ new_size = imap->l_scope_max * 2;
+ newp = (struct r_scope_elem **)
+ malloc (new_size * sizeof (struct r_scope_elem *));
+ if (newp == NULL)
+ _dl_signal_error (ENOMEM, "dlopen", NULL,
+ N_("cannot create scope list"));
+ }
+
+ memcpy (newp, imap->l_scope, cnt * sizeof (imap->l_scope[0]));
+ struct r_scope_elem **old = imap->l_scope;
+
+ imap->l_scope = newp;
+
+ if (old != imap->l_scope_mem)
+ _dl_scope_free (old);
+
+ imap->l_scope_max = new_size;
+ }
+
+ /* First terminate the extended list. Otherwise a thread
+ might use the new last element and then use the garbage
+ at offset IDX+1. */
+ imap->l_scope[cnt + 1] = NULL;
+ atomic_write_barrier ();
+ imap->l_scope[cnt] = &new->l_searchlist;
+
+ /* Print only new scope information. */
+ from_scope = cnt;
+ }
+ /* Only add TLS memory if this object is loaded now and
+ therefore is not yet initialized. */
+ else if (! imap->l_init_called
+ /* Only if the module defines thread local data. */
+ && __builtin_expect (imap->l_tls_blocksize > 0, 0))
+ {
+ /* Now that we know the object is loaded successfully add
+ modules containing TLS data to the slot info table. We
+ might have to increase its size. */
+ _dl_add_to_slotinfo (imap);
+
+ if (imap->l_need_tls_init
+ && first_static_tls == new->l_searchlist.r_nlist)
+ first_static_tls = i;
+
+ /* We have to bump the generation counter. */
+ any_tls = true;
+ }
+
+ /* Print scope information. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
+ _dl_show_scope (imap, from_scope);
+ }
+
+ /* Bump the generation number if necessary. */
+ if (any_tls && __builtin_expect (++GL(dl_tls_generation) == 0, 0))
+ _dl_fatal_printf (N_("\
+TLS generation counter wrapped! Please report this."));
+
+ /* We need a second pass for static tls data, because _dl_update_slotinfo
+ must not be run while calls to _dl_add_to_slotinfo are still pending. */
+ for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i)
+ {
+ struct link_map *imap = new->l_searchlist.r_list[i];
+
+ if (imap->l_need_tls_init
+ && ! imap->l_init_called
+ && imap->l_tls_blocksize > 0)
+ {
+ /* For static TLS we have to allocate the memory here and
+ now, but we can delay updating the DTV. */
+ imap->l_need_tls_init = 0;
+#ifdef SHARED
+ /* Update the slot information data for at least the
+ generation of the DSO we are allocating data for. */
+ _dl_update_slotinfo (imap->l_tls_modid);
+#endif
+
+ GL(dl_init_static_tls) (imap);
+ assert (imap->l_need_tls_init == 0);
+ }
+ }
+
+ /* Notify the debugger all new objects have been relocated. */
+ if (relocation_in_progress)
+ LIBC_PROBE (reloc_complete, 3, args->nsid, r, new);
+
+#ifndef SHARED
+ DL_STATIC_INIT (new);
+#endif
+
+ /* Run the initializer functions of new objects. */
+ _dl_init (new, args->argc, args->argv, args->env);
+
+ /* Now we can make the new map available in the global scope. */
+ if (mode & RTLD_GLOBAL)
+ /* Move the object in the global namespace. */
+ if (add_to_global (new) != 0)
+ /* It failed. */
+ return;
+
+#ifndef SHARED
+ /* We must be the static _dl_open in libc.a. A static program that
+ has loaded a dynamic object now has competition. */
+ __libc_multiple_libcs = 1;
+#endif
+
+ /* Let the user know about the opencount. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_direct_opencount);
+}
+
+
+void *
+_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
+ int argc, char *argv[], char *env[])
+{
+ if ((mode & RTLD_BINDING_MASK) == 0)
+ /* One of the flags must be set. */
+ _dl_signal_error (EINVAL, file, NULL, N_("invalid mode for dlopen()"));
+
+ /* Make sure we are alone. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+ if (__glibc_unlikely (nsid == LM_ID_NEWLM))
+ {
+ /* Find a new namespace. */
+ for (nsid = 1; DL_NNS > 1 && nsid < GL(dl_nns); ++nsid)
+ if (GL(dl_ns)[nsid]._ns_loaded == NULL)
+ break;
+
+ if (__glibc_unlikely (nsid == DL_NNS))
+ {
+ /* No more namespace available. */
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+ _dl_signal_error (EINVAL, file, NULL, N_("\
+no more namespaces available for dlmopen()"));
+ }
+ else if (nsid == GL(dl_nns))
+ {
+ __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
+ ++GL(dl_nns);
+ }
+
+ _dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT;
+ }
+ /* Never allow loading a DSO in a namespace which is empty. Such
+ direct placements is only causing problems. Also don't allow
+ loading into a namespace used for auditing. */
+ else if (__glibc_unlikely (nsid != LM_ID_BASE && nsid != __LM_ID_CALLER)
+ && (__glibc_unlikely (nsid < 0 || nsid >= GL(dl_nns))
+ /* This prevents the [NSID] index expressions from being
+ evaluated, so the compiler won't think that we are
+ accessing an invalid index here in the !SHARED case where
+ DL_NNS is 1 and so any NSID != 0 is invalid. */
+ || DL_NNS == 1
+ || GL(dl_ns)[nsid]._ns_nloaded == 0
+ || GL(dl_ns)[nsid]._ns_loaded->l_auditing))
+ _dl_signal_error (EINVAL, file, NULL,
+ N_("invalid target namespace in dlmopen()"));
+
+ struct dl_open_args args;
+ args.file = file;
+ args.mode = mode;
+ args.caller_dlopen = caller_dlopen;
+ args.caller_dl_open = RETURN_ADDRESS (0);
+ args.map = NULL;
+ args.nsid = nsid;
+ args.argc = argc;
+ args.argv = argv;
+ args.env = env;
+
+ const char *objname;
+ const char *errstring;
+ bool malloced;
+ int errcode = _dl_catch_error (&objname, &errstring, &malloced,
+ dl_open_worker, &args);
+
+#if defined USE_LDCONFIG && !defined MAP_COPY
+ /* We must unmap the cache file. */
+ _dl_unload_cache ();
+#endif
+
+ /* See if an error occurred during loading. */
+ if (__glibc_unlikely (errstring != NULL))
+ {
+ /* Remove the object from memory. It may be in an inconsistent
+ state if relocation failed, for example. */
+ if (args.map)
+ {
+ /* Maybe some of the modules which were loaded use TLS.
+ Since it will be removed in the following _dl_close call
+ we have to mark the dtv array as having gaps to fill the
+ holes. This is a pessimistic assumption which won't hurt
+ if not true. There is no need to do this when we are
+ loading the auditing DSOs since TLS has not yet been set
+ up. */
+ if ((mode & __RTLD_AUDIT) == 0)
+ GL(dl_tls_dtv_gaps) = true;
+
+ _dl_close_worker (args.map, true);
+ }
+
+ assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
+
+ /* Release the lock. */
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+ /* Make a local copy of the error string so that we can release the
+ memory allocated for it. */
+ size_t len_errstring = strlen (errstring) + 1;
+ char *local_errstring;
+ if (objname == errstring + len_errstring)
+ {
+ size_t total_len = len_errstring + strlen (objname) + 1;
+ local_errstring = alloca (total_len);
+ memcpy (local_errstring, errstring, total_len);
+ objname = local_errstring + len_errstring;
+ }
+ else
+ {
+ local_errstring = alloca (len_errstring);
+ memcpy (local_errstring, errstring, len_errstring);
+ }
+
+ if (malloced)
+ free ((char *) errstring);
+
+ /* Reraise the error. */
+ _dl_signal_error (errcode, objname, NULL, local_errstring);
+ }
+
+ assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
+
+ /* Release the lock. */
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+ return args.map;
+}
+
+
+void
+_dl_show_scope (struct link_map *l, int from)
+{
+ _dl_debug_printf ("object=%s [%lu]\n",
+ DSO_FILENAME (l->l_name), l->l_ns);
+ if (l->l_scope != NULL)
+ for (int scope_cnt = from; l->l_scope[scope_cnt] != NULL; ++scope_cnt)
+ {
+ _dl_debug_printf (" scope %u:", scope_cnt);
+
+ for (unsigned int cnt = 0; cnt < l->l_scope[scope_cnt]->r_nlist; ++cnt)
+ if (*l->l_scope[scope_cnt]->r_list[cnt]->l_name)
+ _dl_debug_printf_c (" %s",
+ l->l_scope[scope_cnt]->r_list[cnt]->l_name);
+ else
+ _dl_debug_printf_c (" %s", RTLD_PROGNAME);
+
+ _dl_debug_printf_c ("\n");
+ }
+ else
+ _dl_debug_printf (" no scope\n");
+ _dl_debug_printf ("\n");
+}
diff --git a/REORG.TODO/elf/dl-origin.c b/REORG.TODO/elf/dl-origin.c
new file mode 100644
index 0000000000..1e44272a8e
--- /dev/null
+++ b/REORG.TODO/elf/dl-origin.c
@@ -0,0 +1,50 @@
+/* Find path of executable.
+ Copyright (C) 1998-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <ldsodefs.h>
+
+#include <dl-dst.h>
+
+
+const char *
+_dl_get_origin (void)
+{
+ char *result = (char *) -1;
+ /* We use the environment variable LD_ORIGIN_PATH. If it is set make
+ a copy and strip out trailing slashes. */
+ if (GLRO(dl_origin_path) != NULL)
+ {
+ size_t len = strlen (GLRO(dl_origin_path));
+ result = (char *) malloc (len + 1);
+ if (result == NULL)
+ result = (char *) -1;
+ else
+ {
+ char *cp = __mempcpy (result, GLRO(dl_origin_path), len);
+ while (cp > result + 1 && cp[-1] == '/')
+ --cp;
+ *cp = '\0';
+ }
+ }
+
+ return result;
+}
diff --git a/REORG.TODO/elf/dl-profile.c b/REORG.TODO/elf/dl-profile.c
new file mode 100644
index 0000000000..a4f11089a1
--- /dev/null
+++ b/REORG.TODO/elf/dl-profile.c
@@ -0,0 +1,596 @@
+/* Profiling of shared libraries.
+ Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+ Based on the BSD mcount implementation.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <ldsodefs.h>
+#include <sys/gmon.h>
+#include <sys/gmon_out.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atomic.h>
+
+/* The LD_PROFILE feature has to be implemented different to the
+ normal profiling using the gmon/ functions. The problem is that an
+ arbitrary amount of processes simulataneously can be run using
+ profiling and all write the results in the same file. To provide
+ this mechanism one could implement a complicated mechanism to merge
+ the content of two profiling runs or one could extend the file
+ format to allow more than one data set. For the second solution we
+ would have the problem that the file can grow in size beyond any
+ limit and both solutions have the problem that the concurrency of
+ writing the results is a big problem.
+
+ Another much simpler method is to use mmap to map the same file in
+ all using programs and modify the data in the mmap'ed area and so
+ also automatically on the disk. Using the MAP_SHARED option of
+ mmap(2) this can be done without big problems in more than one
+ file.
+
+ This approach is very different from the normal profiling. We have
+ to use the profiling data in exactly the way they are expected to
+ be written to disk. But the normal format used by gprof is not usable
+ to do this. It is optimized for size. It writes the tags as single
+ bytes but this means that the following 32/64 bit values are
+ unaligned.
+
+ Therefore we use a new format. This will look like this
+
+ 0 1 2 3 <- byte is 32 bit word
+ 0000 g m o n
+ 0004 *version* <- GMON_SHOBJ_VERSION
+ 0008 00 00 00 00
+ 000c 00 00 00 00
+ 0010 00 00 00 00
+
+ 0014 *tag* <- GMON_TAG_TIME_HIST
+ 0018 ?? ?? ?? ??
+ ?? ?? ?? ?? <- 32/64 bit LowPC
+ 0018+A ?? ?? ?? ??
+ ?? ?? ?? ?? <- 32/64 bit HighPC
+ 0018+2*A *histsize*
+ 001c+2*A *profrate*
+ 0020+2*A s e c o
+ 0024+2*A n d s \0
+ 0028+2*A \0 \0 \0 \0
+ 002c+2*A \0 \0 \0
+ 002f+2*A s
+
+ 0030+2*A ?? ?? ?? ?? <- Count data
+ ... ...
+ 0030+2*A+K ?? ?? ?? ??
+
+ 0030+2*A+K *tag* <- GMON_TAG_CG_ARC
+ 0034+2*A+K *lastused*
+ 0038+2*A+K ?? ?? ?? ??
+ ?? ?? ?? ?? <- FromPC#1
+ 0038+3*A+K ?? ?? ?? ??
+ ?? ?? ?? ?? <- ToPC#1
+ 0038+4*A+K ?? ?? ?? ?? <- Count#1
+ ... ... ...
+ 0038+(2*(CN-1)+2)*A+(CN-1)*4+K ?? ?? ?? ??
+ ?? ?? ?? ?? <- FromPC#CGN
+ 0038+(2*(CN-1)+3)*A+(CN-1)*4+K ?? ?? ?? ??
+ ?? ?? ?? ?? <- ToPC#CGN
+ 0038+(2*CN+2)*A+(CN-1)*4+K ?? ?? ?? ?? <- Count#CGN
+
+ We put (for now?) no basic block information in the file since this would
+ introduce rase conditions among all the processes who want to write them.
+
+ `K' is the number of count entries which is computed as
+
+ textsize / HISTFRACTION
+
+ `CG' in the above table is the number of call graph arcs. Normally,
+ the table is sparse and the profiling code writes out only the those
+ entries which are really used in the program run. But since we must
+ not extend this table (the profiling file) we'll keep them all here.
+ So CN can be executed in advance as
+
+ MINARCS <= textsize*(ARCDENSITY/100) <= MAXARCS
+
+ Now the remaining question is: how to build the data structures we can
+ work with from this data. We need the from set and must associate the
+ froms with all the associated tos. We will do this by constructing this
+ data structures at the program start. To do this we'll simply visit all
+ entries in the call graph table and add it to the appropriate list. */
+
+extern int __profile_frequency (void);
+libc_hidden_proto (__profile_frequency)
+
+/* We define a special type to address the elements of the arc table.
+ This is basically the `gmon_cg_arc_record' format but it includes
+ the room for the tag and it uses real types. */
+struct here_cg_arc_record
+ {
+ uintptr_t from_pc;
+ uintptr_t self_pc;
+ /* The count field is atomically incremented in _dl_mcount, which
+ requires it to be properly aligned for its type, and for this
+ alignment to be visible to the compiler. The amount of data
+ before an array of this structure is calculated as
+ expected_size in _dl_start_profile. Everything in that
+ calculation is a multiple of 4 bytes (in the case of
+ kcountsize, because it is derived from a subtraction of
+ page-aligned values, and the corresponding calculation in
+ __monstartup also ensures it is at least a multiple of the size
+ of u_long), so all copies of this field do in fact have the
+ appropriate alignment. */
+ uint32_t count __attribute__ ((aligned (__alignof__ (uint32_t))));
+ } __attribute__ ((packed));
+
+static struct here_cg_arc_record *data;
+
+/* Nonzero if profiling is under way. */
+static int running;
+
+/* This is the number of entry which have been incorporated in the toset. */
+static uint32_t narcs;
+/* This is a pointer to the object representing the number of entries
+ currently in the mmaped file. At no point of time this has to be the
+ same as NARCS. If it is equal all entries from the file are in our
+ lists. */
+static volatile uint32_t *narcsp;
+
+
+struct here_fromstruct
+ {
+ struct here_cg_arc_record volatile *here;
+ uint16_t link;
+ };
+
+static volatile uint16_t *tos;
+
+static struct here_fromstruct *froms;
+static uint32_t fromlimit;
+static volatile uint32_t fromidx;
+
+static uintptr_t lowpc;
+static size_t textsize;
+static unsigned int log_hashfraction;
+
+
+
+/* Set up profiling data to profile object desribed by MAP. The output
+ file is found (or created) in OUTPUT_DIR. */
+void
+internal_function
+_dl_start_profile (void)
+{
+ char *filename;
+ int fd;
+ struct stat64 st;
+ const ElfW(Phdr) *ph;
+ ElfW(Addr) mapstart = ~((ElfW(Addr)) 0);
+ ElfW(Addr) mapend = 0;
+ char *hist, *cp;
+ size_t idx;
+ size_t tossize;
+ size_t fromssize;
+ uintptr_t highpc;
+ uint16_t *kcount;
+ size_t kcountsize;
+ struct gmon_hdr *addr = NULL;
+ off_t expected_size;
+ /* See profil(2) where this is described. */
+ int s_scale;
+#define SCALE_1_TO_1 0x10000L
+ const char *errstr = NULL;
+
+ /* Compute the size of the sections which contain program code. */
+ for (ph = GL(dl_profile_map)->l_phdr;
+ ph < &GL(dl_profile_map)->l_phdr[GL(dl_profile_map)->l_phnum]; ++ph)
+ if (ph->p_type == PT_LOAD && (ph->p_flags & PF_X))
+ {
+ ElfW(Addr) start = (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1));
+ ElfW(Addr) end = ((ph->p_vaddr + ph->p_memsz + GLRO(dl_pagesize) - 1)
+ & ~(GLRO(dl_pagesize) - 1));
+
+ if (start < mapstart)
+ mapstart = start;
+ if (end > mapend)
+ mapend = end;
+ }
+
+ /* Now we can compute the size of the profiling data. This is done
+ with the same formulars as in `monstartup' (see gmon.c). */
+ running = 0;
+ lowpc = ROUNDDOWN (mapstart + GL(dl_profile_map)->l_addr,
+ HISTFRACTION * sizeof (HISTCOUNTER));
+ highpc = ROUNDUP (mapend + GL(dl_profile_map)->l_addr,
+ HISTFRACTION * sizeof (HISTCOUNTER));
+ textsize = highpc - lowpc;
+ kcountsize = textsize / HISTFRACTION;
+ if ((HASHFRACTION & (HASHFRACTION - 1)) == 0)
+ {
+ /* If HASHFRACTION is a power of two, mcount can use shifting
+ instead of integer division. Precompute shift amount.
+
+ This is a constant but the compiler cannot compile the
+ expression away since the __ffs implementation is not known
+ to the compiler. Help the compiler by precomputing the
+ usual cases. */
+ assert (HASHFRACTION == 2);
+
+ if (sizeof (*froms) == 8)
+ log_hashfraction = 4;
+ else if (sizeof (*froms) == 16)
+ log_hashfraction = 5;
+ else
+ log_hashfraction = __ffs (HASHFRACTION * sizeof (*froms)) - 1;
+ }
+ else
+ log_hashfraction = -1;
+ tossize = textsize / HASHFRACTION;
+ fromlimit = textsize * ARCDENSITY / 100;
+ if (fromlimit < MINARCS)
+ fromlimit = MINARCS;
+ if (fromlimit > MAXARCS)
+ fromlimit = MAXARCS;
+ fromssize = fromlimit * sizeof (struct here_fromstruct);
+
+ expected_size = (sizeof (struct gmon_hdr)
+ + 4 + sizeof (struct gmon_hist_hdr) + kcountsize
+ + 4 + 4 + fromssize * sizeof (struct here_cg_arc_record));
+
+ /* Create the gmon_hdr we expect or write. */
+ struct real_gmon_hdr
+ {
+ char cookie[4];
+ int32_t version;
+ char spare[3 * 4];
+ } gmon_hdr;
+ if (sizeof (gmon_hdr) != sizeof (struct gmon_hdr)
+ || (offsetof (struct real_gmon_hdr, cookie)
+ != offsetof (struct gmon_hdr, cookie))
+ || (offsetof (struct real_gmon_hdr, version)
+ != offsetof (struct gmon_hdr, version)))
+ abort ();
+
+ memcpy (&gmon_hdr.cookie[0], GMON_MAGIC, sizeof (gmon_hdr.cookie));
+ gmon_hdr.version = GMON_SHOBJ_VERSION;
+ memset (gmon_hdr.spare, '\0', sizeof (gmon_hdr.spare));
+
+ /* Create the hist_hdr we expect or write. */
+ struct real_gmon_hist_hdr
+ {
+ char *low_pc;
+ char *high_pc;
+ int32_t hist_size;
+ int32_t prof_rate;
+ char dimen[15];
+ char dimen_abbrev;
+ } hist_hdr;
+ if (sizeof (hist_hdr) != sizeof (struct gmon_hist_hdr)
+ || (offsetof (struct real_gmon_hist_hdr, low_pc)
+ != offsetof (struct gmon_hist_hdr, low_pc))
+ || (offsetof (struct real_gmon_hist_hdr, high_pc)
+ != offsetof (struct gmon_hist_hdr, high_pc))
+ || (offsetof (struct real_gmon_hist_hdr, hist_size)
+ != offsetof (struct gmon_hist_hdr, hist_size))
+ || (offsetof (struct real_gmon_hist_hdr, prof_rate)
+ != offsetof (struct gmon_hist_hdr, prof_rate))
+ || (offsetof (struct real_gmon_hist_hdr, dimen)
+ != offsetof (struct gmon_hist_hdr, dimen))
+ || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev)
+ != offsetof (struct gmon_hist_hdr, dimen_abbrev)))
+ abort ();
+
+ hist_hdr.low_pc = (char *) mapstart;
+ hist_hdr.high_pc = (char *) mapend;
+ hist_hdr.hist_size = kcountsize / sizeof (HISTCOUNTER);
+ hist_hdr.prof_rate = __profile_frequency ();
+ if (sizeof (hist_hdr.dimen) >= sizeof ("seconds"))
+ {
+ memcpy (hist_hdr.dimen, "seconds", sizeof ("seconds"));
+ memset (hist_hdr.dimen + sizeof ("seconds"), '\0',
+ sizeof (hist_hdr.dimen) - sizeof ("seconds"));
+ }
+ else
+ strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen));
+ hist_hdr.dimen_abbrev = 's';
+
+ /* First determine the output name. We write in the directory
+ OUTPUT_DIR and the name is composed from the shared objects
+ soname (or the file name) and the ending ".profile". */
+ filename = (char *) alloca (strlen (GLRO(dl_profile_output)) + 1
+ + strlen (GLRO(dl_profile)) + sizeof ".profile");
+ cp = __stpcpy (filename, GLRO(dl_profile_output));
+ *cp++ = '/';
+ __stpcpy (__stpcpy (cp, GLRO(dl_profile)), ".profile");
+
+ fd = __open (filename, O_RDWR | O_CREAT | O_NOFOLLOW, DEFFILEMODE);
+ if (fd == -1)
+ {
+ char buf[400];
+ int errnum;
+
+ /* We cannot write the profiling data so don't do anything. */
+ errstr = "%s: cannot open file: %s\n";
+ print_error:
+ errnum = errno;
+ if (fd != -1)
+ __close (fd);
+ _dl_error_printf (errstr, filename,
+ __strerror_r (errnum, buf, sizeof buf));
+ return;
+ }
+
+ if (__fxstat64 (_STAT_VER, fd, &st) < 0 || !S_ISREG (st.st_mode))
+ {
+ /* Not stat'able or not a regular file => don't use it. */
+ errstr = "%s: cannot stat file: %s\n";
+ goto print_error;
+ }
+
+ /* Test the size. If it does not match what we expect from the size
+ values in the map MAP we don't use it and warn the user. */
+ if (st.st_size == 0)
+ {
+ /* We have to create the file. */
+ char buf[GLRO(dl_pagesize)];
+
+ memset (buf, '\0', GLRO(dl_pagesize));
+
+ if (__lseek (fd, expected_size & ~(GLRO(dl_pagesize) - 1), SEEK_SET) == -1)
+ {
+ cannot_create:
+ errstr = "%s: cannot create file: %s\n";
+ goto print_error;
+ }
+
+ if (TEMP_FAILURE_RETRY (__libc_write (fd, buf, (expected_size
+ & (GLRO(dl_pagesize)
+ - 1))))
+ < 0)
+ goto cannot_create;
+ }
+ else if (st.st_size != expected_size)
+ {
+ __close (fd);
+ wrong_format:
+
+ if (addr != NULL)
+ __munmap ((void *) addr, expected_size);
+
+ _dl_error_printf ("%s: file is no correct profile data file for `%s'\n",
+ filename, GLRO(dl_profile));
+ return;
+ }
+
+ addr = (struct gmon_hdr *) __mmap (NULL, expected_size, PROT_READ|PROT_WRITE,
+ MAP_SHARED|MAP_FILE, fd, 0);
+ if (addr == (struct gmon_hdr *) MAP_FAILED)
+ {
+ errstr = "%s: cannot map file: %s\n";
+ goto print_error;
+ }
+
+ /* We don't need the file descriptor anymore. */
+ __close (fd);
+
+ /* Pointer to data after the header. */
+ hist = (char *) (addr + 1);
+ kcount = (uint16_t *) ((char *) hist + sizeof (uint32_t)
+ + sizeof (struct gmon_hist_hdr));
+
+ /* Compute pointer to array of the arc information. */
+ narcsp = (uint32_t *) ((char *) kcount + kcountsize + sizeof (uint32_t));
+ data = (struct here_cg_arc_record *) ((char *) narcsp + sizeof (uint32_t));
+
+ if (st.st_size == 0)
+ {
+ /* Create the signature. */
+ memcpy (addr, &gmon_hdr, sizeof (struct gmon_hdr));
+
+ *(uint32_t *) hist = GMON_TAG_TIME_HIST;
+ memcpy (hist + sizeof (uint32_t), &hist_hdr,
+ sizeof (struct gmon_hist_hdr));
+
+ narcsp[-1] = GMON_TAG_CG_ARC;
+ }
+ else
+ {
+ /* Test the signature in the file. */
+ if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0
+ || *(uint32_t *) hist != GMON_TAG_TIME_HIST
+ || memcmp (hist + sizeof (uint32_t), &hist_hdr,
+ sizeof (struct gmon_hist_hdr)) != 0
+ || narcsp[-1] != GMON_TAG_CG_ARC)
+ goto wrong_format;
+ }
+
+ /* Allocate memory for the froms data and the pointer to the tos records. */
+ tos = (uint16_t *) calloc (tossize + fromssize, 1);
+ if (tos == NULL)
+ {
+ __munmap ((void *) addr, expected_size);
+ _dl_fatal_printf ("Out of memory while initializing profiler\n");
+ /* NOTREACHED */
+ }
+
+ froms = (struct here_fromstruct *) ((char *) tos + tossize);
+ fromidx = 0;
+
+ /* Now we have to process all the arc count entries. BTW: it is
+ not critical whether the *NARCSP value changes meanwhile. Before
+ we enter a new entry in to toset we will check that everything is
+ available in TOS. This happens in _dl_mcount.
+
+ Loading the entries in reverse order should help to get the most
+ frequently used entries at the front of the list. */
+ for (idx = narcs = MIN (*narcsp, fromlimit); idx > 0; )
+ {
+ size_t to_index;
+ size_t newfromidx;
+ --idx;
+ to_index = (data[idx].self_pc / (HASHFRACTION * sizeof (*tos)));
+ newfromidx = fromidx++;
+ froms[newfromidx].here = &data[idx];
+ froms[newfromidx].link = tos[to_index];
+ tos[to_index] = newfromidx;
+ }
+
+ /* Setup counting data. */
+ if (kcountsize < highpc - lowpc)
+ {
+#if 0
+ s_scale = ((double) kcountsize / (highpc - lowpc)) * SCALE_1_TO_1;
+#else
+ size_t range = highpc - lowpc;
+ size_t quot = range / kcountsize;
+
+ if (quot >= SCALE_1_TO_1)
+ s_scale = 1;
+ else if (quot >= SCALE_1_TO_1 / 256)
+ s_scale = SCALE_1_TO_1 / quot;
+ else if (range > ULONG_MAX / 256)
+ s_scale = (SCALE_1_TO_1 * 256) / (range / (kcountsize / 256));
+ else
+ s_scale = (SCALE_1_TO_1 * 256) / ((range * 256) / kcountsize);
+#endif
+ }
+ else
+ s_scale = SCALE_1_TO_1;
+
+ /* Start the profiler. */
+ __profil ((void *) kcount, kcountsize, lowpc, s_scale);
+
+ /* Turn on profiling. */
+ running = 1;
+}
+
+
+void
+_dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc)
+{
+ volatile uint16_t *topcindex;
+ size_t i, fromindex;
+ struct here_fromstruct *fromp;
+
+ if (! running)
+ return;
+
+ /* Compute relative addresses. The shared object can be loaded at
+ any address. The value of frompc could be anything. We cannot
+ restrict it in any way, just set to a fixed value (0) in case it
+ is outside the allowed range. These calls show up as calls from
+ <external> in the gprof output. */
+ frompc -= lowpc;
+ if (frompc >= textsize)
+ frompc = 0;
+ selfpc -= lowpc;
+ if (selfpc >= textsize)
+ goto done;
+
+ /* Getting here we now have to find out whether the location was
+ already used. If yes we are lucky and only have to increment a
+ counter (this also has to be atomic). If the entry is new things
+ are getting complicated... */
+
+ /* Avoid integer divide if possible. */
+ if ((HASHFRACTION & (HASHFRACTION - 1)) == 0)
+ i = selfpc >> log_hashfraction;
+ else
+ i = selfpc / (HASHFRACTION * sizeof (*tos));
+
+ topcindex = &tos[i];
+ fromindex = *topcindex;
+
+ if (fromindex == 0)
+ goto check_new_or_add;
+
+ fromp = &froms[fromindex];
+
+ /* We have to look through the chain of arcs whether there is already
+ an entry for our arc. */
+ while (fromp->here->from_pc != frompc)
+ {
+ if (fromp->link != 0)
+ do
+ fromp = &froms[fromp->link];
+ while (fromp->link != 0 && fromp->here->from_pc != frompc);
+
+ if (fromp->here->from_pc != frompc)
+ {
+ topcindex = &fromp->link;
+
+ check_new_or_add:
+ /* Our entry is not among the entries we read so far from the
+ data file. Now see whether we have to update the list. */
+ while (narcs != *narcsp && narcs < fromlimit)
+ {
+ size_t to_index;
+ size_t newfromidx;
+ to_index = (data[narcs].self_pc
+ / (HASHFRACTION * sizeof (*tos)));
+ newfromidx = catomic_exchange_and_add (&fromidx, 1) + 1;
+ froms[newfromidx].here = &data[narcs];
+ froms[newfromidx].link = tos[to_index];
+ tos[to_index] = newfromidx;
+ catomic_increment (&narcs);
+ }
+
+ /* If we still have no entry stop searching and insert. */
+ if (*topcindex == 0)
+ {
+ uint_fast32_t newarc = catomic_exchange_and_add (narcsp, 1);
+
+ /* In rare cases it could happen that all entries in FROMS are
+ occupied. So we cannot count this anymore. */
+ if (newarc >= fromlimit)
+ goto done;
+
+ *topcindex = catomic_exchange_and_add (&fromidx, 1) + 1;
+ fromp = &froms[*topcindex];
+
+ fromp->here = &data[newarc];
+ data[newarc].from_pc = frompc;
+ data[newarc].self_pc = selfpc;
+ data[newarc].count = 0;
+ fromp->link = 0;
+ catomic_increment (&narcs);
+
+ break;
+ }
+
+ fromp = &froms[*topcindex];
+ }
+ else
+ /* Found in. */
+ break;
+ }
+
+ /* Increment the counter. */
+ catomic_increment (&fromp->here->count);
+
+ done:
+ ;
+}
+rtld_hidden_def (_dl_mcount)
diff --git a/REORG.TODO/elf/dl-profstub.c b/REORG.TODO/elf/dl-profstub.c
new file mode 100644
index 0000000000..0915e29093
--- /dev/null
+++ b/REORG.TODO/elf/dl-profstub.c
@@ -0,0 +1,41 @@
+/* Helper definitions for profiling of shared libraries.
+ Copyright (C) 1998-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <elf.h>
+#include <ldsodefs.h>
+
+/* This is the map for the shared object we profile. It is defined here
+ only because we test for this value being NULL or not. */
+
+
+void
+_dl_mcount_wrapper (void *selfpc)
+{
+ GLRO(dl_mcount) ((ElfW(Addr)) RETURN_ADDRESS (0), (ElfW(Addr)) selfpc);
+}
+
+
+void
+_dl_mcount_wrapper_check (void *selfpc)
+{
+ if (GL(dl_profile_map) != NULL)
+ GLRO(dl_mcount) ((ElfW(Addr)) RETURN_ADDRESS (0), (ElfW(Addr)) selfpc);
+}
+libc_hidden_def (_dl_mcount_wrapper_check)
diff --git a/REORG.TODO/elf/dl-reloc.c b/REORG.TODO/elf/dl-reloc.c
new file mode 100644
index 0000000000..b3c3a9bbf9
--- /dev/null
+++ b/REORG.TODO/elf/dl-reloc.c
@@ -0,0 +1,363 @@
+/* Relocate a shared object and resolve its references to other loaded objects.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <_itoa.h>
+#include <libc-pointer-arith.h>
+#include "dynamic-link.h"
+
+/* Statistics function. */
+#ifdef SHARED
+# define bump_num_cache_relocations() ++GL(dl_num_cache_relocations)
+#else
+# define bump_num_cache_relocations() ((void) 0)
+#endif
+
+
+/* We are trying to perform a static TLS relocation in MAP, but it was
+ dynamically loaded. This can only work if there is enough surplus in
+ the static TLS area already allocated for each running thread. If this
+ object's TLS segment is too big to fit, we fail. If it fits,
+ we set MAP->l_tls_offset and return.
+ This function intentionally does not return any value but signals error
+ directly, as static TLS should be rare and code handling it should
+ not be inlined as much as possible. */
+int
+internal_function
+_dl_try_allocate_static_tls (struct link_map *map)
+{
+ /* If we've already used the variable with dynamic access, or if the
+ alignment requirements are too high, fail. */
+ if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
+ || map->l_tls_align > GL(dl_tls_static_align))
+ {
+ fail:
+ return -1;
+ }
+
+#if TLS_TCB_AT_TP
+ size_t freebytes = GL(dl_tls_static_size) - GL(dl_tls_static_used);
+ if (freebytes < TLS_TCB_SIZE)
+ goto fail;
+ freebytes -= TLS_TCB_SIZE;
+
+ size_t blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
+ if (freebytes < blsize)
+ goto fail;
+
+ size_t n = (freebytes - blsize) / map->l_tls_align;
+
+ size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
+ - map->l_tls_firstbyte_offset);
+
+ map->l_tls_offset = GL(dl_tls_static_used) = offset;
+#elif TLS_DTV_AT_TP
+ /* dl_tls_static_used includes the TCB at the beginning. */
+ size_t offset = (ALIGN_UP(GL(dl_tls_static_used)
+ - map->l_tls_firstbyte_offset,
+ map->l_tls_align)
+ + map->l_tls_firstbyte_offset);
+ size_t used = offset + map->l_tls_blocksize;
+
+ if (used > GL(dl_tls_static_size))
+ goto fail;
+
+ map->l_tls_offset = offset;
+ map->l_tls_firstbyte_offset = GL(dl_tls_static_used);
+ GL(dl_tls_static_used) = used;
+#else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+#endif
+
+ /* If the object is not yet relocated we cannot initialize the
+ static TLS region. Delay it. */
+ if (map->l_real->l_relocated)
+ {
+#ifdef SHARED
+ if (__builtin_expect (THREAD_DTV()[0].counter != GL(dl_tls_generation),
+ 0))
+ /* Update the slot information data for at least the generation of
+ the DSO we are allocating data for. */
+ (void) _dl_update_slotinfo (map->l_tls_modid);
+#endif
+
+ GL(dl_init_static_tls) (map);
+ }
+ else
+ map->l_need_tls_init = 1;
+
+ return 0;
+}
+
+void
+internal_function __attribute_noinline__
+_dl_allocate_static_tls (struct link_map *map)
+{
+ if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
+ || _dl_try_allocate_static_tls (map))
+ {
+ _dl_signal_error (0, map->l_name, NULL, N_("\
+cannot allocate memory in static TLS block"));
+ }
+}
+
+/* Initialize static TLS area and DTV for current (only) thread.
+ libpthread implementations should provide their own hook
+ to handle all threads. */
+void
+_dl_nothread_init_static_tls (struct link_map *map)
+{
+#if TLS_TCB_AT_TP
+ void *dest = (char *) THREAD_SELF - map->l_tls_offset;
+#elif TLS_DTV_AT_TP
+ void *dest = (char *) THREAD_SELF + map->l_tls_offset + TLS_PRE_TCB_SIZE;
+#else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+#endif
+
+ /* Initialize the memory. */
+ memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
+ '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
+}
+
+
+void
+_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+ int reloc_mode, int consider_profiling)
+{
+ struct textrels
+ {
+ caddr_t start;
+ size_t len;
+ int prot;
+ struct textrels *next;
+ } *textrels = NULL;
+ /* Initialize it to make the compiler happy. */
+ const char *errstring = NULL;
+ int lazy = reloc_mode & RTLD_LAZY;
+ int skip_ifunc = reloc_mode & __RTLD_NOIFUNC;
+
+#ifdef SHARED
+ /* If we are auditing, install the same handlers we need for profiling. */
+ if ((reloc_mode & __RTLD_AUDIT) == 0)
+ consider_profiling |= GLRO(dl_audit) != NULL;
+#elif defined PROF
+ /* Never use dynamic linker profiling for gprof profiling code. */
+# define consider_profiling 0
+#endif
+
+ if (l->l_relocated)
+ return;
+
+ /* If DT_BIND_NOW is set relocate all references in this object. We
+ do not do this if we are profiling, of course. */
+ // XXX Correct for auditing?
+ if (!consider_profiling
+ && __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0))
+ lazy = 0;
+
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_RELOC))
+ _dl_debug_printf ("\nrelocation processing: %s%s\n",
+ DSO_FILENAME (l->l_name), lazy ? " (lazy)" : "");
+
+ /* DT_TEXTREL is now in level 2 and might phase out at some time.
+ But we rewrite the DT_FLAGS entry to a DT_TEXTREL entry to make
+ testing easier and therefore it will be available at all time. */
+ if (__glibc_unlikely (l->l_info[DT_TEXTREL] != NULL))
+ {
+ /* Bletch. We must make read-only segments writable
+ long enough to relocate them. */
+ const ElfW(Phdr) *ph;
+ for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph)
+ if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0)
+ {
+ struct textrels *newp;
+
+ newp = (struct textrels *) alloca (sizeof (*newp));
+ newp->len = ALIGN_UP (ph->p_vaddr + ph->p_memsz, GLRO(dl_pagesize))
+ - ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize));
+ newp->start = PTR_ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize))
+ + (caddr_t) l->l_addr;
+
+ if (__mprotect (newp->start, newp->len, PROT_READ|PROT_WRITE) < 0)
+ {
+ errstring = N_("cannot make segment writable for relocation");
+ call_error:
+ _dl_signal_error (errno, l->l_name, NULL, errstring);
+ }
+
+#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7
+ newp->prot = (PF_TO_PROT
+ >> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf;
+#else
+ newp->prot = 0;
+ if (ph->p_flags & PF_R)
+ newp->prot |= PROT_READ;
+ if (ph->p_flags & PF_W)
+ newp->prot |= PROT_WRITE;
+ if (ph->p_flags & PF_X)
+ newp->prot |= PROT_EXEC;
+#endif
+ newp->next = textrels;
+ textrels = newp;
+ }
+ }
+
+ {
+ /* Do the actual relocation of the object's GOT and other data. */
+
+ /* String table object symbols. */
+ const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
+
+ /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */
+#define RESOLVE_MAP(ref, version, r_type) \
+ ((ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \
+ && __glibc_likely (!dl_symbol_visibility_binds_local_p (*ref))) \
+ ? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0) \
+ && elf_machine_type_class (r_type) == l->l_lookup_cache.type_class) \
+ ? (bump_num_cache_relocations (), \
+ (*ref) = l->l_lookup_cache.ret, \
+ l->l_lookup_cache.value) \
+ : ({ lookup_t _lr; \
+ int _tc = elf_machine_type_class (r_type); \
+ l->l_lookup_cache.type_class = _tc; \
+ l->l_lookup_cache.sym = (*ref); \
+ const struct r_found_version *v = NULL; \
+ if ((version) != NULL && (version)->hash != 0) \
+ v = (version); \
+ _lr = _dl_lookup_symbol_x (strtab + (*ref)->st_name, l, (ref), \
+ scope, v, _tc, \
+ DL_LOOKUP_ADD_DEPENDENCY, NULL); \
+ l->l_lookup_cache.ret = (*ref); \
+ l->l_lookup_cache.value = _lr; })) \
+ : l)
+
+#include "dynamic-link.h"
+
+ ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling, skip_ifunc);
+
+#ifndef PROF
+ if (__glibc_unlikely (consider_profiling)
+ && l->l_info[DT_PLTRELSZ] != NULL)
+ {
+ /* Allocate the array which will contain the already found
+ relocations. If the shared object lacks a PLT (for example
+ if it only contains lead function) the l_info[DT_PLTRELSZ]
+ will be NULL. */
+ size_t sizeofrel = l->l_info[DT_PLTREL]->d_un.d_val == DT_RELA
+ ? sizeof (ElfW(Rela))
+ : sizeof (ElfW(Rel));
+ size_t relcount = l->l_info[DT_PLTRELSZ]->d_un.d_val / sizeofrel;
+ l->l_reloc_result = calloc (sizeof (l->l_reloc_result[0]), relcount);
+
+ if (l->l_reloc_result == NULL)
+ {
+ errstring = N_("\
+%s: out of memory to store relocation results for %s\n");
+ _dl_fatal_printf (errstring, RTLD_PROGNAME, l->l_name);
+ }
+ }
+#endif
+ }
+
+ /* Mark the object so we know this work has been done. */
+ l->l_relocated = 1;
+
+ /* Undo the segment protection changes. */
+ while (__builtin_expect (textrels != NULL, 0))
+ {
+ if (__mprotect (textrels->start, textrels->len, textrels->prot) < 0)
+ {
+ errstring = N_("cannot restore segment prot after reloc");
+ goto call_error;
+ }
+
+#ifdef CLEAR_CACHE
+ CLEAR_CACHE (textrels->start, textrels->start + textrels->len);
+#endif
+
+ textrels = textrels->next;
+ }
+
+ /* In case we can protect the data now that the relocations are
+ done, do it. */
+ if (l->l_relro_size != 0)
+ _dl_protect_relro (l);
+}
+
+
+void internal_function
+_dl_protect_relro (struct link_map *l)
+{
+ ElfW(Addr) start = ALIGN_DOWN((l->l_addr
+ + l->l_relro_addr),
+ GLRO(dl_pagesize));
+ ElfW(Addr) end = ALIGN_DOWN((l->l_addr
+ + l->l_relro_addr
+ + l->l_relro_size),
+ GLRO(dl_pagesize));
+ if (start != end
+ && __mprotect ((void *) start, end - start, PROT_READ) < 0)
+ {
+ static const char errstring[] = N_("\
+cannot apply additional memory protection after relocation");
+ _dl_signal_error (errno, l->l_name, NULL, errstring);
+ }
+}
+
+void
+internal_function __attribute_noinline__
+_dl_reloc_bad_type (struct link_map *map, unsigned int type, int plt)
+{
+#define DIGIT(b) _itoa_lower_digits[(b) & 0xf];
+
+ /* XXX We cannot translate these messages. */
+ static const char msg[2][32
+#if __ELF_NATIVE_CLASS == 64
+ + 6
+#endif
+ ] = { "unexpected reloc type 0x",
+ "unexpected PLT reloc type 0x" };
+ char msgbuf[sizeof (msg[0])];
+ char *cp;
+
+ cp = __stpcpy (msgbuf, msg[plt]);
+#if __ELF_NATIVE_CLASS == 64
+ if (__builtin_expect(type > 0xff, 0))
+ {
+ *cp++ = DIGIT (type >> 28);
+ *cp++ = DIGIT (type >> 24);
+ *cp++ = DIGIT (type >> 20);
+ *cp++ = DIGIT (type >> 16);
+ *cp++ = DIGIT (type >> 12);
+ *cp++ = DIGIT (type >> 8);
+ }
+#endif
+ *cp++ = DIGIT (type >> 4);
+ *cp++ = DIGIT (type);
+ *cp = '\0';
+
+ _dl_signal_error (0, map->l_name, NULL, msgbuf);
+}
diff --git a/REORG.TODO/elf/dl-runtime.c b/REORG.TODO/elf/dl-runtime.c
new file mode 100644
index 0000000000..7d1d240403
--- /dev/null
+++ b/REORG.TODO/elf/dl-runtime.c
@@ -0,0 +1,480 @@
+/* On-demand PLT fixup for shared objects.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#define IN_DL_RUNTIME 1 /* This can be tested in dl-machine.h. */
+
+#include <alloca.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <ldsodefs.h>
+#include <sysdep-cancel.h>
+#include "dynamic-link.h"
+#include <tls.h>
+#include <dl-irel.h>
+
+
+#if (!ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
+ || ELF_MACHINE_NO_REL
+# define PLTREL ElfW(Rela)
+#else
+# define PLTREL ElfW(Rel)
+#endif
+
+/* The fixup functions might have need special attributes. If none
+ are provided define the macro as empty. */
+#ifndef ARCH_FIXUP_ATTRIBUTE
+# define ARCH_FIXUP_ATTRIBUTE
+#endif
+
+#ifndef reloc_offset
+# define reloc_offset reloc_arg
+# define reloc_index reloc_arg / sizeof (PLTREL)
+#endif
+
+
+
+/* This function is called through a special trampoline from the PLT the
+ first time each PLT entry is called. We must perform the relocation
+ specified in the PLT of the given shared object, and return the resolved
+ function address to the trampoline, which will restart the original call
+ to that address. Future calls will bounce directly from the PLT to the
+ function. */
+
+DL_FIXUP_VALUE_TYPE
+attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
+_dl_fixup (
+# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
+ ELF_MACHINE_RUNTIME_FIXUP_ARGS,
+# endif
+ struct link_map *l, ElfW(Word) reloc_arg)
+{
+ const ElfW(Sym) *const symtab
+ = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
+
+ const PLTREL *const reloc
+ = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
+ const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
+ void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
+ lookup_t result;
+ DL_FIXUP_VALUE_TYPE value;
+
+ /* Sanity check that we're really looking at a PLT relocation. */
+ assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
+
+ /* Look up the target symbol. If the normal lookup rules are not
+ used don't look in the global scope. */
+ if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
+ {
+ const struct r_found_version *version = NULL;
+
+ if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+ {
+ const ElfW(Half) *vernum =
+ (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
+ ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
+ version = &l->l_versions[ndx];
+ if (version->hash == 0)
+ version = NULL;
+ }
+
+ /* We need to keep the scope around so do some locking. This is
+ not necessary for objects which cannot be unloaded or when
+ we are not using any threads (yet). */
+ int flags = DL_LOOKUP_ADD_DEPENDENCY;
+ if (!RTLD_SINGLE_THREAD_P)
+ {
+ THREAD_GSCOPE_SET_FLAG ();
+ flags |= DL_LOOKUP_GSCOPE_LOCK;
+ }
+
+#ifdef RTLD_ENABLE_FOREIGN_CALL
+ RTLD_ENABLE_FOREIGN_CALL;
+#endif
+
+ result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope,
+ version, ELF_RTYPE_CLASS_PLT, flags, NULL);
+
+ /* We are done with the global scope. */
+ if (!RTLD_SINGLE_THREAD_P)
+ THREAD_GSCOPE_RESET_FLAG ();
+
+#ifdef RTLD_FINALIZE_FOREIGN_CALL
+ RTLD_FINALIZE_FOREIGN_CALL;
+#endif
+
+ /* Currently result contains the base load address (or link map)
+ of the object that defines sym. Now add in the symbol
+ offset. */
+ value = DL_FIXUP_MAKE_VALUE (result,
+ sym ? (LOOKUP_VALUE_ADDRESS (result)
+ + sym->st_value) : 0);
+ }
+ else
+ {
+ /* We already found the symbol. The module (and therefore its load
+ address) is also known. */
+ value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + sym->st_value);
+ result = l;
+ }
+
+ /* And now perhaps the relocation addend. */
+ value = elf_machine_plt_value (l, reloc, value);
+
+ if (sym != NULL
+ && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0))
+ value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value));
+
+ /* Finally, fix up the plt itself. */
+ if (__glibc_unlikely (GLRO(dl_bind_not)))
+ return value;
+
+ return elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
+}
+
+#ifndef PROF
+DL_FIXUP_VALUE_TYPE
+__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
+_dl_profile_fixup (
+#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
+ ELF_MACHINE_RUNTIME_FIXUP_ARGS,
+#endif
+ struct link_map *l, ElfW(Word) reloc_arg,
+ ElfW(Addr) retaddr, void *regs, long int *framesizep)
+{
+ void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = _dl_mcount;
+
+ if (l->l_reloc_result == NULL)
+ {
+ /* BZ #14843: ELF_DYNAMIC_RELOCATE is called before l_reloc_result
+ is allocated. We will get here if ELF_DYNAMIC_RELOCATE calls a
+ resolver function to resolve an IRELATIVE relocation and that
+ resolver calls a function that is not yet resolved (lazy). For
+ example, the resolver in x86-64 libm.so calls __get_cpu_features
+ defined in libc.so. Skip audit and resolve the external function
+ in this case. */
+ *framesizep = -1;
+ return _dl_fixup (
+# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
+# ifndef ELF_MACHINE_RUNTIME_FIXUP_PARAMS
+# error Please define ELF_MACHINE_RUNTIME_FIXUP_PARAMS.
+# endif
+ ELF_MACHINE_RUNTIME_FIXUP_PARAMS,
+# endif
+ l, reloc_arg);
+ }
+
+ /* This is the address in the array where we store the result of previous
+ relocations. */
+ struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index];
+ DL_FIXUP_VALUE_TYPE *resultp = &reloc_result->addr;
+
+ DL_FIXUP_VALUE_TYPE value = *resultp;
+ if (DL_FIXUP_VALUE_CODE_ADDR (value) == 0)
+ {
+ /* This is the first time we have to relocate this object. */
+ const ElfW(Sym) *const symtab
+ = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
+ const char *strtab = (const char *) D_PTR (l, l_info[DT_STRTAB]);
+
+ const PLTREL *const reloc
+ = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
+ const ElfW(Sym) *refsym = &symtab[ELFW(R_SYM) (reloc->r_info)];
+ const ElfW(Sym) *defsym = refsym;
+ lookup_t result;
+
+ /* Sanity check that we're really looking at a PLT relocation. */
+ assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
+
+ /* Look up the target symbol. If the symbol is marked STV_PROTECTED
+ don't look in the global scope. */
+ if (__builtin_expect (ELFW(ST_VISIBILITY) (refsym->st_other), 0) == 0)
+ {
+ const struct r_found_version *version = NULL;
+
+ if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+ {
+ const ElfW(Half) *vernum =
+ (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
+ ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
+ version = &l->l_versions[ndx];
+ if (version->hash == 0)
+ version = NULL;
+ }
+
+ /* We need to keep the scope around so do some locking. This is
+ not necessary for objects which cannot be unloaded or when
+ we are not using any threads (yet). */
+ int flags = DL_LOOKUP_ADD_DEPENDENCY;
+ if (!RTLD_SINGLE_THREAD_P)
+ {
+ THREAD_GSCOPE_SET_FLAG ();
+ flags |= DL_LOOKUP_GSCOPE_LOCK;
+ }
+
+ result = _dl_lookup_symbol_x (strtab + refsym->st_name, l,
+ &defsym, l->l_scope, version,
+ ELF_RTYPE_CLASS_PLT, flags, NULL);
+
+ /* We are done with the global scope. */
+ if (!RTLD_SINGLE_THREAD_P)
+ THREAD_GSCOPE_RESET_FLAG ();
+
+ /* Currently result contains the base load address (or link map)
+ of the object that defines sym. Now add in the symbol
+ offset. */
+ value = DL_FIXUP_MAKE_VALUE (result,
+ defsym != NULL
+ ? LOOKUP_VALUE_ADDRESS (result)
+ + defsym->st_value : 0);
+
+ if (defsym != NULL
+ && __builtin_expect (ELFW(ST_TYPE) (defsym->st_info)
+ == STT_GNU_IFUNC, 0))
+ value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value));
+ }
+ else
+ {
+ /* We already found the symbol. The module (and therefore its load
+ address) is also known. */
+ value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + refsym->st_value);
+
+ if (__builtin_expect (ELFW(ST_TYPE) (refsym->st_info)
+ == STT_GNU_IFUNC, 0))
+ value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value));
+
+ result = l;
+ }
+ /* And now perhaps the relocation addend. */
+ value = elf_machine_plt_value (l, reloc, value);
+
+#ifdef SHARED
+ /* Auditing checkpoint: we have a new binding. Provide the
+ auditing libraries the possibility to change the value and
+ tell us whether further auditing is wanted. */
+ if (defsym != NULL && GLRO(dl_naudit) > 0)
+ {
+ reloc_result->bound = result;
+ /* Compute index of the symbol entry in the symbol table of
+ the DSO with the definition. */
+ reloc_result->boundndx = (defsym
+ - (ElfW(Sym) *) D_PTR (result,
+ l_info[DT_SYMTAB]));
+
+ /* Determine whether any of the two participating DSOs is
+ interested in auditing. */
+ if ((l->l_audit_any_plt | result->l_audit_any_plt) != 0)
+ {
+ unsigned int flags = 0;
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ /* Synthesize a symbol record where the st_value field is
+ the result. */
+ ElfW(Sym) sym = *defsym;
+ sym.st_value = DL_FIXUP_VALUE_ADDR (value);
+
+ /* Keep track whether there is any interest in tracing
+ the call in the lower two bits. */
+ assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8);
+ assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3);
+ reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT;
+
+ const char *strtab2 = (const void *) D_PTR (result,
+ l_info[DT_STRTAB]);
+
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ /* XXX Check whether both DSOs must request action or
+ only one */
+ if ((l->l_audit[cnt].bindflags & LA_FLG_BINDFROM) != 0
+ && (result->l_audit[cnt].bindflags & LA_FLG_BINDTO) != 0)
+ {
+ if (afct->symbind != NULL)
+ {
+ uintptr_t new_value
+ = afct->symbind (&sym, reloc_result->boundndx,
+ &l->l_audit[cnt].cookie,
+ &result->l_audit[cnt].cookie,
+ &flags,
+ strtab2 + defsym->st_name);
+ if (new_value != (uintptr_t) sym.st_value)
+ {
+ flags |= LA_SYMB_ALTVALUE;
+ sym.st_value = new_value;
+ }
+ }
+
+ /* Remember the results for every audit library and
+ store a summary in the first two bits. */
+ reloc_result->enterexit
+ &= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
+ reloc_result->enterexit
+ |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
+ << ((cnt + 1) * 2));
+ }
+ else
+ /* If the bind flags say this auditor is not interested,
+ set the bits manually. */
+ reloc_result->enterexit
+ |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)
+ << ((cnt + 1) * 2));
+
+ afct = afct->next;
+ }
+
+ reloc_result->flags = flags;
+ value = DL_FIXUP_ADDR_VALUE (sym.st_value);
+ }
+ else
+ /* Set all bits since this symbol binding is not interesting. */
+ reloc_result->enterexit = (1u << DL_NNS) - 1;
+ }
+#endif
+
+ /* Store the result for later runs. */
+ if (__glibc_likely (! GLRO(dl_bind_not)))
+ *resultp = value;
+ }
+
+ /* By default we do not call the pltexit function. */
+ long int framesize = -1;
+
+#ifdef SHARED
+ /* Auditing checkpoint: report the PLT entering and allow the
+ auditors to change the value. */
+ if (DL_FIXUP_VALUE_CODE_ADDR (value) != 0 && GLRO(dl_naudit) > 0
+ /* Don't do anything if no auditor wants to intercept this call. */
+ && (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0)
+ {
+ ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
+ l_info[DT_SYMTAB])
+ + reloc_result->boundndx);
+
+ /* Set up the sym parameter. */
+ ElfW(Sym) sym = *defsym;
+ sym.st_value = DL_FIXUP_VALUE_ADDR (value);
+
+ /* Get the symbol name. */
+ const char *strtab = (const void *) D_PTR (reloc_result->bound,
+ l_info[DT_STRTAB]);
+ const char *symname = strtab + sym.st_name;
+
+ /* Keep track of overwritten addresses. */
+ unsigned int flags = reloc_result->flags;
+
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->ARCH_LA_PLTENTER != NULL
+ && (reloc_result->enterexit
+ & (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0)
+ {
+ long int new_framesize = -1;
+ uintptr_t new_value
+ = afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx,
+ &l->l_audit[cnt].cookie,
+ &reloc_result->bound->l_audit[cnt].cookie,
+ regs, &flags, symname,
+ &new_framesize);
+ if (new_value != (uintptr_t) sym.st_value)
+ {
+ flags |= LA_SYMB_ALTVALUE;
+ sym.st_value = new_value;
+ }
+
+ /* Remember the results for every audit library and
+ store a summary in the first two bits. */
+ reloc_result->enterexit
+ |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
+ << (2 * (cnt + 1)));
+
+ if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT
+ << (2 * (cnt + 1))))
+ == 0 && new_framesize != -1 && framesize != -2)
+ {
+ /* If this is the first call providing information,
+ use it. */
+ if (framesize == -1)
+ framesize = new_framesize;
+ /* If two pltenter calls provide conflicting information,
+ use the larger value. */
+ else if (new_framesize != framesize)
+ framesize = MAX (new_framesize, framesize);
+ }
+ }
+
+ afct = afct->next;
+ }
+
+ value = DL_FIXUP_ADDR_VALUE (sym.st_value);
+ }
+#endif
+
+ /* Store the frame size information. */
+ *framesizep = framesize;
+
+ (*mcount_fct) (retaddr, DL_FIXUP_VALUE_CODE_ADDR (value));
+
+ return value;
+}
+
+#endif /* PROF */
+
+
+#include <stdio.h>
+void
+ARCH_FIXUP_ATTRIBUTE
+_dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_arg,
+ const void *inregs, void *outregs)
+{
+#ifdef SHARED
+ /* This is the address in the array where we store the result of previous
+ relocations. */
+ // XXX Maybe the bound information must be stored on the stack since
+ // XXX with bind_not a new value could have been stored in the meantime.
+ struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index];
+ ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
+ l_info[DT_SYMTAB])
+ + reloc_result->boundndx);
+
+ /* Set up the sym parameter. */
+ ElfW(Sym) sym = *defsym;
+ sym.st_value = DL_FIXUP_VALUE_ADDR (reloc_result->addr);
+
+ /* Get the symbol name. */
+ const char *strtab = (const void *) D_PTR (reloc_result->bound,
+ l_info[DT_STRTAB]);
+ const char *symname = strtab + sym.st_name;
+
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->ARCH_LA_PLTEXIT != NULL
+ && (reloc_result->enterexit
+ & (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0)
+ {
+ afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx,
+ &l->l_audit[cnt].cookie,
+ &reloc_result->bound->l_audit[cnt].cookie,
+ inregs, outregs, symname);
+ }
+
+ afct = afct->next;
+ }
+#endif
+}
diff --git a/REORG.TODO/elf/dl-sbrk.c b/REORG.TODO/elf/dl-sbrk.c
new file mode 100644
index 0000000000..4713a92694
--- /dev/null
+++ b/REORG.TODO/elf/dl-sbrk.c
@@ -0,0 +1,5 @@
+/* We can use the normal code but we also know the __curbrk is not exported
+ from ld.so. */
+extern void *__curbrk attribute_hidden;
+
+#include <sbrk.c>
diff --git a/REORG.TODO/elf/dl-scope.c b/REORG.TODO/elf/dl-scope.c
new file mode 100644
index 0000000000..bb924afa8f
--- /dev/null
+++ b/REORG.TODO/elf/dl-scope.c
@@ -0,0 +1,57 @@
+/* Memory handling for the scope data structures.
+ Copyright (C) 2009-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <ldsodefs.h>
+#include <sysdep-cancel.h>
+
+
+int
+_dl_scope_free (void *old)
+{
+ struct dl_scope_free_list *fsl;
+#define DL_SCOPE_FREE_LIST_SIZE (sizeof (fsl->list) / sizeof (fsl->list[0]))
+
+ if (RTLD_SINGLE_THREAD_P)
+ free (old);
+ else if ((fsl = GL(dl_scope_free_list)) == NULL)
+ {
+ GL(dl_scope_free_list) = fsl = malloc (sizeof (*fsl));
+ if (fsl == NULL)
+ {
+ THREAD_GSCOPE_WAIT ();
+ free (old);
+ return 1;
+ }
+ else
+ {
+ fsl->list[0] = old;
+ fsl->count = 1;
+ }
+ }
+ else if (fsl->count < DL_SCOPE_FREE_LIST_SIZE)
+ fsl->list[fsl->count++] = old;
+ else
+ {
+ THREAD_GSCOPE_WAIT ();
+ while (fsl->count > 0)
+ free (fsl->list[--fsl->count]);
+ return 1;
+ }
+ return 0;
+}
diff --git a/REORG.TODO/elf/dl-support.c b/REORG.TODO/elf/dl-support.c
new file mode 100644
index 0000000000..c22be854f4
--- /dev/null
+++ b/REORG.TODO/elf/dl-support.c
@@ -0,0 +1,389 @@
+/* Support for dynamic linking code in static libc.
+ Copyright (C) 1996-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file defines some things that for the dynamic linker are defined in
+ rtld.c and dl-sysdep.c in ways appropriate to bootstrap dynamic linking. */
+
+#include <errno.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <stdint.h>
+#include <ldsodefs.h>
+#include <dl-machine.h>
+#include <libc-lock.h>
+#include <dl-cache.h>
+#include <dl-librecon.h>
+#include <dl-procinfo.h>
+#include <unsecvars.h>
+#include <hp-timing.h>
+#include <stackinfo.h>
+
+extern char *__progname;
+char **_dl_argv = &__progname; /* This is checked for some error messages. */
+
+/* Name of the architecture. */
+const char *_dl_platform;
+size_t _dl_platformlen;
+
+int _dl_debug_mask;
+int _dl_lazy;
+ElfW(Addr) _dl_use_load_bias = -2;
+int _dl_dynamic_weak;
+
+/* If nonzero print warnings about problematic situations. */
+int _dl_verbose;
+
+/* We never do profiling. */
+const char *_dl_profile;
+const char *_dl_profile_output;
+
+/* Names of shared object for which the RUNPATHs and RPATHs should be
+ ignored. */
+const char *_dl_inhibit_rpath;
+
+/* The map for the object we will profile. */
+struct link_map *_dl_profile_map;
+
+/* This is the address of the last stack address ever used. */
+void *__libc_stack_end;
+
+/* Path where the binary is found. */
+const char *_dl_origin_path;
+
+/* Nonzero if runtime lookup should not update the .got/.plt. */
+int _dl_bind_not;
+
+/* A dummy link map for the executable, used by dlopen to access the global
+ scope. We don't export any symbols ourselves, so this can be minimal. */
+static struct link_map _dl_main_map =
+ {
+ .l_name = (char *) "",
+ .l_real = &_dl_main_map,
+ .l_ns = LM_ID_BASE,
+ .l_libname = &(struct libname_list) { .name = "", .dont_free = 1 },
+ .l_searchlist =
+ {
+ .r_list = &(struct link_map *) { &_dl_main_map },
+ .r_nlist = 1,
+ },
+ .l_symbolic_searchlist = { .r_list = &(struct link_map *) { NULL } },
+ .l_type = lt_executable,
+ .l_scope_mem = { &_dl_main_map.l_searchlist },
+ .l_scope_max = (sizeof (_dl_main_map.l_scope_mem)
+ / sizeof (_dl_main_map.l_scope_mem[0])),
+ .l_scope = _dl_main_map.l_scope_mem,
+ .l_local_scope = { &_dl_main_map.l_searchlist },
+ .l_used = 1,
+ .l_tls_offset = NO_TLS_OFFSET,
+ .l_serial = 1,
+ };
+
+/* Namespace information. */
+struct link_namespaces _dl_ns[DL_NNS] =
+ {
+ [LM_ID_BASE] =
+ {
+ ._ns_loaded = &_dl_main_map,
+ ._ns_nloaded = 1,
+ ._ns_main_searchlist = &_dl_main_map.l_searchlist,
+ }
+ };
+size_t _dl_nns = 1;
+
+/* Incremented whenever something may have been added to dl_loaded. */
+unsigned long long _dl_load_adds = 1;
+
+/* Fake scope of the main application. */
+struct r_scope_elem _dl_initial_searchlist =
+ {
+ .r_list = &(struct link_map *) { &_dl_main_map },
+ .r_nlist = 1,
+ };
+
+#ifndef HAVE_INLINED_SYSCALLS
+/* Nonzero during startup. */
+int _dl_starting_up = 1;
+#endif
+
+/* Random data provided by the kernel. */
+void *_dl_random;
+
+/* Get architecture specific initializer. */
+#include <dl-procinfo.c>
+
+/* Initial value of the CPU clock. */
+#ifndef HP_TIMING_NONAVAIL
+hp_timing_t _dl_cpuclock_offset;
+#endif
+
+void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
+
+size_t _dl_pagesize = EXEC_PAGESIZE;
+
+int _dl_inhibit_cache;
+
+unsigned int _dl_osversion;
+
+/* All known directories in sorted order. */
+struct r_search_path_elem *_dl_all_dirs;
+
+/* All directories after startup. */
+struct r_search_path_elem *_dl_init_all_dirs;
+
+/* The object to be initialized first. */
+struct link_map *_dl_initfirst;
+
+/* Descriptor to write debug messages to. */
+int _dl_debug_fd = STDERR_FILENO;
+
+int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID;
+
+ElfW(auxv_t) *_dl_auxv;
+const ElfW(Phdr) *_dl_phdr;
+size_t _dl_phnum;
+uint64_t _dl_hwcap __attribute__ ((nocommon));
+uint64_t _dl_hwcap2 __attribute__ ((nocommon));
+
+/* The value of the FPU control word the kernel will preset in hardware. */
+fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
+
+#if !HAVE_TUNABLES
+/* This is not initialized to HWCAP_IMPORTANT, matching the definition
+ of _dl_important_hwcaps, below, where no hwcap strings are ever
+ used. This mask is still used to mediate the lookups in the cache
+ file. Since there is no way to set this nonzero (we don't grok the
+ LD_HWCAP_MASK environment variable here), there is no real point in
+ setting _dl_hwcap nonzero below, but we do anyway. */
+uint64_t _dl_hwcap_mask __attribute__ ((nocommon));
+#endif
+
+/* Prevailing state of the stack. Generally this includes PF_X, indicating it's
+ * executable but this isn't true for all platforms. */
+ElfW(Word) _dl_stack_flags = DEFAULT_STACK_PERMS;
+
+/* If loading a shared object requires that we make the stack executable
+ when it was not, we do it by calling this function.
+ It returns an errno code or zero on success. */
+int (*_dl_make_stack_executable_hook) (void **) internal_function
+ = _dl_make_stack_executable;
+
+
+/* Function in libpthread to wait for termination of lookups. */
+void (*_dl_wait_lookup_done) (void);
+
+struct dl_scope_free_list *_dl_scope_free_list;
+
+#ifdef NEED_DL_SYSINFO
+/* Needed for improved syscall handling on at least x86/Linux. */
+uintptr_t _dl_sysinfo = DL_SYSINFO_DEFAULT;
+#endif
+#ifdef NEED_DL_SYSINFO_DSO
+/* Address of the ELF headers in the vsyscall page. */
+const ElfW(Ehdr) *_dl_sysinfo_dso;
+
+struct link_map *_dl_sysinfo_map;
+
+# include "get-dynamic-info.h"
+#endif
+#include "setup-vdso.h"
+
+/* During the program run we must not modify the global data of
+ loaded shared object simultanously in two threads. Therefore we
+ protect `_dl_open' and `_dl_close' in dl-close.c.
+
+ This must be a recursive lock since the initializer function of
+ the loaded object might as well require a call to this function.
+ At this time it is not anymore a problem to modify the tables. */
+__rtld_lock_define_initialized_recursive (, _dl_load_lock)
+/* This lock is used to keep __dl_iterate_phdr from inspecting the
+ list of loaded objects while an object is added to or removed from
+ that list. */
+__rtld_lock_define_initialized_recursive (, _dl_load_write_lock)
+
+
+#ifdef HAVE_AUX_VECTOR
+int _dl_clktck;
+
+void
+internal_function
+_dl_aux_init (ElfW(auxv_t) *av)
+{
+ int seen = 0;
+ uid_t uid = 0;
+ gid_t gid = 0;
+
+ _dl_auxv = av;
+ for (; av->a_type != AT_NULL; ++av)
+ switch (av->a_type)
+ {
+ case AT_PAGESZ:
+ if (av->a_un.a_val != 0)
+ GLRO(dl_pagesize) = av->a_un.a_val;
+ break;
+ case AT_CLKTCK:
+ GLRO(dl_clktck) = av->a_un.a_val;
+ break;
+ case AT_PHDR:
+ GL(dl_phdr) = (const void *) av->a_un.a_val;
+ break;
+ case AT_PHNUM:
+ GL(dl_phnum) = av->a_un.a_val;
+ break;
+ case AT_PLATFORM:
+ GLRO(dl_platform) = (void *) av->a_un.a_val;
+ break;
+ case AT_HWCAP:
+ GLRO(dl_hwcap) = (unsigned long int) av->a_un.a_val;
+ break;
+ case AT_HWCAP2:
+ GLRO(dl_hwcap2) = (unsigned long int) av->a_un.a_val;
+ break;
+ case AT_FPUCW:
+ GLRO(dl_fpu_control) = av->a_un.a_val;
+ break;
+#ifdef NEED_DL_SYSINFO
+ case AT_SYSINFO:
+ GL(dl_sysinfo) = av->a_un.a_val;
+ break;
+#endif
+#ifdef NEED_DL_SYSINFO_DSO
+ case AT_SYSINFO_EHDR:
+ GL(dl_sysinfo_dso) = (void *) av->a_un.a_val;
+ break;
+#endif
+ case AT_UID:
+ uid ^= av->a_un.a_val;
+ seen |= 1;
+ break;
+ case AT_EUID:
+ uid ^= av->a_un.a_val;
+ seen |= 2;
+ break;
+ case AT_GID:
+ gid ^= av->a_un.a_val;
+ seen |= 4;
+ break;
+ case AT_EGID:
+ gid ^= av->a_un.a_val;
+ seen |= 8;
+ break;
+ case AT_SECURE:
+ seen = -1;
+ __libc_enable_secure = av->a_un.a_val;
+ __libc_enable_secure_decided = 1;
+ break;
+ case AT_RANDOM:
+ _dl_random = (void *) av->a_un.a_val;
+ break;
+# ifdef DL_PLATFORM_AUXV
+ DL_PLATFORM_AUXV
+# endif
+ }
+ if (seen == 0xf)
+ {
+ __libc_enable_secure = uid != 0 || gid != 0;
+ __libc_enable_secure_decided = 1;
+ }
+}
+#endif
+
+
+void
+internal_function
+_dl_non_dynamic_init (void)
+{
+ _dl_main_map.l_origin = _dl_get_origin ();
+ _dl_main_map.l_phdr = GL(dl_phdr);
+ _dl_main_map.l_phnum = GL(dl_phnum);
+
+ if (HP_SMALL_TIMING_AVAIL)
+ HP_TIMING_NOW (_dl_cpuclock_offset);
+
+ _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1;
+
+ /* Set up the data structures for the system-supplied DSO early,
+ so they can influence _dl_init_paths. */
+ setup_vdso (NULL, NULL);
+
+ /* Initialize the data structures for the search paths for shared
+ objects. */
+ _dl_init_paths (getenv ("LD_LIBRARY_PATH"));
+
+ /* Remember the last search directory added at startup. */
+ _dl_init_all_dirs = GL(dl_all_dirs);
+
+ _dl_lazy = *(getenv ("LD_BIND_NOW") ?: "") == '\0';
+
+ _dl_bind_not = *(getenv ("LD_BIND_NOT") ?: "") != '\0';
+
+ _dl_dynamic_weak = *(getenv ("LD_DYNAMIC_WEAK") ?: "") == '\0';
+
+ _dl_profile_output = getenv ("LD_PROFILE_OUTPUT");
+ if (_dl_profile_output == NULL || _dl_profile_output[0] == '\0')
+ _dl_profile_output
+ = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];
+
+ if (__libc_enable_secure)
+ {
+ static const char unsecure_envvars[] =
+ UNSECURE_ENVVARS
+#ifdef EXTRA_UNSECURE_ENVVARS
+ EXTRA_UNSECURE_ENVVARS
+#endif
+ ;
+ const char *cp = unsecure_envvars;
+
+ while (cp < unsecure_envvars + sizeof (unsecure_envvars))
+ {
+ __unsetenv (cp);
+ cp = (const char *) __rawmemchr (cp, '\0') + 1;
+ }
+
+#if !HAVE_TUNABLES
+ if (__access ("/etc/suid-debug", F_OK) != 0)
+ __unsetenv ("MALLOC_CHECK_");
+#endif
+ }
+
+#ifdef DL_PLATFORM_INIT
+ DL_PLATFORM_INIT;
+#endif
+
+#ifdef DL_OSVERSION_INIT
+ DL_OSVERSION_INIT;
+#endif
+
+ /* Now determine the length of the platform string. */
+ if (_dl_platform != NULL)
+ _dl_platformlen = strlen (_dl_platform);
+
+ /* Scan for a program header telling us the stack is nonexecutable. */
+ if (_dl_phdr != NULL)
+ for (uint_fast16_t i = 0; i < _dl_phnum; ++i)
+ if (_dl_phdr[i].p_type == PT_GNU_STACK)
+ {
+ _dl_stack_flags = _dl_phdr[i].p_flags;
+ break;
+ }
+}
+
+#ifdef DL_SYSINFO_IMPLEMENTATION
+DL_SYSINFO_IMPLEMENTATION
+#endif
diff --git a/REORG.TODO/elf/dl-sym.c b/REORG.TODO/elf/dl-sym.c
new file mode 100644
index 0000000000..7cd6e97643
--- /dev/null
+++ b/REORG.TODO/elf/dl-sym.c
@@ -0,0 +1,274 @@
+/* Look up a symbol in a shared object loaded by `dlopen'.
+ Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <libintl.h>
+
+#include <dlfcn.h>
+#include <ldsodefs.h>
+#include <dl-hash.h>
+#include <sysdep-cancel.h>
+#include <dl-tls.h>
+#include <dl-irel.h>
+
+
+#ifdef SHARED
+/* Systems which do not have tls_index also probably have to define
+ DONT_USE_TLS_INDEX. */
+
+# ifndef __TLS_GET_ADDR
+# define __TLS_GET_ADDR __tls_get_addr
+# endif
+
+/* Return the symbol address given the map of the module it is in and
+ the symbol record. This is used in dl-sym.c. */
+static void *
+internal_function
+_dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
+{
+# ifndef DONT_USE_TLS_INDEX
+ tls_index tmp =
+ {
+ .ti_module = map->l_tls_modid,
+ .ti_offset = ref->st_value
+ };
+
+ return __TLS_GET_ADDR (&tmp);
+# else
+ return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
+# endif
+}
+#endif
+
+
+struct call_dl_lookup_args
+{
+ /* Arguments to do_dlsym. */
+ struct link_map *map;
+ const char *name;
+ struct r_found_version *vers;
+ int flags;
+
+ /* Return values of do_dlsym. */
+ lookup_t loadbase;
+ const ElfW(Sym) **refp;
+};
+
+static void
+call_dl_lookup (void *ptr)
+{
+ struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr;
+ args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp,
+ args->map->l_scope, args->vers, 0,
+ args->flags, NULL);
+}
+
+
+static void *
+internal_function
+do_sym (void *handle, const char *name, void *who,
+ struct r_found_version *vers, int flags)
+{
+ const ElfW(Sym) *ref = NULL;
+ lookup_t result;
+ ElfW(Addr) caller = (ElfW(Addr)) who;
+
+ struct link_map *l = _dl_find_dso_for_object (caller);
+ /* If the address is not recognized the call comes from the main
+ program (we hope). */
+ struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+
+ if (handle == RTLD_DEFAULT)
+ {
+ /* Search the global scope. We have the simple case where
+ we look up in the scope of an object which was part of
+ the initial binary. And then the more complex part
+ where the object is dynamically loaded and the scope
+ array can change. */
+ if (RTLD_SINGLE_THREAD_P)
+ result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
+ match->l_scope, vers, 0,
+ flags | DL_LOOKUP_ADD_DEPENDENCY,
+ NULL);
+ else
+ {
+ struct call_dl_lookup_args args;
+ args.name = name;
+ args.map = match;
+ args.vers = vers;
+ args.flags
+ = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
+ args.refp = &ref;
+
+ THREAD_GSCOPE_SET_FLAG ();
+
+ const char *objname;
+ const char *errstring = NULL;
+ bool malloced;
+ int err = _dl_catch_error (&objname, &errstring, &malloced,
+ call_dl_lookup, &args);
+
+ THREAD_GSCOPE_RESET_FLAG ();
+
+ if (__glibc_unlikely (errstring != NULL))
+ {
+ /* The lookup was unsuccessful. Rethrow the error. */
+ char *errstring_dup = strdupa (errstring);
+ char *objname_dup = strdupa (objname);
+ if (malloced)
+ free ((char *) errstring);
+
+ _dl_signal_error (err, objname_dup, NULL, errstring_dup);
+ /* NOTREACHED */
+ }
+
+ result = args.map;
+ }
+ }
+ else if (handle == RTLD_NEXT)
+ {
+ if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
+ {
+ if (match == NULL
+ || caller < match->l_map_start
+ || caller >= match->l_map_end)
+ _dl_signal_error (0, NULL, NULL, N_("\
+RTLD_NEXT used in code not dynamically loaded"));
+ }
+
+ struct link_map *l = match;
+ while (l->l_loader != NULL)
+ l = l->l_loader;
+
+ result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
+ vers, 0, 0, match);
+ }
+ else
+ {
+ /* Search the scope of the given object. */
+ struct link_map *map = handle;
+ result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
+ vers, 0, flags, NULL);
+ }
+
+ if (ref != NULL)
+ {
+ void *value;
+
+#ifdef SHARED
+ if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
+ /* The found symbol is a thread-local storage variable.
+ Return the address for to the current thread. */
+ value = _dl_tls_symaddr (result, ref);
+ else
+#endif
+ value = DL_SYMBOL_ADDRESS (result, ref);
+
+ /* Resolve indirect function address. */
+ if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
+ {
+ DL_FIXUP_VALUE_TYPE fixup
+ = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
+ fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
+ value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
+ }
+
+#ifdef SHARED
+ /* Auditing checkpoint: we have a new binding. Provide the
+ auditing libraries the possibility to change the value and
+ tell us whether further auditing is wanted. */
+ if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ {
+ const char *strtab = (const char *) D_PTR (result,
+ l_info[DT_STRTAB]);
+ /* Compute index of the symbol entry in the symbol table of
+ the DSO with the definition. */
+ unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
+ l_info[DT_SYMTAB]));
+
+ if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
+ {
+ unsigned int altvalue = 0;
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ /* Synthesize a symbol record where the st_value field is
+ the result. */
+ ElfW(Sym) sym = *ref;
+ sym.st_value = (ElfW(Addr)) value;
+
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->symbind != NULL
+ && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
+ != 0
+ || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
+ != 0)))
+ {
+ unsigned int flags = altvalue | LA_SYMB_DLSYM;
+ uintptr_t new_value
+ = afct->symbind (&sym, ndx,
+ &match->l_audit[cnt].cookie,
+ &result->l_audit[cnt].cookie,
+ &flags, strtab + ref->st_name);
+ if (new_value != (uintptr_t) sym.st_value)
+ {
+ altvalue = LA_SYMB_ALTVALUE;
+ sym.st_value = new_value;
+ }
+ }
+
+ afct = afct->next;
+ }
+
+ value = (void *) sym.st_value;
+ }
+ }
+#endif
+
+ return value;
+ }
+
+ return NULL;
+}
+
+
+void *
+internal_function
+_dl_vsym (void *handle, const char *name, const char *version, void *who)
+{
+ struct r_found_version vers;
+
+ /* Compute hash value to the version string. */
+ vers.name = version;
+ vers.hidden = 1;
+ vers.hash = _dl_elf_hash (version);
+ /* We don't have a specific file where the symbol can be found. */
+ vers.filename = NULL;
+
+ return do_sym (handle, name, who, &vers, 0);
+}
+
+
+void *
+internal_function
+_dl_sym (void *handle, const char *name, void *who)
+{
+ return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
+}
diff --git a/REORG.TODO/elf/dl-symaddr.c b/REORG.TODO/elf/dl-symaddr.c
new file mode 100644
index 0000000000..5caed4ba21
--- /dev/null
+++ b/REORG.TODO/elf/dl-symaddr.c
@@ -0,0 +1,33 @@
+/* Get the symbol address. Generic version.
+ Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <ldsodefs.h>
+#include <dl-fptr.h>
+
+void *
+_dl_symbol_address (struct link_map *map, const ElfW(Sym) *ref)
+{
+ ElfW(Addr) value = (map ? map->l_addr : 0) + ref->st_value;
+
+ /* Return the pointer to function descriptor. */
+ if (ELFW(ST_TYPE) (ref->st_info) == STT_FUNC)
+ return (void *) _dl_make_fptr (map, ref, value);
+ else
+ return (void *) value;
+}
+rtld_hidden_def (_dl_symbol_address)
diff --git a/REORG.TODO/elf/dl-sysdep-open.h b/REORG.TODO/elf/dl-sysdep-open.h
new file mode 100644
index 0000000000..91851848b3
--- /dev/null
+++ b/REORG.TODO/elf/dl-sysdep-open.h
@@ -0,0 +1,45 @@
+/* System-specific call to open a shared object by name. Stub version.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _DL_SYSDEP_OPEN_H
+#define _DL_SYSDEP_OPEN_H 1
+
+#include <assert.h>
+#include <stddef.h>
+
+/* NAME is a name without slashes, as it appears in a DT_NEEDED entry
+ or a dlopen call's argument or suchlike. NAMELEN is (strlen (NAME) + 1).
+
+ Find NAME in an OS-dependent fashion, and return its "real" name.
+ Optionally fill in *FD with a file descriptor open on that file (or
+ else leave its initial value of -1). The return value is a new
+ malloc'd string, which will be free'd by the caller. If NAME is
+ resolved to an actual file that can be opened, then the return
+ value should name that file (and if *FD was not set, then a normal
+ __open call on that string will be made). If *FD was set by some
+ other means than a normal open and there is no "real" name to use,
+ then __strdup (NAME) is fine (modulo error checking). */
+
+static inline char *
+_dl_sysdep_open_object (const char *name, size_t namelen, int *fd)
+{
+ assert (*fd == -1);
+ return NULL;
+}
+
+#endif /* dl-sysdep-open.h */
diff --git a/REORG.TODO/elf/dl-sysdep.c b/REORG.TODO/elf/dl-sysdep.c
new file mode 100644
index 0000000000..4053ff3c07
--- /dev/null
+++ b/REORG.TODO/elf/dl-sysdep.c
@@ -0,0 +1,360 @@
+/* Operating system support for run-time dynamic linker. Generic Unix version.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* We conditionalize the whole of this file rather than simply eliding it
+ from the static build, because other sysdeps/ versions of this file
+ might define things needed by a static build. */
+
+#ifdef SHARED
+
+#include <assert.h>
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <ldsodefs.h>
+#include <_itoa.h>
+#include <fpu_control.h>
+
+#include <entry.h>
+#include <dl-machine.h>
+#include <dl-procinfo.h>
+#include <dl-osinfo.h>
+#include <hp-timing.h>
+#include <tls.h>
+
+#include <dl-tunables.h>
+
+extern char **_environ attribute_hidden;
+extern char _end[] attribute_hidden;
+
+/* Protect SUID program against misuse of file descriptors. */
+extern void __libc_check_standard_fds (void);
+
+#ifdef NEED_DL_BASE_ADDR
+ElfW(Addr) _dl_base_addr;
+#endif
+int __libc_enable_secure attribute_relro = 0;
+rtld_hidden_data_def (__libc_enable_secure)
+int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
+ of init-first. */
+/* This variable contains the lowest stack address ever used. */
+void *__libc_stack_end attribute_relro = NULL;
+rtld_hidden_data_def(__libc_stack_end)
+void *_dl_random attribute_relro = NULL;
+
+#ifndef DL_FIND_ARG_COMPONENTS
+# define DL_FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp) \
+ do { \
+ void **_tmp; \
+ (argc) = *(long int *) cookie; \
+ (argv) = (char **) ((long int *) cookie + 1); \
+ (envp) = (argv) + (argc) + 1; \
+ for (_tmp = (void **) (envp); *_tmp; ++_tmp) \
+ continue; \
+ (auxp) = (void *) ++_tmp; \
+ } while (0)
+#endif
+
+#ifndef DL_STACK_END
+# define DL_STACK_END(cookie) ((void *) (cookie))
+#endif
+
+ElfW(Addr)
+_dl_sysdep_start (void **start_argptr,
+ void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
+ ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv))
+{
+ const ElfW(Phdr) *phdr = NULL;
+ ElfW(Word) phnum = 0;
+ ElfW(Addr) user_entry;
+ ElfW(auxv_t) *av;
+#ifdef HAVE_AUX_SECURE
+# define set_seen(tag) (tag) /* Evaluate for the side effects. */
+# define set_seen_secure() ((void) 0)
+#else
+ uid_t uid = 0;
+ gid_t gid = 0;
+ unsigned int seen = 0;
+# define set_seen_secure() (seen = -1)
+# ifdef HAVE_AUX_XID
+# define set_seen(tag) (tag) /* Evaluate for the side effects. */
+# else
+# define M(type) (1 << (type))
+# define set_seen(tag) seen |= M ((tag)->a_type)
+# endif
+#endif
+#ifdef NEED_DL_SYSINFO
+ uintptr_t new_sysinfo = 0;
+#endif
+
+ __libc_stack_end = DL_STACK_END (start_argptr);
+ DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, _dl_argv, _environ,
+ GLRO(dl_auxv));
+
+ user_entry = (ElfW(Addr)) ENTRY_POINT;
+ GLRO(dl_platform) = NULL; /* Default to nothing known about the platform. */
+
+ for (av = GLRO(dl_auxv); av->a_type != AT_NULL; set_seen (av++))
+ switch (av->a_type)
+ {
+ case AT_PHDR:
+ phdr = (void *) av->a_un.a_val;
+ break;
+ case AT_PHNUM:
+ phnum = av->a_un.a_val;
+ break;
+ case AT_PAGESZ:
+ GLRO(dl_pagesize) = av->a_un.a_val;
+ break;
+ case AT_ENTRY:
+ user_entry = av->a_un.a_val;
+ break;
+#ifdef NEED_DL_BASE_ADDR
+ case AT_BASE:
+ _dl_base_addr = av->a_un.a_val;
+ break;
+#endif
+#ifndef HAVE_AUX_SECURE
+ case AT_UID:
+ case AT_EUID:
+ uid ^= av->a_un.a_val;
+ break;
+ case AT_GID:
+ case AT_EGID:
+ gid ^= av->a_un.a_val;
+ break;
+#endif
+ case AT_SECURE:
+#ifndef HAVE_AUX_SECURE
+ seen = -1;
+#endif
+ __libc_enable_secure = av->a_un.a_val;
+ break;
+ case AT_PLATFORM:
+ GLRO(dl_platform) = (void *) av->a_un.a_val;
+ break;
+ case AT_HWCAP:
+ GLRO(dl_hwcap) = (unsigned long int) av->a_un.a_val;
+ break;
+ case AT_HWCAP2:
+ GLRO(dl_hwcap2) = (unsigned long int) av->a_un.a_val;
+ break;
+ case AT_CLKTCK:
+ GLRO(dl_clktck) = av->a_un.a_val;
+ break;
+ case AT_FPUCW:
+ GLRO(dl_fpu_control) = av->a_un.a_val;
+ break;
+#ifdef NEED_DL_SYSINFO
+ case AT_SYSINFO:
+ new_sysinfo = av->a_un.a_val;
+ break;
+#endif
+#ifdef NEED_DL_SYSINFO_DSO
+ case AT_SYSINFO_EHDR:
+ GLRO(dl_sysinfo_dso) = (void *) av->a_un.a_val;
+ break;
+#endif
+ case AT_RANDOM:
+ _dl_random = (void *) av->a_un.a_val;
+ break;
+#ifdef DL_PLATFORM_AUXV
+ DL_PLATFORM_AUXV
+#endif
+ }
+
+#ifndef HAVE_AUX_SECURE
+ if (seen != -1)
+ {
+ /* Fill in the values we have not gotten from the kernel through the
+ auxiliary vector. */
+# ifndef HAVE_AUX_XID
+# define SEE(UID, var, uid) \
+ if ((seen & M (AT_##UID)) == 0) var ^= __get##uid ()
+ SEE (UID, uid, uid);
+ SEE (EUID, uid, euid);
+ SEE (GID, gid, gid);
+ SEE (EGID, gid, egid);
+# endif
+
+ /* If one of the two pairs of IDs does not match this is a setuid
+ or setgid run. */
+ __libc_enable_secure = uid | gid;
+ }
+#endif
+
+#ifndef HAVE_AUX_PAGESIZE
+ if (GLRO(dl_pagesize) == 0)
+ GLRO(dl_pagesize) = __getpagesize ();
+#endif
+
+#ifdef NEED_DL_SYSINFO
+ if (new_sysinfo != 0)
+ {
+# ifdef NEED_DL_SYSINFO_DSO
+ /* Only set the sysinfo value if we also have the vsyscall DSO. */
+ if (GLRO(dl_sysinfo_dso) != 0)
+# endif
+ GLRO(dl_sysinfo) = new_sysinfo;
+ }
+#endif
+
+ __tunables_init (_environ);
+
+#ifdef DL_SYSDEP_INIT
+ DL_SYSDEP_INIT;
+#endif
+
+#ifdef DL_PLATFORM_INIT
+ DL_PLATFORM_INIT;
+#endif
+
+ /* Determine the length of the platform name. */
+ if (GLRO(dl_platform) != NULL)
+ GLRO(dl_platformlen) = strlen (GLRO(dl_platform));
+
+ if (__sbrk (0) == _end)
+ /* The dynamic linker was run as a program, and so the initial break
+ starts just after our bss, at &_end. The malloc in dl-minimal.c
+ will consume the rest of this page, so tell the kernel to move the
+ break up that far. When the user program examines its break, it
+ will see this new value and not clobber our data. */
+ __sbrk (GLRO(dl_pagesize)
+ - ((_end - (char *) 0) & (GLRO(dl_pagesize) - 1)));
+
+ /* If this is a SUID program we make sure that FDs 0, 1, and 2 are
+ allocated. If necessary we are doing it ourself. If it is not
+ possible we stop the program. */
+ if (__builtin_expect (__libc_enable_secure, 0))
+ __libc_check_standard_fds ();
+
+ (*dl_main) (phdr, phnum, &user_entry, GLRO(dl_auxv));
+ return user_entry;
+}
+
+void
+internal_function
+_dl_sysdep_start_cleanup (void)
+{
+}
+
+void
+internal_function
+_dl_show_auxv (void)
+{
+ char buf[64];
+ ElfW(auxv_t) *av;
+
+ /* Terminate string. */
+ buf[63] = '\0';
+
+ /* The following code assumes that the AT_* values are encoded
+ starting from 0 with AT_NULL, 1 for AT_IGNORE, and all other values
+ close by (otherwise the array will be too large). In case we have
+ to support a platform where these requirements are not fulfilled
+ some alternative implementation has to be used. */
+ for (av = GLRO(dl_auxv); av->a_type != AT_NULL; ++av)
+ {
+ static const struct
+ {
+ const char label[17];
+ enum { unknown = 0, dec, hex, str, ignore } form : 8;
+ } auxvars[] =
+ {
+ [AT_EXECFD - 2] = { "EXECFD: ", dec },
+ [AT_EXECFN - 2] = { "EXECFN: ", str },
+ [AT_PHDR - 2] = { "PHDR: 0x", hex },
+ [AT_PHENT - 2] = { "PHENT: ", dec },
+ [AT_PHNUM - 2] = { "PHNUM: ", dec },
+ [AT_PAGESZ - 2] = { "PAGESZ: ", dec },
+ [AT_BASE - 2] = { "BASE: 0x", hex },
+ [AT_FLAGS - 2] = { "FLAGS: 0x", hex },
+ [AT_ENTRY - 2] = { "ENTRY: 0x", hex },
+ [AT_NOTELF - 2] = { "NOTELF: ", hex },
+ [AT_UID - 2] = { "UID: ", dec },
+ [AT_EUID - 2] = { "EUID: ", dec },
+ [AT_GID - 2] = { "GID: ", dec },
+ [AT_EGID - 2] = { "EGID: ", dec },
+ [AT_PLATFORM - 2] = { "PLATFORM: ", str },
+ [AT_HWCAP - 2] = { "HWCAP: ", hex },
+ [AT_CLKTCK - 2] = { "CLKTCK: ", dec },
+ [AT_FPUCW - 2] = { "FPUCW: ", hex },
+ [AT_DCACHEBSIZE - 2] = { "DCACHEBSIZE: 0x", hex },
+ [AT_ICACHEBSIZE - 2] = { "ICACHEBSIZE: 0x", hex },
+ [AT_UCACHEBSIZE - 2] = { "UCACHEBSIZE: 0x", hex },
+ [AT_IGNOREPPC - 2] = { "IGNOREPPC", ignore },
+ [AT_SECURE - 2] = { "SECURE: ", dec },
+ [AT_BASE_PLATFORM - 2] = { "BASE_PLATFORM:", str },
+ [AT_SYSINFO - 2] = { "SYSINFO: 0x", hex },
+ [AT_SYSINFO_EHDR - 2] = { "SYSINFO_EHDR: 0x", hex },
+ [AT_RANDOM - 2] = { "RANDOM: 0x", hex },
+ [AT_HWCAP2 - 2] = { "HWCAP2: 0x", hex },
+ };
+ unsigned int idx = (unsigned int) (av->a_type - 2);
+
+ if ((unsigned int) av->a_type < 2u
+ || (idx < sizeof (auxvars) / sizeof (auxvars[0])
+ && auxvars[idx].form == ignore))
+ continue;
+
+ assert (AT_NULL == 0);
+ assert (AT_IGNORE == 1);
+
+ if (av->a_type == AT_HWCAP || av->a_type == AT_HWCAP2)
+ {
+ /* These are handled in a special way per platform. */
+ if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
+ continue;
+ }
+
+ if (idx < sizeof (auxvars) / sizeof (auxvars[0])
+ && auxvars[idx].form != unknown)
+ {
+ const char *val = (char *) av->a_un.a_val;
+
+ if (__builtin_expect (auxvars[idx].form, dec) == dec)
+ val = _itoa ((unsigned long int) av->a_un.a_val,
+ buf + sizeof buf - 1, 10, 0);
+ else if (__builtin_expect (auxvars[idx].form, hex) == hex)
+ val = _itoa ((unsigned long int) av->a_un.a_val,
+ buf + sizeof buf - 1, 16, 0);
+
+ _dl_printf ("AT_%s%s\n", auxvars[idx].label, val);
+
+ continue;
+ }
+
+ /* Unknown value: print a generic line. */
+ char buf2[17];
+ buf2[sizeof (buf2) - 1] = '\0';
+ const char *val2 = _itoa ((unsigned long int) av->a_un.a_val,
+ buf2 + sizeof buf2 - 1, 16, 0);
+ const char *val = _itoa ((unsigned long int) av->a_type,
+ buf + sizeof buf - 1, 16, 0);
+ _dl_printf ("AT_??? (0x%s): 0x%s\n", val, val2);
+ }
+}
+
+#endif
diff --git a/REORG.TODO/elf/dl-tls.c b/REORG.TODO/elf/dl-tls.c
new file mode 100644
index 0000000000..5aba33b3fa
--- /dev/null
+++ b/REORG.TODO/elf/dl-tls.c
@@ -0,0 +1,953 @@
+/* Thread-local storage handling in the ELF dynamic linker. Generic version.
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <errno.h>
+#include <libintl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <atomic.h>
+
+#include <tls.h>
+#include <dl-tls.h>
+#include <ldsodefs.h>
+
+/* Amount of excess space to allocate in the static TLS area
+ to allow dynamic loading of modules defining IE-model TLS data. */
+#define TLS_STATIC_SURPLUS 64 + DL_NNS * 100
+
+
+/* Out-of-memory handler. */
+static void
+__attribute__ ((__noreturn__))
+oom (void)
+{
+ _dl_fatal_printf ("cannot allocate memory for thread-local data: ABORT\n");
+}
+
+
+size_t
+internal_function
+_dl_next_tls_modid (void)
+{
+ size_t result;
+
+ if (__builtin_expect (GL(dl_tls_dtv_gaps), false))
+ {
+ size_t disp = 0;
+ struct dtv_slotinfo_list *runp = GL(dl_tls_dtv_slotinfo_list);
+
+ /* Note that this branch will never be executed during program
+ start since there are no gaps at that time. Therefore it
+ does not matter that the dl_tls_dtv_slotinfo is not allocated
+ yet when the function is called for the first times.
+
+ NB: the offset +1 is due to the fact that DTV[0] is used
+ for something else. */
+ result = GL(dl_tls_static_nelem) + 1;
+ if (result <= GL(dl_tls_max_dtv_idx))
+ do
+ {
+ while (result - disp < runp->len)
+ {
+ if (runp->slotinfo[result - disp].map == NULL)
+ break;
+
+ ++result;
+ assert (result <= GL(dl_tls_max_dtv_idx) + 1);
+ }
+
+ if (result - disp < runp->len)
+ break;
+
+ disp += runp->len;
+ }
+ while ((runp = runp->next) != NULL);
+
+ if (result > GL(dl_tls_max_dtv_idx))
+ {
+ /* The new index must indeed be exactly one higher than the
+ previous high. */
+ assert (result == GL(dl_tls_max_dtv_idx) + 1);
+ /* There is no gap anymore. */
+ GL(dl_tls_dtv_gaps) = false;
+
+ goto nogaps;
+ }
+ }
+ else
+ {
+ /* No gaps, allocate a new entry. */
+ nogaps:
+
+ result = ++GL(dl_tls_max_dtv_idx);
+ }
+
+ return result;
+}
+
+
+size_t
+internal_function
+_dl_count_modids (void)
+{
+ /* It is rare that we have gaps; see elf/dl-open.c (_dl_open) where
+ we fail to load a module and unload it leaving a gap. If we don't
+ have gaps then the number of modids is the current maximum so
+ return that. */
+ if (__glibc_likely (!GL(dl_tls_dtv_gaps)))
+ return GL(dl_tls_max_dtv_idx);
+
+ /* We have gaps and are forced to count the non-NULL entries. */
+ size_t n = 0;
+ struct dtv_slotinfo_list *runp = GL(dl_tls_dtv_slotinfo_list);
+ while (runp != NULL)
+ {
+ for (size_t i = 0; i < runp->len; ++i)
+ if (runp->slotinfo[i].map != NULL)
+ ++n;
+
+ runp = runp->next;
+ }
+
+ return n;
+}
+
+
+#ifdef SHARED
+void
+internal_function
+_dl_determine_tlsoffset (void)
+{
+ size_t max_align = TLS_TCB_ALIGN;
+ size_t freetop = 0;
+ size_t freebottom = 0;
+
+ /* The first element of the dtv slot info list is allocated. */
+ assert (GL(dl_tls_dtv_slotinfo_list) != NULL);
+ /* There is at this point only one element in the
+ dl_tls_dtv_slotinfo_list list. */
+ assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL);
+
+ struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
+
+ /* Determining the offset of the various parts of the static TLS
+ block has several dependencies. In addition we have to work
+ around bugs in some toolchains.
+
+ Each TLS block from the objects available at link time has a size
+ and an alignment requirement. The GNU ld computes the alignment
+ requirements for the data at the positions *in the file*, though.
+ I.e, it is not simply possible to allocate a block with the size
+ of the TLS program header entry. The data is layed out assuming
+ that the first byte of the TLS block fulfills
+
+ p_vaddr mod p_align == &TLS_BLOCK mod p_align
+
+ This means we have to add artificial padding at the beginning of
+ the TLS block. These bytes are never used for the TLS data in
+ this module but the first byte allocated must be aligned
+ according to mod p_align == 0 so that the first byte of the TLS
+ block is aligned according to p_vaddr mod p_align. This is ugly
+ and the linker can help by computing the offsets in the TLS block
+ assuming the first byte of the TLS block is aligned according to
+ p_align.
+
+ The extra space which might be allocated before the first byte of
+ the TLS block need not go unused. The code below tries to use
+ that memory for the next TLS block. This can work if the total
+ memory requirement for the next TLS block is smaller than the
+ gap. */
+
+#if TLS_TCB_AT_TP
+ /* We simply start with zero. */
+ size_t offset = 0;
+
+ for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
+ {
+ assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
+
+ size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset
+ & (slotinfo[cnt].map->l_tls_align - 1));
+ size_t off;
+ max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align);
+
+ if (freebottom - freetop >= slotinfo[cnt].map->l_tls_blocksize)
+ {
+ off = roundup (freetop + slotinfo[cnt].map->l_tls_blocksize
+ - firstbyte, slotinfo[cnt].map->l_tls_align)
+ + firstbyte;
+ if (off <= freebottom)
+ {
+ freetop = off;
+
+ /* XXX For some architectures we perhaps should store the
+ negative offset. */
+ slotinfo[cnt].map->l_tls_offset = off;
+ continue;
+ }
+ }
+
+ off = roundup (offset + slotinfo[cnt].map->l_tls_blocksize - firstbyte,
+ slotinfo[cnt].map->l_tls_align) + firstbyte;
+ if (off > offset + slotinfo[cnt].map->l_tls_blocksize
+ + (freebottom - freetop))
+ {
+ freetop = offset;
+ freebottom = off - slotinfo[cnt].map->l_tls_blocksize;
+ }
+ offset = off;
+
+ /* XXX For some architectures we perhaps should store the
+ negative offset. */
+ slotinfo[cnt].map->l_tls_offset = off;
+ }
+
+ GL(dl_tls_static_used) = offset;
+ GL(dl_tls_static_size) = (roundup (offset + TLS_STATIC_SURPLUS, max_align)
+ + TLS_TCB_SIZE);
+#elif TLS_DTV_AT_TP
+ /* The TLS blocks start right after the TCB. */
+ size_t offset = TLS_TCB_SIZE;
+
+ for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
+ {
+ assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
+
+ size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset
+ & (slotinfo[cnt].map->l_tls_align - 1));
+ size_t off;
+ max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align);
+
+ if (slotinfo[cnt].map->l_tls_blocksize <= freetop - freebottom)
+ {
+ off = roundup (freebottom, slotinfo[cnt].map->l_tls_align);
+ if (off - freebottom < firstbyte)
+ off += slotinfo[cnt].map->l_tls_align;
+ if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop)
+ {
+ slotinfo[cnt].map->l_tls_offset = off - firstbyte;
+ freebottom = (off + slotinfo[cnt].map->l_tls_blocksize
+ - firstbyte);
+ continue;
+ }
+ }
+
+ off = roundup (offset, slotinfo[cnt].map->l_tls_align);
+ if (off - offset < firstbyte)
+ off += slotinfo[cnt].map->l_tls_align;
+
+ slotinfo[cnt].map->l_tls_offset = off - firstbyte;
+ if (off - firstbyte - offset > freetop - freebottom)
+ {
+ freebottom = offset;
+ freetop = off - firstbyte;
+ }
+
+ offset = off + slotinfo[cnt].map->l_tls_blocksize - firstbyte;
+ }
+
+ GL(dl_tls_static_used) = offset;
+ GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS,
+ TLS_TCB_ALIGN);
+#else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+#endif
+
+ /* The alignment requirement for the static TLS block. */
+ GL(dl_tls_static_align) = max_align;
+}
+#endif /* SHARED */
+
+static void *
+internal_function
+allocate_dtv (void *result)
+{
+ dtv_t *dtv;
+ size_t dtv_length;
+
+ /* We allocate a few more elements in the dtv than are needed for the
+ initial set of modules. This should avoid in most cases expansions
+ of the dtv. */
+ dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
+ dtv = calloc (dtv_length + 2, sizeof (dtv_t));
+ if (dtv != NULL)
+ {
+ /* This is the initial length of the dtv. */
+ dtv[0].counter = dtv_length;
+
+ /* The rest of the dtv (including the generation counter) is
+ Initialize with zero to indicate nothing there. */
+
+ /* Add the dtv to the thread data structures. */
+ INSTALL_DTV (result, dtv);
+ }
+ else
+ result = NULL;
+
+ return result;
+}
+
+
+/* Get size and alignment requirements of the static TLS block. */
+void
+internal_function
+_dl_get_tls_static_info (size_t *sizep, size_t *alignp)
+{
+ *sizep = GL(dl_tls_static_size);
+ *alignp = GL(dl_tls_static_align);
+}
+
+/* Derive the location of the pointer to the start of the original
+ allocation (before alignment) from the pointer to the TCB. */
+static inline void **
+tcb_to_pointer_to_free_location (void *tcb)
+{
+#if TLS_TCB_AT_TP
+ /* The TCB follows the TLS blocks, and the pointer to the front
+ follows the TCB. */
+ void **original_pointer_location = tcb + TLS_TCB_SIZE;
+#elif TLS_DTV_AT_TP
+ /* The TCB comes first, preceded by the pre-TCB, and the pointer is
+ before that. */
+ void **original_pointer_location = tcb - TLS_PRE_TCB_SIZE - sizeof (void *);
+#endif
+ return original_pointer_location;
+}
+
+void *
+internal_function
+_dl_allocate_tls_storage (void)
+{
+ void *result;
+ size_t size = GL(dl_tls_static_size);
+
+#if TLS_DTV_AT_TP
+ /* Memory layout is:
+ [ TLS_PRE_TCB_SIZE ] [ TLS_TCB_SIZE ] [ TLS blocks ]
+ ^ This should be returned. */
+ size += TLS_PRE_TCB_SIZE;
+#endif
+
+ /* Perform the allocation. Reserve space for the required alignment
+ and the pointer to the original allocation. */
+ size_t alignment = GL(dl_tls_static_align);
+ void *allocated = malloc (size + alignment + sizeof (void *));
+ if (__glibc_unlikely (allocated == NULL))
+ return NULL;
+
+ /* Perform alignment and allocate the DTV. */
+#if TLS_TCB_AT_TP
+ /* The TCB follows the TLS blocks, which determine the alignment.
+ (TCB alignment requirements have been taken into account when
+ calculating GL(dl_tls_static_align).) */
+ void *aligned = (void *) roundup ((uintptr_t) allocated, alignment);
+ result = aligned + size - TLS_TCB_SIZE;
+
+ /* Clear the TCB data structure. We can't ask the caller (i.e.
+ libpthread) to do it, because we will initialize the DTV et al. */
+ memset (result, '\0', TLS_TCB_SIZE);
+#elif TLS_DTV_AT_TP
+ /* Pre-TCB and TCB come before the TLS blocks. The layout computed
+ in _dl_determine_tlsoffset assumes that the TCB is aligned to the
+ TLS block alignment, and not just the TLS blocks after it. This
+ can leave an unused alignment gap between the TCB and the TLS
+ blocks. */
+ result = (void *) roundup
+ (sizeof (void *) + TLS_PRE_TCB_SIZE + (uintptr_t) allocated,
+ alignment);
+
+ /* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before
+ it. We can't ask the caller (i.e. libpthread) to do it, because
+ we will initialize the DTV et al. */
+ memset (result - TLS_PRE_TCB_SIZE, '\0', TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
+#endif
+
+ /* Record the value of the original pointer for later
+ deallocation. */
+ *tcb_to_pointer_to_free_location (result) = allocated;
+
+ result = allocate_dtv (result);
+ if (result == NULL)
+ free (allocated);
+ return result;
+}
+
+
+#ifndef SHARED
+extern dtv_t _dl_static_dtv[];
+# define _dl_initial_dtv (&_dl_static_dtv[1])
+#endif
+
+static dtv_t *
+_dl_resize_dtv (dtv_t *dtv)
+{
+ /* Resize the dtv. */
+ dtv_t *newp;
+ /* Load GL(dl_tls_max_dtv_idx) atomically since it may be written to by
+ other threads concurrently. */
+ size_t newsize
+ = atomic_load_acquire (&GL(dl_tls_max_dtv_idx)) + DTV_SURPLUS;
+ size_t oldsize = dtv[-1].counter;
+
+ if (dtv == GL(dl_initial_dtv))
+ {
+ /* This is the initial dtv that was either statically allocated in
+ __libc_setup_tls or allocated during rtld startup using the
+ dl-minimal.c malloc instead of the real malloc. We can't free
+ it, we have to abandon the old storage. */
+
+ newp = malloc ((2 + newsize) * sizeof (dtv_t));
+ if (newp == NULL)
+ oom ();
+ memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
+ }
+ else
+ {
+ newp = realloc (&dtv[-1],
+ (2 + newsize) * sizeof (dtv_t));
+ if (newp == NULL)
+ oom ();
+ }
+
+ newp[0].counter = newsize;
+
+ /* Clear the newly allocated part. */
+ memset (newp + 2 + oldsize, '\0',
+ (newsize - oldsize) * sizeof (dtv_t));
+
+ /* Return the generation counter. */
+ return &newp[1];
+}
+
+
+void *
+internal_function
+_dl_allocate_tls_init (void *result)
+{
+ if (result == NULL)
+ /* The memory allocation failed. */
+ return NULL;
+
+ dtv_t *dtv = GET_DTV (result);
+ struct dtv_slotinfo_list *listp;
+ size_t total = 0;
+ size_t maxgen = 0;
+
+ /* Check if the current dtv is big enough. */
+ if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
+ {
+ /* Resize the dtv. */
+ dtv = _dl_resize_dtv (dtv);
+
+ /* Install this new dtv in the thread data structures. */
+ INSTALL_DTV (result, &dtv[-1]);
+ }
+
+ /* We have to prepare the dtv for all currently loaded modules using
+ TLS. For those which are dynamically loaded we add the values
+ indicating deferred allocation. */
+ listp = GL(dl_tls_dtv_slotinfo_list);
+ while (1)
+ {
+ size_t cnt;
+
+ for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
+ {
+ struct link_map *map;
+ void *dest;
+
+ /* Check for the total number of used slots. */
+ if (total + cnt > GL(dl_tls_max_dtv_idx))
+ break;
+
+ map = listp->slotinfo[cnt].map;
+ if (map == NULL)
+ /* Unused entry. */
+ continue;
+
+ /* Keep track of the maximum generation number. This might
+ not be the generation counter. */
+ assert (listp->slotinfo[cnt].gen <= GL(dl_tls_generation));
+ maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
+
+ dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
+ dtv[map->l_tls_modid].pointer.to_free = NULL;
+
+ if (map->l_tls_offset == NO_TLS_OFFSET
+ || map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
+ continue;
+
+ assert (map->l_tls_modid == total + cnt);
+ assert (map->l_tls_blocksize >= map->l_tls_initimage_size);
+#if TLS_TCB_AT_TP
+ assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize);
+ dest = (char *) result - map->l_tls_offset;
+#elif TLS_DTV_AT_TP
+ dest = (char *) result + map->l_tls_offset;
+#else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+#endif
+
+ /* Set up the DTV entry. The simplified __tls_get_addr that
+ some platforms use in static programs requires it. */
+ dtv[map->l_tls_modid].pointer.val = dest;
+
+ /* Copy the initialization image and clear the BSS part. */
+ memset (__mempcpy (dest, map->l_tls_initimage,
+ map->l_tls_initimage_size), '\0',
+ map->l_tls_blocksize - map->l_tls_initimage_size);
+ }
+
+ total += cnt;
+ if (total >= GL(dl_tls_max_dtv_idx))
+ break;
+
+ listp = listp->next;
+ assert (listp != NULL);
+ }
+
+ /* The DTV version is up-to-date now. */
+ dtv[0].counter = maxgen;
+
+ return result;
+}
+rtld_hidden_def (_dl_allocate_tls_init)
+
+void *
+internal_function
+_dl_allocate_tls (void *mem)
+{
+ return _dl_allocate_tls_init (mem == NULL
+ ? _dl_allocate_tls_storage ()
+ : allocate_dtv (mem));
+}
+rtld_hidden_def (_dl_allocate_tls)
+
+
+void
+internal_function
+_dl_deallocate_tls (void *tcb, bool dealloc_tcb)
+{
+ dtv_t *dtv = GET_DTV (tcb);
+
+ /* We need to free the memory allocated for non-static TLS. */
+ for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
+ free (dtv[1 + cnt].pointer.to_free);
+
+ /* The array starts with dtv[-1]. */
+ if (dtv != GL(dl_initial_dtv))
+ free (dtv - 1);
+
+ if (dealloc_tcb)
+ free (*tcb_to_pointer_to_free_location (tcb));
+}
+rtld_hidden_def (_dl_deallocate_tls)
+
+
+#ifdef SHARED
+/* The __tls_get_addr function has two basic forms which differ in the
+ arguments. The IA-64 form takes two parameters, the module ID and
+ offset. The form used, among others, on IA-32 takes a reference to
+ a special structure which contain the same information. The second
+ form seems to be more often used (in the moment) so we default to
+ it. Users of the IA-64 form have to provide adequate definitions
+ of the following macros. */
+# ifndef GET_ADDR_ARGS
+# define GET_ADDR_ARGS tls_index *ti
+# define GET_ADDR_PARAM ti
+# endif
+# ifndef GET_ADDR_MODULE
+# define GET_ADDR_MODULE ti->ti_module
+# endif
+# ifndef GET_ADDR_OFFSET
+# define GET_ADDR_OFFSET ti->ti_offset
+# endif
+
+/* Allocate one DTV entry. */
+static struct dtv_pointer
+allocate_dtv_entry (size_t alignment, size_t size)
+{
+ if (powerof2 (alignment) && alignment <= _Alignof (max_align_t))
+ {
+ /* The alignment is supported by malloc. */
+ void *ptr = malloc (size);
+ return (struct dtv_pointer) { ptr, ptr };
+ }
+
+ /* Emulate memalign to by manually aligning a pointer returned by
+ malloc. First compute the size with an overflow check. */
+ size_t alloc_size = size + alignment;
+ if (alloc_size < size)
+ return (struct dtv_pointer) {};
+
+ /* Perform the allocation. This is the pointer we need to free
+ later. */
+ void *start = malloc (alloc_size);
+ if (start == NULL)
+ return (struct dtv_pointer) {};
+
+ /* Find the aligned position within the larger allocation. */
+ void *aligned = (void *) roundup ((uintptr_t) start, alignment);
+
+ return (struct dtv_pointer) { .val = aligned, .to_free = start };
+}
+
+static struct dtv_pointer
+allocate_and_init (struct link_map *map)
+{
+ struct dtv_pointer result = allocate_dtv_entry
+ (map->l_tls_align, map->l_tls_blocksize);
+ if (result.val == NULL)
+ oom ();
+
+ /* Initialize the memory. */
+ memset (__mempcpy (result.val, map->l_tls_initimage,
+ map->l_tls_initimage_size),
+ '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
+
+ return result;
+}
+
+
+struct link_map *
+_dl_update_slotinfo (unsigned long int req_modid)
+{
+ struct link_map *the_map = NULL;
+ dtv_t *dtv = THREAD_DTV ();
+
+ /* The global dl_tls_dtv_slotinfo array contains for each module
+ index the generation counter current when the entry was created.
+ This array never shrinks so that all module indices which were
+ valid at some time can be used to access it. Before the first
+ use of a new module index in this function the array was extended
+ appropriately. Access also does not have to be guarded against
+ modifications of the array. It is assumed that pointer-size
+ values can be read atomically even in SMP environments. It is
+ possible that other threads at the same time dynamically load
+ code and therefore add to the slotinfo list. This is a problem
+ since we must not pick up any information about incomplete work.
+ The solution to this is to ignore all dtv slots which were
+ created after the one we are currently interested. We know that
+ dynamic loading for this module is completed and this is the last
+ load operation we know finished. */
+ unsigned long int idx = req_modid;
+ struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+
+ while (idx >= listp->len)
+ {
+ idx -= listp->len;
+ listp = listp->next;
+ }
+
+ if (dtv[0].counter < listp->slotinfo[idx].gen)
+ {
+ /* The generation counter for the slot is higher than what the
+ current dtv implements. We have to update the whole dtv but
+ only those entries with a generation counter <= the one for
+ the entry we need. */
+ size_t new_gen = listp->slotinfo[idx].gen;
+ size_t total = 0;
+
+ /* We have to look through the entire dtv slotinfo list. */
+ listp = GL(dl_tls_dtv_slotinfo_list);
+ do
+ {
+ for (size_t cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
+ {
+ size_t gen = listp->slotinfo[cnt].gen;
+
+ if (gen > new_gen)
+ /* This is a slot for a generation younger than the
+ one we are handling now. It might be incompletely
+ set up so ignore it. */
+ continue;
+
+ /* If the entry is older than the current dtv layout we
+ know we don't have to handle it. */
+ if (gen <= dtv[0].counter)
+ continue;
+
+ /* If there is no map this means the entry is empty. */
+ struct link_map *map = listp->slotinfo[cnt].map;
+ if (map == NULL)
+ {
+ if (dtv[-1].counter >= total + cnt)
+ {
+ /* If this modid was used at some point the memory
+ might still be allocated. */
+ free (dtv[total + cnt].pointer.to_free);
+ dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
+ dtv[total + cnt].pointer.to_free = NULL;
+ }
+
+ continue;
+ }
+
+ /* Check whether the current dtv array is large enough. */
+ size_t modid = map->l_tls_modid;
+ assert (total + cnt == modid);
+ if (dtv[-1].counter < modid)
+ {
+ /* Resize the dtv. */
+ dtv = _dl_resize_dtv (dtv);
+
+ assert (modid <= dtv[-1].counter);
+
+ /* Install this new dtv in the thread data
+ structures. */
+ INSTALL_NEW_DTV (dtv);
+ }
+
+ /* If there is currently memory allocate for this
+ dtv entry free it. */
+ /* XXX Ideally we will at some point create a memory
+ pool. */
+ free (dtv[modid].pointer.to_free);
+ dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
+ dtv[modid].pointer.to_free = NULL;
+
+ if (modid == req_modid)
+ the_map = map;
+ }
+
+ total += listp->len;
+ }
+ while ((listp = listp->next) != NULL);
+
+ /* This will be the new maximum generation counter. */
+ dtv[0].counter = new_gen;
+ }
+
+ return the_map;
+}
+
+
+static void *
+__attribute_noinline__
+tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
+{
+ /* The allocation was deferred. Do it now. */
+ if (the_map == NULL)
+ {
+ /* Find the link map for this module. */
+ size_t idx = GET_ADDR_MODULE;
+ struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+
+ while (idx >= listp->len)
+ {
+ idx -= listp->len;
+ listp = listp->next;
+ }
+
+ the_map = listp->slotinfo[idx].map;
+ }
+
+ /* Make sure that, if a dlopen running in parallel forces the
+ variable into static storage, we'll wait until the address in the
+ static TLS block is set up, and use that. If we're undecided
+ yet, make sure we make the decision holding the lock as well. */
+ if (__glibc_unlikely (the_map->l_tls_offset
+ != FORCED_DYNAMIC_TLS_OFFSET))
+ {
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+ if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET))
+ {
+ the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ }
+ else if (__glibc_likely (the_map->l_tls_offset
+ != FORCED_DYNAMIC_TLS_OFFSET))
+ {
+#if TLS_TCB_AT_TP
+ void *p = (char *) THREAD_SELF - the_map->l_tls_offset;
+#elif TLS_DTV_AT_TP
+ void *p = (char *) THREAD_SELF + the_map->l_tls_offset + TLS_PRE_TCB_SIZE;
+#else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+#endif
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+ dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
+ dtv[GET_ADDR_MODULE].pointer.val = p;
+
+ return (char *) p + GET_ADDR_OFFSET;
+ }
+ else
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ }
+ struct dtv_pointer result = allocate_and_init (the_map);
+ dtv[GET_ADDR_MODULE].pointer = result;
+ assert (result.to_free != NULL);
+
+ return (char *) result.val + GET_ADDR_OFFSET;
+}
+
+
+static struct link_map *
+__attribute_noinline__
+update_get_addr (GET_ADDR_ARGS)
+{
+ struct link_map *the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
+ dtv_t *dtv = THREAD_DTV ();
+
+ void *p = dtv[GET_ADDR_MODULE].pointer.val;
+
+ if (__glibc_unlikely (p == TLS_DTV_UNALLOCATED))
+ return tls_get_addr_tail (GET_ADDR_PARAM, dtv, the_map);
+
+ return (void *) p + GET_ADDR_OFFSET;
+}
+
+/* For all machines that have a non-macro version of __tls_get_addr, we
+ want to use rtld_hidden_proto/rtld_hidden_def in order to call the
+ internal alias for __tls_get_addr from ld.so. This avoids a PLT entry
+ in ld.so for __tls_get_addr. */
+
+#ifndef __tls_get_addr
+extern void * __tls_get_addr (GET_ADDR_ARGS);
+rtld_hidden_proto (__tls_get_addr)
+rtld_hidden_def (__tls_get_addr)
+#endif
+
+/* The generic dynamic and local dynamic model cannot be used in
+ statically linked applications. */
+void *
+__tls_get_addr (GET_ADDR_ARGS)
+{
+ dtv_t *dtv = THREAD_DTV ();
+
+ if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
+ return update_get_addr (GET_ADDR_PARAM);
+
+ void *p = dtv[GET_ADDR_MODULE].pointer.val;
+
+ if (__glibc_unlikely (p == TLS_DTV_UNALLOCATED))
+ return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);
+
+ return (char *) p + GET_ADDR_OFFSET;
+}
+#endif
+
+
+/* Look up the module's TLS block as for __tls_get_addr,
+ but never touch anything. Return null if it's not allocated yet. */
+void *
+_dl_tls_get_addr_soft (struct link_map *l)
+{
+ if (__glibc_unlikely (l->l_tls_modid == 0))
+ /* This module has no TLS segment. */
+ return NULL;
+
+ dtv_t *dtv = THREAD_DTV ();
+ if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
+ {
+ /* This thread's DTV is not completely current,
+ but it might already cover this module. */
+
+ if (l->l_tls_modid >= dtv[-1].counter)
+ /* Nope. */
+ return NULL;
+
+ size_t idx = l->l_tls_modid;
+ struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+ while (idx >= listp->len)
+ {
+ idx -= listp->len;
+ listp = listp->next;
+ }
+
+ /* We've reached the slot for this module.
+ If its generation counter is higher than the DTV's,
+ this thread does not know about this module yet. */
+ if (dtv[0].counter < listp->slotinfo[idx].gen)
+ return NULL;
+ }
+
+ void *data = dtv[l->l_tls_modid].pointer.val;
+ if (__glibc_unlikely (data == TLS_DTV_UNALLOCATED))
+ /* The DTV is current, but this thread has not yet needed
+ to allocate this module's segment. */
+ data = NULL;
+
+ return data;
+}
+
+
+void
+_dl_add_to_slotinfo (struct link_map *l)
+{
+ /* Now that we know the object is loaded successfully add
+ modules containing TLS data to the dtv info table. We
+ might have to increase its size. */
+ struct dtv_slotinfo_list *listp;
+ struct dtv_slotinfo_list *prevp;
+ size_t idx = l->l_tls_modid;
+
+ /* Find the place in the dtv slotinfo list. */
+ listp = GL(dl_tls_dtv_slotinfo_list);
+ prevp = NULL; /* Needed to shut up gcc. */
+ do
+ {
+ /* Does it fit in the array of this list element? */
+ if (idx < listp->len)
+ break;
+ idx -= listp->len;
+ prevp = listp;
+ listp = listp->next;
+ }
+ while (listp != NULL);
+
+ if (listp == NULL)
+ {
+ /* When we come here it means we have to add a new element
+ to the slotinfo list. And the new module must be in
+ the first slot. */
+ assert (idx == 0);
+
+ listp = prevp->next = (struct dtv_slotinfo_list *)
+ malloc (sizeof (struct dtv_slotinfo_list)
+ + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
+ if (listp == NULL)
+ {
+ /* We ran out of memory. We will simply fail this
+ call but don't undo anything we did so far. The
+ application will crash or be terminated anyway very
+ soon. */
+
+ /* We have to do this since some entries in the dtv
+ slotinfo array might already point to this
+ generation. */
+ ++GL(dl_tls_generation);
+
+ _dl_signal_error (ENOMEM, "dlopen", NULL, N_("\
+cannot create TLS data structures"));
+ }
+
+ listp->len = TLS_SLOTINFO_SURPLUS;
+ listp->next = NULL;
+ memset (listp->slotinfo, '\0',
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
+ }
+
+ /* Add the information into the slotinfo data structure. */
+ listp->slotinfo[idx].map = l;
+ listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
+}
diff --git a/REORG.TODO/elf/dl-trampoline.c b/REORG.TODO/elf/dl-trampoline.c
new file mode 100644
index 0000000000..3ca89f3879
--- /dev/null
+++ b/REORG.TODO/elf/dl-trampoline.c
@@ -0,0 +1 @@
+#error "Architecture specific PLT trampolines must be defined."
diff --git a/REORG.TODO/elf/dl-tunable-types.h b/REORG.TODO/elf/dl-tunable-types.h
new file mode 100644
index 0000000000..1d516df08f
--- /dev/null
+++ b/REORG.TODO/elf/dl-tunable-types.h
@@ -0,0 +1,62 @@
+/* Tunable type information.
+
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _TUNABLE_TYPES_H_
+# define _TUNABLE_TYPES_H_
+#include <stddef.h>
+
+typedef enum
+{
+ TUNABLE_TYPE_INT_32,
+ TUNABLE_TYPE_UINT_64,
+ TUNABLE_TYPE_SIZE_T,
+ TUNABLE_TYPE_STRING
+} tunable_type_code_t;
+
+typedef struct
+{
+ tunable_type_code_t type_code;
+ int64_t min;
+ int64_t max;
+} tunable_type_t;
+
+typedef union
+{
+ int64_t numval;
+ const char *strval;
+} tunable_val_t;
+
+typedef void (*tunable_callback_t) (tunable_val_t *);
+
+/* Security level for tunables. This decides what to do with individual
+ tunables for AT_SECURE binaries. */
+typedef enum
+{
+ /* Erase the tunable for AT_SECURE binaries so that child processes don't
+ read it. */
+ TUNABLE_SECLEVEL_SXID_ERASE = 0,
+ /* Ignore the tunable for AT_SECURE binaries, but don't erase it, so that
+ child processes can read it. */
+ TUNABLE_SECLEVEL_SXID_IGNORE = 1,
+ /* Read the tunable. */
+ TUNABLE_SECLEVEL_NONE = 2,
+} tunable_seclevel_t;
+
+
+#endif
diff --git a/REORG.TODO/elf/dl-tunables.c b/REORG.TODO/elf/dl-tunables.c
new file mode 100644
index 0000000000..76e8c5cae1
--- /dev/null
+++ b/REORG.TODO/elf/dl-tunables.c
@@ -0,0 +1,490 @@
+/* The tunable framework. See the README.tunables to know how to use the
+ tunable in a glibc module.
+
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <fcntl.h>
+#include <ldsodefs.h>
+
+#define TUNABLES_INTERNAL 1
+#include "dl-tunables.h"
+
+#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
+# define GLIBC_TUNABLES "GLIBC_TUNABLES"
+#endif
+
+/* Compare environment or tunable names, bounded by the name hardcoded in
+ glibc. */
+static bool
+is_name (const char *orig, const char *envname)
+{
+ for (;*orig != '\0' && *envname != '\0'; envname++, orig++)
+ if (*orig != *envname)
+ break;
+
+ /* The ENVNAME is immediately followed by a value. */
+ if (*orig == '\0' && *envname == '=')
+ return true;
+ else
+ return false;
+}
+
+#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
+static char *
+tunables_strdup (const char *in)
+{
+ size_t i = 0;
+
+ while (in[i++] != '\0');
+ char *out = __sbrk (i);
+
+ /* FIXME: In reality if the allocation fails, __sbrk will crash attempting to
+ set the thread-local errno since the TCB has not yet been set up. This
+ needs to be fixed with an __sbrk implementation that does not set
+ errno. */
+ if (out == (void *)-1)
+ return NULL;
+
+ i--;
+
+ while (i-- > 0)
+ out[i] = in[i];
+
+ return out;
+}
+#endif
+
+static char **
+get_next_env (char **envp, char **name, size_t *namelen, char **val,
+ char ***prev_envp)
+{
+ while (envp != NULL && *envp != NULL)
+ {
+ char **prev = envp;
+ char *envline = *envp++;
+ int len = 0;
+
+ while (envline[len] != '\0' && envline[len] != '=')
+ len++;
+
+ /* Just the name and no value, go to the next one. */
+ if (envline[len] == '\0')
+ continue;
+
+ *name = envline;
+ *namelen = len;
+ *val = &envline[len + 1];
+ *prev_envp = prev;
+
+ return envp;
+ }
+
+ return NULL;
+}
+
+/* A stripped down strtoul-like implementation for very early use. It does not
+ set errno if the result is outside bounds because it gets called before
+ errno may have been set up. */
+static uint64_t
+tunables_strtoul (const char *nptr)
+{
+ uint64_t result = 0;
+ long int sign = 1;
+ unsigned max_digit;
+
+ while (*nptr == ' ' || *nptr == '\t')
+ ++nptr;
+
+ if (*nptr == '-')
+ {
+ sign = -1;
+ ++nptr;
+ }
+ else if (*nptr == '+')
+ ++nptr;
+
+ if (*nptr < '0' || *nptr > '9')
+ return 0UL;
+
+ int base = 10;
+ max_digit = 9;
+ if (*nptr == '0')
+ {
+ if (nptr[1] == 'x' || nptr[1] == 'X')
+ {
+ base = 16;
+ nptr += 2;
+ }
+ else
+ {
+ base = 8;
+ max_digit = 7;
+ }
+ }
+
+ while (1)
+ {
+ int digval;
+ if (*nptr >= '0' && *nptr <= '0' + max_digit)
+ digval = *nptr - '0';
+ else if (base == 16)
+ {
+ if (*nptr >= 'a' && *nptr <= 'f')
+ digval = *nptr - 'a' + 10;
+ else if (*nptr >= 'A' && *nptr <= 'F')
+ digval = *nptr - 'A' + 10;
+ else
+ break;
+ }
+ else
+ break;
+
+ if (result >= (UINT64_MAX - digval) / base)
+ return UINT64_MAX;
+ result *= base;
+ result += digval;
+ ++nptr;
+ }
+
+ return result * sign;
+}
+
+#define TUNABLE_SET_VAL_IF_VALID_RANGE(__cur, __val, __type, __default_min, \
+ __default_max) \
+({ \
+ __type min = (__cur)->type.min; \
+ __type max = (__cur)->type.max; \
+ \
+ if (min == max) \
+ { \
+ min = __default_min; \
+ max = __default_max; \
+ } \
+ \
+ if ((__type) (__val) >= min && (__type) (val) <= max) \
+ { \
+ (__cur)->val.numval = val; \
+ (__cur)->initialized = true; \
+ } \
+})
+
+static void
+do_tunable_update_val (tunable_t *cur, const void *valp)
+{
+ uint64_t val;
+
+ if (cur->type.type_code != TUNABLE_TYPE_STRING)
+ val = *((int64_t *) valp);
+
+ switch (cur->type.type_code)
+ {
+ case TUNABLE_TYPE_INT_32:
+ {
+ TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, int64_t, INT32_MIN, INT32_MAX);
+ break;
+ }
+ case TUNABLE_TYPE_UINT_64:
+ {
+ TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t, 0, UINT64_MAX);
+ break;
+ }
+ case TUNABLE_TYPE_SIZE_T:
+ {
+ TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t, 0, SIZE_MAX);
+ break;
+ }
+ case TUNABLE_TYPE_STRING:
+ {
+ cur->val.strval = valp;
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+/* Validate range of the input value and initialize the tunable CUR if it looks
+ good. */
+static void
+tunable_initialize (tunable_t *cur, const char *strval)
+{
+ uint64_t val;
+ const void *valp;
+
+ if (cur->type.type_code != TUNABLE_TYPE_STRING)
+ {
+ val = tunables_strtoul (strval);
+ valp = &val;
+ }
+ else
+ {
+ cur->initialized = true;
+ valp = strval;
+ }
+ do_tunable_update_val (cur, valp);
+}
+
+void
+__tunable_set_val (tunable_id_t id, void *valp)
+{
+ tunable_t *cur = &tunable_list[id];
+
+ do_tunable_update_val (cur, valp);
+}
+
+#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
+/* Parse the tunable string TUNESTR and adjust it to drop any tunables that may
+ be unsafe for AT_SECURE processes so that it can be used as the new
+ environment variable value for GLIBC_TUNABLES. VALSTRING is the original
+ environment variable string which we use to make NULL terminated values so
+ that we don't have to allocate memory again for it. */
+static void
+parse_tunables (char *tunestr, char *valstring)
+{
+ if (tunestr == NULL || *tunestr == '\0')
+ return;
+
+ char *p = tunestr;
+
+ while (true)
+ {
+ char *name = p;
+ size_t len = 0;
+
+ /* First, find where the name ends. */
+ while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
+ len++;
+
+ /* If we reach the end of the string before getting a valid name-value
+ pair, bail out. */
+ if (p[len] == '\0')
+ return;
+
+ /* We did not find a valid name-value pair before encountering the
+ colon. */
+ if (p[len]== ':')
+ {
+ p += len + 1;
+ continue;
+ }
+
+ p += len + 1;
+
+ /* Take the value from the valstring since we need to NULL terminate it. */
+ char *value = &valstring[p - tunestr];
+ len = 0;
+
+ while (p[len] != ':' && p[len] != '\0')
+ len++;
+
+ /* Add the tunable if it exists. */
+ for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
+ {
+ tunable_t *cur = &tunable_list[i];
+
+ if (is_name (cur->name, name))
+ {
+ /* If we are in a secure context (AT_SECURE) then ignore the tunable
+ unless it is explicitly marked as secure. Tunable values take
+ precendence over their envvar aliases. */
+ if (__libc_enable_secure)
+ {
+ if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
+ {
+ if (p[len] == '\0')
+ {
+ /* Last tunable in the valstring. Null-terminate and
+ return. */
+ *name = '\0';
+ return;
+ }
+ else
+ {
+ /* Remove the current tunable from the string. We do
+ this by overwriting the string starting from NAME
+ (which is where the current tunable begins) with
+ the remainder of the string. We then have P point
+ to NAME so that we continue in the correct
+ position in the valstring. */
+ char *q = &p[len + 1];
+ p = name;
+ while (*q != '\0')
+ *name++ = *q++;
+ name[0] = '\0';
+ len = 0;
+ }
+ }
+
+ if (cur->security_level != TUNABLE_SECLEVEL_NONE)
+ break;
+ }
+
+ value[len] = '\0';
+ tunable_initialize (cur, value);
+ break;
+ }
+ }
+
+ if (p[len] == '\0')
+ return;
+ else
+ p += len + 1;
+ }
+}
+#endif
+
+/* Enable the glibc.malloc.check tunable in SETUID/SETGID programs only when
+ the system administrator has created the /etc/suid-debug file. This is a
+ special case where we want to conditionally enable/disable a tunable even
+ for setuid binaries. We use the special version of access() to avoid
+ setting ERRNO, which is a TLS variable since TLS has not yet been set
+ up. */
+static inline void
+__always_inline
+maybe_enable_malloc_check (void)
+{
+ tunable_id_t id = TUNABLE_ENUM_NAME (glibc, malloc, check);
+ if (__libc_enable_secure && __access_noerrno ("/etc/suid-debug", F_OK) == 0)
+ tunable_list[id].security_level = TUNABLE_SECLEVEL_NONE;
+}
+
+/* Initialize the tunables list from the environment. For now we only use the
+ ENV_ALIAS to find values. Later we will also use the tunable names to find
+ values. */
+void
+__tunables_init (char **envp)
+{
+ char *envname = NULL;
+ char *envval = NULL;
+ size_t len = 0;
+ char **prev_envp = envp;
+
+ maybe_enable_malloc_check ();
+
+ while ((envp = get_next_env (envp, &envname, &len, &envval,
+ &prev_envp)) != NULL)
+ {
+#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
+ if (is_name (GLIBC_TUNABLES, envname))
+ {
+ char *new_env = tunables_strdup (envname);
+ if (new_env != NULL)
+ parse_tunables (new_env + len + 1, envval);
+ /* Put in the updated envval. */
+ *prev_envp = new_env;
+ continue;
+ }
+#endif
+
+ for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
+ {
+ tunable_t *cur = &tunable_list[i];
+
+ /* Skip over tunables that have either been set already or should be
+ skipped. */
+ if (cur->initialized || cur->env_alias == NULL)
+ continue;
+
+ const char *name = cur->env_alias;
+
+ /* We have a match. Initialize and move on to the next line. */
+ if (is_name (name, envname))
+ {
+ /* For AT_SECURE binaries, we need to check the security settings of
+ the tunable and decide whether we read the value and also whether
+ we erase the value so that child processes don't inherit them in
+ the environment. */
+ if (__libc_enable_secure)
+ {
+ if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
+ {
+ /* Erase the environment variable. */
+ char **ep = prev_envp;
+
+ while (*ep != NULL)
+ {
+ if (is_name (name, *ep))
+ {
+ char **dp = ep;
+
+ do
+ dp[0] = dp[1];
+ while (*dp++);
+ }
+ else
+ ++ep;
+ }
+ /* Reset the iterator so that we read the environment again
+ from the point we erased. */
+ envp = prev_envp;
+ }
+
+ if (cur->security_level != TUNABLE_SECLEVEL_NONE)
+ continue;
+ }
+
+ tunable_initialize (cur, envval);
+ break;
+ }
+ }
+ }
+}
+
+/* Set the tunable value. This is called by the module that the tunable exists
+ in. */
+void
+__tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
+{
+ tunable_t *cur = &tunable_list[id];
+
+ switch (cur->type.type_code)
+ {
+ case TUNABLE_TYPE_UINT_64:
+ {
+ *((uint64_t *) valp) = (uint64_t) cur->val.numval;
+ break;
+ }
+ case TUNABLE_TYPE_INT_32:
+ {
+ *((int32_t *) valp) = (int32_t) cur->val.numval;
+ break;
+ }
+ case TUNABLE_TYPE_SIZE_T:
+ {
+ *((size_t *) valp) = (size_t) cur->val.numval;
+ break;
+ }
+ case TUNABLE_TYPE_STRING:
+ {
+ *((const char **)valp) = cur->val.strval;
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+
+ if (cur->initialized && callback != NULL)
+ callback (&cur->val);
+}
+
+rtld_hidden_def (__tunable_get_val)
diff --git a/REORG.TODO/elf/dl-tunables.h b/REORG.TODO/elf/dl-tunables.h
new file mode 100644
index 0000000000..6c49dcbf47
--- /dev/null
+++ b/REORG.TODO/elf/dl-tunables.h
@@ -0,0 +1,115 @@
+/* The tunable framework. See the README to know how to use the tunable in
+ a glibc module.
+
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _TUNABLES_H_
+#define _TUNABLES_H_
+
+#if !HAVE_TUNABLES
+static inline void
+__always_inline
+__tunables_init (char **unused __attribute__ ((unused)))
+{
+ /* This is optimized out if tunables are not enabled. */
+}
+#else
+
+# include <stddef.h>
+# include "dl-tunable-types.h"
+
+/* A tunable. */
+struct _tunable
+{
+ const char *name; /* Internal name of the tunable. */
+ tunable_type_t type; /* Data type of the tunable. */
+ tunable_val_t val; /* The value. */
+ bool initialized; /* Flag to indicate that the tunable is
+ initialized. */
+ tunable_seclevel_t security_level; /* Specify the security level for the
+ tunable with respect to AT_SECURE
+ programs. See description of
+ tunable_seclevel_t to see a
+ description of the values.
+
+ Note that even if the tunable is
+ read, it may not get used by the
+ target module if the value is
+ considered unsafe. */
+ /* Compatibility elements. */
+ const char *env_alias; /* The compatibility environment
+ variable name. */
+};
+
+typedef struct _tunable tunable_t;
+
+/* Full name for a tunable is top_ns.tunable_ns.id. */
+# define TUNABLE_NAME_S(top,ns,id) #top "." #ns "." #id
+
+# define TUNABLE_ENUM_NAME(__top,__ns,__id) TUNABLE_ENUM_NAME1 (__top,__ns,__id)
+# define TUNABLE_ENUM_NAME1(__top,__ns,__id) __top ## _ ## __ns ## _ ## __id
+
+# include "dl-tunable-list.h"
+
+extern void __tunables_init (char **);
+extern void __tunable_get_val (tunable_id_t, void *, tunable_callback_t);
+extern void __tunable_set_val (tunable_id_t, void *);
+rtld_hidden_proto (__tunables_init)
+rtld_hidden_proto (__tunable_get_val)
+
+/* Define TUNABLE_GET and TUNABLE_SET in short form if TOP_NAMESPACE and
+ TUNABLE_NAMESPACE are defined. This is useful shorthand to get and set
+ tunables within a module. */
+#if defined TOP_NAMESPACE && defined TUNABLE_NAMESPACE
+# define TUNABLE_GET(__id, __type, __cb) \
+ TUNABLE_GET_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, __type, __cb)
+# define TUNABLE_SET(__id, __type, __val) \
+ TUNABLE_SET_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, __type, __val)
+#else
+# define TUNABLE_GET(__top, __ns, __id, __type, __cb) \
+ TUNABLE_GET_FULL (__top, __ns, __id, __type, __cb)
+# define TUNABLE_SET(__top, __ns, __id, __type, __val) \
+ TUNABLE_SET_FULL (__top, __ns, __id, __type, __val)
+#endif
+
+/* Get and return a tunable value. If the tunable was set externally and __CB
+ is defined then call __CB before returning the value. */
+# define TUNABLE_GET_FULL(__top, __ns, __id, __type, __cb) \
+({ \
+ tunable_id_t id = TUNABLE_ENUM_NAME (__top, __ns, __id); \
+ __type ret; \
+ __tunable_get_val (id, &ret, __cb); \
+ ret; \
+})
+
+/* Set a tunable value. */
+# define TUNABLE_SET_FULL(__top, __ns, __id, __type, __val) \
+({ \
+ __tunable_set_val (TUNABLE_ENUM_NAME (__top, __ns, __id), \
+ & (__type) {__val}); \
+})
+
+/* Namespace sanity for callback functions. Use this macro to keep the
+ namespace of the modules clean. */
+# define TUNABLE_CALLBACK(__name) _dl_tunable_ ## __name
+
+# define TUNABLES_FRONTEND_valstring 1
+/* The default value for TUNABLES_FRONTEND. */
+# define TUNABLES_FRONTEND_yes TUNABLES_FRONTEND_valstring
+#endif
+#endif
diff --git a/REORG.TODO/elf/dl-tunables.list b/REORG.TODO/elf/dl-tunables.list
new file mode 100644
index 0000000000..41ce9afa28
--- /dev/null
+++ b/REORG.TODO/elf/dl-tunables.list
@@ -0,0 +1,87 @@
+# Copyright (C) 2016-2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+# Allowed attributes for tunables:
+#
+# type: Defaults to STRING
+# minval: Optional minimum acceptable value
+# maxval: Optional maximum acceptable value
+# env_alias: An alias environment variable
+# security_level: Specify security level of the tunable. Valid values are:
+#
+# SXID_ERASE: (default) Don't read for AT_SECURE binaries and
+# removed so that child processes can't read it.
+# SXID_IGNORE: Don't read for AT_SECURE binaries, but retained for
+# non-AT_SECURE subprocesses.
+# NONE: Read all the time.
+
+glibc {
+ malloc {
+ check {
+ type: INT_32
+ minval: 0
+ maxval: 3
+ env_alias: MALLOC_CHECK_
+ }
+ top_pad {
+ type: SIZE_T
+ env_alias: MALLOC_TOP_PAD_
+ security_level: SXID_IGNORE
+ }
+ perturb {
+ type: INT_32
+ minval: 0
+ maxval: 0xff
+ env_alias: MALLOC_PERTURB_
+ security_level: SXID_IGNORE
+ }
+ mmap_threshold {
+ type: SIZE_T
+ env_alias: MALLOC_MMAP_THRESHOLD_
+ security_level: SXID_IGNORE
+ }
+ trim_threshold {
+ type: SIZE_T
+ env_alias: MALLOC_TRIM_THRESHOLD_
+ security_level: SXID_IGNORE
+ }
+ mmap_max {
+ type: INT_32
+ env_alias: MALLOC_MMAP_MAX_
+ security_level: SXID_IGNORE
+ }
+ arena_max {
+ type: SIZE_T
+ env_alias: MALLOC_ARENA_MAX
+ minval: 1
+ security_level: SXID_IGNORE
+ }
+ arena_test {
+ type: SIZE_T
+ env_alias: MALLOC_ARENA_TEST
+ minval: 1
+ security_level: SXID_IGNORE
+ }
+ }
+ tune {
+ hwcap_mask {
+ type: UINT_64
+ env_alias: LD_HWCAP_MASK
+ default: HWCAP_IMPORTANT
+ }
+ }
+}
diff --git a/REORG.TODO/elf/dl-unmap-segments.h b/REORG.TODO/elf/dl-unmap-segments.h
new file mode 100644
index 0000000000..f37e183943
--- /dev/null
+++ b/REORG.TODO/elf/dl-unmap-segments.h
@@ -0,0 +1,35 @@
+/* Unmap a shared object's segments. Generic version.
+ Copyright (C) 2014-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _DL_UNMAP_SEGMENTS_H
+#define _DL_UNMAP_SEGMENTS_H 1
+
+#include <link.h>
+#include <sys/mman.h>
+
+/* _dl_map_segments ensures that any whole pages in gaps between segments
+ are filled in with PROT_NONE mappings. So we can just unmap the whole
+ range in one fell swoop. */
+
+static __always_inline void
+_dl_unmap_segments (struct link_map *l)
+{
+ __munmap ((void *) l->l_map_start, l->l_map_end - l->l_map_start);
+}
+
+#endif /* dl-unmap-segments.h */
diff --git a/REORG.TODO/elf/dl-version.c b/REORG.TODO/elf/dl-version.c
new file mode 100644
index 0000000000..c00078e5e4
--- /dev/null
+++ b/REORG.TODO/elf/dl-version.c
@@ -0,0 +1,389 @@
+/* Handle symbol and library versioning.
+ Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <elf.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ldsodefs.h>
+#include <_itoa.h>
+
+#include <assert.h>
+
+
+#define make_string(string, rest...) \
+ ({ \
+ const char *all[] = { string, ## rest }; \
+ size_t len, cnt; \
+ char *result, *cp; \
+ \
+ len = 1; \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ len += strlen (all[cnt]); \
+ \
+ cp = result = alloca (len); \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ cp = __stpcpy (cp, all[cnt]); \
+ \
+ result; \
+ })
+
+
+static inline struct link_map *
+__attribute ((always_inline))
+find_needed (const char *name, struct link_map *map)
+{
+ struct link_map *tmap;
+ unsigned int n;
+
+ for (tmap = GL(dl_ns)[map->l_ns]._ns_loaded; tmap != NULL;
+ tmap = tmap->l_next)
+ if (_dl_name_match_p (name, tmap))
+ return tmap;
+
+ /* The required object is not in the global scope, look to see if it is
+ a dependency of the current object. */
+ for (n = 0; n < map->l_searchlist.r_nlist; n++)
+ if (_dl_name_match_p (name, map->l_searchlist.r_list[n]))
+ return map->l_searchlist.r_list[n];
+
+ /* Should never happen. */
+ return NULL;
+}
+
+
+static int
+internal_function
+match_symbol (const char *name, Lmid_t ns, ElfW(Word) hash, const char *string,
+ struct link_map *map, int verbose, int weak)
+{
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+ ElfW(Addr) def_offset;
+ ElfW(Verdef) *def;
+ /* Initialize to make the compiler happy. */
+ const char *errstring = NULL;
+ int result = 0;
+
+ /* Display information about what we are doing while debugging. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS))
+ _dl_debug_printf ("\
+checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
+ string, DSO_FILENAME (map->l_name),
+ map->l_ns, name, ns);
+
+ if (__glibc_unlikely (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL))
+ {
+ /* The file has no symbol versioning. I.e., the dependent
+ object was linked against another version of this file. We
+ only print a message if verbose output is requested. */
+ if (verbose)
+ {
+ /* XXX We cannot translate the messages. */
+ errstring = make_string ("\
+no version information available (required by ", name, ")");
+ goto call_cerror;
+ }
+ return 0;
+ }
+
+ def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
+ assert (def_offset != 0);
+
+ def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
+ while (1)
+ {
+ /* Currently the version number of the definition entry is 1.
+ Make sure all we see is this version. */
+ if (__builtin_expect (def->vd_version, 1) != 1)
+ {
+ char buf[20];
+ buf[sizeof (buf) - 1] = '\0';
+ /* XXX We cannot translate the message. */
+ errstring = make_string ("unsupported version ",
+ _itoa (def->vd_version,
+ &buf[sizeof (buf) - 1], 10, 0),
+ " of Verdef record");
+ result = 1;
+ goto call_cerror;
+ }
+
+ /* Compare the hash values. */
+ if (hash == def->vd_hash)
+ {
+ ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
+
+ /* To be safe, compare the string as well. */
+ if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0)
+ == 0)
+ /* Bingo! */
+ return 0;
+ }
+
+ /* If no more definitions we failed to find what we want. */
+ if (def->vd_next == 0)
+ break;
+
+ /* Next definition. */
+ def = (ElfW(Verdef) *) ((char *) def + def->vd_next);
+ }
+
+ /* Symbol not found. If it was a weak reference it is not fatal. */
+ if (__glibc_likely (weak))
+ {
+ if (verbose)
+ {
+ /* XXX We cannot translate the message. */
+ errstring = make_string ("weak version `", string,
+ "' not found (required by ", name, ")");
+ goto call_cerror;
+ }
+ return 0;
+ }
+
+ /* XXX We cannot translate the message. */
+ errstring = make_string ("version `", string, "' not found (required by ",
+ name, ")");
+ result = 1;
+ call_cerror:
+ _dl_signal_cerror (0, DSO_FILENAME (map->l_name),
+ N_("version lookup error"), errstring);
+ return result;
+}
+
+
+int
+internal_function
+_dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
+{
+ int result = 0;
+ const char *strtab;
+ /* Pointer to section with needed versions. */
+ ElfW(Dyn) *dyn;
+ /* Pointer to dynamic section with definitions. */
+ ElfW(Dyn) *def;
+ /* We need to find out which is the highest version index used
+ in a dependecy. */
+ unsigned int ndx_high = 0;
+ /* Initialize to make the compiler happy. */
+ const char *errstring = NULL;
+ int errval = 0;
+
+ /* If we don't have a string table, we must be ok. */
+ if (map->l_info[DT_STRTAB] == NULL)
+ return 0;
+ strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+
+ dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
+ def = map->l_info[VERSYMIDX (DT_VERDEF)];
+
+ if (dyn != NULL)
+ {
+ /* This file requires special versions from its dependencies. */
+ ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
+
+ /* Currently the version number of the needed entry is 1.
+ Make sure all we see is this version. */
+ if (__builtin_expect (ent->vn_version, 1) != 1)
+ {
+ char buf[20];
+ buf[sizeof (buf) - 1] = '\0';
+ /* XXX We cannot translate the message. */
+ errstring = make_string ("unsupported version ",
+ _itoa (ent->vn_version,
+ &buf[sizeof (buf) - 1], 10, 0),
+ " of Verneed record\n");
+ call_error:
+ _dl_signal_error (errval, DSO_FILENAME (map->l_name),
+ NULL, errstring);
+ }
+
+ while (1)
+ {
+ ElfW(Vernaux) *aux;
+ struct link_map *needed = find_needed (strtab + ent->vn_file, map);
+
+ /* If NEEDED is NULL this means a dependency was not found
+ and no stub entry was created. This should never happen. */
+ assert (needed != NULL);
+
+ /* Make sure this is no stub we created because of a missing
+ dependency. */
+ if (__builtin_expect (! trace_mode, 1)
+ || ! __builtin_expect (needed->l_faked, 0))
+ {
+ /* NEEDED is the map for the file we need. Now look for the
+ dependency symbols. */
+ aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
+ while (1)
+ {
+ /* Match the symbol. */
+ result |= match_symbol (DSO_FILENAME (map->l_name),
+ map->l_ns, aux->vna_hash,
+ strtab + aux->vna_name,
+ needed->l_real, verbose,
+ aux->vna_flags & VER_FLG_WEAK);
+
+ /* Compare the version index. */
+ if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
+ ndx_high = aux->vna_other & 0x7fff;
+
+ if (aux->vna_next == 0)
+ /* No more symbols. */
+ break;
+
+ /* Next symbol. */
+ aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
+ }
+ }
+
+ if (ent->vn_next == 0)
+ /* No more dependencies. */
+ break;
+
+ /* Next dependency. */
+ ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
+ }
+ }
+
+ /* We also must store the names of the defined versions. Determine
+ the maximum index here as well.
+
+ XXX We could avoid the loop by just taking the number of definitions
+ as an upper bound of new indeces. */
+ if (def != NULL)
+ {
+ ElfW(Verdef) *ent;
+ ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
+ while (1)
+ {
+ if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
+ ndx_high = ent->vd_ndx & 0x7fff;
+
+ if (ent->vd_next == 0)
+ /* No more definitions. */
+ break;
+
+ ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
+ }
+ }
+
+ if (ndx_high > 0)
+ {
+ /* Now we are ready to build the array with the version names
+ which can be indexed by the version index in the VERSYM
+ section. */
+ map->l_versions = (struct r_found_version *)
+ calloc (ndx_high + 1, sizeof (*map->l_versions));
+ if (__glibc_unlikely (map->l_versions == NULL))
+ {
+ errstring = N_("cannot allocate version reference table");
+ errval = ENOMEM;
+ goto call_error;
+ }
+
+ /* Store the number of available symbols. */
+ map->l_nversions = ndx_high + 1;
+
+ /* Compute the pointer to the version symbols. */
+ map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+
+ if (dyn != NULL)
+ {
+ ElfW(Verneed) *ent;
+ ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
+ while (1)
+ {
+ ElfW(Vernaux) *aux;
+ aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
+ while (1)
+ {
+ ElfW(Half) ndx = aux->vna_other & 0x7fff;
+ /* In trace mode, dependencies may be missing. */
+ if (__glibc_likely (ndx < map->l_nversions))
+ {
+ map->l_versions[ndx].hash = aux->vna_hash;
+ map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
+ map->l_versions[ndx].name = &strtab[aux->vna_name];
+ map->l_versions[ndx].filename = &strtab[ent->vn_file];
+ }
+
+ if (aux->vna_next == 0)
+ /* No more symbols. */
+ break;
+
+ /* Advance to next symbol. */
+ aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
+ }
+
+ if (ent->vn_next == 0)
+ /* No more dependencies. */
+ break;
+
+ /* Advance to next dependency. */
+ ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
+ }
+ }
+
+ /* And insert the defined versions. */
+ if (def != NULL)
+ {
+ ElfW(Verdef) *ent;
+ ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
+ while (1)
+ {
+ ElfW(Verdaux) *aux;
+ aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux);
+
+ if ((ent->vd_flags & VER_FLG_BASE) == 0)
+ {
+ /* The name of the base version should not be
+ available for matching a versioned symbol. */
+ ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
+ map->l_versions[ndx].hash = ent->vd_hash;
+ map->l_versions[ndx].name = &strtab[aux->vda_name];
+ map->l_versions[ndx].filename = NULL;
+ }
+
+ if (ent->vd_next == 0)
+ /* No more definitions. */
+ break;
+
+ ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
+ }
+ }
+ }
+
+ return result;
+}
+
+
+int
+internal_function
+_dl_check_all_versions (struct link_map *map, int verbose, int trace_mode)
+{
+ struct link_map *l;
+ int result = 0;
+
+ for (l = map; l != NULL; l = l->l_next)
+ result |= (! l->l_faked
+ && _dl_check_map_versions (l, verbose, trace_mode));
+
+ return result;
+}
diff --git a/REORG.TODO/elf/dl-writev.h b/REORG.TODO/elf/dl-writev.h
new file mode 100644
index 0000000000..4db083bef6
--- /dev/null
+++ b/REORG.TODO/elf/dl-writev.h
@@ -0,0 +1,56 @@
+/* Message-writing for the dynamic linker. Generic version.
+ Copyright (C) 2013-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sys/uio.h>
+#include <ldsodefs.h>
+#include <libc-lock.h>
+
+/* This is used from only one place: dl-misc.c:_dl_debug_vdprintf.
+ Hence it's in a header with the expectation it will be inlined.
+
+ This is writev, but with a constraint added and others loosened:
+
+ 1. Under RTLD_PRIVATE_ERRNO, it must not clobber the private errno
+ when another thread holds the dl_load_lock.
+ 2. It is not obliged to detect and report errors at all.
+ 3. It's not really obliged to deliver a single atomic write
+ (though it may be preferable). */
+
+static inline void
+_dl_writev (int fd, const struct iovec *iov, size_t niov)
+{
+ /* Note that if __writev is an implementation that calls malloc,
+ this will cause linking problems building the dynamic linker. */
+
+#if RTLD_PRIVATE_ERRNO
+ /* We have to take this lock just to be sure we don't clobber the private
+ errno when it's being used by another thread that cares about it.
+ Yet we must be sure not to try calling the lock functions before
+ the thread library is fully initialized. */
+ if (__glibc_unlikely (_dl_starting_up))
+ __writev (fd, iov, niov);
+ else
+ {
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+ __writev (fd, iov, niov);
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ }
+#else
+ __writev (fd, iov, niov);
+#endif
+}
diff --git a/REORG.TODO/elf/do-rel.h b/REORG.TODO/elf/do-rel.h
new file mode 100644
index 0000000000..70071e5c44
--- /dev/null
+++ b/REORG.TODO/elf/do-rel.h
@@ -0,0 +1,191 @@
+/* Do relocations for ELF dynamic linking.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file may be included twice, to define both
+ `elf_dynamic_do_rel' and `elf_dynamic_do_rela'. */
+
+#ifdef DO_RELA
+# define elf_dynamic_do_Rel elf_dynamic_do_Rela
+# define Rel Rela
+# define elf_machine_rel elf_machine_rela
+# define elf_machine_rel_relative elf_machine_rela_relative
+#endif
+
+#ifndef DO_ELF_MACHINE_REL_RELATIVE
+# define DO_ELF_MACHINE_REL_RELATIVE(map, l_addr, relative) \
+ elf_machine_rel_relative (l_addr, relative, \
+ (void *) (l_addr + relative->r_offset))
+#endif
+
+/* Perform the relocations in MAP on the running program image as specified
+ by RELTAG, SZTAG. If LAZY is nonzero, this is the first pass on PLT
+ relocations; they should be set up to call _dl_runtime_resolve, rather
+ than fully resolved now. */
+
+auto inline void __attribute__ ((always_inline))
+elf_dynamic_do_Rel (struct link_map *map,
+ ElfW(Addr) reladdr, ElfW(Addr) relsize,
+ __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative,
+ int lazy, int skip_ifunc)
+{
+ const ElfW(Rel) *r = (const void *) reladdr;
+ const ElfW(Rel) *end = (const void *) (reladdr + relsize);
+ ElfW(Addr) l_addr = map->l_addr;
+# if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
+ const ElfW(Rel) *r2 = NULL;
+ const ElfW(Rel) *end2 = NULL;
+# endif
+
+#if (!defined DO_RELA || !defined ELF_MACHINE_PLT_REL) && !defined RTLD_BOOTSTRAP
+ /* We never bind lazily during ld.so bootstrap. Unfortunately gcc is
+ not clever enough to see through all the function calls to realize
+ that. */
+ if (lazy)
+ {
+ /* Doing lazy PLT relocations; they need very little info. */
+ for (; r < end; ++r)
+# ifdef ELF_MACHINE_IRELATIVE
+ if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
+ {
+ if (r2 == NULL)
+ r2 = r;
+ end2 = r;
+ }
+ else
+# endif
+ elf_machine_lazy_rel (map, l_addr, r, skip_ifunc);
+
+# ifdef ELF_MACHINE_IRELATIVE
+ if (r2 != NULL)
+ for (; r2 <= end2; ++r2)
+ if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
+ elf_machine_lazy_rel (map, l_addr, r2, skip_ifunc);
+# endif
+ }
+ else
+#endif
+ {
+ const ElfW(Sym) *const symtab =
+ (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+ const ElfW(Rel) *relative = r;
+ r += nrelative;
+
+#ifndef RTLD_BOOTSTRAP
+ /* This is defined in rtld.c, but nowhere in the static libc.a; make
+ the reference weak so static programs can still link. This
+ declaration cannot be done when compiling rtld.c (i.e. #ifdef
+ RTLD_BOOTSTRAP) because rtld.c contains the common defn for
+ _dl_rtld_map, which is incompatible with a weak decl in the same
+ file. */
+# ifndef SHARED
+ weak_extern (GL(dl_rtld_map));
+# endif
+ if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */
+# if !defined DO_RELA || defined ELF_MACHINE_REL_RELATIVE
+ /* Rela platforms get the offset from r_addend and this must
+ be copied in the relocation address. Therefore we can skip
+ the relative relocations only if this is for rel
+ relocations or rela relocations if they are computed as
+ memory_loc += l_addr... */
+ if (l_addr != 0)
+# else
+ /* ...or we know the object has been prelinked. */
+ if (l_addr != 0 || ! map->l_info[VALIDX(DT_GNU_PRELINKED)])
+# endif
+#endif
+ for (; relative < r; ++relative)
+ DO_ELF_MACHINE_REL_RELATIVE (map, l_addr, relative);
+
+#ifdef RTLD_BOOTSTRAP
+ /* The dynamic linker always uses versioning. */
+ assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
+#else
+ if (map->l_info[VERSYMIDX (DT_VERSYM)])
+#endif
+ {
+ const ElfW(Half) *const version =
+ (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+
+ for (; r < end; ++r)
+ {
+#if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
+ if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
+ {
+ if (r2 == NULL)
+ r2 = r;
+ end2 = r;
+ continue;
+ }
+#endif
+
+ ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
+ elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
+ &map->l_versions[ndx],
+ (void *) (l_addr + r->r_offset), skip_ifunc);
+ }
+
+#if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
+ if (r2 != NULL)
+ for (; r2 <= end2; ++r2)
+ if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
+ {
+ ElfW(Half) ndx
+ = version[ELFW(R_SYM) (r2->r_info)] & 0x7fff;
+ elf_machine_rel (map, r2,
+ &symtab[ELFW(R_SYM) (r2->r_info)],
+ &map->l_versions[ndx],
+ (void *) (l_addr + r2->r_offset),
+ skip_ifunc);
+ }
+#endif
+ }
+#ifndef RTLD_BOOTSTRAP
+ else
+ {
+ for (; r < end; ++r)
+# ifdef ELF_MACHINE_IRELATIVE
+ if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
+ {
+ if (r2 == NULL)
+ r2 = r;
+ end2 = r;
+ }
+ else
+# endif
+ elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
+ (void *) (l_addr + r->r_offset), skip_ifunc);
+
+# ifdef ELF_MACHINE_IRELATIVE
+ if (r2 != NULL)
+ for (; r2 <= end2; ++r2)
+ if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
+ elf_machine_rel (map, r2, &symtab[ELFW(R_SYM) (r2->r_info)],
+ NULL, (void *) (l_addr + r2->r_offset),
+ skip_ifunc);
+# endif
+ }
+#endif
+ }
+}
+
+#undef elf_dynamic_do_Rel
+#undef Rel
+#undef elf_machine_rel
+#undef elf_machine_rel_relative
+#undef DO_ELF_MACHINE_REL_RELATIVE
+#undef DO_RELA
diff --git a/REORG.TODO/elf/dynamic-link.h b/REORG.TODO/elf/dynamic-link.h
new file mode 100644
index 0000000000..60f2d91151
--- /dev/null
+++ b/REORG.TODO/elf/dynamic-link.h
@@ -0,0 +1,203 @@
+/* Inline functions for dynamic linking.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This macro is used as a callback from elf_machine_rel{a,} when a
+ static TLS reloc is about to be performed. Since (in dl-load.c) we
+ permit dynamic loading of objects that might use such relocs, we
+ have to check whether each use is actually doable. If the object
+ whose TLS segment the reference resolves to was allocated space in
+ the static TLS block at startup, then it's ok. Otherwise, we make
+ an attempt to allocate it in surplus space on the fly. If that
+ can't be done, we fall back to the error that DF_STATIC_TLS is
+ intended to produce. */
+#define HAVE_STATIC_TLS(map, sym_map) \
+ (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET \
+ && ((sym_map)->l_tls_offset \
+ != FORCED_DYNAMIC_TLS_OFFSET), 1))
+
+#define CHECK_STATIC_TLS(map, sym_map) \
+ do { \
+ if (!HAVE_STATIC_TLS (map, sym_map)) \
+ _dl_allocate_static_tls (sym_map); \
+ } while (0)
+
+#define TRY_STATIC_TLS(map, sym_map) \
+ (__builtin_expect ((sym_map)->l_tls_offset \
+ != FORCED_DYNAMIC_TLS_OFFSET, 1) \
+ && (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \
+ || _dl_try_allocate_static_tls (sym_map) == 0))
+
+int internal_function attribute_hidden
+ _dl_try_allocate_static_tls (struct link_map *map);
+
+#include <elf.h>
+
+#ifdef RESOLVE_MAP
+/* We pass reloc_addr as a pointer to void, as opposed to a pointer to
+ ElfW(Addr), because not all architectures can assume that the
+ relocated address is properly aligned, whereas the compiler is
+ entitled to assume that a pointer to a type is properly aligned for
+ the type. Even if we cast the pointer back to some other type with
+ less strict alignment requirements, the compiler might still
+ remember that the pointer was originally more aligned, thereby
+ optimizing away alignment tests or using word instructions for
+ copying memory, breaking the very code written to handle the
+ unaligned cases. */
+# if ! ELF_MACHINE_NO_REL
+auto inline void __attribute__((always_inline))
+elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
+ const ElfW(Sym) *sym, const struct r_found_version *version,
+ void *const reloc_addr, int skip_ifunc);
+auto inline void __attribute__((always_inline))
+elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
+ void *const reloc_addr);
+# endif
+# if ! ELF_MACHINE_NO_RELA
+auto inline void __attribute__((always_inline))
+elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
+ const ElfW(Sym) *sym, const struct r_found_version *version,
+ void *const reloc_addr, int skip_ifunc);
+auto inline void __attribute__((always_inline))
+elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
+ void *const reloc_addr);
+# endif
+# if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL
+auto inline void __attribute__((always_inline))
+elf_machine_lazy_rel (struct link_map *map,
+ ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
+ int skip_ifunc);
+# else
+auto inline void __attribute__((always_inline))
+elf_machine_lazy_rel (struct link_map *map,
+ ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
+ int skip_ifunc);
+# endif
+#endif
+
+#include <dl-machine.h>
+
+#include "get-dynamic-info.h"
+
+#ifdef RESOLVE_MAP
+
+# ifdef RTLD_BOOTSTRAP
+# define ELF_DURING_STARTUP (1)
+# else
+# define ELF_DURING_STARTUP (0)
+# endif
+
+/* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
+ These functions are almost identical, so we use cpp magic to avoid
+ duplicating their code. It cannot be done in a more general function
+ because we must be able to completely inline. */
+
+/* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
+ range. Note that according to the ELF spec, this is completely legal!
+
+ We are guarenteed that we have one of three situations. Either DT_JMPREL
+ comes immediately after DT_REL*, or there is overlap and DT_JMPREL
+ consumes precisely the very end of the DT_REL*, or DT_JMPREL and DT_REL*
+ are completely separate and there is a gap between them. */
+
+# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel) \
+ do { \
+ struct { ElfW(Addr) start, size; \
+ __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
+ ranges[2] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; \
+ \
+ if ((map)->l_info[DT_##RELOC]) \
+ { \
+ ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
+ ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
+ if (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)] != NULL) \
+ ranges[0].nrelative \
+ = map->l_info[VERSYMIDX (DT_##RELOC##COUNT)]->d_un.d_val; \
+ } \
+ if ((map)->l_info[DT_PLTREL] \
+ && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
+ { \
+ ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
+ ElfW(Addr) size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
+ \
+ if (ranges[0].start + ranges[0].size == (start + size)) \
+ ranges[0].size -= size; \
+ if (ELF_DURING_STARTUP \
+ || (!(do_lazy) \
+ && (ranges[0].start + ranges[0].size) == start)) \
+ { \
+ /* Combine processing the sections. */ \
+ ranges[0].size += size; \
+ } \
+ else \
+ { \
+ ranges[1].start = start; \
+ ranges[1].size = size; \
+ ranges[1].lazy = (do_lazy); \
+ } \
+ } \
+ \
+ if (ELF_DURING_STARTUP) \
+ elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, \
+ ranges[0].nrelative, 0, skip_ifunc); \
+ else \
+ { \
+ int ranges_index; \
+ for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
+ elf_dynamic_do_##reloc ((map), \
+ ranges[ranges_index].start, \
+ ranges[ranges_index].size, \
+ ranges[ranges_index].nrelative, \
+ ranges[ranges_index].lazy, \
+ skip_ifunc); \
+ } \
+ } while (0)
+
+# if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
+# define _ELF_CHECK_REL 0
+# else
+# define _ELF_CHECK_REL 1
+# endif
+
+# if ! ELF_MACHINE_NO_REL
+# include "do-rel.h"
+# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) \
+ _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, lazy, skip_ifunc, _ELF_CHECK_REL)
+# else
+# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) /* Nothing to do. */
+# endif
+
+# if ! ELF_MACHINE_NO_RELA
+# define DO_RELA
+# include "do-rel.h"
+# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) \
+ _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, lazy, skip_ifunc, _ELF_CHECK_REL)
+# else
+# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) /* Nothing to do. */
+# endif
+
+/* This can't just be an inline function because GCC is too dumb
+ to inline functions containing inlines themselves. */
+# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile, skip_ifunc) \
+ do { \
+ int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
+ (consider_profile)); \
+ ELF_DYNAMIC_DO_REL ((map), edr_lazy, skip_ifunc); \
+ ELF_DYNAMIC_DO_RELA ((map), edr_lazy, skip_ifunc); \
+ } while (0)
+
+#endif
diff --git a/REORG.TODO/elf/elf.h b/REORG.TODO/elf/elf.h
new file mode 100644
index 0000000000..fff893d433
--- /dev/null
+++ b/REORG.TODO/elf/elf.h
@@ -0,0 +1,3761 @@
+/* This file defines standard ELF types, structures, and macros.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ELF_H
+#define _ELF_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+/* Standard ELF types. */
+
+#include <stdint.h>
+
+/* Type for a 16-bit quantity. */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities. */
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef int32_t Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities. */
+typedef uint64_t Elf32_Xword;
+typedef int64_t Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef int64_t Elf64_Sxword;
+
+/* Type of addresses. */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets. */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities. */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* Type for version symbol information. */
+typedef Elf32_Half Elf32_Versym;
+typedef Elf64_Half Elf64_Versym;
+
+
+/* The ELF file header. This appears at the start of every ELF file. */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf64_Half e_type; /* Object file type */
+ Elf64_Half e_machine; /* Architecture */
+ Elf64_Word e_version; /* Object file version */
+ Elf64_Addr e_entry; /* Entry point virtual address */
+ Elf64_Off e_phoff; /* Program header table file offset */
+ Elf64_Off e_shoff; /* Section header table file offset */
+ Elf64_Word e_flags; /* Processor-specific flags */
+ Elf64_Half e_ehsize; /* ELF header size in bytes */
+ Elf64_Half e_phentsize; /* Program header table entry size */
+ Elf64_Half e_phnum; /* Program header table entry count */
+ Elf64_Half e_shentsize; /* Section header table entry size */
+ Elf64_Half e_shnum; /* Section header table entry count */
+ Elf64_Half e_shstrndx; /* Section header string table index */
+} Elf64_Ehdr;
+
+/* Fields in the e_ident array. The EI_* macros are indices into the
+ array. The macros under each EI_* macro are the values the byte
+ may have. */
+
+#define EI_MAG0 0 /* File identification byte 0 index */
+#define ELFMAG0 0x7f /* Magic number byte 0 */
+
+#define EI_MAG1 1 /* File identification byte 1 index */
+#define ELFMAG1 'E' /* Magic number byte 1 */
+
+#define EI_MAG2 2 /* File identification byte 2 index */
+#define ELFMAG2 'L' /* Magic number byte 2 */
+
+#define EI_MAG3 3 /* File identification byte 3 index */
+#define ELFMAG3 'F' /* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word. */
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define EI_CLASS 4 /* File class byte index */
+#define ELFCLASSNONE 0 /* Invalid class */
+#define ELFCLASS32 1 /* 32-bit objects */
+#define ELFCLASS64 2 /* 64-bit objects */
+#define ELFCLASSNUM 3
+
+#define EI_DATA 5 /* Data encoding byte index */
+#define ELFDATANONE 0 /* Invalid data encoding */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+#define ELFDATA2MSB 2 /* 2's complement, big endian */
+#define ELFDATANUM 3
+
+#define EI_VERSION 6 /* File version byte index */
+ /* Value must be EV_CURRENT */
+
+#define EI_OSABI 7 /* OS ABI identification */
+#define ELFOSABI_NONE 0 /* UNIX System V ABI */
+#define ELFOSABI_SYSV 0 /* Alias. */
+#define ELFOSABI_HPUX 1 /* HP-UX */
+#define ELFOSABI_NETBSD 2 /* NetBSD. */
+#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */
+#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */
+#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */
+#define ELFOSABI_AIX 7 /* IBM AIX. */
+#define ELFOSABI_IRIX 8 /* SGI Irix. */
+#define ELFOSABI_FREEBSD 9 /* FreeBSD. */
+#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */
+#define ELFOSABI_MODESTO 11 /* Novell Modesto. */
+#define ELFOSABI_OPENBSD 12 /* OpenBSD. */
+#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */
+#define ELFOSABI_ARM 97 /* ARM */
+#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
+
+#define EI_ABIVERSION 8 /* ABI version */
+
+#define EI_PAD 9 /* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type). */
+
+#define ET_NONE 0 /* No file type */
+#define ET_REL 1 /* Relocatable file */
+#define ET_EXEC 2 /* Executable file */
+#define ET_DYN 3 /* Shared object file */
+#define ET_CORE 4 /* Core file */
+#define ET_NUM 5 /* Number of defined types */
+#define ET_LOOS 0xfe00 /* OS-specific range start */
+#define ET_HIOS 0xfeff /* OS-specific range end */
+#define ET_LOPROC 0xff00 /* Processor-specific range start */
+#define ET_HIPROC 0xffff /* Processor-specific range end */
+
+/* Legal values for e_machine (architecture). */
+
+#define EM_NONE 0 /* No machine */
+#define EM_M32 1 /* AT&T WE 32100 */
+#define EM_SPARC 2 /* SUN SPARC */
+#define EM_386 3 /* Intel 80386 */
+#define EM_68K 4 /* Motorola m68k family */
+#define EM_88K 5 /* Motorola m88k family */
+#define EM_IAMCU 6 /* Intel MCU */
+#define EM_860 7 /* Intel 80860 */
+#define EM_MIPS 8 /* MIPS R3000 big-endian */
+#define EM_S370 9 /* IBM System/370 */
+#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
+ /* reserved 11-14 */
+#define EM_PARISC 15 /* HPPA */
+ /* reserved 16 */
+#define EM_VPP500 17 /* Fujitsu VPP500 */
+#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
+#define EM_960 19 /* Intel 80960 */
+#define EM_PPC 20 /* PowerPC */
+#define EM_PPC64 21 /* PowerPC 64-bit */
+#define EM_S390 22 /* IBM S390 */
+#define EM_SPU 23 /* IBM SPU/SPC */
+ /* reserved 24-35 */
+#define EM_V800 36 /* NEC V800 series */
+#define EM_FR20 37 /* Fujitsu FR20 */
+#define EM_RH32 38 /* TRW RH-32 */
+#define EM_RCE 39 /* Motorola RCE */
+#define EM_ARM 40 /* ARM */
+#define EM_FAKE_ALPHA 41 /* Digital Alpha */
+#define EM_SH 42 /* Hitachi SH */
+#define EM_SPARCV9 43 /* SPARC v9 64-bit */
+#define EM_TRICORE 44 /* Siemens Tricore */
+#define EM_ARC 45 /* Argonaut RISC Core */
+#define EM_H8_300 46 /* Hitachi H8/300 */
+#define EM_H8_300H 47 /* Hitachi H8/300H */
+#define EM_H8S 48 /* Hitachi H8S */
+#define EM_H8_500 49 /* Hitachi H8/500 */
+#define EM_IA_64 50 /* Intel Merced */
+#define EM_MIPS_X 51 /* Stanford MIPS-X */
+#define EM_COLDFIRE 52 /* Motorola Coldfire */
+#define EM_68HC12 53 /* Motorola M68HC12 */
+#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator */
+#define EM_PCP 55 /* Siemens PCP */
+#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
+#define EM_NDR1 57 /* Denso NDR1 microprocessor */
+#define EM_STARCORE 58 /* Motorola Start*Core processor */
+#define EM_ME16 59 /* Toyota ME16 processor */
+#define EM_ST100 60 /* STMicroelectronic ST100 processor */
+#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam */
+#define EM_X86_64 62 /* AMD x86-64 architecture */
+#define EM_PDSP 63 /* Sony DSP Processor */
+#define EM_PDP10 64 /* Digital PDP-10 */
+#define EM_PDP11 65 /* Digital PDP-11 */
+#define EM_FX66 66 /* Siemens FX66 microcontroller */
+#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
+#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
+#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
+#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
+#define EM_SVX 73 /* Silicon Graphics SVx */
+#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX 75 /* Digital VAX */
+#define EM_CRIS 76 /* Axis Communications 32-bit emb.proc */
+#define EM_JAVELIN 77 /* Infineon Technologies 32-bit emb.proc */
+#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
+#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX 80 /* Donald Knuth's educational 64-bit proc */
+#define EM_HUANY 81 /* Harvard University machine-independent object files */
+#define EM_PRISM 82 /* SiTera Prism */
+#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
+#define EM_FR30 84 /* Fujitsu FR30 */
+#define EM_D10V 85 /* Mitsubishi D10V */
+#define EM_D30V 86 /* Mitsubishi D30V */
+#define EM_V850 87 /* NEC v850 */
+#define EM_M32R 88 /* Mitsubishi M32R */
+#define EM_MN10300 89 /* Matsushita MN10300 */
+#define EM_MN10200 90 /* Matsushita MN10200 */
+#define EM_PJ 91 /* picoJava */
+#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
+#define EM_ARC_COMPACT 93 /* ARC International ARCompact */
+#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
+#define EM_VIDEOCORE 95 /* Alphamosaic VideoCore */
+#define EM_TMM_GPP 96 /* Thompson Multimedia General Purpose Proc */
+#define EM_NS32K 97 /* National Semi. 32000 */
+#define EM_TPC 98 /* Tenor Network TPC */
+#define EM_SNP1K 99 /* Trebia SNP 1000 */
+#define EM_ST200 100 /* STMicroelectronics ST200 */
+#define EM_IP2K 101 /* Ubicom IP2xxx */
+#define EM_MAX 102 /* MAX processor */
+#define EM_CR 103 /* National Semi. CompactRISC */
+#define EM_F2MC16 104 /* Fujitsu F2MC16 */
+#define EM_MSP430 105 /* Texas Instruments msp430 */
+#define EM_BLACKFIN 106 /* Analog Devices Blackfin DSP */
+#define EM_SE_C33 107 /* Seiko Epson S1C33 family */
+#define EM_SEP 108 /* Sharp embedded microprocessor */
+#define EM_ARCA 109 /* Arca RISC */
+#define EM_UNICORE 110 /* PKU-Unity & MPRC Peking Uni. mc series */
+#define EM_EXCESS 111 /* eXcess configurable cpu */
+#define EM_DXP 112 /* Icera Semi. Deep Execution Processor */
+#define EM_ALTERA_NIOS2 113 /* Altera Nios II */
+#define EM_CRX 114 /* National Semi. CompactRISC CRX */
+#define EM_XGATE 115 /* Motorola XGATE */
+#define EM_C166 116 /* Infineon C16x/XC16x */
+#define EM_M16C 117 /* Renesas M16C */
+#define EM_DSPIC30F 118 /* Microchip Technology dsPIC30F */
+#define EM_CE 119 /* Freescale Communication Engine RISC */
+#define EM_M32C 120 /* Renesas M32C */
+ /* reserved 121-130 */
+#define EM_TSK3000 131 /* Altium TSK3000 */
+#define EM_RS08 132 /* Freescale RS08 */
+#define EM_SHARC 133 /* Analog Devices SHARC family */
+#define EM_ECOG2 134 /* Cyan Technology eCOG2 */
+#define EM_SCORE7 135 /* Sunplus S+core7 RISC */
+#define EM_DSP24 136 /* New Japan Radio (NJR) 24-bit DSP */
+#define EM_VIDEOCORE3 137 /* Broadcom VideoCore III */
+#define EM_LATTICEMICO32 138 /* RISC for Lattice FPGA */
+#define EM_SE_C17 139 /* Seiko Epson C17 */
+#define EM_TI_C6000 140 /* Texas Instruments TMS320C6000 DSP */
+#define EM_TI_C2000 141 /* Texas Instruments TMS320C2000 DSP */
+#define EM_TI_C5500 142 /* Texas Instruments TMS320C55x DSP */
+#define EM_TI_ARP32 143 /* Texas Instruments App. Specific RISC */
+#define EM_TI_PRU 144 /* Texas Instruments Prog. Realtime Unit */
+ /* reserved 145-159 */
+#define EM_MMDSP_PLUS 160 /* STMicroelectronics 64bit VLIW DSP */
+#define EM_CYPRESS_M8C 161 /* Cypress M8C */
+#define EM_R32C 162 /* Renesas R32C */
+#define EM_TRIMEDIA 163 /* NXP Semi. TriMedia */
+#define EM_QDSP6 164 /* QUALCOMM DSP6 */
+#define EM_8051 165 /* Intel 8051 and variants */
+#define EM_STXP7X 166 /* STMicroelectronics STxP7x */
+#define EM_NDS32 167 /* Andes Tech. compact code emb. RISC */
+#define EM_ECOG1X 168 /* Cyan Technology eCOG1X */
+#define EM_MAXQ30 169 /* Dallas Semi. MAXQ30 mc */
+#define EM_XIMO16 170 /* New Japan Radio (NJR) 16-bit DSP */
+#define EM_MANIK 171 /* M2000 Reconfigurable RISC */
+#define EM_CRAYNV2 172 /* Cray NV2 vector architecture */
+#define EM_RX 173 /* Renesas RX */
+#define EM_METAG 174 /* Imagination Tech. META */
+#define EM_MCST_ELBRUS 175 /* MCST Elbrus */
+#define EM_ECOG16 176 /* Cyan Technology eCOG16 */
+#define EM_CR16 177 /* National Semi. CompactRISC CR16 */
+#define EM_ETPU 178 /* Freescale Extended Time Processing Unit */
+#define EM_SLE9X 179 /* Infineon Tech. SLE9X */
+#define EM_L10M 180 /* Intel L10M */
+#define EM_K10M 181 /* Intel K10M */
+ /* reserved 182 */
+#define EM_AARCH64 183 /* ARM AARCH64 */
+ /* reserved 184 */
+#define EM_AVR32 185 /* Amtel 32-bit microprocessor */
+#define EM_STM8 186 /* STMicroelectronics STM8 */
+#define EM_TILE64 187 /* Tileta TILE64 */
+#define EM_TILEPRO 188 /* Tilera TILEPro */
+#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */
+#define EM_CUDA 190 /* NVIDIA CUDA */
+#define EM_TILEGX 191 /* Tilera TILE-Gx */
+#define EM_CLOUDSHIELD 192 /* CloudShield */
+#define EM_COREA_1ST 193 /* KIPO-KAIST Core-A 1st gen. */
+#define EM_COREA_2ND 194 /* KIPO-KAIST Core-A 2nd gen. */
+#define EM_ARC_COMPACT2 195 /* Synopsys ARCompact V2 */
+#define EM_OPEN8 196 /* Open8 RISC */
+#define EM_RL78 197 /* Renesas RL78 */
+#define EM_VIDEOCORE5 198 /* Broadcom VideoCore V */
+#define EM_78KOR 199 /* Renesas 78KOR */
+#define EM_56800EX 200 /* Freescale 56800EX DSC */
+#define EM_BA1 201 /* Beyond BA1 */
+#define EM_BA2 202 /* Beyond BA2 */
+#define EM_XCORE 203 /* XMOS xCORE */
+#define EM_MCHP_PIC 204 /* Microchip 8-bit PIC(r) */
+ /* reserved 205-209 */
+#define EM_KM32 210 /* KM211 KM32 */
+#define EM_KMX32 211 /* KM211 KMX32 */
+#define EM_EMX16 212 /* KM211 KMX16 */
+#define EM_EMX8 213 /* KM211 KMX8 */
+#define EM_KVARC 214 /* KM211 KVARC */
+#define EM_CDP 215 /* Paneve CDP */
+#define EM_COGE 216 /* Cognitive Smart Memory Processor */
+#define EM_COOL 217 /* Bluechip CoolEngine */
+#define EM_NORC 218 /* Nanoradio Optimized RISC */
+#define EM_CSR_KALIMBA 219 /* CSR Kalimba */
+#define EM_Z80 220 /* Zilog Z80 */
+#define EM_VISIUM 221 /* Controls and Data Services VISIUMcore */
+#define EM_FT32 222 /* FTDI Chip FT32 */
+#define EM_MOXIE 223 /* Moxie processor */
+#define EM_AMDGPU 224 /* AMD GPU */
+ /* reserved 225-242 */
+#define EM_RISCV 243 /* RISC-V */
+
+#define EM_BPF 247 /* Linux BPF -- in-kernel virtual machine */
+
+#define EM_NUM 248
+
+/* Old spellings/synonyms. */
+
+#define EM_ARC_A5 EM_ARC_COMPACT
+
+/* If it is necessary to assign new unofficial EM_* values, please
+ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+ chances of collision with official or non-GNU unofficial values. */
+
+#define EM_ALPHA 0x9026
+
+/* Legal values for e_version (version). */
+
+#define EV_NONE 0 /* Invalid ELF version */
+#define EV_CURRENT 1 /* Current version */
+#define EV_NUM 2
+
+/* Section header. */
+
+typedef struct
+{
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+ Elf64_Word sh_name; /* Section name (string tbl index) */
+ Elf64_Word sh_type; /* Section type */
+ Elf64_Xword sh_flags; /* Section flags */
+ Elf64_Addr sh_addr; /* Section virtual addr at execution */
+ Elf64_Off sh_offset; /* Section file offset */
+ Elf64_Xword sh_size; /* Section size in bytes */
+ Elf64_Word sh_link; /* Link to another section */
+ Elf64_Word sh_info; /* Additional section information */
+ Elf64_Xword sh_addralign; /* Section alignment */
+ Elf64_Xword sh_entsize; /* Entry size if section holds table */
+} Elf64_Shdr;
+
+/* Special section indices. */
+
+#define SHN_UNDEF 0 /* Undefined section */
+#define SHN_LORESERVE 0xff00 /* Start of reserved indices */
+#define SHN_LOPROC 0xff00 /* Start of processor-specific */
+#define SHN_BEFORE 0xff00 /* Order section before all others
+ (Solaris). */
+#define SHN_AFTER 0xff01 /* Order section after all others
+ (Solaris). */
+#define SHN_HIPROC 0xff1f /* End of processor-specific */
+#define SHN_LOOS 0xff20 /* Start of OS-specific */
+#define SHN_HIOS 0xff3f /* End of OS-specific */
+#define SHN_ABS 0xfff1 /* Associated symbol is absolute */
+#define SHN_COMMON 0xfff2 /* Associated symbol is common */
+#define SHN_XINDEX 0xffff /* Index is in extra table. */
+#define SHN_HIRESERVE 0xffff /* End of reserved indices */
+
+/* Legal values for sh_type (section type). */
+
+#define SHT_NULL 0 /* Section header table entry unused */
+#define SHT_PROGBITS 1 /* Program data */
+#define SHT_SYMTAB 2 /* Symbol table */
+#define SHT_STRTAB 3 /* String table */
+#define SHT_RELA 4 /* Relocation entries with addends */
+#define SHT_HASH 5 /* Symbol hash table */
+#define SHT_DYNAMIC 6 /* Dynamic linking information */
+#define SHT_NOTE 7 /* Notes */
+#define SHT_NOBITS 8 /* Program space with no data (bss) */
+#define SHT_REL 9 /* Relocation entries, no addends */
+#define SHT_SHLIB 10 /* Reserved */
+#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
+#define SHT_INIT_ARRAY 14 /* Array of constructors */
+#define SHT_FINI_ARRAY 15 /* Array of destructors */
+#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
+#define SHT_GROUP 17 /* Section group */
+#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
+#define SHT_NUM 19 /* Number of defined types. */
+#define SHT_LOOS 0x60000000 /* Start OS-specific. */
+#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */
+#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */
+#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
+#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
+#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
+#define SHT_SUNW_move 0x6ffffffa
+#define SHT_SUNW_COMDAT 0x6ffffffb
+#define SHT_SUNW_syminfo 0x6ffffffc
+#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */
+#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */
+#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */
+#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */
+#define SHT_HIOS 0x6fffffff /* End OS-specific type */
+#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
+#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
+#define SHT_LOUSER 0x80000000 /* Start of application-specific */
+#define SHT_HIUSER 0x8fffffff /* End of application-specific */
+
+/* Legal values for sh_flags (section flags). */
+
+#define SHF_WRITE (1 << 0) /* Writable */
+#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
+#define SHF_EXECINSTR (1 << 2) /* Executable */
+#define SHF_MERGE (1 << 4) /* Might be merged */
+#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
+#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */
+#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */
+#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling
+ required */
+#define SHF_GROUP (1 << 9) /* Section is member of a group. */
+#define SHF_TLS (1 << 10) /* Section hold thread-local data. */
+#define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */
+#define SHF_MASKOS 0x0ff00000 /* OS-specific. */
+#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
+#define SHF_ORDERED (1 << 30) /* Special ordering requirement
+ (Solaris). */
+#define SHF_EXCLUDE (1U << 31) /* Section is excluded unless
+ referenced or allocated (Solaris).*/
+
+/* Section compression header. Used when SHF_COMPRESSED is set. */
+
+typedef struct
+{
+ Elf32_Word ch_type; /* Compression format. */
+ Elf32_Word ch_size; /* Uncompressed data size. */
+ Elf32_Word ch_addralign; /* Uncompressed data alignment. */
+} Elf32_Chdr;
+
+typedef struct
+{
+ Elf64_Word ch_type; /* Compression format. */
+ Elf64_Word ch_reserved;
+ Elf64_Xword ch_size; /* Uncompressed data size. */
+ Elf64_Xword ch_addralign; /* Uncompressed data alignment. */
+} Elf64_Chdr;
+
+/* Legal values for ch_type (compression algorithm). */
+#define ELFCOMPRESS_ZLIB 1 /* ZLIB/DEFLATE algorithm. */
+#define ELFCOMPRESS_LOOS 0x60000000 /* Start of OS-specific. */
+#define ELFCOMPRESS_HIOS 0x6fffffff /* End of OS-specific. */
+#define ELFCOMPRESS_LOPROC 0x70000000 /* Start of processor-specific. */
+#define ELFCOMPRESS_HIPROC 0x7fffffff /* End of processor-specific. */
+
+/* Section group handling. */
+#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */
+
+/* Symbol table entry. */
+
+typedef struct
+{
+ Elf32_Word st_name; /* Symbol name (string tbl index) */
+ Elf32_Addr st_value; /* Symbol value */
+ Elf32_Word st_size; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf32_Section st_shndx; /* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+ Elf64_Word st_name; /* Symbol name (string tbl index) */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf64_Section st_shndx; /* Section index */
+ Elf64_Addr st_value; /* Symbol value */
+ Elf64_Xword st_size; /* Symbol size */
+} Elf64_Sym;
+
+/* The syminfo section if available contains additional information about
+ every dynamic symbol. */
+
+typedef struct
+{
+ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */
+ Elf32_Half si_flags; /* Per symbol flags */
+} Elf32_Syminfo;
+
+typedef struct
+{
+ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */
+ Elf64_Half si_flags; /* Per symbol flags */
+} Elf64_Syminfo;
+
+/* Possible values for si_boundto. */
+#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */
+#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */
+#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */
+
+/* Possible bitmasks for si_flags. */
+#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */
+#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */
+#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */
+#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy
+ loaded */
+/* Syminfo version values. */
+#define SYMINFO_NONE 0
+#define SYMINFO_CURRENT 1
+#define SYMINFO_NUM 2
+
+
+/* How to extract and insert information held in the st_info field. */
+
+#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val) ((val) & 0xf)
+#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */
+#define ELF64_ST_BIND(val) ELF32_ST_BIND (val)
+#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val)
+#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type))
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding). */
+
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* Weak symbol */
+#define STB_NUM 3 /* Number of defined types. */
+#define STB_LOOS 10 /* Start of OS-specific */
+#define STB_GNU_UNIQUE 10 /* Unique symbol. */
+#define STB_HIOS 12 /* End of OS-specific */
+#define STB_LOPROC 13 /* Start of processor-specific */
+#define STB_HIPROC 15 /* End of processor-specific */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_SECTION 3 /* Symbol associated with a section */
+#define STT_FILE 4 /* Symbol's name is file name */
+#define STT_COMMON 5 /* Symbol is a common data object */
+#define STT_TLS 6 /* Symbol is thread-local data object*/
+#define STT_NUM 7 /* Number of defined types. */
+#define STT_LOOS 10 /* Start of OS-specific */
+#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */
+#define STT_HIOS 12 /* End of OS-specific */
+#define STT_LOPROC 13 /* Start of processor-specific */
+#define STT_HIPROC 15 /* End of processor-specific */
+
+
+/* Symbol table indices are found in the hash buckets and chain table
+ of a symbol hash table section. This special index value indicates
+ the end of a chain, meaning no further symbols are found in that bucket. */
+
+#define STN_UNDEF 0 /* End of a chain. */
+
+
+/* How to extract and insert information held in the st_other field. */
+
+#define ELF32_ST_VISIBILITY(o) ((o) & 0x03)
+
+/* For ELF64 the definitions are the same. */
+#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o)
+
+/* Symbol visibility specification encoded in the st_other field. */
+#define STV_DEFAULT 0 /* Default symbol visibility rules */
+#define STV_INTERNAL 1 /* Processor specific hidden class */
+#define STV_HIDDEN 2 /* Sym unavailable in other modules */
+#define STV_PROTECTED 3 /* Not preemptible, not exported */
+
+
+/* Relocation table entry without addend (in section of type SHT_REL). */
+
+typedef struct
+{
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+} Elf32_Rel;
+
+/* I have seen two different definitions of the Elf64_Rel and
+ Elf64_Rela structures, so we'll leave them out until Novell (or
+ whoever) gets their act together. */
+/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */
+
+typedef struct
+{
+ Elf64_Addr r_offset; /* Address */
+ Elf64_Xword r_info; /* Relocation type and symbol index */
+} Elf64_Rel;
+
+/* Relocation table entry with addend (in section of type SHT_RELA). */
+
+typedef struct
+{
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+ Elf32_Sword r_addend; /* Addend */
+} Elf32_Rela;
+
+typedef struct
+{
+ Elf64_Addr r_offset; /* Address */
+ Elf64_Xword r_info; /* Relocation type and symbol index */
+ Elf64_Sxword r_addend; /* Addend */
+} Elf64_Rela;
+
+/* How to extract and insert information held in the r_info field. */
+
+#define ELF32_R_SYM(val) ((val) >> 8)
+#define ELF32_R_TYPE(val) ((val) & 0xff)
+#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
+
+#define ELF64_R_SYM(i) ((i) >> 32)
+#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
+#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type))
+
+/* Program segment header. */
+
+typedef struct
+{
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+ Elf64_Word p_type; /* Segment type */
+ Elf64_Word p_flags; /* Segment flags */
+ Elf64_Off p_offset; /* Segment file offset */
+ Elf64_Addr p_vaddr; /* Segment virtual address */
+ Elf64_Addr p_paddr; /* Segment physical address */
+ Elf64_Xword p_filesz; /* Segment size in file */
+ Elf64_Xword p_memsz; /* Segment size in memory */
+ Elf64_Xword p_align; /* Segment alignment */
+} Elf64_Phdr;
+
+/* Special value for e_phnum. This indicates that the real number of
+ program headers is too large to fit into e_phnum. Instead the real
+ value is in the field sh_info of section 0. */
+
+#define PN_XNUM 0xffff
+
+/* Legal values for p_type (segment type). */
+
+#define PT_NULL 0 /* Program header table entry unused */
+#define PT_LOAD 1 /* Loadable program segment */
+#define PT_DYNAMIC 2 /* Dynamic linking information */
+#define PT_INTERP 3 /* Program interpreter */
+#define PT_NOTE 4 /* Auxiliary information */
+#define PT_SHLIB 5 /* Reserved */
+#define PT_PHDR 6 /* Entry for header table itself */
+#define PT_TLS 7 /* Thread-local storage segment */
+#define PT_NUM 8 /* Number of defined types */
+#define PT_LOOS 0x60000000 /* Start of OS-specific */
+#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
+#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
+#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
+#define PT_LOSUNW 0x6ffffffa
+#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
+#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */
+#define PT_HISUNW 0x6fffffff
+#define PT_HIOS 0x6fffffff /* End of OS-specific */
+#define PT_LOPROC 0x70000000 /* Start of processor-specific */
+#define PT_HIPROC 0x7fffffff /* End of processor-specific */
+
+/* Legal values for p_flags (segment flags). */
+
+#define PF_X (1 << 0) /* Segment is executable */
+#define PF_W (1 << 1) /* Segment is writable */
+#define PF_R (1 << 2) /* Segment is readable */
+#define PF_MASKOS 0x0ff00000 /* OS-specific */
+#define PF_MASKPROC 0xf0000000 /* Processor-specific */
+
+/* Legal values for note segment descriptor types for core files. */
+
+#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
+#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
+#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
+#define NT_PRXREG 4 /* Contains copy of prxregset struct */
+#define NT_TASKSTRUCT 4 /* Contains copy of task structure */
+#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */
+#define NT_AUXV 6 /* Contains copy of auxv array */
+#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */
+#define NT_ASRS 8 /* Contains copy of asrset struct */
+#define NT_PSTATUS 10 /* Contains copy of pstatus struct */
+#define NT_PSINFO 13 /* Contains copy of psinfo struct */
+#define NT_PRCRED 14 /* Contains copy of prcred struct */
+#define NT_UTSNAME 15 /* Contains copy of utsname struct */
+#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */
+#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */
+#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */
+#define NT_SIGINFO 0x53494749 /* Contains copy of siginfo_t,
+ size might increase */
+#define NT_FILE 0x46494c45 /* Contains information about mapped
+ files */
+#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */
+#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
+#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
+#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
+#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
+#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
+#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
+#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */
+#define NT_S390_TIMER 0x301 /* s390 timer register */
+#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */
+#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */
+#define NT_S390_CTRS 0x304 /* s390 control registers */
+#define NT_S390_PREFIX 0x305 /* s390 prefix register */
+#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */
+#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
+#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */
+#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
+#define NT_ARM_TLS 0x401 /* ARM TLS register */
+#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
+#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
+#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
+
+/* Legal values for the note segment descriptor types for object files. */
+
+#define NT_VERSION 1 /* Contains a version string. */
+
+
+/* Dynamic section entry. */
+
+typedef struct
+{
+ Elf32_Sword d_tag; /* Dynamic entry type */
+ union
+ {
+ Elf32_Word d_val; /* Integer value */
+ Elf32_Addr d_ptr; /* Address value */
+ } d_un;
+} Elf32_Dyn;
+
+typedef struct
+{
+ Elf64_Sxword d_tag; /* Dynamic entry type */
+ union
+ {
+ Elf64_Xword d_val; /* Integer value */
+ Elf64_Addr d_ptr; /* Address value */
+ } d_un;
+} Elf64_Dyn;
+
+/* Legal values for d_tag (dynamic entry type). */
+
+#define DT_NULL 0 /* Marks end of dynamic section */
+#define DT_NEEDED 1 /* Name of needed library */
+#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */
+#define DT_PLTGOT 3 /* Processor defined value */
+#define DT_HASH 4 /* Address of symbol hash table */
+#define DT_STRTAB 5 /* Address of string table */
+#define DT_SYMTAB 6 /* Address of symbol table */
+#define DT_RELA 7 /* Address of Rela relocs */
+#define DT_RELASZ 8 /* Total size of Rela relocs */
+#define DT_RELAENT 9 /* Size of one Rela reloc */
+#define DT_STRSZ 10 /* Size of string table */
+#define DT_SYMENT 11 /* Size of one symbol table entry */
+#define DT_INIT 12 /* Address of init function */
+#define DT_FINI 13 /* Address of termination function */
+#define DT_SONAME 14 /* Name of shared object */
+#define DT_RPATH 15 /* Library search path (deprecated) */
+#define DT_SYMBOLIC 16 /* Start symbol search here */
+#define DT_REL 17 /* Address of Rel relocs */
+#define DT_RELSZ 18 /* Total size of Rel relocs */
+#define DT_RELENT 19 /* Size of one Rel reloc */
+#define DT_PLTREL 20 /* Type of reloc in PLT */
+#define DT_DEBUG 21 /* For debugging; unspecified */
+#define DT_TEXTREL 22 /* Reloc might modify .text */
+#define DT_JMPREL 23 /* Address of PLT relocs */
+#define DT_BIND_NOW 24 /* Process relocations of object */
+#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
+#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
+#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
+#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
+#define DT_RUNPATH 29 /* Library search path */
+#define DT_FLAGS 30 /* Flags for the object being loaded */
+#define DT_ENCODING 32 /* Start of encoded range */
+#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
+#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
+#define DT_NUM 34 /* Number used */
+#define DT_LOOS 0x6000000d /* Start of OS-specific */
+#define DT_HIOS 0x6ffff000 /* End of OS-specific */
+#define DT_LOPROC 0x70000000 /* Start of processor-specific */
+#define DT_HIPROC 0x7fffffff /* End of processor-specific */
+#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */
+
+/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
+ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's
+ approach. */
+#define DT_VALRNGLO 0x6ffffd00
+#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */
+#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */
+#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */
+#define DT_CHECKSUM 0x6ffffdf8
+#define DT_PLTPADSZ 0x6ffffdf9
+#define DT_MOVEENT 0x6ffffdfa
+#define DT_MOVESZ 0x6ffffdfb
+#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */
+#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting
+ the following DT_* entry. */
+#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */
+#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */
+#define DT_VALRNGHI 0x6ffffdff
+#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */
+#define DT_VALNUM 12
+
+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+ Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+
+ If any adjustment is made to the ELF object after it has been
+ built these entries will need to be adjusted. */
+#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */
+#define DT_TLSDESC_PLT 0x6ffffef6
+#define DT_TLSDESC_GOT 0x6ffffef7
+#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */
+#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */
+#define DT_CONFIG 0x6ffffefa /* Configuration information. */
+#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */
+#define DT_AUDIT 0x6ffffefc /* Object auditing. */
+#define DT_PLTPAD 0x6ffffefd /* PLT padding. */
+#define DT_MOVETAB 0x6ffffefe /* Move table. */
+#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */
+#define DT_ADDRRNGHI 0x6ffffeff
+#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */
+#define DT_ADDRNUM 11
+
+/* The versioning entry types. The next are defined as part of the
+ GNU extension. */
+#define DT_VERSYM 0x6ffffff0
+
+#define DT_RELACOUNT 0x6ffffff9
+#define DT_RELCOUNT 0x6ffffffa
+
+/* These were chosen by Sun. */
+#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */
+#define DT_VERDEF 0x6ffffffc /* Address of version definition
+ table */
+#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */
+#define DT_VERNEED 0x6ffffffe /* Address of table with needed
+ versions */
+#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */
+#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
+#define DT_VERSIONTAGNUM 16
+
+/* Sun added these machine-independent extensions in the "processor-specific"
+ range. Be compatible. */
+#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */
+#define DT_FILTER 0x7fffffff /* Shared object to get values from */
+#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
+#define DT_EXTRANUM 3
+
+/* Values of `d_un.d_val' in the DT_FLAGS entry. */
+#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */
+#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */
+#define DF_TEXTREL 0x00000004 /* Object contains text relocations */
+#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */
+#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */
+
+/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
+ entry in the dynamic section. */
+#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */
+#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */
+#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */
+#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/
+#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/
+#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/
+#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */
+#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */
+#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */
+#define DF_1_TRANS 0x00000200
+#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */
+#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */
+#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */
+#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/
+#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */
+#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */
+#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */
+#define DF_1_NODIRECT 0x00020000 /* Object has no-direct binding. */
+#define DF_1_IGNMULDEF 0x00040000
+#define DF_1_NOKSYMS 0x00080000
+#define DF_1_NOHDR 0x00100000
+#define DF_1_EDITED 0x00200000 /* Object is modified after built. */
+#define DF_1_NORELOC 0x00400000
+#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */
+#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */
+#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */
+
+/* Flags for the feature selection in DT_FEATURE_1. */
+#define DTF_1_PARINIT 0x00000001
+#define DTF_1_CONFEXP 0x00000002
+
+/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */
+#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */
+#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not
+ generally available. */
+
+/* Version definition sections. */
+
+typedef struct
+{
+ Elf32_Half vd_version; /* Version revision */
+ Elf32_Half vd_flags; /* Version information */
+ Elf32_Half vd_ndx; /* Version Index */
+ Elf32_Half vd_cnt; /* Number of associated aux entries */
+ Elf32_Word vd_hash; /* Version name hash value */
+ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */
+ Elf32_Word vd_next; /* Offset in bytes to next verdef
+ entry */
+} Elf32_Verdef;
+
+typedef struct
+{
+ Elf64_Half vd_version; /* Version revision */
+ Elf64_Half vd_flags; /* Version information */
+ Elf64_Half vd_ndx; /* Version Index */
+ Elf64_Half vd_cnt; /* Number of associated aux entries */
+ Elf64_Word vd_hash; /* Version name hash value */
+ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */
+ Elf64_Word vd_next; /* Offset in bytes to next verdef
+ entry */
+} Elf64_Verdef;
+
+
+/* Legal values for vd_version (version revision). */
+#define VER_DEF_NONE 0 /* No version */
+#define VER_DEF_CURRENT 1 /* Current version */
+#define VER_DEF_NUM 2 /* Given version number */
+
+/* Legal values for vd_flags (version information flags). */
+#define VER_FLG_BASE 0x1 /* Version definition of file itself */
+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
+
+/* Versym symbol index values. */
+#define VER_NDX_LOCAL 0 /* Symbol is local. */
+#define VER_NDX_GLOBAL 1 /* Symbol is global. */
+#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */
+#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */
+
+/* Auxialiary version information. */
+
+typedef struct
+{
+ Elf32_Word vda_name; /* Version or dependency names */
+ Elf32_Word vda_next; /* Offset in bytes to next verdaux
+ entry */
+} Elf32_Verdaux;
+
+typedef struct
+{
+ Elf64_Word vda_name; /* Version or dependency names */
+ Elf64_Word vda_next; /* Offset in bytes to next verdaux
+ entry */
+} Elf64_Verdaux;
+
+
+/* Version dependency section. */
+
+typedef struct
+{
+ Elf32_Half vn_version; /* Version of structure */
+ Elf32_Half vn_cnt; /* Number of associated aux entries */
+ Elf32_Word vn_file; /* Offset of filename for this
+ dependency */
+ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */
+ Elf32_Word vn_next; /* Offset in bytes to next verneed
+ entry */
+} Elf32_Verneed;
+
+typedef struct
+{
+ Elf64_Half vn_version; /* Version of structure */
+ Elf64_Half vn_cnt; /* Number of associated aux entries */
+ Elf64_Word vn_file; /* Offset of filename for this
+ dependency */
+ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */
+ Elf64_Word vn_next; /* Offset in bytes to next verneed
+ entry */
+} Elf64_Verneed;
+
+
+/* Legal values for vn_version (version revision). */
+#define VER_NEED_NONE 0 /* No version */
+#define VER_NEED_CURRENT 1 /* Current version */
+#define VER_NEED_NUM 2 /* Given version number */
+
+/* Auxiliary needed version information. */
+
+typedef struct
+{
+ Elf32_Word vna_hash; /* Hash value of dependency name */
+ Elf32_Half vna_flags; /* Dependency specific information */
+ Elf32_Half vna_other; /* Unused */
+ Elf32_Word vna_name; /* Dependency name string offset */
+ Elf32_Word vna_next; /* Offset in bytes to next vernaux
+ entry */
+} Elf32_Vernaux;
+
+typedef struct
+{
+ Elf64_Word vna_hash; /* Hash value of dependency name */
+ Elf64_Half vna_flags; /* Dependency specific information */
+ Elf64_Half vna_other; /* Unused */
+ Elf64_Word vna_name; /* Dependency name string offset */
+ Elf64_Word vna_next; /* Offset in bytes to next vernaux
+ entry */
+} Elf64_Vernaux;
+
+
+/* Legal values for vna_flags. */
+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
+
+
+/* Auxiliary vector. */
+
+/* This vector is normally only used by the program interpreter. The
+ usual definition in an ABI supplement uses the name auxv_t. The
+ vector is not usually defined in a standard <elf.h> file, but it
+ can't hurt. We rename it to avoid conflicts. The sizes of these
+ types are an arrangement between the exec server and the program
+ interpreter, so we don't fully specify them here. */
+
+typedef struct
+{
+ uint32_t a_type; /* Entry type */
+ union
+ {
+ uint32_t a_val; /* Integer value */
+ /* We use to have pointer elements added here. We cannot do that,
+ though, since it does not work when using 32-bit definitions
+ on 64-bit platforms and vice versa. */
+ } a_un;
+} Elf32_auxv_t;
+
+typedef struct
+{
+ uint64_t a_type; /* Entry type */
+ union
+ {
+ uint64_t a_val; /* Integer value */
+ /* We use to have pointer elements added here. We cannot do that,
+ though, since it does not work when using 32-bit definitions
+ on 64-bit platforms and vice versa. */
+ } a_un;
+} Elf64_auxv_t;
+
+/* Legal values for a_type (entry type). */
+
+#define AT_NULL 0 /* End of vector */
+#define AT_IGNORE 1 /* Entry should be ignored */
+#define AT_EXECFD 2 /* File descriptor of program */
+#define AT_PHDR 3 /* Program headers for program */
+#define AT_PHENT 4 /* Size of program header entry */
+#define AT_PHNUM 5 /* Number of program headers */
+#define AT_PAGESZ 6 /* System page size */
+#define AT_BASE 7 /* Base address of interpreter */
+#define AT_FLAGS 8 /* Flags */
+#define AT_ENTRY 9 /* Entry point of program */
+#define AT_NOTELF 10 /* Program is not ELF */
+#define AT_UID 11 /* Real uid */
+#define AT_EUID 12 /* Effective uid */
+#define AT_GID 13 /* Real gid */
+#define AT_EGID 14 /* Effective gid */
+#define AT_CLKTCK 17 /* Frequency of times() */
+
+/* Some more special a_type values describing the hardware. */
+#define AT_PLATFORM 15 /* String identifying platform. */
+#define AT_HWCAP 16 /* Machine-dependent hints about
+ processor capabilities. */
+
+/* This entry gives some information about the FPU initialization
+ performed by the kernel. */
+#define AT_FPUCW 18 /* Used FPU control word. */
+
+/* Cache block sizes. */
+#define AT_DCACHEBSIZE 19 /* Data cache block size. */
+#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */
+#define AT_UCACHEBSIZE 21 /* Unified cache block size. */
+
+/* A special ignored value for PPC, used by the kernel to control the
+ interpretation of the AUXV. Must be > 16. */
+#define AT_IGNOREPPC 22 /* Entry should be ignored. */
+
+#define AT_SECURE 23 /* Boolean, was exec setuid-like? */
+
+#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/
+
+#define AT_RANDOM 25 /* Address of 16 random bytes. */
+
+#define AT_HWCAP2 26 /* More machine-dependent hints about
+ processor capabilities. */
+
+#define AT_EXECFN 31 /* Filename of executable. */
+
+/* Pointer to the global system page used for system calls and other
+ nice things. */
+#define AT_SYSINFO 32
+#define AT_SYSINFO_EHDR 33
+
+/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains
+ log2 of line size; mask those to get cache size. */
+#define AT_L1I_CACHESHAPE 34
+#define AT_L1D_CACHESHAPE 35
+#define AT_L2_CACHESHAPE 36
+#define AT_L3_CACHESHAPE 37
+
+/* Shapes of the caches, with more room to describe them.
+ *GEOMETRY are comprised of cache line size in bytes in the bottom 16 bits
+ and the cache associativity in the next 16 bits. */
+#define AT_L1I_CACHESIZE 40
+#define AT_L1I_CACHEGEOMETRY 41
+#define AT_L1D_CACHESIZE 42
+#define AT_L1D_CACHEGEOMETRY 43
+#define AT_L2_CACHESIZE 44
+#define AT_L2_CACHEGEOMETRY 45
+#define AT_L3_CACHESIZE 46
+#define AT_L3_CACHEGEOMETRY 47
+
+/* Note section contents. Each entry in the note section begins with
+ a header of a fixed form. */
+
+typedef struct
+{
+ Elf32_Word n_namesz; /* Length of the note's name. */
+ Elf32_Word n_descsz; /* Length of the note's descriptor. */
+ Elf32_Word n_type; /* Type of the note. */
+} Elf32_Nhdr;
+
+typedef struct
+{
+ Elf64_Word n_namesz; /* Length of the note's name. */
+ Elf64_Word n_descsz; /* Length of the note's descriptor. */
+ Elf64_Word n_type; /* Type of the note. */
+} Elf64_Nhdr;
+
+/* Known names of notes. */
+
+/* Solaris entries in the note section have this name. */
+#define ELF_NOTE_SOLARIS "SUNW Solaris"
+
+/* Note entries for GNU systems have this name. */
+#define ELF_NOTE_GNU "GNU"
+
+
+/* Defined types of notes for Solaris. */
+
+/* Value of descriptor (one word) is desired pagesize for the binary. */
+#define ELF_NOTE_PAGESIZE_HINT 1
+
+
+/* Defined note types for GNU systems. */
+
+/* ABI information. The descriptor consists of words:
+ word 0: OS descriptor
+ word 1: major version of the ABI
+ word 2: minor version of the ABI
+ word 3: subminor version of the ABI
+*/
+#define NT_GNU_ABI_TAG 1
+#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */
+
+/* Known OSes. These values can appear in word 0 of an
+ NT_GNU_ABI_TAG note section entry. */
+#define ELF_NOTE_OS_LINUX 0
+#define ELF_NOTE_OS_GNU 1
+#define ELF_NOTE_OS_SOLARIS2 2
+#define ELF_NOTE_OS_FREEBSD 3
+
+/* Synthetic hwcap information. The descriptor begins with two words:
+ word 0: number of entries
+ word 1: bitmask of enabled entries
+ Then follow variable-length entries, one byte followed by a
+ '\0'-terminated hwcap name string. The byte gives the bit
+ number to test if enabled, (1U << bit) & bitmask. */
+#define NT_GNU_HWCAP 2
+
+/* Build ID bits as generated by ld --build-id.
+ The descriptor consists of any nonzero number of bytes. */
+#define NT_GNU_BUILD_ID 3
+
+/* Version note generated by GNU gold containing a version string. */
+#define NT_GNU_GOLD_VERSION 4
+
+
+/* Move records. */
+typedef struct
+{
+ Elf32_Xword m_value; /* Symbol value. */
+ Elf32_Word m_info; /* Size and index. */
+ Elf32_Word m_poffset; /* Symbol offset. */
+ Elf32_Half m_repeat; /* Repeat count. */
+ Elf32_Half m_stride; /* Stride info. */
+} Elf32_Move;
+
+typedef struct
+{
+ Elf64_Xword m_value; /* Symbol value. */
+ Elf64_Xword m_info; /* Size and index. */
+ Elf64_Xword m_poffset; /* Symbol offset. */
+ Elf64_Half m_repeat; /* Repeat count. */
+ Elf64_Half m_stride; /* Stride info. */
+} Elf64_Move;
+
+/* Macro to construct move records. */
+#define ELF32_M_SYM(info) ((info) >> 8)
+#define ELF32_M_SIZE(info) ((unsigned char) (info))
+#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size))
+
+#define ELF64_M_SYM(info) ELF32_M_SYM (info)
+#define ELF64_M_SIZE(info) ELF32_M_SIZE (info)
+#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size)
+
+
+/* Motorola 68k specific definitions. */
+
+/* Values for Elf32_Ehdr.e_flags. */
+#define EF_CPU32 0x00810000
+
+/* m68k relocs. */
+
+#define R_68K_NONE 0 /* No reloc */
+#define R_68K_32 1 /* Direct 32 bit */
+#define R_68K_16 2 /* Direct 16 bit */
+#define R_68K_8 3 /* Direct 8 bit */
+#define R_68K_PC32 4 /* PC relative 32 bit */
+#define R_68K_PC16 5 /* PC relative 16 bit */
+#define R_68K_PC8 6 /* PC relative 8 bit */
+#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */
+#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */
+#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */
+#define R_68K_GOT32O 10 /* 32 bit GOT offset */
+#define R_68K_GOT16O 11 /* 16 bit GOT offset */
+#define R_68K_GOT8O 12 /* 8 bit GOT offset */
+#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */
+#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */
+#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */
+#define R_68K_PLT32O 16 /* 32 bit PLT offset */
+#define R_68K_PLT16O 17 /* 16 bit PLT offset */
+#define R_68K_PLT8O 18 /* 8 bit PLT offset */
+#define R_68K_COPY 19 /* Copy symbol at runtime */
+#define R_68K_GLOB_DAT 20 /* Create GOT entry */
+#define R_68K_JMP_SLOT 21 /* Create PLT entry */
+#define R_68K_RELATIVE 22 /* Adjust by program base */
+#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */
+#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */
+#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */
+#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */
+#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */
+#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */
+#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */
+#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */
+#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */
+#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */
+#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */
+#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */
+#define R_68K_TLS_LE32 37 /* 32 bit offset relative to
+ static TLS block */
+#define R_68K_TLS_LE16 38 /* 16 bit offset relative to
+ static TLS block */
+#define R_68K_TLS_LE8 39 /* 8 bit offset relative to
+ static TLS block */
+#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */
+#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */
+#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */
+/* Keep this the last entry. */
+#define R_68K_NUM 43
+
+/* Intel 80386 specific definitions. */
+
+/* i386 relocs. */
+
+#define R_386_NONE 0 /* No reloc */
+#define R_386_32 1 /* Direct 32 bit */
+#define R_386_PC32 2 /* PC relative 32 bit */
+#define R_386_GOT32 3 /* 32 bit GOT entry */
+#define R_386_PLT32 4 /* 32 bit PLT address */
+#define R_386_COPY 5 /* Copy symbol at runtime */
+#define R_386_GLOB_DAT 6 /* Create GOT entry */
+#define R_386_JMP_SLOT 7 /* Create PLT entry */
+#define R_386_RELATIVE 8 /* Adjust by program base */
+#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
+#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */
+#define R_386_32PLT 11
+#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */
+#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS
+ block offset */
+#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block
+ offset */
+#define R_386_TLS_LE 17 /* Offset relative to static TLS
+ block */
+#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of
+ general dynamic thread local data */
+#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of
+ local dynamic thread local data
+ in LE code */
+#define R_386_16 20
+#define R_386_PC16 21
+#define R_386_8 22
+#define R_386_PC8 23
+#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic
+ thread local data */
+#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */
+#define R_386_TLS_GD_CALL 26 /* Relocation for call to
+ __tls_get_addr() */
+#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */
+#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic
+ thread local data in LE code */
+#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */
+#define R_386_TLS_LDM_CALL 30 /* Relocation for call to
+ __tls_get_addr() in LDM code */
+#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */
+#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */
+#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS
+ block offset */
+#define R_386_TLS_LE_32 34 /* Negated offset relative to static
+ TLS block */
+#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */
+#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */
+#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */
+#define R_386_SIZE32 38 /* 32-bit symbol size */
+#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */
+#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS
+ descriptor for
+ relaxation. */
+#define R_386_TLS_DESC 41 /* TLS descriptor containing
+ pointer to code and to
+ argument, returning the TLS
+ offset for the symbol. */
+#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */
+#define R_386_GOT32X 43 /* Load from 32 bit GOT entry,
+ relaxable. */
+/* Keep this the last entry. */
+#define R_386_NUM 44
+
+/* SUN SPARC specific definitions. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */
+
+/* Values for Elf64_Ehdr.e_flags. */
+
+#define EF_SPARCV9_MM 3
+#define EF_SPARCV9_TSO 0
+#define EF_SPARCV9_PSO 1
+#define EF_SPARCV9_RMO 2
+#define EF_SPARC_LEDATA 0x800000 /* little endian data */
+#define EF_SPARC_EXT_MASK 0xFFFF00
+#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */
+#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */
+#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */
+#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */
+
+/* SPARC relocs. */
+
+#define R_SPARC_NONE 0 /* No reloc */
+#define R_SPARC_8 1 /* Direct 8 bit */
+#define R_SPARC_16 2 /* Direct 16 bit */
+#define R_SPARC_32 3 /* Direct 32 bit */
+#define R_SPARC_DISP8 4 /* PC relative 8 bit */
+#define R_SPARC_DISP16 5 /* PC relative 16 bit */
+#define R_SPARC_DISP32 6 /* PC relative 32 bit */
+#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */
+#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */
+#define R_SPARC_HI22 9 /* High 22 bit */
+#define R_SPARC_22 10 /* Direct 22 bit */
+#define R_SPARC_13 11 /* Direct 13 bit */
+#define R_SPARC_LO10 12 /* Truncated 10 bit */
+#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */
+#define R_SPARC_GOT13 14 /* 13 bit GOT entry */
+#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */
+#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */
+#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */
+#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */
+#define R_SPARC_COPY 19 /* Copy symbol at runtime */
+#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */
+#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */
+#define R_SPARC_RELATIVE 22 /* Adjust by program base */
+#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */
+
+/* Additional Sparc64 relocs. */
+
+#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */
+#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */
+#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */
+#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */
+#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */
+#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */
+#define R_SPARC_10 30 /* Direct 10 bit */
+#define R_SPARC_11 31 /* Direct 11 bit */
+#define R_SPARC_64 32 /* Direct 64 bit */
+#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */
+#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */
+#define R_SPARC_HM10 35 /* High middle 10 bits of ... */
+#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */
+#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */
+#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */
+#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */
+#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */
+#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */
+#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */
+#define R_SPARC_7 43 /* Direct 7 bit */
+#define R_SPARC_5 44 /* Direct 5 bit */
+#define R_SPARC_6 45 /* Direct 6 bit */
+#define R_SPARC_DISP64 46 /* PC relative 64 bit */
+#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */
+#define R_SPARC_HIX22 48 /* High 22 bit complemented */
+#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */
+#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */
+#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */
+#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */
+#define R_SPARC_REGISTER 53 /* Global register usage */
+#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */
+#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */
+#define R_SPARC_TLS_GD_HI22 56
+#define R_SPARC_TLS_GD_LO10 57
+#define R_SPARC_TLS_GD_ADD 58
+#define R_SPARC_TLS_GD_CALL 59
+#define R_SPARC_TLS_LDM_HI22 60
+#define R_SPARC_TLS_LDM_LO10 61
+#define R_SPARC_TLS_LDM_ADD 62
+#define R_SPARC_TLS_LDM_CALL 63
+#define R_SPARC_TLS_LDO_HIX22 64
+#define R_SPARC_TLS_LDO_LOX10 65
+#define R_SPARC_TLS_LDO_ADD 66
+#define R_SPARC_TLS_IE_HI22 67
+#define R_SPARC_TLS_IE_LO10 68
+#define R_SPARC_TLS_IE_LD 69
+#define R_SPARC_TLS_IE_LDX 70
+#define R_SPARC_TLS_IE_ADD 71
+#define R_SPARC_TLS_LE_HIX22 72
+#define R_SPARC_TLS_LE_LOX10 73
+#define R_SPARC_TLS_DTPMOD32 74
+#define R_SPARC_TLS_DTPMOD64 75
+#define R_SPARC_TLS_DTPOFF32 76
+#define R_SPARC_TLS_DTPOFF64 77
+#define R_SPARC_TLS_TPOFF32 78
+#define R_SPARC_TLS_TPOFF64 79
+#define R_SPARC_GOTDATA_HIX22 80
+#define R_SPARC_GOTDATA_LOX10 81
+#define R_SPARC_GOTDATA_OP_HIX22 82
+#define R_SPARC_GOTDATA_OP_LOX10 83
+#define R_SPARC_GOTDATA_OP 84
+#define R_SPARC_H34 85
+#define R_SPARC_SIZE32 86
+#define R_SPARC_SIZE64 87
+#define R_SPARC_WDISP10 88
+#define R_SPARC_JMP_IREL 248
+#define R_SPARC_IRELATIVE 249
+#define R_SPARC_GNU_VTINHERIT 250
+#define R_SPARC_GNU_VTENTRY 251
+#define R_SPARC_REV32 252
+/* Keep this the last entry. */
+#define R_SPARC_NUM 253
+
+/* For Sparc64, legal values for d_tag of Elf64_Dyn. */
+
+#define DT_SPARC_REGISTER 0x70000001
+#define DT_SPARC_NUM 2
+
+/* MIPS R3000 specific definitions. */
+
+/* Legal values for e_flags field of Elf32_Ehdr. */
+
+#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used. */
+#define EF_MIPS_PIC 2 /* Contains PIC code. */
+#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */
+#define EF_MIPS_XGOT 8
+#define EF_MIPS_64BIT_WHIRL 16
+#define EF_MIPS_ABI2 32
+#define EF_MIPS_ABI_ON32 64
+#define EF_MIPS_FP64 512 /* Uses FP64 (12 callee-saved). */
+#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
+#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
+
+/* Legal values for MIPS architecture level. */
+
+#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
+#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
+#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
+#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
+#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
+#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */
+#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */
+#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */
+#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */
+
+/* The following are unofficial names and should not be used. */
+
+#define E_MIPS_ARCH_1 EF_MIPS_ARCH_1
+#define E_MIPS_ARCH_2 EF_MIPS_ARCH_2
+#define E_MIPS_ARCH_3 EF_MIPS_ARCH_3
+#define E_MIPS_ARCH_4 EF_MIPS_ARCH_4
+#define E_MIPS_ARCH_5 EF_MIPS_ARCH_5
+#define E_MIPS_ARCH_32 EF_MIPS_ARCH_32
+#define E_MIPS_ARCH_64 EF_MIPS_ARCH_64
+
+/* Special section indices. */
+
+#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols. */
+#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */
+#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */
+#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols. */
+#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols. */
+
+/* Legal values for sh_type field of Elf32_Shdr. */
+
+#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link. */
+#define SHT_MIPS_MSYM 0x70000001
+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols. */
+#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes. */
+#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */
+#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging info. */
+#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information. */
+#define SHT_MIPS_PACKAGE 0x70000007
+#define SHT_MIPS_PACKSYM 0x70000008
+#define SHT_MIPS_RELD 0x70000009
+#define SHT_MIPS_IFACE 0x7000000b
+#define SHT_MIPS_CONTENT 0x7000000c
+#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */
+#define SHT_MIPS_SHDR 0x70000010
+#define SHT_MIPS_FDESC 0x70000011
+#define SHT_MIPS_EXTSYM 0x70000012
+#define SHT_MIPS_DENSE 0x70000013
+#define SHT_MIPS_PDESC 0x70000014
+#define SHT_MIPS_LOCSYM 0x70000015
+#define SHT_MIPS_AUXSYM 0x70000016
+#define SHT_MIPS_OPTSYM 0x70000017
+#define SHT_MIPS_LOCSTR 0x70000018
+#define SHT_MIPS_LINE 0x70000019
+#define SHT_MIPS_RFDESC 0x7000001a
+#define SHT_MIPS_DELTASYM 0x7000001b
+#define SHT_MIPS_DELTAINST 0x7000001c
+#define SHT_MIPS_DELTACLASS 0x7000001d
+#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */
+#define SHT_MIPS_DELTADECL 0x7000001f
+#define SHT_MIPS_SYMBOL_LIB 0x70000020
+#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */
+#define SHT_MIPS_TRANSLATE 0x70000022
+#define SHT_MIPS_PIXIE 0x70000023
+#define SHT_MIPS_XLATE 0x70000024
+#define SHT_MIPS_XLATE_DEBUG 0x70000025
+#define SHT_MIPS_WHIRL 0x70000026
+#define SHT_MIPS_EH_REGION 0x70000027
+#define SHT_MIPS_XLATE_OLD 0x70000028
+#define SHT_MIPS_PDR_EXCEPTION 0x70000029
+
+/* Legal values for sh_flags field of Elf32_Shdr. */
+
+#define SHF_MIPS_GPREL 0x10000000 /* Must be in global data area. */
+#define SHF_MIPS_MERGE 0x20000000
+#define SHF_MIPS_ADDR 0x40000000
+#define SHF_MIPS_STRINGS 0x80000000
+#define SHF_MIPS_NOSTRIP 0x08000000
+#define SHF_MIPS_LOCAL 0x04000000
+#define SHF_MIPS_NAMES 0x02000000
+#define SHF_MIPS_NODUPE 0x01000000
+
+
+/* Symbol tables. */
+
+/* MIPS specific values for `st_other'. */
+#define STO_MIPS_DEFAULT 0x0
+#define STO_MIPS_INTERNAL 0x1
+#define STO_MIPS_HIDDEN 0x2
+#define STO_MIPS_PROTECTED 0x3
+#define STO_MIPS_PLT 0x8
+#define STO_MIPS_SC_ALIGN_UNUSED 0xff
+
+/* MIPS specific values for `st_info'. */
+#define STB_MIPS_SPLIT_COMMON 13
+
+/* Entries found in sections of type SHT_MIPS_GPTAB. */
+
+typedef union
+{
+ struct
+ {
+ Elf32_Word gt_current_g_value; /* -G value used for compilation. */
+ Elf32_Word gt_unused; /* Not used. */
+ } gt_header; /* First entry in section. */
+ struct
+ {
+ Elf32_Word gt_g_value; /* If this value were used for -G. */
+ Elf32_Word gt_bytes; /* This many bytes would be used. */
+ } gt_entry; /* Subsequent entries in section. */
+} Elf32_gptab;
+
+/* Entry found in sections of type SHT_MIPS_REGINFO. */
+
+typedef struct
+{
+ Elf32_Word ri_gprmask; /* General registers used. */
+ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used. */
+ Elf32_Sword ri_gp_value; /* $gp register value. */
+} Elf32_RegInfo;
+
+/* Entries found in sections of type SHT_MIPS_OPTIONS. */
+
+typedef struct
+{
+ unsigned char kind; /* Determines interpretation of the
+ variable part of descriptor. */
+ unsigned char size; /* Size of descriptor, including header. */
+ Elf32_Section section; /* Section header index of section affected,
+ 0 for global options. */
+ Elf32_Word info; /* Kind-specific information. */
+} Elf_Options;
+
+/* Values for `kind' field in Elf_Options. */
+
+#define ODK_NULL 0 /* Undefined. */
+#define ODK_REGINFO 1 /* Register usage information. */
+#define ODK_EXCEPTIONS 2 /* Exception processing options. */
+#define ODK_PAD 3 /* Section padding options. */
+#define ODK_HWPATCH 4 /* Hardware workarounds performed */
+#define ODK_FILL 5 /* record the fill value used by the linker. */
+#define ODK_TAGS 6 /* reserve space for desktop tools to write. */
+#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */
+#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */
+
+/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */
+
+#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */
+#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */
+#define OEX_PAGE0 0x10000 /* page zero must be mapped. */
+#define OEX_SMM 0x20000 /* Force sequential memory mode? */
+#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */
+#define OEX_PRECISEFP OEX_FPDBUG
+#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */
+
+#define OEX_FPU_INVAL 0x10
+#define OEX_FPU_DIV0 0x08
+#define OEX_FPU_OFLO 0x04
+#define OEX_FPU_UFLO 0x02
+#define OEX_FPU_INEX 0x01
+
+/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */
+
+#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */
+#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */
+#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */
+#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */
+
+#define OPAD_PREFIX 0x1
+#define OPAD_POSTFIX 0x2
+#define OPAD_SYMBOL 0x4
+
+/* Entry found in `.options' section. */
+
+typedef struct
+{
+ Elf32_Word hwp_flags1; /* Extra flags. */
+ Elf32_Word hwp_flags2; /* Extra flags. */
+} Elf_Options_Hw;
+
+/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */
+
+#define OHWA0_R4KEOP_CHECKED 0x00000001
+#define OHWA1_R4KEOP_CLEAN 0x00000002
+
+/* MIPS relocs. */
+
+#define R_MIPS_NONE 0 /* No reloc */
+#define R_MIPS_16 1 /* Direct 16 bit */
+#define R_MIPS_32 2 /* Direct 32 bit */
+#define R_MIPS_REL32 3 /* PC relative 32 bit */
+#define R_MIPS_26 4 /* Direct 26 bit shifted */
+#define R_MIPS_HI16 5 /* High 16 bit */
+#define R_MIPS_LO16 6 /* Low 16 bit */
+#define R_MIPS_GPREL16 7 /* GP relative 16 bit */
+#define R_MIPS_LITERAL 8 /* 16 bit literal entry */
+#define R_MIPS_GOT16 9 /* 16 bit GOT entry */
+#define R_MIPS_PC16 10 /* PC relative 16 bit */
+#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */
+#define R_MIPS_GPREL32 12 /* GP relative 32 bit */
+
+#define R_MIPS_SHIFT5 16
+#define R_MIPS_SHIFT6 17
+#define R_MIPS_64 18
+#define R_MIPS_GOT_DISP 19
+#define R_MIPS_GOT_PAGE 20
+#define R_MIPS_GOT_OFST 21
+#define R_MIPS_GOT_HI16 22
+#define R_MIPS_GOT_LO16 23
+#define R_MIPS_SUB 24
+#define R_MIPS_INSERT_A 25
+#define R_MIPS_INSERT_B 26
+#define R_MIPS_DELETE 27
+#define R_MIPS_HIGHER 28
+#define R_MIPS_HIGHEST 29
+#define R_MIPS_CALL_HI16 30
+#define R_MIPS_CALL_LO16 31
+#define R_MIPS_SCN_DISP 32
+#define R_MIPS_REL16 33
+#define R_MIPS_ADD_IMMEDIATE 34
+#define R_MIPS_PJUMP 35
+#define R_MIPS_RELGOT 36
+#define R_MIPS_JALR 37
+#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */
+#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */
+#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */
+#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */
+#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */
+#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */
+#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */
+#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */
+#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */
+#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */
+#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */
+#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */
+#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */
+#define R_MIPS_GLOB_DAT 51
+#define R_MIPS_COPY 126
+#define R_MIPS_JUMP_SLOT 127
+/* Keep this the last entry. */
+#define R_MIPS_NUM 128
+
+/* Legal values for p_type field of Elf32_Phdr. */
+
+#define PT_MIPS_REGINFO 0x70000000 /* Register usage information. */
+#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
+#define PT_MIPS_OPTIONS 0x70000002
+#define PT_MIPS_ABIFLAGS 0x70000003 /* FP mode requirement. */
+
+/* Special program header types. */
+
+#define PF_MIPS_LOCAL 0x10000000
+
+/* Legal values for d_tag field of Elf32_Dyn. */
+
+#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */
+#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */
+#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */
+#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */
+#define DT_MIPS_FLAGS 0x70000005 /* Flags */
+#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */
+#define DT_MIPS_MSYM 0x70000007
+#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */
+#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */
+#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */
+#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */
+#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */
+#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */
+#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */
+#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */
+#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */
+#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */
+#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */
+#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in
+ DT_MIPS_DELTA_CLASS. */
+#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */
+#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
+ DT_MIPS_DELTA_INSTANCE. */
+#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */
+#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
+ DT_MIPS_DELTA_RELOC. */
+#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta
+ relocations refer to. */
+#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
+ DT_MIPS_DELTA_SYM. */
+#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
+ class declaration. */
+#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
+ DT_MIPS_DELTA_CLASSSYM. */
+#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */
+#define DT_MIPS_PIXIE_INIT 0x70000023
+#define DT_MIPS_SYMBOL_LIB 0x70000024
+#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
+#define DT_MIPS_LOCAL_GOTIDX 0x70000026
+#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
+#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
+#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */
+#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */
+#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
+#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
+#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
+ function stored in GOT. */
+#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added
+ by rld on dlopen() calls. */
+#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
+#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */
+#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */
+/* The address of .got.plt in an executable using the new non-PIC ABI. */
+#define DT_MIPS_PLTGOT 0x70000032
+/* The base of the PLT in an executable using the new non-PIC ABI if that
+ PLT is writable. For a non-writable PLT, this is omitted or has a zero
+ value. */
+#define DT_MIPS_RWPLT 0x70000034
+/* An alternative description of the classic MIPS RLD_MAP that is usable
+ in a PIE as it stores a relative offset from the address of the tag
+ rather than an absolute address. */
+#define DT_MIPS_RLD_MAP_REL 0x70000035
+#define DT_MIPS_NUM 0x36
+
+/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */
+
+#define RHF_NONE 0 /* No flags */
+#define RHF_QUICKSTART (1 << 0) /* Use quickstart */
+#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */
+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */
+#define RHF_NO_MOVE (1 << 3)
+#define RHF_SGI_ONLY (1 << 4)
+#define RHF_GUARANTEE_INIT (1 << 5)
+#define RHF_DELTA_C_PLUS_PLUS (1 << 6)
+#define RHF_GUARANTEE_START_INIT (1 << 7)
+#define RHF_PIXIE (1 << 8)
+#define RHF_DEFAULT_DELAY_LOAD (1 << 9)
+#define RHF_REQUICKSTART (1 << 10)
+#define RHF_REQUICKSTARTED (1 << 11)
+#define RHF_CORD (1 << 12)
+#define RHF_NO_UNRES_UNDEF (1 << 13)
+#define RHF_RLD_ORDER_SAFE (1 << 14)
+
+/* Entries found in sections of type SHT_MIPS_LIBLIST. */
+
+typedef struct
+{
+ Elf32_Word l_name; /* Name (string table index) */
+ Elf32_Word l_time_stamp; /* Timestamp */
+ Elf32_Word l_checksum; /* Checksum */
+ Elf32_Word l_version; /* Interface version */
+ Elf32_Word l_flags; /* Flags */
+} Elf32_Lib;
+
+typedef struct
+{
+ Elf64_Word l_name; /* Name (string table index) */
+ Elf64_Word l_time_stamp; /* Timestamp */
+ Elf64_Word l_checksum; /* Checksum */
+ Elf64_Word l_version; /* Interface version */
+ Elf64_Word l_flags; /* Flags */
+} Elf64_Lib;
+
+
+/* Legal values for l_flags. */
+
+#define LL_NONE 0
+#define LL_EXACT_MATCH (1 << 0) /* Require exact match */
+#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */
+#define LL_REQUIRE_MINOR (1 << 2)
+#define LL_EXPORTS (1 << 3)
+#define LL_DELAY_LOAD (1 << 4)
+#define LL_DELTA (1 << 5)
+
+/* Entries found in sections of type SHT_MIPS_CONFLICT. */
+
+typedef Elf32_Addr Elf32_Conflict;
+
+typedef struct
+{
+ /* Version of flags structure. */
+ Elf32_Half version;
+ /* The level of the ISA: 1-5, 32, 64. */
+ unsigned char isa_level;
+ /* The revision of ISA: 0 for MIPS V and below, 1-n otherwise. */
+ unsigned char isa_rev;
+ /* The size of general purpose registers. */
+ unsigned char gpr_size;
+ /* The size of co-processor 1 registers. */
+ unsigned char cpr1_size;
+ /* The size of co-processor 2 registers. */
+ unsigned char cpr2_size;
+ /* The floating-point ABI. */
+ unsigned char fp_abi;
+ /* Processor-specific extension. */
+ Elf32_Word isa_ext;
+ /* Mask of ASEs used. */
+ Elf32_Word ases;
+ /* Mask of general flags. */
+ Elf32_Word flags1;
+ Elf32_Word flags2;
+} Elf_MIPS_ABIFlags_v0;
+
+/* Values for the register size bytes of an abi flags structure. */
+
+#define MIPS_AFL_REG_NONE 0x00 /* No registers. */
+#define MIPS_AFL_REG_32 0x01 /* 32-bit registers. */
+#define MIPS_AFL_REG_64 0x02 /* 64-bit registers. */
+#define MIPS_AFL_REG_128 0x03 /* 128-bit registers. */
+
+/* Masks for the ases word of an ABI flags structure. */
+
+#define MIPS_AFL_ASE_DSP 0x00000001 /* DSP ASE. */
+#define MIPS_AFL_ASE_DSPR2 0x00000002 /* DSP R2 ASE. */
+#define MIPS_AFL_ASE_EVA 0x00000004 /* Enhanced VA Scheme. */
+#define MIPS_AFL_ASE_MCU 0x00000008 /* MCU (MicroController) ASE. */
+#define MIPS_AFL_ASE_MDMX 0x00000010 /* MDMX ASE. */
+#define MIPS_AFL_ASE_MIPS3D 0x00000020 /* MIPS-3D ASE. */
+#define MIPS_AFL_ASE_MT 0x00000040 /* MT ASE. */
+#define MIPS_AFL_ASE_SMARTMIPS 0x00000080 /* SmartMIPS ASE. */
+#define MIPS_AFL_ASE_VIRT 0x00000100 /* VZ ASE. */
+#define MIPS_AFL_ASE_MSA 0x00000200 /* MSA ASE. */
+#define MIPS_AFL_ASE_MIPS16 0x00000400 /* MIPS16 ASE. */
+#define MIPS_AFL_ASE_MICROMIPS 0x00000800 /* MICROMIPS ASE. */
+#define MIPS_AFL_ASE_XPA 0x00001000 /* XPA ASE. */
+#define MIPS_AFL_ASE_MASK 0x00001fff /* All ASEs. */
+
+/* Values for the isa_ext word of an ABI flags structure. */
+
+#define MIPS_AFL_EXT_XLR 1 /* RMI Xlr instruction. */
+#define MIPS_AFL_EXT_OCTEON2 2 /* Cavium Networks Octeon2. */
+#define MIPS_AFL_EXT_OCTEONP 3 /* Cavium Networks OcteonP. */
+#define MIPS_AFL_EXT_LOONGSON_3A 4 /* Loongson 3A. */
+#define MIPS_AFL_EXT_OCTEON 5 /* Cavium Networks Octeon. */
+#define MIPS_AFL_EXT_5900 6 /* MIPS R5900 instruction. */
+#define MIPS_AFL_EXT_4650 7 /* MIPS R4650 instruction. */
+#define MIPS_AFL_EXT_4010 8 /* LSI R4010 instruction. */
+#define MIPS_AFL_EXT_4100 9 /* NEC VR4100 instruction. */
+#define MIPS_AFL_EXT_3900 10 /* Toshiba R3900 instruction. */
+#define MIPS_AFL_EXT_10000 11 /* MIPS R10000 instruction. */
+#define MIPS_AFL_EXT_SB1 12 /* Broadcom SB-1 instruction. */
+#define MIPS_AFL_EXT_4111 13 /* NEC VR4111/VR4181 instruction. */
+#define MIPS_AFL_EXT_4120 14 /* NEC VR4120 instruction. */
+#define MIPS_AFL_EXT_5400 15 /* NEC VR5400 instruction. */
+#define MIPS_AFL_EXT_5500 16 /* NEC VR5500 instruction. */
+#define MIPS_AFL_EXT_LOONGSON_2E 17 /* ST Microelectronics Loongson 2E. */
+#define MIPS_AFL_EXT_LOONGSON_2F 18 /* ST Microelectronics Loongson 2F. */
+
+/* Masks for the flags1 word of an ABI flags structure. */
+#define MIPS_AFL_FLAGS1_ODDSPREG 1 /* Uses odd single-precision registers. */
+
+/* Object attribute values. */
+enum
+{
+ /* Not tagged or not using any ABIs affected by the differences. */
+ Val_GNU_MIPS_ABI_FP_ANY = 0,
+ /* Using hard-float -mdouble-float. */
+ Val_GNU_MIPS_ABI_FP_DOUBLE = 1,
+ /* Using hard-float -msingle-float. */
+ Val_GNU_MIPS_ABI_FP_SINGLE = 2,
+ /* Using soft-float. */
+ Val_GNU_MIPS_ABI_FP_SOFT = 3,
+ /* Using -mips32r2 -mfp64. */
+ Val_GNU_MIPS_ABI_FP_OLD_64 = 4,
+ /* Using -mfpxx. */
+ Val_GNU_MIPS_ABI_FP_XX = 5,
+ /* Using -mips32r2 -mfp64. */
+ Val_GNU_MIPS_ABI_FP_64 = 6,
+ /* Using -mips32r2 -mfp64 -mno-odd-spreg. */
+ Val_GNU_MIPS_ABI_FP_64A = 7,
+ /* Maximum allocated FP ABI value. */
+ Val_GNU_MIPS_ABI_FP_MAX = 7
+};
+
+/* HPPA specific definitions. */
+
+/* Legal values for e_flags field of Elf32_Ehdr. */
+
+#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */
+#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */
+#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */
+#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */
+#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch
+ prediction. */
+#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */
+#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */
+
+/* Defined values for `e_flags & EF_PARISC_ARCH' are: */
+
+#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */
+#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */
+#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */
+
+/* Additional section indeces. */
+
+#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared
+ symbols in ANSI C. */
+#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */
+
+/* Legal values for sh_type field of Elf32_Shdr. */
+
+#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */
+#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */
+#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */
+
+/* Legal values for sh_flags field of Elf32_Shdr. */
+
+#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */
+#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */
+#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */
+
+#define STT_HP_OPAQUE (STT_LOOS + 0x1)
+#define STT_HP_STUB (STT_LOOS + 0x2)
+
+/* HPPA relocs. */
+
+#define R_PARISC_NONE 0 /* No reloc. */
+#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */
+#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */
+#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */
+#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */
+#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */
+#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */
+#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */
+#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */
+#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */
+#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */
+#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */
+#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */
+#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */
+#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */
+#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */
+#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */
+#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */
+#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */
+#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */
+#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */
+#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */
+#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */
+#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */
+#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */
+#define R_PARISC_FPTR64 64 /* 64 bits function address. */
+#define R_PARISC_PLABEL32 65 /* 32 bits function address. */
+#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */
+#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */
+#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */
+#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */
+#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */
+#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */
+#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */
+#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */
+#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */
+#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */
+#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */
+#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */
+#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */
+#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */
+#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */
+#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */
+#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */
+#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */
+#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */
+#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */
+#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */
+#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */
+#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */
+#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */
+#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */
+#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */
+#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */
+#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */
+#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */
+#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */
+#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */
+#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */
+#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LORESERVE 128
+#define R_PARISC_COPY 128 /* Copy relocation. */
+#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */
+#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */
+#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */
+#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */
+#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */
+#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */
+#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */
+#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */
+#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */
+#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */
+#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_GNU_VTENTRY 232
+#define R_PARISC_GNU_VTINHERIT 233
+#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */
+#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */
+#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */
+#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */
+#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */
+#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */
+#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */
+#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */
+#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */
+#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */
+#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */
+#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */
+#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L
+#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R
+#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L
+#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R
+#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32
+#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64
+#define R_PARISC_HIRESERVE 255
+
+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */
+
+#define PT_HP_TLS (PT_LOOS + 0x0)
+#define PT_HP_CORE_NONE (PT_LOOS + 0x1)
+#define PT_HP_CORE_VERSION (PT_LOOS + 0x2)
+#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3)
+#define PT_HP_CORE_COMM (PT_LOOS + 0x4)
+#define PT_HP_CORE_PROC (PT_LOOS + 0x5)
+#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6)
+#define PT_HP_CORE_STACK (PT_LOOS + 0x7)
+#define PT_HP_CORE_SHM (PT_LOOS + 0x8)
+#define PT_HP_CORE_MMF (PT_LOOS + 0x9)
+#define PT_HP_PARALLEL (PT_LOOS + 0x10)
+#define PT_HP_FASTBIND (PT_LOOS + 0x11)
+#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12)
+#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13)
+#define PT_HP_STACK (PT_LOOS + 0x14)
+
+#define PT_PARISC_ARCHEXT 0x70000000
+#define PT_PARISC_UNWIND 0x70000001
+
+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */
+
+#define PF_PARISC_SBP 0x08000000
+
+#define PF_HP_PAGE_SIZE 0x00100000
+#define PF_HP_FAR_SHARED 0x00200000
+#define PF_HP_NEAR_SHARED 0x00400000
+#define PF_HP_CODE 0x01000000
+#define PF_HP_MODIFY 0x02000000
+#define PF_HP_LAZYSWAP 0x04000000
+#define PF_HP_SBP 0x08000000
+
+
+/* Alpha specific definitions. */
+
+/* Legal values for e_flags field of Elf64_Ehdr. */
+
+#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */
+#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */
+
+/* Legal values for sh_type field of Elf64_Shdr. */
+
+/* These two are primerily concerned with ECOFF debugging info. */
+#define SHT_ALPHA_DEBUG 0x70000001
+#define SHT_ALPHA_REGINFO 0x70000002
+
+/* Legal values for sh_flags field of Elf64_Shdr. */
+
+#define SHF_ALPHA_GPREL 0x10000000
+
+/* Legal values for st_other field of Elf64_Sym. */
+#define STO_ALPHA_NOPV 0x80 /* No PV required. */
+#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */
+
+/* Alpha relocs. */
+
+#define R_ALPHA_NONE 0 /* No reloc */
+#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
+#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
+#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
+#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
+#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
+#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
+#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
+#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */
+#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */
+#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */
+#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
+#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
+#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
+#define R_ALPHA_TLS_GD_HI 28
+#define R_ALPHA_TLSGD 29
+#define R_ALPHA_TLS_LDM 30
+#define R_ALPHA_DTPMOD64 31
+#define R_ALPHA_GOTDTPREL 32
+#define R_ALPHA_DTPREL64 33
+#define R_ALPHA_DTPRELHI 34
+#define R_ALPHA_DTPRELLO 35
+#define R_ALPHA_DTPREL16 36
+#define R_ALPHA_GOTTPREL 37
+#define R_ALPHA_TPREL64 38
+#define R_ALPHA_TPRELHI 39
+#define R_ALPHA_TPRELLO 40
+#define R_ALPHA_TPREL16 41
+/* Keep this the last entry. */
+#define R_ALPHA_NUM 46
+
+/* Magic values of the LITUSE relocation addend. */
+#define LITUSE_ALPHA_ADDR 0
+#define LITUSE_ALPHA_BASE 1
+#define LITUSE_ALPHA_BYTOFF 2
+#define LITUSE_ALPHA_JSR 3
+#define LITUSE_ALPHA_TLS_GD 4
+#define LITUSE_ALPHA_TLS_LDM 5
+
+/* Legal values for d_tag of Elf64_Dyn. */
+#define DT_ALPHA_PLTRO (DT_LOPROC + 0)
+#define DT_ALPHA_NUM 1
+
+/* PowerPC specific declarations */
+
+/* Values for Elf32/64_Ehdr.e_flags. */
+#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */
+
+/* Cygnus local bits below */
+#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/
+#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib
+ flag */
+
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE 0
+#define R_PPC_ADDR32 1 /* 32bit absolute address */
+#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */
+#define R_PPC_ADDR16 3 /* 16bit absolute address */
+#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */
+#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN 8
+#define R_PPC_ADDR14_BRNTAKEN 9
+#define R_PPC_REL24 10 /* PC relative 26 bit */
+#define R_PPC_REL14 11 /* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN 12
+#define R_PPC_REL14_BRNTAKEN 13
+#define R_PPC_GOT16 14
+#define R_PPC_GOT16_LO 15
+#define R_PPC_GOT16_HI 16
+#define R_PPC_GOT16_HA 17
+#define R_PPC_PLTREL24 18
+#define R_PPC_COPY 19
+#define R_PPC_GLOB_DAT 20
+#define R_PPC_JMP_SLOT 21
+#define R_PPC_RELATIVE 22
+#define R_PPC_LOCAL24PC 23
+#define R_PPC_UADDR32 24
+#define R_PPC_UADDR16 25
+#define R_PPC_REL32 26
+#define R_PPC_PLT32 27
+#define R_PPC_PLTREL32 28
+#define R_PPC_PLT16_LO 29
+#define R_PPC_PLT16_HI 30
+#define R_PPC_PLT16_HA 31
+#define R_PPC_SDAREL16 32
+#define R_PPC_SECTOFF 33
+#define R_PPC_SECTOFF_LO 34
+#define R_PPC_SECTOFF_HI 35
+#define R_PPC_SECTOFF_HA 36
+
+/* PowerPC relocations defined for the TLS access ABI. */
+#define R_PPC_TLS 67 /* none (sym+add)@tls */
+#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */
+#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */
+#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
+#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
+#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
+#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */
+#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */
+#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
+#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
+#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
+#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */
+#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
+#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
+#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
+#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
+#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
+#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
+#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
+#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
+#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */
+#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */
+#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
+#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
+#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */
+#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */
+#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */
+#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */
+#define R_PPC_TLSGD 95 /* none (sym+add)@tlsgd */
+#define R_PPC_TLSLD 96 /* none (sym+add)@tlsld */
+
+/* The remaining relocs are from the Embedded ELF ABI, and are not
+ in the SVR4 ELF ABI. */
+#define R_PPC_EMB_NADDR32 101
+#define R_PPC_EMB_NADDR16 102
+#define R_PPC_EMB_NADDR16_LO 103
+#define R_PPC_EMB_NADDR16_HI 104
+#define R_PPC_EMB_NADDR16_HA 105
+#define R_PPC_EMB_SDAI16 106
+#define R_PPC_EMB_SDA2I16 107
+#define R_PPC_EMB_SDA2REL 108
+#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */
+#define R_PPC_EMB_MRKREF 110
+#define R_PPC_EMB_RELSEC16 111
+#define R_PPC_EMB_RELST_LO 112
+#define R_PPC_EMB_RELST_HI 113
+#define R_PPC_EMB_RELST_HA 114
+#define R_PPC_EMB_BIT_FLD 115
+#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */
+
+/* Diab tool relocations. */
+#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */
+#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */
+#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */
+#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */
+#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */
+#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */
+
+/* GNU extension to support local ifunc. */
+#define R_PPC_IRELATIVE 248
+
+/* GNU relocs used in PIC code sequences. */
+#define R_PPC_REL16 249 /* half16 (sym+add-.) */
+#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */
+#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */
+#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */
+
+/* This is a phony reloc to handle any old fashioned TOC16 references
+ that may still be in object files. */
+#define R_PPC_TOC16 255
+
+/* PowerPC specific values for the Dyn d_tag field. */
+#define DT_PPC_GOT (DT_LOPROC + 0)
+#define DT_PPC_OPT (DT_LOPROC + 1)
+#define DT_PPC_NUM 2
+
+/* PowerPC specific values for the DT_PPC_OPT Dyn entry. */
+#define PPC_OPT_TLS 1
+
+/* PowerPC64 relocations defined by the ABIs */
+#define R_PPC64_NONE R_PPC_NONE
+#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */
+#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */
+#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */
+#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */
+#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */
+#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */
+#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */
+#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN
+#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN
+#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
+#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */
+#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN
+#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN
+#define R_PPC64_GOT16 R_PPC_GOT16
+#define R_PPC64_GOT16_LO R_PPC_GOT16_LO
+#define R_PPC64_GOT16_HI R_PPC_GOT16_HI
+#define R_PPC64_GOT16_HA R_PPC_GOT16_HA
+
+#define R_PPC64_COPY R_PPC_COPY
+#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT
+#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT
+#define R_PPC64_RELATIVE R_PPC_RELATIVE
+
+#define R_PPC64_UADDR32 R_PPC_UADDR32
+#define R_PPC64_UADDR16 R_PPC_UADDR16
+#define R_PPC64_REL32 R_PPC_REL32
+#define R_PPC64_PLT32 R_PPC_PLT32
+#define R_PPC64_PLTREL32 R_PPC_PLTREL32
+#define R_PPC64_PLT16_LO R_PPC_PLT16_LO
+#define R_PPC64_PLT16_HI R_PPC_PLT16_HI
+#define R_PPC64_PLT16_HA R_PPC_PLT16_HA
+
+#define R_PPC64_SECTOFF R_PPC_SECTOFF
+#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO
+#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI
+#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA
+#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */
+#define R_PPC64_ADDR64 38 /* doubleword64 S + A */
+#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */
+#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */
+#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */
+#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */
+#define R_PPC64_UADDR64 43 /* doubleword64 S + A */
+#define R_PPC64_REL64 44 /* doubleword64 S + A - P */
+#define R_PPC64_PLT64 45 /* doubleword64 L + A */
+#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */
+#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */
+#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */
+#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */
+#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */
+#define R_PPC64_TOC 51 /* doubleword64 .TOC */
+#define R_PPC64_PLTGOT16 52 /* half16* M + A */
+#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */
+#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */
+#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */
+
+#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */
+#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */
+#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */
+#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */
+#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */
+#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */
+#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */
+#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */
+#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */
+#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */
+#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */
+
+/* PowerPC64 relocations defined for the TLS access ABI. */
+#define R_PPC64_TLS 67 /* none (sym+add)@tls */
+#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */
+#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
+#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
+#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */
+#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
+#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
+#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
+#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
+#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
+#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
+#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
+#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
+#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
+#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
+#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
+#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
+#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
+#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
+#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */
+#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */
+#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */
+#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */
+#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */
+#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */
+#define R_PPC64_TLSGD 107 /* none (sym+add)@tlsgd */
+#define R_PPC64_TLSLD 108 /* none (sym+add)@tlsld */
+#define R_PPC64_TOCSAVE 109 /* none */
+
+/* Added when HA and HI relocs were changed to report overflows. */
+#define R_PPC64_ADDR16_HIGH 110
+#define R_PPC64_ADDR16_HIGHA 111
+#define R_PPC64_TPREL16_HIGH 112
+#define R_PPC64_TPREL16_HIGHA 113
+#define R_PPC64_DTPREL16_HIGH 114
+#define R_PPC64_DTPREL16_HIGHA 115
+
+/* GNU extension to support local ifunc. */
+#define R_PPC64_JMP_IREL 247
+#define R_PPC64_IRELATIVE 248
+#define R_PPC64_REL16 249 /* half16 (sym+add-.) */
+#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */
+#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */
+#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */
+
+/* e_flags bits specifying ABI.
+ 1 for original function descriptor using ABI,
+ 2 for revised ABI without function descriptors,
+ 0 for unspecified or not using any features affected by the differences. */
+#define EF_PPC64_ABI 3
+
+/* PowerPC64 specific values for the Dyn d_tag field. */
+#define DT_PPC64_GLINK (DT_LOPROC + 0)
+#define DT_PPC64_OPD (DT_LOPROC + 1)
+#define DT_PPC64_OPDSZ (DT_LOPROC + 2)
+#define DT_PPC64_OPT (DT_LOPROC + 3)
+#define DT_PPC64_NUM 4
+
+/* PowerPC64 specific values for the DT_PPC64_OPT Dyn entry. */
+#define PPC64_OPT_TLS 1
+#define PPC64_OPT_MULTI_TOC 2
+
+/* PowerPC64 specific values for the Elf64_Sym st_other field. */
+#define STO_PPC64_LOCAL_BIT 5
+#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT)
+#define PPC64_LOCAL_ENTRY_OFFSET(other) \
+ (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2)
+
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field. */
+#define EF_ARM_RELEXEC 0x01
+#define EF_ARM_HASENTRY 0x02
+#define EF_ARM_INTERWORK 0x04
+#define EF_ARM_APCS_26 0x08
+#define EF_ARM_APCS_FLOAT 0x10
+#define EF_ARM_PIC 0x20
+#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */
+#define EF_ARM_NEW_ABI 0x80
+#define EF_ARM_OLD_ABI 0x100
+#define EF_ARM_SOFT_FLOAT 0x200
+#define EF_ARM_VFP_FLOAT 0x400
+#define EF_ARM_MAVERICK_FLOAT 0x800
+
+#define EF_ARM_ABI_FLOAT_SOFT 0x200 /* NB conflicts with EF_ARM_SOFT_FLOAT */
+#define EF_ARM_ABI_FLOAT_HARD 0x400 /* NB conflicts with EF_ARM_VFP_FLOAT */
+
+
+/* Other constants defined in the ARM ELF spec. version B-01. */
+/* NB. These conflict with values defined above. */
+#define EF_ARM_SYMSARESORTED 0x04
+#define EF_ARM_DYNSYMSUSESEGIDX 0x08
+#define EF_ARM_MAPSYMSFIRST 0x10
+#define EF_ARM_EABIMASK 0XFF000000
+
+/* Constants defined in AAELF. */
+#define EF_ARM_BE8 0x00800000
+#define EF_ARM_LE8 0x00400000
+
+#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)
+#define EF_ARM_EABI_UNKNOWN 0x00000000
+#define EF_ARM_EABI_VER1 0x01000000
+#define EF_ARM_EABI_VER2 0x02000000
+#define EF_ARM_EABI_VER3 0x03000000
+#define EF_ARM_EABI_VER4 0x04000000
+#define EF_ARM_EABI_VER5 0x05000000
+
+/* Additional symbol types for Thumb. */
+#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */
+#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */
+
+/* ARM-specific values for sh_flags */
+#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */
+#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined
+ in the input to a link step. */
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB 0x10000000 /* Segment contains the location
+ addressed by the static base. */
+#define PF_ARM_PI 0x20000000 /* Position-independent segment. */
+#define PF_ARM_ABS 0x40000000 /* Absolute segment. */
+
+/* Processor specific values for the Phdr p_type field. */
+#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */
+
+/* Processor specific values for the Shdr sh_type field. */
+#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */
+#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */
+#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */
+
+
+/* AArch64 relocs. */
+
+#define R_AARCH64_NONE 0 /* No relocation. */
+
+/* ILP32 AArch64 relocs. */
+#define R_AARCH64_P32_ABS32 1 /* Direct 32 bit. */
+#define R_AARCH64_P32_COPY 180 /* Copy symbol at runtime. */
+#define R_AARCH64_P32_GLOB_DAT 181 /* Create GOT entry. */
+#define R_AARCH64_P32_JUMP_SLOT 182 /* Create PLT entry. */
+#define R_AARCH64_P32_RELATIVE 183 /* Adjust by program base. */
+#define R_AARCH64_P32_TLS_DTPMOD 184 /* Module number, 32 bit. */
+#define R_AARCH64_P32_TLS_DTPREL 185 /* Module-relative offset, 32 bit. */
+#define R_AARCH64_P32_TLS_TPREL 186 /* TP-relative offset, 32 bit. */
+#define R_AARCH64_P32_TLSDESC 187 /* TLS Descriptor. */
+#define R_AARCH64_P32_IRELATIVE 188 /* STT_GNU_IFUNC relocation. */
+
+/* LP64 AArch64 relocs. */
+#define R_AARCH64_ABS64 257 /* Direct 64 bit. */
+#define R_AARCH64_ABS32 258 /* Direct 32 bit. */
+#define R_AARCH64_ABS16 259 /* Direct 16-bit. */
+#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */
+#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */
+#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */
+#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */
+#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */
+#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */
+#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */
+#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */
+#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */
+#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */
+#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */
+#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */
+#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */
+#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */
+#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */
+#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */
+#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */
+#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */
+#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */
+#define R_AARCH64_CALL26 283 /* Likewise for CALL. */
+#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */
+#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */
+#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */
+#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */
+#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */
+#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */
+#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */
+#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */
+#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */
+#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */
+#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */
+#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */
+#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */
+#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */
+#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */
+#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */
+#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */
+#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */
+#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */
+#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */
+#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */
+#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */
+#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */
+#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */
+#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */
+#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */
+#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */
+#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */
+#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */
+#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */
+#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */
+#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */
+#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */
+#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */
+#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */
+#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */
+#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */
+#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */
+#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */
+#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */
+#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */
+#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */
+#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */
+#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */
+#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */
+#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */
+#define R_AARCH64_TLS_DTPMOD 1028 /* Module number, 64 bit. */
+#define R_AARCH64_TLS_DTPREL 1029 /* Module-relative offset, 64 bit. */
+#define R_AARCH64_TLS_TPREL 1030 /* TP-relative offset, 64 bit. */
+#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */
+#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */
+
+/* ARM relocs. */
+
+#define R_ARM_NONE 0 /* No reloc */
+#define R_ARM_PC24 1 /* Deprecated PC relative 26
+ bit branch. */
+#define R_ARM_ABS32 2 /* Direct 32 bit */
+#define R_ARM_REL32 3 /* PC relative 32 bit */
+#define R_ARM_PC13 4
+#define R_ARM_ABS16 5 /* Direct 16 bit */
+#define R_ARM_ABS12 6 /* Direct 12 bit */
+#define R_ARM_THM_ABS5 7 /* Direct & 0x7C (LDR, STR). */
+#define R_ARM_ABS8 8 /* Direct 8 bit */
+#define R_ARM_SBREL32 9
+#define R_ARM_THM_PC22 10 /* PC relative 24 bit (Thumb32 BL). */
+#define R_ARM_THM_PC8 11 /* PC relative & 0x3FC
+ (Thumb16 LDR, ADD, ADR). */
+#define R_ARM_AMP_VCALL9 12
+#define R_ARM_SWI24 13 /* Obsolete static relocation. */
+#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */
+#define R_ARM_THM_SWI8 14 /* Reserved. */
+#define R_ARM_XPC25 15 /* Reserved. */
+#define R_ARM_THM_XPC22 16 /* Reserved. */
+#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */
+#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */
+#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */
+#define R_ARM_COPY 20 /* Copy symbol at runtime */
+#define R_ARM_GLOB_DAT 21 /* Create GOT entry */
+#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */
+#define R_ARM_RELATIVE 23 /* Adjust by program base */
+#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */
+#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */
+#define R_ARM_GOT32 26 /* 32 bit GOT entry */
+#define R_ARM_PLT32 27 /* Deprecated, 32 bit PLT address. */
+#define R_ARM_CALL 28 /* PC relative 24 bit (BL, BLX). */
+#define R_ARM_JUMP24 29 /* PC relative 24 bit
+ (B, BL<cond>). */
+#define R_ARM_THM_JUMP24 30 /* PC relative 24 bit (Thumb32 B.W). */
+#define R_ARM_BASE_ABS 31 /* Adjust by program base. */
+#define R_ARM_ALU_PCREL_7_0 32 /* Obsolete. */
+#define R_ARM_ALU_PCREL_15_8 33 /* Obsolete. */
+#define R_ARM_ALU_PCREL_23_15 34 /* Obsolete. */
+#define R_ARM_LDR_SBREL_11_0 35 /* Deprecated, prog. base relative. */
+#define R_ARM_ALU_SBREL_19_12 36 /* Deprecated, prog. base relative. */
+#define R_ARM_ALU_SBREL_27_20 37 /* Deprecated, prog. base relative. */
+#define R_ARM_TARGET1 38
+#define R_ARM_SBREL31 39 /* Program base relative. */
+#define R_ARM_V4BX 40
+#define R_ARM_TARGET2 41
+#define R_ARM_PREL31 42 /* 32 bit PC relative. */
+#define R_ARM_MOVW_ABS_NC 43 /* Direct 16-bit (MOVW). */
+#define R_ARM_MOVT_ABS 44 /* Direct high 16-bit (MOVT). */
+#define R_ARM_MOVW_PREL_NC 45 /* PC relative 16-bit (MOVW). */
+#define R_ARM_MOVT_PREL 46 /* PC relative (MOVT). */
+#define R_ARM_THM_MOVW_ABS_NC 47 /* Direct 16 bit (Thumb32 MOVW). */
+#define R_ARM_THM_MOVT_ABS 48 /* Direct high 16 bit
+ (Thumb32 MOVT). */
+#define R_ARM_THM_MOVW_PREL_NC 49 /* PC relative 16 bit
+ (Thumb32 MOVW). */
+#define R_ARM_THM_MOVT_PREL 50 /* PC relative high 16 bit
+ (Thumb32 MOVT). */
+#define R_ARM_THM_JUMP19 51 /* PC relative 20 bit
+ (Thumb32 B<cond>.W). */
+#define R_ARM_THM_JUMP6 52 /* PC relative X & 0x7E
+ (Thumb16 CBZ, CBNZ). */
+#define R_ARM_THM_ALU_PREL_11_0 53 /* PC relative 12 bit
+ (Thumb32 ADR.W). */
+#define R_ARM_THM_PC12 54 /* PC relative 12 bit
+ (Thumb32 LDR{D,SB,H,SH}). */
+#define R_ARM_ABS32_NOI 55 /* Direct 32-bit. */
+#define R_ARM_REL32_NOI 56 /* PC relative 32-bit. */
+#define R_ARM_ALU_PC_G0_NC 57 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G0 58 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G1_NC 59 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G1 60 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G2 61 /* PC relative (ADD, SUB). */
+#define R_ARM_LDR_PC_G1 62 /* PC relative (LDR,STR,LDRB,STRB). */
+#define R_ARM_LDR_PC_G2 63 /* PC relative (LDR,STR,LDRB,STRB). */
+#define R_ARM_LDRS_PC_G0 64 /* PC relative (STR{D,H},
+ LDR{D,SB,H,SH}). */
+#define R_ARM_LDRS_PC_G1 65 /* PC relative (STR{D,H},
+ LDR{D,SB,H,SH}). */
+#define R_ARM_LDRS_PC_G2 66 /* PC relative (STR{D,H},
+ LDR{D,SB,H,SH}). */
+#define R_ARM_LDC_PC_G0 67 /* PC relative (LDC, STC). */
+#define R_ARM_LDC_PC_G1 68 /* PC relative (LDC, STC). */
+#define R_ARM_LDC_PC_G2 69 /* PC relative (LDC, STC). */
+#define R_ARM_ALU_SB_G0_NC 70 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G0 71 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G1_NC 72 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G1 73 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G2 74 /* Program base relative (ADD,SUB). */
+#define R_ARM_LDR_SB_G0 75 /* Program base relative (LDR,
+ STR, LDRB, STRB). */
+#define R_ARM_LDR_SB_G1 76 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDR_SB_G2 77 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDRS_SB_G0 78 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDRS_SB_G1 79 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDRS_SB_G2 80 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDC_SB_G0 81 /* Program base relative (LDC,STC). */
+#define R_ARM_LDC_SB_G1 82 /* Program base relative (LDC,STC). */
+#define R_ARM_LDC_SB_G2 83 /* Program base relative (LDC,STC). */
+#define R_ARM_MOVW_BREL_NC 84 /* Program base relative 16
+ bit (MOVW). */
+#define R_ARM_MOVT_BREL 85 /* Program base relative high
+ 16 bit (MOVT). */
+#define R_ARM_MOVW_BREL 86 /* Program base relative 16
+ bit (MOVW). */
+#define R_ARM_THM_MOVW_BREL_NC 87 /* Program base relative 16
+ bit (Thumb32 MOVW). */
+#define R_ARM_THM_MOVT_BREL 88 /* Program base relative high
+ 16 bit (Thumb32 MOVT). */
+#define R_ARM_THM_MOVW_BREL 89 /* Program base relative 16
+ bit (Thumb32 MOVW). */
+#define R_ARM_TLS_GOTDESC 90
+#define R_ARM_TLS_CALL 91
+#define R_ARM_TLS_DESCSEQ 92 /* TLS relaxation. */
+#define R_ARM_THM_TLS_CALL 93
+#define R_ARM_PLT32_ABS 94
+#define R_ARM_GOT_ABS 95 /* GOT entry. */
+#define R_ARM_GOT_PREL 96 /* PC relative GOT entry. */
+#define R_ARM_GOT_BREL12 97 /* GOT entry relative to GOT
+ origin (LDR). */
+#define R_ARM_GOTOFF12 98 /* 12 bit, GOT entry relative
+ to GOT origin (LDR, STR). */
+#define R_ARM_GOTRELAX 99
+#define R_ARM_GNU_VTENTRY 100
+#define R_ARM_GNU_VTINHERIT 101
+#define R_ARM_THM_PC11 102 /* PC relative & 0xFFE (Thumb16 B). */
+#define R_ARM_THM_PC9 103 /* PC relative & 0x1FE
+ (Thumb16 B/B<cond>). */
+#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic
+ thread local data */
+#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic
+ thread local data */
+#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS
+ block */
+#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of
+ static TLS block offset */
+#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static
+ TLS block */
+#define R_ARM_TLS_LDO12 109 /* 12 bit relative to TLS
+ block (LDR, STR). */
+#define R_ARM_TLS_LE12 110 /* 12 bit relative to static
+ TLS block (LDR, STR). */
+#define R_ARM_TLS_IE12GP 111 /* 12 bit GOT entry relative
+ to GOT origin (LDR). */
+#define R_ARM_ME_TOO 128 /* Obsolete. */
+#define R_ARM_THM_TLS_DESCSEQ 129
+#define R_ARM_THM_TLS_DESCSEQ16 129
+#define R_ARM_THM_TLS_DESCSEQ32 130
+#define R_ARM_THM_GOT_BREL12 131 /* GOT entry relative to GOT
+ origin, 12 bit (Thumb32 LDR). */
+#define R_ARM_IRELATIVE 160
+#define R_ARM_RXPC25 249
+#define R_ARM_RSBREL32 250
+#define R_ARM_THM_RPC22 251
+#define R_ARM_RREL32 252
+#define R_ARM_RABS22 253
+#define R_ARM_RPC24 254
+#define R_ARM_RBASE 255
+/* Keep this the last entry. */
+#define R_ARM_NUM 256
+
+/* IA-64 specific declarations. */
+
+/* Processor specific flags for the Ehdr e_flags field. */
+#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */
+#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */
+#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */
+
+/* Processor specific values for the Phdr p_type field. */
+#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */
+#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */
+#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12)
+#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13)
+#define PT_IA_64_HP_STACK (PT_LOOS + 0x14)
+
+/* Processor specific flags for the Phdr p_flags field. */
+#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */
+
+/* Processor specific values for the Shdr sh_type field. */
+#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */
+#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */
+
+/* Processor specific flags for the Shdr sh_flags field. */
+#define SHF_IA_64_SHORT 0x10000000 /* section near gp */
+#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */
+
+/* Processor specific values for the Dyn d_tag field. */
+#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0)
+#define DT_IA_64_NUM 1
+
+/* IA-64 relocations. */
+#define R_IA64_NONE 0x00 /* none */
+#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */
+#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */
+#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */
+#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */
+#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */
+#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */
+#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */
+#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */
+#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */
+#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */
+#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */
+#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */
+#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */
+#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */
+#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */
+#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */
+#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */
+#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */
+#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */
+#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */
+#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */
+#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */
+#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */
+#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */
+#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */
+#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */
+#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */
+#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */
+#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */
+#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */
+#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */
+#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */
+#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */
+#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */
+#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */
+#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */
+#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */
+#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */
+#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */
+#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */
+#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */
+#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */
+#define R_IA64_REL32MSB 0x6c /* data 4 + REL */
+#define R_IA64_REL32LSB 0x6d /* data 4 + REL */
+#define R_IA64_REL64MSB 0x6e /* data 8 + REL */
+#define R_IA64_REL64LSB 0x6f /* data 8 + REL */
+#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */
+#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */
+#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */
+#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */
+#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */
+#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */
+#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */
+#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */
+#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */
+#define R_IA64_COPY 0x84 /* copy relocation */
+#define R_IA64_SUB 0x85 /* Addend and symbol difference */
+#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */
+#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */
+#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */
+#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */
+#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */
+#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */
+#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */
+#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */
+#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */
+#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */
+#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */
+#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */
+#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */
+#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */
+#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */
+#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */
+
+/* SH specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field. */
+#define EF_SH_MACH_MASK 0x1f
+#define EF_SH_UNKNOWN 0x0
+#define EF_SH1 0x1
+#define EF_SH2 0x2
+#define EF_SH3 0x3
+#define EF_SH_DSP 0x4
+#define EF_SH3_DSP 0x5
+#define EF_SH4AL_DSP 0x6
+#define EF_SH3E 0x8
+#define EF_SH4 0x9
+#define EF_SH2E 0xb
+#define EF_SH4A 0xc
+#define EF_SH2A 0xd
+#define EF_SH4_NOFPU 0x10
+#define EF_SH4A_NOFPU 0x11
+#define EF_SH4_NOMMU_NOFPU 0x12
+#define EF_SH2A_NOFPU 0x13
+#define EF_SH3_NOMMU 0x14
+#define EF_SH2A_SH4_NOFPU 0x15
+#define EF_SH2A_SH3_NOFPU 0x16
+#define EF_SH2A_SH4 0x17
+#define EF_SH2A_SH3E 0x18
+
+/* SH relocs. */
+#define R_SH_NONE 0
+#define R_SH_DIR32 1
+#define R_SH_REL32 2
+#define R_SH_DIR8WPN 3
+#define R_SH_IND12W 4
+#define R_SH_DIR8WPL 5
+#define R_SH_DIR8WPZ 6
+#define R_SH_DIR8BP 7
+#define R_SH_DIR8W 8
+#define R_SH_DIR8L 9
+#define R_SH_SWITCH16 25
+#define R_SH_SWITCH32 26
+#define R_SH_USES 27
+#define R_SH_COUNT 28
+#define R_SH_ALIGN 29
+#define R_SH_CODE 30
+#define R_SH_DATA 31
+#define R_SH_LABEL 32
+#define R_SH_SWITCH8 33
+#define R_SH_GNU_VTINHERIT 34
+#define R_SH_GNU_VTENTRY 35
+#define R_SH_TLS_GD_32 144
+#define R_SH_TLS_LD_32 145
+#define R_SH_TLS_LDO_32 146
+#define R_SH_TLS_IE_32 147
+#define R_SH_TLS_LE_32 148
+#define R_SH_TLS_DTPMOD32 149
+#define R_SH_TLS_DTPOFF32 150
+#define R_SH_TLS_TPOFF32 151
+#define R_SH_GOT32 160
+#define R_SH_PLT32 161
+#define R_SH_COPY 162
+#define R_SH_GLOB_DAT 163
+#define R_SH_JMP_SLOT 164
+#define R_SH_RELATIVE 165
+#define R_SH_GOTOFF 166
+#define R_SH_GOTPC 167
+/* Keep this the last entry. */
+#define R_SH_NUM 256
+
+/* S/390 specific definitions. */
+
+/* Valid values for the e_flags field. */
+
+#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */
+
+/* Additional s390 relocs */
+
+#define R_390_NONE 0 /* No reloc. */
+#define R_390_8 1 /* Direct 8 bit. */
+#define R_390_12 2 /* Direct 12 bit. */
+#define R_390_16 3 /* Direct 16 bit. */
+#define R_390_32 4 /* Direct 32 bit. */
+#define R_390_PC32 5 /* PC relative 32 bit. */
+#define R_390_GOT12 6 /* 12 bit GOT offset. */
+#define R_390_GOT32 7 /* 32 bit GOT offset. */
+#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */
+#define R_390_COPY 9 /* Copy symbol at runtime. */
+#define R_390_GLOB_DAT 10 /* Create GOT entry. */
+#define R_390_JMP_SLOT 11 /* Create PLT entry. */
+#define R_390_RELATIVE 12 /* Adjust by program base. */
+#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */
+#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */
+#define R_390_GOT16 15 /* 16 bit GOT offset. */
+#define R_390_PC16 16 /* PC relative 16 bit. */
+#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */
+#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */
+#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */
+#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */
+#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */
+#define R_390_64 22 /* Direct 64 bit. */
+#define R_390_PC64 23 /* PC relative 64 bit. */
+#define R_390_GOT64 24 /* 64 bit GOT offset. */
+#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */
+#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */
+#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */
+#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */
+#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */
+#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */
+#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */
+#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */
+#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */
+#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */
+#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */
+#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */
+#define R_390_TLS_GDCALL 38 /* Tag for function call in general
+ dynamic TLS code. */
+#define R_390_TLS_LDCALL 39 /* Tag for function call in local
+ dynamic TLS code. */
+#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic
+ thread local data. */
+#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic
+ thread local data. */
+#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS
+ block offset. */
+#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS
+ block offset. */
+#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS
+ block offset. */
+#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic
+ thread local data in LE code. */
+#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic
+ thread local data in LE code. */
+#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for
+ negated static TLS block offset. */
+#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for
+ negated static TLS block offset. */
+#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for
+ negated static TLS block offset. */
+#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to
+ static TLS block. */
+#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to
+ static TLS block. */
+#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS
+ block. */
+#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS
+ block. */
+#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */
+#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */
+#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS
+ block. */
+#define R_390_20 57 /* Direct 20 bit. */
+#define R_390_GOT20 58 /* 20 bit GOT offset. */
+#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */
+#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS
+ block offset. */
+#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */
+/* Keep this the last entry. */
+#define R_390_NUM 62
+
+
+/* CRIS relocations. */
+#define R_CRIS_NONE 0
+#define R_CRIS_8 1
+#define R_CRIS_16 2
+#define R_CRIS_32 3
+#define R_CRIS_8_PCREL 4
+#define R_CRIS_16_PCREL 5
+#define R_CRIS_32_PCREL 6
+#define R_CRIS_GNU_VTINHERIT 7
+#define R_CRIS_GNU_VTENTRY 8
+#define R_CRIS_COPY 9
+#define R_CRIS_GLOB_DAT 10
+#define R_CRIS_JUMP_SLOT 11
+#define R_CRIS_RELATIVE 12
+#define R_CRIS_16_GOT 13
+#define R_CRIS_32_GOT 14
+#define R_CRIS_16_GOTPLT 15
+#define R_CRIS_32_GOTPLT 16
+#define R_CRIS_32_GOTREL 17
+#define R_CRIS_32_PLT_GOTREL 18
+#define R_CRIS_32_PLT_PCREL 19
+
+#define R_CRIS_NUM 20
+
+
+/* AMD x86-64 relocations. */
+#define R_X86_64_NONE 0 /* No reloc */
+#define R_X86_64_64 1 /* Direct 64 bit */
+#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
+#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
+#define R_X86_64_PLT32 4 /* 32 bit PLT address */
+#define R_X86_64_COPY 5 /* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
+#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
+#define R_X86_64_RELATIVE 8 /* Adjust by program base */
+#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative
+ offset to GOT */
+#define R_X86_64_32 10 /* Direct 32 bit zero extended */
+#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
+#define R_X86_64_16 12 /* Direct 16 bit zero extended */
+#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
+#define R_X86_64_8 14 /* Direct 8 bit sign extended */
+#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
+#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
+#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */
+#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */
+#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset
+ to two GOT entries for GD symbol */
+#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset
+ to two GOT entries for LD symbol */
+#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
+#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset
+ to GOT entry for IE symbol */
+#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */
+#define R_X86_64_PC64 24 /* PC relative 64 bit */
+#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */
+#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative
+ offset to GOT */
+#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */
+#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset
+ to GOT entry */
+#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */
+#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */
+#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset
+ to PLT entry */
+#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */
+#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */
+#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */
+#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS
+ descriptor. */
+#define R_X86_64_TLSDESC 36 /* TLS descriptor. */
+#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */
+#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */
+ /* 39 Reserved was R_X86_64_PC32_BND */
+ /* 40 Reserved was R_X86_64_PLT32_BND */
+#define R_X86_64_GOTPCRELX 41 /* Load from 32 bit signed pc relative
+ offset to GOT entry without REX
+ prefix, relaxable. */
+#define R_X86_64_REX_GOTPCRELX 42 /* Load from 32 bit signed pc relative
+ offset to GOT entry with REX prefix,
+ relaxable. */
+#define R_X86_64_NUM 43
+
+
+/* AM33 relocations. */
+#define R_MN10300_NONE 0 /* No reloc. */
+#define R_MN10300_32 1 /* Direct 32 bit. */
+#define R_MN10300_16 2 /* Direct 16 bit. */
+#define R_MN10300_8 3 /* Direct 8 bit. */
+#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */
+#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */
+#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */
+#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */
+#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */
+#define R_MN10300_24 9 /* Direct 24 bit. */
+#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */
+#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */
+#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */
+#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */
+#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */
+#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */
+#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */
+#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */
+#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */
+#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */
+#define R_MN10300_COPY 20 /* Copy symbol at runtime. */
+#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */
+#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */
+#define R_MN10300_RELATIVE 23 /* Adjust by program base. */
+#define R_MN10300_TLS_GD 24 /* 32-bit offset for global dynamic. */
+#define R_MN10300_TLS_LD 25 /* 32-bit offset for local dynamic. */
+#define R_MN10300_TLS_LDO 26 /* Module-relative offset. */
+#define R_MN10300_TLS_GOTIE 27 /* GOT offset for static TLS block
+ offset. */
+#define R_MN10300_TLS_IE 28 /* GOT address for static TLS block
+ offset. */
+#define R_MN10300_TLS_LE 29 /* Offset relative to static TLS
+ block. */
+#define R_MN10300_TLS_DTPMOD 30 /* ID of module containing symbol. */
+#define R_MN10300_TLS_DTPOFF 31 /* Offset in module TLS block. */
+#define R_MN10300_TLS_TPOFF 32 /* Offset in static TLS block. */
+#define R_MN10300_SYM_DIFF 33 /* Adjustment for next reloc as needed
+ by linker relaxation. */
+#define R_MN10300_ALIGN 34 /* Alignment requirement for linker
+ relaxation. */
+#define R_MN10300_NUM 35
+
+
+/* M32R relocs. */
+#define R_M32R_NONE 0 /* No reloc. */
+#define R_M32R_16 1 /* Direct 16 bit. */
+#define R_M32R_32 2 /* Direct 32 bit. */
+#define R_M32R_24 3 /* Direct 24 bit. */
+#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */
+#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */
+#define R_M32R_LO16 9 /* Low 16 bit. */
+#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */
+#define R_M32R_GNU_VTINHERIT 11
+#define R_M32R_GNU_VTENTRY 12
+/* M32R relocs use SHT_RELA. */
+#define R_M32R_16_RELA 33 /* Direct 16 bit. */
+#define R_M32R_32_RELA 34 /* Direct 32 bit. */
+#define R_M32R_24_RELA 35 /* Direct 24 bit. */
+#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */
+#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */
+#define R_M32R_LO16_RELA 41 /* Low 16 bit */
+#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */
+#define R_M32R_RELA_GNU_VTINHERIT 43
+#define R_M32R_RELA_GNU_VTENTRY 44
+#define R_M32R_REL32 45 /* PC relative 32 bit. */
+
+#define R_M32R_GOT24 48 /* 24 bit GOT entry */
+#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */
+#define R_M32R_COPY 50 /* Copy symbol at runtime */
+#define R_M32R_GLOB_DAT 51 /* Create GOT entry */
+#define R_M32R_JMP_SLOT 52 /* Create PLT entry */
+#define R_M32R_RELATIVE 53 /* Adjust by program base */
+#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */
+#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */
+#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned
+ low */
+#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed
+ low */
+#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */
+#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to
+ GOT with unsigned low */
+#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to
+ GOT with signed low */
+#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to
+ GOT */
+#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT
+ with unsigned low */
+#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT
+ with signed low */
+#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */
+#define R_M32R_NUM 256 /* Keep this the last entry. */
+
+/* MicroBlaze relocations */
+#define R_MICROBLAZE_NONE 0 /* No reloc. */
+#define R_MICROBLAZE_32 1 /* Direct 32 bit. */
+#define R_MICROBLAZE_32_PCREL 2 /* PC relative 32 bit. */
+#define R_MICROBLAZE_64_PCREL 3 /* PC relative 64 bit. */
+#define R_MICROBLAZE_32_PCREL_LO 4 /* Low 16 bits of PCREL32. */
+#define R_MICROBLAZE_64 5 /* Direct 64 bit. */
+#define R_MICROBLAZE_32_LO 6 /* Low 16 bit. */
+#define R_MICROBLAZE_SRO32 7 /* Read-only small data area. */
+#define R_MICROBLAZE_SRW32 8 /* Read-write small data area. */
+#define R_MICROBLAZE_64_NONE 9 /* No reloc. */
+#define R_MICROBLAZE_32_SYM_OP_SYM 10 /* Symbol Op Symbol relocation. */
+#define R_MICROBLAZE_GNU_VTINHERIT 11 /* GNU C++ vtable hierarchy. */
+#define R_MICROBLAZE_GNU_VTENTRY 12 /* GNU C++ vtable member usage. */
+#define R_MICROBLAZE_GOTPC_64 13 /* PC-relative GOT offset. */
+#define R_MICROBLAZE_GOT_64 14 /* GOT entry offset. */
+#define R_MICROBLAZE_PLT_64 15 /* PLT offset (PC-relative). */
+#define R_MICROBLAZE_REL 16 /* Adjust by program base. */
+#define R_MICROBLAZE_JUMP_SLOT 17 /* Create PLT entry. */
+#define R_MICROBLAZE_GLOB_DAT 18 /* Create GOT entry. */
+#define R_MICROBLAZE_GOTOFF_64 19 /* 64 bit offset to GOT. */
+#define R_MICROBLAZE_GOTOFF_32 20 /* 32 bit offset to GOT. */
+#define R_MICROBLAZE_COPY 21 /* Runtime copy. */
+#define R_MICROBLAZE_TLS 22 /* TLS Reloc. */
+#define R_MICROBLAZE_TLSGD 23 /* TLS General Dynamic. */
+#define R_MICROBLAZE_TLSLD 24 /* TLS Local Dynamic. */
+#define R_MICROBLAZE_TLSDTPMOD32 25 /* TLS Module ID. */
+#define R_MICROBLAZE_TLSDTPREL32 26 /* TLS Offset Within TLS Block. */
+#define R_MICROBLAZE_TLSDTPREL64 27 /* TLS Offset Within TLS Block. */
+#define R_MICROBLAZE_TLSGOTTPREL32 28 /* TLS Offset From Thread Pointer. */
+#define R_MICROBLAZE_TLSTPREL32 29 /* TLS Offset From Thread Pointer. */
+
+/* Legal values for d_tag (dynamic entry type). */
+#define DT_NIOS2_GP 0x70000002 /* Address of _gp. */
+
+/* Nios II relocations. */
+#define R_NIOS2_NONE 0 /* No reloc. */
+#define R_NIOS2_S16 1 /* Direct signed 16 bit. */
+#define R_NIOS2_U16 2 /* Direct unsigned 16 bit. */
+#define R_NIOS2_PCREL16 3 /* PC relative 16 bit. */
+#define R_NIOS2_CALL26 4 /* Direct call. */
+#define R_NIOS2_IMM5 5 /* 5 bit constant expression. */
+#define R_NIOS2_CACHE_OPX 6 /* 5 bit expression, shift 22. */
+#define R_NIOS2_IMM6 7 /* 6 bit constant expression. */
+#define R_NIOS2_IMM8 8 /* 8 bit constant expression. */
+#define R_NIOS2_HI16 9 /* High 16 bit. */
+#define R_NIOS2_LO16 10 /* Low 16 bit. */
+#define R_NIOS2_HIADJ16 11 /* High 16 bit, adjusted. */
+#define R_NIOS2_BFD_RELOC_32 12 /* 32 bit symbol value + addend. */
+#define R_NIOS2_BFD_RELOC_16 13 /* 16 bit symbol value + addend. */
+#define R_NIOS2_BFD_RELOC_8 14 /* 8 bit symbol value + addend. */
+#define R_NIOS2_GPREL 15 /* 16 bit GP pointer offset. */
+#define R_NIOS2_GNU_VTINHERIT 16 /* GNU C++ vtable hierarchy. */
+#define R_NIOS2_GNU_VTENTRY 17 /* GNU C++ vtable member usage. */
+#define R_NIOS2_UJMP 18 /* Unconditional branch. */
+#define R_NIOS2_CJMP 19 /* Conditional branch. */
+#define R_NIOS2_CALLR 20 /* Indirect call through register. */
+#define R_NIOS2_ALIGN 21 /* Alignment requirement for
+ linker relaxation. */
+#define R_NIOS2_GOT16 22 /* 16 bit GOT entry. */
+#define R_NIOS2_CALL16 23 /* 16 bit GOT entry for function. */
+#define R_NIOS2_GOTOFF_LO 24 /* %lo of offset to GOT pointer. */
+#define R_NIOS2_GOTOFF_HA 25 /* %hiadj of offset to GOT pointer. */
+#define R_NIOS2_PCREL_LO 26 /* %lo of PC relative offset. */
+#define R_NIOS2_PCREL_HA 27 /* %hiadj of PC relative offset. */
+#define R_NIOS2_TLS_GD16 28 /* 16 bit GOT offset for TLS GD. */
+#define R_NIOS2_TLS_LDM16 29 /* 16 bit GOT offset for TLS LDM. */
+#define R_NIOS2_TLS_LDO16 30 /* 16 bit module relative offset. */
+#define R_NIOS2_TLS_IE16 31 /* 16 bit GOT offset for TLS IE. */
+#define R_NIOS2_TLS_LE16 32 /* 16 bit LE TP-relative offset. */
+#define R_NIOS2_TLS_DTPMOD 33 /* Module number. */
+#define R_NIOS2_TLS_DTPREL 34 /* Module-relative offset. */
+#define R_NIOS2_TLS_TPREL 35 /* TP-relative offset. */
+#define R_NIOS2_COPY 36 /* Copy symbol at runtime. */
+#define R_NIOS2_GLOB_DAT 37 /* Create GOT entry. */
+#define R_NIOS2_JUMP_SLOT 38 /* Create PLT entry. */
+#define R_NIOS2_RELATIVE 39 /* Adjust by program base. */
+#define R_NIOS2_GOTOFF 40 /* 16 bit offset to GOT pointer. */
+#define R_NIOS2_CALL26_NOAT 41 /* Direct call in .noat section. */
+#define R_NIOS2_GOT_LO 42 /* %lo() of GOT entry. */
+#define R_NIOS2_GOT_HA 43 /* %hiadj() of GOT entry. */
+#define R_NIOS2_CALL_LO 44 /* %lo() of function GOT entry. */
+#define R_NIOS2_CALL_HA 45 /* %hiadj() of function GOT entry. */
+
+/* TILEPro relocations. */
+#define R_TILEPRO_NONE 0 /* No reloc */
+#define R_TILEPRO_32 1 /* Direct 32 bit */
+#define R_TILEPRO_16 2 /* Direct 16 bit */
+#define R_TILEPRO_8 3 /* Direct 8 bit */
+#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */
+#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */
+#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */
+#define R_TILEPRO_LO16 7 /* Low 16 bit */
+#define R_TILEPRO_HI16 8 /* High 16 bit */
+#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */
+#define R_TILEPRO_COPY 10 /* Copy relocation */
+#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */
+#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */
+#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */
+#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */
+#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */
+#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */
+#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */
+#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */
+#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */
+#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */
+#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */
+#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */
+#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */
+#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */
+#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */
+#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */
+#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */
+#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */
+#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */
+#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */
+#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */
+#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */
+#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */
+#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */
+#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */
+#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */
+#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */
+#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */
+#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */
+#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */
+#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */
+#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */
+#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */
+#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */
+#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */
+#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */
+#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */
+#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */
+/* Relocs 56-59 are currently not defined. */
+#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */
+#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */
+#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */
+#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */
+#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */
+#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */
+#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */
+#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */
+
+#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */
+#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */
+
+#define R_TILEPRO_NUM 130
+
+
+/* TILE-Gx relocations. */
+#define R_TILEGX_NONE 0 /* No reloc */
+#define R_TILEGX_64 1 /* Direct 64 bit */
+#define R_TILEGX_32 2 /* Direct 32 bit */
+#define R_TILEGX_16 3 /* Direct 16 bit */
+#define R_TILEGX_8 4 /* Direct 8 bit */
+#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */
+#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */
+#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */
+#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */
+#define R_TILEGX_HW0 9 /* hword 0 16-bit */
+#define R_TILEGX_HW1 10 /* hword 1 16-bit */
+#define R_TILEGX_HW2 11 /* hword 2 16-bit */
+#define R_TILEGX_HW3 12 /* hword 3 16-bit */
+#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */
+#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */
+#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */
+#define R_TILEGX_COPY 16 /* Copy relocation */
+#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */
+#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */
+#define R_TILEGX_RELATIVE 19 /* Adjust by program base */
+#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */
+#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */
+#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */
+#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */
+#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */
+#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */
+#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */
+#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */
+#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */
+#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */
+#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */
+#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */
+#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */
+#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */
+#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */
+#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */
+#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */
+#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */
+#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */
+#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */
+#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */
+#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */
+#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */
+#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */
+#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */
+#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */
+#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */
+#define R_TILEGX_IMM16_X0_HW0_PLT_PCREL 66 /* X0 pipe PC-rel PLT hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_PLT_PCREL 67 /* X1 pipe PC-rel PLT hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_PLT_PCREL 68 /* X0 pipe PC-rel PLT hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_PLT_PCREL 69 /* X1 pipe PC-rel PLT hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_PLT_PCREL 70 /* X0 pipe PC-rel PLT hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_PLT_PCREL 71 /* X1 pipe PC-rel PLT hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */
+#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */
+#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */
+#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */
+#define R_TILEGX_IMM16_X0_HW3_PLT_PCREL 76 /* X0 pipe PC-rel PLT hword 3 */
+#define R_TILEGX_IMM16_X1_HW3_PLT_PCREL 77 /* X1 pipe PC-rel PLT hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */
+#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */
+/* Relocs 90-91 are currently not defined. */
+#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */
+#define R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL 94 /* X0 pipe PC-rel PLT last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL 95 /* X1 pipe PC-rel PLT last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL 96 /* X0 pipe PC-rel PLT last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL 97 /* X1 pipe PC-rel PLT last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL 98 /* X0 pipe PC-rel PLT last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL 99 /* X1 pipe PC-rel PLT last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */
+/* Relocs 104-105 are currently not defined. */
+#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */
+#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */
+#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */
+#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */
+#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */
+#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */
+#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */
+#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */
+#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */
+#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */
+
+#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */
+#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */
+
+#define R_TILEGX_NUM 130
+
+/* BPF specific declarations. */
+
+#define R_BPF_NONE 0 /* No reloc */
+#define R_BPF_MAP_FD 1 /* Map fd to pointer */
+
+/* Imagination Meta specific relocations. */
+
+#define R_METAG_HIADDR16 0
+#define R_METAG_LOADDR16 1
+#define R_METAG_ADDR32 2 /* 32bit absolute address */
+#define R_METAG_NONE 3 /* No reloc */
+#define R_METAG_RELBRANCH 4
+#define R_METAG_GETSETOFF 5
+
+/* Backward compatability */
+#define R_METAG_REG32OP1 6
+#define R_METAG_REG32OP2 7
+#define R_METAG_REG32OP3 8
+#define R_METAG_REG16OP1 9
+#define R_METAG_REG16OP2 10
+#define R_METAG_REG16OP3 11
+#define R_METAG_REG32OP4 12
+
+#define R_METAG_HIOG 13
+#define R_METAG_LOOG 14
+
+#define R_METAG_REL8 15
+#define R_METAG_REL16 16
+
+/* GNU */
+#define R_METAG_GNU_VTINHERIT 30
+#define R_METAG_GNU_VTENTRY 31
+
+/* PIC relocations */
+#define R_METAG_HI16_GOTOFF 32
+#define R_METAG_LO16_GOTOFF 33
+#define R_METAG_GETSET_GOTOFF 34
+#define R_METAG_GETSET_GOT 35
+#define R_METAG_HI16_GOTPC 36
+#define R_METAG_LO16_GOTPC 37
+#define R_METAG_HI16_PLT 38
+#define R_METAG_LO16_PLT 39
+#define R_METAG_RELBRANCH_PLT 40
+#define R_METAG_GOTOFF 41
+#define R_METAG_PLT 42
+#define R_METAG_COPY 43
+#define R_METAG_JMP_SLOT 44
+#define R_METAG_RELATIVE 45
+#define R_METAG_GLOB_DAT 46
+
+/* TLS relocations */
+#define R_METAG_TLS_GD 47
+#define R_METAG_TLS_LDM 48
+#define R_METAG_TLS_LDO_HI16 49
+#define R_METAG_TLS_LDO_LO16 50
+#define R_METAG_TLS_LDO 51
+#define R_METAG_TLS_IE 52
+#define R_METAG_TLS_IENONPIC 53
+#define R_METAG_TLS_IENONPIC_HI16 54
+#define R_METAG_TLS_IENONPIC_LO16 55
+#define R_METAG_TLS_TPOFF 56
+#define R_METAG_TLS_DTPMOD 57
+#define R_METAG_TLS_DTPOFF 58
+#define R_METAG_TLS_LE 59
+#define R_METAG_TLS_LE_HI16 60
+#define R_METAG_TLS_LE_LO16 61
+
+__END_DECLS
+
+#endif /* elf.h */
diff --git a/REORG.TODO/elf/enbl-secure.c b/REORG.TODO/elf/enbl-secure.c
new file mode 100644
index 0000000000..c0723774d9
--- /dev/null
+++ b/REORG.TODO/elf/enbl-secure.c
@@ -0,0 +1,36 @@
+/* Define and initialize the `__libc_enable_secure' flag. Generic version.
+ Copyright (C) 1996-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is used in the static libc. For the shared library,
+ dl-sysdep.c defines and initializes __libc_enable_secure. */
+
+#include <unistd.h>
+#include <libc-internal.h>
+
+/* If nonzero __libc_enable_secure is already set. */
+int __libc_enable_secure_decided;
+/* Safest assumption, if somehow the initializer isn't run. */
+int __libc_enable_secure = 1;
+
+void
+__libc_init_secure (void)
+{
+ if (__libc_enable_secure_decided == 0)
+ __libc_enable_secure = (__geteuid () != __getuid ()
+ || __getegid () != __getgid ());
+}
diff --git a/REORG.TODO/elf/failobj.c b/REORG.TODO/elf/failobj.c
new file mode 100644
index 0000000000..500606382e
--- /dev/null
+++ b/REORG.TODO/elf/failobj.c
@@ -0,0 +1,10 @@
+/* This function is supposed to not exist. */
+extern int xyzzy (int);
+
+extern int foo (int);
+
+int
+foo (int a)
+{
+ return xyzzy (a);
+}
diff --git a/REORG.TODO/elf/filter.c b/REORG.TODO/elf/filter.c
new file mode 100644
index 0000000000..46aa15ba16
--- /dev/null
+++ b/REORG.TODO/elf/filter.c
@@ -0,0 +1,19 @@
+#include <mcheck.h>
+#include <stdio.h>
+#include <string.h>
+
+extern const char *foo (void);
+
+int
+main (void)
+{
+ const char *s;
+
+ mtrace ();
+
+ s = foo ();
+
+ printf ("called `foo' from `%s'\n", s);
+
+ return strcmp (s, "filtmod2.c");
+}
diff --git a/REORG.TODO/elf/filtmod1.c b/REORG.TODO/elf/filtmod1.c
new file mode 100644
index 0000000000..1d9b19481d
--- /dev/null
+++ b/REORG.TODO/elf/filtmod1.c
@@ -0,0 +1,7 @@
+extern const char *foo (void);
+
+const char *
+foo (void)
+{
+ return __FILE__;
+}
diff --git a/REORG.TODO/elf/filtmod2.c b/REORG.TODO/elf/filtmod2.c
new file mode 100644
index 0000000000..1d9b19481d
--- /dev/null
+++ b/REORG.TODO/elf/filtmod2.c
@@ -0,0 +1,7 @@
+extern const char *foo (void);
+
+const char *
+foo (void)
+{
+ return __FILE__;
+}
diff --git a/REORG.TODO/elf/firstobj.c b/REORG.TODO/elf/firstobj.c
new file mode 100644
index 0000000000..2e6033eab6
--- /dev/null
+++ b/REORG.TODO/elf/firstobj.c
@@ -0,0 +1,10 @@
+#include <errno.h>
+
+extern int foo (void);
+
+int
+foo (void)
+{
+ errno = 0;
+ return 0;
+}
diff --git a/REORG.TODO/elf/gen-trusted-dirs.awk b/REORG.TODO/elf/gen-trusted-dirs.awk
new file mode 100644
index 0000000000..59f10a4856
--- /dev/null
+++ b/REORG.TODO/elf/gen-trusted-dirs.awk
@@ -0,0 +1,37 @@
+BEGIN {
+ FS = " ";
+}
+
+{
+ for (i = 1; i <= NF; ++i) {
+ s[cnt++] = $i"/";
+ }
+}
+
+END {
+ printf ("#define SYSTEM_DIRS \\\n");
+
+ printf (" \"%s\"", s[0]);
+
+ for (i = 1; i < cnt; ++i) {
+ printf (" \"\\0\" \"%s\"", s[i]);
+ }
+
+ printf ("\n\n");
+
+ printf ("#define SYSTEM_DIRS_LEN \\\n");
+
+ printf (" %d", length (s[0]));
+ m = length (s[0]);
+
+ for (i = 1; i < cnt; ++i) {
+ printf (", %d", length(s[i]));
+ if (length(s[i]) > m) {
+ m = length(s[i]);
+ }
+ }
+
+ printf ("\n\n");
+
+ printf ("#define SYSTEM_DIRS_MAX_LEN\t%d\n", m);
+}
diff --git a/REORG.TODO/elf/genrtldtbl.awk b/REORG.TODO/elf/genrtldtbl.awk
new file mode 100644
index 0000000000..0e2a374901
--- /dev/null
+++ b/REORG.TODO/elf/genrtldtbl.awk
@@ -0,0 +1,29 @@
+#!/usr/bin/awk
+BEGIN {
+ FS=":";
+ count=0;
+}
+{
+ for (i = 1; i <= NF; ++i) {
+ gsub (/\/*$/, "", $i);
+ dir[count++] = $i;
+ }
+}
+END {
+ for (i = 0; i < count; ++i) {
+ printf ("static struct r_search_path_elem rtld_search_dir%d =\n", i+1);
+ printf (" { \"%s/\", %d, unknown, 0, nonexisting, NULL, NULL, ",
+ dir[i], length (dir[i]) + 1);
+ if (i== 0)
+ printf ("NULL };\n");
+ else
+ printf ("&rtld_search_dir%d };\n", i);
+ }
+ printf ("\nstatic struct r_search_path_elem *rtld_search_dirs[] =\n{\n");
+ for (i = 0; i < count; ++i) {
+ printf (" &rtld_search_dir%d,\n", i + 1);
+ }
+ printf (" NULL\n};\n\n");
+ printf ("static struct r_search_path_elem *all_dirs = &rtld_search_dir%d;\n",
+ count);
+}
diff --git a/REORG.TODO/elf/get-dynamic-info.h b/REORG.TODO/elf/get-dynamic-info.h
new file mode 100644
index 0000000000..7525c3a5b2
--- /dev/null
+++ b/REORG.TODO/elf/get-dynamic-info.h
@@ -0,0 +1,184 @@
+/* Read the dynamic section at DYN and fill in INFO with indices DT_*.
+ Copyright (C) 2012-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is included multiple times and therefore lacks a header
+ file inclusion guard. */
+
+#include <assert.h>
+#include <libc-diag.h>
+
+#ifndef RESOLVE_MAP
+static
+#else
+auto
+#endif
+inline void __attribute__ ((unused, always_inline))
+elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
+{
+ ElfW(Dyn) *dyn = l->l_ld;
+ ElfW(Dyn) **info;
+#if __ELF_NATIVE_CLASS == 32
+ typedef Elf32_Word d_tag_utype;
+#elif __ELF_NATIVE_CLASS == 64
+ typedef Elf64_Xword d_tag_utype;
+#endif
+
+#ifndef RTLD_BOOTSTRAP
+ if (dyn == NULL)
+ return;
+#endif
+
+ info = l->l_info;
+
+ while (dyn->d_tag != DT_NULL)
+ {
+ if ((d_tag_utype) dyn->d_tag < DT_NUM)
+ info[dyn->d_tag] = dyn;
+ else if (dyn->d_tag >= DT_LOPROC &&
+ dyn->d_tag < DT_LOPROC + DT_THISPROCNUM)
+ {
+ /* This does not violate the array bounds of l->l_info, but
+ gcc 4.6 on sparc somehow does not see this. */
+ DIAG_PUSH_NEEDS_COMMENT;
+ DIAG_IGNORE_NEEDS_COMMENT (4.6,
+ "-Warray-bounds");
+ info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn;
+ DIAG_POP_NEEDS_COMMENT;
+ }
+ else if ((d_tag_utype) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM)
+ info[VERSYMIDX (dyn->d_tag)] = dyn;
+ else if ((d_tag_utype) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
+ info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
+ + DT_VERSIONTAGNUM] = dyn;
+ else if ((d_tag_utype) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
+ info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
+ + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn;
+ else if ((d_tag_utype) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
+ info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
+ + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;
+ ++dyn;
+ }
+
+#define DL_RO_DYN_TEMP_CNT 8
+
+#ifndef DL_RO_DYN_SECTION
+ /* Don't adjust .dynamic unnecessarily. */
+ if (l->l_addr != 0)
+ {
+ ElfW(Addr) l_addr = l->l_addr;
+ int cnt = 0;
+
+# define ADJUST_DYN_INFO(tag) \
+ do \
+ if (info[tag] != NULL) \
+ { \
+ if (temp) \
+ { \
+ temp[cnt].d_tag = info[tag]->d_tag; \
+ temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr; \
+ info[tag] = temp + cnt++; \
+ } \
+ else \
+ info[tag]->d_un.d_ptr += l_addr; \
+ } \
+ while (0)
+
+ ADJUST_DYN_INFO (DT_HASH);
+ ADJUST_DYN_INFO (DT_PLTGOT);
+ ADJUST_DYN_INFO (DT_STRTAB);
+ ADJUST_DYN_INFO (DT_SYMTAB);
+# if ! ELF_MACHINE_NO_RELA
+ ADJUST_DYN_INFO (DT_RELA);
+# endif
+# if ! ELF_MACHINE_NO_REL
+ ADJUST_DYN_INFO (DT_REL);
+# endif
+ ADJUST_DYN_INFO (DT_JMPREL);
+ ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
+ ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
+ + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
+# undef ADJUST_DYN_INFO
+ assert (cnt <= DL_RO_DYN_TEMP_CNT);
+ }
+#endif
+ if (info[DT_PLTREL] != NULL)
+ {
+#if ELF_MACHINE_NO_RELA
+ assert (info[DT_PLTREL]->d_un.d_val == DT_REL);
+#elif ELF_MACHINE_NO_REL
+ assert (info[DT_PLTREL]->d_un.d_val == DT_RELA);
+#else
+ assert (info[DT_PLTREL]->d_un.d_val == DT_REL
+ || info[DT_PLTREL]->d_un.d_val == DT_RELA);
+#endif
+ }
+#if ! ELF_MACHINE_NO_RELA
+ if (info[DT_RELA] != NULL)
+ assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
+# endif
+# if ! ELF_MACHINE_NO_REL
+ if (info[DT_REL] != NULL)
+ assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
+#endif
+#ifdef RTLD_BOOTSTRAP
+ /* Only the bind now flags are allowed. */
+ assert (info[VERSYMIDX (DT_FLAGS_1)] == NULL
+ || (info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val & ~DF_1_NOW) == 0);
+ assert (info[DT_FLAGS] == NULL
+ || (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0);
+ /* Flags must not be set for ld.so. */
+ assert (info[DT_RUNPATH] == NULL);
+ assert (info[DT_RPATH] == NULL);
+#else
+ if (info[DT_FLAGS] != NULL)
+ {
+ /* Flags are used. Translate to the old form where available.
+ Since these l_info entries are only tested for NULL pointers it
+ is ok if they point to the DT_FLAGS entry. */
+ l->l_flags = info[DT_FLAGS]->d_un.d_val;
+
+ if (l->l_flags & DF_SYMBOLIC)
+ info[DT_SYMBOLIC] = info[DT_FLAGS];
+ if (l->l_flags & DF_TEXTREL)
+ info[DT_TEXTREL] = info[DT_FLAGS];
+ if (l->l_flags & DF_BIND_NOW)
+ info[DT_BIND_NOW] = info[DT_FLAGS];
+ }
+ if (info[VERSYMIDX (DT_FLAGS_1)] != NULL)
+ {
+ l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;
+
+ /* Only DT_1_SUPPORTED_MASK bits are supported, and we would like
+ to assert this, but we can't. Users have been setting
+ unsupported DF_1_* flags for a long time and glibc has ignored
+ them. Therefore to avoid breaking existing applications the
+ best we can do is add a warning during debugging with the
+ intent of notifying the user of the problem. */
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)
+ && l->l_flags_1 & ~DT_1_SUPPORTED_MASK)
+ _dl_debug_printf ("\nWARNING: Unsupported flag value(s) of 0x%x in DT_FLAGS_1.\n",
+ l->l_flags_1 & ~DT_1_SUPPORTED_MASK);
+
+ if (l->l_flags_1 & DF_1_NOW)
+ info[DT_BIND_NOW] = info[VERSYMIDX (DT_FLAGS_1)];
+ }
+ if (info[DT_RUNPATH] != NULL)
+ /* If both RUNPATH and RPATH are given, the latter is ignored. */
+ info[DT_RPATH] = NULL;
+#endif
+}
diff --git a/REORG.TODO/elf/global.c b/REORG.TODO/elf/global.c
new file mode 100644
index 0000000000..c675858b64
--- /dev/null
+++ b/REORG.TODO/elf/global.c
@@ -0,0 +1,7 @@
+extern int test (void);
+
+int
+main (void)
+{
+ return test ();
+}
diff --git a/REORG.TODO/elf/globalmod1.c b/REORG.TODO/elf/globalmod1.c
new file mode 100644
index 0000000000..3f80822269
--- /dev/null
+++ b/REORG.TODO/elf/globalmod1.c
@@ -0,0 +1,17 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+extern int test (void);
+
+int
+test (void)
+{
+ (void) dlopen ("reldepmod4.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (dlsym (RTLD_DEFAULT, "call_me") != NULL)
+ {
+ puts ("found \"call_me\"");
+ return 0;
+ }
+ puts ("didn't find \"call_me\"");
+ return 1;
+}
diff --git a/REORG.TODO/elf/ifuncdep1.c b/REORG.TODO/elf/ifuncdep1.c
new file mode 100644
index 0000000000..77d663dcec
--- /dev/null
+++ b/REORG.TODO/elf/ifuncdep1.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols without -fPIC. */
+
+#include "ifuncmod1.c"
diff --git a/REORG.TODO/elf/ifuncdep1pic.c b/REORG.TODO/elf/ifuncdep1pic.c
new file mode 100644
index 0000000000..b6381e4868
--- /dev/null
+++ b/REORG.TODO/elf/ifuncdep1pic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncmod1.c"
diff --git a/REORG.TODO/elf/ifuncdep2.c b/REORG.TODO/elf/ifuncdep2.c
new file mode 100644
index 0000000000..d87d61d5be
--- /dev/null
+++ b/REORG.TODO/elf/ifuncdep2.c
@@ -0,0 +1,59 @@
+/* Test 3 STT_GNU_IFUNC symbols. */
+
+#include "ifunc-sel.h"
+
+int global = -1;
+/* Can't use __attribute__((visibility("protected"))) until the GCC bug:
+
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65248
+
+ is fixed. */
+asm (".protected global");
+
+static int
+one (void)
+{
+ return 1;
+}
+
+static int
+minus_one (void)
+{
+ return -1;
+}
+
+static int
+zero (void)
+{
+ return 0;
+}
+
+void * foo1_ifunc (void) __asm__ ("foo1");
+__asm__(".type foo1, %gnu_indirect_function");
+
+void *
+inhibit_stack_protector
+foo1_ifunc (void)
+{
+ return ifunc_sel (one, minus_one, zero);
+}
+
+void * foo2_ifunc (void) __asm__ ("foo2");
+__asm__(".type foo2, %gnu_indirect_function");
+
+void *
+inhibit_stack_protector
+foo2_ifunc (void)
+{
+ return ifunc_sel (minus_one, one, zero);
+}
+
+void * foo3_ifunc (void) __asm__ ("foo3");
+__asm__(".type foo3, %gnu_indirect_function");
+
+void *
+inhibit_stack_protector
+foo3_ifunc (void)
+{
+ return ifunc_sel (one, zero, minus_one);
+}
diff --git a/REORG.TODO/elf/ifuncdep2pic.c b/REORG.TODO/elf/ifuncdep2pic.c
new file mode 100644
index 0000000000..a84253dbc4
--- /dev/null
+++ b/REORG.TODO/elf/ifuncdep2pic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncdep2.c"
diff --git a/REORG.TODO/elf/ifuncdep5.c b/REORG.TODO/elf/ifuncdep5.c
new file mode 100644
index 0000000000..f26234336e
--- /dev/null
+++ b/REORG.TODO/elf/ifuncdep5.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols without -fPIC. */
+
+#include "ifuncmod5.c"
diff --git a/REORG.TODO/elf/ifuncdep5pic.c b/REORG.TODO/elf/ifuncdep5pic.c
new file mode 100644
index 0000000000..3edb3a07c6
--- /dev/null
+++ b/REORG.TODO/elf/ifuncdep5pic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncmod5.c"
diff --git a/REORG.TODO/elf/ifuncmain1.c b/REORG.TODO/elf/ifuncmain1.c
new file mode 100644
index 0000000000..747fc02648
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain1.c
@@ -0,0 +1,64 @@
+/* Test STT_GNU_IFUNC symbols:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility without override.
+ */
+
+#include <stdlib.h>
+
+int ret_foo;
+int ret_foo_hidden;
+int ret_foo_protected;
+
+extern int foo (void);
+extern int foo_protected (void);
+
+#ifndef FOO_P
+typedef int (*foo_p) (void);
+#endif
+
+foo_p foo_ptr = foo;
+foo_p foo_procted_ptr = foo_protected;
+
+extern foo_p get_foo_p (void);
+extern foo_p get_foo_hidden_p (void);
+extern foo_p get_foo_protected_p (void);
+
+int
+main (void)
+{
+ foo_p p;
+
+ if (foo_ptr != foo)
+ abort ();
+ if (foo () != -1)
+ abort ();
+ if ((*foo_ptr) () != -1)
+ abort ();
+
+ if (foo_procted_ptr != foo_protected)
+ abort ();
+ if (foo_protected () != 0)
+ abort ();
+ if ((*foo_procted_ptr) () != 0)
+ abort ();
+
+ p = get_foo_p ();
+ if (p != foo)
+ abort ();
+ if (ret_foo != -1 || (*p) () != ret_foo)
+ abort ();
+
+ p = get_foo_hidden_p ();
+ if (ret_foo_hidden != 1 || (*p) () != ret_foo_hidden)
+ abort ();
+
+ p = get_foo_protected_p ();
+ if (p != foo_protected)
+ abort ();
+ if (ret_foo_protected != 0 || (*p) () != ret_foo_protected)
+ abort ();
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/ifuncmain1pic.c b/REORG.TODO/elf/ifuncmain1pic.c
new file mode 100644
index 0000000000..db19dc9678
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain1pic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncmain1.c"
diff --git a/REORG.TODO/elf/ifuncmain1picstatic.c b/REORG.TODO/elf/ifuncmain1picstatic.c
new file mode 100644
index 0000000000..c937933029
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain1picstatic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC and -static. */
+
+#include "ifuncmain1.c"
diff --git a/REORG.TODO/elf/ifuncmain1pie.c b/REORG.TODO/elf/ifuncmain1pie.c
new file mode 100644
index 0000000000..c16ef6dd09
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain1pie.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with PIE. */
+
+#include "ifuncmain1.c"
diff --git a/REORG.TODO/elf/ifuncmain1static.c b/REORG.TODO/elf/ifuncmain1static.c
new file mode 100644
index 0000000000..fdd1e09024
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain1static.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -static. */
+
+#include "ifuncmain1.c"
diff --git a/REORG.TODO/elf/ifuncmain1staticpic.c b/REORG.TODO/elf/ifuncmain1staticpic.c
new file mode 100644
index 0000000000..39e0cbb4b8
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain1staticpic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC and no DSO. */
+
+#include "ifuncmain1.c"
diff --git a/REORG.TODO/elf/ifuncmain1staticpie.c b/REORG.TODO/elf/ifuncmain1staticpie.c
new file mode 100644
index 0000000000..4891114260
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain1staticpie.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with PIE and no DSO. */
+
+#include "ifuncmain1.c"
diff --git a/REORG.TODO/elf/ifuncmain1vis.c b/REORG.TODO/elf/ifuncmain1vis.c
new file mode 100644
index 0000000000..d35e2f81fc
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain1vis.c
@@ -0,0 +1,87 @@
+/* Test STT_GNU_IFUNC symbols:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility with override.
+ */
+
+#include <stdlib.h>
+
+int ret_foo;
+int ret_foo_hidden;
+int ret_foo_protected;
+
+extern int foo (void);
+extern int foo_protected (void);
+
+#ifndef FOO_P
+typedef int (*foo_p) (void);
+#endif
+
+foo_p foo_ptr = foo;
+foo_p foo_procted_ptr = foo_protected;
+
+extern foo_p get_foo_p (void);
+extern foo_p get_foo_hidden_p (void);
+extern foo_p get_foo_protected_p (void);
+
+int
+__attribute__ ((noinline))
+foo (void)
+{
+ return -30;
+}
+
+int
+__attribute__ ((noinline))
+foo_hidden (void)
+{
+ return -20;
+}
+
+int
+__attribute__ ((noinline))
+foo_protected (void)
+{
+ return -40;
+}
+
+int
+main (void)
+{
+ foo_p p;
+
+ if (foo_ptr != foo)
+ abort ();
+ if ((*foo_ptr) () != -30)
+ abort ();
+
+ if (foo_procted_ptr != foo_protected)
+ abort ();
+ if ((*foo_procted_ptr) () != -40)
+ abort ();
+
+ p = get_foo_p ();
+ if (p != foo)
+ abort ();
+ if (foo () != -30)
+ abort ();
+ if (ret_foo != -30 || (*p) () != ret_foo)
+ abort ();
+
+ p = get_foo_hidden_p ();
+ if (foo_hidden () != -20)
+ abort ();
+ if (ret_foo_hidden != 1 || (*p) () != ret_foo_hidden)
+ abort ();
+
+ p = get_foo_protected_p ();
+ if (p == foo_protected)
+ abort ();
+ if (foo_protected () != -40)
+ abort ();
+ if (ret_foo_protected != 0 || (*p) () != ret_foo_protected)
+ abort ();
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/ifuncmain1vispic.c b/REORG.TODO/elf/ifuncmain1vispic.c
new file mode 100644
index 0000000000..f8c104d560
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain1vispic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncmain1vis.c"
diff --git a/REORG.TODO/elf/ifuncmain1vispie.c b/REORG.TODO/elf/ifuncmain1vispie.c
new file mode 100644
index 0000000000..ad06d2ba1c
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain1vispie.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with PIE. */
+
+#include "ifuncmain1vis.c"
diff --git a/REORG.TODO/elf/ifuncmain2.c b/REORG.TODO/elf/ifuncmain2.c
new file mode 100644
index 0000000000..db3ba56a02
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain2.c
@@ -0,0 +1,14 @@
+/* Test calling one STT_GNU_IFUNC function with 3 different
+ STT_GNU_IFUNC definitions. */
+
+#include <stdlib.h>
+
+extern int foo1 (void);
+
+int
+main (void)
+{
+ if (foo1 () != -1)
+ abort ();
+ return 0;
+}
diff --git a/REORG.TODO/elf/ifuncmain2pic.c b/REORG.TODO/elf/ifuncmain2pic.c
new file mode 100644
index 0000000000..0006012a96
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain2pic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncmain2.c"
diff --git a/REORG.TODO/elf/ifuncmain2picstatic.c b/REORG.TODO/elf/ifuncmain2picstatic.c
new file mode 100644
index 0000000000..3e89db536d
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain2picstatic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC and -static. */
+
+#include "ifuncmain2.c"
diff --git a/REORG.TODO/elf/ifuncmain2static.c b/REORG.TODO/elf/ifuncmain2static.c
new file mode 100644
index 0000000000..6932ae8066
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain2static.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -static. */
+
+#include "ifuncmain2.c"
diff --git a/REORG.TODO/elf/ifuncmain3.c b/REORG.TODO/elf/ifuncmain3.c
new file mode 100644
index 0000000000..1574dd5cbe
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain3.c
@@ -0,0 +1,129 @@
+/* Test STT_GNU_IFUNC symbols with dlopen:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility with override.
+ */
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef int (*foo_p) (void);
+
+int
+__attribute__ ((noinline))
+foo (void)
+{
+ return -30;
+}
+
+int
+__attribute__ ((noinline))
+foo_hidden (void)
+{
+ return -20;
+}
+
+int
+__attribute__ ((noinline))
+foo_protected (void)
+{
+ return -40;
+}
+
+int
+main (void)
+{
+ foo_p p;
+ foo_p (*f) (void);
+ int *ret;
+
+ void *h = dlopen ("ifuncmod3.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot load: %s\n", dlerror ());
+ return 1;
+ }
+
+ p = dlsym (h, "foo");
+ if (p == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+ if ((*p) () != -1)
+ abort ();
+
+ f = dlsym (h, "get_foo_p");
+ if (f == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ ret = dlsym (h, "ret_foo");
+ if (ret == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ p = (*f) ();
+ if (p != foo)
+ abort ();
+ if (foo () != -30)
+ abort ();
+ if (*ret != -30 || (*p) () != *ret)
+ abort ();
+
+ f = dlsym (h, "get_foo_hidden_p");
+ if (f == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ ret = dlsym (h, "ret_foo_hidden");
+ if (ret == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ p = (*f) ();
+ if (foo_hidden () != -20)
+ abort ();
+ if (*ret != 1 || (*p) () != *ret)
+ abort ();
+
+ f = dlsym (h, "get_foo_protected_p");
+ if (f == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ ret = dlsym (h, "ret_foo_protected");
+ if (ret == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ p = (*f) ();
+ if (p == foo_protected)
+ abort ();
+ if (foo_protected () != -40)
+ abort ();
+ if (*ret != 0 || (*p) () != *ret)
+ abort ();
+
+ if (dlclose (h) != 0)
+ {
+ printf ("cannot close: %s\n", dlerror ());
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/ifuncmain4.c b/REORG.TODO/elf/ifuncmain4.c
new file mode 100644
index 0000000000..e55fee2eb3
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain4.c
@@ -0,0 +1,4 @@
+/* Test STT_GNU_IFUNC symbols in a single source file. */
+
+#include "ifuncmod1.c"
+#include "ifuncmain1.c"
diff --git a/REORG.TODO/elf/ifuncmain4picstatic.c b/REORG.TODO/elf/ifuncmain4picstatic.c
new file mode 100644
index 0000000000..977d7f97fc
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain4picstatic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC and -static. */
+
+#include "ifuncmain4.c"
diff --git a/REORG.TODO/elf/ifuncmain4static.c b/REORG.TODO/elf/ifuncmain4static.c
new file mode 100644
index 0000000000..c399977013
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain4static.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -static. */
+
+#include "ifuncmain4.c"
diff --git a/REORG.TODO/elf/ifuncmain5.c b/REORG.TODO/elf/ifuncmain5.c
new file mode 100644
index 0000000000..f398085cb4
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain5.c
@@ -0,0 +1,38 @@
+/* Test STT_GNU_IFUNC symbols with dynamic function pointer only. */
+
+#include <stdlib.h>
+
+extern int foo (void);
+extern int foo_protected (void);
+
+typedef int (*foo_p) (void);
+
+foo_p
+__attribute__ ((noinline))
+get_foo (void)
+{
+ return foo;
+}
+
+foo_p
+__attribute__ ((noinline))
+get_foo_protected (void)
+{
+ return foo_protected;
+}
+
+int
+main (void)
+{
+ foo_p p;
+
+ p = get_foo ();
+ if ((*p) () != -1)
+ abort ();
+
+ p = get_foo_protected ();
+ if ((*p) () != 0)
+ abort ();
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/ifuncmain5pic.c b/REORG.TODO/elf/ifuncmain5pic.c
new file mode 100644
index 0000000000..e9144fbb20
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain5pic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncmain5.c"
diff --git a/REORG.TODO/elf/ifuncmain5picstatic.c b/REORG.TODO/elf/ifuncmain5picstatic.c
new file mode 100644
index 0000000000..a0afe905d7
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain5picstatic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC and -static. */
+
+#include "ifuncmain5.c"
diff --git a/REORG.TODO/elf/ifuncmain5pie.c b/REORG.TODO/elf/ifuncmain5pie.c
new file mode 100644
index 0000000000..669f31eeda
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain5pie.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with PIE. */
+
+#include "ifuncmain5.c"
diff --git a/REORG.TODO/elf/ifuncmain5static.c b/REORG.TODO/elf/ifuncmain5static.c
new file mode 100644
index 0000000000..72504404a5
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain5static.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -static. */
+
+#include "ifuncmain5.c"
diff --git a/REORG.TODO/elf/ifuncmain5staticpic.c b/REORG.TODO/elf/ifuncmain5staticpic.c
new file mode 100644
index 0000000000..9e8bac254f
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain5staticpic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC and no DSO. */
+
+#include "ifuncmain5.c"
diff --git a/REORG.TODO/elf/ifuncmain6pie.c b/REORG.TODO/elf/ifuncmain6pie.c
new file mode 100644
index 0000000000..04faeb86ef
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain6pie.c
@@ -0,0 +1,65 @@
+/* Test STT_GNU_IFUNC symbols in PIE:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Reference from a shared library.
+ */
+
+#include <stdlib.h>
+#include "ifunc-sel.h"
+
+typedef int (*foo_p) (void);
+extern foo_p foo_ptr;
+
+static int
+one (void)
+{
+ return -30;
+}
+
+void * foo_ifunc (void) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+
+void *
+inhibit_stack_protector
+foo_ifunc (void)
+{
+ return ifunc_one (one);
+}
+
+extern int foo (void);
+extern foo_p get_foo (void);
+extern foo_p get_foo_p (void);
+
+foo_p my_foo_ptr = foo;
+
+int
+main (void)
+{
+ foo_p p;
+
+ p = get_foo ();
+ if (p != foo)
+ abort ();
+ if ((*p) () != -30)
+ abort ();
+
+ p = get_foo_p ();
+ if (p != foo)
+ abort ();
+ if ((*p) () != -30)
+ abort ();
+
+ if (foo_ptr != foo)
+ abort ();
+ if (my_foo_ptr != foo)
+ abort ();
+ if ((*foo_ptr) () != -30)
+ abort ();
+ if ((*my_foo_ptr) () != -30)
+ abort ();
+ if (foo () != -30)
+ abort ();
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/ifuncmain7.c b/REORG.TODO/elf/ifuncmain7.c
new file mode 100644
index 0000000000..1e8f7ea38e
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain7.c
@@ -0,0 +1,72 @@
+/* Test local STT_GNU_IFUNC symbols:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ */
+
+#include <stdlib.h>
+#include "ifunc-sel.h"
+
+extern int foo (void);
+
+static int
+one (void)
+{
+ return -30;
+}
+
+static void * foo_ifunc (void) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+
+static void *
+__attribute__ ((used))
+inhibit_stack_protector
+foo_ifunc (void)
+{
+ return ifunc_one (one);
+}
+
+typedef int (*foo_p) (void);
+
+foo_p foo_ptr = foo;
+
+foo_p
+__attribute__ ((noinline))
+get_foo_p (void)
+{
+ return foo_ptr;
+}
+
+foo_p
+__attribute__ ((noinline))
+get_foo (void)
+{
+ return foo;
+}
+
+int
+main (void)
+{
+ foo_p p;
+
+ p = get_foo ();
+ if (p != foo)
+ abort ();
+ if ((*p) () != -30)
+ abort ();
+
+ p = get_foo_p ();
+ if (p != foo)
+ abort ();
+ if ((*p) () != -30)
+ abort ();
+
+ if (foo_ptr != foo)
+ abort ();
+ if ((*foo_ptr) () != -30)
+ abort ();
+ if (foo () != -30)
+ abort ();
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/ifuncmain7pic.c b/REORG.TODO/elf/ifuncmain7pic.c
new file mode 100644
index 0000000000..fc37bf4469
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain7pic.c
@@ -0,0 +1,7 @@
+/* Test local STT_GNU_IFUNC symbols with -fPIC:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ */
+
+#include "ifuncmain7.c"
diff --git a/REORG.TODO/elf/ifuncmain7picstatic.c b/REORG.TODO/elf/ifuncmain7picstatic.c
new file mode 100644
index 0000000000..baf8934b95
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain7picstatic.c
@@ -0,0 +1,7 @@
+/* Test local STT_GNU_IFUNC symbols with -fPIC and -static:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ */
+
+#include "ifuncmain7.c"
diff --git a/REORG.TODO/elf/ifuncmain7pie.c b/REORG.TODO/elf/ifuncmain7pie.c
new file mode 100644
index 0000000000..254d453f1e
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain7pie.c
@@ -0,0 +1,7 @@
+/* Test local STT_GNU_IFUNC symbols with PIE:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ */
+
+#include "ifuncmain7.c"
diff --git a/REORG.TODO/elf/ifuncmain7static.c b/REORG.TODO/elf/ifuncmain7static.c
new file mode 100644
index 0000000000..e470d570ef
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmain7static.c
@@ -0,0 +1,7 @@
+/* Test local STT_GNU_IFUNC symbols with -static:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ */
+
+#include "ifuncmain7.c"
diff --git a/REORG.TODO/elf/ifuncmod1.c b/REORG.TODO/elf/ifuncmod1.c
new file mode 100644
index 0000000000..f0bf5fb45f
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmod1.c
@@ -0,0 +1,100 @@
+/* Test STT_GNU_IFUNC symbols:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility.
+ */
+#include "ifunc-sel.h"
+
+int global = -1;
+/* Can't use __attribute__((visibility("protected"))) until the GCC bug:
+
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65248
+
+ is fixed. */
+asm (".protected global");
+
+static int
+one (void)
+{
+ return 1;
+}
+
+static int
+minus_one (void)
+{
+ return -1;
+}
+
+static int
+zero (void)
+{
+ return 0;
+}
+
+void * foo_ifunc (void) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+
+void *
+inhibit_stack_protector
+foo_ifunc (void)
+{
+ return ifunc_sel (one, minus_one, zero);
+}
+
+void * foo_hidden_ifunc (void) __asm__ ("foo_hidden");
+__asm__(".type foo_hidden, %gnu_indirect_function");
+
+void *
+inhibit_stack_protector
+foo_hidden_ifunc (void)
+{
+ return ifunc_sel (minus_one, one, zero);
+}
+
+void * foo_protected_ifunc (void) __asm__ ("foo_protected");
+__asm__(".type foo_protected, %gnu_indirect_function");
+
+void *
+inhibit_stack_protector
+foo_protected_ifunc (void)
+{
+ return ifunc_sel (one, zero, minus_one);
+}
+
+/* Test hidden indirect function. */
+__asm__(".hidden foo_hidden");
+
+/* Test protected indirect function. */
+__asm__(".protected foo_protected");
+
+extern int foo (void);
+extern int foo_hidden (void);
+extern int foo_protected (void);
+extern int ret_foo;
+extern int ret_foo_hidden;
+extern int ret_foo_protected;
+
+#define FOO_P
+typedef int (*foo_p) (void);
+
+foo_p
+get_foo_p (void)
+{
+ ret_foo = foo ();
+ return foo;
+}
+
+foo_p
+get_foo_hidden_p (void)
+{
+ ret_foo_hidden = foo_hidden ();
+ return foo_hidden;
+}
+
+foo_p
+get_foo_protected_p (void)
+{
+ ret_foo_protected = foo_protected ();
+ return foo_protected;
+}
diff --git a/REORG.TODO/elf/ifuncmod3.c b/REORG.TODO/elf/ifuncmod3.c
new file mode 100644
index 0000000000..ca2d962600
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmod3.c
@@ -0,0 +1,7 @@
+/* Test STT_GNU_IFUNC symbols with dlopen. */
+
+#include "ifuncmod1.c"
+
+int ret_foo;
+int ret_foo_hidden;
+int ret_foo_protected;
diff --git a/REORG.TODO/elf/ifuncmod5.c b/REORG.TODO/elf/ifuncmod5.c
new file mode 100644
index 0000000000..5a957800e8
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmod5.c
@@ -0,0 +1,64 @@
+/* Test STT_GNU_IFUNC symbols without direct function call. */
+#include "ifunc-sel.h"
+
+int global = -1;
+/* Can't use __attribute__((visibility("protected"))) until the GCC bug:
+
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65248
+
+ is fixed. */
+asm (".protected global");
+
+static int
+one (void)
+{
+ return 1;
+}
+
+static int
+minus_one (void)
+{
+ return -1;
+}
+
+static int
+zero (void)
+{
+ return 0;
+}
+
+void * foo_ifunc (void) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+
+void *
+inhibit_stack_protector
+foo_ifunc (void)
+{
+ return ifunc_sel (one, minus_one, zero);
+}
+
+void * foo_hidden_ifunc (void) __asm__ ("foo_hidden");
+__asm__(".type foo_hidden, %gnu_indirect_function");
+
+void *
+inhibit_stack_protector
+foo_hidden_ifunc (void)
+{
+ return ifunc_sel (minus_one, one, zero);
+}
+
+void * foo_protected_ifunc (void) __asm__ ("foo_protected");
+__asm__(".type foo_protected, %gnu_indirect_function");
+
+void *
+inhibit_stack_protector
+foo_protected_ifunc (void)
+{
+ return ifunc_sel (one, zero, minus_one);
+}
+
+/* Test hidden indirect function. */
+__asm__(".hidden foo_hidden");
+
+/* Test protected indirect function. */
+__asm__(".protected foo_protected");
diff --git a/REORG.TODO/elf/ifuncmod6.c b/REORG.TODO/elf/ifuncmod6.c
new file mode 100644
index 0000000000..2e16c1d06d
--- /dev/null
+++ b/REORG.TODO/elf/ifuncmod6.c
@@ -0,0 +1,19 @@
+/* Test STT_GNU_IFUNC symbol reference in a shared library. */
+
+extern int foo (void);
+
+typedef int (*foo_p) (void);
+
+foo_p foo_ptr = foo;
+
+foo_p
+get_foo_p (void)
+{
+ return foo_ptr;
+}
+
+foo_p
+get_foo (void)
+{
+ return foo;
+}
diff --git a/REORG.TODO/elf/initfirst.c b/REORG.TODO/elf/initfirst.c
new file mode 100644
index 0000000000..5ca83d21bc
--- /dev/null
+++ b/REORG.TODO/elf/initfirst.c
@@ -0,0 +1,22 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+ void *h = dlopen ("firstobj.so", RTLD_LAZY);
+ void *f;
+ if (! h)
+ {
+ printf ("cannot find firstobj.so: %s\n", dlerror ());
+ return 1;
+ }
+ f = dlsym (h, "foo");
+ if (! f)
+ {
+ printf ("cannot find symbol foo: %s\n", dlerror ());
+ return 2;
+ }
+ ((void (*) (void)) f) ();
+ return 0;
+}
diff --git a/REORG.TODO/elf/interp.c b/REORG.TODO/elf/interp.c
new file mode 100644
index 0000000000..b6e8f04444
--- /dev/null
+++ b/REORG.TODO/elf/interp.c
@@ -0,0 +1,22 @@
+/* interp - add information about dynamic loader to shared library objects.
+ Copyright (C) 1996-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <runtime-linker.h>
+
+const char __invoke_dynamic_linker__[] __attribute__ ((section (".interp")))
+ = RUNTIME_LINKER;
diff --git a/REORG.TODO/elf/lateglobal.c b/REORG.TODO/elf/lateglobal.c
new file mode 100644
index 0000000000..4a1a7cd085
--- /dev/null
+++ b/REORG.TODO/elf/lateglobal.c
@@ -0,0 +1,47 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ void *h[2];
+ int fail;
+ int (*fp) (void);
+
+ mtrace ();
+
+ h[0] = dlopen ("ltglobmod1.so", RTLD_LAZY);
+ if (h[0] == NULL)
+ {
+ printf ("%s: cannot open %s: %s",
+ __FUNCTION__, "ltglobmod1.so", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+ h[1] = dlopen ("ltglobmod2.so", RTLD_LAZY);
+ if (h[1] == NULL)
+ {
+ printf ("%s: cannot open %s: %s",
+ __FUNCTION__, "ltglobmod2.so", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ puts ("loaded \"ltglobmod1.so\" without RTLD_GLOBAL");
+
+ fp = dlsym (h[1], "foo");
+ if (fp == NULL)
+ {
+ printf ("cannot get address of `foo': %s", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ fail = fp ();
+
+ puts ("back in main");
+
+ dlclose (h[1]);
+ dlclose (h[0]);
+
+ return fail;
+}
diff --git a/REORG.TODO/elf/ldconfig.c b/REORG.TODO/elf/ldconfig.c
new file mode 100644
index 0000000000..99caf9e9bb
--- /dev/null
+++ b/REORG.TODO/elf/ldconfig.c
@@ -0,0 +1,1418 @@
+/* Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Andreas Jaeger <aj@suse.de>, 1999.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+#define PROCINFO_CLASS static
+#include <alloca.h>
+#include <argp.h>
+#include <dirent.h>
+#include <elf.h>
+#include <error.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <libintl.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <glob.h>
+#include <libgen.h>
+
+#include <ldconfig.h>
+#include <dl-cache.h>
+
+#include <dl-procinfo.h>
+
+#ifdef _DL_FIRST_PLATFORM
+# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
+#else
+# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT
+#endif
+
+#ifndef LD_SO_CONF
+# define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
+#endif
+
+/* Get libc version number. */
+#include <version.h>
+
+#define PACKAGE _libc_intl_domainname
+
+static const struct
+{
+ const char *name;
+ int flag;
+} lib_types[] =
+{
+ {"libc4", FLAG_LIBC4},
+ {"libc5", FLAG_ELF_LIBC5},
+ {"libc6", FLAG_ELF_LIBC6},
+ {"glibc2", FLAG_ELF_LIBC6}
+};
+
+
+/* List of directories to handle. */
+struct dir_entry
+{
+ char *path;
+ int flag;
+ ino64_t ino;
+ dev_t dev;
+ struct dir_entry *next;
+};
+
+/* The list is unsorted, contains no duplicates. Entries are added at
+ the end. */
+static struct dir_entry *dir_entries;
+
+/* Flags for different options. */
+/* Print Cache. */
+static int opt_print_cache;
+
+/* Be verbose. */
+int opt_verbose;
+
+/* Format to support. */
+/* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */
+int opt_format = 1;
+
+/* Build cache. */
+static int opt_build_cache = 1;
+
+/* Enable symbolic link processing. If set, create or update symbolic
+ links, and remove stale symbolic links. */
+static int opt_link = 1;
+
+/* Only process directories specified on the command line. */
+static int opt_only_cline;
+
+/* Path to root for chroot. */
+static char *opt_chroot;
+
+/* Manually link given shared libraries. */
+static int opt_manual_link;
+
+/* Should we ignore an old auxiliary cache file? */
+static int opt_ignore_aux_cache;
+
+/* Cache file to use. */
+static char *cache_file;
+
+/* Configuration file. */
+static const char *config_file;
+
+/* Mask to use for important hardware capabilities. */
+static unsigned long int hwcap_mask = HWCAP_IMPORTANT;
+
+/* Configuration-defined capabilities defined in kernel vDSOs. */
+static const char *hwcap_extra[64 - _DL_FIRST_EXTRA];
+
+/* Name and version of program. */
+static void print_version (FILE *stream, struct argp_state *state);
+void (*argp_program_version_hook) (FILE *, struct argp_state *)
+ = print_version;
+
+/* Function to print some extra text in the help message. */
+static char *more_help (int key, const char *text, void *input);
+
+/* Definitions of arguments for argp functions. */
+static const struct argp_option options[] =
+{
+ { "print-cache", 'p', NULL, 0, N_("Print cache"), 0},
+ { "verbose", 'v', NULL, 0, N_("Generate verbose messages"), 0},
+ { NULL, 'N', NULL, 0, N_("Don't build cache"), 0},
+ { NULL, 'X', NULL, 0, N_("Don't update symbolic links"), 0},
+ { NULL, 'r', N_("ROOT"), 0, N_("Change to and use ROOT as root directory"), 0},
+ { NULL, 'C', N_("CACHE"), 0, N_("Use CACHE as cache file"), 0},
+ { NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0},
+ { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0},
+ { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
+ { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new, old or compat (default)"), 0},
+ { "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0},
+ { NULL, 0, NULL, 0, NULL, 0 }
+};
+
+#define PROCINFO_CLASS static
+#include <dl-procinfo.c>
+
+/* Short description of program. */
+static const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.");
+
+/* Prototype for option handler. */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Data structure to communicate with argp functions. */
+static struct argp argp =
+{
+ options, parse_opt, NULL, doc, NULL, more_help, NULL
+};
+
+/* Check if string corresponds to an important hardware capability or
+ a platform. */
+static int
+is_hwcap_platform (const char *name)
+{
+ int hwcap_idx = _dl_string_hwcap (name);
+
+ /* Is this a normal hwcap for the machine like "fpu?" */
+ if (hwcap_idx != -1 && ((1 << hwcap_idx) & hwcap_mask))
+ return 1;
+
+ /* Is this a platform pseudo-hwcap like "i686?" */
+ hwcap_idx = _dl_string_platform (name);
+ if (hwcap_idx != -1)
+ return 1;
+
+ /* Is this one of the extra pseudo-hwcaps that we map beyond
+ _DL_FIRST_EXTRA like "tls", or "nosegneg?" */
+ for (hwcap_idx = _DL_FIRST_EXTRA; hwcap_idx < 64; ++hwcap_idx)
+ if (hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA] != NULL
+ && !strcmp (name, hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA]))
+ return 1;
+
+ return 0;
+}
+
+/* Get hwcap (including platform) encoding of path. */
+static uint64_t
+path_hwcap (const char *path)
+{
+ char *str = xstrdup (path);
+ char *ptr;
+ uint64_t hwcap = 0;
+ uint64_t h;
+
+ size_t len;
+
+ len = strlen (str);
+ if (str[len] == '/')
+ str[len] = '\0';
+
+ /* Search pathname from the end and check for hwcap strings. */
+ for (;;)
+ {
+ ptr = strrchr (str, '/');
+
+ if (ptr == NULL)
+ break;
+
+ h = _dl_string_hwcap (ptr + 1);
+
+ if (h == (uint64_t) -1)
+ {
+ h = _dl_string_platform (ptr + 1);
+ if (h == (uint64_t) -1)
+ {
+ for (h = _DL_FIRST_EXTRA; h < 64; ++h)
+ if (hwcap_extra[h - _DL_FIRST_EXTRA] != NULL
+ && !strcmp (ptr + 1, hwcap_extra[h - _DL_FIRST_EXTRA]))
+ break;
+ if (h == 64)
+ break;
+ }
+ }
+ hwcap += 1ULL << h;
+
+ /* Search the next part of the path. */
+ *ptr = '\0';
+ }
+
+ free (str);
+ return hwcap;
+}
+
+/* Handle program arguments. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'C':
+ cache_file = arg;
+ /* Ignore auxiliary cache since we use non-standard cache. */
+ opt_ignore_aux_cache = 1;
+ break;
+ case 'f':
+ config_file = arg;
+ break;
+ case 'i':
+ opt_ignore_aux_cache = 1;
+ break;
+ case 'l':
+ opt_manual_link = 1;
+ break;
+ case 'N':
+ opt_build_cache = 0;
+ break;
+ case 'n':
+ opt_build_cache = 0;
+ opt_only_cline = 1;
+ break;
+ case 'p':
+ opt_print_cache = 1;
+ break;
+ case 'r':
+ opt_chroot = arg;
+ break;
+ case 'v':
+ opt_verbose = 1;
+ break;
+ case 'X':
+ opt_link = 0;
+ break;
+ case 'c':
+ if (strcmp (arg, "old") == 0)
+ opt_format = 0;
+ else if (strcmp (arg, "compat") == 0)
+ opt_format = 1;
+ else if (strcmp (arg, "new") == 0)
+ opt_format = 2;
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+/* Print bug-reporting information in the help message. */
+static char *
+more_help (int key, const char *text, void *input)
+{
+ char *tp = NULL;
+ switch (key)
+ {
+ case ARGP_KEY_HELP_EXTRA:
+ /* We print some extra information. */
+ if (asprintf (&tp, gettext ("\
+For bug reporting instructions, please see:\n\
+%s.\n"), REPORT_BUGS_TO) < 0)
+ return NULL;
+ return tp;
+ default:
+ break;
+ }
+ return (char *) text;
+}
+
+/* Print the version information. */
+static void
+print_version (FILE *stream, struct argp_state *state)
+{
+ fprintf (stream, "ldconfig %s%s\n", PKGVERSION, VERSION);
+ fprintf (stream, gettext ("\
+Copyright (C) %s Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions. There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"), "2017");
+ fprintf (stream, gettext ("Written by %s.\n"),
+ "Andreas Jaeger");
+}
+
+/* Add a single directory entry. */
+static void
+add_single_dir (struct dir_entry *entry, int verbose)
+{
+ struct dir_entry *ptr, *prev;
+
+ ptr = dir_entries;
+ prev = ptr;
+ while (ptr != NULL)
+ {
+ /* Check for duplicates. */
+ if (ptr->ino == entry->ino && ptr->dev == entry->dev)
+ {
+ if (opt_verbose && verbose)
+ error (0, 0, _("Path `%s' given more than once"), entry->path);
+ /* Use the newer information. */
+ ptr->flag = entry->flag;
+ free (entry->path);
+ free (entry);
+ break;
+ }
+ prev = ptr;
+ ptr = ptr->next;
+ }
+ /* Is this the first entry? */
+ if (ptr == NULL && dir_entries == NULL)
+ dir_entries = entry;
+ else if (ptr == NULL)
+ prev->next = entry;
+}
+
+/* Add one directory to the list of directories to process. */
+static void
+add_dir (const char *line)
+{
+ unsigned int i;
+ struct dir_entry *entry = xmalloc (sizeof (struct dir_entry));
+ entry->next = NULL;
+
+ /* Search for an '=' sign. */
+ entry->path = xstrdup (line);
+ char *equal_sign = strchr (entry->path, '=');
+ if (equal_sign)
+ {
+ *equal_sign = '\0';
+ ++equal_sign;
+ entry->flag = FLAG_ANY;
+ for (i = 0; i < sizeof (lib_types) / sizeof (lib_types[0]); ++i)
+ if (strcmp (equal_sign, lib_types[i].name) == 0)
+ {
+ entry->flag = lib_types[i].flag;
+ break;
+ }
+ if (entry->flag == FLAG_ANY)
+ error (0, 0, _("%s is not a known library type"), equal_sign);
+ }
+ else
+ {
+ entry->flag = FLAG_ANY;
+ }
+
+ /* Canonify path: for now only remove leading and trailing
+ whitespace and the trailing slashes. */
+ i = strlen (entry->path);
+
+ while (i > 0 && isspace (entry->path[i - 1]))
+ entry->path[--i] = '\0';
+
+ while (i > 0 && entry->path[i - 1] == '/')
+ entry->path[--i] = '\0';
+
+ if (i == 0)
+ return;
+
+ char *path = entry->path;
+ if (opt_chroot)
+ path = chroot_canon (opt_chroot, path);
+
+ struct stat64 stat_buf;
+ if (path == NULL || stat64 (path, &stat_buf))
+ {
+ if (opt_verbose)
+ error (0, errno, _("Can't stat %s"), entry->path);
+ free (entry->path);
+ free (entry);
+ }
+ else
+ {
+ entry->ino = stat_buf.st_ino;
+ entry->dev = stat_buf.st_dev;
+
+ add_single_dir (entry, 1);
+ }
+
+ if (opt_chroot)
+ free (path);
+}
+
+
+static int
+chroot_stat (const char *real_path, const char *path, struct stat64 *st)
+{
+ int ret;
+ char *canon_path;
+
+ if (!opt_chroot)
+ return stat64 (real_path, st);
+
+ ret = lstat64 (real_path, st);
+ if (ret || !S_ISLNK (st->st_mode))
+ return ret;
+
+ canon_path = chroot_canon (opt_chroot, path);
+ if (canon_path == NULL)
+ return -1;
+
+ ret = stat64 (canon_path, st);
+ free (canon_path);
+ return ret;
+}
+
+/* Create a symbolic link from soname to libname in directory path. */
+static void
+create_links (const char *real_path, const char *path, const char *libname,
+ const char *soname)
+{
+ char *full_libname, *full_soname;
+ char *real_full_libname, *real_full_soname;
+ struct stat64 stat_lib, stat_so, lstat_so;
+ int do_link = 1;
+ int do_remove = 1;
+ /* XXX: The logics in this function should be simplified. */
+
+ /* Get complete path. */
+ full_libname = alloca (strlen (path) + strlen (libname) + 2);
+ full_soname = alloca (strlen (path) + strlen (soname) + 2);
+ sprintf (full_libname, "%s/%s", path, libname);
+ sprintf (full_soname, "%s/%s", path, soname);
+ if (opt_chroot)
+ {
+ real_full_libname = alloca (strlen (real_path) + strlen (libname) + 2);
+ real_full_soname = alloca (strlen (real_path) + strlen (soname) + 2);
+ sprintf (real_full_libname, "%s/%s", real_path, libname);
+ sprintf (real_full_soname, "%s/%s", real_path, soname);
+ }
+ else
+ {
+ real_full_libname = full_libname;
+ real_full_soname = full_soname;
+ }
+
+ /* Does soname already exist and point to the right library? */
+ if (chroot_stat (real_full_soname, full_soname, &stat_so) == 0)
+ {
+ if (chroot_stat (real_full_libname, full_libname, &stat_lib))
+ {
+ error (0, 0, _("Can't stat %s\n"), full_libname);
+ return;
+ }
+ if (stat_lib.st_dev == stat_so.st_dev
+ && stat_lib.st_ino == stat_so.st_ino)
+ /* Link is already correct. */
+ do_link = 0;
+ else if (lstat64 (full_soname, &lstat_so) == 0
+ && !S_ISLNK (lstat_so.st_mode))
+ {
+ error (0, 0, _("%s is not a symbolic link\n"), full_soname);
+ do_link = 0;
+ do_remove = 0;
+ }
+ }
+ else if (lstat64 (real_full_soname, &lstat_so) != 0
+ || !S_ISLNK (lstat_so.st_mode))
+ /* Unless it is a stale symlink, there is no need to remove. */
+ do_remove = 0;
+
+ if (opt_verbose)
+ printf ("\t%s -> %s", soname, libname);
+
+ if (do_link && opt_link)
+ {
+ /* Remove old link. */
+ if (do_remove)
+ if (unlink (real_full_soname))
+ {
+ error (0, 0, _("Can't unlink %s"), full_soname);
+ do_link = 0;
+ }
+ /* Create symbolic link. */
+ if (do_link && symlink (libname, real_full_soname))
+ {
+ error (0, 0, _("Can't link %s to %s"), full_soname, libname);
+ do_link = 0;
+ }
+ if (opt_verbose)
+ {
+ if (do_link)
+ fputs (_(" (changed)\n"), stdout);
+ else
+ fputs (_(" (SKIPPED)\n"), stdout);
+ }
+ }
+ else if (opt_verbose)
+ fputs ("\n", stdout);
+}
+
+/* Manually link the given library. */
+static void
+manual_link (char *library)
+{
+ char *path;
+ char *real_path;
+ char *real_library;
+ char *libname;
+ char *soname;
+ struct stat64 stat_buf;
+ int flag;
+ unsigned int osversion;
+
+ /* Prepare arguments for create_links call. Split library name in
+ directory and filename first. Since path is allocated, we've got
+ to be careful to free at the end. */
+ path = xstrdup (library);
+ libname = strrchr (path, '/');
+
+ if (libname)
+ {
+ /* Successfully split names. Check if path is just "/" to avoid
+ an empty path. */
+ if (libname == path)
+ {
+ libname = library + 1;
+ path = xrealloc (path, 2);
+ strcpy (path, "/");
+ }
+ else
+ {
+ *libname = '\0';
+ ++libname;
+ }
+ }
+ else
+ {
+ /* There's no path, construct one. */
+ libname = library;
+ path = xrealloc (path, 2);
+ strcpy (path, ".");
+ }
+
+ if (opt_chroot)
+ {
+ real_path = chroot_canon (opt_chroot, path);
+ if (real_path == NULL)
+ {
+ error (0, errno, _("Can't find %s"), path);
+ free (path);
+ return;
+ }
+ real_library = alloca (strlen (real_path) + strlen (libname) + 2);
+ sprintf (real_library, "%s/%s", real_path, libname);
+ }
+ else
+ {
+ real_path = path;
+ real_library = library;
+ }
+
+ /* Do some sanity checks first. */
+ if (lstat64 (real_library, &stat_buf))
+ {
+ error (0, errno, _("Cannot lstat %s"), library);
+ free (path);
+ return;
+ }
+ /* We don't want links here! */
+ else if (!S_ISREG (stat_buf.st_mode))
+ {
+ error (0, 0, _("Ignored file %s since it is not a regular file."),
+ library);
+ free (path);
+ return;
+ }
+
+ if (process_file (real_library, library, libname, &flag, &osversion,
+ &soname, 0, &stat_buf))
+ {
+ error (0, 0, _("No link created since soname could not be found for %s"),
+ library);
+ free (path);
+ return;
+ }
+ if (soname == NULL)
+ soname = implicit_soname (libname, flag);
+ create_links (real_path, path, libname, soname);
+ free (soname);
+ free (path);
+}
+
+
+/* Read a whole directory and search for libraries.
+ The purpose is two-fold:
+ - search for libraries which will be added to the cache
+ - create symbolic links to the soname for each library
+
+ This has to be done separatly for each directory.
+
+ To keep track of which libraries to add to the cache and which
+ links to create, we save a list of all libraries.
+
+ The algorithm is basically:
+ for all libraries in the directory do
+ get soname of library
+ if soname is already in list
+ if new library is newer, replace entry
+ otherwise ignore this library
+ otherwise add library to list
+
+ For example, if the two libraries libxy.so.1.1 and libxy.so.1.2
+ exist and both have the same soname, e.g. libxy.so, a symbolic link
+ is created from libxy.so.1.2 (the newer one) to libxy.so.
+ libxy.so.1.2 and libxy.so are added to the cache - but not
+ libxy.so.1.1. */
+
+/* Information for one library. */
+struct dlib_entry
+{
+ char *name;
+ char *soname;
+ int flag;
+ int is_link;
+ unsigned int osversion;
+ struct dlib_entry *next;
+};
+
+
+static void
+search_dir (const struct dir_entry *entry)
+{
+ uint64_t hwcap = path_hwcap (entry->path);
+ if (opt_verbose)
+ {
+ if (hwcap != 0)
+ printf ("%s: (hwcap: %#.16" PRIx64 ")\n", entry->path, hwcap);
+ else
+ printf ("%s:\n", entry->path);
+ }
+
+ char *dir_name;
+ char *real_file_name;
+ size_t real_file_name_len;
+ size_t file_name_len = PATH_MAX;
+ char *file_name = alloca (file_name_len);
+ if (opt_chroot)
+ {
+ dir_name = chroot_canon (opt_chroot, entry->path);
+ real_file_name_len = PATH_MAX;
+ real_file_name = alloca (real_file_name_len);
+ }
+ else
+ {
+ dir_name = entry->path;
+ real_file_name_len = 0;
+ real_file_name = file_name;
+ }
+
+ DIR *dir;
+ if (dir_name == NULL || (dir = opendir (dir_name)) == NULL)
+ {
+ if (opt_verbose)
+ error (0, errno, _("Can't open directory %s"), entry->path);
+ if (opt_chroot && dir_name)
+ free (dir_name);
+ return;
+ }
+
+ struct dirent64 *direntry;
+ struct dlib_entry *dlibs = NULL;
+ while ((direntry = readdir64 (dir)) != NULL)
+ {
+ int flag;
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* We only look at links and regular files. */
+ if (direntry->d_type != DT_UNKNOWN
+ && direntry->d_type != DT_LNK
+ && direntry->d_type != DT_REG
+ && direntry->d_type != DT_DIR)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+ /* Does this file look like a shared library or is it a hwcap
+ subdirectory? The dynamic linker is also considered as
+ shared library. */
+ if (((strncmp (direntry->d_name, "lib", 3) != 0
+ && strncmp (direntry->d_name, "ld-", 3) != 0)
+ || strstr (direntry->d_name, ".so") == NULL)
+ && (
+#ifdef _DIRENT_HAVE_D_TYPE
+ direntry->d_type == DT_REG ||
+#endif
+ !is_hwcap_platform (direntry->d_name)))
+ continue;
+
+ size_t len = strlen (direntry->d_name);
+ /* Skip temporary files created by the prelink program. Files with
+ names like these are never really DSOs we want to look at. */
+ if (len >= sizeof (".#prelink#") - 1)
+ {
+ if (strcmp (direntry->d_name + len - sizeof (".#prelink#") + 1,
+ ".#prelink#") == 0)
+ continue;
+ if (len >= sizeof (".#prelink#.XXXXXX") - 1
+ && memcmp (direntry->d_name + len - sizeof (".#prelink#.XXXXXX")
+ + 1, ".#prelink#.", sizeof (".#prelink#.") - 1) == 0)
+ continue;
+ }
+ len += strlen (entry->path) + 2;
+ if (len > file_name_len)
+ {
+ file_name_len = len;
+ file_name = alloca (file_name_len);
+ if (!opt_chroot)
+ real_file_name = file_name;
+ }
+ sprintf (file_name, "%s/%s", entry->path, direntry->d_name);
+ if (opt_chroot)
+ {
+ len = strlen (dir_name) + strlen (direntry->d_name) + 2;
+ if (len > real_file_name_len)
+ {
+ real_file_name_len = len;
+ real_file_name = alloca (real_file_name_len);
+ }
+ sprintf (real_file_name, "%s/%s", dir_name, direntry->d_name);
+ }
+
+ struct stat64 lstat_buf;
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* We optimize and try to do the lstat call only if needed. */
+ if (direntry->d_type != DT_UNKNOWN)
+ lstat_buf.st_mode = DTTOIF (direntry->d_type);
+ else
+#endif
+ if (__glibc_unlikely (lstat64 (real_file_name, &lstat_buf)))
+ {
+ error (0, errno, _("Cannot lstat %s"), file_name);
+ continue;
+ }
+
+ struct stat64 stat_buf;
+ int is_dir;
+ int is_link = S_ISLNK (lstat_buf.st_mode);
+ if (is_link)
+ {
+ /* In case of symlink, we check if the symlink refers to
+ a directory. */
+ char *target_name = real_file_name;
+ if (opt_chroot)
+ {
+ target_name = chroot_canon (opt_chroot, file_name);
+ if (target_name == NULL)
+ {
+ if (strstr (file_name, ".so") == NULL)
+ error (0, 0, _("Input file %s not found.\n"), file_name);
+ continue;
+ }
+ }
+ if (__glibc_unlikely (stat64 (target_name, &stat_buf)))
+ {
+ if (opt_verbose)
+ error (0, errno, _("Cannot stat %s"), file_name);
+
+ /* Remove stale symlinks. */
+ if (opt_link && strstr (direntry->d_name, ".so."))
+ unlink (real_file_name);
+ continue;
+ }
+ is_dir = S_ISDIR (stat_buf.st_mode);
+
+ /* lstat_buf is later stored, update contents. */
+ lstat_buf.st_dev = stat_buf.st_dev;
+ lstat_buf.st_ino = stat_buf.st_ino;
+ lstat_buf.st_size = stat_buf.st_size;
+ lstat_buf.st_ctime = stat_buf.st_ctime;
+ }
+ else
+ is_dir = S_ISDIR (lstat_buf.st_mode);
+
+ if (is_dir && is_hwcap_platform (direntry->d_name))
+ {
+ /* Handle subdirectory later. */
+ struct dir_entry *new_entry;
+
+ new_entry = xmalloc (sizeof (struct dir_entry));
+ new_entry->path = xstrdup (file_name);
+ new_entry->flag = entry->flag;
+ new_entry->next = NULL;
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* We have filled in lstat only #ifndef
+ _DIRENT_HAVE_D_TYPE. Fill it in if needed. */
+ if (!is_link
+ && direntry->d_type != DT_UNKNOWN
+ && __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
+ {
+ error (0, errno, _("Cannot lstat %s"), file_name);
+ free (new_entry->path);
+ free (new_entry);
+ continue;
+ }
+#endif
+ new_entry->ino = lstat_buf.st_ino;
+ new_entry->dev = lstat_buf.st_dev;
+ add_single_dir (new_entry, 0);
+ continue;
+ }
+ else if (!S_ISREG (lstat_buf.st_mode) && !is_link)
+ continue;
+
+ char *real_name;
+ if (opt_chroot && is_link)
+ {
+ real_name = chroot_canon (opt_chroot, file_name);
+ if (real_name == NULL)
+ {
+ if (strstr (file_name, ".so") == NULL)
+ error (0, 0, _("Input file %s not found.\n"), file_name);
+ continue;
+ }
+ }
+ else
+ real_name = real_file_name;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Call lstat64 if not done yet. */
+ if (!is_link
+ && direntry->d_type != DT_UNKNOWN
+ && __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
+ {
+ error (0, errno, _("Cannot lstat %s"), file_name);
+ continue;
+ }
+#endif
+
+ /* First search whether the auxiliary cache contains this
+ library already and it's not changed. */
+ char *soname;
+ unsigned int osversion;
+ if (!search_aux_cache (&lstat_buf, &flag, &osversion, &soname))
+ {
+ if (process_file (real_name, file_name, direntry->d_name, &flag,
+ &osversion, &soname, is_link, &lstat_buf))
+ {
+ if (real_name != real_file_name)
+ free (real_name);
+ continue;
+ }
+ else if (opt_build_cache)
+ add_to_aux_cache (&lstat_buf, flag, osversion, soname);
+ }
+
+ if (soname == NULL)
+ soname = implicit_soname (direntry->d_name, flag);
+
+ /* A link may just point to itself. */
+ if (is_link)
+ {
+ /* If the path the link points to isn't its soname or it is not
+ the .so symlink for ld(1), we treat it as a normal file.
+
+ You should always do this:
+
+ libfoo.so -> SONAME -> Arbitrary package-chosen name.
+
+ e.g. libfoo.so -> libfoo.so.1 -> libfooimp.so.9.99.
+ Given a SONAME of libfoo.so.1.
+
+ You should *never* do this:
+
+ libfoo.so -> libfooimp.so.9.99
+
+ If you do, and your SONAME is libfoo.so.1, then libfoo.so
+ fails to point at the SONAME. In that case ldconfig may consider
+ libfoo.so as another implementation of SONAME and will create
+ symlinks against it causing problems when you try to upgrade
+ or downgrade. The problems will arise because ldconfig will,
+ depending on directory ordering, creat symlinks against libfoo.so
+ e.g. libfoo.so.1.2 -> libfoo.so, but when libfoo.so is removed
+ (typically by the removal of a development pacakge not required
+ for the runtime) it will break the libfoo.so.1.2 symlink and the
+ application will fail to start. */
+ const char *real_base_name = basename (real_file_name);
+
+ if (strcmp (real_base_name, soname) != 0)
+ {
+ len = strlen (real_base_name);
+ if (len < strlen (".so")
+ || strcmp (real_base_name + len - strlen (".so"), ".so") != 0
+ || strncmp (real_base_name, soname, len) != 0)
+ is_link = 0;
+ }
+ }
+
+ if (real_name != real_file_name)
+ free (real_name);
+
+ if (is_link)
+ {
+ free (soname);
+ soname = xstrdup (direntry->d_name);
+ }
+
+ if (flag == FLAG_ELF
+ && (entry->flag == FLAG_ELF_LIBC5
+ || entry->flag == FLAG_ELF_LIBC6))
+ flag = entry->flag;
+
+ /* Some sanity checks to print warnings. */
+ if (opt_verbose)
+ {
+ if (flag == FLAG_ELF_LIBC5 && entry->flag != FLAG_ELF_LIBC5
+ && entry->flag != FLAG_ANY)
+ error (0, 0, _("libc5 library %s in wrong directory"), file_name);
+ if (flag == FLAG_ELF_LIBC6 && entry->flag != FLAG_ELF_LIBC6
+ && entry->flag != FLAG_ANY)
+ error (0, 0, _("libc6 library %s in wrong directory"), file_name);
+ if (flag == FLAG_LIBC4 && entry->flag != FLAG_LIBC4
+ && entry->flag != FLAG_ANY)
+ error (0, 0, _("libc4 library %s in wrong directory"), file_name);
+ }
+
+ /* Add library to list. */
+ struct dlib_entry *dlib_ptr;
+ for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
+ {
+ /* Is soname already in list? */
+ if (strcmp (dlib_ptr->soname, soname) == 0)
+ {
+ /* Prefer a file to a link, otherwise check which one
+ is newer. */
+ if ((!is_link && dlib_ptr->is_link)
+ || (is_link == dlib_ptr->is_link
+ && _dl_cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))
+ {
+ /* It's newer - add it. */
+ /* Flag should be the same - sanity check. */
+ if (dlib_ptr->flag != flag)
+ {
+ if (dlib_ptr->flag == FLAG_ELF
+ && (flag == FLAG_ELF_LIBC5 || flag == FLAG_ELF_LIBC6))
+ dlib_ptr->flag = flag;
+ else if ((dlib_ptr->flag == FLAG_ELF_LIBC5
+ || dlib_ptr->flag == FLAG_ELF_LIBC6)
+ && flag == FLAG_ELF)
+ dlib_ptr->flag = flag;
+ else
+ error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),
+ dlib_ptr->name, direntry->d_name,
+ entry->path);
+ }
+ free (dlib_ptr->name);
+ dlib_ptr->name = xstrdup (direntry->d_name);
+ dlib_ptr->is_link = is_link;
+ dlib_ptr->osversion = osversion;
+ }
+ /* Don't add this library, abort loop. */
+ /* Also free soname, since it's dynamically allocated. */
+ free (soname);
+ break;
+ }
+ }
+ /* Add the library if it's not already in. */
+ if (dlib_ptr == NULL)
+ {
+ dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
+ dlib_ptr->name = xstrdup (direntry->d_name);
+ dlib_ptr->soname = soname;
+ dlib_ptr->flag = flag;
+ dlib_ptr->is_link = is_link;
+ dlib_ptr->osversion = osversion;
+ /* Add at head of list. */
+ dlib_ptr->next = dlibs;
+ dlibs = dlib_ptr;
+ }
+ }
+
+ closedir (dir);
+
+ /* Now dlibs contains a list of all libs - add those to the cache
+ and created all symbolic links. */
+ struct dlib_entry *dlib_ptr;
+ for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
+ {
+ /* Don't create links to links. */
+ if (dlib_ptr->is_link == 0)
+ create_links (dir_name, entry->path, dlib_ptr->name,
+ dlib_ptr->soname);
+ if (opt_build_cache)
+ add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag,
+ dlib_ptr->osversion, hwcap);
+ }
+
+ /* Free all resources. */
+ while (dlibs)
+ {
+ dlib_ptr = dlibs;
+ free (dlib_ptr->soname);
+ free (dlib_ptr->name);
+ dlibs = dlibs->next;
+ free (dlib_ptr);
+ }
+
+ if (opt_chroot && dir_name)
+ free (dir_name);
+}
+
+/* Search through all libraries. */
+static void
+search_dirs (void)
+{
+ struct dir_entry *entry;
+
+ for (entry = dir_entries; entry != NULL; entry = entry->next)
+ search_dir (entry);
+
+ /* Free all allocated memory. */
+ while (dir_entries)
+ {
+ entry = dir_entries;
+ dir_entries = dir_entries->next;
+ free (entry->path);
+ free (entry);
+ }
+}
+
+
+static void parse_conf_include (const char *config_file, unsigned int lineno,
+ bool do_chroot, const char *pattern);
+
+/* Parse configuration file. */
+static void
+parse_conf (const char *filename, bool do_chroot)
+{
+ FILE *file = NULL;
+ char *line = NULL;
+ const char *canon;
+ size_t len = 0;
+ unsigned int lineno;
+
+ if (do_chroot && opt_chroot)
+ {
+ canon = chroot_canon (opt_chroot, filename);
+ if (canon)
+ file = fopen (canon, "r");
+ else
+ canon = filename;
+ }
+ else
+ {
+ canon = filename;
+ file = fopen (filename, "r");
+ }
+
+ if (file == NULL)
+ {
+ error (0, errno, _("\
+Warning: ignoring configuration file that cannot be opened: %s"),
+ canon);
+ if (canon != filename)
+ free ((char *) canon);
+ return;
+ }
+
+ /* No threads use this stream. */
+ __fsetlocking (file, FSETLOCKING_BYCALLER);
+
+ if (canon != filename)
+ free ((char *) canon);
+
+ lineno = 0;
+ do
+ {
+ ssize_t n = getline (&line, &len, file);
+ if (n < 0)
+ break;
+
+ ++lineno;
+ if (line[n - 1] == '\n')
+ line[n - 1] = '\0';
+
+ /* Because the file format does not know any form of quoting we
+ can search forward for the next '#' character and if found
+ make it terminating the line. */
+ *strchrnul (line, '#') = '\0';
+
+ /* Remove leading whitespace. NUL is no whitespace character. */
+ char *cp = line;
+ while (isspace (*cp))
+ ++cp;
+
+ /* If the line is blank it is ignored. */
+ if (cp[0] == '\0')
+ continue;
+
+ if (!strncmp (cp, "include", 7) && isblank (cp[7]))
+ {
+ char *dir;
+ cp += 8;
+ while ((dir = strsep (&cp, " \t")) != NULL)
+ if (dir[0] != '\0')
+ parse_conf_include (filename, lineno, do_chroot, dir);
+ }
+ else if (!strncasecmp (cp, "hwcap", 5) && isblank (cp[5]))
+ {
+ cp += 6;
+ char *p, *name = NULL;
+ unsigned long int n = strtoul (cp, &cp, 0);
+ if (cp != NULL && isblank (*cp))
+ while ((p = strsep (&cp, " \t")) != NULL)
+ if (p[0] != '\0')
+ {
+ if (name == NULL)
+ name = p;
+ else
+ {
+ name = NULL;
+ break;
+ }
+ }
+ if (name == NULL)
+ {
+ error (EXIT_FAILURE, 0, _("%s:%u: bad syntax in hwcap line"),
+ filename, lineno);
+ break;
+ }
+ if (n >= (64 - _DL_FIRST_EXTRA))
+ error (EXIT_FAILURE, 0,
+ _("%s:%u: hwcap index %lu above maximum %u"),
+ filename, lineno, n, 64 - _DL_FIRST_EXTRA - 1);
+ if (hwcap_extra[n] == NULL)
+ {
+ for (unsigned long int h = 0; h < (64 - _DL_FIRST_EXTRA); ++h)
+ if (hwcap_extra[h] != NULL && !strcmp (name, hwcap_extra[h]))
+ error (EXIT_FAILURE, 0,
+ _("%s:%u: hwcap index %lu already defined as %s"),
+ filename, lineno, h, name);
+ hwcap_extra[n] = xstrdup (name);
+ }
+ else
+ {
+ if (strcmp (name, hwcap_extra[n]))
+ error (EXIT_FAILURE, 0,
+ _("%s:%u: hwcap index %lu already defined as %s"),
+ filename, lineno, n, hwcap_extra[n]);
+ if (opt_verbose)
+ error (0, 0, _("%s:%u: duplicate hwcap %lu %s"),
+ filename, lineno, n, name);
+ }
+ }
+ else
+ add_dir (cp);
+ }
+ while (!feof_unlocked (file));
+
+ /* Free buffer and close file. */
+ free (line);
+ fclose (file);
+}
+
+/* Handle one word in an `include' line, a glob pattern of additional
+ config files to read. */
+static void
+parse_conf_include (const char *config_file, unsigned int lineno,
+ bool do_chroot, const char *pattern)
+{
+ if (opt_chroot && pattern[0] != '/')
+ error (EXIT_FAILURE, 0,
+ _("need absolute file name for configuration file when using -r"));
+
+ char *copy = NULL;
+ if (pattern[0] != '/' && strchr (config_file, '/') != NULL)
+ {
+ if (asprintf (&copy, "%s/%s", dirname (strdupa (config_file)),
+ pattern) < 0)
+ error (EXIT_FAILURE, 0, _("memory exhausted"));
+ pattern = copy;
+ }
+
+ glob64_t gl;
+ int result;
+ if (do_chroot && opt_chroot)
+ {
+ char *canon = chroot_canon (opt_chroot, pattern);
+ if (canon == NULL)
+ return;
+ result = glob64 (canon, 0, NULL, &gl);
+ free (canon);
+ }
+ else
+ result = glob64 (pattern, 0, NULL, &gl);
+
+ switch (result)
+ {
+ case 0:
+ for (size_t i = 0; i < gl.gl_pathc; ++i)
+ parse_conf (gl.gl_pathv[i], false);
+ globfree64 (&gl);
+ break;
+
+ case GLOB_NOMATCH:
+ break;
+
+ case GLOB_NOSPACE:
+ errno = ENOMEM;
+ case GLOB_ABORTED:
+ if (opt_verbose)
+ error (0, errno, _("%s:%u: cannot read directory %s"),
+ config_file, lineno, pattern);
+ break;
+
+ default:
+ abort ();
+ break;
+ }
+
+ free (copy);
+}
+
+/* Honour LD_HWCAP_MASK. */
+static void
+set_hwcap (void)
+{
+ char *mask = getenv ("LD_HWCAP_MASK");
+
+ if (mask)
+ hwcap_mask = strtoul (mask, NULL, 0);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ /* Set locale via LC_ALL. */
+ setlocale (LC_ALL, "");
+
+ /* Set the text message domain. */
+ textdomain (_libc_intl_domainname);
+
+ /* Parse and process arguments. */
+ int remaining;
+ argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+ /* Remaining arguments are additional directories if opt_manual_link
+ is not set. */
+ if (remaining != argc && !opt_manual_link)
+ {
+ int i;
+ for (i = remaining; i < argc; ++i)
+ if (opt_build_cache && argv[i][0] != '/')
+ error (EXIT_FAILURE, 0,
+ _("relative path `%s' used to build cache"),
+ argv[i]);
+ else
+ add_dir (argv[i]);
+ }
+
+ /* The last entry in hwcap_extra is reserved for the "tls" pseudo-hwcap which
+ indicates support for TLS. This pseudo-hwcap is only used by old versions
+ under which TLS support was optional. The entry is no longer needed, but
+ must remain for compatibility. */
+ hwcap_extra[63 - _DL_FIRST_EXTRA] = "tls";
+
+ set_hwcap ();
+
+ if (opt_chroot)
+ {
+ /* Normalize the path a bit, we might need it for printing later. */
+ char *endp = rawmemchr (opt_chroot, '\0');
+ while (endp > opt_chroot && endp[-1] == '/')
+ --endp;
+ *endp = '\0';
+ if (endp == opt_chroot)
+ opt_chroot = NULL;
+
+ if (opt_chroot)
+ {
+ /* It is faster to use chroot if we can. */
+ if (!chroot (opt_chroot))
+ {
+ if (chdir ("/"))
+ error (EXIT_FAILURE, errno, _("Can't chdir to /"));
+ opt_chroot = NULL;
+ }
+ }
+ }
+
+ if (cache_file == NULL)
+ {
+ cache_file = alloca (strlen (LD_SO_CACHE) + 1);
+ strcpy (cache_file, LD_SO_CACHE);
+ }
+
+ if (config_file == NULL)
+ config_file = LD_SO_CONF;
+
+ if (opt_print_cache)
+ {
+ if (opt_chroot)
+ {
+ char *p = chroot_canon (opt_chroot, cache_file);
+ if (p == NULL)
+ error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"),
+ cache_file);
+ cache_file = p;
+ }
+ print_cache (cache_file);
+ if (opt_chroot)
+ free (cache_file);
+ exit (0);
+ }
+
+ if (opt_chroot)
+ {
+ /* Canonicalize the directory name of cache_file, not cache_file,
+ because we'll rename a temporary cache file to it. */
+ char *p = strrchr (cache_file, '/');
+ char *canon = chroot_canon (opt_chroot,
+ p ? (*p = '\0', cache_file) : "/");
+
+ if (canon == NULL)
+ error (EXIT_FAILURE, errno,
+ _("Can't open cache file directory %s\n"),
+ p ? cache_file : "/");
+
+ if (p)
+ ++p;
+ else
+ p = cache_file;
+
+ cache_file = alloca (strlen (canon) + strlen (p) + 2);
+ sprintf (cache_file, "%s/%s", canon, p);
+ free (canon);
+ }
+
+ if (opt_manual_link)
+ {
+ /* Link all given libraries manually. */
+ int i;
+
+ for (i = remaining; i < argc; ++i)
+ manual_link (argv[i]);
+
+ exit (0);
+ }
+
+
+ if (opt_build_cache)
+ init_cache ();
+
+ if (!opt_only_cline)
+ {
+ parse_conf (config_file, true);
+
+ /* Always add the standard search paths. */
+ add_system_dir (SLIBDIR);
+ if (strcmp (SLIBDIR, LIBDIR))
+ add_system_dir (LIBDIR);
+ }
+
+ const char *aux_cache_file = _PATH_LDCONFIG_AUX_CACHE;
+ if (opt_chroot)
+ aux_cache_file = chroot_canon (opt_chroot, aux_cache_file);
+
+ if (! opt_ignore_aux_cache && aux_cache_file)
+ load_aux_cache (aux_cache_file);
+ else
+ init_aux_cache ();
+
+ search_dirs ();
+
+ if (opt_build_cache)
+ {
+ save_cache (cache_file);
+ if (aux_cache_file)
+ save_aux_cache (aux_cache_file);
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/ldd.bash.in b/REORG.TODO/elf/ldd.bash.in
new file mode 100644
index 0000000000..7dd1fccf24
--- /dev/null
+++ b/REORG.TODO/elf/ldd.bash.in
@@ -0,0 +1,203 @@
+#! @BASH@
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+
+# This is the `ldd' command, which lists what shared libraries are
+# used by given dynamically-linked executables. It works by invoking the
+# run-time dynamic linker as a command and setting the environment
+# variable LD_TRACE_LOADED_OBJECTS to a non-empty value.
+
+# We should be able to find the translation right at the beginning.
+TEXTDOMAIN=libc
+TEXTDOMAINDIR=@TEXTDOMAINDIR@
+
+RTLDLIST=@RTLD@
+warn=
+bind_now=
+verbose=
+
+while test $# -gt 0; do
+ case "$1" in
+ --vers | --versi | --versio | --version)
+ echo 'ldd @PKGVERSION@@VERSION@'
+ printf $"Copyright (C) %s Free Software Foundation, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+" "2017"
+ printf $"Written by %s and %s.
+" "Roland McGrath" "Ulrich Drepper"
+ exit 0
+ ;;
+ --h | --he | --hel | --help)
+ echo $"Usage: ldd [OPTION]... FILE...
+ --help print this help and exit
+ --version print version information and exit
+ -d, --data-relocs process data relocations
+ -r, --function-relocs process data and function relocations
+ -u, --unused print unused direct dependencies
+ -v, --verbose print all information
+"
+ printf $"For bug reporting instructions, please see:\\n%s.\\n" \
+ "@REPORT_BUGS_TO@"
+ exit 0
+ ;;
+ -d | --d | --da | --dat | --data | --data- | --data-r | --data-re | \
+ --data-rel | --data-relo | --data-reloc | --data-relocs)
+ warn=yes
+ shift
+ ;;
+ -r | --f | --fu | --fun | --func | --funct | --functi | --functio | \
+ --function | --function- | --function-r | --function-re | --function-rel | \
+ --function-relo | --function-reloc | --function-relocs)
+ warn=yes
+ bind_now=yes
+ shift
+ ;;
+ -v | --verb | --verbo | --verbos | --verbose)
+ verbose=yes
+ shift
+ ;;
+ -u | --u | --un | --unu | --unus | --unuse | --unused)
+ unused=yes
+ shift
+ ;;
+ --v | --ve | --ver)
+ echo >&2 $"ldd: option \`$1' is ambiguous"
+ exit 1
+ ;;
+ --) # Stop option processing.
+ shift; break
+ ;;
+ -*)
+ echo >&2 'ldd:' $"unrecognized option" "\`$1'"
+ echo >&2 $"Try \`ldd --help' for more information."
+ exit 1
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+nonelf ()
+{
+ # Maybe extra code for non-ELF binaries.
+ return 1;
+}
+
+add_env="LD_TRACE_LOADED_OBJECTS=1 LD_WARN=$warn LD_BIND_NOW=$bind_now"
+add_env="$add_env LD_VERBOSE=$verbose"
+if test "$unused" = yes; then
+ add_env="$add_env LD_DEBUG=\"$LD_DEBUG${LD_DEBUG:+,}unused\""
+fi
+
+# The following command substitution is needed to make ldd work in SELinux
+# environments where the RTLD might not have permission to write to the
+# terminal. The extra "x" character prevents the shell from trimming trailing
+# newlines from command substitution results. This function is defined as a
+# subshell compound list (using "(...)") to prevent parameter assignments from
+# affecting the calling shell execution environment.
+try_trace() (
+ output=$(eval $add_env '"$@"' 2>&1; rc=$?; printf 'x'; exit $rc)
+ rc=$?
+ printf '%s' "${output%x}"
+ return $rc
+)
+
+case $# in
+0)
+ echo >&2 'ldd:' $"missing file arguments"
+ echo >&2 $"Try \`ldd --help' for more information."
+ exit 1
+ ;;
+1)
+ single_file=t
+ ;;
+*)
+ single_file=f
+ ;;
+esac
+
+result=0
+for file do
+ # We don't list the file name when there is only one.
+ test $single_file = t || echo "${file}:"
+ case $file in
+ */*) :
+ ;;
+ *) file=./$file
+ ;;
+ esac
+ if test ! -e "$file"; then
+ echo "ldd: ${file}:" $"No such file or directory" >&2
+ result=1
+ elif test ! -f "$file"; then
+ echo "ldd: ${file}:" $"not regular file" >&2
+ result=1
+ elif test -r "$file"; then
+ test -x "$file" || echo 'ldd:' $"\
+warning: you do not have execution permission for" "\`$file'" >&2
+ RTLD=
+ ret=1
+ for rtld in ${RTLDLIST}; do
+ if test -x $rtld; then
+ verify_out=`${rtld} --verify "$file"`
+ ret=$?
+ case $ret in
+ [02]) RTLD=${rtld}; break;;
+ esac
+ fi
+ done
+ case $ret in
+ 0)
+ # If the program exits with exit code 5, it means the process has been
+ # invoked with __libc_enable_secure. Fall back to running it through
+ # the dynamic linker.
+ try_trace "$file"
+ rc=$?
+ if [ $rc = 5 ]; then
+ try_trace "$RTLD" "$file"
+ rc=$?
+ fi
+ [ $rc = 0 ] || result=1
+ ;;
+ 1)
+ # This can be a non-ELF binary or no binary at all.
+ nonelf "$file" || {
+ echo $" not a dynamic executable"
+ result=1
+ }
+ ;;
+ 2)
+ try_trace "$RTLD" "$file" || result=1
+ ;;
+ *)
+ echo 'ldd:' ${RTLD} $"exited with unknown exit code" "($ret)" >&2
+ exit 1
+ ;;
+ esac
+ else
+ echo 'ldd:' $"error: you do not have read permission for" "\`$file'" >&2
+ result=1
+ fi
+done
+
+exit $result
+# Local Variables:
+# mode:ksh
+# End:
diff --git a/REORG.TODO/elf/link.h b/REORG.TODO/elf/link.h
new file mode 100644
index 0000000000..0e223ce9f0
--- /dev/null
+++ b/REORG.TODO/elf/link.h
@@ -0,0 +1,194 @@
+/* Data structure for communication from the run-time dynamic linker for
+ loaded ELF shared objects.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LINK_H
+#define _LINK_H 1
+
+#include <features.h>
+#include <elf.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+
+/* We use this macro to refer to ELF types independent of the native wordsize.
+ `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */
+#define ElfW(type) _ElfW (Elf, __ELF_NATIVE_CLASS, type)
+#define _ElfW(e,w,t) _ElfW_1 (e, w, _##t)
+#define _ElfW_1(e,w,t) e##w##t
+
+#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
+#include <bits/link.h>
+
+/* Rendezvous structure used by the run-time dynamic linker to communicate
+ details of shared object loading to the debugger. If the executable's
+ dynamic section has a DT_DEBUG element, the run-time linker sets that
+ element's value to the address where this structure can be found. */
+
+struct r_debug
+ {
+ int r_version; /* Version number for this protocol. */
+
+ struct link_map *r_map; /* Head of the chain of loaded objects. */
+
+ /* This is the address of a function internal to the run-time linker,
+ that will always be called when the linker begins to map in a
+ library or unmap it, and again when the mapping change is complete.
+ The debugger can set a breakpoint at this address if it wants to
+ notice shared object mapping changes. */
+ ElfW(Addr) r_brk;
+ enum
+ {
+ /* This state value describes the mapping change taking place when
+ the `r_brk' address is called. */
+ RT_CONSISTENT, /* Mapping change is complete. */
+ RT_ADD, /* Beginning to add a new object. */
+ RT_DELETE /* Beginning to remove an object mapping. */
+ } r_state;
+
+ ElfW(Addr) r_ldbase; /* Base address the linker is loaded at. */
+ };
+
+/* This is the instance of that structure used by the dynamic linker. */
+extern struct r_debug _r_debug;
+
+/* This symbol refers to the "dynamic structure" in the `.dynamic' section
+ of whatever module refers to `_DYNAMIC'. So, to find its own
+ `struct r_debug', a program could do:
+ for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn)
+ if (dyn->d_tag == DT_DEBUG)
+ r_debug = (struct r_debug *) dyn->d_un.d_ptr;
+ */
+extern ElfW(Dyn) _DYNAMIC[];
+
+/* Structure describing a loaded shared object. The `l_next' and `l_prev'
+ members form a chain of all the shared objects loaded at startup.
+
+ These data structures exist in space used by the run-time dynamic linker;
+ modifying them may have disastrous results. */
+
+struct link_map
+ {
+ /* These first few members are part of the protocol with the debugger.
+ This is the same format used in SVR4. */
+
+ ElfW(Addr) l_addr; /* Difference between the address in the ELF
+ file and the addresses in memory. */
+ char *l_name; /* Absolute file name object was found in. */
+ ElfW(Dyn) *l_ld; /* Dynamic section of the shared object. */
+ struct link_map *l_next, *l_prev; /* Chain of loaded objects. */
+ };
+
+#ifdef __USE_GNU
+
+/* Version numbers for la_version handshake interface. */
+#define LAV_CURRENT 1
+
+/* Activity types signaled through la_activity. */
+enum
+ {
+ LA_ACT_CONSISTENT, /* Link map consistent again. */
+ LA_ACT_ADD, /* New object will be added. */
+ LA_ACT_DELETE /* Objects will be removed. */
+ };
+
+/* Values representing origin of name for dynamic loading. */
+enum
+ {
+ LA_SER_ORIG = 0x01, /* Original name. */
+ LA_SER_LIBPATH = 0x02, /* Directory from LD_LIBRARY_PATH. */
+ LA_SER_RUNPATH = 0x04, /* Directory from RPATH/RUNPATH. */
+ LA_SER_CONFIG = 0x08, /* Found through ldconfig. */
+ LA_SER_DEFAULT = 0x40, /* Default directory. */
+ LA_SER_SECURE = 0x80 /* Unused. */
+ };
+
+/* Values for la_objopen return value. */
+enum
+ {
+ LA_FLG_BINDTO = 0x01, /* Audit symbols bound to this object. */
+ LA_FLG_BINDFROM = 0x02 /* Audit symbols bound from this object. */
+ };
+
+/* Values for la_symbind flags parameter. */
+enum
+ {
+ LA_SYMB_NOPLTENTER = 0x01, /* la_pltenter will not be called. */
+ LA_SYMB_NOPLTEXIT = 0x02, /* la_pltexit will not be called. */
+ LA_SYMB_STRUCTCALL = 0x04, /* Return value is a structure. */
+ LA_SYMB_DLSYM = 0x08, /* Binding due to dlsym call. */
+ LA_SYMB_ALTVALUE = 0x10 /* Value has been changed by a previous
+ la_symbind call. */
+ };
+
+struct dl_phdr_info
+ {
+ ElfW(Addr) dlpi_addr;
+ const char *dlpi_name;
+ const ElfW(Phdr) *dlpi_phdr;
+ ElfW(Half) dlpi_phnum;
+
+ /* Note: Following members were introduced after the first
+ version of this structure was available. Check the SIZE
+ argument passed to the dl_iterate_phdr callback to determine
+ whether or not each later member is available. */
+
+ /* Incremented when a new object may have been added. */
+ __extension__ unsigned long long int dlpi_adds;
+ /* Incremented when an object may have been removed. */
+ __extension__ unsigned long long int dlpi_subs;
+
+ /* If there is a PT_TLS segment, its module ID as used in
+ TLS relocations, else zero. */
+ size_t dlpi_tls_modid;
+
+ /* The address of the calling thread's instance of this module's
+ PT_TLS segment, if it has one and it has been allocated
+ in the calling thread, otherwise a null pointer. */
+ void *dlpi_tls_data;
+ };
+
+__BEGIN_DECLS
+
+extern int dl_iterate_phdr (int (*__callback) (struct dl_phdr_info *,
+ size_t, void *),
+ void *__data);
+
+
+/* Prototypes for the ld.so auditing interfaces. These are not
+ defined anywhere in ld.so but instead have to be provided by the
+ auditing DSO. */
+extern unsigned int la_version (unsigned int __version);
+extern void la_activity (uintptr_t *__cookie, unsigned int __flag);
+extern char *la_objsearch (const char *__name, uintptr_t *__cookie,
+ unsigned int __flag);
+extern unsigned int la_objopen (struct link_map *__map, Lmid_t __lmid,
+ uintptr_t *__cookie);
+extern void la_preinit (uintptr_t *__cookie);
+extern uintptr_t la_symbind32 (Elf32_Sym *__sym, unsigned int __ndx,
+ uintptr_t *__refcook, uintptr_t *__defcook,
+ unsigned int *__flags, const char *__symname);
+extern uintptr_t la_symbind64 (Elf64_Sym *__sym, unsigned int __ndx,
+ uintptr_t *__refcook, uintptr_t *__defcook,
+ unsigned int *__flags, const char *__symname);
+extern unsigned int la_objclose (uintptr_t *__cookie);
+
+__END_DECLS
+
+#endif
+
+#endif /* link.h */
diff --git a/REORG.TODO/elf/loadfail.c b/REORG.TODO/elf/loadfail.c
new file mode 100644
index 0000000000..7531aa958e
--- /dev/null
+++ b/REORG.TODO/elf/loadfail.c
@@ -0,0 +1,42 @@
+#include <dlfcn.h>
+#include <error.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ void *su[5];
+ void *h;
+ int n;
+
+ mtrace ();
+
+ if ((su[0] = dlopen ("testobj1.so", RTLD_GLOBAL | RTLD_NOW)) == NULL
+ || (su[1] = dlopen ("testobj2.so", RTLD_GLOBAL | RTLD_NOW)) == NULL
+ || (su[2] = dlopen ("testobj3.so", RTLD_GLOBAL | RTLD_NOW)) == NULL
+ || (su[3] = dlopen ("testobj4.so", RTLD_GLOBAL | RTLD_NOW)) == NULL
+ || (su[4] = dlopen ("testobj5.so", RTLD_GLOBAL | RTLD_NOW)) == NULL)
+ error (EXIT_FAILURE, 0, "failed to load shared object: %s", dlerror ());
+
+ h = dlopen ("failobj.so", RTLD_GLOBAL | RTLD_NOW);
+
+ printf ("h = %p, %s\n", h, h == NULL ? "ok" : "fail");
+
+ for (n = 0; n < 5; ++n)
+ if (dlclose (su[n]) != 0)
+ {
+ printf ("failed to unload su[%d]: %s\n", n, dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ return h != NULL;
+}
+
+extern int foo (int a);
+int
+foo (int a)
+{
+ return 10;
+}
diff --git a/REORG.TODO/elf/loadtest.c b/REORG.TODO/elf/loadtest.c
new file mode 100644
index 0000000000..727469b496
--- /dev/null
+++ b/REORG.TODO/elf/loadtest.c
@@ -0,0 +1,202 @@
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <error.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* How many load/unload operations do we do. */
+#define TEST_ROUNDS 1000
+
+
+static struct
+{
+ /* Name of the module. */
+ const char *name;
+ /* The handle. */
+ void *handle;
+} testobjs[] =
+{
+ { "testobj1.so", NULL },
+ { "testobj2.so", NULL },
+ { "testobj3.so", NULL },
+ { "testobj4.so", NULL },
+ { "testobj5.so", NULL },
+ { "testobj6.so", NULL },
+};
+#define NOBJS (sizeof (testobjs) / sizeof (testobjs[0]))
+
+
+static const struct
+{
+ /* Name of a function to call. */
+ const char *fname;
+ /* Index in status and handle array. */
+ int index;
+ /* Options while loading the module. */
+ int options;
+} tests[] =
+{
+ { "obj1func2", 0, RTLD_LAZY },
+ { "obj1func1", 0, RTLD_LAZY | RTLD_GLOBAL },
+ { "obj1func1", 0, RTLD_NOW, },
+ { "obj1func2", 0, RTLD_NOW | RTLD_GLOBAL },
+ { "obj2func2", 1, RTLD_LAZY },
+ { "obj2func1", 1, RTLD_LAZY | RTLD_GLOBAL, },
+ { "obj2func1", 1, RTLD_NOW, },
+ { "obj2func2", 1, RTLD_NOW | RTLD_GLOBAL },
+ { "obj3func2", 2, RTLD_LAZY },
+ { "obj3func1", 2, RTLD_LAZY | RTLD_GLOBAL },
+ { "obj3func1", 2, RTLD_NOW },
+ { "obj3func2", 2, RTLD_NOW | RTLD_GLOBAL },
+ { "obj4func2", 3, RTLD_LAZY },
+ { "obj4func1", 3, RTLD_LAZY | RTLD_GLOBAL },
+ { "obj4func1", 3, RTLD_NOW },
+ { "obj4func2", 3, RTLD_NOW | RTLD_GLOBAL },
+ { "obj5func2", 4, RTLD_LAZY },
+ { "obj5func1", 4, RTLD_LAZY | RTLD_GLOBAL },
+ { "obj5func1", 4, RTLD_NOW },
+ { "obj5func2", 4, RTLD_NOW | RTLD_GLOBAL },
+ { "obj6func2", 5, RTLD_LAZY },
+ { "obj6func1", 5, RTLD_LAZY | RTLD_GLOBAL },
+ { "obj6func1", 5, RTLD_NOW },
+ { "obj6func2", 5, RTLD_NOW | RTLD_GLOBAL },
+};
+#define NTESTS (sizeof (tests) / sizeof (tests[0]))
+
+
+#include <include/link.h>
+
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
+#define OUT \
+ for (map = MAPS; map != NULL; map = map->l_next) \
+ if (map->l_type == lt_loaded) \
+ printf ("name = \"%s\", direct_opencount = %d\n", \
+ map->l_name, (int) map->l_direct_opencount); \
+ fflush (stdout)
+
+
+int
+main (int argc, char *argv[])
+{
+ int debug = argc > 1 && argv[1][0] != '\0';
+ int count = TEST_ROUNDS;
+ int result = 0;
+ struct link_map *map;
+
+ mtrace ();
+
+ /* Just a seed. */
+ srandom (TEST_ROUNDS);
+
+ if (debug)
+ {
+ puts ("in the beginning");
+ OUT;
+ }
+
+ while (count--)
+ {
+ int nr = random () % NTESTS;
+ int index = tests[nr].index;
+
+ printf ("%4d: %4d: ", count + 1, nr);
+ fflush (stdout);
+
+ if (testobjs[index].handle == NULL)
+ {
+ int (*fct) (int);
+
+ /* Load the object. */
+ testobjs[index].handle = dlopen (testobjs[index].name,
+ tests[nr].options);
+ if (testobjs[index].handle == NULL)
+ error (EXIT_FAILURE, 0, "cannot load `%s': %s",
+ testobjs[index].name, dlerror ());
+
+ /* Test the function call. */
+ fct = dlsym (testobjs[index].handle, tests[nr].fname);
+ if (fct == NULL)
+ error (EXIT_FAILURE, 0,
+ "cannot get function `%s' from shared object `%s': %s",
+ tests[nr].fname, testobjs[index].name, dlerror ());
+
+ fct (10);
+
+ printf ("successfully loaded `%s', handle %p\n",
+ testobjs[index].name, testobjs[index].handle);
+ }
+ else
+ {
+ if (dlclose (testobjs[index].handle) != 0)
+ {
+ printf ("failed to close %s\n", testobjs[index].name);
+ result = 1;
+ }
+ else
+ printf ("successfully unloaded `%s', handle %p\n",
+ testobjs[index].name, testobjs[index].handle);
+
+ testobjs[index].handle = NULL;
+
+ if (testobjs[0].handle == NULL
+ && testobjs[1].handle == NULL
+ && testobjs[5].handle == NULL)
+ {
+ /* In this case none of the objects above should be
+ present. */
+ for (map = MAPS; map != NULL; map = map->l_next)
+ if (map->l_type == lt_loaded
+ && (strstr (map->l_name, testobjs[0].name) != NULL
+ || strstr (map->l_name, testobjs[1].name) != NULL
+ || strstr (map->l_name, testobjs[5].name) != NULL))
+ {
+ printf ("`%s' is still loaded\n", map->l_name);
+ result = 1;
+ }
+ }
+ }
+
+ if (debug)
+ OUT;
+ }
+
+ /* Unload all loaded modules. */
+ for (count = 0; count < (int) NOBJS; ++count)
+ if (testobjs[count].handle != NULL)
+ {
+ printf ("\nclose: %s: l_initfini = %p, l_versions = %p\n",
+ testobjs[count].name,
+ ((struct link_map *) testobjs[count].handle)->l_initfini,
+ ((struct link_map *) testobjs[count].handle)->l_versions);
+
+ if (dlclose (testobjs[count].handle) != 0)
+ {
+ printf ("failed to close %s\n", testobjs[count].name);
+ result = 1;
+ }
+ }
+
+ /* Check whether all files are unloaded. */
+ for (map = MAPS; map != NULL; map = map->l_next)
+ if (map->l_type == lt_loaded)
+ {
+ printf ("name = \"%s\", direct_opencount = %d\n",
+ map->l_name, (int) map->l_direct_opencount);
+ result = 1;
+ }
+
+ return result;
+}
+
+
+extern int foo (int a);
+int
+foo (int a)
+{
+ return a - 1;
+}
diff --git a/REORG.TODO/elf/ltglobmod1.c b/REORG.TODO/elf/ltglobmod1.c
new file mode 100644
index 0000000000..300fa9a89f
--- /dev/null
+++ b/REORG.TODO/elf/ltglobmod1.c
@@ -0,0 +1,7 @@
+extern int bar (void);
+
+int
+bar (void)
+{
+ return 42;
+}
diff --git a/REORG.TODO/elf/ltglobmod2.c b/REORG.TODO/elf/ltglobmod2.c
new file mode 100644
index 0000000000..33f14cc980
--- /dev/null
+++ b/REORG.TODO/elf/ltglobmod2.c
@@ -0,0 +1,33 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int bar (void);
+extern int foo (void);
+
+int
+foo (void)
+{
+ void *h;
+ int res;
+
+ /* Load ltglobalmod1 in the global namespace. */
+ h = dlopen ("ltglobmod1.so", RTLD_GLOBAL | RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("%s: cannot open %s: %s",
+ __FUNCTION__, "ltglobmod1.so", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ /* Call bar. This is undefined in the DSO. */
+ puts ("about to call `bar'");
+ fflush (stdout);
+ res = bar ();
+
+ printf ("bar returned %d\n", res);
+
+ dlclose (h);
+
+ return res != 42;
+}
diff --git a/REORG.TODO/elf/multiload.c b/REORG.TODO/elf/multiload.c
new file mode 100644
index 0000000000..e85cc96589
--- /dev/null
+++ b/REORG.TODO/elf/multiload.c
@@ -0,0 +1,105 @@
+#include <dlfcn.h>
+#include <errno.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int
+main (void)
+{
+ void *a;
+ void *b;
+ void *c;
+ void *d;
+ char *wd;
+ char *base;
+ char *buf;
+
+ mtrace ();
+
+ /* Change to the binary directory. */
+ if (chdir (OBJDIR) != 0)
+ {
+ printf ("cannot change to `%s': %m", OBJDIR);
+ exit (EXIT_FAILURE);
+ }
+
+ wd = getcwd (NULL, 0);
+ base = basename (wd);
+ buf = alloca (strlen (wd) + strlen (base) + 5 + sizeof "testobj1.so");
+
+ printf ("loading `%s'\n", "./testobj1.so");
+ a = dlopen ("./testobj1.so", RTLD_NOW);
+ if (a == NULL)
+ {
+ printf ("cannot load `./testobj1.so': %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ stpcpy (stpcpy (stpcpy (buf, "../"), base), "/testobj1.so");
+ printf ("loading `%s'\n", buf);
+ b = dlopen (buf, RTLD_NOW);
+ if (b == NULL)
+ {
+ printf ("cannot load `%s': %s\n", buf, dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ stpcpy (stpcpy (buf, wd), "/testobj1.so");
+ printf ("loading `%s'\n", buf);
+ c = dlopen (buf, RTLD_NOW);
+ if (c == NULL)
+ {
+ printf ("cannot load `%s': %s\n", buf, dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ stpcpy (stpcpy (stpcpy (stpcpy (buf, wd), "/../"), base), "/testobj1.so");
+ printf ("loading `%s'\n", buf);
+ d = dlopen (buf, RTLD_NOW);
+ if (d == NULL)
+ {
+ printf ("cannot load `%s': %s\n", buf, dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ if (a != b || b != c || c != d)
+ {
+ puts ("shared object loaded more than once");
+ exit (EXIT_FAILURE);
+ }
+
+ if (dlclose (a) != 0)
+ {
+ puts ("closing `a' failed");
+ exit (EXIT_FAILURE);
+ }
+ if (dlclose (b) != 0)
+ {
+ puts ("closing `a' failed");
+ exit (EXIT_FAILURE);
+ }
+ if (dlclose (c) != 0)
+ {
+ puts ("closing `a' failed");
+ exit (EXIT_FAILURE);
+ }
+ if (dlclose (d) != 0)
+ {
+ puts ("closing `a' failed");
+ exit (EXIT_FAILURE);
+ }
+
+ free (wd);
+
+ return 0;
+}
+
+extern int foo (int a);
+int
+foo (int a)
+{
+ return a;
+}
diff --git a/REORG.TODO/elf/neededobj1.c b/REORG.TODO/elf/neededobj1.c
new file mode 100644
index 0000000000..eb55adab39
--- /dev/null
+++ b/REORG.TODO/elf/neededobj1.c
@@ -0,0 +1,6 @@
+extern void c_function (void);
+
+void
+c_function (void)
+{
+}
diff --git a/REORG.TODO/elf/neededobj2.c b/REORG.TODO/elf/neededobj2.c
new file mode 100644
index 0000000000..5ad8a51d62
--- /dev/null
+++ b/REORG.TODO/elf/neededobj2.c
@@ -0,0 +1,8 @@
+extern void b_function (void);
+extern void c_function (void);
+
+void
+b_function (void)
+{
+ c_function();
+}
diff --git a/REORG.TODO/elf/neededobj3.c b/REORG.TODO/elf/neededobj3.c
new file mode 100644
index 0000000000..da25329aa7
--- /dev/null
+++ b/REORG.TODO/elf/neededobj3.c
@@ -0,0 +1,10 @@
+extern void a_function (void);
+extern void b_function (void);
+extern void c_function (void);
+
+void
+a_function (void)
+{
+ b_function ();
+ c_function ();
+}
diff --git a/REORG.TODO/elf/neededobj4.c b/REORG.TODO/elf/neededobj4.c
new file mode 100644
index 0000000000..3ea8540047
--- /dev/null
+++ b/REORG.TODO/elf/neededobj4.c
@@ -0,0 +1,12 @@
+extern void a_function (void);
+extern void b_function (void);
+extern void c_function (void);
+extern void d_function (void);
+
+void
+d_function (void)
+{
+ a_function ();
+ b_function ();
+ c_function ();
+}
diff --git a/REORG.TODO/elf/neededobj5.c b/REORG.TODO/elf/neededobj5.c
new file mode 100644
index 0000000000..2d629b0880
--- /dev/null
+++ b/REORG.TODO/elf/neededobj5.c
@@ -0,0 +1,5 @@
+extern void a1_function (void);
+
+void a1_function (void)
+{
+}
diff --git a/REORG.TODO/elf/neededobj6.c b/REORG.TODO/elf/neededobj6.c
new file mode 100644
index 0000000000..639b6f195e
--- /dev/null
+++ b/REORG.TODO/elf/neededobj6.c
@@ -0,0 +1,7 @@
+extern void a1_function (void);
+extern void a2_function (void);
+
+void a2_function (void)
+{
+ a1_function ();
+}
diff --git a/REORG.TODO/elf/neededtest.c b/REORG.TODO/elf/neededtest.c
new file mode 100644
index 0000000000..3cea499314
--- /dev/null
+++ b/REORG.TODO/elf/neededtest.c
@@ -0,0 +1,125 @@
+#include <dlfcn.h>
+#include <libintl.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
+static int
+check_loaded_objects (const char **loaded)
+{
+ struct link_map *lm;
+ int n;
+ int *found = NULL;
+ int errors = 0;
+
+ for (n = 0; loaded[n]; n++)
+ /* NOTHING */;
+
+ if (n)
+ {
+ found = (int *) alloca (sizeof (int) * n);
+ memset (found, 0, sizeof (int) * n);
+ }
+
+ printf(" Name\n");
+ printf(" --------------------------------------------------------\n");
+ for (lm = MAPS; lm; lm = lm->l_next)
+ {
+ if (lm->l_name && lm->l_name[0])
+ printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
+ if (lm->l_type == lt_loaded && lm->l_name)
+ {
+ int match = 0;
+ for (n = 0; loaded[n] != NULL; n++)
+ {
+ if (strcmp (basename (loaded[n]), basename (lm->l_name)) == 0)
+ {
+ found[n] = 1;
+ match = 1;
+ break;
+ }
+ }
+
+ if (match == 0)
+ {
+ ++errors;
+ printf ("ERRORS: %s is not unloaded\n", lm->l_name);
+ }
+ }
+ }
+
+ for (n = 0; loaded[n] != NULL; n++)
+ {
+ if (found[n] == 0)
+ {
+ ++errors;
+ printf ("ERRORS: %s is not loaded\n", loaded[n]);
+ }
+ }
+
+ return errors;
+}
+
+int
+main (void)
+{
+ void *obj2[2];
+ void *obj3;
+ const char *loaded[] = { NULL, NULL, NULL, NULL };
+ int errors = 0;
+
+ printf ("\nThis is what is in memory now:\n");
+ errors += check_loaded_objects (loaded);
+
+ printf( "Loading shared object neededobj3.so\n");
+ obj3 = dlopen( "neededobj3.so", RTLD_LAZY);
+ if (obj3 == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ loaded[0] = "neededobj1.so";
+ loaded[1] = "neededobj2.so";
+ loaded[2] = "neededobj3.so";
+ errors += check_loaded_objects (loaded);
+
+ printf ("Now loading shared object neededobj2.so\n");
+ obj2[0] = dlopen ("neededobj2.so", RTLD_LAZY);
+ if (obj2[0] == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ errors += check_loaded_objects (loaded);
+
+ printf ("And loading shared object neededobj2.so again\n");
+ obj2[1] = dlopen ("neededobj2.so", RTLD_LAZY);
+ if (obj2[1] == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ errors += check_loaded_objects (loaded);
+
+ printf ("Closing neededobj2.so for the first time\n");
+ dlclose (obj2[0]);
+ errors += check_loaded_objects (loaded);
+
+ printf ("Closing neededobj3.so\n");
+ dlclose (obj3);
+ loaded[2] = NULL;
+ errors += check_loaded_objects (loaded);
+
+ printf ("Closing neededobj2.so for the second time\n");
+ dlclose (obj2[1]);
+ loaded[0] = NULL;
+ loaded[1] = NULL;
+ errors += check_loaded_objects (loaded);
+
+ if (errors != 0)
+ printf ("%d errors found\n", errors);
+ return errors;
+}
diff --git a/REORG.TODO/elf/neededtest2.c b/REORG.TODO/elf/neededtest2.c
new file mode 100644
index 0000000000..17c75f2ba3
--- /dev/null
+++ b/REORG.TODO/elf/neededtest2.c
@@ -0,0 +1,118 @@
+#include <dlfcn.h>
+#include <libintl.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
+static int
+check_loaded_objects (const char **loaded)
+{
+ struct link_map *lm;
+ int n;
+ int *found = NULL;
+ int errors = 0;
+
+ for (n = 0; loaded[n]; n++)
+ /* NOTHING */;
+
+ if (n)
+ {
+ found = (int *) alloca (sizeof (int) * n);
+ memset (found, 0, sizeof (int) * n);
+ }
+
+ printf(" Name\n");
+ printf(" --------------------------------------------------------\n");
+ for (lm = MAPS; lm; lm = lm->l_next)
+ {
+ if (lm->l_name && lm->l_name[0])
+ printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
+ if (lm->l_type == lt_loaded && lm->l_name)
+ {
+ int match = 0;
+ for (n = 0; loaded[n] != NULL; n++)
+ {
+ if (strcmp (basename (loaded[n]), basename (lm->l_name)) == 0)
+ {
+ found[n] = 1;
+ match = 1;
+ break;
+ }
+ }
+
+ if (match == 0)
+ {
+ ++errors;
+ printf ("ERRORS: %s is not unloaded\n", lm->l_name);
+ }
+ }
+ }
+
+ for (n = 0; loaded[n] != NULL; n++)
+ {
+ if (found[n] == 0)
+ {
+ ++errors;
+ printf ("ERRORS: %s is not loaded\n", loaded[n]);
+ }
+ }
+
+ return errors;
+}
+
+int
+main (void)
+{
+ void *obj2;
+ void *obj3[2];
+ const char *loaded[] = { NULL, NULL, NULL, NULL };
+ int errors = 0;
+
+ printf ("\nThis is what is in memory now:\n");
+ errors += check_loaded_objects (loaded);
+ printf ("\nLoading shared object neededobj2.so\n");
+ obj2 = dlopen ("neededobj2.so", RTLD_LAZY);
+ if (obj2 == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ loaded[0] = "neededobj1.so";
+ loaded[1] = "neededobj2.so";
+ errors += check_loaded_objects (loaded);
+ printf ("\nLoading shared object neededobj3.so\n");
+ obj3[0] = dlopen( "neededobj3.so", RTLD_LAZY);
+ if (obj3[0] == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ loaded[2] = "neededobj3.so";
+ errors += check_loaded_objects (loaded);
+ printf ("\nNow loading shared object neededobj3.so again\n");
+ obj3[1] = dlopen ("neededobj3.so", RTLD_LAZY);
+ if (obj3[1] == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ errors += check_loaded_objects (loaded);
+ printf ("\nClosing neededobj3.so once\n");
+ dlclose (obj3[0]);
+ errors += check_loaded_objects (loaded);
+ printf ("\nClosing neededobj2.so\n");
+ dlclose (obj2);
+ errors += check_loaded_objects (loaded);
+ printf ("\nClosing neededobj3.so for the second time\n");
+ dlclose (obj3[1]);
+ loaded[0] = NULL;
+ loaded[1] = NULL;
+ loaded[2] = NULL;
+ errors += check_loaded_objects (loaded);
+ if (errors != 0)
+ printf ("%d errors found\n", errors);
+ return errors;
+}
diff --git a/REORG.TODO/elf/neededtest3.c b/REORG.TODO/elf/neededtest3.c
new file mode 100644
index 0000000000..41970cf2c7
--- /dev/null
+++ b/REORG.TODO/elf/neededtest3.c
@@ -0,0 +1,129 @@
+#include <dlfcn.h>
+#include <libintl.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
+static int
+check_loaded_objects (const char **loaded)
+{
+ struct link_map *lm;
+ int n;
+ int *found = NULL;
+ int errors = 0;
+
+ for (n = 0; loaded[n]; n++)
+ /* NOTHING */;
+
+ if (n)
+ {
+ found = (int *) alloca (sizeof (int) * n);
+ memset (found, 0, sizeof (int) * n);
+ }
+
+ printf(" Name\n");
+ printf(" --------------------------------------------------------\n");
+ for (lm = MAPS; lm; lm = lm->l_next)
+ {
+ if (lm->l_name && lm->l_name[0])
+ printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
+ if (lm->l_type == lt_loaded && lm->l_name)
+ {
+ int match = 0;
+ for (n = 0; loaded[n] != NULL; n++)
+ {
+ if (strcmp (basename (loaded[n]), basename (lm->l_name)) == 0)
+ {
+ found[n] = 1;
+ match = 1;
+ break;
+ }
+ }
+
+ if (match == 0)
+ {
+ ++errors;
+ printf ("ERRORS: %s is not unloaded\n", lm->l_name);
+ }
+ }
+ }
+
+ for (n = 0; loaded[n] != NULL; n++)
+ {
+ if (found[n] == 0)
+ {
+ ++errors;
+ printf ("ERRORS: %s is not loaded\n", loaded[n]);
+ }
+ }
+
+ return errors;
+}
+
+int
+main (void)
+{
+ void *obj2;
+ void *obj3;
+ void *obj4;
+ const char *loaded[] = { NULL, NULL, NULL, NULL, NULL };
+ int errors = 0;
+
+ printf ("\nThis is what is in memory now:\n");
+ errors += check_loaded_objects (loaded);
+
+ printf ("Now loading shared object neededobj2.so\n");
+ obj2 = dlopen ("neededobj2.so", RTLD_LAZY);
+ if (obj2 == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ loaded[0] = "neededobj1.so";
+ loaded[1] = "neededobj2.so";
+ errors += check_loaded_objects (loaded);
+
+ printf( "Loading shared object neededobj3.so\n");
+ obj3 = dlopen( "neededobj3.so", RTLD_LAZY);
+ if (obj3 == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ loaded[2] = "neededobj3.so";
+ errors += check_loaded_objects (loaded);
+
+
+ printf( "Loading shared object neededobj4.so\n");
+ obj4 = dlopen( "neededobj4.so", RTLD_LAZY);
+ if (obj4 == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ loaded[3] = "neededobj4.so";
+ errors += check_loaded_objects (loaded);
+
+ printf ("Closing neededobj2.so\n");
+ dlclose (obj2);
+ errors += check_loaded_objects (loaded);
+
+ printf ("Closing neededobj3.so\n");
+ dlclose (obj3);
+ errors += check_loaded_objects (loaded);
+
+ printf ("Closing neededobj4.so\n");
+ dlclose (obj4);
+ loaded[0] = NULL;
+ loaded[1] = NULL;
+ loaded[2] = NULL;
+ loaded[3] = NULL;
+ errors += check_loaded_objects (loaded);
+
+ if (errors != 0)
+ printf ("%d errors found\n", errors);
+ return errors;
+}
diff --git a/REORG.TODO/elf/neededtest4.c b/REORG.TODO/elf/neededtest4.c
new file mode 100644
index 0000000000..0ae0b7ff47
--- /dev/null
+++ b/REORG.TODO/elf/neededtest4.c
@@ -0,0 +1,158 @@
+#include <dlfcn.h>
+#include <libintl.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
+static int
+check_loaded_objects (const char **loaded)
+{
+ struct link_map *lm;
+ int n;
+ int *found = NULL;
+ int errors = 0;
+
+ for (n = 0; loaded[n]; n++)
+ /* NOTHING */;
+
+ if (n)
+ {
+ found = (int *) alloca (sizeof (int) * n);
+ memset (found, 0, sizeof (int) * n);
+ }
+
+ printf(" Name\n");
+ printf(" --------------------------------------------------------\n");
+ for (lm = MAPS; lm; lm = lm->l_next)
+ {
+ if (lm->l_name && lm->l_name[0])
+ printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
+ if (lm->l_type == lt_loaded && lm->l_name)
+ {
+ int match = 0;
+ for (n = 0; loaded[n] != NULL; n++)
+ {
+ if (strcmp (basename (loaded[n]), basename (lm->l_name)) == 0)
+ {
+ found[n] = 1;
+ match = 1;
+ break;
+ }
+ }
+
+ if (match == 0)
+ {
+ ++errors;
+ printf ("ERRORS: %s is not unloaded\n", lm->l_name);
+ }
+ }
+ }
+
+ for (n = 0; loaded[n] != NULL; n++)
+ {
+ if (found[n] == 0)
+ {
+ ++errors;
+ printf ("ERRORS: %s is not loaded\n", loaded[n]);
+ }
+ }
+
+ return errors;
+}
+
+extern void c_function (void);
+extern char *dirname (const char *__filename);
+
+int
+main (int argc, char **argv)
+{
+ void *obj;
+ const char *loaded[] = { NULL, NULL, NULL};
+ int errors = 0;
+ void (*f) (void);
+ const char *dir = dirname (argv [0]);
+ char *oldfilename;
+ char *newfilename;
+
+ c_function ();
+
+ printf ("\nThis is what is in memory now:\n");
+ errors += check_loaded_objects (loaded);
+
+ printf( "Loading shared object neededobj6.so\n");
+ obj = dlopen( "neededobj6.so", RTLD_LAZY);
+ if (obj == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ f = dlsym (obj, "a2_function");
+ if (f == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ f ();
+ loaded[0] = "neededobj5.so";
+ loaded[1] = "neededobj6.so";
+ errors += check_loaded_objects (loaded);
+
+ printf ("Closing neededobj6.so\n");
+ dlclose (obj);
+ loaded[0] = NULL;
+ errors += check_loaded_objects (loaded);
+
+ printf ("Rename neededobj5.so\n");
+ oldfilename = alloca (strlen (dir) + 1 + sizeof ("neededobj5.so"));
+ strcpy (oldfilename, dir);
+ strcat (oldfilename, "/");
+ strcat (oldfilename, "neededobj5.so");
+ newfilename = alloca (strlen (oldfilename) + sizeof (".renamed"));
+ strcpy (newfilename, oldfilename);
+ strcat (newfilename, ".renamed");
+ if (rename (oldfilename, newfilename))
+ {
+ perror ("rename");
+ exit (1);
+ }
+
+ printf( "Loading shared object neededobj6.so\n");
+ obj = dlopen( "neededobj6.so", RTLD_LAZY);
+ if (obj == NULL)
+ printf ("%s\n", dlerror ());
+ else
+ {
+ printf ("neededobj6.so should fail to load\n");
+ exit (1);
+ }
+
+ printf( "Loading shared object neededobj1.so\n");
+ obj = dlopen( "neededobj1.so", RTLD_LAZY);
+ if (obj == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ errors += check_loaded_objects (loaded);
+ f = dlsym (obj, "c_function");
+ if (f == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ f ();
+
+ printf ("Restore neededobj5.so\n");
+ if (rename (newfilename, oldfilename))
+ {
+ perror ("rename");
+ exit (1);
+ }
+
+ if (errors != 0)
+ printf ("%d errors found\n", errors);
+ return errors;
+}
diff --git a/REORG.TODO/elf/next.c b/REORG.TODO/elf/next.c
new file mode 100644
index 0000000000..a0d532b8c3
--- /dev/null
+++ b/REORG.TODO/elf/next.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+
+
+extern int successful_rtld_next_test (void);
+extern void *failing_rtld_next_use (void);
+
+
+static int
+do_test (void)
+{
+ int result;
+ void *addr;
+
+ /* First try call a function which uses RTLD_NEXT and calls that
+ function. */
+ result = successful_rtld_next_test ();
+ if (result == 42)
+ {
+ puts ("RTLD_NEXT seems to work for existing functions");
+ result = 0;
+ }
+ else
+ {
+ printf ("Heh? `successful_rtld_next_test' returned %d\n", result);
+ result = 1;
+ }
+
+ /* Next try a function which tries to get a function with RTLD_NEXT
+ but that fails. This dlsym() call should return a NULL pointer
+ and do nothing else. */
+ addr = failing_rtld_next_use ();
+ if (addr == NULL)
+ puts ("dlsym returned NULL for non-existing function. Good");
+ else
+ {
+ puts ("dlsym found something !?");
+ result = 1;
+ }
+
+ return result;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/nextmod1.c b/REORG.TODO/elf/nextmod1.c
new file mode 100644
index 0000000000..56de3536a0
--- /dev/null
+++ b/REORG.TODO/elf/nextmod1.c
@@ -0,0 +1,30 @@
+#include <dlfcn.h>
+
+extern int successful_rtld_next_test (void);
+extern void *failing_rtld_next_use (void);
+
+int nextmod1_dummy_var;
+
+int
+successful_rtld_next_test (void)
+{
+ int (*fp) (void);
+
+ /* Get the next function... */
+ fp = (int (*) (void)) dlsym (RTLD_NEXT, __FUNCTION__);
+
+ /* ...and simply call it. */
+ return fp ();
+}
+
+
+void *
+failing_rtld_next_use (void)
+{
+ void *ret = dlsym (RTLD_NEXT, __FUNCTION__);
+
+ /* Ensure we are not tail call optimized, because then RTLD_NEXT
+ might return this function. */
+ ++nextmod1_dummy_var;
+ return ret;
+}
diff --git a/REORG.TODO/elf/nextmod2.c b/REORG.TODO/elf/nextmod2.c
new file mode 100644
index 0000000000..b2c435f341
--- /dev/null
+++ b/REORG.TODO/elf/nextmod2.c
@@ -0,0 +1,10 @@
+/* Very elaborated function. */
+
+extern int successful_rtld_next_test (void);
+
+
+int
+successful_rtld_next_test (void)
+{
+ return 42;
+}
diff --git a/REORG.TODO/elf/nodel2mod1.c b/REORG.TODO/elf/nodel2mod1.c
new file mode 100644
index 0000000000..acddc4cf8b
--- /dev/null
+++ b/REORG.TODO/elf/nodel2mod1.c
@@ -0,0 +1,19 @@
+#include <stdlib.h>
+void
+foo (void)
+{
+ exit (0);
+}
+
+void
+__attribute__((destructor))
+bar (void)
+{
+ static int i;
+ foo ();
+ ++i;
+}
+void
+baz (void)
+{
+}
diff --git a/REORG.TODO/elf/nodel2mod2.c b/REORG.TODO/elf/nodel2mod2.c
new file mode 100644
index 0000000000..d0020240a8
--- /dev/null
+++ b/REORG.TODO/elf/nodel2mod2.c
@@ -0,0 +1,7 @@
+void
+__attribute__((constructor))
+xxx (void)
+{
+ extern void baz (void);
+ baz ();
+}
diff --git a/REORG.TODO/elf/nodel2mod3.c b/REORG.TODO/elf/nodel2mod3.c
new file mode 100644
index 0000000000..6d1a0d47b7
--- /dev/null
+++ b/REORG.TODO/elf/nodel2mod3.c
@@ -0,0 +1 @@
+int x;
diff --git a/REORG.TODO/elf/nodelete.c b/REORG.TODO/elf/nodelete.c
new file mode 100644
index 0000000000..c8d71152f2
--- /dev/null
+++ b/REORG.TODO/elf/nodelete.c
@@ -0,0 +1,210 @@
+#include <dlfcn.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+
+
+static sigjmp_buf jmpbuf;
+
+
+int fini_ran;
+
+
+static void
+__attribute__ ((noreturn))
+handler (int sig)
+{
+ siglongjmp (jmpbuf, 1);
+}
+
+
+static int
+do_test (void)
+{
+ /* We are testing the two possibilities to mark an object as not deletable:
+ - marked on the linker commandline with `-z nodelete'
+ - with the RTLD_NODELETE flag at dlopen()-time.
+
+ The test we are performing should be safe. We are loading the objects,
+ get the address of variables in the respective object, unload the object
+ and then try to read the variable. If the object is unloaded this
+ should lead to an segmentation fault. */
+ int result = 0;
+ void *p;
+ struct sigaction sa;
+
+ sa.sa_handler = handler;
+ sigfillset (&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+
+ if (sigaction (SIGSEGV, &sa, NULL) == -1)
+ printf ("cannot install signal handler: %m\n");
+
+ p = dlopen ("nodelmod1.so", RTLD_LAZY);
+ if (p == NULL)
+ {
+ printf ("failed to load \"nodelmod1.so\": %s\n", dlerror ());
+ result = 1;
+ }
+ else
+ {
+ int *varp;
+
+ puts ("succeeded loading \"nodelmod1.so\"");
+
+ varp = dlsym (p, "var1");
+ if (varp == NULL)
+ {
+ puts ("failed to get address of \"var1\" in \"nodelmod1.so\"");
+ result = 1;
+ }
+ else
+ {
+ *varp = 20000720;
+
+ /* Now close the object. */
+ fini_ran = 0;
+ if (dlclose (p) != 0)
+ {
+ puts ("failed to close \"nodelmod1.so\"");
+ result = 1;
+ }
+ else if (! sigsetjmp (jmpbuf, 1))
+ {
+ /* Access the variable again. */
+ if (*varp != 20000720)
+ {
+ puts ("\"var1\" value not correct");
+ result = 1;
+ }
+ else if (fini_ran != 0)
+ {
+ puts ("destructor of \"nodelmod1.so\" ran");
+ result = 1;
+ }
+ else
+ puts ("-z nodelete test succeeded");
+ }
+ else
+ {
+ /* We caught an segmentation fault. */
+ puts ("\"nodelmod1.so\" got deleted");
+ result = 1;
+ }
+ }
+ }
+
+ p = dlopen ("nodelmod2.so", RTLD_LAZY | RTLD_NODELETE);
+ if (p == NULL)
+ {
+ printf ("failed to load \"nodelmod2.so\": %s\n", dlerror ());
+ result = 1;
+ }
+ else
+ {
+ int *varp;
+
+ puts ("succeeded loading \"nodelmod2.so\"");
+
+ varp = dlsym (p, "var2");
+ if (varp == NULL)
+ {
+ puts ("failed to get address of \"var2\" in \"nodelmod2.so\"");
+ result = 1;
+ }
+ else
+ {
+ *varp = 42;
+
+ /* Now close the object. */
+ fini_ran = 0;
+ if (dlclose (p) != 0)
+ {
+ puts ("failed to close \"nodelmod2.so\"");
+ result = 1;
+ }
+ else if (! sigsetjmp (jmpbuf, 1))
+ {
+ /* Access the variable again. */
+ if (*varp != 42)
+ {
+ puts ("\"var2\" value not correct");
+ result = 1;
+ }
+ else if (fini_ran != 0)
+ {
+ puts ("destructor of \"nodelmod2.so\" ran");
+ result = 1;
+ }
+ else
+ puts ("RTLD_NODELETE test succeeded");
+ }
+ else
+ {
+ /* We caught an segmentation fault. */
+ puts ("\"nodelmod2.so\" got deleted");
+ result = 1;
+ }
+ }
+ }
+
+ p = dlopen ("nodelmod3.so", RTLD_LAZY);
+ if (p == NULL)
+ {
+ printf ("failed to load \"nodelmod3.so\": %s\n", dlerror ());
+ result = 1;
+ }
+ else
+ {
+ int *(*fctp) (void);
+
+ puts ("succeeded loading \"nodelmod3.so\"");
+
+ fctp = dlsym (p, "addr");
+ if (fctp == NULL)
+ {
+ puts ("failed to get address of \"addr\" in \"nodelmod3.so\"");
+ result = 1;
+ }
+ else
+ {
+ int *varp = fctp ();
+
+ *varp = -1;
+
+ /* Now close the object. */
+ fini_ran = 0;
+ if (dlclose (p) != 0)
+ {
+ puts ("failed to close \"nodelmod3.so\"");
+ result = 1;
+ }
+ else if (! sigsetjmp (jmpbuf, 1))
+ {
+ /* Access the variable again. */
+ if (*varp != -1)
+ {
+ puts ("\"var_in_mod4\" value not correct");
+ result = 1;
+ }
+ else if (fini_ran != 0)
+ {
+ puts ("destructor of \"nodelmod4.so\" ran");
+ result = 1;
+ }
+ else
+ puts ("-z nodelete in dependency succeeded");
+ }
+ else
+ {
+ /* We caught an segmentation fault. */
+ puts ("\"nodelmod4.so\" got deleted");
+ result = 1;
+ }
+ }
+ }
+
+ return result;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/nodelete2.c b/REORG.TODO/elf/nodelete2.c
new file mode 100644
index 0000000000..b3d7e31a08
--- /dev/null
+++ b/REORG.TODO/elf/nodelete2.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+int
+main (void)
+{
+ void *handle = dlopen ("nodel2mod3.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ dlclose (handle);
+ exit (1);
+}
diff --git a/REORG.TODO/elf/nodelmod1.c b/REORG.TODO/elf/nodelmod1.c
new file mode 100644
index 0000000000..fc24a7b172
--- /dev/null
+++ b/REORG.TODO/elf/nodelmod1.c
@@ -0,0 +1,9 @@
+int var1 = 42;
+
+static void
+__attribute__ ((__destructor__))
+destr (void)
+{
+ extern int fini_ran;
+ fini_ran = 1;
+}
diff --git a/REORG.TODO/elf/nodelmod2.c b/REORG.TODO/elf/nodelmod2.c
new file mode 100644
index 0000000000..6bd7108a13
--- /dev/null
+++ b/REORG.TODO/elf/nodelmod2.c
@@ -0,0 +1,9 @@
+int var2 = 100;
+
+static void
+__attribute__ ((__destructor__))
+destr (void)
+{
+ extern int fini_ran;
+ fini_ran = 1;
+}
diff --git a/REORG.TODO/elf/nodelmod3.c b/REORG.TODO/elf/nodelmod3.c
new file mode 100644
index 0000000000..817c94db6e
--- /dev/null
+++ b/REORG.TODO/elf/nodelmod3.c
@@ -0,0 +1,8 @@
+extern int var_in_mod4;
+extern int *addr (void);
+
+int *
+addr (void)
+{
+ return &var_in_mod4;
+}
diff --git a/REORG.TODO/elf/nodelmod4.c b/REORG.TODO/elf/nodelmod4.c
new file mode 100644
index 0000000000..2cca43a6e8
--- /dev/null
+++ b/REORG.TODO/elf/nodelmod4.c
@@ -0,0 +1,9 @@
+int var_in_mod4 = 99;
+
+static void
+__attribute__ ((__destructor__))
+destr (void)
+{
+ extern int fini_ran;
+ fini_ran = 1;
+}
diff --git a/REORG.TODO/elf/nodlopen.c b/REORG.TODO/elf/nodlopen.c
new file mode 100644
index 0000000000..642bdb3011
--- /dev/null
+++ b/REORG.TODO/elf/nodlopen.c
@@ -0,0 +1,15 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+ if (dlopen ("nodlopenmod.so", RTLD_LAZY) != NULL)
+ {
+ puts ("opening \"nodlopenmod.so\" succeeded, FAIL");
+ return 1;
+ }
+
+ puts ("opening \"nodlopenmod.so\" failed, OK");
+ return 0;
+}
diff --git a/REORG.TODO/elf/nodlopen2.c b/REORG.TODO/elf/nodlopen2.c
new file mode 100644
index 0000000000..a223f36834
--- /dev/null
+++ b/REORG.TODO/elf/nodlopen2.c
@@ -0,0 +1,15 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+ if (dlopen ("nodlopenmod2.so", RTLD_LAZY) != NULL)
+ {
+ puts ("opening \"nodlopenmod2.so\" succeeded, FAIL");
+ return 1;
+ }
+
+ puts ("opening \"nodlopenmod2.so\" failed, OK");
+ return 0;
+}
diff --git a/REORG.TODO/elf/nodlopenmod.c b/REORG.TODO/elf/nodlopenmod.c
new file mode 100644
index 0000000000..4bcf8c9786
--- /dev/null
+++ b/REORG.TODO/elf/nodlopenmod.c
@@ -0,0 +1 @@
+int a = 42;
diff --git a/REORG.TODO/elf/nodlopenmod2.c b/REORG.TODO/elf/nodlopenmod2.c
new file mode 100644
index 0000000000..e72ae53e95
--- /dev/null
+++ b/REORG.TODO/elf/nodlopenmod2.c
@@ -0,0 +1,9 @@
+extern int a;
+
+extern int foo (void);
+
+int
+foo (void)
+{
+ return a;
+}
diff --git a/REORG.TODO/elf/noload.c b/REORG.TODO/elf/noload.c
new file mode 100644
index 0000000000..bcc85efc27
--- /dev/null
+++ b/REORG.TODO/elf/noload.c
@@ -0,0 +1,81 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <mcheck.h>
+
+int
+main (void)
+{
+ int result = 0;
+ void *p;
+
+ mtrace ();
+
+ /* First try to load an object which is a dependency. This should
+ succeed. */
+ p = dlopen ("testobj1.so", RTLD_LAZY | RTLD_NOLOAD);
+ if (p == NULL)
+ {
+ printf ("cannot open \"testobj1.so\": %s\n", dlerror ());
+ result = 1;
+ }
+ else
+ {
+ puts ("loading \"testobj1.so\" succeeded, OK");
+ dlclose (p);
+ }
+
+ /* Now try loading an object which is not already loaded. */
+ if (dlopen ("testobj5.so", RTLD_LAZY | RTLD_NOLOAD) != NULL)
+ {
+ puts ("succeeded in loading \"testobj5.so\"");
+ result = 1;
+ }
+ else
+ {
+ /* Load the object and run the same test again. */
+ puts ("\"testobj5.so\" wasn't loaded and RTLD_NOLOAD prevented it, OK");
+
+ p = dlopen ("testobj5.so", RTLD_LAZY);
+
+ if (p == NULL)
+ {
+ printf ("cannot open \"testobj5.so\" without RTLD_NOLOAD: %s\n",
+ dlerror ());
+ result = 1;
+ }
+ else
+ {
+ puts ("loading \"testobj5.so\" succeeded, OK");
+
+ void *q = dlopen ("testobj5.so", RTLD_LAZY | RTLD_NOLOAD);
+ if (q == NULL)
+ {
+ printf ("cannot open \"testobj5.so\": %s\n", dlerror ());
+ result = 1;
+ }
+ else
+ {
+ puts ("loading \"testobj5.so\" with RTLD_NOLOAD succeeded, OK");
+ dlclose (q);
+ }
+
+ if (dlclose (p) != 0)
+ {
+ printf ("cannot close \"testobj5.so\": %s\n", dlerror ());
+ result = 1;
+ }
+ else
+ puts ("closing \"testobj5.so\" succeeded, OK");
+ }
+ }
+
+ return result;
+}
+
+
+extern int foo (int a);
+int
+foo (int a)
+{
+ return 42 + a;
+}
diff --git a/REORG.TODO/elf/order.c b/REORG.TODO/elf/order.c
new file mode 100644
index 0000000000..ca617cbc09
--- /dev/null
+++ b/REORG.TODO/elf/order.c
@@ -0,0 +1,25 @@
+#include <unistd.h>
+
+void init (void) __attribute__ ((constructor));
+void
+__attribute__ ((constructor))
+init (void)
+{
+ write (1, "4", 1);
+}
+
+void fini (void) __attribute__ ((destructor));
+void
+__attribute__ ((destructor))
+fini (void)
+{
+ write (1, "5", 1);
+}
+
+extern int dep1 (void);
+
+int
+main (void)
+{
+ return dep1 () != 42;
+}
diff --git a/REORG.TODO/elf/order2.c b/REORG.TODO/elf/order2.c
new file mode 100644
index 0000000000..bcf266d5b1
--- /dev/null
+++ b/REORG.TODO/elf/order2.c
@@ -0,0 +1,45 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+
+int call_puts;
+
+static int
+do_test (void)
+{
+ call_puts = 1;
+
+ void *h1 = dlopen ("$ORIGIN/order2mod1.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (h1 == NULL)
+ {
+ puts ("cannot load order2mod1");
+ return 1;
+ }
+ void *h2 = dlopen ("$ORIGIN/order2mod2.so", RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ puts ("cannot load order2mod2");
+ return 1;
+ }
+ if (dlclose (h1) != 0)
+ {
+ puts ("dlclose order2mod1 failed");
+ return 1;
+ }
+ if (dlclose (h2) != 0)
+ {
+ puts ("dlclose order2mod2 failed");
+ return 1;
+ }
+ return 0;
+}
+
+#include <support/test-driver.c>
+
+static void
+__attribute__ ((destructor))
+fini (void)
+{
+ if (call_puts)
+ puts ("5");
+}
diff --git a/REORG.TODO/elf/order2mod1.c b/REORG.TODO/elf/order2mod1.c
new file mode 100644
index 0000000000..b695db29b7
--- /dev/null
+++ b/REORG.TODO/elf/order2mod1.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+static void
+__attribute__ ((destructor))
+fini (void)
+{
+ putchar ('1');
+}
diff --git a/REORG.TODO/elf/order2mod2.c b/REORG.TODO/elf/order2mod2.c
new file mode 100644
index 0000000000..026cd2acc4
--- /dev/null
+++ b/REORG.TODO/elf/order2mod2.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+extern int foo (void);
+extern int bar (void);
+
+void
+__attribute__ ((constructor))
+init (void)
+{
+ (void) (foo () - bar ());
+}
+
+static void
+__attribute__ ((destructor))
+fini (void)
+{
+ putchar ('2');
+}
diff --git a/REORG.TODO/elf/order2mod3.c b/REORG.TODO/elf/order2mod3.c
new file mode 100644
index 0000000000..7913a79925
--- /dev/null
+++ b/REORG.TODO/elf/order2mod3.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+int
+bar (void)
+{
+ return 1;
+}
+
+static void
+__attribute__ ((destructor))
+fini (void)
+{
+ putchar ('4');
+}
diff --git a/REORG.TODO/elf/order2mod4.c b/REORG.TODO/elf/order2mod4.c
new file mode 100644
index 0000000000..4f2026f041
--- /dev/null
+++ b/REORG.TODO/elf/order2mod4.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern int bar (void);
+
+int
+foo (void)
+{
+ return 42 + bar ();
+}
+
+static void
+__attribute__ ((destructor))
+fini (void)
+{
+ putchar ('3');
+}
diff --git a/REORG.TODO/elf/origtest.c b/REORG.TODO/elf/origtest.c
new file mode 100644
index 0000000000..1cacabcc39
--- /dev/null
+++ b/REORG.TODO/elf/origtest.c
@@ -0,0 +1,39 @@
+#include <dlfcn.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ void *h;
+ int (*fp) (int);
+ int res;
+
+ h = dlopen ("${ORIGIN}/testobj1.so", RTLD_LAZY);
+ if (h == NULL)
+ error (EXIT_FAILURE, 0, "while loading `%s': %s", "testobj1.so",
+ dlerror ());
+
+ fp = dlsym (h, "obj1func1");
+ if (fp == NULL)
+ error (EXIT_FAILURE, 0, "getting `obj1func1' in `%s': %s",
+ "testobj1.so", dlerror ());
+
+ res = fp (10);
+ printf ("fp(10) = %d\n", res);
+
+ if (dlclose (h) != 0)
+ error (EXIT_FAILURE, 0, "while close `%s': %s",
+ "testobj1.so", dlerror ());
+
+ return res != 42;
+}
+
+
+extern int foo (int a);
+int
+foo (int a)
+{
+ return a + 10;
+}
diff --git a/REORG.TODO/elf/pathoptobj.c b/REORG.TODO/elf/pathoptobj.c
new file mode 100644
index 0000000000..a452c2d7d4
--- /dev/null
+++ b/REORG.TODO/elf/pathoptobj.c
@@ -0,0 +1,8 @@
+extern int in_renamed (int);
+
+
+int
+in_renamed (int a)
+{
+ return a - 10;
+}
diff --git a/REORG.TODO/elf/pldd-xx.c b/REORG.TODO/elf/pldd-xx.c
new file mode 100644
index 0000000000..5ce0bce4c9
--- /dev/null
+++ b/REORG.TODO/elf/pldd-xx.c
@@ -0,0 +1,251 @@
+/* Copyright (C) 2011-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#define E(name) E_(name, CLASS)
+#define E_(name, cl) E__(name, cl)
+#define E__(name, cl) name##cl
+#define EW(type) EW_(Elf, CLASS, type)
+#define EW_(e, w, t) EW__(e, w, _##t)
+#define EW__(e, w, t) e##w##t
+
+#define pldd_assert(name, exp) \
+ typedef int __assert_##name[((exp) != 0) - 1]
+
+
+struct E(link_map)
+{
+ EW(Addr) l_addr;
+ EW(Addr) l_name;
+ EW(Addr) l_ld;
+ EW(Addr) l_next;
+ EW(Addr) l_prev;
+ EW(Addr) l_real;
+ Lmid_t l_ns;
+ EW(Addr) l_libname;
+};
+#if CLASS == __ELF_NATIVE_CLASS
+pldd_assert (l_addr, (offsetof (struct link_map, l_addr)
+ == offsetof (struct E(link_map), l_addr)));
+pldd_assert (l_name, (offsetof (struct link_map, l_name)
+ == offsetof (struct E(link_map), l_name)));
+pldd_assert (l_next, (offsetof (struct link_map, l_next)
+ == offsetof (struct E(link_map), l_next)));
+#endif
+
+
+struct E(libname_list)
+{
+ EW(Addr) name;
+ EW(Addr) next;
+};
+#if CLASS == __ELF_NATIVE_CLASS
+pldd_assert (name, (offsetof (struct libname_list, name)
+ == offsetof (struct E(libname_list), name)));
+pldd_assert (next, (offsetof (struct libname_list, next)
+ == offsetof (struct E(libname_list), next)));
+#endif
+
+struct E(r_debug)
+{
+ int r_version;
+#if CLASS == 64
+ int pad;
+#endif
+ EW(Addr) r_map;
+};
+#if CLASS == __ELF_NATIVE_CLASS
+pldd_assert (r_version, (offsetof (struct r_debug, r_version)
+ == offsetof (struct E(r_debug), r_version)));
+pldd_assert (r_map, (offsetof (struct r_debug, r_map)
+ == offsetof (struct E(r_debug), r_map)));
+#endif
+
+
+static int
+
+E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
+{
+ EW(Addr) phdr = 0;
+ unsigned int phnum = 0;
+ unsigned int phent = 0;
+
+ EW(auxv_t) *auxvXX = (EW(auxv_t) *) auxv;
+ for (int i = 0; i < auxv_size / sizeof (EW(auxv_t)); ++i)
+ switch (auxvXX[i].a_type)
+ {
+ case AT_PHDR:
+ phdr = auxvXX[i].a_un.a_val;
+ break;
+ case AT_PHNUM:
+ phnum = auxvXX[i].a_un.a_val;
+ break;
+ case AT_PHENT:
+ phent = auxvXX[i].a_un.a_val;
+ break;
+ default:
+ break;
+ }
+
+ if (phdr == 0 || phnum == 0 || phent == 0)
+ error (EXIT_FAILURE, 0, gettext ("cannot find program header of process"));
+
+ EW(Phdr) *p = alloca (phnum * phent);
+ if (pread64 (memfd, p, phnum * phent, phdr) != phnum * phent)
+ {
+ error (0, 0, gettext ("cannot read program header"));
+ return EXIT_FAILURE;
+ }
+
+ /* Determine the load offset. We need this for interpreting the
+ other program header entries so we do this in a separate loop.
+ Fortunately it is the first time unless someone does something
+ stupid when linking the application. */
+ EW(Addr) offset = 0;
+ for (unsigned int i = 0; i < phnum; ++i)
+ if (p[i].p_type == PT_PHDR)
+ {
+ offset = phdr - p[i].p_vaddr;
+ break;
+ }
+
+ EW(Addr) list = 0;
+ char *interp = NULL;
+ for (unsigned int i = 0; i < phnum; ++i)
+ if (p[i].p_type == PT_DYNAMIC)
+ {
+ EW(Dyn) *dyn = xmalloc (p[i].p_filesz);
+ if (pread64 (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr)
+ != p[i].p_filesz)
+ {
+ error (0, 0, gettext ("cannot read dynamic section"));
+ return EXIT_FAILURE;
+ }
+
+ /* Search for the DT_DEBUG entry. */
+ for (unsigned int j = 0; j < p[i].p_filesz / sizeof (EW(Dyn)); ++j)
+ if (dyn[j].d_tag == DT_DEBUG && dyn[j].d_un.d_ptr != 0)
+ {
+ struct E(r_debug) r;
+ if (pread64 (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr)
+ != sizeof (r))
+ {
+ error (0, 0, gettext ("cannot read r_debug"));
+ return EXIT_FAILURE;
+ }
+
+ if (r.r_map != 0)
+ {
+ list = r.r_map;
+ break;
+ }
+ }
+
+ free (dyn);
+ break;
+ }
+ else if (p[i].p_type == PT_INTERP)
+ {
+ interp = alloca (p[i].p_filesz);
+ if (pread64 (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr)
+ != p[i].p_filesz)
+ {
+ error (0, 0, gettext ("cannot read program interpreter"));
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (list == 0)
+ {
+ if (interp == NULL)
+ {
+ // XXX check whether the executable itself is the loader
+ return EXIT_FAILURE;
+ }
+
+ // XXX perhaps try finding ld.so and _r_debug in it
+
+ return EXIT_FAILURE;
+ }
+
+ /* Print the PID and program name first. */
+ printf ("%lu:\t%s\n", (unsigned long int) pid, exe);
+
+ /* Iterate over the list of objects and print the information. */
+ struct scratch_buffer tmpbuf;
+ scratch_buffer_init (&tmpbuf);
+ int status = 0;
+ do
+ {
+ struct E(link_map) m;
+ if (pread64 (memfd, &m, sizeof (m), list) != sizeof (m))
+ {
+ error (0, 0, gettext ("cannot read link map"));
+ status = EXIT_FAILURE;
+ goto out;
+ }
+
+ EW(Addr) name_offset = m.l_name;
+ again:
+ while (1)
+ {
+ ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset);
+ if (n == -1)
+ {
+ error (0, 0, gettext ("cannot read object name"));
+ status = EXIT_FAILURE;
+ goto out;
+ }
+
+ if (memchr (tmpbuf.data, '\0', n) != NULL)
+ break;
+
+ if (!scratch_buffer_grow (&tmpbuf))
+ {
+ error (0, 0, gettext ("cannot allocate buffer for object name"));
+ status = EXIT_FAILURE;
+ goto out;
+ }
+ }
+
+ if (((char *)tmpbuf.data)[0] == '\0' && name_offset == m.l_name
+ && m.l_libname != 0)
+ {
+ /* Try the l_libname element. */
+ struct E(libname_list) ln;
+ if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln))
+ {
+ name_offset = ln.name;
+ goto again;
+ }
+ }
+
+ /* Skip over the executable. */
+ if (((char *)tmpbuf.data)[0] != '\0')
+ printf ("%s\n", (char *)tmpbuf.data);
+
+ list = m.l_next;
+ }
+ while (list != 0);
+
+ out:
+ scratch_buffer_free (&tmpbuf);
+ return status;
+}
+
+
+#undef CLASS
diff --git a/REORG.TODO/elf/pldd.c b/REORG.TODO/elf/pldd.c
new file mode 100644
index 0000000000..ddfa88d63b
--- /dev/null
+++ b/REORG.TODO/elf/pldd.c
@@ -0,0 +1,344 @@
+/* List dynamic shared objects linked into given process.
+ Copyright (C) 2011-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <alloca.h>
+#include <argp.h>
+#include <assert.h>
+#include <dirent.h>
+#include <elf.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <link.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <scratch_buffer.h>
+
+#include <ldsodefs.h>
+#include <version.h>
+
+/* Global variables. */
+extern char *program_invocation_short_name;
+#define PACKAGE _libc_intl_domainname
+
+/* External functions. */
+#include <programs/xmalloc.h>
+
+/* Name and version of program. */
+static void print_version (FILE *stream, struct argp_state *state);
+void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
+
+/* Function to print some extra text in the help message. */
+static char *more_help (int key, const char *text, void *input);
+
+/* Definitions of arguments for argp functions. */
+static const struct argp_option options[] =
+{
+ { NULL, 0, NULL, 0, NULL }
+};
+
+/* Short description of program. */
+static const char doc[] = N_("\
+List dynamic shared objects loaded into process.");
+
+/* Strings for arguments in help texts. */
+static const char args_doc[] = N_("PID");
+
+/* Prototype for option handler. */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Data structure to communicate with argp functions. */
+static struct argp argp =
+{
+ options, parse_opt, args_doc, doc, NULL, more_help, NULL
+};
+
+// File descriptor of /proc/*/mem file.
+static int memfd;
+
+/* Name of the executable */
+static char *exe;
+
+/* Local functions. */
+static int get_process_info (int dfd, long int pid);
+static void wait_for_ptrace_stop (long int pid);
+
+
+int
+main (int argc, char *argv[])
+{
+ /* Parse and process arguments. */
+ int remaining;
+ argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+ if (remaining != argc - 1)
+ {
+ fprintf (stderr,
+ gettext ("Exactly one parameter with process ID required.\n"));
+ argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
+ return 1;
+ }
+
+ assert (sizeof (pid_t) == sizeof (int)
+ || sizeof (pid_t) == sizeof (long int));
+ char *endp;
+ errno = 0;
+ long int pid = strtol (argv[remaining], &endp, 10);
+ if (pid < 0 || (pid == ULONG_MAX && errno == ERANGE) || *endp != '\0'
+ || (sizeof (pid_t) < sizeof (pid) && pid > INT_MAX))
+ error (EXIT_FAILURE, 0, gettext ("invalid process ID '%s'"),
+ argv[remaining]);
+
+ /* Determine the program name. */
+ char buf[7 + 3 * sizeof (pid)];
+ snprintf (buf, sizeof (buf), "/proc/%lu", pid);
+ int dfd = open (buf, O_RDONLY | O_DIRECTORY);
+ if (dfd == -1)
+ error (EXIT_FAILURE, errno, gettext ("cannot open %s"), buf);
+
+ struct scratch_buffer exebuf;
+ scratch_buffer_init (&exebuf);
+ ssize_t nexe;
+ while ((nexe = readlinkat (dfd, "exe",
+ exebuf.data, exebuf.length)) == exebuf.length)
+ {
+ if (!scratch_buffer_grow (&exebuf))
+ {
+ nexe = -1;
+ break;
+ }
+ }
+ if (nexe == -1)
+ exe = (char *) "<program name undetermined>";
+ else
+ {
+ exe = exebuf.data;
+ exe[nexe] = '\0';
+ }
+
+ /* Stop all threads since otherwise the list of loaded modules might
+ change while we are reading it. */
+ struct thread_list
+ {
+ pid_t tid;
+ struct thread_list *next;
+ } *thread_list = NULL;
+
+ int taskfd = openat (dfd, "task", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+ if (taskfd == 1)
+ error (EXIT_FAILURE, errno, gettext ("cannot open %s/task"), buf);
+ DIR *dir = fdopendir (taskfd);
+ if (dir == NULL)
+ error (EXIT_FAILURE, errno, gettext ("cannot prepare reading %s/task"),
+ buf);
+
+ struct dirent64 *d;
+ while ((d = readdir64 (dir)) != NULL)
+ {
+ if (! isdigit (d->d_name[0]))
+ continue;
+
+ errno = 0;
+ long int tid = strtol (d->d_name, &endp, 10);
+ if (tid < 0 || (tid == ULONG_MAX && errno == ERANGE) || *endp != '\0'
+ || (sizeof (pid_t) < sizeof (pid) && tid > INT_MAX))
+ error (EXIT_FAILURE, 0, gettext ("invalid thread ID '%s'"),
+ d->d_name);
+
+ if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
+ {
+ /* There might be a race between reading the directory and
+ threads terminating. Ignore errors attaching to unknown
+ threads unless this is the main thread. */
+ if (errno == ESRCH && tid != pid)
+ continue;
+
+ error (EXIT_FAILURE, errno, gettext ("cannot attach to process %lu"),
+ tid);
+ }
+
+ wait_for_ptrace_stop (tid);
+
+ struct thread_list *newp = alloca (sizeof (*newp));
+ newp->tid = tid;
+ newp->next = thread_list;
+ thread_list = newp;
+ }
+
+ closedir (dir);
+
+ int status = get_process_info (dfd, pid);
+
+ assert (thread_list != NULL);
+ do
+ {
+ ptrace (PTRACE_DETACH, thread_list->tid, NULL, NULL);
+ thread_list = thread_list->next;
+ }
+ while (thread_list != NULL);
+
+ close (dfd);
+
+ return status;
+}
+
+
+/* Wait for PID to enter ptrace-stop state after being attached. */
+static void
+wait_for_ptrace_stop (long int pid)
+{
+ int status;
+
+ /* While waiting for SIGSTOP being delivered to the tracee we have to
+ reinject any other pending signal. Ignore all other errors. */
+ while (waitpid (pid, &status, __WALL) == pid && WIFSTOPPED (status))
+ {
+ /* The STOP signal should not be delivered to the tracee. */
+ if (WSTOPSIG (status) == SIGSTOP)
+ return;
+ if (ptrace (PTRACE_CONT, pid, NULL,
+ (void *) (uintptr_t) WSTOPSIG (status)))
+ /* The only possible error is that the process died. */
+ return;
+ }
+}
+
+
+/* Handle program arguments. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+
+/* Print bug-reporting information in the help message. */
+static char *
+more_help (int key, const char *text, void *input)
+{
+ char *tp = NULL;
+ switch (key)
+ {
+ case ARGP_KEY_HELP_EXTRA:
+ /* We print some extra information. */
+ if (asprintf (&tp, gettext ("\
+For bug reporting instructions, please see:\n\
+%s.\n"), REPORT_BUGS_TO) < 0)
+ return NULL;
+ return tp;
+ default:
+ break;
+ }
+ return (char *) text;
+}
+
+/* Print the version information. */
+static void
+print_version (FILE *stream, struct argp_state *state)
+{
+ fprintf (stream, "pldd %s%s\n", PKGVERSION, VERSION);
+ fprintf (stream, gettext ("\
+Copyright (C) %s Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions. There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"), "2017");
+ fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
+}
+
+
+#define CLASS 32
+#include "pldd-xx.c"
+#define CLASS 64
+#include "pldd-xx.c"
+
+
+static int
+get_process_info (int dfd, long int pid)
+{
+ memfd = openat (dfd, "mem", O_RDONLY);
+ if (memfd == -1)
+ goto no_info;
+
+ int fd = openat (dfd, "exe", O_RDONLY);
+ if (fd == -1)
+ {
+ no_info:
+ error (0, errno, gettext ("cannot get information about process %lu"),
+ pid);
+ return EXIT_FAILURE;
+ }
+
+ char e_ident[EI_NIDENT];
+ if (read (fd, e_ident, EI_NIDENT) != EI_NIDENT)
+ goto no_info;
+
+ close (fd);
+
+ if (memcmp (e_ident, ELFMAG, SELFMAG) != 0)
+ {
+ error (0, 0, gettext ("process %lu is no ELF program"), pid);
+ return EXIT_FAILURE;
+ }
+
+ fd = openat (dfd, "auxv", O_RDONLY);
+ if (fd == -1)
+ goto no_info;
+
+ size_t auxv_size = 0;
+ void *auxv = NULL;
+ while (1)
+ {
+ auxv_size += 512;
+ auxv = xrealloc (auxv, auxv_size);
+
+ ssize_t n = pread (fd, auxv, auxv_size, 0);
+ if (n < 0)
+ goto no_info;
+ if (n < auxv_size)
+ {
+ auxv_size = n;
+ break;
+ }
+ }
+
+ close (fd);
+
+ int retval;
+ if (e_ident[EI_CLASS] == ELFCLASS32)
+ retval = find_maps32 (pid, auxv, auxv_size);
+ else
+ retval = find_maps64 (pid, auxv, auxv_size);
+
+ free (auxv);
+ close (memfd);
+
+ return retval;
+}
diff --git a/REORG.TODO/elf/preloadtest.c b/REORG.TODO/elf/preloadtest.c
new file mode 100644
index 0000000000..7ea10b9b5b
--- /dev/null
+++ b/REORG.TODO/elf/preloadtest.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+#include "testobj.h"
+
+int
+main (void)
+{
+ int res = preload (42);
+
+ printf ("preload (42) = %d, %s\n", res, res == 92 ? "ok" : "wrong");
+
+ return res != 92;
+}
+
+int
+foo (int a)
+{
+ return a;
+}
diff --git a/REORG.TODO/elf/readelflib.c b/REORG.TODO/elf/readelflib.c
new file mode 100644
index 0000000000..9ad56dcc34
--- /dev/null
+++ b/REORG.TODO/elf/readelflib.c
@@ -0,0 +1,234 @@
+/* Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
+ Jakub Jelinek <jakub@redhat.com>, 1999.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This code is a heavily simplified version of the readelf program
+ that's part of the current binutils development version. For architectures
+ which need to handle both 32bit and 64bit ELF libraries, this file is
+ included twice for each arch size. */
+
+/* check_ptr checks that a pointer is in the mmaped file and doesn't
+ point outside it. */
+#undef check_ptr
+#define check_ptr(ptr) \
+do \
+ { \
+ if ((void *)(ptr) < file_contents \
+ || (void *)(ptr) > (file_contents+file_length)) \
+ { \
+ error (0, 0, _("file %s is truncated\n"), file_name); \
+ return 1; \
+ } \
+ } \
+ while (0);
+
+/* Returns 0 if everything is ok, != 0 in case of error. */
+int
+process_elf_file (const char *file_name, const char *lib, int *flag,
+ unsigned int *osversion, char **soname, void *file_contents,
+ size_t file_length)
+{
+ int i;
+ unsigned int j;
+ ElfW(Addr) loadaddr;
+ unsigned int dynamic_addr;
+ size_t dynamic_size;
+ char *program_interpreter;
+
+ ElfW(Ehdr) *elf_header;
+ ElfW(Phdr) *elf_pheader, *segment;
+ ElfW(Dyn) *dynamic_segment, *dyn_entry;
+ char *dynamic_strings;
+
+ elf_header = (ElfW(Ehdr) *) file_contents;
+ *osversion = 0;
+
+ if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS))
+ {
+ if (opt_verbose)
+ {
+ if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
+ error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name);
+ else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64)
+ error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name);
+ else
+ error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name);
+ }
+ return 1;
+ }
+
+ if (elf_header->e_type != ET_DYN)
+ {
+ error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
+ elf_header->e_type);
+ return 1;
+ }
+
+ /* Get information from elf program header. */
+ elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents);
+ check_ptr (elf_pheader);
+
+ /* The library is an elf library, now search for soname and
+ libc5/libc6. */
+ *flag = FLAG_ELF;
+
+ loadaddr = -1;
+ dynamic_addr = 0;
+ dynamic_size = 0;
+ program_interpreter = NULL;
+ for (i = 0, segment = elf_pheader;
+ i < elf_header->e_phnum; i++, segment++)
+ {
+ check_ptr (segment);
+
+ switch (segment->p_type)
+ {
+ case PT_LOAD:
+ if (loadaddr == (ElfW(Addr)) -1)
+ loadaddr = segment->p_vaddr - segment->p_offset;
+ break;
+
+ case PT_DYNAMIC:
+ if (dynamic_addr)
+ error (0, 0, _("more than one dynamic segment\n"));
+
+ dynamic_addr = segment->p_offset;
+ dynamic_size = segment->p_filesz;
+ break;
+
+ case PT_INTERP:
+ program_interpreter = (char *) (file_contents + segment->p_offset);
+ check_ptr (program_interpreter);
+
+ /* Check if this is enough to classify the binary. */
+ for (j = 0; j < sizeof (interpreters) / sizeof (interpreters [0]);
+ ++j)
+ if (strcmp (program_interpreter, interpreters[j].soname) == 0)
+ {
+ *flag = interpreters[j].flag;
+ break;
+ }
+ break;
+
+ case PT_NOTE:
+ if (!*osversion && segment->p_filesz >= 32 && segment->p_align >= 4)
+ {
+ ElfW(Word) *abi_note = (ElfW(Word) *) (file_contents
+ + segment->p_offset);
+ ElfW(Addr) size = segment->p_filesz;
+
+ while (abi_note [0] != 4 || abi_note [1] != 16
+ || abi_note [2] != 1
+ || memcmp (abi_note + 3, "GNU", 4) != 0)
+ {
+#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
+ ElfW(Addr) note_size = 3 * sizeof (ElfW(Word))
+ + ROUND (abi_note[0])
+ + ROUND (abi_note[1]);
+
+ if (size - 32 < note_size || note_size == 0)
+ {
+ size = 0;
+ break;
+ }
+ size -= note_size;
+ abi_note = (void *) abi_note + note_size;
+ }
+
+ if (size == 0)
+ break;
+
+ *osversion = (abi_note [4] << 24) |
+ ((abi_note [5] & 0xff) << 16) |
+ ((abi_note [6] & 0xff) << 8) |
+ (abi_note [7] & 0xff);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ if (loadaddr == (ElfW(Addr)) -1)
+ {
+ /* Very strange. */
+ loadaddr = 0;
+ }
+
+ /* Now we can read the dynamic sections. */
+ if (dynamic_size == 0)
+ return 1;
+
+ dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr);
+ check_ptr (dynamic_segment);
+
+ /* Find the string table. */
+ dynamic_strings = NULL;
+ for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
+ ++dyn_entry)
+ {
+ check_ptr (dyn_entry);
+ if (dyn_entry->d_tag == DT_STRTAB)
+ {
+ dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
+ check_ptr (dynamic_strings);
+ break;
+ }
+ }
+
+ if (dynamic_strings == NULL)
+ return 1;
+
+ /* Now read the DT_NEEDED and DT_SONAME entries. */
+ for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
+ ++dyn_entry)
+ {
+ if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME)
+ {
+ char *name = dynamic_strings + dyn_entry->d_un.d_val;
+ check_ptr (name);
+
+ if (dyn_entry->d_tag == DT_NEEDED)
+ {
+
+ if (*flag == FLAG_ELF)
+ {
+ /* Check if this is enough to classify the binary. */
+ for (j = 0;
+ j < sizeof (known_libs) / sizeof (known_libs [0]);
+ ++j)
+ if (strcmp (name, known_libs [j].soname) == 0)
+ {
+ *flag = known_libs [j].flag;
+ break;
+ }
+ }
+ }
+
+ else if (dyn_entry->d_tag == DT_SONAME)
+ *soname = xstrdup (name);
+
+ /* Do we have everything we need? */
+ if (*soname && *flag != FLAG_ELF)
+ return 0;
+ }
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/readlib.c b/REORG.TODO/elf/readlib.c
new file mode 100644
index 0000000000..d278a189b2
--- /dev/null
+++ b/REORG.TODO/elf/readlib.c
@@ -0,0 +1,212 @@
+/* Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
+ Jakub Jelinek <jakub@redhat.com>, 1999.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+/* The code in this file and in readelflib is a heavily simplified
+ version of the readelf program that's part of the current binutils
+ development version. Besides the simplification, it has also been
+ modified to read some other file formats. */
+
+#include <a.out.h>
+#include <elf.h>
+#include <error.h>
+#include <libintl.h>
+#include <link.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <gnu/lib-names.h>
+
+#include <ldconfig.h>
+
+#define Elf32_CLASS ELFCLASS32
+#define Elf64_CLASS ELFCLASS64
+
+struct known_names
+{
+ const char *soname;
+ int flag;
+};
+
+static struct known_names interpreters[] =
+{
+ { "/lib/" LD_SO, FLAG_ELF_LIBC6 },
+#ifdef SYSDEP_KNOWN_INTERPRETER_NAMES
+ SYSDEP_KNOWN_INTERPRETER_NAMES
+#endif
+};
+
+static struct known_names known_libs[] =
+{
+ { LIBC_SO, FLAG_ELF_LIBC6 },
+ { LIBM_SO, FLAG_ELF_LIBC6 },
+#ifdef SYSDEP_KNOWN_LIBRARY_NAMES
+ SYSDEP_KNOWN_LIBRARY_NAMES
+#endif
+};
+
+
+/* Check if string corresponds to a GDB Python file. */
+static bool
+is_gdb_python_file (const char *name)
+{
+ size_t len = strlen (name);
+ return len > 7 && strcmp (name + len - 7, "-gdb.py") == 0;
+}
+
+/* Returns 0 if everything is ok, != 0 in case of error. */
+int
+process_file (const char *real_file_name, const char *file_name,
+ const char *lib, int *flag, unsigned int *osversion,
+ char **soname, int is_link, struct stat64 *stat_buf)
+{
+ FILE *file;
+ struct stat64 statbuf;
+ void *file_contents;
+ int ret;
+ ElfW(Ehdr) *elf_header;
+ struct exec *aout_header;
+
+ ret = 0;
+ *flag = FLAG_ANY;
+ *soname = NULL;
+
+ file = fopen (real_file_name, "rb");
+ if (file == NULL)
+ {
+ /* No error for stale symlink. */
+ if (is_link && strstr (file_name, ".so") != NULL)
+ return 1;
+ error (0, 0, _("Input file %s not found.\n"), file_name);
+ return 1;
+ }
+
+ if (fstat64 (fileno (file), &statbuf) < 0)
+ {
+ error (0, 0, _("Cannot fstat file %s.\n"), file_name);
+ fclose (file);
+ return 1;
+ }
+
+ /* Check that the file is large enough so that we can access the
+ information. We're only checking the size of the headers here. */
+ if ((size_t) statbuf.st_size < sizeof (struct exec)
+ || (size_t) statbuf.st_size < sizeof (ElfW(Ehdr)))
+ {
+ if (statbuf.st_size == 0)
+ error (0, 0, _("File %s is empty, not checked."), file_name);
+ else
+ {
+ char buf[SELFMAG];
+ size_t n = MIN (statbuf.st_size, SELFMAG);
+ if (fread (buf, n, 1, file) == 1 && memcmp (buf, ELFMAG, n) == 0)
+ error (0, 0, _("File %s is too small, not checked."), file_name);
+ }
+ fclose (file);
+ return 1;
+ }
+
+ file_contents = mmap (0, statbuf.st_size, PROT_READ, MAP_SHARED,
+ fileno (file), 0);
+ if (file_contents == MAP_FAILED)
+ {
+ error (0, 0, _("Cannot mmap file %s.\n"), file_name);
+ fclose (file);
+ return 1;
+ }
+
+ /* First check if this is an aout file. */
+ aout_header = (struct exec *) file_contents;
+ if (N_MAGIC (*aout_header) == ZMAGIC
+#ifdef QMAGIC /* Linuxism. */
+ || N_MAGIC (*aout_header) == QMAGIC
+#endif
+ )
+ {
+ /* Aout files don't have a soname, just return the name
+ including the major number. */
+ char *copy, *major, *dot;
+ copy = xstrdup (lib);
+ major = strstr (copy, ".so.");
+ if (major)
+ {
+ dot = strstr (major + 4, ".");
+ if (dot)
+ *dot = '\0';
+ }
+ *soname = copy;
+ *flag = FLAG_LIBC4;
+ goto done;
+ }
+
+ elf_header = (ElfW(Ehdr) *) file_contents;
+ if (memcmp (elf_header->e_ident, ELFMAG, SELFMAG) != 0)
+ {
+ /* The file is neither ELF nor aout. Check if it's a linker
+ script, like libc.so - otherwise complain. Only search the
+ beginning of the file. */
+ size_t len = MIN (statbuf.st_size, 512);
+ if (memmem (file_contents, len, "GROUP", 5) == NULL
+ && memmem (file_contents, len, "GNU ld script", 13) == NULL
+ && !is_gdb_python_file (file_name))
+ error (0, 0, _("%s is not an ELF file - it has the wrong magic bytes at the start.\n"),
+ file_name);
+ ret = 1;
+ }
+ /* Libraries have to be shared object files. */
+ else if (elf_header->e_type != ET_DYN)
+ ret = 1;
+ else if (process_elf_file (file_name, lib, flag, osversion, soname,
+ file_contents, statbuf.st_size))
+ ret = 1;
+
+ done:
+ /* Clean up allocated memory and resources. */
+ munmap (file_contents, statbuf.st_size);
+ fclose (file);
+
+ *stat_buf = statbuf;
+ return ret;
+}
+
+/* Returns made up soname if lib doesn't have explicit DT_SONAME. */
+
+char *
+implicit_soname (const char *lib, int flag)
+{
+ char *soname = xstrdup (lib);
+
+ if ((flag & FLAG_TYPE_MASK) != FLAG_LIBC4)
+ return soname;
+
+ /* Aout files don't have a soname, just return the name
+ including the major number. */
+ char *major = strstr (soname, ".so.");
+ if (major)
+ {
+ char *dot = strstr (major + 4, ".");
+ if (dot)
+ *dot = '\0';
+ }
+ return soname;
+}
+
+/* Get architecture specific version of process_elf_file. */
+#include <readelflib.c>
diff --git a/REORG.TODO/elf/reldep.c b/REORG.TODO/elf/reldep.c
new file mode 100644
index 0000000000..adabc0d5d5
--- /dev/null
+++ b/REORG.TODO/elf/reldep.c
@@ -0,0 +1,111 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ void *h1;
+ void *h2;
+ int (*fp) (void);
+ int *vp;
+
+ mtrace ();
+
+ /* Open the two objects. */
+ h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (h1 == NULL)
+ {
+ printf ("cannot open reldepmod1.so: %s\n", dlerror ());
+ exit (1);
+ }
+ h2 = dlopen ("reldepmod2.so", RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ printf ("cannot open reldepmod2.so: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Get the address of the variable in reldepmod1.so. */
+ vp = dlsym (h1, "some_var");
+ if (vp == NULL)
+ {
+ printf ("cannot get address of \"some_var\": %s\n", dlerror ());
+ exit (1);
+ }
+
+ *vp = 42;
+
+ /* Get the function `call_me' in the second object. This has a
+ dependency which is resolved by a definition in reldepmod1.so. */
+ fp = dlsym (h2, "call_me");
+ if (fp == NULL)
+ {
+ printf ("cannot get address of \"call_me\": %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Call the function. */
+ if (fp () != 0)
+ {
+ puts ("function \"call_me\" returned wrong result");
+ exit (1);
+ }
+
+ /* Now close the first object. If must still be around since we have
+ an implicit dependency. */
+ if (dlclose (h1) != 0)
+ {
+ printf ("closing h1 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Try calling the function again. This will fail if the first object
+ got unloaded. */
+ if (fp () != 0)
+ {
+ puts ("second call of function \"call_me\" returned wrong result");
+ exit (1);
+ }
+
+ /* Now close the second file as well. */
+ if (dlclose (h2) != 0)
+ {
+ printf ("closing h2 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Finally, open the first object again. */
+ h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (h1 == NULL)
+ {
+ printf ("cannot open reldepmod1.so the second time: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* And get the variable address again. */
+ vp = dlsym (h1, "some_var");
+ if (vp == NULL)
+ {
+ printf ("cannot get address of \"some_var\" the second time: %s\n",
+ dlerror ());
+ exit (1);
+ }
+
+ /* The variable now must have its originial value. */
+ if (*vp != 0)
+ {
+ puts ("variable \"some_var\" not reset");
+ exit (1);
+ }
+
+ /* Close the first object again, we are done. */
+ if (dlclose (h1) != 0)
+ {
+ printf ("closing h1 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/reldep2.c b/REORG.TODO/elf/reldep2.c
new file mode 100644
index 0000000000..ba5ab222f9
--- /dev/null
+++ b/REORG.TODO/elf/reldep2.c
@@ -0,0 +1,101 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ void *h1;
+ void *h2;
+ int (*fp) (void);
+ int *vp;
+
+ mtrace ();
+
+ /* Open the two objects. */
+ h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (h1 == NULL)
+ {
+ printf ("cannot open reldepmod1.so: %s\n", dlerror ());
+ exit (1);
+ }
+ h2 = dlopen ("reldepmod3.so", RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ printf ("cannot open reldepmod3.so: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Get the address of the variable in reldepmod1.so. */
+ vp = dlsym (h1, "some_var");
+ if (vp == NULL)
+ {
+ printf ("cannot get address of \"some_var\": %s\n", dlerror ());
+ exit (1);
+ }
+
+ *vp = 42;
+
+ /* Get the function `call_me' in the second object. This has a
+ dependency which is resolved by a definition in reldepmod1.so. */
+ fp = dlsym (h2, "call_me");
+ if (fp == NULL)
+ {
+ printf ("cannot get address of \"call_me\": %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Call the function. */
+ if (fp () != 0)
+ {
+ puts ("function \"call_me\" returned wrong result");
+ exit (1);
+ }
+
+ /* Now close the first object. It must still be around since we have
+ an implicit dependency. */
+ if (dlclose (h1) != 0)
+ {
+ printf ("closing h1 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Open the first object again. */
+ h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (h1 == NULL)
+ {
+ printf ("cannot open reldepmod1.so the second time: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Get the variable address again. */
+ vp = dlsym (h1, "some_var");
+ if (vp == NULL)
+ {
+ printf ("cannot get address of \"some_var\" the second time: %s\n",
+ dlerror ());
+ exit (1);
+ }
+
+ /* The variable now must have its originial value. */
+ if (*vp != 42)
+ {
+ puts ("variable \"some_var\" reset");
+ exit (1);
+ }
+
+ /* Close the first object again, we are done. */
+ if (dlclose (h1) != 0)
+ {
+ printf ("closing h1 failed: %s\n", dlerror ());
+ exit (1);
+ }
+ if (dlclose (h2) != 0)
+ {
+ printf ("closing h2 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/reldep3.c b/REORG.TODO/elf/reldep3.c
new file mode 100644
index 0000000000..05013d3509
--- /dev/null
+++ b/REORG.TODO/elf/reldep3.c
@@ -0,0 +1,101 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ void *h1;
+ void *h2;
+ int (*fp) (void);
+ int *vp;
+
+ mtrace ();
+
+ /* Open the two objects. */
+ h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (h1 == NULL)
+ {
+ printf ("cannot open reldepmod1.so: %s\n", dlerror ());
+ exit (1);
+ }
+ h2 = dlopen ("reldepmod4.so", RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ printf ("cannot open reldepmod4.so: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Get the address of the variable in reldepmod1.so. */
+ vp = dlsym (h1, "some_var");
+ if (vp == NULL)
+ {
+ printf ("cannot get address of \"some_var\": %s\n", dlerror ());
+ exit (1);
+ }
+
+ *vp = 42;
+
+ /* Get the function `call_me' in the second object. This has a
+ dependency which is resolved by a definition in reldepmod1.so. */
+ fp = dlsym (h2, "call_me");
+ if (fp == NULL)
+ {
+ printf ("cannot get address of \"call_me\": %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Call the function. */
+ if (fp () != 0)
+ {
+ puts ("function \"call_me\" returned wrong result");
+ exit (1);
+ }
+
+ /* Now close the first object. If must still be around since we have
+ an implicit dependency. */
+ if (dlclose (h1) != 0)
+ {
+ printf ("closing h1 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Open the first object again. */
+ h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (h1 == NULL)
+ {
+ printf ("cannot open reldepmod1.so the second time: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Get the variable address again. */
+ vp = dlsym (h1, "some_var");
+ if (vp == NULL)
+ {
+ printf ("cannot get address of \"some_var\" the second time: %s\n",
+ dlerror ());
+ exit (1);
+ }
+
+ /* The variable now must have its originial value. */
+ if (*vp != 0)
+ {
+ puts ("variable \"some_var\" not reset");
+ exit (1);
+ }
+
+ /* Close the first object again, we are done. */
+ if (dlclose (h1) != 0)
+ {
+ printf ("closing h1 failed: %s\n", dlerror ());
+ exit (1);
+ }
+ if (dlclose (h2) != 0)
+ {
+ printf ("closing h2 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/reldep4.c b/REORG.TODO/elf/reldep4.c
new file mode 100644
index 0000000000..ba12e7d9c4
--- /dev/null
+++ b/REORG.TODO/elf/reldep4.c
@@ -0,0 +1,40 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ int i;
+ void *h1, *h2;
+
+ mtrace ();
+
+ for (i = 0; i < 3; i++)
+ {
+ h1 = dlopen ("reldep4mod1.so", RTLD_NOW | RTLD_GLOBAL);
+ if (h1 == NULL)
+ {
+ printf ("cannot open reldep4mod1.so: %s\n", dlerror ());
+ exit (1);
+ }
+ h2 = dlopen ("reldep4mod2.so", RTLD_NOW | RTLD_GLOBAL);
+ if (h2 == NULL)
+ {
+ printf ("cannot open reldep4mod2.so: %s\n", dlerror ());
+ exit (1);
+ }
+ if (dlclose (h1) != 0)
+ {
+ printf ("closing h1 failed: %s\n", dlerror ());
+ exit (1);
+ }
+ if (dlclose (h2) != 0)
+ {
+ printf ("closing h2 failed: %s\n", dlerror ());
+ exit (1);
+ }
+ }
+ return 0;
+}
diff --git a/REORG.TODO/elf/reldep4mod1.c b/REORG.TODO/elf/reldep4mod1.c
new file mode 100644
index 0000000000..934a68096e
--- /dev/null
+++ b/REORG.TODO/elf/reldep4mod1.c
@@ -0,0 +1,7 @@
+int foo (void);
+
+int foo (void)
+{
+ return 0;
+}
+
diff --git a/REORG.TODO/elf/reldep4mod2.c b/REORG.TODO/elf/reldep4mod2.c
new file mode 100644
index 0000000000..26ce6bf13a
--- /dev/null
+++ b/REORG.TODO/elf/reldep4mod2.c
@@ -0,0 +1,8 @@
+extern int foo (void);
+extern int bar (void);
+
+int
+bar (void)
+{
+ return foo ();
+}
diff --git a/REORG.TODO/elf/reldep4mod3.c b/REORG.TODO/elf/reldep4mod3.c
new file mode 100644
index 0000000000..934a68096e
--- /dev/null
+++ b/REORG.TODO/elf/reldep4mod3.c
@@ -0,0 +1,7 @@
+int foo (void);
+
+int foo (void)
+{
+ return 0;
+}
+
diff --git a/REORG.TODO/elf/reldep4mod4.c b/REORG.TODO/elf/reldep4mod4.c
new file mode 100644
index 0000000000..26ce6bf13a
--- /dev/null
+++ b/REORG.TODO/elf/reldep4mod4.c
@@ -0,0 +1,8 @@
+extern int foo (void);
+extern int bar (void);
+
+int
+bar (void)
+{
+ return foo ();
+}
diff --git a/REORG.TODO/elf/reldep5.c b/REORG.TODO/elf/reldep5.c
new file mode 100644
index 0000000000..881d519ff6
--- /dev/null
+++ b/REORG.TODO/elf/reldep5.c
@@ -0,0 +1,70 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ void *h1;
+ void *h2;
+ int (*fp) (void);
+
+ mtrace ();
+
+ /* Open the two objects. */
+ h1 = dlopen ("reldepmod5.so", RTLD_LAZY);
+ if (h1 == NULL)
+ {
+ printf ("cannot open reldepmod5.so: %s\n", dlerror ());
+ exit (1);
+ }
+ h2 = dlopen ("reldepmod6.so", RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ printf ("cannot open reldepmod6.so: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Get the address of the variable in reldepmod1.so. */
+ fp = dlsym (h2, "bar");
+ if (fp == NULL)
+ {
+ printf ("cannot get address of \"bar\": %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Call the function. */
+ puts ("calling fp for the first time");
+ if (fp () != 0)
+ {
+ puts ("function \"call_me\" returned wrong result");
+ exit (1);
+ }
+
+ /* Now close the first object. It must still be around since we have
+ an implicit dependency. */
+ if (dlclose (h1) != 0)
+ {
+ printf ("closing h1 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Calling the function must still work. */
+ puts ("calling fp for the second time");
+ if (fp () != 0)
+ {
+ puts ("function \"call_me\" the second time returned wrong result");
+ exit (1);
+ }
+ puts ("second call suceeded as well");
+
+ /* Close the second object, we are done. */
+ if (dlclose (h2) != 0)
+ {
+ printf ("closing h2 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/reldep6.c b/REORG.TODO/elf/reldep6.c
new file mode 100644
index 0000000000..1eeec6c862
--- /dev/null
+++ b/REORG.TODO/elf/reldep6.c
@@ -0,0 +1,109 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef int (*fn)(void);
+#define CHUNKS 1024
+#define REPEAT 64
+
+int
+main (void)
+{
+ void *h1;
+ void *h2;
+ fn **foopp;
+ fn bar, baz;
+ int i, j;
+ int n;
+ void *allocs[REPEAT][CHUNKS];
+
+ mtrace ();
+
+ /* Open the two objects. */
+ h1 = dlopen ("reldep6mod3.so", RTLD_LAZY);
+ if (h1 == NULL)
+ {
+ printf ("cannot open reldep6mod3.so: %s\n", dlerror ());
+ exit (1);
+ }
+
+ foopp = dlsym (h1, "foopp");
+ if (foopp == NULL)
+ {
+ printf ("cannot get address of \"foopp\": %s\n", dlerror ());
+ exit (1);
+ }
+ n = (**foopp) ();
+ if (n != 20)
+ {
+ printf ("(**foopp)() return %d, not return 20\n", n);
+ exit (1);
+ }
+
+ h2 = dlopen ("reldep6mod4.so", RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ printf ("cannot open reldep6mod4.so: %s\n", dlerror ());
+ exit (1);
+ }
+
+ baz = dlsym (h2, "baz");
+ if (baz == NULL)
+ {
+ printf ("cannot get address of \"baz\": %s\n", dlerror ());
+ exit (1);
+ }
+ if (baz () != 31)
+ {
+ printf ("baz() did not return 31\n");
+ exit (1);
+ }
+
+ if (dlclose (h1) != 0)
+ {
+ printf ("closing h1 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ /* Clobber memory. */
+ for (i = 0; i < REPEAT; ++i)
+ for (j = 0; j < CHUNKS; ++j)
+ allocs[i][j] = calloc (1, j + 1);
+
+ bar = dlsym (h2, "bar");
+ if (bar == NULL)
+ {
+ printf ("cannot get address of \"bar\": %s\n", dlerror ());
+ exit (1);
+ }
+ if (bar () != 40)
+ {
+ printf ("bar() did not return 40\n");
+ exit (1);
+ }
+
+ baz = dlsym (h2, "baz");
+ if (baz == NULL)
+ {
+ printf ("cannot get address of \"baz\": %s\n", dlerror ());
+ exit (1);
+ }
+ if (baz () != 31)
+ {
+ printf ("baz() did not return 31\n");
+ exit (1);
+ }
+
+ for (i = 0; i < REPEAT; ++i)
+ for (j = 0; j < CHUNKS; ++j)
+ free (allocs[i][j]);
+
+ if (dlclose (h2) != 0)
+ {
+ printf ("closing h2 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/reldep6mod0.c b/REORG.TODO/elf/reldep6mod0.c
new file mode 100644
index 0000000000..58f3745fb4
--- /dev/null
+++ b/REORG.TODO/elf/reldep6mod0.c
@@ -0,0 +1,8 @@
+int bar (void);
+extern void free (void *);
+
+int bar (void)
+{
+ free (0);
+ return 40;
+}
diff --git a/REORG.TODO/elf/reldep6mod1.c b/REORG.TODO/elf/reldep6mod1.c
new file mode 100644
index 0000000000..037a73a198
--- /dev/null
+++ b/REORG.TODO/elf/reldep6mod1.c
@@ -0,0 +1,14 @@
+int foo (void);
+int baz (void);
+extern int weak (void);
+asm (".weak weak");
+
+int foo (void)
+{
+ return 20;
+}
+
+int baz (void)
+{
+ return weak () + 1;
+}
diff --git a/REORG.TODO/elf/reldep6mod2.c b/REORG.TODO/elf/reldep6mod2.c
new file mode 100644
index 0000000000..c2ef3f9bc0
--- /dev/null
+++ b/REORG.TODO/elf/reldep6mod2.c
@@ -0,0 +1,3 @@
+extern int foo (void);
+
+void *foop = (void *) foo;
diff --git a/REORG.TODO/elf/reldep6mod3.c b/REORG.TODO/elf/reldep6mod3.c
new file mode 100644
index 0000000000..881828ef6e
--- /dev/null
+++ b/REORG.TODO/elf/reldep6mod3.c
@@ -0,0 +1,3 @@
+extern void *foop;
+
+void **foopp = &foop;
diff --git a/REORG.TODO/elf/reldep6mod4.c b/REORG.TODO/elf/reldep6mod4.c
new file mode 100644
index 0000000000..8fa89de64b
--- /dev/null
+++ b/REORG.TODO/elf/reldep6mod4.c
@@ -0,0 +1,12 @@
+int foo (void);
+int weak (void);
+
+int foo (void)
+{
+ return 10;
+}
+
+int weak (void)
+{
+ return 30;
+}
diff --git a/REORG.TODO/elf/reldep7.c b/REORG.TODO/elf/reldep7.c
new file mode 100644
index 0000000000..5275a0e8f1
--- /dev/null
+++ b/REORG.TODO/elf/reldep7.c
@@ -0,0 +1,58 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ void *h1;
+ void *h2;
+ void *mod1_bar, *mod2_bar;
+
+ h1 = dlopen ("reldep7mod1.so", RTLD_GLOBAL | RTLD_LAZY);
+ if (h1 == NULL)
+ {
+ printf ("cannot open reldep7mod1.so: %s\n", dlerror ());
+ exit (1);
+ }
+
+ h2 = dlopen ("reldep7mod2.so", RTLD_GLOBAL | RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ printf ("cannot open reldep7mod1.so: %s\n", dlerror ());
+ exit (1);
+ }
+
+ mod1_bar = dlsym (h1, "mod1_bar");
+ if (mod1_bar == NULL)
+ {
+ printf ("cannot get address of \"mod1_bar\": %s\n", dlerror ());
+ exit (1);
+ }
+
+ mod2_bar = dlsym (h2, "mod2_bar");
+ if (mod2_bar == NULL)
+ {
+ printf ("cannot get address of \"mod2_bar\": %s\n", dlerror ());
+ exit (1);
+ }
+
+ printf ("%d\n", ((int (*) (void)) mod1_bar) ());
+ printf ("%d\n", ((int (*) (void)) mod2_bar) ());
+
+ if (dlclose (h1) != 0)
+ {
+ printf ("closing h1 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ printf ("%d\n", ((int (*) (void)) mod2_bar) ());
+
+ if (dlclose (h2) != 0)
+ {
+ printf ("closing h2 failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/reldep7mod1.c b/REORG.TODO/elf/reldep7mod1.c
new file mode 100644
index 0000000000..de1bb3a6cd
--- /dev/null
+++ b/REORG.TODO/elf/reldep7mod1.c
@@ -0,0 +1,12 @@
+int foo (void) __attribute__ ((weak));
+int
+foo (void)
+{
+ return 1;
+}
+
+int
+mod1_bar (void)
+{
+ return foo ();
+}
diff --git a/REORG.TODO/elf/reldep7mod2.c b/REORG.TODO/elf/reldep7mod2.c
new file mode 100644
index 0000000000..3fa3368792
--- /dev/null
+++ b/REORG.TODO/elf/reldep7mod2.c
@@ -0,0 +1,12 @@
+int foo (void) __attribute__ ((weak));
+int
+foo (void)
+{
+ return 2;
+}
+
+int
+mod2_bar (void)
+{
+ return foo ();
+}
diff --git a/REORG.TODO/elf/reldep8.c b/REORG.TODO/elf/reldep8.c
new file mode 100644
index 0000000000..90009a5609
--- /dev/null
+++ b/REORG.TODO/elf/reldep8.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+int
+main (void)
+{
+ void *handle = dlopen ("reldep8mod3.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ dlclose (handle);
+ abort ();
+}
diff --git a/REORG.TODO/elf/reldep8mod1.c b/REORG.TODO/elf/reldep8mod1.c
new file mode 100644
index 0000000000..acddc4cf8b
--- /dev/null
+++ b/REORG.TODO/elf/reldep8mod1.c
@@ -0,0 +1,19 @@
+#include <stdlib.h>
+void
+foo (void)
+{
+ exit (0);
+}
+
+void
+__attribute__((destructor))
+bar (void)
+{
+ static int i;
+ foo ();
+ ++i;
+}
+void
+baz (void)
+{
+}
diff --git a/REORG.TODO/elf/reldep8mod2.c b/REORG.TODO/elf/reldep8mod2.c
new file mode 100644
index 0000000000..d0020240a8
--- /dev/null
+++ b/REORG.TODO/elf/reldep8mod2.c
@@ -0,0 +1,7 @@
+void
+__attribute__((constructor))
+xxx (void)
+{
+ extern void baz (void);
+ baz ();
+}
diff --git a/REORG.TODO/elf/reldep8mod3.c b/REORG.TODO/elf/reldep8mod3.c
new file mode 100644
index 0000000000..6d1a0d47b7
--- /dev/null
+++ b/REORG.TODO/elf/reldep8mod3.c
@@ -0,0 +1 @@
+int x;
diff --git a/REORG.TODO/elf/reldep9.c b/REORG.TODO/elf/reldep9.c
new file mode 100644
index 0000000000..51c7a8bb9e
--- /dev/null
+++ b/REORG.TODO/elf/reldep9.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+int
+main (void)
+{
+ void *handle = dlopen ("reldep9mod3.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ dlclose (handle);
+ abort ();
+}
diff --git a/REORG.TODO/elf/reldep9mod1.c b/REORG.TODO/elf/reldep9mod1.c
new file mode 100644
index 0000000000..249a2bae1c
--- /dev/null
+++ b/REORG.TODO/elf/reldep9mod1.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+void
+foo (void)
+{
+ exit (0);
+}
+
+void
+__attribute__((destructor))
+bar (void)
+{
+ static int i;
+ foo ();
+ ++i;
+}
+
+void
+__attribute__((constructor))
+destr (void)
+{
+ extern void baz (void);
+ baz ();
+}
diff --git a/REORG.TODO/elf/reldep9mod2.c b/REORG.TODO/elf/reldep9mod2.c
new file mode 100644
index 0000000000..090966e3e3
--- /dev/null
+++ b/REORG.TODO/elf/reldep9mod2.c
@@ -0,0 +1,3 @@
+void baz (void)
+{
+}
diff --git a/REORG.TODO/elf/reldep9mod3.c b/REORG.TODO/elf/reldep9mod3.c
new file mode 100644
index 0000000000..6d1a0d47b7
--- /dev/null
+++ b/REORG.TODO/elf/reldep9mod3.c
@@ -0,0 +1 @@
+int x;
diff --git a/REORG.TODO/elf/reldepmod1.c b/REORG.TODO/elf/reldepmod1.c
new file mode 100644
index 0000000000..b8ef6401e1
--- /dev/null
+++ b/REORG.TODO/elf/reldepmod1.c
@@ -0,0 +1,10 @@
+extern int foo (void);
+
+int some_var;
+
+
+int
+foo (void)
+{
+ return some_var;
+}
diff --git a/REORG.TODO/elf/reldepmod2.c b/REORG.TODO/elf/reldepmod2.c
new file mode 100644
index 0000000000..b7edebae80
--- /dev/null
+++ b/REORG.TODO/elf/reldepmod2.c
@@ -0,0 +1,8 @@
+extern int foo (void);
+extern int call_me (void);
+
+int
+call_me (void)
+{
+ return foo () - 42;
+}
diff --git a/REORG.TODO/elf/reldepmod3.c b/REORG.TODO/elf/reldepmod3.c
new file mode 100644
index 0000000000..66a996cd90
--- /dev/null
+++ b/REORG.TODO/elf/reldepmod3.c
@@ -0,0 +1,20 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int call_me (void);
+
+int
+call_me (void)
+{
+ int (*fp) (void);
+
+ fp = dlsym (RTLD_DEFAULT, "foo");
+ if (fp == NULL)
+ {
+ printf ("cannot get address of foo in global scope: %s\n", dlerror ());
+ exit (1);
+ }
+
+ return fp () - 42;
+}
diff --git a/REORG.TODO/elf/reldepmod4.c b/REORG.TODO/elf/reldepmod4.c
new file mode 100644
index 0000000000..dcb503bba7
--- /dev/null
+++ b/REORG.TODO/elf/reldepmod4.c
@@ -0,0 +1,37 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int call_me (void);
+
+int
+call_me (void)
+{
+ void *h;
+ int (*fp) (void);
+ int res;
+
+ h = dlopen ("reldepmod1.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open reldepmod1.so in %s: %s\n", __FILE__, dlerror ());
+ exit (1);
+ }
+
+ fp = dlsym (h, "foo");
+ if (fp == NULL)
+ {
+ printf ("cannot get address of foo in global scope: %s\n", dlerror ());
+ exit (1);
+ }
+
+ res = fp () - 42;
+
+ if (dlclose (h) != 0)
+ {
+ printf ("failure when closing h in %s: %s\n", __FILE__, dlerror ());
+ exit (1);
+ }
+
+ return res;
+}
diff --git a/REORG.TODO/elf/reldepmod5.c b/REORG.TODO/elf/reldepmod5.c
new file mode 100644
index 0000000000..62df697162
--- /dev/null
+++ b/REORG.TODO/elf/reldepmod5.c
@@ -0,0 +1,7 @@
+extern int foo (void);
+
+int
+foo (void)
+{
+ return 42;
+}
diff --git a/REORG.TODO/elf/reldepmod6.c b/REORG.TODO/elf/reldepmod6.c
new file mode 100644
index 0000000000..cd2aeb400d
--- /dev/null
+++ b/REORG.TODO/elf/reldepmod6.c
@@ -0,0 +1,8 @@
+extern int call_me (void);
+extern int bar (void);
+
+int
+bar (void)
+{
+ return call_me ();
+}
diff --git a/REORG.TODO/elf/resolvfail.c b/REORG.TODO/elf/resolvfail.c
new file mode 100644
index 0000000000..ebd635d153
--- /dev/null
+++ b/REORG.TODO/elf/resolvfail.c
@@ -0,0 +1,31 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+static const char obj[] = "testobj1.so";
+
+int
+main (void)
+{
+ void *d = dlopen (obj, RTLD_LAZY);
+ int n;
+
+ if (d == NULL)
+ {
+ printf ("cannot load %s: %s\n", obj, dlerror ());
+ return 1;
+ }
+
+ for (n = 0; n < 10000; ++n)
+ if (dlsym (d, "does not exist") != NULL)
+ {
+ puts ("dlsym() did not fail");
+ return 1;
+ }
+ else if (dlerror () == NULL)
+ {
+ puts ("dlerror() didn't return a string");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/restest1.c b/REORG.TODO/elf/restest1.c
new file mode 100644
index 0000000000..eb5aeca59e
--- /dev/null
+++ b/REORG.TODO/elf/restest1.c
@@ -0,0 +1,57 @@
+#include <dlfcn.h>
+#include <error.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ void *h1;
+ int (*fp1) (int);
+ void *h2;
+ int (*fp2) (int);
+ int res1;
+ int res2;
+
+ mtrace ();
+
+ h1 = dlopen ("testobj1.so", RTLD_LAZY);
+ if (h1 == NULL)
+ error (EXIT_FAILURE, 0, "while loading `%s': %s", "testobj1.so",
+ dlerror ());
+
+ h2 = dlopen ("testobj1_1.so", RTLD_LAZY);
+ if (h1 == NULL)
+ error (EXIT_FAILURE, 0, "while loading `%s': %s", "testobj1_1.so",
+ dlerror ());
+
+ fp1 = dlsym (h1, "obj1func1");
+ if (fp1 == NULL)
+ error (EXIT_FAILURE, 0, "getting `obj1func1' in `%s': %s",
+ "testobj1.so", dlerror ());
+
+ fp2 = dlsym (h2, "obj1func1");
+ if (fp2 == NULL)
+ error (EXIT_FAILURE, 0, "getting `obj1func1' in `%s': %s",
+ "testobj1_1.so", dlerror ());
+
+ res1 = fp1 (10);
+ res2 = fp2 (10);
+ printf ("fp1(10) = %d\nfp2(10) = %d\n", res1, res2);
+
+ if (dlclose (h1) != 0)
+ error (EXIT_FAILURE, 0, "cannot close testobj1.so: %s\n", dlerror ());
+ if (dlclose (h2) != 0)
+ error (EXIT_FAILURE, 0, "cannot close testobj1_1.so: %s\n", dlerror ());
+
+ return res1 != 42 || res2 != 72;
+}
+
+
+extern int foo (int a);
+int
+foo (int a)
+{
+ return a + 10;
+}
diff --git a/REORG.TODO/elf/restest2.c b/REORG.TODO/elf/restest2.c
new file mode 100644
index 0000000000..f959f030a0
--- /dev/null
+++ b/REORG.TODO/elf/restest2.c
@@ -0,0 +1,33 @@
+#include <sys/types.h>
+#include <dlfcn.h>
+#include <error.h>
+#include <mcheck.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+pid_t pid, pid2;
+
+pid_t getpid(void)
+{
+ pid_t (*f)(void);
+ f = (pid_t (*)(void)) dlsym (RTLD_NEXT, "getpid");
+ if (f == NULL)
+ error (EXIT_FAILURE, 0, "dlsym (RTLD_NEXT, \"getpid\"): %s", dlerror ());
+ return (pid2 = f()) + 26;
+}
+
+int
+main (void)
+{
+ pid_t (*f)(void);
+
+ mtrace ();
+
+ f = (pid_t (*)(void)) dlsym (RTLD_DEFAULT, "getpid");
+ if (f == NULL)
+ error (EXIT_FAILURE, 0, "dlsym (RTLD_DEFAULT, \"getpid\"): %s", dlerror ());
+ pid = f();
+ if (pid != pid2 + 26)
+ error (EXIT_FAILURE, 0, "main getpid() not called");
+ return 0;
+}
diff --git a/REORG.TODO/elf/rtld-Rules b/REORG.TODO/elf/rtld-Rules
new file mode 100644
index 0000000000..2c7b99828c
--- /dev/null
+++ b/REORG.TODO/elf/rtld-Rules
@@ -0,0 +1,149 @@
+# Subroutine makefile for compiling libc modules linked into dynamic linker.
+
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+# This makefile is never used by itself, but only from the rtld-libc.a
+# rule in Makefile, which does make -f librtld.mk -f rtld-Rules.
+# librtld.mk is the generated file containing variable definitions for
+# `rtld-subdirs', a subset of the top-level $(subdirs) list; and for each
+# SUBDIR in $(rtld-subdirs), `rtld-SUBDIR' listing `module.os' file names.
+
+.PHONY: rtld-all
+rtld-all:
+
+# When run from the elf/Makefile to build rtld-libc.a, $(subdir) is elf.
+ifneq ($(subdir),elf)
+ifndef rtld-modules
+error rtld-modules not set
+endif
+endif
+
+ifndef rtld-modules
+# Running to build rtld-libc.a, driving runs of $(rtld-subdir-make), below.
+
+ifndef rtld-subdirs
+error This makefile is a subroutine of elf/Makefile not to be used directly
+endif
+
+include ../Makeconfig
+
+rtld-all: $(objpfx)rtld-libc.a
+
+$(objpfx)rtld-libc.a: $(foreach dir,$(rtld-subdirs),\
+ $(addprefix $(common-objpfx)$(dir)/rtld-,\
+ $(rtld-$(dir))))
+ @-rm -f $@T
+ $(AR) cq$(verbose) $@T $^
+ mv -f $@T $@
+
+# Use the verbose option of ar and tar when not running silently.
+ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s
+verbose := v
+else # -s
+verbose :=
+endif # not -s
+
+
+# For each subdirectory, define a pattern rule that makes all of that
+# subdirectory's modules at once with one recursive make command.
+object-suffixes-left := $(rtld-subdirs)
+define o-iterator-doit
+$(foreach obj,$(rtld-$o),$(common-objpfx)%/rtld-$(obj)): FORCE ; \
+ +$$(rtld-subdir-make)
+endef
+include $(patsubst %,../o-iterator.mk,$(object-suffixes-left))
+
+# This is how we descend into each subdirectory. See below.
+define rtld-subdir-make
+$(MAKE) $(subdir-args) objdir=$(objdir) \
+ -f Makefile -f ../elf/rtld-Rules rtld-all \
+ rtld-modules='$(addprefix rtld-,$(rtld-$*))'
+endef
+
+# See subdir-target-args in ../Makefile for the model.
+subdir-args = subdir=$*$(if $($*-srcdir),\
+ -C $($*-srcdir) ..=`pwd`/,\
+ -C $(..)$* ..=../)
+
+FORCE:
+
+else
+
+# In this case we are being run by $(rtld-subdir-make), above.
+# Some other subdir's Makefile has provided all its normal rules,
+# and we just provide some additional definitions.
+
+rtld-compile-command.S = $(compile-command.S) $(rtld-CPPFLAGS)
+rtld-compile-command.s = $(compile-command.s) $(rtld-CPPFLAGS)
+rtld-compile-command.c = $(compile-command.c) $(rtld-CPPFLAGS) $(rtld-CFLAGS)
+
+# These are the basic compilation rules corresponding to the Makerules ones.
+# The sysd-rules generated makefile already defines pattern rules for rtld-%
+# targets built from sysdeps source files.
+$(objpfx)rtld-%.os: rtld-%.S $(before-compile)
+ $(rtld-compile-command.S)
+$(objpfx)rtld-%.os: rtld-%.s $(before-compile)
+ $(rtld-compile-command.s)
+$(objpfx)rtld-%.os: rtld-%.c $(before-compile)
+ $(rtld-compile-command.c)
+$(objpfx)rtld-%.os: %.S $(before-compile)
+ $(rtld-compile-command.S)
+$(objpfx)rtld-%.os: %.s $(before-compile)
+ $(rtld-compile-command.s)
+$(objpfx)rtld-%.os: %.c $(before-compile)
+ $(rtld-compile-command.c)
+
+# The rules for generated source files.
+$(objpfx)rtld-%.os: $(objpfx)rtld-%.S $(before-compile)
+ $(rtld-compile-command.S)
+$(objpfx)rtld-%.os: $(objpfx)rtld-%.s $(before-compile)
+ $(rtld-compile-command.s)
+$(objpfx)rtld-%.os: $(objpfx)rtld-%.c $(before-compile)
+ $(rtld-compile-command.c)
+$(objpfx)rtld-%.os: $(objpfx)%.S $(before-compile)
+ $(rtld-compile-command.S)
+$(objpfx)rtld-%.os: $(objpfx)%.s $(before-compile)
+ $(rtld-compile-command.s)
+$(objpfx)rtld-%.os: $(objpfx)%.c $(before-compile)
+ $(rtld-compile-command.c)
+
+# The command line setting of rtld-modules (see above) tells us
+# what we need to build, and that tells us what dependency files we need.
+rtld-all: $(addprefix $(objpfx),$(rtld-modules))
+
+# Figure out the dependency files we need. After respecting the $(omit-deps)
+# list as applied to the names without the `rtld-', there may be none left.
+rtld-depfiles := $(patsubst %,$(objpfx)rtld-%.os.d,\
+ $(filter-out $(omit-deps),\
+ $(rtld-modules:rtld-%.os=%)))
+rtld-depfiles := $(strip $(wildcard $(rtld-depfiles)) \
+ $(patsubst %.dt,%.d,\
+ $(wildcard $(rtld-depfiles:.d=.dt))))
+ifdef rtld-depfiles
+-include $(rtld-depfiles)
+endif
+
+# This here is the whole point of all the shenanigans.
+# Set libof-* for each routine.
+cpp-srcs-left := $(rtld-modules:%.os=%)
+lib := rtld
+include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
+
+rtld-CFLAGS += $(no-stack-protector)
+
+endif
diff --git a/REORG.TODO/elf/rtld-debugger-interface.txt b/REORG.TODO/elf/rtld-debugger-interface.txt
new file mode 100644
index 0000000000..61bc99e4b0
--- /dev/null
+++ b/REORG.TODO/elf/rtld-debugger-interface.txt
@@ -0,0 +1,122 @@
+Standard debugger interface
+===========================
+
+The run-time linker exposes a rendezvous structure to allow debuggers
+to interface with it. This structure, r_debug, is defined in link.h.
+If the executable's dynamic section has a DT_DEBUG element, the
+run-time linker sets that element's value to the address where this
+structure can be found.
+
+The r_debug structure contains (amongst others) the following fields:
+
+ struct link_map *r_map:
+ A linked list of loaded objects.
+
+ enum { RT_CONSISTENT, RT_ADD, RT_DELETE } r_state:
+ The current state of the r_map list. RT_CONSISTENT means that r_map
+ is not currently being modified and may safely be inspected. RT_ADD
+ means that an object is being added to r_map, and that the list is
+ not guaranteed to be consistent. Likewise RT_DELETE means that an
+ object is being removed from the list.
+
+ ElfW(Addr) r_brk:
+ The address of a function internal to the run-time linker which is
+ called whenever r_state is changed. The debugger should set a
+ breakpoint at this address if it wants to notice mapping changes.
+
+This protocol is widely supported, but somewhat limited in that it
+has no provision to provide access to multiple namespaces, and that
+the notifications (via r_brk) only refer to changes to r_map--the
+debugger is notified that a new object has been added, for instance,
+but there is no way for the debugger to discover whether any of the
+objects in the link-map have been relocated or not.
+
+
+Probe-based debugger interface
+==============================
+
+Systemtap is a dynamic tracing/instrumenting tool available on Linux.
+Probes that are not fired at run time have close to zero overhead.
+glibc contains a number of probes that debuggers can set breakpoints
+on in order to notice certain events.
+
+All rtld probes have the following arguments:
+
+ arg1: Lmid_t lmid:
+ The link-map ID of the link-map list that the object was loaded
+ into. This will be LM_ID_BASE for the application's main link-map
+ list, or some other value for different namespaces.
+
+ arg2: struct r_debug *r_debug:
+ A pointer to the r_debug structure containing the link-map list
+ that the object was loaded into. This will be the value stored in
+ DT_DEBUG for the application's main link-map list, or some other
+ value for different namespaces.
+
+map_complete and reloc_complete may have the following additional
+argument:
+
+ arg3: struct link_map *new:
+ A pointer which, if not NULL, points to the entry in the specified
+ r_debug structure's link-map list corresponding to the first new
+ object to have been mapped or relocated, with new->l_next pointing
+ to the link-map of the next new object to have been mapped or
+ relocated, and so on. Note that because `new' is an entry in a
+ larger list, new->l_prev (if not NULL) will point to what was the
+ last link-map in the link-map list prior to the new objects being
+ mapped or relocated.
+
+The following probes are available:
+
+ init_start:
+ This is called once, when the linker is about to fill in the main
+ r_debug structure at application startup. init_start always has
+ lmid set to LM_ID_BASE and r_debug set to the value stored in
+ DT_DEBUG. r_debug is not guaranteed to be consistent until
+ init_complete is fired.
+
+ init_complete:
+ This is called once, when the linker has filled in the main
+ r_debug structure at application startup. init_complete always
+ has lmid set to LM_ID_BASE and r_debug set to the value stored
+ in DT_DEBUG. The r_debug structure is consistent and may be
+ inspected, and all objects in the link-map are guaranteed to
+ have been relocated.
+
+ map_start:
+ The linker is about to map new objects into the specified
+ namespace. The namespace's r_debug structure is not guaranteed
+ to be consistent until a corresponding map_complete is fired.
+
+ map_complete:
+ The linker has finished mapping new objects into the specified
+ namespace. The namespace's r_debug structure is consistent and
+ may be inspected, although objects in the namespace's link-map
+ are not guaranteed to have been relocated.
+
+ map_failed:
+ The linker failed while attempting to map new objects into
+ the specified namespace. The namespace's r_debug structure
+ is consistent and may be inspected.
+
+ reloc_start:
+ The linker is about to relocate all unrelocated objects in the
+ specified namespace. The namespace's r_debug structure is not
+ guaranteed to be consistent until a corresponding reloc_complete
+ is fired.
+
+ reloc_complete:
+ The linker has relocated all objects in the specified namespace.
+ The namespace's r_debug structure is consistent and may be
+ inspected, and all objects in the namespace's link-map are
+ guaranteed to have been relocated.
+
+ unmap_start:
+ The linker is about to remove objects from the specified
+ namespace. The namespace's r_debug structure is not guaranteed to
+ be consistent until a corresponding unmap_complete is fired.
+
+ unmap_complete:
+ The linker has finished removing objects into the specified
+ namespace. The namespace's r_debug structure is consistent and
+ may be inspected.
diff --git a/REORG.TODO/elf/rtld.c b/REORG.TODO/elf/rtld.c
new file mode 100644
index 0000000000..3746653afb
--- /dev/null
+++ b/REORG.TODO/elf/rtld.c
@@ -0,0 +1,2652 @@
+/* Run time dynamic linker.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <ldsodefs.h>
+#include <_itoa.h>
+#include <entry.h>
+#include <fpu_control.h>
+#include <hp-timing.h>
+#include <libc-lock.h>
+#include "dynamic-link.h"
+#include <dl-librecon.h>
+#include <unsecvars.h>
+#include <dl-cache.h>
+#include <dl-osinfo.h>
+#include <dl-procinfo.h>
+#include <tls.h>
+#include <stap-probe.h>
+#include <stackinfo.h>
+
+#include <assert.h>
+
+/* Avoid PLT use for our local calls at startup. */
+extern __typeof (__mempcpy) __mempcpy attribute_hidden;
+
+/* GCC has mental blocks about _exit. */
+extern __typeof (_exit) exit_internal asm ("_exit") attribute_hidden;
+#define _exit exit_internal
+
+/* Helper function to handle errors while resolving symbols. */
+static void print_unresolved (int errcode, const char *objname,
+ const char *errsting);
+
+/* Helper function to handle errors when a version is missing. */
+static void print_missing_version (int errcode, const char *objname,
+ const char *errsting);
+
+/* Print the various times we collected. */
+static void print_statistics (hp_timing_t *total_timep);
+
+/* Add audit objects. */
+static void process_dl_audit (char *str);
+
+/* This is a list of all the modes the dynamic loader can be in. */
+enum mode { normal, list, verify, trace };
+
+/* Process all environments variables the dynamic linker must recognize.
+ Since all of them start with `LD_' we are a bit smarter while finding
+ all the entries. */
+static void process_envvars (enum mode *modep);
+
+#ifdef DL_ARGV_NOT_RELRO
+int _dl_argc attribute_hidden;
+char **_dl_argv = NULL;
+/* Nonzero if we were run directly. */
+unsigned int _dl_skip_args attribute_hidden;
+#else
+int _dl_argc attribute_relro attribute_hidden;
+char **_dl_argv attribute_relro = NULL;
+unsigned int _dl_skip_args attribute_relro attribute_hidden;
+#endif
+rtld_hidden_data_def (_dl_argv)
+
+#ifndef THREAD_SET_STACK_GUARD
+/* Only exported for architectures that don't store the stack guard canary
+ in thread local area. */
+uintptr_t __stack_chk_guard attribute_relro;
+#endif
+
+/* Only exported for architectures that don't store the pointer guard
+ value in thread local area. */
+uintptr_t __pointer_chk_guard_local
+ attribute_relro attribute_hidden __attribute__ ((nocommon));
+#ifndef THREAD_SET_POINTER_GUARD
+strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)
+#endif
+
+
+/* List of auditing DSOs. */
+static struct audit_list
+{
+ const char *name;
+ struct audit_list *next;
+} *audit_list;
+
+#ifndef HAVE_INLINED_SYSCALLS
+/* Set nonzero during loading and initialization of executable and
+ libraries, cleared before the executable's entry point runs. This
+ must not be initialized to nonzero, because the unused dynamic
+ linker loaded in for libc.so's "ld.so.1" dep will provide the
+ definition seen by libc.so's initializer; that value must be zero,
+ and will be since that dynamic linker's _dl_start and dl_main will
+ never be called. */
+int _dl_starting_up = 0;
+rtld_hidden_def (_dl_starting_up)
+#endif
+
+/* This is the structure which defines all variables global to ld.so
+ (except those which cannot be added for some reason). */
+struct rtld_global _rtld_global =
+ {
+ /* Generally the default presumption without further information is an
+ * executable stack but this is not true for all platforms. */
+ ._dl_stack_flags = DEFAULT_STACK_PERMS,
+#ifdef _LIBC_REENTRANT
+ ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
+ ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
+#endif
+ ._dl_nns = 1,
+ ._dl_ns =
+ {
+#ifdef _LIBC_REENTRANT
+ [LM_ID_BASE] = { ._ns_unique_sym_table
+ = { .lock = _RTLD_LOCK_RECURSIVE_INITIALIZER } }
+#endif
+ }
+ };
+/* If we would use strong_alias here the compiler would see a
+ non-hidden definition. This would undo the effect of the previous
+ declaration. So spell out was strong_alias does plus add the
+ visibility attribute. */
+extern struct rtld_global _rtld_local
+ __attribute__ ((alias ("_rtld_global"), visibility ("hidden")));
+
+
+/* This variable is similar to _rtld_local, but all values are
+ read-only after relocation. */
+struct rtld_global_ro _rtld_global_ro attribute_relro =
+ {
+ /* Get architecture specific initializer. */
+#include <dl-procinfo.c>
+#ifdef NEED_DL_SYSINFO
+ ._dl_sysinfo = DL_SYSINFO_DEFAULT,
+#endif
+ ._dl_debug_fd = STDERR_FILENO,
+ ._dl_use_load_bias = -2,
+ ._dl_correct_cache_id = _DL_CACHE_DEFAULT_ID,
+#if !HAVE_TUNABLES
+ ._dl_hwcap_mask = HWCAP_IMPORTANT,
+#endif
+ ._dl_lazy = 1,
+ ._dl_fpu_control = _FPU_DEFAULT,
+ ._dl_pagesize = EXEC_PAGESIZE,
+ ._dl_inhibit_cache = 0,
+
+ /* Function pointers. */
+ ._dl_debug_printf = _dl_debug_printf,
+ ._dl_mcount = _dl_mcount,
+ ._dl_lookup_symbol_x = _dl_lookup_symbol_x,
+ ._dl_check_caller = _dl_check_caller,
+ ._dl_open = _dl_open,
+ ._dl_close = _dl_close,
+ ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
+#ifdef HAVE_DL_DISCOVER_OSVERSION
+ ._dl_discover_osversion = _dl_discover_osversion
+#endif
+ };
+/* If we would use strong_alias here the compiler would see a
+ non-hidden definition. This would undo the effect of the previous
+ declaration. So spell out was strong_alias does plus add the
+ visibility attribute. */
+extern struct rtld_global_ro _rtld_local_ro
+ __attribute__ ((alias ("_rtld_global_ro"), visibility ("hidden")));
+
+
+static void dl_main (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
+ ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv);
+
+/* These two variables cannot be moved into .data.rel.ro. */
+static struct libname_list _dl_rtld_libname;
+static struct libname_list _dl_rtld_libname2;
+
+/* Variable for statistics. */
+#ifndef HP_TIMING_NONAVAIL
+static hp_timing_t relocate_time;
+static hp_timing_t load_time attribute_relro;
+static hp_timing_t start_time attribute_relro;
+#endif
+
+/* Additional definitions needed by TLS initialization. */
+#ifdef TLS_INIT_HELPER
+TLS_INIT_HELPER
+#endif
+
+/* Helper function for syscall implementation. */
+#ifdef DL_SYSINFO_IMPLEMENTATION
+DL_SYSINFO_IMPLEMENTATION
+#endif
+
+/* Before ld.so is relocated we must not access variables which need
+ relocations. This means variables which are exported. Variables
+ declared as static are fine. If we can mark a variable hidden this
+ is fine, too. The latter is important here. We can avoid setting
+ up a temporary link map for ld.so if we can mark _rtld_global as
+ hidden. */
+#ifdef PI_STATIC_AND_HIDDEN
+# define DONT_USE_BOOTSTRAP_MAP 1
+#endif
+
+#ifdef DONT_USE_BOOTSTRAP_MAP
+static ElfW(Addr) _dl_start_final (void *arg);
+#else
+struct dl_start_final_info
+{
+ struct link_map l;
+#if !defined HP_TIMING_NONAVAIL && HP_TIMING_INLINE
+ hp_timing_t start_time;
+#endif
+};
+static ElfW(Addr) _dl_start_final (void *arg,
+ struct dl_start_final_info *info);
+#endif
+
+/* These defined magically in the linker script. */
+extern char _begin[] attribute_hidden;
+extern char _etext[] attribute_hidden;
+extern char _end[] attribute_hidden;
+
+
+#ifdef RTLD_START
+RTLD_START
+#else
+# error "sysdeps/MACHINE/dl-machine.h fails to define RTLD_START"
+#endif
+
+/* This is the second half of _dl_start (below). It can be inlined safely
+ under DONT_USE_BOOTSTRAP_MAP, where it is careful not to make any GOT
+ references. When the tools don't permit us to avoid using a GOT entry
+ for _dl_rtld_global (no attribute_hidden support), we must make sure
+ this function is not inlined (see below). */
+
+#ifdef DONT_USE_BOOTSTRAP_MAP
+static inline ElfW(Addr) __attribute__ ((always_inline))
+_dl_start_final (void *arg)
+#else
+static ElfW(Addr) __attribute__ ((noinline))
+_dl_start_final (void *arg, struct dl_start_final_info *info)
+#endif
+{
+ ElfW(Addr) start_addr;
+
+ if (HP_SMALL_TIMING_AVAIL)
+ {
+ /* If it hasn't happen yet record the startup time. */
+ if (! HP_TIMING_INLINE)
+ HP_TIMING_NOW (start_time);
+#if !defined DONT_USE_BOOTSTRAP_MAP && !defined HP_TIMING_NONAVAIL
+ else
+ start_time = info->start_time;
+#endif
+ }
+
+ /* Transfer data about ourselves to the permanent link_map structure. */
+#ifndef DONT_USE_BOOTSTRAP_MAP
+ GL(dl_rtld_map).l_addr = info->l.l_addr;
+ GL(dl_rtld_map).l_ld = info->l.l_ld;
+ memcpy (GL(dl_rtld_map).l_info, info->l.l_info,
+ sizeof GL(dl_rtld_map).l_info);
+ GL(dl_rtld_map).l_mach = info->l.l_mach;
+ GL(dl_rtld_map).l_relocated = 1;
+#endif
+ _dl_setup_hash (&GL(dl_rtld_map));
+ GL(dl_rtld_map).l_real = &GL(dl_rtld_map);
+ GL(dl_rtld_map).l_map_start = (ElfW(Addr)) _begin;
+ GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
+ GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext;
+ /* Copy the TLS related data if necessary. */
+#ifndef DONT_USE_BOOTSTRAP_MAP
+# if NO_TLS_OFFSET != 0
+ GL(dl_rtld_map).l_tls_offset = NO_TLS_OFFSET;
+# endif
+#endif
+
+ HP_TIMING_NOW (GL(dl_cpuclock_offset));
+
+ /* Initialize the stack end variable. */
+ __libc_stack_end = __builtin_frame_address (0);
+
+ /* Call the OS-dependent function to set up life so we can do things like
+ file access. It will call `dl_main' (below) to do all the real work
+ of the dynamic linker, and then unwind our frame and run the user
+ entry point on the same stack we entered on. */
+ start_addr = _dl_sysdep_start (arg, &dl_main);
+
+#ifndef HP_TIMING_NONAVAIL
+ hp_timing_t rtld_total_time;
+ if (HP_SMALL_TIMING_AVAIL)
+ {
+ hp_timing_t end_time;
+
+ /* Get the current time. */
+ HP_TIMING_NOW (end_time);
+
+ /* Compute the difference. */
+ HP_TIMING_DIFF (rtld_total_time, start_time, end_time);
+ }
+#endif
+
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
+ {
+#ifndef HP_TIMING_NONAVAIL
+ print_statistics (&rtld_total_time);
+#else
+ print_statistics (NULL);
+#endif
+ }
+
+ return start_addr;
+}
+
+static ElfW(Addr) __attribute_used__ internal_function
+_dl_start (void *arg)
+{
+#ifdef DONT_USE_BOOTSTRAP_MAP
+# define bootstrap_map GL(dl_rtld_map)
+#else
+ struct dl_start_final_info info;
+# define bootstrap_map info.l
+#endif
+
+ /* This #define produces dynamic linking inline functions for
+ bootstrap relocation instead of general-purpose relocation.
+ Since ld.so must not have any undefined symbols the result
+ is trivial: always the map of ld.so itself. */
+#define RTLD_BOOTSTRAP
+#define RESOLVE_MAP(sym, version, flags) (&bootstrap_map)
+#include "dynamic-link.h"
+
+ if (HP_TIMING_INLINE && HP_SMALL_TIMING_AVAIL)
+#ifdef DONT_USE_BOOTSTRAP_MAP
+ HP_TIMING_NOW (start_time);
+#else
+ HP_TIMING_NOW (info.start_time);
+#endif
+
+ /* Partly clean the `bootstrap_map' structure up. Don't use
+ `memset' since it might not be built in or inlined and we cannot
+ make function calls at this point. Use '__builtin_memset' if we
+ know it is available. We do not have to clear the memory if we
+ do not have to use the temporary bootstrap_map. Global variables
+ are initialized to zero by default. */
+#ifndef DONT_USE_BOOTSTRAP_MAP
+# ifdef HAVE_BUILTIN_MEMSET
+ __builtin_memset (bootstrap_map.l_info, '\0', sizeof (bootstrap_map.l_info));
+# else
+ for (size_t cnt = 0;
+ cnt < sizeof (bootstrap_map.l_info) / sizeof (bootstrap_map.l_info[0]);
+ ++cnt)
+ bootstrap_map.l_info[cnt] = 0;
+# endif
+#endif
+
+ /* Figure out the run-time load address of the dynamic linker itself. */
+ bootstrap_map.l_addr = elf_machine_load_address ();
+
+ /* Read our own dynamic section and fill in the info array. */
+ bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
+ elf_get_dynamic_info (&bootstrap_map, NULL);
+
+#if NO_TLS_OFFSET != 0
+ bootstrap_map.l_tls_offset = NO_TLS_OFFSET;
+#endif
+
+#ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
+ ELF_MACHINE_BEFORE_RTLD_RELOC (bootstrap_map.l_info);
+#endif
+
+ if (bootstrap_map.l_addr || ! bootstrap_map.l_info[VALIDX(DT_GNU_PRELINKED)])
+ {
+ /* Relocate ourselves so we can do normal function calls and
+ data access using the global offset table. */
+
+ ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0, 0);
+ }
+ bootstrap_map.l_relocated = 1;
+
+ /* Please note that we don't allow profiling of this object and
+ therefore need not test whether we have to allocate the array
+ for the relocation results (as done in dl-reloc.c). */
+
+ /* Now life is sane; we can call functions and access global data.
+ Set up to use the operating system facilities, and find out from
+ the operating system's program loader where to find the program
+ header table in core. Put the rest of _dl_start into a separate
+ function, that way the compiler cannot put accesses to the GOT
+ before ELF_DYNAMIC_RELOCATE. */
+ {
+#ifdef DONT_USE_BOOTSTRAP_MAP
+ ElfW(Addr) entry = _dl_start_final (arg);
+#else
+ ElfW(Addr) entry = _dl_start_final (arg, &info);
+#endif
+
+#ifndef ELF_MACHINE_START_ADDRESS
+# define ELF_MACHINE_START_ADDRESS(map, start) (start)
+#endif
+
+ return ELF_MACHINE_START_ADDRESS (GL(dl_ns)[LM_ID_BASE]._ns_loaded, entry);
+ }
+}
+
+
+
+/* Now life is peachy; we can do all normal operations.
+ On to the real work. */
+
+/* Some helper functions. */
+
+/* Arguments to relocate_doit. */
+struct relocate_args
+{
+ struct link_map *l;
+ int reloc_mode;
+};
+
+struct map_args
+{
+ /* Argument to map_doit. */
+ const char *str;
+ struct link_map *loader;
+ int mode;
+ /* Return value of map_doit. */
+ struct link_map *map;
+};
+
+struct dlmopen_args
+{
+ const char *fname;
+ struct link_map *map;
+};
+
+struct lookup_args
+{
+ const char *name;
+ struct link_map *map;
+ void *result;
+};
+
+/* Arguments to version_check_doit. */
+struct version_check_args
+{
+ int doexit;
+ int dotrace;
+};
+
+static void
+relocate_doit (void *a)
+{
+ struct relocate_args *args = (struct relocate_args *) a;
+
+ _dl_relocate_object (args->l, args->l->l_scope, args->reloc_mode, 0);
+}
+
+static void
+map_doit (void *a)
+{
+ struct map_args *args = (struct map_args *) a;
+ int type = (args->mode == __RTLD_OPENEXEC) ? lt_executable : lt_library;
+ args->map = _dl_map_object (args->loader, args->str, type, 0,
+ args->mode, LM_ID_BASE);
+}
+
+static void
+dlmopen_doit (void *a)
+{
+ struct dlmopen_args *args = (struct dlmopen_args *) a;
+ args->map = _dl_open (args->fname,
+ (RTLD_LAZY | __RTLD_DLOPEN | __RTLD_AUDIT
+ | __RTLD_SECURE),
+ dl_main, LM_ID_NEWLM, _dl_argc, _dl_argv,
+ __environ);
+}
+
+static void
+lookup_doit (void *a)
+{
+ struct lookup_args *args = (struct lookup_args *) a;
+ const ElfW(Sym) *ref = NULL;
+ args->result = NULL;
+ lookup_t l = _dl_lookup_symbol_x (args->name, args->map, &ref,
+ args->map->l_local_scope, NULL, 0,
+ DL_LOOKUP_RETURN_NEWEST, NULL);
+ if (ref != NULL)
+ args->result = DL_SYMBOL_ADDRESS (l, ref);
+}
+
+static void
+version_check_doit (void *a)
+{
+ struct version_check_args *args = (struct version_check_args *) a;
+ if (_dl_check_all_versions (GL(dl_ns)[LM_ID_BASE]._ns_loaded, 1,
+ args->dotrace) && args->doexit)
+ /* We cannot start the application. Abort now. */
+ _exit (1);
+}
+
+
+static inline struct link_map *
+find_needed (const char *name)
+{
+ struct r_scope_elem *scope = &GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_searchlist;
+ unsigned int n = scope->r_nlist;
+
+ while (n-- > 0)
+ if (_dl_name_match_p (name, scope->r_list[n]))
+ return scope->r_list[n];
+
+ /* Should never happen. */
+ return NULL;
+}
+
+static int
+match_version (const char *string, struct link_map *map)
+{
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+ ElfW(Verdef) *def;
+
+#define VERDEFTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERDEF))
+ if (map->l_info[VERDEFTAG] == NULL)
+ /* The file has no symbol versioning. */
+ return 0;
+
+ def = (ElfW(Verdef) *) ((char *) map->l_addr
+ + map->l_info[VERDEFTAG]->d_un.d_ptr);
+ while (1)
+ {
+ ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
+
+ /* Compare the version strings. */
+ if (strcmp (string, strtab + aux->vda_name) == 0)
+ /* Bingo! */
+ return 1;
+
+ /* If no more definitions we failed to find what we want. */
+ if (def->vd_next == 0)
+ break;
+
+ /* Next definition. */
+ def = (ElfW(Verdef) *) ((char *) def + def->vd_next);
+ }
+
+ return 0;
+}
+
+static bool tls_init_tp_called;
+
+static void *
+init_tls (void)
+{
+ /* Number of elements in the static TLS block. */
+ GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
+
+ /* Do not do this twice. The audit interface might have required
+ the DTV interfaces to be set up early. */
+ if (GL(dl_initial_dtv) != NULL)
+ return NULL;
+
+ /* Allocate the array which contains the information about the
+ dtv slots. We allocate a few entries more than needed to
+ avoid the need for reallocation. */
+ size_t nelem = GL(dl_tls_max_dtv_idx) + 1 + TLS_SLOTINFO_SURPLUS;
+
+ /* Allocate. */
+ GL(dl_tls_dtv_slotinfo_list) = (struct dtv_slotinfo_list *)
+ calloc (sizeof (struct dtv_slotinfo_list)
+ + nelem * sizeof (struct dtv_slotinfo), 1);
+ /* No need to check the return value. If memory allocation failed
+ the program would have been terminated. */
+
+ struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
+ GL(dl_tls_dtv_slotinfo_list)->len = nelem;
+ GL(dl_tls_dtv_slotinfo_list)->next = NULL;
+
+ /* Fill in the information from the loaded modules. No namespace
+ but the base one can be filled at this time. */
+ assert (GL(dl_ns)[LM_ID_BASE + 1]._ns_loaded == NULL);
+ int i = 0;
+ for (struct link_map *l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; l != NULL;
+ l = l->l_next)
+ if (l->l_tls_blocksize != 0)
+ {
+ /* This is a module with TLS data. Store the map reference.
+ The generation counter is zero. */
+ slotinfo[i].map = l;
+ /* slotinfo[i].gen = 0; */
+ ++i;
+ }
+ assert (i == GL(dl_tls_max_dtv_idx));
+
+ /* Compute the TLS offsets for the various blocks. */
+ _dl_determine_tlsoffset ();
+
+ /* Construct the static TLS block and the dtv for the initial
+ thread. For some platforms this will include allocating memory
+ for the thread descriptor. The memory for the TLS block will
+ never be freed. It should be allocated accordingly. The dtv
+ array can be changed if dynamic loading requires it. */
+ void *tcbp = _dl_allocate_tls_storage ();
+ if (tcbp == NULL)
+ _dl_fatal_printf ("\
+cannot allocate TLS data structures for initial thread");
+
+ /* Store for detection of the special case by __tls_get_addr
+ so it knows not to pass this dtv to the normal realloc. */
+ GL(dl_initial_dtv) = GET_DTV (tcbp);
+
+ /* And finally install it for the main thread. */
+ const char *lossage = TLS_INIT_TP (tcbp);
+ if (__glibc_unlikely (lossage != NULL))
+ _dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
+ tls_init_tp_called = true;
+
+ return tcbp;
+}
+
+static unsigned int
+do_preload (const char *fname, struct link_map *main_map, const char *where)
+{
+ const char *objname;
+ const char *err_str = NULL;
+ struct map_args args;
+ bool malloced;
+
+ args.str = fname;
+ args.loader = main_map;
+ args.mode = __RTLD_SECURE;
+
+ unsigned int old_nloaded = GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
+
+ (void) _dl_catch_error (&objname, &err_str, &malloced, map_doit, &args);
+ if (__glibc_unlikely (err_str != NULL))
+ {
+ _dl_error_printf ("\
+ERROR: ld.so: object '%s' from %s cannot be preloaded (%s): ignored.\n",
+ fname, where, err_str);
+ /* No need to call free, this is still before
+ the libc's malloc is used. */
+ }
+ else if (GL(dl_ns)[LM_ID_BASE]._ns_nloaded != old_nloaded)
+ /* It is no duplicate. */
+ return 1;
+
+ /* Nothing loaded. */
+ return 0;
+}
+
+#if defined SHARED && defined _LIBC_REENTRANT \
+ && defined __rtld_lock_default_lock_recursive
+static void
+rtld_lock_default_lock_recursive (void *lock)
+{
+ __rtld_lock_default_lock_recursive (lock);
+}
+
+static void
+rtld_lock_default_unlock_recursive (void *lock)
+{
+ __rtld_lock_default_unlock_recursive (lock);
+}
+#endif
+
+
+static void
+security_init (void)
+{
+ /* Set up the stack checker's canary. */
+ uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
+#ifdef THREAD_SET_STACK_GUARD
+ THREAD_SET_STACK_GUARD (stack_chk_guard);
+#else
+ __stack_chk_guard = stack_chk_guard;
+#endif
+
+ /* Set up the pointer guard as well, if necessary. */
+ uintptr_t pointer_chk_guard
+ = _dl_setup_pointer_guard (_dl_random, stack_chk_guard);
+#ifdef THREAD_SET_POINTER_GUARD
+ THREAD_SET_POINTER_GUARD (pointer_chk_guard);
+#endif
+ __pointer_chk_guard_local = pointer_chk_guard;
+
+ /* We do not need the _dl_random value anymore. The less
+ information we leave behind, the better, so clear the
+ variable. */
+ _dl_random = NULL;
+}
+
+#include "setup-vdso.h"
+
+/* The library search path. */
+static const char *library_path attribute_relro;
+/* The list preloaded objects. */
+static const char *preloadlist attribute_relro;
+/* Nonzero if information about versions has to be printed. */
+static int version_info attribute_relro;
+
+static void
+dl_main (const ElfW(Phdr) *phdr,
+ ElfW(Word) phnum,
+ ElfW(Addr) *user_entry,
+ ElfW(auxv_t) *auxv)
+{
+ const ElfW(Phdr) *ph;
+ enum mode mode;
+ struct link_map *main_map;
+ size_t file_size;
+ char *file;
+ bool has_interp = false;
+ unsigned int i;
+ bool prelinked = false;
+ bool rtld_is_main = false;
+#ifndef HP_TIMING_NONAVAIL
+ hp_timing_t start;
+ hp_timing_t stop;
+ hp_timing_t diff;
+#endif
+ void *tcbp = NULL;
+
+ GL(dl_init_static_tls) = &_dl_nothread_init_static_tls;
+
+#if defined SHARED && defined _LIBC_REENTRANT \
+ && defined __rtld_lock_default_lock_recursive
+ GL(dl_rtld_lock_recursive) = rtld_lock_default_lock_recursive;
+ GL(dl_rtld_unlock_recursive) = rtld_lock_default_unlock_recursive;
+#endif
+
+ /* The explicit initialization here is cheaper than processing the reloc
+ in the _rtld_local definition's initializer. */
+ GL(dl_make_stack_executable_hook) = &_dl_make_stack_executable;
+
+ /* Process the environment variable which control the behaviour. */
+ process_envvars (&mode);
+
+#ifndef HAVE_INLINED_SYSCALLS
+ /* Set up a flag which tells we are just starting. */
+ _dl_starting_up = 1;
+#endif
+
+ if (*user_entry == (ElfW(Addr)) ENTRY_POINT)
+ {
+ /* Ho ho. We are not the program interpreter! We are the program
+ itself! This means someone ran ld.so as a command. Well, that
+ might be convenient to do sometimes. We support it by
+ interpreting the args like this:
+
+ ld.so PROGRAM ARGS...
+
+ The first argument is the name of a file containing an ELF
+ executable we will load and run with the following arguments.
+ To simplify life here, PROGRAM is searched for using the
+ normal rules for shared objects, rather than $PATH or anything
+ like that. We just load it and use its entry point; we don't
+ pay attention to its PT_INTERP command (we are the interpreter
+ ourselves). This is an easy way to test a new ld.so before
+ installing it. */
+ rtld_is_main = true;
+
+ /* Note the place where the dynamic linker actually came from. */
+ GL(dl_rtld_map).l_name = rtld_progname;
+
+ while (_dl_argc > 1)
+ if (! strcmp (_dl_argv[1], "--list"))
+ {
+ mode = list;
+ GLRO(dl_lazy) = -1; /* This means do no dependency analysis. */
+
+ ++_dl_skip_args;
+ --_dl_argc;
+ ++_dl_argv;
+ }
+ else if (! strcmp (_dl_argv[1], "--verify"))
+ {
+ mode = verify;
+
+ ++_dl_skip_args;
+ --_dl_argc;
+ ++_dl_argv;
+ }
+ else if (! strcmp (_dl_argv[1], "--inhibit-cache"))
+ {
+ GLRO(dl_inhibit_cache) = 1;
+ ++_dl_skip_args;
+ --_dl_argc;
+ ++_dl_argv;
+ }
+ else if (! strcmp (_dl_argv[1], "--library-path")
+ && _dl_argc > 2)
+ {
+ library_path = _dl_argv[2];
+
+ _dl_skip_args += 2;
+ _dl_argc -= 2;
+ _dl_argv += 2;
+ }
+ else if (! strcmp (_dl_argv[1], "--inhibit-rpath")
+ && _dl_argc > 2)
+ {
+ GLRO(dl_inhibit_rpath) = _dl_argv[2];
+
+ _dl_skip_args += 2;
+ _dl_argc -= 2;
+ _dl_argv += 2;
+ }
+ else if (! strcmp (_dl_argv[1], "--audit") && _dl_argc > 2)
+ {
+ process_dl_audit (_dl_argv[2]);
+
+ _dl_skip_args += 2;
+ _dl_argc -= 2;
+ _dl_argv += 2;
+ }
+ else
+ break;
+
+ /* If we have no further argument the program was called incorrectly.
+ Grant the user some education. */
+ if (_dl_argc < 2)
+ _dl_fatal_printf ("\
+Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\
+You have invoked `ld.so', the helper program for shared library executables.\n\
+This program usually lives in the file `/lib/ld.so', and special directives\n\
+in executable files using ELF shared libraries tell the system's program\n\
+loader to load the helper program from this file. This helper program loads\n\
+the shared libraries needed by the program executable, prepares the program\n\
+to run, and runs it. You may invoke this helper program directly from the\n\
+command line to load and run an ELF executable file; this is like executing\n\
+that file itself, but always uses this helper program from the file you\n\
+specified, instead of the helper program file specified in the executable\n\
+file you run. This is mostly of use for maintainers to test new versions\n\
+of this helper program; chances are you did not intend to run this program.\n\
+\n\
+ --list list all dependencies and how they are resolved\n\
+ --verify verify that given object really is a dynamically linked\n\
+ object we can handle\n\
+ --inhibit-cache Do not use " LD_SO_CACHE "\n\
+ --library-path PATH use given PATH instead of content of the environment\n\
+ variable LD_LIBRARY_PATH\n\
+ --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\
+ in LIST\n\
+ --audit LIST use objects named in LIST as auditors\n");
+
+ ++_dl_skip_args;
+ --_dl_argc;
+ ++_dl_argv;
+
+ /* The initialization of _dl_stack_flags done below assumes the
+ executable's PT_GNU_STACK may have been honored by the kernel, and
+ so a PT_GNU_STACK with PF_X set means the stack started out with
+ execute permission. However, this is not really true if the
+ dynamic linker is the executable the kernel loaded. For this
+ case, we must reinitialize _dl_stack_flags to match the dynamic
+ linker itself. If the dynamic linker was built with a
+ PT_GNU_STACK, then the kernel may have loaded us with a
+ nonexecutable stack that we will have to make executable when we
+ load the program below unless it has a PT_GNU_STACK indicating
+ nonexecutable stack is ok. */
+
+ for (ph = phdr; ph < &phdr[phnum]; ++ph)
+ if (ph->p_type == PT_GNU_STACK)
+ {
+ GL(dl_stack_flags) = ph->p_flags;
+ break;
+ }
+
+ if (__builtin_expect (mode, normal) == verify)
+ {
+ const char *objname;
+ const char *err_str = NULL;
+ struct map_args args;
+ bool malloced;
+
+ args.str = rtld_progname;
+ args.loader = NULL;
+ args.mode = __RTLD_OPENEXEC;
+ (void) _dl_catch_error (&objname, &err_str, &malloced, map_doit,
+ &args);
+ if (__glibc_unlikely (err_str != NULL))
+ /* We don't free the returned string, the programs stops
+ anyway. */
+ _exit (EXIT_FAILURE);
+ }
+ else
+ {
+ HP_TIMING_NOW (start);
+ _dl_map_object (NULL, rtld_progname, lt_executable, 0,
+ __RTLD_OPENEXEC, LM_ID_BASE);
+ HP_TIMING_NOW (stop);
+
+ HP_TIMING_DIFF (load_time, start, stop);
+ }
+
+ /* Now the map for the main executable is available. */
+ main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+
+ if (__builtin_expect (mode, normal) == normal
+ && GL(dl_rtld_map).l_info[DT_SONAME] != NULL
+ && main_map->l_info[DT_SONAME] != NULL
+ && strcmp ((const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
+ + GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_val,
+ (const char *) D_PTR (main_map, l_info[DT_STRTAB])
+ + main_map->l_info[DT_SONAME]->d_un.d_val) == 0)
+ _dl_fatal_printf ("loader cannot load itself\n");
+
+ phdr = main_map->l_phdr;
+ phnum = main_map->l_phnum;
+ /* We overwrite here a pointer to a malloc()ed string. But since
+ the malloc() implementation used at this point is the dummy
+ implementations which has no real free() function it does not
+ makes sense to free the old string first. */
+ main_map->l_name = (char *) "";
+ *user_entry = main_map->l_entry;
+
+#ifdef HAVE_AUX_VECTOR
+ /* Adjust the on-stack auxiliary vector so that it looks like the
+ binary was executed directly. */
+ for (ElfW(auxv_t) *av = auxv; av->a_type != AT_NULL; av++)
+ switch (av->a_type)
+ {
+ case AT_PHDR:
+ av->a_un.a_val = (uintptr_t) phdr;
+ break;
+ case AT_PHNUM:
+ av->a_un.a_val = phnum;
+ break;
+ case AT_ENTRY:
+ av->a_un.a_val = *user_entry;
+ break;
+ case AT_EXECFN:
+ av->a_un.a_val = (uintptr_t) _dl_argv[0];
+ break;
+ }
+#endif
+ }
+ else
+ {
+ /* Create a link_map for the executable itself.
+ This will be what dlopen on "" returns. */
+ main_map = _dl_new_object ((char *) "", "", lt_executable, NULL,
+ __RTLD_OPENEXEC, LM_ID_BASE);
+ assert (main_map != NULL);
+ main_map->l_phdr = phdr;
+ main_map->l_phnum = phnum;
+ main_map->l_entry = *user_entry;
+
+ /* Even though the link map is not yet fully initialized we can add
+ it to the map list since there are no possible users running yet. */
+ _dl_add_to_namespace_list (main_map, LM_ID_BASE);
+ assert (main_map == GL(dl_ns)[LM_ID_BASE]._ns_loaded);
+
+ /* At this point we are in a bit of trouble. We would have to
+ fill in the values for l_dev and l_ino. But in general we
+ do not know where the file is. We also do not handle AT_EXECFD
+ even if it would be passed up.
+
+ We leave the values here defined to 0. This is normally no
+ problem as the program code itself is normally no shared
+ object and therefore cannot be loaded dynamically. Nothing
+ prevent the use of dynamic binaries and in these situations
+ we might get problems. We might not be able to find out
+ whether the object is already loaded. But since there is no
+ easy way out and because the dynamic binary must also not
+ have an SONAME we ignore this program for now. If it becomes
+ a problem we can force people using SONAMEs. */
+
+ /* We delay initializing the path structure until we got the dynamic
+ information for the program. */
+ }
+
+ main_map->l_map_end = 0;
+ main_map->l_text_end = 0;
+ /* Perhaps the executable has no PT_LOAD header entries at all. */
+ main_map->l_map_start = ~0;
+ /* And it was opened directly. */
+ ++main_map->l_direct_opencount;
+
+ /* Scan the program header table for the dynamic section. */
+ for (ph = phdr; ph < &phdr[phnum]; ++ph)
+ switch (ph->p_type)
+ {
+ case PT_PHDR:
+ /* Find out the load address. */
+ main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
+ break;
+ case PT_DYNAMIC:
+ /* This tells us where to find the dynamic section,
+ which tells us everything we need to do. */
+ main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
+ break;
+ case PT_INTERP:
+ /* This "interpreter segment" was used by the program loader to
+ find the program interpreter, which is this program itself, the
+ dynamic linker. We note what name finds us, so that a future
+ dlopen call or DT_NEEDED entry, for something that wants to link
+ against the dynamic linker as a shared library, will know that
+ the shared object is already loaded. */
+ _dl_rtld_libname.name = ((const char *) main_map->l_addr
+ + ph->p_vaddr);
+ /* _dl_rtld_libname.next = NULL; Already zero. */
+ GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
+
+ /* Ordinarilly, we would get additional names for the loader from
+ our DT_SONAME. This can't happen if we were actually linked as
+ a static executable (detect this case when we have no DYNAMIC).
+ If so, assume the filename component of the interpreter path to
+ be our SONAME, and add it to our name list. */
+ if (GL(dl_rtld_map).l_ld == NULL)
+ {
+ const char *p = NULL;
+ const char *cp = _dl_rtld_libname.name;
+
+ /* Find the filename part of the path. */
+ while (*cp != '\0')
+ if (*cp++ == '/')
+ p = cp;
+
+ if (p != NULL)
+ {
+ _dl_rtld_libname2.name = p;
+ /* _dl_rtld_libname2.next = NULL; Already zero. */
+ _dl_rtld_libname.next = &_dl_rtld_libname2;
+ }
+ }
+
+ has_interp = true;
+ break;
+ case PT_LOAD:
+ {
+ ElfW(Addr) mapstart;
+ ElfW(Addr) allocend;
+
+ /* Remember where the main program starts in memory. */
+ mapstart = (main_map->l_addr
+ + (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)));
+ if (main_map->l_map_start > mapstart)
+ main_map->l_map_start = mapstart;
+
+ /* Also where it ends. */
+ allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz;
+ if (main_map->l_map_end < allocend)
+ main_map->l_map_end = allocend;
+ if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end)
+ main_map->l_text_end = allocend;
+ }
+ break;
+
+ case PT_TLS:
+ if (ph->p_memsz > 0)
+ {
+ /* Note that in the case the dynamic linker we duplicate work
+ here since we read the PT_TLS entry already in
+ _dl_start_final. But the result is repeatable so do not
+ check for this special but unimportant case. */
+ main_map->l_tls_blocksize = ph->p_memsz;
+ main_map->l_tls_align = ph->p_align;
+ if (ph->p_align == 0)
+ main_map->l_tls_firstbyte_offset = 0;
+ else
+ main_map->l_tls_firstbyte_offset = (ph->p_vaddr
+ & (ph->p_align - 1));
+ main_map->l_tls_initimage_size = ph->p_filesz;
+ main_map->l_tls_initimage = (void *) ph->p_vaddr;
+
+ /* This image gets the ID one. */
+ GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
+ }
+ break;
+
+ case PT_GNU_STACK:
+ GL(dl_stack_flags) = ph->p_flags;
+ break;
+
+ case PT_GNU_RELRO:
+ main_map->l_relro_addr = ph->p_vaddr;
+ main_map->l_relro_size = ph->p_memsz;
+ break;
+ }
+
+ /* Adjust the address of the TLS initialization image in case
+ the executable is actually an ET_DYN object. */
+ if (main_map->l_tls_initimage != NULL)
+ main_map->l_tls_initimage
+ = (char *) main_map->l_tls_initimage + main_map->l_addr;
+ if (! main_map->l_map_end)
+ main_map->l_map_end = ~0;
+ if (! main_map->l_text_end)
+ main_map->l_text_end = ~0;
+ if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name)
+ {
+ /* We were invoked directly, so the program might not have a
+ PT_INTERP. */
+ _dl_rtld_libname.name = GL(dl_rtld_map).l_name;
+ /* _dl_rtld_libname.next = NULL; Already zero. */
+ GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
+ }
+ else
+ assert (GL(dl_rtld_map).l_libname); /* How else did we get here? */
+
+ /* If the current libname is different from the SONAME, add the
+ latter as well. */
+ if (GL(dl_rtld_map).l_info[DT_SONAME] != NULL
+ && strcmp (GL(dl_rtld_map).l_libname->name,
+ (const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
+ + GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_val) != 0)
+ {
+ static struct libname_list newname;
+ newname.name = ((char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
+ + GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_ptr);
+ newname.next = NULL;
+ newname.dont_free = 1;
+
+ assert (GL(dl_rtld_map).l_libname->next == NULL);
+ GL(dl_rtld_map).l_libname->next = &newname;
+ }
+ /* The ld.so must be relocated since otherwise loading audit modules
+ will fail since they reuse the very same ld.so. */
+ assert (GL(dl_rtld_map).l_relocated);
+
+ if (! rtld_is_main)
+ {
+ /* Extract the contents of the dynamic section for easy access. */
+ elf_get_dynamic_info (main_map, NULL);
+ /* Set up our cache of pointers into the hash table. */
+ _dl_setup_hash (main_map);
+ }
+
+ if (__builtin_expect (mode, normal) == verify)
+ {
+ /* We were called just to verify that this is a dynamic
+ executable using us as the program interpreter. Exit with an
+ error if we were not able to load the binary or no interpreter
+ is specified (i.e., this is no dynamically linked binary. */
+ if (main_map->l_ld == NULL)
+ _exit (1);
+
+ /* We allow here some platform specific code. */
+#ifdef DISTINGUISH_LIB_VERSIONS
+ DISTINGUISH_LIB_VERSIONS;
+#endif
+ _exit (has_interp ? 0 : 2);
+ }
+
+ struct link_map **first_preload = &GL(dl_rtld_map).l_next;
+ /* Set up the data structures for the system-supplied DSO early,
+ so they can influence _dl_init_paths. */
+ setup_vdso (main_map, &first_preload);
+
+#ifdef DL_SYSDEP_OSCHECK
+ DL_SYSDEP_OSCHECK (_dl_fatal_printf);
+#endif
+
+ /* Initialize the data structures for the search paths for shared
+ objects. */
+ _dl_init_paths (library_path);
+
+ /* Initialize _r_debug. */
+ struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr,
+ LM_ID_BASE);
+ r->r_state = RT_CONSISTENT;
+
+ /* Put the link_map for ourselves on the chain so it can be found by
+ name. Note that at this point the global chain of link maps contains
+ exactly one element, which is pointed to by dl_loaded. */
+ if (! GL(dl_rtld_map).l_name)
+ /* If not invoked directly, the dynamic linker shared object file was
+ found by the PT_INTERP name. */
+ GL(dl_rtld_map).l_name = (char *) GL(dl_rtld_map).l_libname->name;
+ GL(dl_rtld_map).l_type = lt_library;
+ main_map->l_next = &GL(dl_rtld_map);
+ GL(dl_rtld_map).l_prev = main_map;
+ ++GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
+ ++GL(dl_load_adds);
+
+ /* If LD_USE_LOAD_BIAS env variable has not been seen, default
+ to not using bias for non-prelinked PIEs and libraries
+ and using it for executables or prelinked PIEs or libraries. */
+ if (GLRO(dl_use_load_bias) == (ElfW(Addr)) -2)
+ GLRO(dl_use_load_bias) = main_map->l_addr == 0 ? -1 : 0;
+
+ /* Set up the program header information for the dynamic linker
+ itself. It is needed in the dl_iterate_phdr callbacks. */
+ const ElfW(Ehdr) *rtld_ehdr;
+
+ /* Starting from binutils-2.23, the linker will define the magic symbol
+ __ehdr_start to point to our own ELF header if it is visible in a
+ segment that also includes the phdrs. If that's not available, we use
+ the old method that assumes the beginning of the file is part of the
+ lowest-addressed PT_LOAD segment. */
+#ifdef HAVE_EHDR_START
+ extern const ElfW(Ehdr) __ehdr_start __attribute__ ((visibility ("hidden")));
+ rtld_ehdr = &__ehdr_start;
+#else
+ rtld_ehdr = (void *) GL(dl_rtld_map).l_map_start;
+#endif
+ assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
+ assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
+
+ const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
+
+ GL(dl_rtld_map).l_phdr = rtld_phdr;
+ GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
+
+
+ /* PT_GNU_RELRO is usually the last phdr. */
+ size_t cnt = rtld_ehdr->e_phnum;
+ while (cnt-- > 0)
+ if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
+ {
+ GL(dl_rtld_map).l_relro_addr = rtld_phdr[cnt].p_vaddr;
+ GL(dl_rtld_map).l_relro_size = rtld_phdr[cnt].p_memsz;
+ break;
+ }
+
+ /* Add the dynamic linker to the TLS list if it also uses TLS. */
+ if (GL(dl_rtld_map).l_tls_blocksize != 0)
+ /* Assign a module ID. Do this before loading any audit modules. */
+ GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
+
+ /* If we have auditing DSOs to load, do it now. */
+ if (__glibc_unlikely (audit_list != NULL))
+ {
+ /* Iterate over all entries in the list. The order is important. */
+ struct audit_ifaces *last_audit = NULL;
+ struct audit_list *al = audit_list->next;
+
+ /* Since we start using the auditing DSOs right away we need to
+ initialize the data structures now. */
+ tcbp = init_tls ();
+
+ /* Initialize security features. We need to do it this early
+ since otherwise the constructors of the audit libraries will
+ use different values (especially the pointer guard) and will
+ fail later on. */
+ security_init ();
+
+ do
+ {
+ int tls_idx = GL(dl_tls_max_dtv_idx);
+
+ /* Now it is time to determine the layout of the static TLS
+ block and allocate it for the initial thread. Note that we
+ always allocate the static block, we never defer it even if
+ no DF_STATIC_TLS bit is set. The reason is that we know
+ glibc will use the static model. */
+ struct dlmopen_args dlmargs;
+ dlmargs.fname = al->name;
+ dlmargs.map = NULL;
+
+ const char *objname;
+ const char *err_str = NULL;
+ bool malloced;
+ (void) _dl_catch_error (&objname, &err_str, &malloced, dlmopen_doit,
+ &dlmargs);
+ if (__glibc_unlikely (err_str != NULL))
+ {
+ not_loaded:
+ _dl_error_printf ("\
+ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ al->name, err_str);
+ if (malloced)
+ free ((char *) err_str);
+ }
+ else
+ {
+ struct lookup_args largs;
+ largs.name = "la_version";
+ largs.map = dlmargs.map;
+
+ /* Check whether the interface version matches. */
+ (void) _dl_catch_error (&objname, &err_str, &malloced,
+ lookup_doit, &largs);
+
+ unsigned int (*laversion) (unsigned int);
+ unsigned int lav;
+ if (err_str == NULL
+ && (laversion = largs.result) != NULL
+ && (lav = laversion (LAV_CURRENT)) > 0
+ && lav <= LAV_CURRENT)
+ {
+ /* Allocate structure for the callback function pointers.
+ This call can never fail. */
+ union
+ {
+ struct audit_ifaces ifaces;
+#define naudit_ifaces 8
+ void (*fptr[naudit_ifaces]) (void);
+ } *newp = malloc (sizeof (*newp));
+
+ /* Names of the auditing interfaces. All in one
+ long string. */
+ static const char audit_iface_names[] =
+ "la_activity\0"
+ "la_objsearch\0"
+ "la_objopen\0"
+ "la_preinit\0"
+#if __ELF_NATIVE_CLASS == 32
+ "la_symbind32\0"
+#elif __ELF_NATIVE_CLASS == 64
+ "la_symbind64\0"
+#else
+# error "__ELF_NATIVE_CLASS must be defined"
+#endif
+#define STRING(s) __STRING (s)
+ "la_" STRING (ARCH_LA_PLTENTER) "\0"
+ "la_" STRING (ARCH_LA_PLTEXIT) "\0"
+ "la_objclose\0";
+ unsigned int cnt = 0;
+ const char *cp = audit_iface_names;
+ do
+ {
+ largs.name = cp;
+ (void) _dl_catch_error (&objname, &err_str, &malloced,
+ lookup_doit, &largs);
+
+ /* Store the pointer. */
+ if (err_str == NULL && largs.result != NULL)
+ {
+ newp->fptr[cnt] = largs.result;
+
+ /* The dynamic linker link map is statically
+ allocated, initialize the data now. */
+ GL(dl_rtld_map).l_audit[cnt].cookie
+ = (intptr_t) &GL(dl_rtld_map);
+ }
+ else
+ newp->fptr[cnt] = NULL;
+ ++cnt;
+
+ cp = (char *) rawmemchr (cp, '\0') + 1;
+ }
+ while (*cp != '\0');
+ assert (cnt == naudit_ifaces);
+
+ /* Now append the new auditing interface to the list. */
+ newp->ifaces.next = NULL;
+ if (last_audit == NULL)
+ last_audit = GLRO(dl_audit) = &newp->ifaces;
+ else
+ last_audit = last_audit->next = &newp->ifaces;
+ ++GLRO(dl_naudit);
+
+ /* Mark the DSO as being used for auditing. */
+ dlmargs.map->l_auditing = 1;
+ }
+ else
+ {
+ /* We cannot use the DSO, it does not have the
+ appropriate interfaces or it expects something
+ more recent. */
+#ifndef NDEBUG
+ Lmid_t ns = dlmargs.map->l_ns;
+#endif
+ _dl_close (dlmargs.map);
+
+ /* Make sure the namespace has been cleared entirely. */
+ assert (GL(dl_ns)[ns]._ns_loaded == NULL);
+ assert (GL(dl_ns)[ns]._ns_nloaded == 0);
+
+ GL(dl_tls_max_dtv_idx) = tls_idx;
+ goto not_loaded;
+ }
+ }
+
+ al = al->next;
+ }
+ while (al != audit_list->next);
+
+ /* If we have any auditing modules, announce that we already
+ have two objects loaded. */
+ if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ {
+ struct link_map *ls[2] = { main_map, &GL(dl_rtld_map) };
+
+ for (unsigned int outer = 0; outer < 2; ++outer)
+ {
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->objopen != NULL)
+ {
+ ls[outer]->l_audit[cnt].bindflags
+ = afct->objopen (ls[outer], LM_ID_BASE,
+ &ls[outer]->l_audit[cnt].cookie);
+
+ ls[outer]->l_audit_any_plt
+ |= ls[outer]->l_audit[cnt].bindflags != 0;
+ }
+
+ afct = afct->next;
+ }
+ }
+ }
+ }
+
+ /* Keep track of the currently loaded modules to count how many
+ non-audit modules which use TLS are loaded. */
+ size_t count_modids = _dl_count_modids ();
+
+ /* Set up debugging before the debugger is notified for the first time. */
+#ifdef ELF_MACHINE_DEBUG_SETUP
+ /* Some machines (e.g. MIPS) don't use DT_DEBUG in this way. */
+ ELF_MACHINE_DEBUG_SETUP (main_map, r);
+ ELF_MACHINE_DEBUG_SETUP (&GL(dl_rtld_map), r);
+#else
+ if (main_map->l_info[DT_DEBUG] != NULL)
+ /* There is a DT_DEBUG entry in the dynamic section. Fill it in
+ with the run-time address of the r_debug structure */
+ main_map->l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) r;
+
+ /* Fill in the pointer in the dynamic linker's own dynamic section, in
+ case you run gdb on the dynamic linker directly. */
+ if (GL(dl_rtld_map).l_info[DT_DEBUG] != NULL)
+ GL(dl_rtld_map).l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) r;
+#endif
+
+ /* We start adding objects. */
+ r->r_state = RT_ADD;
+ _dl_debug_state ();
+ LIBC_PROBE (init_start, 2, LM_ID_BASE, r);
+
+ /* Auditing checkpoint: we are ready to signal that the initial map
+ is being constructed. */
+ if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ {
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->activity != NULL)
+ afct->activity (&main_map->l_audit[cnt].cookie, LA_ACT_ADD);
+
+ afct = afct->next;
+ }
+ }
+
+ /* We have two ways to specify objects to preload: via environment
+ variable and via the file /etc/ld.so.preload. The latter can also
+ be used when security is enabled. */
+ assert (*first_preload == NULL);
+ struct link_map **preloads = NULL;
+ unsigned int npreloads = 0;
+
+ if (__glibc_unlikely (preloadlist != NULL))
+ {
+ /* The LD_PRELOAD environment variable gives list of libraries
+ separated by white space or colons that are loaded before the
+ executable's dependencies and prepended to the global scope
+ list. If the binary is running setuid all elements
+ containing a '/' are ignored since it is insecure. */
+ char *list = strdupa (preloadlist);
+ char *p;
+
+ HP_TIMING_NOW (start);
+
+ /* Prevent optimizing strsep. Speed is not important here. */
+ while ((p = (strsep) (&list, " :")) != NULL)
+ if (p[0] != '\0'
+ && (__builtin_expect (! __libc_enable_secure, 1)
+ || strchr (p, '/') == NULL))
+ npreloads += do_preload (p, main_map, "LD_PRELOAD");
+
+ HP_TIMING_NOW (stop);
+ HP_TIMING_DIFF (diff, start, stop);
+ HP_TIMING_ACCUM_NT (load_time, diff);
+ }
+
+ /* There usually is no ld.so.preload file, it should only be used
+ for emergencies and testing. So the open call etc should usually
+ fail. Using access() on a non-existing file is faster than using
+ open(). So we do this first. If it succeeds we do almost twice
+ the work but this does not matter, since it is not for production
+ use. */
+ static const char preload_file[] = "/etc/ld.so.preload";
+ if (__glibc_unlikely (__access (preload_file, R_OK) == 0))
+ {
+ /* Read the contents of the file. */
+ file = _dl_sysdep_read_whole_file (preload_file, &file_size,
+ PROT_READ | PROT_WRITE);
+ if (__glibc_unlikely (file != MAP_FAILED))
+ {
+ /* Parse the file. It contains names of libraries to be loaded,
+ separated by white spaces or `:'. It may also contain
+ comments introduced by `#'. */
+ char *problem;
+ char *runp;
+ size_t rest;
+
+ /* Eliminate comments. */
+ runp = file;
+ rest = file_size;
+ while (rest > 0)
+ {
+ char *comment = memchr (runp, '#', rest);
+ if (comment == NULL)
+ break;
+
+ rest -= comment - runp;
+ do
+ *comment = ' ';
+ while (--rest > 0 && *++comment != '\n');
+ }
+
+ /* We have one problematic case: if we have a name at the end of
+ the file without a trailing terminating characters, we cannot
+ place the \0. Handle the case separately. */
+ if (file[file_size - 1] != ' ' && file[file_size - 1] != '\t'
+ && file[file_size - 1] != '\n' && file[file_size - 1] != ':')
+ {
+ problem = &file[file_size];
+ while (problem > file && problem[-1] != ' '
+ && problem[-1] != '\t'
+ && problem[-1] != '\n' && problem[-1] != ':')
+ --problem;
+
+ if (problem > file)
+ problem[-1] = '\0';
+ }
+ else
+ {
+ problem = NULL;
+ file[file_size - 1] = '\0';
+ }
+
+ HP_TIMING_NOW (start);
+
+ if (file != problem)
+ {
+ char *p;
+ runp = file;
+ while ((p = strsep (&runp, ": \t\n")) != NULL)
+ if (p[0] != '\0')
+ npreloads += do_preload (p, main_map, preload_file);
+ }
+
+ if (problem != NULL)
+ {
+ char *p = strndupa (problem, file_size - (problem - file));
+
+ npreloads += do_preload (p, main_map, preload_file);
+ }
+
+ HP_TIMING_NOW (stop);
+ HP_TIMING_DIFF (diff, start, stop);
+ HP_TIMING_ACCUM_NT (load_time, diff);
+
+ /* We don't need the file anymore. */
+ __munmap (file, file_size);
+ }
+ }
+
+ if (__glibc_unlikely (*first_preload != NULL))
+ {
+ /* Set up PRELOADS with a vector of the preloaded libraries. */
+ struct link_map *l = *first_preload;
+ preloads = __alloca (npreloads * sizeof preloads[0]);
+ i = 0;
+ do
+ {
+ preloads[i++] = l;
+ l = l->l_next;
+ } while (l);
+ assert (i == npreloads);
+ }
+
+ /* Load all the libraries specified by DT_NEEDED entries. If LD_PRELOAD
+ specified some libraries to load, these are inserted before the actual
+ dependencies in the executable's searchlist for symbol resolution. */
+ HP_TIMING_NOW (start);
+ _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0);
+ HP_TIMING_NOW (stop);
+ HP_TIMING_DIFF (diff, start, stop);
+ HP_TIMING_ACCUM_NT (load_time, diff);
+
+ /* Mark all objects as being in the global scope. */
+ for (i = main_map->l_searchlist.r_nlist; i > 0; )
+ main_map->l_searchlist.r_list[--i]->l_global = 1;
+
+ /* Remove _dl_rtld_map from the chain. */
+ GL(dl_rtld_map).l_prev->l_next = GL(dl_rtld_map).l_next;
+ if (GL(dl_rtld_map).l_next != NULL)
+ GL(dl_rtld_map).l_next->l_prev = GL(dl_rtld_map).l_prev;
+
+ for (i = 1; i < main_map->l_searchlist.r_nlist; ++i)
+ if (main_map->l_searchlist.r_list[i] == &GL(dl_rtld_map))
+ break;
+
+ bool rtld_multiple_ref = false;
+ if (__glibc_likely (i < main_map->l_searchlist.r_nlist))
+ {
+ /* Some DT_NEEDED entry referred to the interpreter object itself, so
+ put it back in the list of visible objects. We insert it into the
+ chain in symbol search order because gdb uses the chain's order as
+ its symbol search order. */
+ rtld_multiple_ref = true;
+
+ GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
+ if (__builtin_expect (mode, normal) == normal)
+ {
+ GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
+ ? main_map->l_searchlist.r_list[i + 1]
+ : NULL);
+#ifdef NEED_DL_SYSINFO_DSO
+ if (GLRO(dl_sysinfo_map) != NULL
+ && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map)
+ && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map))
+ GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map);
+#endif
+ }
+ else
+ /* In trace mode there might be an invisible object (which we
+ could not find) after the previous one in the search list.
+ In this case it doesn't matter much where we put the
+ interpreter object, so we just initialize the list pointer so
+ that the assertion below holds. */
+ GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next;
+
+ assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next);
+ GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map);
+ if (GL(dl_rtld_map).l_next != NULL)
+ {
+ assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev);
+ GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map);
+ }
+ }
+
+ /* Now let us see whether all libraries are available in the
+ versions we need. */
+ {
+ struct version_check_args args;
+ args.doexit = mode == normal;
+ args.dotrace = mode == trace;
+ _dl_receive_error (print_missing_version, version_check_doit, &args);
+ }
+
+ /* We do not initialize any of the TLS functionality unless any of the
+ initial modules uses TLS. This makes dynamic loading of modules with
+ TLS impossible, but to support it requires either eagerly doing setup
+ now or lazily doing it later. Doing it now makes us incompatible with
+ an old kernel that can't perform TLS_INIT_TP, even if no TLS is ever
+ used. Trying to do it lazily is too hairy to try when there could be
+ multiple threads (from a non-TLS-using libpthread). */
+ bool was_tls_init_tp_called = tls_init_tp_called;
+ if (tcbp == NULL)
+ tcbp = init_tls ();
+
+ if (__glibc_likely (audit_list == NULL))
+ /* Initialize security features. But only if we have not done it
+ earlier. */
+ security_init ();
+
+ if (__builtin_expect (mode, normal) != normal)
+ {
+ /* We were run just to list the shared libraries. It is
+ important that we do this before real relocation, because the
+ functions we call below for output may no longer work properly
+ after relocation. */
+ struct link_map *l;
+
+ if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
+ {
+ struct r_scope_elem *scope = &main_map->l_searchlist;
+
+ for (i = 0; i < scope->r_nlist; i++)
+ {
+ l = scope->r_list [i];
+ if (l->l_faked)
+ {
+ _dl_printf ("\t%s => not found\n", l->l_libname->name);
+ continue;
+ }
+ if (_dl_name_match_p (GLRO(dl_trace_prelink), l))
+ GLRO(dl_trace_prelink_map) = l;
+ _dl_printf ("\t%s => %s (0x%0*Zx, 0x%0*Zx)",
+ DSO_FILENAME (l->l_libname->name),
+ DSO_FILENAME (l->l_name),
+ (int) sizeof l->l_map_start * 2,
+ (size_t) l->l_map_start,
+ (int) sizeof l->l_addr * 2,
+ (size_t) l->l_addr);
+
+ if (l->l_tls_modid)
+ _dl_printf (" TLS(0x%Zx, 0x%0*Zx)\n", l->l_tls_modid,
+ (int) sizeof l->l_tls_offset * 2,
+ (size_t) l->l_tls_offset);
+ else
+ _dl_printf ("\n");
+ }
+ }
+ else if (GLRO(dl_debug_mask) & DL_DEBUG_UNUSED)
+ {
+ /* Look through the dependencies of the main executable
+ and determine which of them is not actually
+ required. */
+ struct link_map *l = main_map;
+
+ /* Relocate the main executable. */
+ struct relocate_args args = { .l = l,
+ .reloc_mode = ((GLRO(dl_lazy)
+ ? RTLD_LAZY : 0)
+ | __RTLD_NOIFUNC) };
+ _dl_receive_error (print_unresolved, relocate_doit, &args);
+
+ /* This loop depends on the dependencies of the executable to
+ correspond in number and order to the DT_NEEDED entries. */
+ ElfW(Dyn) *dyn = main_map->l_ld;
+ bool first = true;
+ while (dyn->d_tag != DT_NULL)
+ {
+ if (dyn->d_tag == DT_NEEDED)
+ {
+ l = l->l_next;
+#ifdef NEED_DL_SYSINFO_DSO
+ /* Skip the VDSO since it's not part of the list
+ of objects we brought in via DT_NEEDED entries. */
+ if (l == GLRO(dl_sysinfo_map))
+ l = l->l_next;
+#endif
+ if (!l->l_used)
+ {
+ if (first)
+ {
+ _dl_printf ("Unused direct dependencies:\n");
+ first = false;
+ }
+
+ _dl_printf ("\t%s\n", l->l_name);
+ }
+ }
+
+ ++dyn;
+ }
+
+ _exit (first != true);
+ }
+ else if (! main_map->l_info[DT_NEEDED])
+ _dl_printf ("\tstatically linked\n");
+ else
+ {
+ for (l = main_map->l_next; l; l = l->l_next)
+ if (l->l_faked)
+ /* The library was not found. */
+ _dl_printf ("\t%s => not found\n", l->l_libname->name);
+ else if (strcmp (l->l_libname->name, l->l_name) == 0)
+ _dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name,
+ (int) sizeof l->l_map_start * 2,
+ (size_t) l->l_map_start);
+ else
+ _dl_printf ("\t%s => %s (0x%0*Zx)\n", l->l_libname->name,
+ l->l_name, (int) sizeof l->l_map_start * 2,
+ (size_t) l->l_map_start);
+ }
+
+ if (__builtin_expect (mode, trace) != trace)
+ for (i = 1; i < (unsigned int) _dl_argc; ++i)
+ {
+ const ElfW(Sym) *ref = NULL;
+ ElfW(Addr) loadbase;
+ lookup_t result;
+
+ result = _dl_lookup_symbol_x (_dl_argv[i], main_map,
+ &ref, main_map->l_scope,
+ NULL, ELF_RTYPE_CLASS_PLT,
+ DL_LOOKUP_ADD_DEPENDENCY, NULL);
+
+ loadbase = LOOKUP_VALUE_ADDRESS (result);
+
+ _dl_printf ("%s found at 0x%0*Zd in object at 0x%0*Zd\n",
+ _dl_argv[i],
+ (int) sizeof ref->st_value * 2,
+ (size_t) ref->st_value,
+ (int) sizeof loadbase * 2, (size_t) loadbase);
+ }
+ else
+ {
+ /* If LD_WARN is set, warn about undefined symbols. */
+ if (GLRO(dl_lazy) >= 0 && GLRO(dl_verbose))
+ {
+ /* We have to do symbol dependency testing. */
+ struct relocate_args args;
+ unsigned int i;
+
+ args.reloc_mode = ((GLRO(dl_lazy) ? RTLD_LAZY : 0)
+ | __RTLD_NOIFUNC);
+
+ i = main_map->l_searchlist.r_nlist;
+ while (i-- > 0)
+ {
+ struct link_map *l = main_map->l_initfini[i];
+ if (l != &GL(dl_rtld_map) && ! l->l_faked)
+ {
+ args.l = l;
+ _dl_receive_error (print_unresolved, relocate_doit,
+ &args);
+ }
+ }
+
+ if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
+ && rtld_multiple_ref)
+ {
+ /* Mark the link map as not yet relocated again. */
+ GL(dl_rtld_map).l_relocated = 0;
+ _dl_relocate_object (&GL(dl_rtld_map),
+ main_map->l_scope, __RTLD_NOIFUNC, 0);
+ }
+ }
+#define VERNEEDTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED))
+ if (version_info)
+ {
+ /* Print more information. This means here, print information
+ about the versions needed. */
+ int first = 1;
+ struct link_map *map;
+
+ for (map = main_map; map != NULL; map = map->l_next)
+ {
+ const char *strtab;
+ ElfW(Dyn) *dyn = map->l_info[VERNEEDTAG];
+ ElfW(Verneed) *ent;
+
+ if (dyn == NULL)
+ continue;
+
+ strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+ ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
+
+ if (first)
+ {
+ _dl_printf ("\n\tVersion information:\n");
+ first = 0;
+ }
+
+ _dl_printf ("\t%s:\n", DSO_FILENAME (map->l_name));
+
+ while (1)
+ {
+ ElfW(Vernaux) *aux;
+ struct link_map *needed;
+
+ needed = find_needed (strtab + ent->vn_file);
+ aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
+
+ while (1)
+ {
+ const char *fname = NULL;
+
+ if (needed != NULL
+ && match_version (strtab + aux->vna_name,
+ needed))
+ fname = needed->l_name;
+
+ _dl_printf ("\t\t%s (%s) %s=> %s\n",
+ strtab + ent->vn_file,
+ strtab + aux->vna_name,
+ aux->vna_flags & VER_FLG_WEAK
+ ? "[WEAK] " : "",
+ fname ?: "not found");
+
+ if (aux->vna_next == 0)
+ /* No more symbols. */
+ break;
+
+ /* Next symbol. */
+ aux = (ElfW(Vernaux) *) ((char *) aux
+ + aux->vna_next);
+ }
+
+ if (ent->vn_next == 0)
+ /* No more dependencies. */
+ break;
+
+ /* Next dependency. */
+ ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
+ }
+ }
+ }
+ }
+
+ _exit (0);
+ }
+
+ if (main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)]
+ && ! __builtin_expect (GLRO(dl_profile) != NULL, 0)
+ && ! __builtin_expect (GLRO(dl_dynamic_weak), 0))
+ {
+ ElfW(Lib) *liblist, *liblistend;
+ struct link_map **r_list, **r_listend, *l;
+ const char *strtab = (const void *) D_PTR (main_map, l_info[DT_STRTAB]);
+
+ assert (main_map->l_info[VALIDX (DT_GNU_LIBLISTSZ)] != NULL);
+ liblist = (ElfW(Lib) *)
+ main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)]->d_un.d_ptr;
+ liblistend = (ElfW(Lib) *)
+ ((char *) liblist +
+ main_map->l_info[VALIDX (DT_GNU_LIBLISTSZ)]->d_un.d_val);
+ r_list = main_map->l_searchlist.r_list;
+ r_listend = r_list + main_map->l_searchlist.r_nlist;
+
+ for (; r_list < r_listend && liblist < liblistend; r_list++)
+ {
+ l = *r_list;
+
+ if (l == main_map)
+ continue;
+
+ /* If the library is not mapped where it should, fail. */
+ if (l->l_addr)
+ break;
+
+ /* Next, check if checksum matches. */
+ if (l->l_info [VALIDX(DT_CHECKSUM)] == NULL
+ || l->l_info [VALIDX(DT_CHECKSUM)]->d_un.d_val
+ != liblist->l_checksum)
+ break;
+
+ if (l->l_info [VALIDX(DT_GNU_PRELINKED)] == NULL
+ || l->l_info [VALIDX(DT_GNU_PRELINKED)]->d_un.d_val
+ != liblist->l_time_stamp)
+ break;
+
+ if (! _dl_name_match_p (strtab + liblist->l_name, l))
+ break;
+
+ ++liblist;
+ }
+
+
+ if (r_list == r_listend && liblist == liblistend)
+ prelinked = true;
+
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
+ _dl_debug_printf ("\nprelink checking: %s\n",
+ prelinked ? "ok" : "failed");
+ }
+
+
+ /* Now set up the variable which helps the assembler startup code. */
+ GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist = &main_map->l_searchlist;
+
+ /* Save the information about the original global scope list since
+ we need it in the memory handling later. */
+ GLRO(dl_initial_searchlist) = *GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist;
+
+ /* Remember the last search directory added at startup, now that
+ malloc will no longer be the one from dl-minimal.c. */
+ GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
+
+ /* Print scope information. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
+ {
+ _dl_debug_printf ("\nInitial object scopes\n");
+
+ for (struct link_map *l = main_map; l != NULL; l = l->l_next)
+ _dl_show_scope (l, 0);
+ }
+
+ if (prelinked)
+ {
+ if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
+ {
+ ElfW(Rela) *conflict, *conflictend;
+#ifndef HP_TIMING_NONAVAIL
+ hp_timing_t start;
+ hp_timing_t stop;
+#endif
+
+ HP_TIMING_NOW (start);
+ assert (main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL);
+ conflict = (ElfW(Rela) *)
+ main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr;
+ conflictend = (ElfW(Rela) *)
+ ((char *) conflict
+ + main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val);
+ _dl_resolve_conflicts (main_map, conflict, conflictend);
+ HP_TIMING_NOW (stop);
+ HP_TIMING_DIFF (relocate_time, start, stop);
+ }
+
+
+ /* Mark all the objects so we know they have been already relocated. */
+ for (struct link_map *l = main_map; l != NULL; l = l->l_next)
+ {
+ l->l_relocated = 1;
+ if (l->l_relro_size)
+ _dl_protect_relro (l);
+
+ /* Add object to slot information data if necessasy. */
+ if (l->l_tls_blocksize != 0 && tls_init_tp_called)
+ _dl_add_to_slotinfo (l);
+ }
+ }
+ else
+ {
+ /* Now we have all the objects loaded. Relocate them all except for
+ the dynamic linker itself. We do this in reverse order so that copy
+ relocs of earlier objects overwrite the data written by later
+ objects. We do not re-relocate the dynamic linker itself in this
+ loop because that could result in the GOT entries for functions we
+ call being changed, and that would break us. It is safe to relocate
+ the dynamic linker out of order because it has no copy relocs (we
+ know that because it is self-contained). */
+
+ int consider_profiling = GLRO(dl_profile) != NULL;
+#ifndef HP_TIMING_NONAVAIL
+ hp_timing_t start;
+ hp_timing_t stop;
+#endif
+
+ /* If we are profiling we also must do lazy reloaction. */
+ GLRO(dl_lazy) |= consider_profiling;
+
+ HP_TIMING_NOW (start);
+ unsigned i = main_map->l_searchlist.r_nlist;
+ while (i-- > 0)
+ {
+ struct link_map *l = main_map->l_initfini[i];
+
+ /* While we are at it, help the memory handling a bit. We have to
+ mark some data structures as allocated with the fake malloc()
+ implementation in ld.so. */
+ struct libname_list *lnp = l->l_libname->next;
+
+ while (__builtin_expect (lnp != NULL, 0))
+ {
+ lnp->dont_free = 1;
+ lnp = lnp->next;
+ }
+ /* Also allocated with the fake malloc(). */
+ l->l_free_initfini = 0;
+
+ if (l != &GL(dl_rtld_map))
+ _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0,
+ consider_profiling);
+
+ /* Add object to slot information data if necessasy. */
+ if (l->l_tls_blocksize != 0 && tls_init_tp_called)
+ _dl_add_to_slotinfo (l);
+ }
+ HP_TIMING_NOW (stop);
+
+ HP_TIMING_DIFF (relocate_time, start, stop);
+
+ /* Now enable profiling if needed. Like the previous call,
+ this has to go here because the calls it makes should use the
+ rtld versions of the functions (particularly calloc()), but it
+ needs to have _dl_profile_map set up by the relocator. */
+ if (__glibc_unlikely (GL(dl_profile_map) != NULL))
+ /* We must prepare the profiling. */
+ _dl_start_profile ();
+ }
+
+ if ((!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0)
+ || count_modids != _dl_count_modids ())
+ ++GL(dl_tls_generation);
+
+ /* Now that we have completed relocation, the initializer data
+ for the TLS blocks has its final values and we can copy them
+ into the main thread's TLS area, which we allocated above. */
+ _dl_allocate_tls_init (tcbp);
+
+ /* And finally install it for the main thread. */
+ if (! tls_init_tp_called)
+ {
+ const char *lossage = TLS_INIT_TP (tcbp);
+ if (__glibc_unlikely (lossage != NULL))
+ _dl_fatal_printf ("cannot set up thread-local storage: %s\n",
+ lossage);
+ }
+
+ /* Make sure no new search directories have been added. */
+ assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs));
+
+ if (! prelinked && rtld_multiple_ref)
+ {
+ /* There was an explicit ref to the dynamic linker as a shared lib.
+ Re-relocate ourselves with user-controlled symbol definitions.
+
+ We must do this after TLS initialization in case after this
+ re-relocation, we might call a user-supplied function
+ (e.g. calloc from _dl_relocate_object) that uses TLS data. */
+
+#ifndef HP_TIMING_NONAVAIL
+ hp_timing_t start;
+ hp_timing_t stop;
+ hp_timing_t add;
+#endif
+
+ HP_TIMING_NOW (start);
+ /* Mark the link map as not yet relocated again. */
+ GL(dl_rtld_map).l_relocated = 0;
+ _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+ HP_TIMING_NOW (stop);
+ HP_TIMING_DIFF (add, start, stop);
+ HP_TIMING_ACCUM_NT (relocate_time, add);
+ }
+
+ /* Do any necessary cleanups for the startup OS interface code.
+ We do these now so that no calls are made after rtld re-relocation
+ which might be resolved to different functions than we expect.
+ We cannot do this before relocating the other objects because
+ _dl_relocate_object might need to call `mprotect' for DT_TEXTREL. */
+ _dl_sysdep_start_cleanup ();
+
+#ifdef SHARED
+ /* Auditing checkpoint: we have added all objects. */
+ if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ {
+ struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+ /* Do not call the functions for any auditing object. */
+ if (head->l_auditing == 0)
+ {
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->activity != NULL)
+ afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
+
+ afct = afct->next;
+ }
+ }
+ }
+#endif
+
+ /* Notify the debugger all new objects are now ready to go. We must re-get
+ the address since by now the variable might be in another object. */
+ r = _dl_debug_initialize (0, LM_ID_BASE);
+ r->r_state = RT_CONSISTENT;
+ _dl_debug_state ();
+ LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
+
+#if defined USE_LDCONFIG && !defined MAP_COPY
+ /* We must munmap() the cache file. */
+ _dl_unload_cache ();
+#endif
+
+ /* Once we return, _dl_sysdep_start will invoke
+ the DT_INIT functions and then *USER_ENTRY. */
+}
+
+/* This is a little helper function for resolving symbols while
+ tracing the binary. */
+static void
+print_unresolved (int errcode __attribute__ ((unused)), const char *objname,
+ const char *errstring)
+{
+ if (objname[0] == '\0')
+ objname = RTLD_PROGNAME;
+ _dl_error_printf ("%s (%s)\n", errstring, objname);
+}
+
+/* This is a little helper function for resolving symbols while
+ tracing the binary. */
+static void
+print_missing_version (int errcode __attribute__ ((unused)),
+ const char *objname, const char *errstring)
+{
+ _dl_error_printf ("%s: %s: %s\n", RTLD_PROGNAME,
+ objname, errstring);
+}
+
+/* Nonzero if any of the debugging options is enabled. */
+static int any_debug attribute_relro;
+
+/* Process the string given as the parameter which explains which debugging
+ options are enabled. */
+static void
+process_dl_debug (const char *dl_debug)
+{
+ /* When adding new entries make sure that the maximal length of a name
+ is correctly handled in the LD_DEBUG_HELP code below. */
+ static const struct
+ {
+ unsigned char len;
+ const char name[10];
+ const char helptext[41];
+ unsigned short int mask;
+ } debopts[] =
+ {
+#define LEN_AND_STR(str) sizeof (str) - 1, str
+ { LEN_AND_STR ("libs"), "display library search paths",
+ DL_DEBUG_LIBS | DL_DEBUG_IMPCALLS },
+ { LEN_AND_STR ("reloc"), "display relocation processing",
+ DL_DEBUG_RELOC | DL_DEBUG_IMPCALLS },
+ { LEN_AND_STR ("files"), "display progress for input file",
+ DL_DEBUG_FILES | DL_DEBUG_IMPCALLS },
+ { LEN_AND_STR ("symbols"), "display symbol table processing",
+ DL_DEBUG_SYMBOLS | DL_DEBUG_IMPCALLS },
+ { LEN_AND_STR ("bindings"), "display information about symbol binding",
+ DL_DEBUG_BINDINGS | DL_DEBUG_IMPCALLS },
+ { LEN_AND_STR ("versions"), "display version dependencies",
+ DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS },
+ { LEN_AND_STR ("scopes"), "display scope information",
+ DL_DEBUG_SCOPES },
+ { LEN_AND_STR ("all"), "all previous options combined",
+ DL_DEBUG_LIBS | DL_DEBUG_RELOC | DL_DEBUG_FILES | DL_DEBUG_SYMBOLS
+ | DL_DEBUG_BINDINGS | DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS
+ | DL_DEBUG_SCOPES },
+ { LEN_AND_STR ("statistics"), "display relocation statistics",
+ DL_DEBUG_STATISTICS },
+ { LEN_AND_STR ("unused"), "determined unused DSOs",
+ DL_DEBUG_UNUSED },
+ { LEN_AND_STR ("help"), "display this help message and exit",
+ DL_DEBUG_HELP },
+ };
+#define ndebopts (sizeof (debopts) / sizeof (debopts[0]))
+
+ /* Skip separating white spaces and commas. */
+ while (*dl_debug != '\0')
+ {
+ if (*dl_debug != ' ' && *dl_debug != ',' && *dl_debug != ':')
+ {
+ size_t cnt;
+ size_t len = 1;
+
+ while (dl_debug[len] != '\0' && dl_debug[len] != ' '
+ && dl_debug[len] != ',' && dl_debug[len] != ':')
+ ++len;
+
+ for (cnt = 0; cnt < ndebopts; ++cnt)
+ if (debopts[cnt].len == len
+ && memcmp (dl_debug, debopts[cnt].name, len) == 0)
+ {
+ GLRO(dl_debug_mask) |= debopts[cnt].mask;
+ any_debug = 1;
+ break;
+ }
+
+ if (cnt == ndebopts)
+ {
+ /* Display a warning and skip everything until next
+ separator. */
+ char *copy = strndupa (dl_debug, len);
+ _dl_error_printf ("\
+warning: debug option `%s' unknown; try LD_DEBUG=help\n", copy);
+ }
+
+ dl_debug += len;
+ continue;
+ }
+
+ ++dl_debug;
+ }
+
+ if (GLRO(dl_debug_mask) & DL_DEBUG_UNUSED)
+ {
+ /* In order to get an accurate picture of whether a particular
+ DT_NEEDED entry is actually used we have to process both
+ the PLT and non-PLT relocation entries. */
+ GLRO(dl_lazy) = 0;
+ }
+
+ if (GLRO(dl_debug_mask) & DL_DEBUG_HELP)
+ {
+ size_t cnt;
+
+ _dl_printf ("\
+Valid options for the LD_DEBUG environment variable are:\n\n");
+
+ for (cnt = 0; cnt < ndebopts; ++cnt)
+ _dl_printf (" %.*s%s%s\n", debopts[cnt].len, debopts[cnt].name,
+ " " + debopts[cnt].len - 3,
+ debopts[cnt].helptext);
+
+ _dl_printf ("\n\
+To direct the debugging output into a file instead of standard output\n\
+a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n");
+ _exit (0);
+ }
+}
+
+static void
+process_dl_audit (char *str)
+{
+ /* The parameter is a colon separated list of DSO names. */
+ char *p;
+
+ while ((p = (strsep) (&str, ":")) != NULL)
+ if (p[0] != '\0'
+ && (__builtin_expect (! __libc_enable_secure, 1)
+ || strchr (p, '/') == NULL))
+ {
+ /* This is using the local malloc, not the system malloc. The
+ memory can never be freed. */
+ struct audit_list *newp = malloc (sizeof (*newp));
+ newp->name = p;
+
+ if (audit_list == NULL)
+ audit_list = newp->next = newp;
+ else
+ {
+ newp->next = audit_list->next;
+ audit_list = audit_list->next = newp;
+ }
+ }
+}
+
+/* Process all environments variables the dynamic linker must recognize.
+ Since all of them start with `LD_' we are a bit smarter while finding
+ all the entries. */
+extern char **_environ attribute_hidden;
+
+
+static void
+process_envvars (enum mode *modep)
+{
+ char **runp = _environ;
+ char *envline;
+ enum mode mode = normal;
+ char *debug_output = NULL;
+
+ /* This is the default place for profiling data file. */
+ GLRO(dl_profile_output)
+ = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];
+
+ while ((envline = _dl_next_ld_env_entry (&runp)) != NULL)
+ {
+ size_t len = 0;
+
+ while (envline[len] != '\0' && envline[len] != '=')
+ ++len;
+
+ if (envline[len] != '=')
+ /* This is a "LD_" variable at the end of the string without
+ a '=' character. Ignore it since otherwise we will access
+ invalid memory below. */
+ continue;
+
+ switch (len)
+ {
+ case 4:
+ /* Warning level, verbose or not. */
+ if (memcmp (envline, "WARN", 4) == 0)
+ GLRO(dl_verbose) = envline[5] != '\0';
+ break;
+
+ case 5:
+ /* Debugging of the dynamic linker? */
+ if (memcmp (envline, "DEBUG", 5) == 0)
+ {
+ process_dl_debug (&envline[6]);
+ break;
+ }
+ if (memcmp (envline, "AUDIT", 5) == 0)
+ process_dl_audit (&envline[6]);
+ break;
+
+ case 7:
+ /* Print information about versions. */
+ if (memcmp (envline, "VERBOSE", 7) == 0)
+ {
+ version_info = envline[8] != '\0';
+ break;
+ }
+
+ /* List of objects to be preloaded. */
+ if (memcmp (envline, "PRELOAD", 7) == 0)
+ {
+ preloadlist = &envline[8];
+ break;
+ }
+
+ /* Which shared object shall be profiled. */
+ if (memcmp (envline, "PROFILE", 7) == 0 && envline[8] != '\0')
+ GLRO(dl_profile) = &envline[8];
+ break;
+
+ case 8:
+ /* Do we bind early? */
+ if (memcmp (envline, "BIND_NOW", 8) == 0)
+ {
+ GLRO(dl_lazy) = envline[9] == '\0';
+ break;
+ }
+ if (memcmp (envline, "BIND_NOT", 8) == 0)
+ GLRO(dl_bind_not) = envline[9] != '\0';
+ break;
+
+ case 9:
+ /* Test whether we want to see the content of the auxiliary
+ array passed up from the kernel. */
+ if (!__libc_enable_secure
+ && memcmp (envline, "SHOW_AUXV", 9) == 0)
+ _dl_show_auxv ();
+ break;
+
+#if !HAVE_TUNABLES
+ case 10:
+ /* Mask for the important hardware capabilities. */
+ if (!__libc_enable_secure
+ && memcmp (envline, "HWCAP_MASK", 10) == 0)
+ GLRO(dl_hwcap_mask) = __strtoul_internal (&envline[11], NULL,
+ 0, 0);
+ break;
+#endif
+
+ case 11:
+ /* Path where the binary is found. */
+ if (!__libc_enable_secure
+ && memcmp (envline, "ORIGIN_PATH", 11) == 0)
+ GLRO(dl_origin_path) = &envline[12];
+ break;
+
+ case 12:
+ /* The library search path. */
+ if (memcmp (envline, "LIBRARY_PATH", 12) == 0)
+ {
+ library_path = &envline[13];
+ break;
+ }
+
+ /* Where to place the profiling data file. */
+ if (memcmp (envline, "DEBUG_OUTPUT", 12) == 0)
+ {
+ debug_output = &envline[13];
+ break;
+ }
+
+ if (!__libc_enable_secure
+ && memcmp (envline, "DYNAMIC_WEAK", 12) == 0)
+ GLRO(dl_dynamic_weak) = 1;
+ break;
+
+ case 13:
+ /* We might have some extra environment variable with length 13
+ to handle. */
+#ifdef EXTRA_LD_ENVVARS_13
+ EXTRA_LD_ENVVARS_13
+#endif
+ if (!__libc_enable_secure
+ && memcmp (envline, "USE_LOAD_BIAS", 13) == 0)
+ {
+ GLRO(dl_use_load_bias) = envline[14] == '1' ? -1 : 0;
+ break;
+ }
+ break;
+
+ case 14:
+ /* Where to place the profiling data file. */
+ if (!__libc_enable_secure
+ && memcmp (envline, "PROFILE_OUTPUT", 14) == 0
+ && envline[15] != '\0')
+ GLRO(dl_profile_output) = &envline[15];
+ break;
+
+ case 16:
+ /* The mode of the dynamic linker can be set. */
+ if (memcmp (envline, "TRACE_PRELINKING", 16) == 0)
+ {
+ mode = trace;
+ GLRO(dl_verbose) = 1;
+ GLRO(dl_debug_mask) |= DL_DEBUG_PRELINK;
+ GLRO(dl_trace_prelink) = &envline[17];
+ }
+ break;
+
+ case 20:
+ /* The mode of the dynamic linker can be set. */
+ if (memcmp (envline, "TRACE_LOADED_OBJECTS", 20) == 0)
+ mode = trace;
+ break;
+
+ /* We might have some extra environment variable to handle. This
+ is tricky due to the pre-processing of the length of the name
+ in the switch statement here. The code here assumes that added
+ environment variables have a different length. */
+#ifdef EXTRA_LD_ENVVARS
+ EXTRA_LD_ENVVARS
+#endif
+ }
+ }
+
+ /* The caller wants this information. */
+ *modep = mode;
+
+ /* Extra security for SUID binaries. Remove all dangerous environment
+ variables. */
+ if (__builtin_expect (__libc_enable_secure, 0))
+ {
+ static const char unsecure_envvars[] =
+#ifdef EXTRA_UNSECURE_ENVVARS
+ EXTRA_UNSECURE_ENVVARS
+#endif
+ UNSECURE_ENVVARS;
+ const char *nextp;
+
+ nextp = unsecure_envvars;
+ do
+ {
+ unsetenv (nextp);
+ /* We could use rawmemchr but this need not be fast. */
+ nextp = (char *) (strchr) (nextp, '\0') + 1;
+ }
+ while (*nextp != '\0');
+
+ if (__access ("/etc/suid-debug", F_OK) != 0)
+ {
+#if !HAVE_TUNABLES
+ unsetenv ("MALLOC_CHECK_");
+#endif
+ GLRO(dl_debug_mask) = 0;
+ }
+
+ if (mode != normal)
+ _exit (5);
+ }
+ /* If we have to run the dynamic linker in debugging mode and the
+ LD_DEBUG_OUTPUT environment variable is given, we write the debug
+ messages to this file. */
+ else if (any_debug && debug_output != NULL)
+ {
+ const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW;
+ size_t name_len = strlen (debug_output);
+ char buf[name_len + 12];
+ char *startp;
+
+ buf[name_len + 11] = '\0';
+ startp = _itoa (__getpid (), &buf[name_len + 11], 10, 0);
+ *--startp = '.';
+ startp = memcpy (startp - name_len, debug_output, name_len);
+
+ GLRO(dl_debug_fd) = __open (startp, flags, DEFFILEMODE);
+ if (GLRO(dl_debug_fd) == -1)
+ /* We use standard output if opening the file failed. */
+ GLRO(dl_debug_fd) = STDOUT_FILENO;
+ }
+}
+
+
+/* Print the various times we collected. */
+static void
+__attribute ((noinline))
+print_statistics (hp_timing_t *rtld_total_timep)
+{
+#ifndef HP_TIMING_NONAVAIL
+ char buf[200];
+ char *cp;
+ char *wp;
+
+ /* Total time rtld used. */
+ if (HP_SMALL_TIMING_AVAIL)
+ {
+ HP_TIMING_PRINT (buf, sizeof (buf), *rtld_total_timep);
+ _dl_debug_printf ("\nruntime linker statistics:\n"
+ " total startup time in dynamic loader: %s\n", buf);
+
+ /* Print relocation statistics. */
+ char pbuf[30];
+ HP_TIMING_PRINT (buf, sizeof (buf), relocate_time);
+ cp = _itoa ((1000ULL * relocate_time) / *rtld_total_timep,
+ pbuf + sizeof (pbuf), 10, 0);
+ wp = pbuf;
+ switch (pbuf + sizeof (pbuf) - cp)
+ {
+ case 3:
+ *wp++ = *cp++;
+ case 2:
+ *wp++ = *cp++;
+ case 1:
+ *wp++ = '.';
+ *wp++ = *cp++;
+ }
+ *wp = '\0';
+ _dl_debug_printf ("\
+ time needed for relocation: %s (%s%%)\n", buf, pbuf);
+ }
+#endif
+
+ unsigned long int num_relative_relocations = 0;
+ for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
+ {
+ if (GL(dl_ns)[ns]._ns_loaded == NULL)
+ continue;
+
+ struct r_scope_elem *scope = &GL(dl_ns)[ns]._ns_loaded->l_searchlist;
+
+ for (unsigned int i = 0; i < scope->r_nlist; i++)
+ {
+ struct link_map *l = scope->r_list [i];
+
+ if (l->l_addr != 0 && l->l_info[VERSYMIDX (DT_RELCOUNT)])
+ num_relative_relocations
+ += l->l_info[VERSYMIDX (DT_RELCOUNT)]->d_un.d_val;
+#ifndef ELF_MACHINE_REL_RELATIVE
+ /* Relative relocations are processed on these architectures if
+ library is loaded to different address than p_vaddr or
+ if not prelinked. */
+ if ((l->l_addr != 0 || !l->l_info[VALIDX(DT_GNU_PRELINKED)])
+ && l->l_info[VERSYMIDX (DT_RELACOUNT)])
+#else
+ /* On e.g. IA-64 or Alpha, relative relocations are processed
+ only if library is loaded to different address than p_vaddr. */
+ if (l->l_addr != 0 && l->l_info[VERSYMIDX (DT_RELACOUNT)])
+#endif
+ num_relative_relocations
+ += l->l_info[VERSYMIDX (DT_RELACOUNT)]->d_un.d_val;
+ }
+ }
+
+ _dl_debug_printf (" number of relocations: %lu\n"
+ " number of relocations from cache: %lu\n"
+ " number of relative relocations: %lu\n",
+ GL(dl_num_relocations),
+ GL(dl_num_cache_relocations),
+ num_relative_relocations);
+
+#ifndef HP_TIMING_NONAVAIL
+ /* Time spend while loading the object and the dependencies. */
+ if (HP_SMALL_TIMING_AVAIL)
+ {
+ char pbuf[30];
+ HP_TIMING_PRINT (buf, sizeof (buf), load_time);
+ cp = _itoa ((1000ULL * load_time) / *rtld_total_timep,
+ pbuf + sizeof (pbuf), 10, 0);
+ wp = pbuf;
+ switch (pbuf + sizeof (pbuf) - cp)
+ {
+ case 3:
+ *wp++ = *cp++;
+ case 2:
+ *wp++ = *cp++;
+ case 1:
+ *wp++ = '.';
+ *wp++ = *cp++;
+ }
+ *wp = '\0';
+ _dl_debug_printf ("\
+ time needed to load objects: %s (%s%%)\n",
+ buf, pbuf);
+ }
+#endif
+}
diff --git a/REORG.TODO/elf/setup-vdso.h b/REORG.TODO/elf/setup-vdso.h
new file mode 100644
index 0000000000..2db597eba3
--- /dev/null
+++ b/REORG.TODO/elf/setup-vdso.h
@@ -0,0 +1,121 @@
+/* Set up the data structures for the system-supplied DSO.
+ Copyright (C) 2012-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+static inline void __attribute__ ((always_inline))
+setup_vdso (struct link_map *main_map __attribute__ ((unused)),
+ struct link_map ***first_preload __attribute__ ((unused)))
+{
+#ifdef NEED_DL_SYSINFO_DSO
+ if (GLRO(dl_sysinfo_dso) == NULL)
+ return;
+
+ /* Do an abridged version of the work _dl_map_object_from_fd would do
+ to map in the object. It's already mapped and prelinked (and
+ better be, since it's read-only and so we couldn't relocate it).
+ We just want our data structures to describe it as if we had just
+ mapped and relocated it normally. */
+ struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL,
+ 0, LM_ID_BASE);
+ if (__glibc_likely (l != NULL))
+ {
+ static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro;
+
+ l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso)
+ + GLRO(dl_sysinfo_dso)->e_phoff);
+ l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum;
+ for (uint_fast16_t i = 0; i < l->l_phnum; ++i)
+ {
+ const ElfW(Phdr) *const ph = &l->l_phdr[i];
+ if (ph->p_type == PT_DYNAMIC)
+ {
+ l->l_ld = (void *) ph->p_vaddr;
+ l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+ }
+ else if (ph->p_type == PT_LOAD)
+ {
+ if (! l->l_addr)
+ l->l_addr = ph->p_vaddr;
+ if (ph->p_vaddr + ph->p_memsz >= l->l_map_end)
+ l->l_map_end = ph->p_vaddr + ph->p_memsz;
+ if ((ph->p_flags & PF_X)
+ && ph->p_vaddr + ph->p_memsz >= l->l_text_end)
+ l->l_text_end = ph->p_vaddr + ph->p_memsz;
+ }
+ else
+ /* There must be no TLS segment. */
+ assert (ph->p_type != PT_TLS);
+ }
+ l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso);
+ l->l_addr = l->l_map_start - l->l_addr;
+ l->l_map_end += l->l_addr;
+ l->l_text_end += l->l_addr;
+ l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr);
+ elf_get_dynamic_info (l, dyn_temp);
+ _dl_setup_hash (l);
+ l->l_relocated = 1;
+
+ /* The vDSO is always used. */
+ l->l_used = 1;
+
+ /* Initialize l_local_scope to contain just this map. This allows
+ the use of dl_lookup_symbol_x to resolve symbols within the vdso.
+ So we create a single entry list pointing to l_real as its only
+ element */
+ l->l_local_scope[0]->r_nlist = 1;
+ l->l_local_scope[0]->r_list = &l->l_real;
+
+ /* Now that we have the info handy, use the DSO image's soname
+ so this object can be looked up by name. Note that we do not
+ set l_name here. That field gives the file name of the DSO,
+ and this DSO is not associated with any file. */
+ if (l->l_info[DT_SONAME] != NULL)
+ {
+ /* Work around a kernel problem. The kernel cannot handle
+ addresses in the vsyscall DSO pages in writev() calls. */
+ const char *dsoname = ((char *) D_PTR (l, l_info[DT_STRTAB])
+ + l->l_info[DT_SONAME]->d_un.d_val);
+ size_t len = strlen (dsoname) + 1;
+ char *copy = malloc (len);
+ if (copy == NULL)
+ _dl_fatal_printf ("out of memory\n");
+ l->l_libname->name = l->l_name = memcpy (copy, dsoname, len);
+ }
+
+ /* Add the vDSO to the object list. */
+ _dl_add_to_namespace_list (l, LM_ID_BASE);
+
+# if IS_IN (rtld)
+ /* Rearrange the list so this DSO appears after rtld_map. */
+ assert (l->l_next == NULL);
+ assert (l->l_prev == main_map);
+ GL(dl_rtld_map).l_next = l;
+ l->l_prev = &GL(dl_rtld_map);
+ *first_preload = &l->l_next;
+# else
+ GL(dl_nns) = 1;
+# endif
+
+ /* We have a prelinked DSO preloaded by the system. */
+ GLRO(dl_sysinfo_map) = l;
+# ifdef NEED_DL_SYSINFO
+ if (GLRO(dl_sysinfo) == DL_SYSINFO_DEFAULT)
+ GLRO(dl_sysinfo) = GLRO(dl_sysinfo_dso)->e_entry + l->l_addr;
+# endif
+ }
+#endif
+}
diff --git a/REORG.TODO/elf/sln.c b/REORG.TODO/elf/sln.c
new file mode 100644
index 0000000000..af2d0de164
--- /dev/null
+++ b/REORG.TODO/elf/sln.c
@@ -0,0 +1,202 @@
+/* `sln' program to create symbolic links between files.
+ Copyright (C) 1998-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <error.h>
+#include <errno.h>
+#include <libintl.h>
+#include <locale.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+#include "../version.h"
+
+#define PACKAGE _libc_intl_domainname
+
+static int makesymlink (const char *src, const char *dest);
+static int makesymlinks (const char *file);
+static void usage (void);
+
+int
+main (int argc, char **argv)
+{
+ /* Set locale via LC_ALL. */
+ setlocale (LC_ALL, "");
+
+ /* Set the text message domain. */
+ textdomain (PACKAGE);
+
+ switch (argc)
+ {
+ case 2:
+ if (strcmp (argv[1], "--version") == 0) {
+ printf ("sln %s%s\n", PKGVERSION, VERSION);
+ return 0;
+ } else if (strcmp (argv[1], "--help") == 0) {
+ usage ();
+ return 0;
+ }
+ return makesymlinks (argv [1]);
+ break;
+
+ case 3:
+ return makesymlink (argv [1], argv [2]);
+ break;
+
+ default:
+ usage ();
+ return 1;
+ break;
+ }
+}
+
+static void
+usage (void)
+{
+ printf (_("Usage: sln src dest|file\n\n"));
+ printf (_("For bug reporting instructions, please see:\n\
+%s.\n"), REPORT_BUGS_TO);
+}
+
+static int
+makesymlinks (const char *file)
+{
+ char *buffer = NULL;
+ size_t bufferlen = 0;
+ int ret;
+ int lineno;
+ FILE *fp;
+
+ if (strcmp (file, "-") == 0)
+ fp = stdin;
+ else
+ {
+ fp = fopen (file, "r");
+ if (fp == NULL)
+ {
+ fprintf (stderr, _("%s: file open error: %m\n"), file);
+ return 1;
+ }
+ }
+
+ ret = 0;
+ lineno = 0;
+ while (!feof_unlocked (fp))
+ {
+ ssize_t n = getline (&buffer, &bufferlen, fp);
+ char *src;
+ char *dest;
+ char *cp = buffer;
+
+ if (n < 0)
+ break;
+ if (buffer[n - 1] == '\n')
+ buffer[n - 1] = '\0';
+
+ ++lineno;
+ while (isspace (*cp))
+ ++cp;
+ if (*cp == '\0')
+ /* Ignore empty lines. */
+ continue;
+ src = cp;
+
+ do
+ ++cp;
+ while (*cp != '\0' && ! isspace (*cp));
+ if (*cp != '\0')
+ *cp++ = '\0';
+
+ while (isspace (*cp))
+ ++cp;
+ if (*cp == '\0')
+ {
+ fprintf (stderr, _("No target in line %d\n"), lineno);
+ ret = 1;
+ continue;
+ }
+ dest = cp;
+
+ do
+ ++cp;
+ while (*cp != '\0' && ! isspace (*cp));
+ if (*cp != '\0')
+ *cp++ = '\0';
+
+ ret |= makesymlink (src, dest);
+ }
+ fclose (fp);
+
+ return ret;
+}
+
+static int
+makesymlink (const char *src, const char *dest)
+{
+ struct stat64 stats;
+ const char *error;
+
+ /* Destination must not be a directory. */
+ if (lstat64 (dest, &stats) == 0)
+ {
+ if (S_ISDIR (stats.st_mode))
+ {
+ fprintf (stderr, _("%s: destination must not be a directory\n"),
+ dest);
+ return 1;
+ }
+ else if (unlink (dest) && errno != ENOENT)
+ {
+ fprintf (stderr, _("%s: failed to remove the old destination\n"),
+ dest);
+ return 1;
+ }
+ }
+ else if (errno != ENOENT)
+ {
+ error = strerror (errno);
+ fprintf (stderr, _("%s: invalid destination: %s\n"), dest, error);
+ return -1;
+ }
+
+ if (symlink (src, dest) == 0)
+ {
+ /* Destination must exist by now. */
+ if (access (dest, F_OK))
+ {
+ error = strerror (errno);
+ unlink (dest);
+ fprintf (stderr, _("Invalid link from \"%s\" to \"%s\": %s\n"),
+ src, dest, error);
+ return 1;
+ }
+ return 0;
+ }
+ else
+ {
+ error = strerror (errno);
+ fprintf (stderr, _("Invalid link from \"%s\" to \"%s\": %s\n"),
+ src, dest, error);
+ return 1;
+ }
+}
diff --git a/REORG.TODO/elf/sofini.c b/REORG.TODO/elf/sofini.c
new file mode 100644
index 0000000000..13e74b7903
--- /dev/null
+++ b/REORG.TODO/elf/sofini.c
@@ -0,0 +1,19 @@
+/* Finalizer module for ELF shared C library. This provides terminating
+ null pointer words in the `.ctors' and `.dtors' sections. */
+
+#ifndef NO_CTORS_DTORS_SECTIONS
+static void (*const __CTOR_END__[1]) (void)
+ __attribute__ ((used, section (".ctors")))
+ = { 0 };
+static void (*const __DTOR_END__[1]) (void)
+ __attribute__ ((used, section (".dtors")))
+ = { 0 };
+#endif
+
+/* Terminate the frame unwind info section with a 4byte 0 as a sentinel;
+ this would be the 'length' field in a real FDE. */
+
+typedef unsigned int ui32 __attribute__ ((mode (SI)));
+static const ui32 __FRAME_END__[1]
+ __attribute__ ((used, section (".eh_frame")))
+ = { 0 };
diff --git a/REORG.TODO/elf/soinit.c b/REORG.TODO/elf/soinit.c
new file mode 100644
index 0000000000..fe9935732b
--- /dev/null
+++ b/REORG.TODO/elf/soinit.c
@@ -0,0 +1,43 @@
+/* Initializer module for building the ELF shared C library. This file and
+ sofini.c do the work normally done by crtbeginS.o and crtendS.o, to wrap
+ the `.ctors' and `.dtors' sections so the lists are terminated, and
+ calling those lists of functions. */
+
+#ifndef NO_CTORS_DTORS_SECTIONS
+# include <stdlib.h>
+
+static void (*const __CTOR_LIST__[1]) (void)
+ __attribute__ ((used, section (".ctors")))
+ = { (void (*) (void)) -1 };
+static void (*const __DTOR_LIST__[1]) (void)
+ __attribute__ ((used, section (".dtors")))
+ = { (void (*) (void)) -1 };
+
+static inline void
+run_hooks (void (*const list[]) (void))
+{
+ while (*++list)
+ (**list) ();
+}
+
+/* This function will be called from _init in init-first.c. */
+void
+__libc_global_ctors (void)
+{
+ /* Call constructor functions. */
+ run_hooks (__CTOR_LIST__);
+}
+
+
+/* This function becomes the DT_FINI termination function
+ for the C library. */
+void
+__libc_fini (void)
+{
+ /* Call destructor functions. */
+ run_hooks (__DTOR_LIST__);
+}
+
+void (*_fini_ptr) (void) __attribute__ ((section (".fini_array")))
+ = &__libc_fini;
+#endif
diff --git a/REORG.TODO/elf/sotruss-lib.c b/REORG.TODO/elf/sotruss-lib.c
new file mode 100644
index 0000000000..da2fedd52a
--- /dev/null
+++ b/REORG.TODO/elf/sotruss-lib.c
@@ -0,0 +1,386 @@
+/* Trace calls through PLTs and show caller, callee, and parameters.
+ Copyright (C) 2011-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include <ldsodefs.h>
+
+
+extern const char *__progname;
+extern const char *__progname_full;
+
+
+/* List of objects to trace calls from. */
+static const char *fromlist;
+/* List of objects to trace calls to. */
+static const char *tolist;
+
+/* If non-zero, also trace returns of the calls. */
+static int do_exit;
+/* If non-zero print PID for each line. */
+static int print_pid;
+
+/* The output stream to use. */
+static FILE *out_file;
+
+
+static int
+match_pid (pid_t pid, const char *which)
+{
+ if (which == NULL || which[0] == '\0')
+ {
+ print_pid = 1;
+ return 1;
+ }
+
+ char *endp;
+ unsigned long n = strtoul (which, &endp, 0);
+ return *endp == '\0' && n == pid;
+}
+
+
+static void
+init (void)
+{
+ fromlist = getenv ("SOTRUSS_FROMLIST");
+ if (fromlist != NULL && fromlist[0] == '\0')
+ fromlist = NULL;
+ tolist = getenv ("SOTRUSS_TOLIST");
+ if (tolist != NULL && tolist[0] == '\0')
+ tolist = NULL;
+ do_exit = (getenv ("SOTRUSS_EXIT") ?: "")[0] != '\0';
+
+ /* Determine whether this process is supposed to be traced and if
+ yes, whether we should print into a file. */
+ const char *which_process = getenv ("SOTRUSS_WHICH");
+ pid_t pid = getpid ();
+ int out_fd = -1;
+ if (match_pid (pid, which_process))
+ {
+ const char *out_filename = getenv ("SOTRUSS_OUTNAME");
+
+ if (out_filename != NULL && out_filename[0] != 0)
+ {
+ size_t out_filename_len = strlen (out_filename) + 13;
+ char fullname[out_filename_len];
+ char *endp = stpcpy (fullname, out_filename);
+ if (which_process == NULL || which_process[0] == '\0')
+ snprintf (endp, 13, ".%ld", (long int) pid);
+
+ out_fd = open (fullname, O_RDWR | O_CREAT | O_TRUNC, 0666);
+ if (out_fd != -1)
+ print_pid = 0;
+ }
+ }
+
+ /* If we do not write into a file write to stderr. Duplicate the
+ descriptor so that we can keep printing in case the program
+ closes stderr. Try first to allocate a descriptor with a value
+ usually not used as to minimize interference with the
+ program. */
+ if (out_fd == -1)
+ {
+ out_fd = fcntl (STDERR_FILENO, F_DUPFD, 1000);
+ if (out_fd == -1)
+ out_fd = dup (STDERR_FILENO);
+ }
+
+ if (out_fd != -1)
+ {
+ /* Convert file descriptor into a stream. */
+ out_file = fdopen (out_fd, "w");
+ if (out_file != NULL)
+ setlinebuf (out_file);
+ }
+}
+
+
+/* Audit interface verification. We also initialize everything if
+ everything checks out OK. */
+unsigned int
+la_version (unsigned int v)
+{
+ if (v != LAV_CURRENT)
+ error (1, 0, "cannot handle interface version %u", v);
+
+ init ();
+
+ return v;
+}
+
+
+/* Check whether a file name is on the colon-separated list of file
+ names. */
+static unsigned int
+match_file (const char *list, const char *name, size_t name_len,
+ unsigned int mask)
+{
+ if (list[0] == '\0')
+ return 0;
+
+ const char *cp = list;
+ while (1)
+ {
+ if (strncmp (cp, name, name_len) == 0
+ && (cp[name_len] == ':' || cp[name_len] == '\0'))
+ return mask;
+
+ cp = strchr (cp, ':');
+ if (cp == NULL)
+ return 0;
+ ++cp;
+ }
+}
+
+
+unsigned int
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
+{
+ if (out_file == NULL)
+ return 0;
+
+ const char *full_name = map->l_name ?: "";
+ if (full_name[0] == '\0')
+ full_name = __progname_full;
+ size_t full_name_len = strlen (full_name);
+ const char *base_name = basename (full_name);
+ if (base_name[0] == '\0')
+ base_name = __progname;
+ size_t base_name_len = strlen (base_name);
+
+ int result = 0;
+ const char *print_name = NULL;
+ for (struct libname_list *l = map->l_libname; l != NULL; l = l->next)
+ {
+ if (print_name == NULL || (print_name[0] == '/' && l->name[0] != '/'))
+ print_name = l->name;
+
+ if (fromlist != NULL)
+ result |= match_file (fromlist, l->name, strlen (l->name),
+ LA_FLG_BINDFROM);
+
+ if (tolist != NULL)
+ result |= match_file (tolist, l->name, strlen (l->name),LA_FLG_BINDTO);
+ }
+
+ if (print_name == NULL)
+ print_name = base_name;
+ if (print_name[0] == '\0')
+ print_name = __progname;
+
+ /* We cannot easily get to the object name in the PLT handling
+ functions. Use the cookie to get the string pointer passed back
+ to us. */
+ *cookie = (uintptr_t) print_name;
+
+ /* The object name has to be on the list of objects to trace calls
+ from or that list must be empty. In the latter case we trace
+ only calls from the main binary. */
+ if (fromlist == NULL)
+ result |= map->l_name[0] == '\0' ? LA_FLG_BINDFROM : 0;
+ else
+ result |= (match_file (fromlist, full_name, full_name_len,
+ LA_FLG_BINDFROM)
+ | match_file (fromlist, base_name, base_name_len,
+ LA_FLG_BINDFROM));
+
+ /* The object name has to be on the list of objects to trace calls
+ to or that list must be empty. In the latter case we trace
+ calls toall objects. */
+ if (tolist == NULL)
+ result |= LA_FLG_BINDTO;
+ else
+ result |= (match_file (tolist, full_name, full_name_len, LA_FLG_BINDTO)
+ | match_file (tolist, base_name, base_name_len, LA_FLG_BINDTO));
+
+ return result;
+}
+
+
+#if __ELF_NATIVE_CLASS == 32
+# define la_symbind la_symbind32
+typedef Elf32_Sym Elf_Sym;
+#else
+# define la_symbind la_symbind64
+typedef Elf64_Sym Elf_Sym;
+#endif
+
+uintptr_t
+la_symbind (Elf_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, unsigned int *flags, const char *symname)
+{
+ if (!do_exit)
+ *flags = LA_SYMB_NOPLTEXIT;
+
+ return sym->st_value;
+}
+
+
+static void
+print_enter (uintptr_t *refcook, uintptr_t *defcook, const char *symname,
+ unsigned long int reg1, unsigned long int reg2,
+ unsigned long int reg3, unsigned int flags)
+{
+ char buf[3 * sizeof (pid_t) + 3];
+ buf[0] = '\0';
+ if (print_pid)
+ snprintf (buf, sizeof (buf), "%5ld: ", (long int) getpid ());
+
+ fprintf (out_file, "%s%15s -> %-15s:%s%s(0x%lx, 0x%lx, 0x%lx)\n",
+ buf, (char *) *refcook, (char *) *defcook,
+ (flags & LA_SYMB_NOPLTEXIT) ? "*" : " ", symname, reg1, reg2, reg3);
+}
+
+
+#ifdef __i386__
+Elf32_Addr
+la_i86_gnu_pltenter (Elf32_Sym *sym __attribute__ ((unused)),
+ unsigned int ndx __attribute__ ((unused)),
+ uintptr_t *refcook, uintptr_t *defcook,
+ La_i86_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ unsigned long int *sp = (unsigned long int *) regs->lr_esp;
+
+ print_enter (refcook, defcook, symname, sp[1], sp[2], sp[3], *flags);
+
+ /* No need to copy anything, we will not need the parameters in any case. */
+ *framesizep = 0;
+
+ return sym->st_value;
+}
+#elif defined __x86_64__
+Elf64_Addr
+la_x86_64_gnu_pltenter (Elf64_Sym *sym __attribute__ ((unused)),
+ unsigned int ndx __attribute__ ((unused)),
+ uintptr_t *refcook, uintptr_t *defcook,
+ La_x86_64_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ print_enter (refcook, defcook, symname,
+ regs->lr_rdi, regs->lr_rsi, regs->lr_rdx, *flags);
+
+ /* No need to copy anything, we will not need the parameters in any case. */
+ *framesizep = 0;
+
+ return sym->st_value;
+}
+#elif defined __sparc__ && !defined __arch64__
+Elf32_Addr
+la_sparc32_gnu_pltenter (Elf32_Sym *sym __attribute__ ((unused)),
+ unsigned int ndx __attribute__ ((unused)),
+ uintptr_t *refcook, uintptr_t *defcook,
+ La_sparc32_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ print_enter (refcook, defcook, symname,
+ regs->lr_reg[0], regs->lr_reg[1], regs->lr_reg[2],
+ *flags);
+
+ /* No need to copy anything, we will not need the parameters in any case. */
+ *framesizep = 0;
+
+ return sym->st_value;
+}
+#elif defined __sparc__ && defined __arch64__
+Elf64_Addr
+la_sparc64_gnu_pltenter (Elf64_Sym *sym __attribute__ ((unused)),
+ unsigned int ndx __attribute__ ((unused)),
+ uintptr_t *refcook, uintptr_t *defcook,
+ La_sparc64_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ print_enter (refcook, defcook, symname,
+ regs->lr_reg[0], regs->lr_reg[1], regs->lr_reg[2],
+ *flags);
+
+ /* No need to copy anything, we will not need the parameters in any case. */
+ *framesizep = 0;
+
+ return sym->st_value;
+}
+#elif !defined HAVE_ARCH_PLTENTER
+# warning "pltenter for architecture not supported"
+#endif
+
+
+static void
+print_exit (uintptr_t *refcook, uintptr_t *defcook, const char *symname,
+ unsigned long int reg)
+{
+ char buf[3 * sizeof (pid_t) + 3];
+ buf[0] = '\0';
+ if (print_pid)
+ snprintf (buf, sizeof (buf), "%5ld: ", (long int) getpid ());
+
+ fprintf (out_file, "%s%15s -> %-15s:%s%s - 0x%lx\n",
+ buf, (char *) *refcook, (char *) *defcook, " ", symname, reg);
+}
+
+
+#ifdef __i386__
+unsigned int
+la_i86_gnu_pltexit (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const struct La_i86_regs *inregs,
+ struct La_i86_retval *outregs, const char *symname)
+{
+ print_exit (refcook, defcook, symname, outregs->lrv_eax);
+
+ return 0;
+}
+#elif defined __x86_64__
+unsigned int
+la_x86_64_gnu_pltexit (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const struct La_x86_64_regs *inregs,
+ struct La_x86_64_retval *outregs, const char *symname)
+{
+ print_exit (refcook, defcook, symname, outregs->lrv_rax);
+
+ return 0;
+}
+#elif defined __sparc__ && !defined __arch64__
+unsigned int
+la_sparc32_gnu_pltexit (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const struct La_sparc32_regs *inregs,
+ struct La_sparc32_retval *outregs, const char *symname)
+{
+ print_exit (refcook, defcook, symname, outregs->lrv_reg[0]);
+
+ return 0;
+}
+#elif defined __sparc__ && defined __arch64__
+unsigned int
+la_sparc64_gnu_pltexit (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const struct La_sparc64_regs *inregs,
+ struct La_sparc64_retval *outregs, const char *symname)
+{
+ print_exit (refcook, defcook, symname, outregs->lrv_reg[0]);
+
+ return 0;
+}
+#elif !defined HAVE_ARCH_PLTEXIT
+# warning "pltexit for architecture not supported"
+#endif
diff --git a/REORG.TODO/elf/sotruss.sh b/REORG.TODO/elf/sotruss.sh
new file mode 100755
index 0000000000..c83e837e0e
--- /dev/null
+++ b/REORG.TODO/elf/sotruss.sh
@@ -0,0 +1,152 @@
+#! @BASH@
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+# We should be able to find the translation right at the beginning.
+TEXTDOMAIN=libc
+TEXTDOMAINDIR=@TEXTDOMAINDIR@
+
+unset SOTRUSS_FROMLIST
+unset SOTRUSS_TOLIST
+unset SOTRUSS_OUTNAME
+unset SOTRUSS_EXIT
+unset SOTRUSS_NOINDENT
+SOTRUSS_WHICH=$$
+lib='@PREFIX@/$LIB/audit/sotruss-lib.so'
+
+do_help() {
+ echo $"Usage: sotruss [OPTION...] [--] EXECUTABLE [EXECUTABLE-OPTION...]
+ -F, --from FROMLIST Trace calls from objects on FROMLIST
+ -T, --to TOLIST Trace calls to objects on TOLIST
+
+ -e, --exit Also show exits from the function calls
+ -f, --follow Trace child processes
+ -o, --output FILENAME Write output to FILENAME (or FILENAME.$PID in case
+ -f is also used) instead of standard error
+
+ -?, --help Give this help list
+ --usage Give a short usage message
+ --version Print program version"
+
+ echo
+ printf $"Mandatory arguments to long options are also mandatory for any corresponding\nshort options.\n"
+ echo
+
+ printf $"For bug reporting instructions, please see:\\n%s.\\n" \
+ "@REPORT_BUGS_TO@"
+ exit 0
+}
+
+do_missing_arg() {
+ printf >&2 $"%s: option requires an argument -- '%s'\n" sotruss "$1"
+ printf >&2 $"Try \`%s --help' or \`%s --usage' for more information.\n" sotruss sotruss
+ exit 1
+}
+
+do_ambiguous() {
+ printf >&2 $"%s: option is ambiguous; possibilities:"
+ while test $# -gt 0; do
+ printf >&2 " '%s'" $1
+ shift
+ done
+ printf >&2 "\n"
+ printf >&2 $"Try \`%s --help' or \`%s --usage' for more information.\n" sotruss sotruss
+ exit 1
+}
+
+while test $# -gt 0; do
+ case "$1" in
+ --v | --ve | --ver | --vers | --versi | --versio | --version)
+ echo "sotruss @PKGVERSION@@VERSION@"
+ printf $"Copyright (C) %s Free Software Foundation, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+" "2017"
+ printf $"Written by %s.\n" "Ulrich Drepper"
+ exit 0
+ ;;
+ -\? | --h | --he | --hel | --help)
+ do_help
+ ;;
+ --u | --us | --usa | --usag | --usage)
+ printf $"Usage: %s [-ef] [-F FROMLIST] [-o FILENAME] [-T TOLIST] [--exit]
+ [--follow] [--from FROMLIST] [--output FILENAME] [--to TOLIST]
+ [--help] [--usage] [--version] [--]
+ EXECUTABLE [EXECUTABLE-OPTION...]\n" sotruss
+ exit 0
+ ;;
+ -F | --fr | --fro | --from)
+ if test $# -eq 1; then
+ do_missing_arg "$1"
+ fi
+ shift
+ SOTRUSS_FROMLIST="$1"
+ ;;
+ -T | --t | --to)
+ if test $# -eq 1; then
+ do_missing_arg "$1"
+ fi
+ shift
+ SOTRUSS_TOLIST="$1"
+ ;;
+ -o | --o | --ou | --out | --outp | --outpu | --output)
+ if test $# -eq 1; then
+ do_missing_arg "$1"
+ fi
+ shift
+ SOTRUSS_OUTNAME="$1"
+ ;;
+ -f | --fo | --fol | --foll | --follo | --follow)
+ unset SOTRUSS_WHICH
+ ;;
+ -l | --l | --li | --lib)
+ if test $# -eq 1; then
+ do_missing_arg "$1"
+ fi
+ shift
+ lib="$1"
+ ;;
+ -e | --e | --ex | --exi | --exit)
+ SOTRUSS_EXIT=1
+ ;;
+ --f)
+ do_ambiguous '--from' '--follow'
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ printf >&2 $"%s: unrecognized option '%c%s'\n" sotruss '-' ${1#-}
+ printf >&2 $"Try \`%s --help' or \`%s --usage' for more information.\n" sotruss sotruss
+ exit 1
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+done
+
+export SOTRUSS_FROMLIST
+export SOTRUSS_TOLIST
+export SOTRUSS_OUTNAME
+export SOTRUSS_WHICH
+export SOTRUSS_EXIT
+export LD_AUDIT="$lib"
+
+exec "$@"
diff --git a/REORG.TODO/elf/sprof.c b/REORG.TODO/elf/sprof.c
new file mode 100644
index 0000000000..85c4975360
--- /dev/null
+++ b/REORG.TODO/elf/sprof.c
@@ -0,0 +1,1436 @@
+/* Read and display shared object profiling data.
+ Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <argp.h>
+#include <dlfcn.h>
+#include <elf.h>
+#include <error.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libintl.h>
+#include <locale.h>
+#include <obstack.h>
+#include <search.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <ldsodefs.h>
+#include <sys/gmon.h>
+#include <sys/gmon_out.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+/* Get libc version number. */
+#include "../version.h"
+
+#define PACKAGE _libc_intl_domainname
+
+
+#include <endian.h>
+#if BYTE_ORDER == BIG_ENDIAN
+# define byteorder ELFDATA2MSB
+# define byteorder_name "big-endian"
+#elif BYTE_ORDER == LITTLE_ENDIAN
+# define byteorder ELFDATA2LSB
+# define byteorder_name "little-endian"
+#else
+# error "Unknown BYTE_ORDER " BYTE_ORDER
+# define byteorder ELFDATANONE
+#endif
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+
+extern int __profile_frequency (void);
+
+/* Name and version of program. */
+static void print_version (FILE *stream, struct argp_state *state);
+void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
+
+#define OPT_TEST 1
+
+/* Definitions of arguments for argp functions. */
+static const struct argp_option options[] =
+{
+ { NULL, 0, NULL, 0, N_("Output selection:") },
+ { "call-pairs", 'c', NULL, 0,
+ N_("print list of count paths and their number of use") },
+ { "flat-profile", 'p', NULL, 0,
+ N_("generate flat profile with counts and ticks") },
+ { "graph", 'q', NULL, 0, N_("generate call graph") },
+
+ { "test", OPT_TEST, NULL, OPTION_HIDDEN, NULL },
+ { NULL, 0, NULL, 0, NULL }
+};
+
+/* Short description of program. */
+static const char doc[] = N_("Read and display shared object profiling data.");
+//For bug reporting instructions, please see:\n
+//<http://www.gnu.org/software/libc/bugs.html>.\n");
+
+/* Strings for arguments in help texts. */
+static const char args_doc[] = N_("SHOBJ [PROFDATA]");
+
+/* Prototype for option handler. */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Function to print some extra text in the help message. */
+static char *more_help (int key, const char *text, void *input);
+
+/* Data structure to communicate with argp functions. */
+static struct argp argp =
+{
+ options, parse_opt, args_doc, doc, NULL, more_help
+};
+
+
+/* Operation modes. */
+static enum
+{
+ NONE = 0,
+ FLAT_MODE = 1 << 0,
+ CALL_GRAPH_MODE = 1 << 1,
+ CALL_PAIRS = 1 << 2,
+
+ DEFAULT_MODE = FLAT_MODE | CALL_GRAPH_MODE
+} mode;
+
+/* Nozero for testing. */
+static int do_test;
+
+/* Strcuture describing calls. */
+struct here_fromstruct
+{
+ struct here_cg_arc_record volatile *here;
+ uint16_t link;
+};
+
+/* We define a special type to address the elements of the arc table.
+ This is basically the `gmon_cg_arc_record' format but it includes
+ the room for the tag and it uses real types. */
+struct here_cg_arc_record
+{
+ uintptr_t from_pc;
+ uintptr_t self_pc;
+ uint32_t count;
+} __attribute__ ((packed));
+
+
+struct known_symbol;
+struct arc_list
+{
+ size_t idx;
+ uintmax_t count;
+
+ struct arc_list *next;
+};
+
+static struct obstack ob_list;
+
+
+struct known_symbol
+{
+ const char *name;
+ uintptr_t addr;
+ size_t size;
+ bool weak;
+ bool hidden;
+
+ uintmax_t ticks;
+ uintmax_t calls;
+
+ struct arc_list *froms;
+ struct arc_list *tos;
+};
+
+
+struct shobj
+{
+ const char *name; /* User-provided name. */
+
+ struct link_map *map;
+ const char *dynstrtab; /* Dynamic string table of shared object. */
+ const char *soname; /* Soname of shared object. */
+
+ uintptr_t lowpc;
+ uintptr_t highpc;
+ unsigned long int kcountsize;
+ size_t expected_size; /* Expected size of profiling file. */
+ size_t tossize;
+ size_t fromssize;
+ size_t fromlimit;
+ unsigned int hashfraction;
+ int s_scale;
+
+ void *symbol_map;
+ size_t symbol_mapsize;
+ const ElfW(Sym) *symtab;
+ size_t symtab_size;
+ const char *strtab;
+
+ struct obstack ob_str;
+ struct obstack ob_sym;
+};
+
+
+struct real_gmon_hist_hdr
+{
+ char *low_pc;
+ char *high_pc;
+ int32_t hist_size;
+ int32_t prof_rate;
+ char dimen[15];
+ char dimen_abbrev;
+};
+
+
+struct profdata
+{
+ void *addr;
+ off_t size;
+
+ char *hist;
+ struct real_gmon_hist_hdr *hist_hdr;
+ uint16_t *kcount;
+ uint32_t narcs; /* Number of arcs in toset. */
+ struct here_cg_arc_record *data;
+ uint16_t *tos;
+ struct here_fromstruct *froms;
+};
+
+/* Search tree for symbols. */
+static void *symroot;
+static struct known_symbol **sortsym;
+static size_t symidx;
+static uintmax_t total_ticks;
+
+/* Prototypes for local functions. */
+static struct shobj *load_shobj (const char *name);
+static void unload_shobj (struct shobj *shobj);
+static struct profdata *load_profdata (const char *name, struct shobj *shobj);
+static void unload_profdata (struct profdata *profdata);
+static void count_total_ticks (struct shobj *shobj, struct profdata *profdata);
+static void count_calls (struct shobj *shobj, struct profdata *profdata);
+static void read_symbols (struct shobj *shobj);
+static void add_arcs (struct profdata *profdata);
+static void generate_flat_profile (struct profdata *profdata);
+static void generate_call_graph (struct profdata *profdata);
+static void generate_call_pair_list (struct profdata *profdata);
+
+
+int
+main (int argc, char *argv[])
+{
+ const char *shobj;
+ const char *profdata;
+ struct shobj *shobj_handle;
+ struct profdata *profdata_handle;
+ int remaining;
+
+ setlocale (LC_ALL, "");
+
+ /* Initialize the message catalog. */
+ textdomain (_libc_intl_domainname);
+
+ /* Parse and process arguments. */
+ argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+ if (argc - remaining == 0 || argc - remaining > 2)
+ {
+ /* We need exactly two non-option parameter. */
+ argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
+ program_invocation_short_name);
+ exit (1);
+ }
+
+ /* Get parameters. */
+ shobj = argv[remaining];
+ if (argc - remaining == 2)
+ profdata = argv[remaining + 1];
+ else
+ /* No filename for the profiling data given. We will determine it
+ from the soname of the shobj, later. */
+ profdata = NULL;
+
+ /* First see whether we can load the shared object. */
+ shobj_handle = load_shobj (shobj);
+ if (shobj_handle == NULL)
+ exit (1);
+
+ /* We can now determine the filename for the profiling data, if
+ nececessary. */
+ if (profdata == NULL)
+ {
+ char *newp;
+ const char *soname;
+ size_t soname_len;
+
+ soname = shobj_handle->soname ?: basename (shobj);
+ soname_len = strlen (soname);
+ newp = (char *) alloca (soname_len + sizeof ".profile");
+ stpcpy (mempcpy (newp, soname, soname_len), ".profile");
+ profdata = newp;
+ }
+
+ /* Now see whether the profiling data file matches the given object. */
+ profdata_handle = load_profdata (profdata, shobj_handle);
+ if (profdata_handle == NULL)
+ {
+ unload_shobj (shobj_handle);
+
+ exit (1);
+ }
+
+ read_symbols (shobj_handle);
+
+ /* Count the ticks. */
+ count_total_ticks (shobj_handle, profdata_handle);
+
+ /* Count the calls. */
+ count_calls (shobj_handle, profdata_handle);
+
+ /* Add the arc information. */
+ add_arcs (profdata_handle);
+
+ /* If no mode is specified fall back to the default mode. */
+ if (mode == NONE)
+ mode = DEFAULT_MODE;
+
+ /* Do some work. */
+ if (mode & FLAT_MODE)
+ generate_flat_profile (profdata_handle);
+
+ if (mode & CALL_GRAPH_MODE)
+ generate_call_graph (profdata_handle);
+
+ if (mode & CALL_PAIRS)
+ generate_call_pair_list (profdata_handle);
+
+ /* Free the resources. */
+ unload_shobj (shobj_handle);
+ unload_profdata (profdata_handle);
+
+ return 0;
+}
+
+
+/* Handle program arguments. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'c':
+ mode |= CALL_PAIRS;
+ break;
+ case 'p':
+ mode |= FLAT_MODE;
+ break;
+ case 'q':
+ mode |= CALL_GRAPH_MODE;
+ break;
+ case OPT_TEST:
+ do_test = 1;
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+
+static char *
+more_help (int key, const char *text, void *input)
+{
+ char *tp = NULL;
+ switch (key)
+ {
+ case ARGP_KEY_HELP_EXTRA:
+ /* We print some extra information. */
+ if (asprintf (&tp, gettext ("\
+For bug reporting instructions, please see:\n\
+%s.\n"), REPORT_BUGS_TO) < 0)
+ return NULL;
+ return tp;
+ default:
+ break;
+ }
+ return (char *) text;
+}
+
+
+/* Print the version information. */
+static void
+print_version (FILE *stream, struct argp_state *state)
+{
+ fprintf (stream, "sprof %s%s\n", PKGVERSION, VERSION);
+ fprintf (stream, gettext ("\
+Copyright (C) %s Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions. There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"),
+ "2017");
+ fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
+}
+
+
+/* Note that we must not use `dlopen' etc. The shobj object must not
+ be loaded for use. */
+static struct shobj *
+load_shobj (const char *name)
+{
+ struct link_map *map = NULL;
+ struct shobj *result;
+ ElfW(Addr) mapstart = ~((ElfW(Addr)) 0);
+ ElfW(Addr) mapend = 0;
+ const ElfW(Phdr) *ph;
+ size_t textsize;
+ ElfW(Ehdr) *ehdr;
+ int fd;
+ ElfW(Shdr) *shdr;
+ size_t pagesize = getpagesize ();
+
+ /* Since we use dlopen() we must be prepared to work around the sometimes
+ strange lookup rules for the shared objects. If we have a file foo.so
+ in the current directory and the user specfies foo.so on the command
+ line (without specifying a directory) we should load the file in the
+ current directory even if a normal dlopen() call would read the other
+ file. We do this by adding a directory portion to the name. */
+ if (strchr (name, '/') == NULL)
+ {
+ char *load_name = (char *) alloca (strlen (name) + 3);
+ stpcpy (stpcpy (load_name, "./"), name);
+
+ map = (struct link_map *) dlopen (load_name, RTLD_LAZY | __RTLD_SPROF);
+ }
+ if (map == NULL)
+ {
+ map = (struct link_map *) dlopen (name, RTLD_LAZY | __RTLD_SPROF);
+ if (map == NULL)
+ {
+ error (0, errno, _("failed to load shared object `%s'"), name);
+ return NULL;
+ }
+ }
+
+ /* Prepare the result. */
+ result = (struct shobj *) calloc (1, sizeof (struct shobj));
+ if (result == NULL)
+ {
+ error (0, errno, _("cannot create internal descriptor"));
+ dlclose (map);
+ return NULL;
+ }
+ result->name = name;
+ result->map = map;
+
+ /* Compute the size of the sections which contain program code.
+ This must match the code in dl-profile.c (_dl_start_profile). */
+ for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
+ if (ph->p_type == PT_LOAD && (ph->p_flags & PF_X))
+ {
+ ElfW(Addr) start = (ph->p_vaddr & ~(pagesize - 1));
+ ElfW(Addr) end = ((ph->p_vaddr + ph->p_memsz + pagesize - 1)
+ & ~(pagesize - 1));
+
+ if (start < mapstart)
+ mapstart = start;
+ if (end > mapend)
+ mapend = end;
+ }
+
+ result->lowpc = ROUNDDOWN ((uintptr_t) (mapstart + map->l_addr),
+ HISTFRACTION * sizeof (HISTCOUNTER));
+ result->highpc = ROUNDUP ((uintptr_t) (mapend + map->l_addr),
+ HISTFRACTION * sizeof (HISTCOUNTER));
+ if (do_test)
+ printf ("load addr: %0#*" PRIxPTR "\n"
+ "lower bound PC: %0#*" PRIxPTR "\n"
+ "upper bound PC: %0#*" PRIxPTR "\n",
+ __ELF_NATIVE_CLASS == 32 ? 10 : 18, map->l_addr,
+ __ELF_NATIVE_CLASS == 32 ? 10 : 18, result->lowpc,
+ __ELF_NATIVE_CLASS == 32 ? 10 : 18, result->highpc);
+
+ textsize = result->highpc - result->lowpc;
+ result->kcountsize = textsize / HISTFRACTION;
+ result->hashfraction = HASHFRACTION;
+ if (do_test)
+ printf ("hashfraction = %d\ndivider = %Zu\n",
+ result->hashfraction,
+ result->hashfraction * sizeof (struct here_fromstruct));
+ result->tossize = textsize / HASHFRACTION;
+ result->fromlimit = textsize * ARCDENSITY / 100;
+ if (result->fromlimit < MINARCS)
+ result->fromlimit = MINARCS;
+ if (result->fromlimit > MAXARCS)
+ result->fromlimit = MAXARCS;
+ result->fromssize = result->fromlimit * sizeof (struct here_fromstruct);
+
+ result->expected_size = (sizeof (struct gmon_hdr)
+ + 4 + sizeof (struct gmon_hist_hdr)
+ + result->kcountsize
+ + 4 + 4
+ + (result->fromssize
+ * sizeof (struct here_cg_arc_record)));
+
+ if (do_test)
+ printf ("expected size: %Zd\n", result->expected_size);
+
+#define SCALE_1_TO_1 0x10000L
+
+ if (result->kcountsize < result->highpc - result->lowpc)
+ {
+ size_t range = result->highpc - result->lowpc;
+ size_t quot = range / result->kcountsize;
+
+ if (quot >= SCALE_1_TO_1)
+ result->s_scale = 1;
+ else if (quot >= SCALE_1_TO_1 / 256)
+ result->s_scale = SCALE_1_TO_1 / quot;
+ else if (range > ULONG_MAX / 256)
+ result->s_scale = ((SCALE_1_TO_1 * 256)
+ / (range / (result->kcountsize / 256)));
+ else
+ result->s_scale = ((SCALE_1_TO_1 * 256)
+ / ((range * 256) / result->kcountsize));
+ }
+ else
+ result->s_scale = SCALE_1_TO_1;
+
+ if (do_test)
+ printf ("s_scale: %d\n", result->s_scale);
+
+ /* Determine the dynamic string table. */
+ if (map->l_info[DT_STRTAB] == NULL)
+ result->dynstrtab = NULL;
+ else
+ result->dynstrtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
+ if (do_test)
+ printf ("string table: %p\n", result->dynstrtab);
+
+ /* Determine the soname. */
+ if (map->l_info[DT_SONAME] == NULL)
+ result->soname = NULL;
+ else
+ result->soname = result->dynstrtab + map->l_info[DT_SONAME]->d_un.d_val;
+ if (do_test && result->soname != NULL)
+ printf ("soname: %s\n", result->soname);
+
+ /* Now we have to load the symbol table.
+
+ First load the section header table. */
+ ehdr = (ElfW(Ehdr) *) map->l_map_start;
+
+ /* Make sure we are on the right party. */
+ if (ehdr->e_shentsize != sizeof (ElfW(Shdr)))
+ abort ();
+
+ /* And we need the shared object file descriptor again. */
+ fd = open (map->l_name, O_RDONLY);
+ if (fd == -1)
+ /* Dooh, this really shouldn't happen. We know the file is available. */
+ error (EXIT_FAILURE, errno, _("Reopening shared object `%s' failed"),
+ map->l_name);
+
+ /* Map the section header. */
+ size_t size = ehdr->e_shnum * sizeof (ElfW(Shdr));
+ shdr = (ElfW(Shdr) *) alloca (size);
+ if (pread (fd, shdr, size, ehdr->e_shoff) != size)
+ error (EXIT_FAILURE, errno, _("reading of section headers failed"));
+
+ /* Get the section header string table. */
+ char *shstrtab = (char *) alloca (shdr[ehdr->e_shstrndx].sh_size);
+ if (pread (fd, shstrtab, shdr[ehdr->e_shstrndx].sh_size,
+ shdr[ehdr->e_shstrndx].sh_offset)
+ != shdr[ehdr->e_shstrndx].sh_size)
+ error (EXIT_FAILURE, errno,
+ _("reading of section header string table failed"));
+
+ /* Search for the ".symtab" section. */
+ ElfW(Shdr) *symtab_entry = NULL;
+ ElfW(Shdr) *debuglink_entry = NULL;
+ for (int idx = 0; idx < ehdr->e_shnum; ++idx)
+ if (shdr[idx].sh_type == SHT_SYMTAB
+ && strcmp (shstrtab + shdr[idx].sh_name, ".symtab") == 0)
+ {
+ symtab_entry = &shdr[idx];
+ break;
+ }
+ else if (shdr[idx].sh_type == SHT_PROGBITS
+ && strcmp (shstrtab + shdr[idx].sh_name, ".gnu_debuglink") == 0)
+ debuglink_entry = &shdr[idx];
+
+ /* Get the file name of the debuginfo file if necessary. */
+ int symfd = fd;
+ if (symtab_entry == NULL && debuglink_entry != NULL)
+ {
+ size_t size = debuglink_entry->sh_size;
+ char *debuginfo_fname = (char *) alloca (size + 1);
+ debuginfo_fname[size] = '\0';
+ if (pread (fd, debuginfo_fname, size, debuglink_entry->sh_offset)
+ != size)
+ {
+ fprintf (stderr, _("*** Cannot read debuginfo file name: %m\n"));
+ goto no_debuginfo;
+ }
+
+ static const char procpath[] = "/proc/self/fd/%d";
+ char origprocname[sizeof (procpath) + sizeof (int) * 3];
+ snprintf (origprocname, sizeof (origprocname), procpath, fd);
+ char *origlink = (char *) alloca (PATH_MAX);
+ ssize_t n = readlink (origprocname, origlink, PATH_MAX - 1);
+ if (n == -1)
+ goto no_debuginfo;
+ origlink[n] = '\0';
+
+ /* Try to find the actual file. There are three places:
+ 1. the same directory the DSO is in
+ 2. in a subdir named .debug of the directory the DSO is in
+ 3. in /usr/lib/debug/PATH-OF-DSO
+ */
+ char *realname = canonicalize_file_name (origlink);
+ char *cp = NULL;
+ if (realname == NULL || (cp = strrchr (realname, '/')) == NULL)
+ error (EXIT_FAILURE, errno, _("cannot determine file name"));
+
+ /* Leave the last slash in place. */
+ *++cp = '\0';
+
+ /* First add the debuginfo file name only. */
+ static const char usrlibdebug[]= "/usr/lib/debug/";
+ char *workbuf = (char *) alloca (sizeof (usrlibdebug)
+ + (cp - realname)
+ + strlen (debuginfo_fname));
+ strcpy (stpcpy (workbuf, realname), debuginfo_fname);
+
+ int fd2 = open (workbuf, O_RDONLY);
+ if (fd2 == -1)
+ {
+ strcpy (stpcpy (stpcpy (workbuf, realname), ".debug/"),
+ debuginfo_fname);
+ fd2 = open (workbuf, O_RDONLY);
+ if (fd2 == -1)
+ {
+ strcpy (stpcpy (stpcpy (workbuf, usrlibdebug), realname),
+ debuginfo_fname);
+ fd2 = open (workbuf, O_RDONLY);
+ }
+ }
+
+ if (fd2 != -1)
+ {
+ ElfW(Ehdr) ehdr2;
+
+ /* Read the ELF header. */
+ if (pread (fd2, &ehdr2, sizeof (ehdr2), 0) != sizeof (ehdr2))
+ error (EXIT_FAILURE, errno,
+ _("reading of ELF header failed"));
+
+ /* Map the section header. */
+ size_t size = ehdr2.e_shnum * sizeof (ElfW(Shdr));
+ ElfW(Shdr) *shdr2 = (ElfW(Shdr) *) alloca (size);
+ if (pread (fd2, shdr2, size, ehdr2.e_shoff) != size)
+ error (EXIT_FAILURE, errno,
+ _("reading of section headers failed"));
+
+ /* Get the section header string table. */
+ shstrtab = (char *) alloca (shdr2[ehdr2.e_shstrndx].sh_size);
+ if (pread (fd2, shstrtab, shdr2[ehdr2.e_shstrndx].sh_size,
+ shdr2[ehdr2.e_shstrndx].sh_offset)
+ != shdr2[ehdr2.e_shstrndx].sh_size)
+ error (EXIT_FAILURE, errno,
+ _("reading of section header string table failed"));
+
+ /* Search for the ".symtab" section. */
+ for (int idx = 0; idx < ehdr2.e_shnum; ++idx)
+ if (shdr2[idx].sh_type == SHT_SYMTAB
+ && strcmp (shstrtab + shdr2[idx].sh_name, ".symtab") == 0)
+ {
+ symtab_entry = &shdr2[idx];
+ shdr = shdr2;
+ symfd = fd2;
+ break;
+ }
+
+ if (fd2 != symfd)
+ close (fd2);
+ }
+ }
+
+ no_debuginfo:
+ if (symtab_entry == NULL)
+ {
+ fprintf (stderr, _("\
+*** The file `%s' is stripped: no detailed analysis possible\n"),
+ name);
+ result->symtab = NULL;
+ result->strtab = NULL;
+ }
+ else
+ {
+ ElfW(Off) min_offset, max_offset;
+ ElfW(Shdr) *strtab_entry;
+
+ strtab_entry = &shdr[symtab_entry->sh_link];
+
+ /* Find the minimum and maximum offsets that include both the symbol
+ table and the string table. */
+ if (symtab_entry->sh_offset < strtab_entry->sh_offset)
+ {
+ min_offset = symtab_entry->sh_offset & ~(pagesize - 1);
+ max_offset = strtab_entry->sh_offset + strtab_entry->sh_size;
+ }
+ else
+ {
+ min_offset = strtab_entry->sh_offset & ~(pagesize - 1);
+ max_offset = symtab_entry->sh_offset + symtab_entry->sh_size;
+ }
+
+ result->symbol_map = mmap (NULL, max_offset - min_offset,
+ PROT_READ, MAP_SHARED|MAP_FILE, symfd,
+ min_offset);
+ if (result->symbol_map == MAP_FAILED)
+ error (EXIT_FAILURE, errno, _("failed to load symbol data"));
+
+ result->symtab
+ = (const ElfW(Sym) *) ((const char *) result->symbol_map
+ + (symtab_entry->sh_offset - min_offset));
+ result->symtab_size = symtab_entry->sh_size;
+ result->strtab = ((const char *) result->symbol_map
+ + (strtab_entry->sh_offset - min_offset));
+ result->symbol_mapsize = max_offset - min_offset;
+ }
+
+ /* Free the descriptor for the shared object. */
+ close (fd);
+ if (symfd != fd)
+ close (symfd);
+
+ return result;
+}
+
+
+static void
+unload_shobj (struct shobj *shobj)
+{
+ munmap (shobj->symbol_map, shobj->symbol_mapsize);
+ dlclose (shobj->map);
+}
+
+
+static struct profdata *
+load_profdata (const char *name, struct shobj *shobj)
+{
+ struct profdata *result;
+ int fd;
+ struct stat64 st;
+ void *addr;
+ uint32_t *narcsp;
+ size_t fromlimit;
+ struct here_cg_arc_record *data;
+ struct here_fromstruct *froms;
+ uint16_t *tos;
+ size_t fromidx;
+ size_t idx;
+
+ fd = open (name, O_RDONLY);
+ if (fd == -1)
+ {
+ char *ext_name;
+
+ if (errno != ENOENT || strchr (name, '/') != NULL)
+ /* The file exists but we are not allowed to read it or the
+ file does not exist and the name includes a path
+ specification.. */
+ return NULL;
+
+ /* A file with the given name does not exist in the current
+ directory, try it in the default location where the profiling
+ files are created. */
+ ext_name = (char *) alloca (strlen (name) + sizeof "/var/tmp/");
+ stpcpy (stpcpy (ext_name, "/var/tmp/"), name);
+ name = ext_name;
+
+ fd = open (ext_name, O_RDONLY);
+ if (fd == -1)
+ {
+ /* Even this file does not exist. */
+ error (0, errno, _("cannot load profiling data"));
+ return NULL;
+ }
+ }
+
+ /* We have found the file, now make sure it is the right one for the
+ data file. */
+ if (fstat64 (fd, &st) < 0)
+ {
+ error (0, errno, _("while stat'ing profiling data file"));
+ close (fd);
+ return NULL;
+ }
+
+ if ((size_t) st.st_size != shobj->expected_size)
+ {
+ error (0, 0,
+ _("profiling data file `%s' does not match shared object `%s'"),
+ name, shobj->name);
+ close (fd);
+ return NULL;
+ }
+
+ /* The data file is most probably the right one for our shared
+ object. Map it now. */
+ addr = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
+ if (addr == MAP_FAILED)
+ {
+ error (0, errno, _("failed to mmap the profiling data file"));
+ close (fd);
+ return NULL;
+ }
+
+ /* We don't need the file desriptor anymore. */
+ if (close (fd) < 0)
+ {
+ error (0, errno, _("error while closing the profiling data file"));
+ munmap (addr, st.st_size);
+ return NULL;
+ }
+
+ /* Prepare the result. */
+ result = (struct profdata *) calloc (1, sizeof (struct profdata));
+ if (result == NULL)
+ {
+ error (0, errno, _("cannot create internal descriptor"));
+ munmap (addr, st.st_size);
+ return NULL;
+ }
+
+ /* Store the address and size so that we can later free the resources. */
+ result->addr = addr;
+ result->size = st.st_size;
+
+ /* Pointer to data after the header. */
+ result->hist = (char *) ((struct gmon_hdr *) addr + 1);
+ result->hist_hdr = (struct real_gmon_hist_hdr *) ((char *) result->hist
+ + sizeof (uint32_t));
+ result->kcount = (uint16_t *) ((char *) result->hist + sizeof (uint32_t)
+ + sizeof (struct real_gmon_hist_hdr));
+
+ /* Compute pointer to array of the arc information. */
+ narcsp = (uint32_t *) ((char *) result->kcount + shobj->kcountsize
+ + sizeof (uint32_t));
+ result->narcs = *narcsp;
+ result->data = (struct here_cg_arc_record *) ((char *) narcsp
+ + sizeof (uint32_t));
+
+ /* Create the gmon_hdr we expect or write. */
+ struct real_gmon_hdr
+ {
+ char cookie[4];
+ int32_t version;
+ char spare[3 * 4];
+ } gmon_hdr;
+ if (sizeof (gmon_hdr) != sizeof (struct gmon_hdr)
+ || (offsetof (struct real_gmon_hdr, cookie)
+ != offsetof (struct gmon_hdr, cookie))
+ || (offsetof (struct real_gmon_hdr, version)
+ != offsetof (struct gmon_hdr, version)))
+ abort ();
+
+ memcpy (&gmon_hdr.cookie[0], GMON_MAGIC, sizeof (gmon_hdr.cookie));
+ gmon_hdr.version = GMON_SHOBJ_VERSION;
+ memset (gmon_hdr.spare, '\0', sizeof (gmon_hdr.spare));
+
+ /* Create the hist_hdr we expect or write. */
+ struct real_gmon_hist_hdr hist_hdr;
+ if (sizeof (hist_hdr) != sizeof (struct gmon_hist_hdr)
+ || (offsetof (struct real_gmon_hist_hdr, low_pc)
+ != offsetof (struct gmon_hist_hdr, low_pc))
+ || (offsetof (struct real_gmon_hist_hdr, high_pc)
+ != offsetof (struct gmon_hist_hdr, high_pc))
+ || (offsetof (struct real_gmon_hist_hdr, hist_size)
+ != offsetof (struct gmon_hist_hdr, hist_size))
+ || (offsetof (struct real_gmon_hist_hdr, prof_rate)
+ != offsetof (struct gmon_hist_hdr, prof_rate))
+ || (offsetof (struct real_gmon_hist_hdr, dimen)
+ != offsetof (struct gmon_hist_hdr, dimen))
+ || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev)
+ != offsetof (struct gmon_hist_hdr, dimen_abbrev)))
+ abort ();
+
+ hist_hdr.low_pc = (char *) shobj->lowpc - shobj->map->l_addr;
+ hist_hdr.high_pc = (char *) shobj->highpc - shobj->map->l_addr;
+ if (do_test)
+ printf ("low_pc = %p\nhigh_pc = %p\n", hist_hdr.low_pc, hist_hdr.high_pc);
+ hist_hdr.hist_size = shobj->kcountsize / sizeof (HISTCOUNTER);
+ hist_hdr.prof_rate = __profile_frequency ();
+ strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen));
+ hist_hdr.dimen_abbrev = 's';
+
+ /* Test whether the header of the profiling data is ok. */
+ if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0
+ || *(uint32_t *) result->hist != GMON_TAG_TIME_HIST
+ || memcmp (result->hist_hdr, &hist_hdr,
+ sizeof (struct gmon_hist_hdr)) != 0
+ || narcsp[-1] != GMON_TAG_CG_ARC)
+ {
+ error (0, 0, _("`%s' is no correct profile data file for `%s'"),
+ name, shobj->name);
+ if (do_test)
+ {
+ if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0)
+ puts ("gmon_hdr differs");
+ if (*(uint32_t *) result->hist != GMON_TAG_TIME_HIST)
+ puts ("result->hist differs");
+ if (memcmp (result->hist_hdr, &hist_hdr,
+ sizeof (struct gmon_hist_hdr)) != 0)
+ puts ("hist_hdr differs");
+ if (narcsp[-1] != GMON_TAG_CG_ARC)
+ puts ("narcsp[-1] differs");
+ }
+ free (result);
+ munmap (addr, st.st_size);
+ return NULL;
+ }
+
+ /* We are pretty sure now that this is a correct input file. Set up
+ the remaining information in the result structure and return. */
+ result->tos = (uint16_t *) calloc (shobj->tossize + shobj->fromssize, 1);
+ if (result->tos == NULL)
+ {
+ error (0, errno, _("cannot create internal descriptor"));
+ munmap (addr, st.st_size);
+ free (result);
+ return NULL;
+ }
+
+ result->froms = (struct here_fromstruct *) ((char *) result->tos
+ + shobj->tossize);
+ fromidx = 0;
+
+ /* Now we have to process all the arc count entries. */
+ fromlimit = shobj->fromlimit;
+ data = result->data;
+ froms = result->froms;
+ tos = result->tos;
+ for (idx = 0; idx < MIN (*narcsp, fromlimit); ++idx)
+ {
+ size_t to_index;
+ size_t newfromidx;
+ to_index = (data[idx].self_pc / (shobj->hashfraction * sizeof (*tos)));
+ newfromidx = fromidx++;
+ froms[newfromidx].here = &data[idx];
+ froms[newfromidx].link = tos[to_index];
+ tos[to_index] = newfromidx;
+ }
+
+ return result;
+}
+
+
+static void
+unload_profdata (struct profdata *profdata)
+{
+ free (profdata->tos);
+ munmap (profdata->addr, profdata->size);
+ free (profdata);
+}
+
+
+static void
+count_total_ticks (struct shobj *shobj, struct profdata *profdata)
+{
+ volatile uint16_t *kcount = profdata->kcount;
+ size_t maxkidx = shobj->kcountsize;
+ size_t factor = 2 * (65536 / shobj->s_scale);
+ size_t kidx = 0;
+ size_t sidx = 0;
+
+ while (sidx < symidx)
+ {
+ uintptr_t start = sortsym[sidx]->addr;
+ uintptr_t end = start + sortsym[sidx]->size;
+
+ while (kidx < maxkidx && factor * kidx < start)
+ ++kidx;
+ if (kidx == maxkidx)
+ break;
+
+ while (kidx < maxkidx && factor * kidx < end)
+ sortsym[sidx]->ticks += kcount[kidx++];
+ if (kidx == maxkidx)
+ break;
+
+ total_ticks += sortsym[sidx++]->ticks;
+ }
+}
+
+
+static size_t
+find_symbol (uintptr_t addr)
+{
+ size_t sidx = 0;
+
+ while (sidx < symidx)
+ {
+ uintptr_t start = sortsym[sidx]->addr;
+ uintptr_t end = start + sortsym[sidx]->size;
+
+ if (addr >= start && addr < end)
+ return sidx;
+
+ if (addr < start)
+ break;
+
+ ++sidx;
+ }
+
+ return (size_t) -1l;
+}
+
+
+static void
+count_calls (struct shobj *shobj, struct profdata *profdata)
+{
+ struct here_cg_arc_record *data = profdata->data;
+ uint32_t narcs = profdata->narcs;
+ uint32_t cnt;
+
+ for (cnt = 0; cnt < narcs; ++cnt)
+ {
+ uintptr_t here = data[cnt].self_pc;
+ size_t symbol_idx;
+
+ /* Find the symbol for this address. */
+ symbol_idx = find_symbol (here);
+ if (symbol_idx != (size_t) -1l)
+ sortsym[symbol_idx]->calls += data[cnt].count;
+ }
+}
+
+
+static int
+symorder (const void *o1, const void *o2)
+{
+ const struct known_symbol *p1 = (const struct known_symbol *) o1;
+ const struct known_symbol *p2 = (const struct known_symbol *) o2;
+
+ return p1->addr - p2->addr;
+}
+
+
+static void
+printsym (const void *node, VISIT value, int level)
+{
+ if (value == leaf || value == postorder)
+ sortsym[symidx++] = *(struct known_symbol **) node;
+}
+
+
+static void
+read_symbols (struct shobj *shobj)
+{
+ int n = 0;
+
+ /* Initialize the obstacks. */
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+ obstack_init (&shobj->ob_str);
+ obstack_init (&shobj->ob_sym);
+ obstack_init (&ob_list);
+
+ /* Process the symbols. */
+ if (shobj->symtab != NULL)
+ {
+ const ElfW(Sym) *sym = shobj->symtab;
+ const ElfW(Sym) *sym_end
+ = (const ElfW(Sym) *) ((const char *) sym + shobj->symtab_size);
+ for (; sym < sym_end; sym++)
+ if ((ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
+ || ELFW(ST_TYPE) (sym->st_info) == STT_NOTYPE)
+ && sym->st_size != 0)
+ {
+ struct known_symbol **existp;
+ struct known_symbol *newsym
+ = (struct known_symbol *) obstack_alloc (&shobj->ob_sym,
+ sizeof (*newsym));
+ if (newsym == NULL)
+ error (EXIT_FAILURE, errno, _("cannot allocate symbol data"));
+
+ newsym->name = &shobj->strtab[sym->st_name];
+ newsym->addr = sym->st_value;
+ newsym->size = sym->st_size;
+ newsym->weak = ELFW(ST_BIND) (sym->st_info) == STB_WEAK;
+ newsym->hidden = (ELFW(ST_VISIBILITY) (sym->st_other)
+ != STV_DEFAULT);
+ newsym->ticks = 0;
+ newsym->calls = 0;
+
+ existp = tfind (newsym, &symroot, symorder);
+ if (existp == NULL)
+ {
+ /* New function. */
+ tsearch (newsym, &symroot, symorder);
+ ++n;
+ }
+ else
+ {
+ /* The function is already defined. See whether we have
+ a better name here. */
+ if (((*existp)->hidden && !newsym->hidden)
+ || ((*existp)->name[0] == '_' && newsym->name[0] != '_')
+ || ((*existp)->name[0] != '_' && newsym->name[0] != '_'
+ && ((*existp)->weak && !newsym->weak)))
+ *existp = newsym;
+ else
+ /* We don't need the allocated memory. */
+ obstack_free (&shobj->ob_sym, newsym);
+ }
+ }
+ }
+ else
+ {
+ /* Blarg, the binary is stripped. We have to rely on the
+ information contained in the dynamic section of the object. */
+ const ElfW(Sym) *symtab = (ElfW(Sym) *) D_PTR (shobj->map,
+ l_info[DT_SYMTAB]);
+ const char *strtab = (const char *) D_PTR (shobj->map,
+ l_info[DT_STRTAB]);
+
+ /* We assume that the string table follows the symbol table,
+ because there is no way in ELF to know the size of the
+ dynamic symbol table without looking at the section headers. */
+ while ((void *) symtab < (void *) strtab)
+ {
+ if ((ELFW(ST_TYPE)(symtab->st_info) == STT_FUNC
+ || ELFW(ST_TYPE)(symtab->st_info) == STT_NOTYPE)
+ && symtab->st_size != 0)
+ {
+ struct known_symbol *newsym;
+ struct known_symbol **existp;
+
+ newsym =
+ (struct known_symbol *) obstack_alloc (&shobj->ob_sym,
+ sizeof (*newsym));
+ if (newsym == NULL)
+ error (EXIT_FAILURE, errno, _("cannot allocate symbol data"));
+
+ newsym->name = &strtab[symtab->st_name];
+ newsym->addr = symtab->st_value;
+ newsym->size = symtab->st_size;
+ newsym->weak = ELFW(ST_BIND) (symtab->st_info) == STB_WEAK;
+ newsym->hidden = (ELFW(ST_VISIBILITY) (symtab->st_other)
+ != STV_DEFAULT);
+ newsym->ticks = 0;
+ newsym->froms = NULL;
+ newsym->tos = NULL;
+
+ existp = tfind (newsym, &symroot, symorder);
+ if (existp == NULL)
+ {
+ /* New function. */
+ tsearch (newsym, &symroot, symorder);
+ ++n;
+ }
+ else
+ {
+ /* The function is already defined. See whether we have
+ a better name here. */
+ if (((*existp)->hidden && !newsym->hidden)
+ || ((*existp)->name[0] == '_' && newsym->name[0] != '_')
+ || ((*existp)->name[0] != '_' && newsym->name[0] != '_'
+ && ((*existp)->weak && !newsym->weak)))
+ *existp = newsym;
+ else
+ /* We don't need the allocated memory. */
+ obstack_free (&shobj->ob_sym, newsym);
+ }
+ }
+
+ ++symtab;
+ }
+ }
+
+ sortsym = malloc (n * sizeof (struct known_symbol *));
+ if (sortsym == NULL)
+ abort ();
+
+ twalk (symroot, printsym);
+}
+
+
+static void
+add_arcs (struct profdata *profdata)
+{
+ uint32_t narcs = profdata->narcs;
+ struct here_cg_arc_record *data = profdata->data;
+ uint32_t cnt;
+
+ for (cnt = 0; cnt < narcs; ++cnt)
+ {
+ /* First add the incoming arc. */
+ size_t sym_idx = find_symbol (data[cnt].self_pc);
+
+ if (sym_idx != (size_t) -1l)
+ {
+ struct known_symbol *sym = sortsym[sym_idx];
+ struct arc_list *runp = sym->froms;
+
+ while (runp != NULL
+ && ((data[cnt].from_pc == 0 && runp->idx != (size_t) -1l)
+ || (data[cnt].from_pc != 0
+ && (runp->idx == (size_t) -1l
+ || data[cnt].from_pc < sortsym[runp->idx]->addr
+ || (data[cnt].from_pc
+ >= (sortsym[runp->idx]->addr
+ + sortsym[runp->idx]->size))))))
+ runp = runp->next;
+
+ if (runp == NULL)
+ {
+ /* We need a new entry. */
+ struct arc_list *newp = (struct arc_list *)
+ obstack_alloc (&ob_list, sizeof (struct arc_list));
+
+ if (data[cnt].from_pc == 0)
+ newp->idx = (size_t) -1l;
+ else
+ newp->idx = find_symbol (data[cnt].from_pc);
+ newp->count = data[cnt].count;
+ newp->next = sym->froms;
+ sym->froms = newp;
+ }
+ else
+ /* Increment the counter for the found entry. */
+ runp->count += data[cnt].count;
+ }
+
+ /* Now add it to the appropriate outgoing list. */
+ sym_idx = find_symbol (data[cnt].from_pc);
+ if (sym_idx != (size_t) -1l)
+ {
+ struct known_symbol *sym = sortsym[sym_idx];
+ struct arc_list *runp = sym->tos;
+
+ while (runp != NULL
+ && (runp->idx == (size_t) -1l
+ || data[cnt].self_pc < sortsym[runp->idx]->addr
+ || data[cnt].self_pc >= (sortsym[runp->idx]->addr
+ + sortsym[runp->idx]->size)))
+ runp = runp->next;
+
+ if (runp == NULL)
+ {
+ /* We need a new entry. */
+ struct arc_list *newp = (struct arc_list *)
+ obstack_alloc (&ob_list, sizeof (struct arc_list));
+
+ newp->idx = find_symbol (data[cnt].self_pc);
+ newp->count = data[cnt].count;
+ newp->next = sym->tos;
+ sym->tos = newp;
+ }
+ else
+ /* Increment the counter for the found entry. */
+ runp->count += data[cnt].count;
+ }
+ }
+}
+
+
+static int
+countorder (const void *p1, const void *p2)
+{
+ struct known_symbol *s1 = (struct known_symbol *) p1;
+ struct known_symbol *s2 = (struct known_symbol *) p2;
+
+ if (s1->ticks != s2->ticks)
+ return (int) (s2->ticks - s1->ticks);
+
+ if (s1->calls != s2->calls)
+ return (int) (s2->calls - s1->calls);
+
+ return strcmp (s1->name, s2->name);
+}
+
+
+static double tick_unit;
+static uintmax_t cumu_ticks;
+
+static void
+printflat (const void *node, VISIT value, int level)
+{
+ if (value == leaf || value == postorder)
+ {
+ struct known_symbol *s = *(struct known_symbol **) node;
+
+ cumu_ticks += s->ticks;
+
+ printf ("%6.2f%10.2f%9.2f%9" PRIdMAX "%9.2f %s\n",
+ total_ticks ? (100.0 * s->ticks) / total_ticks : 0.0,
+ tick_unit * cumu_ticks,
+ tick_unit * s->ticks,
+ s->calls,
+ s->calls ? (s->ticks * 1000000) * tick_unit / s->calls : 0,
+ /* FIXME: don't know about called functions. */
+ s->name);
+ }
+}
+
+
+/* ARGUSED */
+static void
+freenoop (void *p)
+{
+}
+
+
+static void
+generate_flat_profile (struct profdata *profdata)
+{
+ size_t n;
+ void *data = NULL;
+
+ tick_unit = 1.0 / profdata->hist_hdr->prof_rate;
+
+ printf ("Flat profile:\n\n"
+ "Each sample counts as %g %s.\n",
+ tick_unit, profdata->hist_hdr->dimen);
+ fputs (" % cumulative self self total\n"
+ " time seconds seconds calls us/call us/call name\n",
+ stdout);
+
+ for (n = 0; n < symidx; ++n)
+ if (sortsym[n]->calls != 0 || sortsym[n]->ticks != 0)
+ tsearch (sortsym[n], &data, countorder);
+
+ twalk (data, printflat);
+
+ tdestroy (data, freenoop);
+}
+
+
+static void
+generate_call_graph (struct profdata *profdata)
+{
+ size_t cnt;
+
+ puts ("\nindex % time self children called name\n");
+
+ for (cnt = 0; cnt < symidx; ++cnt)
+ if (sortsym[cnt]->froms != NULL || sortsym[cnt]->tos != NULL)
+ {
+ struct arc_list *runp;
+ size_t n;
+
+ /* First print the from-information. */
+ runp = sortsym[cnt]->froms;
+ while (runp != NULL)
+ {
+ printf (" %8.2f%8.2f%9" PRIdMAX "/%-9" PRIdMAX " %s",
+ (runp->idx != (size_t) -1l
+ ? sortsym[runp->idx]->ticks * tick_unit : 0.0),
+ 0.0, /* FIXME: what's time for the children, recursive */
+ runp->count, sortsym[cnt]->calls,
+ (runp->idx != (size_t) -1l ?
+ sortsym[runp->idx]->name : "<UNKNOWN>"));
+
+ if (runp->idx != (size_t) -1l)
+ printf (" [%Zd]", runp->idx);
+ putchar_unlocked ('\n');
+
+ runp = runp->next;
+ }
+
+ /* Info about the function itself. */
+ n = printf ("[%Zu]", cnt);
+ printf ("%*s%5.1f%8.2f%8.2f%9" PRIdMAX " %s [%Zd]\n",
+ (int) (7 - n), " ",
+ total_ticks ? (100.0 * sortsym[cnt]->ticks) / total_ticks : 0,
+ sortsym[cnt]->ticks * tick_unit,
+ 0.0, /* FIXME: what's time for the children, recursive */
+ sortsym[cnt]->calls,
+ sortsym[cnt]->name, cnt);
+
+ /* Info about the functions this function calls. */
+ runp = sortsym[cnt]->tos;
+ while (runp != NULL)
+ {
+ printf (" %8.2f%8.2f%9" PRIdMAX "/",
+ (runp->idx != (size_t) -1l
+ ? sortsym[runp->idx]->ticks * tick_unit : 0.0),
+ 0.0, /* FIXME: what's time for the children, recursive */
+ runp->count);
+
+ if (runp->idx != (size_t) -1l)
+ printf ("%-9" PRIdMAX " %s [%Zd]\n",
+ sortsym[runp->idx]->calls,
+ sortsym[runp->idx]->name,
+ runp->idx);
+ else
+ fputs ("??? <UNKNOWN>\n\n", stdout);
+
+ runp = runp->next;
+ }
+
+ fputs ("-----------------------------------------------\n", stdout);
+ }
+}
+
+
+static void
+generate_call_pair_list (struct profdata *profdata)
+{
+ size_t cnt;
+
+ for (cnt = 0; cnt < symidx; ++cnt)
+ if (sortsym[cnt]->froms != NULL || sortsym[cnt]->tos != NULL)
+ {
+ struct arc_list *runp;
+
+ /* First print the incoming arcs. */
+ runp = sortsym[cnt]->froms;
+ while (runp != NULL)
+ {
+ if (runp->idx == (size_t) -1l)
+ printf ("\
+<UNKNOWN> %-34s %9" PRIdMAX "\n",
+ sortsym[cnt]->name, runp->count);
+ runp = runp->next;
+ }
+
+ /* Next the outgoing arcs. */
+ runp = sortsym[cnt]->tos;
+ while (runp != NULL)
+ {
+ printf ("%-34s %-34s %9" PRIdMAX "\n",
+ sortsym[cnt]->name,
+ (runp->idx != (size_t) -1l
+ ? sortsym[runp->idx]->name : "<UNKNOWN>"),
+ runp->count);
+ runp = runp->next;
+ }
+ }
+}
diff --git a/REORG.TODO/elf/static-stubs.c b/REORG.TODO/elf/static-stubs.c
new file mode 100644
index 0000000000..f81d5b792b
--- /dev/null
+++ b/REORG.TODO/elf/static-stubs.c
@@ -0,0 +1,46 @@
+/* Stub implementations of functions to link into statically linked
+ programs without needing libgcc_eh.
+ Copyright (C) 2012-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Avoid backtrace (and so _Unwind_Backtrace) dependencies from
+ sysdeps/unix/sysv/linux/libc_fatal.c. */
+#include <sysdeps/posix/libc_fatal.c>
+
+#include <stdlib.h>
+#include <unwind.h>
+
+/* These programs do not use thread cancellation, so _Unwind_Resume
+ and the personality routine are never actually called. */
+
+void
+_Unwind_Resume (struct _Unwind_Exception *exc __attribute__ ((unused)))
+{
+ abort ();
+}
+
+_Unwind_Reason_Code
+__gcc_personality_v0 (int version __attribute__ ((unused)),
+ _Unwind_Action actions __attribute__ ((unused)),
+ _Unwind_Exception_Class exception_class
+ __attribute__ ((unused)),
+ struct _Unwind_Exception *ue_header
+ __attribute__ ((unused)),
+ struct _Unwind_Context *context __attribute__ ((unused)))
+{
+ abort ();
+}
diff --git a/REORG.TODO/elf/testobj.h b/REORG.TODO/elf/testobj.h
new file mode 100644
index 0000000000..1707ae340e
--- /dev/null
+++ b/REORG.TODO/elf/testobj.h
@@ -0,0 +1,28 @@
+extern int preload (int a);
+
+extern int foo (int);
+
+extern int obj1func1 (int);
+
+extern int obj1func2 (int);
+
+extern int obj2func1 (int);
+
+extern int obj2func2 (int);
+
+extern int obj3func1 (int);
+
+extern int obj3func2 (int);
+
+extern int obj4func1 (int);
+
+extern int obj4func2 (int);
+
+extern int obj5func1 (int);
+
+extern int obj5func2 (int);
+
+extern int obj6func1 (int);
+
+extern int obj6func2 (int);
+
diff --git a/REORG.TODO/elf/testobj1.c b/REORG.TODO/elf/testobj1.c
new file mode 100644
index 0000000000..5ab20efd62
--- /dev/null
+++ b/REORG.TODO/elf/testobj1.c
@@ -0,0 +1,25 @@
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include "testobj.h"
+
+int
+obj1func1 (int a __attribute__ ((unused)))
+{
+ return 42;
+}
+
+int
+obj1func2 (int a)
+{
+ return foo (a) + 10;
+}
+
+int
+preload (int a)
+{
+ int (*fp) (int) = dlsym (RTLD_NEXT, "preload");
+ if (fp != NULL)
+ return fp (a) + 10;
+ return 10;
+}
diff --git a/REORG.TODO/elf/testobj1_1.c b/REORG.TODO/elf/testobj1_1.c
new file mode 100644
index 0000000000..2541a5ad1b
--- /dev/null
+++ b/REORG.TODO/elf/testobj1_1.c
@@ -0,0 +1,7 @@
+#include "testobj.h"
+
+int
+obj1func1 (int a)
+{
+ return 42 + obj1func2 (a);
+}
diff --git a/REORG.TODO/elf/testobj2.c b/REORG.TODO/elf/testobj2.c
new file mode 100644
index 0000000000..7e4b610982
--- /dev/null
+++ b/REORG.TODO/elf/testobj2.c
@@ -0,0 +1,32 @@
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testobj.h"
+
+int
+obj2func1 (int a __attribute__ ((unused)))
+{
+ return 43;
+}
+
+int
+obj2func2 (int a)
+{
+ return obj1func1 (a) + 10;
+}
+
+int
+preload (int a)
+{
+ int (*fp) (int) = dlsym (RTLD_NEXT, "preload");
+ if (fp != NULL)
+ return fp (a) + 10;
+ return 10;
+}
+
+void
+p (void)
+{
+ puts ("hello world");
+}
diff --git a/REORG.TODO/elf/testobj3.c b/REORG.TODO/elf/testobj3.c
new file mode 100644
index 0000000000..c025ff631a
--- /dev/null
+++ b/REORG.TODO/elf/testobj3.c
@@ -0,0 +1,26 @@
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include "testobj.h"
+
+
+int
+obj3func1 (int a __attribute__ ((unused)))
+{
+ return 44;
+}
+
+int
+obj3func2 (int a)
+{
+ return foo (a) + 42;
+}
+
+int
+preload (int a)
+{
+ int (*fp) (int) = dlsym (RTLD_NEXT, "preload");
+ if (fp != NULL)
+ return fp (a) + 10;
+ return 10;
+}
diff --git a/REORG.TODO/elf/testobj4.c b/REORG.TODO/elf/testobj4.c
new file mode 100644
index 0000000000..2729ba32be
--- /dev/null
+++ b/REORG.TODO/elf/testobj4.c
@@ -0,0 +1,25 @@
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include "testobj.h"
+
+int
+obj4func1 (int a __attribute__ ((unused)))
+{
+ return 55;
+}
+
+int
+obj4func2 (int a)
+{
+ return foo (a) + 43;
+}
+
+int
+preload (int a)
+{
+ int (*fp) (int) = dlsym (RTLD_NEXT, "preload");
+ if (fp != NULL)
+ return fp (a) + 10;
+ return 10;
+}
diff --git a/REORG.TODO/elf/testobj5.c b/REORG.TODO/elf/testobj5.c
new file mode 100644
index 0000000000..9675cad88d
--- /dev/null
+++ b/REORG.TODO/elf/testobj5.c
@@ -0,0 +1,26 @@
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include "testobj.h"
+
+
+int
+obj5func1 (int a __attribute__ ((unused)))
+{
+ return 66;
+}
+
+int
+obj5func2 (int a)
+{
+ return foo (a) + 44;
+}
+
+int
+preload (int a)
+{
+ int (*fp) (int) = dlsym (RTLD_NEXT, "preload");
+ if (fp != NULL)
+ return fp (a) + 10;
+ return 10;
+}
diff --git a/REORG.TODO/elf/testobj6.c b/REORG.TODO/elf/testobj6.c
new file mode 100644
index 0000000000..fcba01631d
--- /dev/null
+++ b/REORG.TODO/elf/testobj6.c
@@ -0,0 +1,19 @@
+#include "testobj.h"
+
+int
+obj6func1 (int a __attribute__ ((unused)))
+{
+ return 77;
+}
+
+int
+obj6func2 (int a)
+{
+ return foo (a) + 46;
+}
+
+int
+preload (int a)
+{
+ return a;
+}
diff --git a/REORG.TODO/elf/tls-macros.h b/REORG.TODO/elf/tls-macros.h
new file mode 100644
index 0000000000..e25e33b0f0
--- /dev/null
+++ b/REORG.TODO/elf/tls-macros.h
@@ -0,0 +1,25 @@
+/* Macros to support TLS testing in times of missing compiler support. */
+
+#define COMMON_INT_DEF(x) \
+ asm (".tls_common " #x ",4,4")
+/* XXX Until we get compiler support we don't need declarations. */
+#define COMMON_INT_DECL(x)
+
+/* XXX This definition will probably be machine specific, too. */
+#define VAR_INT_DEF(x) \
+ asm (".section .tdata\n\t" \
+ ".globl " #x "\n" \
+ ".balign 4\n" \
+ #x ":\t.long 0\n\t" \
+ ".size " #x ",4\n\t" \
+ ".previous")
+/* XXX Until we get compiler support we don't need declarations. */
+#define VAR_INT_DECL(x)
+
+#include_next <tls-macros.h>
+
+ /* XXX Each architecture must have its own asm for now. */
+#if !defined TLS_LE || !defined TLS_IE \
+ || !defined TLS_LD || !defined TLS_GD
+# error "No support for this architecture so far."
+#endif
diff --git a/REORG.TODO/elf/tlsdeschtab.h b/REORG.TODO/elf/tlsdeschtab.h
new file mode 100644
index 0000000000..3091d8b420
--- /dev/null
+++ b/REORG.TODO/elf/tlsdeschtab.h
@@ -0,0 +1,164 @@
+/* Hash table for TLS descriptors.
+ Copyright (C) 2005-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Alexandre Oliva <aoliva@redhat.com>
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef TLSDESCHTAB_H
+# define TLSDESCHTAB_H 1
+
+#include <atomic.h>
+
+# ifdef SHARED
+
+# include <inline-hashtab.h>
+
+inline static int
+hash_tlsdesc (void *p)
+{
+ struct tlsdesc_dynamic_arg *td = p;
+
+ /* We know all entries are for the same module, so ti_offset is the
+ only distinguishing entry. */
+ return td->tlsinfo.ti_offset;
+}
+
+inline static int
+eq_tlsdesc (void *p, void *q)
+{
+ struct tlsdesc_dynamic_arg *tdp = p, *tdq = q;
+
+ return tdp->tlsinfo.ti_offset == tdq->tlsinfo.ti_offset;
+}
+
+inline static size_t
+map_generation (struct link_map *map)
+{
+ size_t idx = map->l_tls_modid;
+ struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+
+ /* Find the place in the dtv slotinfo list. */
+ do
+ {
+ /* Does it fit in the array of this list element? */
+ if (idx < listp->len)
+ {
+ /* We should never get here for a module in static TLS, so
+ we can assume that, if the generation count is zero, we
+ still haven't determined the generation count for this
+ module. */
+ if (listp->slotinfo[idx].map == map && listp->slotinfo[idx].gen)
+ return listp->slotinfo[idx].gen;
+ else
+ break;
+ }
+ idx -= listp->len;
+ listp = listp->next;
+ }
+ while (listp != NULL);
+
+ /* If we get to this point, the module still hasn't been assigned an
+ entry in the dtv slotinfo data structures, and it will when we're
+ done with relocations. At that point, the module will get a
+ generation number that is one past the current generation, so
+ return exactly that. */
+ return GL(dl_tls_generation) + 1;
+}
+
+void *
+internal_function
+_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
+{
+ struct hashtab *ht;
+ void **entry;
+ struct tlsdesc_dynamic_arg *td, test;
+
+ /* FIXME: We could use a per-map lock here, but is it worth it? */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+ ht = map->l_mach.tlsdesc_table;
+ if (! ht)
+ {
+ ht = htab_create ();
+ if (! ht)
+ {
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ return 0;
+ }
+ map->l_mach.tlsdesc_table = ht;
+ }
+
+ test.tlsinfo.ti_module = map->l_tls_modid;
+ test.tlsinfo.ti_offset = ti_offset;
+ entry = htab_find_slot (ht, &test, 1, hash_tlsdesc, eq_tlsdesc);
+ if (! entry)
+ {
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ return 0;
+ }
+
+ if (*entry)
+ {
+ td = *entry;
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ return td;
+ }
+
+ *entry = td = malloc (sizeof (struct tlsdesc_dynamic_arg));
+ /* This may be higher than the map's generation, but it doesn't
+ matter much. Worst case, we'll have one extra DTV update per
+ thread. */
+ td->gen_count = map_generation (map);
+ td->tlsinfo = test.tlsinfo;
+
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ return td;
+}
+
+# endif /* SHARED */
+
+/* The idea of the following two functions is to stop multiple threads
+ from attempting to resolve the same TLS descriptor without busy
+ waiting. Ideally, we should be able to release the lock right
+ after changing td->entry, and then using say a condition variable
+ or a futex wake to wake up any waiting threads, but let's try to
+ avoid introducing such dependencies. */
+
+static int
+_dl_tlsdesc_resolve_early_return_p (struct tlsdesc volatile *td, void *caller)
+{
+ if (caller != atomic_load_relaxed (&td->entry))
+ return 1;
+
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+ if (caller != atomic_load_relaxed (&td->entry))
+ {
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ return 1;
+ }
+
+ atomic_store_relaxed (&td->entry, _dl_tlsdesc_resolve_hold);
+
+ return 0;
+}
+
+static void
+_dl_tlsdesc_wake_up_held_fixups (void)
+{
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+}
+
+#endif
diff --git a/REORG.TODO/elf/tst-_dl_addr_inside_object.c b/REORG.TODO/elf/tst-_dl_addr_inside_object.c
new file mode 100644
index 0000000000..1604b8df63
--- /dev/null
+++ b/REORG.TODO/elf/tst-_dl_addr_inside_object.c
@@ -0,0 +1,222 @@
+/* Unit test for _dl_addr_inside_object.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <link.h>
+#include <elf.h>
+#include <libc-symbols.h>
+
+extern int internal_function _dl_addr_inside_object (struct link_map *l,
+ const ElfW(Addr) addr);
+
+static int
+do_test (void)
+{
+ int ret, err = 0;
+ ElfW(Addr) addr;
+ struct link_map map;
+ ElfW(Phdr) header;
+ map.l_phdr = &header;
+ map.l_phnum = 1;
+ map.l_addr = 0x0;
+ /* Segment spans 0x2000 -> 0x4000. */
+ header.p_vaddr = 0x2000;
+ header.p_memsz = 0x2000;
+ header.p_type = PT_LOAD;
+ /* Address is above the segment e.g. > 0x4000. */
+ addr = 0x5000;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: Above: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: Above: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: Above: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is inside the segment e.g. 0x2000 < addr < 0x4000. */
+ addr = 0x3000;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("FAIL: Inside: Address is detected as outside the segment.\n");
+ err++;
+ break;
+ case 1:
+ printf ("PASS: Inside: Address is detected as inside the segment.\n");
+ break;
+ default:
+ printf ("FAIL: Inside: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is below the segment e.g. < 0x2000. */
+ addr = 0x1000;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: Below: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: Below: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: Below: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is in the segment and addr == p_vaddr. */
+ addr = 0x2000;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("FAIL: At p_vaddr: Address is detected as outside the segment.\n");
+ err++;
+ break;
+ case 1:
+ printf ("PASS: At p_vaddr: Address is detected as inside the segment.\n");
+ break;
+ default:
+ printf ("FAIL: At p_vaddr: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is in the segment and addr == p_vaddr + p_memsz - 1. */
+ addr = 0x2000 + 0x2000 - 0x1;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("FAIL: At p_memsz-1: Address is detected as outside the segment.\n");
+ err++;
+ break;
+ case 1:
+ printf ("PASS: At p_memsz-1: Address is detected as inside the segment.\n");
+ break;
+ default:
+ printf ("FAIL: At p_memsz-1: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is outside the segment and addr == p_vaddr + p_memsz. */
+ addr = 0x2000 + 0x2000;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: At p_memsz: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: At p_memsz: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: At p_memsz: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is outside the segment and p_vaddr at maximum address. */
+ addr = 0x0 - 0x2;
+ header.p_vaddr = 0x0 - 0x1;
+ header.p_memsz = 0x1;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: At max: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: At max: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: At max: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is outside the segment and p_vaddr at minimum address. */
+ addr = 0x1;
+ header.p_vaddr = 0x0;
+ header.p_memsz = 0x1;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: At min: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: At min: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: At min: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is always inside the segment with p_memsz at max. */
+ addr = 0x0;
+ header.p_vaddr = 0x0;
+ header.p_memsz = 0x0 - 0x1;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("FAIL: At maxmem: Address is detected as outside the segment.\n");
+ err++;
+ break;
+ case 1:
+ printf ("PASS: At maxmem: Address is detected as inside the segment.\n");
+ break;
+ default:
+ printf ("FAIL: At maxmem: Invalid return value.\n");
+ exit (1);
+ }
+ /* Attempt to wrap addr into the segment.
+ Pick a load address in the middle of the address space.
+ Place the test address at 0x0 so it wraps to the middle again. */
+ map.l_addr = 0x0 - 0x1;
+ map.l_addr = map.l_addr / 2;
+ addr = 0;
+ /* Setup a segment covering 1/2 the address space. */
+ header.p_vaddr = 0x0;
+ header.p_memsz = 0x0 - 0x1 - map.l_addr;
+ /* No matter where you place addr everything is shifted modulo l_addr
+ and even with this underflow you're always 1 byte away from being
+ in the range. */
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: Underflow: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: Underflow: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: Underflow: Invalid return value.\n");
+ exit (1);
+ }
+
+ return err;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-addr1.c b/REORG.TODO/elf/tst-addr1.c
new file mode 100644
index 0000000000..68ff74aabd
--- /dev/null
+++ b/REORG.TODO/elf/tst-addr1.c
@@ -0,0 +1,25 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+
+static int
+do_test (void)
+{
+ Dl_info i;
+ if (dladdr (&printf, &i) == 0)
+ {
+ puts ("not found");
+ return 1;
+ }
+ printf ("found symbol %s in %s\n", i.dli_sname, i.dli_fname);
+ return i.dli_sname == NULL
+ || (strcmp (i.dli_sname, "printf") != 0
+ /* On architectures which create PIC code by default
+ &printf may resolve to an address in libc.so
+ rather than in the binary. printf and _IO_printf
+ are aliased and which one comes first in the
+ hash table is up to the linker. */
+ && strcmp (i.dli_sname, "_IO_printf") != 0);
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-align.c b/REORG.TODO/elf/tst-align.c
new file mode 100644
index 0000000000..01b0b4ffb3
--- /dev/null
+++ b/REORG.TODO/elf/tst-align.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 2003-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+ static const char modname[] = "tst-alignmod.so";
+ int result = 0;
+ void (*fp) (int *);
+ void *h;
+
+ h = dlopen (modname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname, dlerror ());
+ exit (1);
+ }
+
+ fp = dlsym (h, "in_dso");
+ if (fp == NULL)
+ {
+ printf ("cannot get symbol 'in_dso': %s\n", dlerror ());
+ exit (1);
+ }
+
+ fp (&result);
+
+ dlclose (h);
+
+ return result;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-align2.c b/REORG.TODO/elf/tst-align2.c
new file mode 100644
index 0000000000..78b66be20a
--- /dev/null
+++ b/REORG.TODO/elf/tst-align2.c
@@ -0,0 +1,155 @@
+/* Copyright (C) 2005-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2005.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <tst-stack-align.h>
+#include <unistd.h>
+
+static int res, fds[2], result;
+static bool test_destructors;
+
+extern void in_dso (int *, bool *, int *);
+
+static void __attribute__ ((constructor)) con (void)
+{
+ res = TEST_STACK_ALIGN () ? -1 : 1;
+}
+
+static void __attribute__ ((destructor)) des (void)
+{
+ if (!test_destructors)
+ return;
+
+ char c = TEST_STACK_ALIGN () ? 'B' : 'A';
+ write (fds[1], &c, 1);
+}
+
+static int
+do_test (void)
+{
+ if (!res)
+ {
+ puts ("binary's constructor has not been run");
+ result = 1;
+ }
+ else if (res != 1)
+ {
+ puts ("binary's constructor has been run without sufficient alignment");
+ result = 1;
+ }
+
+ if (TEST_STACK_ALIGN ())
+ {
+ puts ("insufficient stack alignment in do_test");
+ result = 1;
+ }
+
+ in_dso (&result, &test_destructors, &fds[1]);
+
+ if (pipe (fds) < 0)
+ {
+ printf ("couldn't create pipe: %m\n");
+ return 1;
+ }
+
+ pid_t pid = fork ();
+ if (pid < 0)
+ {
+ printf ("fork failed: %m\n");
+ return 1;
+ }
+
+ if (!pid)
+ {
+ close (fds[0]);
+ test_destructors = true;
+ exit (0);
+ }
+
+ close (fds[1]);
+
+ unsigned char c;
+ ssize_t len;
+ int des_seen = 0, dso_des_seen = 0;
+ while ((len = TEMP_FAILURE_RETRY (read (fds[0], &c, 1))) > 0)
+ {
+ switch (c)
+ {
+ case 'B':
+ puts ("insufficient alignment in binary's destructor");
+ result = 1;
+ /* FALLTHROUGH */
+ case 'A':
+ des_seen++;
+ break;
+ case 'D':
+ puts ("insufficient alignment in DSO destructor");
+ result = 1;
+ /* FALLTHROUGH */
+ case 'C':
+ dso_des_seen++;
+ break;
+ default:
+ printf ("unexpected character %x read from pipe", c);
+ result = 1;
+ break;
+ }
+ }
+
+ close (fds[0]);
+
+ if (des_seen != 1)
+ {
+ printf ("binary destructor run %d times instead of once\n", des_seen);
+ result = 1;
+ }
+
+ if (dso_des_seen != 1)
+ {
+ printf ("DSO destructor run %d times instead of once\n", dso_des_seen);
+ result = 1;
+ }
+
+ int status;
+ pid_t termpid;
+ termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (termpid == -1)
+ {
+ printf ("waitpid failed: %m\n");
+ result = 1;
+ }
+ else if (termpid != pid)
+ {
+ printf ("waitpid returned %ld != %ld\n",
+ (long int) termpid, (long int) pid);
+ result = 1;
+ }
+ else if (!WIFEXITED (status) || WEXITSTATUS (status))
+ {
+ puts ("child hasn't exited with exit status 0");
+ result = 1;
+ }
+
+ return result;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-alignmod.c b/REORG.TODO/elf/tst-alignmod.c
new file mode 100644
index 0000000000..b5e47be0bd
--- /dev/null
+++ b/REORG.TODO/elf/tst-alignmod.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 2003-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <tst-stack-align.h>
+
+static int res, *resp;
+
+static void __attribute__((constructor))
+con (void)
+{
+ res = TEST_STACK_ALIGN () ? -1 : 1;
+}
+
+void
+in_dso (int *result)
+{
+ if (!res)
+ {
+ puts ("constructor has not been run");
+ *result = 1;
+ }
+ else if (res != 1)
+ {
+ puts ("constructor has been run without sufficient alignment");
+ *result = 1;
+ }
+
+ resp = result;
+}
+
+static void __attribute__((destructor))
+des (void)
+{
+ if (TEST_STACK_ALIGN ())
+ *resp = 1;
+}
diff --git a/REORG.TODO/elf/tst-alignmod2.c b/REORG.TODO/elf/tst-alignmod2.c
new file mode 100644
index 0000000000..f338ab5c27
--- /dev/null
+++ b/REORG.TODO/elf/tst-alignmod2.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 2003-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <tst-stack-align.h>
+#include <unistd.h>
+
+static int res, *fdp;
+static bool *test_destructorsp;
+
+static void __attribute__((constructor))
+con (void)
+{
+ res = TEST_STACK_ALIGN () ? -1 : 1;
+}
+
+void
+in_dso (int *result, bool *test_destructors, int *fd)
+{
+ if (!res)
+ {
+ puts ("constructor has not been run");
+ *result = 1;
+ }
+ else if (res != 1)
+ {
+ puts ("constructor has been run without sufficient alignment");
+ *result = 1;
+ }
+
+ test_destructorsp = test_destructors;
+ fdp = fd;
+}
+
+static void __attribute__((destructor))
+des (void)
+{
+ if (!test_destructorsp || !*test_destructorsp)
+ return;
+
+ char c = TEST_STACK_ALIGN () ? 'D' : 'C';
+ write (*fdp, &c, 1);
+}
diff --git a/REORG.TODO/elf/tst-array1-static.c b/REORG.TODO/elf/tst-array1-static.c
new file mode 100644
index 0000000000..21539a4212
--- /dev/null
+++ b/REORG.TODO/elf/tst-array1-static.c
@@ -0,0 +1 @@
+#include "tst-array1.c"
diff --git a/REORG.TODO/elf/tst-array1.c b/REORG.TODO/elf/tst-array1.c
new file mode 100644
index 0000000000..e998932b36
--- /dev/null
+++ b/REORG.TODO/elf/tst-array1.c
@@ -0,0 +1,103 @@
+#include <unistd.h>
+
+/* Give init non-default priority so that it runs before init_array. */
+static void init (void) __attribute__ ((constructor (1000)));
+
+static void
+init (void)
+{
+ write (STDOUT_FILENO, "init\n", 5);
+}
+
+/* Give fini the same priority as init. */
+static void fini (void) __attribute__ ((destructor (1000)));
+
+static void
+fini (void)
+{
+ write (STDOUT_FILENO, "fini\n", 5);
+}
+
+static void
+preinit_0 (void)
+{
+ write (STDOUT_FILENO, "preinit array 0\n", 16);
+}
+
+static void
+preinit_1 (void)
+{
+ write (STDOUT_FILENO, "preinit array 1\n", 16);
+}
+
+static void
+preinit_2 (void)
+{
+ write (STDOUT_FILENO, "preinit array 2\n", 16);
+}
+
+void (*const preinit_array []) (void)
+ __attribute__ ((section (".preinit_array"), aligned (sizeof (void *)))) =
+{
+ &preinit_0,
+ &preinit_1,
+ &preinit_2
+};
+
+static void
+init_0 (void)
+{
+ write (STDOUT_FILENO, "init array 0\n", 13);
+}
+
+static void
+init_1 (void)
+{
+ write (STDOUT_FILENO, "init array 1\n", 13);
+}
+
+static void
+init_2 (void)
+{
+ write (STDOUT_FILENO, "init array 2\n", 13);
+}
+
+void (*init_array []) (void)
+ __attribute__ ((section (".init_array"), aligned (sizeof (void *)))) =
+{
+ &init_0,
+ &init_1,
+ &init_2
+};
+
+static void
+fini_0 (void)
+{
+ write (STDOUT_FILENO, "fini array 0\n", 13);
+}
+
+static void
+fini_1 (void)
+{
+ write (STDOUT_FILENO, "fini array 1\n", 13);
+}
+
+static void
+fini_2 (void)
+{
+ write (STDOUT_FILENO, "fini array 2\n", 13);
+}
+
+void (*fini_array []) (void)
+ __attribute__ ((section (".fini_array"), aligned (sizeof (void *)))) =
+{
+ &fini_0,
+ &fini_1,
+ &fini_2
+};
+
+int
+main (void)
+{
+ return 0;
+}
diff --git a/REORG.TODO/elf/tst-array1.exp b/REORG.TODO/elf/tst-array1.exp
new file mode 100644
index 0000000000..cfcec9de0f
--- /dev/null
+++ b/REORG.TODO/elf/tst-array1.exp
@@ -0,0 +1,11 @@
+preinit array 0
+preinit array 1
+preinit array 2
+init
+init array 0
+init array 1
+init array 2
+fini array 2
+fini array 1
+fini array 0
+fini
diff --git a/REORG.TODO/elf/tst-array2.c b/REORG.TODO/elf/tst-array2.c
new file mode 100644
index 0000000000..21539a4212
--- /dev/null
+++ b/REORG.TODO/elf/tst-array2.c
@@ -0,0 +1 @@
+#include "tst-array1.c"
diff --git a/REORG.TODO/elf/tst-array2.exp b/REORG.TODO/elf/tst-array2.exp
new file mode 100644
index 0000000000..ed203525b5
--- /dev/null
+++ b/REORG.TODO/elf/tst-array2.exp
@@ -0,0 +1,19 @@
+preinit array 0
+preinit array 1
+preinit array 2
+DSO init
+DSO init array 0
+DSO init array 1
+DSO init array 2
+init
+init array 0
+init array 1
+init array 2
+fini array 2
+fini array 1
+fini array 0
+fini
+DSO fini array 2
+DSO fini array 1
+DSO fini array 0
+DSO fini
diff --git a/REORG.TODO/elf/tst-array2dep.c b/REORG.TODO/elf/tst-array2dep.c
new file mode 100644
index 0000000000..2f920cdc8d
--- /dev/null
+++ b/REORG.TODO/elf/tst-array2dep.c
@@ -0,0 +1,71 @@
+#include <unistd.h>
+
+/* Give init non-default priority so that it runs before init_array. */
+static void init (void) __attribute__ ((constructor (1000)));
+
+static void
+init (void)
+{
+ write (STDOUT_FILENO, "DSO init\n", 9);
+}
+
+/* Give fini the same priority as init. */
+static void fini (void) __attribute__ ((destructor (1000)));
+
+static void
+fini (void)
+{
+ write (STDOUT_FILENO, "DSO fini\n", 9);
+}
+
+static void
+init_0 (void)
+{
+ write (STDOUT_FILENO, "DSO init array 0\n", 17);
+}
+
+static void
+init_1 (void)
+{
+ write (STDOUT_FILENO, "DSO init array 1\n", 17);
+}
+
+static void
+init_2 (void)
+{
+ write (STDOUT_FILENO, "DSO init array 2\n", 17);
+}
+
+void (*init_array []) (void)
+ __attribute__ ((section (".init_array"), aligned (sizeof (void *)))) =
+{
+ &init_0,
+ &init_1,
+ &init_2
+};
+
+static void
+fini_0 (void)
+{
+ write (STDOUT_FILENO, "DSO fini array 0\n", 17);
+}
+
+static void
+fini_1 (void)
+{
+ write (STDOUT_FILENO, "DSO fini array 1\n", 17);
+}
+
+static void
+fini_2 (void)
+{
+ write (STDOUT_FILENO, "DSO fini array 2\n", 17);
+}
+
+void (*fini_array []) (void)
+ __attribute__ ((section (".fini_array"), aligned (sizeof (void *)))) =
+{
+ &fini_0,
+ &fini_1,
+ &fini_2
+};
diff --git a/REORG.TODO/elf/tst-array3.c b/REORG.TODO/elf/tst-array3.c
new file mode 100644
index 0000000000..21539a4212
--- /dev/null
+++ b/REORG.TODO/elf/tst-array3.c
@@ -0,0 +1 @@
+#include "tst-array1.c"
diff --git a/REORG.TODO/elf/tst-array4.c b/REORG.TODO/elf/tst-array4.c
new file mode 100644
index 0000000000..ac3d4eb716
--- /dev/null
+++ b/REORG.TODO/elf/tst-array4.c
@@ -0,0 +1,18 @@
+#include <dlfcn.h>
+
+#define main array1_main
+#include "tst-array1.c"
+#undef main
+
+int
+main (void)
+{
+ void *handle = dlopen ("tst-array2dep.so", RTLD_LAZY);
+
+ array1_main ();
+
+ if (handle != NULL)
+ dlclose (handle);
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/tst-array4.exp b/REORG.TODO/elf/tst-array4.exp
new file mode 100644
index 0000000000..560444d2e8
--- /dev/null
+++ b/REORG.TODO/elf/tst-array4.exp
@@ -0,0 +1,19 @@
+preinit array 0
+preinit array 1
+preinit array 2
+init
+init array 0
+init array 1
+init array 2
+DSO init
+DSO init array 0
+DSO init array 1
+DSO init array 2
+DSO fini array 2
+DSO fini array 1
+DSO fini array 0
+DSO fini
+fini array 2
+fini array 1
+fini array 0
+fini
diff --git a/REORG.TODO/elf/tst-array5-static.c b/REORG.TODO/elf/tst-array5-static.c
new file mode 100644
index 0000000000..4ef2aba3f3
--- /dev/null
+++ b/REORG.TODO/elf/tst-array5-static.c
@@ -0,0 +1 @@
+#include "tst-array5.c"
diff --git a/REORG.TODO/elf/tst-array5-static.exp b/REORG.TODO/elf/tst-array5-static.exp
new file mode 100644
index 0000000000..b1dc9e467b
--- /dev/null
+++ b/REORG.TODO/elf/tst-array5-static.exp
@@ -0,0 +1,2 @@
+preinit array in executable: tst-array5-static
+init array in executable: tst-array5-static
diff --git a/REORG.TODO/elf/tst-array5.c b/REORG.TODO/elf/tst-array5.c
new file mode 100644
index 0000000000..03a5668326
--- /dev/null
+++ b/REORG.TODO/elf/tst-array5.c
@@ -0,0 +1,50 @@
+#include <string.h>
+#include <unistd.h>
+
+static void
+preinit_0 (int argc __attribute__ ((unused)), char **argv)
+{
+ char *p = strrchr (argv [0], '/');
+
+ if (p == NULL)
+ return;
+
+ p++;
+ size_t len = strlen (p);
+ write (STDOUT_FILENO, "preinit array in executable: ", 29);
+ write (STDOUT_FILENO, p, len);
+ write (STDOUT_FILENO, "\n", 1);
+}
+
+void (*const preinit_array []) (int, char **)
+ __attribute__ ((section (".preinit_array"), aligned (sizeof (void *)))) =
+{
+ &preinit_0,
+};
+
+static void
+init_0 (int argc __attribute__ ((unused)), char **argv)
+{
+ char *p = strrchr (argv [0], '/');
+
+ if (p == NULL)
+ return;
+
+ p++;
+ size_t len = strlen (p);
+ write (STDOUT_FILENO, "init array in executable: ", 26);
+ write (STDOUT_FILENO, p, len);
+ write (STDOUT_FILENO, "\n", 1);
+}
+
+void (*const init_array []) (int, char **)
+ __attribute__ ((section (".init_array"), aligned (sizeof (void *)))) =
+{
+ &init_0,
+};
+
+int
+main (void)
+{
+ return 0;
+}
diff --git a/REORG.TODO/elf/tst-array5.exp b/REORG.TODO/elf/tst-array5.exp
new file mode 100644
index 0000000000..28b4909833
--- /dev/null
+++ b/REORG.TODO/elf/tst-array5.exp
@@ -0,0 +1,3 @@
+preinit array in executable: tst-array5
+init array in DSO: tst-array5
+init array in executable: tst-array5
diff --git a/REORG.TODO/elf/tst-array5dep.c b/REORG.TODO/elf/tst-array5dep.c
new file mode 100644
index 0000000000..570d282af4
--- /dev/null
+++ b/REORG.TODO/elf/tst-array5dep.c
@@ -0,0 +1,23 @@
+#include <string.h>
+#include <unistd.h>
+
+static void
+init_0 (int argc __attribute__ ((unused)), char **argv)
+{
+ char *p = strrchr (argv [0], '/');
+
+ if (p == NULL)
+ return;
+
+ p++;
+ size_t len = strlen (p);
+ write (STDOUT_FILENO, "init array in DSO: ", 19);
+ write (STDOUT_FILENO, p, len);
+ write (STDOUT_FILENO, "\n", 1);
+}
+
+void (*const init_array []) (int, char **)
+ __attribute__ ((section (".init_array"), aligned (sizeof (void *)))) =
+{
+ &init_0,
+};
diff --git a/REORG.TODO/elf/tst-audit1.c b/REORG.TODO/elf/tst-audit1.c
new file mode 100644
index 0000000000..63656b4ee9
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit1.c
@@ -0,0 +1 @@
+#include "../io/pwd.c"
diff --git a/REORG.TODO/elf/tst-audit11.c b/REORG.TODO/elf/tst-audit11.c
new file mode 100644
index 0000000000..ff91a6bd6d
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit11.c
@@ -0,0 +1,35 @@
+/* Test version symbol binding can find a DSO replaced by la_objsearch.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+do_test (void)
+{
+ puts ("Start");
+ if (dlopen ("$ORIGIN/tst-audit11mod1.so", RTLD_LAZY) == NULL)
+ {
+ printf ("module not loaded: %s\n", dlerror ());
+ return 1;
+ }
+ puts ("OK");
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-audit11mod1.c b/REORG.TODO/elf/tst-audit11mod1.c
new file mode 100644
index 0000000000..0c0f5c6838
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit11mod1.c
@@ -0,0 +1,24 @@
+/* DSO directly opened by tst-audit11.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+extern int f2 (void);
+int
+f1 (void)
+{
+ return f2 ();
+}
diff --git a/REORG.TODO/elf/tst-audit11mod2.c b/REORG.TODO/elf/tst-audit11mod2.c
new file mode 100644
index 0000000000..d5eb029744
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit11mod2.c
@@ -0,0 +1,23 @@
+/* DSO indirectly opened by tst-audit11, with symbol versioning.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+int
+f2 (void)
+{
+ return 42;
+}
diff --git a/REORG.TODO/elf/tst-audit11mod2.map b/REORG.TODO/elf/tst-audit11mod2.map
new file mode 100644
index 0000000000..278787872c
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit11mod2.map
@@ -0,0 +1,22 @@
+/* Symbol versioning for the DSO indirectly opened by tst-audit11.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+V1 {
+ global: f2;
+ local: *;
+};
diff --git a/REORG.TODO/elf/tst-audit12.c b/REORG.TODO/elf/tst-audit12.c
new file mode 100644
index 0000000000..62ac5f28a4
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit12.c
@@ -0,0 +1,48 @@
+/* Test that symbol is bound to a DSO replaced by la_objsearch.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+do_test (void)
+{
+ puts ("Start");
+ void *h = dlopen ("$ORIGIN/tst-audit12mod1.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("module not loaded: %s\n", dlerror ());
+ return 1;
+ }
+ int (*fp) (void) = (int (*) (void)) dlsym (h, "f1");
+ if (fp == NULL)
+ {
+ printf ("function f1 not found: %s\n", dlerror ());
+ return 1;
+ }
+ int res = fp ();
+ if (res != 43)
+ {
+ puts ("incorrect function f2 called");
+ return 1;
+ }
+ printf ("%d is OK\n", res);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-audit12mod1.c b/REORG.TODO/elf/tst-audit12mod1.c
new file mode 100644
index 0000000000..a48795b661
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit12mod1.c
@@ -0,0 +1,24 @@
+/* DSO directly opened by tst-audit12.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+extern int f2 (void);
+int
+f1 (void)
+{
+ return f2 ();
+}
diff --git a/REORG.TODO/elf/tst-audit12mod2.c b/REORG.TODO/elf/tst-audit12mod2.c
new file mode 100644
index 0000000000..593d02dfb6
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit12mod2.c
@@ -0,0 +1,23 @@
+/* Replaced DSO referenced by tst-audit12mod1.so, for tst-audit12.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+int
+f2 (void)
+{
+ return 42;
+}
diff --git a/REORG.TODO/elf/tst-audit12mod2.map b/REORG.TODO/elf/tst-audit12mod2.map
new file mode 100644
index 0000000000..11e22bbdee
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit12mod2.map
@@ -0,0 +1,22 @@
+/* Symbol versioning for tst-audit12mod2.so used by tst-audit12.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+V1 {
+ global: f2;
+ local: *;
+};
diff --git a/REORG.TODO/elf/tst-audit12mod3.c b/REORG.TODO/elf/tst-audit12mod3.c
new file mode 100644
index 0000000000..1e01bb8eea
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit12mod3.c
@@ -0,0 +1,23 @@
+/* Replacement DSO loaded by the audit module, for tst-audit12.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+int
+f2 (void)
+{
+ return 43;
+}
diff --git a/REORG.TODO/elf/tst-audit2.c b/REORG.TODO/elf/tst-audit2.c
new file mode 100644
index 0000000000..0e66f5c328
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit2.c
@@ -0,0 +1,60 @@
+/* Test case for early TLS initialization in dynamic linker. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#define MAGIC1 0xabcdef72
+#define MAGIC2 0xd8675309
+static __thread unsigned int magic[] = { MAGIC1, MAGIC2 };
+static __thread int calloc_called;
+
+#undef calloc
+
+/* This calloc definition will be called by the dynamic linker itself.
+ We test that interposed calloc is called by the dynamic loader, and
+ that TLS is fully initialized by then. */
+
+void *
+calloc (size_t n, size_t m)
+{
+ if (!calloc_called)
+ {
+ /* Allow our calloc to be called more than once. */
+ calloc_called = 1;
+ if (magic[0] != MAGIC1 || magic[1] != MAGIC2)
+ {
+ printf ("{%x, %x} != {%x, %x}\n",
+ magic[0], magic[1], MAGIC1, MAGIC2);
+ abort ();
+ }
+ magic[0] = MAGIC2;
+ magic[1] = MAGIC1;
+ }
+
+ n *= m;
+ void *ptr = malloc (n);
+ if (ptr != NULL)
+ memset (ptr, '\0', n);
+ return ptr;
+}
+
+static int
+do_test (void)
+{
+ /* Make sure that our calloc is called from the dynamic linker at least
+ once. */
+ void *h = dlopen("$ORIGIN/tst-auditmod9b.so", RTLD_LAZY);
+ if (h != NULL)
+ dlclose (h);
+ if (magic[1] != MAGIC1 || magic[0] != MAGIC2)
+ {
+ printf ("{%x, %x} != {%x, %x}\n", magic[0], magic[1], MAGIC2, MAGIC1);
+ return 1;
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-audit8.c b/REORG.TODO/elf/tst-audit8.c
new file mode 100644
index 0000000000..63656b4ee9
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit8.c
@@ -0,0 +1 @@
+#include "../io/pwd.c"
diff --git a/REORG.TODO/elf/tst-audit9.c b/REORG.TODO/elf/tst-audit9.c
new file mode 100644
index 0000000000..b9de1bf5a2
--- /dev/null
+++ b/REORG.TODO/elf/tst-audit9.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+
+static int
+do_test (void)
+{
+ void *h = dlopen("$ORIGIN/tst-auditmod9b.so", RTLD_LAZY);
+ int (*fp)(void) = dlsym(h, "f");
+ return fp() - 1;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-auditmod1.c b/REORG.TODO/elf/tst-auditmod1.c
new file mode 100644
index 0000000000..573e37abd6
--- /dev/null
+++ b/REORG.TODO/elf/tst-auditmod1.c
@@ -0,0 +1,135 @@
+#include <dlfcn.h>
+#include <link.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <bits/wordsize.h>
+#include <gnu/lib-names.h>
+
+
+unsigned int
+la_version (unsigned int v)
+{
+ setlinebuf (stdout);
+
+ printf ("version: %u\n", v);
+
+ char buf[20];
+ sprintf (buf, "%u", v);
+
+ return v;
+}
+
+void
+la_activity (uintptr_t *cookie, unsigned int flag)
+{
+ if (flag == LA_ACT_CONSISTENT)
+ printf ("activity: consistent\n");
+ else if (flag == LA_ACT_ADD)
+ printf ("activity: add\n");
+ else if (flag == LA_ACT_DELETE)
+ printf ("activity: delete\n");
+ else
+ printf ("activity: unknown activity %u\n", flag);
+}
+
+char *
+la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag)
+{
+ char buf[100];
+ const char *flagstr;
+ if (flag == LA_SER_ORIG)
+ flagstr = "LA_SET_ORIG";
+ else if (flag == LA_SER_LIBPATH)
+ flagstr = "LA_SER_LIBPATH";
+ else if (flag == LA_SER_RUNPATH)
+ flagstr = "LA_SER_RUNPATH";
+ else if (flag == LA_SER_CONFIG)
+ flagstr = "LA_SER_CONFIG";
+ else if (flag == LA_SER_DEFAULT)
+ flagstr = "LA_SER_DEFAULT";
+ else if (flag == LA_SER_SECURE)
+ flagstr = "LA_SER_SECURE";
+ else
+ {
+ sprintf (buf, "unknown flag %d", flag);
+ flagstr = buf;
+ }
+ printf ("objsearch: %s, %s\n", name, flagstr);
+
+ return (char *) name;
+}
+
+unsigned int
+la_objopen (struct link_map *l, Lmid_t lmid, uintptr_t *cookie)
+{
+ printf ("objopen: %ld, %s\n", lmid, l->l_name);
+
+ return 3;
+}
+
+void
+la_preinit (uintptr_t *cookie)
+{
+ printf ("preinit\n");
+}
+
+unsigned int
+la_objclose (uintptr_t *cookie)
+{
+ printf ("objclose\n");
+ return 0;
+}
+
+uintptr_t
+la_symbind32 (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, unsigned int *flags, const char *symname)
+{
+ printf ("symbind32: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
+ symname, (long int) sym->st_value, ndx, *flags);
+
+ return sym->st_value;
+}
+
+uintptr_t
+la_symbind64 (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, unsigned int *flags, const char *symname)
+{
+ printf ("symbind64: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
+ symname, (long int) sym->st_value, ndx, *flags);
+
+ return sym->st_value;
+}
+
+#include <tst-audit.h>
+#if (!defined (pltenter) || !defined (pltexit) || !defined (La_regs) \
+ || !defined (La_retval) || !defined (int_retval))
+# error "architecture specific code needed in sysdeps/CPU/tst-audit.h"
+#endif
+
+
+ElfW(Addr)
+pltenter (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, La_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ printf ("pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
+ symname, (long int) sym->st_value, ndx, *flags);
+
+ return sym->st_value;
+}
+
+unsigned int
+pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const La_regs *inregs, La_retval *outregs,
+ const char *symname)
+{
+ printf ("pltexit: symname=%s, st_value=%#lx, ndx=%u, retval=%tu\n",
+ symname, (long int) sym->st_value, ndx,
+ (ptrdiff_t) outregs->int_retval);
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/tst-auditmod11.c b/REORG.TODO/elf/tst-auditmod11.c
new file mode 100644
index 0000000000..18feb5efc4
--- /dev/null
+++ b/REORG.TODO/elf/tst-auditmod11.c
@@ -0,0 +1,39 @@
+/* Audit module for tst-audit11.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+unsigned int
+la_version (unsigned int version)
+{
+ return version;
+}
+
+char *
+la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag)
+{
+ if (strcmp (name, "tst-audit11mod2.so") == 0)
+ {
+ return (char *) "$ORIGIN/tst-audit11mod2.so";
+ }
+ return (char *) name;
+}
diff --git a/REORG.TODO/elf/tst-auditmod12.c b/REORG.TODO/elf/tst-auditmod12.c
new file mode 100644
index 0000000000..039b7cd62b
--- /dev/null
+++ b/REORG.TODO/elf/tst-auditmod12.c
@@ -0,0 +1,43 @@
+/* Audit module for tst-audit12.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+unsigned int
+la_version (unsigned int version)
+{
+ return version;
+}
+
+char *
+la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag)
+{
+ const char target[] = "tst-audit12mod2.so";
+
+ size_t namelen = strlen (name);
+ if (namelen >= sizeof (target) - 1
+ && strcmp (name + namelen - (sizeof (target) - 1), target) == 0)
+ {
+ return (char *) "$ORIGIN/tst-audit12mod3.so";
+ }
+ return (char *) name;
+}
diff --git a/REORG.TODO/elf/tst-auditmod9a.c b/REORG.TODO/elf/tst-auditmod9a.c
new file mode 100644
index 0000000000..7213ade123
--- /dev/null
+++ b/REORG.TODO/elf/tst-auditmod9a.c
@@ -0,0 +1,15 @@
+#include <stdint.h>
+
+__thread int var;
+
+unsigned int
+la_version (unsigned int v)
+{
+ return v;
+}
+
+void
+la_activity (uintptr_t *cookie, unsigned int flag)
+{
+ ++var;
+}
diff --git a/REORG.TODO/elf/tst-auditmod9b.c b/REORG.TODO/elf/tst-auditmod9b.c
new file mode 100644
index 0000000000..8eeeb49986
--- /dev/null
+++ b/REORG.TODO/elf/tst-auditmod9b.c
@@ -0,0 +1,6 @@
+__thread int a;
+
+int f(void)
+{
+ return ++a;
+}
diff --git a/REORG.TODO/elf/tst-auxv.c b/REORG.TODO/elf/tst-auxv.c
new file mode 100644
index 0000000000..bc571c5fa7
--- /dev/null
+++ b/REORG.TODO/elf/tst-auxv.c
@@ -0,0 +1,70 @@
+/* Copyright (C) 2013-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <elf.h>
+#include <errno.h>
+#include <link.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <misc/sys/auxv.h>
+
+static int
+do_test (int argc, char *argv[])
+{
+ errno = 0;
+ const char *execfn = (const char *) getauxval (AT_NULL);
+
+ if (errno != ENOENT)
+ {
+ printf ("errno is %d rather than %d (ENOENT) on failure\n", errno,
+ ENOENT);
+ return 1;
+ }
+
+ if (execfn != NULL)
+ {
+ printf ("getauxval return value is nonzero on failure\n");
+ return 1;
+ }
+
+ errno = 0;
+ execfn = (const char *) getauxval (AT_EXECFN);
+
+ if (execfn == NULL)
+ {
+ printf ("No AT_EXECFN found, AT_EXECFN test skipped\n");
+ return 0;
+ }
+
+ if (errno != 0)
+ {
+ printf ("errno erroneously set to %d on success\n", errno);
+ return 1;
+ }
+
+ if (strcmp (argv[0], execfn) != 0)
+ {
+ printf ("Mismatch: argv[0]: %s vs. AT_EXECFN: %s\n", argv[0], execfn);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-deep1.c b/REORG.TODO/elf/tst-deep1.c
new file mode 100644
index 0000000000..97dce7ea4d
--- /dev/null
+++ b/REORG.TODO/elf/tst-deep1.c
@@ -0,0 +1,35 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+xyzzy (void)
+{
+ printf ("%s:%s\n", __FILE__, __func__);
+ return 21;
+}
+
+int
+back (void)
+{
+ printf ("%s:%s\n", __FILE__, __func__);
+ return 1;
+}
+
+extern int foo (void);
+
+static int
+do_test (void)
+{
+ void *p = dlopen ("$ORIGIN/tst-deep1mod2.so", RTLD_LAZY|RTLD_DEEPBIND);
+
+ int (*f) (void) = dlsym (p, "bar");
+ if (f == NULL)
+ {
+ puts (dlerror ());
+ return 1;
+ }
+
+ return foo () + f ();
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-deep1mod1.c b/REORG.TODO/elf/tst-deep1mod1.c
new file mode 100644
index 0000000000..cc922e6ea5
--- /dev/null
+++ b/REORG.TODO/elf/tst-deep1mod1.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+int
+foo (void)
+{
+ printf ("%s:%s\n", __FILE__, __func__);
+ return 1;
+}
+
+int
+baz (void)
+{
+ printf ("%s:%s\n", __FILE__, __func__);
+ return 20;
+}
diff --git a/REORG.TODO/elf/tst-deep1mod2.c b/REORG.TODO/elf/tst-deep1mod2.c
new file mode 100644
index 0000000000..b99caf0328
--- /dev/null
+++ b/REORG.TODO/elf/tst-deep1mod2.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+extern int baz (void);
+extern int xyzzy (void);
+int
+bar (void)
+{
+ printf ("%s:%s\n", __FILE__, __func__);
+ return baz () + xyzzy ();;
+}
+
+int
+back (void)
+{
+ printf ("%s:%s\n", __FILE__, __func__);
+ return -1;
+}
diff --git a/REORG.TODO/elf/tst-deep1mod3.c b/REORG.TODO/elf/tst-deep1mod3.c
new file mode 100644
index 0000000000..eee7d5c97b
--- /dev/null
+++ b/REORG.TODO/elf/tst-deep1mod3.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+extern int back (void);
+
+int
+baz (void)
+{
+ printf ("%s:%s\n", __FILE__, __func__);
+ return back ();
+}
+
+int
+xyzzy (void)
+{
+ printf ("%s:%s\n", __FILE__, __func__);
+ return 0;
+}
diff --git a/REORG.TODO/elf/tst-dl-iter-static.c b/REORG.TODO/elf/tst-dl-iter-static.c
new file mode 100644
index 0000000000..9a2758c8ef
--- /dev/null
+++ b/REORG.TODO/elf/tst-dl-iter-static.c
@@ -0,0 +1,46 @@
+/* BZ #16046 dl_iterate_phdr static executable test.
+ Copyright (C) 2014-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <link.h>
+
+/* Check that the link map of the static executable itself is iterated
+ over exactly once. */
+
+static int
+callback (struct dl_phdr_info *info, size_t size, void *data)
+{
+ int *count = data;
+
+ if (info->dlpi_name[0] == '\0')
+ (*count)++;
+
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ int count = 0;
+ int status;
+
+ status = dl_iterate_phdr (callback, &count);
+
+ return status || count != 1;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-dlmodcount.c b/REORG.TODO/elf/tst-dlmodcount.c
new file mode 100644
index 0000000000..34c5b25d7f
--- /dev/null
+++ b/REORG.TODO/elf/tst-dlmodcount.c
@@ -0,0 +1,108 @@
+/* Copyright (C) 2004-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Mosberger <davidm@hpl.hp.com>, 2004.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <link.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define SET 0
+#define ADD 1
+#define REMOVE 2
+
+#define leq(l,r) (((r) - (l)) <= ~0ULL / 2)
+
+static int
+callback (struct dl_phdr_info *info, size_t size, void *ptr)
+{
+ static int last_adds = 0, last_subs = 0;
+ intptr_t cmd = (intptr_t) ptr;
+
+ printf (" size = %Zu\n", size);
+ if (size < (offsetof (struct dl_phdr_info, dlpi_subs)
+ + sizeof (info->dlpi_subs)))
+ {
+ fprintf (stderr, "dl_iterate_phdr failed to pass dlpi_adds/dlpi_subs\n");
+ exit (5);
+ }
+
+ printf (" dlpi_adds = %Lu dlpi_subs = %Lu\n",
+ info->dlpi_adds, info->dlpi_subs);
+
+ switch (cmd)
+ {
+ case SET:
+ break;
+
+ case ADD:
+ if (leq (info->dlpi_adds, last_adds))
+ {
+ fprintf (stderr, "dlpi_adds failed to get incremented!\n");
+ exit (3);
+ }
+ break;
+
+ case REMOVE:
+ if (leq (info->dlpi_subs, last_subs))
+ {
+ fprintf (stderr, "dlpi_subs failed to get incremented!\n");
+ exit (4);
+ }
+ break;
+ }
+ last_adds = info->dlpi_adds;
+ last_subs = info->dlpi_subs;
+ return -1;
+}
+
+static void *
+load (const char *path)
+{
+ void *handle;
+
+ printf ("loading `%s'\n", path);
+ handle = dlopen (path, RTLD_LAZY);
+ if (!handle)
+ exit (1);
+ dl_iterate_phdr (callback, (void *)(intptr_t) ADD);
+ return handle;
+}
+
+static void
+unload (const char *path, void *handle)
+{
+ printf ("unloading `%s'\n", path);
+ if (dlclose (handle) < 0)
+ exit (2);
+ dl_iterate_phdr (callback, (void *)(intptr_t) REMOVE);
+}
+
+static int
+do_test (void)
+{
+ void *handle1, *handle2;
+
+ dl_iterate_phdr (callback, (void *)(intptr_t) SET);
+ handle1 = load ("firstobj.so");
+ handle2 = load ("globalmod1.so");
+ unload ("firstobj.so", handle1);
+ unload ("globalmod1.so", handle2);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-dlmopen1.c b/REORG.TODO/elf/tst-dlmopen1.c
new file mode 100644
index 0000000000..24145cfca6
--- /dev/null
+++ b/REORG.TODO/elf/tst-dlmopen1.c
@@ -0,0 +1,80 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <gnu/lib-names.h>
+
+#define TEST_SO "$ORIGIN/tst-dlmopen1mod.so"
+
+static int
+do_test (void)
+{
+ void *h = dlopen (LIBC_SO, RTLD_LAZY|RTLD_NOLOAD);
+ if (h == NULL)
+ {
+ printf ("cannot get handle for %s: %s\n", LIBC_SO, dlerror ());
+ return 1;
+ }
+
+ Lmid_t ns = -10;
+ if (dlinfo (h, RTLD_DI_LMID, &ns) != 0)
+ {
+ printf ("dlinfo for %s in %s failed: %s\n",
+ LIBC_SO, __func__, dlerror ());
+ return 1;
+ }
+
+ if (ns != LM_ID_BASE)
+ {
+ printf ("namespace for %s not LM_ID_BASE\n", LIBC_SO);
+ return 1;
+ }
+
+ if (dlclose (h) != 0)
+ {
+ printf ("dlclose for %s in %s failed: %s\n",
+ LIBC_SO, __func__, dlerror ());
+ return 1;
+ }
+
+ h = dlmopen (LM_ID_NEWLM, TEST_SO, RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot get handle for %s: %s\n",
+ "tst-dlmopen1mod.so", dlerror ());
+ return 1;
+ }
+
+ ns = -10;
+ if (dlinfo (h, RTLD_DI_LMID, &ns) != 0)
+ {
+ printf ("dlinfo for %s in %s failed: %s\n",
+ "tst-dlmopen1mod.so", __func__, dlerror ());
+ return 1;
+ }
+
+ if (ns == LM_ID_BASE)
+ {
+ printf ("namespace for %s is LM_ID_BASE\n", TEST_SO);
+ return 1;
+ }
+
+ int (*fct) (Lmid_t) = dlsym (h, "foo");
+ if (fct == NULL)
+ {
+ printf ("could not find %s: %s\n", "foo", dlerror ());
+ return 1;
+ }
+
+ if (fct (ns) != 0)
+ return 1;
+
+ if (dlclose (h) != 0)
+ {
+ printf ("dlclose for %s in %s failed: %s\n",
+ TEST_SO, __func__, dlerror ());
+ return 1;
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-dlmopen1mod.c b/REORG.TODO/elf/tst-dlmopen1mod.c
new file mode 100644
index 0000000000..142488098a
--- /dev/null
+++ b/REORG.TODO/elf/tst-dlmopen1mod.c
@@ -0,0 +1,59 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <gnu/lib-names.h>
+
+
+static int cnt;
+
+static void
+__attribute ((constructor))
+constr (void)
+{
+ ++cnt;
+}
+
+
+int
+foo (Lmid_t ns2)
+{
+ void *h = dlopen (LIBC_SO, RTLD_LAZY|RTLD_NOLOAD);
+ if (h == NULL)
+ {
+ printf ("cannot get handle for %s: %s\n", LIBC_SO, dlerror ());
+ return 1;
+ }
+
+ Lmid_t ns = -10;
+ if (dlinfo (h, RTLD_DI_LMID, &ns) != 0)
+ {
+ printf ("dlinfo for %s in %s failed: %s\n",
+ LIBC_SO, __func__, dlerror ());
+ return 1;
+ }
+
+ if (ns != ns2)
+ {
+ printf ("namespace for %s not LM_ID_BASE\n", LIBC_SO);
+ return 1;
+ }
+
+ if (dlclose (h) != 0)
+ {
+ printf ("dlclose for %s in %s failed: %s\n",
+ LIBC_SO, __func__, dlerror ());
+ return 1;
+ }
+
+ if (cnt == 0)
+ {
+ puts ("constructor did not run");
+ return 1;
+ }
+ else if (cnt != 1)
+ {
+ puts ("constructor did not run exactly once");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/tst-dlmopen2.c b/REORG.TODO/elf/tst-dlmopen2.c
new file mode 100644
index 0000000000..8489ffba08
--- /dev/null
+++ b/REORG.TODO/elf/tst-dlmopen2.c
@@ -0,0 +1,69 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+#include <gnu/lib-names.h>
+#include <ldsodefs.h>
+
+
+static int
+do_test (void)
+{
+ int result = 0;
+
+ for (int i = 1; i <= 10; ++i)
+ {
+ void *h[DL_NNS - 1];
+ char used[DL_NNS];
+
+ printf ("round %d\n", i);
+
+ memset (used, '\0', sizeof (used));
+ used[LM_ID_BASE] = 1;
+
+ for (int j = 0; j < DL_NNS - 1; ++j)
+ {
+ h[j] = dlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
+ RTLD_LAZY);
+ if (h[j] == NULL)
+ {
+ printf ("round %d, namespace %d: load failed: %s\n",
+ i, j, dlerror ());
+ return 1;
+ }
+ Lmid_t ns;
+ if (dlinfo (h[j], RTLD_DI_LMID, &ns) != 0)
+ {
+ printf ("round %d, namespace %d: dlinfo failed: %s\n",
+ i, j, dlerror ());
+ return 1;
+ }
+ if (ns < 0 || ns >= DL_NNS)
+ {
+ printf ("round %d, namespace %d: invalid namespace %ld",
+ i, j, (long int) ns);
+ result = 1;
+ }
+ else if (used[ns] != 0)
+ {
+ printf ("\
+round %d, namespace %d: duplicate allocate of namespace %ld",
+ i, j, (long int) ns);
+ result = 1;
+ }
+ else
+ used[ns] = 1;
+ }
+
+ for (int j = 0; j < DL_NNS - 1; ++j)
+ if (dlclose (h[j]) != 0)
+ {
+ printf ("round %d, namespace %d: close failed: %s\n",
+ i, j, dlerror ());
+ return 1;
+ }
+ }
+
+ return result;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-dlmopen3.c b/REORG.TODO/elf/tst-dlmopen3.c
new file mode 100644
index 0000000000..8167507784
--- /dev/null
+++ b/REORG.TODO/elf/tst-dlmopen3.c
@@ -0,0 +1,21 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+ void *h = dlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot get handle for %s: %s\n",
+ "tst-dlmopen1mod.so", dlerror ());
+ return 1;
+ }
+
+ /* Do not unload. */
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-dlopen-aout.c b/REORG.TODO/elf/tst-dlopen-aout.c
new file mode 100644
index 0000000000..cccc508966
--- /dev/null
+++ b/REORG.TODO/elf/tst-dlopen-aout.c
@@ -0,0 +1,67 @@
+/* Test case for BZ #16634.
+
+ Verify that incorrectly dlopen()ing an executable without
+ __RTLD_OPENEXEC does not cause assertion in ld.so.
+
+ Copyright (C) 2014-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>.
+
+ Note: this test currently only fails when glibc is configured with
+ --enable-hardcoded-path-in-tests. */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <pthread.h>
+
+__thread int x;
+
+void *
+fn (void *p)
+{
+ return p;
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+ int j;
+
+ for (j = 0; j < 100; ++j)
+ {
+ pthread_t thr;
+ void *p;
+ int rc;
+
+ p = dlopen (argv[0], RTLD_LAZY);
+ if (p != NULL)
+ {
+ fprintf (stderr, "dlopen unexpectedly succeeded\n");
+ return 1;
+ }
+ rc = pthread_create (&thr, NULL, fn, NULL);
+ assert (rc == 0);
+
+ rc = pthread_join (thr, NULL);
+ assert (rc == 0);
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-dlopenrpath.c b/REORG.TODO/elf/tst-dlopenrpath.c
new file mode 100644
index 0000000000..77346d36f9
--- /dev/null
+++ b/REORG.TODO/elf/tst-dlopenrpath.c
@@ -0,0 +1,70 @@
+/* Copyright (C) 2004-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+extern int foo (void);
+
+static const char testsubdir[] = PFX "test-subdir";
+
+
+static int
+do_test (void)
+{
+ struct stat64 st;
+ int result = 1;
+
+ if (mkdir (testsubdir, 0777) != 0
+ && (errno != EEXIST
+ || stat64 (testsubdir, &st) != 0
+ || !S_ISDIR (st.st_mode)))
+ {
+ printf ("cannot create directory %s\n", testsubdir);
+ return 1;
+ }
+
+ if (system ("cp " PFX "firstobj.so " PFX "test-subdir/in-subdir.so") != 0)
+ {
+ puts ("cannot copy DSO");
+ return 1;
+ }
+
+ void *p = dlopen ("in-subdir.so", RTLD_LAZY|RTLD_LOCAL);
+ if (p != NULL)
+ {
+ puts ("succeeded in opening in-subdir.so from do_test");
+ dlclose (p);
+ goto out;
+ }
+
+ result = foo ();
+
+ out:
+ unlink (PFX "test-subdir/in-subdir.so");
+ rmdir (testsubdir);
+
+ return result;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-dlopenrpathmod.c b/REORG.TODO/elf/tst-dlopenrpathmod.c
new file mode 100644
index 0000000000..6d244401bf
--- /dev/null
+++ b/REORG.TODO/elf/tst-dlopenrpathmod.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2004-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+
+int
+foo (void)
+{
+ void *p = dlopen ("in-subdir.so", RTLD_LAZY|RTLD_LOCAL);
+ if (p != NULL)
+ {
+ dlclose (p);
+ return 0;
+ }
+
+ puts ("couldn't open in-subdir.so from foo");
+ return 1;
+}
diff --git a/REORG.TODO/elf/tst-dlsym-error.c b/REORG.TODO/elf/tst-dlsym-error.c
new file mode 100644
index 0000000000..fac8f10ccf
--- /dev/null
+++ b/REORG.TODO/elf/tst-dlsym-error.c
@@ -0,0 +1,113 @@
+/* Test error reporting for dlsym, dlvsym failures.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Used to disambiguate symbol names. */
+static int counter;
+
+static void
+test_one (void *handle, const char *name, void *(func) (void *, const char *),
+ const char *suffix)
+{
+ ++counter;
+ char symbol[32];
+ snprintf (symbol, sizeof (symbol), "no_such_symbol_%d", counter);
+ char *expected_message;
+ if (asprintf (&expected_message, ": undefined symbol: %s%s",
+ symbol, suffix) < 0)
+ {
+ printf ("error: asprintf: %m\n");
+ abort ();
+ }
+
+ void *addr = func (handle, symbol);
+ if (addr != NULL)
+ {
+ printf ("error: %s: found symbol \"no_such_symbol\"\n", name);
+ abort ();
+ }
+ const char *message = dlerror ();
+ if (message == NULL)
+ {
+ printf ("error: %s: missing error message\n", name);
+ abort ();
+ }
+ const char *message_without_path = strchrnul (message, ':');
+ if (strcmp (message_without_path, expected_message) != 0)
+ {
+ printf ("error: %s: unexpected error message: %s\n", name, message);
+ abort ();
+ }
+ free (expected_message);
+
+ message = dlerror ();
+ if (message != NULL)
+ {
+ printf ("error: %s: unexpected error message: %s\n", name, message);
+ abort ();
+ }
+}
+
+static void
+test_handles (const char *name, void *(func) (void *, const char *),
+ const char *suffix)
+{
+ test_one (RTLD_DEFAULT, name, func, suffix);
+ test_one (RTLD_NEXT, name, func, suffix);
+
+ void *handle = dlopen (LIBC_SO, RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("error: cannot dlopen %s: %s\n", LIBC_SO, dlerror ());
+ abort ();
+ }
+ test_one (handle, name, func, suffix);
+ dlclose (handle);
+}
+
+static void *
+dlvsym_no_such_version (void *handle, const char *name)
+{
+ return dlvsym (handle, name, "NO_SUCH_VERSION");
+}
+
+static void *
+dlvsym_glibc_private (void *handle, const char *name)
+{
+ return dlvsym (handle, name, "GLIBC_PRIVATE");
+}
+
+static int
+do_test (void)
+{
+ test_handles ("dlsym", dlsym, "");
+ test_handles ("dlvsym", dlvsym_no_such_version,
+ ", version NO_SUCH_VERSION");
+ test_handles ("dlvsym", dlvsym_glibc_private,
+ ", version GLIBC_PRIVATE");
+
+ return 0;
+}
+
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-env-setuid-tunables.c b/REORG.TODO/elf/tst-env-setuid-tunables.c
new file mode 100644
index 0000000000..afcb146e6d
--- /dev/null
+++ b/REORG.TODO/elf/tst-env-setuid-tunables.c
@@ -0,0 +1,75 @@
+/* Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Verify that tunables correctly filter out unsafe tunables like
+ glibc.malloc.check and glibc.malloc.mmap_threshold but also retain
+ glibc.malloc.mmap_threshold in an unprivileged child. */
+
+/* This is compiled as part of the testsuite but needs to see
+ HAVE_TUNABLES. */
+#define _LIBC 1
+#include "config.h"
+#undef _LIBC
+
+#define test_parent test_parent_tunables
+#define test_child test_child_tunables
+
+static int test_child_tunables (void);
+static int test_parent_tunables (void);
+
+#include "tst-env-setuid.c"
+
+#define CHILD_VALSTRING_VALUE "glibc.malloc.mmap_threshold=4096"
+#define PARENT_VALSTRING_VALUE \
+ "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096"
+
+static int
+test_child_tunables (void)
+{
+ const char *val = getenv ("GLIBC_TUNABLES");
+
+#if HAVE_TUNABLES
+ if (val != NULL && strcmp (val, CHILD_VALSTRING_VALUE) == 0)
+ return 0;
+
+ if (val != NULL)
+ printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
+
+ return 1;
+#else
+ if (val != NULL)
+ {
+ printf ("GLIBC_TUNABLES not cleared\n");
+ return 1;
+ }
+ return 0;
+#endif
+}
+
+static int
+test_parent_tunables (void)
+{
+ const char *val = getenv ("GLIBC_TUNABLES");
+
+ if (val != NULL && strcmp (val, PARENT_VALSTRING_VALUE) == 0)
+ return 0;
+
+ if (val != NULL)
+ printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
+
+ return 1;
+}
diff --git a/REORG.TODO/elf/tst-env-setuid.c b/REORG.TODO/elf/tst-env-setuid.c
new file mode 100644
index 0000000000..eec408eb5d
--- /dev/null
+++ b/REORG.TODO/elf/tst-env-setuid.c
@@ -0,0 +1,296 @@
+/* Copyright (C) 2012-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Verify that tunables correctly filter out unsafe environment variables like
+ MALLOC_CHECK_ and MALLOC_MMAP_THRESHOLD_ but also retain
+ MALLOC_MMAP_THRESHOLD_ in an unprivileged child. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <support/support.h>
+#include <support/test-driver.h>
+
+static char SETGID_CHILD[] = "setgid-child";
+#define CHILD_STATUS 42
+
+/* Return a GID which is not our current GID, but is present in the
+ supplementary group list. */
+static gid_t
+choose_gid (void)
+{
+ const int count = 64;
+ gid_t groups[count];
+ int ret = getgroups (count, groups);
+ if (ret < 0)
+ {
+ printf ("getgroups: %m\n");
+ exit (1);
+ }
+ gid_t current = getgid ();
+ for (int i = 0; i < ret; ++i)
+ {
+ if (groups[i] != current)
+ return groups[i];
+ }
+ return 0;
+}
+
+/* Spawn and execute a program and verify that it returns the CHILD_STATUS. */
+static pid_t
+do_execve (char **args)
+{
+ pid_t kid = vfork ();
+
+ if (kid < 0)
+ {
+ printf ("vfork: %m\n");
+ return -1;
+ }
+
+ if (kid == 0)
+ {
+ /* Child process. */
+ execve (args[0], args, environ);
+ _exit (-errno);
+ }
+
+ if (kid < 0)
+ return 1;
+
+ int status;
+
+ if (waitpid (kid, &status, 0) < 0)
+ {
+ printf ("waitpid: %m\n");
+ return 1;
+ }
+
+ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+ return EXIT_UNSUPPORTED;
+
+ if (!WIFEXITED (status) || WEXITSTATUS (status) != CHILD_STATUS)
+ {
+ printf ("Unexpected exit status %d from child process\n",
+ WEXITSTATUS (status));
+ return 1;
+ }
+ return 0;
+}
+
+/* Copies the executable into a restricted directory, so that we can
+ safely make it SGID with the TARGET group ID. Then runs the
+ executable. */
+static int
+run_executable_sgid (gid_t target)
+{
+ char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
+ test_dir, (intmax_t) getpid ());
+ char *execname = xasprintf ("%s/bin", dirname);
+ int infd = -1;
+ int outfd = -1;
+ int ret = 0;
+ if (mkdir (dirname, 0700) < 0)
+ {
+ printf ("mkdir: %m\n");
+ goto err;
+ }
+ infd = open ("/proc/self/exe", O_RDONLY);
+ if (infd < 0)
+ {
+ printf ("open (/proc/self/exe): %m\n");
+ goto err;
+ }
+ outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
+ if (outfd < 0)
+ {
+ printf ("open (%s): %m\n", execname);
+ goto err;
+ }
+ char buf[4096];
+ for (;;)
+ {
+ ssize_t rdcount = read (infd, buf, sizeof (buf));
+ if (rdcount < 0)
+ {
+ printf ("read: %m\n");
+ goto err;
+ }
+ if (rdcount == 0)
+ break;
+ char *p = buf;
+ char *end = buf + rdcount;
+ while (p != end)
+ {
+ ssize_t wrcount = write (outfd, buf, end - p);
+ if (wrcount == 0)
+ errno = ENOSPC;
+ if (wrcount <= 0)
+ {
+ printf ("write: %m\n");
+ goto err;
+ }
+ p += wrcount;
+ }
+ }
+ if (fchown (outfd, getuid (), target) < 0)
+ {
+ printf ("fchown (%s): %m\n", execname);
+ goto err;
+ }
+ if (fchmod (outfd, 02750) < 0)
+ {
+ printf ("fchmod (%s): %m\n", execname);
+ goto err;
+ }
+ if (close (outfd) < 0)
+ {
+ printf ("close (outfd): %m\n");
+ goto err;
+ }
+ if (close (infd) < 0)
+ {
+ printf ("close (infd): %m\n");
+ goto err;
+ }
+
+ char *args[] = {execname, SETGID_CHILD, NULL};
+
+ ret = do_execve (args);
+
+err:
+ if (outfd >= 0)
+ close (outfd);
+ if (infd >= 0)
+ close (infd);
+ if (execname)
+ {
+ unlink (execname);
+ free (execname);
+ }
+ if (dirname)
+ {
+ rmdir (dirname);
+ free (dirname);
+ }
+ return ret;
+}
+
+#ifndef test_child
+static int
+test_child (void)
+{
+ if (getenv ("MALLOC_CHECK_") != NULL)
+ {
+ printf ("MALLOC_CHECK_ is still set\n");
+ return 1;
+ }
+
+ if (getenv ("MALLOC_MMAP_THRESHOLD_") == NULL)
+ {
+ printf ("MALLOC_MMAP_THRESHOLD_ lost\n");
+ return 1;
+ }
+
+ if (getenv ("LD_HWCAP_MASK") != NULL)
+ {
+ printf ("LD_HWCAP_MASK still set\n");
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef test_parent
+static int
+test_parent (void)
+{
+ if (getenv ("MALLOC_CHECK_") == NULL)
+ {
+ printf ("MALLOC_CHECK_ lost\n");
+ return 1;
+ }
+
+ if (getenv ("MALLOC_MMAP_THRESHOLD_") == NULL)
+ {
+ printf ("MALLOC_MMAP_THRESHOLD_ lost\n");
+ return 1;
+ }
+
+ if (getenv ("LD_HWCAP_MASK") == NULL)
+ {
+ printf ("LD_HWCAP_MASK lost\n");
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+static int
+do_test (int argc, char **argv)
+{
+ /* Setgid child process. */
+ if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0)
+ {
+ if (getgid () == getegid ())
+ {
+ /* This can happen if the file system is mounted nosuid. */
+ fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
+ (intmax_t) getgid ());
+ exit (EXIT_UNSUPPORTED);
+ }
+
+ int ret = test_child ();
+
+ if (ret != 0)
+ exit (1);
+
+ exit (CHILD_STATUS);
+ }
+ else
+ {
+ if (test_parent () != 0)
+ exit (1);
+
+ /* Try running a setgid program. */
+ gid_t target = choose_gid ();
+ if (target == 0)
+ {
+ fprintf (stderr,
+ "Could not find a suitable GID for user %jd, skipping test\n",
+ (intmax_t) getuid ());
+ exit (0);
+ }
+
+ return run_executable_sgid (target);
+ }
+
+ /* Something went wrong and our argv was corrupted. */
+ _exit (1);
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-execstack-mod.c b/REORG.TODO/elf/tst-execstack-mod.c
new file mode 100644
index 0000000000..038e6550b5
--- /dev/null
+++ b/REORG.TODO/elf/tst-execstack-mod.c
@@ -0,0 +1,30 @@
+/* Test module for making nonexecutable stacks executable
+ on load of a DSO that requires executable stacks. */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void callme (void (*callback) (void));
+
+/* This is a function that makes use of executable stack by
+ using a local function trampoline. */
+void
+tryme (void)
+{
+ bool ok = false;
+ void callback (void) { ok = true; }
+
+ callme (&callback);
+
+ if (ok)
+ printf ("DSO called ok (local %p, trampoline %p)\n", &ok, &callback);
+ else
+ abort ();
+}
+
+void
+callme (void (*callback) (void))
+{
+ (*callback) ();
+}
diff --git a/REORG.TODO/elf/tst-execstack-needed.c b/REORG.TODO/elf/tst-execstack-needed.c
new file mode 100644
index 0000000000..8b794a3d47
--- /dev/null
+++ b/REORG.TODO/elf/tst-execstack-needed.c
@@ -0,0 +1,34 @@
+/* Test program for making nonexecutable stacks executable
+ on DT_NEEDED load of a DSO that requires executable stacks. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <error.h>
+
+extern void tryme (void); /* from tst-execstack-mod.so */
+
+static void deeper (void (*f) (void));
+
+static int
+do_test (void)
+{
+ tryme ();
+
+ /* Test that growing the stack region gets new executable pages too. */
+ deeper (&tryme);
+
+ return 0;
+}
+
+static void
+deeper (void (*f) (void))
+{
+ char stack[1100 * 1024];
+ memfrob (stack, sizeof stack);
+ (*f) ();
+ memfrob (stack, sizeof stack);
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-execstack-prog.c b/REORG.TODO/elf/tst-execstack-prog.c
new file mode 100644
index 0000000000..8663153372
--- /dev/null
+++ b/REORG.TODO/elf/tst-execstack-prog.c
@@ -0,0 +1,33 @@
+/* Test program for executable stacks in an executable itself. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <error.h>
+
+#include "tst-execstack-mod.c" /* This defines the `tryme' test function. */
+
+static void deeper (void (*f) (void));
+
+static int
+do_test (void)
+{
+ tryme ();
+
+ /* Test that growing the stack region gets new executable pages too. */
+ deeper (&tryme);
+
+ return 0;
+}
+
+static void
+deeper (void (*f) (void))
+{
+ char stack[1100 * 1024];
+ memfrob (stack, sizeof stack);
+ (*f) ();
+ memfrob (stack, sizeof stack);
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-execstack.c b/REORG.TODO/elf/tst-execstack.c
new file mode 100644
index 0000000000..114f341d76
--- /dev/null
+++ b/REORG.TODO/elf/tst-execstack.c
@@ -0,0 +1,236 @@
+/* Test program for making nonexecutable stacks executable
+ on load of a DSO that requires executable stacks. */
+
+#include <dlfcn.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <error.h>
+#include <stackinfo.h>
+
+static void
+print_maps (void)
+{
+#if 0
+ char *cmd = NULL;
+ asprintf (&cmd, "cat /proc/%d/maps", getpid ());
+ system (cmd);
+ free (cmd);
+#endif
+}
+
+static void deeper (void (*f) (void));
+
+#if USE_PTHREADS
+# include <pthread.h>
+
+static void *
+tryme_thread (void *f)
+{
+ (*((void (*) (void)) f)) ();
+
+ return 0;
+}
+
+static pthread_barrier_t startup_barrier, go_barrier;
+static void *
+waiter_thread (void *arg)
+{
+ void **f = arg;
+ pthread_barrier_wait (&startup_barrier);
+ pthread_barrier_wait (&go_barrier);
+
+ (*((void (*) (void)) *f)) ();
+
+ return 0;
+}
+#endif
+
+static bool allow_execstack = true;
+
+
+static int
+do_test (void)
+{
+ /* Check whether SELinux is enabled and disallows executable stacks. */
+ FILE *fp = fopen ("/selinux/enforce", "r");
+ if (fp != NULL)
+ {
+ char *line = NULL;
+ size_t linelen = 0;
+
+ bool enabled = false;
+ ssize_t n = getline (&line, &linelen, fp);
+ if (n > 0 && line[0] != '0')
+ enabled = true;
+
+ fclose (fp);
+
+ if (enabled)
+ {
+ fp = fopen ("/selinux/booleans/allow_execstack", "r");
+ if (fp != NULL)
+ {
+ n = getline (&line, &linelen, fp);
+ if (n > 0 && line[0] == '0')
+ allow_execstack = false;
+ }
+
+ fclose (fp);
+ }
+ }
+
+ printf ("executable stacks %sallowed\n", allow_execstack ? "" : "not ");
+
+ static void *f; /* Address of this is used in other threads. */
+
+#if USE_PTHREADS
+ /* Create some threads while stacks are nonexecutable. */
+ #define N 5
+ pthread_t thr[N];
+
+ pthread_barrier_init (&startup_barrier, NULL, N + 1);
+ pthread_barrier_init (&go_barrier, NULL, N + 1);
+
+ for (int i = 0; i < N; ++i)
+ {
+ int rc = pthread_create (&thr[i], NULL, &waiter_thread, &f);
+ if (rc)
+ error (1, rc, "pthread_create");
+ }
+
+ /* Make sure they are all there using their stacks. */
+ pthread_barrier_wait (&startup_barrier);
+ puts ("threads waiting");
+#endif
+
+ print_maps ();
+
+#if USE_PTHREADS
+ void *old_stack_addr, *new_stack_addr;
+ size_t stack_size;
+ pthread_t me = pthread_self ();
+ pthread_attr_t attr;
+ int ret = 0;
+
+ ret = pthread_getattr_np (me, &attr);
+ if (ret)
+ {
+ printf ("before execstack: pthread_getattr_np returned error: %s\n",
+ strerror (ret));
+ return 1;
+ }
+
+ ret = pthread_attr_getstack (&attr, &old_stack_addr, &stack_size);
+ if (ret)
+ {
+ printf ("before execstack: pthread_attr_getstack returned error: %s\n",
+ strerror (ret));
+ return 1;
+ }
+# if _STACK_GROWS_DOWN
+ old_stack_addr += stack_size;
+# else
+ old_stack_addr -= stack_size;
+# endif
+#endif
+
+ /* Loading this module should force stacks to become executable. */
+ void *h = dlopen ("tst-execstack-mod.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot load: %s\n", dlerror ());
+ return allow_execstack;
+ }
+
+ f = dlsym (h, "tryme");
+ if (f == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ /* Test if that really made our stack executable.
+ The `tryme' function should crash if not. */
+
+ (*((void (*) (void)) f)) ();
+
+ print_maps ();
+
+#if USE_PTHREADS
+ ret = pthread_getattr_np (me, &attr);
+ if (ret)
+ {
+ printf ("after execstack: pthread_getattr_np returned error: %s\n",
+ strerror (ret));
+ return 1;
+ }
+
+ ret = pthread_attr_getstack (&attr, &new_stack_addr, &stack_size);
+ if (ret)
+ {
+ printf ("after execstack: pthread_attr_getstack returned error: %s\n",
+ strerror (ret));
+ return 1;
+ }
+
+# if _STACK_GROWS_DOWN
+ new_stack_addr += stack_size;
+# else
+ new_stack_addr -= stack_size;
+# endif
+
+ /* It is possible that the dlopen'd module may have been mmapped just below
+ the stack. The stack size is taken as MIN(stack rlimit size, end of last
+ vma) in pthread_getattr_np. If rlimit is set high enough, it is possible
+ that the size may have changed. A subsequent call to
+ pthread_attr_getstack returns the size and (bottom - size) as the
+ stacksize and stackaddr respectively. If the size changes due to the
+ above, then both stacksize and stackaddr can change, but the stack bottom
+ should remain the same, which is computed as stackaddr + stacksize. */
+ if (old_stack_addr != new_stack_addr)
+ {
+ printf ("Stack end changed, old: %p, new: %p\n",
+ old_stack_addr, new_stack_addr);
+ return 1;
+ }
+ printf ("Stack address remains the same: %p\n", old_stack_addr);
+#endif
+
+ /* Test that growing the stack region gets new executable pages too. */
+ deeper ((void (*) (void)) f);
+
+ print_maps ();
+
+#if USE_PTHREADS
+ /* Test that a fresh thread now gets an executable stack. */
+ {
+ pthread_t th;
+ int rc = pthread_create (&th, NULL, &tryme_thread, f);
+ if (rc)
+ error (1, rc, "pthread_create");
+ }
+
+ puts ("threads go");
+ /* The existing threads' stacks should have been changed.
+ Let them run to test it. */
+ pthread_barrier_wait (&go_barrier);
+
+ pthread_exit ((void *) (long int) (! allow_execstack));
+#endif
+
+ return ! allow_execstack;
+}
+
+static void
+deeper (void (*f) (void))
+{
+ char stack[1100 * 1024];
+ memfrob (stack, sizeof stack);
+ (*f) ();
+ memfrob (stack, sizeof stack);
+}
+
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-global1.c b/REORG.TODO/elf/tst-global1.c
new file mode 100644
index 0000000000..5dae74eec0
--- /dev/null
+++ b/REORG.TODO/elf/tst-global1.c
@@ -0,0 +1,38 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+ void *h1 = dlopen ("$ORIGIN/testobj6.so", RTLD_GLOBAL|RTLD_LAZY);
+ if (h1 == NULL)
+ {
+ puts ("cannot open testobj6");
+ return 1;
+ }
+
+ void *h2 = dlopen ("$ORIGIN/testobj2.so",
+ RTLD_GLOBAL|RTLD_DEEPBIND|RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ puts ("cannot open testobj2");
+ return 1;
+ }
+
+ dlclose (h1);
+
+ void (*f) (void) = dlsym (h2, "p");
+ if (f == NULL)
+ {
+ puts ("cannot find p");
+ return 1;
+ }
+
+ f ();
+
+ dlclose (h2);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-gnu2-tls1.c b/REORG.TODO/elf/tst-gnu2-tls1.c
new file mode 100644
index 0000000000..b33b60a301
--- /dev/null
+++ b/REORG.TODO/elf/tst-gnu2-tls1.c
@@ -0,0 +1,51 @@
+/* Test local and global dynamic models for GNU2 TLS.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int * get_gd (void);
+extern void set_gd (int);
+extern int test_gd (int);
+extern int * get_ld (void);
+extern void set_ld (int);
+extern int test_ld (int);
+
+__thread int gd = 1;
+
+static int
+do_test (void)
+{
+ int *p;
+
+ p = get_gd ();
+ set_gd (3);
+ if (*p != 3 || !test_gd (3))
+ abort ();
+
+ p = get_ld ();
+ set_ld (4);
+ if (*p != 4 || !test_ld (4))
+ abort ();
+
+ printf ("PASS\n");
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-gnu2-tls1mod.c b/REORG.TODO/elf/tst-gnu2-tls1mod.c
new file mode 100644
index 0000000000..fa76ab1222
--- /dev/null
+++ b/REORG.TODO/elf/tst-gnu2-tls1mod.c
@@ -0,0 +1,56 @@
+/* DSO used by tst-gnu2-tls1.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+static __thread int ld;
+
+int *
+get_ld (void)
+{
+ return &ld;
+}
+
+void
+set_ld (int i)
+{
+ ld = i;
+}
+
+int
+test_ld (int i)
+{
+ return ld == i;
+}
+extern __thread int gd;
+
+int *
+get_gd (void)
+{
+ return &gd;
+}
+
+void
+set_gd (int i)
+{
+ gd = i;
+}
+
+int
+test_gd (int i)
+{
+ return gd == i;
+}
diff --git a/REORG.TODO/elf/tst-initorder.c b/REORG.TODO/elf/tst-initorder.c
new file mode 100644
index 0000000000..9638382104
--- /dev/null
+++ b/REORG.TODO/elf/tst-initorder.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int
+main( int argc, char *argv[] )
+{
+ printf( "main\n" );
+}
diff --git a/REORG.TODO/elf/tst-initorder.exp b/REORG.TODO/elf/tst-initorder.exp
new file mode 100644
index 0000000000..8718f65765
--- /dev/null
+++ b/REORG.TODO/elf/tst-initorder.exp
@@ -0,0 +1,13 @@
+start_a1
+start_a2
+start_b1
+start_b2
+start_a3
+start_a4
+main
+finish_a4
+finish_a3
+finish_b2
+finish_b1
+finish_a2
+finish_a1
diff --git a/REORG.TODO/elf/tst-initorder2.c b/REORG.TODO/elf/tst-initorder2.c
new file mode 100644
index 0000000000..050f9568b8
--- /dev/null
+++ b/REORG.TODO/elf/tst-initorder2.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+
+#ifndef NAME
+int
+main (void)
+{
+ puts ("main");
+}
+#else
+static void __attribute__ ((constructor))
+init (void)
+{
+ puts ("init: " NAME);
+}
+static void __attribute__ ((destructor))
+fini (void)
+{
+ puts ("fini: " NAME);
+}
+#endif
diff --git a/REORG.TODO/elf/tst-initorder2.exp b/REORG.TODO/elf/tst-initorder2.exp
new file mode 100644
index 0000000000..5169489b85
--- /dev/null
+++ b/REORG.TODO/elf/tst-initorder2.exp
@@ -0,0 +1,9 @@
+init: d
+init: c
+init: b
+init: a
+main
+fini: a
+fini: b
+fini: c
+fini: d
diff --git a/REORG.TODO/elf/tst-initordera1.c b/REORG.TODO/elf/tst-initordera1.c
new file mode 100644
index 0000000000..f161257142
--- /dev/null
+++ b/REORG.TODO/elf/tst-initordera1.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_a1( void ) __attribute__((constructor));
+extern void finish_a1( void ) __attribute__((destructor));
+
+void
+start_a1( void )
+{
+ printf( "start_a1\n" );
+}
+
+void
+finish_a1( void )
+{
+ printf( "finish_a1\n" );
+}
diff --git a/REORG.TODO/elf/tst-initordera2.c b/REORG.TODO/elf/tst-initordera2.c
new file mode 100644
index 0000000000..a5a9b42ff6
--- /dev/null
+++ b/REORG.TODO/elf/tst-initordera2.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_a2( void ) __attribute__((constructor));
+extern void finish_a2( void ) __attribute__((destructor));
+
+void
+start_a2( void )
+{
+ printf( "start_a2\n" );
+}
+
+void
+finish_a2( void )
+{
+ printf( "finish_a2\n" );
+}
diff --git a/REORG.TODO/elf/tst-initordera3.c b/REORG.TODO/elf/tst-initordera3.c
new file mode 100644
index 0000000000..1c7f496e9a
--- /dev/null
+++ b/REORG.TODO/elf/tst-initordera3.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_a3( void ) __attribute__((constructor));
+extern void finish_a3( void ) __attribute__((destructor));
+
+void
+start_a3( void )
+{
+ printf( "start_a3\n" );
+}
+
+void
+finish_a3( void )
+{
+ printf( "finish_a3\n" );
+}
diff --git a/REORG.TODO/elf/tst-initordera4.c b/REORG.TODO/elf/tst-initordera4.c
new file mode 100644
index 0000000000..70b9f5e392
--- /dev/null
+++ b/REORG.TODO/elf/tst-initordera4.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_a4( void ) __attribute__((constructor));
+extern void finish_a4( void ) __attribute__((destructor));
+
+void
+start_a4( void )
+{
+ printf( "start_a4\n" );
+}
+
+void
+finish_a4( void )
+{
+ printf( "finish_a4\n" );
+}
diff --git a/REORG.TODO/elf/tst-initorderb1.c b/REORG.TODO/elf/tst-initorderb1.c
new file mode 100644
index 0000000000..993ea3fe30
--- /dev/null
+++ b/REORG.TODO/elf/tst-initorderb1.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_b1( void ) __attribute__((constructor));
+extern void finish_b1( void ) __attribute__((destructor));
+
+void
+start_b1( void )
+{
+ printf( "start_b1\n" );
+}
+
+void
+finish_b1( void )
+{
+ printf( "finish_b1\n" );
+}
diff --git a/REORG.TODO/elf/tst-initorderb2.c b/REORG.TODO/elf/tst-initorderb2.c
new file mode 100644
index 0000000000..3334dda0a9
--- /dev/null
+++ b/REORG.TODO/elf/tst-initorderb2.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_b2( void ) __attribute__((constructor));
+extern void finish_b2( void ) __attribute__((destructor));
+
+void
+start_b2( void )
+{
+ printf( "start_b2\n" );
+}
+
+void
+finish_b2( void )
+{
+ printf( "finish_b2\n" );
+}
diff --git a/REORG.TODO/elf/tst-latepthread.c b/REORG.TODO/elf/tst-latepthread.c
new file mode 100644
index 0000000000..ca2f82243d
--- /dev/null
+++ b/REORG.TODO/elf/tst-latepthread.c
@@ -0,0 +1,104 @@
+/* Test that loading libpthread does not break ld.so exceptions (bug 16628).
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ void *handle = dlopen ("tst-latepthreadmod.so", RTLD_LOCAL | RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("error: dlopen failed: %s\n", dlerror ());
+ return 1;
+ }
+ void *ptr = dlsym (handle, "trigger_dynlink_failure");
+ if (ptr == NULL)
+ {
+ printf ("error: dlsym failed: %s\n", dlerror ());
+ return 1;
+ }
+ int (*func) (void) = ptr;
+
+ /* Run the actual test in a subprocess, to capture the error. */
+ int fds[2];
+ if (pipe (fds) < 0)
+ {
+ printf ("error: pipe: %m\n");
+ return 1;
+ }
+ pid_t pid = fork ();
+ if (pid < 0)
+ {
+ printf ("error: fork: %m\n");
+ return 1;
+ }
+ else if (pid == 0)
+ {
+ if (dup2 (fds[1], STDERR_FILENO) < 0)
+ _exit (2);
+ /* Trigger an abort. */
+ func ();
+ _exit (3);
+ }
+ /* NB: This assumes that the abort message is so short that the pipe
+ does not block. */
+ int status;
+ if (waitpid (pid, &status, 0) < 0)
+ {
+ printf ("error: waitpid: %m\n");
+ return 1;
+ }
+
+ /* Check the printed error message. */
+ if (close (fds[1]) < 0)
+ {
+ printf ("error: close: %m\n");
+ return 1;
+ }
+ char buf[512];
+ /* Leave room for the NUL terminator. */
+ ssize_t ret = read (fds[0], buf, sizeof (buf) - 1);
+ if (ret < 0)
+ {
+ printf ("error: read: %m\n");
+ return 1;
+ }
+ if (ret > 0 && buf[ret - 1] == '\n')
+ --ret;
+ buf[ret] = '\0';
+ printf ("info: exit status: %d, message: %s\n", status, buf);
+ if (strstr (buf, "undefined symbol: this_function_is_not_defined") == NULL)
+ {
+ printf ("error: message does not contain expected string\n");
+ return 1;
+ }
+ if (!WIFEXITED (status) || WEXITSTATUS (status) != 127)
+ {
+ printf ("error: unexpected process exit status\n");
+ return 1;
+ }
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-latepthreadmod.c b/REORG.TODO/elf/tst-latepthreadmod.c
new file mode 100644
index 0000000000..35a82d388b
--- /dev/null
+++ b/REORG.TODO/elf/tst-latepthreadmod.c
@@ -0,0 +1,33 @@
+/* DSO which links against libpthread and triggers a lazy binding.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is compiled into a DSO which loads libpthread, but fails
+ the dynamic linker afterwards. */
+
+#include <pthread.h>
+
+/* Link in libpthread. */
+void *pthread_create_ptr = &pthread_create;
+
+int this_function_is_not_defined (void);
+
+int
+trigger_dynlink_failure (void)
+{
+ return this_function_is_not_defined ();
+}
diff --git a/REORG.TODO/elf/tst-ldconfig-X.sh b/REORG.TODO/elf/tst-ldconfig-X.sh
new file mode 100644
index 0000000000..e97ca89946
--- /dev/null
+++ b/REORG.TODO/elf/tst-ldconfig-X.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# Test that ldconfig -X does not remove stale symbolic links.
+# Copyright (C) 2000-2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+set -ex
+
+common_objpfx=$1
+test_wrapper_env=$2
+run_program_env=$3
+
+testroot="${common_objpfx}elf/bug19610-test-directory"
+cleanup () {
+ rm -rf "$testroot"
+}
+trap cleanup 0
+
+rm -rf "$testroot"
+mkdir -p $testroot/lib $testroot/etc
+
+# Relative symbolic link target.
+ln -s libdoesnotexist.so.1.1 $testroot/lib/libdoesnotexist.so.1
+
+# Absolute symbolic link target.
+ln -s $testroot/opt/sw/lib/libdoesnotexist2.so.1.1 $testroot/lib/
+
+errors=0
+check_files () {
+ for name in libdoesnotexist.so.1 libdoesnotexist2.so.1.1 ; do
+ path="$testroot/lib/$name"
+ if test ! -h $path ; then
+ echo "error: missing file: $path"
+ errors=1
+ fi
+ done
+}
+
+check_files
+
+${test_wrapper_env} \
+${run_program_env} \
+${common_objpfx}elf/ldconfig -X -f /dev/null \
+ -C $testroot/etc/ld.so.cache \
+ $testroot/lib
+
+check_files
+
+exit $errors
diff --git a/REORG.TODO/elf/tst-leaks1-static.c b/REORG.TODO/elf/tst-leaks1-static.c
new file mode 100644
index 0000000000..b956d66905
--- /dev/null
+++ b/REORG.TODO/elf/tst-leaks1-static.c
@@ -0,0 +1 @@
+#include "tst-leaks1.c"
diff --git a/REORG.TODO/elf/tst-leaks1.c b/REORG.TODO/elf/tst-leaks1.c
new file mode 100644
index 0000000000..d67e8269c4
--- /dev/null
+++ b/REORG.TODO/elf/tst-leaks1.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+ mtrace ();
+
+ int ret = 0;
+ for (int i = 0; i < 10; i++)
+ {
+ void *h = dlopen (i < 5 ? "./tst-leaks1.c"
+ : "$ORIGIN/tst-leaks1.o", RTLD_LAZY);
+ if (h != NULL)
+ {
+ puts ("dlopen unexpectedly succeeded");
+ ret = 1;
+ dlclose (h);
+ }
+ }
+
+ return ret;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-linkall-static.c b/REORG.TODO/elf/tst-linkall-static.c
new file mode 100644
index 0000000000..8f40657244
--- /dev/null
+++ b/REORG.TODO/elf/tst-linkall-static.c
@@ -0,0 +1,52 @@
+/* Test static linking against multiple libraries, to find symbol conflicts.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#include <math.h>
+#include <pthread.h>
+#include <crypt.h>
+#include <resolv.h>
+#include <dlfcn.h>
+#include <utmp.h>
+#include <aio.h>
+#include <netdb.h>
+
+/* These references force linking the executable against central
+ functions in the static libraries, pulling significant parts of
+ each library into the link. */
+void *references[] =
+ {
+ &pow, /* libm */
+ &pthread_create, /* libpthread */
+#if USE_CRYPT
+ &crypt, /* libcrypt */
+#endif
+ &res_send, /* libresolv */
+ &dlopen, /* libdl */
+ &login, /* libutil */
+ &aio_init, /* librt */
+ &getaddrinfo_a, /* libanl */
+ };
+
+static int
+do_test (void)
+{
+ /* This is a link-time test. There is nothing to run here. */
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-nodelete-dlclose-dso.c b/REORG.TODO/elf/tst-nodelete-dlclose-dso.c
new file mode 100644
index 0000000000..4042c78b8a
--- /dev/null
+++ b/REORG.TODO/elf/tst-nodelete-dlclose-dso.c
@@ -0,0 +1,90 @@
+/* Bug 11941: Improper assert map->l_init_called in dlclose.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This is the primary DSO that is loaded by the appliation. This DSO
+ then loads a plugin with RTLD_NODELETE. This plugin depends on this
+ DSO. This dependency chain means that at application shutdown the
+ plugin will be destructed first. Thus by the time this DSO is
+ destructed we will be calling dlclose on an object that has already
+ been destructed. It is allowed to call dlclose in this way and
+ should not assert. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+/* Plugin to load. */
+static void *plugin_lib = NULL;
+/* Plugin function. */
+static void (*plugin_func) (void);
+#define LIB_PLUGIN "tst-nodelete-dlclose-plugin.so"
+
+/* This function is never called but the plugin references it.
+ We do this to avoid any future --as-needed from removing the
+ plugin's DT_NEEDED on this DSO (required for the test). */
+void
+primary_reference (void)
+{
+ printf ("INFO: Called primary_reference function.\n");
+}
+
+void
+primary (void)
+{
+ char *error;
+
+ plugin_lib = dlopen (LIB_PLUGIN, RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE);
+ if (plugin_lib == NULL)
+ {
+ printf ("ERROR: Unable to load plugin library.\n");
+ exit (EXIT_FAILURE);
+ }
+ dlerror ();
+
+ plugin_func = (void (*) (void)) dlsym (plugin_lib, "plugin_func");
+ error = dlerror ();
+ if (error != NULL)
+ {
+ printf ("ERROR: Unable to find symbol with error \"%s\".",
+ error);
+ exit (EXIT_FAILURE);
+ }
+
+ return;
+}
+
+__attribute__ ((destructor))
+static void
+primary_dtor (void)
+{
+ int ret;
+
+ printf ("INFO: Calling primary destructor.\n");
+
+ /* The destructor runs in the test driver also, which
+ hasn't called primary, in that case do nothing. */
+ if (plugin_lib == NULL)
+ return;
+
+ ret = dlclose (plugin_lib);
+ if (ret != 0)
+ {
+ printf ("ERROR: Calling dlclose failed with \"%s\"\n",
+ dlerror ());
+ exit (EXIT_FAILURE);
+ }
+}
diff --git a/REORG.TODO/elf/tst-nodelete-dlclose-plugin.c b/REORG.TODO/elf/tst-nodelete-dlclose-plugin.c
new file mode 100644
index 0000000000..00c84d0bc0
--- /dev/null
+++ b/REORG.TODO/elf/tst-nodelete-dlclose-plugin.c
@@ -0,0 +1,40 @@
+/* Bug 11941: Improper assert map->l_init_called in dlclose.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This DSO simulates a plugin with a dependency on the
+ primary DSO loaded by the appliation. */
+#include <stdio.h>
+
+extern void primary_reference (void);
+
+void
+plugin_func (void)
+{
+ printf ("INFO: Calling plugin function.\n");
+ /* Need a reference to the DSO to ensure that a potential --as-needed
+ doesn't remove the DT_NEEDED entry which we rely upon to ensure
+ destruction ordering. */
+ primary_reference ();
+}
+
+__attribute__ ((destructor))
+static void
+plugin_dtor (void)
+{
+ printf ("INFO: Calling plugin destructor.\n");
+}
diff --git a/REORG.TODO/elf/tst-nodelete-dlclose.c b/REORG.TODO/elf/tst-nodelete-dlclose.c
new file mode 100644
index 0000000000..178673e9d0
--- /dev/null
+++ b/REORG.TODO/elf/tst-nodelete-dlclose.c
@@ -0,0 +1,35 @@
+/* Bug 11941: Improper assert map->l_init_called in dlclose.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This simulates an application using the primary DSO which loads the
+ plugin DSO. */
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void primary (void);
+
+static int
+do_test (void)
+{
+ printf ("INFO: Starting application.\n");
+ primary ();
+ printf ("INFO: Exiting application.\n");
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-nodelete-opened-lib.c b/REORG.TODO/elf/tst-nodelete-opened-lib.c
new file mode 100644
index 0000000000..3e1dcdfc1b
--- /dev/null
+++ b/REORG.TODO/elf/tst-nodelete-opened-lib.c
@@ -0,0 +1,19 @@
+/* Verify that objects opened with RTLD_NODELETE are not unloaded - the DSO.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+int foo_var = 42;
diff --git a/REORG.TODO/elf/tst-nodelete-opened.c b/REORG.TODO/elf/tst-nodelete-opened.c
new file mode 100644
index 0000000000..d71efa4603
--- /dev/null
+++ b/REORG.TODO/elf/tst-nodelete-opened.c
@@ -0,0 +1,68 @@
+/* Verify that an already opened DSO opened agained with RTLD_NODELETE actually
+ sets the NODELETE flag.
+
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+do_test (void)
+{
+ void *h1 = dlopen ("$ORIGIN/tst-nodelete-opened-lib.so", RTLD_LAZY);
+ if (h1 == NULL)
+ {
+ printf ("h1: failed to open DSO: %s\n", dlerror ());
+ return 1;
+ }
+
+ void *h2 = dlopen ("$ORIGIN/tst-nodelete-opened-lib.so",
+ RTLD_LAZY | RTLD_NODELETE);
+ if (h2 == NULL)
+ {
+ printf ("h2: failed to open DSO: %s\n", dlerror ());
+ return 1;
+ }
+
+ int *foo = dlsym (h2, "foo_var");
+ if (foo == NULL)
+ {
+ printf ("failed to load symbol foo_var: %s\n", dlerror ());
+ return 1;
+ }
+
+ if (dlclose (h1) != 0)
+ {
+ printf ("h1: dlclose failed: %s\n", dlerror ());
+ return 1;
+ }
+
+ if (dlclose (h2) != 0)
+ {
+ printf ("h2: dlclose failed: %s\n", dlerror ());
+ return 1;
+ }
+
+ /* This FOO dereference will crash with a segfault if the DSO was
+ unloaded. */
+ printf ("foo == %d\n", *foo);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-nodelete-rtldmod.cc b/REORG.TODO/elf/tst-nodelete-rtldmod.cc
new file mode 100644
index 0000000000..740e1d8181
--- /dev/null
+++ b/REORG.TODO/elf/tst-nodelete-rtldmod.cc
@@ -0,0 +1,6 @@
+extern int not_exist (void);
+
+int foo (void)
+{
+ return not_exist ();
+}
diff --git a/REORG.TODO/elf/tst-nodelete-uniquemod.cc b/REORG.TODO/elf/tst-nodelete-uniquemod.cc
new file mode 100644
index 0000000000..632b303d58
--- /dev/null
+++ b/REORG.TODO/elf/tst-nodelete-uniquemod.cc
@@ -0,0 +1,14 @@
+extern int not_exist (void);
+
+inline int make_unique (void)
+{
+ /* Static variables in inline functions and classes
+ generate STB_GNU_UNIQUE symbols. */
+ static int unique;
+ return ++unique;
+}
+
+int foo (void)
+{
+ return make_unique () + not_exist ();
+}
diff --git a/REORG.TODO/elf/tst-nodelete-zmod.cc b/REORG.TODO/elf/tst-nodelete-zmod.cc
new file mode 100644
index 0000000000..740e1d8181
--- /dev/null
+++ b/REORG.TODO/elf/tst-nodelete-zmod.cc
@@ -0,0 +1,6 @@
+extern int not_exist (void);
+
+int foo (void)
+{
+ return not_exist ();
+}
diff --git a/REORG.TODO/elf/tst-nodelete.cc b/REORG.TODO/elf/tst-nodelete.cc
new file mode 100644
index 0000000000..5752e7df26
--- /dev/null
+++ b/REORG.TODO/elf/tst-nodelete.cc
@@ -0,0 +1,50 @@
+#include "../dlfcn/dlfcn.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+ int result = 0;
+
+ /* This is a test for correct handling of dlopen failures for library that
+ is loaded with RTLD_NODELETE flag. The first dlopen should fail because
+ of undefined symbols in shared library. The second dlopen then verifies
+ that library was properly unloaded. */
+ if (dlopen ("tst-nodelete-rtldmod.so", RTLD_NOW | RTLD_NODELETE) != NULL
+ || dlopen ("tst-nodelete-rtldmod.so", RTLD_LAZY | RTLD_NOLOAD) != NULL)
+ {
+ printf ("RTLD_NODELETE test failed\n");
+ result = 1;
+ }
+
+ /* This is a test for correct handling of dlopen failures for library that
+ is linked with '-z nodelete' option and hence has DF_1_NODELETE flag.
+ The first dlopen should fail because of undefined symbols in shared
+ library. The second dlopen then verifies that library was properly
+ unloaded. */
+ if (dlopen ("tst-nodelete-zmod.so", RTLD_NOW) != NULL
+ || dlopen ("tst-nodelete-zmod.so", RTLD_LAZY | RTLD_NOLOAD) != NULL)
+ {
+ printf ("-z nodelete test failed\n");
+ result = 1;
+ }
+
+ /* This is a test for correct handling of dlopen failures for library
+ with unique symbols. The first dlopen should fail because of undefined
+ symbols in shared library. The second dlopen then verifies that library
+ was properly unloaded. */
+ if (dlopen ("tst-nodelete-uniquemod.so", RTLD_NOW) != NULL
+ || dlopen ("tst-nodelete-uniquemod.so", RTLD_LAZY | RTLD_NOLOAD) != NULL)
+ {
+ printf ("Unique symbols test failed\n");
+ result = 1;
+ }
+
+ if (result == 0)
+ printf ("SUCCESS\n");
+
+ return result;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-nodelete2.c b/REORG.TODO/elf/tst-nodelete2.c
new file mode 100644
index 0000000000..010c4ae237
--- /dev/null
+++ b/REORG.TODO/elf/tst-nodelete2.c
@@ -0,0 +1,36 @@
+#include "../dlfcn/dlfcn.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <gnu/lib-names.h>
+
+static int
+do_test (void)
+{
+ int result = 0;
+
+ printf ("\nOpening pthread library.\n");
+ void *pthread = dlopen (LIBPTHREAD_SO, RTLD_LAZY);
+
+ /* This is a test for correct DF_1_NODELETE clearing when dlopen failure
+ happens. We should clear DF_1_NODELETE for failed library only, because
+ doing this for others (e.g. libpthread) might cause them to be unloaded,
+ that may lead to some global references (e.g. __rtld_lock_unlock) to be
+ broken. The dlopen should fail because of undefined symbols in shared
+ library, that cause DF_1_NODELETE to be cleared. For libpthread, this
+ flag should be set, because if not, SIGSEGV will happen in dlclose. */
+ if (dlopen ("tst-nodelete2mod.so", RTLD_NOW) != NULL)
+ {
+ printf ("Unique symbols test failed\n");
+ result = 1;
+ }
+
+ if (pthread)
+ dlclose (pthread);
+
+ if (result == 0)
+ printf ("SUCCESS\n");
+
+ return result;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-nodelete2mod.c b/REORG.TODO/elf/tst-nodelete2mod.c
new file mode 100644
index 0000000000..e88c756f5e
--- /dev/null
+++ b/REORG.TODO/elf/tst-nodelete2mod.c
@@ -0,0 +1,7 @@
+/* Undefined symbol. */
+extern int not_exist (void);
+
+int foo (void)
+{
+ return not_exist ();
+}
diff --git a/REORG.TODO/elf/tst-noload.c b/REORG.TODO/elf/tst-noload.c
new file mode 100644
index 0000000000..3fb2895e2c
--- /dev/null
+++ b/REORG.TODO/elf/tst-noload.c
@@ -0,0 +1,72 @@
+/* Verify that RTLD_NOLOAD works as expected.
+
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <gnu/lib-names.h>
+
+static int
+do_test (void)
+{
+ /* Test that no object is loaded with RTLD_NOLOAD. */
+ void *h1 = dlopen (LIBM_SO, RTLD_LAZY | RTLD_NOLOAD);
+ if (h1 != NULL)
+ {
+ printf ("h1: DSO has been loaded while it should have not\n");
+ return 1;
+ }
+
+ /* This used to segfault in some glibc versions. */
+ void *h2 = dlopen (LIBM_SO, RTLD_LAZY | RTLD_NOLOAD | RTLD_NODELETE);
+ if (h2 != NULL)
+ {
+ printf ("h2: DSO has been loaded while it should have not\n");
+ return 1;
+ }
+
+ /* Test that loading an already loaded object returns the same. */
+ void *h3 = dlopen (LIBM_SO, RTLD_LAZY);
+ if (h3 == NULL)
+ {
+ printf ("h3: failed to open DSO: %s\n", dlerror ());
+ return 1;
+ }
+ void *h4 = dlopen (LIBM_SO, RTLD_LAZY | RTLD_NOLOAD);
+ if (h4 == NULL)
+ {
+ printf ("h4: failed to open DSO: %s\n", dlerror ());
+ return 1;
+ }
+ if (h4 != h3)
+ {
+ printf ("h4: should return the same object\n");
+ return 1;
+ }
+
+ /* Cleanup */
+ if (dlclose (h3) != 0)
+ {
+ printf ("h3: dlclose failed: %s\n", dlerror ());
+ return 1;
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-null-argv-lib.c b/REORG.TODO/elf/tst-null-argv-lib.c
new file mode 100644
index 0000000000..12af03ba95
--- /dev/null
+++ b/REORG.TODO/elf/tst-null-argv-lib.c
@@ -0,0 +1,24 @@
+/* Verify that program does not crash when LD_DEBUG is set and the program name
+ is not available. This is the library.
+ Copyright (C) 2013-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+void
+foo (void)
+{
+ return;
+}
diff --git a/REORG.TODO/elf/tst-null-argv.c b/REORG.TODO/elf/tst-null-argv.c
new file mode 100644
index 0000000000..21b87327c1
--- /dev/null
+++ b/REORG.TODO/elf/tst-null-argv.c
@@ -0,0 +1,36 @@
+/* Verify that program does not crash when LD_DEBUG is set and the program name
+ is not available.
+ Copyright (C) 2013-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+extern void foo (void);
+
+int
+do_test (int argc, char **argv)
+{
+ argv[0] = argv[1];
+ argc--;
+
+ /* This should result in a symbol lookup, causing a volley of debug output
+ when LD_DEBUG=symbols. */
+ foo ();
+
+ return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-order-a1.c b/REORG.TODO/elf/tst-order-a1.c
new file mode 100644
index 0000000000..f161257142
--- /dev/null
+++ b/REORG.TODO/elf/tst-order-a1.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_a1( void ) __attribute__((constructor));
+extern void finish_a1( void ) __attribute__((destructor));
+
+void
+start_a1( void )
+{
+ printf( "start_a1\n" );
+}
+
+void
+finish_a1( void )
+{
+ printf( "finish_a1\n" );
+}
diff --git a/REORG.TODO/elf/tst-order-a2.c b/REORG.TODO/elf/tst-order-a2.c
new file mode 100644
index 0000000000..a5a9b42ff6
--- /dev/null
+++ b/REORG.TODO/elf/tst-order-a2.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_a2( void ) __attribute__((constructor));
+extern void finish_a2( void ) __attribute__((destructor));
+
+void
+start_a2( void )
+{
+ printf( "start_a2\n" );
+}
+
+void
+finish_a2( void )
+{
+ printf( "finish_a2\n" );
+}
diff --git a/REORG.TODO/elf/tst-order-a3.c b/REORG.TODO/elf/tst-order-a3.c
new file mode 100644
index 0000000000..1c7f496e9a
--- /dev/null
+++ b/REORG.TODO/elf/tst-order-a3.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_a3( void ) __attribute__((constructor));
+extern void finish_a3( void ) __attribute__((destructor));
+
+void
+start_a3( void )
+{
+ printf( "start_a3\n" );
+}
+
+void
+finish_a3( void )
+{
+ printf( "finish_a3\n" );
+}
diff --git a/REORG.TODO/elf/tst-order-a4.c b/REORG.TODO/elf/tst-order-a4.c
new file mode 100644
index 0000000000..70b9f5e392
--- /dev/null
+++ b/REORG.TODO/elf/tst-order-a4.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_a4( void ) __attribute__((constructor));
+extern void finish_a4( void ) __attribute__((destructor));
+
+void
+start_a4( void )
+{
+ printf( "start_a4\n" );
+}
+
+void
+finish_a4( void )
+{
+ printf( "finish_a4\n" );
+}
diff --git a/REORG.TODO/elf/tst-order-b1.c b/REORG.TODO/elf/tst-order-b1.c
new file mode 100644
index 0000000000..993ea3fe30
--- /dev/null
+++ b/REORG.TODO/elf/tst-order-b1.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_b1( void ) __attribute__((constructor));
+extern void finish_b1( void ) __attribute__((destructor));
+
+void
+start_b1( void )
+{
+ printf( "start_b1\n" );
+}
+
+void
+finish_b1( void )
+{
+ printf( "finish_b1\n" );
+}
diff --git a/REORG.TODO/elf/tst-order-b2.c b/REORG.TODO/elf/tst-order-b2.c
new file mode 100644
index 0000000000..3334dda0a9
--- /dev/null
+++ b/REORG.TODO/elf/tst-order-b2.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void start_b2( void ) __attribute__((constructor));
+extern void finish_b2( void ) __attribute__((destructor));
+
+void
+start_b2( void )
+{
+ printf( "start_b2\n" );
+}
+
+void
+finish_b2( void )
+{
+ printf( "finish_b2\n" );
+}
diff --git a/REORG.TODO/elf/tst-order-main.c b/REORG.TODO/elf/tst-order-main.c
new file mode 100644
index 0000000000..2a90130db6
--- /dev/null
+++ b/REORG.TODO/elf/tst-order-main.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+ printf( "main\n" );
+ exit(EXIT_SUCCESS);
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-pathopt.c b/REORG.TODO/elf/tst-pathopt.c
new file mode 100644
index 0000000000..e2c96fbc72
--- /dev/null
+++ b/REORG.TODO/elf/tst-pathopt.c
@@ -0,0 +1,41 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int
+do_test (void)
+{
+ void *h;
+ int (*fp) (int);
+ int result;
+
+ mtrace ();
+
+ h = dlopen ("renamed.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("failed to load \"%s\": %s\n", "renamed.so", dlerror ());
+ exit (1);
+ }
+
+ fp = dlsym (h, "in_renamed");
+ if (fp == NULL)
+ {
+ printf ("lookup of \"%s\" failed: %s\n", "in_renamed", dlerror ());
+ exit (1);
+ }
+
+ result = fp (10);
+
+ if (dlclose (h) != 0)
+ {
+ printf ("failed to close \"%s\": %s\n", "renamed.so", dlerror ());
+ exit (1);
+ }
+
+ return result;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-pathopt.sh b/REORG.TODO/elf/tst-pathopt.sh
new file mode 100755
index 0000000000..4183a697dc
--- /dev/null
+++ b/REORG.TODO/elf/tst-pathopt.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Test lookup path optimization.
+# Copyright (C) 2000-2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+set -e
+
+common_objpfx=$1
+test_wrapper_env=$2
+run_program_env=$3
+
+test -e ${common_objpfx}elf/will-be-empty &&
+ rm -fr ${common_objpfx}elf/will-be-empty
+test -d ${common_objpfx}elf/for-renamed ||
+ mkdir ${common_objpfx}elf/for-renamed
+
+cp ${common_objpfx}elf/pathoptobj.so ${common_objpfx}elf/for-renamed/renamed.so
+
+${test_wrapper_env} \
+${run_program_env} \
+LD_LIBRARY_PATH=${common_objpfx}elf/will-be-empty:${common_objpfx}elf/for-renamed:${common_objpfx}.:${common_objpfx}dlfcn \
+ ${common_objpfx}elf/ld.so ${common_objpfx}elf/tst-pathopt \
+ > ${common_objpfx}elf/tst-pathopt.out
+
+exit $?
diff --git a/REORG.TODO/elf/tst-pie1.c b/REORG.TODO/elf/tst-pie1.c
new file mode 100644
index 0000000000..75d941f21f
--- /dev/null
+++ b/REORG.TODO/elf/tst-pie1.c
@@ -0,0 +1,5 @@
+int
+foo (void)
+{
+ return 34;
+}
diff --git a/REORG.TODO/elf/tst-pie2.c b/REORG.TODO/elf/tst-pie2.c
new file mode 100644
index 0000000000..32943bbc1a
--- /dev/null
+++ b/REORG.TODO/elf/tst-pie2.c
@@ -0,0 +1,40 @@
+/* Test case for BZ #16381
+
+ Copyright (C) 2014-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+
+#include <assert.h>
+
+static int g;
+
+void init_g (void) __attribute__((constructor));
+
+void
+init_g (void)
+{
+ assert (g == 0);
+ g += 1;
+}
+
+static int
+do_test (void)
+{
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-piemod1.c b/REORG.TODO/elf/tst-piemod1.c
new file mode 100644
index 0000000000..72d7e0a187
--- /dev/null
+++ b/REORG.TODO/elf/tst-piemod1.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+
+int
+foo (void)
+{
+ return 21;
+}
+
+static int
+do_test (void)
+{
+ int val = foo ();
+ if (val != 34)
+ {
+ printf ("foo () returned %d\n", val);
+ return 1;
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-prelink.c b/REORG.TODO/elf/tst-prelink.c
new file mode 100644
index 0000000000..7435c321d3
--- /dev/null
+++ b/REORG.TODO/elf/tst-prelink.c
@@ -0,0 +1,29 @@
+/* Test the output from the environment variable, LD_TRACE_PRELINKING,
+ for prelink.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+ fprintf (stdout, "hello\n");
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-prelink.exp b/REORG.TODO/elf/tst-prelink.exp
new file mode 100644
index 0000000000..b35b4c9705
--- /dev/null
+++ b/REORG.TODO/elf/tst-prelink.exp
@@ -0,0 +1 @@
+/0 stdout
diff --git a/REORG.TODO/elf/tst-protected1a.c b/REORG.TODO/elf/tst-protected1a.c
new file mode 100644
index 0000000000..4267b951c4
--- /dev/null
+++ b/REORG.TODO/elf/tst-protected1a.c
@@ -0,0 +1,234 @@
+/* Test the protected visibility when main is linked with moda and modb
+ in that order:
+ 1. Protected symbols, protected1, protected2 and protected3, defined
+ in moda, are used in moda.
+ 2. Protected symbol, protected3, defined in modb, are used in modb.
+ 3. Symbol, protected1, defined in moda, is also used in main and modb.
+ 4. Symbol, protected2, defined in main, is used in main.
+ 5. Symbol, protected3, defined in moda, is also used in main.
+
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file must be compiled as PIE to avoid copy relocation when
+ accessing protected symbols defined in shared libaries since copy
+ relocation doesn't work with protected symbols and linker in
+ binutils 2.26 enforces this rule. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tst-protected1mod.h"
+
+/* Prototype for our test function. */
+extern int do_test (void);
+
+int protected2 = -1;
+
+/* This defines the `main' function and some more. */
+#include <support/test-driver.c>
+
+int
+do_test (void)
+{
+ int res = 0;
+
+ /* Check if we get the same address for the protected data symbol. */
+ if (&protected1 != protected1a_p ())
+ {
+ puts ("`protected1' in main and moda doesn't have same address");
+ res = 1;
+ }
+ if (&protected1 != protected1b_p ())
+ {
+ puts ("`protected1' in main and modb doesn't have same address");
+ res = 1;
+ }
+
+ /* Check if we get the right value for the protected data symbol. */
+ if (protected1 != 3)
+ {
+ puts ("`protected1' in main and moda doesn't have same value");
+ res = 1;
+ }
+
+ /* Check if we get the right value for data defined in executable. */
+ if (protected2 != -1)
+ {
+ puts ("`protected2' in main has the wrong value");
+ res = 1;
+ }
+
+ /* Check `protected1' in moda. */
+ if (!check_protected1 ())
+ {
+ puts ("`protected1' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check `protected2' in moda. */
+ if (!check_protected2 ())
+ {
+ puts ("`protected2' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if we get the same address for the protected data symbol. */
+ if (&protected3 != protected3a_p ())
+ {
+ puts ("`protected3' in main and moda doesn't have same address");
+ res = 1;
+ }
+ if (&protected3 == protected3b_p ())
+ {
+ puts ("`protected3' in main and modb has same address");
+ res = 1;
+ }
+
+ /* Check if we get the right value for the protected data symbol. */
+ if (protected3 != 5)
+ {
+ puts ("`protected3' in main and moda doesn't have same value");
+ res = 1;
+ }
+
+ /* Check `protected3' in moda. */
+ if (!check_protected3a ())
+ {
+ puts ("`protected3' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check `protected3' in modb. */
+ if (!check_protected3b ())
+ {
+ puts ("`protected3' in modb has the wrong value");
+ res = 1;
+ }
+
+ /* Set `protected2' in moda to 30. */
+ set_protected2 (300);
+
+ /* Check `protected2' in moda. */
+ if (!check_protected2 ())
+ {
+ puts ("`protected2' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Set `protected1' in moda to 30. */
+ set_protected1a (30);
+
+ /* Check `protected1' in moda. */
+ if (!check_protected1 ())
+ {
+ puts ("`protected1' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if we get the updated value for the protected data symbol. */
+ if (protected1 != 30)
+ {
+ puts ("`protected1' in main doesn't have the updated value");
+ res = 1;
+ }
+
+ protected2 = -300;
+
+ /* Check `protected2' in moda. */
+ if (!check_protected2 ())
+ {
+ puts ("`protected2' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if data defined in executable is changed. */
+ if (protected2 != -300)
+ {
+ puts ("`protected2' in main is changed");
+ res = 1;
+ }
+
+ /* Set `protected1' in modb to 40. */
+ set_protected1b (40);
+ set_expected_protected1 (40);
+
+ /* Check `protected1' in moda. */
+ if (!check_protected1 ())
+ {
+ puts ("`protected1' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if we get the updated value for the protected data symbol. */
+ if (protected1 != 40)
+ {
+ puts ("`protected1' in main doesn't have the updated value");
+ res = 1;
+ }
+
+ /* Set `protected3' in moda to 80. */
+ set_protected3a (80);
+
+ /* Check `protected3' in moda. */
+ if (!check_protected3a ())
+ {
+ puts ("`protected3' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if we get the updated value for the protected data symbol. */
+ if (protected3 != 80)
+ {
+ puts ("`protected3' in main doesn't have the updated value");
+ res = 1;
+ }
+
+ /* Check `protected3' in modb. */
+ if (!check_protected3b ())
+ {
+ puts ("`protected3' in modb has the wrong value");
+ res = 1;
+ }
+
+ /* Set `protected3' in modb to 100. */
+ set_protected3b (100);
+
+ /* Check `protected3' in moda. */
+ if (!check_protected3a ())
+ {
+ puts ("`protected3' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if we get the updated value for the protected data symbol. */
+ if (protected3 != 80)
+ {
+ puts ("`protected3' in main doesn't have the updated value");
+ res = 1;
+ }
+
+ /* Check `protected3' in modb. */
+ if (!check_protected3b ())
+ {
+ puts ("`protected3' in modb has the wrong value");
+ res = 1;
+ }
+
+ return res;
+}
diff --git a/REORG.TODO/elf/tst-protected1b.c b/REORG.TODO/elf/tst-protected1b.c
new file mode 100644
index 0000000000..9fd695bffa
--- /dev/null
+++ b/REORG.TODO/elf/tst-protected1b.c
@@ -0,0 +1,240 @@
+/* Test the protected visibility when main is linked with modb and moda
+ in that order:
+ 1. Protected symbols, protected1, protected2 and protected3, defined
+ in moda, are used in moda.
+ 2. Protected symbol, protected3, defined in modb, are used in modb
+ 3. Symbol, protected1, defined in modb, is used in main and modb.
+ 4. Symbol, protected2, defined in main, is used in main.
+ 5. Symbol, protected3, defined in modb, is also used in main.
+
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file must be compiled as PIE to avoid copy relocation when
+ accessing protected symbols defined in shared libaries since copy
+ relocation doesn't work with protected symbols and linker in
+ binutils 2.26 enforces this rule. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tst-protected1mod.h"
+
+/* Prototype for our test function. */
+extern int do_test (void);
+
+int protected2 = -1;
+
+/* This defines the `main' function and some more. */
+#include <support/test-driver.c>
+
+int
+do_test (void)
+{
+ int res = 0;
+
+ /* Check if we get the same address for the protected data symbol. */
+ if (&protected1 == protected1a_p ())
+ {
+ puts ("`protected1' in main and moda has same address");
+ res = 1;
+ }
+ if (&protected1 != protected1b_p ())
+ {
+ puts ("`protected1' in main and modb doesn't have same address");
+ res = 1;
+ }
+
+ /* Check if we get the right value for the protected data symbol. */
+ if (protected1 != -3)
+ {
+ puts ("`protected1' in main and modb doesn't have same value");
+ res = 1;
+ }
+
+ /* Check if we get the right value for data defined in executable. */
+ if (protected2 != -1)
+ {
+ puts ("`protected2' in main has the wrong value");
+ res = 1;
+ }
+
+ /* Check `protected1' in moda. */
+ if (!check_protected1 ())
+ {
+ puts ("`protected1' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check `protected2' in moda. */
+ if (!check_protected2 ())
+ {
+ puts ("`protected2' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if we get the same address for the protected data symbol. */
+ if (&protected3 == protected3a_p ())
+ {
+ puts ("`protected3' in main and moda has same address");
+ res = 1;
+ }
+ if (&protected3 != protected3b_p ())
+ {
+ puts ("`protected3' in main and modb doesn't have same address");
+ res = 1;
+ }
+
+ /* Check if we get the right value for the protected data symbol. */
+ if (protected3 != -5)
+ {
+ puts ("`protected3' in main and modb doesn't have same value");
+ res = 1;
+ }
+
+ /* Check `protected3' in moda. */
+ if (!check_protected3a ())
+ {
+ puts ("`protected3' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check `protected3' in modb. */
+ if (!check_protected3b ())
+ {
+ puts ("`protected3' in modb has the wrong value");
+ res = 1;
+ }
+
+ /* Set `protected2' in moda to 30. */
+ set_protected2 (300);
+
+ /* Check `protected2' in moda. */
+ if (!check_protected2 ())
+ {
+ puts ("`protected2' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if we get the right value for data defined in executable. */
+ if (protected2 != -1)
+ {
+ puts ("`protected2' in main has the wrong value");
+ res = 1;
+ }
+
+ /* Set `protected1' in moda to 30. */
+ set_protected1a (30);
+
+ /* Check `protected1' in moda. */
+ if (!check_protected1 ())
+ {
+ puts ("`protected1' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if we get the same value for the protected data symbol. */
+ if (protected1 != -3)
+ {
+ puts ("`protected1' in main has the wrong value");
+ res = 1;
+ }
+
+ protected2 = -300;
+
+ /* Check `protected2' in moda. */
+ if (!check_protected2 ())
+ {
+ puts ("`protected2' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if data defined in executable is changed. */
+ if (protected2 != -300)
+ {
+ puts ("`protected2' in main is changed");
+ res = 1;
+ }
+
+ /* Set `protected1' in modb to 40. */
+ set_protected1b (40);
+
+ /* Check `protected1' in moda. */
+ if (!check_protected1 ())
+ {
+ puts ("`protected1' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if we get the updated value for the protected data symbol. */
+ if (protected1 != 40)
+ {
+ puts ("`protected1' in main doesn't have the updated value");
+ res = 1;
+ }
+
+ /* Set `protected3' in moda to 80. */
+ set_protected3a (80);
+
+ /* Check `protected3' in moda. */
+ if (!check_protected3a ())
+ {
+ puts ("`protected3' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if we get the updated value for the protected data symbol. */
+ if (protected3 != -5)
+ {
+ puts ("`protected3' in main doesn't have the updated value");
+ res = 1;
+ }
+
+ /* Check `protected3' in modb. */
+ if (!check_protected3b ())
+ {
+ puts ("`protected3' in modb has the wrong value");
+ res = 1;
+ }
+
+ /* Set `protected3' in modb to 100. */
+ set_protected3b (100);
+
+ /* Check `protected3' in moda. */
+ if (!check_protected3a ())
+ {
+ puts ("`protected3' in moda has the wrong value");
+ res = 1;
+ }
+
+ /* Check if we get the updated value for the protected data symbol. */
+ if (protected3 != 100)
+ {
+ puts ("`protected3' in main doesn't have the updated value");
+ res = 1;
+ }
+
+ /* Check `protected3' in modb. */
+ if (!check_protected3b ())
+ {
+ puts ("`protected3' in modb has the wrong value");
+ res = 1;
+ }
+
+ return res;
+}
diff --git a/REORG.TODO/elf/tst-protected1mod.h b/REORG.TODO/elf/tst-protected1mod.h
new file mode 100644
index 0000000000..a47d65f6b1
--- /dev/null
+++ b/REORG.TODO/elf/tst-protected1mod.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Prototypes for the functions in the DSOs. */
+extern int protected1;
+extern int protected2;
+extern int protected3;
+
+extern void set_protected1a (int);
+extern void set_protected1b (int);
+extern int *protected1a_p (void);
+extern int *protected1b_p (void);
+
+extern void set_expected_protected1 (int);
+extern int check_protected1 (void);
+
+extern void set_protected2 (int);
+extern int check_protected2 (void);
+
+extern void set_expected_protected3a (int);
+extern void set_protected3a (int);
+extern int check_protected3a (void);
+extern int *protected3a_p (void);
+extern void set_expected_protected3b (int);
+extern void set_protected3b (int);
+extern int check_protected3b (void);
+extern int *protected3b_p (void);
diff --git a/REORG.TODO/elf/tst-protected1moda.c b/REORG.TODO/elf/tst-protected1moda.c
new file mode 100644
index 0000000000..aca4fc82a8
--- /dev/null
+++ b/REORG.TODO/elf/tst-protected1moda.c
@@ -0,0 +1,92 @@
+/* Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "tst-protected1mod.h"
+
+int protected1 = 3;
+static int expected_protected1 = 3;
+int protected2 = 4;
+static int expected_protected2 = 4;
+int protected3 = 5;
+static int expected_protected3 = 5;
+
+asm (".protected protected1");
+asm (".protected protected2");
+asm (".protected protected3");
+
+void
+set_protected1a (int i)
+{
+ protected1 = i;
+ set_expected_protected1 (i);
+}
+
+void
+set_expected_protected1 (int i)
+{
+ expected_protected1 = i;
+}
+
+int *
+protected1a_p (void)
+{
+ return &protected1;
+}
+
+int
+check_protected1 (void)
+{
+ return protected1 == expected_protected1;
+}
+
+void
+set_protected2 (int i)
+{
+ protected2 = i;
+ expected_protected2 = i;
+}
+
+int
+check_protected2 (void)
+{
+ return protected2 == expected_protected2;
+}
+
+void
+set_expected_protected3a (int i)
+{
+ expected_protected3 = i;
+}
+
+void
+set_protected3a (int i)
+{
+ protected3 = i;
+ set_expected_protected3a (i);
+}
+
+int
+check_protected3a (void)
+{
+ return protected3 == expected_protected3;
+}
+
+int *
+protected3a_p (void)
+{
+ return &protected3;
+}
diff --git a/REORG.TODO/elf/tst-protected1modb.c b/REORG.TODO/elf/tst-protected1modb.c
new file mode 100644
index 0000000000..5036b6c3e7
--- /dev/null
+++ b/REORG.TODO/elf/tst-protected1modb.c
@@ -0,0 +1,62 @@
+/* Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include "tst-protected1mod.h"
+
+int protected1 = -3;
+int protected3 = -5;
+static int expected_protected3 = -5;
+
+asm (".protected protected3");
+
+void
+set_protected1b (int i)
+{
+ protected1 = i;
+}
+
+int *
+protected1b_p (void)
+{
+ return &protected1;
+}
+
+void
+set_expected_protected3b (int i)
+{
+ expected_protected3 = i;
+}
+
+void
+set_protected3b (int i)
+{
+ protected3 = i;
+ set_expected_protected3b (i);
+}
+
+int
+check_protected3b (void)
+{
+ return protected3 == expected_protected3;
+}
+
+int *
+protected3b_p (void)
+{
+ return &protected3;
+}
diff --git a/REORG.TODO/elf/tst-ptrguard1-static.c b/REORG.TODO/elf/tst-ptrguard1-static.c
new file mode 100644
index 0000000000..7aff3b7b5d
--- /dev/null
+++ b/REORG.TODO/elf/tst-ptrguard1-static.c
@@ -0,0 +1 @@
+#include "tst-ptrguard1.c"
diff --git a/REORG.TODO/elf/tst-ptrguard1.c b/REORG.TODO/elf/tst-ptrguard1.c
new file mode 100644
index 0000000000..8ea65bb0bb
--- /dev/null
+++ b/REORG.TODO/elf/tst-ptrguard1.c
@@ -0,0 +1,217 @@
+/* Copyright (C) 2013-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <stackguard-macros.h>
+#include <tls.h>
+#include <unistd.h>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+/* Requires _GNU_SOURCE */
+#include <getopt.h>
+
+#ifndef POINTER_CHK_GUARD
+extern uintptr_t __pointer_chk_guard;
+# define POINTER_CHK_GUARD __pointer_chk_guard
+#endif
+
+static const char *command;
+static bool child;
+static uintptr_t ptr_chk_guard_copy;
+static bool ptr_chk_guard_copy_set;
+static int fds[2];
+
+static void __attribute__ ((constructor))
+con (void)
+{
+ ptr_chk_guard_copy = POINTER_CHK_GUARD;
+ ptr_chk_guard_copy_set = true;
+}
+
+static int
+uintptr_t_cmp (const void *a, const void *b)
+{
+ if (*(uintptr_t *) a < *(uintptr_t *) b)
+ return 1;
+ if (*(uintptr_t *) a > *(uintptr_t *) b)
+ return -1;
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ if (!ptr_chk_guard_copy_set)
+ {
+ puts ("constructor has not been run");
+ return 1;
+ }
+
+ if (ptr_chk_guard_copy != POINTER_CHK_GUARD)
+ {
+ puts ("POINTER_CHK_GUARD changed between constructor and do_test");
+ return 1;
+ }
+
+ if (child)
+ {
+ write (2, &ptr_chk_guard_copy, sizeof (ptr_chk_guard_copy));
+ return 0;
+ }
+
+ if (command == NULL)
+ {
+ puts ("missing --command or --child argument");
+ return 1;
+ }
+
+#define N 16
+ uintptr_t child_ptr_chk_guards[N + 1];
+ child_ptr_chk_guards[N] = ptr_chk_guard_copy;
+ int i;
+ for (i = 0; i < N; ++i)
+ {
+ if (pipe (fds) < 0)
+ {
+ printf ("couldn't create pipe: %m\n");
+ return 1;
+ }
+
+ pid_t pid = fork ();
+ if (pid < 0)
+ {
+ printf ("fork failed: %m\n");
+ return 1;
+ }
+
+ if (!pid)
+ {
+ if (ptr_chk_guard_copy != POINTER_CHK_GUARD)
+ {
+ puts ("POINTER_CHK_GUARD changed after fork");
+ exit (1);
+ }
+
+ close (fds[0]);
+ close (2);
+ dup2 (fds[1], 2);
+ close (fds[1]);
+
+ system (command);
+ exit (0);
+ }
+
+ close (fds[1]);
+
+ if (TEMP_FAILURE_RETRY (read (fds[0], &child_ptr_chk_guards[i],
+ sizeof (uintptr_t))) != sizeof (uintptr_t))
+ {
+ puts ("could not read ptr_chk_guard value from child");
+ return 1;
+ }
+
+ close (fds[0]);
+
+ pid_t termpid;
+ int status;
+ termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (termpid == -1)
+ {
+ printf ("waitpid failed: %m\n");
+ return 1;
+ }
+ else if (termpid != pid)
+ {
+ printf ("waitpid returned %ld != %ld\n",
+ (long int) termpid, (long int) pid);
+ return 1;
+ }
+ else if (!WIFEXITED (status) || WEXITSTATUS (status))
+ {
+ puts ("child hasn't exited with exit status 0");
+ return 1;
+ }
+ }
+
+ qsort (child_ptr_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
+
+ /* The default pointer guard is the same as the default stack guard.
+ They are only set to default if dl_random is NULL. */
+ uintptr_t default_guard = 0;
+ unsigned char *p = (unsigned char *) &default_guard;
+ p[sizeof (uintptr_t) - 1] = 255;
+ p[sizeof (uintptr_t) - 2] = '\n';
+ p[0] = 0;
+
+ /* Test if the pointer guard canaries are either randomized,
+ or equal to the default pointer guard value.
+ Even with randomized pointer guards it might happen
+ that the random number generator generates the same
+ values, but if that happens in more than half from
+ the 16 runs, something is very wrong. */
+ int ndifferences = 0;
+ int ndefaults = 0;
+ for (i = 0; i < N; ++i)
+ {
+ if (child_ptr_chk_guards[i] != child_ptr_chk_guards[i+1])
+ ndifferences++;
+ else if (child_ptr_chk_guards[i] == default_guard)
+ ndefaults++;
+ }
+
+ printf ("differences %d defaults %d\n", ndifferences, ndefaults);
+
+ if (ndifferences < N / 2 && ndefaults < N / 2)
+ {
+ puts ("pointer guard values are not randomized enough");
+ puts ("nor equal to the default value");
+ return 1;
+ }
+
+ return 0;
+}
+
+#define OPT_COMMAND 10000
+#define OPT_CHILD 10001
+#define CMDLINE_OPTIONS \
+ { "command", required_argument, NULL, OPT_COMMAND }, \
+ { "child", no_argument, NULL, OPT_CHILD },
+
+static void __attribute((used))
+cmdline_process_function (int c)
+{
+ switch (c)
+ {
+ case OPT_COMMAND:
+ command = optarg;
+ break;
+ case OPT_CHILD:
+ child = true;
+ break;
+ }
+}
+
+#define CMDLINE_PROCESS cmdline_process_function
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-relsort1.c b/REORG.TODO/elf/tst-relsort1.c
new file mode 100644
index 0000000000..775c968e1f
--- /dev/null
+++ b/REORG.TODO/elf/tst-relsort1.c
@@ -0,0 +1,18 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+ const char lib[] = "$ORIGIN/tst-relsort1mod1.so";
+ void *h = dlopen (lib, RTLD_NOW);
+ if (h == NULL)
+ {
+ puts (dlerror ());
+ return 1;
+ }
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-relsort1mod1.c b/REORG.TODO/elf/tst-relsort1mod1.c
new file mode 100644
index 0000000000..9e4a94321d
--- /dev/null
+++ b/REORG.TODO/elf/tst-relsort1mod1.c
@@ -0,0 +1,7 @@
+extern int foo (double);
+
+int
+bar (void)
+{
+ return foo (1.2);
+}
diff --git a/REORG.TODO/elf/tst-relsort1mod2.c b/REORG.TODO/elf/tst-relsort1mod2.c
new file mode 100644
index 0000000000..a2c3e551e4
--- /dev/null
+++ b/REORG.TODO/elf/tst-relsort1mod2.c
@@ -0,0 +1,7 @@
+#include <math.h>
+
+int
+foo (double d)
+{
+ return floor (d) != 0.0;
+}
diff --git a/REORG.TODO/elf/tst-rtld-load-self.sh b/REORG.TODO/elf/tst-rtld-load-self.sh
new file mode 100755
index 0000000000..e05f6d145f
--- /dev/null
+++ b/REORG.TODO/elf/tst-rtld-load-self.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Test how rtld loads itself.
+# Copyright (C) 2012-2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+set -e
+
+rtld=$1
+test_wrapper=$2
+test_wrapper_env=$3
+result=0
+
+echo '# normal mode'
+${test_wrapper} $rtld $rtld 2>&1 && rc=0 || rc=$?
+echo "# exit status $rc"
+test $rc -le 127 || result=1
+
+echo '# list mode'
+${test_wrapper} $rtld --list $rtld 2>&1 && rc=0 || rc=$?
+echo "# exit status $rc"
+test $rc -eq 0 || result=1
+
+echo '# verify mode'
+${test_wrapper} $rtld --verify $rtld 2>&1 && rc=0 || rc=$?
+echo "# exit status $rc"
+test $rc -eq 2 || result=1
+
+echo '# trace mode'
+${test_wrapper_env} LD_TRACE_LOADED_OBJECTS=1 \
+ $rtld $rtld 2>&1 && rc=0 || rc=$?
+echo "# exit status $rc"
+test $rc -eq 0 || result=1
+
+exit $result
diff --git a/REORG.TODO/elf/tst-stackguard1-static.c b/REORG.TODO/elf/tst-stackguard1-static.c
new file mode 100644
index 0000000000..db1e21554d
--- /dev/null
+++ b/REORG.TODO/elf/tst-stackguard1-static.c
@@ -0,0 +1 @@
+#include "tst-stackguard1.c"
diff --git a/REORG.TODO/elf/tst-stackguard1.c b/REORG.TODO/elf/tst-stackguard1.c
new file mode 100644
index 0000000000..78e33c7083
--- /dev/null
+++ b/REORG.TODO/elf/tst-stackguard1.c
@@ -0,0 +1,205 @@
+/* Copyright (C) 2005-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2005.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <stackguard-macros.h>
+#include <tls.h>
+#include <unistd.h>
+
+static const char *command;
+static bool child;
+static uintptr_t stack_chk_guard_copy;
+static bool stack_chk_guard_copy_set;
+static int fds[2];
+
+static void __attribute__ ((constructor))
+con (void)
+{
+ stack_chk_guard_copy = STACK_CHK_GUARD;
+ stack_chk_guard_copy_set = true;
+}
+
+static int
+uintptr_t_cmp (const void *a, const void *b)
+{
+ if (*(uintptr_t *) a < *(uintptr_t *) b)
+ return 1;
+ if (*(uintptr_t *) a > *(uintptr_t *) b)
+ return -1;
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ if (!stack_chk_guard_copy_set)
+ {
+ puts ("constructor has not been run");
+ return 1;
+ }
+
+ if (stack_chk_guard_copy != STACK_CHK_GUARD)
+ {
+ puts ("STACK_CHK_GUARD changed between constructor and do_test");
+ return 1;
+ }
+
+ if (child)
+ {
+ write (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy));
+ return 0;
+ }
+
+ if (command == NULL)
+ {
+ puts ("missing --command or --child argument");
+ return 1;
+ }
+
+#define N 16
+ uintptr_t child_stack_chk_guards[N + 1];
+ child_stack_chk_guards[N] = stack_chk_guard_copy;
+ int i;
+ for (i = 0; i < N; ++i)
+ {
+ if (pipe (fds) < 0)
+ {
+ printf ("couldn't create pipe: %m\n");
+ return 1;
+ }
+
+ pid_t pid = fork ();
+ if (pid < 0)
+ {
+ printf ("fork failed: %m\n");
+ return 1;
+ }
+
+ if (!pid)
+ {
+ if (stack_chk_guard_copy != STACK_CHK_GUARD)
+ {
+ puts ("STACK_CHK_GUARD changed after fork");
+ exit (1);
+ }
+
+ close (fds[0]);
+ close (2);
+ dup2 (fds[1], 2);
+ close (fds[1]);
+
+ system (command);
+ exit (0);
+ }
+
+ close (fds[1]);
+
+ if (TEMP_FAILURE_RETRY (read (fds[0], &child_stack_chk_guards[i],
+ sizeof (uintptr_t))) != sizeof (uintptr_t))
+ {
+ puts ("could not read stack_chk_guard value from child");
+ return 1;
+ }
+
+ close (fds[0]);
+
+ pid_t termpid;
+ int status;
+ termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (termpid == -1)
+ {
+ printf ("waitpid failed: %m\n");
+ return 1;
+ }
+ else if (termpid != pid)
+ {
+ printf ("waitpid returned %ld != %ld\n",
+ (long int) termpid, (long int) pid);
+ return 1;
+ }
+ else if (!WIFEXITED (status) || WEXITSTATUS (status))
+ {
+ puts ("child hasn't exited with exit status 0");
+ return 1;
+ }
+ }
+
+ qsort (child_stack_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
+
+ uintptr_t default_guard = 0;
+ unsigned char *p = (unsigned char *) &default_guard;
+ p[sizeof (uintptr_t) - 1] = 255;
+ p[sizeof (uintptr_t) - 2] = '\n';
+ p[0] = 0;
+
+ /* Test if the stack guard canaries are either randomized,
+ or equal to the default stack guard canary value.
+ Even with randomized stack guards it might happen
+ that the random number generator generates the same
+ values, but if that happens in more than half from
+ the 16 runs, something is very wrong. */
+ int ndifferences = 0;
+ int ndefaults = 0;
+ for (i = 0; i < N; ++i)
+ {
+ if (child_stack_chk_guards[i] != child_stack_chk_guards[i+1])
+ ndifferences++;
+ else if (child_stack_chk_guards[i] == default_guard)
+ ndefaults++;
+ }
+
+ printf ("differences %d defaults %d\n", ndifferences, ndefaults);
+
+ if (ndifferences < N / 2 && ndefaults < N / 2)
+ {
+ puts ("stack guard canaries are not randomized enough");
+ puts ("nor equal to the default canary value");
+ return 1;
+ }
+
+ return 0;
+}
+
+#define OPT_COMMAND 10000
+#define OPT_CHILD 10001
+#define CMDLINE_OPTIONS \
+ { "command", required_argument, NULL, OPT_COMMAND }, \
+ { "child", no_argument, NULL, OPT_CHILD },
+
+static void __attribute__((used))
+cmdline_process_function (int c)
+{
+ switch (c)
+ {
+ case OPT_COMMAND:
+ command = optarg;
+ break;
+ case OPT_CHILD:
+ child = true;
+ break;
+ }
+}
+#define CMDLINE_PROCESS cmdline_process_function
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-thrlock.c b/REORG.TODO/elf/tst-thrlock.c
new file mode 100644
index 0000000000..1beffc3861
--- /dev/null
+++ b/REORG.TODO/elf/tst-thrlock.c
@@ -0,0 +1,58 @@
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnu/lib-names.h>
+
+static void *
+tf (void *arg)
+{
+ void *h = dlopen (LIBM_SO, RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("dlopen failed: %s\n", dlerror ());
+ exit (1);
+ }
+ if (dlsym (h, "sin") == NULL)
+ {
+ printf ("dlsym failed: %s\n", dlerror ());
+ exit (1);
+ }
+ if (dlclose (h) != 0)
+ {
+ printf ("dlclose failed: %s\n", dlerror ());
+ exit (1);
+ }
+ return NULL;
+}
+
+
+static int
+do_test (void)
+{
+#define N 10
+ pthread_t th[N];
+ for (int i = 0; i < N; ++i)
+ {
+ int e = pthread_create (&th[i], NULL, tf, NULL);
+ if (e != 0)
+ {
+ printf ("pthread_create failed with %d (%s)\n", e, strerror (e));
+ return 1;
+ }
+ }
+ for (int i = 0; i < N; ++i)
+ {
+ void *res;
+ int e = pthread_join (th[i], &res);
+ if (e != 0 || res != NULL)
+ {
+ puts ("thread failed");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls-dlinfo.c b/REORG.TODO/elf/tst-tls-dlinfo.c
new file mode 100644
index 0000000000..7d2b42e2ab
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls-dlinfo.c
@@ -0,0 +1,85 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int
+do_test (void)
+{
+ static const char modname[] = "tst-tlsmod2.so";
+ int result = 0;
+ int *foop;
+ int (*fp) (int, int *);
+ void *h;
+
+ h = dlopen (modname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname, dlerror ());
+ exit (1);
+ }
+
+ fp = dlsym (h, "in_dso");
+ if (fp == NULL)
+ {
+ printf ("cannot get symbol 'in_dso': %s\n", dlerror ());
+ exit (1);
+ }
+
+ size_t modid = -1;
+ if (dlinfo (h, RTLD_DI_TLS_MODID, &modid))
+ {
+ printf ("dlinfo RTLD_DI_TLS_MODID failed: %s\n", dlerror ());
+ result = 1;
+ }
+ else
+ printf ("dlinfo says TLS module ID %Zu\n", modid);
+
+ void *block;
+ if (dlinfo (h, RTLD_DI_TLS_DATA, &block))
+ {
+ printf ("dlinfo RTLD_DI_TLS_DATA failed: %s\n", dlerror ());
+ result = 1;
+ }
+ else if (block != NULL)
+ {
+ printf ("dlinfo RTLD_DI_TLS_DATA says %p but should be unallocated\n",
+ block);
+ result = 1;
+ }
+
+ result |= fp (0, NULL);
+
+ foop = dlsym (h, "foo");
+ if (foop == NULL)
+ {
+ printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ());
+ exit (1);
+ }
+ if (*foop != 16)
+ {
+ puts ("foo != 16");
+ result = 1;
+ }
+
+ /* Now the module's TLS block has been used and should appear. */
+ if (dlinfo (h, RTLD_DI_TLS_DATA, &block))
+ {
+ printf ("dlinfo RTLD_DI_TLS_DATA failed the second time: %s\n",
+ dlerror ());
+ result = 1;
+ }
+ else if (block != foop)
+ {
+ printf ("dlinfo RTLD_DI_TLS_DATA says %p but should be %p\n",
+ block, foop);
+ result = 1;
+ }
+
+ dlclose (h);
+
+ return result;
+}
+
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls-manydynamic.c b/REORG.TODO/elf/tst-tls-manydynamic.c
new file mode 100644
index 0000000000..b072d0be68
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls-manydynamic.c
@@ -0,0 +1,151 @@
+/* Test with many dynamic TLS variables.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This test intends to exercise dynamic TLS variable allocation. It
+ achieves this by combining dlopen (to avoid static TLS allocation
+ after static TLS resizing), many DSOs with a large variable (to
+ exceed the static TLS reserve), and an already-running thread (to
+ force full dynamic TLS initialization). */
+
+#include "tst-tls-manydynamic.h"
+
+#include <errno.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int do_test (void);
+#include <support/xthread.h>
+#include <support/test-driver.c>
+
+void *handles[COUNT];
+set_value_func set_value_funcs[COUNT];
+get_value_func get_value_funcs[COUNT];
+
+static void
+init_functions (void)
+{
+ for (int i = 0; i < COUNT; ++i)
+ {
+ /* Open the module. */
+ {
+ char soname[100];
+ snprintf (soname, sizeof (soname), "tst-tls-manydynamic%02dmod.so", i);
+ handles[i] = dlopen (soname, RTLD_LAZY);
+ if (handles[i] == NULL)
+ {
+ printf ("error: dlopen failed: %s\n", dlerror ());
+ exit (1);
+ }
+ }
+
+ /* Obtain the setter function. */
+ {
+ char fname[100];
+ snprintf (fname, sizeof (fname), "set_value_%02d", i);
+ void *func = dlsym (handles[i], fname);
+ if (func == NULL)
+ {
+ printf ("error: dlsym: %s\n", dlerror ());
+ exit (1);
+ }
+ set_value_funcs[i] = func;
+ }
+
+ /* Obtain the getter function. */
+ {
+ char fname[100];
+ snprintf (fname, sizeof (fname), "get_value_%02d", i);
+ void *func = dlsym (handles[i], fname);
+ if (func == NULL)
+ {
+ printf ("error: dlsym: %s\n", dlerror ());
+ exit (1);
+ }
+ get_value_funcs[i] = func;
+ }
+ }
+}
+
+static pthread_barrier_t barrier;
+
+/* Running thread which forces real TLS initialization. */
+static void *
+blocked_thread_func (void *closure)
+{
+ xpthread_barrier_wait (&barrier);
+
+ /* TLS test runs here in the main thread. */
+
+ xpthread_barrier_wait (&barrier);
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ {
+ int ret = pthread_barrier_init (&barrier, NULL, 2);
+ if (ret != 0)
+ {
+ errno = ret;
+ printf ("error: pthread_barrier_init: %m\n");
+ exit (1);
+ }
+ }
+
+ pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL);
+ xpthread_barrier_wait (&barrier);
+
+ init_functions ();
+
+ struct value values[COUNT];
+ /* Initialze the TLS variables. */
+ for (int i = 0; i < COUNT; ++i)
+ {
+ for (int j = 0; j < PER_VALUE_COUNT; ++j)
+ values[i].num[j] = rand ();
+ set_value_funcs[i] (&values[i]);
+ }
+
+ /* Read back their values to check that they do not overlap. */
+ for (int i = 0; i < COUNT; ++i)
+ {
+ struct value actual;
+ get_value_funcs[i] (&actual);
+
+ for (int j = 0; j < PER_VALUE_COUNT; ++j)
+ if (actual.num[j] != values[i].num[j])
+ {
+ printf ("error: mismatch at variable %d/%d: %d != %d\n",
+ i, j, actual.num[j], values[i].num[j]);
+ exit (1);
+ }
+ }
+
+ xpthread_barrier_wait (&barrier);
+ xpthread_join (blocked_thread);
+
+ /* Close the modules. */
+ for (int i = 0; i < COUNT; ++i)
+ dlclose (handles[i]);
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/tst-tls-manydynamic.h b/REORG.TODO/elf/tst-tls-manydynamic.h
new file mode 100644
index 0000000000..13fac4e7e8
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls-manydynamic.h
@@ -0,0 +1,44 @@
+/* Interfaces for test with many dynamic TLS variables.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef TST_TLS_MANYDYNAMIC_H
+#define TST_TLS_MANYDYNAMIC_H
+
+enum
+ {
+ /* This many TLS variables (and modules) are defined. */
+ COUNT = 100,
+
+ /* Number of elements in the TLS variable. */
+ PER_VALUE_COUNT = 1,
+ };
+
+/* The TLS variables are of this type. We use a larger type to ensure
+ that we can reach the static TLS limit with COUNT variables. */
+struct value
+{
+ int num[PER_VALUE_COUNT];
+};
+
+/* Set the TLS variable defined in the module. */
+typedef void (*set_value_func) (const struct value *);
+
+/* Read the TLS variable defined in the module. */
+typedef void (*get_value_func) (struct value *);
+
+#endif /* TST_TLS_MANYDYNAMICMOD_H */
diff --git a/REORG.TODO/elf/tst-tls-manydynamicmod.c b/REORG.TODO/elf/tst-tls-manydynamicmod.c
new file mode 100644
index 0000000000..edfaeef7f3
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls-manydynamicmod.c
@@ -0,0 +1,36 @@
+/* Module for test with many dynamic TLS variables.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is parameterized by macros NAME, SETTER, GETTER, which
+ are set form the Makefile. */
+
+#include "tst-tls-manydynamic.h"
+
+__thread struct value NAME;
+
+void
+SETTER (const struct value *value)
+{
+ NAME = *value;
+}
+
+void
+GETTER (struct value *value)
+{
+ *value = NAME;
+}
diff --git a/REORG.TODO/elf/tst-tls1-static.c b/REORG.TODO/elf/tst-tls1-static.c
new file mode 100644
index 0000000000..a01008073b
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls1-static.c
@@ -0,0 +1 @@
+#include "tst-tls1.c"
diff --git a/REORG.TODO/elf/tst-tls1.c b/REORG.TODO/elf/tst-tls1.c
new file mode 100644
index 0000000000..c31da56ce9
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls1.c
@@ -0,0 +1,82 @@
+/* glibc test for TLS in ld.so. */
+#include <stdio.h>
+
+#include "tls-macros.h"
+
+
+/* Two common 'int' variables in TLS. */
+COMMON_INT_DEF(foo);
+COMMON_INT_DEF(bar);
+
+
+static int
+do_test (void)
+{
+ int result = 0;
+ int *ap, *bp;
+
+
+ /* Set the variable using the local exec model. */
+ puts ("set bar to 1 (LE)");
+ ap = TLS_LE (bar);
+ *ap = 1;
+
+
+ /* Get variables using initial exec model. */
+ fputs ("get sum of foo and bar (IE)", stdout);
+ ap = TLS_IE (foo);
+ bp = TLS_IE (bar);
+ printf (" = %d\n", *ap + *bp);
+ result |= *ap + *bp != 1;
+ if (*ap != 0)
+ {
+ printf ("foo = %d\n", *ap);
+ result = 1;
+ }
+ if (*bp != 1)
+ {
+ printf ("bar = %d\n", *bp);
+ result = 1;
+ }
+
+
+ /* Get variables using local dynamic model. */
+ fputs ("get sum of foo and bar (LD)", stdout);
+ ap = TLS_LD (foo);
+ bp = TLS_LD (bar);
+ printf (" = %d\n", *ap + *bp);
+ result |= *ap + *bp != 1;
+ if (*ap != 0)
+ {
+ printf ("foo = %d\n", *ap);
+ result = 1;
+ }
+ if (*bp != 1)
+ {
+ printf ("bar = %d\n", *bp);
+ result = 1;
+ }
+
+
+ /* Get variables using generic dynamic model. */
+ fputs ("get sum of foo and bar (GD)", stdout);
+ ap = TLS_GD (foo);
+ bp = TLS_GD (bar);
+ printf (" = %d\n", *ap + *bp);
+ result |= *ap + *bp != 1;
+ if (*ap != 0)
+ {
+ printf ("foo = %d\n", *ap);
+ result = 1;
+ }
+ if (*bp != 1)
+ {
+ printf ("bar = %d\n", *bp);
+ result = 1;
+ }
+
+ return result;
+}
+
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls10.c b/REORG.TODO/elf/tst-tls10.c
new file mode 100644
index 0000000000..d9611aac6d
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls10.c
@@ -0,0 +1,39 @@
+#include "tst-tls10.h"
+
+__thread int dummy __attribute__((visibility ("hidden"))) = 12;
+__thread struct A local = { 1, 2, 3 };
+
+#define CHECK(N, S) \
+ p = f##N##a (); \
+ if (p->a != S || p->b != S + 1 || p->c != S + 2) \
+ abort ()
+
+static int
+do_test (void)
+{
+ struct A *p;
+ if (local.a != 1 || local.b != 2 || local.c != 3)
+ abort ();
+ if (a1.a != 4 || a1.b != 5 || a1.c != 6)
+ abort ();
+ if (a2.a != 22 || a2.b != 23 || a2.c != 24)
+ abort ();
+ if (a3.a != 10 || a3.b != 11 || a3.c != 12)
+ abort ();
+ if (a4.a != 25 || a4.b != 26 || a4.c != 27)
+ abort ();
+ check1 ();
+ check2 ();
+ if (f1a () != &a1 || f2a () != &a2 || f3a () != &a3 || f4a () != &a4)
+ abort ();
+ CHECK (5, 16);
+ CHECK (6, 19);
+ if (f7a () != &a2 || f8a () != &a4)
+ abort ();
+ CHECK (9, 28);
+ CHECK (10, 31);
+
+ exit (0);
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls10.h b/REORG.TODO/elf/tst-tls10.h
new file mode 100644
index 0000000000..7c8c6a6391
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls10.h
@@ -0,0 +1,32 @@
+#include <stdlib.h>
+
+struct A
+{
+ char a;
+ int b;
+ long long c;
+};
+
+extern __thread struct A a1, a2, a3, a4;
+extern struct A *f1a (void);
+extern struct A *f2a (void);
+extern struct A *f3a (void);
+extern struct A *f4a (void);
+extern struct A *f5a (void);
+extern struct A *f6a (void);
+extern struct A *f7a (void);
+extern struct A *f8a (void);
+extern struct A *f9a (void);
+extern struct A *f10a (void);
+extern int f1b (void);
+extern int f2b (void);
+extern int f3b (void);
+extern int f4b (void);
+extern int f5b (void);
+extern int f6b (void);
+extern int f7b (void);
+extern int f8b (void);
+extern int f9b (void);
+extern int f10b (void);
+extern void check1 (void);
+extern void check2 (void);
diff --git a/REORG.TODO/elf/tst-tls11.c b/REORG.TODO/elf/tst-tls11.c
new file mode 100644
index 0000000000..a5c3dd70b0
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls11.c
@@ -0,0 +1,28 @@
+#include "tst-tls10.h"
+
+#define CHECK(N, S) \
+ p = f##N##a (); \
+ if (p->a != S || p->b != S + 1 || p->c != S + 2) \
+ abort ()
+
+static int
+do_test (void)
+{
+ struct A *p;
+ check1 ();
+ check2 ();
+ CHECK (1, 4);
+ CHECK (2, 22);
+ CHECK (3, 10);
+ CHECK (4, 25);
+ CHECK (5, 16);
+ CHECK (6, 19);
+ CHECK (7, 22);
+ CHECK (8, 25);
+ CHECK (9, 28);
+ CHECK (10, 31);
+
+ exit (0);
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls12.c b/REORG.TODO/elf/tst-tls12.c
new file mode 100644
index 0000000000..ccd5f8b43e
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls12.c
@@ -0,0 +1,19 @@
+#include "tst-tls10.h"
+
+#define CHECK(N, S) \
+ p = &a##N; \
+ if (p->a != S || p->b != S + 1 || p->c != S + 2) \
+ abort ()
+
+static int
+do_test (void)
+{
+ struct A *p;
+ check1 ();
+ CHECK (1, 4);
+ CHECK (2, 7);
+
+ exit (0);
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls13.c b/REORG.TODO/elf/tst-tls13.c
new file mode 100644
index 0000000000..b1d303310f
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls13.c
@@ -0,0 +1,28 @@
+/* Check unloading modules with data in static TLS block. */
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static int
+do_test (void)
+{
+ for (int i = 0; i < 1000;)
+ {
+ printf ("round %d\n",++i);
+
+ void *h = dlopen ("$ORIGIN/tst-tlsmod13a.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot load: %s\n", dlerror ());
+ exit (1);
+ }
+
+ dlclose (h);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls14.c b/REORG.TODO/elf/tst-tls14.c
new file mode 100644
index 0000000000..a6a79ef24f
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls14.c
@@ -0,0 +1,54 @@
+/* Check alignment of TLS variable. */
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define AL 4096
+struct foo
+{
+ int i;
+} __attribute ((aligned (AL)));
+
+static __thread struct foo f;
+static struct foo g;
+
+
+extern int in_dso1 (void);
+
+
+static int
+do_test (void)
+{
+ int result = 0;
+
+ int fail = (((uintptr_t) &f) & (AL - 1)) != 0;
+ printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK");
+ result |= fail;
+
+ fail = (((uintptr_t) &g) & (AL - 1)) != 0;
+ printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK");
+ result |= fail;
+
+ result |= in_dso1 ();
+
+ void *h = dlopen ("tst-tlsmod14b.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open tst-tlsmod14b.so: %m\n");
+ exit (1);
+ }
+
+ int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso2");
+ if (fp == NULL)
+ {
+ puts ("cannot find in_dso2");
+ exit (1);
+ }
+
+ result |= fp ();
+
+ return result;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls15.c b/REORG.TODO/elf/tst-tls15.c
new file mode 100644
index 0000000000..db2a4f4b77
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls15.c
@@ -0,0 +1,32 @@
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+ void *h = dlopen ("tst-tlsmod15a.so", RTLD_NOW);
+ if (h != NULL)
+ {
+ puts ("unexpectedly succeeded to open tst-tlsmod15a.so");
+ exit (1);
+ }
+
+ h = dlopen ("tst-tlsmod15b.so", RTLD_NOW);
+ if (h == NULL)
+ {
+ puts ("failed to open tst-tlsmod15b.so");
+ exit (1);
+ }
+
+ int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso");
+ if (fp == NULL)
+ {
+ puts ("cannot find in_dso");
+ exit (1);
+ }
+
+ return fp ();
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls16.c b/REORG.TODO/elf/tst-tls16.c
new file mode 100644
index 0000000000..f2830b8a4f
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls16.c
@@ -0,0 +1,52 @@
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+ void *h = dlopen ("tst-tlsmod16a.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (h == NULL)
+ {
+ puts ("unexpectedly failed to open tst-tlsmod16a.so");
+ exit (1);
+ }
+
+ void *p = dlsym (h, "tlsvar");
+
+ /* This dlopen should indeed fail, because tlsvar was assigned to
+ dynamic TLS, and the new module requests it to be in static TLS.
+ However, there's a possibility that dlopen succeeds if the
+ variable is, for whatever reason, assigned to static TLS, or if
+ the module fails to require static TLS, or even if TLS is not
+ supported. */
+ h = dlopen ("tst-tlsmod16b.so", RTLD_NOW | RTLD_GLOBAL);
+ if (h == NULL)
+ {
+ return 0;
+ }
+
+ puts ("unexpectedly succeeded to open tst-tlsmod16b.so");
+
+
+ void *(*fp) (void) = (void *(*) (void)) dlsym (h, "in_dso");
+ if (fp == NULL)
+ {
+ puts ("cannot find in_dso");
+ exit (1);
+ }
+
+ /* If the dlopen passes, at least make sure the address returned by
+ dlsym is the same as that returned by the initial-exec access.
+ If the variable was assigned to dynamic TLS during dlsym, this
+ portion will fail. */
+ if (fp () != p)
+ {
+ puts ("returned values do not match");
+ exit (1);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls17.c b/REORG.TODO/elf/tst-tls17.c
new file mode 100644
index 0000000000..c2a972d3c4
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls17.c
@@ -0,0 +1,28 @@
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+ void *h = dlopen ("tst-tlsmod17b.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("unexpectedly failed to open tst-tlsmod17b.so");
+ exit (1);
+ }
+
+ int (*fp) (void) = (int (*) (void)) dlsym (h, "tlsmod17b");
+ if (fp == NULL)
+ {
+ puts ("cannot find tlsmod17b");
+ exit (1);
+ }
+
+ if (fp ())
+ exit (1);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls18.c b/REORG.TODO/elf/tst-tls18.c
new file mode 100644
index 0000000000..b705b61d60
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls18.c
@@ -0,0 +1,37 @@
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+ char modname[sizeof "tst-tlsmod18aXX.so"];
+ void *h[20];
+ for (int i = 0; i < 20; i++)
+ {
+ snprintf (modname, sizeof modname, "tst-tlsmod18a%d.so", i);
+ h[i] = dlopen (modname, RTLD_LAZY);
+ if (h[i] == NULL)
+ {
+ printf ("unexpectedly failed to open %s", modname);
+ exit (1);
+ }
+ }
+
+ for (int i = 0; i < 20; i++)
+ {
+ int (*fp) (void) = (int (*) (void)) dlsym (h[i], "test");
+ if (fp == NULL)
+ {
+ printf ("cannot find test in tst-tlsmod18a%d.so", i);
+ exit (1);
+ }
+
+ if (fp ())
+ exit (1);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls19.c b/REORG.TODO/elf/tst-tls19.c
new file mode 100644
index 0000000000..dd8ea42c3f
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls19.c
@@ -0,0 +1,26 @@
+// BZ 12453
+#include <stdio.h>
+#include <dlfcn.h>
+
+
+static int
+do_test (void)
+{
+ void* dl = dlopen ("tst-tls19mod1.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (dl == NULL)
+ {
+ printf ("Error loading tst-tls19mod1.so: %s\n", dlerror ());
+ return 1;
+ }
+
+ int (*fn) (void) = dlsym (dl, "foo");
+ if (fn == NULL)
+ {
+ printf("Error obtaining symbol foo\n");
+ return 1;
+ }
+
+ return fn ();
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls19mod1.c b/REORG.TODO/elf/tst-tls19mod1.c
new file mode 100644
index 0000000000..2790097ae5
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls19mod1.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+extern int bar (void);
+extern int baz (void);
+
+int
+foo (void)
+{
+ int v1 = bar ();
+ int v2 = baz ();
+
+ printf ("bar=%d, baz=%d\n", v1, v2);
+
+ return v1 != 666 || v2 != 42;
+}
diff --git a/REORG.TODO/elf/tst-tls19mod2.c b/REORG.TODO/elf/tst-tls19mod2.c
new file mode 100644
index 0000000000..cae702f67c
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls19mod2.c
@@ -0,0 +1,13 @@
+static int __thread tbar __attribute__ ((tls_model ("initial-exec"))) = 666;
+
+void
+setter (int a)
+{
+ tbar = a;
+}
+
+int
+bar (void)
+{
+ return tbar;
+}
diff --git a/REORG.TODO/elf/tst-tls19mod3.c b/REORG.TODO/elf/tst-tls19mod3.c
new file mode 100644
index 0000000000..e7b28016b3
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls19mod3.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+static int __thread tbaz __attribute__ ((tls_model ("local-dynamic"))) = 42;
+
+void
+setter2 (int a)
+{
+ tbaz = a;
+}
+
+int
+baz (void)
+{
+ printf ("&tbaz=%p\n", &tbaz);
+ return tbaz;
+}
diff --git a/REORG.TODO/elf/tst-tls2-static.c b/REORG.TODO/elf/tst-tls2-static.c
new file mode 100644
index 0000000000..55ffa57448
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls2-static.c
@@ -0,0 +1 @@
+#include "tst-tls2.c"
diff --git a/REORG.TODO/elf/tst-tls2.c b/REORG.TODO/elf/tst-tls2.c
new file mode 100644
index 0000000000..963b8d6c88
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls2.c
@@ -0,0 +1,82 @@
+/* glibc test for TLS in ld.so. */
+#include <stdio.h>
+
+#include "tls-macros.h"
+
+
+/* Two 'int' variables in TLS. */
+VAR_INT_DEF(foo);
+VAR_INT_DEF(bar);
+
+
+static int
+do_test (void)
+{
+ int result = 0;
+ int *ap, *bp;
+
+
+ /* Set the variable using the local exec model. */
+ puts ("set bar to 1 (LE)");
+ ap = TLS_LE (bar);
+ *ap = 1;
+
+
+ /* Get variables using initial exec model. */
+ fputs ("get sum of foo and bar (IE)", stdout);
+ ap = TLS_IE (foo);
+ bp = TLS_IE (bar);
+ printf (" = %d\n", *ap + *bp);
+ result |= *ap + *bp != 1;
+ if (*ap != 0)
+ {
+ printf ("foo = %d\n", *ap);
+ result = 1;
+ }
+ if (*bp != 1)
+ {
+ printf ("bar = %d\n", *bp);
+ result = 1;
+ }
+
+
+ /* Get variables using local dynamic model. */
+ fputs ("get sum of foo and bar (LD)", stdout);
+ ap = TLS_LD (foo);
+ bp = TLS_LD (bar);
+ printf (" = %d\n", *ap + *bp);
+ result |= *ap + *bp != 1;
+ if (*ap != 0)
+ {
+ printf ("foo = %d\n", *ap);
+ result = 1;
+ }
+ if (*bp != 1)
+ {
+ printf ("bar = %d\n", *bp);
+ result = 1;
+ }
+
+
+ /* Get variables using generic dynamic model. */
+ fputs ("get sum of foo and bar (GD)", stdout);
+ ap = TLS_GD (foo);
+ bp = TLS_GD (bar);
+ printf (" = %d\n", *ap + *bp);
+ result |= *ap + *bp != 1;
+ if (*ap != 0)
+ {
+ printf ("foo = %d\n", *ap);
+ result = 1;
+ }
+ if (*bp != 1)
+ {
+ printf ("bar = %d\n", *bp);
+ result = 1;
+ }
+
+ return result;
+}
+
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls3.c b/REORG.TODO/elf/tst-tls3.c
new file mode 100644
index 0000000000..7e0abb4c58
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls3.c
@@ -0,0 +1,67 @@
+/* glibc test for TLS in ld.so. */
+#include <stdio.h>
+
+#include "tls-macros.h"
+
+
+/* One define int variable, two externs. */
+COMMON_INT_DECL(foo);
+VAR_INT_DECL(bar);
+VAR_INT_DEF(baz);
+
+
+extern int in_dso (void);
+
+
+static int
+do_test (void)
+{
+ int result = 0;
+ int *ap, *bp, *cp;
+
+
+ /* Set the variable using the local exec model. */
+ puts ("set baz to 3 (LE)");
+ ap = TLS_LE (baz);
+ *ap = 3;
+
+
+ /* Get variables using initial exec model. */
+ puts ("set variables foo and bar (IE)");
+ ap = TLS_IE (foo);
+ *ap = 1;
+ bp = TLS_IE (bar);
+ *bp = 2;
+
+
+ /* Get variables using local dynamic model. */
+ fputs ("get sum of foo, bar (GD) and baz (LD)", stdout);
+ ap = TLS_GD (foo);
+ bp = TLS_GD (bar);
+ cp = TLS_LD (baz);
+ printf (" = %d\n", *ap + *bp + *cp);
+ result |= *ap + *bp + *cp != 6;
+ if (*ap != 1)
+ {
+ printf ("foo = %d\n", *ap);
+ result = 1;
+ }
+ if (*bp != 2)
+ {
+ printf ("bar = %d\n", *bp);
+ result = 1;
+ }
+ if (*cp != 3)
+ {
+ printf ("baz = %d\n", *cp);
+ result = 1;
+ }
+
+
+ result |= in_dso ();
+
+ return result;
+}
+
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls4.c b/REORG.TODO/elf/tst-tls4.c
new file mode 100644
index 0000000000..6841f81386
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls4.c
@@ -0,0 +1,49 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int
+do_test (void)
+{
+ static const char modname[] = "tst-tlsmod2.so";
+ int result = 0;
+ int *foop;
+ int (*fp) (int, int *);
+ void *h;
+
+ h = dlopen (modname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname, dlerror ());
+ exit (1);
+ }
+
+ fp = dlsym (h, "in_dso");
+ if (fp == NULL)
+ {
+ printf ("cannot get symbol 'in_dso': %s\n", dlerror ());
+ exit (1);
+ }
+
+ result |= fp (0, NULL);
+
+ foop = dlsym (h, "foo");
+ if (foop == NULL)
+ {
+ printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ());
+ exit (1);
+ }
+ if (*foop != 16)
+ {
+ puts ("foo != 16");
+ result = 1;
+ }
+
+ dlclose (h);
+
+ return result;
+}
+
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls5.c b/REORG.TODO/elf/tst-tls5.c
new file mode 100644
index 0000000000..5f006fd645
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls5.c
@@ -0,0 +1,65 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int
+do_test (void)
+{
+ static const char modname[] = "tst-tlsmod2.so";
+ int result = 0;
+ int *foop;
+ int *foop2;
+ int (*fp) (int, int *);
+ void *h;
+
+ h = dlopen (modname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname, dlerror ());
+ exit (1);
+ }
+
+ foop = dlsym (h, "foo");
+ if (foop == NULL)
+ {
+ printf ("cannot get symbol 'foo': %s\n", dlerror ());
+ exit (1);
+ }
+
+ *foop = 42;
+
+ fp = dlsym (h, "in_dso");
+ if (fp == NULL)
+ {
+ printf ("cannot get symbol 'in_dso': %s\n", dlerror ());
+ exit (1);
+ }
+
+ result |= fp (42, foop);
+
+ foop2 = dlsym (h, "foo");
+ if (foop2 == NULL)
+ {
+ printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ());
+ exit (1);
+ }
+
+ if (foop != foop2)
+ {
+ puts ("address of 'foo' different the second time");
+ result = 1;
+ }
+ else if (*foop != 16)
+ {
+ puts ("foo != 16");
+ result = 1;
+ }
+
+ dlclose (h);
+
+ return result;
+}
+
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls6.c b/REORG.TODO/elf/tst-tls6.c
new file mode 100644
index 0000000000..df81c1f6b4
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls6.c
@@ -0,0 +1,84 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <link.h>
+
+
+static int
+do_test (void)
+{
+ static const char modname[] = "tst-tlsmod2.so";
+ int result = 0;
+ int *foop;
+ int *foop2;
+ int (*fp) (int, int *);
+ void *h;
+ int i;
+ int modid = -1;
+
+ for (i = 0; i < 10; ++i)
+ {
+ h = dlopen (modname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname, dlerror ());
+ exit (1);
+ }
+
+ /* Dirty test code here: we peek into a private data structure.
+ We make sure that the module gets assigned the same ID every
+ time. The value of the first round is used. */
+ if (modid == -1)
+ modid = ((struct link_map *) h)->l_tls_modid;
+ else if (((struct link_map *) h)->l_tls_modid != modid)
+ {
+ printf ("round %d: modid now %zd, initially %d\n",
+ i, ((struct link_map *) h)->l_tls_modid, modid);
+ result = 1;
+ }
+
+ foop = dlsym (h, "foo");
+ if (foop == NULL)
+ {
+ printf ("cannot get symbol 'foo': %s\n", dlerror ());
+ exit (1);
+ }
+
+ *foop = 42 + i;
+
+ fp = dlsym (h, "in_dso");
+ if (fp == NULL)
+ {
+ printf ("cannot get symbol 'in_dso': %s\n", dlerror ());
+ exit (1);
+ }
+
+ result |= fp (42 + i, foop);
+
+ foop2 = dlsym (h, "foo");
+ if (foop2 == NULL)
+ {
+ printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ());
+ exit (1);
+ }
+
+ if (foop != foop2)
+ {
+ puts ("address of 'foo' different the second time");
+ result = 1;
+ }
+ else if (*foop != 16)
+ {
+ puts ("foo != 16");
+ result = 1;
+ }
+
+ dlclose (h);
+ }
+
+ return result;
+}
+
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls7.c b/REORG.TODO/elf/tst-tls7.c
new file mode 100644
index 0000000000..fa46709600
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls7.c
@@ -0,0 +1,55 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <link.h>
+
+
+static int
+do_test (void)
+{
+ static const char modname[] = "tst-tlsmod3.so";
+ int result = 0;
+ int (*fp) (void);
+ void *h;
+ int i;
+ int modid = -1;
+
+ for (i = 0; i < 10; ++i)
+ {
+ h = dlopen (modname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname, dlerror ());
+ exit (1);
+ }
+
+ /* Dirty test code here: we peek into a private data structure.
+ We make sure that the module gets assigned the same ID every
+ time. The value of the first round is used. */
+ if (modid == -1)
+ modid = ((struct link_map *) h)->l_tls_modid;
+ else if (((struct link_map *) h)->l_tls_modid != (size_t) modid)
+ {
+ printf ("round %d: modid now %zu, initially %d\n",
+ i, ((struct link_map *) h)->l_tls_modid, modid);
+ result = 1;
+ }
+
+ fp = dlsym (h, "in_dso2");
+ if (fp == NULL)
+ {
+ printf ("cannot get symbol 'in_dso2': %s\n", dlerror ());
+ exit (1);
+ }
+
+ result |= fp ();
+
+ dlclose (h);
+ }
+
+ return result;
+}
+
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls8.c b/REORG.TODO/elf/tst-tls8.c
new file mode 100644
index 0000000000..c779572617
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls8.c
@@ -0,0 +1,167 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <link.h>
+
+
+static int
+do_test (void)
+{
+ static const char modname1[] = "$ORIGIN/tst-tlsmod3.so";
+ static const char modname2[] = "$ORIGIN/tst-tlsmod4.so";
+ int result = 0;
+ int (*fp1) (void);
+ int (*fp2) (int, int *);
+ void *h1;
+ void *h2;
+ int i;
+ size_t modid1 = (size_t) -1;
+ size_t modid2 = (size_t) -1;
+ int *bazp;
+
+ for (i = 0; i < 10; ++i)
+ {
+ h1 = dlopen (modname1, RTLD_LAZY);
+ if (h1 == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname1, dlerror ());
+ exit (1);
+ }
+
+ /* Dirty test code here: we peek into a private data structure.
+ We make sure that the module gets assigned the same ID every
+ time. The value of the first round is used. */
+ if (modid1 == (size_t) -1)
+ modid1 = ((struct link_map *) h1)->l_tls_modid;
+ else if (((struct link_map *) h1)->l_tls_modid != modid1)
+ {
+ printf ("round %d: modid now %zd, initially %zd\n",
+ i, ((struct link_map *) h1)->l_tls_modid, modid1);
+ result = 1;
+ }
+
+ fp1 = dlsym (h1, "in_dso2");
+ if (fp1 == NULL)
+ {
+ printf ("cannot get symbol 'in_dso2' in %s\n", modname1);
+ exit (1);
+ }
+
+ result |= fp1 ();
+
+
+
+ h2 = dlopen (modname2, RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname2, dlerror ());
+ exit (1);
+ }
+
+ /* Dirty test code here: we peek into a private data structure.
+ We make sure that the module gets assigned the same ID every
+ time. The value of the first round is used. */
+ if (modid2 == (size_t) -1)
+ modid2 = ((struct link_map *) h1)->l_tls_modid;
+ else if (((struct link_map *) h1)->l_tls_modid != modid2)
+ {
+ printf ("round %d: modid now %zd, initially %zd\n",
+ i, ((struct link_map *) h1)->l_tls_modid, modid2);
+ result = 1;
+ }
+
+ bazp = dlsym (h2, "baz");
+ if (bazp == NULL)
+ {
+ printf ("cannot get symbol 'baz' in %s\n", modname2);
+ exit (1);
+ }
+
+ *bazp = 42 + i;
+
+ fp2 = dlsym (h2, "in_dso");
+ if (fp2 == NULL)
+ {
+ printf ("cannot get symbol 'in_dso' in %s\n", modname2);
+ exit (1);
+ }
+
+ result |= fp2 (42 + i, bazp);
+
+ dlclose (h1);
+ dlclose (h2);
+
+
+ h1 = dlopen (modname1, RTLD_LAZY);
+ if (h1 == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname1, dlerror ());
+ exit (1);
+ }
+
+ /* Dirty test code here: we peek into a private data structure.
+ We make sure that the module gets assigned the same ID every
+ time. The value of the first round is used. */
+ if (((struct link_map *) h1)->l_tls_modid != modid1)
+ {
+ printf ("round %d: modid now %zd, initially %zd\n",
+ i, ((struct link_map *) h1)->l_tls_modid, modid1);
+ result = 1;
+ }
+
+ fp1 = dlsym (h1, "in_dso2");
+ if (fp1 == NULL)
+ {
+ printf ("cannot get symbol 'in_dso2' in %s\n", modname1);
+ exit (1);
+ }
+
+ result |= fp1 ();
+
+
+
+ h2 = dlopen (modname2, RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname2, dlerror ());
+ exit (1);
+ }
+
+ /* Dirty test code here: we peek into a private data structure.
+ We make sure that the module gets assigned the same ID every
+ time. The value of the first round is used. */
+ if (((struct link_map *) h1)->l_tls_modid != modid2)
+ {
+ printf ("round %d: modid now %zd, initially %zd\n",
+ i, ((struct link_map *) h1)->l_tls_modid, modid2);
+ result = 1;
+ }
+
+ bazp = dlsym (h2, "baz");
+ if (bazp == NULL)
+ {
+ printf ("cannot get symbol 'baz' in %s\n", modname2);
+ exit (1);
+ }
+
+ *bazp = 62 + i;
+
+ fp2 = dlsym (h2, "in_dso");
+ if (fp2 == NULL)
+ {
+ printf ("cannot get symbol 'in_dso' in %s\n", modname2);
+ exit (1);
+ }
+
+ result |= fp2 (62 + i, bazp);
+
+ /* This time the dlclose calls are in reverse order. */
+ dlclose (h2);
+ dlclose (h1);
+ }
+
+ return result;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tls9-static.c b/REORG.TODO/elf/tst-tls9-static.c
new file mode 100644
index 0000000000..51812ccc7d
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls9-static.c
@@ -0,0 +1 @@
+#include "tst-tls9.c"
diff --git a/REORG.TODO/elf/tst-tls9.c b/REORG.TODO/elf/tst-tls9.c
new file mode 100644
index 0000000000..ee21b47c70
--- /dev/null
+++ b/REORG.TODO/elf/tst-tls9.c
@@ -0,0 +1,36 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <link.h>
+
+static int
+do_test (void)
+{
+ static const char modname1[] = "tst-tlsmod5.so";
+ static const char modname2[] = "tst-tlsmod6.so";
+ int result = 0;
+
+ void *h1 = dlopen (modname1, RTLD_LAZY);
+ if (h1 == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname1, dlerror ());
+ result = 1;
+ }
+ void *h2 = dlopen (modname2, RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname2, dlerror ());
+ result = 1;
+ }
+
+ if (h1 != NULL)
+ dlclose (h1);
+ if (h2 != NULL)
+ dlclose (h2);
+
+ return result;
+}
+
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tlsalign-extern-static.c b/REORG.TODO/elf/tst-tlsalign-extern-static.c
new file mode 100644
index 0000000000..e84900eee4
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsalign-extern-static.c
@@ -0,0 +1 @@
+#include "tst-tlsalign-extern.c"
diff --git a/REORG.TODO/elf/tst-tlsalign-extern.c b/REORG.TODO/elf/tst-tlsalign-extern.c
new file mode 100644
index 0000000000..11384d085e
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsalign-extern.c
@@ -0,0 +1,73 @@
+/* Test for large alignment in TLS blocks (extern case), BZ#18383.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This is the same as tst-tlsalign-static.c, except that it uses
+ TLS variables that are defined in a separate translation unit
+ (ts-tlsalign-vars.c). It turned out that the cause of BZ#18383
+ on ARM was actually an ARM assembler bug triggered by the ways of
+ using .tdata/.tbss sections and relocs referring to them that GCC
+ chooses when the variables are defined in the same translation
+ unit that contains the references. */
+
+extern __thread int tdata1;
+extern __thread int tdata2;
+extern __thread int tdata3;
+extern __thread int tbss1;
+extern __thread int tbss2;
+extern __thread int tbss3;
+
+static int
+test_one (const char *which, unsigned int alignment, int *var, int value)
+{
+ uintptr_t addr = (uintptr_t) var;
+ unsigned int misalign = addr & (alignment - 1);
+
+ printf ("%s TLS address %p %% %u = %u\n",
+ which, (void *) var, alignment, misalign);
+
+ int got = *var;
+ if (got != value)
+ {
+ printf ("%s value %d should be %d\n", which, got, value);
+ return 1;
+ }
+
+ return misalign != 0;
+}
+
+static int
+do_test (void)
+{
+ int fail = 0;
+
+ fail |= test_one ("tdata1", 4, &tdata1, 1);
+ fail |= test_one ("tdata2", 0x10, &tdata2, 2);
+ fail |= test_one ("tdata3", 0x1000, &tdata3, 4);
+
+ fail |= test_one ("tbss1", 4, &tbss1, 0);
+ fail |= test_one ("tbss2", 0x10, &tbss2, 0);
+ fail |= test_one ("tbss3", 0x1000, &tbss3, 0);
+
+ return fail ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tlsalign-lib.c b/REORG.TODO/elf/tst-tlsalign-lib.c
new file mode 100644
index 0000000000..4371e581a6
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsalign-lib.c
@@ -0,0 +1,6 @@
+__thread int mod_tdata1 = 1;
+__thread int mod_tdata2 __attribute__ ((aligned (0x10))) = 2;
+__thread int mod_tdata3 __attribute__ ((aligned (0x1000))) = 4;
+__thread int mod_tbss1;
+__thread int mod_tbss2 __attribute__ ((aligned (0x10)));
+__thread int mod_tbss3 __attribute__ ((aligned (0x1000)));
diff --git a/REORG.TODO/elf/tst-tlsalign-static.c b/REORG.TODO/elf/tst-tlsalign-static.c
new file mode 100644
index 0000000000..1671abf28e
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsalign-static.c
@@ -0,0 +1,2 @@
+#define NO_LIB
+#include "tst-tlsalign.c"
diff --git a/REORG.TODO/elf/tst-tlsalign-vars.c b/REORG.TODO/elf/tst-tlsalign-vars.c
new file mode 100644
index 0000000000..01b3501d3b
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsalign-vars.c
@@ -0,0 +1,28 @@
+/* This is for tst-tlsalign-extern.c, which see. It's essential for the
+ purpose of the test that these definitions be in a separate translation
+ unit from the code using the variables. */
+
+__thread int tdata1 = 1;
+__thread int tdata2 __attribute__ ((aligned (0x10))) = 2;
+__thread int tdata3 __attribute__ ((aligned (0x1000))) = 4;
+__thread int tbss1;
+__thread int tbss2 __attribute__ ((aligned (0x10)));
+__thread int tbss3 __attribute__ ((aligned (0x1000)));
+
+/* This function is never called. But its presence in this translation
+ unit makes GCC emit the variables above in the order defined (perhaps
+ because it's the order in which they're used here?) rather than
+ reordering them into descending order of alignment requirement--and so
+ keeps it more similar to the tst-tlsalign-static.c case--just in case
+ that affects the bug (though there is no evidence that it does). */
+
+void
+unused (void)
+{
+ tdata1 = -1;
+ tdata2 = -2;
+ tdata3 = -3;
+ tbss1 = -4;
+ tbss2 = -5;
+ tbss3 = -6;
+}
diff --git a/REORG.TODO/elf/tst-tlsalign.c b/REORG.TODO/elf/tst-tlsalign.c
new file mode 100644
index 0000000000..b129ebda0e
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsalign.c
@@ -0,0 +1,84 @@
+/* Test for large alignment in TLS blocks, BZ#18383.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static __thread int tdata1 = 1;
+static __thread int tdata2 __attribute__ ((aligned (0x10))) = 2;
+static __thread int tdata3 __attribute__ ((aligned (0x1000))) = 4;
+static __thread int tbss1;
+static __thread int tbss2 __attribute__ ((aligned (0x10)));
+static __thread int tbss3 __attribute__ ((aligned (0x1000)));
+
+#ifndef NO_LIB
+extern __thread int mod_tdata1;
+extern __thread int mod_tdata2;
+extern __thread int mod_tdata3;
+extern __thread int mod_tbss1;
+extern __thread int mod_tbss2;
+extern __thread int mod_tbss3;
+#endif
+
+static int
+test_one (const char *which, unsigned int alignment, int *var, int value)
+{
+ uintptr_t addr = (uintptr_t) var;
+ unsigned int misalign = addr & (alignment - 1);
+
+ printf ("%s TLS address %p %% %u = %u\n",
+ which, (void *) var, alignment, misalign);
+
+ int got = *var;
+ if (got != value)
+ {
+ printf ("%s value %d should be %d\n", which, got, value);
+ return 1;
+ }
+
+ return misalign != 0;
+}
+
+static int
+do_test (void)
+{
+ int fail = 0;
+
+ fail |= test_one ("tdata1", 4, &tdata1, 1);
+ fail |= test_one ("tdata2", 0x10, &tdata2, 2);
+ fail |= test_one ("tdata3", 0x1000, &tdata3, 4);
+
+ fail |= test_one ("tbss1", 4, &tbss1, 0);
+ fail |= test_one ("tbss2", 0x10, &tbss2, 0);
+ fail |= test_one ("tbss3", 0x1000, &tbss3, 0);
+
+#ifndef NO_LIB
+ fail |= test_one ("mod_tdata1", 4, &mod_tdata1, 1);
+ fail |= test_one ("mod_tdata2", 0x10, &mod_tdata2, 2);
+ fail |= test_one ("mod_tdata3", 0x1000, &mod_tdata3, 4);
+
+ fail |= test_one ("mod_tbss1", 4, &mod_tbss1, 0);
+ fail |= test_one ("mod_tbss2", 0x10, &mod_tbss2, 0);
+ fail |= test_one ("mod_tbss3", 0x1000, &mod_tbss3, 0);
+#endif
+
+ return fail ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-tlsmod1.c b/REORG.TODO/elf/tst-tlsmod1.c
new file mode 100644
index 0000000000..8d9156791b
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod1.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+
+#include "tls-macros.h"
+
+
+/* One define int variable, two externs. */
+COMMON_INT_DEF(foo);
+VAR_INT_DEF(bar);
+VAR_INT_DECL(baz);
+
+extern int in_dso (void);
+
+int
+in_dso (void)
+{
+ int result = 0;
+ int *ap, *bp, *cp;
+
+ /* Get variables using initial exec model. */
+ fputs ("get sum of foo and bar (IE)", stdout);
+ asm ("" ::: "memory");
+ ap = TLS_IE (foo);
+ bp = TLS_IE (bar);
+ printf (" = %d\n", *ap + *bp);
+ result |= *ap + *bp != 3;
+ if (*ap != 1)
+ {
+ printf ("foo = %d\n", *ap);
+ result = 1;
+ }
+ if (*bp != 2)
+ {
+ printf ("bar = %d\n", *bp);
+ result = 1;
+ }
+
+
+ /* Get variables using generic dynamic model. */
+ fputs ("get sum of foo and bar and baz (GD)", stdout);
+ ap = TLS_GD (foo);
+ bp = TLS_GD (bar);
+ cp = TLS_GD (baz);
+ printf (" = %d\n", *ap + *bp + *cp);
+ result |= *ap + *bp + *cp != 6;
+ if (*ap != 1)
+ {
+ printf ("foo = %d\n", *ap);
+ result = 1;
+ }
+ if (*bp != 2)
+ {
+ printf ("bar = %d\n", *bp);
+ result = 1;
+ }
+ if (*cp != 3)
+ {
+ printf ("baz = %d\n", *cp);
+ result = 1;
+ }
+
+ return result;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod10.c b/REORG.TODO/elf/tst-tlsmod10.c
new file mode 100644
index 0000000000..32e54f3c04
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod10.c
@@ -0,0 +1 @@
+#include "tst-tlsmod8.c"
diff --git a/REORG.TODO/elf/tst-tlsmod11.c b/REORG.TODO/elf/tst-tlsmod11.c
new file mode 100644
index 0000000000..cffbd68edc
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod11.c
@@ -0,0 +1,4 @@
+#include "tst-tls10.h"
+
+__thread struct A a1 = { 4, 5, 6 };
+__thread struct A a2 = { 7, 8, 9 };
diff --git a/REORG.TODO/elf/tst-tlsmod12.c b/REORG.TODO/elf/tst-tlsmod12.c
new file mode 100644
index 0000000000..d0be51891a
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod12.c
@@ -0,0 +1,12 @@
+#include "tst-tls10.h"
+
+extern __thread struct A a2 __attribute__((tls_model("initial-exec")));
+
+void
+check1 (void)
+{
+ if (a1.a != 4 || a1.b != 5 || a1.c != 6)
+ abort ();
+ if (a2.a != 7 || a2.b != 8 || a2.c != 9)
+ abort ();
+}
diff --git a/REORG.TODO/elf/tst-tlsmod13.c b/REORG.TODO/elf/tst-tlsmod13.c
new file mode 100644
index 0000000000..7712d8b8c8
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod13.c
@@ -0,0 +1,7 @@
+__thread int a[2] __attribute__ ((tls_model ("initial-exec")));
+
+int
+foo (void)
+{
+ return a[0];
+}
diff --git a/REORG.TODO/elf/tst-tlsmod13a.c b/REORG.TODO/elf/tst-tlsmod13a.c
new file mode 100644
index 0000000000..ca4eaccbff
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod13a.c
@@ -0,0 +1,9 @@
+__thread int b[2] __attribute__ ((tls_model ("initial-exec")));
+
+extern int foo (void);
+
+int
+bar (void)
+{
+ return foo () + b[0];
+}
diff --git a/REORG.TODO/elf/tst-tlsmod14a.c b/REORG.TODO/elf/tst-tlsmod14a.c
new file mode 100644
index 0000000000..824c06d1f9
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod14a.c
@@ -0,0 +1,35 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#define AL 4096
+struct foo
+{
+ int i;
+} __attribute ((aligned (AL)));
+
+static __thread struct foo f;
+static struct foo g;
+
+
+#ifndef FCT
+# define FCT in_dso1
+#endif
+
+
+int
+FCT (void)
+{
+ puts (__func__);
+
+ int result = 0;
+
+ int fail = (((uintptr_t) &f) & (AL - 1)) != 0;
+ printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK");
+ result |= fail;
+
+ fail = (((uintptr_t) &g) & (AL - 1)) != 0;
+ printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK");
+ result |= fail;
+
+ return result;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod14b.c b/REORG.TODO/elf/tst-tlsmod14b.c
new file mode 100644
index 0000000000..24d9ceaf7e
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod14b.c
@@ -0,0 +1,2 @@
+#define FCT in_dso2
+#include "tst-tlsmod14a.c"
diff --git a/REORG.TODO/elf/tst-tlsmod15a.c b/REORG.TODO/elf/tst-tlsmod15a.c
new file mode 100644
index 0000000000..66c707129a
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod15a.c
@@ -0,0 +1,6 @@
+extern int nonexistent_dummy_var;
+int *
+foo (void)
+{
+ return &nonexistent_dummy_var;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod15b.c b/REORG.TODO/elf/tst-tlsmod15b.c
new file mode 100644
index 0000000000..b37283686a
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod15b.c
@@ -0,0 +1,9 @@
+#include "tst-tls10.h"
+
+__thread int mod15b_var __attribute__((tls_model("initial-exec")));
+
+int
+in_dso (void)
+{
+ return mod15b_var;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod16a.c b/REORG.TODO/elf/tst-tlsmod16a.c
new file mode 100644
index 0000000000..4ec6a6c37d
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod16a.c
@@ -0,0 +1 @@
+int __thread tlsvar;
diff --git a/REORG.TODO/elf/tst-tlsmod16b.c b/REORG.TODO/elf/tst-tlsmod16b.c
new file mode 100644
index 0000000000..1ecba26dbe
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod16b.c
@@ -0,0 +1,7 @@
+extern __thread int tlsvar __attribute__((tls_model("initial-exec")));
+
+void *
+in_dso (void)
+{
+ return &tlsvar;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod17a.c b/REORG.TODO/elf/tst-tlsmod17a.c
new file mode 100644
index 0000000000..24c84a1590
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod17a.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+
+#ifndef N
+#define N 0
+#endif
+#define CONCAT1(s, n) s##n
+#define CONCAT(s, n) CONCAT1(s, n)
+
+__thread int CONCAT (v, N) = 4;
+
+int
+CONCAT (tlsmod17a, N) (void)
+{
+ int *p = &CONCAT (v, N);
+ /* GCC assumes &var is never NULL, add optimization barrier. */
+ asm volatile ("" : "+r" (p));
+ if (p == NULL || *p != 4)
+ {
+ printf ("fail %d %p\n", N, p);
+ return 1;
+ }
+ return 0;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod17b.c b/REORG.TODO/elf/tst-tlsmod17b.c
new file mode 100644
index 0000000000..6178828737
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod17b.c
@@ -0,0 +1,15 @@
+#define P(N) extern int tlsmod17a##N (void);
+#define PS P(0) P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9) \
+ P(10) P(12) P(13) P(14) P(15) P(16) P(17) P(18) P(19)
+PS
+#undef P
+
+int
+tlsmod17b (void)
+{
+ int res = 0;
+#define P(N) res |= tlsmod17a##N ();
+ PS
+#undef P
+ return res;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod18a.c b/REORG.TODO/elf/tst-tlsmod18a.c
new file mode 100644
index 0000000000..1d728daa05
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod18a.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+
+#ifndef N
+# define N 0
+#endif
+
+static __thread int var = 4;
+
+int
+test (void)
+{
+ int *p = &var;
+ /* GCC assumes &var is never NULL, add optimization barrier. */
+ asm volatile ("" : "+r" (p));
+ if (p == NULL || *p != 4)
+ {
+ printf ("fail %d %p\n", N, p);
+ return 1;
+ }
+ return 0;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod2.c b/REORG.TODO/elf/tst-tlsmod2.c
new file mode 100644
index 0000000000..40eb1407f8
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod2.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+
+#include "tls-macros.h"
+
+
+COMMON_INT_DEF(foo);
+
+
+int
+in_dso (int n, int *caller_foop)
+{
+ int *foop;
+ int result = 0;
+
+ puts ("foo"); /* Make sure PLT is used before macros. */
+ asm ("" ::: "memory");
+
+ foop = TLS_GD (foo);
+
+ if (caller_foop != NULL && foop != caller_foop)
+ {
+ printf ("callers address of foo differs: %p vs %p\n", caller_foop, foop);
+ result = 1;
+ }
+ else if (*foop != n)
+ {
+ printf ("foo != %d\n", n);
+ result = 1;
+ }
+
+ *foop = 16;
+
+ return result;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod3.c b/REORG.TODO/elf/tst-tlsmod3.c
new file mode 100644
index 0000000000..6d186c47ee
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod3.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+
+#include "tls-macros.h"
+
+extern int in_dso (int n, int *caller_foop);
+
+COMMON_INT_DEF(comm_n);
+
+
+
+
+int
+in_dso2 (void)
+{
+ int *foop;
+ int result = 0;
+ static int n;
+ int *np;
+
+ puts ("foo"); /* Make sure PLT is used before macros. */
+ asm ("" ::: "memory");
+
+ foop = TLS_GD (foo);
+ np = TLS_GD (comm_n);
+
+ if (n != *np)
+ {
+ printf ("n = %d != comm_n = %d\n", n, *np);
+ result = 1;
+ }
+
+ result |= in_dso (*foop = 42 + n++, foop);
+
+ *foop = 16;
+
+ return result;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod4.c b/REORG.TODO/elf/tst-tlsmod4.c
new file mode 100644
index 0000000000..86889aac7e
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod4.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+
+#include "tls-macros.h"
+
+
+COMMON_INT_DEF(baz);
+
+
+int
+in_dso (int n, int *caller_bazp)
+{
+ int *bazp;
+ int result = 0;
+
+ puts ("foo"); /* Make sure PLT is used before macros. */
+ asm ("" ::: "memory");
+
+ bazp = TLS_GD (baz);
+
+ if (caller_bazp != NULL && bazp != caller_bazp)
+ {
+ printf ("callers address of baz differs: %p vs %p\n", caller_bazp, bazp);
+ result = 1;
+ }
+ else if (*bazp != n)
+ {
+ printf ("baz != %d\n", n);
+ result = 1;
+ }
+
+ *bazp = 16;
+
+ return result;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod5.c b/REORG.TODO/elf/tst-tlsmod5.c
new file mode 100644
index 0000000000..a97c7e5e0c
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod5.c
@@ -0,0 +1,3 @@
+#include "tls-macros.h"
+
+COMMON_INT_DEF(foo);
diff --git a/REORG.TODO/elf/tst-tlsmod6.c b/REORG.TODO/elf/tst-tlsmod6.c
new file mode 100644
index 0000000000..e968596dd4
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod6.c
@@ -0,0 +1,3 @@
+#include "tls-macros.h"
+
+COMMON_INT_DEF(bar);
diff --git a/REORG.TODO/elf/tst-tlsmod7.c b/REORG.TODO/elf/tst-tlsmod7.c
new file mode 100644
index 0000000000..3df7907bcf
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod7.c
@@ -0,0 +1,101 @@
+#include "tst-tls10.h"
+
+__thread int dummy __attribute__((visibility ("hidden"))) = 12;
+__thread struct A a1 = { 4, 5, 6 };
+__thread struct A a2 = { 7, 8, 9 };
+__thread struct A a3 __attribute__((tls_model("initial-exec")))
+ = { 10, 11, 12 };
+__thread struct A a4 __attribute__((tls_model("initial-exec")))
+ = { 13, 14, 15 };
+static __thread struct A local1 = { 16, 17, 18 };
+static __thread struct A local2 __attribute__((tls_model("initial-exec")))
+ = { 19, 20, 21 };
+
+void
+check1 (void)
+{
+ if (a1.a != 4 || a1.b != 5 || a1.c != 6)
+ abort ();
+ if (a2.a != 22 || a2.b != 23 || a2.c != 24)
+ abort ();
+ if (a3.a != 10 || a3.b != 11 || a3.c != 12)
+ abort ();
+ if (a4.a != 25 || a4.b != 26 || a4.c != 27)
+ abort ();
+ if (local1.a != 16 || local1.b != 17 || local1.c != 18)
+ abort ();
+ if (local2.a != 19 || local2.b != 20 || local2.c != 21)
+ abort ();
+}
+
+struct A *
+f1a (void)
+{
+ return &a1;
+}
+
+struct A *
+f2a (void)
+{
+ return &a2;
+}
+
+struct A *
+f3a (void)
+{
+ return &a3;
+}
+
+struct A *
+f4a (void)
+{
+ return &a4;
+}
+
+struct A *
+f5a (void)
+{
+ return &local1;
+}
+
+struct A *
+f6a (void)
+{
+ return &local2;
+}
+
+int
+f1b (void)
+{
+ return a1.a;
+}
+
+int
+f2b (void)
+{
+ return a2.b;
+}
+
+int
+f3b (void)
+{
+ return a3.c;
+}
+
+int
+f4b (void)
+{
+ return a4.a;
+}
+
+int
+f5b (void)
+{
+ return local1.b;
+}
+
+int
+f6b (void)
+{
+ return local2.c;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod8.c b/REORG.TODO/elf/tst-tlsmod8.c
new file mode 100644
index 0000000000..89772ac42f
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod8.c
@@ -0,0 +1,70 @@
+#include "tst-tls10.h"
+
+__thread long long dummy __attribute__((visibility ("hidden"))) = 12;
+__thread struct A a2 = { 22, 23, 24 };
+__thread struct A a4 __attribute__((tls_model("initial-exec")))
+ = { 25, 26, 27 };
+static __thread struct A local1 = { 28, 29, 30 };
+static __thread struct A local2 __attribute__((tls_model("initial-exec")))
+ = { 31, 32, 33 };
+
+void
+check2 (void)
+{
+ if (a2.a != 22 || a2.b != 23 || a2.c != 24)
+ abort ();
+ if (a4.a != 25 || a4.b != 26 || a4.c != 27)
+ abort ();
+ if (local1.a != 28 || local1.b != 29 || local1.c != 30)
+ abort ();
+ if (local2.a != 31 || local2.b != 32 || local2.c != 33)
+ abort ();
+}
+
+struct A *
+f7a (void)
+{
+ return &a2;
+}
+
+struct A *
+f8a (void)
+{
+ return &a4;
+}
+
+struct A *
+f9a (void)
+{
+ return &local1;
+}
+
+struct A *
+f10a (void)
+{
+ return &local2;
+}
+
+int
+f7b (void)
+{
+ return a2.b;
+}
+
+int
+f8b (void)
+{
+ return a4.a;
+}
+
+int
+f9b (void)
+{
+ return local1.b;
+}
+
+int
+f10b (void)
+{
+ return local2.c;
+}
diff --git a/REORG.TODO/elf/tst-tlsmod9.c b/REORG.TODO/elf/tst-tlsmod9.c
new file mode 100644
index 0000000000..6b11ed58b8
--- /dev/null
+++ b/REORG.TODO/elf/tst-tlsmod9.c
@@ -0,0 +1,99 @@
+#include "tst-tls10.h"
+
+__thread int dummy __attribute__((visibility ("hidden"))) = 12;
+__thread struct A a1 = { 4, 5, 6 };
+__thread struct A a3 __attribute__((tls_model("initial-exec")))
+ = { 10, 11, 12 };
+extern __thread struct A a4 __attribute__((tls_model("initial-exec")));
+static __thread struct A local1 = { 16, 17, 18 };
+static __thread struct A local2 __attribute__((tls_model("initial-exec")))
+ = { 19, 20, 21 };
+
+void
+check1 (void)
+{
+ if (a1.a != 4 || a1.b != 5 || a1.c != 6)
+ abort ();
+ if (a2.a != 22 || a2.b != 23 || a2.c != 24)
+ abort ();
+ if (a3.a != 10 || a3.b != 11 || a3.c != 12)
+ abort ();
+ if (a4.a != 25 || a4.b != 26 || a4.c != 27)
+ abort ();
+ if (local1.a != 16 || local1.b != 17 || local1.c != 18)
+ abort ();
+ if (local2.a != 19 || local2.b != 20 || local2.c != 21)
+ abort ();
+}
+
+struct A *
+f1a (void)
+{
+ return &a1;
+}
+
+struct A *
+f2a (void)
+{
+ return &a2;
+}
+
+struct A *
+f3a (void)
+{
+ return &a3;
+}
+
+struct A *
+f4a (void)
+{
+ return &a4;
+}
+
+struct A *
+f5a (void)
+{
+ return &local1;
+}
+
+struct A *
+f6a (void)
+{
+ return &local2;
+}
+
+int
+f1b (void)
+{
+ return a1.a;
+}
+
+int
+f2b (void)
+{
+ return a2.b;
+}
+
+int
+f3b (void)
+{
+ return a3.c;
+}
+
+int
+f4b (void)
+{
+ return a4.a;
+}
+
+int
+f5b (void)
+{
+ return local1.b;
+}
+
+int
+f6b (void)
+{
+ return local2.c;
+}
diff --git a/REORG.TODO/elf/tst-unique1.c b/REORG.TODO/elf/tst-unique1.c
new file mode 100644
index 0000000000..b5e53e49a0
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique1.c
@@ -0,0 +1,73 @@
+#include <config.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <sys/mman.h>
+
+static int
+do_test (void)
+{
+ void *h1 = dlopen ("tst-unique1mod1.so", RTLD_LAZY);
+ if (h1 == NULL)
+ {
+ puts ("cannot load tst-unique1mod1");
+ return 1;
+ }
+ int *(*f1) (void) = dlsym (h1, "f");
+ if (f1 == NULL)
+ {
+ puts ("cannot locate f in tst-unique1mod1");
+ return 1;
+ }
+ void *h2 = dlopen ("tst-unique1mod2.so", RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ puts ("cannot load tst-unique1mod2");
+ return 1;
+ }
+ int (*f2) (int *) = dlsym (h2, "f");
+ if (f2 == NULL)
+ {
+ puts ("cannot locate f in tst-unique1mod2");
+ return 1;
+ }
+ if (f2 (f1 ()))
+ {
+ puts ("f from tst-unique1mod2 failed");
+ return 1;
+ }
+ dlclose (h2);
+ dlclose (h1);
+ mmap (NULL, 1024 * 1024 * 16, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ h2 = dlopen ("tst-unique1mod2.so", RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ puts ("cannot load tst-unique1mod2");
+ return 1;
+ }
+ f2 = dlsym (h2, "f");
+ if (f2 == NULL)
+ {
+ puts ("cannot locate f in tst-unique1mod2");
+ return 1;
+ }
+ h1 = dlopen ("tst-unique1mod1.so", RTLD_LAZY);
+ if (h1 == NULL)
+ {
+ puts ("cannot load tst-unique1mod1");
+ return 1;
+ }
+ f1 = dlsym (h1, "f");
+ if (f1 == NULL)
+ {
+ puts ("cannot locate f in tst-unique1mod1");
+ return 1;
+ }
+ if (f2 (f1 ()))
+ {
+ puts ("f from tst-unique1mod2 failed");
+ return 1;
+ }
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-unique1mod1.c b/REORG.TODO/elf/tst-unique1mod1.c
new file mode 100644
index 0000000000..84b1f908d6
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique1mod1.c
@@ -0,0 +1,16 @@
+#include <config.h>
+
+asm (".data;"
+ ".globl var\n"
+ ".type var, %gnu_unique_object\n"
+ ".size var, 4\n"
+ "var:.zero 4\n"
+ ".previous");
+extern int var;
+
+int *
+f (void)
+{
+ var = 1;
+ return &var;
+}
diff --git a/REORG.TODO/elf/tst-unique1mod2.c b/REORG.TODO/elf/tst-unique1mod2.c
new file mode 100644
index 0000000000..126ca1ac6c
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique1mod2.c
@@ -0,0 +1,15 @@
+#include <config.h>
+
+asm (".data;"
+ ".globl var\n"
+ ".type var, %gnu_unique_object\n"
+ ".size var, 4\n"
+ "var:.zero 4\n"
+ ".previous");
+extern int var;
+
+int
+f (int *p)
+{
+ return &var != p || *p != 1;
+}
diff --git a/REORG.TODO/elf/tst-unique2.c b/REORG.TODO/elf/tst-unique2.c
new file mode 100644
index 0000000000..e0173b7bcc
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique2.c
@@ -0,0 +1,27 @@
+#include <config.h>
+#include <dlfcn.h>
+#include <stdio.h>
+
+extern int var;
+
+static int
+do_test (void)
+{
+ var = 1;
+
+ void *h = dlopen ("tst-unique2mod2.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("cannot load tst-unique2mod2");
+ return 1;
+ }
+ int (*f) (int *) = dlsym (h, "f");
+ if (f == NULL)
+ {
+ puts ("cannot locate f in tst-unique2mod2");
+ return 1;
+ }
+ return f (&var);
+}
+
+#include <support/test-driver.c>
diff --git a/REORG.TODO/elf/tst-unique2mod1.c b/REORG.TODO/elf/tst-unique2mod1.c
new file mode 100644
index 0000000000..7cdb0eb0a0
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique2mod1.c
@@ -0,0 +1,8 @@
+#include <config.h>
+
+asm (".data;"
+ ".globl var\n"
+ ".type var, %gnu_unique_object\n"
+ ".size var, 4\n"
+ "var:.zero 4\n"
+ ".previous");
diff --git a/REORG.TODO/elf/tst-unique2mod2.c b/REORG.TODO/elf/tst-unique2mod2.c
new file mode 100644
index 0000000000..126ca1ac6c
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique2mod2.c
@@ -0,0 +1,15 @@
+#include <config.h>
+
+asm (".data;"
+ ".globl var\n"
+ ".type var, %gnu_unique_object\n"
+ ".size var, 4\n"
+ "var:.zero 4\n"
+ ".previous");
+extern int var;
+
+int
+f (int *p)
+{
+ return &var != p || *p != 1;
+}
diff --git a/REORG.TODO/elf/tst-unique3.cc b/REORG.TODO/elf/tst-unique3.cc
new file mode 100644
index 0000000000..efdd6d78c2
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique3.cc
@@ -0,0 +1,24 @@
+#include "tst-unique3.h"
+
+#include <cstdio>
+#include "../dlfcn/dlfcn.h"
+
+int t = S<char>::i;
+
+int
+main (void)
+{
+ std::printf ("%d %d\n", S<char>::i, t);
+ int result = S<char>::i++ != 1 || t != 1;
+ result |= in_lib ();
+ void *d = dlopen ("$ORIGIN/tst-unique3lib2.so", RTLD_LAZY);
+ int (*fp) ();
+ if (d == NULL || (fp = (int(*)()) dlsym (d, "in_lib2")) == NULL)
+ {
+ std::printf ("failed to get symbol in_lib2\n");
+ return 1;
+ }
+ result |= fp ();
+ dlclose (d);
+ return result;
+}
diff --git a/REORG.TODO/elf/tst-unique3.h b/REORG.TODO/elf/tst-unique3.h
new file mode 100644
index 0000000000..716d23641c
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique3.h
@@ -0,0 +1,8 @@
+// BZ 12510
+template<typename T>
+struct S
+{
+ static int i;
+};
+
+extern int in_lib (void);
diff --git a/REORG.TODO/elf/tst-unique3lib.cc b/REORG.TODO/elf/tst-unique3lib.cc
new file mode 100644
index 0000000000..fa8e85a36c
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique3lib.cc
@@ -0,0 +1,11 @@
+#include <cstdio>
+#include "tst-unique3.h"
+template<typename T> int S<T>::i = 1;
+static int i = S<char>::i;
+
+int
+in_lib (void)
+{
+ std::printf ("in_lib: %d %d\n", S<char>::i, i);
+ return S<char>::i++ != 2 || i != 1;
+}
diff --git a/REORG.TODO/elf/tst-unique3lib2.cc b/REORG.TODO/elf/tst-unique3lib2.cc
new file mode 100644
index 0000000000..17d817e12e
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique3lib2.cc
@@ -0,0 +1,12 @@
+#include <cstdio>
+#include "tst-unique3.h"
+
+template<typename T> int S<T>::i;
+
+extern "C"
+int
+in_lib2 ()
+{
+ std::printf ("in_lib2: %d\n", S<char>::i);
+ return S<char>::i != 3;
+}
diff --git a/REORG.TODO/elf/tst-unique4.cc b/REORG.TODO/elf/tst-unique4.cc
new file mode 100644
index 0000000000..575c70d3a1
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique4.cc
@@ -0,0 +1,28 @@
+// BZ 12511
+#include "tst-unique4.h"
+
+#include <cstdio>
+
+static int a[24] =
+ {
+ S<1>::i, S<2>::i, S<3>::i, S<4>::i, S<5>::i, S<6>::i, S<7>::i, S<8>::i,
+ S<9>::i, S<10>::i, S<11>::i, S<12>::i, S<13>::i, S<14>::i, S<15>::i,
+ S<16>::i, S<17>::i, S<18>::i, S<19>::i, S<20>::i, S<21>::i, S<22>::i,
+ S<23>::i, S<24>::i
+ };
+
+int
+main (void)
+{
+ int result = 0;
+ for (int i = 0; i < 24; ++i)
+ {
+ printf("%d ", a[i]);
+ result |= a[i] != i + 1;
+ }
+
+ printf("\n%d\n", S<1>::j);
+ result |= S<1>::j != -1;
+
+ return result;
+}
diff --git a/REORG.TODO/elf/tst-unique4.h b/REORG.TODO/elf/tst-unique4.h
new file mode 100644
index 0000000000..2d377f5d51
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique4.h
@@ -0,0 +1,7 @@
+// BZ 12511
+template<int N>
+struct S
+{
+ static int i;
+ static const int j;
+};
diff --git a/REORG.TODO/elf/tst-unique4lib.cc b/REORG.TODO/elf/tst-unique4lib.cc
new file mode 100644
index 0000000000..17a7cdf567
--- /dev/null
+++ b/REORG.TODO/elf/tst-unique4lib.cc
@@ -0,0 +1,17 @@
+// BZ 12511
+#include "tst-unique4.h"
+
+template<int N>
+int S<N>::i = N;
+template<int N>
+const int S<N>::j __attribute__ ((used)) = -1;
+
+static int a[24] __attribute__ ((used)) =
+ {
+ S<1>::i, S<2>::i, S<3>::i, S<4>::i, S<5>::i, S<6>::i, S<7>::i, S<8>::i,
+ S<9>::i, S<10>::i, S<11>::i, S<12>::i, S<13>::i, S<14>::i, S<15>::i,
+ S<16>::i, S<17>::i, S<18>::i, S<19>::i, S<20>::i, S<21>::i, S<22>::i,
+ S<23>::i, S<24>::i
+ };
+
+static int b __attribute__ ((used)) = S<1>::j;
diff --git a/REORG.TODO/elf/unload.c b/REORG.TODO/elf/unload.c
new file mode 100644
index 0000000000..4566f226f8
--- /dev/null
+++ b/REORG.TODO/elf/unload.c
@@ -0,0 +1,91 @@
+/* Test for unloading (really unmapping) of objects. By Franz Sirl.
+ This test does not have to passed in all dlopen() et.al. implementation
+ since it is not required the unloading actually happens. But we
+ require it for glibc. */
+
+#include <dlfcn.h>
+#include <link.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
+#define OUT \
+ for (map = MAPS; map != NULL; map = map->l_next) \
+ if (map->l_type == lt_loaded) \
+ printf ("name = \"%s\", direct_opencount = %d\n", \
+ map->l_name, (int) map->l_direct_opencount); \
+ fflush (stdout)
+
+typedef struct
+{
+ void *next;
+} strct;
+
+int
+main (void)
+{
+ void *sohandle;
+ strct *testdat;
+ int ret;
+ int result = 0;
+ struct link_map *map;
+
+ mtrace ();
+
+ puts ("\nBefore");
+ OUT;
+
+ sohandle = dlopen ("unloadmod.so", RTLD_NOW | RTLD_GLOBAL);
+ if (sohandle == NULL)
+ {
+ printf ("*** first dlopen failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ puts ("\nAfter loading unloadmod.so");
+ OUT;
+
+ testdat = dlsym (sohandle, "testdat");
+ testdat->next = (void *) -1;
+
+ ret = dlclose (sohandle);
+ if (ret != 0)
+ {
+ puts ("*** first dlclose failed");
+ result = 1;
+ }
+
+ puts ("\nAfter closing unloadmod.so");
+ OUT;
+
+ sohandle = dlopen ("unloadmod.so", RTLD_NOW | RTLD_GLOBAL);
+ if (sohandle == NULL)
+ {
+ printf ("*** second dlopen failed: %s\n", dlerror ());
+ exit (1);
+ }
+
+ puts ("\nAfter loading unloadmod.so the second time");
+ OUT;
+
+ testdat = dlsym (sohandle, "testdat");
+ if (testdat->next == (void *) -1)
+ {
+ puts ("*** testdat->next == (void *) -1");
+ result = 1;
+ }
+
+ ret = dlclose (sohandle);
+ if (ret != 0)
+ {
+ puts ("*** second dlclose failed");
+ result = 1;
+ }
+
+ puts ("\nAfter closing unloadmod.so again");
+ OUT;
+
+ return result;
+}
diff --git a/REORG.TODO/elf/unload2.c b/REORG.TODO/elf/unload2.c
new file mode 100644
index 0000000000..eef2bfd426
--- /dev/null
+++ b/REORG.TODO/elf/unload2.c
@@ -0,0 +1,59 @@
+#include <dlfcn.h>
+#include <elf.h>
+#include <errno.h>
+#include <error.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
+#define OUT \
+ for (map = MAPS; map != NULL; map = map->l_next) \
+ if (map->l_type == lt_loaded) \
+ printf ("name = \"%s\", direct_opencount = %d\n", \
+ map->l_name, (int) map->l_direct_opencount); \
+ fflush (stdout)
+
+int
+main (void)
+{
+ void *h[3];
+ struct link_map *map;
+ void (*fp) (void);
+
+ h[0] = dlopen ("unload2mod.so", RTLD_LAZY);
+ h[1] = dlopen ("unload2mod.so", RTLD_LAZY);
+ if (h[0] == NULL || h[1] == NULL)
+ error (EXIT_FAILURE, errno, "cannot load \"unload2mod.so\"");
+ h[2] = dlopen ("unload2dep.so", RTLD_LAZY);
+ if (h[2] == NULL)
+ error (EXIT_FAILURE, errno, "cannot load \"unload2dep.so\"");
+
+ puts ("\nAfter loading everything:");
+ OUT;
+
+ dlclose (h[0]);
+
+ puts ("\nAfter unloading \"unload2mod.so\" once:");
+ OUT;
+
+ dlclose (h[1]);
+
+ puts ("\nAfter unloading \"unload2mod.so\" twice:");
+ OUT;
+
+ fp = dlsym (h[2], "foo");
+ puts ("\nnow calling `foo'");
+ fflush (stdout);
+ fp ();
+ puts ("managed to call `foo'");
+ fflush (stdout);
+
+ dlclose (h[2]);
+
+ puts ("\nAfter unloading \"unload2dep.so\":");
+ OUT;
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/unload2dep.c b/REORG.TODO/elf/unload2dep.c
new file mode 100644
index 0000000000..0d319515d5
--- /dev/null
+++ b/REORG.TODO/elf/unload2dep.c
@@ -0,0 +1,6 @@
+extern void foo (void);
+
+void
+foo (void)
+{
+}
diff --git a/REORG.TODO/elf/unload2mod.c b/REORG.TODO/elf/unload2mod.c
new file mode 100644
index 0000000000..9c2ea586bc
--- /dev/null
+++ b/REORG.TODO/elf/unload2mod.c
@@ -0,0 +1,8 @@
+extern void foo (void);
+extern void bar (void);
+
+void
+bar (void)
+{
+ foo ();
+}
diff --git a/REORG.TODO/elf/unload3.c b/REORG.TODO/elf/unload3.c
new file mode 100644
index 0000000000..6f1af707e6
--- /dev/null
+++ b/REORG.TODO/elf/unload3.c
@@ -0,0 +1,41 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+ void *g = dlopen ("unload3mod1.so", RTLD_GLOBAL | RTLD_NOW);
+ void *h = dlopen ("unload3mod2.so", RTLD_GLOBAL | RTLD_NOW);
+ if (g == NULL || h == NULL)
+ {
+ printf ("dlopen unload3mod{1,2}.so failed: %p %p\n", g, h);
+ return 1;
+ }
+ dlclose (h);
+ dlclose (g);
+
+ g = dlopen ("unload3mod3.so", RTLD_GLOBAL | RTLD_NOW);
+ h = dlopen ("unload3mod4.so", RTLD_GLOBAL | RTLD_NOW);
+ if (g == NULL || h == NULL)
+ {
+ printf ("dlopen unload3mod{3,4}.so failed: %p %p\n", g, h);
+ return 1;
+ }
+
+ int (*fn) (int);
+ fn = dlsym (h, "bar");
+ if (fn == NULL)
+ {
+ puts ("dlsym failed");
+ return 1;
+ }
+
+ int val = fn (16);
+ if (val != 24)
+ {
+ printf ("bar returned %d != 24\n", val);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/unload3mod1.c b/REORG.TODO/elf/unload3mod1.c
new file mode 100644
index 0000000000..e886b11c18
--- /dev/null
+++ b/REORG.TODO/elf/unload3mod1.c
@@ -0,0 +1 @@
+int dummy1;
diff --git a/REORG.TODO/elf/unload3mod2.c b/REORG.TODO/elf/unload3mod2.c
new file mode 100644
index 0000000000..03252a523b
--- /dev/null
+++ b/REORG.TODO/elf/unload3mod2.c
@@ -0,0 +1 @@
+int dummy2;
diff --git a/REORG.TODO/elf/unload3mod3.c b/REORG.TODO/elf/unload3mod3.c
new file mode 100644
index 0000000000..046022c55d
--- /dev/null
+++ b/REORG.TODO/elf/unload3mod3.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int
+foo (int x)
+{
+ puts ("foo");
+ return x * 2;
+}
diff --git a/REORG.TODO/elf/unload3mod4.c b/REORG.TODO/elf/unload3mod4.c
new file mode 100644
index 0000000000..52f808e79b
--- /dev/null
+++ b/REORG.TODO/elf/unload3mod4.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+extern int foo (int x);
+
+int
+bar (int x)
+{
+ puts ("bar");
+ fflush (stdout);
+ x = foo (x - 4);
+ puts ("bar after foo");
+ return x;
+}
diff --git a/REORG.TODO/elf/unload4.c b/REORG.TODO/elf/unload4.c
new file mode 100644
index 0000000000..6e171a22e0
--- /dev/null
+++ b/REORG.TODO/elf/unload4.c
@@ -0,0 +1,48 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <malloc.h>
+
+int
+main (void)
+{
+#ifdef M_PERTURB
+ mallopt (M_PERTURB, 0xaa);
+#endif
+
+ void *h;
+ int (*fn) (int);
+ h = dlopen ("unload4mod1.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("1st dlopen failed");
+ return 1;
+ }
+ fn = dlsym (h, "foo");
+ if (fn == NULL)
+ {
+ puts ("dlsym failed");
+ return 1;
+ }
+ int n = fn (10);
+ if (n != 28)
+ {
+ printf ("foo (10) returned %d != 28\n", n);
+ return 1;
+ }
+ dlclose (h);
+ h = dlopen ("unload4mod3.so", RTLD_LAZY);
+ fn = dlsym (h, "mod3fn2");
+ if (fn == NULL)
+ {
+ puts ("second dlsym failed");
+ return 1;
+ }
+ n = fn (10);
+ if (n != 22)
+ {
+ printf ("mod3fn2 (10) returned %d != 22\n", n);
+ return 1;
+ }
+ dlclose (h);
+ return 0;
+}
diff --git a/REORG.TODO/elf/unload4mod1.c b/REORG.TODO/elf/unload4mod1.c
new file mode 100644
index 0000000000..38c5b0168d
--- /dev/null
+++ b/REORG.TODO/elf/unload4mod1.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern int bar (int);
+
+int
+foo (int x)
+{
+ puts ("in foo");
+ return bar (x / 2) + 2;
+}
diff --git a/REORG.TODO/elf/unload4mod2.c b/REORG.TODO/elf/unload4mod2.c
new file mode 100644
index 0000000000..497ef5d93b
--- /dev/null
+++ b/REORG.TODO/elf/unload4mod2.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int
+baz (int x)
+{
+ puts ("in baz");
+ return x * 4;
+}
diff --git a/REORG.TODO/elf/unload4mod3.c b/REORG.TODO/elf/unload4mod3.c
new file mode 100644
index 0000000000..4b280bc05b
--- /dev/null
+++ b/REORG.TODO/elf/unload4mod3.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+int
+__attribute__((noinline))
+mod3fn1 (int x)
+{
+ puts ("in mod3fn1");
+ return x + 6;
+}
+
+int
+mod3fn2 (int x)
+{
+ puts ("in mod3fn2");
+ return mod3fn1 (x / 2) * 2;
+}
diff --git a/REORG.TODO/elf/unload4mod4.c b/REORG.TODO/elf/unload4mod4.c
new file mode 100644
index 0000000000..ba5a144d38
--- /dev/null
+++ b/REORG.TODO/elf/unload4mod4.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+__attribute__((noinline))
+baz (int x)
+{
+ abort ();
+}
+
+int
+bar (int x)
+{
+ puts ("in bar");
+ return baz (x + 1) + 2;
+}
diff --git a/REORG.TODO/elf/unload5.c b/REORG.TODO/elf/unload5.c
new file mode 100644
index 0000000000..0555052ce8
--- /dev/null
+++ b/REORG.TODO/elf/unload5.c
@@ -0,0 +1,42 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+ void *g = dlopen ("unload3mod1.so", RTLD_GLOBAL | RTLD_NOW);
+ void *h = dlopen ("unload3mod2.so", RTLD_GLOBAL | RTLD_NOW);
+ if (g == NULL || h == NULL)
+ {
+ printf ("dlopen unload3mod{1,2}.so failed: %p %p\n", g, h);
+ return 1;
+ }
+ dlopen ("unload3mod4.so", RTLD_GLOBAL | RTLD_NOW);
+ dlclose (h);
+ dlclose (g);
+
+ g = dlopen ("unload3mod3.so", RTLD_GLOBAL | RTLD_NOW);
+ h = dlopen ("unload3mod4.so", RTLD_GLOBAL | RTLD_NOW);
+ if (g == NULL || h == NULL)
+ {
+ printf ("dlopen unload3mod{3,4}.so failed: %p %p\n", g, h);
+ return 1;
+ }
+
+ int (*fn) (int);
+ fn = dlsym (h, "bar");
+ if (fn == NULL)
+ {
+ puts ("dlsym failed");
+ return 1;
+ }
+
+ int val = fn (16);
+ if (val != 24)
+ {
+ printf ("bar returned %d != 24\n", val);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/unload6.c b/REORG.TODO/elf/unload6.c
new file mode 100644
index 0000000000..1efc7eb841
--- /dev/null
+++ b/REORG.TODO/elf/unload6.c
@@ -0,0 +1,30 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+ void *h = dlopen ("unload6mod1.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("dlopen unload6mod1.so failed");
+ return 1;
+ }
+
+ int (*fn) (int);
+ fn = dlsym (h, "foo");
+ if (fn == NULL)
+ {
+ puts ("dlsym failed");
+ return 1;
+ }
+
+ int val = fn (16);
+ if (val != 24)
+ {
+ printf ("foo returned %d != 24\n", val);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/unload6mod1.c b/REORG.TODO/elf/unload6mod1.c
new file mode 100644
index 0000000000..24f2e5a19a
--- /dev/null
+++ b/REORG.TODO/elf/unload6mod1.c
@@ -0,0 +1,16 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+foo (int i)
+{
+ void *h = dlopen ("unload6mod2.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("dlopen unload6mod2.so failed");
+ return 1;
+ }
+
+ dlclose (h);
+ return i + 8;
+}
diff --git a/REORG.TODO/elf/unload6mod2.c b/REORG.TODO/elf/unload6mod2.c
new file mode 100644
index 0000000000..980efa4b0e
--- /dev/null
+++ b/REORG.TODO/elf/unload6mod2.c
@@ -0,0 +1,23 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static void *h;
+
+static void __attribute__((constructor))
+mod2init (void)
+{
+ h = dlopen ("unload6mod3.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("dlopen unload6mod3.so failed");
+ fflush (stdout);
+ _exit (1);
+ }
+}
+
+static void __attribute__((destructor))
+mod2fini (void)
+{
+ dlclose (h);
+}
diff --git a/REORG.TODO/elf/unload6mod3.c b/REORG.TODO/elf/unload6mod3.c
new file mode 100644
index 0000000000..7b29e1d626
--- /dev/null
+++ b/REORG.TODO/elf/unload6mod3.c
@@ -0,0 +1,23 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static void *h;
+
+static void __attribute__((constructor))
+mod3init (void)
+{
+ h = dlopen ("unload6mod1.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("dlopen unload6mod1.so failed");
+ fflush (stdout);
+ _exit (1);
+ }
+}
+
+static void __attribute__((destructor))
+mod3fini (void)
+{
+ dlclose (h);
+}
diff --git a/REORG.TODO/elf/unload7.c b/REORG.TODO/elf/unload7.c
new file mode 100644
index 0000000000..198f7db286
--- /dev/null
+++ b/REORG.TODO/elf/unload7.c
@@ -0,0 +1,39 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+ void *h = dlopen ("$ORIGIN/unload7mod1.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("dlopen unload7mod1.so failed");
+ return 1;
+ }
+
+ int (*fn) (void);
+ fn = dlsym (h, "foo");
+ if (fn == NULL)
+ {
+ puts ("dlsym failed");
+ return 1;
+ }
+
+ int ret = 0;
+ if (fn () == 0)
+ ++ret;
+
+ void *h2 = dlopen ("$ORIGIN/unload7mod2.so", RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ puts ("dlopen unload7mod2.so failed");
+ return 1;
+ }
+ dlclose (h2);
+
+ if (fn () == 0)
+ ++ret;
+
+ dlclose (h);
+ return ret;
+}
diff --git a/REORG.TODO/elf/unload7mod1.c b/REORG.TODO/elf/unload7mod1.c
new file mode 100644
index 0000000000..7435adce2c
--- /dev/null
+++ b/REORG.TODO/elf/unload7mod1.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+foo (int i)
+{
+ if (dlsym (RTLD_DEFAULT, "unload7_nonexistent_symbol") == NULL)
+ return 1;
+ puts ("dlsym returned non-NULL");
+ return 0;
+}
diff --git a/REORG.TODO/elf/unload7mod2.c b/REORG.TODO/elf/unload7mod2.c
new file mode 100644
index 0000000000..6d1a0d47b7
--- /dev/null
+++ b/REORG.TODO/elf/unload7mod2.c
@@ -0,0 +1 @@
+int x;
diff --git a/REORG.TODO/elf/unload8.c b/REORG.TODO/elf/unload8.c
new file mode 100644
index 0000000000..f984a38098
--- /dev/null
+++ b/REORG.TODO/elf/unload8.c
@@ -0,0 +1,33 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+ void *h = dlopen ("$ORIGIN/unload8mod1.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("dlopen unload8mod1.so failed");
+ return 1;
+ }
+
+ void *h2 = dlopen ("$ORIGIN/unload8mod1x.so", RTLD_LAZY);
+ if (h2 == NULL)
+ {
+ puts ("dlopen unload8mod1x.so failed");
+ return 1;
+ }
+ dlclose (h2);
+
+ int (*mod1) (void) = dlsym (h, "mod1");
+ if (mod1 == NULL)
+ {
+ puts ("dlsym failed");
+ return 1;
+ }
+
+ mod1 ();
+ dlclose (h);
+
+ return 0;
+}
diff --git a/REORG.TODO/elf/unload8mod1.c b/REORG.TODO/elf/unload8mod1.c
new file mode 100644
index 0000000000..fe7e81c1c3
--- /dev/null
+++ b/REORG.TODO/elf/unload8mod1.c
@@ -0,0 +1,7 @@
+extern void mod2 (void);
+
+void
+mod1 (void)
+{
+ mod2 ();
+}
diff --git a/REORG.TODO/elf/unload8mod1x.c b/REORG.TODO/elf/unload8mod1x.c
new file mode 100644
index 0000000000..835b634914
--- /dev/null
+++ b/REORG.TODO/elf/unload8mod1x.c
@@ -0,0 +1 @@
+int mod1x;
diff --git a/REORG.TODO/elf/unload8mod2.c b/REORG.TODO/elf/unload8mod2.c
new file mode 100644
index 0000000000..2fd8b6768a
--- /dev/null
+++ b/REORG.TODO/elf/unload8mod2.c
@@ -0,0 +1,7 @@
+extern void mod3 (void);
+
+void
+mod2 (void)
+{
+ mod3 ();
+}
diff --git a/REORG.TODO/elf/unload8mod3.c b/REORG.TODO/elf/unload8mod3.c
new file mode 100644
index 0000000000..d49e22b24c
--- /dev/null
+++ b/REORG.TODO/elf/unload8mod3.c
@@ -0,0 +1,27 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+mod3_fini2 (void)
+{
+}
+
+void
+mod3_fini (void)
+{
+ mod3_fini2 ();
+}
+
+void
+mod3 (void)
+{
+ void *h = dlopen ("$ORIGIN/unload8mod2.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("dlopen unload8mod2.so failed");
+ exit (1);
+ }
+
+ atexit (mod3_fini);
+}
diff --git a/REORG.TODO/elf/unloadmod.c b/REORG.TODO/elf/unloadmod.c
new file mode 100644
index 0000000000..3aa5403edf
--- /dev/null
+++ b/REORG.TODO/elf/unloadmod.c
@@ -0,0 +1,4 @@
+struct testdat
+{
+ void *next;
+} testdat;
diff --git a/REORG.TODO/elf/vismain.c b/REORG.TODO/elf/vismain.c
new file mode 100644
index 0000000000..43f1d8f095
--- /dev/null
+++ b/REORG.TODO/elf/vismain.c
@@ -0,0 +1,260 @@
+/* Copyright (C) 2000-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file must be compiled as PIE to avoid copy relocation when
+ accessing protected symbols defined in shared libaries since copy
+ relocation doesn't work with protected symbols and linker in
+ binutils 2.26 enforces this rule. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vismod.h"
+
+/* Prototype for our test function. */
+extern int do_test (void);
+
+
+/* This defines the `main' function and some more. */
+#include <support/test-driver.c>
+
+
+/* Prototypes for local functions. */
+extern int protlocal (void);
+
+const char *protvarlocal = __FILE__;
+extern const char *protvarinmod;
+extern const char *protvaritcpt;
+
+int
+do_test (void)
+{
+ int res = 0;
+ int val;
+
+ /* First test: check whether .protected is handled correctly by the
+ assembler/linker. The uses of `protlocal' in the DSOs and in the
+ main program should all be resolved with the local definitions. */
+ val = protlocal () + calllocal1 () + calllocal2 ();
+ if (val != 0x155)
+ {
+ puts ("\
+The handling of `.protected' seems to be implemented incorrectly: giving up");
+ abort ();
+ }
+ puts ("`.protected' seems to be handled correctly, good!");
+
+ /* Function pointers: for functions which are marked local and for
+ which definitions are available all function pointers must be
+ distinct. */
+ if (protlocal == getlocal1 ())
+ {
+ puts ("`protlocal' in main and mod1 have same address");
+ res = 1;
+ }
+ if (protlocal == getlocal2 ())
+ {
+ puts ("`protlocal' in main and mod2 have same address");
+ res = 1;
+ }
+ if (getlocal1 () == getlocal2 ())
+ {
+ puts ("`protlocal' in mod1 and mod2 have same address");
+ res = 1;
+ }
+ if (getlocal1 () () + getlocal2 () () != 0x44)
+ {
+ puts ("pointers to `protlocal' in mod1 or mod2 incorrect");
+ res = 1;
+ }
+
+ /* Next test. This is similar to the last one but the function we
+ are calling is not defined in the main object. This means that
+ the invocation in the main object uses the definition in the
+ first DSO. */
+ if (protinmod != getinmod1 ())
+ {
+ printf ("&protinmod in main (%p) != &protinmod in mod1 (%p)\n",
+ protinmod, getinmod1 ());
+ res = 1;
+ }
+ if (protinmod == getinmod2 ())
+ {
+ puts ("`protinmod' in main and mod2 have same address");
+ res = 1;
+ }
+ if (getinmod1 () == getinmod2 ())
+ {
+ puts ("`protinmod' in mod1 and mod2 have same address");
+ res = 1;
+ }
+ if (protinmod () + getinmod1 () () + getinmod2 () () != 0x4800)
+ {
+ puts ("pointers to `protinmod' in mod1 or mod2 incorrect");
+ res = 1;
+ }
+ val = protinmod () + callinmod1 () + callinmod2 ();
+ if (val != 0x15800)
+ {
+ printf ("calling of `protinmod' leads to wrong result (%#x)\n", val);
+ res = 1;
+ }
+
+ /* A very similar text. Same setup for the main object and the modules
+ but this time we have another definition in a preloaded module. This
+ one intercepts the references from the main object. */
+ if (protitcpt != getitcpt3 ())
+ {
+ printf ("&protitcpt in main (%p) != &protitcpt in mod3 (%p)\n",
+ &protitcpt, getitcpt3 ());
+ res = 1;
+ }
+ if (protitcpt == getitcpt1 ())
+ {
+ puts ("`protitcpt' in main and mod1 have same address");
+ res = 1;
+ }
+ if (protitcpt == getitcpt2 ())
+ {
+ puts ("`protitcpt' in main and mod2 have same address");
+ res = 1;
+ }
+ if (getitcpt1 () == getitcpt2 ())
+ {
+ puts ("`protitcpt' in mod1 and mod2 have same address");
+ res = 1;
+ }
+ val = protitcpt () + getitcpt1 () () + getitcpt2 () () + getitcpt3 () ();
+ if (val != 0x8440000)
+ {
+ printf ("\
+pointers to `protitcpt' in mod1 or mod2 or mod3 incorrect (%#x)\n", val);
+ res = 1;
+ }
+ val = protitcpt () + callitcpt1 () + callitcpt2 () + callitcpt3 ();
+ if (val != 0x19540000)
+ {
+ printf ("calling of `protitcpt' leads to wrong result (%#x)\n", val);
+ res = 1;
+ }
+
+ /* Now look at variables. First a variable which is available
+ everywhere. We must have three different addresses. */
+ if (&protvarlocal == getvarlocal1 ())
+ {
+ puts ("`protvarlocal' in main and mod1 have same address");
+ res = 1;
+ }
+ if (&protvarlocal == getvarlocal2 ())
+ {
+ puts ("`protvarlocal' in main and mod2 have same address");
+ res = 1;
+ }
+ if (getvarlocal1 () == getvarlocal2 ())
+ {
+ puts ("`protvarlocal' in mod1 and mod2 have same address");
+ res = 1;
+ }
+ if (strcmp (protvarlocal, __FILE__) != 0)
+ {
+ puts ("`protvarlocal in main has wrong value");
+ res = 1;
+ }
+ if (strcmp (*getvarlocal1 (), "vismod1.c") != 0)
+ {
+ puts ("`getvarlocal1' returns wrong value");
+ res = 1;
+ }
+ if (strcmp (*getvarlocal2 (), "vismod2.c") != 0)
+ {
+ puts ("`getvarlocal2' returns wrong value");
+ res = 1;
+ }
+
+ /* Now the case where there is no local definition. */
+ if (&protvarinmod != getvarinmod1 ())
+ {
+ printf ("&protvarinmod in main (%p) != &protitcpt in mod1 (%p)\n",
+ &protvarinmod, getvarinmod1 ());
+ // XXX Possibly enable once fixed.
+ // res = 1;
+ }
+ if (&protvarinmod == getvarinmod2 ())
+ {
+ puts ("`protvarinmod' in main and mod2 have same address");
+ res = 1;
+ }
+ if (strcmp (*getvarinmod1 (), "vismod1.c") != 0)
+ {
+ puts ("`getvarinmod1' returns wrong value");
+ res = 1;
+ }
+ if (strcmp (*getvarinmod2 (), "vismod2.c") != 0)
+ {
+ puts ("`getvarinmod2' returns wrong value");
+ res = 1;
+ }
+
+ /* And a test where a variable definition is intercepted. */
+ if (&protvaritcpt == getvaritcpt1 ())
+ {
+ puts ("`protvaritcpt' in main and mod1 have same address");
+ res = 1;
+ }
+ if (&protvaritcpt == getvaritcpt2 ())
+ {
+ puts ("`protvaritcpt' in main and mod2 have same address");
+ res = 1;
+ }
+ if (&protvaritcpt != getvaritcpt3 ())
+ {
+ printf ("&protvaritcpt in main (%p) != &protvaritcpt in mod3 (%p)\n",
+ &protvaritcpt, getvaritcpt3 ());
+ // XXX Possibly enable once fixed.
+ // res = 1;
+ }
+ if (getvaritcpt1 () == getvaritcpt2 ())
+ {
+ puts ("`protvaritcpt' in mod1 and mod2 have same address");
+ res = 1;
+ }
+ if (strcmp (protvaritcpt, "vismod3.c") != 0)
+ {
+ puts ("`protvaritcpt in main has wrong value");
+ res = 1;
+ }
+ if (strcmp (*getvaritcpt1 (), "vismod1.c") != 0)
+ {
+ puts ("`getvaritcpt1' returns wrong value");
+ res = 1;
+ }
+ if (strcmp (*getvaritcpt2 (), "vismod2.c") != 0)
+ {
+ puts ("`getvaritcpt2' returns wrong value");
+ res = 1;
+ }
+
+ return res;
+}
+
+
+int
+protlocal (void)
+{
+ return 0x1;
+}
diff --git a/REORG.TODO/elf/vismod.h b/REORG.TODO/elf/vismod.h
new file mode 100644
index 0000000000..ef05ffd5e9
--- /dev/null
+++ b/REORG.TODO/elf/vismod.h
@@ -0,0 +1,27 @@
+/* Prototypes for the functions in the DSOs. */
+extern int calllocal1 (void);
+extern int (*getlocal1 (void)) (void);
+extern int callinmod1 (void);
+extern int (*getinmod1 (void)) (void);
+extern int callitcpt1 (void);
+extern int (*getitcpt1 (void)) (void);
+extern const char **getvarlocal1 (void);
+extern const char **getvarinmod1 (void);
+extern const char **getvaritcpt1 (void);
+extern int calllocal2 (void);
+extern int (*getlocal2 (void)) (void);
+extern int callinmod2 (void);
+extern int (*getinmod2 (void)) (void);
+extern int callitcpt2 (void);
+extern int (*getitcpt2 (void)) (void);
+extern const char **getvarlocal2 (void);
+extern const char **getvarinmod2 (void);
+extern const char **getvaritcpt2 (void);
+extern int callitcpt3 (void);
+extern int (*getitcpt3 (void)) (void);
+extern const char **getvaritcpt3 (void);
+
+extern int protinmod (void);
+extern int protitcpt (void);
+extern int protlocal (void);
+
diff --git a/REORG.TODO/elf/vismod1.c b/REORG.TODO/elf/vismod1.c
new file mode 100644
index 0000000000..3e56404ce7
--- /dev/null
+++ b/REORG.TODO/elf/vismod1.c
@@ -0,0 +1,103 @@
+/* Copyright (C) 2000-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "vismod.h"
+
+int
+protlocal (void)
+{
+ return 0x4;
+}
+asm (".protected protlocal");
+
+
+int
+calllocal1 (void)
+{
+ return protlocal () + 0x10;
+}
+
+int
+(*getlocal1 (void)) (void)
+{
+ return protlocal;
+}
+
+int
+protinmod (void)
+{
+ return 0x400;
+}
+asm (".protected protinmod");
+
+int
+callinmod1 (void)
+{
+ return protinmod () + 0x1000;
+}
+
+int
+(*getinmod1 (void)) (void)
+{
+ return protinmod;
+}
+
+int
+protitcpt (void)
+{
+ return 0x40000;
+}
+asm (".protected protitcpt");
+
+int
+callitcpt1 (void)
+{
+ return protitcpt () + 0x100000;
+}
+
+int
+(*getitcpt1 (void)) (void)
+{
+ return protitcpt;
+}
+
+const char *protvarlocal = __FILE__;
+asm (".protected protvarlocal");
+
+const char **
+getvarlocal1 (void)
+{
+ return &protvarlocal;
+}
+
+const char *protvarinmod = __FILE__;
+asm (".protected protvarinmod");
+
+const char **
+getvarinmod1 (void)
+{
+ return &protvarinmod;
+}
+
+const char *protvaritcpt = __FILE__;
+asm (".protected protvaritcpt");
+
+const char **
+getvaritcpt1 (void)
+{
+ return &protvaritcpt;
+}
diff --git a/REORG.TODO/elf/vismod2.c b/REORG.TODO/elf/vismod2.c
new file mode 100644
index 0000000000..89be69728a
--- /dev/null
+++ b/REORG.TODO/elf/vismod2.c
@@ -0,0 +1,123 @@
+/* Copyright (C) 2000-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include "vismod.h"
+
+int
+protlocal (void)
+{
+ return 0x40;
+}
+asm (".protected protlocal");
+
+
+int
+calllocal2 (void)
+{
+ return protlocal () + 0x100;
+}
+
+int
+(*getlocal2 (void)) (void)
+{
+ return protlocal;
+}
+
+int
+protinmod (void)
+{
+ return 0x4000;
+}
+asm (".protected protinmod");
+
+int
+callinmod2 (void)
+{
+ return protinmod () + 0x10000;
+}
+
+int
+(*getinmod2 (void)) (void)
+{
+ return protinmod;
+}
+
+int
+protitcpt (void)
+{
+ return 0x400000;
+}
+asm (".protected protitcpt");
+
+int
+callitcpt2 (void)
+{
+ return protitcpt () + 0x1000000;
+}
+
+int
+(*getitcpt2 (void)) (void)
+{
+ return protitcpt;
+}
+
+const char *protvarlocal = __FILE__;
+asm (".protected protvarlocal");
+
+const char **
+getvarlocal2 (void)
+{
+ return &protvarlocal;
+}
+
+const char *protvarinmod = __FILE__;
+asm (".protected protvarinmod");
+
+const char **
+getvarinmod2 (void)
+{
+ return &protvarinmod;
+}
+
+const char *protvaritcpt = __FILE__;
+asm (".protected protvaritcpt");
+
+const char **
+getvaritcpt2 (void)
+{
+ return &protvaritcpt;
+}
+
+/* We must never call these functions. */
+int
+callitcpt3 (void)
+{
+ abort ();
+}
+
+int
+(*getitcpt3 (void)) (void)
+{
+ abort ();
+}
+
+const char **
+getvaritcpt3 (void)
+{
+ abort ();
+}
diff --git a/REORG.TODO/elf/vismod3.c b/REORG.TODO/elf/vismod3.c
new file mode 100644
index 0000000000..1074d1bcda
--- /dev/null
+++ b/REORG.TODO/elf/vismod3.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2000-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "vismod.h"
+
+int
+protitcpt (void)
+{
+ return 0x4000000;
+}
+asm (".protected protitcpt");
+
+int
+callitcpt3 (void)
+{
+ return protitcpt () + 0x10000000;
+}
+
+int
+(*getitcpt3 (void)) (void)
+{
+ return protitcpt;
+}
+
+const char *protvaritcpt = __FILE__;
+asm (".protected protvaritcpt");
+
+const char **
+getvaritcpt3 (void)
+{
+ return &protvaritcpt;
+}