mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-09 23:58:37 +08:00
Compare commits
272
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98f5e8eb96 | ||
|
|
e00ff02338 | ||
|
|
1ac71ef719 | ||
|
|
07ea91c03b | ||
|
|
6683e677bc | ||
|
|
a0ee7ab46c | ||
|
|
82dcfc6d7b | ||
|
|
be3c0fe888 | ||
|
|
5643a977d0 | ||
|
|
ac5b880423 | ||
|
|
66bec53f07 | ||
|
|
2b1ebe408a | ||
|
|
2d7ea00f76 | ||
|
|
e371f141f9 | ||
|
|
66cff6cd8a | ||
|
|
0778e25fe1 | ||
|
|
5ac69deee6 | ||
|
|
57afddcb68 | ||
|
|
60417c3867 | ||
|
|
2676793257 | ||
|
|
bade6276d1 | ||
|
|
aacd7e0eb6 | ||
|
|
fe59db4d1b | ||
|
|
950a6559ad | ||
|
|
3697387eab | ||
|
|
2dda6eab52 | ||
|
|
16ca0733a0 | ||
|
|
7255e947f2 | ||
|
|
2fa202fdd1 | ||
|
|
20f6c92422 | ||
|
|
15c4b8cbcc | ||
|
|
da683b1f10 | ||
|
|
d3c732cb43 | ||
|
|
c0a4365442 | ||
|
|
98fa83a2a8 | ||
|
|
bf291348a7 | ||
|
|
633d14073f | ||
|
|
d7c1214f4d | ||
|
|
aac0d8a9a3 | ||
|
|
903a6c6d5a | ||
|
|
b0d12dcb63 | ||
|
|
add8e34cd7 | ||
|
|
bc129fb15b | ||
|
|
7334a4d5c3 | ||
|
|
e457303afe | ||
|
|
ec38ea9597 | ||
|
|
6056776143 | ||
|
|
359a244dc6 | ||
|
|
453aafef16 | ||
|
|
804887a0c8 | ||
|
|
77d2c2fd0d | ||
|
|
1a8e6a6562 | ||
|
|
f1d716a048 | ||
|
|
8c5a6bf813 | ||
|
|
6951b6ac39 | ||
|
|
2887b50077 | ||
|
|
6db4535a70 | ||
|
|
c0e9696c3c | ||
|
|
b3331e2d53 | ||
|
|
1515a92a53 | ||
|
|
22d31aef9e | ||
|
|
282bbfc364 | ||
|
|
8238afcd89 | ||
|
|
df64d52310 | ||
|
|
a21d58a0dc | ||
|
|
2d20ffe431 | ||
|
|
c8aaaf67f6 | ||
|
|
c015f0cc57 | ||
|
|
d4d26acd8a | ||
|
|
76f9784421 | ||
|
|
e525ff25df | ||
|
|
bc57e68bbb | ||
|
|
5e46b24985 | ||
|
|
0ed6ae04d6 | ||
|
|
bd1e10723b | ||
|
|
87ac253d00 | ||
|
|
04938f76dd | ||
|
|
bcc638805a | ||
|
|
d548adb4ef | ||
|
|
e62db8fce4 | ||
|
|
2c9e5207e4 | ||
|
|
c3064d5f50 | ||
|
|
cb90884046 | ||
|
|
144448d566 | ||
|
|
1ba3eb044d | ||
|
|
86079708ee | ||
|
|
d0d7b3d2b3 | ||
|
|
6a12504329 | ||
|
|
396a77d48e | ||
|
|
7d7724e795 | ||
|
|
3a84f426fd | ||
|
|
c4d57c29b5 | ||
|
|
66c8103bdf | ||
|
|
af63681769 | ||
|
|
6733782381 | ||
|
|
ad41eacfb7 | ||
|
|
8d141ab782 | ||
|
|
e1c6d2b0f4 | ||
|
|
83bede0cfc | ||
|
|
038be62f96 | ||
|
|
6676d4161d | ||
|
|
059f0081cf | ||
|
|
738baca865 | ||
|
|
0337af1396 | ||
|
|
43afb70033 | ||
|
|
895947a3ca | ||
|
|
b930ad424b | ||
|
|
c4c787ff1b | ||
|
|
b1ecb7cf85 | ||
|
|
9e8081d123 | ||
|
|
91da896a3e | ||
|
|
c51bab1714 | ||
|
|
b2d0b20ae6 | ||
|
|
bb9e16c6ea | ||
|
|
590786950c | ||
|
|
3372bfe221 | ||
|
|
960ba7975c | ||
|
|
e04e10b431 | ||
|
|
452fe68a53 | ||
|
|
4b86f820b8 | ||
|
|
5e4f72b895 | ||
|
|
e21102f77e | ||
|
|
bb112e11de | ||
|
|
7724302310 | ||
|
|
1e88b203b3 | ||
|
|
6fd7bec86f | ||
|
|
d21dfbccdc | ||
|
|
acf11f4420 | ||
|
|
b2d69ea7ac | ||
|
|
6ea6782b69 | ||
|
|
b35774068a | ||
|
|
96509a9dce | ||
|
|
9b6c937b00 | ||
|
|
f9bd60b7c0 | ||
|
|
0f93e3333f | ||
|
|
21991760c7 | ||
|
|
c0ab16f8cc | ||
|
|
3e9a530aae | ||
|
|
74f10c8aad | ||
|
|
5884367eb9 | ||
|
|
4d4222dd27 | ||
|
|
121dc10a6d | ||
|
|
537386b1c9 | ||
|
|
3eb848f535 | ||
|
|
c4fde9669a | ||
|
|
da768de04f | ||
|
|
0c65d0085d | ||
|
|
dd5ed1e875 | ||
|
|
1073cbb0ba | ||
|
|
c13e59843a | ||
|
|
b3356fb4a1 | ||
|
|
1ab675ca63 | ||
|
|
43092e2ec2 | ||
|
|
adb65ebdcd | ||
|
|
d6df404c01 | ||
|
|
c01dc8b1ff | ||
|
|
dadc309087 | ||
|
|
da41ab8923 | ||
|
|
803f0773fb | ||
|
|
d0a2b24eb9 | ||
|
|
b88e5137e6 | ||
|
|
80153017d1 | ||
|
|
ee056103a0 | ||
|
|
35abf882dd | ||
|
|
012483cf93 | ||
|
|
ab9c196492 | ||
|
|
c1b247e3c4 | ||
|
|
88b3498548 | ||
|
|
07f3103a27 | ||
|
|
2506b2401d | ||
|
|
a53136e6d8 | ||
|
|
f6f3e83ea2 | ||
|
|
83d6db8187 | ||
|
|
bc7cdeb7f0 | ||
|
|
9a21941968 | ||
|
|
fbac9a26b2 | ||
|
|
3d67bc8070 | ||
|
|
3e6bbf417e | ||
|
|
e157ee6889 | ||
|
|
064c0ff384 | ||
|
|
438b279674 | ||
|
|
8044d7c6f7 | ||
|
|
4d1ae634e6 | ||
|
|
f109026488 | ||
|
|
0c5e931cc0 | ||
|
|
eea71a3beb | ||
|
|
a888c9b8b4 | ||
|
|
3db5e60013 | ||
|
|
a573a314d4 | ||
|
|
2d66557e88 | ||
|
|
28def2cb11 | ||
|
|
002eeb4cda | ||
|
|
6cb1736f3a | ||
|
|
2f60855711 | ||
|
|
58f9551f5b | ||
|
|
40513af8ad | ||
|
|
903b7aed7c | ||
|
|
090479eb8c | ||
|
|
8254ee748c | ||
|
|
8205f0d10e | ||
|
|
60548afc9f | ||
|
|
d57236debc | ||
|
|
641cae4c36 | ||
|
|
349ff1d0d5 | ||
|
|
476f7cf2f2 | ||
|
|
85dc56b95f | ||
|
|
60cdb6bb4e | ||
|
|
cf93513721 | ||
|
|
6f9557ac2e | ||
|
|
9590be9960 | ||
|
|
8eb1716c91 | ||
|
|
1a771e688f | ||
|
|
31caad179b | ||
|
|
d5adfa3af5 | ||
|
|
496eb9854c | ||
|
|
502932b7f5 | ||
|
|
21c2ca10b1 | ||
|
|
4e15d3291c | ||
|
|
f098d7ac4c | ||
|
|
aeca36379f | ||
|
|
b5861b06a6 | ||
|
|
b06c649991 | ||
|
|
eb00251677 | ||
|
|
fc36100b27 | ||
|
|
d41bed3ce0 | ||
|
|
491d419cdd | ||
|
|
f2d31c80d6 | ||
|
|
a4c60a19bc | ||
|
|
eb3215d3bd | ||
|
|
f0c4b81ce8 | ||
|
|
9c0f7f1394 | ||
|
|
10388c49b2 | ||
|
|
1a12397c10 | ||
|
|
654fbaf1b7 | ||
|
|
6302c3ccf8 | ||
|
|
fdb03f9736 | ||
|
|
6614ff3213 | ||
|
|
edeaa90058 | ||
|
|
18417626b7 | ||
|
|
85450bb67a | ||
|
|
bf806c9c4e | ||
|
|
3235a02111 | ||
|
|
47826951cf | ||
|
|
6b6086fea8 | ||
|
|
34cb52c02f | ||
|
|
dfb17f123a | ||
|
|
becb228b43 | ||
|
|
3f1c409c0a | ||
|
|
2224a3d98d | ||
|
|
fe9f4b71d6 | ||
|
|
96d0e6f1e0 | ||
|
|
5ac413c4fd | ||
|
|
066e928543 | ||
|
|
85d7a988c6 | ||
|
|
bc79ff3412 | ||
|
|
ce1670f0a9 | ||
|
|
3119277963 | ||
|
|
a61a3a2f64 | ||
|
|
d555ce07f4 | ||
|
|
f555d1a9b7 | ||
|
|
c9a3019796 | ||
|
|
1f3a3e1742 | ||
|
|
5a8bc50ed9 | ||
|
|
d01cba7dd1 | ||
|
|
cd0a44fe16 | ||
|
|
22bef64863 | ||
|
|
e08a64e708 | ||
|
|
56170e064e | ||
|
|
00c5a2d77a | ||
|
|
c8ad6ac1d1 | ||
|
|
ce8a6550fa | ||
|
|
bdac1623cc |
@@ -1,3 +1,409 @@
|
||||
2019-01-21 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #20018]
|
||||
CVE-2016-10739
|
||||
resolv: Reject trailing characters in host names
|
||||
* include/arpa/inet.h (__inet_aton_exact): Declare.
|
||||
(inet_aton): Remove hidden prototype. No longer used internally.
|
||||
* nscd/gai.c (__inet_aton): Do not define.
|
||||
* nscd/gethstbynm3_r.c (__inet_aton): Likewise.
|
||||
* nss/digits_dots.c (__inet_aton): Likewise.
|
||||
(__nss_hostname_digits_dots_context): Call __inet_aton_exact.
|
||||
* resolv/Makefile (tests-internal): Add tst-inet_aton_exact.
|
||||
(tests): Add tst-resolv-nondecimal, tst-resolv-trailing.
|
||||
(tst-resolv-nondecimal): Link with libresolv.so and libpthread.
|
||||
(tst-resolv-trailing): Likewise.
|
||||
* resolv/Versions (GLIBC_PRIVATE): Export __inet_aton_exact from
|
||||
libc.
|
||||
* resolv/inet_addr.c (inet_aton_end): Remame from __inet_aton.
|
||||
Make static. Add endp parameter.
|
||||
(__inet_aton_exact): New function.
|
||||
(__inet_aton_ignore_trailing): New function, aliased to inet_aton.
|
||||
(__inet_addr): Call inet_aton_end.
|
||||
* resolv/res_init.c (res_vinit_1): Truncate nameserver for IPv4,
|
||||
not just IPv6. Call __inet_aton_exact.
|
||||
* resolv/tst-aton.c: Switch to <support/test-driver.c>.
|
||||
(tests): Make const. Add additional test cases with trailing
|
||||
characters.
|
||||
(do_test): Use array_length.
|
||||
* resolv/tst-inet_aton_exact.c: New file.
|
||||
* resolv/tst-resolv-trailing.c: Likewise.
|
||||
* resolv/tst-resolv-nondecimal.c: Likewise.
|
||||
* sysdeps/posix/getaddrinfo.c (gaih_inet): Call __inet_aton_exact.
|
||||
|
||||
2018-11-27 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #23927]
|
||||
CVE-2018-19591
|
||||
* sysdeps/unix/sysv/linux/if_index.c (__if_nametoindex): Avoid
|
||||
descriptor leak in case of ENODEV error.
|
||||
|
||||
2018-05-18 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
[BZ #22639]
|
||||
* time/tzset.c (SECSPERDAY): Cast to time_t.
|
||||
* time/tst-y2039.c: New file.
|
||||
* time/Makefile (tests): Add tst-y2039.
|
||||
|
||||
|
||||
2018-02-12 Zack Weinberg <zackw@panix.com>
|
||||
|
||||
[BZ #19239]
|
||||
* posix/sys/types.h: Don't include sys/sysmacros.h.
|
||||
* misc/sys/sysmacros.h: Remove the conditional deprecation
|
||||
warnings for the macros defined by this header.
|
||||
|
||||
2018-05-23 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
[BZ #23196]
|
||||
* string/test-memcpy.c (do_test1): New function.
|
||||
(test_main): Call it.
|
||||
|
||||
2018-05-23 Andreas Schwab <schwab@suse.de>
|
||||
|
||||
[BZ #23196]
|
||||
CVE-2018-11237
|
||||
* sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S
|
||||
(L(preloop_large)): Save initial destination pointer in %r11 and
|
||||
use it instead of %rax after the loop.
|
||||
* string/test-mempcpy.c (MIN_PAGE_SIZE): Define.
|
||||
|
||||
2018-05-11 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #23166]
|
||||
* include/rpc/clnt.h (rpc_createerr): Declare hidden alias.
|
||||
* include/rpc/svc.h (svc_pollfd, svc_max_pollfd, svc_fdset):
|
||||
Likewise.
|
||||
* sunrpc/rpc_common.c (svc_fdset, rpc_createerr, svc_pollfd)
|
||||
(svc_max_pollfd): Add nocommon attribute and hidden alias. Do not
|
||||
export without --enable-obsolete-rpc.
|
||||
* sunrpc/svcauth_des.c (svcauthdes_stats): Turn into compatibility
|
||||
symbol. This should not have been exported, ever.
|
||||
|
||||
2018-05-11 Rafal Luzynski <digitalfreak@lingonborough.com>
|
||||
|
||||
[BZ #23152]
|
||||
* localedata/locales/gd_GB (abmon): Fix typo in May:
|
||||
"Mhàrt" -> "Cèit". Adjust the comment according to the change.
|
||||
|
||||
2018-05-09 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
|
||||
[BZ #22786]
|
||||
CVE-2018-11236
|
||||
* stdlib/canonicalize.c (__realpath): Fix overflow in path length
|
||||
computation.
|
||||
* stdlib/Makefile (test-bz22786): New test.
|
||||
* stdlib/test-bz22786.c: New test.
|
||||
|
||||
2018-05-05 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
|
||||
[BZ #20419]
|
||||
* elf/dl-load.c (open_verify): Fix stack overflow.
|
||||
* elf/Makefile (tst-big-note): New test.
|
||||
* elf/tst-big-note-lib.S: New.
|
||||
* elf/tst-big-note.c: New.
|
||||
|
||||
2018-05-04 Stefan Liebler <stli@linux.vnet.ibm.com>
|
||||
|
||||
[BZ #23137]
|
||||
* sysdeps/nptl/lowlevellock.h (lll_wait_tid):
|
||||
Use atomic_load_acquire to load __tid.
|
||||
|
||||
2018-04-24 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/sys/ptrace.h
|
||||
(PTRACE_SECCOMP_GET_METADATA): New enum value and macro.
|
||||
* sysdeps/unix/sysv/linux/bits/ptrace-shared.h
|
||||
(struct __ptrace_seccomp_metadata): New type.
|
||||
* sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h
|
||||
(PTRACE_SECCOMP_GET_METADATA): Likewise.
|
||||
* sysdeps/unix/sysv/linux/arm/sys/ptrace.h
|
||||
(PTRACE_SECCOMP_GET_METADATA): Likewise.
|
||||
* sysdeps/unix/sysv/linux/ia64/sys/ptrace.h
|
||||
(PTRACE_SECCOMP_GET_METADATA): Likewise.
|
||||
* sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h
|
||||
(PTRACE_SECCOMP_GET_METADATA): Likewise.
|
||||
* sysdeps/unix/sysv/linux/s390/sys/ptrace.h
|
||||
(PTRACE_SECCOMP_GET_METADATA): Likewise.
|
||||
* sysdeps/unix/sysv/linux/sparc/sys/ptrace.h
|
||||
(PTRACE_SECCOMP_GET_METADATA): Likewise.
|
||||
* sysdeps/unix/sysv/linux/tile/sys/ptrace.h
|
||||
(PTRACE_SECCOMP_GET_METADATA): Likewise.
|
||||
* sysdeps/unix/sysv/linux/x86/sys/ptrace.h
|
||||
(PTRACE_SECCOMP_GET_METADATA): Likewise.
|
||||
|
||||
2018-04-09 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #23037]
|
||||
* resolv/res_send.c (send_dg): Use designated initializers instead
|
||||
of assignment to zero-initialize other fields of struct mmsghdr.
|
||||
|
||||
2018-04-06 Andreas Schwab <schwab@linux-m68k.org>
|
||||
|
||||
* manual/charset.texi (Converting a Character): Fix typo.
|
||||
|
||||
2018-04-05 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* manual/examples/mbstouwcs.c (mbstouwcs): Fix loop termination,
|
||||
integer overflow, memory leak on error, and indeterminate errno
|
||||
value. Add a null wide character to terminate the result string.
|
||||
* manual/charset.texi (Converting a Character): Mention embedded
|
||||
null bytes in the mbrtowc input string. Explain what happens in
|
||||
the -2 result case. Do not claim that mbrtowc is simple or
|
||||
obvious to use. Adjust the description of the code example. Use
|
||||
@code, not @var, for concrete variables.
|
||||
|
||||
2018-04-05 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* manual/examples/mbstouwcs.c: New file.
|
||||
* manual/charset.texi (Converting a Character): Include it.
|
||||
|
||||
2018-04-03 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
[BZ #22947]
|
||||
* bits/uio-ext.h (RWF_APPEND): New.
|
||||
* sysdeps/unix/sysv/linux/bits/uio-ext.h (RWF_APPEND): Likewise.
|
||||
* manual/llio.texi: Document RWF_APPEND.
|
||||
* misc/tst-preadvwritev2-common.c (RWF_APPEND): New.
|
||||
(RWF_SUPPORTED): Add RWF_APPEND.
|
||||
|
||||
2018-03-27 Jesse Hathaway <jesse@mbuki-mvuki.org>
|
||||
|
||||
* sysdeps/unix/sysv/linux/getlogin_r.c (__getlogin_r_loginuid): Return
|
||||
early when linux sentinel value is set.
|
||||
|
||||
2018-03-27 Andreas Schwab <schwab@suse.de>
|
||||
|
||||
[BZ #23005]
|
||||
* resolv/res_send.c (__res_context_send): Return ENOMEM if
|
||||
allocation of private copy of nsaddr_list fails.
|
||||
|
||||
2018-03-20 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
[BZ #17343]
|
||||
* stdlib/random_r.c (__random_r): Use unsigned arithmetic for
|
||||
possibly overflowing computations.
|
||||
|
||||
2018-04-26 Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
* signal/tst-sigaction.c: New file to test BZ #23069.
|
||||
* signal/Makefile (tests): Fix indentation. Add tst-sigaction.
|
||||
|
||||
2018-04-28 Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
[BZ #23069]
|
||||
* sysdeps/unix/sysv/linux/riscv/kernel_sigaction.h: New file.
|
||||
|
||||
2018-03-29 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/i386/tst-bz21269.c (do_test): Also
|
||||
capture SIGBUS.
|
||||
|
||||
2018-03-23 Andrew Senkevich <andrew.senkevich@intel.com>
|
||||
Max Horn <max@quendi.de>
|
||||
|
||||
[BZ #22644]
|
||||
CVE-2017-18269
|
||||
* sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S: Fixed
|
||||
branch conditions.
|
||||
* string/test-memmove.c (do_test2): New testcase.
|
||||
|
||||
2018-02-22 Andrew Waterman <andrew@sifive.com>
|
||||
|
||||
[BZ # 22884]
|
||||
* sysdeps/riscv/rvd/s_fmax.c (__fmax): Handle sNaNs correctly.
|
||||
* sysdeps/riscv/rvd/s_fmin.c (__fmin): Likewise.
|
||||
* sysdeps/riscv/rvf/s_fmaxf.c (__fmaxf): Likewise.
|
||||
* sysdeps/riscv/rvf/s_fminf.c (__fminf): Likewise.
|
||||
|
||||
2018-02-22 DJ Delorie <dj@delorie.com>
|
||||
|
||||
* sysdeps/riscv/tls-macros.h: Do not initialize $gp.
|
||||
|
||||
2018-03-16 Rafal Luzynski <digitalfreak@lingonborough.com>
|
||||
|
||||
[BZ #22963]
|
||||
* localedata/locales/cs_CZ (mon): Rename to...
|
||||
(alt_mon): This.
|
||||
(mon): Import from CLDR (genitive case).
|
||||
|
||||
2018-03-16 Rafal Luzynski <digitalfreak@lingonborough.com>
|
||||
|
||||
[BZ #22937]
|
||||
* localedata/locales/el_CY (abmon): Rename to...
|
||||
(ab_alt_mon): This.
|
||||
(abmon): Import from CLDR (abbreviated genitive case).
|
||||
* localedata/locales/el_GR (abmon): Rename to...
|
||||
(ab_alt_mon): This.
|
||||
(abmon): Import from CLDR (abbreviated genitive case).
|
||||
|
||||
2018-03-16 Rafal Luzynski <digitalfreak@lingonborough.com>
|
||||
|
||||
[BZ #22932]
|
||||
* localedata/locales/lt_LT (abmon): Synchronize with CLDR.
|
||||
|
||||
2018-03-16 Robert Buj <robert.buj@gmail.com>
|
||||
|
||||
[BZ #22848]
|
||||
* localedata/locales/ca_ES (abmon): Rename to...
|
||||
(ab_alt_mon): This, then synchronize with CLDR (nominative case).
|
||||
(mon): Rename to...
|
||||
(alt_mon): This.
|
||||
(abmon): Import from CLDR (genitive case, month names preceded by
|
||||
"de" or "d’").
|
||||
(mon): Likewise.
|
||||
(abday): Synchronize with CLDR.
|
||||
(d_t_fmt): Likewise.
|
||||
(d_fmt): Likewise.
|
||||
(am_pm): Likewise.
|
||||
|
||||
(LC_TIME): Improve indentation.
|
||||
(LC_TELEPHONE): Likewise.
|
||||
(LC_NAME): Likewise.
|
||||
(LC_ADDRESS): Likewise.
|
||||
|
||||
2018-03-12 Dmitry V. Levin <ldv@altlinux.org>
|
||||
|
||||
* po/pt_BR.po: Update translations.
|
||||
|
||||
2018-03-03 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
[BZ #21269]
|
||||
* sysdeps/unix/sysv/linux/i386/Makefile (tests): Add tst-bz21269.
|
||||
* sysdeps/unix/sysv/linux/i386/sigaction.c (SET_SA_RESTORER): Clear
|
||||
sa_restorer for vDSO case.
|
||||
* sysdeps/unix/sysv/linux/i386/tst-bz21269.c: New file.
|
||||
|
||||
2018-03-03 Andreas Schwab <schwab@linux-m68k.org>
|
||||
|
||||
[BZ #22918]
|
||||
* nss/nsswitch.h (DEFINE_DATABASE): Don't define __nss_*_database.
|
||||
* nss/nsswitch.c (DEFINE_DATABASE): Define __nss_*_database here.
|
||||
* nscd/gai.c (__nss_hosts_database): Readd definition.
|
||||
* posix/tst-rfc3484.c (__nss_hosts_database): Likewise.
|
||||
* posix/tst-rfc3484-3.c (__nss_hosts_database): Likewise.
|
||||
* posix/tst-rfc3484-2.c (__nss_hosts_database): Likewise.
|
||||
|
||||
2018-03-01 DJ Delorie <dj@delorie.com>
|
||||
|
||||
[BZ #22342]
|
||||
* nscd/netgroupcache.c (addinnetgrX): Include trailing NUL in
|
||||
key value.
|
||||
|
||||
2018-02-26 Dmitry V. Levin <ldv@altlinux.org>
|
||||
|
||||
[BZ #22433]
|
||||
[BZ #22807]
|
||||
* sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h (__ptrace_request): Add
|
||||
PTRACE_GETREGS, PTRACE_SETREGS, PTRACE_GETFPREGS, PTRACE_SETFPREGS,
|
||||
PTRACE_GETVRREGS, PTRACE_SETVRREGS, PTRACE_GETEVRREGS,
|
||||
PTRACE_SETEVRREGS, PTRACE_GETREGS64, PTRACE_SETREGS64,
|
||||
PTRACE_GET_DEBUGREG, PTRACE_SET_DEBUGREG, PTRACE_GETVSRREGS,
|
||||
PTRACE_SETVSRREGS, and PTRACE_SINGLEBLOCK.
|
||||
|
||||
2018-02-26 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h: Undefine Linux
|
||||
macros used in __ptrace_request.
|
||||
|
||||
2018-02-21 Mike FABIAN <mfabian@redhat.com>
|
||||
|
||||
[BZ #22517]
|
||||
* localedata/locales/et_EE (LC_COLLATE): add missing “reorder-end”
|
||||
|
||||
2018-02-21 Rical Jasan <ricaljasan@pacific.net>
|
||||
|
||||
* io/fcntl.h: Fix a typo in a comment.
|
||||
|
||||
2018-02-20 Rical Jasan <ricaljasan@pacific.net>
|
||||
|
||||
* manual/creature.texi (_ISOC99_SOURCE): Update the dated
|
||||
description.
|
||||
|
||||
[BZ #16335]
|
||||
* manual/creature.texi (_POSIX_C_SOURCE): Document special values
|
||||
of 199606L, 200112L, and 200809L.
|
||||
(_XOPEN_SOURCE): Document special values of 600 and 700.
|
||||
(_ISOC11_SOURCE): Document macro.
|
||||
(_ATFILE_SOURCE): Likewise.
|
||||
(_FORTIFY_SOURCE): Likewise.
|
||||
|
||||
2018-03-09 Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
[BZ #22919]
|
||||
* sysdeps/unix/sysv/linux/sparc/sparc32/setcontext.S (__startcontext):
|
||||
Add nop before __startcontext, add explaining comments.
|
||||
|
||||
2018-03-07 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
[BZ #22926]
|
||||
* sysdeps/powerpc/powerpc32/sysdep.h (ABORT_TRANSACTION_IMPL): Define
|
||||
empty for __SPE__.
|
||||
* sysdeps/powerpc/sysdep.h (ABORT_TRANSACTION): Likewise.
|
||||
* sysdeps/unix/sysv/linux/powerpc/elision-lock.c (__lll_lock_elision):
|
||||
Do not build hardware transactional code for __SPE__.
|
||||
* sysdeps/unix/sysv/linux/powerpc/elision-trylock.c
|
||||
(__lll_trylock_elision): Likewise.
|
||||
* sysdeps/unix/sysv/linux/powerpc/elision-unlock.c
|
||||
(__lll_unlock_elision): Likewise.
|
||||
|
||||
2018-02-19 Rical Jasan <ricaljasan@pacific.net>
|
||||
|
||||
[BZ #6889]
|
||||
* manual/filesys.texi (get_current_dir_name): Clarify behaviour.
|
||||
|
||||
2018-02-16 Rical Jasan <ricaljasan@pacific.net>
|
||||
|
||||
* manual/platform.texi (__riscv_flush_icache): Fix @deftypefun
|
||||
syntax.
|
||||
|
||||
2018-02-09 Rical Jasan <ricaljasan@pacific.net>
|
||||
|
||||
* manual/creature.texi: Convert references to gcc.info to gcc.
|
||||
* manual/stdio.texi: Likewise.
|
||||
* manual/string.texi: Likewise.
|
||||
|
||||
2018-02-18 Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
[BZ #22818]
|
||||
* posix/tst-glob_lstat_compat.c [__alpha__] (glob): Access
|
||||
the GLIBC_2.1 version.
|
||||
|
||||
2018-02-02 Sean McKean <smckean83@gmail.com>
|
||||
|
||||
[BZ #22735]
|
||||
* time/time.h (clock): Reference CLOCKS_PER_SEC in comment.
|
||||
|
||||
2018-02-10 Dmitry V. Levin <ldv@altlinux.org>
|
||||
|
||||
[BZ #22433]
|
||||
* sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h (__ptrace_request):
|
||||
Remove arm-specific PTRACE_GET_THREAD_AREA, PTRACE_GETHBPREGS,
|
||||
and PTRACE_SETHBPREGS.
|
||||
|
||||
2018-02-14 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
* sysdeps/sh/libm-test-ulps: Update.
|
||||
|
||||
2018-02-09 DJ Delorie <dj@redhat.com>
|
||||
|
||||
[BZ #22827]
|
||||
* sysdeps/unix/sysv/linux/riscv/readelflib.c (process_elf_file): Use
|
||||
64-bit ELF type for 64-bit ELF objects.
|
||||
|
||||
2018-02-07 Igor Gnatenko <ignatenko@redhat.com>
|
||||
|
||||
[BZ #22797]
|
||||
* sysdeps/unix/sysv/linux/bits/mman-shared.h (pkey_get): Add
|
||||
missing second underscore to parameter name.
|
||||
|
||||
2018-02-05 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
[BZ #22638]
|
||||
* sysdeps/sparc/sparc32/start.S (_start): Check PIC instead of
|
||||
SHARED.
|
||||
* sysdeps/sparc/sparc64/start.S (_start): Likewise.
|
||||
|
||||
2018-02-01 Dmitry V. Levin <ldv@altlinux.org>
|
||||
|
||||
* version.h (RELEASE): Set to "stable".
|
||||
@@ -710,7 +1116,9 @@
|
||||
2018-01-18 Arjun Shankar <arjun@redhat.com>
|
||||
|
||||
[BZ #22343]
|
||||
[BZ #22774]
|
||||
CVE-2018-6485
|
||||
CVE-2018-6551
|
||||
* malloc/malloc.c (checked_request2size): call REQUEST_OUT_OF_RANGE
|
||||
after padding.
|
||||
(_int_memalign): check for integer overflow before calling
|
||||
|
||||
+47
-1
@@ -521,8 +521,13 @@ CFLAGS-printers-tests := -O0 -ggdb3 -DIS_IN_build
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
# These indicate whether to link using the built ld.so or the installed one.
|
||||
ifeq ($(with-lld),no)
|
||||
installed-rtld-LDFLAGS = -Wl,-dynamic-linker=$(rtlddir)/$(rtld-installed-name)
|
||||
built-rtld-LDFLAGS = -Wl,-dynamic-linker=$(elf-objpfx)ld.so
|
||||
else
|
||||
installed-rtld-LDFLAGS = -Wl,-dynamic-linker,$(rtlddir)/$(rtld-installed-name)
|
||||
built-rtld-LDFLAGS = -Wl,-dynamic-linker,$(elf-objpfx)ld.so
|
||||
endif
|
||||
|
||||
ifndef rtld-LDFLAGS
|
||||
rtld-LDFLAGS = $(installed-rtld-LDFLAGS)
|
||||
@@ -656,20 +661,39 @@ libc.so-gnulib := -lgcc
|
||||
endif
|
||||
+preinit = $(addprefix $(csu-objpfx),crti.o)
|
||||
+postinit = $(addprefix $(csu-objpfx),crtn.o)
|
||||
ifeq ($(with-clang),yes)
|
||||
# With clang, use the clang_rt.crt*.o files from the compiler-rt package
|
||||
# in a LLVM_ENABLE_RUNTIMES build.
|
||||
+prector = `$(CC) $(sysdep-LDFLAGS) --print-file-name=clang_rt.crtbegin.o`
|
||||
+postctor = `$(CC) $(sysdep-LDFLAGS) --print-file-name=clang_rt.crtend.o`
|
||||
else
|
||||
+prector = `$(CC) $(sysdep-LDFLAGS) --print-file-name=crtbegin.o`
|
||||
+postctor = `$(CC) $(sysdep-LDFLAGS) --print-file-name=crtend.o`
|
||||
endif
|
||||
# Variants of the two previous definitions for linking PIE programs.
|
||||
ifeq ($(with-clang),yes)
|
||||
# compiler-rt crt*.o also works for PIE.
|
||||
+prectorS = $(+prector)
|
||||
+postctorS = $(+postctor)
|
||||
else
|
||||
+prectorS = `$(CC) $(sysdep-LDFLAGS) --print-file-name=crtbeginS.o`
|
||||
+postctorS = `$(CC) $(sysdep-LDFLAGS) --print-file-name=crtendS.o`
|
||||
endif
|
||||
# Variants of the two previous definitions for statically linking programs.
|
||||
ifeq (yes,$(enable-static-pie))
|
||||
# Static PIE must use PIE variants.
|
||||
+prectorT = $(+prectorS)
|
||||
+postctorT = $(+postctorS)
|
||||
else
|
||||
ifeq ($(with-clang),yes)
|
||||
# compiler-rt crt*.o also works for static PIE.
|
||||
+prectorT = $(+prector)
|
||||
+postctorT = $(+postctor)
|
||||
else
|
||||
+prectorT = `$(CC) $(sysdep-LDFLAGS) --print-file-name=crtbeginT.o`
|
||||
+postctorT = `$(CC) $(sysdep-LDFLAGS) --print-file-name=crtend.o`
|
||||
endif
|
||||
endif
|
||||
csu-objpfx = $(common-objpfx)csu/
|
||||
elf-objpfx = $(common-objpfx)elf/
|
||||
|
||||
@@ -829,7 +853,9 @@ endif
|
||||
# We have to assume that glibc functions are called in any rounding
|
||||
# mode and also change the rounding mode in a few functions. So,
|
||||
# disable any optimization that assume default rounding mode.
|
||||
ifeq ($(with-clang),no)
|
||||
+math-flags = -frounding-math
|
||||
endif
|
||||
|
||||
# We might want to compile with some stack-protection flag.
|
||||
ifneq ($(stack-protector),)
|
||||
@@ -895,6 +921,26 @@ ifeq "$(strip $(+cflags))" ""
|
||||
+cflags := $(default_cflags)
|
||||
endif # $(+cflags) == ""
|
||||
|
||||
# For now, manually add known-needed clang flags here.
|
||||
ifeq ($(with-clang),yes)
|
||||
+cflags += -fheinous-gnu-extensions
|
||||
# Don't complain about __sigsetjmp.
|
||||
+cflags += -Wno-builtin-requires-header
|
||||
+cflags += -Wno-incomplete-setjmp-declaration
|
||||
# clang takes gnu89 as requiring a warning about duplicates, gcc does not
|
||||
+cflags += -Wno-duplicate-decl-specifier
|
||||
# Non-string format arguments come from debugging prints in ld.so.
|
||||
+cflags += -Wno-format-security
|
||||
|
||||
ifeq ($(with-lld),yes)
|
||||
LDFLAGS.so += -fuse-ld=lld
|
||||
LDFLAGS-rtld += -fuse-ld=lld
|
||||
LDFLAGS += -fuse-ld=lld
|
||||
LDFLAGS += -Wl,--undefined-version
|
||||
endif
|
||||
|
||||
endif # with-clang == yes
|
||||
|
||||
+cflags += $(cflags-cpu) $(+gccwarn) $(+merge-constants) $(+math-flags) \
|
||||
$(+stack-protector)
|
||||
+gcc-nowarn := -w
|
||||
@@ -1202,7 +1248,7 @@ all-subdirs = csu assert ctype locale intl catgets math setjmp signal \
|
||||
grp pwd posix io termios resource misc socket sysvipc gmon \
|
||||
gnulib iconv iconvdata wctype manual shadow gshadow po argp \
|
||||
crypt localedata timezone rt conform debug mathvec support \
|
||||
dlfcn elf
|
||||
dlfcn elf google-nsl-stub
|
||||
|
||||
ifndef avoid-generated
|
||||
# sysd-sorted itself will contain rules making the sysd-sorted target
|
||||
|
||||
@@ -653,7 +653,7 @@ $(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
|
||||
common-generated += shlib.lds
|
||||
|
||||
shlib-lds = $(common-objpfx)shlib.lds
|
||||
shlib-lds-flags = -T $(shlib-lds)
|
||||
shlib-lds-flags = -Wl,-T,$(shlib-lds)
|
||||
endif
|
||||
|
||||
define build-shlib
|
||||
@@ -705,7 +705,7 @@ LDFLAGS-c.so = -nostdlib -nostartfiles
|
||||
# But we still want to link libc.so against $(libc.so-gnulib).
|
||||
LDLIBS-c.so += $(libc.so-gnulib)
|
||||
# Give libc.so an entry point and make it directly runnable itself.
|
||||
LDFLAGS-c.so += -e __libc_main
|
||||
LDFLAGS-c.so += -Wl,-e,__libc_main
|
||||
# Pre-link the objects of libc_pic.a so that we can locally resolve
|
||||
# COMMON symbols before we link against ld.so. This is because ld.so
|
||||
# contains some of libc_pic.a already, which will prevent the COMMONs
|
||||
@@ -736,7 +736,7 @@ endif
|
||||
ifeq (,$(filter sunrpc,$(subdirs)))
|
||||
$(common-objpfx)linkobj/libc_pic.a: $(common-objpfx)libc_pic.a
|
||||
$(make-target-directory)
|
||||
ln -f $< $@
|
||||
$(LN_S) -f $< $@
|
||||
else
|
||||
$(common-objpfx)linkobj/libc_pic.a: $(common-objpfx)libc_pic.a \
|
||||
$(common-objpfx)sunrpc/librpc_compat_pic.a
|
||||
@@ -1094,7 +1094,7 @@ mv -f $@.new $@
|
||||
endef
|
||||
define make-link-multidir
|
||||
$(make-target-directory)
|
||||
ln -f $(objpfx)/$(@F) $@
|
||||
$(LN_S) -f $(objpfx)/$(@F) $@
|
||||
endef
|
||||
endif
|
||||
|
||||
@@ -1133,20 +1133,13 @@ install: $(inst_slibdir)/libc.so$(libc.so-version)
|
||||
# for the configuration we are building. We put this statement into
|
||||
# the linker scripts we install for -lc et al so that they will not be
|
||||
# used by a link for a different format on a multi-architecture system.
|
||||
$(common-objpfx)format.lds: $(..)scripts/output-format.sed \
|
||||
$(common-objpfx)config.make \
|
||||
$(common-objpfx)format.lds: $(common-objpfx)config.make \
|
||||
$(common-objpfx)config.h $(..)Makerules
|
||||
ifneq (unknown,$(output-format))
|
||||
echo > $@.new 'OUTPUT_FORMAT($(output-format))'
|
||||
else
|
||||
$(LINK.o) -shared $(sysdep-LDFLAGS) $(rtld-LDFLAGS) \
|
||||
$(LDFLAGS.so) $(LDFLAGS-lib.so) \
|
||||
-x c /dev/null -o $@.so -Wl,--verbose -v 2>&1 \
|
||||
| sed -n -f $< > $@.new
|
||||
test -s $@.new
|
||||
-x c /dev/null -o $@.so 2>/dev/null
|
||||
$(OBJDUMP) -f $@.so | sed -n 's/.*file format \(.*\)/OUTPUT_FORMAT(\1)/;T;p' > $@
|
||||
rm -f $@.so
|
||||
endif
|
||||
mv -f $@.new $@
|
||||
common-generated += format.lds
|
||||
|
||||
ifndef subdir
|
||||
|
||||
@@ -4,6 +4,92 @@ See the end for copying conditions.
|
||||
|
||||
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
|
||||
using `glibc' in the "product" field.
|
||||
|
||||
Version 2.27.1
|
||||
|
||||
Major new features:
|
||||
|
||||
* Nominative and genitive month names are now supported for the Catalan and
|
||||
Czech languages. The Catalan and Greek languages now support abbreviated
|
||||
alternative month names.
|
||||
|
||||
Deprecated and removed features, and other changes affecting compatibility:
|
||||
|
||||
* The macros 'major', 'minor', and 'makedev' are now only available from
|
||||
the header <sys/sysmacros.h>; not from <sys/types.h> or various other
|
||||
headers that happen to include <sys/types.h>. These macros are rarely
|
||||
used, not part of POSIX nor XSI, and their names frequently collide with
|
||||
user code; see https://sourceware.org/bugzilla/show_bug.cgi?id=19239 for
|
||||
further explanation.
|
||||
|
||||
<sys/sysmacros.h> is a GNU extension. Portable programs that require
|
||||
these macros should first include <sys/types.h>, and then include
|
||||
<sys/sysmacros.h> if __GNU_LIBRARY__ is defined.
|
||||
|
||||
Security related changes:
|
||||
|
||||
CVE-2021-3999: Passing a buffer of size exactly 1 byte to the getcwd
|
||||
function may result in an off-by-one buffer underflow and overflow
|
||||
when the current working directory is longer than PATH_MAX and also
|
||||
corresponds to the / directory through an unprivileged mount
|
||||
namespace. Reported by Qualys.
|
||||
|
||||
CVE-2016-10739: The getaddrinfo function could successfully parse IPv4
|
||||
addresses with arbitrary trailing characters, potentially leading to data
|
||||
or command injection issues in applications.
|
||||
|
||||
CVE-2018-19591: A file descriptor leak in if_nametoindex can lead to a
|
||||
denial of service due to resource exhaustion when processing getaddrinfo
|
||||
calls with crafted host names. Reported by Guido Vranken.
|
||||
|
||||
CVE-2017-18269: An SSE2-based memmove implementation for the i386
|
||||
architecture could corrupt memory. Reported by Max Horn.
|
||||
|
||||
CVE-2018-11236: Very long pathname arguments to realpath function could
|
||||
result in an integer overflow and buffer overflow. Reported by Alexey
|
||||
Izbyshev.
|
||||
|
||||
CVE-2018-11237: The mempcpy implementation for the Intel Xeon Phi
|
||||
architecture could write beyond the target buffer, resulting in a buffer
|
||||
overflow. Reported by Andreas Schwab.
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[6889] 'PWD' mentioned but not specified
|
||||
[16335] Feature test macro documentation incomplete and out of date
|
||||
[17343] Signed integer overflow in /stdlib/random_r.c
|
||||
[20419] files with large allocated notes crash in open_verify
|
||||
[21269] i386 sigaction sa_restorer handling is wrong
|
||||
[22342] NSCD not properly caching netgroup
|
||||
[22638] sparc: static binaries are broken if glibc is built by gcc
|
||||
configured with --enable-default-pie
|
||||
[22644] memmove-sse2-unaligned on 32bit x86 produces garbage when crossing
|
||||
2GB threshold
|
||||
[22735] Misleading typo in time.h source comment regarding CLOCKS_PER_SECOND
|
||||
[22786] Stack buffer overflow in realpath() if input size is close
|
||||
to SSIZE_MAX
|
||||
[22797] Linux: use reserved name __key in pkey_get
|
||||
[22807] PTRACE_* constants missing for powerpc
|
||||
[22818] posix/tst-glob_lstat_compat failure on alpha
|
||||
[22827] RISC-V ELF64 parser mis-reads flag in ldconfig
|
||||
[22848] ca_ES: update date definitions from CLDR
|
||||
[22884] RISCV fmax/fmin handle signalling NANs incorrectly
|
||||
[22918] multiple common of `__nss_shadow_database'
|
||||
[22919] sparc32: backtrace yields infinite backtrace with makecontext
|
||||
[22926] FTBFS on powerpcspe
|
||||
[22932] lt_LT: Update of abbreviated month names from CLDR required
|
||||
[22937] Greek (el_GR, el_CY) locales actually need ab_alt_mon
|
||||
[22947] FAIL: misc/tst-preadvwritev2
|
||||
[22963] cs_CZ: Add alternative month names
|
||||
[23005] Crash in __res_context_send after memory allocation failure
|
||||
[23037] initialize msg_flags to zero for sendmmsg() calls
|
||||
[23069] sigaction broken on riscv64-linux-gnu
|
||||
[23137] s390: pthread_join sometimes block indefinitely (on 31bit and libc
|
||||
build with -Os)
|
||||
[23152] gd_GB: Fix typo in "May" (abbreviated)
|
||||
[23166] sunrpc: Remove stray exports without --enable-obsolete-rpc
|
||||
[23196] __mempcpy_avx512_no_vzeroupper mishandles large copies
|
||||
|
||||
|
||||
Version 2.27
|
||||
|
||||
@@ -262,6 +348,10 @@ Security related changes:
|
||||
an object size near the value of SIZE_MAX, would return a pointer to a
|
||||
buffer which is too small, instead of NULL. Reported by Jakub Wilk.
|
||||
|
||||
CVE-2018-6551: The malloc function, when called with an object size near
|
||||
the value of SIZE_MAX, would return a pointer to a buffer which is too
|
||||
small, instead of NULL.
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[866] glob: glob should match dangling symlinks
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
This file documents Google's modified version of glibc, known as GRTE
|
||||
(Google Run Time Environment). GRTE serves as the common C library for
|
||||
internal Google applications running on production systems.
|
||||
|
||||
While GRTE is nearly identical to stock glibc, it does have a number
|
||||
of local changes. These run the gamut from patches that were
|
||||
submitted but not accepted for trunk glibc, to workarounds for quirks
|
||||
of Google infrastructure, to extensions that are critical for the
|
||||
proper functioning of applications. The ideal, however, is to have no
|
||||
local changes at all.
|
||||
|
||||
GRTE versions are identified by a small integer, which generally
|
||||
corresponds to a particular glibc version. GRTE v4 is based on
|
||||
glibc-2.19, while GRTE v5 is based on glibc-2.27, for instance.
|
||||
|
||||
BUILDING GRTE WITH GCC
|
||||
|
||||
When using GCC, GRTE v4 and later will build with native
|
||||
configure/make in the usual way for glibc. For v4, nscd does not
|
||||
work, so add --disable-nscd when configuring.
|
||||
|
||||
Supported architectures include x86_64 and ppc64le.
|
||||
|
||||
Testsuites will likely have some additional failures.
|
||||
|
||||
BUILDING GRTE WITH CLANG
|
||||
|
||||
GRTE v5 and later can also be built with clang and (optionally) lld.
|
||||
LLVM support for GNU source code continues to evolve (as of June
|
||||
2018), so the process is less straightforward, and likely to change
|
||||
from what is documented here. There are a number of glibc patches
|
||||
that make this work, including additional configure options mentioned
|
||||
below.
|
||||
|
||||
The minimum version of clang is 6.0.0. If lld is to be used for linking,
|
||||
it needs to be newer than 6.0.0.
|
||||
|
||||
Configure:
|
||||
|
||||
CC=path-to-llvm/clang CXX=path-to-llvm/clang++ \
|
||||
../glibc/configure --disable-werror --with-clang --disable-float128 \
|
||||
--with-lld --with-default-link --disable-multi-arch --prefix=/something
|
||||
|
||||
To build with BFD ld as linker, omit the "--with-lld
|
||||
--with-default-link". (Gold has had problems in the past.)
|
||||
|
||||
Build:
|
||||
|
||||
make
|
||||
make install
|
||||
|
||||
Test:
|
||||
|
||||
make check
|
||||
|
||||
Testsuite results will show many unexpected failures beyond the
|
||||
GCC-compiled results; about 390 for x86-64. These are a combination
|
||||
of known bugs in clang, and issues with conformance to old standards
|
||||
predating clang. Note that the clang build still needs symlinks to
|
||||
libgcc and libstdc++ in the installed library directory, so that
|
||||
thread cancellation tests pass.
|
||||
Vendored
+8
-11
@@ -223,20 +223,17 @@ AC_DEFUN([LIBC_LINKER_FEATURE],
|
||||
[AC_MSG_CHECKING([for linker that supports $1])
|
||||
libc_linker_feature=no
|
||||
if test x"$gnu_ld" = x"yes"; then
|
||||
libc_linker_check=`$LD -v --help 2>/dev/null | grep "\$1"`
|
||||
if test -n "$libc_linker_check"; then
|
||||
cat > conftest.c <<EOF
|
||||
cat > conftest.c <<EOF
|
||||
int _start (void) { return 42; }
|
||||
EOF
|
||||
if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||
$2 -nostdlib -nostartfiles
|
||||
-fPIC -shared -o conftest.so conftest.c
|
||||
1>&AS_MESSAGE_LOG_FD])
|
||||
then
|
||||
libc_linker_feature=yes
|
||||
fi
|
||||
rm -f conftest*
|
||||
if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||
$2 -nostdlib -nostartfiles
|
||||
-fPIC -shared -o conftest.so conftest.c
|
||||
1>&AS_MESSAGE_LOG_FD])
|
||||
then
|
||||
libc_linker_feature=yes
|
||||
fi
|
||||
rm -f conftest*
|
||||
fi
|
||||
if test $libc_linker_feature = yes; then
|
||||
$3
|
||||
|
||||
+12
-1
@@ -86,10 +86,21 @@ __END_DECLS
|
||||
parentheses around EXPR. Otherwise, those added parentheses would
|
||||
suppress warnings we'd expect to be detected by gcc's -Wparentheses. */
|
||||
# if defined __cplusplus
|
||||
# if defined __has_builtin
|
||||
# if __has_builtin (__builtin_FILE)
|
||||
# define __ASSERT_FILE __builtin_FILE ()
|
||||
# define __ASSERT_LINE __builtin_LINE ()
|
||||
# endif
|
||||
# endif
|
||||
# if !defined __ASSERT_FILE
|
||||
# define __ASSERT_FILE __FILE__
|
||||
# define __ASSERT_LINE __LINE__
|
||||
# endif
|
||||
# define assert(expr) \
|
||||
(static_cast <bool> (expr) \
|
||||
? void (0) \
|
||||
: __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION))
|
||||
: __assert_fail (#expr, __ASSERT_FILE, __ASSERT_LINE, \
|
||||
__ASSERT_FUNCTION))
|
||||
# elif !defined __GNUC__ || defined __STRICT_ANSI__
|
||||
# define assert(expr) \
|
||||
((expr) \
|
||||
|
||||
@@ -9450,7 +9450,6 @@ move-if-change
|
||||
check-execstack.awk
|
||||
pylint
|
||||
pylintrc
|
||||
output-format.sed
|
||||
merge-test-results.sh
|
||||
update-copyrights
|
||||
config-uname.sh
|
||||
|
||||
@@ -28,5 +28,6 @@
|
||||
#define RWF_DSYNC 0x00000002 /* per-IO O_DSYNC. */
|
||||
#define RWF_SYNC 0x00000004 /* per-IO O_SYNC. */
|
||||
#define RWF_NOWAIT 0x00000008 /* per-IO nonblocking mode. */
|
||||
#define RWF_APPEND 0x00000010 /* per-IO O_APPEND. */
|
||||
|
||||
#endif /* sys/uio_ext.h */
|
||||
|
||||
+4
-2
@@ -171,8 +171,10 @@
|
||||
/* Define if gcc supports attribute ifunc. */
|
||||
#undef HAVE_GCC_IFUNC
|
||||
|
||||
/* Define if the linker defines __ehdr_start. */
|
||||
#undef HAVE_EHDR_START
|
||||
/* Define if CC supports attribute retain. */
|
||||
#undef HAVE_GNU_RETAIN
|
||||
|
||||
#define WANT_FLOAT128 0
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
+1
-1
@@ -72,7 +72,6 @@ fno-unit-at-a-time = @fno_unit_at_a_time@
|
||||
bind-now = @bindnow@
|
||||
have-hash-style = @libc_cv_hashstyle@
|
||||
use-default-link = @use_default_link@
|
||||
output-format = @libc_cv_output_format@
|
||||
have-cxx-thread_local = @libc_cv_cxx_thread_local@
|
||||
have-loop-to-function = @libc_cv_cc_loop_to_function@
|
||||
|
||||
@@ -101,6 +100,7 @@ use-nscd = @use_nscd@
|
||||
build-hardcoded-path-in-tests= @hardcoded_path_in_tests@
|
||||
build-pt-chown = @build_pt_chown@
|
||||
have-tunables = @have_tunables@
|
||||
enable-float128 = @enable_float128@
|
||||
|
||||
# Build tools.
|
||||
CC = @CC@
|
||||
|
||||
@@ -623,7 +623,6 @@ libc_cv_cc_submachine
|
||||
libc_cv_cc_nofma
|
||||
libc_cv_mtls_dialect_gnu2
|
||||
fno_unit_at_a_time
|
||||
libc_cv_output_format
|
||||
libc_cv_has_glob_dat
|
||||
libc_cv_hashstyle
|
||||
libc_cv_fpie
|
||||
@@ -669,6 +668,7 @@ stack_protector
|
||||
libc_cv_ssp
|
||||
libc_cv_with_fp
|
||||
base_machine
|
||||
enable_float128
|
||||
have_tunables
|
||||
build_pt_chown
|
||||
build_nscd
|
||||
@@ -759,6 +759,8 @@ with_gd_include
|
||||
with_gd_lib
|
||||
with_binutils
|
||||
with_selinux
|
||||
with_clang
|
||||
with_lld
|
||||
with_headers
|
||||
with_default_link
|
||||
enable_sanity_checks
|
||||
@@ -787,6 +789,7 @@ enable_build_nscd
|
||||
enable_nscd
|
||||
enable_pt_chown
|
||||
enable_tunables
|
||||
enable_float128
|
||||
enable_mathvec
|
||||
with_cpu
|
||||
'
|
||||
@@ -1459,6 +1462,7 @@ Optional Features:
|
||||
--enable-pt_chown Enable building and installing pt_chown
|
||||
--enable-tunables Enable tunables support. Known values are 'yes',
|
||||
'no' and 'valstring'
|
||||
--disable-float128 disable float128 support
|
||||
--enable-mathvec Enable building and installing mathvec [default
|
||||
depends on architecture]
|
||||
|
||||
@@ -1472,6 +1476,8 @@ Optional Packages:
|
||||
--with-gd-lib=DIR find libgd library files in DIR
|
||||
--with-binutils=PATH specify location of binutils (as and ld)
|
||||
--with-selinux if building with SELinux support
|
||||
--with-clang if building with clang (temporary)
|
||||
--with-lld if building/linking with lld (temporary)
|
||||
--with-headers=PATH location of system headers to use (for example
|
||||
/usr/src/linux/include) [default=compiler default]
|
||||
--with-default-link do not use explicit linker scripts
|
||||
@@ -3312,6 +3318,26 @@ else
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-clang was given.
|
||||
if test "${with_clang+set}" = set; then :
|
||||
withval=$with_clang; with_clang=$withval
|
||||
else
|
||||
with_clang=no
|
||||
fi
|
||||
|
||||
config_vars="$config_vars
|
||||
with-clang = $with_clang"
|
||||
|
||||
# Check whether --with-lld was given.
|
||||
if test "${with_lld+set}" = set; then :
|
||||
withval=$with_lld; with_lld=$withval
|
||||
else
|
||||
with_lld=no
|
||||
fi
|
||||
|
||||
config_vars="$config_vars
|
||||
with-lld = $with_lld"
|
||||
|
||||
|
||||
# Check whether --with-headers was given.
|
||||
if test "${with_headers+set}" = set; then :
|
||||
@@ -3721,6 +3747,19 @@ if test "$have_tunables" = yes; then
|
||||
|
||||
fi
|
||||
|
||||
# Check whether --enable-float128 was given.
|
||||
if test "${enable_float128+set}" = set; then :
|
||||
enableval=$enable_float128; enable_float128=$enableval
|
||||
else
|
||||
enable_float128=yes
|
||||
fi
|
||||
|
||||
|
||||
if test "$enable_float128" = yes; then
|
||||
$as_echo "#define WANT_FLOAT128 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
# The abi-tags file uses a fairly simplistic model for name recognition that
|
||||
# can't distinguish i486-pc-linux-gnu fully from i486-pc-gnu. So we mutate a
|
||||
# $host_os of `gnu*' here to be `gnu-gnu*' just so that it can tell.
|
||||
@@ -4009,6 +4048,31 @@ fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gcc_indirect_function" >&5
|
||||
$as_echo "$libc_cv_gcc_indirect_function" >&6; }
|
||||
|
||||
# Check if CC supports attribute retain as it is used in attribute_used_retain macro.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU attribute retain support" >&5
|
||||
$as_echo_n "checking for GNU attribute retain support... " >&6; }
|
||||
if ${libc_cv_gnu_retain+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat > conftest.c <<EOF
|
||||
static int var __attribute__ ((used, retain, section ("__libc_atexit")));
|
||||
EOF
|
||||
libc_cv_gnu_retain=no
|
||||
if ${CC-cc} -Werror -c conftest.c -o /dev/null 1>&5 \
|
||||
2>&5 ; then
|
||||
libc_cv_gnu_retain=yes
|
||||
fi
|
||||
rm -f conftest*
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gnu_retain" >&5
|
||||
$as_echo "$libc_cv_gnu_retain" >&6; }
|
||||
if test $libc_cv_gnu_retain = yes; then
|
||||
$as_echo "#define HAVE_GNU_RETAIN 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
config_vars="$config_vars
|
||||
have-gnu-retain = $libc_cv_gnu_retain"
|
||||
|
||||
# Check if gcc warns about alias for function with incompatible types.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler warns about alias for function with incompatible types" >&5
|
||||
$as_echo_n "checking if compiler warns about alias for function with incompatible types... " >&6; }
|
||||
@@ -4438,6 +4502,7 @@ $as_echo "$libc_cv_prog_ld_gnu" >&6; }
|
||||
gnu_ld=$libc_cv_prog_ld_gnu
|
||||
|
||||
|
||||
if test "$with_clang" = no; then
|
||||
# Accept binutils 2.25 or newer.
|
||||
for ac_prog in $AS
|
||||
do
|
||||
@@ -4502,7 +4567,9 @@ if test $ac_verc_fail = yes; then
|
||||
AS=: critic_missing="$critic_missing as"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if test "$with_lld" = no; then
|
||||
if test -n "`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"; then
|
||||
# Accept gold 1.14 or higher
|
||||
for ac_prog in $LD
|
||||
@@ -4632,6 +4699,7 @@ if test $ac_verc_fail = yes; then
|
||||
LD=: critic_missing="$critic_missing GNU ld"
|
||||
fi
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
# These programs are version sensitive.
|
||||
@@ -5030,7 +5098,9 @@ main ()
|
||||
{
|
||||
|
||||
#if !defined __GNUC__ || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9)
|
||||
#if !defined __clang__
|
||||
#error insufficient compiler
|
||||
#endif
|
||||
#endif
|
||||
;
|
||||
return 0;
|
||||
@@ -5307,6 +5377,8 @@ fi
|
||||
# Obtain some C++ header file paths. This is used to make a local
|
||||
# copy of those headers in Makerules.
|
||||
if test -n "$CXX"; then
|
||||
# In theory the clang and gcc regexes can be merged, but the
|
||||
# result is incomprehensible.
|
||||
find_cxx_header () {
|
||||
echo "#include <$1>" | $CXX -M -MP -x c++ - 2>/dev/null \
|
||||
| sed -n "\,$1:,{s/:\$//;p}"
|
||||
@@ -5817,17 +5889,17 @@ fi
|
||||
$as_echo "$libc_linker_feature" >&6; }
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker that supports --no-dynamic-linker" >&5
|
||||
$as_echo_n "checking for linker that supports --no-dynamic-linker... " >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z start-stop-gc" >&5
|
||||
$as_echo_n "checking for linker that supports -z start-stop-gc... " >&6; }
|
||||
libc_linker_feature=no
|
||||
if test x"$gnu_ld" = x"yes"; then
|
||||
libc_linker_check=`$LD -v --help 2>/dev/null | grep "\--no-dynamic-linker"`
|
||||
libc_linker_check=`$LD -v --help 2>/dev/null | grep "\-z start-stop-gc"`
|
||||
if test -n "$libc_linker_check"; then
|
||||
cat > conftest.c <<EOF
|
||||
int _start (void) { return 42; }
|
||||
EOF
|
||||
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||
-Wl,--no-dynamic-linker -nostdlib -nostartfiles
|
||||
-Wl,-z,start-stop-gc -nostdlib -nostartfiles
|
||||
-fPIC -shared -o conftest.so conftest.c
|
||||
1>&5'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
@@ -5841,6 +5913,68 @@ EOF
|
||||
rm -f conftest*
|
||||
fi
|
||||
fi
|
||||
if test $libc_linker_feature = yes; then
|
||||
libc_cv_z_start_stop_gc=yes
|
||||
else
|
||||
libc_cv_z_start_stop_gc=no
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
|
||||
$as_echo "$libc_linker_feature" >&6; }
|
||||
config_vars="$config_vars
|
||||
have-z-start-stop-gc = $libc_cv_z_start_stop_gc"
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z pack-relative-relocs" >&5
|
||||
$as_echo_n "checking for linker that supports -z pack-relative-relocs... " >&6; }
|
||||
libc_linker_feature=no
|
||||
if test x"$gnu_ld" = x"yes"; then
|
||||
cat > conftest.c <<EOF
|
||||
int _start (void) { return 42; }
|
||||
EOF
|
||||
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||
-Wl,-z,pack-relative-relocs -nostdlib -nostartfiles
|
||||
-fPIC -shared -o conftest.so conftest.c
|
||||
1>&5'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then
|
||||
libc_linker_feature=yes
|
||||
fi
|
||||
rm -f conftest*
|
||||
fi
|
||||
if test $libc_linker_feature = yes; then
|
||||
libc_cv_dt_relr=yes
|
||||
else
|
||||
libc_cv_dt_relr=no
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
|
||||
$as_echo "$libc_linker_feature" >&6; }
|
||||
config_vars="$config_vars
|
||||
have-dt-relr = $libc_cv_dt_relr"
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker that supports --no-dynamic-linker" >&5
|
||||
$as_echo_n "checking for linker that supports --no-dynamic-linker... " >&6; }
|
||||
libc_linker_feature=no
|
||||
if test x"$gnu_ld" = x"yes"; then
|
||||
cat > conftest.c <<EOF
|
||||
int _start (void) { return 42; }
|
||||
EOF
|
||||
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||
-Wl,--no-dynamic-linker -nostdlib -nostartfiles
|
||||
-fPIC -shared -o conftest.so conftest.c
|
||||
1>&5'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then
|
||||
libc_linker_feature=yes
|
||||
fi
|
||||
rm -f conftest*
|
||||
fi
|
||||
if test $libc_linker_feature = yes; then
|
||||
libc_cv_no_dynamic_linker=yes
|
||||
else
|
||||
@@ -6018,24 +6152,6 @@ fi
|
||||
$as_echo "$libc_cv_has_glob_dat" >&6; }
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker output format" >&5
|
||||
$as_echo_n "checking linker output format... " >&6; }
|
||||
if ${libc_cv_output_format+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if libc_cv_output_format=`
|
||||
${CC-cc} -nostartfiles -nostdlib $no_ssp -Wl,--print-output-format 2>&5`
|
||||
then
|
||||
:
|
||||
else
|
||||
libc_cv_output_format=
|
||||
fi
|
||||
test -n "$libc_cv_output_format" || libc_cv_output_format=unknown
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_output_format" >&5
|
||||
$as_echo "$libc_cv_output_format" >&6; }
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fno-toplevel-reorder -fno-section-anchors" >&5
|
||||
$as_echo_n "checking for -fno-toplevel-reorder -fno-section-anchors... " >&6; }
|
||||
if ${libc_cv_fno_toplevel_reorder+:} false; then :
|
||||
@@ -6170,7 +6286,7 @@ char *foo (const char *a, const char *b)
|
||||
return __builtin_strstr (a, b);
|
||||
}
|
||||
EOF
|
||||
if { ac_try='${CC-cc} -O3 -S conftest.c -o - | grep -F "my_strstr" > /dev/null'
|
||||
if { ac_try='${CC-cc} -O3 -S conftest.c -o - | grep -F "strstr" > /dev/null'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
@@ -6251,7 +6367,7 @@ __attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns")))
|
||||
foo (void) {}
|
||||
EOF
|
||||
libc_cv_cc_loop_to_function=no
|
||||
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -c conftest.c'
|
||||
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -Werror -c conftest.c'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
@@ -6502,58 +6618,6 @@ if test $libc_cv_predef_fortify_source = yes; then
|
||||
fi
|
||||
|
||||
|
||||
# Some linkers on some architectures support __ehdr_start but with
|
||||
# bugs. Make sure usage of it does not create relocations in the
|
||||
# output (as the linker should resolve them all for us).
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker provides working __ehdr_start" >&5
|
||||
$as_echo_n "checking whether the linker provides working __ehdr_start... " >&6; }
|
||||
if ${libc_cv_ehdr_start+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
|
||||
old_CFLAGS="$CFLAGS"
|
||||
old_LDFLAGS="$LDFLAGS"
|
||||
old_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS -fPIC"
|
||||
LDFLAGS="$LDFLAGS -nostdlib -nostartfiles -shared $no_ssp"
|
||||
LIBS=
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
typedef struct {
|
||||
char foo;
|
||||
long val;
|
||||
} Ehdr;
|
||||
extern const Ehdr __ehdr_start __attribute__ ((visibility ("hidden")));
|
||||
long ehdr (void) { return __ehdr_start.val; }
|
||||
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
if $READELF -r conftest | grep -F __ehdr_start >/dev/null; then
|
||||
libc_cv_ehdr_start=broken
|
||||
else
|
||||
libc_cv_ehdr_start=yes
|
||||
fi
|
||||
else
|
||||
libc_cv_ehdr_start=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
CFLAGS="$old_CFLAGS"
|
||||
LDFLAGS="$old_LDFLAGS"
|
||||
LIBS="$old_LIBS"
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ehdr_start" >&5
|
||||
$as_echo "$libc_cv_ehdr_start" >&6; }
|
||||
if test "$libc_cv_ehdr_start" = yes; then
|
||||
$as_echo "#define HAVE_EHDR_START 1" >>confdefs.h
|
||||
|
||||
elif test "$libc_cv_ehdr_start" = broken; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: linker is broken -- you should upgrade" >&5
|
||||
$as_echo "$as_me: WARNING: linker is broken -- you should upgrade" >&2;}
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_trap with no external dependencies" >&5
|
||||
$as_echo_n "checking for __builtin_trap with no external dependencies... " >&6; }
|
||||
if ${libc_cv_builtin_trap+:} false; then :
|
||||
@@ -6771,7 +6835,10 @@ libc_cv_pie_default=$libc_cv_cc_pie_default
|
||||
|
||||
# Set the `multidir' variable by grabbing the variable from the compiler.
|
||||
# We do it once and save the result in a generated makefile.
|
||||
libc_cv_multidir=.
|
||||
if test "$with_clang" = no; then
|
||||
libc_cv_multidir=`${CC-cc} $CFLAGS $CPPFLAGS -print-multi-directory`
|
||||
fi
|
||||
|
||||
|
||||
if test "$static_pie" = yes; then
|
||||
|
||||
+65
-47
@@ -137,6 +137,20 @@ AC_ARG_WITH([selinux],
|
||||
[if building with SELinux support]),
|
||||
[with_selinux=$withval],
|
||||
[with_selinux=auto])
|
||||
dnl This is a temporary hack, to help sort out wired-in GCC assumptions.
|
||||
AC_ARG_WITH([clang],
|
||||
AC_HELP_STRING([--with-clang],
|
||||
[if building with clang (temporary)]),
|
||||
[with_clang=$withval],
|
||||
[with_clang=no])
|
||||
LIBC_CONFIG_VAR([with-clang], [$with_clang])
|
||||
dnl This is a temporary hack, to help with BFD LD vs LLD debugging.
|
||||
AC_ARG_WITH([lld],
|
||||
AC_HELP_STRING([--with-lld],
|
||||
[if building/linking with lld (temporary)]),
|
||||
[with_lld=$withval],
|
||||
[with_lld=no])
|
||||
LIBC_CONFIG_VAR([with-lld], [$with_lld])
|
||||
|
||||
AC_ARG_WITH([headers],
|
||||
AC_HELP_STRING([--with-headers=PATH],
|
||||
@@ -435,6 +449,16 @@ if test "$have_tunables" = yes; then
|
||||
AC_DEFINE(HAVE_TUNABLES)
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([float128],
|
||||
AC_HELP_STRING([--disable-float128],
|
||||
[disable float128 support]),
|
||||
[enable_float128=$enableval],
|
||||
[enable_float128=yes])
|
||||
AC_SUBST(enable_float128)
|
||||
if test "$enable_float128" = yes; then
|
||||
AC_DEFINE(WANT_FLOAT128)
|
||||
fi
|
||||
|
||||
# The abi-tags file uses a fairly simplistic model for name recognition that
|
||||
# can't distinguish i486-pc-linux-gnu fully from i486-pc-gnu. So we mutate a
|
||||
# $host_os of `gnu*' here to be `gnu-gnu*' just so that it can tell.
|
||||
@@ -646,6 +670,23 @@ if ${CC-cc} -c conftest.c -o conftest.o 1>&AS_MESSAGE_LOG_FD \
|
||||
fi
|
||||
rm -f conftest*])
|
||||
|
||||
# Check if CC supports attribute retain as it is used in attribute_used_retain macro.
|
||||
AC_CACHE_CHECK([for GNU attribute retain support],
|
||||
libc_cv_gnu_retain, [dnl
|
||||
cat > conftest.c <<EOF
|
||||
static int var __attribute__ ((used, retain, section ("__libc_atexit")));
|
||||
EOF
|
||||
libc_cv_gnu_retain=no
|
||||
if ${CC-cc} -Werror -c conftest.c -o /dev/null 1>&AS_MESSAGE_LOG_FD \
|
||||
2>&AS_MESSAGE_LOG_FD ; then
|
||||
libc_cv_gnu_retain=yes
|
||||
fi
|
||||
rm -f conftest*])
|
||||
if test $libc_cv_gnu_retain = yes; then
|
||||
AC_DEFINE(HAVE_GNU_RETAIN)
|
||||
fi
|
||||
LIBC_CONFIG_VAR([have-gnu-retain], [$libc_cv_gnu_retain])
|
||||
|
||||
# Check if gcc warns about alias for function with incompatible types.
|
||||
AC_CACHE_CHECK([if compiler warns about alias for function with incompatible types],
|
||||
libc_cv_gcc_incompatible_alias, [dnl
|
||||
@@ -911,12 +952,15 @@ AC_PROG_LN_S
|
||||
|
||||
LIBC_PROG_BINUTILS
|
||||
|
||||
if test "$with_clang" = no; then
|
||||
# Accept binutils 2.25 or newer.
|
||||
AC_CHECK_PROG_VER(AS, $AS, --version,
|
||||
[GNU assembler.* \([0-9]*\.[0-9.]*\)],
|
||||
[2.1[0-9][0-9]*|2.2[5-9]*|2.[3-9][0-9]*|[3-9].*|[1-9][0-9]*],
|
||||
AS=: critic_missing="$critic_missing as")
|
||||
fi
|
||||
|
||||
if test "$with_lld" = no; then
|
||||
if test -n "`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"; then
|
||||
# Accept gold 1.14 or higher
|
||||
AC_CHECK_PROG_VER(LD, $LD, --version,
|
||||
@@ -929,6 +973,7 @@ else
|
||||
[2.1[0-9][0-9]*|2.2[5-9]*|2.[3-9][0-9]*|[3-9].*|[1-9][0-9]*],
|
||||
LD=: critic_missing="$critic_missing GNU ld")
|
||||
fi
|
||||
fi
|
||||
|
||||
# These programs are version sensitive.
|
||||
AC_CHECK_TOOL_PREFIX
|
||||
@@ -958,7 +1003,9 @@ AC_CHECK_PROG_VER(BISON, bison, --version,
|
||||
AC_CACHE_CHECK([if $CC is sufficient to build libc], libc_cv_compiler_ok, [
|
||||
AC_TRY_COMPILE([], [
|
||||
#if !defined __GNUC__ || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9)
|
||||
#if !defined __clang__
|
||||
#error insufficient compiler
|
||||
#endif
|
||||
#endif],
|
||||
[libc_cv_compiler_ok=yes],
|
||||
[libc_cv_compiler_ok=no])])
|
||||
@@ -1037,7 +1084,10 @@ AC_SUBST(CXX_SYSINCLUDES)
|
||||
|
||||
# Obtain some C++ header file paths. This is used to make a local
|
||||
# copy of those headers in Makerules.
|
||||
changequote(,)dnl
|
||||
if test -n "$CXX"; then
|
||||
# In theory the clang and gcc regexes can be merged, but the
|
||||
# result is incomprehensible.
|
||||
find_cxx_header () {
|
||||
echo "#include <$1>" | $CXX -M -MP -x c++ - 2>/dev/null \
|
||||
| sed -n "\,$1:,{s/:\$//;p}"
|
||||
@@ -1046,6 +1096,7 @@ if test -n "$CXX"; then
|
||||
CXX_CMATH_HEADER="$(find_cxx_header cmath)"
|
||||
CXX_BITS_STD_ABS_H="$(find_cxx_header bits/std_abs.h)"
|
||||
fi
|
||||
changequote([,])dnl
|
||||
AC_SUBST(CXX_CSTDLIB_HEADER)
|
||||
AC_SUBST(CXX_CMATH_HEADER)
|
||||
AC_SUBST(CXX_BITS_STD_ABS_H)
|
||||
@@ -1292,6 +1343,15 @@ LIBC_LINKER_FEATURE([-z execstack], [-Wl,-z,execstack],
|
||||
[libc_cv_z_execstack=yes], [libc_cv_z_execstack=no])
|
||||
AC_SUBST(libc_cv_z_execstack)
|
||||
|
||||
LIBC_LINKER_FEATURE([-z start-stop-gc], [-Wl,-z,start-stop-gc],
|
||||
[libc_cv_z_start_stop_gc=yes], [libc_cv_z_start_stop_gc=no])
|
||||
LIBC_CONFIG_VAR([have-z-start-stop-gc], [$libc_cv_z_start_stop_gc])
|
||||
|
||||
LIBC_LINKER_FEATURE([-z pack-relative-relocs],
|
||||
[-Wl,-z,pack-relative-relocs],
|
||||
[libc_cv_dt_relr=yes], [libc_cv_dt_relr=no])
|
||||
LIBC_CONFIG_VAR([have-dt-relr], [$libc_cv_dt_relr])
|
||||
|
||||
LIBC_LINKER_FEATURE([--no-dynamic-linker],
|
||||
[-Wl,--no-dynamic-linker],
|
||||
[libc_cv_no_dynamic_linker=yes],
|
||||
@@ -1403,17 +1463,6 @@ fi
|
||||
rm -f conftest*])
|
||||
AC_SUBST(libc_cv_has_glob_dat)
|
||||
|
||||
AC_CACHE_CHECK(linker output format, libc_cv_output_format, [dnl
|
||||
if libc_cv_output_format=`
|
||||
${CC-cc} -nostartfiles -nostdlib $no_ssp -Wl,--print-output-format 2>&AS_MESSAGE_LOG_FD`
|
||||
then
|
||||
:
|
||||
else
|
||||
libc_cv_output_format=
|
||||
fi
|
||||
test -n "$libc_cv_output_format" || libc_cv_output_format=unknown])
|
||||
AC_SUBST(libc_cv_output_format)
|
||||
|
||||
AC_CACHE_CHECK(for -fno-toplevel-reorder -fno-section-anchors, libc_cv_fno_toplevel_reorder, [dnl
|
||||
cat > conftest.c <<EOF
|
||||
int foo;
|
||||
@@ -1502,7 +1551,7 @@ char *foo (const char *a, const char *b)
|
||||
}
|
||||
EOF
|
||||
dnl
|
||||
if AC_TRY_COMMAND([${CC-cc} -O3 -S conftest.c -o - | grep -F "my_strstr" > /dev/null]);
|
||||
if AC_TRY_COMMAND([${CC-cc} -O3 -S conftest.c -o - | grep -F "strstr" > /dev/null]);
|
||||
then
|
||||
libc_cv_gcc_builtin_redirection=yes
|
||||
else
|
||||
@@ -1545,7 +1594,7 @@ __attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns")))
|
||||
foo (void) {}
|
||||
EOF
|
||||
libc_cv_cc_loop_to_function=no
|
||||
if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -c conftest.c])
|
||||
if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -Werror -c conftest.c])
|
||||
then
|
||||
libc_cv_cc_loop_to_function=yes
|
||||
fi
|
||||
@@ -1624,40 +1673,6 @@ if test $libc_cv_predef_fortify_source = yes; then
|
||||
fi
|
||||
AC_SUBST(CPPUNDEFS)
|
||||
|
||||
# Some linkers on some architectures support __ehdr_start but with
|
||||
# bugs. Make sure usage of it does not create relocations in the
|
||||
# output (as the linker should resolve them all for us).
|
||||
AC_CACHE_CHECK([whether the linker provides working __ehdr_start],
|
||||
libc_cv_ehdr_start, [
|
||||
old_CFLAGS="$CFLAGS"
|
||||
old_LDFLAGS="$LDFLAGS"
|
||||
old_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS -fPIC"
|
||||
LDFLAGS="$LDFLAGS -nostdlib -nostartfiles -shared $no_ssp"
|
||||
LIBS=
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([
|
||||
typedef struct {
|
||||
char foo;
|
||||
long val;
|
||||
} Ehdr;
|
||||
extern const Ehdr __ehdr_start __attribute__ ((visibility ("hidden")));
|
||||
long ehdr (void) { return __ehdr_start.val; }
|
||||
])],
|
||||
[if $READELF -r conftest | grep -F __ehdr_start >/dev/null; then
|
||||
libc_cv_ehdr_start=broken
|
||||
else
|
||||
libc_cv_ehdr_start=yes
|
||||
fi], [libc_cv_ehdr_start=no])
|
||||
CFLAGS="$old_CFLAGS"
|
||||
LDFLAGS="$old_LDFLAGS"
|
||||
LIBS="$old_LIBS"
|
||||
])
|
||||
if test "$libc_cv_ehdr_start" = yes; then
|
||||
AC_DEFINE([HAVE_EHDR_START])
|
||||
elif test "$libc_cv_ehdr_start" = broken; then
|
||||
AC_MSG_WARN([linker is broken -- you should upgrade])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK(for __builtin_trap with no external dependencies,
|
||||
libc_cv_builtin_trap, [dnl
|
||||
libc_cv_builtin_trap=no
|
||||
@@ -1811,7 +1826,10 @@ AC_SUBST(libc_cv_pie_default)
|
||||
|
||||
# Set the `multidir' variable by grabbing the variable from the compiler.
|
||||
# We do it once and save the result in a generated makefile.
|
||||
libc_cv_multidir=.
|
||||
if test "$with_clang" = no; then
|
||||
libc_cv_multidir=`${CC-cc} $CFLAGS $CPPFLAGS -print-multi-directory`
|
||||
fi
|
||||
AC_SUBST(libc_cv_multidir)
|
||||
|
||||
if test "$static_pie" = yes; then
|
||||
|
||||
+22
-1
@@ -39,20 +39,26 @@ $CFLAGS{"POSIX2008"} = "-std=c99 -D_POSIX_C_SOURCE=200809L";
|
||||
# Return a list of functions exported by a header, empty if an include
|
||||
# of the header does not compile.
|
||||
sub list_exported_functions {
|
||||
my ($cc, $standard, $header, $tmpdir) = @_;
|
||||
my ($cc, $standard, $header, $tmpdir, $withclang) = @_;
|
||||
my ($cc_all) = "$cc -D_ISOMAC $CFLAGS{$standard}";
|
||||
my ($tmpfile) = "$tmpdir/list-$$.c";
|
||||
my ($auxfile) = "$tmpdir/list-$$.c.aux";
|
||||
my ($astfile) = "$tmpdir/list-$$.c.ast";
|
||||
my ($ret);
|
||||
my (%res) = ();
|
||||
open (TMPFILE, ">$tmpfile") || die ("open $tmpfile: $!\n");
|
||||
print TMPFILE "#include <$header>\n";
|
||||
close (TMPFILE) || die ("close $tmpfile: $!\n");
|
||||
if ($withclang ne "yes") {
|
||||
$ret = system "$cc_all -c $tmpfile -o /dev/null -aux-info $auxfile > /dev/null";
|
||||
} else {
|
||||
$ret = system "$cc_all -c $tmpfile -o /dev/null -Xclang -ast-dump |grep FunctionDecl > $astfile";
|
||||
}
|
||||
unlink ($tmpfile) || die ("unlink $tmpfile: $!\n");
|
||||
if ($ret != 0) {
|
||||
return;
|
||||
}
|
||||
if ($withclang ne "yes") {
|
||||
open (AUXFILE, "<$auxfile") || die ("open $auxfile: $!\n");
|
||||
while (<AUXFILE>) {
|
||||
s|/\*.*?\*/||g;
|
||||
@@ -70,5 +76,20 @@ sub list_exported_functions {
|
||||
}
|
||||
close (AUXFILE) || die ("close $auxfile: $!\n");
|
||||
unlink ($auxfile) || die ("unlink $auxfile: $!\n");
|
||||
} else {
|
||||
open (ASTFILE, "<$astfile") || die ("open $astfile: $!\n");
|
||||
while (<ASTFILE>) {
|
||||
s/^.*:[0-9][0-9]*:[0-9][0-9]* //g;
|
||||
s/^.*:[0-9][0-9]* implicit //g;
|
||||
s/^.*:[0-9][0-9]* //g;
|
||||
if (/(\w+)\s* /) {
|
||||
$res{$1} = 1;
|
||||
} else {
|
||||
die ("couldn't parse -ast-dump output: $_\n");
|
||||
}
|
||||
}
|
||||
close (ASTFILE) || die ("close $astfile: $!\n");
|
||||
unlink ($astfile) || die ("unlink $astfile: $!\n");
|
||||
}
|
||||
return sort keys %res;
|
||||
}
|
||||
|
||||
@@ -178,6 +178,7 @@ $(conformtest-header-tests): $(objpfx)%/conform.out: \
|
||||
$(PERL) -I. conformtest.pl --tmpdir=$(@D)/scratch --cc='$(CC)' \
|
||||
--flags='$(conformtest-cc-flags)' --standard=$$std \
|
||||
--headers=$$hdr $(conformtest-xfail) $(conformtest-cross) \
|
||||
--withclang='$(with-clang)' \
|
||||
> $@); \
|
||||
$(evaluate-test)
|
||||
|
||||
@@ -185,6 +186,7 @@ $(linknamespace-symlists-tests): $(objpfx)symlist-%: list-header-symbols.pl
|
||||
$(PERL) -I. -w $< --tmpdir=$(objpfx) --cc='$(CC)' \
|
||||
--flags='$(conformtest-cc-flags)' --standard=$* \
|
||||
--headers="$(strip $(conformtest-headers-$*))" \
|
||||
--withclang='$(with-clang)' \
|
||||
> $@ 2> $@.err; \
|
||||
$(evaluate-test)
|
||||
|
||||
@@ -225,6 +227,7 @@ $(linknamespace-header-tests): $(objpfx)%/linknamespace.out: \
|
||||
--stdsyms=$(objpfx)symlist-$$std --header=$$hdr \
|
||||
--libsyms=$(objpfx)symlist-stdlibs-$$std \
|
||||
--readelf='$(READELF)' \
|
||||
--withclang='$(with-clang)' \
|
||||
> $@ 2>&1); \
|
||||
$(evaluate-test)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ $cross = "";
|
||||
$xfail_str = "";
|
||||
GetOptions ('headers=s' => \@headers, 'standard=s' => \$standard,
|
||||
'flags=s' => \$flags, 'cc=s' => \$CC, 'tmpdir=s' => \$tmpdir,
|
||||
'cross' => \$cross, 'xfail=s' => \$xfail_str);
|
||||
'cross' => \$cross, 'xfail=s' => \$xfail_str, 'withclang=s' => \$withclang);
|
||||
@headers = split(/,/,join(',',@headers));
|
||||
|
||||
# List of the headers we are testing.
|
||||
@@ -270,9 +270,17 @@ sub checknamespace {
|
||||
close (TESTFILE);
|
||||
|
||||
undef %errors;
|
||||
if ($withclang eq "yes") {
|
||||
open (CONTENT, "$CC $CFLAGS_namespace -E $fnamebase.c -P -Wp,-dM | sed -e '/^# [1-9]/d' -e '/^[[:space:]]*\$/d' |");
|
||||
} else {
|
||||
open (CONTENT, "$CC $CFLAGS_namespace -E $fnamebase.c -P -Wp,-dN | sed -e '/^# [1-9]/d' -e '/^[[:space:]]*\$/d' |");
|
||||
}
|
||||
loop: while (<CONTENT>) {
|
||||
chop;
|
||||
if ($withclang eq "yes") {
|
||||
# Filter extra output coming from -dM
|
||||
s/^(#[^ ]+ [^ (]+).*$/$1/g;
|
||||
}
|
||||
if (/^#define (.*)/) {
|
||||
newtoken ($1, @allow);
|
||||
} elsif (/^#undef (.*)/) {
|
||||
|
||||
@@ -27,7 +27,9 @@ use Getopt::Long;
|
||||
GetOptions ('header=s' => \$header, 'standard=s' => \$standard,
|
||||
'flags=s' => \$flags, 'cc=s' => \$CC, 'tmpdir=s' => \$tmpdir,
|
||||
'stdsyms=s' => \$stdsyms_file, 'libsyms=s' => \$libsyms_file,
|
||||
'readelf=s' => \$READELF);
|
||||
'readelf=s' => \$READELF, 'withclang=s' => \$withclang);
|
||||
|
||||
$debug = 1;
|
||||
|
||||
# Load the list of symbols that are OK.
|
||||
%stdsyms = ();
|
||||
@@ -162,7 +164,7 @@ foreach my $sym (@sym_data) {
|
||||
# detected by this script if the same namespace issue applies for
|
||||
# static linking.
|
||||
|
||||
@c_syms = list_exported_functions ("$CC $flags", $standard, $header, $tmpdir);
|
||||
@c_syms = list_exported_functions ("$CC $flags", $standard, $header, $tmpdir, $withclang);
|
||||
$cincfile = "$tmpdir/undef-$$.c";
|
||||
$cincfile_o = "$tmpdir/undef-$$.o";
|
||||
$cincfile_sym = "$tmpdir/undef-$$.sym";
|
||||
@@ -177,9 +179,11 @@ system ("$CC $flags -D_ISOMAC $CFLAGS{$standard} -c $cincfile -o $cincfile_o")
|
||||
system ("LC_ALL=C $READELF -W -s $cincfile_o > $cincfile_sym")
|
||||
&& die ("readelf failed\n");
|
||||
@elf_syms = list_syms ($cincfile_sym);
|
||||
unlink ($cincfile) || die ("unlink $cincfile: $!\n");
|
||||
unlink ($cincfile_o) || die ("unlink $cincfile_o: $!\n");
|
||||
unlink ($cincfile_sym) || die ("unlink $cincfile_sym: $!\n");
|
||||
if (!$debug) {
|
||||
unlink ($cincfile) || die ("unlink $cincfile: $!\n");
|
||||
unlink ($cincfile_o) || die ("unlink $cincfile_o: $!\n");
|
||||
unlink ($cincfile_sym) || die ("unlink $cincfile_sym: $!\n");
|
||||
}
|
||||
|
||||
%seen_where = ();
|
||||
%files_seen = ();
|
||||
@@ -207,7 +211,31 @@ while (%current_undef) {
|
||||
$seen_where{$ssym} = "$current_undef{$sym} -> [$file] $ssym";
|
||||
}
|
||||
}
|
||||
# A clang build can leave strong undefined symbols in the file,
|
||||
# instead of GC'ing them; filter them out.
|
||||
foreach my $usym (@{$strong_undef_syms{$file}}) {
|
||||
$alsoseen = 0;
|
||||
foreach my $ssym (@{$seen_syms{$file}}) {
|
||||
if ($ssym eq $usym) {
|
||||
if ($debug) {
|
||||
print "$usym is strong undef also seen in $file, skipping\n";
|
||||
}
|
||||
$alsoseen = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ($alsoseen) {
|
||||
next;
|
||||
}
|
||||
if ($debug) {
|
||||
foreach my $file2 (@{$sym_objs{$sym}}) {
|
||||
foreach my $ssym (@{$seen_syms{$file2}}) {
|
||||
if ($ssym eq $usym) {
|
||||
print " seen in $file2";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!defined ($all_undef{$usym})) {
|
||||
$all_undef{$usym} = "$current_undef{$sym} -> [$file] $usym";
|
||||
$new_undef{$usym} = "$current_undef{$sym} -> [$file] $usym";
|
||||
@@ -220,14 +248,27 @@ while (%current_undef) {
|
||||
|
||||
$ret = 0;
|
||||
foreach my $sym (sort keys %seen_where) {
|
||||
if ($debug) {
|
||||
print "RAW $seen_where{$sym}\n";
|
||||
}
|
||||
if ($sym =~ /^_/) {
|
||||
next;
|
||||
}
|
||||
if (defined ($stdsyms{$sym})) {
|
||||
if ($debug) {
|
||||
print "$sym IS IN stdsyms\n";
|
||||
}
|
||||
next;
|
||||
}
|
||||
if ($debug) {
|
||||
print "FINAL ";
|
||||
}
|
||||
print "$seen_where{$sym}\n";
|
||||
$ret = 1;
|
||||
}
|
||||
|
||||
if ($debug) {
|
||||
print "Return result is $ret\n";
|
||||
}
|
||||
|
||||
exit $ret;
|
||||
|
||||
@@ -24,7 +24,7 @@ use GlibcConform;
|
||||
use Getopt::Long;
|
||||
|
||||
GetOptions ('headers=s' => \$headers, 'standard=s' => \$standard,
|
||||
'flags=s' => \$flags, 'cc=s' => \$CC, 'tmpdir=s' => \$tmpdir);
|
||||
'flags=s' => \$flags, 'cc=s' => \$CC, 'tmpdir=s' => \$tmpdir, 'withclang=s' => \$withclang);
|
||||
@headers = split (/\s+/, $headers);
|
||||
|
||||
# Extra symbols possibly not found through -aux-info but still
|
||||
@@ -67,7 +67,7 @@ $extra_syms{"POSIX2008"} = ["errno", "setjmp", "va_end", "environ",
|
||||
%user_syms = ();
|
||||
|
||||
foreach my $header (@headers) {
|
||||
@syms = list_exported_functions ("$CC $flags", $standard, $header, $tmpdir);
|
||||
@syms = list_exported_functions ("$CC $flags", $standard, $header, $tmpdir, $withclang);
|
||||
foreach my $sym (@syms) {
|
||||
if ($sym !~ /^_/) {
|
||||
$user_syms{$sym} = 1;
|
||||
|
||||
+13
-1
@@ -105,8 +105,20 @@ include ../Rules
|
||||
# Make these in the lib pass so they're available in time to link things with.
|
||||
subdir_lib: $(extra-objs:%=$(objpfx)%)
|
||||
|
||||
ifeq ($(LLVM_OBJCOPY),)
|
||||
OBJCOPY_FOR_ADDRSIG = ${OBJCOPY}
|
||||
else
|
||||
OBJCOPY_FOR_ADDRSIG = ${LLVM_OBJCOPY}
|
||||
endif
|
||||
|
||||
define link-relocatable
|
||||
$(CC) -nostdlib -nostartfiles -r -o $@ $^
|
||||
$(CC) -nostdlib -nostartfiles -r -o $@.precopy $^
|
||||
# Remove a section generated by clang for safe ICF; when lld links and
|
||||
# retains relocs, the section is garbled and causes errors in later
|
||||
# links done with --icf=safe. The removal can be unconditional as it
|
||||
# is a no-op for non-clang/lld.
|
||||
$(OBJCOPY_FOR_ADDRSIG) --remove-section=.llvm_addrsig $@.precopy $@
|
||||
rm $@.precopy
|
||||
endef
|
||||
|
||||
ifndef start-installed-name-rule
|
||||
|
||||
+3
-4
@@ -39,8 +39,7 @@
|
||||
static void
|
||||
check_one_fd (int fd, int mode)
|
||||
{
|
||||
/* Note that fcntl() with this parameter is not a cancellation point. */
|
||||
if (__builtin_expect (__libc_fcntl (fd, F_GETFD), 0) == -1
|
||||
if (__builtin_expect (__fcntl_nocancel (fd, F_GETFD), 0) == -1
|
||||
&& errno == EBADF)
|
||||
{
|
||||
const char *name;
|
||||
@@ -50,12 +49,12 @@ check_one_fd (int fd, int mode)
|
||||
if ((mode & O_ACCMODE) == O_WRONLY)
|
||||
{
|
||||
name = _PATH_DEV "full";
|
||||
dev = makedev (DEV_FULL_MAJOR, DEV_FULL_MINOR);
|
||||
dev = __gnu_dev_makedev (DEV_FULL_MAJOR, DEV_FULL_MINOR);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = _PATH_DEVNULL;
|
||||
dev = makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR);
|
||||
dev = __gnu_dev_makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR);
|
||||
}
|
||||
|
||||
/* Something is wrong with this descriptor, it's probably not
|
||||
|
||||
@@ -45,9 +45,11 @@ tolower (int c)
|
||||
{
|
||||
return c >= -128 && c < 256 ? __ctype_tolower[c] : c;
|
||||
}
|
||||
libc_hidden_def (tolower)
|
||||
|
||||
int
|
||||
toupper (int c)
|
||||
{
|
||||
return c >= -128 && c < 256 ? __ctype_toupper[c] : c;
|
||||
}
|
||||
libc_hidden_def (toupper)
|
||||
|
||||
@@ -11,6 +11,9 @@ libdl {
|
||||
GLIBC_2.3.4 {
|
||||
dlmopen;
|
||||
}
|
||||
GLIBC_2.15 {
|
||||
__google_dlopen_with_offset; __google_dlmopen_with_offset;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
_dlfcn_hook;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <features.h>
|
||||
#define __need_size_t
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Collect various system dependent definitions and declarations. */
|
||||
#include <bits/dlfcn.h>
|
||||
@@ -55,6 +56,11 @@ __BEGIN_DECLS
|
||||
passed to `dlsym' to get symbol values from it. */
|
||||
extern void *dlopen (const char *__file, int __mode) __THROWNL;
|
||||
|
||||
/* Same as above, but ELF header is at OFF from the start of file. */
|
||||
extern void *__google_dlopen_with_offset (__const char *__file,
|
||||
off_t offset,
|
||||
int __mode) __THROW;
|
||||
|
||||
/* Unmap and close a shared object opened by `dlopen'.
|
||||
The handle cannot be used again after calling `dlclose'. */
|
||||
extern int dlclose (void *__handle) __THROWNL __nonnull ((1));
|
||||
@@ -68,6 +74,12 @@ extern void *dlsym (void *__restrict __handle,
|
||||
/* Like `dlopen', but request object to be allocated in a new namespace. */
|
||||
extern void *dlmopen (Lmid_t __nsid, const char *__file, int __mode) __THROWNL;
|
||||
|
||||
/* Same as above, but ELF header is at OFF from the start of file. */
|
||||
extern void *__google_dlmopen_with_offset (Lmid_t __nsid,
|
||||
__const char *__file,
|
||||
off_t offset,
|
||||
int __mode) __THROW;
|
||||
|
||||
/* Find the run-time address in the shared object HANDLE refers to
|
||||
of the symbol called NAME with VERSION. */
|
||||
extern void *dlvsym (void *__restrict __handle,
|
||||
|
||||
+46
-12
@@ -30,7 +30,9 @@ dlmopen (Lmid_t nsid, const char *file, int mode)
|
||||
{
|
||||
return __dlmopen (nsid, file, mode, RETURN_ADDRESS (0));
|
||||
}
|
||||
#if 0 // Google-local
|
||||
static_link_warning (dlmopen)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
@@ -38,6 +40,8 @@ struct dlmopen_args
|
||||
{
|
||||
/* Namespace ID. */
|
||||
Lmid_t nsid;
|
||||
/* ELF header at offset in file. */
|
||||
off_t offset;
|
||||
/* The arguments for dlopen_doit. */
|
||||
const char *file;
|
||||
int mode;
|
||||
@@ -68,13 +72,52 @@ dlmopen_doit (void *a)
|
||||
_dl_signal_error (EINVAL, NULL, NULL, N_("invalid mode"));
|
||||
}
|
||||
|
||||
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->new = GLRO(dl_open) (args->file ?: "", args->offset, args->mode | __RTLD_DLOPEN,
|
||||
args->caller,
|
||||
args->nsid, __dlfcn_argc, __dlfcn_argv,
|
||||
__environ);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
__dlmopen_common (struct dlmopen_args *args)
|
||||
{
|
||||
|
||||
# ifdef SHARED
|
||||
return _dlerror_run (dlmopen_doit, args) ? NULL : args->new;
|
||||
# else
|
||||
if (_dlerror_run (dlmopen_doit, args))
|
||||
return NULL;
|
||||
|
||||
__libc_register_dl_open_hook ((struct link_map *) args->new);
|
||||
__libc_register_dlfcn_hook ((struct link_map *) args->new);
|
||||
|
||||
return args->new;
|
||||
# endif
|
||||
}
|
||||
|
||||
void *
|
||||
__dlmopen_with_offset (Lmid_t nsid, const char *file, off_t offset,
|
||||
int mode DL_CALLER_DECL)
|
||||
{
|
||||
# ifdef SHARED
|
||||
if (!rtld_active ())
|
||||
return _dlfcn_hook->dlmopen_with_offset (nsid, file, offset, mode, RETURN_ADDRESS (0));
|
||||
# endif
|
||||
|
||||
struct dlmopen_args oargs;
|
||||
oargs.nsid = nsid;
|
||||
oargs.file = file;
|
||||
oargs.offset = offset;
|
||||
oargs.mode = mode;
|
||||
oargs.caller = DL_CALLER;
|
||||
|
||||
return __dlmopen_common (&oargs);
|
||||
}
|
||||
# ifdef SHARED
|
||||
strong_alias (__dlmopen_with_offset, __google_dlmopen_with_offset)
|
||||
# endif
|
||||
|
||||
void *
|
||||
__dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL)
|
||||
{
|
||||
@@ -86,20 +129,11 @@ __dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL)
|
||||
struct dlmopen_args args;
|
||||
args.nsid = nsid;
|
||||
args.file = file;
|
||||
args.offset = 0;
|
||||
args.mode = mode;
|
||||
args.caller = DL_CALLER;
|
||||
|
||||
# ifdef SHARED
|
||||
return _dlerror_run (dlmopen_doit, &args) ? NULL : args.new;
|
||||
# else
|
||||
if (_dlerror_run (dlmopen_doit, &args))
|
||||
return NULL;
|
||||
|
||||
__libc_register_dl_open_hook ((struct link_map *) args.new);
|
||||
__libc_register_dlfcn_hook ((struct link_map *) args.new);
|
||||
|
||||
return args.new;
|
||||
# endif
|
||||
return __dlmopen_common (&args);
|
||||
}
|
||||
# ifdef SHARED
|
||||
strong_alias (__dlmopen, dlmopen)
|
||||
|
||||
+41
-12
@@ -29,7 +29,9 @@ dlopen (const char *file, int mode)
|
||||
{
|
||||
return __dlopen (file, mode, RETURN_ADDRESS (0));
|
||||
}
|
||||
#if 0 // Google-local
|
||||
static_link_warning (dlopen)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
@@ -37,6 +39,8 @@ struct dlopen_args
|
||||
{
|
||||
/* The arguments for dlopen_doit. */
|
||||
const char *file;
|
||||
/* ELF header at offset in file. */
|
||||
off_t offset;
|
||||
int mode;
|
||||
/* The return value of dlopen_doit. */
|
||||
void *new;
|
||||
@@ -63,13 +67,47 @@ dlopen_doit (void *a)
|
||||
| __RTLD_SPROF))
|
||||
_dl_signal_error (0, NULL, NULL, _("invalid mode parameter"));
|
||||
|
||||
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->new = GLRO(dl_open) (args->file ?: "", args->offset, args->mode | __RTLD_DLOPEN,
|
||||
args->caller,
|
||||
args->file == NULL ? LM_ID_BASE : NS,
|
||||
__dlfcn_argc, __dlfcn_argv, __environ);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
__dlopen_common (struct dlopen_args *args)
|
||||
{
|
||||
# ifdef SHARED
|
||||
return _dlerror_run (dlopen_doit, args) ? NULL : args->new;
|
||||
# else
|
||||
if (_dlerror_run (dlopen_doit, args))
|
||||
return NULL;
|
||||
|
||||
__libc_register_dl_open_hook ((struct link_map *) args->new);
|
||||
__libc_register_dlfcn_hook ((struct link_map *) args->new);
|
||||
|
||||
return args->new;
|
||||
# endif
|
||||
}
|
||||
|
||||
# ifdef SHARED
|
||||
void *
|
||||
__dlopen_with_offset (const char *file, off_t offset, int mode DL_CALLER_DECL)
|
||||
{
|
||||
if (!rtld_active ())
|
||||
return _dlfcn_hook->dlopen_with_offset (file, offset, mode, DL_CALLER);
|
||||
|
||||
struct dlopen_args oargs;
|
||||
oargs.file = file;
|
||||
oargs.offset = offset;
|
||||
oargs.mode = mode;
|
||||
oargs.caller = DL_CALLER;
|
||||
|
||||
return __dlopen_common (&oargs);
|
||||
}
|
||||
strong_alias (__dlopen_with_offset, __google_dlopen_with_offset)
|
||||
# endif
|
||||
|
||||
void *
|
||||
__dlopen (const char *file, int mode DL_CALLER_DECL)
|
||||
{
|
||||
@@ -80,20 +118,11 @@ __dlopen (const char *file, int mode DL_CALLER_DECL)
|
||||
|
||||
struct dlopen_args args;
|
||||
args.file = file;
|
||||
args.offset = 0;
|
||||
args.mode = mode;
|
||||
args.caller = DL_CALLER;
|
||||
|
||||
# ifdef SHARED
|
||||
return _dlerror_run (dlopen_doit, &args) ? NULL : args.new;
|
||||
# else
|
||||
if (_dlerror_run (dlopen_doit, &args))
|
||||
return NULL;
|
||||
|
||||
__libc_register_dl_open_hook ((struct link_map *) args.new);
|
||||
__libc_register_dlfcn_hook ((struct link_map *) args.new);
|
||||
|
||||
return args.new;
|
||||
# endif
|
||||
return __dlopen_common (&args);
|
||||
}
|
||||
# ifdef SHARED
|
||||
# include <shlib-compat.h>
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ dlopen_doit (void *a)
|
||||
{
|
||||
struct dlopen_args *args = (struct dlopen_args *) a;
|
||||
|
||||
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->new = GLRO(dl_open) (args->file ?: "", 0, args->mode | __RTLD_DLOPEN,
|
||||
args->caller,
|
||||
args->file == NULL ? LM_ID_BASE : NS,
|
||||
__dlfcn_argc, __dlfcn_argv, __environ);
|
||||
|
||||
+136
-9
@@ -62,6 +62,9 @@ rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \
|
||||
dl-error-minimal dl-conflict
|
||||
all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines)
|
||||
|
||||
# Hack around a clang alias+optimization problem.
|
||||
CFLAGS-rtld.c += -O0
|
||||
|
||||
CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables
|
||||
CFLAGS-dl-lookup.c += -fexceptions -fasynchronous-unwind-tables
|
||||
CFLAGS-dl-iterate-phdr.c += $(uses-callbacks)
|
||||
@@ -149,7 +152,7 @@ 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 \
|
||||
tests-static-internal := tst-tls1-static \
|
||||
tst-ptrguard1-static tst-stackguard1-static \
|
||||
tst-tls1-static-non-pie tst-libc_dlvsym-static
|
||||
|
||||
@@ -159,7 +162,7 @@ tst-tls1-static-non-pie-no-pie = yes
|
||||
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-internal := tst-tls1 $(tests-static-internal)
|
||||
tests-static := $(tests-static-normal) $(tests-static-internal)
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
@@ -177,6 +180,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
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-dlopen-offset \
|
||||
tst-dlmopen1 tst-dlmopen3 \
|
||||
unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
|
||||
tst-audit1 tst-audit2 tst-audit8 tst-audit9 \
|
||||
@@ -187,7 +191,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
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 \
|
||||
tst-debug1 tst-main1
|
||||
tst-debug1 tst-main1 tst-big-note
|
||||
# reldep9
|
||||
tests-internal += loadtest unload unload2 circleload1 \
|
||||
neededtest neededtest2 neededtest3 neededtest4 \
|
||||
@@ -200,9 +204,49 @@ endif
|
||||
test-srcs = tst-pathopt
|
||||
selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null)
|
||||
ifneq ($(selinux-enabled),1)
|
||||
ifneq ($(with-clang),yes)
|
||||
tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifeq ($(have-dt-relr),yes)
|
||||
tests += \
|
||||
tst-relr \
|
||||
tst-relr2 \
|
||||
tst-relr3 \
|
||||
tst-relr4 \
|
||||
# tests
|
||||
modules-names-dt-relr = \
|
||||
tst-relr-mod2 \
|
||||
tst-relr-mod3a \
|
||||
tst-relr-mod3b \
|
||||
tst-relr-mod4a \
|
||||
tst-relr-mod4b \
|
||||
# modules-names-dt-relr
|
||||
modules-names += $(modules-names-dt-relr)
|
||||
# These shared libraries have special build rules.
|
||||
modules-names-nobuild += $(modules-names-dt-relr)
|
||||
ifeq ($(have-fpie),yes)
|
||||
tests += \
|
||||
tst-relr-pie \
|
||||
# tests
|
||||
tests-pie += \
|
||||
tst-relr-pie \
|
||||
# tests-pie
|
||||
tests-special += \
|
||||
$(objpfx)check-tst-relr-pie.out \
|
||||
# tests-special
|
||||
endif
|
||||
CFLAGS-tst-relr-pie.c += $(pie-ccflag)
|
||||
LDFLAGS-tst-relr += -Wl,-z,pack-relative-relocs
|
||||
LDFLAGS-tst-relr-pie += -Wl,-z,pack-relative-relocs
|
||||
LDFLAGS-tst-relr2 += -Wl,--allow-shlib-undefined
|
||||
CFLAGS-tst-relr-mod2.c += $(no-stack-protector)
|
||||
CFLAGS-tst-relr-mod3a.c += $(no-stack-protector)
|
||||
CFLAGS-tst-relr-mod3b.c += $(no-stack-protector)
|
||||
CFLAGS-tst-relr-mod4a.c += $(no-stack-protector)
|
||||
CFLAGS-tst-relr-mod4b.c += $(no-stack-protector)
|
||||
endif
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests-special += $(objpfx)tst-leaks1-mem.out \
|
||||
$(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out \
|
||||
@@ -272,7 +316,10 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \
|
||||
tst-latepthreadmod $(tst-tls-many-dynamic-modules) \
|
||||
tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \
|
||||
tst-main1mod tst-libc_dlvsym-dso
|
||||
tst-dlopen-offset-mod1 tst-dlopen-offset-mod2 tst-dlopen-offset-mod3 \
|
||||
tst-main1mod tst-libc_dlvsym-dso \
|
||||
tst-big-note-lib
|
||||
|
||||
ifeq (yes,$(have-mtls-dialect-gnu2))
|
||||
tests += tst-gnu2-tls1
|
||||
modules-names += tst-gnu2-tls1mod
|
||||
@@ -280,6 +327,8 @@ $(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
|
||||
# Somehow configure is failing to notice that lld can't do protected data.
|
||||
ifeq ($(with-lld),no)
|
||||
ifeq (yes,$(have-protected-data))
|
||||
modules-names += tst-protected1moda tst-protected1modb
|
||||
tests += tst-protected1a tst-protected1b
|
||||
@@ -294,6 +343,7 @@ tst-protected1modb.so-no-z-defs = yes
|
||||
test-xfail-tst-protected1a = yes
|
||||
test-xfail-tst-protected1b = yes
|
||||
endif
|
||||
endif # lld
|
||||
ifeq (yesyes,$(have-fpie)$(build-shared))
|
||||
modules-names += tst-piemod1
|
||||
tests += tst-pie1 tst-pie2
|
||||
@@ -304,7 +354,9 @@ tests-pie += vismain
|
||||
CFLAGS-vismain.c += $(PIE-ccflag)
|
||||
endif
|
||||
endif
|
||||
ifneq ($(with-clang),yes)
|
||||
modules-execstack-yes = tst-execstack-mod
|
||||
endif
|
||||
extra-test-objs += $(addsuffix .os,$(strip $(modules-names)))
|
||||
|
||||
# filtmod1.so has a special rule
|
||||
@@ -322,11 +374,15 @@ tests-static += $(tests-ifuncstatic)
|
||||
tests-internal += $(tests-ifuncstatic)
|
||||
ifeq (yes,$(build-shared))
|
||||
tests-internal += \
|
||||
ifuncmain1 ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
|
||||
ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
|
||||
ifuncmain1staticpic \
|
||||
ifuncmain2 ifuncmain2pic ifuncmain3 ifuncmain4 \
|
||||
ifuncmain5 ifuncmain5pic ifuncmain5staticpic \
|
||||
ifuncmain5pic ifuncmain5staticpic \
|
||||
ifuncmain7 ifuncmain7pic
|
||||
ifneq ($(with-clang),yes)
|
||||
# Skip over tests where lld errors with "cannot preempt symbol"
|
||||
tests-internal += ifuncmain1 ifuncmain5
|
||||
endif
|
||||
ifunc-test-modules = ifuncdep1 ifuncdep1pic ifuncdep2 ifuncdep2pic \
|
||||
ifuncdep5 ifuncdep5pic
|
||||
extra-test-objs += $(ifunc-test-modules:=.o)
|
||||
@@ -440,10 +496,13 @@ $(objpfx)librtld.map: $(objpfx)dl-allobjs.os $(common-objpfx)libc_pic.a
|
||||
rm -f $@.o
|
||||
mv -f $@T $@
|
||||
|
||||
# For lld, add to regexp below for optional address and size to be at front of line.
|
||||
# Also, Google b/79865038 reports that make 3.81 can segfault while iterating over
|
||||
# the repeated lib+file entries in the map; work around with sort -u .
|
||||
$(objpfx)librtld.mk: $(objpfx)librtld.map Makefile
|
||||
LC_ALL=C \
|
||||
sed -n 's@^$(common-objpfx)\([^(]*\)(\([^)]*\.os\)) *.*$$@\1 \2@p' \
|
||||
$< | \
|
||||
sed -n 's@^[0-9a-f ]*$(common-objpfx)\([^(]*\)(\([^)]*\.os\)) *.*$$@\1 \2@p' \
|
||||
$< | LC_ALL=C sort -u | \
|
||||
while read lib file; do \
|
||||
case $$lib in \
|
||||
libc_pic.a) \
|
||||
@@ -631,7 +690,7 @@ $(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)unload8mod1.so: $(objpfx)unload8mod2.so $(libdl)
|
||||
$(objpfx)unload8mod2.so: $(objpfx)unload8mod3.so
|
||||
$(objpfx)unload8mod3.so: $(libdl)
|
||||
$(objpfx)tst-initordera2.so: $(objpfx)tst-initordera1.so
|
||||
@@ -1277,6 +1336,11 @@ $(objpfx)tst-unique2.out: $(objpfx)tst-unique2mod2.so
|
||||
$(objpfx)tst-unique3: $(libdl) $(objpfx)tst-unique3lib.so
|
||||
$(objpfx)tst-unique3.out: $(objpfx)tst-unique3lib2.so
|
||||
|
||||
# clang optimization drops seemingly-unused instantiations
|
||||
ifeq ($(with-clang),yes)
|
||||
CFLAGS-tst-unique4lib.cc += -O0
|
||||
endif
|
||||
|
||||
$(objpfx)tst-unique4: $(objpfx)tst-unique4lib.so
|
||||
|
||||
$(objpfx)tst-nodelete: $(libdl)
|
||||
@@ -1446,3 +1510,66 @@ $(objpfx)tst-libc_dlvsym-static: $(common-objpfx)dlfcn/libdl.a
|
||||
tst-libc_dlvsym-static-ENV = \
|
||||
LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn
|
||||
$(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so
|
||||
|
||||
|
||||
$(objpfx)tst-dlopen-offset: $(libdl)
|
||||
$(objpfx)tst-dlopen-offset.out: $(objpfx)tst-dlopen-offset-comb.so
|
||||
$(objpfx)tst-dlopen-offset-comb.so: $(objpfx)tst-dlopen-offset-mod1.so $(objpfx)tst-dlopen-offset-mod2.so $(objpfx)tst-dlopen-offset-mod3.so
|
||||
dd if=$(objpfx)tst-dlopen-offset-mod1.so of=$(objpfx)tst-dlopen-offset-comb.so bs=1024 seek=64
|
||||
dd if=$(objpfx)tst-dlopen-offset-mod2.so of=$(objpfx)tst-dlopen-offset-comb.so bs=1024 seek=128
|
||||
dd if=$(objpfx)tst-dlopen-offset-mod3.so of=$(objpfx)tst-dlopen-offset-comb.so bs=1024 seek=192
|
||||
|
||||
$(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so
|
||||
|
||||
$(objpfx)check-tst-relr-pie.out: $(objpfx)tst-relr-pie
|
||||
LC_ALL=C $(OBJDUMP) -p $< \
|
||||
| sed -ne '/required from libc.so/,$$ p' \
|
||||
| grep GLIBC_ABI_DT_RELR > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
# The test checks if a DT_RELR shared library without DT_NEEDED works as
|
||||
# intended, so it uses an explicit link rule.
|
||||
$(objpfx)tst-relr2: $(objpfx)tst-relr-mod2.so
|
||||
$(objpfx)tst-relr-mod2.so: $(objpfx)tst-relr-mod2.os
|
||||
$(LINK.o) -nostdlib -nostartfiles -Wl,-z,pack-relative-relocs \
|
||||
$(LDFLAGS-soname-fname) \
|
||||
-shared -o $@.new $(filter-out $(map-file),$^)
|
||||
$(call after-link,$@.new)
|
||||
mv -f $@.new $@
|
||||
|
||||
# The test checks if a DT_RELR shared library without DT_VERNEED works as
|
||||
# intended, so it uses an explicit link rule.
|
||||
$(objpfx)tst-relr3: $(objpfx)tst-relr-mod3a.so
|
||||
$(objpfx)tst-relr-mod3b.so: $(objpfx)tst-relr-mod3b.os
|
||||
$(LINK.o) -nostdlib -nostartfiles -Wl,-z,pack-relative-relocs \
|
||||
$(LDFLAGS-soname-fname) \
|
||||
-shared -o $@.new $(filter-out $(map-file),$^)
|
||||
$(call after-link,$@.new)
|
||||
mv -f $@.new $@
|
||||
|
||||
$(objpfx)tst-relr-mod3a.so: $(objpfx)tst-relr-mod3a.os \
|
||||
$(objpfx)tst-relr-mod3b.so
|
||||
$(LINK.o) -nostdlib -nostartfiles -Wl,-z,pack-relative-relocs \
|
||||
$(LDFLAGS-soname-fname) \
|
||||
-shared -o $@.new $(filter-out $(map-file),$^)
|
||||
$(call after-link,$@.new)
|
||||
mv -f $@.new $@
|
||||
|
||||
# The test checks if a DT_RELR shared library without libc.so on DT_NEEDED
|
||||
# works as intended, so it uses an explicit link rule.
|
||||
$(objpfx)tst-relr4: $(objpfx)tst-relr-mod4a.so
|
||||
$(objpfx)tst-relr-mod4b.so: $(objpfx)tst-relr-mod4b.os
|
||||
$(LINK.o) -nostdlib -nostartfiles -Wl,-z,pack-relative-relocs \
|
||||
$(LDFLAGS-soname-fname) \
|
||||
-Wl,--version-script=tst-relr-mod4b.map \
|
||||
-shared -o $@.new $(filter-out $(map-file),$^)
|
||||
$(call after-link,$@.new)
|
||||
mv -f $@.new $@
|
||||
|
||||
$(objpfx)tst-relr-mod4a.so: $(objpfx)tst-relr-mod4a.os \
|
||||
$(objpfx)tst-relr-mod4b.so
|
||||
$(LINK.o) -nostdlib -nostartfiles -Wl,-z,pack-relative-relocs \
|
||||
$(LDFLAGS-soname-fname) \
|
||||
-shared -o $@.new $(filter-out $(map-file),$^)
|
||||
$(call after-link,$@.new)
|
||||
mv -f $@.new $@
|
||||
|
||||
@@ -20,6 +20,11 @@ libc {
|
||||
__register_frame_info_table_bases; _Unwind_Find_FDE;
|
||||
}
|
||||
%endif
|
||||
GLIBC_ABI_DT_RELR {
|
||||
# This symbol is used only for empty version map and will be removed
|
||||
# by scripts/versions.awk.
|
||||
__placeholder_only_for_empty_version_map;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
# functions used in other libraries
|
||||
_dl_addr;
|
||||
@@ -61,6 +66,7 @@ ld {
|
||||
_dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info;
|
||||
_dl_deallocate_tls; _dl_make_stack_executable;
|
||||
_dl_rtld_di_serinfo; _dl_starting_up;
|
||||
_dl_clear_dtv;
|
||||
_rtld_global; _rtld_global_ro;
|
||||
|
||||
# Only here for gdb while a better method is developed.
|
||||
@@ -78,5 +84,7 @@ ld {
|
||||
|
||||
# Set value of a tunable.
|
||||
__tunable_get_val;
|
||||
|
||||
_google_dl_debug_state_hook;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +135,12 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
Lmid_t nsid = map->l_ns;
|
||||
struct link_namespaces *ns = &GL(dl_ns)[nsid];
|
||||
|
||||
/* Recompute _ns_last next time we need it.
|
||||
It is tempting to set _ns_last to map->l_prev, but map->l_prev might also
|
||||
be going away as part of current dlclose, and using it may cause _ns_last
|
||||
to become dangling. */
|
||||
ns->_ns_last = NULL;
|
||||
|
||||
retry:
|
||||
dl_close_state = pending;
|
||||
|
||||
@@ -717,6 +723,9 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
_dl_debug_printf ("\nfile=%s [%lu]; destroying link map\n",
|
||||
imap->l_name, imap->l_ns);
|
||||
|
||||
/* Remove from hashtables. */
|
||||
_dl_hash_del_object (imap);
|
||||
|
||||
/* This name always is allocated. */
|
||||
free (imap->l_name);
|
||||
/* Remove the list with all the names of the shared object. */
|
||||
|
||||
+42
-11
@@ -27,17 +27,8 @@
|
||||
#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));
|
||||
#ifndef NESTING
|
||||
|
||||
{
|
||||
/* 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)
|
||||
@@ -51,13 +42,49 @@ _dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict,
|
||||
(map) = resolve_conflict_map; \
|
||||
} while (0)
|
||||
|
||||
#include "dynamic-link.h"
|
||||
|
||||
#endif /* n NESTING */
|
||||
|
||||
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. */
|
||||
|
||||
#ifdef NESTING
|
||||
|
||||
/* 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)
|
||||
|
||||
#endif /* NESTING */
|
||||
|
||||
/* 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;
|
||||
|
||||
#ifdef NESTING
|
||||
|
||||
#include "dynamic-link.h"
|
||||
|
||||
#endif /* NESTING */
|
||||
|
||||
/* Override these, defined in dynamic-link.h. */
|
||||
#undef CHECK_STATIC_TLS
|
||||
#define CHECK_STATIC_TLS(ref_map, sym_map) ((void) 0)
|
||||
@@ -68,7 +95,11 @@ _dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict,
|
||||
|
||||
for (; conflict < conflictend; ++conflict)
|
||||
elf_machine_rela (l, conflict, NULL, NULL, (void *) conflict->r_offset,
|
||||
0);
|
||||
0
|
||||
#ifndef NESTING
|
||||
, NULL
|
||||
#endif
|
||||
);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -64,6 +64,8 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||
}
|
||||
|
||||
|
||||
void (*_google_dl_debug_state_hook)(const struct r_debug *);
|
||||
|
||||
/* 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
|
||||
@@ -71,5 +73,7 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||
void
|
||||
_dl_debug_state (void)
|
||||
{
|
||||
if (_google_dl_debug_state_hook)
|
||||
_google_dl_debug_state_hook(&_r_debug);
|
||||
}
|
||||
rtld_hidden_def (_dl_debug_state)
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ openaux (void *a)
|
||||
{
|
||||
struct openaux_args *args = (struct openaux_args *) a;
|
||||
|
||||
args->aux = _dl_map_object (args->map, args->name,
|
||||
args->aux = _dl_map_object (args->map, args->name, 0,
|
||||
(args->map->l_type == lt_executable
|
||||
? lt_library : args->map->l_type),
|
||||
args->trace_mode, args->open_mode,
|
||||
|
||||
+7
-2
@@ -65,8 +65,13 @@
|
||||
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)); \
|
||||
\
|
||||
const char *exec_origin = GLRO(google_exec_origin_dir); \
|
||||
size_t exec_origin_len = \
|
||||
(exec_origin == NULL) ? 0 : strlen (exec_origin); \
|
||||
\
|
||||
dst_len = MAX (MAX (MAX (dst_len, GLRO(dl_platformlen)), \
|
||||
strlen (DL_DST_LIB)), exec_origin_len); \
|
||||
if (dst_len > 4) \
|
||||
__len += __cnt * (dst_len - 4); \
|
||||
} \
|
||||
|
||||
@@ -85,6 +85,21 @@ fatal_error (int errcode, const char *objname, const char *occasion,
|
||||
: ""));
|
||||
}
|
||||
|
||||
/* Due to a complicated set of interactions with different symbol
|
||||
versions, presumably including a VMX-specific __vmx__longjmp, PPC
|
||||
clang ends calling __longjump with ld.so through the global entry
|
||||
point (+0x0) instead of via the local entry point (+0x8) which
|
||||
results in ld.so exceptions crashing because the TOC is not set up.
|
||||
The hack here simply calls the function through a pointer, which
|
||||
guarantees that the global entry point has the TOC set up. (This
|
||||
may or may not be a clang bug, the symbol aliasing is tricky and
|
||||
literally affects only __longjmp out of all the symbols in
|
||||
libc.) */
|
||||
#if defined __clang__ && defined __powerpc64__
|
||||
volatile void (*longjmpptr) (struct __jmp_buf_tag __env[1], int __val)
|
||||
__attribute__ ((__nothrow__)) __attribute__ ((__noreturn__)) = __longjmp;
|
||||
#endif
|
||||
|
||||
void
|
||||
_dl_signal_exception (int errcode, struct dl_exception *exception,
|
||||
const char *occasion)
|
||||
@@ -96,7 +111,11 @@ _dl_signal_exception (int errcode, struct dl_exception *exception,
|
||||
*lcatch->errcode = errcode;
|
||||
|
||||
/* We do not restore the signal mask because none was saved. */
|
||||
#if defined __clang__ && defined __powerpc64__
|
||||
(*longjmpptr) (lcatch->env[0].__jmpbuf, 1);
|
||||
#else
|
||||
__longjmp (lcatch->env[0].__jmpbuf, 1);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
fatal_error (errcode, exception->objname, occasion, exception->errstring);
|
||||
@@ -118,7 +137,11 @@ _dl_signal_error (int errcode, const char *objname, const char *occation,
|
||||
*lcatch->errcode = errcode;
|
||||
|
||||
/* We do not restore the signal mask because none was saved. */
|
||||
#if defined __clang__ && defined __powerpc64__
|
||||
(*longjmpptr) (lcatch->env[0].__jmpbuf, 1);
|
||||
#else
|
||||
__longjmp (lcatch->env[0].__jmpbuf, 1);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
fatal_error (errcode, objname, occation, errstring);
|
||||
|
||||
+3
-1
@@ -59,6 +59,7 @@ struct do_dlopen_args
|
||||
{
|
||||
/* Argument to do_dlopen. */
|
||||
const char *name;
|
||||
off_t offset;
|
||||
/* Opening mode. */
|
||||
int mode;
|
||||
/* This is the caller of the dlopen() function. */
|
||||
@@ -93,7 +94,7 @@ 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,
|
||||
args->map = GLRO(dl_open) (args->name, args->offset, args->mode, args->caller_dlopen,
|
||||
__LM_ID_CALLER, __libc_argc, __libc_argv,
|
||||
__environ);
|
||||
}
|
||||
@@ -186,6 +187,7 @@ __libc_dlopen_mode (const char *name, int mode)
|
||||
{
|
||||
struct do_dlopen_args args;
|
||||
args.name = name;
|
||||
args.offset = 0;
|
||||
args.mode = mode;
|
||||
args.caller_dlopen = RETURN_ADDRESS (0);
|
||||
|
||||
|
||||
+305
-77
@@ -46,6 +46,9 @@
|
||||
#include <dl-machine-reject-phdr.h>
|
||||
#include <dl-sysdep-open.h>
|
||||
|
||||
/* Code below to add offset to symbol names references itoa. */
|
||||
#include <_itoa.h>
|
||||
#include <not-cancel.h>
|
||||
|
||||
#include <endian.h>
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
@@ -232,7 +235,8 @@ _dl_dst_count (const char *name)
|
||||
++name;
|
||||
if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0
|
||||
|| (len = is_dst (start, name, "PLATFORM", 0)) != 0
|
||||
|| (len = is_dst (start, name, "LIB", 0)) != 0)
|
||||
|| (len = is_dst (start, name, "LIB", 0)) != 0
|
||||
|| (len = is_dst (start, name, "EXEC_ORIGIN", 0)) != 0)
|
||||
++cnt;
|
||||
|
||||
name = strchr (name + len, '$');
|
||||
@@ -274,6 +278,13 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result)
|
||||
repl = GLRO(dl_platform);
|
||||
else if ((len = is_dst (start, name, "LIB", 0)) != 0)
|
||||
repl = DL_DST_LIB;
|
||||
else if ((len = is_dst (start, name, "EXEC_ORIGIN", 0)) != 0)
|
||||
{
|
||||
if (__libc_enable_secure)
|
||||
_dl_fatal_printf ("$EXEC_ORIGIN rpath entry not allowed in setuid/setgid executables.\n");
|
||||
|
||||
repl = GLRO(google_exec_origin_dir);
|
||||
}
|
||||
|
||||
if (repl != NULL && repl != (const char *) -1)
|
||||
{
|
||||
@@ -347,8 +358,7 @@ expand_dynamic_string_token (struct link_map *l, const char *s)
|
||||
|
||||
/* 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. */
|
||||
be freed if the shared object already has this name. */
|
||||
static void
|
||||
add_name_to_object (struct link_map *l, const char *name)
|
||||
{
|
||||
@@ -777,7 +787,7 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
|
||||
{
|
||||
/* The file might already be closed. */
|
||||
if (fd != -1)
|
||||
(void) __close (fd);
|
||||
(void) __close_nocancel (fd);
|
||||
if (l != NULL && l->l_origin != (char *) -1l)
|
||||
free ((char *) l->l_origin);
|
||||
free (l);
|
||||
@@ -794,6 +804,177 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
|
||||
}
|
||||
|
||||
|
||||
/* Hash tables of loaded objects; one keyed on name, one keyed on inode. */
|
||||
|
||||
struct lib_hash_namenode
|
||||
{
|
||||
const char *name;
|
||||
struct link_map *lib;
|
||||
struct lib_hash_namenode *next;
|
||||
uint32_t hash;
|
||||
};
|
||||
|
||||
struct lib_hash_filenode
|
||||
{
|
||||
struct link_map *lib;
|
||||
struct lib_hash_filenode *next;
|
||||
uint32_t hash;
|
||||
};
|
||||
|
||||
/* Must be a power of 2. */
|
||||
#define LIB_HASH_BUCKETS 256
|
||||
|
||||
static struct lib_hash_namenode *lib_hash_nametable[LIB_HASH_BUCKETS];
|
||||
static struct lib_hash_filenode *lib_hash_filetable[LIB_HASH_BUCKETS];
|
||||
|
||||
static size_t
|
||||
lib_hash_bucket (uint32_t hash)
|
||||
{
|
||||
return hash & (LIB_HASH_BUCKETS-1);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
hash_mix (uint32_t h, size_t val)
|
||||
{
|
||||
h ^= val;
|
||||
h *= 0x5bd1e995;
|
||||
h ^= h >> 15;
|
||||
val >>= 4 * sizeof val;
|
||||
h ^= val;
|
||||
h *= 0x5bd1e995;
|
||||
h ^= h >> 15;
|
||||
return h;
|
||||
}
|
||||
|
||||
static struct link_map *
|
||||
lib_hash_getname (Lmid_t nsid, const char *name)
|
||||
{
|
||||
uint32_t hash = hash_mix (dl_new_hash (name), nsid);
|
||||
struct lib_hash_namenode *n = lib_hash_nametable[lib_hash_bucket (hash)];
|
||||
while (n)
|
||||
{
|
||||
struct link_map *l = n->lib;
|
||||
if (n->hash == hash && !strcmp (n->name, name) && l->l_ns == nsid && !l->l_removed)
|
||||
return l;
|
||||
n = n->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
lib_hash_addname (const char *name, struct link_map *lib)
|
||||
{
|
||||
if (lib->l_faked)
|
||||
return;
|
||||
struct lib_hash_namenode *n = malloc (sizeof (struct lib_hash_namenode));
|
||||
if (!n)
|
||||
_dl_fatal_printf ("%s: out of memory\n", __func__);
|
||||
uint32_t hash = hash_mix (dl_new_hash (name), lib->l_ns);
|
||||
struct lib_hash_namenode **p = lib_hash_nametable + lib_hash_bucket (hash);
|
||||
n->name = name;
|
||||
n->lib = lib;
|
||||
n->next = *p;
|
||||
n->hash = hash;
|
||||
*p = n;
|
||||
}
|
||||
|
||||
/* 'name' must be the exact pointer originally passed to lib_hash_addname(). */
|
||||
static void
|
||||
lib_hash_delname (const char *name, struct link_map *lib)
|
||||
{
|
||||
uint32_t hash = hash_mix (dl_new_hash (name), lib->l_ns);
|
||||
struct lib_hash_namenode **p = lib_hash_nametable + lib_hash_bucket (hash);
|
||||
while (*p)
|
||||
{
|
||||
struct lib_hash_namenode *n = *p;
|
||||
if (n->hash == hash && n->lib == lib && n->name == name) {
|
||||
*p = n->next;
|
||||
free (n);
|
||||
return;
|
||||
}
|
||||
p = &n->next;
|
||||
}
|
||||
_dl_fatal_printf ("%s: can't unhash '%s'\n", __func__, name);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
hash_file (Lmid_t nsid, dev_t dev, ino64_t ino, off_t off)
|
||||
{
|
||||
return hash_mix (hash_mix (hash_mix (hash_mix (0, nsid), dev), ino), off);
|
||||
}
|
||||
|
||||
static struct link_map *
|
||||
lib_hash_getfile (Lmid_t nsid, dev_t dev, ino64_t ino, off_t off)
|
||||
{
|
||||
uint32_t hash = hash_file (nsid, dev, ino, off);
|
||||
struct lib_hash_filenode *n = lib_hash_filetable[lib_hash_bucket (hash)];
|
||||
while (n)
|
||||
{
|
||||
struct link_map *l = n->lib;
|
||||
if (n->hash == hash && !l->l_removed && l->l_ns == nsid &&
|
||||
l->l_file_id.dev == dev && l->l_file_id.ino == ino && l->l_off == off)
|
||||
return l;
|
||||
n = n->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
lib_hash_addfile (struct link_map *lib)
|
||||
{
|
||||
if (lib->l_faked)
|
||||
return;
|
||||
struct lib_hash_filenode *n = malloc (sizeof (struct lib_hash_filenode));
|
||||
if (!n)
|
||||
_dl_fatal_printf ("%s: out of memory\n", __func__);
|
||||
uint32_t hash = hash_file (lib->l_ns, lib->l_file_id.dev, lib->l_file_id.ino, lib->l_off);
|
||||
struct lib_hash_filenode **p = lib_hash_filetable + lib_hash_bucket (hash);
|
||||
n->lib = lib;
|
||||
n->next = *p;
|
||||
n->hash = hash;
|
||||
*p = n;
|
||||
}
|
||||
|
||||
static void
|
||||
lib_hash_delfile (struct link_map *lib)
|
||||
{
|
||||
uint32_t hash = hash_file (lib->l_ns, lib->l_file_id.dev, lib->l_file_id.ino, lib->l_off);
|
||||
struct lib_hash_filenode **p = lib_hash_filetable + lib_hash_bucket (hash);
|
||||
while (*p)
|
||||
{
|
||||
struct lib_hash_filenode *n = *p;
|
||||
if (n->hash == hash && n->lib == lib)
|
||||
{
|
||||
*p = n->next;
|
||||
free (n);
|
||||
return;
|
||||
}
|
||||
p = &n->next;
|
||||
}
|
||||
_dl_fatal_printf ("%s: can't unhash '%s'\n", __func__, lib->l_name);
|
||||
}
|
||||
|
||||
void
|
||||
_dl_hash_add_object (struct link_map *lib)
|
||||
{
|
||||
lib_hash_addfile (lib);
|
||||
lib_hash_addname (lib->l_name, lib);
|
||||
for (struct libname_list *ln = lib->l_libname; ln; ln = ln->next)
|
||||
{
|
||||
lib_hash_addname (ln->name, lib);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_dl_hash_del_object (struct link_map *lib)
|
||||
{
|
||||
lib_hash_delfile (lib);
|
||||
lib_hash_delname (lib->l_name, lib);
|
||||
for (struct libname_list *ln = lib->l_libname; ln; ln = ln->next) {
|
||||
lib_hash_delname (ln->name, lib);
|
||||
}
|
||||
}
|
||||
|
||||
/* Map in the shared object NAME, actually located in REALNAME, and already
|
||||
opened on FD. */
|
||||
|
||||
@@ -801,7 +982,7 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
|
||||
static
|
||||
#endif
|
||||
struct link_map *
|
||||
_dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
_dl_map_object_from_fd (const char *name, const char *origname, int fd, off_t offset,
|
||||
struct filebuf *fbp, char *realname,
|
||||
struct link_map *loader, int l_type, int mode,
|
||||
void **stack_endp, Lmid_t nsid)
|
||||
@@ -831,24 +1012,25 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
}
|
||||
|
||||
/* 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);
|
||||
l = lib_hash_getfile (nsid, id.dev, id.ino, offset);
|
||||
if (l)
|
||||
{
|
||||
/* The object is already loaded.
|
||||
Just bump its reference count and return it. */
|
||||
__close_nocancel (fd);
|
||||
|
||||
/* If the name is not in the list of names for this object add
|
||||
it. */
|
||||
free (realname);
|
||||
add_name_to_object (l, name);
|
||||
free (realname);
|
||||
|
||||
return l;
|
||||
}
|
||||
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. */
|
||||
|
||||
/* Note that this test is wrong in two ways:
|
||||
1) it doesn't consider offset, and
|
||||
2) l_file_id.ino and l_file_id.dev for rtld are always zero! */
|
||||
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))))
|
||||
@@ -864,7 +1046,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
|
||||
/* No need to bump the refcount of the real object, ld.so will
|
||||
never be unloaded. */
|
||||
__close (fd);
|
||||
__close_nocancel (fd);
|
||||
|
||||
/* Add the map for the mirrored object to the object list. */
|
||||
_dl_add_to_namespace_list (l, nsid);
|
||||
@@ -878,7 +1060,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
/* We are not supposed to load the object unless it is already
|
||||
loaded. So return now. */
|
||||
free (realname);
|
||||
__close (fd);
|
||||
__close_nocancel (fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -897,7 +1079,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
if (_dl_zerofd == -1)
|
||||
{
|
||||
free (realname);
|
||||
__close (fd);
|
||||
__close_nocancel (fd);
|
||||
_dl_signal_error (errno, NULL, NULL,
|
||||
N_("cannot open zero fill device"));
|
||||
}
|
||||
@@ -939,8 +1121,29 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
else
|
||||
assert (r->r_state == RT_ADD);
|
||||
|
||||
#ifdef SHARED
|
||||
// This code could be linked into 'sln', which does not have _itoa.
|
||||
// We only care about this when this is linked into ld-linux.
|
||||
if (offset != 0)
|
||||
{
|
||||
/* Google-specific: to help GDB, and for b/18243822, turn realname
|
||||
into "realname/@0x<offset>" */
|
||||
realname = realloc (realname, strlen(realname) + 16 + 4 /* "/@0x" */);
|
||||
if (realname == NULL)
|
||||
{
|
||||
errstring = N_("unable to realloc");
|
||||
goto call_lose_errno;
|
||||
}
|
||||
strcat(realname, "/@0x");
|
||||
|
||||
char tmp[20];
|
||||
tmp[19] = '\0';
|
||||
strcat(realname, _itoa(offset, &tmp[19], 16, 0));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enter the new object in the list of loaded objects. */
|
||||
l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
|
||||
l = _dl_new_object (realname, (offset ? realname : name), l_type, loader, mode, nsid);
|
||||
if (__glibc_unlikely (l == NULL))
|
||||
{
|
||||
#ifdef SHARED
|
||||
@@ -963,7 +1166,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
{
|
||||
phdr = alloca (maplength);
|
||||
__lseek (fd, header->e_phoff, SEEK_SET);
|
||||
if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength)
|
||||
if ((size_t) __read_nocancel (fd, (void *) phdr, maplength) != maplength)
|
||||
{
|
||||
errstring = N_("cannot read file data");
|
||||
goto call_lose_errno;
|
||||
@@ -1027,7 +1230,12 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
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));
|
||||
if (offset & (GLRO(dl_pagesize) - 1))
|
||||
{
|
||||
errstring = N_("invalid offset");
|
||||
goto call_lose;
|
||||
}
|
||||
c->mapoff = ALIGN_DOWN(offset + ph->p_offset, GLRO(dl_pagesize));
|
||||
|
||||
/* Determine whether there is a gap between the last segment
|
||||
and this one. */
|
||||
@@ -1239,7 +1447,7 @@ cannot enable executable stack as shared object requires");
|
||||
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))
|
||||
if (__glibc_unlikely (__close_nocancel (fd) != 0))
|
||||
{
|
||||
errstring = N_("cannot close file descriptor");
|
||||
goto call_lose_errno;
|
||||
@@ -1307,10 +1515,9 @@ cannot enable executable stack as shared object requires");
|
||||
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)
|
||||
l->l_off = offset;
|
||||
|
||||
if (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));
|
||||
|
||||
@@ -1392,7 +1599,7 @@ print_search_path (struct r_search_path_elem **list,
|
||||
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,
|
||||
open_verify (const char *name, int fd, off_t offset,
|
||||
struct filebuf *fbp, struct link_map *loader,
|
||||
int whatcode, int mode, bool *found_other_class, bool free_name)
|
||||
{
|
||||
@@ -1454,7 +1661,7 @@ open_verify (const char *name, int fd,
|
||||
{
|
||||
/* An audit library changed what we're supposed to open,
|
||||
so FD no longer matches it. */
|
||||
__close (fd);
|
||||
__close_nocancel (fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
@@ -1462,16 +1669,20 @@ open_verify (const char *name, int fd,
|
||||
|
||||
if (fd == -1)
|
||||
/* Open the file. We always open files read-only. */
|
||||
fd = __open (name, O_RDONLY | O_CLOEXEC);
|
||||
fd = __open64_nocancel (name, O_RDONLY | O_CLOEXEC);
|
||||
|
||||
if (fd != -1)
|
||||
{
|
||||
ElfW(Ehdr) *ehdr;
|
||||
ElfW(Phdr) *phdr, *ph;
|
||||
ElfW(Word) *abi_note;
|
||||
ElfW(Word) *abi_note_malloced = NULL;
|
||||
unsigned int osversion;
|
||||
size_t maplength;
|
||||
|
||||
if (__lseek (fd, offset, SEEK_SET) == -1)
|
||||
goto close_and_out;
|
||||
|
||||
/* We successfully opened the file. Now verify it is a file
|
||||
we can use. */
|
||||
__set_errno (0);
|
||||
@@ -1480,8 +1691,8 @@ open_verify (const char *name, int fd,
|
||||
/* Read in the header. */
|
||||
do
|
||||
{
|
||||
ssize_t retlen = __libc_read (fd, fbp->buf + fbp->len,
|
||||
sizeof (fbp->buf) - fbp->len);
|
||||
ssize_t retlen = __read_nocancel (fd, fbp->buf + fbp->len,
|
||||
sizeof (fbp->buf) - fbp->len);
|
||||
if (retlen <= 0)
|
||||
break;
|
||||
fbp->len += retlen;
|
||||
@@ -1604,7 +1815,8 @@ open_verify (const char *name, int fd,
|
||||
{
|
||||
phdr = alloca (maplength);
|
||||
__lseek (fd, ehdr->e_phoff, SEEK_SET);
|
||||
if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength)
|
||||
if ((size_t) __read_nocancel (fd, (void *) phdr, maplength)
|
||||
!= maplength)
|
||||
{
|
||||
read_error:
|
||||
errval = errno;
|
||||
@@ -1640,10 +1852,25 @@ open_verify (const char *name, int fd,
|
||||
abi_note = (void *) (fbp->buf + ph->p_offset);
|
||||
else
|
||||
{
|
||||
abi_note = alloca (size);
|
||||
/* Note: __libc_use_alloca is not usable here, because
|
||||
thread info may not have been set up yet. */
|
||||
if (size < __MAX_ALLOCA_CUTOFF)
|
||||
abi_note = alloca (size);
|
||||
else
|
||||
{
|
||||
/* There could be multiple PT_NOTEs. */
|
||||
abi_note_malloced = realloc (abi_note_malloced, size);
|
||||
if (abi_note_malloced == NULL)
|
||||
goto read_error;
|
||||
|
||||
abi_note = abi_note_malloced;
|
||||
}
|
||||
__lseek (fd, ph->p_offset, SEEK_SET);
|
||||
if (__libc_read (fd, (void *) abi_note, size) != size)
|
||||
goto read_error;
|
||||
if (__read_nocancel (fd, (void *) abi_note, size) != size)
|
||||
{
|
||||
free (abi_note_malloced);
|
||||
goto read_error;
|
||||
}
|
||||
}
|
||||
|
||||
while (memcmp (abi_note, &expected_note, sizeof (expected_note)))
|
||||
@@ -1671,13 +1898,14 @@ open_verify (const char *name, int fd,
|
||||
|| (GLRO(dl_osversion) && GLRO(dl_osversion) < osversion))
|
||||
{
|
||||
close_and_out:
|
||||
__close (fd);
|
||||
__close_nocancel (fd);
|
||||
__set_errno (ENOENT);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
free (abi_note_malloced);
|
||||
}
|
||||
|
||||
return fd;
|
||||
@@ -1691,7 +1919,7 @@ open_verify (const char *name, int fd,
|
||||
if MAY_FREE_DIRS is true. */
|
||||
|
||||
static int
|
||||
open_path (const char *name, size_t namelen, int mode,
|
||||
open_path (const char *name, size_t namelen, off_t offset, int mode,
|
||||
struct r_search_path_struct *sps, char **realname,
|
||||
struct filebuf *fbp, struct link_map *loader, int whatcode,
|
||||
bool *found_other_class)
|
||||
@@ -1743,7 +1971,7 @@ open_path (const char *name, size_t namelen, int mode,
|
||||
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,
|
||||
fd = open_verify (buf, -1, offset, fbp, loader, whatcode, mode,
|
||||
found_other_class, false);
|
||||
if (this_dir->status[cnt] == unknown)
|
||||
{
|
||||
@@ -1787,7 +2015,7 @@ open_path (const char *name, size_t namelen, int mode,
|
||||
/* 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);
|
||||
__close_nocancel (fd);
|
||||
fd = -1;
|
||||
/* We simply ignore the file, signal this by setting
|
||||
the error value which would have been set by `open'. */
|
||||
@@ -1808,7 +2036,7 @@ open_path (const char *name, size_t namelen, int mode,
|
||||
{
|
||||
/* No memory for the name, we certainly won't be able
|
||||
to load and link it. */
|
||||
__close (fd);
|
||||
__close_nocancel (fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -1838,10 +2066,22 @@ open_path (const char *name, size_t namelen, int mode,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
match_one (const char *name, struct link_map *l)
|
||||
{
|
||||
/* 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 (__builtin_expect (l->l_faked, 0) != 0
|
||||
|| __builtin_expect (l->l_removed, 0) != 0)
|
||||
return 0;
|
||||
return _dl_name_match_p (name, l);
|
||||
}
|
||||
|
||||
/* Map in the shared object file NAME. */
|
||||
|
||||
struct link_map *
|
||||
_dl_map_object (struct link_map *loader, const char *name,
|
||||
_dl_map_object (struct link_map *loader, const char *name, off_t offset,
|
||||
int type, int trace_mode, int mode, Lmid_t nsid)
|
||||
{
|
||||
int fd;
|
||||
@@ -1855,33 +2095,21 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
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 (name[0] == '\0')
|
||||
{
|
||||
/* 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;
|
||||
/* Special case: both main exe and vdso can have empty name;
|
||||
so search from head: it is important to return the map for main
|
||||
a.out; else dlsym(0, ...) will fail unexpectedly. */
|
||||
|
||||
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;
|
||||
for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
|
||||
if (match_one (name, l))
|
||||
return l;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = lib_hash_getname(nsid, name);
|
||||
if (l)
|
||||
return l;
|
||||
}
|
||||
|
||||
/* Display information if we are debugging. */
|
||||
@@ -1956,7 +2184,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
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,
|
||||
fd = open_path (name, namelen, offset, mode,
|
||||
&l->l_rpath_dirs,
|
||||
&realname, &fb, loader, LA_SER_RUNPATH,
|
||||
&found_other_class);
|
||||
@@ -1972,7 +2200,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
&& 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,
|
||||
fd = open_path (name, namelen, offset, mode,
|
||||
&main_map->l_rpath_dirs,
|
||||
&realname, &fb, loader ?: main_map, LA_SER_RUNPATH,
|
||||
&found_other_class);
|
||||
@@ -1980,7 +2208,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
|
||||
/* 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,
|
||||
fd = open_path (name, namelen, offset, mode, &env_path_list,
|
||||
&realname, &fb,
|
||||
loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
|
||||
LA_SER_LIBPATH, &found_other_class);
|
||||
@@ -1989,7 +2217,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
if (fd == -1 && loader != NULL
|
||||
&& cache_rpath (loader, &loader->l_runpath_dirs,
|
||||
DT_RUNPATH, "RUNPATH"))
|
||||
fd = open_path (name, namelen, mode,
|
||||
fd = open_path (name, namelen, offset, mode,
|
||||
&loader->l_runpath_dirs, &realname, &fb, loader,
|
||||
LA_SER_RUNPATH, &found_other_class);
|
||||
|
||||
@@ -1998,7 +2226,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
realname = _dl_sysdep_open_object (name, namelen, &fd);
|
||||
if (realname != NULL)
|
||||
{
|
||||
fd = open_verify (realname, fd,
|
||||
fd = open_verify (realname, fd, offset,
|
||||
&fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
|
||||
LA_SER_CONFIG, mode, &found_other_class,
|
||||
false);
|
||||
@@ -2052,7 +2280,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
|
||||
if (cached != NULL)
|
||||
{
|
||||
fd = open_verify (cached, -1,
|
||||
fd = open_verify (cached, -1, 0,
|
||||
&fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
|
||||
LA_SER_CONFIG, mode, &found_other_class,
|
||||
false);
|
||||
@@ -2070,7 +2298,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
&& ((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,
|
||||
fd = open_path (name, namelen, offset, mode, &rtld_search_dirs,
|
||||
&realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
|
||||
|
||||
/* Add another newline when we are tracing the library loading. */
|
||||
@@ -2087,7 +2315,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
fd = -1;
|
||||
else
|
||||
{
|
||||
fd = open_verify (realname, -1, &fb,
|
||||
fd = open_verify (realname, -1, offset, &fb,
|
||||
loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, mode,
|
||||
&found_other_class, true);
|
||||
if (__glibc_unlikely (fd == -1))
|
||||
@@ -2149,7 +2377,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
}
|
||||
|
||||
void *stack_end = __libc_stack_end;
|
||||
return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader,
|
||||
return _dl_map_object_from_fd (name, origname, fd, offset, &fb, realname, loader,
|
||||
type, mode, &stack_end, nsid);
|
||||
}
|
||||
|
||||
|
||||
+352
-10
@@ -25,6 +25,7 @@
|
||||
#include <dl-hash.h>
|
||||
#include <dl-machine.h>
|
||||
#include <sysdep-cancel.h>
|
||||
#include <hp-timing.h>
|
||||
#include <libc-lock.h>
|
||||
#include <tls.h>
|
||||
#include <atomic.h>
|
||||
@@ -39,6 +40,11 @@
|
||||
|
||||
#define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
|
||||
|
||||
#ifndef ADDRIDX
|
||||
# define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
|
||||
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag))
|
||||
#endif
|
||||
|
||||
|
||||
struct sym_val
|
||||
{
|
||||
@@ -325,6 +331,326 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
|
||||
result->m = (struct link_map *) map;
|
||||
}
|
||||
|
||||
|
||||
/* A hash table used to speed up lookups when we have a lot of shared
|
||||
libraries. We record in the table how many ELF objects in the link
|
||||
map we can safely skip, because they are known to not contain the symbol
|
||||
we are looking for.
|
||||
|
||||
We go through each object (executable or DSO) in their order in the
|
||||
main_map and insert pos_in_main_map into the table. Searches for
|
||||
symbols not present in the table start at num_objects, skipping every
|
||||
object preprocessed in this way.
|
||||
|
||||
If there is already an earlier (smaller) entry in the table, we leave it
|
||||
alone. It represents an earlier instance of the same symbol (eg weak
|
||||
__stdout definition in multiple objects). */
|
||||
|
||||
struct position_hash
|
||||
{
|
||||
/* The Bernstein hash, shifted right one bit. (This lets us build a table
|
||||
directly from the precomputed values in DT_GNU_HASH sections, in which
|
||||
the low bit is repurposed to terminate hash chains.) */
|
||||
uint32_t hash;
|
||||
/* The position of the first library with this symbol in the search list. */
|
||||
uint32_t pos;
|
||||
/* The symbol name. */
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static struct position_hash *position_hash_table;
|
||||
static size_t position_hash_table_slots;
|
||||
static size_t position_hash_table_slots_occupied;
|
||||
static int position_hash_lookup_default;
|
||||
|
||||
static int
|
||||
position_hash_put (struct position_hash *table, size_t slots,
|
||||
struct position_hash *item)
|
||||
{
|
||||
size_t mask = slots - 1;
|
||||
/* Search for a matching entry or a free slot. This loop always terminates
|
||||
because we don't allow the hashtable to become completely full. */
|
||||
for (size_t stride = 0, i = item->hash; ; i += ++stride)
|
||||
{
|
||||
struct position_hash *slot = &table[i & mask];
|
||||
if (slot->name == NULL)
|
||||
{
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf ("fastload: put %s hash 0x%x pos %u slot 0x%lx\n",
|
||||
item->name, item->hash, item->pos, slot - table);
|
||||
slot->hash = item->hash;
|
||||
slot->pos = item->pos;
|
||||
slot->name = item->name;
|
||||
return 1;
|
||||
}
|
||||
else if (slot->hash == item->hash &&
|
||||
(slot->name == item->name || !strcmp (slot->name, item->name)))
|
||||
{
|
||||
if (item->pos < slot->pos)
|
||||
slot->pos = item->pos;
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf ("fastload: dup %s hash 0x%x pos %u slot 0x%lx\n",
|
||||
item->name, item->hash, slot->pos, slot - table);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
position_hash_resize (struct position_hash *oldtable,
|
||||
size_t oldslots, size_t newslots)
|
||||
{
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf ("fastload: resizing hashtable to %lu slots\n", newslots);
|
||||
assert (!oldtable == !oldslots);
|
||||
void *ptr = mmap (NULL, newslots * sizeof *oldtable, PROT_READ|PROT_WRITE,
|
||||
MAP_ANON|MAP_PRIVATE|MAP_POPULATE, -1, 0);
|
||||
if (ptr == MAP_FAILED)
|
||||
_dl_signal_error (errno, NULL, NULL, "cannot mmap fastload hashtable");
|
||||
struct position_hash *newtable = position_hash_table = ptr;
|
||||
position_hash_table_slots = newslots;
|
||||
if (oldtable == NULL)
|
||||
return;
|
||||
for (size_t i = 0; i < oldslots; ++i)
|
||||
{
|
||||
if (oldtable[i].name)
|
||||
position_hash_put (newtable, newslots, &oldtable[i]);
|
||||
}
|
||||
|
||||
if (munmap (oldtable, oldslots * sizeof *oldtable))
|
||||
_dl_signal_error (errno, NULL, NULL, "cannot munmap fastload hashtable");
|
||||
}
|
||||
|
||||
static void
|
||||
position_hash_init (int lookup_default)
|
||||
{
|
||||
assert (position_hash_table == NULL);
|
||||
position_hash_lookup_default = lookup_default;
|
||||
position_hash_resize (NULL, 0, 8192);
|
||||
}
|
||||
|
||||
static void
|
||||
position_hash_insert (uint32_t hash, const char *name, uint32_t pos)
|
||||
{
|
||||
struct position_hash *table = position_hash_table;
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf ("fastload: insert %s hash 0x%x pos %u\n", name, hash, pos);
|
||||
size_t slots = position_hash_table_slots;
|
||||
struct position_hash item = { hash, pos, name };
|
||||
if (!position_hash_put (table, slots, &item))
|
||||
return;
|
||||
size_t newsize = ++position_hash_table_slots_occupied;
|
||||
if (newsize >= slots / 2)
|
||||
/* The load factor has reached 50%. Double the table size and rehash. */
|
||||
position_hash_resize (table, slots, 2 * slots);
|
||||
}
|
||||
|
||||
static int
|
||||
position_hash_lookup (uint32_t hash, const char *name)
|
||||
{
|
||||
struct position_hash *table = position_hash_table;
|
||||
if (table == NULL)
|
||||
return 0;
|
||||
size_t mask = position_hash_table_slots - 1;
|
||||
for (size_t stride = 0, i = hash; ; i += ++stride)
|
||||
{
|
||||
struct position_hash *slot = &table[i & mask];
|
||||
if (slot->hash == hash &&
|
||||
(slot->name == name || !strcmp (slot->name, name)))
|
||||
{
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf ("fastload: found %s at slot 0x%lx, pos %u\n",
|
||||
name, slot - table, slot->pos);
|
||||
return slot->pos;
|
||||
}
|
||||
else if (slot->name == NULL)
|
||||
{
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf ("fastload: missed %s at slot 0x%lx, default pos %u\n",
|
||||
name, slot - table, position_hash_lookup_default);
|
||||
return position_hash_lookup_default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
position_hash_include_symbol (const ElfW(Sym) *sym)
|
||||
{
|
||||
if (sym->st_value == 0 && ELFW(ST_TYPE) (sym->st_info) != STT_TLS)
|
||||
return 0;
|
||||
|
||||
switch (ELFW(ST_TYPE) (sym->st_info))
|
||||
{
|
||||
case STT_SECTION:
|
||||
case STT_FILE:
|
||||
case STT_COMMON:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Local symbols are ignored. */
|
||||
return ELFW(ST_BIND) (sym->st_info) != STB_LOCAL;
|
||||
}
|
||||
|
||||
static int
|
||||
last_gnu_hash_bucket (const struct link_map *map)
|
||||
{
|
||||
/* The best documentation for GNU_HASH I found:
|
||||
http://www.linker-aliens.org/blogs/ali/entry/gnu_hash_elf_sections/
|
||||
|
||||
_dl_setup_hash() has already set things up for us. */
|
||||
|
||||
if (__builtin_expect (map->l_nbuckets < 1, 0))
|
||||
/* Paranoia: neither gold nor gnu-ld will construct an empty
|
||||
.gnu.hash, but some other linker just might. */
|
||||
return 0;
|
||||
|
||||
/* In the GNU hash the symbol index of a symbol is determined by
|
||||
the offset of the symbol's entry in the hash table itself.
|
||||
|
||||
We start at the last bucket map->l_gnu_buckets[map->l_nbuckets-1]
|
||||
and loop backward from the end until we find a bucket which is
|
||||
not zero. */
|
||||
|
||||
int last_bucket_idx = map->l_nbuckets - 1;
|
||||
|
||||
while (last_bucket_idx > 0 &&
|
||||
map->l_gnu_buckets[last_bucket_idx] == 0)
|
||||
--last_bucket_idx;
|
||||
|
||||
return map->l_gnu_buckets[last_bucket_idx];
|
||||
}
|
||||
|
||||
static void
|
||||
position_hash_fill_from_gnu_hash (const struct link_map *map,
|
||||
int pos_in_main_map)
|
||||
{
|
||||
int last_bucket = last_gnu_hash_bucket (map);
|
||||
if (last_bucket == 0)
|
||||
return;
|
||||
|
||||
/* Start of hash values. */
|
||||
const Elf32_Word *chains = &map->l_gnu_buckets[map->l_nbuckets];
|
||||
|
||||
/* Reconstruct the number of symbols omitted. */
|
||||
const Elf32_Word *zero = map->l_gnu_chain_zero;
|
||||
int symbias = chains - zero;
|
||||
|
||||
const ElfW(Sym) *const symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
|
||||
const char *const strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
|
||||
|
||||
/* Iterate through the symbols in the GNU hash chains and insert them
|
||||
into the position hash table. If the symbol wouldn't pass the tests
|
||||
in do_lookup_x(), then don't insert it. */
|
||||
for (int k = symbias; ; ++k)
|
||||
{
|
||||
uint32_t hash = zero[k];
|
||||
const ElfW(Sym) *sym = &symtab[k];
|
||||
if (position_hash_include_symbol (sym))
|
||||
position_hash_insert (hash >> 1, strtab + sym->st_name, pos_in_main_map);
|
||||
|
||||
/* Stop when we've passed the start of the last chain and the sentinel bit
|
||||
terminating a chain is set. This is the end of the section. */
|
||||
if (k >= last_bucket && (hash & 1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
old_hash_nchain (const struct link_map *map)
|
||||
{
|
||||
if (map->l_info[DT_HASH] == NULL)
|
||||
return 0;
|
||||
const Elf_Symndx *const hash = (void *) D_PTR (map, l_info[DT_HASH]);
|
||||
if (hash == NULL)
|
||||
return 0;
|
||||
/* Read the "nchain" field of the DT_HASH section; see
|
||||
https://refspecs.linuxfoundation.org/elf/gabi4+/ch5.dynamic.html#hash. */
|
||||
return hash[1];
|
||||
}
|
||||
|
||||
static void
|
||||
position_hash_fill_from_symtab (const struct link_map *const map,
|
||||
int pos_in_main_map)
|
||||
{
|
||||
const ElfW(Sym) *const symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
|
||||
const char *const strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
|
||||
const int num_symbols = old_hash_nchain (map);
|
||||
|
||||
/* Iterate through the symbols defined in this map and insert them
|
||||
into the position hash table. If the symbol wouldn't pass the tests
|
||||
in do_lookup_x(), then don't insert it. */
|
||||
for (int k = 0; k < num_symbols; k++)
|
||||
{
|
||||
const ElfW(Sym) *sym = &symtab[k];
|
||||
if (position_hash_include_symbol (sym))
|
||||
{
|
||||
uint32_t hash = dl_new_hash (strtab + sym->st_name);
|
||||
position_hash_insert (hash >> 1, strtab + sym->st_name, pos_in_main_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the fastload position hash (if requested). Given a link_map
|
||||
containing all required objects, iterate through all symbols. For each
|
||||
symbol which could match in do_lookup_x, insert the index of the
|
||||
providing object in main_map. */
|
||||
|
||||
void
|
||||
_dl_fill_position_hash (struct link_map *main_map)
|
||||
{
|
||||
const int num_objects = main_map->l_searchlist.r_nlist;
|
||||
const int debug_fastload = GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD;
|
||||
int k;
|
||||
|
||||
/* If we have more than dl_position_hash_cutoff shared libraries,
|
||||
fill in the hash table of earliest known positions for symbols in
|
||||
main_map. We'll use this in do_lookup_x(). */
|
||||
|
||||
/* If cutoff is negative, fastload is disabled. */
|
||||
if (GLRO(dl_position_hash_cutoff) < 0)
|
||||
{
|
||||
if (__builtin_expect (debug_fastload, 0))
|
||||
_dl_debug_printf ("fastload: disabled (configuration)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we don't have enough mapped objects, fastload is disabled. */
|
||||
if (num_objects <= GLRO(dl_position_hash_cutoff))
|
||||
{
|
||||
if (__builtin_expect (debug_fastload, 0))
|
||||
_dl_debug_printf ("fastload: disabled (too few objects,"
|
||||
" %u <= cutoff %u)\n",
|
||||
num_objects, GLRO(dl_position_hash_cutoff));
|
||||
return;
|
||||
}
|
||||
|
||||
int timing = (HP_TIMING_AVAIL) && (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS);
|
||||
hp_timing_t start, stop, elapsed;
|
||||
if (timing)
|
||||
HP_TIMING_NOW (start);
|
||||
|
||||
position_hash_init (num_objects);
|
||||
|
||||
for (k = 0; k < num_objects; ++k)
|
||||
{
|
||||
const struct link_map *const map = main_map->l_searchlist.r_list[k];
|
||||
|
||||
if (map->l_info[ADDRIDX (DT_GNU_HASH)] != NULL)
|
||||
position_hash_fill_from_gnu_hash (map, k);
|
||||
else
|
||||
position_hash_fill_from_symtab (map, k);
|
||||
|
||||
}
|
||||
|
||||
if (!timing)
|
||||
return;
|
||||
HP_TIMING_NOW (stop);
|
||||
HP_TIMING_DIFF (elapsed, start, stop);
|
||||
char buf[80];
|
||||
HP_TIMING_PRINT (buf, sizeof buf, elapsed);
|
||||
_dl_debug_printf ("\t time to build fastload table: %s\n", buf);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
@@ -344,6 +670,32 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
|
||||
__asm volatile ("" : "+r" (n), "+m" (scope->r_list));
|
||||
struct link_map **list = scope->r_list;
|
||||
|
||||
if (scope == GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist && i == 0)
|
||||
{
|
||||
const int skip_to = position_hash_lookup (new_hash >> 1, undef_name);
|
||||
|
||||
if (skip_to < n)
|
||||
{
|
||||
i = skip_to;
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf ("fastload: lookup %s skipping to %u\n",
|
||||
undef_name, (unsigned int) i);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Symbol was not found in any of the initial libraries,
|
||||
and no new libraries have been added. */
|
||||
|
||||
assert (skip_to == n);
|
||||
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf ("fastload: lookup %s, %u >= %u (scope->r_nlist)\n",
|
||||
undef_name, (unsigned int) skip_to,
|
||||
(unsigned int) n);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
const struct link_map *map = list[i]->l_real;
|
||||
@@ -548,16 +900,6 @@ skip:
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
|
||||
|
||||
+183
-11
@@ -33,7 +33,7 @@
|
||||
#include <sysdep.h>
|
||||
#include <_itoa.h>
|
||||
#include <dl-writev.h>
|
||||
|
||||
#include <not-cancel.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
|
||||
@@ -44,7 +44,7 @@ _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);
|
||||
int fd = __open64_nocancel (file, O_RDONLY | O_CLOEXEC);
|
||||
if (fd >= 0)
|
||||
{
|
||||
if (__fxstat64 (_STAT_VER, fd, &st) >= 0)
|
||||
@@ -65,7 +65,7 @@ _dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot)
|
||||
#endif
|
||||
, fd, 0);
|
||||
}
|
||||
__close (fd);
|
||||
__close_nocancel (fd);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -81,7 +81,10 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
|
||||
struct iovec iov[NIOVMAX];
|
||||
int niov = 0;
|
||||
pid_t pid = 0;
|
||||
char pidbuf[12];
|
||||
char pidbuf[23];
|
||||
pid_t tid = 0;
|
||||
/* Start with a known bad value, should never get used. */
|
||||
char *tag_start = NULL;
|
||||
|
||||
while (*fmt != '\0')
|
||||
{
|
||||
@@ -93,20 +96,32 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
|
||||
colon followed by a tab. */
|
||||
if (pid == 0)
|
||||
{
|
||||
char *p;
|
||||
char *p = &pidbuf[21];
|
||||
|
||||
pid = __getpid ();
|
||||
assert (pid >= 0 && sizeof (pid_t) <= 4);
|
||||
p = _itoa (pid, &pidbuf[10], 10, 0);
|
||||
while (p > pidbuf)
|
||||
|
||||
/* If we are doing thread-related output, maybe add a thread id,
|
||||
taking care that pid continues to appear at the same
|
||||
positions. */
|
||||
tid = _dl_tls_tid ();
|
||||
if (tid > 0)
|
||||
{
|
||||
p = _itoa (tid, p, 10, 0);
|
||||
*--p = '/';
|
||||
}
|
||||
tag_start = p - 10;
|
||||
p = _itoa (pid, p, 10, 0);
|
||||
while (p > tag_start)
|
||||
*--p = ' ';
|
||||
pidbuf[10] = ':';
|
||||
pidbuf[11] = '\t';
|
||||
pidbuf[21] = ':';
|
||||
pidbuf[22] = '\t';
|
||||
}
|
||||
|
||||
/* Append to the output. */
|
||||
assert (niov < NIOVMAX);
|
||||
iov[niov].iov_len = 12;
|
||||
iov[niov++].iov_base = pidbuf;
|
||||
iov[niov].iov_len = &(pidbuf[23]) - tag_start;
|
||||
iov[niov++].iov_base = tag_start;
|
||||
|
||||
/* No more tags until we see the next newline. */
|
||||
tag_p = -1;
|
||||
@@ -440,3 +455,160 @@ _dl_strtoul (const char *nptr, char **endptr)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* To support accessing TLS variables from signal handlers, we need an
|
||||
async signal safe memory allocator. These routines are never
|
||||
themselves invoked reentrantly (all calls to them are surrounded by
|
||||
signal masks) but may be invoked concurrently from many threads.
|
||||
The current implementation is not particularly performant nor space
|
||||
efficient, but it will be used rarely (and only in binaries that use
|
||||
dlopen.) The API matches that of malloc() and friends. */
|
||||
|
||||
struct __signal_safe_allocator_header
|
||||
{
|
||||
size_t size;
|
||||
void *start;
|
||||
};
|
||||
|
||||
static inline struct __signal_safe_allocator_header *
|
||||
ptr_to_signal_safe_allocator_header (void *ptr)
|
||||
{
|
||||
return (struct __signal_safe_allocator_header *)
|
||||
((char *) (ptr) - sizeof (struct __signal_safe_allocator_header));
|
||||
}
|
||||
|
||||
void *weak_function
|
||||
__signal_safe_memalign (size_t boundary, size_t size)
|
||||
{
|
||||
struct __signal_safe_allocator_header *header;
|
||||
|
||||
if (boundary < sizeof (*header))
|
||||
boundary = sizeof (*header);
|
||||
|
||||
/* Boundary must be a power of two. */
|
||||
if (!powerof2 (boundary))
|
||||
return NULL;
|
||||
|
||||
size_t pg = GLRO (dl_pagesize);
|
||||
size_t padded_size;
|
||||
if (boundary <= pg)
|
||||
{
|
||||
/* We'll get a pointer certainly aligned to boundary, so just
|
||||
add one more boundary-sized chunk to hold the header. */
|
||||
padded_size = roundup (size, boundary) + boundary;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we want K pages aligned to a J-page boundary, K+J+1 pages
|
||||
contains at least one such region that isn't directly at the start
|
||||
(so we can place the header.) This is wasteful, but you're the one
|
||||
who wanted 64K-aligned TLS. */
|
||||
padded_size = roundup (size, pg) + boundary + pg;
|
||||
}
|
||||
|
||||
|
||||
size_t actual_size = roundup (padded_size, pg);
|
||||
void *actual = mmap (NULL, actual_size, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if (actual == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
if (boundary <= pg)
|
||||
{
|
||||
header = actual + boundary - sizeof (*header);
|
||||
}
|
||||
else
|
||||
{
|
||||
intptr_t actual_pg = ((intptr_t) actual) / pg;
|
||||
intptr_t boundary_pg = boundary / pg;
|
||||
intptr_t start_pg = actual_pg + boundary_pg;
|
||||
start_pg -= start_pg % boundary_pg;
|
||||
if (start_pg > (actual_pg + 1))
|
||||
{
|
||||
int ret = munmap (actual, (start_pg - actual_pg - 1) * pg);
|
||||
assert (ret == 0);
|
||||
actual = (void *) ((start_pg - 1) * pg);
|
||||
}
|
||||
char *start = (void *) (start_pg * pg);
|
||||
header = ptr_to_signal_safe_allocator_header (start);
|
||||
}
|
||||
|
||||
header->size = actual_size;
|
||||
header->start = actual;
|
||||
void *ptr = header;
|
||||
ptr += sizeof (*header);
|
||||
if (((intptr_t) ptr) % boundary != 0)
|
||||
_dl_fatal_printf ("__signal_safe_memalign produced incorrect alignment\n");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void * weak_function
|
||||
__signal_safe_malloc (size_t size)
|
||||
{
|
||||
if (!GLRO(dl_async_signal_safe))
|
||||
return malloc (size);
|
||||
|
||||
return __signal_safe_memalign (1, size);
|
||||
}
|
||||
|
||||
void weak_function
|
||||
__signal_safe_free (void *ptr)
|
||||
{
|
||||
if (!GLRO(dl_async_signal_safe))
|
||||
{
|
||||
free (ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
|
||||
struct __signal_safe_allocator_header *header
|
||||
= ptr_to_signal_safe_allocator_header (ptr);
|
||||
int ret = munmap (header->start, header->size);
|
||||
|
||||
assert (ret == 0);
|
||||
}
|
||||
|
||||
void * weak_function
|
||||
__signal_safe_realloc (void *ptr, size_t size)
|
||||
{
|
||||
if (!GLRO(dl_async_signal_safe))
|
||||
return realloc (ptr, size);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
__signal_safe_free (ptr);
|
||||
return NULL;
|
||||
}
|
||||
if (ptr == NULL)
|
||||
return __signal_safe_malloc (size);
|
||||
|
||||
struct __signal_safe_allocator_header *header
|
||||
= ptr_to_signal_safe_allocator_header (ptr);
|
||||
size_t old_size = header->size;
|
||||
if (old_size - sizeof (*header) >= size)
|
||||
return ptr;
|
||||
|
||||
void *new_ptr = __signal_safe_malloc (size);
|
||||
if (new_ptr == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Copy over the old block (but not its header). */
|
||||
memcpy (new_ptr, ptr, old_size - sizeof (*header));
|
||||
__signal_safe_free (ptr);
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void * weak_function
|
||||
__signal_safe_calloc (size_t nmemb, size_t size)
|
||||
{
|
||||
if (!GLRO(dl_async_signal_safe))
|
||||
return calloc (nmemb, size);
|
||||
|
||||
void *ptr = __signal_safe_malloc (nmemb * size);
|
||||
if (ptr == NULL)
|
||||
return NULL;
|
||||
return memset (ptr, 0, nmemb * size);
|
||||
}
|
||||
|
||||
+4
-5
@@ -34,9 +34,7 @@ _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
|
||||
|
||||
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;
|
||||
struct link_map *l = _dl_last_entry (&GL(dl_ns)[nsid]);
|
||||
new->l_prev = l;
|
||||
/* new->l_next = NULL; Would be necessary but we use calloc. */
|
||||
l->l_next = new;
|
||||
@@ -47,12 +45,13 @@ _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
|
||||
new->l_serial = GL(dl_load_adds);
|
||||
++GL(dl_load_adds);
|
||||
|
||||
_dl_hash_add_object (new);
|
||||
|
||||
__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. */
|
||||
/* Allocate a `struct link_map' for a new object being loaded. */
|
||||
struct link_map *
|
||||
_dl_new_object (char *realname, const char *libname, int type,
|
||||
struct link_map *loader, int mode, Lmid_t nsid)
|
||||
|
||||
+9
-3
@@ -44,6 +44,8 @@
|
||||
struct dl_open_args
|
||||
{
|
||||
const char *file;
|
||||
/* ELF header at offset in file. */
|
||||
off_t offset;
|
||||
int mode;
|
||||
/* This is the caller of the dlopen() function. */
|
||||
const void *caller_dlopen;
|
||||
@@ -221,7 +223,7 @@ dl_open_worker (void *a)
|
||||
|
||||
/* Load the named object. */
|
||||
struct link_map *new;
|
||||
args->map = new = _dl_map_object (call_map, file, lt_loaded, 0,
|
||||
args->map = new = _dl_map_object (call_map, file, args->offset, lt_loaded, 0,
|
||||
mode | __RTLD_CALLMAP, args->nsid);
|
||||
|
||||
/* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
|
||||
@@ -493,7 +495,10 @@ TLS generation counter wrapped! Please report this."));
|
||||
generation of the DSO we are allocating data for. */
|
||||
_dl_update_slotinfo (imap->l_tls_modid);
|
||||
#endif
|
||||
|
||||
/* We do this iteration under a signal mask in dl-reloc; why not
|
||||
here? Because these symbols are new and dlopen hasn't
|
||||
returned yet. So we can't possibly be racing with a TLS
|
||||
access to them from another thread. */
|
||||
GL(dl_init_static_tls) (imap);
|
||||
assert (imap->l_need_tls_init == 0);
|
||||
}
|
||||
@@ -531,7 +536,7 @@ TLS generation counter wrapped! Please report this."));
|
||||
|
||||
|
||||
void *
|
||||
_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
|
||||
_dl_open (const char *file, off_t offset, int mode, const void *caller_dlopen, Lmid_t nsid,
|
||||
int argc, char *argv[], char *env[])
|
||||
{
|
||||
if ((mode & RTLD_BINDING_MASK) == 0)
|
||||
@@ -581,6 +586,7 @@ no more namespaces available for dlmopen()"));
|
||||
|
||||
struct dl_open_args args;
|
||||
args.file = file;
|
||||
args.offset = offset;
|
||||
args.mode = mode;
|
||||
args.caller_dlopen = caller_dlopen;
|
||||
args.caller_dl_open = RETURN_ADDRESS (0);
|
||||
|
||||
+7
-7
@@ -35,6 +35,7 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <atomic.h>
|
||||
#include <not-cancel.h>
|
||||
|
||||
/* The LD_PROFILE feature has to be implemented different to the
|
||||
normal profiling using the gmon/ functions. The problem is that an
|
||||
@@ -324,7 +325,7 @@ _dl_start_profile (void)
|
||||
*cp++ = '/';
|
||||
__stpcpy (__stpcpy (cp, GLRO(dl_profile)), ".profile");
|
||||
|
||||
fd = __open (filename, O_RDWR | O_CREAT | O_NOFOLLOW, DEFFILEMODE);
|
||||
fd = __open64_nocancel (filename, O_RDWR|O_CREAT|O_NOFOLLOW, DEFFILEMODE);
|
||||
if (fd == -1)
|
||||
{
|
||||
char buf[400];
|
||||
@@ -335,7 +336,7 @@ _dl_start_profile (void)
|
||||
print_error:
|
||||
errnum = errno;
|
||||
if (fd != -1)
|
||||
__close (fd);
|
||||
__close_nocancel (fd);
|
||||
_dl_error_printf (errstr, filename,
|
||||
__strerror_r (errnum, buf, sizeof buf));
|
||||
return;
|
||||
@@ -364,15 +365,14 @@ _dl_start_profile (void)
|
||||
goto print_error;
|
||||
}
|
||||
|
||||
if (TEMP_FAILURE_RETRY (__libc_write (fd, buf, (expected_size
|
||||
& (GLRO(dl_pagesize)
|
||||
- 1))))
|
||||
if (TEMP_FAILURE_RETRY
|
||||
(__write_nocancel (fd, buf, (expected_size & (GLRO(dl_pagesize) - 1))))
|
||||
< 0)
|
||||
goto cannot_create;
|
||||
}
|
||||
else if (st.st_size != expected_size)
|
||||
{
|
||||
__close (fd);
|
||||
__close_nocancel (fd);
|
||||
wrong_format:
|
||||
|
||||
if (addr != NULL)
|
||||
@@ -392,7 +392,7 @@ _dl_start_profile (void)
|
||||
}
|
||||
|
||||
/* We don't need the file descriptor anymore. */
|
||||
__close (fd);
|
||||
__close_nocancel (fd);
|
||||
|
||||
/* Pointer to data after the header. */
|
||||
hist = (char *) (addr + 1);
|
||||
|
||||
@@ -19,7 +19,13 @@
|
||||
#if ENABLE_STATIC_PIE
|
||||
#include <unistd.h>
|
||||
#include <ldsodefs.h>
|
||||
#include "dynamic-link.h"
|
||||
|
||||
#ifndef NESTING
|
||||
# define STATIC_PIE_BOOTSTRAP
|
||||
# define BOOTSTRAP_MAP (main_map)
|
||||
# define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP
|
||||
# include "dynamic-link.h"
|
||||
#endif /* n NESTING */
|
||||
|
||||
/* Relocate static executable with PIE. */
|
||||
|
||||
@@ -28,10 +34,12 @@ _dl_relocate_static_pie (void)
|
||||
{
|
||||
struct link_map *main_map = _dl_get_dl_main_map ();
|
||||
|
||||
#ifdef NESTING
|
||||
# define STATIC_PIE_BOOTSTRAP
|
||||
# define BOOTSTRAP_MAP (main_map)
|
||||
# define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP
|
||||
# include "dynamic-link.h"
|
||||
#endif /* NESTING */
|
||||
|
||||
/* Figure out the run-time load address of static PIE. */
|
||||
main_map->l_addr = elf_machine_load_address ();
|
||||
@@ -46,7 +54,11 @@ _dl_relocate_static_pie (void)
|
||||
|
||||
/* Relocate ourselves so we can do normal function calls and
|
||||
data access using the global offset table. */
|
||||
ELF_DYNAMIC_RELOCATE (main_map, 0, 0, 0);
|
||||
ELF_DYNAMIC_RELOCATE (main_map, 0, 0, 0
|
||||
#ifndef NESTING
|
||||
, main_map
|
||||
#endif
|
||||
);
|
||||
main_map->l_relocated = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
+105
-7
@@ -16,8 +16,10 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <atomic.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <ldsodefs.h>
|
||||
@@ -71,7 +73,8 @@ _dl_try_allocate_static_tls (struct link_map *map)
|
||||
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;
|
||||
if (!GLRO(dl_async_signal_safe))
|
||||
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)
|
||||
@@ -83,12 +86,48 @@ _dl_try_allocate_static_tls (struct link_map *map)
|
||||
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;
|
||||
if (!GLRO(dl_async_signal_safe)) {
|
||||
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 (GLRO(dl_async_signal_safe)) {
|
||||
/* We've computed the new value we want, now try to install it. */
|
||||
ptrdiff_t val;
|
||||
if ((val = map->l_tls_offset) == NO_TLS_OFFSET)
|
||||
{
|
||||
/* l_tls_offset starts out at NO_TLS_OFFSET, and all attempts to
|
||||
change it go from NO_TLS_OFFSET to some other value. We use
|
||||
compare_and_exchange to ensure only one attempt succeeds. We
|
||||
don't actually need any memory ordering here, but _acq is the
|
||||
weakest available. */
|
||||
(void ) atomic_compare_and_exchange_bool_acq (&map->l_tls_offset,
|
||||
offset,
|
||||
NO_TLS_OFFSET);
|
||||
val = map->l_tls_offset;
|
||||
assert (val != NO_TLS_OFFSET);
|
||||
}
|
||||
if (val != offset)
|
||||
{
|
||||
/* We'd like to set a static offset for this section, but another
|
||||
thread has already used a dynamic TLS block for it. Since we can
|
||||
only use static offsets if everyone does (and it's not practical
|
||||
to move that thread's dynamic block), we have to fail. */
|
||||
goto fail;
|
||||
}
|
||||
/* We installed the value; now update the globals. */
|
||||
#if TLS_TCB_AT_TP // second
|
||||
GL(dl_tls_static_used) = offset;
|
||||
#elif TLS_DTV_AT_TP // second
|
||||
map->l_tls_firstbyte_offset = GL(dl_tls_static_used);
|
||||
GL(dl_tls_static_used) = used;
|
||||
#else // second
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" // second
|
||||
#endif // second
|
||||
}
|
||||
|
||||
/* If the object is not yet relocated we cannot initialize the
|
||||
static TLS region. Delay it. */
|
||||
@@ -114,8 +153,19 @@ void
|
||||
__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))
|
||||
/* We wrap this in a signal mask because it has to iterate all threads
|
||||
(including this one) and update this map's TLS entry. A signal handler
|
||||
accessing TLS would try to do the same update and break. */
|
||||
sigset_t old;
|
||||
if (GLRO(dl_async_signal_safe))
|
||||
_dl_mask_all_signals (&old);
|
||||
int err = -1;
|
||||
if (map->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)
|
||||
err = _dl_try_allocate_static_tls (map);
|
||||
|
||||
if (GLRO(dl_async_signal_safe))
|
||||
_dl_unmask_signals (&old);
|
||||
if (err != 0)
|
||||
{
|
||||
_dl_signal_error (0, map->l_name, NULL, N_("\
|
||||
cannot allocate memory in static TLS block"));
|
||||
@@ -141,6 +191,40 @@ _dl_nothread_init_static_tls (struct link_map *map)
|
||||
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||
}
|
||||
|
||||
#ifndef NESTING
|
||||
|
||||
/* String table object symbols. */
|
||||
|
||||
static struct link_map *glob_l;
|
||||
static struct r_scope_elem **glob_scope;
|
||||
static const char *glob_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) == glob_l->l_lookup_cache.sym, 0) \
|
||||
&& elf_machine_type_class (r_type) == glob_l->l_lookup_cache.type_class) \
|
||||
? (bump_num_cache_relocations (), \
|
||||
(*ref) = glob_l->l_lookup_cache.ret, \
|
||||
glob_l->l_lookup_cache.value) \
|
||||
: ({ lookup_t _lr; \
|
||||
int _tc = elf_machine_type_class (r_type); \
|
||||
glob_l->l_lookup_cache.type_class = _tc; \
|
||||
glob_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 (glob_strtab + (*ref)->st_name, glob_l, (ref), \
|
||||
glob_scope, v, _tc, \
|
||||
DL_LOOKUP_ADD_DEPENDENCY, NULL); \
|
||||
glob_l->l_lookup_cache.ret = (*ref); \
|
||||
glob_l->l_lookup_cache.value = _lr; })) \
|
||||
: glob_l)
|
||||
|
||||
#include "dynamic-link.h"
|
||||
|
||||
#endif /* n NESTING */
|
||||
|
||||
void
|
||||
_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
@@ -227,6 +311,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
{
|
||||
/* Do the actual relocation of the object's GOT and other data. */
|
||||
|
||||
#ifdef NESTING
|
||||
|
||||
/* String table object symbols. */
|
||||
const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
|
||||
|
||||
@@ -255,7 +341,19 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
|
||||
#include "dynamic-link.h"
|
||||
|
||||
ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling, skip_ifunc);
|
||||
#else
|
||||
|
||||
glob_l = l;
|
||||
glob_scope = scope;
|
||||
glob_strtab = (const void *) D_PTR (glob_l, l_info[DT_STRTAB]);
|
||||
|
||||
#endif /* NESTING */
|
||||
|
||||
ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling, skip_ifunc
|
||||
#ifndef NESTING
|
||||
, NULL
|
||||
#endif
|
||||
);
|
||||
|
||||
#ifndef PROF
|
||||
if (__glibc_unlikely (consider_profiling)
|
||||
|
||||
+24
-3
@@ -33,11 +33,32 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
|
||||
unsigned int i = 0;
|
||||
uint16_t seen[nmaps];
|
||||
memset (seen, 0, nmaps * sizeof (seen[0]));
|
||||
while (1)
|
||||
|
||||
/* Mark objects with in-edges. */
|
||||
for (unsigned j = i; j < nmaps; ++j)
|
||||
maps[j]->l_inedge = 0;
|
||||
|
||||
for (unsigned j = i; j < nmaps; ++j)
|
||||
{
|
||||
for (struct link_map **p = maps[j]->l_initfini; p && *p; ++p)
|
||||
{
|
||||
if (*p != maps[j]) /* Skip self-edges. */
|
||||
(*p)->l_inedge = 1;
|
||||
}
|
||||
}
|
||||
|
||||
while (i < nmaps)
|
||||
{
|
||||
struct link_map *thisp = maps[i];
|
||||
if (!thisp->l_inedge)
|
||||
{
|
||||
/* No dependencies on this object. */
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Keep track of which object we looked at this round. */
|
||||
++seen[i];
|
||||
struct link_map *thisp = maps[i];
|
||||
|
||||
if (__glibc_unlikely (for_fini))
|
||||
{
|
||||
@@ -52,7 +73,7 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
|
||||
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. */
|
||||
|
||||
@@ -67,9 +67,15 @@ void *__libc_stack_end;
|
||||
/* Path where the binary is found. */
|
||||
const char *_dl_origin_path;
|
||||
|
||||
/* Directory where the AT_EXECFN is found. */
|
||||
const char *_google_exec_origin_dir;
|
||||
|
||||
/* Nonzero if runtime lookup should not update the .got/.plt. */
|
||||
int _dl_bind_not;
|
||||
|
||||
/* Nonzero if TLS handling should be async-signal-safe. */
|
||||
int _dl_async_signal_safe;
|
||||
|
||||
/* 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 =
|
||||
@@ -136,6 +142,9 @@ hp_timing_t _dl_cpuclock_offset;
|
||||
|
||||
void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
|
||||
|
||||
/* The merged position hash table used if we have a lot of shared objects. */
|
||||
int _dl_position_hash_cutoff = DL_POSITION_HASH_CUTOFF_DEFAULT;
|
||||
|
||||
size_t _dl_pagesize = EXEC_PAGESIZE;
|
||||
|
||||
int _dl_inhibit_cache;
|
||||
|
||||
+300
-7
@@ -17,6 +17,7 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <atomic.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <signal.h>
|
||||
@@ -29,6 +30,8 @@
|
||||
#include <dl-tls.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
static void _dl_print_dtv(const char *msg, dtv_t *dtv, int numentries);
|
||||
|
||||
/* 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
|
||||
@@ -283,7 +286,7 @@ allocate_dtv (void *result)
|
||||
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));
|
||||
dtv = __signal_safe_calloc (dtv_length + 2, sizeof (dtv_t));
|
||||
if (dtv != NULL)
|
||||
{
|
||||
/* This is the initial length of the dtv. */
|
||||
@@ -408,14 +411,14 @@ _dl_resize_dtv (dtv_t *dtv)
|
||||
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));
|
||||
newp = __signal_safe_malloc ((2 + newsize) * sizeof (dtv_t));
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
newp = realloc (&dtv[-1],
|
||||
newp = __signal_safe_realloc (&dtv[-1],
|
||||
(2 + newsize) * sizeof (dtv_t));
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
@@ -427,6 +430,13 @@ _dl_resize_dtv (dtv_t *dtv)
|
||||
memset (newp + 2 + oldsize, '\0',
|
||||
(newsize - oldsize) * sizeof (dtv_t));
|
||||
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("Resized dtv 0x%0*Zx, size %lu, to dtv 0x%0*Zx, size %lu\n",
|
||||
(int) sizeof (void *) * 2, (unsigned long int) dtv,
|
||||
oldsize,
|
||||
(int) sizeof (void *) * 2, (unsigned long int) &newp[1],
|
||||
newsize);
|
||||
|
||||
/* Return the generation counter. */
|
||||
return &newp[1];
|
||||
}
|
||||
@@ -483,6 +493,12 @@ _dl_allocate_tls_init (void *result)
|
||||
|
||||
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[map->l_tls_modid].pointer.to_free = NULL;
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("_dl_allocate_tls_init unallocates %sdtv 0x%0*Zx module %lu\n",
|
||||
(dtv == THREAD_DTV () ? "own " : ""),
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv,
|
||||
map->l_tls_modid);
|
||||
|
||||
if (map->l_tls_offset == NO_TLS_OFFSET
|
||||
|| map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
|
||||
@@ -502,6 +518,14 @@ _dl_allocate_tls_init (void *result)
|
||||
/* 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;
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("_dl_allocate_tls_init sets %sdtv 0x%0*Zx module %lu to 0x%0*Zx\n",
|
||||
(dtv == THREAD_DTV () ? "own " : ""),
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv,
|
||||
map->l_tls_modid,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dest);
|
||||
|
||||
/* Copy the initialization image and clear the BSS part. */
|
||||
memset (__mempcpy (dest, map->l_tls_initimage,
|
||||
@@ -520,6 +544,9 @@ _dl_allocate_tls_init (void *result)
|
||||
/* The DTV version is up-to-date now. */
|
||||
dtv[0].counter = maxgen;
|
||||
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_print_dtv ("_dl_allocate_tls_init return ", dtv, 10);
|
||||
|
||||
return result;
|
||||
}
|
||||
rtld_hidden_def (_dl_allocate_tls_init)
|
||||
@@ -533,6 +560,19 @@ _dl_allocate_tls (void *mem)
|
||||
}
|
||||
rtld_hidden_def (_dl_allocate_tls)
|
||||
|
||||
/* Clear the given dtv. (We have this here because __signal_safe_free is
|
||||
not visible to nptl/allocatestack.c.) */
|
||||
|
||||
void
|
||||
_dl_clear_dtv (dtv_t *dtv)
|
||||
{
|
||||
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
||||
__signal_safe_free (dtv[1 + cnt].pointer.to_free);
|
||||
|
||||
memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
|
||||
}
|
||||
|
||||
rtld_hidden_def (_dl_clear_dtv)
|
||||
|
||||
void
|
||||
_dl_deallocate_tls (void *tcb, bool dealloc_tcb)
|
||||
@@ -541,11 +581,11 @@ _dl_deallocate_tls (void *tcb, bool dealloc_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);
|
||||
__signal_safe_free (dtv[1 + cnt].pointer.to_free);
|
||||
|
||||
/* The array starts with dtv[-1]. */
|
||||
if (dtv != GL(dl_initial_dtv))
|
||||
free (dtv - 1);
|
||||
__signal_safe_free (dtv - 1);
|
||||
|
||||
if (dealloc_tcb)
|
||||
free (*tcb_to_pointer_to_free_location (tcb));
|
||||
@@ -617,6 +657,24 @@ allocate_and_init (struct link_map *map)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
signal_safe_allocate_and_init (dtv_t *dtv, struct link_map *map)
|
||||
{
|
||||
void *newp;
|
||||
newp = __signal_safe_memalign (map->l_tls_align, map->l_tls_blocksize);
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
|
||||
/* Initialize the memory. Since this is our thread's space, we are
|
||||
under a signal mask, and no one has touched this section before,
|
||||
we can safely just overwrite whatever's there. */
|
||||
memset (__mempcpy (newp, map->l_tls_initimage,
|
||||
map->l_tls_initimage_size),
|
||||
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||
|
||||
dtv->pointer.val = newp;
|
||||
dtv->pointer.to_free = newp;
|
||||
}
|
||||
|
||||
struct link_map *
|
||||
_dl_update_slotinfo (unsigned long int req_modid)
|
||||
@@ -624,6 +682,12 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
struct link_map *the_map = NULL;
|
||||
dtv_t *dtv = THREAD_DTV ();
|
||||
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
// (should mention module name?)
|
||||
_dl_debug_printf ("Updating slot info for own dtv 0x%0*Zx module %lu\n",
|
||||
(int) sizeof (void *) * 2, (unsigned long int) dtv,
|
||||
req_modid);
|
||||
|
||||
/* 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
|
||||
@@ -656,7 +720,25 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
the entry we need. */
|
||||
size_t new_gen = listp->slotinfo[idx].gen;
|
||||
size_t total = 0;
|
||||
sigset_t old;
|
||||
|
||||
if (GLRO(dl_async_signal_safe)) {
|
||||
_dl_mask_all_signals (&old);
|
||||
/* We use the signal mask as a lock against reentrancy here.
|
||||
Check that a signal taken before the lock didn't already
|
||||
update us. */
|
||||
dtv = THREAD_DTV ();
|
||||
if (dtv[0].counter >= listp->slotinfo[idx].gen)
|
||||
{
|
||||
_dl_unmask_signals (&old);
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("Slot info update for own dtv 0x%0*Zx module %lu done, exiting early\n",
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv,
|
||||
req_modid);
|
||||
return the_map;
|
||||
}
|
||||
}
|
||||
/* We have to look through the entire dtv slotinfo list. */
|
||||
listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
do
|
||||
@@ -684,7 +766,14 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
{
|
||||
/* If this modid was used at some point the memory
|
||||
might still be allocated. */
|
||||
free (dtv[total + cnt].pointer.to_free);
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("Slot info update for own dtv 0x%0*Zx module %lu unallocating 0x%0*Zx\n",
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv,
|
||||
total + cnt,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv[total + cnt].pointer.val);
|
||||
__signal_safe_free (dtv[total + cnt].pointer.to_free);
|
||||
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[total + cnt].pointer.to_free = NULL;
|
||||
}
|
||||
@@ -711,7 +800,14 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
dtv entry free it. */
|
||||
/* XXX Ideally we will at some point create a memory
|
||||
pool. */
|
||||
free (dtv[modid].pointer.to_free);
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("Slot info update for own dtv 0x%0*Zx module %lu unallocating 0x%0*Zx\n",
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv,
|
||||
modid,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv[modid].pointer.val);
|
||||
__signal_safe_free (dtv[modid].pointer.to_free);
|
||||
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[modid].pointer.to_free = NULL;
|
||||
|
||||
@@ -725,6 +821,8 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
|
||||
/* This will be the new maximum generation counter. */
|
||||
dtv[0].counter = new_gen;
|
||||
if (GLRO(dl_async_signal_safe))
|
||||
_dl_unmask_signals (&old);
|
||||
}
|
||||
|
||||
return the_map;
|
||||
@@ -750,6 +848,17 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
|
||||
|
||||
the_map = listp->slotinfo[idx].map;
|
||||
}
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
{
|
||||
char *map_name = (the_map->l_name ? the_map->l_name : "no name");
|
||||
_dl_debug_printf ("tls_get_addr_tail entry, own dtv 0x%0*Zx module %lu (%s) pointer.val = 0x%0*Zx\n",
|
||||
(int) sizeof (void *) * 2, (unsigned long int) dtv,
|
||||
GET_ADDR_MODULE, map_name,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv[GET_ADDR_MODULE].pointer.val);
|
||||
}
|
||||
|
||||
if (!GLRO(dl_async_signal_safe)) {
|
||||
|
||||
/* Make sure that, if a dlopen running in parallel forces the
|
||||
variable into static storage, we'll wait until the address in the
|
||||
@@ -778,6 +887,13 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
|
||||
|
||||
dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
|
||||
dtv[GET_ADDR_MODULE].pointer.val = p;
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("tls_get_addr_tail sets own dtv 0x%0*Zx module %lu pointer.val to 0x%0*Zx, returns\n",
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv,
|
||||
GET_ADDR_MODULE,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) p);
|
||||
|
||||
return (char *) p + GET_ADDR_OFFSET;
|
||||
}
|
||||
@@ -787,8 +903,120 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
|
||||
struct dtv_pointer result = allocate_and_init (the_map);
|
||||
dtv[GET_ADDR_MODULE].pointer = result;
|
||||
assert (result.to_free != NULL);
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("tls_get_addr_tail sets own dtv 0x%0*Zx module %lu pointer.val to 0x%0*Zx, returns\n",
|
||||
(int) sizeof (void *) * 2, (unsigned long int) dtv,
|
||||
GET_ADDR_MODULE,
|
||||
(int) sizeof (void *) * 2, (unsigned long int) result.val);
|
||||
|
||||
return (char *) result.val + GET_ADDR_OFFSET;
|
||||
|
||||
} else {
|
||||
|
||||
sigset_t old;
|
||||
_dl_mask_all_signals (&old);
|
||||
|
||||
/* As with update_slotinfo, we use the sigmask as a check against
|
||||
reentrancy. */
|
||||
if (dtv[GET_ADDR_MODULE].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
{
|
||||
_dl_unmask_signals (&old);
|
||||
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("tls_get_addr_tail keeps own dtv pointer.val, returns\n");
|
||||
|
||||
return (char *) dtv[GET_ADDR_MODULE].pointer.val + GET_ADDR_OFFSET;
|
||||
}
|
||||
|
||||
/* Synchronize against a parallel dlopen() forcing this variable
|
||||
into static storage. If that happens, we have to be more careful
|
||||
about initializing the area, as that dlopen() will be iterating
|
||||
the threads to do so itself. */
|
||||
ptrdiff_t offset = the_map->l_tls_offset;
|
||||
if (offset == NO_TLS_OFFSET)
|
||||
{
|
||||
/* l_tls_offset starts out at NO_TLS_OFFSET, and all attempts to
|
||||
change it go from NO_TLS_OFFSET to some other value. We use
|
||||
compare_and_exchange to ensure only one attempt succeeds. We
|
||||
don't actually need any memory ordering here, but _acq is the
|
||||
weakest available. */
|
||||
(void) atomic_compare_and_exchange_bool_acq (&the_map->l_tls_offset,
|
||||
FORCED_DYNAMIC_TLS_OFFSET,
|
||||
NO_TLS_OFFSET);
|
||||
offset = the_map->l_tls_offset;
|
||||
assert (offset != NO_TLS_OFFSET);
|
||||
}
|
||||
|
||||
if (offset == FORCED_DYNAMIC_TLS_OFFSET)
|
||||
{
|
||||
signal_safe_allocate_and_init (&dtv[GET_ADDR_MODULE], the_map);
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("tls_get_addr_tail allocates own dtv 0x%0*Zx module %lu pointer.val = 0x%0*Zx\n",
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv,
|
||||
GET_ADDR_MODULE,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv[GET_ADDR_MODULE].pointer.val);
|
||||
}
|
||||
/* It can happen that slot info updates will un-allocate a pointer (possibly
|
||||
due to a bug elsewhere), which leaves us waiting indefinitely for the
|
||||
dlopen that will never happen. Emulate the async-signal-unsafe case above
|
||||
and use a static TLS address. */
|
||||
else if (dtv[GET_ADDR_MODULE].pointer.val == TLS_DTV_UNALLOCATED)
|
||||
{
|
||||
#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
|
||||
dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
|
||||
dtv[GET_ADDR_MODULE].pointer.val = p;
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("tls_get_addr_tail sets unallocated own dtv 0x%0*Zx module %lu pointer.val = 0x%0*Zx\n",
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv,
|
||||
GET_ADDR_MODULE,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv[GET_ADDR_MODULE].pointer.val);
|
||||
}
|
||||
else
|
||||
{
|
||||
void ** volatile pp = &dtv[GET_ADDR_MODULE].pointer.val;
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("tls_get_addr_tail waiting for own dtv 0x%0*Zx module %lu to be allocated\n",
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv,
|
||||
GET_ADDR_MODULE);
|
||||
while (atomic_forced_read (*pp) == TLS_DTV_UNALLOCATED)
|
||||
{
|
||||
/* for lack of a better (safe) thing to do, just spin.
|
||||
Someone else (not us; it's done under a signal mask) set
|
||||
this map to a static TLS offset, and they'll iterate all
|
||||
threads to initialize it. They'll eventually write
|
||||
to pointer.val, at which point we know they've fully
|
||||
completed initialization. */
|
||||
atomic_spin_nop ();
|
||||
}
|
||||
/* Make sure we've picked up their initialization of the actual
|
||||
block; this pairs against the write barrier in
|
||||
init_one_static_tls, guaranteeing that we see their write of
|
||||
the tls_initimage into the static region. */
|
||||
atomic_read_barrier ();
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
_dl_debug_printf ("tls_get_addr_tail sees own dtv 0x%0*Zx module %lu has pointer.val = 0x%0*Zx\n",
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv,
|
||||
GET_ADDR_MODULE,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv[GET_ADDR_MODULE].pointer.val);
|
||||
}
|
||||
assert (dtv[GET_ADDR_MODULE].pointer.val != TLS_DTV_UNALLOCATED);
|
||||
_dl_unmask_signals (&old);
|
||||
|
||||
return (char *) dtv[GET_ADDR_MODULE].pointer.val + GET_ADDR_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -942,3 +1170,68 @@ cannot create TLS data structures"));
|
||||
listp->slotinfo[idx].map = l;
|
||||
listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
|
||||
}
|
||||
|
||||
/* Return a thread id of the current thread if we are debugging tls and the
|
||||
value is meaningful. */
|
||||
|
||||
pid_t
|
||||
_dl_tls_tid (void)
|
||||
{
|
||||
if (!__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
|
||||
return 0;
|
||||
|
||||
#ifdef SHARED
|
||||
if (GL(dl_initial_dtv) == NULL)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
struct pthread *thr = THREAD_SELF;
|
||||
|
||||
return thr->tid;
|
||||
}
|
||||
|
||||
/* Print all or part of a dtv. Note that the output may be large; for instance
|
||||
nptl/tst-stack4 has dtv's with hundreds of entries. */
|
||||
|
||||
static void
|
||||
_dl_print_dtv (const char *msg, dtv_t *dtv, int numentries)
|
||||
{
|
||||
size_t cnt, last_used, num_to_print, i;
|
||||
|
||||
cnt = dtv[-1].counter;
|
||||
last_used = 0;
|
||||
for (i = 1; i <= cnt; ++i)
|
||||
{
|
||||
if (dtv[i].pointer.val || dtv[i].pointer.to_free)
|
||||
last_used = i;
|
||||
}
|
||||
num_to_print = last_used;
|
||||
if (numentries >= 0 && numentries < num_to_print)
|
||||
num_to_print = numentries;
|
||||
_dl_debug_printf ("%sdtv 0x%0*Zx has %lu used of %lu entries, generation %lu\n",
|
||||
msg,
|
||||
(int) sizeof (void *) * 2, (unsigned long int) dtv,
|
||||
last_used, cnt, dtv[0].counter);
|
||||
for (i = 1; i <= num_to_print; ++i)
|
||||
{
|
||||
if (dtv[i].pointer.to_free == dtv[i].pointer.val)
|
||||
_dl_debug_printf ("%*lu: pointer.val = 0x%0*Zx to_free = same\n",
|
||||
4, i,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv[i].pointer.val);
|
||||
else if (dtv[i].pointer.to_free)
|
||||
_dl_debug_printf ("%*lu: pointer.val = 0x%0*Zx to_free = 0x%0*Zx\n",
|
||||
4, i,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv[i].pointer.val,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv[i].pointer.to_free);
|
||||
else
|
||||
_dl_debug_printf ("%*lu: pointer.val = 0x%0*Zx\n",
|
||||
4, i,
|
||||
(int) sizeof (void *) * 2,
|
||||
(unsigned long int) dtv[i].pointer.val);
|
||||
}
|
||||
if (num_to_print < last_used)
|
||||
_dl_debug_printf (" [...]\n");
|
||||
}
|
||||
|
||||
+17
-4
@@ -34,10 +34,23 @@ 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;
|
||||
if (name[0] == '\0')
|
||||
{
|
||||
/* Special case: both main exe and vdso can have empty name;
|
||||
so search from head: it is important to return the map for main
|
||||
a.out; else dlsym(0, ...) will fail unexpectedly. */
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (tmap = _dl_last_entry (&GL(dl_ns)[map->l_ns]); tmap != NULL;
|
||||
tmap = tmap->l_prev)
|
||||
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. */
|
||||
|
||||
+25
-5
@@ -41,7 +41,11 @@ 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)
|
||||
int lazy, int skip_ifunc
|
||||
#ifndef NESTING
|
||||
, struct link_map *boot_map
|
||||
#endif
|
||||
)
|
||||
{
|
||||
const ElfW(Rel) *r = (const void *) reladdr;
|
||||
const ElfW(Rel) *end = (const void *) (reladdr + relsize);
|
||||
@@ -136,7 +140,11 @@ elf_dynamic_do_Rel (struct link_map *map,
|
||||
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);
|
||||
(void *) (l_addr + r->r_offset), skip_ifunc
|
||||
#ifndef NESTING
|
||||
, boot_map
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
#if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
|
||||
@@ -150,7 +158,11 @@ elf_dynamic_do_Rel (struct link_map *map,
|
||||
&symtab[ELFW(R_SYM) (r2->r_info)],
|
||||
&map->l_versions[ndx],
|
||||
(void *) (l_addr + r2->r_offset),
|
||||
skip_ifunc);
|
||||
skip_ifunc
|
||||
#ifndef NESTING
|
||||
, boot_map
|
||||
#endif
|
||||
);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -168,7 +180,11 @@ elf_dynamic_do_Rel (struct link_map *map,
|
||||
else
|
||||
# endif
|
||||
elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
|
||||
(void *) (l_addr + r->r_offset), skip_ifunc);
|
||||
(void *) (l_addr + r->r_offset), skip_ifunc
|
||||
#ifndef NESTING
|
||||
, boot_map
|
||||
#endif
|
||||
);
|
||||
|
||||
# ifdef ELF_MACHINE_IRELATIVE
|
||||
if (r2 != NULL)
|
||||
@@ -176,7 +192,11 @@ elf_dynamic_do_Rel (struct link_map *map,
|
||||
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);
|
||||
skip_ifunc
|
||||
#ifndef NESTING
|
||||
, boot_map
|
||||
#endif
|
||||
);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
+133
-1
@@ -16,6 +16,10 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef NESTING
|
||||
#define auto static
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
@@ -70,7 +74,11 @@ elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
|
||||
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);
|
||||
void *const reloc_addr, int skip_ifunc
|
||||
#ifndef NESTING
|
||||
, struct link_map *boot_map
|
||||
#endif
|
||||
);
|
||||
auto inline void __attribute__((always_inline))
|
||||
elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
|
||||
void *const reloc_addr);
|
||||
@@ -113,6 +121,64 @@ elf_machine_lazy_rel (struct link_map *map,
|
||||
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. */
|
||||
|
||||
#ifndef NESTING
|
||||
# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel, boot_map) \
|
||||
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 } }; \
|
||||
\
|
||||
/* With DT_RELR, DT_RELA/DT_REL can have zero value. */ \
|
||||
if ((map)->l_info[DT_##RELOC] != NULL \
|
||||
&& (map)->l_info[DT_##RELOC]->d_un.d_ptr != 0) \
|
||||
{ \
|
||||
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 == 0) \
|
||||
ranges[0].start = start; \
|
||||
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, boot_map); \
|
||||
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, boot_map); \
|
||||
} \
|
||||
} while (0)
|
||||
#else /* NESTING */
|
||||
# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel) \
|
||||
do { \
|
||||
struct { ElfW(Addr) start, size; \
|
||||
@@ -165,6 +231,7 @@ elf_machine_lazy_rel (struct link_map *map,
|
||||
skip_ifunc); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif /* NESTING */
|
||||
|
||||
# if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
|
||||
# define _ELF_CHECK_REL 0
|
||||
@@ -172,6 +239,70 @@ elf_machine_lazy_rel (struct link_map *map,
|
||||
# define _ELF_CHECK_REL 1
|
||||
# endif
|
||||
|
||||
#ifndef NESTING
|
||||
# if ! ELF_MACHINE_NO_REL
|
||||
# include "do-rel.h"
|
||||
# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc, boot_map) \
|
||||
_ELF_DYNAMIC_DO_RELOC (REL, Rel, map, lazy, skip_ifunc, _ELF_CHECK_REL, boot_map)
|
||||
# else
|
||||
# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc, boot_map) /* 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, boot_map) \
|
||||
_ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, lazy, skip_ifunc, _ELF_CHECK_REL, boot_map)
|
||||
# else
|
||||
# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc, boot_map) /* Nothing to do. */
|
||||
# endif
|
||||
|
||||
/* Google-local: b/208156916. To not bump DT_NUM, use DT_VERSYM+1 for DT_RELR
|
||||
and DT_VERSYM+2 for DT_RELRSZ. */
|
||||
# define ELF_DYNAMIC_DO_RELR(map) \
|
||||
do { \
|
||||
ElfW(Addr) l_addr = (map)->l_addr, *where = 0; \
|
||||
const ElfW(Relr) *r, *end; \
|
||||
if (!(map)->l_info[VERSYMIDX (DT_VERSYM + 1)]) \
|
||||
break; \
|
||||
r = (const ElfW(Relr) *)D_PTR((map), l_info[VERSYMIDX (DT_VERSYM + 1)]); \
|
||||
end = (const ElfW(Relr) *)((const char *)r + \
|
||||
(map)->l_info[VERSYMIDX (DT_VERSYM + 2)]->d_un.d_val); \
|
||||
for (; r < end; r++) \
|
||||
{ \
|
||||
ElfW(Relr) entry = *r; \
|
||||
if ((entry & 1) == 0) \
|
||||
{ \
|
||||
where = (ElfW(Addr) *)(l_addr + entry); \
|
||||
*where++ += l_addr; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
for (long i = 0; (entry >>= 1) != 0; i++) \
|
||||
if ((entry & 1) != 0) \
|
||||
where[i] += l_addr; \
|
||||
where += CHAR_BIT * sizeof(ElfW(Relr)) - 1; \
|
||||
} \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
/* This can't just be an inline function because GCC is too dumb
|
||||
to inline functions containing inlines themselves. */
|
||||
# ifdef RTLD_BOOTSTRAP
|
||||
# define DO_RTLD_BOOTSTRAP 1
|
||||
# else
|
||||
# define DO_RTLD_BOOTSTRAP 0
|
||||
# endif
|
||||
# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile, skip_ifunc, boot_map) \
|
||||
do { \
|
||||
int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
|
||||
(consider_profile)); \
|
||||
if (((map) != &GL(dl_rtld_map) || DO_RTLD_BOOTSTRAP)) \
|
||||
ELF_DYNAMIC_DO_RELR (map); \
|
||||
ELF_DYNAMIC_DO_REL ((map), edr_lazy, skip_ifunc, boot_map); \
|
||||
ELF_DYNAMIC_DO_RELA ((map), edr_lazy, skip_ifunc, boot_map); \
|
||||
} while (0)
|
||||
#else /* NESTING */
|
||||
# if ! ELF_MACHINE_NO_REL
|
||||
# include "do-rel.h"
|
||||
# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) \
|
||||
@@ -198,5 +329,6 @@ elf_machine_lazy_rel (struct link_map *map,
|
||||
ELF_DYNAMIC_DO_REL ((map), edr_lazy, skip_ifunc); \
|
||||
ELF_DYNAMIC_DO_RELA ((map), edr_lazy, skip_ifunc); \
|
||||
} while (0)
|
||||
#endif /* NESTING */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -444,8 +444,9 @@ typedef struct
|
||||
#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_SYMTAB_SHNDX 18 /* Extended section indices */
|
||||
#define SHT_RELR 19 /* RELR relative relocations */
|
||||
#define SHT_NUM 20 /* 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. */
|
||||
@@ -663,6 +664,11 @@ typedef struct
|
||||
Elf64_Sxword r_addend; /* Addend */
|
||||
} Elf64_Rela;
|
||||
|
||||
/* RELR relocation table entry */
|
||||
|
||||
typedef Elf32_Word Elf32_Relr;
|
||||
typedef Elf64_Xword Elf64_Relr;
|
||||
|
||||
/* How to extract and insert information held in the r_info field. */
|
||||
|
||||
#define ELF32_R_SYM(val) ((val) >> 8)
|
||||
@@ -861,6 +867,11 @@ typedef struct
|
||||
#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_SYMTAB_SHNDX 34 /* Address of SYMTAB_SHNDX section */
|
||||
#define DT_RELRSZ 35 /* Total size of RELR relative relocations */
|
||||
#define DT_RELR 36 /* Address of RELR relative relocations */
|
||||
#define DT_RELRENT 37 /* Size of one RELR relative relocaction */
|
||||
/* Google-local: b/208156916. Don't bump DT_NUM. */
|
||||
#define DT_NUM 34 /* Number used */
|
||||
#define DT_LOOS 0x6000000d /* Start of OS-specific */
|
||||
#define DT_HIOS 0x6ffff000 /* End of OS-specific */
|
||||
|
||||
+31
-5
@@ -22,6 +22,8 @@
|
||||
#include <assert.h>
|
||||
#include <libc-diag.h>
|
||||
|
||||
#if defined NESTING || !defined SAW_EGDI
|
||||
|
||||
#ifndef RESOLVE_MAP
|
||||
static
|
||||
#else
|
||||
@@ -47,7 +49,12 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
|
||||
|
||||
while (dyn->d_tag != DT_NULL)
|
||||
{
|
||||
if ((d_tag_utype) dyn->d_tag < DT_NUM)
|
||||
/* Google-local: b/208156916. See ELF_DYNAMIC_DO_RELR. */
|
||||
if (dyn->d_tag == DT_RELR)
|
||||
info[VERSYMIDX (DT_VERSYM + 1)] = dyn;
|
||||
else if (dyn->d_tag == DT_RELRSZ)
|
||||
info[VERSYMIDX (DT_VERSYM + 2)] = dyn;
|
||||
else 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)
|
||||
@@ -102,16 +109,27 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
|
||||
ADJUST_DYN_INFO (DT_PLTGOT);
|
||||
ADJUST_DYN_INFO (DT_STRTAB);
|
||||
ADJUST_DYN_INFO (DT_SYMTAB);
|
||||
ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM + 1)); /* DT_RELR */
|
||||
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
|
||||
|
||||
/* DT_RELA/DT_REL are mandatory. But they may have zero value if
|
||||
there is DT_RELR. Don't relocate them if they are zero. */
|
||||
# define ADJUST_DYN_INFO(tag) \
|
||||
do \
|
||||
if (info[tag] != NULL && info[tag]->d_un.d_ptr != 0) \
|
||||
info[tag]->d_un.d_ptr += l_addr; \
|
||||
while (0)
|
||||
|
||||
# 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);
|
||||
}
|
||||
@@ -184,3 +202,11 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
|
||||
info[DT_RPATH] = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef NESTING
|
||||
#ifndef SAW_EGDI
|
||||
#define SAW_EGDI
|
||||
#endif
|
||||
#endif /* n NESTING */
|
||||
|
||||
+4
-4
@@ -34,6 +34,8 @@
|
||||
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
|
||||
#include <bits/link.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* 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
|
||||
@@ -162,8 +164,6 @@ struct dl_phdr_info
|
||||
void *dlpi_tls_data;
|
||||
};
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern int dl_iterate_phdr (int (*__callback) (struct dl_phdr_info *,
|
||||
size_t, void *),
|
||||
void *__data);
|
||||
@@ -187,8 +187,8 @@ extern uintptr_t la_symbind64 (Elf64_Sym *__sym, unsigned int __ndx,
|
||||
unsigned int *__flags, const char *__symname);
|
||||
extern unsigned int la_objclose (uintptr_t *__cookie);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* link.h */
|
||||
|
||||
+185
-16
@@ -41,6 +41,7 @@
|
||||
#include <tls.h>
|
||||
#include <stap-probe.h>
|
||||
#include <stackinfo.h>
|
||||
#include <not-cancel.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -51,6 +52,12 @@ extern __typeof (__mempcpy) __mempcpy attribute_hidden;
|
||||
extern __typeof (_exit) exit_internal asm ("_exit") attribute_hidden;
|
||||
#define _exit exit_internal
|
||||
|
||||
/* Iterate over auxv, find AT_EXECFN if any. */
|
||||
static char * get_at_execfn(ElfW(auxv_t) *auxv);
|
||||
|
||||
/* Given file path, return fully resolved directory path. */
|
||||
static char * get_directory (const char *file_path);
|
||||
|
||||
/* Helper function to handle errors while resolving symbols. */
|
||||
static void print_unresolved (int errcode, const char *objname,
|
||||
const char *errsting);
|
||||
@@ -73,6 +80,9 @@ enum mode { normal, list, verify, trace };
|
||||
all the entries. */
|
||||
static void process_envvars (enum mode *modep);
|
||||
|
||||
/* Set GLRO(google_exec_origin_dir). */
|
||||
static void set_exec_origin_dir(const char *exe_path);
|
||||
|
||||
#ifdef DL_ARGV_NOT_RELRO
|
||||
int _dl_argc attribute_hidden;
|
||||
char **_dl_argv = NULL;
|
||||
@@ -282,6 +292,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
|
||||
._dl_open = _dl_open,
|
||||
._dl_close = _dl_close,
|
||||
._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
|
||||
._dl_position_hash_cutoff = DL_POSITION_HASH_CUTOFF_DEFAULT,
|
||||
#ifdef HAVE_DL_DISCOVER_OSVERSION
|
||||
._dl_discover_osversion = _dl_discover_osversion
|
||||
#endif
|
||||
@@ -439,9 +450,30 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
|
||||
return start_addr;
|
||||
}
|
||||
|
||||
#ifndef NESTING
|
||||
#ifdef DONT_USE_BOOTSTRAP_MAP
|
||||
# define bootstrap_map GL(dl_rtld_map)
|
||||
#else
|
||||
# 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"
|
||||
#endif /* n NESTING */
|
||||
|
||||
static ElfW(Addr) __attribute_used__
|
||||
_dl_start (void *arg)
|
||||
{
|
||||
#ifndef NESTING
|
||||
#ifndef DONT_USE_BOOTSTRAP_MAP
|
||||
struct dl_start_final_info info;
|
||||
#endif /* DUBM */
|
||||
#else /* NESTING */
|
||||
#ifdef DONT_USE_BOOTSTRAP_MAP
|
||||
# define bootstrap_map GL(dl_rtld_map)
|
||||
#else
|
||||
@@ -457,6 +489,7 @@ _dl_start (void *arg)
|
||||
#define BOOTSTRAP_MAP (&bootstrap_map)
|
||||
#define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP
|
||||
#include "dynamic-link.h"
|
||||
#endif /* NESTING */
|
||||
|
||||
if (HP_TIMING_INLINE && HP_SMALL_TIMING_AVAIL)
|
||||
#ifdef DONT_USE_BOOTSTRAP_MAP
|
||||
@@ -502,7 +535,11 @@ _dl_start (void *arg)
|
||||
/* 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);
|
||||
ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0, 0
|
||||
#ifndef NESTING
|
||||
, &bootstrap_map
|
||||
#endif
|
||||
);
|
||||
}
|
||||
bootstrap_map.l_relocated = 1;
|
||||
|
||||
@@ -588,7 +625,7 @@ 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->map = _dl_map_object (args->loader, args->str, 0, type, 0,
|
||||
args->mode, LM_ID_BASE);
|
||||
}
|
||||
|
||||
@@ -596,7 +633,7 @@ static void
|
||||
dlmopen_doit (void *a)
|
||||
{
|
||||
struct dlmopen_args *args = (struct dlmopen_args *) a;
|
||||
args->map = _dl_open (args->fname,
|
||||
args->map = _dl_open (args->fname, 0,
|
||||
(RTLD_LAZY | __RTLD_DLOPEN | __RTLD_AUDIT
|
||||
| __RTLD_SECURE),
|
||||
dl_main, LM_ID_NEWLM, _dl_argc, _dl_argv,
|
||||
@@ -1007,6 +1044,8 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
in LIST\n\
|
||||
--audit LIST use objects named in LIST as auditors\n");
|
||||
|
||||
set_exec_origin_dir (_dl_argv[1]);
|
||||
|
||||
++_dl_skip_args;
|
||||
--_dl_argc;
|
||||
++_dl_argv;
|
||||
@@ -1050,7 +1089,7 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
else
|
||||
{
|
||||
HP_TIMING_NOW (start);
|
||||
_dl_map_object (NULL, rtld_progname, lt_executable, 0,
|
||||
_dl_map_object (NULL, rtld_progname, 0, lt_executable, 0,
|
||||
__RTLD_OPENEXEC, LM_ID_BASE);
|
||||
HP_TIMING_NOW (stop);
|
||||
|
||||
@@ -1101,6 +1140,8 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
}
|
||||
else
|
||||
{
|
||||
set_exec_origin_dir (get_at_execfn (auxv));
|
||||
|
||||
/* Create a link_map for the executable itself.
|
||||
This will be what dlopen on "" returns. */
|
||||
main_map = _dl_new_object ((char *) "", "", lt_executable, NULL,
|
||||
@@ -1335,6 +1376,7 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
GL(dl_rtld_map).l_type = lt_library;
|
||||
main_map->l_next = &GL(dl_rtld_map);
|
||||
GL(dl_rtld_map).l_prev = main_map;
|
||||
_dl_hash_add_object (&GL(dl_rtld_map));
|
||||
++GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
|
||||
++GL(dl_load_adds);
|
||||
|
||||
@@ -1344,21 +1386,16 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
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
|
||||
|
||||
/* 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 = &__ehdr_start;
|
||||
assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
|
||||
assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
|
||||
|
||||
@@ -1722,6 +1759,11 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
dependencies in the executable's searchlist for symbol resolution. */
|
||||
HP_TIMING_NOW (start);
|
||||
_dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0);
|
||||
|
||||
/* We have now finished loading every required (linked-in) object.
|
||||
Set up the position hash if needed. */
|
||||
_dl_fill_position_hash (main_map);
|
||||
|
||||
HP_TIMING_NOW (stop);
|
||||
HP_TIMING_DIFF (diff, start, stop);
|
||||
HP_TIMING_ACCUM_NT (load_time, diff);
|
||||
@@ -2349,10 +2391,14 @@ process_dl_debug (const char *dl_debug)
|
||||
DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS },
|
||||
{ LEN_AND_STR ("scopes"), "display scope information",
|
||||
DL_DEBUG_SCOPES },
|
||||
{ LEN_AND_STR ("tls"), "display thread-local storage processing",
|
||||
DL_DEBUG_TLS },
|
||||
{ LEN_AND_STR ("fastload"), "display fastload information",
|
||||
DL_DEBUG_FASTLOAD },
|
||||
{ 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 },
|
||||
| DL_DEBUG_SCOPES | DL_DEBUG_FASTLOAD },
|
||||
{ LEN_AND_STR ("statistics"), "display relocation statistics",
|
||||
DL_DEBUG_STATISTICS },
|
||||
{ LEN_AND_STR ("unused"), "determined unused DSOs",
|
||||
@@ -2464,6 +2510,9 @@ process_envvars (enum mode *modep)
|
||||
enum mode mode = normal;
|
||||
char *debug_output = NULL;
|
||||
|
||||
/* Enable async-signal-safe TLS by default. */
|
||||
GLRO(dl_async_signal_safe) = 1;
|
||||
|
||||
/* This is the default place for profiling data file. */
|
||||
GLRO(dl_profile_output)
|
||||
= &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];
|
||||
@@ -2487,6 +2536,10 @@ process_envvars (enum mode *modep)
|
||||
/* Warning level, verbose or not. */
|
||||
if (memcmp (envline, "WARN", 4) == 0)
|
||||
GLRO(dl_verbose) = envline[5] != '\0';
|
||||
#if 0 /* enable to get runtime control over async signal safety */
|
||||
if (memcmp (envline, "SAFE", 4) == 0)
|
||||
GLRO(dl_async_signal_safe) = 1;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 5:
|
||||
@@ -2499,7 +2552,12 @@ process_envvars (enum mode *modep)
|
||||
if (memcmp (envline, "AUDIT", 5) == 0)
|
||||
audit_list_string = &envline[6];
|
||||
break;
|
||||
|
||||
#if 0 /* enable to get runtime control over async signal safety */
|
||||
case 6:
|
||||
if (memcmp (envline, "UNSAFE", 6) == 0)
|
||||
GLRO(dl_async_signal_safe) = 0;
|
||||
break;
|
||||
#endif
|
||||
case 7:
|
||||
/* Print information about versions. */
|
||||
if (memcmp (envline, "VERBOSE", 7) == 0)
|
||||
@@ -2623,11 +2681,36 @@ process_envvars (enum mode *modep)
|
||||
EXTRA_LD_ENVVARS
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Handle all fastload-related env vars here. This may duplicate
|
||||
effort with the switch table above, but it localizes changes
|
||||
made by the fastload patch. On Linux, the '15' case is used
|
||||
by another environment variable (LIBRARY_VERSION) and much
|
||||
change would be needed to add support adding a variable of
|
||||
that length with the existing style. */
|
||||
switch (len)
|
||||
{
|
||||
case 15:
|
||||
if (memcmp (envline, "FASTLOAD_CUTOFF", 15) == 0)
|
||||
GLRO(dl_position_hash_cutoff)
|
||||
= _dl_strtoul (&envline[16], NULL);;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The caller wants this information. */
|
||||
*modep = mode;
|
||||
|
||||
#if 0 /* enable this to help debug async-safe TLS */
|
||||
if (GLRO(dl_debug_mask))
|
||||
{
|
||||
if (GLRO(dl_async_signal_safe))
|
||||
_dl_printf ("TLS is async-signal-safe\n");
|
||||
else
|
||||
_dl_printf ("TLS is NOT async-signal-safe\n");
|
||||
}
|
||||
#endif /* for async-safe TLS */
|
||||
|
||||
/* Extra security for SUID binaries. Remove all dangerous environment
|
||||
variables. */
|
||||
if (__builtin_expect (__libc_enable_secure, 0))
|
||||
@@ -2674,7 +2757,7 @@ process_envvars (enum mode *modep)
|
||||
*--startp = '.';
|
||||
startp = memcpy (startp - name_len, debug_output, name_len);
|
||||
|
||||
GLRO(dl_debug_fd) = __open (startp, flags, DEFFILEMODE);
|
||||
GLRO(dl_debug_fd) = __open64_nocancel (startp, flags, DEFFILEMODE);
|
||||
if (GLRO(dl_debug_fd) == -1)
|
||||
/* We use standard output if opening the file failed. */
|
||||
GLRO(dl_debug_fd) = STDOUT_FILENO;
|
||||
@@ -2785,3 +2868,89 @@ print_statistics (hp_timing_t *rtld_total_timep)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Given file path, return an absolute directory path.
|
||||
Examples: in: "/foo/bar/a.out", out: "/foo/bar/";
|
||||
in: "./a.out", out: "/dot/resolved/to/full/path/./". */
|
||||
static char *
|
||||
get_directory (const char *file_path)
|
||||
{
|
||||
assert (file_path != NULL);
|
||||
|
||||
/* Find the end of the directory substring in file_path. */
|
||||
size_t path_len = strlen (file_path);
|
||||
while (path_len > 0 && file_path[path_len - 1] != '/')
|
||||
--path_len;
|
||||
|
||||
/* Allocate space and set the path prefix according to whether or not
|
||||
this is an absolute path. */
|
||||
char *dest;
|
||||
char *full_dir_path;
|
||||
if (file_path[0] == '/')
|
||||
{
|
||||
full_dir_path = malloc (path_len + 1);
|
||||
assert (full_dir_path != NULL);
|
||||
dest = full_dir_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For a relative path, we need to include space for the largest
|
||||
possible current path, a joining '/', the relevant part of
|
||||
file_path, and a trailing '\0'. */
|
||||
full_dir_path = malloc (PATH_MAX + path_len + 2);
|
||||
assert (full_dir_path != NULL);
|
||||
|
||||
char *status = __getcwd (full_dir_path, PATH_MAX);
|
||||
assert (status != NULL);
|
||||
|
||||
dest = __rawmemchr (full_dir_path, '\0');
|
||||
if (dest[-1] != '/')
|
||||
*dest++ = '/';
|
||||
}
|
||||
|
||||
if (path_len > 0)
|
||||
dest = __mempcpy (dest, file_path, path_len);
|
||||
*dest = '\0';
|
||||
|
||||
return full_dir_path;
|
||||
}
|
||||
|
||||
/* Set GLRO(google_exec_origin_dir). */
|
||||
static void
|
||||
set_exec_origin_dir (const char *exe_path)
|
||||
{
|
||||
assert (GLRO(google_exec_origin_dir) == NULL);
|
||||
|
||||
if (GLRO(dl_origin_path) != NULL)
|
||||
GLRO(google_exec_origin_dir) = strdup (GLRO(dl_origin_path));
|
||||
else if (exe_path != NULL)
|
||||
GLRO(google_exec_origin_dir) = get_directory (exe_path);
|
||||
}
|
||||
|
||||
/* Iterate over auxv, find AT_EXECFN if any. */
|
||||
static char *
|
||||
get_at_execfn (ElfW(auxv_t) *auxv)
|
||||
{
|
||||
assert (auxv != NULL);
|
||||
|
||||
for (; auxv->a_type != AT_NULL; ++auxv)
|
||||
if (auxv->a_type == AT_EXECFN)
|
||||
return (char *) auxv->a_un.a_val;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef NESTING
|
||||
char *dummy1 = (char *)elf_get_dynamic_info;
|
||||
# if ! ELF_MACHINE_NO_REL
|
||||
char *dummy2 = (char *)elf_machine_rel;
|
||||
char *dummy3 = (char *)elf_machine_rel_relative;
|
||||
#endif
|
||||
# if ! ELF_MACHINE_NO_RELA
|
||||
char *dummy4 = (char *)elf_machine_rela;
|
||||
char *dummy5 = (char *)elf_machine_rela_relative;
|
||||
#endif
|
||||
# if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL
|
||||
char *dummy6 = (char *)elf_machine_lazy_rel;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/* 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
|
||||
@@ -0,0 +1,26 @@
|
||||
/* Bug 20419: test for stack overflow in elf/dl-load.c open_verify()
|
||||
Copyright (C) 2018 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 creates a .so with 8MiB PT_NOTE segment.
|
||||
On a typical Linux system with 8MiB "ulimit -s", that was enough
|
||||
to trigger stack overflow in open_verify. */
|
||||
|
||||
.pushsection .note.big,"a"
|
||||
.balign 4
|
||||
.fill 8*1024*1024, 1, 0
|
||||
.popsection
|
||||
@@ -0,0 +1,26 @@
|
||||
/* Bug 20419: test for stack overflow in elf/dl-load.c open_verify()
|
||||
Copyright (C) 2018 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 run from within a directory called "elf". */
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
/* Nothing to do here: merely linking against tst-big-note-lib.so triggers
|
||||
the bug. */
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
foo (void)
|
||||
{
|
||||
printf ("In %s:%s\n", __FILE__, __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
foosub (void)
|
||||
{
|
||||
printf ("In %s:%s\n", __FILE__, __func__);
|
||||
return 20;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
bar (void)
|
||||
{
|
||||
printf ("In %s:%s\n", __FILE__, __func__);
|
||||
return 123;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
xyzzy (void)
|
||||
{
|
||||
printf ("In %s:%s\n", __FILE__, __func__);
|
||||
return 21;
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* These numbers need to be coordinated with the offsets passed to make the combined .so. */
|
||||
int offa = 64;
|
||||
int offb = 128;
|
||||
int offc = 192;
|
||||
|
||||
int
|
||||
do_test (void)
|
||||
{
|
||||
void *p1 = __google_dlopen_with_offset ("$ORIGIN/tst-dlopen-offset-comb.so", offa * 1024, RTLD_LAZY);
|
||||
|
||||
if (!p1)
|
||||
{
|
||||
puts (dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int (*f) (void) = dlsym (p1, "foo");
|
||||
if (f)
|
||||
{
|
||||
(*f)();
|
||||
}
|
||||
else
|
||||
{
|
||||
puts (dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *p2 = __google_dlopen_with_offset ("$ORIGIN/tst-dlopen-offset-comb.so", offb * 1024, RTLD_LAZY);
|
||||
|
||||
int (*bar) (void) = dlsym (p2, "bar");
|
||||
if (bar)
|
||||
{
|
||||
(*bar)();
|
||||
}
|
||||
else
|
||||
{
|
||||
puts (dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *p3 = __google_dlopen_with_offset ("$ORIGIN/tst-dlopen-offset-comb.so", offc * 1024, RTLD_LAZY);
|
||||
|
||||
int (*xyzzy) (void) = dlsym (p3, "xyzzy");
|
||||
if (xyzzy)
|
||||
{
|
||||
(*xyzzy)();
|
||||
}
|
||||
else
|
||||
{
|
||||
puts (dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (p1)
|
||||
dlclose (p1);
|
||||
|
||||
p1 = __google_dlopen_with_offset ("$ORIGIN/tst-dlopen-offset-comb.so", offa * 1024, RTLD_LAZY);
|
||||
|
||||
f = dlsym (p1, "someothersym");
|
||||
if (!f)
|
||||
{
|
||||
puts (dlerror ());
|
||||
puts (" (expected)");
|
||||
}
|
||||
else
|
||||
{
|
||||
puts ("Symbol found unexpectedly");
|
||||
return 1;
|
||||
}
|
||||
|
||||
f = dlsym (p1, "xyzzy");
|
||||
if (!f)
|
||||
{
|
||||
puts (dlerror ());
|
||||
puts (" (expected)");
|
||||
}
|
||||
else
|
||||
{
|
||||
puts ("Symbol found unexpectedly");
|
||||
return 1;
|
||||
}
|
||||
|
||||
p1 = __google_dlopen_with_offset ("$ORIGIN/tst-dlopen-offset-comb.so", offa * 1024, RTLD_LAZY);
|
||||
|
||||
f = dlsym (p1, "foo");
|
||||
if (f)
|
||||
{
|
||||
(*f)();
|
||||
}
|
||||
else
|
||||
{
|
||||
puts (dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *px = __google_dlopen_with_offset ("$ORIGIN/tst-dlopen-offset-comb.so", 0, RTLD_LAZY);
|
||||
|
||||
if (!px)
|
||||
{
|
||||
puts (dlerror ());
|
||||
puts (" (expected)");
|
||||
}
|
||||
else
|
||||
{
|
||||
puts ("dlopen_with_offset succeeded unexpectedly");
|
||||
return 1;
|
||||
}
|
||||
|
||||
px = __google_dlopen_with_offset ("$ORIGIN/tst-dlopen-offset-mod1.so", 0, RTLD_LAZY);
|
||||
|
||||
f = dlsym (px, "foo");
|
||||
if (f)
|
||||
{
|
||||
(*f)();
|
||||
}
|
||||
else
|
||||
{
|
||||
puts (dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
px = __google_dlopen_with_offset ("$ORIGIN/nonexistent.so", 0, RTLD_LAZY);
|
||||
|
||||
if (!px)
|
||||
{
|
||||
puts (dlerror ());
|
||||
puts (" (expected)");
|
||||
}
|
||||
else
|
||||
{
|
||||
puts ("dlopen_with_offset succeeded unexpectedly");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TIMEOUT 100
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Test for DT_RELR in a shared library without DT_NEEDED.
|
||||
Copyright (C) 2022 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <array_length.h>
|
||||
|
||||
static int o, x;
|
||||
|
||||
#define ELEMS O O O O O O O O X X X X X X X O O X O O X X X E X E E O X O E
|
||||
#define E 0,
|
||||
|
||||
#define O &o,
|
||||
#define X &x,
|
||||
void *arr[] = { ELEMS };
|
||||
#undef O
|
||||
#undef X
|
||||
|
||||
#define O 1,
|
||||
#define X 2,
|
||||
static char val[] = { ELEMS };
|
||||
|
||||
int
|
||||
foo (void)
|
||||
{
|
||||
int err = 0;
|
||||
for (int i = 0; i < array_length (arr); i++)
|
||||
if (!((arr[i] == 0 && val[i] == 0)
|
||||
|| (arr[i] == &o && val[i] == 1)
|
||||
|| (arr[i] == &x && val[i] == 2)))
|
||||
err++;
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* Test for DT_RELR in a shared library without DT_VERNEED.
|
||||
Copyright (C) 2022 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <array_length.h>
|
||||
|
||||
static int o, x;
|
||||
|
||||
#define ELEMS O O O O O O O O X X X X X X X O O X O O X X X E X E E O X O E
|
||||
#define E 0,
|
||||
|
||||
#define O &o,
|
||||
#define X &x,
|
||||
void *arr[] = { ELEMS };
|
||||
#undef O
|
||||
#undef X
|
||||
|
||||
#define O 1,
|
||||
#define X 2,
|
||||
static char val[] = { ELEMS };
|
||||
|
||||
extern void bar (void);
|
||||
|
||||
int
|
||||
foo (void)
|
||||
{
|
||||
int err = 0;
|
||||
for (int i = 0; i < array_length (arr); i++)
|
||||
if (!((arr[i] == 0 && val[i] == 0)
|
||||
|| (arr[i] == &o && val[i] == 1)
|
||||
|| (arr[i] == &x && val[i] == 2)))
|
||||
err++;
|
||||
bar ();
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* Test for DT_RELR in a shared library without DT_VERNEED.
|
||||
Copyright (C) 2022 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
void
|
||||
bar (void)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/* Test for DT_RELR in a shared library without libc.so on DT_NEEDED.
|
||||
Copyright (C) 2022 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "tst-relr-mod3a.c"
|
||||
@@ -0,0 +1,19 @@
|
||||
/* Test for DT_RELR in a shared library without libc.so on DT_NEEDED.
|
||||
Copyright (C) 2022 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "tst-relr-mod3b.c"
|
||||
@@ -0,0 +1,3 @@
|
||||
DT_RELR {
|
||||
global: bar;
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
#include "tst-relr.c"
|
||||
@@ -0,0 +1,65 @@
|
||||
/* Basic tests for DT_RELR.
|
||||
Copyright (C) 2022 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <link.h>
|
||||
#include <stdbool.h>
|
||||
#include <array_length.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int o, x;
|
||||
|
||||
#define ELEMS O O O O O O O O X X X X X X X O O X O O X X X E X E E O X O E
|
||||
#define E 0,
|
||||
|
||||
#define O &o,
|
||||
#define X &x,
|
||||
void *arr[] = { ELEMS };
|
||||
#undef O
|
||||
#undef X
|
||||
|
||||
#define O 1,
|
||||
#define X 2,
|
||||
static char val[] = { ELEMS };
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
ElfW(Dyn) *d = _DYNAMIC;
|
||||
if (d)
|
||||
{
|
||||
bool has_relr = false;
|
||||
for (; d->d_tag != DT_NULL; d++)
|
||||
if (d->d_tag == DT_RELR)
|
||||
has_relr = true;
|
||||
|
||||
#if defined __PIE__ || defined __pie__ || defined PIE || defined pie
|
||||
TEST_VERIFY (has_relr);
|
||||
#else
|
||||
TEST_VERIFY (!has_relr);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (int i = 0; i < array_length (arr); i++)
|
||||
TEST_VERIFY ((arr[i] == 0 && val[i] == 0)
|
||||
|| (arr[i] == &o && val[i] == 1)
|
||||
|| (arr[i] == &x && val[i] == 2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,27 @@
|
||||
/* Test for DT_RELR in a shared library without DT_NEEDED.
|
||||
Copyright (C) 2022 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
extern int foo (void);
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
return foo ();
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,27 @@
|
||||
/* Test for DT_RELR in a shared library without libc.so on DT_NEEDED.
|
||||
Copyright (C) 2022 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
extern int foo (void);
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
return foo ();
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1 @@
|
||||
#include "tst-relr3.c"
|
||||
+25
-39
@@ -1,13 +1,14 @@
|
||||
/* 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);
|
||||
|
||||
__thread int foo, bar __attribute__ ((tls_model("local-exec")));
|
||||
extern __thread int foo_gd asm ("foo") __attribute__ ((tls_model("global-dynamic")));
|
||||
extern __thread int foo_ld asm ("foo") __attribute__ ((tls_model("local-dynamic")));
|
||||
extern __thread int foo_ie asm ("foo") __attribute__ ((tls_model("initial-exec")));
|
||||
extern __thread int bar_gd asm ("bar") __attribute__ ((tls_model("global-dynamic")));
|
||||
extern __thread int bar_ld asm ("bar") __attribute__ ((tls_model("local-dynamic")));
|
||||
extern __thread int bar_ie asm ("bar") __attribute__ ((tls_model("initial-exec")));
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
@@ -18,63 +19,48 @@ do_test (void)
|
||||
|
||||
/* Set the variable using the local exec model. */
|
||||
puts ("set bar to 1 (LE)");
|
||||
ap = TLS_LE (bar);
|
||||
*ap = 1;
|
||||
bar = 1;
|
||||
|
||||
|
||||
/* Get variables using initial exec model. */
|
||||
fputs ("get sum of foo and bar (IE)", stdout);
|
||||
ap = TLS_IE (foo);
|
||||
bp = TLS_IE (bar);
|
||||
ap = &foo_ie;
|
||||
bp = &bar_ie;
|
||||
printf (" = %d\n", *ap + *bp);
|
||||
result |= *ap + *bp != 1;
|
||||
if (*ap != 0)
|
||||
if (*ap != 0 || *bp != 1)
|
||||
{
|
||||
printf ("foo = %d\n", *ap);
|
||||
result = 1;
|
||||
}
|
||||
if (*bp != 1)
|
||||
{
|
||||
printf ("bar = %d\n", *bp);
|
||||
printf ("foo = %d\nbar = %d\n", *ap, *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);
|
||||
/* Get variables using local dynamic model or TLSDESC. */
|
||||
fputs ("get sum of foo and bar (LD or TLSDESC)", stdout);
|
||||
ap = &foo_ld;
|
||||
bp = &bar_ld;
|
||||
printf (" = %d\n", *ap + *bp);
|
||||
result |= *ap + *bp != 1;
|
||||
if (*ap != 0)
|
||||
if (*ap != 0 || *bp != 1)
|
||||
{
|
||||
printf ("foo = %d\n", *ap);
|
||||
result = 1;
|
||||
}
|
||||
if (*bp != 1)
|
||||
{
|
||||
printf ("bar = %d\n", *bp);
|
||||
printf ("foo = %d\nbar = %d\n", *ap, *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);
|
||||
/* Get variables using general dynamic model or TLSDESC. */
|
||||
fputs ("get sum of foo and bar (GD or TLSDESC)", stdout);
|
||||
ap = &foo_gd;
|
||||
bp = &bar_gd;
|
||||
printf (" = %d\n", *ap + *bp);
|
||||
result |= *ap + *bp != 1;
|
||||
if (*ap != 0)
|
||||
if (*ap != 0 || *bp != 1)
|
||||
{
|
||||
printf ("foo = %d\n", *ap);
|
||||
result = 1;
|
||||
}
|
||||
if (*bp != 1)
|
||||
{
|
||||
printf ("bar = %d\n", *bp);
|
||||
printf ("foo = %d\nbar = %d\n", *ap, *bp);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/* 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>
|
||||
+11
-15
@@ -1,13 +1,12 @@
|
||||
/* 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);
|
||||
__thread int foo, bar __attribute__ ((tls_model("initial-exec")));
|
||||
__thread int baz __attribute__ ((tls_model("local-exec")));
|
||||
extern __thread int foo_gd __attribute__ ((alias("foo"), tls_model("global-dynamic")));
|
||||
extern __thread int bar_gd __attribute__ ((alias("bar"), tls_model("global-dynamic")));
|
||||
extern __thread int baz_ld __attribute__ ((alias("baz"), tls_model("local-dynamic")));
|
||||
|
||||
|
||||
extern int in_dso (void);
|
||||
@@ -22,23 +21,20 @@ do_test (void)
|
||||
|
||||
/* Set the variable using the local exec model. */
|
||||
puts ("set baz to 3 (LE)");
|
||||
ap = TLS_LE (baz);
|
||||
*ap = 3;
|
||||
baz = 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;
|
||||
foo = 1;
|
||||
bar = 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);
|
||||
ap = &foo_gd;
|
||||
bp = &bar_gd;
|
||||
cp = &baz_ld;
|
||||
printf (" = %d\n", *ap + *bp + *cp);
|
||||
result |= *ap + *bp + *cp != 6;
|
||||
if (*ap != 1)
|
||||
|
||||
+12
-12
@@ -1,12 +1,12 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tls-macros.h"
|
||||
|
||||
__thread int foo, bar __attribute__ ((tls_model("global-dynamic")));
|
||||
extern __thread int baz __attribute__ ((tls_model("global-dynamic")));
|
||||
extern __thread int foo_ie asm ("foo") __attribute__ ((tls_model("initial-exec")));
|
||||
extern __thread int bar_ie asm ("bar") __attribute__ ((tls_model("initial-exec")));
|
||||
extern __thread int baz_ie asm ("baz") __attribute__ ((tls_model("initial-exec")));
|
||||
|
||||
/* One define int variable, two externs. */
|
||||
COMMON_INT_DEF(foo);
|
||||
VAR_INT_DEF(bar);
|
||||
VAR_INT_DECL(baz);
|
||||
|
||||
extern int in_dso (void);
|
||||
|
||||
@@ -19,8 +19,8 @@ in_dso (void)
|
||||
/* 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);
|
||||
ap = &foo_ie;
|
||||
bp = &bar_ie;
|
||||
printf (" = %d\n", *ap + *bp);
|
||||
result |= *ap + *bp != 3;
|
||||
if (*ap != 1)
|
||||
@@ -35,11 +35,11 @@ in_dso (void)
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
/* Get variables using generic dynamic model or TLSDESC. */
|
||||
fputs ("get sum of foo and bar and baz (GD or TLSDESC)", stdout);
|
||||
ap = &foo;
|
||||
bp = &bar;
|
||||
cp = &baz;
|
||||
printf (" = %d\n", *ap + *bp + *cp);
|
||||
result |= *ap + *bp + *cp != 6;
|
||||
if (*ap != 1)
|
||||
|
||||
+2
-4
@@ -1,9 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tls-macros.h"
|
||||
|
||||
|
||||
COMMON_INT_DEF(foo);
|
||||
__thread int foo;
|
||||
|
||||
|
||||
int
|
||||
@@ -15,7 +13,7 @@ in_dso (int n, int *caller_foop)
|
||||
puts ("foo"); /* Make sure PLT is used before macros. */
|
||||
asm ("" ::: "memory");
|
||||
|
||||
foop = TLS_GD (foo);
|
||||
foop = &foo;
|
||||
|
||||
if (caller_foop != NULL && foop != caller_foop)
|
||||
{
|
||||
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tls-macros.h"
|
||||
|
||||
extern int in_dso (int n, int *caller_foop);
|
||||
|
||||
COMMON_INT_DEF(comm_n);
|
||||
extern __thread int foo;
|
||||
__thread int comm_n;
|
||||
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ in_dso2 (void)
|
||||
puts ("foo"); /* Make sure PLT is used before macros. */
|
||||
asm ("" ::: "memory");
|
||||
|
||||
foop = TLS_GD (foo);
|
||||
np = TLS_GD (comm_n);
|
||||
foop = &foo;
|
||||
np = &comm_n;
|
||||
|
||||
if (n != *np)
|
||||
{
|
||||
|
||||
+2
-4
@@ -1,9 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tls-macros.h"
|
||||
|
||||
|
||||
COMMON_INT_DEF(baz);
|
||||
__thread int baz;
|
||||
|
||||
|
||||
int
|
||||
@@ -15,7 +13,7 @@ in_dso (int n, int *caller_bazp)
|
||||
puts ("foo"); /* Make sure PLT is used before macros. */
|
||||
asm ("" ::: "memory");
|
||||
|
||||
bazp = TLS_GD (baz);
|
||||
bazp = &baz;
|
||||
|
||||
if (caller_bazp != NULL && bazp != caller_bazp)
|
||||
{
|
||||
|
||||
+1
-3
@@ -1,3 +1 @@
|
||||
#include "tls-macros.h"
|
||||
|
||||
COMMON_INT_DEF(foo);
|
||||
__thread int foo;
|
||||
|
||||
+1
-3
@@ -1,3 +1 @@
|
||||
#include "tls-macros.h"
|
||||
|
||||
COMMON_INT_DEF(bar);
|
||||
__thread int bar;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
int
|
||||
__attribute__((noinline))
|
||||
/* Workaround for clang/lld failing to override this from a module. */
|
||||
__attribute__((weak))
|
||||
baz (int x)
|
||||
{
|
||||
abort ();
|
||||
|
||||
@@ -27,7 +27,48 @@ main (void)
|
||||
}
|
||||
|
||||
mod1 ();
|
||||
|
||||
// Additional test to detect when the fastload hash table has bad pointers to
|
||||
// names of unloaded libraries hanging around in it.
|
||||
|
||||
int (*mod1b) (void) = dlsym (h, "mod1b");
|
||||
if (mod1b == NULL)
|
||||
{
|
||||
puts ("dlsym failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
mod1b ();
|
||||
|
||||
dlclose (h);
|
||||
|
||||
void *h2x = dlopen ("$ORIGIN/unload8mod2.so", RTLD_LAZY);
|
||||
if (h2x == NULL)
|
||||
{
|
||||
puts ("dlopen unload8mod2.so failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void *h2xx = dlopen ("$ORIGIN/unload8mod1x.so", RTLD_LAZY);
|
||||
if (h2xx == NULL)
|
||||
{
|
||||
puts ("dlopen unload8mod1x.so failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
dlclose (h);
|
||||
dlclose (h2x);
|
||||
dlclose (h2xx);
|
||||
|
||||
void *h3xx = dlopen ("$ORIGIN/unload8mod3.so", RTLD_LAZY);
|
||||
if (h3xx == NULL)
|
||||
{
|
||||
puts ("dlopen unload8mod3.so failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
dlclose (h3xx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include <dlfcn.h>
|
||||
|
||||
extern void mod2 (void);
|
||||
|
||||
void
|
||||
@@ -5,3 +7,15 @@ mod1 (void)
|
||||
{
|
||||
mod2 ();
|
||||
}
|
||||
|
||||
int
|
||||
mod1b (void)
|
||||
{
|
||||
void *h = dlopen ("$ORIGIN/unload8mod3.so", RTLD_LAZY);
|
||||
if (h == NULL)
|
||||
{
|
||||
puts ("dlopen unload8mod3.so failed");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Copyright (C) 2003-2013 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 google-nsl-stub add-on subdirectory of GNU C Library.
|
||||
# Based on libidn/Makefile.
|
||||
|
||||
subdir := google-nsl-stub
|
||||
|
||||
extra-libs = libnsl
|
||||
extra-libs-others = $(extra-libs)
|
||||
|
||||
libnsl-routines := ypclnt
|
||||
|
||||
include $(..)Makeconfig
|
||||
|
||||
libnsl-inhibit-o = $(filter-out .os,$(object-suffixes))
|
||||
|
||||
include $(..)Rules
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
# This is a shell script fragment sourced by the main configure script.
|
||||
# We're obliged to give here the canonical name that will be used to
|
||||
# as a subdirectory to search for in other add-ons' sysdeps trees.
|
||||
|
||||
libc_add_on_canonical=google-nsl-stub
|
||||
libc_add_on_subdirs=.
|
||||
@@ -0,0 +1 @@
|
||||
libnsl=1
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Copyright (C) 2013 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 a Google-local stub version of nis/ypclnt.c. These functions
|
||||
are required for dynamic linking of some precompiled executables. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int yp_get_default_domain(char **domp) {
|
||||
/* We duplicate glibc's error behavior and return a null pointer. */
|
||||
*domp = NULL;
|
||||
return 12; /* YPERR_NODOM */
|
||||
}
|
||||
|
||||
static const char err[] = "not implemented in Google-local stub";
|
||||
char *yperr_string(int incode) {
|
||||
return err;
|
||||
}
|
||||
|
||||
int yp_match(char *indomain, char *inmap, const char *inkey, int inkeylen,
|
||||
char **outval, int *outvallen) {
|
||||
*outval = malloc(2);
|
||||
(*outval)[0] = '\n';
|
||||
(*outval)[1] = '\0';
|
||||
*outvallen = 0;
|
||||
return 0;
|
||||
}
|
||||
+16
-2
@@ -26,7 +26,7 @@ headers = iconv.h gconv.h
|
||||
routines = iconv_open iconv iconv_close \
|
||||
gconv_open gconv gconv_close gconv_db gconv_conf \
|
||||
gconv_builtin gconv_simple gconv_trans gconv_cache
|
||||
routines += gconv_dl
|
||||
routines += gconv_dl gconv_charset
|
||||
|
||||
vpath %.c ../locale/programs ../intl
|
||||
|
||||
@@ -43,7 +43,8 @@ CFLAGS-charmap.c += -DCHARMAP_PATH='"$(i18ndir)/charmaps"' \
|
||||
CFLAGS-linereader.c += -DNO_TRANSLITERATION
|
||||
CFLAGS-simple-hash.c += -I../locale
|
||||
|
||||
tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6
|
||||
tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 \
|
||||
tst-iconv8 # tst-iconv-opt needs work to add back
|
||||
|
||||
others = iconv_prog iconvconfig
|
||||
install-others-programs = $(inst_bindir)/iconv
|
||||
@@ -60,6 +61,7 @@ include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
xtests-special += $(objpfx)test-iconvconfig.out
|
||||
tests-special += $(objpfx)tst-iconv_prog.out
|
||||
endif
|
||||
|
||||
# Make a copy of the file because gconv module names are constructed
|
||||
@@ -78,6 +80,13 @@ endif
|
||||
|
||||
include ../Rules
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
LOCALES := en_US.UTF-8
|
||||
include ../gen-locales.mk
|
||||
|
||||
$(objpfx)tst-iconv-opt.out: $(gen-locales)
|
||||
endif
|
||||
|
||||
$(inst_bindir)/iconv: $(objpfx)iconv_prog $(+force)
|
||||
$(do-install-program)
|
||||
|
||||
@@ -92,3 +101,8 @@ $(objpfx)test-iconvconfig.out: /dev/null $(objpfx)iconvconfig
|
||||
cmp $$tmp $(inst_gconvdir)/gconv-modules.cache; \
|
||||
rm -f $$tmp) > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
$(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog
|
||||
$(BASH) $< $(common-objdir) '$(test-wrapper-env)' \
|
||||
'$(run-program-env)' > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
@@ -7,6 +7,9 @@ libc {
|
||||
# functions shared with iconv program
|
||||
__gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db;
|
||||
|
||||
# functions used elsewhere in glibc
|
||||
__gconv_open; __gconv_create_spec; __gconv_destroy_spec;
|
||||
|
||||
# function used by the gconv modules
|
||||
__gconv_transliterate;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
/* Charset name normalization.
|
||||
Copyright (C) 2020 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 <ctype.h>
|
||||
#include <locale.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include "gconv_int.h"
|
||||
#include "gconv_charset.h"
|
||||
|
||||
|
||||
/* This function returns a pointer to the last suffix in a conversion code
|
||||
string. Valid suffixes matched by this function are of the form: '/' or ','
|
||||
followed by arbitrary text that doesn't contain '/' or ','. It does not
|
||||
edit the string in any way. The caller is expected to parse the suffix and
|
||||
remove it (by e.g. truncating the string) before the next call. */
|
||||
static char *
|
||||
find_suffix (char *s)
|
||||
{
|
||||
/* The conversion code is in the form of a triplet, separated by '/' chars.
|
||||
The third component of the triplet contains suffixes. If we don't have two
|
||||
slashes, we don't have a suffix. */
|
||||
|
||||
int slash_count = 0;
|
||||
char *suffix_term = NULL;
|
||||
|
||||
for (int i = 0; s[i] != '\0'; i++)
|
||||
switch (s[i])
|
||||
{
|
||||
case '/':
|
||||
slash_count++;
|
||||
/* Fallthrough */
|
||||
case ',':
|
||||
suffix_term = &s[i];
|
||||
}
|
||||
|
||||
if (slash_count >= 2)
|
||||
return suffix_term;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct gconv_parsed_code
|
||||
{
|
||||
char *code;
|
||||
bool translit;
|
||||
bool ignore;
|
||||
};
|
||||
|
||||
|
||||
/* This function parses an iconv_open encoding PC.CODE, strips any suffixes
|
||||
(such as TRANSLIT or IGNORE) from it and sets corresponding flags in it. */
|
||||
static void
|
||||
gconv_parse_code (struct gconv_parsed_code *pc)
|
||||
{
|
||||
pc->translit = false;
|
||||
pc->ignore = false;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* First drop any trailing whitespaces and separators. */
|
||||
size_t len = strlen (pc->code);
|
||||
while ((len > 0)
|
||||
&& (isspace (pc->code[len - 1])
|
||||
|| pc->code[len - 1] == ','
|
||||
|| pc->code[len - 1] == '/'))
|
||||
len--;
|
||||
|
||||
pc->code[len] = '\0';
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
char * suffix = find_suffix (pc->code);
|
||||
if (suffix == NULL)
|
||||
{
|
||||
/* At this point, we have processed and removed all suffixes from the
|
||||
code and what remains of the code is suffix free. */
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A suffix is processed from the end of the code array going
|
||||
backwards, one suffix at a time. The suffix is an index into the
|
||||
code character array and points to: one past the end of the code
|
||||
and any unprocessed suffixes, and to the beginning of the suffix
|
||||
currently being processed during this iteration. We must process
|
||||
this suffix and then drop it from the code by terminating the
|
||||
preceding text with NULL.
|
||||
|
||||
We want to allow and recognize suffixes such as:
|
||||
|
||||
"/TRANSLIT" i.e. single suffix
|
||||
"//TRANSLIT" i.e. single suffix and multiple separators
|
||||
"//TRANSLIT/IGNORE" i.e. suffixes separated by "/"
|
||||
"/TRANSLIT//IGNORE" i.e. suffixes separated by "//"
|
||||
"//IGNORE,TRANSLIT" i.e. suffixes separated by ","
|
||||
"//IGNORE," i.e. trailing ","
|
||||
"//TRANSLIT/" i.e. trailing "/"
|
||||
"//TRANSLIT//" i.e. trailing "//"
|
||||
"/" i.e. empty suffix.
|
||||
|
||||
Unknown suffixes are silently discarded and ignored. */
|
||||
|
||||
if ((__strcasecmp_l (suffix,
|
||||
GCONV_TRIPLE_SEPARATOR
|
||||
GCONV_TRANSLIT_SUFFIX,
|
||||
_nl_C_locobj_ptr) == 0)
|
||||
|| (__strcasecmp_l (suffix,
|
||||
GCONV_SUFFIX_SEPARATOR
|
||||
GCONV_TRANSLIT_SUFFIX,
|
||||
_nl_C_locobj_ptr) == 0))
|
||||
pc->translit = true;
|
||||
|
||||
if ((__strcasecmp_l (suffix,
|
||||
GCONV_TRIPLE_SEPARATOR
|
||||
GCONV_IGNORE_ERRORS_SUFFIX,
|
||||
_nl_C_locobj_ptr) == 0)
|
||||
|| (__strcasecmp_l (suffix,
|
||||
GCONV_SUFFIX_SEPARATOR
|
||||
GCONV_IGNORE_ERRORS_SUFFIX,
|
||||
_nl_C_locobj_ptr) == 0))
|
||||
pc->ignore = true;
|
||||
|
||||
/* We just processed this suffix. We can now drop it from the
|
||||
code string by truncating it at the suffix's position. */
|
||||
suffix[0] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This function accepts the charset names of the source and destination of the
|
||||
conversion and populates *conv_spec with an equivalent conversion
|
||||
specification that may later be used by __gconv_open. The charset names
|
||||
might contain options in the form of suffixes that alter the conversion,
|
||||
e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
|
||||
and truncating any suffix options in fromcode, and processing and truncating
|
||||
any suffix options in tocode. Supported suffix options ("TRANSLIT" or
|
||||
"IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
|
||||
to be set to true. Unrecognized suffix options are silently discarded. If
|
||||
the function succeeds, it returns conv_spec back to the caller. It returns
|
||||
NULL upon failure. conv_spec must be allocated and freed by the caller. */
|
||||
struct gconv_spec *
|
||||
__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
|
||||
const char *tocode)
|
||||
{
|
||||
struct gconv_parsed_code pfc, ptc;
|
||||
struct gconv_spec *ret = NULL;
|
||||
|
||||
pfc.code = __strdup (fromcode);
|
||||
ptc.code = __strdup (tocode);
|
||||
|
||||
if ((pfc.code == NULL)
|
||||
|| (ptc.code == NULL))
|
||||
goto out;
|
||||
|
||||
gconv_parse_code (&pfc);
|
||||
gconv_parse_code (&ptc);
|
||||
|
||||
/* We ignore suffixes in the fromcode because that is how the current
|
||||
implementation has always handled them. Only suffixes in the tocode are
|
||||
processed and handled. The reality is that invalid input in the input
|
||||
character set should only be ignored if the fromcode specifies IGNORE.
|
||||
The current implementation ignores invalid intput in the input character
|
||||
set if the tocode contains IGNORE. We preserve this behavior for
|
||||
backwards compatibility. In the future we may split the handling of
|
||||
IGNORE to allow a finer grained specification of ignorning invalid input
|
||||
and/or ignoring invalid output. */
|
||||
conv_spec->translit = ptc.translit;
|
||||
conv_spec->ignore = ptc.ignore;
|
||||
|
||||
/* 3 extra bytes because 1 extra for '\0', and 2 extra so strip might
|
||||
be able to add one or two trailing '/' characters if necessary. */
|
||||
conv_spec->fromcode = malloc (strlen (fromcode) + 3);
|
||||
if (conv_spec->fromcode == NULL)
|
||||
goto out;
|
||||
|
||||
conv_spec->tocode = malloc (strlen (tocode) + 3);
|
||||
if (conv_spec->tocode == NULL)
|
||||
{
|
||||
free (conv_spec->fromcode);
|
||||
conv_spec->fromcode = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Strip unrecognized characters and ensure that the code has two '/'
|
||||
characters as per conversion code triplet specification. */
|
||||
strip (conv_spec->fromcode, pfc.code);
|
||||
strip (conv_spec->tocode, ptc.code);
|
||||
ret = conv_spec;
|
||||
|
||||
out:
|
||||
free (pfc.code);
|
||||
free (ptc.code);
|
||||
|
||||
return ret;
|
||||
}
|
||||
libc_hidden_def (__gconv_create_spec)
|
||||
|
||||
|
||||
void
|
||||
__gconv_destroy_spec (struct gconv_spec *conv_spec)
|
||||
{
|
||||
free (conv_spec->fromcode);
|
||||
free (conv_spec->tocode);
|
||||
return;
|
||||
}
|
||||
libc_hidden_def (__gconv_destroy_spec)
|
||||
+33
-1
@@ -19,9 +19,41 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include "gconv_int.h"
|
||||
|
||||
|
||||
static void
|
||||
/* An iconv encoding is in the form of a triplet, with parts separated by
|
||||
a '/' character. The first part is the standard name, the second part is
|
||||
the character set, and the third part is the error handler. If the first
|
||||
part is sufficient to identify both the standard and the character set
|
||||
then the second part can be empty e.g. UTF-8//. If the first part is not
|
||||
sufficient to identify both the standard and the character set then the
|
||||
second part is required e.g. ISO-10646/UTF8/. If neither the first or
|
||||
second parts are provided e.g. //, then the current locale is used.
|
||||
The actual values used in the first and second parts are not entirely
|
||||
relevant to the implementation. The values themselves are used in a hash
|
||||
table to lookup modules and so the naming convention of the first two parts
|
||||
is somewhat arbitrary and only helps locate the entries in the cache.
|
||||
The third part is the error handler and is comprised of a ',' or '/'
|
||||
separated list of suffixes. Currently, we support "TRANSLIT" for
|
||||
transliteration and "IGNORE" for ignoring conversion errors due to
|
||||
unrecognized input characters. */
|
||||
#define GCONV_TRIPLE_SEPARATOR "/"
|
||||
#define GCONV_SUFFIX_SEPARATOR ","
|
||||
#define GCONV_TRANSLIT_SUFFIX "TRANSLIT"
|
||||
#define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE"
|
||||
|
||||
|
||||
/* This function copies in-order, characters from the source 's' that are
|
||||
either alpha-numeric or one in one of these: "_-.,:/" - into the destination
|
||||
'wp' while dropping all other characters. In the process, it converts all
|
||||
alphabetical characters to upper case. It then appends up to two '/'
|
||||
characters so that the total number of '/'es in the destination is 2. */
|
||||
static inline void __attribute__ ((unused, always_inline))
|
||||
strip (char *wp, const char *s)
|
||||
{
|
||||
int slash_count = 0;
|
||||
|
||||
+36
-4
@@ -92,6 +92,15 @@ struct gconv_module
|
||||
};
|
||||
|
||||
|
||||
/* The specification of the conversion that needs to be performed. */
|
||||
struct gconv_spec
|
||||
{
|
||||
char *fromcode;
|
||||
char *tocode;
|
||||
bool translit;
|
||||
bool ignore;
|
||||
};
|
||||
|
||||
/* Flags for `gconv_open'. */
|
||||
enum
|
||||
{
|
||||
@@ -154,10 +163,33 @@ __libc_lock_define (extern, __gconv_lock attribute_hidden)
|
||||
})
|
||||
|
||||
|
||||
/* Return in *HANDLE decriptor for transformation from FROMSET to TOSET. */
|
||||
extern int __gconv_open (const char *toset, const char *fromset,
|
||||
__gconv_t *handle, int flags)
|
||||
attribute_hidden;
|
||||
/* Return in *HANDLE, a decriptor for the transformation. The function expects
|
||||
the specification of the transformation in the structure pointed to by
|
||||
CONV_SPEC. It only reads *CONV_SPEC and does not take ownership of it. */
|
||||
extern int __gconv_open (struct gconv_spec *conv_spec,
|
||||
__gconv_t *handle, int flags);
|
||||
libc_hidden_proto (__gconv_open)
|
||||
|
||||
/* This function accepts the charset names of the source and destination of the
|
||||
conversion and populates *conv_spec with an equivalent conversion
|
||||
specification that may later be used by __gconv_open. The charset names
|
||||
might contain options in the form of suffixes that alter the conversion,
|
||||
e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
|
||||
and truncating any suffix options in fromcode, and processing and truncating
|
||||
any suffix options in tocode. Supported suffix options ("TRANSLIT" or
|
||||
"IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
|
||||
to be set to true. Unrecognized suffix options are silently discarded. If
|
||||
the function succeeds, it returns conv_spec back to the caller. It returns
|
||||
NULL upon failure. */
|
||||
extern struct gconv_spec *
|
||||
__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
|
||||
const char *tocode);
|
||||
libc_hidden_proto (__gconv_create_spec)
|
||||
|
||||
/* This function frees all heap memory allocated by __gconv_create_spec. */
|
||||
extern void
|
||||
__gconv_destroy_spec (struct gconv_spec *conv_spec);
|
||||
libc_hidden_proto (__gconv_destroy_spec)
|
||||
|
||||
/* Free resources associated with transformation descriptor CD. */
|
||||
extern int __gconv_close (__gconv_t cd)
|
||||
|
||||
+13
-51
@@ -27,7 +27,7 @@
|
||||
|
||||
|
||||
int
|
||||
__gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
|
||||
__gconv_open (struct gconv_spec *conv_spec, __gconv_t *handle,
|
||||
int flags)
|
||||
{
|
||||
struct __gconv_step *steps;
|
||||
@@ -36,77 +36,38 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
|
||||
size_t cnt = 0;
|
||||
int res;
|
||||
int conv_flags = 0;
|
||||
const char *errhand;
|
||||
const char *ignore;
|
||||
bool translit = false;
|
||||
char *tocode, *fromcode;
|
||||
|
||||
/* Find out whether any error handling method is specified. */
|
||||
errhand = strchr (toset, '/');
|
||||
if (errhand != NULL)
|
||||
errhand = strchr (errhand + 1, '/');
|
||||
if (__glibc_likely (errhand != NULL))
|
||||
{
|
||||
if (*++errhand == '\0')
|
||||
errhand = NULL;
|
||||
else
|
||||
{
|
||||
/* Make copy without the error handling description. */
|
||||
char *newtoset = (char *) alloca (errhand - toset + 1);
|
||||
char *tok;
|
||||
char *ptr = NULL /* Work around a bogus warning */;
|
||||
translit = conv_spec->translit;
|
||||
|
||||
newtoset[errhand - toset] = '\0';
|
||||
toset = memcpy (newtoset, toset, errhand - toset);
|
||||
if (conv_spec->ignore)
|
||||
conv_flags |= __GCONV_IGNORE_ERRORS;
|
||||
|
||||
/* Find the appropriate transliteration handlers. */
|
||||
tok = strdupa (errhand);
|
||||
|
||||
tok = __strtok_r (tok, ",", &ptr);
|
||||
while (tok != NULL)
|
||||
{
|
||||
if (__strcasecmp_l (tok, "TRANSLIT", _nl_C_locobj_ptr) == 0)
|
||||
translit = true;
|
||||
else if (__strcasecmp_l (tok, "IGNORE", _nl_C_locobj_ptr) == 0)
|
||||
/* Set the flag to ignore all errors. */
|
||||
conv_flags |= __GCONV_IGNORE_ERRORS;
|
||||
|
||||
tok = __strtok_r (NULL, ",", &ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* For the source character set we ignore the error handler specification.
|
||||
XXX Is this really always the best? */
|
||||
ignore = strchr (fromset, '/');
|
||||
if (ignore != NULL && (ignore = strchr (ignore + 1, '/')) != NULL
|
||||
&& *++ignore != '\0')
|
||||
{
|
||||
char *newfromset = (char *) alloca (ignore - fromset + 1);
|
||||
|
||||
newfromset[ignore - fromset] = '\0';
|
||||
fromset = memcpy (newfromset, fromset, ignore - fromset);
|
||||
}
|
||||
tocode = conv_spec->tocode;
|
||||
fromcode = conv_spec->fromcode;
|
||||
|
||||
/* If the string is empty define this to mean the charset of the
|
||||
currently selected locale. */
|
||||
if (strcmp (toset, "//") == 0)
|
||||
if (strcmp (tocode, "//") == 0)
|
||||
{
|
||||
const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
|
||||
size_t len = strlen (codeset);
|
||||
char *dest;
|
||||
toset = dest = (char *) alloca (len + 3);
|
||||
tocode = dest = (char *) alloca (len + 3);
|
||||
memcpy (__mempcpy (dest, codeset, len), "//", 3);
|
||||
}
|
||||
if (strcmp (fromset, "//") == 0)
|
||||
if (strcmp (fromcode, "//") == 0)
|
||||
{
|
||||
const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
|
||||
size_t len = strlen (codeset);
|
||||
char *dest;
|
||||
fromset = dest = (char *) alloca (len + 3);
|
||||
fromcode = dest = (char *) alloca (len + 3);
|
||||
memcpy (__mempcpy (dest, codeset, len), "//", 3);
|
||||
}
|
||||
|
||||
res = __gconv_find_transform (toset, fromset, &steps, &nsteps, flags);
|
||||
res = __gconv_find_transform (tocode, fromcode, &steps, &nsteps, flags);
|
||||
if (res == __GCONV_OK)
|
||||
{
|
||||
/* Allocate room for handle. */
|
||||
@@ -205,3 +166,4 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
|
||||
*handle = result;
|
||||
return res;
|
||||
}
|
||||
libc_hidden_def (__gconv_open)
|
||||
|
||||
+4
-12
@@ -237,11 +237,9 @@ ucs4_internal_loop (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
uint32_t inval;
|
||||
|
||||
@@ -304,11 +302,9 @@ ucs4_internal_loop_unaligned (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
if (__glibc_unlikely (inptr[0] > 0x80))
|
||||
{
|
||||
@@ -607,11 +603,9 @@ ucs4le_internal_loop (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
uint32_t inval;
|
||||
|
||||
@@ -677,11 +671,9 @@ ucs4le_internal_loop_unaligned (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
if (__glibc_unlikely (inptr[3] > 0x80))
|
||||
{
|
||||
|
||||
+7
-41
@@ -31,49 +31,15 @@
|
||||
iconv_t
|
||||
iconv_open (const char *tocode, const char *fromcode)
|
||||
{
|
||||
/* Normalize the name. We remove all characters beside alpha-numeric,
|
||||
'_', '-', '/', '.', and ':'. */
|
||||
size_t tocode_len = strlen (tocode) + 3;
|
||||
char *tocode_conv;
|
||||
bool tocode_usealloca = __libc_use_alloca (tocode_len);
|
||||
if (tocode_usealloca)
|
||||
tocode_conv = (char *) alloca (tocode_len);
|
||||
else
|
||||
{
|
||||
tocode_conv = (char *) malloc (tocode_len);
|
||||
if (tocode_conv == NULL)
|
||||
return (iconv_t) -1;
|
||||
}
|
||||
strip (tocode_conv, tocode);
|
||||
tocode = (tocode_conv[2] == '\0' && tocode[0] != '\0'
|
||||
? upstr (tocode_conv, tocode) : tocode_conv);
|
||||
|
||||
size_t fromcode_len = strlen (fromcode) + 3;
|
||||
char *fromcode_conv;
|
||||
bool fromcode_usealloca = __libc_use_alloca (fromcode_len);
|
||||
if (fromcode_usealloca)
|
||||
fromcode_conv = (char *) alloca (fromcode_len);
|
||||
else
|
||||
{
|
||||
fromcode_conv = (char *) malloc (fromcode_len);
|
||||
if (fromcode_conv == NULL)
|
||||
{
|
||||
if (! tocode_usealloca)
|
||||
free (tocode_conv);
|
||||
return (iconv_t) -1;
|
||||
}
|
||||
}
|
||||
strip (fromcode_conv, fromcode);
|
||||
fromcode = (fromcode_conv[2] == '\0' && fromcode[0] != '\0'
|
||||
? upstr (fromcode_conv, fromcode) : fromcode_conv);
|
||||
|
||||
__gconv_t cd;
|
||||
int res = __gconv_open (tocode, fromcode, &cd, 0);
|
||||
struct gconv_spec conv_spec;
|
||||
|
||||
if (! fromcode_usealloca)
|
||||
free (fromcode_conv);
|
||||
if (! tocode_usealloca)
|
||||
free (tocode_conv);
|
||||
if (__gconv_create_spec (&conv_spec, fromcode, tocode) == NULL)
|
||||
return (iconv_t) -1;
|
||||
|
||||
int res = __gconv_open (&conv_spec, &cd, 0);
|
||||
|
||||
__gconv_destroy_spec (&conv_spec);
|
||||
|
||||
if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
|
||||
{
|
||||
|
||||
+23
-40
@@ -39,6 +39,7 @@
|
||||
#include <gconv_int.h>
|
||||
#include "iconv_prog.h"
|
||||
#include "iconvconfig.h"
|
||||
#include "gconv_charset.h"
|
||||
|
||||
/* Get libc version number. */
|
||||
#include "../version.h"
|
||||
@@ -118,8 +119,7 @@ main (int argc, char *argv[])
|
||||
{
|
||||
int status = EXIT_SUCCESS;
|
||||
int remaining;
|
||||
iconv_t cd;
|
||||
const char *orig_to_code;
|
||||
__gconv_t cd;
|
||||
struct charmap_t *from_charmap = NULL;
|
||||
struct charmap_t *to_charmap = NULL;
|
||||
|
||||
@@ -139,39 +139,6 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* If we have to ignore errors make sure we use the appropriate name for
|
||||
the to-character-set. */
|
||||
orig_to_code = to_code;
|
||||
if (omit_invalid)
|
||||
{
|
||||
const char *errhand = strchrnul (to_code, '/');
|
||||
int nslash = 2;
|
||||
char *newp;
|
||||
char *cp;
|
||||
|
||||
if (*errhand == '/')
|
||||
{
|
||||
--nslash;
|
||||
errhand = strchrnul (errhand + 1, '/');
|
||||
|
||||
if (*errhand == '/')
|
||||
{
|
||||
--nslash;
|
||||
errhand = strchr (errhand, '\0');
|
||||
}
|
||||
}
|
||||
|
||||
newp = (char *) alloca (errhand - to_code + nslash + 7 + 1);
|
||||
cp = mempcpy (newp, to_code, errhand - to_code);
|
||||
while (nslash-- > 0)
|
||||
*cp++ = '/';
|
||||
if (cp[-1] != '/')
|
||||
*cp++ = ',';
|
||||
memcpy (cp, "IGNORE", sizeof ("IGNORE"));
|
||||
|
||||
to_code = newp;
|
||||
}
|
||||
|
||||
/* POSIX 1003.2b introduces a silly thing: the arguments to -t anf -f
|
||||
can be file names of charmaps. In this case iconv will have to read
|
||||
those charmaps and use them to do the conversion. But there are
|
||||
@@ -184,10 +151,10 @@ main (int argc, char *argv[])
|
||||
file. */
|
||||
from_charmap = charmap_read (from_code, /*0, 1*/1, 0, 0, 0);
|
||||
|
||||
if (strchr (orig_to_code, '/') != NULL)
|
||||
if (strchr (to_code, '/') != NULL)
|
||||
/* The to-name might be a charmap file name. Try reading the
|
||||
file. */
|
||||
to_charmap = charmap_read (orig_to_code, /*0, 1,*/1, 0, 0, 0);
|
||||
to_charmap = charmap_read (to_code, /*0, 1,*/1, 0, 0, 0);
|
||||
|
||||
|
||||
/* At this point we have to handle two cases. The first one is
|
||||
@@ -201,9 +168,25 @@ main (int argc, char *argv[])
|
||||
argc, remaining, argv, output_file);
|
||||
else
|
||||
{
|
||||
struct gconv_spec conv_spec;
|
||||
int res;
|
||||
|
||||
if (__gconv_create_spec (&conv_spec, from_code, to_code) == NULL)
|
||||
{
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to start conversion processing"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (omit_invalid)
|
||||
conv_spec.ignore = true;
|
||||
|
||||
/* Let's see whether we have these coded character sets. */
|
||||
cd = iconv_open (to_code, from_code);
|
||||
if (cd == (iconv_t) -1)
|
||||
res = __gconv_open (&conv_spec, &cd, 0);
|
||||
|
||||
__gconv_destroy_spec (&conv_spec);
|
||||
|
||||
if (res != __GCONV_OK)
|
||||
{
|
||||
if (errno == EINVAL)
|
||||
{
|
||||
@@ -221,7 +204,7 @@ main (int argc, char *argv[])
|
||||
const char *from_pretty =
|
||||
(from_code[0] ? from_code : nl_langinfo (CODESET));
|
||||
const char *to_pretty =
|
||||
(orig_to_code[0] ? orig_to_code : nl_langinfo (CODESET));
|
||||
(to_code[0] ? to_code : nl_langinfo (CODESET));
|
||||
|
||||
if (from_wrong)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
/* Test iconv's TRANSLIT and IGNORE option handling
|
||||
|
||||
Copyright (C) 2020 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
#include <iconv.h>
|
||||
#include <locale.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <support/support.h>
|
||||
#include <support/check.h>
|
||||
|
||||
|
||||
/* Run one iconv test. Arguments:
|
||||
to: destination character set and options
|
||||
from: source character set
|
||||
input: input string to be converted
|
||||
exp_in: expected number of bytes consumed
|
||||
exp_ret: expected return value (error or number of irreversible conversions)
|
||||
exp_out: expected output string
|
||||
exp_err: expected value of `errno' after iconv returns. */
|
||||
static void
|
||||
test_iconv (const char *to, const char *from, char *input, size_t exp_in,
|
||||
size_t exp_ret, const char *exp_out, int exp_err)
|
||||
{
|
||||
iconv_t cd;
|
||||
char outbuf[500];
|
||||
size_t inlen, outlen;
|
||||
char *inptr, *outptr;
|
||||
size_t n;
|
||||
|
||||
cd = iconv_open (to, from);
|
||||
TEST_VERIFY (cd != (iconv_t) -1);
|
||||
|
||||
inlen = strlen (input);
|
||||
outlen = sizeof (outbuf);
|
||||
inptr = input;
|
||||
outptr = outbuf;
|
||||
|
||||
errno = 0;
|
||||
n = iconv (cd, &inptr, &inlen, &outptr, &outlen);
|
||||
|
||||
TEST_COMPARE (n, exp_ret);
|
||||
TEST_VERIFY (inptr == input + exp_in);
|
||||
TEST_COMPARE (errno, exp_err);
|
||||
TEST_COMPARE_BLOB (outbuf, outptr - outbuf, exp_out, strlen (exp_out));
|
||||
TEST_VERIFY (iconv_close (cd) == 0);
|
||||
}
|
||||
|
||||
|
||||
/* We test option parsing by converting UTF-8 inputs to ASCII under various
|
||||
option combinations. The UTF-8 inputs fall into three categories:
|
||||
- ASCII-only,
|
||||
- non-ASCII,
|
||||
- non-ASCII with invalid UTF-8 characters. */
|
||||
|
||||
/* 1. */
|
||||
char ascii[] = "Just some ASCII text";
|
||||
|
||||
/* 2. Valid UTF-8 input and some corresponding expected outputs with various
|
||||
options. The two non-ASCII characters below are accented alphabets:
|
||||
an `a' then an `o'. */
|
||||
char utf8[] = "UTF-8 text with \u00E1 couple \u00F3f non-ASCII characters";
|
||||
char u2a[] = "UTF-8 text with ";
|
||||
char u2a_translit[] = "UTF-8 text with a couple of non-ASCII characters";
|
||||
char u2a_ignore[] = "UTF-8 text with couple f non-ASCII characters";
|
||||
|
||||
/* 3. Invalid UTF-8 input and some corresponding expected outputs. \xff is
|
||||
invalid UTF-8. It's followed by some valid but non-ASCII UTF-8. */
|
||||
char iutf8[] = "Invalid UTF-8 \xff\u27E6text\u27E7";
|
||||
char iu2a[] = "Invalid UTF-8 ";
|
||||
char iu2a_ignore[] = "Invalid UTF-8 text";
|
||||
char iu2a_both[] = "Invalid UTF-8 [|text|]";
|
||||
|
||||
/* 4. Another invalid UTF-8 input and corresponding expected outputs. This time
|
||||
the valid non-ASCII UTF-8 characters appear before the invalid \xff. */
|
||||
char jutf8[] = "Invalid \u27E6UTF-8\u27E7 \xfftext";
|
||||
char ju2a[] = "Invalid ";
|
||||
char ju2a_translit[] = "Invalid [|UTF-8|] ";
|
||||
char ju2a_ignore[] = "Invalid UTF-8 text";
|
||||
char ju2a_both[] = "Invalid [|UTF-8|] text";
|
||||
|
||||
/* We also test option handling for character set names that have the form
|
||||
"A/B". In this test, we test conversions "ISO-10646/UTF-8", and either
|
||||
ISO-8859-1 or ASCII. */
|
||||
|
||||
/* 5. Accented 'A' and 'a' characters in ISO-8859-1 and UTF-8, and an
|
||||
equivalent ASCII transliteration. */
|
||||
char iso8859_1_a[] = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, /* Accented A's. */
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, /* Accented a's. */
|
||||
0x00};
|
||||
char utf8_a[] = "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5"
|
||||
"\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5";
|
||||
char ascii_a[] = "AAAAAAaaaaaa";
|
||||
|
||||
/* 6. An invalid ASCII string where [0] is invalid and [1] is '~'. */
|
||||
char iascii [] = {0x80, '~', '\0'};
|
||||
char empty[] = "";
|
||||
char ia2u_ignore[] = "~";
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
xsetlocale (LC_ALL, "en_US.UTF-8");
|
||||
|
||||
|
||||
/* 0. iconv_open should gracefully fail for invalid character sets. */
|
||||
|
||||
TEST_VERIFY (iconv_open ("INVALID", "UTF-8") == (iconv_t) -1);
|
||||
TEST_VERIFY (iconv_open ("UTF-8", "INVALID") == (iconv_t) -1);
|
||||
TEST_VERIFY (iconv_open ("INVALID", "INVALID") == (iconv_t) -1);
|
||||
|
||||
|
||||
/* 1. ASCII-only UTF-8 input should convert to ASCII with no changes: */
|
||||
|
||||
test_iconv ("ASCII", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
|
||||
test_iconv ("ASCII//", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
|
||||
test_iconv ("ASCII//TRANSLIT", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
|
||||
test_iconv ("ASCII//TRANSLIT//", "UTF-8", ascii, strlen (ascii), 0, ascii,
|
||||
0);
|
||||
test_iconv ("ASCII//IGNORE", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
|
||||
test_iconv ("ASCII//IGNORE//", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
|
||||
|
||||
|
||||
/* 2. Valid UTF-8 input with non-ASCII characters: */
|
||||
|
||||
/* EILSEQ when converted to ASCII. */
|
||||
test_iconv ("ASCII", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, EILSEQ);
|
||||
|
||||
/* Converted without error with TRANSLIT enabled. */
|
||||
test_iconv ("ASCII//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, u2a_translit,
|
||||
0);
|
||||
|
||||
/* EILSEQ with IGNORE enabled. Non-ASCII chars dropped from output. */
|
||||
test_iconv ("ASCII//IGNORE", "UTF-8", utf8, strlen (utf8), (size_t) -1,
|
||||
u2a_ignore, EILSEQ);
|
||||
|
||||
/* With TRANSLIT and IGNORE enabled, transliterated without error. We test
|
||||
four combinations. */
|
||||
|
||||
test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
/* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
|
||||
test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
|
||||
/* Misspellings of TRANSLIT and IGNORE are ignored, but conversion still
|
||||
works while respecting any other correctly spelled options. */
|
||||
|
||||
test_iconv ("ASCII//T", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
|
||||
EILSEQ);
|
||||
test_iconv ("ASCII//TRANSLITERATE", "UTF-8", utf8, strlen (u2a), (size_t) -1,
|
||||
u2a, EILSEQ);
|
||||
test_iconv ("ASCII//I", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
|
||||
EILSEQ);
|
||||
test_iconv ("ASCII//IGNORED", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
|
||||
EILSEQ);
|
||||
test_iconv ("ASCII//TRANSLITERATE//IGNORED", "UTF-8", utf8, strlen (u2a),
|
||||
(size_t) -1, u2a, EILSEQ);
|
||||
test_iconv ("ASCII//IGNORED,TRANSLITERATE", "UTF-8", utf8, strlen (u2a),
|
||||
(size_t) -1, u2a, EILSEQ);
|
||||
test_iconv ("ASCII//T//I", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
|
||||
EILSEQ);
|
||||
|
||||
test_iconv ("ASCII//TRANSLIT//I", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
/* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
|
||||
test_iconv ("ASCII//I//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
test_iconv ("ASCII//IGNORED,TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
test_iconv ("ASCII//TRANSLIT,IGNORED", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
|
||||
test_iconv ("ASCII//IGNORE,T", "UTF-8", utf8, strlen (utf8), (size_t) -1,
|
||||
u2a_ignore, EILSEQ);
|
||||
test_iconv ("ASCII//T,IGNORE", "UTF-8", utf8, strlen (utf8), (size_t) -1,
|
||||
u2a_ignore, EILSEQ);
|
||||
/* Due to bug 19519, iconv was ignoring IGNORE for the following input. */
|
||||
test_iconv ("ASCII//TRANSLITERATE//IGNORE", "UTF-8", utf8, strlen (utf8),
|
||||
(size_t) -1, u2a_ignore, EILSEQ);
|
||||
test_iconv ("ASCII//IGNORE//TRANSLITERATE", "UTF-8", utf8, strlen (utf8),
|
||||
(size_t) -1, u2a_ignore, EILSEQ);
|
||||
|
||||
|
||||
/* 3. Invalid UTF-8 followed by some valid non-ASCII UTF-8 characters: */
|
||||
|
||||
/* EILSEQ; output is truncated at the first invalid UTF-8 character. */
|
||||
test_iconv ("ASCII", "UTF-8", iutf8, strlen (iu2a), (size_t) -1, iu2a,
|
||||
EILSEQ);
|
||||
|
||||
/* With TRANSLIT enabled: EILSEQ; output still truncated at the first invalid
|
||||
UTF-8 character. */
|
||||
test_iconv ("ASCII//TRANSLIT", "UTF-8", iutf8, strlen (iu2a), (size_t) -1,
|
||||
iu2a, EILSEQ);
|
||||
|
||||
/* With IGNORE enabled: EILSEQ; output omits invalid UTF-8 characters and
|
||||
valid UTF-8 non-ASCII characters. */
|
||||
test_iconv ("ASCII//IGNORE", "UTF-8", iutf8, strlen (iutf8), (size_t) -1,
|
||||
iu2a_ignore, EILSEQ);
|
||||
|
||||
/* With TRANSLIT and IGNORE enabled, output omits only invalid UTF-8
|
||||
characters and transliterates valid non-ASCII UTF-8 characters. We test
|
||||
four combinations. */
|
||||
|
||||
test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", iutf8, strlen (iutf8), 2,
|
||||
iu2a_both, 0);
|
||||
/* Due to bug 19519, iconv was ignoring IGNORE for the following input. */
|
||||
test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", iutf8, strlen (iutf8), 2,
|
||||
iu2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", iutf8, strlen (iutf8), 2,
|
||||
iu2a_both, 0);
|
||||
/* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
|
||||
test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", iutf8, strlen (iutf8), 2,
|
||||
iu2a_both, 0);
|
||||
|
||||
|
||||
/* 4. Invalid UTF-8 with valid non-ASCII UTF-8 chars appearing first: */
|
||||
|
||||
/* EILSEQ; output is truncated at the first non-ASCII character. */
|
||||
test_iconv ("ASCII", "UTF-8", jutf8, strlen (ju2a), (size_t) -1, ju2a,
|
||||
EILSEQ);
|
||||
|
||||
/* With TRANSLIT enabled: EILSEQ; output now truncated at the first invalid
|
||||
UTF-8 character. */
|
||||
test_iconv ("ASCII//TRANSLIT", "UTF-8", jutf8, strlen (jutf8) - 5,
|
||||
(size_t) -1, ju2a_translit, EILSEQ);
|
||||
test_iconv ("ASCII//translit", "UTF-8", jutf8, strlen (jutf8) - 5,
|
||||
(size_t) -1, ju2a_translit, EILSEQ);
|
||||
|
||||
/* With IGNORE enabled: EILSEQ; output omits invalid UTF-8 characters and
|
||||
valid UTF-8 non-ASCII characters. */
|
||||
test_iconv ("ASCII//IGNORE", "UTF-8", jutf8, strlen (jutf8), (size_t) -1,
|
||||
ju2a_ignore, EILSEQ);
|
||||
test_iconv ("ASCII//ignore", "UTF-8", jutf8, strlen (jutf8), (size_t) -1,
|
||||
ju2a_ignore, EILSEQ);
|
||||
|
||||
/* With TRANSLIT and IGNORE enabled, output omits only invalid UTF-8
|
||||
characters and transliterates valid non-ASCII UTF-8 characters. We test
|
||||
several combinations. */
|
||||
|
||||
test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
/* Due to bug 19519, iconv was ignoring IGNORE for the following input. */
|
||||
test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
/* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
|
||||
test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//translit,ignore", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
/* Trailing whitespace and separators should be ignored. */
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT ", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT/", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT//", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT,", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT,,", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT /,", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
|
||||
/* TRANSLIT or IGNORE suffixes in fromcode should be ignored. */
|
||||
test_iconv ("ASCII", "UTF-8//TRANSLIT", jutf8, strlen (ju2a), (size_t) -1,
|
||||
ju2a, EILSEQ);
|
||||
test_iconv ("ASCII", "UTF-8//IGNORE", jutf8, strlen (ju2a), (size_t) -1,
|
||||
ju2a, EILSEQ);
|
||||
test_iconv ("ASCII", "UTF-8//TRANSLIT,IGNORE", jutf8, strlen (ju2a),
|
||||
(size_t) -1, ju2a, EILSEQ);
|
||||
|
||||
|
||||
/* 5. Charset names of the form "A/B/": */
|
||||
|
||||
/* ISO-8859-1 is converted to UTF-8 without needing transliteration. */
|
||||
test_iconv ("ISO-10646/UTF-8", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8/", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8/IGNORE", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8//IGNORE", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8/TRANSLIT", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8//TRANSLIT", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8//TRANSLIT/IGNORE", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8//TRANSLIT//IGNORE", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8/TRANSLIT,IGNORE", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
|
||||
/* UTF-8 with accented A's is converted to ASCII with transliteration. */
|
||||
test_iconv ("ASCII", "ISO-10646/UTF-8", utf8_a,
|
||||
0, (size_t) -1, empty, EILSEQ);
|
||||
test_iconv ("ASCII//IGNORE", "ISO-10646/UTF-8", utf8_a,
|
||||
strlen (utf8_a), (size_t) -1, empty, EILSEQ);
|
||||
test_iconv ("ASCII//TRANSLIT", "ISO-10646/UTF-8", utf8_a,
|
||||
strlen (utf8_a), 12, ascii_a, 0);
|
||||
|
||||
/* Invalid ASCII is converted to UTF-8 only with IGNORE. */
|
||||
test_iconv ("ISO-10646/UTF-8", "ASCII", iascii, strlen (empty), (size_t) -1,
|
||||
empty, EILSEQ);
|
||||
test_iconv ("ISO-10646/UTF-8/TRANSLIT", "ASCII", iascii, strlen (empty),
|
||||
(size_t) -1, empty, EILSEQ);
|
||||
test_iconv ("ISO-10646/UTF-8/IGNORE", "ASCII", iascii, strlen (iascii),
|
||||
(size_t) -1, ia2u_ignore, EILSEQ);
|
||||
test_iconv ("ISO-10646/UTF-8/TRANSLIT,IGNORE", "ASCII", iascii,
|
||||
strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
|
||||
/* Due to bug 19519, iconv was ignoring IGNORE for the following three
|
||||
inputs: */
|
||||
test_iconv ("ISO-10646/UTF-8/TRANSLIT/IGNORE", "ASCII", iascii,
|
||||
strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
|
||||
test_iconv ("ISO-10646/UTF-8//TRANSLIT,IGNORE", "ASCII", iascii,
|
||||
strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
|
||||
test_iconv ("ISO-10646/UTF-8//TRANSLIT//IGNORE", "ASCII", iascii,
|
||||
strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,50 @@
|
||||
/* Test iconv behavior on UCS4 conversions with //IGNORE.
|
||||
Copyright (C) 2020 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/>. */
|
||||
|
||||
/* Derived from BZ #26923 */
|
||||
#include <errno.h>
|
||||
#include <iconv.h>
|
||||
#include <stdio.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
iconv_t cd = iconv_open ("UTF-8//IGNORE", "ISO-10646/UCS4/");
|
||||
TEST_VERIFY_EXIT (cd != (iconv_t) -1);
|
||||
|
||||
/*
|
||||
* Convert sequence beginning with an irreversible character into buffer that
|
||||
* is too small.
|
||||
*/
|
||||
char input[12] = "\xe1\x80\xa1" "AAAAAAAAA";
|
||||
char *inptr = input;
|
||||
size_t insize = sizeof (input);
|
||||
char output[6];
|
||||
char *outptr = output;
|
||||
size_t outsize = sizeof (output);
|
||||
|
||||
TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == -1);
|
||||
TEST_VERIFY (errno == E2BIG);
|
||||
|
||||
TEST_VERIFY_EXIT (iconv_close (cd) != -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,280 @@
|
||||
#!/bin/bash
|
||||
# Test for some known iconv(1) hangs from bug 19519, and miscellaneous
|
||||
# iconv(1) program error conditions.
|
||||
# Copyright (C) 2020 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
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
|
||||
codir=$1
|
||||
test_wrapper_env="$2"
|
||||
run_program_env="$3"
|
||||
|
||||
# We have to have some directories in the library path.
|
||||
LIBPATH=$codir:$codir/iconvdata
|
||||
|
||||
# How the start the iconv(1) program. $from is not defined/expanded yet.
|
||||
ICONV='
|
||||
$codir/elf/ld.so --library-path $LIBPATH --inhibit-rpath ${from}.so
|
||||
$codir/iconv/iconv_prog
|
||||
'
|
||||
ICONV="$test_wrapper_env $run_program_env $ICONV"
|
||||
|
||||
# List of known hangs;
|
||||
# Gathered by running an exhaustive 2 byte input search against glibc-2.28
|
||||
hangarray=(
|
||||
"\x00\x23;-c;ANSI_X3.110;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa1;-c;ARMSCII-8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa1;-c;ASMO_449;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;BIG5;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xff;-c;BIG5HKSCS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xff;-c;BRF;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xff;-c;BS_4730;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1250;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x98;-c;CP1251;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1252;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1253;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1254;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1255;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1257;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1258;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;CP932;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;CSA_Z243.4-1985-1;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;CSA_Z243.4-1985-2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;DEC-MCS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;DIN_66003;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;DS_2089;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-AT-DE;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-AT-DE-A;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-CA-FR;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-DK-NO;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-DK-NO-A;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-ES;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-ES-A;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-ES-S;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-FI-SE;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-FI-SE-A;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-FR;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-IS-FRISS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-IT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-PT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-UK;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-US;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ES;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ES2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-CN;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-JISX0213;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-JP;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-JP-MS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-KR;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-TW;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GB18030;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GB_1988-80;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GBK;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GOST_19768-74;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GREEK7;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GREEK7-OLD;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GREEK-CCITT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;HP-GREEK8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;HP-ROMAN8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;HP-ROMAN9;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;HP-THAI8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;HP-TURKISH8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM038;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM1004;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xff;-c;IBM1008;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;IBM1046;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x51;-c;IBM1132;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa0;-c;IBM1133;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xce;-c;IBM1137;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM1161;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xdb;-c;IBM1162;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x70;-c;IBM12712;UTF-8//TRANSLIT//IGNORE"
|
||||
# These are known hangs that are yet to be fixed:
|
||||
# "\x00\x0f;-c;IBM1364;UTF-8"
|
||||
# "\x00\x0f;-c;IBM1371;UTF-8"
|
||||
# "\x00\x0f;-c;IBM1388;UTF-8"
|
||||
# "\x00\x0f;-c;IBM1390;UTF-8"
|
||||
# "\x00\x0f;-c;IBM1399;UTF-8"
|
||||
"\x00\x53;-c;IBM16804;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM274;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM275;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM281;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x57;-c;IBM290;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x45;-c;IBM420;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x68;-c;IBM423;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x70;-c;IBM424;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x53;-c;IBM4517;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x53;-c;IBM4899;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa5;-c;IBM4909;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xdc;-c;IBM4971;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM803;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x91;-c;IBM851;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x9b;-c;IBM856;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xd5;-c;IBM857;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;IBM864;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x94;-c;IBM868;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x94;-c;IBM869;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;IBM874;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x6a;-c;IBM875;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM880;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM891;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;IBM903;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;IBM904;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM905;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM9066;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x48;-c;IBM918;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x57;-c;IBM930;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM932;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM933;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM935;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM937;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM939;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM943;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;INIS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;INIS-8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;INIS-CYRILLIC;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xec;-c;ISIRI-3342;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xec;-c;ISO_10367-BOX;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-CN;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-CN-EXT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-JP;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-JP-2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-JP-3;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-KR;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO_2033;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO_5427;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO_5427-EXT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO_5428;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa4;-c;ISO_6937;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa0;-c;ISO_6937-2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-8859-11;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa5;-c;ISO-8859-3;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-8859-6;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-8859-7;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-8859-8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;ISO-IR-197;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;ISO-IR-209;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;JIS_C6220-1969-RO;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;JIS_C6229-1984-B;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;JOHAB;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;JUS_I.B1.002;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;KOI-8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x88;-c;KOI8-T;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;KSC5636;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;LATIN-GREEK;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;LATIN-GREEK-1;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xf6;-c;MAC-IS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;MSZ_7795.3;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NATS-DANO;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NATS-SEFI;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NC_NC00-10;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NF_Z_62-010;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NF_Z_62-010_1973;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NS_4551-1;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NS_4551-2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;PT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;PT2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x98;-c;RK1048;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x98;-c;SEN_850200_B;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x98;-c;SEN_850200_C;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;Shift_JISX0213;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;SJIS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x23;-c;T.61-8BIT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;TIS-620;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;TSCII;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;UHC;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xd8;-c;UNICODE;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xdc;-c;UTF-16;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xdc\x00;-c;UTF-16BE;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xdc;-c;UTF-16LE;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;UTF-7;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;WIN-SAMI-2;UTF-8//TRANSLIT//IGNORE"
|
||||
)
|
||||
|
||||
# List of option combinations that *should* lead to an error
|
||||
errorarray=(
|
||||
# Converting from/to invalid character sets should cause error
|
||||
"\x00\x00;;INVALID;INVALID"
|
||||
"\x00\x00;;INVALID;UTF-8"
|
||||
"\x00\x00;;UTF-8;INVALID"
|
||||
)
|
||||
|
||||
# Requires $twobyte input, $c flag, $from, and $to to be set; sets $ret
|
||||
execute_test ()
|
||||
{
|
||||
eval PROG=\"$ICONV\"
|
||||
echo -en "$twobyte" \
|
||||
| timeout -k 4 3 $PROG $c -f $from -t "$to" &>/dev/null
|
||||
ret=$?
|
||||
}
|
||||
|
||||
check_hangtest_result ()
|
||||
{
|
||||
if [ "$ret" -eq "124" ] || [ "$ret" -eq "137" ]; then # timeout/hang
|
||||
result="HANG"
|
||||
else
|
||||
if [ "$ret" -eq "139" ]; then # segfault
|
||||
result="SEGFAULT"
|
||||
else
|
||||
if [ "$ret" -gt "127" ]; then # unexpected error
|
||||
result="UNEXPECTED"
|
||||
else
|
||||
result="OK"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -n "$result: from: \"$from\", to: \"$to\","
|
||||
echo " input \"$twobyte\", flags \"$c\""
|
||||
|
||||
if [ "$result" != "OK" ]; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
for hangcommand in "${hangarray[@]}"; do
|
||||
twobyte="$(echo "$hangcommand" | cut -d";" -f 1)"
|
||||
c="$(echo "$hangcommand" | cut -d";" -f 2)"
|
||||
from="$(echo "$hangcommand" | cut -d";" -f 3)"
|
||||
to="$(echo "$hangcommand" | cut -d";" -f 4)"
|
||||
execute_test
|
||||
check_hangtest_result
|
||||
done
|
||||
|
||||
check_errtest_result ()
|
||||
{
|
||||
if [ "$ret" -eq "1" ]; then # we errored out as expected
|
||||
result="PASS"
|
||||
else
|
||||
result="FAIL"
|
||||
fi
|
||||
echo -n "$result: from: \"$from\", to: \"$to\","
|
||||
echo " input \"$twobyte\", flags \"$c\", return code $ret"
|
||||
|
||||
if [ "$result" != "PASS" ]; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
for errorcommand in "${errorarray[@]}"; do
|
||||
twobyte="$(echo "$errorcommand" | cut -d";" -f 1)"
|
||||
c="$(echo "$errorcommand" | cut -d";" -f 2)"
|
||||
from="$(echo "$errorcommand" | cut -d";" -f 3)"
|
||||
to="$(echo "$errorcommand" | cut -d";" -f 4)"
|
||||
execute_test
|
||||
check_errtest_result
|
||||
done
|
||||
+4
-1
@@ -73,7 +73,8 @@ modules.so := $(addsuffix .so, $(modules))
|
||||
ifeq (yes,$(build-shared))
|
||||
tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
|
||||
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
|
||||
bug-iconv10 bug-iconv11 bug-iconv12
|
||||
bug-iconv10 bug-iconv11 bug-iconv12 \
|
||||
bug-iconv13 bug-iconv14
|
||||
ifeq ($(have-thread-library),yes)
|
||||
tests += bug-iconv3
|
||||
endif
|
||||
@@ -316,6 +317,8 @@ $(objpfx)bug-iconv10.out: $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
$(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
$(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
|
||||
$(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so)) \
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user