From d0be539e01424fa720840dfe702dedf8e54379fb Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 17 Sep 2014 14:59:24 -0700 Subject: [PATCH 001/114] Revert "Revert "Added a bionic systrace class and tracing to pthread_mutex.cpp."" This reverts commit 26c1420fbb68916d66a8621b5efe8bb25cfdad7b. (cherry picked from commit 9e87f2f876243225deef37645ddceaa5d225cb41) Change-Id: I46a71a456952e3dd2c2bb0d9934820ffe8dc8469 --- libc/Android.mk | 1 + libc/bionic/bionic_systrace.cpp | 107 ++++++++++++++++++++++++++++++++ libc/bionic/pthread_mutex.cpp | 12 ++++ libc/private/bionic_systrace.h | 35 +++++++++++ 4 files changed, 155 insertions(+) create mode 100644 libc/bionic/bionic_systrace.cpp create mode 100644 libc/private/bionic_systrace.h diff --git a/libc/Android.mk b/libc/Android.mk index 5052cb10d..5f5add22b 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -89,6 +89,7 @@ libc_bionic_src_files := \ bionic/access.cpp \ bionic/assert.cpp \ bionic/atof.cpp \ + bionic/bionic_systrace.cpp \ bionic/bionic_time_conversions.cpp \ bionic/brk.cpp \ bionic/c16rtomb.cpp \ diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp new file mode 100644 index 000000000..b8e892e72 --- /dev/null +++ b/libc/bionic/bionic_systrace.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "private/bionic_systrace.h" +#include "private/libc_logging.h" + +#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ +#include + +#define WRITE_OFFSET 32 + +static const prop_info* g_pinfo = NULL; +static uint32_t g_serial = -1; +static uint64_t g_tags = 0; +static int g_trace_marker_fd = -1; + +static bool should_trace() { + // If g_pinfo is null, this means that systrace hasn't been run and it's safe to + // assume that no trace writing will need to take place. However, to avoid running + // this costly find check each time, we set it to a non-tracing value so that next + // time, it will just check the serial to see if the value has been changed. + // this function also deals with the bootup case, during which the call to property + // set will fail if the property server hasn't yet started. + if (g_pinfo == NULL) { + g_pinfo = __system_property_find("debug.atrace.tags.enableflags"); + if (g_pinfo == NULL) { + __system_property_set("debug.atrace.tags.enableflags", "0"); + g_pinfo = __system_property_find("debug.atrace.tags.enableflags"); + if (g_pinfo == NULL) { + return false; + } + } + } + + // Find out which tags have been enabled on the command line and set + // the value of tags accordingly. If the value of the property changes, + // the serial will also change, so the costly system_property_read function + // can be avoided by calling the much cheaper system_property_serial + // first. The values within pinfo may change, but its location is guaranteed + // not to move. + const uint32_t cur_serial = __system_property_serial(g_pinfo); + if (cur_serial != g_serial) { + g_serial = cur_serial; + char value[PROP_VALUE_MAX]; + __system_property_read(g_pinfo, 0, value); + g_tags = strtoull(value, NULL, 0); + } + + // Finally, verify that this tag value enables bionic tracing. + return ((g_tags & ATRACE_TAG_BIONIC) != 0); +} + +ScopedTrace::ScopedTrace(const char* message) { + if (!should_trace()) { + return; + } + + if (g_trace_marker_fd == -1) { + g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC); + if (g_trace_marker_fd == -1) { + __libc_fatal("Could not open kernel trace file: %s\n", strerror(errno)); + } + } + + // If bionic tracing has been enabled, then write the message to the + // kernel trace_marker. + int length = strlen(message); + char buf[length + WRITE_OFFSET]; + size_t len = snprintf(buf, length + WRITE_OFFSET, "B|%d|%s", getpid(), message); + ssize_t wbytes = TEMP_FAILURE_RETRY(write(g_trace_marker_fd, buf, len)); + + // Error while writing + if (static_cast(wbytes) != len) { + __libc_fatal("Could not write to kernel trace file: %s\n", strerror(errno)); + } +} + +ScopedTrace::~ScopedTrace() { + if (!should_trace()) { + return; + } + + ssize_t wbytes = TEMP_FAILURE_RETRY(write(g_trace_marker_fd, "E", 1)); + + // Error while writing + if (static_cast(wbytes) != 1) { + __libc_fatal("Could not write to kernel trace file: %s\n", strerror(errno)); + } +} diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp index 546166166..e00ffb437 100644 --- a/libc/bionic/pthread_mutex.cpp +++ b/libc/bionic/pthread_mutex.cpp @@ -39,6 +39,8 @@ #include "private/bionic_futex.h" #include "private/bionic_tls.h" +#include "private/bionic_systrace.h" + extern void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex); extern void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex); @@ -333,6 +335,10 @@ static inline void _normal_lock(pthread_mutex_t* mutex, int shared) { * that the mutex is in state 2 when we go to sleep on it, which * guarantees a wake-up call. */ + + ScopedTrace trace("Contending for pthread mutex"); + + while (__bionic_swap(locked_contended, &mutex->value) != unlocked) { __futex_wait_ex(&mutex->value, shared, locked_contended, NULL); } @@ -473,6 +479,8 @@ int pthread_mutex_lock(pthread_mutex_t* mutex) { mvalue = mutex->value; } + ScopedTrace trace("Contending for pthread mutex"); + for (;;) { int newval; @@ -626,6 +634,8 @@ static int __pthread_mutex_timedlock(pthread_mutex_t* mutex, const timespec* abs return 0; } + ScopedTrace trace("Contending for timed pthread mutex"); + // Loop while needed. while (__bionic_swap(locked_contended, &mutex->value) != unlocked) { if (__timespec_from_absolute(&ts, abs_timeout, clock) < 0) { @@ -658,6 +668,8 @@ static int __pthread_mutex_timedlock(pthread_mutex_t* mutex, const timespec* abs mvalue = mutex->value; } + ScopedTrace trace("Contending for timed pthread mutex"); + while (true) { // If the value is 'unlocked', try to acquire it directly. // NOTE: put state to 2 since we know there is contention. diff --git a/libc/private/bionic_systrace.h b/libc/private/bionic_systrace.h new file mode 100644 index 000000000..ad9ff7f71 --- /dev/null +++ b/libc/private/bionic_systrace.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BIONIC_SYSTRACE_H +#define BIONIC_SYSTRACE_H + +#include "bionic_macros.h" + +// Tracing class for bionic. To begin a trace at a specified point: +// ScopedTrace("Trace message"); +// The trace will end when the contructor goes out of scope. + +class ScopedTrace { + public: + explicit ScopedTrace(const char* message); + ~ScopedTrace(); + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedTrace); +}; + +#endif From 411ff42f20729200c0fc2e24a83bc1dcd7a42a51 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Wed, 13 Aug 2014 11:25:01 -0700 Subject: [PATCH 002/114] Hide ScopedTrace. (cherry-pick of f2c1e7ee78a167ff323b9f45d20532d064d6778d.) Bug: 11156955 (cherry picked from commit ebb6b4a4d3fab87800b912c9d6ea917f5359f8af) Change-Id: Ifc10364b35384a9f34e4c2c634dd78a16065a817 --- libc/private/bionic_systrace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/private/bionic_systrace.h b/libc/private/bionic_systrace.h index ad9ff7f71..0b4560f92 100644 --- a/libc/private/bionic_systrace.h +++ b/libc/private/bionic_systrace.h @@ -23,7 +23,7 @@ // ScopedTrace("Trace message"); // The trace will end when the contructor goes out of scope. -class ScopedTrace { +class __LIBC_HIDDEN__ ScopedTrace { public: explicit ScopedTrace(const char* message); ~ScopedTrace(); From c189ffaaec45efb49e785517e504b41a5e57b088 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 26 Aug 2014 16:20:59 -0700 Subject: [PATCH 003/114] More cases where libc should use O_CLOEXEC. (cherry picked from commit f73183f1a34df22b62a3d0bbf82e18d5797c9cde) (cherry picked from commit 21ce3f506f3b54e4f57a37847375cef9f8aff57f) Change-Id: I70b240bd40ad8d2ba33ae7ab2618782709fd0d6a --- libc/bionic/bionic_systrace.cpp | 2 +- libc/bionic/dirent.cpp | 2 +- libc/bionic/malloc_debug_qemu.cpp | 2 +- libc/bionic/pthread_setname_np.cpp | 2 +- libc/bionic/system_properties.cpp | 21 ++------------------- 5 files changed, 6 insertions(+), 23 deletions(-) diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp index b8e892e72..f5be41553 100644 --- a/libc/bionic/bionic_systrace.cpp +++ b/libc/bionic/bionic_systrace.cpp @@ -74,7 +74,7 @@ ScopedTrace::ScopedTrace(const char* message) { } if (g_trace_marker_fd == -1) { - g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC); + g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY); if (g_trace_marker_fd == -1) { __libc_fatal("Could not open kernel trace file: %s\n", strerror(errno)); } diff --git a/libc/bionic/dirent.cpp b/libc/bionic/dirent.cpp index 7abc7f3ec..5e1c7a565 100644 --- a/libc/bionic/dirent.cpp +++ b/libc/bionic/dirent.cpp @@ -78,7 +78,7 @@ DIR* fdopendir(int fd) { } DIR* opendir(const char* path) { - int fd = open(path, O_RDONLY | O_DIRECTORY); + int fd = open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY); return (fd != -1) ? __allocate_DIR(fd) : NULL; } diff --git a/libc/bionic/malloc_debug_qemu.cpp b/libc/bionic/malloc_debug_qemu.cpp index b3b604d86..2f4949b12 100644 --- a/libc/bionic/malloc_debug_qemu.cpp +++ b/libc/bionic/malloc_debug_qemu.cpp @@ -606,7 +606,7 @@ extern "C" bool malloc_debug_initialize(HashTable*, const MallocDebug* malloc_di * the memory mapped spaces into writes to an I/O port that emulator * "listens to" on the other end. Note that until we open and map that * device, logging to emulator's stdout will not be available. */ - int fd = open("/dev/qemu_trace", O_RDWR); + int fd = open("/dev/qemu_trace", O_CLOEXEC | O_RDWR); if (fd < 0) { error_log("Unable to open /dev/qemu_trace"); return false; diff --git a/libc/bionic/pthread_setname_np.cpp b/libc/bionic/pthread_setname_np.cpp index 1ddf81044..7b2fa6b0a 100644 --- a/libc/bionic/pthread_setname_np.cpp +++ b/libc/bionic/pthread_setname_np.cpp @@ -67,7 +67,7 @@ int pthread_setname_np(pthread_t t, const char* thread_name) { } char comm_name[sizeof(TASK_COMM_FMT) + 8]; snprintf(comm_name, sizeof(comm_name), TASK_COMM_FMT, tid); - int fd = open(comm_name, O_WRONLY); + int fd = open(comm_name, O_CLOEXEC | O_WRONLY); if (fd == -1) { return errno; } diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp index ad69cf5f9..411d6bf34 100644 --- a/libc/bionic/system_properties.cpp +++ b/libc/bionic/system_properties.cpp @@ -201,14 +201,6 @@ static int map_prop_area_rw() return -1; } - // TODO: Is this really required ? Does android run on any kernels that - // don't support O_CLOEXEC ? - const int ret = fcntl(fd, F_SETFD, FD_CLOEXEC); - if (ret < 0) { - close(fd); - return -1; - } - if (ftruncate(fd, PA_SIZE) < 0) { close(fd); return -1; @@ -271,18 +263,9 @@ static int map_fd_ro(const int fd) { static int map_prop_area() { - int fd(open(property_filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC)); - if (fd >= 0) { - /* For old kernels that don't support O_CLOEXEC */ - const int ret = fcntl(fd, F_SETFD, FD_CLOEXEC); - if (ret < 0) { - close(fd); - return -1; - } - } - + int fd = open(property_filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY); bool close_fd = true; - if ((fd < 0) && (errno == ENOENT)) { + if (fd == -1 && errno == ENOENT) { /* * For backwards compatibility, if the file doesn't * exist, we use the environment to get the file descriptor. From 9969481d5bf05954fff9c0f3d1c95bb99c36b9a8 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 17 Sep 2014 15:25:35 -0700 Subject: [PATCH 004/114] Fix an unintended difference between aosp/master and lmp-dev-plus-aosp. Whitespace difference presumably introduced while fixing a merge conflict. Bug: 17549448 (cherry picked from commit 8fa377eb6afdea4b03b6a0d112471f7ee988fb96) Change-Id: I7e30f37da4430af19d09a661e489c8ff65e42297 --- libc/Android.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libc/Android.mk b/libc/Android.mk index 5f5add22b..56e98768b 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -865,8 +865,7 @@ LOCAL_CONLYFLAGS := $(libc_common_conlyflags) LOCAL_CPPFLAGS := $(libc_common_cppflags) LOCAL_C_INCLUDES := $(libc_common_c_includes) LOCAL_MODULE := libc_cxa -# GCC refuses to hide new/delete -LOCAL_CLANG := true +LOCAL_CLANG := true # GCC refuses to hide new/delete LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies) LOCAL_SYSTEM_SHARED_LIBRARIES := From b5f5b0e418e5c382573e367dd4aff9373180bbe4 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 30 Sep 2014 17:30:01 -0700 Subject: [PATCH 005/114] Fix update-tzdata.py to rebuild icu4c .dat file. Bug: 17731498 (cherry picked from commit f8896c6c93fd698b129742780878123a3a19ae07) Change-Id: If97e1ccf593a2ed6c2356077e660d6fd88a05875 --- libc/tools/zoneinfo/update-tzdata.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libc/tools/zoneinfo/update-tzdata.py b/libc/tools/zoneinfo/update-tzdata.py index e800e8f8b..f5681beb2 100755 --- a/libc/tools/zoneinfo/update-tzdata.py +++ b/libc/tools/zoneinfo/update-tzdata.py @@ -123,18 +123,21 @@ def BuildIcuToolsAndData(data_filename): print 'Making ICU data...' subprocess.check_call(['make']) - # Copy the output files to their ultimate destination. + # Copy the source file to its ultimate destination. icu_txt_data_dir = '%s/data/misc' % icu_dir print 'Copying zoneinfo64.txt to %s ...' % icu_txt_data_dir shutil.copy('zoneinfo64.txt', icu_txt_data_dir) + # Regenerate the .dat file. os.chdir(icu_working_dir) + subprocess.check_call(['make', '-j32']) + + # Copy the .dat file to its ultimate destination. icu_dat_data_dir = '%s/stubdata' % icu_dir datfiles = glob.glob('data/out/tmp/icudt??l.dat') if len(datfiles) != 1: print 'ERROR: Unexpectedly found %d .dat files (%s). Halting.' % (len(datfiles), datfiles) sys.exit(1) - datfile = datfiles[0] print 'Copying %s to %s ...' % (datfile, icu_dat_data_dir) shutil.copy(datfile, icu_dat_data_dir) From d18205049d5eac715ccad996fb6802b72544f50b Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 30 Sep 2014 17:35:38 -0700 Subject: [PATCH 006/114] Update bionic to tzdata 2014h. From the release notes: Changes affecting past time stamps America/Jamaica's 1974 spring-forward transition was Jan. 6, not Apr. 28. Shanks says Asia/Novokuznetsk switched from LMT (not "NMT") on 1924-05-01, not 1920-01-06. The old entry was based on a misinterpretation of Shanks. Some more zones have been turned into links, when they differed from existing zones only for older time stamps. As usual, these changes affect UTC offsets in pre-1970 time stamps only. Their old contents have been moved to the 'backzone' file. The affected zones are: Africa/Blantyre, Africa/Bujumbura, Africa/Gaborone, Africa/Harare, Africa/Kigali, Africa/Lubumbashi, Africa/Lusaka, Africa/Maseru, and Africa/Mbabane. Bug: 17731498 (cherry picked from commit 0c8fb51e6b8cfcd00d453cb5ebfa516f02009854) Change-Id: Icf8a9cbd309951b4ffc20c74eb1e78c1e39c222f --- libc/zoneinfo/tzdata | Bin 566837 -> 565331 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata index 8d574f5611ee934b7ec6e0e111f12d831787090b..33bfe6b88d2ea23fc55e4d52a60669dec57dddcd 100644 GIT binary patch delta 4398 zcmX}v0bCSS9tZHG78a+NU~6C^qLO0KNlHeA z{LCf7M2`}c3WF3CjR+MDlN3EPuJ)3OJ5liyC>H7cX10#cXZg;X`M)`@}q!zv!NlY9Ho2FPqn$XEoK5c_m;P0^TN@%b8sH|0sM$y$ zGb52tW>`??Ds>Zv1nHC}5?vIyXwWT{FDBUi{}+?&t~9vKU5RcatlP)qQL}lmJqXi> z{IzMpSV14=z4@zg!Ekh%My?=Ojj zeu4W_>~>$$o1n6mdaH`n)ZQ_|&3 zQK__XFdDqEaDYjdo5$jFO0jT&N#tEs;!kq(tx<3?e(MY+zH)#GW>0V3yM-(+Q{tcZ zG>P|qN4BRVK6o0Ho}n7m{kv#qare704V1*bmtiHmhn#_u$Nn0XN^?(s@Qwpp^xj+R zy~L*n(ZPVvo8W7d#366kjFQLUc*fN$aXD#vFO(X+#W8QxFyi=lbdtIc;Xg>l9%i5wy~%>ibkU0Qz!kmz&u0}1A$~R%o9a~52}fbEHCty#F##W zk#SpKClPHZA)Ah%nS`u?cBmvmEeI!*n~_GI4M!*6)F3n529C0hLN!4(Bj0#}_4f1B!-u>NXuwsdOvleW)AeBiWJYIy2%g+g8U^h{1GG) zzwb~$0!E;LjQJ3~WYW(F9?9pDgd`I65w;PYp^?m;fE zgQz39XV6Vv=W9An5^ruqB1xTy0+RnY8ptQ>(d*h79KtjBAW7y3wvpmFx2kB0PkzYQB-9-uc?^HCC8!Bi+$yW#`w-+Fd-06?f z&`^!$emYuM)NF=cV(JS(1kpZ$bfWJ?8M*omT3r|>@Bw7NLcGr*lMFbEa#yL1n5MuO z#xyb)Q8G7?MSP=BLD-6uOmo0%q9m5+5G~V#Y+}zwB}qMwb}};^rb&`WUjZvwc?vls zqZrlX-JR$l+pX|@R1(Es!$#C*$MfOiZ zz+`d(2`=)|@j8c6*e^paD%5IjW^O_4|<&Fis^ zeET9A$@vTDBQ1krjv$wiOfCx)kt=R!B1?3Iku2;+82Mol?Bqu+N(j5Gnfx>t+NqNG zxgFu;+WSZ&H+G?v+=@U8>B)nBn$k%T(?T`c-@ixtpO(q??LsRL^PUVA7XP>b%b#Xi zlj_B&twc02KZ-VTs{Zi$g zn}OF>2Wi~)e}PsWt{MzO9C-tlILSl*t4bAkT8_f~q=$4=7q}ed45)n-Z7z&Yvebhp za%>f{WO`6Rj<1DN<}SRRlEfEl5iP^_lhmz3rOYj~lP_1mWFyyMCH1MuAv{C1T>1|> z$X9mw&LP)eBMmPhSLPOK$capJ%G`nfTuGc8~bNQ5lL>C1v8f3mhFS%qv@O(}xe;|pZ@%3I9`U`8S`wIzE;42#0+N(7C6KV+ zkWW~zj_|I#T?8#w9%`bCg2j?&?W-KRYvge}D=yxQFQ4*9Wt2{S^1ZI0;ODv2*@&d) zr2$KNm{T^(u`x?hP-pi;v&BQi1)@=o`3-$!#=l@*!behsWHKuNMKV=rBGIE{Tmm37I_>&B>Bsb|V|#p`0ND2Qo%(wdgcjCfx88CE=zKE+0!%Li;n%a_t%? zhr*mT5=M<)<9@0S`lXWmeH1~gDM%;r@1u;&AB0xIg@@qYEHsx zUdtqr{Sl%Gb4oTTorg-Ydo2;=gDGNNqqovWDcO3e6sO)?kJM=qtnoUYt-GWq8RC?c&P zXi|0-u2jZn7~$(^C)eIb3E|w^Oyo&7LwSwE3DZm(;fHJ~;U{4W;X+uyO8F9tAp9gs zCtPfo5%x|id21{TnaX#Sh48Uu5`HX{6JB&1Vd^rjmORg-@G&Z5{+V&}<||{qd4W!T z*RxjhvX7#IoJpy2u702&%&!=#9?nUa;&AR&>#IDE6=*S~KF^W#u-g!*8@OTC8XV)M z>-8J^ojlasimmTR7bS0bj#0vg2hxWv3GjD45nf&VFIdDAd-?4CGJ8pZlRLQ}z2_ F_#YpI8h`)* delta 4978 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 Date: Wed, 23 Jul 2014 11:22:25 -0700 Subject: [PATCH 007/114] Added test for ifunc support in dynamic linker. ifuncs now work in i386 and x86_64 when called in the same library as well as in a different library. Bug:6657325 (cherry picked from commit c5a13efa9bc4264be0a9a9e37c00633af01584ed) Change-Id: I321d780bc2f9bd1baa749e1acacd2683aefe827b --- libc/include/elf.h | 19 ++--- linker/linker.cpp | 114 +++++++++++++++++++++++++++++- linker/linker.h | 6 ++ linker/linker_debug.h | 1 + tests/dlfcn_test.cpp | 33 +++++++++ tests/libs/Android.mk | 14 ++++ tests/libs/dlopen_testlib_ifunc.c | 37 ++++++++++ 7 files changed, 214 insertions(+), 10 deletions(-) create mode 100644 tests/libs/dlopen_testlib_ifunc.c diff --git a/libc/include/elf.h b/libc/include/elf.h index 0975b7a61..faae73e92 100644 --- a/libc/include/elf.h +++ b/libc/include/elf.h @@ -69,14 +69,17 @@ typedef struct { #define PT_GNU_RELRO 0x6474e552 -#define STB_LOOS 10 -#define STB_HIOS 12 -#define STB_LOPROC 13 -#define STB_HIPROC 15 +#define STB_LOOS 10 +#define STB_HIOS 12 +#define STB_LOPROC 13 +#define STB_HIPROC 15 -#define STT_LOOS 10 -#define STT_HIOS 12 -#define STT_LOPROC 13 -#define STT_HIPROC 15 +#define STT_GNU_IFUNC 10 +#define STT_LOOS 10 +#define STT_HIOS 12 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +#define R_386_IRELATIVE 42 #endif /* _ELF_H */ diff --git a/linker/linker.cpp b/linker/linker.cpp index cf657057e..b28a01d49 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -466,6 +466,29 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) return NULL; } +static void resolve_ifunc_symbols(soinfo* si) { + + phdr_table_unprotect_segments(si->phdr, si->phnum, si->load_bias); + + TRACE_TYPE(IFUNC, "CHECKING FOR IFUNCS AND PERFORMING SYMBOL UPDATES"); + + for (size_t i = 0; i < si->nchain; ++i) { + ElfW(Sym)* s = &si->symtab[i]; + if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { + // The address of the ifunc in the symbol table is the address of the + // function that chooses the function to which the ifunc will refer. + // In order to return the proper value, we run the choosing function + // in the linker and then return its result (minus the base offset). + TRACE_TYPE(IFUNC, "FOUND IFUNC"); + ElfW(Addr) (*ifunc_ptr)(); + ifunc_ptr = reinterpret_cast(s->st_value + si->base); + s->st_value = (ifunc_ptr() - si->base); + TRACE_TYPE(IFUNC, "NEW VALUE IS %p", (void*)s->st_value); + } + } + phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias); +} + static unsigned elfhash(const char* _name) { const unsigned char* name = reinterpret_cast(_name); unsigned h = 0, g; @@ -804,6 +827,10 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin return NULL; } + // if the library has any ifuncs, we will need to resolve them so that dlsym + // can handle them properly + resolve_ifunc_symbols(si); + return si; } @@ -931,6 +958,53 @@ void do_dlclose(soinfo* si) { protect_data(PROT_READ); } +// ifuncs are only defined for x86 +#if defined(__i386__) +static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* needed[]) { + for (size_t idx = 0; idx < count; ++idx, ++rel) { + ElfW(Sym)* s; + soinfo* lsi; + unsigned type = ELFW(R_TYPE)(rel->r_info); + unsigned sym = ELFW(R_SYM)(rel->r_info); + ElfW(Addr) reloc = static_cast(rel->r_offset + si->load_bias); + ElfW(Addr) sym_addr = 0; + const char* sym_name = NULL; + sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); + s = soinfo_do_lookup(si, sym_name, &lsi, needed); + + if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_386_JMP_SLOT) { + TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr)); + ElfW(Addr) (*ifunc_ptr)(); + ifunc_ptr = reinterpret_cast(s->st_value + si->base); + *reinterpret_cast(reloc) = ifunc_ptr(); + } + } +} +#endif + +#if defined(__x86_64__) +static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* needed[]) { + for (size_t idx = 0; idx < count; ++idx, ++rela) { + ElfW(Sym)* s; + soinfo* lsi; + unsigned type = ELFW(R_TYPE)(rela->r_info); + unsigned sym = ELFW(R_SYM)(rela->r_info); + ElfW(Addr) reloc = static_cast(rela->r_offset + si->load_bias); + ElfW(Addr) sym_addr = 0; + const char* sym_name = NULL; + sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); + s = soinfo_do_lookup(si, sym_name, &lsi, needed); + + if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_X86_64_JUMP_SLOT) { + TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr + rela->r_addend)); + ElfW(Addr) (*ifunc_ptr)(); + ifunc_ptr = reinterpret_cast(s->st_value + si->base); + *reinterpret_cast(reloc) = ifunc_ptr(); + } + } +} +#endif + #if defined(USE_RELA) static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* needed[]) { ElfW(Sym)* s; @@ -1142,7 +1216,11 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* MARK(rela->r_offset); TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast(reloc), static_cast(sym_addr + rela->r_addend), sym_name); - *reinterpret_cast(reloc) = sym_addr + rela->r_addend; + if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { + si->set_has_ifuncs(true); + } else { + *reinterpret_cast(reloc) = sym_addr + rela->r_addend; + } break; case R_X86_64_GLOB_DAT: count_relocation(kRelocAbsolute); @@ -1321,7 +1399,11 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n count_relocation(kRelocAbsolute); MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); - *reinterpret_cast(reloc) = sym_addr; + if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { + si->set_has_ifuncs(true); + } else { + *reinterpret_cast(reloc) = sym_addr; + } break; case R_386_GLOB_DAT: count_relocation(kRelocAbsolute); @@ -1581,6 +1663,14 @@ void soinfo::set_st_ino(ino_t ino) { st_ino = ino; } +void soinfo::set_has_ifuncs(bool ifuncs) { + if ((this->flags & FLAG_NEW_SOINFO) == 0) { + return; + } + + has_ifuncs = ifuncs; +} + dev_t soinfo::get_st_dev() { if ((this->flags & FLAG_NEW_SOINFO) == 0) { return 0; @@ -1597,6 +1687,14 @@ ino_t soinfo::get_st_ino() { return st_ino; } +bool soinfo::get_has_ifuncs() { + if ((this->flags & FLAG_NEW_SOINFO) == 0) { + return false; + } + + return has_ifuncs; +} + // This is a return on get_children() in case // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -1981,6 +2079,18 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { } #endif + // if there are ifuncs, we need to do an additional relocation pass. + // they cannot be resolved until the rest of the relocations are done + // because we need to call the resolution function which may be waiting + // on relocations. + if(si->get_has_ifuncs()) { +#if defined(__i386__) + soinfo_ifunc_relocate(si, si->plt_rel, si->plt_rel_count, needed); +#elif defined(__x86_64__) + soinfo_ifunc_relocate(si, si->plt_rela, si->plt_rela_count, needed); +#endif + } + #if defined(__mips__) if (!mips_relocate_got(si, needed)) { return false; diff --git a/linker/linker.h b/linker/linker.h index 374652eb8..d7cf24bfa 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -204,8 +204,12 @@ struct soinfo { void set_st_dev(dev_t st_dev); void set_st_ino(ino_t st_ino); + void set_has_ifuncs(bool ifunc); ino_t get_st_ino(); dev_t get_st_dev(); + bool get_has_ifuncs(); + + soinfo_list_t& get_children(); @@ -218,6 +222,8 @@ struct soinfo { // when FLAG_NEW_SOINFO is set in this->flags. unsigned int version; + bool has_ifuncs; + dev_t st_dev; ino_t st_ino; diff --git a/linker/linker_debug.h b/linker/linker_debug.h index 3faa38ef4..0c7a78418 100644 --- a/linker/linker_debug.h +++ b/linker/linker_debug.h @@ -42,6 +42,7 @@ #define TRACE_DEBUG 1 #define DO_TRACE_LOOKUP 1 #define DO_TRACE_RELO 1 +#define DO_TRACE_IFUNC 1 #define TIMING 0 #define STATS 0 #define COUNT_PAGES 0 diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 457fcd5c0..260cbd601 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -87,6 +87,39 @@ TEST(dlfcn, dlopen_noload) { ASSERT_EQ(0, dlclose(handle2)); } +// ifuncs are only supported on intel for now +#if defined(__i386__) || defined(__x86_64__) +TEST(dlfcn, ifunc) { + const char* (*foo_ptr)(); + const char* (*foo_library_ptr)(); + + // ifunc's choice depends on whether IFUNC_CHOICE has a value + // first check the set case + setenv("IFUNC_CHOICE", "set", 1); + void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); + ASSERT_TRUE(handle != NULL); + *(void **)(&foo_ptr) = dlsym(handle, "foo"); + *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library"); + ASSERT_TRUE(foo_ptr != NULL); + ASSERT_TRUE(foo_library_ptr != NULL); + ASSERT_EQ(strncmp("set", (*foo_ptr)(), 3), 0); + ASSERT_EQ(strncmp("set", (*foo_library_ptr)(), 3), 0); + dlclose(handle); + + // then check the unset case + unsetenv("IFUNC_CHOICE"); + handle = dlopen("libtest_ifunc.so", RTLD_NOW); + ASSERT_TRUE(handle != NULL); + *(void **)(&foo_ptr) = dlsym(handle, "foo"); + *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library"); + ASSERT_TRUE(foo_ptr != NULL); + ASSERT_TRUE(foo_library_ptr != NULL); + ASSERT_EQ(strncmp("unset", (*foo_ptr)(), 5), 0); + ASSERT_EQ(strncmp("unset", (*foo_library_ptr)(), 3), 0); + dlclose(handle); +} +#endif + TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 75df539b9..8f0ec7a56 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -114,6 +114,20 @@ build_type := target build_target := SHARED_LIBRARY include $(TEST_PATH)/Android.build.mk +# ----------------------------------------------------------------------------- +# Library used by ifunc tests +# ----------------------------------------------------------------------------- +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64)) + libtest_ifunc_src_files := \ + dlopen_testlib_ifunc.c + + LOCAL_SDK_VERSION := current + module := libtest_ifunc + build_type := target + build_target := SHARED_LIBRARY + include $(TEST_PATH)/Android.build.mk +endif + # ----------------------------------------------------------------------------- # Library used by atexit tests # ----------------------------------------------------------------------------- diff --git a/tests/libs/dlopen_testlib_ifunc.c b/tests/libs/dlopen_testlib_ifunc.c new file mode 100644 index 000000000..1c4baface --- /dev/null +++ b/tests/libs/dlopen_testlib_ifunc.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +const char* foo() __attribute__ ((ifunc ("foo_ifunc"))); + +const char* f1() { + return "unset"; +} + +const char* f2() { + return "set"; +} + +void* foo_ifunc() { + char* choice = getenv("IFUNC_CHOICE"); + return choice == NULL ? f1 : f2; +} + +const char* foo_library() { + return foo(); +} \ No newline at end of file From bd321c1106ed30a71d55d5c365335dfe552b0883 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 21 Aug 2014 13:54:03 -0700 Subject: [PATCH 008/114] Run constructors before resolving ifunc functions Bug: 17177284 (cherry picked from commit 9598b8c415e2fa9f240508185fe8c964b83f538d) Change-Id: I2c9631ee1cd77f8cf95ec0216a35b605c8786454 --- libc/include/elf.h | 2 -- linker/linker.cpp | 23 ++++++++++++----------- linker/linker.h | 1 + tests/Android.mk | 16 ++++++++++++++++ tests/dlfcn_test.cpp | 30 ++++++++++++++++++++---------- tests/libs/dlopen_testlib_ifunc.c | 21 ++++++++++++++++++++- 6 files changed, 69 insertions(+), 24 deletions(-) diff --git a/libc/include/elf.h b/libc/include/elf.h index faae73e92..7a9485aea 100644 --- a/libc/include/elf.h +++ b/libc/include/elf.h @@ -80,6 +80,4 @@ typedef struct { #define STT_LOPROC 13 #define STT_HIPROC 15 -#define R_386_IRELATIVE 42 - #endif /* _ELF_H */ diff --git a/linker/linker.cpp b/linker/linker.cpp index b28a01d49..ec0681fe6 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -466,14 +466,17 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) return NULL; } -static void resolve_ifunc_symbols(soinfo* si) { +void soinfo::resolve_ifunc_symbols() { + if (!get_has_ifuncs()) { + return; + } - phdr_table_unprotect_segments(si->phdr, si->phnum, si->load_bias); + phdr_table_unprotect_segments(phdr, phnum, load_bias); TRACE_TYPE(IFUNC, "CHECKING FOR IFUNCS AND PERFORMING SYMBOL UPDATES"); - for (size_t i = 0; i < si->nchain; ++i) { - ElfW(Sym)* s = &si->symtab[i]; + for (size_t i = 0; i < nchain; ++i) { + ElfW(Sym)* s = &symtab[i]; if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { // The address of the ifunc in the symbol table is the address of the // function that chooses the function to which the ifunc will refer. @@ -481,12 +484,12 @@ static void resolve_ifunc_symbols(soinfo* si) { // in the linker and then return its result (minus the base offset). TRACE_TYPE(IFUNC, "FOUND IFUNC"); ElfW(Addr) (*ifunc_ptr)(); - ifunc_ptr = reinterpret_cast(s->st_value + si->base); - s->st_value = (ifunc_ptr() - si->base); + ifunc_ptr = reinterpret_cast(s->st_value + base); + s->st_value = (ifunc_ptr() - base); TRACE_TYPE(IFUNC, "NEW VALUE IS %p", (void*)s->st_value); } } - phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias); + phdr_table_protect_segments(phdr, phnum, load_bias); } static unsigned elfhash(const char* _name) { @@ -827,10 +830,6 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin return NULL; } - // if the library has any ifuncs, we will need to resolve them so that dlsym - // can handle them properly - resolve_ifunc_symbols(si); - return si; } @@ -1599,6 +1598,8 @@ void soinfo::CallConstructors() { // DT_INIT should be called before DT_INIT_ARRAY if both are present. CallFunction("DT_INIT", init_func); CallArray("DT_INIT_ARRAY", init_array, init_array_count, false); + + resolve_ifunc_symbols(); } void soinfo::CallDestructors() { diff --git a/linker/linker.h b/linker/linker.h index d7cf24bfa..684561a88 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -216,6 +216,7 @@ struct soinfo { private: void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); + void resolve_ifunc_symbols(); private: // This part of the structure is only available diff --git a/tests/Android.mk b/tests/Android.mk index 8184bf74b..9ee33e004 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -356,6 +356,22 @@ bionic-unit-tests-run-on-host: bionic-unit-tests $(TARGET_OUT_EXECUTABLES)/$(LIN $(TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests$(NATIVE_TEST_SUFFIX) $(BIONIC_TEST_FLAGS) endif +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86_64)) +# add target to run lp32 tests +bionic-unit-tests-run-on-host32: bionic-unit-tests $(TARGET_OUT_EXECUTABLES)/$(LINKER) $(TARGET_OUT_EXECUTABLES)/sh + if [ ! -d /system -o ! -d /system/bin ]; then \ + echo "Attempting to create /system/bin"; \ + sudo mkdir -p -m 0777 /system/bin; \ + fi + mkdir -p $(TARGET_OUT_DATA)/local/tmp + cp $(TARGET_OUT_EXECUTABLES)/linker /system/bin + cp $(TARGET_OUT_EXECUTABLES)/sh /system/bin + ANDROID_DATA=$(TARGET_OUT_DATA) \ + ANDROID_ROOT=$(TARGET_OUT) \ + LD_LIBRARY_PATH=$(2ND_TARGET_OUT_SHARED_LIBRARIES) \ + $(2ND_TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests32 $(BIONIC_TEST_FLAGS) +endif + endif # linux-x86 include $(call first-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 260cbd601..6de38c89e 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -90,32 +90,42 @@ TEST(dlfcn, dlopen_noload) { // ifuncs are only supported on intel for now #if defined(__i386__) || defined(__x86_64__) TEST(dlfcn, ifunc) { - const char* (*foo_ptr)(); - const char* (*foo_library_ptr)(); + typedef const char* (*fn_ptr)(); // ifunc's choice depends on whether IFUNC_CHOICE has a value // first check the set case setenv("IFUNC_CHOICE", "set", 1); void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); ASSERT_TRUE(handle != NULL); - *(void **)(&foo_ptr) = dlsym(handle, "foo"); - *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library"); + fn_ptr foo_ptr = reinterpret_cast(dlsym(handle, "foo")); + fn_ptr foo_library_ptr = reinterpret_cast(dlsym(handle, "foo_library")); ASSERT_TRUE(foo_ptr != NULL); ASSERT_TRUE(foo_library_ptr != NULL); - ASSERT_EQ(strncmp("set", (*foo_ptr)(), 3), 0); - ASSERT_EQ(strncmp("set", (*foo_library_ptr)(), 3), 0); + ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0); + ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0); dlclose(handle); // then check the unset case unsetenv("IFUNC_CHOICE"); handle = dlopen("libtest_ifunc.so", RTLD_NOW); ASSERT_TRUE(handle != NULL); - *(void **)(&foo_ptr) = dlsym(handle, "foo"); - *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library"); + foo_ptr = reinterpret_cast(dlsym(handle, "foo")); + foo_library_ptr = reinterpret_cast(dlsym(handle, "foo_library")); ASSERT_TRUE(foo_ptr != NULL); ASSERT_TRUE(foo_library_ptr != NULL); - ASSERT_EQ(strncmp("unset", (*foo_ptr)(), 5), 0); - ASSERT_EQ(strncmp("unset", (*foo_library_ptr)(), 3), 0); + ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0); + ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0); + dlclose(handle); +} + +TEST(dlfcn, ifunc_ctor_call) { + typedef const char* (*fn_ptr)(); + + void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); + ASSERT_TRUE(handle != NULL) << dlerror(); + fn_ptr is_ctor_called = reinterpret_cast(dlsym(handle, "is_ctor_called")); + ASSERT_TRUE(is_ctor_called != NULL) << dlerror(); + ASSERT_STREQ("true", is_ctor_called()); dlclose(handle); } #endif diff --git a/tests/libs/dlopen_testlib_ifunc.c b/tests/libs/dlopen_testlib_ifunc.c index 1c4baface..48748417d 100644 --- a/tests/libs/dlopen_testlib_ifunc.c +++ b/tests/libs/dlopen_testlib_ifunc.c @@ -17,7 +17,22 @@ #include #include +static int g_flag = 0; + +static void __attribute__((constructor)) init_flag() { + g_flag = 1; +} + const char* foo() __attribute__ ((ifunc ("foo_ifunc"))); +const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun"))); + +const char* return_true() { + return "true"; +} + +const char* return_false() { + return "false"; +} const char* f1() { return "unset"; @@ -27,6 +42,10 @@ const char* f2() { return "set"; } +void* is_ctor_called_ifun() { + return g_flag == 0 ? return_false : return_true; +} + void* foo_ifunc() { char* choice = getenv("IFUNC_CHOICE"); return choice == NULL ? f1 : f2; @@ -34,4 +53,4 @@ void* foo_ifunc() { const char* foo_library() { return foo(); -} \ No newline at end of file +} From 3bbd218ef1a70e59662e704c59af6dff1f9d1253 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Fri, 22 Aug 2014 12:25:04 -0700 Subject: [PATCH 009/114] Bump soinfo version This includes: 1. Placing has_ifunc after fields with version = 0 2. Switch to has_min_version(v) function. 3. Minor soinfo initialization refactoring (placement new + ctor) (cherry picked from commit 0d15094287fe0f288d9c258953143fc1998b6b5a) Change-Id: Idf135fdd3d4826b5653f32add2adc6db5d4a4f95 --- linker/dlfcn.cpp | 11 ++--- linker/linker.cpp | 110 ++++++++++++++++++++++------------------------ linker/linker.h | 18 +++++--- 3 files changed, 69 insertions(+), 70 deletions(-) diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 5d6db8e29..e15f54d56 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -232,17 +232,12 @@ static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 }; static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; #endif -// Defined as global because we do not yet have access -// to synchronization functions __cxa_guard_* needed -// to define statics inside functions. -static soinfo __libdl_info; +static soinfo __libdl_info("libdl.so", nullptr); // This is used by the dynamic linker. Every process gets these symbols for free. soinfo* get_libdl_info() { - if (__libdl_info.name[0] == '\0') { - // initialize - strncpy(__libdl_info.name, "libdl.so", sizeof(__libdl_info.name)); - __libdl_info.flags = FLAG_LINKED | FLAG_NEW_SOINFO; + if ((__libdl_info.flags & FLAG_LINKED) == 0) { + __libdl_info.flags |= FLAG_LINKED; __libdl_info.strtab = ANDROID_LIBDL_STRTAB; __libdl_info.symtab = g_libdl_symtab; __libdl_info.nbucket = sizeof(g_libdl_buckets)/sizeof(unsigned); diff --git a/linker/linker.cpp b/linker/linker.cpp index ec0681fe6..e4a6523b7 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -35,9 +35,10 @@ #include #include #include -#include #include +#include + // Private C library headers. #include "private/bionic_tls.h" #include "private/KernelArgumentBlock.h" @@ -290,17 +291,7 @@ static soinfo* soinfo_alloc(const char* name, struct stat* file_stat) { return NULL; } - soinfo* si = g_soinfo_allocator.alloc(); - - // Initialize the new element. - memset(si, 0, sizeof(soinfo)); - strlcpy(si->name, name, sizeof(si->name)); - si->flags = FLAG_NEW_SOINFO; - - if (file_stat != NULL) { - si->set_st_dev(file_stat->st_dev); - si->set_st_ino(file_stat->st_ino); - } + soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat); sonext->next = si; sonext = si; @@ -466,6 +457,19 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) return NULL; } +soinfo::soinfo(const char* name, const struct stat* file_stat) { + memset(this, 0, sizeof(*this)); + + strlcpy(this->name, name, sizeof(this->name)); + flags = FLAG_NEW_SOINFO; + version = SOINFO_VERSION; + + if (file_stat != NULL) { + set_st_dev(file_stat->st_dev); + set_st_ino(file_stat->st_ino); + } +} + void soinfo::resolve_ifunc_symbols() { if (!get_has_ifuncs()) { return; @@ -878,7 +882,7 @@ static void soinfo_unload(soinfo* si) { TRACE("unloading '%s'", si->name); si->CallDestructors(); - if ((si->flags | FLAG_NEW_SOINFO) != 0) { + if (si->has_min_version(0)) { si->get_children().for_each([&] (soinfo* child) { TRACE("%s needs to unload %s", si->name, child->name); soinfo_unload(child); @@ -1617,16 +1621,14 @@ void soinfo::CallDestructors() { } void soinfo::add_child(soinfo* child) { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return; + if (has_min_version(0)) { + this->children.push_front(child); + child->parents.push_front(this); } - - this->children.push_front(child); - child->parents.push_front(this); } void soinfo::remove_all_links() { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { + if (!has_min_version(0)) { return; } @@ -1649,51 +1651,45 @@ void soinfo::remove_all_links() { } void soinfo::set_st_dev(dev_t dev) { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return; + if (has_min_version(0)) { + st_dev = dev; } - - st_dev = dev; } void soinfo::set_st_ino(ino_t ino) { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return; + if (has_min_version(0)) { + st_ino = ino; } - - st_ino = ino; } void soinfo::set_has_ifuncs(bool ifuncs) { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return; + if (has_min_version(1)) { + has_ifuncs = ifuncs; } - - has_ifuncs = ifuncs; } dev_t soinfo::get_st_dev() { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return 0; + if (has_min_version(0)) { + return st_dev; } - return st_dev; + return 0; }; ino_t soinfo::get_st_ino() { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return 0; + if (has_min_version(0)) { + return st_ino; } - return st_ino; + return 0; } bool soinfo::get_has_ifuncs() { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return false; + if (has_min_version(1)) { + return has_ifuncs; } - return has_ifuncs; + return false; } // This is a return on get_children() in case @@ -1701,11 +1697,11 @@ bool soinfo::get_has_ifuncs() { static soinfo::soinfo_list_t g_empty_list; soinfo::soinfo_list_t& soinfo::get_children() { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return g_empty_list; + if (has_min_version(0)) { + return this->children; } - return this->children; + return g_empty_list; } /* Force any of the closed stdin, stdout and stderr to be associated with @@ -2167,7 +2163,12 @@ static void add_vdso(KernelArgumentBlock& args __unused) { /* * This is linker soinfo for GDB. See details below. */ -static soinfo linker_soinfo_for_gdb; +#if defined(__LP64__) +#define LINKER_PATH "/system/bin/linker64" +#else +#define LINKER_PATH "/system/bin/linker" +#endif +static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr); /* gdb expects the linker to be in the debug shared object list. * Without this, gdb has trouble locating the linker's ".text" @@ -2177,12 +2178,6 @@ static soinfo linker_soinfo_for_gdb; * be on the soinfo list. */ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) { -#if defined(__LP64__) - strlcpy(linker_soinfo_for_gdb.name, "/system/bin/linker64", sizeof(linker_soinfo_for_gdb.name)); -#else - strlcpy(linker_soinfo_for_gdb.name, "/system/bin/linker", sizeof(linker_soinfo_for_gdb.name)); -#endif - linker_soinfo_for_gdb.flags = FLAG_NEW_SOINFO; linker_soinfo_for_gdb.base = linker_base; /* @@ -2401,10 +2396,6 @@ extern "C" void _start(); * function, or other GOT reference will generate a segfault. */ extern "C" ElfW(Addr) __linker_init(void* raw_args) { - // Initialize static variables. - solist = get_libdl_info(); - sonext = get_libdl_info(); - KernelArgumentBlock args(raw_args); ElfW(Addr) linker_addr = args.getauxval(AT_BASE); @@ -2412,8 +2403,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_addr); ElfW(Phdr)* phdr = reinterpret_cast(linker_addr + elf_hdr->e_phoff); - soinfo linker_so; - memset(&linker_so, 0, sizeof(soinfo)); + soinfo linker_so("[dynamic linker]", nullptr); // If the linker is not acting as PT_INTERP entry_point is equal to // _start. Which means that the linker is running as an executable and @@ -2425,7 +2415,6 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]); } - strcpy(linker_so.name, "[dynamic linker]"); linker_so.base = linker_addr; linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); @@ -2449,6 +2438,13 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { // Initialize the linker's own global variables linker_so.CallConstructors(); + // Initialize static variables. Note that in order to + // get correct libdl_info we need to call constructors + // before get_libdl_info(). + solist = get_libdl_info(); + sonext = get_libdl_info(); + + // We have successfully fixed our own relocations. It's safe to run // the main part of the linker now. args.abort_message_ptr = &g_abort_message; diff --git a/linker/linker.h b/linker/linker.h index 684561a88..5e21f7015 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -30,6 +30,7 @@ #define _LINKER_H_ #include +#include #include #include #include @@ -88,6 +89,8 @@ #define FLAG_LINKER 0x00000010 // The linker itself #define FLAG_NEW_SOINFO 0x40000000 // new soinfo format +#define SOINFO_VERSION 1 + #define SOINFO_NAME_LEN 128 typedef void (*linker_function_t)(); @@ -195,6 +198,9 @@ struct soinfo { bool has_text_relocations; #endif bool has_DT_SYMBOLIC; + + soinfo(const char* name, const struct stat* file_stat); + void CallConstructors(); void CallDestructors(); void CallPreInitConstructors(); @@ -209,10 +215,11 @@ struct soinfo { dev_t get_st_dev(); bool get_has_ifuncs(); - - soinfo_list_t& get_children(); + bool inline has_min_version(uint32_t min_version) { + return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; + } private: void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); @@ -221,10 +228,9 @@ struct soinfo { private: // This part of the structure is only available // when FLAG_NEW_SOINFO is set in this->flags. - unsigned int version; - - bool has_ifuncs; + uint32_t version; + // version >= 0 dev_t st_dev; ino_t st_ino; @@ -232,6 +238,8 @@ struct soinfo { soinfo_list_t children; soinfo_list_t parents; + // version >= 1 + bool has_ifuncs; }; extern soinfo* get_libdl_info(); From 93c3f4203c92ece8b97d770af9b675f5ffb90c67 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 26 Aug 2014 14:16:52 -0700 Subject: [PATCH 010/114] Enable __cxa_atexit && __cxa_finalize for linker This allows adding destructors to classes used for global variables. (cherry picked from commit 14241402de0faa4b244b1bd6b1f0799ce169b880) Change-Id: I1d8776130d1e01a8c53d23a2949f5010f4c96b16 --- linker/Android.mk | 1 + linker/linked_list.h | 3 +++ linker/linker.cpp | 13 ++----------- linker/linker_libc_support.c | 17 +++++++++++++++++ tests/Android.mk | 2 +- 5 files changed, 24 insertions(+), 12 deletions(-) create mode 100644 linker/linker_libc_support.c diff --git a/linker/Android.mk b/linker/Android.mk index 5853c9070..4298032a4 100644 --- a/linker/Android.mk +++ b/linker/Android.mk @@ -8,6 +8,7 @@ LOCAL_SRC_FILES:= \ linker.cpp \ linker_allocator.cpp \ linker_environ.cpp \ + linker_libc_support.c \ linker_phdr.cpp \ rt.cpp \ diff --git a/linker/linked_list.h b/linker/linked_list.h index 8096e623d..e51eb9cb0 100644 --- a/linker/linked_list.h +++ b/linker/linked_list.h @@ -32,6 +32,9 @@ template class LinkedList { public: LinkedList() : head_(nullptr), tail_(nullptr) {} + ~LinkedList() { + clear(); + } void push_front(T* const element) { LinkedListEntry* new_entry = Allocator::alloc(); diff --git a/linker/linker.cpp b/linker/linker.cpp index e4a6523b7..6aba39471 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -2199,16 +2199,6 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) { * and other non-local data at this point. */ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) { - /* NOTE: we store the args pointer on a special location - * of the temporary TLS area in order to pass it to - * the C Library's runtime initializer. - * - * The initializer must clear the slot and reset the TLS - * to point to a different location to ensure that no other - * shared library constructor can access it. - */ - __libc_init_tls(args); - #if TIMING struct timeval t0, t1; gettimeofday(&t0, 0); @@ -2435,6 +2425,8 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { _exit(EXIT_FAILURE); } + __libc_init_tls(args); + // Initialize the linker's own global variables linker_so.CallConstructors(); @@ -2444,7 +2436,6 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { solist = get_libdl_info(); sonext = get_libdl_info(); - // We have successfully fixed our own relocations. It's safe to run // the main part of the linker now. args.abort_message_ptr = &g_abort_message; diff --git a/linker/linker_libc_support.c b/linker/linker_libc_support.c new file mode 100644 index 000000000..17db6d4e7 --- /dev/null +++ b/linker/linker_libc_support.c @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../libc/arch-common/bionic/__dso_handle.h" diff --git a/tests/Android.mk b/tests/Android.mk index 9ee33e004..864052e81 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -358,7 +358,7 @@ endif ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86_64)) # add target to run lp32 tests -bionic-unit-tests-run-on-host32: bionic-unit-tests $(TARGET_OUT_EXECUTABLES)/$(LINKER) $(TARGET_OUT_EXECUTABLES)/sh +bionic-unit-tests-run-on-host32: bionic-unit-tests_32 $(TARGET_OUT_EXECUTABLES)/$(LINKER) $(TARGET_OUT_EXECUTABLES)/sh if [ ! -d /system -o ! -d /system/bin ]; then \ echo "Attempting to create /system/bin"; \ sudo mkdir -p -m 0777 /system/bin; \ From 5dfe802d0dedbfce355a7ece5bc77c7346941bb2 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 26 Aug 2014 15:56:31 -0700 Subject: [PATCH 011/114] Remove unnecessary calls to LinkedList::clear() (cherry picked from commit 608217e1674d8fd8b334fe18c753b6c4638ed783) Change-Id: I031359d79b2e77977ace197ef410e41539dc0ce6 --- linker/linker.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 6aba39471..9a58103b0 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -657,8 +657,6 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { if (result != nullptr) { *found = current_soinfo; - visit_list.clear(); - visited.clear(); return result; } visited.push_back(current_soinfo); @@ -668,8 +666,6 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { }); } - visit_list.clear(); - visited.clear(); return nullptr; } From cfad7ae9346af5c665a1bc239e1bbe4f679750c6 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Fri, 29 Aug 2014 12:02:36 -0700 Subject: [PATCH 012/114] Replace NULL with nullptr (cherry picked from commit 851135bf9941b3813adb9b4f43d76e040c4ba157) Change-Id: Ic4997907680db7472ef38ffb0f0ca66fff37b797 --- linker/debugger.cpp | 26 ++--- linker/dlfcn.cpp | 46 ++++----- linker/linker.cpp | 198 +++++++++++++++++++------------------- linker/linker_environ.cpp | 30 +++--- linker/linker_environ.h | 2 +- linker/linker_phdr.cpp | 32 +++--- linker/linker_phdr.h | 2 +- 7 files changed, 168 insertions(+), 168 deletions(-) diff --git a/linker/debugger.cpp b/linker/debugger.cpp index c31615171..6565985b5 100644 --- a/linker/debugger.cpp +++ b/linker/debugger.cpp @@ -162,12 +162,12 @@ static void log_signal_summary(int signum, const siginfo_t* info) { thread_name[MAX_TASK_NAME_LEN] = 0; } - // "info" will be NULL if the siginfo_t information was not available. + // "info" will be null if the siginfo_t information was not available. // Many signals don't have an address or a code. char code_desc[32]; // ", code -6" char addr_desc[32]; // ", fault addr 0x1234" addr_desc[0] = code_desc[0] = 0; - if (info != NULL) { + if (info != nullptr) { // For a rethrown signal, this si_code will be right and the one debuggerd shows will // always be SI_TKILL. __libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code); @@ -198,7 +198,7 @@ static bool have_siginfo(int signum) { } bool result = (old_action.sa_flags & SA_SIGINFO) != 0; - if (sigaction(signum, &old_action, NULL) == -1) { + if (sigaction(signum, &old_action, nullptr) == -1) { __libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s", strerror(errno)); } @@ -230,7 +230,7 @@ static void send_debuggerd_packet(siginfo_t* info) { msg.action = DEBUGGER_ACTION_CRASH; msg.tid = gettid(); msg.abort_msg_address = reinterpret_cast(g_abort_message); - msg.original_si_code = (info != NULL) ? info->si_code : 0; + msg.original_si_code = (info != nullptr) ? info->si_code : 0; int ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))); if (ret == sizeof(msg)) { char debuggerd_ack; @@ -255,7 +255,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) // It's possible somebody cleared the SA_SIGINFO flag, which would mean // our "info" arg holds an undefined value. if (!have_siginfo(signal_number)) { - info = NULL; + info = nullptr; } log_signal_summary(signal_number, info); @@ -296,14 +296,14 @@ __LIBC_HIDDEN__ void debuggerd_init() { // Use the alternate signal stack if available so we can catch stack overflows. action.sa_flags |= SA_ONSTACK; - sigaction(SIGABRT, &action, NULL); - sigaction(SIGBUS, &action, NULL); - sigaction(SIGFPE, &action, NULL); - sigaction(SIGILL, &action, NULL); - sigaction(SIGPIPE, &action, NULL); - sigaction(SIGSEGV, &action, NULL); + sigaction(SIGABRT, &action, nullptr); + sigaction(SIGBUS, &action, nullptr); + sigaction(SIGFPE, &action, nullptr); + sigaction(SIGILL, &action, nullptr); + sigaction(SIGPIPE, &action, nullptr); + sigaction(SIGSEGV, &action, nullptr); #if defined(SIGSTKFLT) - sigaction(SIGSTKFLT, &action, NULL); + sigaction(SIGSTKFLT, &action, nullptr); #endif - sigaction(SIGTRAP, &action, NULL); + sigaction(SIGTRAP, &action, nullptr); } diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index e15f54d56..38484d995 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -42,7 +42,7 @@ static const char* __bionic_set_dlerror(char* new_value) { static void __bionic_format_dlerror(const char* msg, const char* detail) { char* buffer = __get_thread()->dlerror_buffer; strlcpy(buffer, msg, __BIONIC_DLERROR_BUFFER_SIZE); - if (detail != NULL) { + if (detail != nullptr) { strlcat(buffer, ": ", __BIONIC_DLERROR_BUFFER_SIZE); strlcat(buffer, detail, __BIONIC_DLERROR_BUFFER_SIZE); } @@ -51,7 +51,7 @@ static void __bionic_format_dlerror(const char* msg, const char* detail) { } const char* dlerror() { - const char* old_value = __bionic_set_dlerror(NULL); + const char* old_value = __bionic_set_dlerror(nullptr); return old_value; } @@ -68,9 +68,9 @@ void android_update_LD_LIBRARY_PATH(const char* ld_library_path) { static void* dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) { ScopedPthreadMutexLocker locker(&g_dl_mutex); soinfo* result = do_dlopen(filename, flags, extinfo); - if (result == NULL) { + if (result == nullptr) { __bionic_format_dlerror("dlopen failed", linker_get_error_buffer()); - return NULL; + return nullptr; } return result; } @@ -80,33 +80,33 @@ void* android_dlopen_ext(const char* filename, int flags, const android_dlextinf } void* dlopen(const char* filename, int flags) { - return dlopen_ext(filename, flags, NULL); + return dlopen_ext(filename, flags, nullptr); } void* dlsym(void* handle, const char* symbol) { ScopedPthreadMutexLocker locker(&g_dl_mutex); #if !defined(__LP64__) - if (handle == NULL) { - __bionic_format_dlerror("dlsym library handle is null", NULL); - return NULL; + if (handle == nullptr) { + __bionic_format_dlerror("dlsym library handle is null", nullptr); + return nullptr; } #endif - if (symbol == NULL) { - __bionic_format_dlerror("dlsym symbol name is null", NULL); - return NULL; + if (symbol == nullptr) { + __bionic_format_dlerror("dlsym symbol name is null", nullptr); + return nullptr; } - soinfo* found = NULL; - ElfW(Sym)* sym = NULL; + soinfo* found = nullptr; + ElfW(Sym)* sym = nullptr; if (handle == RTLD_DEFAULT) { - sym = dlsym_linear_lookup(symbol, &found, NULL); + sym = dlsym_linear_lookup(symbol, &found, nullptr); } else if (handle == RTLD_NEXT) { void* caller_addr = __builtin_return_address(0); soinfo* si = find_containing_library(caller_addr); - sym = NULL; + sym = nullptr; if (si && si->next) { sym = dlsym_linear_lookup(symbol, &found, si->next); } @@ -114,7 +114,7 @@ void* dlsym(void* handle, const char* symbol) { sym = dlsym_handle_lookup(reinterpret_cast(handle), &found, symbol); } - if (sym != NULL) { + if (sym != nullptr) { unsigned bind = ELF_ST_BIND(sym->st_info); if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) { @@ -122,10 +122,10 @@ void* dlsym(void* handle, const char* symbol) { } __bionic_format_dlerror("symbol found but not global", symbol); - return NULL; + return nullptr; } else { __bionic_format_dlerror("undefined symbol", symbol); - return NULL; + return nullptr; } } @@ -134,7 +134,7 @@ int dladdr(const void* addr, Dl_info* info) { // Determine if this address can be found in any library currently mapped. soinfo* si = find_containing_library(addr); - if (si == NULL) { + if (si == nullptr) { return 0; } @@ -146,7 +146,7 @@ int dladdr(const void* addr, Dl_info* info) { // Determine if any symbol in the library contains the specified address. ElfW(Sym)* sym = dladdr_find_symbol(si, addr); - if (sym != NULL) { + if (sym != nullptr) { info->dli_sname = si->strtab + sym->st_name; info->dli_saddr = reinterpret_cast(si->load_bias + sym->st_value); } @@ -164,7 +164,7 @@ int dlclose(void* handle) { // name_offset: starting index of the name in libdl_info.strtab #define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \ { name_offset, \ - reinterpret_cast(reinterpret_cast(value)), \ + reinterpret_cast(value), \ /* st_size */ 0, \ (shndx == 0) ? 0 : (STB_GLOBAL << 4), \ /* st_other */ 0, \ @@ -176,7 +176,7 @@ int dlclose(void* handle) { (shndx == 0) ? 0 : (STB_GLOBAL << 4), \ /* st_other */ 0, \ shndx, \ - reinterpret_cast(reinterpret_cast(value)), \ + reinterpret_cast(value), \ /* st_size */ 0, \ } @@ -199,7 +199,7 @@ static ElfW(Sym) g_libdl_symtab[] = { // This is actually the STH_UNDEF entry. Technically, it's // supposed to have st_name == 0, but instead, it points to an index // in the strtab with a \0 to make iterating through the symtab easier. - ELFW(SYM_INITIALIZER)(sizeof(ANDROID_LIBDL_STRTAB) - 1, NULL, 0), + ELFW(SYM_INITIALIZER)(sizeof(ANDROID_LIBDL_STRTAB) - 1, nullptr, 0), ELFW(SYM_INITIALIZER)( 0, &dlopen, 1), ELFW(SYM_INITIALIZER)( 7, &dlclose, 1), ELFW(SYM_INITIALIZER)( 15, &dlsym, 1), diff --git a/linker/linker.cpp b/linker/linker.cpp index 9a58103b0..8d8ccb508 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -97,7 +97,7 @@ static const char* const kDefaultLdPaths[] = { "/vendor/lib", "/system/lib", #endif - NULL + nullptr }; #define LDPATH_BUFSIZE (LDPATH_MAX*64) @@ -116,7 +116,7 @@ static soinfo* g_ld_preloads[LDPRELOAD_MAX + 1]; __LIBC_HIDDEN__ int g_ld_debug_verbosity; -__LIBC_HIDDEN__ abort_msg_t* g_abort_message = NULL; // For debuggerd. +__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd. enum RelocationKind { kRelocAbsolute = 0, @@ -189,7 +189,7 @@ size_t linker_get_error_buffer_size() { extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity(); static pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER; -static r_debug _r_debug = {1, NULL, reinterpret_cast(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0}; +static r_debug _r_debug = {1, nullptr, reinterpret_cast(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0}; static link_map* r_debug_tail = 0; static void insert_soinfo_into_debug_map(soinfo* info) { @@ -288,7 +288,7 @@ static void protect_data(int protection) { static soinfo* soinfo_alloc(const char* name, struct stat* file_stat) { if (strlen(name) >= SOINFO_NAME_LEN) { DL_ERR("library name \"%s\" too long", name); - return NULL; + return nullptr; } soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat); @@ -301,7 +301,7 @@ static soinfo* soinfo_alloc(const char* name, struct stat* file_stat) { } static void soinfo_free(soinfo* si) { - if (si == NULL) { + if (si == nullptr) { return; } @@ -309,16 +309,16 @@ static void soinfo_free(soinfo* si) { munmap(reinterpret_cast(si->base), si->size); } - soinfo *prev = NULL, *trav; + soinfo *prev = nullptr, *trav; TRACE("name %s: freeing soinfo @ %p", si->name, si); - for (trav = solist; trav != NULL; trav = trav->next) { + for (trav = solist; trav != nullptr; trav = trav->next) { if (trav == si) break; prev = trav; } - if (trav == NULL) { + if (trav == nullptr) { /* si was not in solist */ DL_ERR("name \"%s\" is not in solist!", si->name); return; @@ -327,7 +327,7 @@ static void soinfo_free(soinfo* si) { // clear links to/from si si->remove_all_links(); - /* prev will never be NULL, because the first entry in solist is + /* prev will never be null, because the first entry in solist is always the static libdl_info. */ prev->next = si->next; @@ -341,7 +341,7 @@ static void soinfo_free(soinfo* si) { static void parse_path(const char* path, const char* delimiters, const char** array, char* buf, size_t buf_size, size_t max_count) { - if (path == NULL) { + if (path == nullptr) { return; } @@ -358,9 +358,9 @@ static void parse_path(const char* path, const char* delimiters, // Forget the last path if we had to truncate; this occurs if the 2nd to // last char isn't '\0' (i.e. wasn't originally a delimiter). if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') { - array[i - 1] = NULL; + array[i - 1] = nullptr; } else { - array[i] = NULL; + array[i] = nullptr; } } @@ -396,7 +396,7 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) { } } *pcount = 0; - return NULL; + return nullptr; } #endif @@ -405,7 +405,7 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) { * loaded libraries. gcc_eh does the rest. */ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) { int rv = 0; - for (soinfo* si = solist; si != NULL; si = si->next) { + for (soinfo* si = solist; si != nullptr; si = si->next) { dl_phdr_info dl_info; dl_info.dlpi_addr = si->link_map_head.l_addr; dl_info.dlpi_name = si->link_map_head.l_name; @@ -454,7 +454,7 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) name, si->name, reinterpret_cast(si->base), hash, hash % si->nbucket); - return NULL; + return nullptr; } soinfo::soinfo(const char* name, const struct stat* file_stat) { @@ -464,7 +464,7 @@ soinfo::soinfo(const char* name, const struct stat* file_stat) { flags = FLAG_NEW_SOINFO; version = SOINFO_VERSION; - if (file_stat != NULL) { + if (file_stat != nullptr) { set_st_dev(file_stat->st_dev); set_st_ino(file_stat->st_ino); } @@ -511,9 +511,9 @@ static unsigned elfhash(const char* _name) { static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, soinfo* needed[]) { unsigned elf_hash = elfhash(name); - ElfW(Sym)* s = NULL; + ElfW(Sym)* s = nullptr; - if (si != NULL && somain != NULL) { + if (si != nullptr && somain != nullptr) { /* * Local scope is executable scope. Just start looking into it right away * for the shortcut. @@ -521,7 +521,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s if (si == somain) { s = soinfo_elf_lookup(si, elf_hash, name); - if (s != NULL) { + if (s != nullptr) { *lsi = si; goto done; } @@ -547,7 +547,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s DEBUG("%s: looking up %s in executable %s", si->name, name, somain->name); s = soinfo_elf_lookup(somain, elf_hash, name); - if (s != NULL) { + if (s != nullptr) { *lsi = somain; goto done; } @@ -573,7 +573,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s * Here we return the first definition found for simplicity. */ s = soinfo_elf_lookup(si, elf_hash, name); - if (s != NULL) { + if (s != nullptr) { *lsi = si; goto done; } @@ -587,7 +587,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s DEBUG("%s: looking up %s in executable %s after local scope", si->name, name, somain->name); s = soinfo_elf_lookup(somain, elf_hash, name); - if (s != NULL) { + if (s != nullptr) { *lsi = somain; goto done; } @@ -604,18 +604,18 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s } } - for (int i = 0; needed[i] != NULL; i++) { + for (int i = 0; needed[i] != nullptr; i++) { DEBUG("%s: looking up %s in %s", si->name, name, needed[i]->name); s = soinfo_elf_lookup(needed[i], elf_hash, name); - if (s != NULL) { + if (s != nullptr) { *lsi = needed[i]; goto done; } } done: - if (s != NULL) { + if (s != nullptr) { TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " "found in %s, base = %p, load bias = %p", si->name, name, reinterpret_cast(s->st_value), @@ -624,7 +624,7 @@ done: return s; } - return NULL; + return nullptr; } // Another soinfo list allocator to use in dlsym. We don't reuse @@ -677,20 +677,20 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) { unsigned elf_hash = elfhash(name); - if (start == NULL) { + if (start == nullptr) { start = solist; } - ElfW(Sym)* s = NULL; - for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) { + ElfW(Sym)* s = nullptr; + for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) { s = soinfo_elf_lookup(si, elf_hash, name); - if (s != NULL) { + if (s != nullptr) { *found = si; break; } } - if (s != NULL) { + if (s != nullptr) { TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p", name, reinterpret_cast(s->st_value), reinterpret_cast((*found)->base)); } @@ -700,12 +700,12 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) soinfo* find_containing_library(const void* p) { ElfW(Addr) address = reinterpret_cast(p); - for (soinfo* si = solist; si != NULL; si = si->next) { + for (soinfo* si = solist; si != nullptr; si = si->next) { if (address >= si->base && address - si->base < si->size) { return si; } } - return NULL; + return nullptr; } ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr) { @@ -722,12 +722,12 @@ ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr) { } } - return NULL; + return nullptr; } static int open_library_on_path(const char* name, const char* const paths[]) { char buf[512]; - for (size_t i = 0; paths[i] != NULL; ++i) { + for (size_t i = 0; paths[i] != nullptr; ++i) { int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name); if (n < 0 || n >= static_cast(sizeof(buf))) { PRINT("Warning: ignoring very long library path: %s/%s", paths[i], name); @@ -745,7 +745,7 @@ static int open_library(const char* name) { TRACE("[ opening %s ]", name); // If the name contains a slash, we should attempt to open it directly and not search the paths. - if (strchr(name, '/') != NULL) { + if (strchr(name, '/') != nullptr) { int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC)); if (fd != -1) { return fd; @@ -768,14 +768,14 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin int fd = -1; ScopedFd file_guard(-1); - if (extinfo != NULL && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { + if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { fd = extinfo->library_fd; } else { // Open the file. fd = open_library(name); if (fd == -1) { DL_ERR("library \"%s\" not found", name); - return NULL; + return nullptr; } file_guard.reset(fd); @@ -786,12 +786,12 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin struct stat file_stat; if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); - return NULL; + return nullptr; } // Check for symlink and other situations where // file can have different names. - for (soinfo* si = solist; si != NULL; si = si->next) { + for (soinfo* si = solist; si != nullptr; si = si->next) { if (si->get_st_dev() != 0 && si->get_st_ino() != 0 && si->get_st_dev() == file_stat.st_dev && @@ -802,17 +802,17 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin } if ((dlflags & RTLD_NOLOAD) != 0) { - return NULL; + return nullptr; } // Read the ELF header and load the segments. if (!elf_reader.Load(extinfo)) { - return NULL; + return nullptr; } soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat); - if (si == NULL) { - return NULL; + if (si == nullptr) { + return nullptr; } si->base = elf_reader.load_start(); si->size = elf_reader.load_size(); @@ -827,7 +827,7 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin if (!soinfo_link_image(si, extinfo)) { soinfo_free(si); - return NULL; + return nullptr; } return si; @@ -835,16 +835,16 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin static soinfo *find_loaded_library_by_name(const char* name) { const char* search_name = SEARCH_NAME(name); - for (soinfo* si = solist; si != NULL; si = si->next) { + for (soinfo* si = solist; si != nullptr; si = si->next) { if (!strcmp(search_name, si->name)) { return si; } } - return NULL; + return nullptr; } static soinfo* find_library_internal(const char* name, int dlflags, const android_dlextinfo* extinfo) { - if (name == NULL) { + if (name == nullptr) { return somain; } @@ -852,14 +852,14 @@ static soinfo* find_library_internal(const char* name, int dlflags, const androi // Library might still be loaded, the accurate detection // of this fact is done by load_library - if (si == NULL) { + if (si == nullptr) { TRACE("[ '%s' has not been found by name. Trying harder...]", name); si = load_library(name, dlflags, extinfo); } - if (si != NULL && (si->flags & FLAG_LINKED) == 0) { + if (si != nullptr && (si->flags & FLAG_LINKED) == 0) { DL_ERR("recursive link to \"%s\"", si->name); - return NULL; + return nullptr; } return si; @@ -867,7 +867,7 @@ static soinfo* find_library_internal(const char* name, int dlflags, const androi static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { soinfo* si = find_library_internal(name, dlflags, extinfo); - if (si != NULL) { + if (si != nullptr) { si->ref_count++; } return si; @@ -888,8 +888,8 @@ static void soinfo_unload(soinfo* si) { if (d->d_tag == DT_NEEDED) { const char* library_name = si->strtab + d->d_un.d_val; TRACE("%s needs to unload %s", si->name, library_name); - soinfo* needed = find_library(library_name, RTLD_NOLOAD, NULL); - if (needed != NULL) { + soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); + if (needed != nullptr) { soinfo_unload(needed); } else { // Not found: for example if symlink was deleted between dlopen and dlclose @@ -936,15 +936,15 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) { soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) { if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NOLOAD)) != 0) { DL_ERR("invalid flags to dlopen: %x", flags); - return NULL; + return nullptr; } - if (extinfo != NULL && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) { + if (extinfo != nullptr && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) { DL_ERR("invalid extended flags to android_dlopen_ext: %" PRIx64, extinfo->flags); - return NULL; + return nullptr; } protect_data(PROT_READ | PROT_WRITE); soinfo* si = find_library(name, flags, extinfo); - if (si != NULL) { + if (si != nullptr) { si->CallConstructors(); } protect_data(PROT_READ); @@ -967,7 +967,7 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, so unsigned sym = ELFW(R_SYM)(rel->r_info); ElfW(Addr) reloc = static_cast(rel->r_offset + si->load_bias); ElfW(Addr) sym_addr = 0; - const char* sym_name = NULL; + const char* sym_name = nullptr; sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); s = soinfo_do_lookup(si, sym_name, &lsi, needed); @@ -990,7 +990,7 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, unsigned sym = ELFW(R_SYM)(rela->r_info); ElfW(Addr) reloc = static_cast(rela->r_offset + si->load_bias); ElfW(Addr) sym_addr = 0; - const char* sym_name = NULL; + const char* sym_name = nullptr; sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); s = soinfo_do_lookup(si, sym_name, &lsi, needed); @@ -1014,7 +1014,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* unsigned sym = ELFW(R_SYM)(rela->r_info); ElfW(Addr) reloc = static_cast(rela->r_offset + si->load_bias); ElfW(Addr) sym_addr = 0; - const char* sym_name = NULL; + const char* sym_name = nullptr; DEBUG("Processing '%s' relocation at index %zd", si->name, idx); if (type == 0) { // R_*_NONE @@ -1023,7 +1023,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* if (sym != 0) { sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); s = soinfo_do_lookup(si, sym_name, &lsi, needed); - if (s == NULL) { + if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &si->symtab[sym]; if (ELF_ST_BIND(s->st_info) != STB_WEAK) { @@ -1079,7 +1079,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* } count_relocation(kRelocSymbol); } else { - s = NULL; + s = nullptr; } switch (type) { @@ -1283,7 +1283,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n unsigned sym = ELFW(R_SYM)(rel->r_info); ElfW(Addr) reloc = static_cast(rel->r_offset + si->load_bias); ElfW(Addr) sym_addr = 0; - const char* sym_name = NULL; + const char* sym_name = nullptr; DEBUG("Processing '%s' relocation at index %zd", si->name, idx); if (type == 0) { // R_*_NONE @@ -1292,7 +1292,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n if (sym != 0) { sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); s = soinfo_do_lookup(si, sym_name, &lsi, needed); - if (s == NULL) { + if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &si->symtab[sym]; if (ELF_ST_BIND(s->st_info) != STB_WEAK) { @@ -1351,7 +1351,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n } count_relocation(kRelocSymbol); } else { - s = NULL; + s = nullptr; } switch (type) { @@ -1476,7 +1476,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n #if defined(__mips__) static bool mips_relocate_got(soinfo* si, soinfo* needed[]) { ElfW(Addr)** got = si->plt_got; - if (got == NULL) { + if (got == nullptr) { return true; } unsigned local_gotno = si->mips_local_gotno; @@ -1508,7 +1508,7 @@ static bool mips_relocate_got(soinfo* si, soinfo* needed[]) { const char* sym_name = si->strtab + sym->st_name; soinfo* lsi; ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, needed); - if (s == NULL) { + if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. s = &symtab[g]; if (ELF_ST_BIND(s->st_info) != STB_WEAK) { @@ -1528,7 +1528,7 @@ static bool mips_relocate_got(soinfo* si, soinfo* needed[]) { #endif void soinfo::CallArray(const char* array_name __unused, linker_function_t* functions, size_t count, bool reverse) { - if (functions == NULL) { + if (functions == nullptr) { return; } @@ -1547,7 +1547,7 @@ void soinfo::CallArray(const char* array_name __unused, linker_function_t* funct } void soinfo::CallFunction(const char* function_name __unused, linker_function_t function) { - if (function == NULL || reinterpret_cast(function) == static_cast(-1)) { + if (function == nullptr || reinterpret_cast(function) == static_cast(-1)) { return; } @@ -1583,7 +1583,7 @@ void soinfo::CallConstructors() { // out above, the libc constructor will be called again (recursively!). constructors_called = true; - if ((flags & FLAG_EXE) == 0 && preinit_array != NULL) { + if ((flags & FLAG_EXE) == 0 && preinit_array != nullptr) { // The GNU dynamic linker silently ignores these, but we warn the developer. PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!", name, preinit_array_count); @@ -1779,7 +1779,7 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { ElfW(Word) dynamic_flags; phdr_table_get_dynamic_section(phdr, phnum, base, &si->dynamic, &dynamic_count, &dynamic_flags); - if (si->dynamic == NULL) { + if (si->dynamic == nullptr) { if (!relocating_linker) { DL_ERR("missing PT_DYNAMIC in \"%s\"", si->name); } @@ -1997,9 +1997,9 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { if (si->flags & FLAG_EXE) { memset(g_ld_preloads, 0, sizeof(g_ld_preloads)); size_t preload_count = 0; - for (size_t i = 0; g_ld_preload_names[i] != NULL; i++) { - soinfo* lsi = find_library(g_ld_preload_names[i], 0, NULL); - if (lsi != NULL) { + for (size_t i = 0; g_ld_preload_names[i] != nullptr; i++) { + soinfo* lsi = find_library(g_ld_preload_names[i], 0, nullptr); + if (lsi != nullptr) { g_ld_preloads[preload_count++] = lsi; } else { // As with glibc, failure to load an LD_PRELOAD library is just a warning. @@ -2016,8 +2016,8 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { if (d->d_tag == DT_NEEDED) { const char* library_name = si->strtab + d->d_un.d_val; DEBUG("%s needs %s", si->name, library_name); - soinfo* lsi = find_library(library_name, 0, NULL); - if (lsi == NULL) { + soinfo* lsi = find_library(library_name, 0, nullptr); + if (lsi == nullptr) { strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf)); DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s", library_name, si->name, tmp_err_buf); @@ -2028,7 +2028,7 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { *pneeded++ = lsi; } } - *pneeded = NULL; + *pneeded = nullptr; #if !defined(__LP64__) if (si->has_text_relocations) { @@ -2045,26 +2045,26 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { #endif #if defined(USE_RELA) - if (si->plt_rela != NULL) { + if (si->plt_rela != nullptr) { DEBUG("[ relocating %s plt ]\n", si->name); if (soinfo_relocate(si, si->plt_rela, si->plt_rela_count, needed)) { return false; } } - if (si->rela != NULL) { + if (si->rela != nullptr) { DEBUG("[ relocating %s ]\n", si->name); if (soinfo_relocate(si, si->rela, si->rela_count, needed)) { return false; } } #else - if (si->plt_rel != NULL) { + if (si->plt_rel != nullptr) { DEBUG("[ relocating %s plt ]", si->name); if (soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed)) { return false; } } - if (si->rel != NULL) { + if (si->rel != nullptr) { DEBUG("[ relocating %s ]", si->name); if (soinfo_relocate(si, si->rel, si->rel_count, needed)) { return false; @@ -2140,11 +2140,11 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { static void add_vdso(KernelArgumentBlock& args __unused) { #if defined(AT_SYSINFO_EHDR) ElfW(Ehdr)* ehdr_vdso = reinterpret_cast(args.getauxval(AT_SYSINFO_EHDR)); - if (ehdr_vdso == NULL) { + if (ehdr_vdso == nullptr) { return; } - soinfo* si = soinfo_alloc("[vdso]", NULL); + soinfo* si = soinfo_alloc("[vdso]", nullptr); si->phdr = reinterpret_cast(reinterpret_cast(ehdr_vdso) + ehdr_vdso->e_phoff); si->phnum = ehdr_vdso->e_phnum; @@ -2152,7 +2152,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->size = phdr_table_get_load_size(si->phdr, si->phnum); si->load_bias = get_elf_exec_load_bias(ehdr_vdso); - soinfo_link_image(si, NULL); + soinfo_link_image(si, nullptr); #endif } @@ -2185,7 +2185,7 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) { ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_base); ElfW(Phdr)* phdr = reinterpret_cast(linker_base + elf_hdr->e_phoff); phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, - &linker_soinfo_for_gdb.dynamic, NULL, NULL); + &linker_soinfo_for_gdb.dynamic, nullptr, nullptr); insert_soinfo_into_debug_map(&linker_soinfo_for_gdb); } @@ -2213,14 +2213,14 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( // Get a few environment variables. const char* LD_DEBUG = linker_env_get("LD_DEBUG"); - if (LD_DEBUG != NULL) { + if (LD_DEBUG != nullptr) { g_ld_debug_verbosity = atoi(LD_DEBUG); } // Normally, these are cleaned by linker_env_init, but the test // doesn't cost us anything. - const char* ldpath_env = NULL; - const char* ldpreload_env = NULL; + const char* ldpath_env = nullptr; + const char* ldpreload_env = nullptr; if (!get_AT_SECURE()) { ldpath_env = linker_env_get("LD_LIBRARY_PATH"); ldpreload_env = linker_env_get("LD_PRELOAD"); @@ -2228,8 +2228,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( INFO("[ android linker & debugger ]"); - soinfo* si = soinfo_alloc(args.argv[0], NULL); - if (si == NULL) { + soinfo* si = soinfo_alloc(args.argv[0], nullptr); + if (si == nullptr) { exit(EXIT_FAILURE); } @@ -2239,8 +2239,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( map->l_addr = 0; map->l_name = args.argv[0]; - map->l_prev = NULL; - map->l_next = NULL; + map->l_prev = nullptr; + map->l_next = nullptr; _r_debug.r_map = map; r_debug_tail = map; @@ -2266,7 +2266,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( break; } } - si->dynamic = NULL; + si->dynamic = nullptr; si->ref_count = 1; ElfW(Ehdr)* elf_hdr = reinterpret_cast(si->base); @@ -2281,7 +2281,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( somain = si; - if (!soinfo_link_image(si, NULL)) { + if (!soinfo_link_image(si, nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); } @@ -2290,7 +2290,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( si->CallPreInitConstructors(); - for (size_t i = 0; g_ld_preloads[i] != NULL; ++i) { + for (size_t i = 0; g_ld_preloads[i] != nullptr; ++i) { g_ld_preloads[i]->CallConstructors(); } @@ -2303,7 +2303,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( si->CallConstructors(); #if TIMING - gettimeofday(&t1, NULL); + gettimeofday(&t1, nullptr); PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) ( (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec))); @@ -2404,12 +2404,12 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_so.base = linker_addr; linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); - linker_so.dynamic = NULL; + linker_so.dynamic = nullptr; linker_so.phdr = phdr; linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - if (!soinfo_link_image(&linker_so, NULL)) { + if (!soinfo_link_image(&linker_so, nullptr)) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as diff --git a/linker/linker_environ.cpp b/linker/linker_environ.cpp index 846624b9a..daee56f7e 100644 --- a/linker/linker_environ.cpp +++ b/linker/linker_environ.cpp @@ -58,7 +58,7 @@ static void __init_AT_SECURE(KernelArgumentBlock& args) { // Check if the environment variable definition at 'envstr' // starts with '=', and if so return the address of the -// first character after the equal sign. Otherwise return NULL. +// first character after the equal sign. Otherwise return null. static const char* env_match(const char* envstr, const char* name) { size_t i = 0; @@ -70,7 +70,7 @@ static const char* env_match(const char* envstr, const char* name) { return envstr + i + 1; } - return NULL; + return nullptr; } static bool __is_valid_environment_variable(const char* name) { @@ -78,7 +78,7 @@ static bool __is_valid_environment_variable(const char* name) { // as the maximum size for an env. variable definition. const int MAX_ENV_LEN = 32*4096; - if (name == NULL) { + if (name == nullptr) { return false; } @@ -136,10 +136,10 @@ static bool __is_unsafe_environment_variable(const char* name) { "RES_OPTIONS", "TMPDIR", "TZDIR", - NULL + nullptr }; - for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != NULL; ++i) { - if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != NULL) { + for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != nullptr; ++i) { + if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != nullptr) { return true; } } @@ -149,7 +149,7 @@ static bool __is_unsafe_environment_variable(const char* name) { static void __sanitize_environment_variables() { char** src = _envp; char** dst = _envp; - for (; src[0] != NULL; ++src) { + for (; src[0] != nullptr; ++src) { if (!__is_valid_environment_variable(src[0])) { continue; } @@ -160,11 +160,11 @@ static void __sanitize_environment_variables() { dst[0] = src[0]; ++dst; } - dst[0] = NULL; + dst[0] = nullptr; } void linker_env_init(KernelArgumentBlock& args) { - // Store environment pointer - can't be NULL. + // Store environment pointer - can't be null. _envp = args.envp; __init_AT_SECURE(args); @@ -172,18 +172,18 @@ void linker_env_init(KernelArgumentBlock& args) { } const char* linker_env_get(const char* name) { - if (name == NULL || name[0] == '\0') { - return NULL; + if (name == nullptr || name[0] == '\0') { + return nullptr; } - for (char** p = _envp; p[0] != NULL; ++p) { + for (char** p = _envp; p[0] != nullptr; ++p) { const char* val = env_match(p[0], name); - if (val != NULL) { + if (val != nullptr) { if (val[0] == '\0') { - return NULL; // Return NULL for empty strings. + return nullptr; // Return null for empty strings. } return val; } } - return NULL; + return nullptr; } diff --git a/linker/linker_environ.h b/linker/linker_environ.h index d3f54fd08..0f6ac084d 100644 --- a/linker/linker_environ.h +++ b/linker/linker_environ.h @@ -35,7 +35,7 @@ class KernelArgumentBlock; extern void linker_env_init(KernelArgumentBlock& args); // Returns the value of environment variable 'name' if defined and not -// empty, or NULL otherwise. +// empty, or null otherwise. extern const char* linker_env_get(const char* name); // Returns the value of this program's AT_SECURE variable. diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index 0b99d2065..1bbd57778 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -121,13 +121,13 @@ ElfReader::ElfReader(const char* name, int fd) : name_(name), fd_(fd), - phdr_num_(0), phdr_mmap_(NULL), phdr_table_(NULL), phdr_size_(0), - load_start_(NULL), load_size_(0), load_bias_(0), - loaded_phdr_(NULL) { + phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0), + load_start_(nullptr), load_size_(0), load_bias_(0), + loaded_phdr_(nullptr) { } ElfReader::~ElfReader() { - if (phdr_mmap_ != NULL) { + if (phdr_mmap_ != nullptr) { munmap(phdr_mmap_, phdr_size_); } } @@ -225,7 +225,7 @@ bool ElfReader::ReadProgramHeader() { phdr_size_ = page_max - page_min; - void* mmap_result = mmap(NULL, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min); + void* mmap_result = mmap(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min); if (mmap_result == MAP_FAILED) { DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno)); return false; @@ -242,7 +242,7 @@ bool ElfReader::ReadProgramHeader() { * process' address space. If there are no loadable segments, 0 is * returned. * - * If out_min_vaddr or out_max_vaddr are non-NULL, they will be + * If out_min_vaddr or out_max_vaddr are not null, they will be * set to the minimum and maximum addresses of pages to be reserved, * or 0 if there is nothing to load. */ @@ -276,10 +276,10 @@ size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count, min_vaddr = PAGE_START(min_vaddr); max_vaddr = PAGE_END(max_vaddr); - if (out_min_vaddr != NULL) { + if (out_min_vaddr != nullptr) { *out_min_vaddr = min_vaddr; } - if (out_max_vaddr != NULL) { + if (out_max_vaddr != nullptr) { *out_max_vaddr = max_vaddr; } return max_vaddr - min_vaddr; @@ -301,7 +301,7 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) { size_t reserved_size = 0; bool reserved_hint = true; - if (extinfo != NULL) { + if (extinfo != nullptr) { if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) { reserved_size = extinfo->reserved_size; reserved_hint = false; @@ -585,9 +585,9 @@ int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, El return -1; } off_t file_size = file_stat.st_size; - void* temp_mapping = NULL; + void* temp_mapping = nullptr; if (file_size > 0) { - temp_mapping = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0); + temp_mapping = mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0); if (temp_mapping == MAP_FAILED) { return -1; } @@ -667,7 +667,7 @@ int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, El * phdr_count -> number of entries in tables * load_bias -> load bias * Output: - * arm_exidx -> address of table in memory (NULL on failure). + * arm_exidx -> address of table in memory (null on failure). * arm_exidx_count -> number of items in table (0 on failure). * Return: * 0 on error, -1 on failure (_no_ error code in errno) @@ -687,21 +687,21 @@ int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, *arm_exidx_count = (unsigned)(phdr->p_memsz / 8); return 0; } - *arm_exidx = NULL; + *arm_exidx = nullptr; *arm_exidx_count = 0; return -1; } #endif /* Return the address and size of the ELF file's .dynamic section in memory, - * or NULL if missing. + * or null if missing. * * Input: * phdr_table -> program header table * phdr_count -> number of entries in tables * load_bias -> load bias * Output: - * dynamic -> address of table in memory (NULL on failure). + * dynamic -> address of table in memory (null on failure). * dynamic_count -> number of items in table (0 on failure). * dynamic_flags -> protection flags for section (unset on failure) * Return: @@ -727,7 +727,7 @@ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_co } return; } - *dynamic = NULL; + *dynamic = nullptr; if (dynamic_count) { *dynamic_count = 0; } diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h index 611f1a7cb..50708a0e6 100644 --- a/linker/linker_phdr.h +++ b/linker/linker_phdr.h @@ -81,7 +81,7 @@ class ElfReader { }; size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count, - ElfW(Addr)* min_vaddr = NULL, ElfW(Addr)* max_vaddr = NULL); + ElfW(Addr)* min_vaddr = nullptr, ElfW(Addr)* max_vaddr = nullptr); int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias); From 4d01d08c2935980fbd9de2d7699230db11074453 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Fri, 29 Aug 2014 14:01:48 -0700 Subject: [PATCH 013/114] Erase elements in LinkedList::remove_if (cherry picked from commit 4bea498544bb1377f610520d7f58856382a6e5fc) Change-Id: I1ffe248bc2b7572f38fbd987e9c6db5ecbd4559d --- linker/linked_list.h | 44 ++++++++++++++---- linker/linker.cpp | 19 ++++++-- linker/tests/linked_list_test.cpp | 77 +++++++++++++++++++++++++++++-- 3 files changed, 121 insertions(+), 19 deletions(-) diff --git a/linker/linked_list.h b/linker/linked_list.h index e51eb9cb0..14fe1e58d 100644 --- a/linker/linked_list.h +++ b/linker/linked_list.h @@ -88,24 +88,50 @@ class LinkedList { template void for_each(F&& action) { for (LinkedListEntry* e = head_; e != nullptr; e = e->next) { - if (e->element != nullptr) { - action(e->element); - } + action(e->element); } } template - void remove_if(F&& predicate) { - for (LinkedListEntry* e = head_; e != nullptr; e = e->next) { - if (e->element != nullptr && predicate(e->element)) { - e->element = nullptr; + void remove_if(F predicate) { + for (LinkedListEntry* e = head_, *p = nullptr; e != nullptr;) { + if (predicate(e->element)) { + LinkedListEntry* next = e->next; + if (p == nullptr) { + head_ = next; + } else { + p->next = next; + } + Allocator::free(e); + e = next; + } else { + p = e; + e = e->next; } } } - bool contains(const T* el) { + size_t size() const { + size_t sz = 0; for (LinkedListEntry* e = head_; e != nullptr; e = e->next) { - if (e->element != nullptr && e->element == el) { + ++sz; + } + + return sz; + } + + size_t copy_to_array(T* array[], size_t array_length) const { + size_t sz = 0; + for (LinkedListEntry* e = head_; sz < array_length && e != nullptr; e = e->next) { + array[sz++] = e->element; + } + + return sz; + } + + bool contains(const T* el) const { + for (LinkedListEntry* e = head_; e != nullptr; e = e->next) { + if (e->element == el) { return true; } } diff --git a/linker/linker.cpp b/linker/linker.cpp index 8d8ccb508..919f8c04a 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -627,6 +627,8 @@ done: return nullptr; } + + // Another soinfo list allocator to use in dlsym. We don't reuse // SoinfoListAllocator because it is write-protected most of the time. static LinkerAllocator> g_soinfo_list_allocator_rw; @@ -879,10 +881,17 @@ static void soinfo_unload(soinfo* si) { si->CallDestructors(); if (si->has_min_version(0)) { - si->get_children().for_each([&] (soinfo* child) { - TRACE("%s needs to unload %s", si->name, child->name); - soinfo_unload(child); - }); + // It is not safe to do si->get_children().for_each, because + // during soinfo_free the child will concurrently modify the si->children + // list, therefore we create a copy and use it to unload children. + size_t children_count = si->get_children().size(); + soinfo* children[children_count]; + si->get_children().copy_to_array(children, children_count); + + for (size_t i = 0; i < children_count; ++i) { + TRACE("%s needs to unload %s", si->name, children[i]->name); + soinfo_unload(children[i]); + } } else { for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { if (d->d_tag == DT_NEEDED) { @@ -1636,7 +1645,7 @@ void soinfo::remove_all_links() { }); parents.for_each([&] (soinfo* parent) { - parent->children.for_each([&] (const soinfo* child) { + parent->children.remove_if([&] (const soinfo* child) { return child == this; }); }); diff --git a/linker/tests/linked_list_test.cpp b/linker/tests/linked_list_test.cpp index b9816fa10..0483b8412 100644 --- a/linker/tests/linked_list_test.cpp +++ b/linker/tests/linked_list_test.cpp @@ -80,7 +80,7 @@ TEST(linked_list, simple) { }); ASSERT_TRUE(!alloc_called); - ASSERT_TRUE(!free_called); + ASSERT_TRUE(free_called); ASSERT_EQ("dba", test_list_to_string(list)); alloc_called = free_called = false; @@ -103,15 +103,82 @@ TEST(linked_list, push_pop) { ASSERT_EQ("ab", test_list_to_string(list)); list.push_back("c"); ASSERT_EQ("abc", test_list_to_string(list)); - ASSERT_EQ("a", list.pop_front()); + ASSERT_STREQ("a", list.pop_front()); ASSERT_EQ("bc", test_list_to_string(list)); - ASSERT_EQ("b", list.pop_front()); + ASSERT_STREQ("b", list.pop_front()); ASSERT_EQ("c", test_list_to_string(list)); - ASSERT_EQ("c", list.pop_front()); + ASSERT_STREQ("c", list.pop_front()); ASSERT_EQ("", test_list_to_string(list)); ASSERT_TRUE(list.pop_front() == nullptr); list.push_back("r"); ASSERT_EQ("r", test_list_to_string(list)); - ASSERT_EQ("r", list.pop_front()); + ASSERT_STREQ("r", list.pop_front()); ASSERT_TRUE(list.pop_front() == nullptr); } + +TEST(linked_list, remove_if_then_pop) { + test_list_t list; + list.push_back("a"); + list.push_back("b"); + list.push_back("c"); + list.push_back("d"); + list.remove_if([](const char* c) { + return *c == 'b' || *c == 'c'; + }); + + ASSERT_EQ("ad", test_list_to_string(list)); + ASSERT_STREQ("a", list.pop_front()); + ASSERT_EQ("d", test_list_to_string(list)); + ASSERT_STREQ("d", list.pop_front()); + ASSERT_TRUE(list.pop_front() == nullptr); +} + +TEST(linked_list, copy_to_array) { + test_list_t list; + const size_t max_size = 128; + const char* buf[max_size]; + memset(buf, 0, sizeof(buf)); + + ASSERT_EQ(0U, list.size()); + ASSERT_EQ(0U, list.copy_to_array(buf, max_size)); + ASSERT_EQ(nullptr, buf[0]); + + list.push_back("a"); + list.push_back("b"); + list.push_back("c"); + list.push_back("d"); + + memset(buf, 0, sizeof(buf)); + ASSERT_EQ(4U, list.size()); + ASSERT_EQ(2U, list.copy_to_array(buf, 2)); + ASSERT_EQ('a', *buf[0]); + ASSERT_EQ('b', *buf[1]); + ASSERT_EQ(nullptr, buf[2]); + + ASSERT_EQ(4U, list.copy_to_array(buf, max_size)); + ASSERT_EQ('a', *buf[0]); + ASSERT_EQ('b', *buf[1]); + ASSERT_EQ('c', *buf[2]); + ASSERT_EQ('d', *buf[3]); + ASSERT_EQ(nullptr, buf[4]); + + memset(buf, 0, sizeof(buf)); + list.remove_if([](const char* c) { + return *c != 'c'; + }); + ASSERT_EQ(1U, list.size()); + ASSERT_EQ(1U, list.copy_to_array(buf, max_size)); + ASSERT_EQ('c', *buf[0]); + ASSERT_EQ(nullptr, buf[1]); + + memset(buf, 0, sizeof(buf)); + + list.remove_if([](const char* c) { + return *c == 'c'; + }); + + ASSERT_EQ(0U, list.size()); + ASSERT_EQ(0U, list.copy_to_array(buf, max_size)); + ASSERT_EQ(nullptr, buf[0]); +} + From ff01f6fcced83b6446136d6ddc9b3a536fab57f7 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 1 Sep 2014 16:15:52 -0700 Subject: [PATCH 014/114] Introduce size-based r/w allocators (cherry picked from commit 0cd83ebb0e9784827d9ec0a8028a710e73a28b2b) Change-Id: Ib037bd5313c9a78b6051482f14e789aa820b4dd1 --- linker/linker.cpp | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 919f8c04a..16730d663 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -627,10 +627,42 @@ done: return nullptr; } +// Each size has it's own allocator. +template +class SizeBasedAllocator { + public: + static void* alloc() { + return allocator_.alloc(); + } + static void free(void* ptr) { + allocator_.free(ptr); + } + + private: + static LinkerBlockAllocator allocator_; +}; + +template +LinkerBlockAllocator SizeBasedAllocator::allocator_(size); + +template +class TypeBasedAllocator { + public: + static T* alloc() { + return reinterpret_cast(SizeBasedAllocator::alloc()); + } + + static void free(T* ptr) { + SizeBasedAllocator::free(ptr); + } +}; + +template +using linked_list_t = LinkedList>>; + +typedef linked_list_t SoinfoLinkedList; -// Another soinfo list allocator to use in dlsym. We don't reuse -// SoinfoListAllocator because it is write-protected most of the time. static LinkerAllocator> g_soinfo_list_allocator_rw; class SoinfoListAllocatorRW { public: @@ -646,8 +678,9 @@ class SoinfoListAllocatorRW { // This is used by dlsym(3). It performs symbol lookup only within the // specified soinfo object and its dependencies in breadth first order. ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { - LinkedList visit_list; - LinkedList visited; + SoinfoLinkedList visit_list; + SoinfoLinkedList visited; + visit_list.push_back(si); soinfo* current_soinfo; while ((current_soinfo = visit_list.pop_front()) != nullptr) { From 4466bd72fb9daeb0ef8f250e8314b555aab30817 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 2 Sep 2014 09:45:40 -0700 Subject: [PATCH 015/114] Implement LinkedList::visit() (cherry picked from commit a4926058496c1c24c00ac07e42d45048dac7c487) Change-Id: I59554be45c910bfe33494016595a5ade9daad230 --- linker/linked_list.h | 15 ++++++++-- linker/tests/linked_list_test.cpp | 50 ++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/linker/linked_list.h b/linker/linked_list.h index 14fe1e58d..5fbdc8ffb 100644 --- a/linker/linked_list.h +++ b/linker/linked_list.h @@ -86,10 +86,21 @@ class LinkedList { } template - void for_each(F&& action) { + void for_each(F action) { + visit([&] (T* si) { + action(si); + return true; + }); + } + + template + bool visit(F action) { for (LinkedListEntry* e = head_; e != nullptr; e = e->next) { - action(e->element); + if (!action(e->element)) { + return false; + } } + return true; } template diff --git a/linker/tests/linked_list_test.cpp b/linker/tests/linked_list_test.cpp index 0483b8412..a555edb33 100644 --- a/linker/tests/linked_list_test.cpp +++ b/linker/tests/linked_list_test.cpp @@ -151,15 +151,15 @@ TEST(linked_list, copy_to_array) { memset(buf, 0, sizeof(buf)); ASSERT_EQ(4U, list.size()); ASSERT_EQ(2U, list.copy_to_array(buf, 2)); - ASSERT_EQ('a', *buf[0]); - ASSERT_EQ('b', *buf[1]); + ASSERT_STREQ("a", buf[0]); + ASSERT_STREQ("b", buf[1]); ASSERT_EQ(nullptr, buf[2]); ASSERT_EQ(4U, list.copy_to_array(buf, max_size)); - ASSERT_EQ('a', *buf[0]); - ASSERT_EQ('b', *buf[1]); - ASSERT_EQ('c', *buf[2]); - ASSERT_EQ('d', *buf[3]); + ASSERT_STREQ("a", buf[0]); + ASSERT_STREQ("b", buf[1]); + ASSERT_STREQ("c", buf[2]); + ASSERT_STREQ("d", buf[3]); ASSERT_EQ(nullptr, buf[4]); memset(buf, 0, sizeof(buf)); @@ -168,7 +168,7 @@ TEST(linked_list, copy_to_array) { }); ASSERT_EQ(1U, list.size()); ASSERT_EQ(1U, list.copy_to_array(buf, max_size)); - ASSERT_EQ('c', *buf[0]); + ASSERT_STREQ("c", buf[0]); ASSERT_EQ(nullptr, buf[1]); memset(buf, 0, sizeof(buf)); @@ -182,3 +182,39 @@ TEST(linked_list, copy_to_array) { ASSERT_EQ(nullptr, buf[0]); } +TEST(linked_list, test_visit) { + test_list_t list; + list.push_back("a"); + list.push_back("b"); + list.push_back("c"); + list.push_back("d"); + + int visits = 0; + std::stringstream ss; + bool result = list.visit([&](const char* c) { + ++visits; + ss << c; + return true; + }); + + ASSERT_TRUE(result); + ASSERT_EQ(4, visits); + ASSERT_EQ("abcd", ss.str()); + + visits = 0; + ss.str(std::string()); + + result = list.visit([&](const char* c) { + if (++visits == 3) { + return false; + } + + ss << c; + return true; + }); + + ASSERT_TRUE(!result); + ASSERT_EQ(3, visits); + ASSERT_EQ("ab", ss.str()); +} + From 7210c41fdce065a37f29dce7f32880301cce90c2 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 2 Sep 2014 11:47:23 -0700 Subject: [PATCH 016/114] Encapsulate soinfo_link_image and soinfo_relocate Also get rid of needed[] array for these functions (cherry picked from commit 29bbc9dd4c606de9187e46d8899a2a744715c967) Change-Id: Id208621f66afa2e02a6b3facacee7d874466d81b --- linker/linker.cpp | 297 ++++++++++++++++++++++------------------------ linker/linker.h | 6 + 2 files changed, 149 insertions(+), 154 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 16730d663..9eb74403c 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -79,7 +79,6 @@ static const char* get_base_name(const char* name) { #define SEARCH_NAME(x) get_base_name(x) #endif -static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo); static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf); static LinkerAllocator g_soinfo_allocator; @@ -509,7 +508,7 @@ static unsigned elfhash(const char* _name) { return h; } -static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, soinfo* needed[]) { +static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { unsigned elf_hash = elfhash(name); ElfW(Sym)* s = nullptr; @@ -604,15 +603,15 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s } } - for (int i = 0; needed[i] != nullptr; i++) { - DEBUG("%s: looking up %s in %s", - si->name, name, needed[i]->name); - s = soinfo_elf_lookup(needed[i], elf_hash, name); + si->get_children().visit([&](soinfo* child) { + DEBUG("%s: looking up %s in %s", si->name, name, child->name); + s = soinfo_elf_lookup(child, elf_hash, name); if (s != nullptr) { - *lsi = needed[i]; - goto done; + *lsi = child; + return false; } - } + return true; + }); done: if (s != nullptr) { @@ -860,7 +859,7 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin TRACE("[ load_library base=%p size=%zu name='%s' ]", reinterpret_cast(si->base), si->size, si->name); - if (!soinfo_link_image(si, extinfo)) { + if (!si->LinkImage(extinfo)) { soinfo_free(si); return nullptr; } @@ -1001,7 +1000,7 @@ void do_dlclose(soinfo* si) { // ifuncs are only defined for x86 #if defined(__i386__) -static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* needed[]) { +static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count) { for (size_t idx = 0; idx < count; ++idx, ++rel) { ElfW(Sym)* s; soinfo* lsi; @@ -1011,7 +1010,7 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, so ElfW(Addr) sym_addr = 0; const char* sym_name = nullptr; sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); - s = soinfo_do_lookup(si, sym_name, &lsi, needed); + s = soinfo_do_lookup(si, sym_name, &lsi); if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_386_JMP_SLOT) { TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr)); @@ -1024,7 +1023,7 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, so #endif #if defined(__x86_64__) -static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* needed[]) { +static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count) { for (size_t idx = 0; idx < count; ++idx, ++rela) { ElfW(Sym)* s; soinfo* lsi; @@ -1034,7 +1033,7 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, ElfW(Addr) sym_addr = 0; const char* sym_name = nullptr; sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); - s = soinfo_do_lookup(si, sym_name, &lsi, needed); + s = soinfo_do_lookup(si, sym_name, &lsi); if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_X86_64_JUMP_SLOT) { TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr + rela->r_addend)); @@ -1047,29 +1046,29 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, #endif #if defined(USE_RELA) -static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* needed[]) { +int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { ElfW(Sym)* s; soinfo* lsi; for (size_t idx = 0; idx < count; ++idx, ++rela) { unsigned type = ELFW(R_TYPE)(rela->r_info); unsigned sym = ELFW(R_SYM)(rela->r_info); - ElfW(Addr) reloc = static_cast(rela->r_offset + si->load_bias); + ElfW(Addr) reloc = static_cast(rela->r_offset + load_bias); ElfW(Addr) sym_addr = 0; const char* sym_name = nullptr; - DEBUG("Processing '%s' relocation at index %zd", si->name, idx); + DEBUG("Processing '%s' relocation at index %zd", name, idx); if (type == 0) { // R_*_NONE continue; } if (sym != 0) { - sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); - s = soinfo_do_lookup(si, sym_name, &lsi, needed); + sym_name = reinterpret_cast(strtab + symtab[sym].st_name); + s = soinfo_do_lookup(this, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... - s = &si->symtab[sym]; + s = &symtab[sym]; if (ELF_ST_BIND(s->st_info) != STB_WEAK) { - DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name); + DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name); return -1; } @@ -1227,8 +1226,8 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* return -1; } TRACE_TYPE(RELO, "RELO RELATIVE %16llx <- %16llx\n", - reloc, (si->base + rela->r_addend)); - *reinterpret_cast(reloc) = (si->base + rela->r_addend); + reloc, (base + rela->r_addend)); + *reinterpret_cast(reloc) = (base + rela->r_addend); break; case R_AARCH64_COPY: @@ -1241,7 +1240,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* * R_AARCH64_COPY may only appear in executable objects where e_type is * set to ET_EXEC. */ - DL_ERR("%s R_AARCH64_COPY relocations are not supported", si->name); + DL_ERR("%s R_AARCH64_COPY relocations are not supported", name); return -1; case R_AARCH64_TLS_TPREL64: TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n", @@ -1258,7 +1257,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast(reloc), static_cast(sym_addr + rela->r_addend), sym_name); if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { - si->set_has_ifuncs(true); + set_has_ifuncs(true); } else { *reinterpret_cast(reloc) = sym_addr + rela->r_addend; } @@ -1278,8 +1277,8 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* return -1; } TRACE_TYPE(RELO, "RELO RELATIVE %08zx <- +%08zx", static_cast(reloc), - static_cast(si->base)); - *reinterpret_cast(reloc) = si->base + rela->r_addend; + static_cast(base)); + *reinterpret_cast(reloc) = base + rela->r_addend; break; case R_X86_64_32: count_relocation(kRelocRelative); @@ -1314,8 +1313,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* } #else // REL, not RELA. - -static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* needed[]) { +int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { ElfW(Sym)* s; soinfo* lsi; @@ -1323,22 +1321,22 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n unsigned type = ELFW(R_TYPE)(rel->r_info); // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. unsigned sym = ELFW(R_SYM)(rel->r_info); - ElfW(Addr) reloc = static_cast(rel->r_offset + si->load_bias); + ElfW(Addr) reloc = static_cast(rel->r_offset + load_bias); ElfW(Addr) sym_addr = 0; const char* sym_name = nullptr; - DEBUG("Processing '%s' relocation at index %zd", si->name, idx); + DEBUG("Processing '%s' relocation at index %zd", name, idx); if (type == 0) { // R_*_NONE continue; } if (sym != 0) { - sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); - s = soinfo_do_lookup(si, sym_name, &lsi, needed); + sym_name = reinterpret_cast(strtab + symtab[sym].st_name); + s = soinfo_do_lookup(this, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... - s = &si->symtab[sym]; + s = &symtab[sym]; if (ELF_ST_BIND(s->st_info) != STB_WEAK) { - DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name); + DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name); return -1; } @@ -1433,7 +1431,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n * R_ARM_COPY may only appear in executable objects where e_type is * set to ET_EXEC. */ - DL_ERR("%s R_ARM_COPY relocations are not supported", si->name); + DL_ERR("%s R_ARM_COPY relocations are not supported", name); return -1; #elif defined(__i386__) case R_386_JMP_SLOT: @@ -1441,7 +1439,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { - si->set_has_ifuncs(true); + set_has_ifuncs(true); } else { *reinterpret_cast(reloc) = sym_addr; } @@ -1485,7 +1483,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n if (s) { *reinterpret_cast(reloc) += sym_addr; } else { - *reinterpret_cast(reloc) += si->base; + *reinterpret_cast(reloc) += base; } break; #endif @@ -1502,8 +1500,8 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n return -1; } TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p", - reinterpret_cast(reloc), reinterpret_cast(si->base)); - *reinterpret_cast(reloc) += si->base; + reinterpret_cast(reloc), reinterpret_cast(base)); + *reinterpret_cast(reloc) += base; break; default: @@ -1516,7 +1514,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n #endif #if defined(__mips__) -static bool mips_relocate_got(soinfo* si, soinfo* needed[]) { +static bool mips_relocate_got(soinfo* si) { ElfW(Addr)** got = si->plt_got; if (got == nullptr) { return true; @@ -1549,7 +1547,7 @@ static bool mips_relocate_got(soinfo* si, soinfo* needed[]) { // This is an undefined reference... try to locate it. const char* sym_name = si->strtab + sym->st_name; soinfo* lsi; - ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, needed); + ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. s = &symtab[g]; @@ -1803,84 +1801,80 @@ static int nullify_closed_stdio() { return return_value; } -static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { - /* "base" might wrap around UINT32_MAX. */ - ElfW(Addr) base = si->load_bias; - const ElfW(Phdr)* phdr = si->phdr; - int phnum = si->phnum; - bool relocating_linker = (si->flags & FLAG_LINKER) != 0; +bool soinfo::LinkImage(const android_dlextinfo* extinfo) { + bool relocating_linker = (flags & FLAG_LINKER) != 0; /* We can't debug anything until the linker is relocated */ if (!relocating_linker) { - INFO("[ linking %s ]", si->name); - DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast(si->base), si->flags); + INFO("[ linking %s ]", name); + DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast(base), flags); } /* Extract dynamic section */ size_t dynamic_count; ElfW(Word) dynamic_flags; - phdr_table_get_dynamic_section(phdr, phnum, base, &si->dynamic, + phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_count, &dynamic_flags); - if (si->dynamic == nullptr) { + if (dynamic == nullptr) { if (!relocating_linker) { - DL_ERR("missing PT_DYNAMIC in \"%s\"", si->name); + DL_ERR("missing PT_DYNAMIC in \"%s\"", name); } return false; } else { if (!relocating_linker) { - DEBUG("dynamic = %p", si->dynamic); + DEBUG("dynamic = %p", dynamic); } } #if defined(__arm__) - (void) phdr_table_get_arm_exidx(phdr, phnum, base, - &si->ARM_exidx, &si->ARM_exidx_count); + (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias, + &ARM_exidx, &ARM_exidx_count); #endif // Extract useful information from dynamic section. uint32_t needed_count = 0; - for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { + for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", d, reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); switch (d->d_tag) { case DT_HASH: - si->nbucket = reinterpret_cast(base + d->d_un.d_ptr)[0]; - si->nchain = reinterpret_cast(base + d->d_un.d_ptr)[1]; - si->bucket = reinterpret_cast(base + d->d_un.d_ptr + 8); - si->chain = reinterpret_cast(base + d->d_un.d_ptr + 8 + si->nbucket * 4); + nbucket = reinterpret_cast(load_bias + d->d_un.d_ptr)[0]; + nchain = reinterpret_cast(load_bias + d->d_un.d_ptr)[1]; + bucket = reinterpret_cast(load_bias + d->d_un.d_ptr + 8); + chain = reinterpret_cast(load_bias + d->d_un.d_ptr + 8 + nbucket * 4); break; case DT_STRTAB: - si->strtab = reinterpret_cast(base + d->d_un.d_ptr); + strtab = reinterpret_cast(load_bias + d->d_un.d_ptr); break; case DT_SYMTAB: - si->symtab = reinterpret_cast(base + d->d_un.d_ptr); + symtab = reinterpret_cast(load_bias + d->d_un.d_ptr); break; #if !defined(__LP64__) case DT_PLTREL: if (d->d_un.d_val != DT_REL) { - DL_ERR("unsupported DT_RELA in \"%s\"", si->name); + DL_ERR("unsupported DT_RELA in \"%s\"", name); return false; } break; #endif case DT_JMPREL: #if defined(USE_RELA) - si->plt_rela = reinterpret_cast(base + d->d_un.d_ptr); + plt_rela = reinterpret_cast(load_bias + d->d_un.d_ptr); #else - si->plt_rel = reinterpret_cast(base + d->d_un.d_ptr); + plt_rel = reinterpret_cast(load_bias + d->d_un.d_ptr); #endif break; case DT_PLTRELSZ: #if defined(USE_RELA) - si->plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); + plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); #else - si->plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); + plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); #endif break; #if defined(__mips__) case DT_PLTGOT: // Used by mips and mips64. - si->plt_got = reinterpret_cast(base + d->d_un.d_ptr); + plt_got = reinterpret_cast(load_bias + d->d_un.d_ptr); break; #endif case DT_DEBUG: @@ -1898,67 +1892,67 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { #endif #if defined(USE_RELA) case DT_RELA: - si->rela = reinterpret_cast(base + d->d_un.d_ptr); + rela = reinterpret_cast(load_bias + d->d_un.d_ptr); break; case DT_RELASZ: - si->rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); + rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); break; case DT_REL: - DL_ERR("unsupported DT_REL in \"%s\"", si->name); + DL_ERR("unsupported DT_REL in \"%s\"", name); return false; case DT_RELSZ: - DL_ERR("unsupported DT_RELSZ in \"%s\"", si->name); + DL_ERR("unsupported DT_RELSZ in \"%s\"", name); return false; #else case DT_REL: - si->rel = reinterpret_cast(base + d->d_un.d_ptr); + rel = reinterpret_cast(load_bias + d->d_un.d_ptr); break; case DT_RELSZ: - si->rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); + rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); break; case DT_RELA: - DL_ERR("unsupported DT_RELA in \"%s\"", si->name); + DL_ERR("unsupported DT_RELA in \"%s\"", name); return false; #endif case DT_INIT: - si->init_func = reinterpret_cast(base + d->d_un.d_ptr); - DEBUG("%s constructors (DT_INIT) found at %p", si->name, si->init_func); + init_func = reinterpret_cast(load_bias + d->d_un.d_ptr); + DEBUG("%s constructors (DT_INIT) found at %p", name, init_func); break; case DT_FINI: - si->fini_func = reinterpret_cast(base + d->d_un.d_ptr); - DEBUG("%s destructors (DT_FINI) found at %p", si->name, si->fini_func); + fini_func = reinterpret_cast(load_bias + d->d_un.d_ptr); + DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func); break; case DT_INIT_ARRAY: - si->init_array = reinterpret_cast(base + d->d_un.d_ptr); - DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", si->name, si->init_array); + init_array = reinterpret_cast(load_bias + d->d_un.d_ptr); + DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array); break; case DT_INIT_ARRAYSZ: - si->init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); + init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); break; case DT_FINI_ARRAY: - si->fini_array = reinterpret_cast(base + d->d_un.d_ptr); - DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", si->name, si->fini_array); + fini_array = reinterpret_cast(load_bias + d->d_un.d_ptr); + DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array); break; case DT_FINI_ARRAYSZ: - si->fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); + fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); break; case DT_PREINIT_ARRAY: - si->preinit_array = reinterpret_cast(base + d->d_un.d_ptr); - DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", si->name, si->preinit_array); + preinit_array = reinterpret_cast(load_bias + d->d_un.d_ptr); + DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array); break; case DT_PREINIT_ARRAYSZ: - si->preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); + preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); break; case DT_TEXTREL: #if defined(__LP64__) - DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", si->name); + DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name); return false; #else - si->has_text_relocations = true; + has_text_relocations = true; break; #endif case DT_SYMBOLIC: - si->has_DT_SYMBOLIC = true; + has_DT_SYMBOLIC = true; break; case DT_NEEDED: ++needed_count; @@ -1966,14 +1960,14 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { case DT_FLAGS: if (d->d_un.d_val & DF_TEXTREL) { #if defined(__LP64__) - DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", si->name); + DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", name); return false; #else - si->has_text_relocations = true; + has_text_relocations = true; #endif } if (d->d_un.d_val & DF_SYMBOLIC) { - si->has_DT_SYMBOLIC = true; + has_DT_SYMBOLIC = true; } break; #if defined(__mips__) @@ -1984,7 +1978,7 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { case DT_MIPS_RLD_MAP: // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. { - r_debug** dp = reinterpret_cast(base + d->d_un.d_ptr); + r_debug** dp = reinterpret_cast(load_bias + d->d_un.d_ptr); *dp = &_r_debug; } break; @@ -1995,15 +1989,15 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { break; case DT_MIPS_SYMTABNO: - si->mips_symtabno = d->d_un.d_val; + mips_symtabno = d->d_un.d_val; break; case DT_MIPS_LOCAL_GOTNO: - si->mips_local_gotno = d->d_un.d_val; + mips_local_gotno = d->d_un.d_val; break; case DT_MIPS_GOTSYM: - si->mips_gotsym = d->d_un.d_val; + mips_gotsym = d->d_un.d_val; break; #endif @@ -2015,28 +2009,28 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { } DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", - reinterpret_cast(si->base), si->strtab, si->symtab); + reinterpret_cast(base), strtab, symtab); // Sanity checks. if (relocating_linker && needed_count != 0) { DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries"); return false; } - if (si->nbucket == 0) { - DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", si->name); + if (nbucket == 0) { + DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", name); return false; } - if (si->strtab == 0) { - DL_ERR("empty/missing DT_STRTAB in \"%s\"", si->name); + if (strtab == 0) { + DL_ERR("empty/missing DT_STRTAB in \"%s\"", name); return false; } - if (si->symtab == 0) { - DL_ERR("empty/missing DT_SYMTAB in \"%s\"", si->name); + if (symtab == 0) { + DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name); return false; } // If this is the main executable, then load all of the libraries from LD_PRELOAD now. - if (si->flags & FLAG_EXE) { + if (flags & FLAG_EXE) { memset(g_ld_preloads, 0, sizeof(g_ld_preloads)); size_t preload_count = 0; for (size_t i = 0; g_ld_preload_names[i] != nullptr; i++) { @@ -2046,69 +2040,64 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { } else { // As with glibc, failure to load an LD_PRELOAD library is just a warning. DL_WARN("could not load library \"%s\" from LD_PRELOAD for \"%s\"; caused by %s", - g_ld_preload_names[i], si->name, linker_get_error_buffer()); + g_ld_preload_names[i], name, linker_get_error_buffer()); } } } - soinfo** needed = reinterpret_cast(alloca((1 + needed_count) * sizeof(soinfo*))); - soinfo** pneeded = needed; - - for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { + for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { if (d->d_tag == DT_NEEDED) { - const char* library_name = si->strtab + d->d_un.d_val; - DEBUG("%s needs %s", si->name, library_name); + const char* library_name = strtab + d->d_un.d_val; + DEBUG("%s needs %s", name, library_name); soinfo* lsi = find_library(library_name, 0, nullptr); if (lsi == nullptr) { strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf)); DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s", - library_name, si->name, tmp_err_buf); + library_name, name, tmp_err_buf); return false; } - si->add_child(lsi); - *pneeded++ = lsi; + add_child(lsi); } } - *pneeded = nullptr; #if !defined(__LP64__) - if (si->has_text_relocations) { + if (has_text_relocations) { // Make segments writable to allow text relocations to work properly. We will later call // phdr_table_protect_segments() after all of them are applied and all constructors are run. DL_WARN("%s has text relocations. This is wasting memory and prevents " - "security hardening. Please fix.", si->name); - if (phdr_table_unprotect_segments(si->phdr, si->phnum, si->load_bias) < 0) { + "security hardening. Please fix.", name); + if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { DL_ERR("can't unprotect loadable segments for \"%s\": %s", - si->name, strerror(errno)); + name, strerror(errno)); return false; } } #endif #if defined(USE_RELA) - if (si->plt_rela != nullptr) { - DEBUG("[ relocating %s plt ]\n", si->name); - if (soinfo_relocate(si, si->plt_rela, si->plt_rela_count, needed)) { + if (plt_rela != nullptr) { + DEBUG("[ relocating %s plt ]\n", name); + if (Relocate(plt_rela, plt_rela_count)) { return false; } } - if (si->rela != nullptr) { - DEBUG("[ relocating %s ]\n", si->name); - if (soinfo_relocate(si, si->rela, si->rela_count, needed)) { + if (rela != nullptr) { + DEBUG("[ relocating %s ]\n", name); + if (Relocate(rela, rela_count)) { return false; } } #else - if (si->plt_rel != nullptr) { - DEBUG("[ relocating %s plt ]", si->name); - if (soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed)) { + if (plt_rel != nullptr) { + DEBUG("[ relocating %s plt ]", name); + if (Relocate(plt_rel, plt_rel_count)) { return false; } } - if (si->rel != nullptr) { - DEBUG("[ relocating %s ]", si->name); - if (soinfo_relocate(si, si->rel, si->rel_count, needed)) { + if (rel != nullptr) { + DEBUG("[ relocating %s ]", name); + if (Relocate(rel, rel_count)) { return false; } } @@ -2118,59 +2107,59 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { // they cannot be resolved until the rest of the relocations are done // because we need to call the resolution function which may be waiting // on relocations. - if(si->get_has_ifuncs()) { + if(get_has_ifuncs()) { #if defined(__i386__) - soinfo_ifunc_relocate(si, si->plt_rel, si->plt_rel_count, needed); + soinfo_ifunc_relocate(this, plt_rel, plt_rel_count); #elif defined(__x86_64__) - soinfo_ifunc_relocate(si, si->plt_rela, si->plt_rela_count, needed); + soinfo_ifunc_relocate(this, plt_rela, plt_rela_count); #endif } #if defined(__mips__) - if (!mips_relocate_got(si, needed)) { + if (!mips_relocate_got(this)) { return false; } #endif - si->flags |= FLAG_LINKED; - DEBUG("[ finished linking %s ]", si->name); + flags |= FLAG_LINKED; + DEBUG("[ finished linking %s ]", name); #if !defined(__LP64__) - if (si->has_text_relocations) { + if (has_text_relocations) { // All relocations are done, we can protect our segments back to read-only. - if (phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias) < 0) { + if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { DL_ERR("can't protect segments for \"%s\": %s", - si->name, strerror(errno)); + name, strerror(errno)); return false; } } #endif /* We can also turn on GNU RELRO protection */ - if (phdr_table_protect_gnu_relro(si->phdr, si->phnum, si->load_bias) < 0) { + if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) { DL_ERR("can't enable GNU RELRO protection for \"%s\": %s", - si->name, strerror(errno)); + name, strerror(errno)); return false; } /* Handle serializing/sharing the RELRO segment */ if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) { - if (phdr_table_serialize_gnu_relro(si->phdr, si->phnum, si->load_bias, + if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias, extinfo->relro_fd) < 0) { DL_ERR("failed serializing GNU RELRO section for \"%s\": %s", - si->name, strerror(errno)); + name, strerror(errno)); return false; } } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) { - if (phdr_table_map_gnu_relro(si->phdr, si->phnum, si->load_bias, + if (phdr_table_map_gnu_relro(phdr, phnum, load_bias, extinfo->relro_fd) < 0) { DL_ERR("failed mapping GNU RELRO section for \"%s\": %s", - si->name, strerror(errno)); + name, strerror(errno)); return false; } } - notify_gdb_of_load(si); + notify_gdb_of_load(this); return true; } @@ -2194,7 +2183,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->size = phdr_table_get_load_size(si->phdr, si->phnum); si->load_bias = get_elf_exec_load_bias(ehdr_vdso); - soinfo_link_image(si, nullptr); + si->LinkImage(nullptr); #endif } @@ -2323,7 +2312,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( somain = si; - if (!soinfo_link_image(si, nullptr)) { + if (!si->LinkImage(nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); } @@ -2336,7 +2325,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( g_ld_preloads[i]->CallConstructors(); } - /* After the link_image, the si->load_bias is initialized. + /* After the LinkImage, the si->load_bias is initialized. * For so lib, the map->l_addr will be updated in notify_gdb_of_load. * We need to update this value for so exe here. So Unwind_Backtrace * for some arch like x86 could work correctly within so exe. @@ -2451,7 +2440,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - if (!soinfo_link_image(&linker_so, nullptr)) { + if (!linker_so.LinkImage(nullptr)) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as diff --git a/linker/linker.h b/linker/linker.h index 5e21f7015..6547d685e 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -204,6 +204,7 @@ struct soinfo { void CallConstructors(); void CallDestructors(); void CallPreInitConstructors(); + bool LinkImage(const android_dlextinfo* extinfo); void add_child(soinfo* child); void remove_all_links(); @@ -224,6 +225,11 @@ struct soinfo { void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); void resolve_ifunc_symbols(); +#if defined(USE_RELA) + int Relocate(ElfW(Rela)* rela, unsigned count); +#else + int Relocate(ElfW(Rel)* rel, unsigned count); +#endif private: // This part of the structure is only available From 81fe2b16dc3ac8f17719964d3d01e92e2dc3cc4c Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Thu, 4 Sep 2014 15:19:52 -0700 Subject: [PATCH 017/114] Enable clang compilation with libc but not linker. Clang is still disabled for x86 and x86_64 long double code, for x86_64 special assembly instruction, and the linker module. BUG: 17163651 BUG: 17302991 BUG: 17403674 (cherry picked from commit b58db8b083ce41798a5310616e4f20885cec611f) Change-Id: I916c05056d37a9c287b0a5ae3b1a209d98c8f70e --- libc/Android.mk | 26 +++++++++++++++++++++++--- linker/linker_executable.mk | 2 ++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/libc/Android.mk b/libc/Android.mk index 9c5e785ae..fe1f31577 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -503,7 +503,10 @@ ifneq ($(TARGET_USES_LOGD),false) libc_common_cflags += -DTARGET_USES_LOGD endif -use_clang := false +use_clang := $(USE_CLANG_PLATFORM_BUILD) +ifeq ($(use_clang),) + use_clang := false +endif # Try to catch typical 32-bit assumptions that break with 64-bit pointers. libc_common_cflags += \ @@ -733,6 +736,13 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_SRC_FILES := $(libc_upstream_openbsd_src_files) +ifneq (,$(filter $(TARGET_ARCH),x86 x86_64)) + # Clang has wrong long double size or LDBL_MANT_DIG, http://b/17163651. + LOCAL_CLANG := false +else + LOCAL_CLANG := $(use_clang) +endif + LOCAL_CFLAGS := \ $(libc_common_cflags) \ -Wno-sign-compare -Wno-uninitialized -Wno-unused-parameter \ @@ -746,7 +756,6 @@ LOCAL_CONLYFLAGS := $(libc_common_conlyflags) LOCAL_CPPFLAGS := $(libc_common_cppflags) LOCAL_C_INCLUDES := $(libc_common_c_includes) LOCAL_MODULE := libc_openbsd -LOCAL_CLANG := $(use_clang) LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies) LOCAL_SYSTEM_SHARED_LIBRARIES := @@ -765,6 +774,13 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES_32 := $(libc_upstream_openbsd_gdtoa_src_files_32) LOCAL_SRC_FILES_64 := $(libc_upstream_openbsd_gdtoa_src_files_64) +ifneq (,$(filter $(TARGET_ARCH),x86 x86_64)) + # Clang has wrong long double size or LDBL_MANT_DIG, http://b/17163651. + LOCAL_CLANG := false +else + LOCAL_CLANG := $(use_clang) +endif + LOCAL_CFLAGS := \ $(libc_common_cflags) \ -Wno-sign-compare -Wno-uninitialized \ @@ -778,7 +794,6 @@ LOCAL_CONLYFLAGS := $(libc_common_conlyflags) LOCAL_CPPFLAGS := $(libc_common_cppflags) LOCAL_C_INCLUDES := $(libc_common_c_includes) LOCAL_MODULE := libc_gdtoa -LOCAL_CLANG := $(use_clang) LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies) LOCAL_SYSTEM_SHARED_LIBRARIES := @@ -796,6 +811,11 @@ LOCAL_SRC_FILES := $(libc_bionic_src_files) LOCAL_CFLAGS := $(libc_common_cflags) \ -Wframe-larger-than=2048 \ +ifeq ($(TARGET_ARCH),x86_64) + # Clang assembler has problem with ssse3-strcmp-slm.S, http://b/17302991 + LOCAL_CLANG_ASFLAGS += -no-integrated-as +endif + LOCAL_CONLYFLAGS := $(libc_common_conlyflags) LOCAL_CPPFLAGS := $(libc_common_cppflags) LOCAL_C_INCLUDES := $(libc_common_c_includes) diff --git a/linker/linker_executable.mk b/linker/linker_executable.mk index 4902a0cc5..a596a4805 100644 --- a/linker/linker_executable.mk +++ b/linker/linker_executable.mk @@ -9,6 +9,8 @@ LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_MODULE_SUFFIX := $(TARGET_EXECUTABLE_SUFFIX) +# Clang calls /usr/bin/ld: unrecognized option '--icf=safe', http://b/17403674. +LOCAL_CLANG := false include $(BUILD_SYSTEM)/dynamic_binary.mk # See build/core/executable_internal.mk From 59c12a652794273da22907a374222f4fa7d975c6 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 29 Jul 2014 14:21:45 -0700 Subject: [PATCH 018/114] Load libraries in breadth-first order This patch fixes the problem with symbol search order for dlsym(RTLD_DEFAULT/RTLD_NEXT, .) by loading libraries and ld_preloads in correct order. Bug: https://code.google.com/p/android/issues/detail?id=74255 (cherry picked from commit a3ad450a2e3fb6b3fe359683b247eba20896f646) Change-Id: I1125de10272c84e4f075cbc72859c1f6b3e89943 --- libc/private/UniquePtr.h | 140 +++++++++ linker/dlfcn.cpp | 1 + linker/linker.cpp | 433 +++++++++++++++++---------- linker/linker.h | 2 + linker/linker_phdr.cpp | 29 +- linker/linker_phdr.h | 3 +- tests/Android.mk | 1 + tests/dlfcn_test.cpp | 49 +++ tests/libs/Android.mk | 154 ++++++++++ tests/libs/dlopen_testlib_answer.cpp | 25 ++ tests/uniqueptr_test.cpp | 101 +++++++ 11 files changed, 759 insertions(+), 179 deletions(-) create mode 100644 libc/private/UniquePtr.h create mode 100644 tests/libs/dlopen_testlib_answer.cpp create mode 100644 tests/uniqueptr_test.cpp diff --git a/libc/private/UniquePtr.h b/libc/private/UniquePtr.h new file mode 100644 index 000000000..5ac7599a0 --- /dev/null +++ b/libc/private/UniquePtr.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UNIQUE_PTR_H_included +#define UNIQUE_PTR_H_included + +// Default deleter for pointer types. +template +struct DefaultDelete { + enum { type_must_be_complete = sizeof(T) }; + DefaultDelete() {} + void operator()(T* p) const { + delete p; + } +}; + +// Default deleter for array types. +template +struct DefaultDelete { + enum { type_must_be_complete = sizeof(T) }; + void operator()(T* p) const { + delete[] p; + } +}; + +// A smart pointer that deletes the given pointer on destruction. +// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr +// and boost::scoped_array). +// Named to be in keeping with Android style but also to avoid +// collision with any other implementation, until we can switch over +// to unique_ptr. +// Use thus: +// UniquePtr c(new C); +template > +class UniquePtr { +public: + // Construct a new UniquePtr, taking ownership of the given raw pointer. + explicit UniquePtr(T* ptr = nullptr) : mPtr(ptr) { } + + UniquePtr(UniquePtr&& that) { + mPtr = that.mPtr; + that.mPtr = nullptr; + } + + ~UniquePtr() { + reset(); + } + + // Accessors. + T& operator*() const { return *mPtr; } + T* operator->() const { return mPtr; } + T* get() const { return mPtr; } + + // Returns the raw pointer and hands over ownership to the caller. + // The pointer will not be deleted by UniquePtr. + T* release() __attribute__((warn_unused_result)) { + T* result = mPtr; + mPtr = nullptr; + return result; + } + + // Takes ownership of the given raw pointer. + // If this smart pointer previously owned a different raw pointer, that + // raw pointer will be freed. + void reset(T* ptr = nullptr) { + if (ptr != mPtr) { + D()(mPtr); + mPtr = ptr; + } + } + +private: + // The raw pointer. + T* mPtr; + + // Comparing unique pointers is probably a mistake, since they're unique. + template bool operator==(const UniquePtr& p) const = delete; + template bool operator!=(const UniquePtr& p) const = delete; + + // Disallow copy and assignment. + UniquePtr(const UniquePtr&) = delete; + void operator=(const UniquePtr&) = delete; +}; + +// Partial specialization for array types. Like std::unique_ptr, this removes +// operator* and operator-> but adds operator[]. +template +class UniquePtr { +public: + explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) { + } + UniquePtr(UniquePtr&& that) { + mPtr = that.mPtr; + that.mPtr = nullptr; + } + + ~UniquePtr() { + reset(); + } + + T& operator[](size_t i) const { + return mPtr[i]; + } + T* get() const { return mPtr; } + + T* release() __attribute__((warn_unused_result)) { + T* result = mPtr; + mPtr = NULL; + return result; + } + + void reset(T* ptr = NULL) { + if (ptr != mPtr) { + D()(mPtr); + mPtr = ptr; + } + } + +private: + T* mPtr; + + // Disallow copy and assignment. + UniquePtr(const UniquePtr&) = delete; + void operator=(const UniquePtr&) = delete; +}; + +#endif // UNIQUE_PTR_H_included diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 38484d995..3024b3c29 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -245,6 +245,7 @@ soinfo* get_libdl_info() { __libdl_info.bucket = g_libdl_buckets; __libdl_info.chain = g_libdl_chains; __libdl_info.has_DT_SYMBOLIC = true; + __libdl_info.ref_count = 1; } return &__libdl_info; diff --git a/linker/linker.cpp b/linker/linker.cpp index 9eb74403c..610489ea5 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -44,6 +44,8 @@ #include "private/KernelArgumentBlock.h" #include "private/ScopedPthreadMutexLocker.h" #include "private/ScopedFd.h" +#include "private/ScopeGuard.h" +#include "private/UniquePtr.h" #include "linker.h" #include "linker_debug.h" @@ -170,7 +172,6 @@ DISALLOW_ALLOCATION(void, free, (void* u __unused)); DISALLOW_ALLOCATION(void*, realloc, (void* u1 __unused, size_t u2 __unused)); DISALLOW_ALLOCATION(void*, calloc, (size_t u1 __unused, size_t u2 __unused)); -static char tmp_err_buf[768]; static char __linker_dl_err_buf[768]; char* linker_get_error_buffer() { @@ -512,7 +513,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { unsigned elf_hash = elfhash(name); ElfW(Sym)* s = nullptr; - if (si != nullptr && somain != nullptr) { + if (somain != nullptr) { /* * Local scope is executable scope. Just start looking into it right away * for the shortcut. @@ -657,22 +658,47 @@ class TypeBasedAllocator { } }; +class LoadTask { + public: + struct deleter_t { + void operator()(LoadTask* t) { + TypeBasedAllocator::free(t); + } + }; + + typedef UniquePtr unique_ptr; + + static deleter_t deleter; + + static LoadTask* create(const char* name, soinfo* needed_by) { + LoadTask* ptr = TypeBasedAllocator::alloc(); + return new (ptr) LoadTask(name, needed_by); + } + + const char* get_name() { + return name_; + } + + soinfo* get_needed_by() { + return needed_by_; + } + private: + LoadTask(const char* name, soinfo* needed_by) + : name_(name), needed_by_(needed_by) {} + + const char* name_; + soinfo* needed_by_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask); +}; + template using linked_list_t = LinkedList>>; typedef linked_list_t SoinfoLinkedList; +typedef linked_list_t StringLinkedList; +typedef linked_list_t LoadTaskList; -static LinkerAllocator> g_soinfo_list_allocator_rw; -class SoinfoListAllocatorRW { - public: - static LinkedListEntry* alloc() { - return g_soinfo_list_allocator_rw.alloc(); - } - - static void free(LinkedListEntry* ptr) { - g_soinfo_list_allocator_rw.free(ptr); - } -}; // This is used by dlsym(3). It performs symbol lookup only within the // specified soinfo object and its dependencies in breadth first order. @@ -798,73 +824,80 @@ static int open_library(const char* name) { return fd; } -static soinfo* load_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { - int fd = -1; - ScopedFd file_guard(-1); - - if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { - fd = extinfo->library_fd; - } else { - // Open the file. - fd = open_library(name); - if (fd == -1) { - DL_ERR("library \"%s\" not found", name); - return nullptr; - } - - file_guard.reset(fd); +template +static void for_each_dt_needed(const soinfo* si, F action) { + for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { + if (d->d_tag == DT_NEEDED) { + action(si->strtab + d->d_un.d_val); } + } +} - ElfReader elf_reader(name, fd); +static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { + int fd = -1; + ScopedFd file_guard(-1); - struct stat file_stat; - if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { - DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); + if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { + fd = extinfo->library_fd; + } else { + // Open the file. + fd = open_library(name); + if (fd == -1) { + DL_ERR("library \"%s\" not found", name); return nullptr; } - // Check for symlink and other situations where - // file can have different names. - for (soinfo* si = solist; si != nullptr; si = si->next) { - if (si->get_st_dev() != 0 && - si->get_st_ino() != 0 && - si->get_st_dev() == file_stat.st_dev && - si->get_st_ino() == file_stat.st_ino) { - TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name); - return si; - } + file_guard.reset(fd); + } + + struct stat file_stat; + if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { + DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); + return nullptr; + } + + // Check for symlink and other situations where + // file can have different names. + for (soinfo* si = solist; si != nullptr; si = si->next) { + if (si->get_st_dev() != 0 && + si->get_st_ino() != 0 && + si->get_st_dev() == file_stat.st_dev && + si->get_st_ino() == file_stat.st_ino) { + TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name); + return si; } + } - if ((dlflags & RTLD_NOLOAD) != 0) { - return nullptr; - } + if ((dlflags & RTLD_NOLOAD) != 0) { + return nullptr; + } - // Read the ELF header and load the segments. - if (!elf_reader.Load(extinfo)) { - return nullptr; - } + // Read the ELF header and load the segments. + ElfReader elf_reader(name, fd); + if (!elf_reader.Load(extinfo)) { + return nullptr; + } - soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat); - if (si == nullptr) { - return nullptr; - } - si->base = elf_reader.load_start(); - si->size = elf_reader.load_size(); - si->load_bias = elf_reader.load_bias(); - si->phnum = elf_reader.phdr_count(); - si->phdr = elf_reader.loaded_phdr(); + soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat); + if (si == nullptr) { + return nullptr; + } + si->base = elf_reader.load_start(); + si->size = elf_reader.load_size(); + si->load_bias = elf_reader.load_bias(); + si->phnum = elf_reader.phdr_count(); + si->phdr = elf_reader.loaded_phdr(); - // At this point we know that whatever is loaded @ base is a valid ELF - // shared library whose segments are properly mapped in. - TRACE("[ load_library base=%p size=%zu name='%s' ]", - reinterpret_cast(si->base), si->size, si->name); + if (!si->PrelinkImage()) { + soinfo_free(si); + return nullptr; + } - if (!si->LinkImage(extinfo)) { - soinfo_free(si); - return nullptr; - } + for_each_dt_needed(si, [&] (const char* name) { + load_tasks.push_back(LoadTask::create(name, si)); + }); - return si; + return si; } static soinfo *find_loaded_library_by_name(const char* name) { @@ -877,33 +910,122 @@ static soinfo *find_loaded_library_by_name(const char* name) { return nullptr; } -static soinfo* find_library_internal(const char* name, int dlflags, const android_dlextinfo* extinfo) { - if (name == nullptr) { - return somain; - } +static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { soinfo* si = find_loaded_library_by_name(name); // Library might still be loaded, the accurate detection - // of this fact is done by load_library + // of this fact is done by load_library. if (si == nullptr) { TRACE("[ '%s' has not been found by name. Trying harder...]", name); - si = load_library(name, dlflags, extinfo); - } - - if (si != nullptr && (si->flags & FLAG_LINKED) == 0) { - DL_ERR("recursive link to \"%s\"", si->name); - return nullptr; + si = load_library(load_tasks, name, dlflags, extinfo); } return si; } -static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { - soinfo* si = find_library_internal(name, dlflags, extinfo); - if (si != nullptr) { - si->ref_count++; +static void soinfo_unload(soinfo* si); + +static bool is_recursive(soinfo* si, soinfo* parent) { + if (parent == nullptr) { + return false; } + + if (si == parent) { + DL_ERR("recursive link to \"%s\"", si->name); + return true; + } + + return !parent->get_parents().visit([&](soinfo* grandparent) { + return !is_recursive(si, grandparent); + }); +} + +static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[], + soinfo* ld_preloads[], size_t ld_preloads_size, int dlflags, const android_dlextinfo* extinfo) { + // Step 0: prepare. + LoadTaskList load_tasks; + for (size_t i = 0; i < library_names_size; ++i) { + const char* name = library_names[i]; + load_tasks.push_back(LoadTask::create(name, nullptr)); + } + + // Libraries added to this list in reverse order so that we can + // start linking from bottom-up - see step 2. + SoinfoLinkedList found_libs; + size_t soinfos_size = 0; + + auto failure_guard = create_scope_guard([&]() { + // Housekeeping + load_tasks.for_each([] (LoadTask* t) { + LoadTask::deleter(t); + }); + + for (size_t i = 0; iget_name(), dlflags, extinfo); + if (si == nullptr) { + return false; + } + + soinfo* needed_by = task->get_needed_by(); + + if (is_recursive(si, needed_by)) { + soinfo_free(si); + return false; + } + + si->ref_count++; + if (needed_by != nullptr) { + needed_by->add_child(si); + } + found_libs.push_front(si); + + // When ld_preloads is not null first + // ld_preloads_size libs are in fact ld_preloads. + if (ld_preloads != nullptr && soinfos_size < ld_preloads_size) { + ld_preloads[soinfos_size] = si; + } + + if (soinfos_sizeflags & FLAG_LINKED) == 0) { + if (!si->LinkImage(extinfo)) { + return false; + } + si->flags |= FLAG_LINKED; + } + } + + // All is well - found_libs and load_tasks are empty at this point + // and all libs are successfully linked. + failure_guard.disable(); + return true; +} + +static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { + if (name == nullptr) { + somain->ref_count++; + return somain; + } + + soinfo* si; + + if (!find_libraries(&name, 1, &si, nullptr, 0, dlflags, extinfo)) { + return nullptr; + } + return si; } @@ -925,20 +1047,17 @@ static void soinfo_unload(soinfo* si) { soinfo_unload(children[i]); } } else { - for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { - if (d->d_tag == DT_NEEDED) { - const char* library_name = si->strtab + d->d_un.d_val; - TRACE("%s needs to unload %s", si->name, library_name); - soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); - if (needed != nullptr) { - soinfo_unload(needed); - } else { - // Not found: for example if symlink was deleted between dlopen and dlclose - // Since we cannot really handle errors at this point - print and continue. - PRINT("warning: couldn't find %s needed by %s on unload.", library_name, si->name); - } + for_each_dt_needed(si, [&] (const char* library_name) { + TRACE("deprecated (old format of soinfo): %s needs to unload %s", si->name, library_name); + soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); + if (needed != nullptr) { + soinfo_unload(needed); + } else { + // Not found: for example if symlink was deleted between dlopen and dlclose + // Since we cannot really handle errors at this point - print and continue. + PRINT("warning: couldn't find %s needed by %s on unload.", library_name, si->name); } - } + }); } notify_gdb_of_unload(si); @@ -1047,9 +1166,6 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count) #if defined(USE_RELA) int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { - ElfW(Sym)* s; - soinfo* lsi; - for (size_t idx = 0; idx < count; ++idx, ++rela) { unsigned type = ELFW(R_TYPE)(rela->r_info); unsigned sym = ELFW(R_SYM)(rela->r_info); @@ -1061,6 +1177,10 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { if (type == 0) { // R_*_NONE continue; } + + ElfW(Sym)* s = nullptr; + soinfo* lsi = nullptr; + if (sym != 0) { sym_name = reinterpret_cast(strtab + symtab[sym].st_name); s = soinfo_do_lookup(this, sym_name, &lsi); @@ -1119,8 +1239,6 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { sym_addr = static_cast(s->st_value + lsi->load_bias); } count_relocation(kRelocSymbol); - } else { - s = nullptr; } switch (type) { @@ -1314,9 +1432,6 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { #else // REL, not RELA. int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { - ElfW(Sym)* s; - soinfo* lsi; - for (size_t idx = 0; idx < count; ++idx, ++rel) { unsigned type = ELFW(R_TYPE)(rel->r_info); // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. @@ -1329,6 +1444,10 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { if (type == 0) { // R_*_NONE continue; } + + ElfW(Sym)* s = nullptr; + soinfo* lsi = nullptr; + if (sym != 0) { sym_name = reinterpret_cast(strtab + symtab[sym].st_name); s = soinfo_do_lookup(this, sym_name, &lsi); @@ -1390,8 +1509,6 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { sym_addr = static_cast(s->st_value + lsi->load_bias); } count_relocation(kRelocSymbol); - } else { - s = nullptr; } switch (type) { @@ -1546,7 +1663,7 @@ static bool mips_relocate_got(soinfo* si) { for (size_t g = gotsym; g < symtabno; g++, sym++, got++) { // This is an undefined reference... try to locate it. const char* sym_name = si->strtab + sym->st_name; - soinfo* lsi; + soinfo* lsi = nullptr; ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. @@ -1643,6 +1760,9 @@ void soinfo::CallConstructors() { } void soinfo::CallDestructors() { + if (!constructors_called) { + return; + } TRACE("\"%s\": calling destructors", name); // DT_FINI_ARRAY must be parsed in reverse order. @@ -1728,7 +1848,7 @@ bool soinfo::get_has_ifuncs() { return false; } -// This is a return on get_children() in case +// This is a return on get_children()/get_parents() if // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -1740,6 +1860,14 @@ soinfo::soinfo_list_t& soinfo::get_children() { return g_empty_list; } +soinfo::soinfo_list_t& soinfo::get_parents() { + if ((this->flags & FLAG_NEW_SOINFO) == 0) { + return g_empty_list; + } + + return this->parents; +} + /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -1801,20 +1929,18 @@ static int nullify_closed_stdio() { return return_value; } -bool soinfo::LinkImage(const android_dlextinfo* extinfo) { - bool relocating_linker = (flags & FLAG_LINKER) != 0; +bool soinfo::PrelinkImage() { + phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic); - /* We can't debug anything until the linker is relocated */ + /* We can't log anything until the linker is relocated */ + bool relocating_linker = (flags & FLAG_LINKER) != 0; if (!relocating_linker) { INFO("[ linking %s ]", name); DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast(base), flags); } /* Extract dynamic section */ - size_t dynamic_count; - ElfW(Word) dynamic_flags; - phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, - &dynamic_count, &dynamic_flags); + ElfW(Word) dynamic_flags = phdr->p_flags; if (dynamic == nullptr) { if (!relocating_linker) { DL_ERR("missing PT_DYNAMIC in \"%s\"", name); @@ -1882,7 +2008,7 @@ bool soinfo::LinkImage(const android_dlextinfo* extinfo) { // if the dynamic table is writable // FIXME: not working currently for N64 // The flags for the LOAD and DYNAMIC program headers do not agree. -// The LOAD section containng the dynamic table has been mapped as +// The LOAD section containing the dynamic table has been mapped as // read-only, but the DYNAMIC header claims it is writable. #if !(defined(__mips__) && defined(__LP64__)) if ((dynamic_flags & PF_W) != 0) { @@ -2028,38 +2154,10 @@ bool soinfo::LinkImage(const android_dlextinfo* extinfo) { DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name); return false; } + return true; +} - // If this is the main executable, then load all of the libraries from LD_PRELOAD now. - if (flags & FLAG_EXE) { - memset(g_ld_preloads, 0, sizeof(g_ld_preloads)); - size_t preload_count = 0; - for (size_t i = 0; g_ld_preload_names[i] != nullptr; i++) { - soinfo* lsi = find_library(g_ld_preload_names[i], 0, nullptr); - if (lsi != nullptr) { - g_ld_preloads[preload_count++] = lsi; - } else { - // As with glibc, failure to load an LD_PRELOAD library is just a warning. - DL_WARN("could not load library \"%s\" from LD_PRELOAD for \"%s\"; caused by %s", - g_ld_preload_names[i], name, linker_get_error_buffer()); - } - } - } - - for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { - if (d->d_tag == DT_NEEDED) { - const char* library_name = strtab + d->d_un.d_val; - DEBUG("%s needs %s", name, library_name); - soinfo* lsi = find_library(library_name, 0, nullptr); - if (lsi == nullptr) { - strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf)); - DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s", - library_name, name, tmp_err_buf); - return false; - } - - add_child(lsi); - } - } +bool soinfo::LinkImage(const android_dlextinfo* extinfo) { #if !defined(__LP64__) if (has_text_relocations) { @@ -2121,7 +2219,6 @@ bool soinfo::LinkImage(const android_dlextinfo* extinfo) { } #endif - flags |= FLAG_LINKED; DEBUG("[ finished linking %s ]", name); #if !defined(__LP64__) @@ -2183,6 +2280,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->size = phdr_table_get_load_size(si->phdr, si->phnum); si->load_bias = get_elf_exec_load_bias(ehdr_vdso); + si->PrelinkImage(); si->LinkImage(nullptr); #endif } @@ -2216,7 +2314,7 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) { ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_base); ElfW(Phdr)* phdr = reinterpret_cast(linker_base + elf_hdr->e_phoff); phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, - &linker_soinfo_for_gdb.dynamic, nullptr, nullptr); + &linker_soinfo_for_gdb.dynamic); insert_soinfo_into_debug_map(&linker_soinfo_for_gdb); } @@ -2312,6 +2410,37 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( somain = si; + si->PrelinkImage(); + + // Load ld_preloads and dependencies. + StringLinkedList needed_library_name_list; + size_t needed_libraries_count = 0; + size_t ld_preloads_count = 0; + while (g_ld_preload_names[ld_preloads_count] != nullptr) { + needed_library_name_list.push_back(g_ld_preload_names[ld_preloads_count++]); + ++needed_libraries_count; + } + + for_each_dt_needed(si, [&](const char* name) { + needed_library_name_list.push_back(name); + ++needed_libraries_count; + }); + + const char* needed_library_names[needed_libraries_count]; + soinfo* needed_library_si[needed_libraries_count]; + + memset(needed_library_names, 0, sizeof(needed_library_names)); + needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); + + if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, 0, nullptr)) { + __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); + exit(EXIT_FAILURE); + } + + for (size_t i = 0; iadd_child(needed_library_si[i]); + } + if (!si->LinkImage(nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); @@ -2321,11 +2450,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( si->CallPreInitConstructors(); - for (size_t i = 0; g_ld_preloads[i] != nullptr; ++i) { - g_ld_preloads[i]->CallConstructors(); - } - - /* After the LinkImage, the si->load_bias is initialized. + /* After the PrelinkImage, the si->load_bias is initialized. * For so lib, the map->l_addr will be updated in notify_gdb_of_load. * We need to update this value for so exe here. So Unwind_Backtrace * for some arch like x86 could work correctly within so exe. @@ -2440,7 +2565,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - if (!linker_so.LinkImage(nullptr)) { + if (!(linker_so.PrelinkImage() && linker_so.LinkImage(nullptr))) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as diff --git a/linker/linker.h b/linker/linker.h index 6547d685e..3024d3ab2 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -204,6 +204,7 @@ struct soinfo { void CallConstructors(); void CallDestructors(); void CallPreInitConstructors(); + bool PrelinkImage(); bool LinkImage(const android_dlextinfo* extinfo); void add_child(soinfo* child); @@ -217,6 +218,7 @@ struct soinfo { bool get_has_ifuncs(); soinfo_list_t& get_children(); + soinfo_list_t& get_parents(); bool inline has_min_version(uint32_t min_version) { return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index 1bbd57778..436517271 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -702,34 +702,17 @@ int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, * load_bias -> load bias * Output: * dynamic -> address of table in memory (null on failure). - * dynamic_count -> number of items in table (0 on failure). - * dynamic_flags -> protection flags for section (unset on failure) * Return: * void */ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count, - ElfW(Addr) load_bias, - ElfW(Dyn)** dynamic, size_t* dynamic_count, ElfW(Word)* dynamic_flags) { - const ElfW(Phdr)* phdr = phdr_table; - const ElfW(Phdr)* phdr_limit = phdr + phdr_count; - - for (phdr = phdr_table; phdr < phdr_limit; phdr++) { - if (phdr->p_type != PT_DYNAMIC) { - continue; - } - - *dynamic = reinterpret_cast(load_bias + phdr->p_vaddr); - if (dynamic_count) { - *dynamic_count = (unsigned)(phdr->p_memsz / 8); - } - if (dynamic_flags) { - *dynamic_flags = phdr->p_flags; - } - return; - } + ElfW(Addr) load_bias, ElfW(Dyn)** dynamic) { *dynamic = nullptr; - if (dynamic_count) { - *dynamic_count = 0; + for (const ElfW(Phdr)* phdr = phdr_table, *phdr_limit = phdr + phdr_count; phdr < phdr_limit; phdr++) { + if (phdr->p_type == PT_DYNAMIC) { + *dynamic = reinterpret_cast(load_bias + phdr->p_vaddr); + return; + } } } diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h index 50708a0e6..d4c3ce85f 100644 --- a/linker/linker_phdr.h +++ b/linker/linker_phdr.h @@ -101,7 +101,6 @@ int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, El #endif void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count, - ElfW(Addr) load_bias, - ElfW(Dyn)** dynamic, size_t* dynamic_count, ElfW(Word)* dynamic_flags); + ElfW(Addr) load_bias, ElfW(Dyn)** dynamic); #endif /* LINKER_PHDR_H */ diff --git a/tests/Android.mk b/tests/Android.mk index 864052e81..64d3b596e 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -112,6 +112,7 @@ libBionicStandardTests_src_files := \ system_properties_test.cpp \ time_test.cpp \ uchar_test.cpp \ + uniqueptr_test.cpp \ unistd_test.cpp \ wchar_test.cpp \ diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 6de38c89e..b8c33dd53 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -130,6 +130,55 @@ TEST(dlfcn, ifunc_ctor_call) { } #endif +TEST(dlfcn, dlopen_check_order) { + // Here is how the test library and its dt_needed + // libraries are arranged + // + // libtest_check_order.so + // | + // +-> libtest_check_order_1_left.so + // | | + // | +-> libtest_check_order_a.so + // | | + // | +-> libtest_check_order_b.so + // | + // +-> libtest_check_order_2_right.so + // | | + // | +-> libtest_check_order_d.so + // | | + // | +-> libtest_check_order_b.so + // | + // +-> libtest_check_order_3_c.so + // + // load order should be (1, 2, 3, a, b, d) + // + // get_answer() is defined in (2, 3, a, b, c) + // get_answer2() is defined in (b, d) + void* sym = dlsym(RTLD_DEFAULT, "dlopen_test_get_answer"); + ASSERT_TRUE(sym == nullptr); + void* handle = dlopen("libtest_check_order.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr); + typedef int (*fn_t) (void); + fn_t fn, fn2; + fn = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer")); + ASSERT_TRUE(fn != NULL); + fn2 = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer2")); + ASSERT_TRUE(fn2 != NULL); + + ASSERT_EQ(42, fn()); + ASSERT_EQ(43, fn2()); + dlclose(handle); +} + +// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> +// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so -> +// libtest_with_dependency_loop_a.so +TEST(dlfcn, dlopen_check_loop) { + void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW); + ASSERT_TRUE(handle == NULL); + ASSERT_STREQ("dlopen failed: recursive link to \"libtest_with_dependency_loop_a.so\"", dlerror()); +} + TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 8f0ec7a56..e7a2676ec 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -101,6 +101,160 @@ build_type := target build_target := SHARED_LIBRARY include $(TEST_PATH)/Android.build.mk +# ----------------------------------------------------------------------------- +# Libraries used by dlfcn tests to verify correct load order: +# libtest_check_order_2_right.so +# ----------------------------------------------------------------------------- +libtest_check_order_2_right_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_2_right_cflags := -D__ANSWER=42 +module := libtest_check_order_2_right +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_a.so +# ----------------------------------------------------------------------------- +libtest_check_order_a_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_a_cflags := -D__ANSWER=1 +module := libtest_check_order_a +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_b.so +# ----------------------------------------------------------------------------- +libtest_check_order_b_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 +module := libtest_check_order_b +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_c.so +# ----------------------------------------------------------------------------- +libtest_check_order_3_c_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_3_c_cflags := -D__ANSWER=3 +module := libtest_check_order_3_c +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_d.so +# ----------------------------------------------------------------------------- +libtest_check_order_d_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_d_shared_libraries := libtest_check_order_b +libtest_check_order_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 +module := libtest_check_order_d +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_left.so +# ----------------------------------------------------------------------------- +libtest_check_order_1_left_src_files := \ + empty.cpp + +libtest_check_order_1_left_shared_libraries := libtest_check_order_a libtest_check_order_b + +module := libtest_check_order_1_left +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order.so +# ----------------------------------------------------------------------------- +libtest_check_order_src_files := \ + empty.cpp + +libtest_check_order_shared_libraries := libtest_check_order_1_left \ + libtest_check_order_2_right libtest_check_order_3_c + +module := libtest_check_order +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# Library with dependency loop used by dlfcn tests +# +# libtest_with_dependency_loop -> a -> b -> c -> a +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_src_files := empty.cpp + +libtest_with_dependency_loop_shared_libraries := \ + libtest_with_dependency_loop_a + +module := libtest_with_dependency_loop +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_a.so +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_a_src_files := empty.cpp + +libtest_with_dependency_loop_a_shared_libraries := \ + libtest_with_dependency_loop_b_tmp + +module := libtest_with_dependency_loop_a +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_b.so +# +# this is temporary placeholder - will be removed +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_b_tmp_src_files := empty.cpp +libtest_with_dependency_loop_b_tmp_ldflags := -Wl,-soname=libtest_with_dependency_loop_b.so + +module := libtest_with_dependency_loop_b_tmp +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_b.so +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_b_src_files := empty.cpp +libtest_with_dependency_loop_b_shared_libraries := libtest_with_dependency_loop_c + +module := libtest_with_dependency_loop_b +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_c.so +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_c_src_files := empty.cpp + +libtest_with_dependency_loop_c_shared_libraries := \ + libtest_with_dependency_loop_a + +module := libtest_with_dependency_loop_c +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + # ----------------------------------------------------------------------------- # Library with dependency used by dlfcn tests # ----------------------------------------------------------------------------- diff --git a/tests/libs/dlopen_testlib_answer.cpp b/tests/libs/dlopen_testlib_answer.cpp new file mode 100644 index 000000000..a4d75046e --- /dev/null +++ b/tests/libs/dlopen_testlib_answer.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int dlopen_test_get_answer() { + return __ANSWER; +} + +#ifdef __ANSWER2 +extern "C" int dlopen_test_get_answer2() { + return __ANSWER2; +} +#endif diff --git a/tests/uniqueptr_test.cpp b/tests/uniqueptr_test.cpp new file mode 100644 index 000000000..4b6608af2 --- /dev/null +++ b/tests/uniqueptr_test.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +static int cCount = 0; +struct C { + C() { ++cCount; } + ~C() { --cCount; } +}; + +static bool freed = false; +struct Freer { + void operator() (int* p) { + ASSERT_EQ(123, *p); + free(p); + freed = true; + } +}; + +TEST(UniquePtr, smoke) { + // + // UniquePtr tests... + // + + // Can we free a single object? + { + UniquePtr c(new C); + ASSERT_TRUE(cCount == 1); + } + ASSERT_TRUE(cCount == 0); + // Does release work? + C* rawC; + { + UniquePtr c(new C); + ASSERT_TRUE(cCount == 1); + rawC = c.release(); + } + ASSERT_TRUE(cCount == 1); + delete rawC; + // Does reset work? + { + UniquePtr c(new C); + ASSERT_TRUE(cCount == 1); + c.reset(new C); + ASSERT_TRUE(cCount == 1); + } + ASSERT_TRUE(cCount == 0); + + // + // UniquePtr tests... + // + + // Can we free an array? + { + UniquePtr cs(new C[4]); + ASSERT_TRUE(cCount == 4); + } + ASSERT_TRUE(cCount == 0); + // Does release work? + { + UniquePtr c(new C[4]); + ASSERT_TRUE(cCount == 4); + rawC = c.release(); + } + ASSERT_TRUE(cCount == 4); + delete[] rawC; + // Does reset work? + { + UniquePtr c(new C[4]); + ASSERT_TRUE(cCount == 4); + c.reset(new C[2]); + ASSERT_TRUE(cCount == 2); + } + ASSERT_TRUE(cCount == 0); + + // + // Custom deleter tests... + // + ASSERT_TRUE(!freed); + { + UniquePtr i(reinterpret_cast(malloc(sizeof(int)))); + *i = 123; + } + ASSERT_TRUE(freed); +} From 8de1ddece0d0b85eafeb86c06cf3a734dadf2b55 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 4 Sep 2014 18:23:00 -0700 Subject: [PATCH 019/114] Fix order of soinfo links (repairs libcxx tests). (cherry picked from commit b2a30ee8d209154efc367db11b4167a5d6db605f) Change-Id: I59c5333bc050cbbea14051cea9220be2f64ee383 --- linker/linker.cpp | 4 +-- tests/Android.mk | 1 + tests/dlfcn_test.cpp | 28 +++++++++++++++++++ tests/libs/Android.mk | 23 +++++++++++++++ ...pen_testlib_relo_check_dt_needed_order.cpp | 21 ++++++++++++++ ...n_testlib_relo_check_dt_needed_order_1.cpp | 19 +++++++++++++ ...n_testlib_relo_check_dt_needed_order_2.cpp | 19 +++++++++++++ 7 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp create mode 100644 tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp create mode 100644 tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp diff --git a/linker/linker.cpp b/linker/linker.cpp index 610489ea5..ac470a54b 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -1778,8 +1778,8 @@ void soinfo::CallDestructors() { void soinfo::add_child(soinfo* child) { if (has_min_version(0)) { - this->children.push_front(child); - child->parents.push_front(this); + child->parents.push_back(this); + this->children.push_back(child); } } diff --git a/tests/Android.mk b/tests/Android.mk index 64d3b596e..69ff8110a 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -257,6 +257,7 @@ bionic-unit-tests_ldflags := \ -Wl,-u,DlSymTestFunction \ bionic-unit-tests_c_includes := \ + bionic/libc \ $(call include-path-for, libpagemap) \ bionic-unit-tests_shared_libraries_target := \ diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index b8c33dd53..fb3bfc511 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -22,6 +22,8 @@ #include #include +#include "private/ScopeGuard.h" + #include #define ASSERT_SUBSTR(needle, haystack) \ @@ -130,6 +132,32 @@ TEST(dlfcn, ifunc_ctor_call) { } #endif +TEST(dlfcn, dlopen_check_relocation_dt_needed_order) { + // This is the structure of the test library and + // its dt_needed libraries + // libtest_relo_check_dt_needed_order.so + // | + // +-> libtest_relo_check_dt_needed_order_1.so + // | + // +-> libtest_relo_check_dt_needed_order_2.so + // + // The root library references relo_test_get_answer_lib - which is defined + // in both dt_needed libraries, the correct relocation should + // use the function defined in libtest_relo_check_dt_needed_order_1.so + void* handle = nullptr; + auto guard = create_scope_guard([&]() { + dlclose(handle); + }); + + handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + typedef int (*fn_t) (void); + fn_t fn = reinterpret_cast(dlsym(handle, "relo_test_get_answer")); + ASSERT_TRUE(fn != nullptr) << dlerror(); + ASSERT_EQ(1, fn()); +} + TEST(dlfcn, dlopen_check_order) { // Here is how the test library and its dt_needed // libraries are arranged diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index e7a2676ec..21681eec9 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -255,6 +255,29 @@ build_type := target build_target := SHARED_LIBRARY include $(TEST_PATH)/Android.build.mk +# ----------------------------------------------------------------------------- +# libtest_relo_check_dt_needed_order.so +# | +# +-> libtest_relo_check_dt_needed_order_1.so +# | +# +-> libtest_relo_check_dt_needed_order_2.so +# ----------------------------------------------------------------------------- +libtest_relo_check_dt_needed_order_shared_libraries := \ + libtest_relo_check_dt_needed_order_1 libtest_relo_check_dt_needed_order_2 + +libtest_relo_check_dt_needed_order_src_files := dlopen_testlib_relo_check_dt_needed_order.cpp +libtest_relo_check_dt_needed_order_1_src_files := dlopen_testlib_relo_check_dt_needed_order_1.cpp +libtest_relo_check_dt_needed_order_2_src_files := dlopen_testlib_relo_check_dt_needed_order_2.cpp +build_type := target +build_target := SHARED_LIBRARY + +module := libtest_relo_check_dt_needed_order +include $(TEST_PATH)/Android.build.mk +module := libtest_relo_check_dt_needed_order_1 +include $(TEST_PATH)/Android.build.mk +module := libtest_relo_check_dt_needed_order_2 +include $(TEST_PATH)/Android.build.mk + # ----------------------------------------------------------------------------- # Library with dependency used by dlfcn tests # ----------------------------------------------------------------------------- diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp new file mode 100644 index 000000000..d8fb543ad --- /dev/null +++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int relo_test_get_answer_lib(); + +extern "C" int relo_test_get_answer() { + return relo_test_get_answer_lib(); +} diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp new file mode 100644 index 000000000..4c877d0a1 --- /dev/null +++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int relo_test_get_answer_lib() { + return 1; +} diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp new file mode 100644 index 000000000..10288a086 --- /dev/null +++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int relo_test_get_answer_lib() { + return 2; +} From c0133a73b6f37b88afc8dafb6f63af03cbb708f6 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Fri, 5 Sep 2014 14:57:59 -0700 Subject: [PATCH 020/114] Revert "Load libraries in breadth-first order" This reverts commit a3ad450a2e3fb6b3fe359683b247eba20896f646. (cherry picked from commit 498eb18b82a425f9f30132e4832f327b2ee0e545) Change-Id: Iec7eab83d0c0ed1604e1e8ea3f9e9d0ce1d29680 --- libc/private/UniquePtr.h | 140 --------- linker/dlfcn.cpp | 1 - linker/linker.cpp | 431 ++++++++++----------------- linker/linker.h | 2 - linker/linker_phdr.cpp | 29 +- linker/linker_phdr.h | 3 +- tests/Android.mk | 1 - tests/dlfcn_test.cpp | 49 --- tests/libs/Android.mk | 154 ---------- tests/libs/dlopen_testlib_answer.cpp | 25 -- tests/uniqueptr_test.cpp | 101 ------- 11 files changed, 178 insertions(+), 758 deletions(-) delete mode 100644 libc/private/UniquePtr.h delete mode 100644 tests/libs/dlopen_testlib_answer.cpp delete mode 100644 tests/uniqueptr_test.cpp diff --git a/libc/private/UniquePtr.h b/libc/private/UniquePtr.h deleted file mode 100644 index 5ac7599a0..000000000 --- a/libc/private/UniquePtr.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef UNIQUE_PTR_H_included -#define UNIQUE_PTR_H_included - -// Default deleter for pointer types. -template -struct DefaultDelete { - enum { type_must_be_complete = sizeof(T) }; - DefaultDelete() {} - void operator()(T* p) const { - delete p; - } -}; - -// Default deleter for array types. -template -struct DefaultDelete { - enum { type_must_be_complete = sizeof(T) }; - void operator()(T* p) const { - delete[] p; - } -}; - -// A smart pointer that deletes the given pointer on destruction. -// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr -// and boost::scoped_array). -// Named to be in keeping with Android style but also to avoid -// collision with any other implementation, until we can switch over -// to unique_ptr. -// Use thus: -// UniquePtr c(new C); -template > -class UniquePtr { -public: - // Construct a new UniquePtr, taking ownership of the given raw pointer. - explicit UniquePtr(T* ptr = nullptr) : mPtr(ptr) { } - - UniquePtr(UniquePtr&& that) { - mPtr = that.mPtr; - that.mPtr = nullptr; - } - - ~UniquePtr() { - reset(); - } - - // Accessors. - T& operator*() const { return *mPtr; } - T* operator->() const { return mPtr; } - T* get() const { return mPtr; } - - // Returns the raw pointer and hands over ownership to the caller. - // The pointer will not be deleted by UniquePtr. - T* release() __attribute__((warn_unused_result)) { - T* result = mPtr; - mPtr = nullptr; - return result; - } - - // Takes ownership of the given raw pointer. - // If this smart pointer previously owned a different raw pointer, that - // raw pointer will be freed. - void reset(T* ptr = nullptr) { - if (ptr != mPtr) { - D()(mPtr); - mPtr = ptr; - } - } - -private: - // The raw pointer. - T* mPtr; - - // Comparing unique pointers is probably a mistake, since they're unique. - template bool operator==(const UniquePtr& p) const = delete; - template bool operator!=(const UniquePtr& p) const = delete; - - // Disallow copy and assignment. - UniquePtr(const UniquePtr&) = delete; - void operator=(const UniquePtr&) = delete; -}; - -// Partial specialization for array types. Like std::unique_ptr, this removes -// operator* and operator-> but adds operator[]. -template -class UniquePtr { -public: - explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) { - } - UniquePtr(UniquePtr&& that) { - mPtr = that.mPtr; - that.mPtr = nullptr; - } - - ~UniquePtr() { - reset(); - } - - T& operator[](size_t i) const { - return mPtr[i]; - } - T* get() const { return mPtr; } - - T* release() __attribute__((warn_unused_result)) { - T* result = mPtr; - mPtr = NULL; - return result; - } - - void reset(T* ptr = NULL) { - if (ptr != mPtr) { - D()(mPtr); - mPtr = ptr; - } - } - -private: - T* mPtr; - - // Disallow copy and assignment. - UniquePtr(const UniquePtr&) = delete; - void operator=(const UniquePtr&) = delete; -}; - -#endif // UNIQUE_PTR_H_included diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 3024b3c29..38484d995 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -245,7 +245,6 @@ soinfo* get_libdl_info() { __libdl_info.bucket = g_libdl_buckets; __libdl_info.chain = g_libdl_chains; __libdl_info.has_DT_SYMBOLIC = true; - __libdl_info.ref_count = 1; } return &__libdl_info; diff --git a/linker/linker.cpp b/linker/linker.cpp index ac470a54b..2186b3d30 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -44,8 +44,6 @@ #include "private/KernelArgumentBlock.h" #include "private/ScopedPthreadMutexLocker.h" #include "private/ScopedFd.h" -#include "private/ScopeGuard.h" -#include "private/UniquePtr.h" #include "linker.h" #include "linker_debug.h" @@ -172,6 +170,7 @@ DISALLOW_ALLOCATION(void, free, (void* u __unused)); DISALLOW_ALLOCATION(void*, realloc, (void* u1 __unused, size_t u2 __unused)); DISALLOW_ALLOCATION(void*, calloc, (size_t u1 __unused, size_t u2 __unused)); +static char tmp_err_buf[768]; static char __linker_dl_err_buf[768]; char* linker_get_error_buffer() { @@ -513,7 +512,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { unsigned elf_hash = elfhash(name); ElfW(Sym)* s = nullptr; - if (somain != nullptr) { + if (si != nullptr && somain != nullptr) { /* * Local scope is executable scope. Just start looking into it right away * for the shortcut. @@ -658,47 +657,22 @@ class TypeBasedAllocator { } }; -class LoadTask { - public: - struct deleter_t { - void operator()(LoadTask* t) { - TypeBasedAllocator::free(t); - } - }; - - typedef UniquePtr unique_ptr; - - static deleter_t deleter; - - static LoadTask* create(const char* name, soinfo* needed_by) { - LoadTask* ptr = TypeBasedAllocator::alloc(); - return new (ptr) LoadTask(name, needed_by); - } - - const char* get_name() { - return name_; - } - - soinfo* get_needed_by() { - return needed_by_; - } - private: - LoadTask(const char* name, soinfo* needed_by) - : name_(name), needed_by_(needed_by) {} - - const char* name_; - soinfo* needed_by_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask); -}; - template using linked_list_t = LinkedList>>; typedef linked_list_t SoinfoLinkedList; -typedef linked_list_t StringLinkedList; -typedef linked_list_t LoadTaskList; +static LinkerAllocator> g_soinfo_list_allocator_rw; +class SoinfoListAllocatorRW { + public: + static LinkedListEntry* alloc() { + return g_soinfo_list_allocator_rw.alloc(); + } + + static void free(LinkedListEntry* ptr) { + g_soinfo_list_allocator_rw.free(ptr); + } +}; // This is used by dlsym(3). It performs symbol lookup only within the // specified soinfo object and its dependencies in breadth first order. @@ -824,80 +798,73 @@ static int open_library(const char* name) { return fd; } -template -static void for_each_dt_needed(const soinfo* si, F action) { - for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { - if (d->d_tag == DT_NEEDED) { - action(si->strtab + d->d_un.d_val); +static soinfo* load_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { + int fd = -1; + ScopedFd file_guard(-1); + + if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { + fd = extinfo->library_fd; + } else { + // Open the file. + fd = open_library(name); + if (fd == -1) { + DL_ERR("library \"%s\" not found", name); + return nullptr; + } + + file_guard.reset(fd); } - } -} -static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { - int fd = -1; - ScopedFd file_guard(-1); + ElfReader elf_reader(name, fd); - if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { - fd = extinfo->library_fd; - } else { - // Open the file. - fd = open_library(name); - if (fd == -1) { - DL_ERR("library \"%s\" not found", name); + struct stat file_stat; + if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { + DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); return nullptr; } - file_guard.reset(fd); - } - - struct stat file_stat; - if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { - DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); - return nullptr; - } - - // Check for symlink and other situations where - // file can have different names. - for (soinfo* si = solist; si != nullptr; si = si->next) { - if (si->get_st_dev() != 0 && - si->get_st_ino() != 0 && - si->get_st_dev() == file_stat.st_dev && - si->get_st_ino() == file_stat.st_ino) { - TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name); - return si; + // Check for symlink and other situations where + // file can have different names. + for (soinfo* si = solist; si != nullptr; si = si->next) { + if (si->get_st_dev() != 0 && + si->get_st_ino() != 0 && + si->get_st_dev() == file_stat.st_dev && + si->get_st_ino() == file_stat.st_ino) { + TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name); + return si; + } } - } - if ((dlflags & RTLD_NOLOAD) != 0) { - return nullptr; - } + if ((dlflags & RTLD_NOLOAD) != 0) { + return nullptr; + } - // Read the ELF header and load the segments. - ElfReader elf_reader(name, fd); - if (!elf_reader.Load(extinfo)) { - return nullptr; - } + // Read the ELF header and load the segments. + if (!elf_reader.Load(extinfo)) { + return nullptr; + } - soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat); - if (si == nullptr) { - return nullptr; - } - si->base = elf_reader.load_start(); - si->size = elf_reader.load_size(); - si->load_bias = elf_reader.load_bias(); - si->phnum = elf_reader.phdr_count(); - si->phdr = elf_reader.loaded_phdr(); + soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat); + if (si == nullptr) { + return nullptr; + } + si->base = elf_reader.load_start(); + si->size = elf_reader.load_size(); + si->load_bias = elf_reader.load_bias(); + si->phnum = elf_reader.phdr_count(); + si->phdr = elf_reader.loaded_phdr(); - if (!si->PrelinkImage()) { - soinfo_free(si); - return nullptr; - } + // At this point we know that whatever is loaded @ base is a valid ELF + // shared library whose segments are properly mapped in. + TRACE("[ load_library base=%p size=%zu name='%s' ]", + reinterpret_cast(si->base), si->size, si->name); - for_each_dt_needed(si, [&] (const char* name) { - load_tasks.push_back(LoadTask::create(name, si)); - }); + if (!si->LinkImage(extinfo)) { + soinfo_free(si); + return nullptr; + } - return si; + return si; } static soinfo *find_loaded_library_by_name(const char* name) { @@ -910,122 +877,33 @@ static soinfo *find_loaded_library_by_name(const char* name) { return nullptr; } -static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { +static soinfo* find_library_internal(const char* name, int dlflags, const android_dlextinfo* extinfo) { + if (name == nullptr) { + return somain; + } soinfo* si = find_loaded_library_by_name(name); // Library might still be loaded, the accurate detection - // of this fact is done by load_library. + // of this fact is done by load_library if (si == nullptr) { TRACE("[ '%s' has not been found by name. Trying harder...]", name); - si = load_library(load_tasks, name, dlflags, extinfo); + si = load_library(name, dlflags, extinfo); + } + + if (si != nullptr && (si->flags & FLAG_LINKED) == 0) { + DL_ERR("recursive link to \"%s\"", si->name); + return nullptr; } return si; } -static void soinfo_unload(soinfo* si); - -static bool is_recursive(soinfo* si, soinfo* parent) { - if (parent == nullptr) { - return false; - } - - if (si == parent) { - DL_ERR("recursive link to \"%s\"", si->name); - return true; - } - - return !parent->get_parents().visit([&](soinfo* grandparent) { - return !is_recursive(si, grandparent); - }); -} - -static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[], - soinfo* ld_preloads[], size_t ld_preloads_size, int dlflags, const android_dlextinfo* extinfo) { - // Step 0: prepare. - LoadTaskList load_tasks; - for (size_t i = 0; i < library_names_size; ++i) { - const char* name = library_names[i]; - load_tasks.push_back(LoadTask::create(name, nullptr)); - } - - // Libraries added to this list in reverse order so that we can - // start linking from bottom-up - see step 2. - SoinfoLinkedList found_libs; - size_t soinfos_size = 0; - - auto failure_guard = create_scope_guard([&]() { - // Housekeeping - load_tasks.for_each([] (LoadTask* t) { - LoadTask::deleter(t); - }); - - for (size_t i = 0; iget_name(), dlflags, extinfo); - if (si == nullptr) { - return false; - } - - soinfo* needed_by = task->get_needed_by(); - - if (is_recursive(si, needed_by)) { - soinfo_free(si); - return false; - } - - si->ref_count++; - if (needed_by != nullptr) { - needed_by->add_child(si); - } - found_libs.push_front(si); - - // When ld_preloads is not null first - // ld_preloads_size libs are in fact ld_preloads. - if (ld_preloads != nullptr && soinfos_size < ld_preloads_size) { - ld_preloads[soinfos_size] = si; - } - - if (soinfos_sizeflags & FLAG_LINKED) == 0) { - if (!si->LinkImage(extinfo)) { - return false; - } - si->flags |= FLAG_LINKED; - } - } - - // All is well - found_libs and load_tasks are empty at this point - // and all libs are successfully linked. - failure_guard.disable(); - return true; -} - static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { - if (name == nullptr) { - somain->ref_count++; - return somain; + soinfo* si = find_library_internal(name, dlflags, extinfo); + if (si != nullptr) { + si->ref_count++; } - - soinfo* si; - - if (!find_libraries(&name, 1, &si, nullptr, 0, dlflags, extinfo)) { - return nullptr; - } - return si; } @@ -1047,17 +925,20 @@ static void soinfo_unload(soinfo* si) { soinfo_unload(children[i]); } } else { - for_each_dt_needed(si, [&] (const char* library_name) { - TRACE("deprecated (old format of soinfo): %s needs to unload %s", si->name, library_name); - soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); - if (needed != nullptr) { - soinfo_unload(needed); - } else { - // Not found: for example if symlink was deleted between dlopen and dlclose - // Since we cannot really handle errors at this point - print and continue. - PRINT("warning: couldn't find %s needed by %s on unload.", library_name, si->name); + for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { + if (d->d_tag == DT_NEEDED) { + const char* library_name = si->strtab + d->d_un.d_val; + TRACE("%s needs to unload %s", si->name, library_name); + soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); + if (needed != nullptr) { + soinfo_unload(needed); + } else { + // Not found: for example if symlink was deleted between dlopen and dlclose + // Since we cannot really handle errors at this point - print and continue. + PRINT("warning: couldn't find %s needed by %s on unload.", library_name, si->name); + } } - }); + } } notify_gdb_of_unload(si); @@ -1166,6 +1047,9 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count) #if defined(USE_RELA) int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { + ElfW(Sym)* s; + soinfo* lsi; + for (size_t idx = 0; idx < count; ++idx, ++rela) { unsigned type = ELFW(R_TYPE)(rela->r_info); unsigned sym = ELFW(R_SYM)(rela->r_info); @@ -1177,10 +1061,6 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { if (type == 0) { // R_*_NONE continue; } - - ElfW(Sym)* s = nullptr; - soinfo* lsi = nullptr; - if (sym != 0) { sym_name = reinterpret_cast(strtab + symtab[sym].st_name); s = soinfo_do_lookup(this, sym_name, &lsi); @@ -1239,6 +1119,8 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { sym_addr = static_cast(s->st_value + lsi->load_bias); } count_relocation(kRelocSymbol); + } else { + s = nullptr; } switch (type) { @@ -1432,6 +1314,9 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { #else // REL, not RELA. int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { + ElfW(Sym)* s; + soinfo* lsi; + for (size_t idx = 0; idx < count; ++idx, ++rel) { unsigned type = ELFW(R_TYPE)(rel->r_info); // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. @@ -1444,10 +1329,6 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { if (type == 0) { // R_*_NONE continue; } - - ElfW(Sym)* s = nullptr; - soinfo* lsi = nullptr; - if (sym != 0) { sym_name = reinterpret_cast(strtab + symtab[sym].st_name); s = soinfo_do_lookup(this, sym_name, &lsi); @@ -1509,6 +1390,8 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { sym_addr = static_cast(s->st_value + lsi->load_bias); } count_relocation(kRelocSymbol); + } else { + s = nullptr; } switch (type) { @@ -1663,7 +1546,7 @@ static bool mips_relocate_got(soinfo* si) { for (size_t g = gotsym; g < symtabno; g++, sym++, got++) { // This is an undefined reference... try to locate it. const char* sym_name = si->strtab + sym->st_name; - soinfo* lsi = nullptr; + soinfo* lsi; ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. @@ -1760,9 +1643,6 @@ void soinfo::CallConstructors() { } void soinfo::CallDestructors() { - if (!constructors_called) { - return; - } TRACE("\"%s\": calling destructors", name); // DT_FINI_ARRAY must be parsed in reverse order. @@ -1848,7 +1728,7 @@ bool soinfo::get_has_ifuncs() { return false; } -// This is a return on get_children()/get_parents() if +// This is a return on get_children() in case // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -1860,14 +1740,6 @@ soinfo::soinfo_list_t& soinfo::get_children() { return g_empty_list; } -soinfo::soinfo_list_t& soinfo::get_parents() { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return g_empty_list; - } - - return this->parents; -} - /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -1929,18 +1801,20 @@ static int nullify_closed_stdio() { return return_value; } -bool soinfo::PrelinkImage() { - phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic); - - /* We can't log anything until the linker is relocated */ +bool soinfo::LinkImage(const android_dlextinfo* extinfo) { bool relocating_linker = (flags & FLAG_LINKER) != 0; + + /* We can't debug anything until the linker is relocated */ if (!relocating_linker) { INFO("[ linking %s ]", name); DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast(base), flags); } /* Extract dynamic section */ - ElfW(Word) dynamic_flags = phdr->p_flags; + size_t dynamic_count; + ElfW(Word) dynamic_flags; + phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, + &dynamic_count, &dynamic_flags); if (dynamic == nullptr) { if (!relocating_linker) { DL_ERR("missing PT_DYNAMIC in \"%s\"", name); @@ -2008,7 +1882,7 @@ bool soinfo::PrelinkImage() { // if the dynamic table is writable // FIXME: not working currently for N64 // The flags for the LOAD and DYNAMIC program headers do not agree. -// The LOAD section containing the dynamic table has been mapped as +// The LOAD section containng the dynamic table has been mapped as // read-only, but the DYNAMIC header claims it is writable. #if !(defined(__mips__) && defined(__LP64__)) if ((dynamic_flags & PF_W) != 0) { @@ -2154,10 +2028,38 @@ bool soinfo::PrelinkImage() { DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name); return false; } - return true; -} -bool soinfo::LinkImage(const android_dlextinfo* extinfo) { + // If this is the main executable, then load all of the libraries from LD_PRELOAD now. + if (flags & FLAG_EXE) { + memset(g_ld_preloads, 0, sizeof(g_ld_preloads)); + size_t preload_count = 0; + for (size_t i = 0; g_ld_preload_names[i] != nullptr; i++) { + soinfo* lsi = find_library(g_ld_preload_names[i], 0, nullptr); + if (lsi != nullptr) { + g_ld_preloads[preload_count++] = lsi; + } else { + // As with glibc, failure to load an LD_PRELOAD library is just a warning. + DL_WARN("could not load library \"%s\" from LD_PRELOAD for \"%s\"; caused by %s", + g_ld_preload_names[i], name, linker_get_error_buffer()); + } + } + } + + for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { + if (d->d_tag == DT_NEEDED) { + const char* library_name = strtab + d->d_un.d_val; + DEBUG("%s needs %s", name, library_name); + soinfo* lsi = find_library(library_name, 0, nullptr); + if (lsi == nullptr) { + strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf)); + DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s", + library_name, name, tmp_err_buf); + return false; + } + + add_child(lsi); + } + } #if !defined(__LP64__) if (has_text_relocations) { @@ -2219,6 +2121,7 @@ bool soinfo::LinkImage(const android_dlextinfo* extinfo) { } #endif + flags |= FLAG_LINKED; DEBUG("[ finished linking %s ]", name); #if !defined(__LP64__) @@ -2280,7 +2183,6 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->size = phdr_table_get_load_size(si->phdr, si->phnum); si->load_bias = get_elf_exec_load_bias(ehdr_vdso); - si->PrelinkImage(); si->LinkImage(nullptr); #endif } @@ -2314,7 +2216,7 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) { ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_base); ElfW(Phdr)* phdr = reinterpret_cast(linker_base + elf_hdr->e_phoff); phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, - &linker_soinfo_for_gdb.dynamic); + &linker_soinfo_for_gdb.dynamic, nullptr, nullptr); insert_soinfo_into_debug_map(&linker_soinfo_for_gdb); } @@ -2410,37 +2312,6 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( somain = si; - si->PrelinkImage(); - - // Load ld_preloads and dependencies. - StringLinkedList needed_library_name_list; - size_t needed_libraries_count = 0; - size_t ld_preloads_count = 0; - while (g_ld_preload_names[ld_preloads_count] != nullptr) { - needed_library_name_list.push_back(g_ld_preload_names[ld_preloads_count++]); - ++needed_libraries_count; - } - - for_each_dt_needed(si, [&](const char* name) { - needed_library_name_list.push_back(name); - ++needed_libraries_count; - }); - - const char* needed_library_names[needed_libraries_count]; - soinfo* needed_library_si[needed_libraries_count]; - - memset(needed_library_names, 0, sizeof(needed_library_names)); - needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); - - if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, 0, nullptr)) { - __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); - exit(EXIT_FAILURE); - } - - for (size_t i = 0; iadd_child(needed_library_si[i]); - } - if (!si->LinkImage(nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); @@ -2450,7 +2321,11 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( si->CallPreInitConstructors(); - /* After the PrelinkImage, the si->load_bias is initialized. + for (size_t i = 0; g_ld_preloads[i] != nullptr; ++i) { + g_ld_preloads[i]->CallConstructors(); + } + + /* After the LinkImage, the si->load_bias is initialized. * For so lib, the map->l_addr will be updated in notify_gdb_of_load. * We need to update this value for so exe here. So Unwind_Backtrace * for some arch like x86 could work correctly within so exe. @@ -2565,7 +2440,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - if (!(linker_so.PrelinkImage() && linker_so.LinkImage(nullptr))) { + if (!linker_so.LinkImage(nullptr)) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as diff --git a/linker/linker.h b/linker/linker.h index 3024d3ab2..6547d685e 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -204,7 +204,6 @@ struct soinfo { void CallConstructors(); void CallDestructors(); void CallPreInitConstructors(); - bool PrelinkImage(); bool LinkImage(const android_dlextinfo* extinfo); void add_child(soinfo* child); @@ -218,7 +217,6 @@ struct soinfo { bool get_has_ifuncs(); soinfo_list_t& get_children(); - soinfo_list_t& get_parents(); bool inline has_min_version(uint32_t min_version) { return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index 436517271..1bbd57778 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -702,17 +702,34 @@ int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, * load_bias -> load bias * Output: * dynamic -> address of table in memory (null on failure). + * dynamic_count -> number of items in table (0 on failure). + * dynamic_flags -> protection flags for section (unset on failure) * Return: * void */ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count, - ElfW(Addr) load_bias, ElfW(Dyn)** dynamic) { - *dynamic = nullptr; - for (const ElfW(Phdr)* phdr = phdr_table, *phdr_limit = phdr + phdr_count; phdr < phdr_limit; phdr++) { - if (phdr->p_type == PT_DYNAMIC) { - *dynamic = reinterpret_cast(load_bias + phdr->p_vaddr); - return; + ElfW(Addr) load_bias, + ElfW(Dyn)** dynamic, size_t* dynamic_count, ElfW(Word)* dynamic_flags) { + const ElfW(Phdr)* phdr = phdr_table; + const ElfW(Phdr)* phdr_limit = phdr + phdr_count; + + for (phdr = phdr_table; phdr < phdr_limit; phdr++) { + if (phdr->p_type != PT_DYNAMIC) { + continue; } + + *dynamic = reinterpret_cast(load_bias + phdr->p_vaddr); + if (dynamic_count) { + *dynamic_count = (unsigned)(phdr->p_memsz / 8); + } + if (dynamic_flags) { + *dynamic_flags = phdr->p_flags; + } + return; + } + *dynamic = nullptr; + if (dynamic_count) { + *dynamic_count = 0; } } diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h index d4c3ce85f..50708a0e6 100644 --- a/linker/linker_phdr.h +++ b/linker/linker_phdr.h @@ -101,6 +101,7 @@ int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, El #endif void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count, - ElfW(Addr) load_bias, ElfW(Dyn)** dynamic); + ElfW(Addr) load_bias, + ElfW(Dyn)** dynamic, size_t* dynamic_count, ElfW(Word)* dynamic_flags); #endif /* LINKER_PHDR_H */ diff --git a/tests/Android.mk b/tests/Android.mk index 69ff8110a..38509654c 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -112,7 +112,6 @@ libBionicStandardTests_src_files := \ system_properties_test.cpp \ time_test.cpp \ uchar_test.cpp \ - uniqueptr_test.cpp \ unistd_test.cpp \ wchar_test.cpp \ diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index fb3bfc511..15ba3414c 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -158,55 +158,6 @@ TEST(dlfcn, dlopen_check_relocation_dt_needed_order) { ASSERT_EQ(1, fn()); } -TEST(dlfcn, dlopen_check_order) { - // Here is how the test library and its dt_needed - // libraries are arranged - // - // libtest_check_order.so - // | - // +-> libtest_check_order_1_left.so - // | | - // | +-> libtest_check_order_a.so - // | | - // | +-> libtest_check_order_b.so - // | - // +-> libtest_check_order_2_right.so - // | | - // | +-> libtest_check_order_d.so - // | | - // | +-> libtest_check_order_b.so - // | - // +-> libtest_check_order_3_c.so - // - // load order should be (1, 2, 3, a, b, d) - // - // get_answer() is defined in (2, 3, a, b, c) - // get_answer2() is defined in (b, d) - void* sym = dlsym(RTLD_DEFAULT, "dlopen_test_get_answer"); - ASSERT_TRUE(sym == nullptr); - void* handle = dlopen("libtest_check_order.so", RTLD_NOW); - ASSERT_TRUE(handle != nullptr); - typedef int (*fn_t) (void); - fn_t fn, fn2; - fn = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer")); - ASSERT_TRUE(fn != NULL); - fn2 = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer2")); - ASSERT_TRUE(fn2 != NULL); - - ASSERT_EQ(42, fn()); - ASSERT_EQ(43, fn2()); - dlclose(handle); -} - -// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> -// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so -> -// libtest_with_dependency_loop_a.so -TEST(dlfcn, dlopen_check_loop) { - void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW); - ASSERT_TRUE(handle == NULL); - ASSERT_STREQ("dlopen failed: recursive link to \"libtest_with_dependency_loop_a.so\"", dlerror()); -} - TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 21681eec9..20bc263b0 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -101,160 +101,6 @@ build_type := target build_target := SHARED_LIBRARY include $(TEST_PATH)/Android.build.mk -# ----------------------------------------------------------------------------- -# Libraries used by dlfcn tests to verify correct load order: -# libtest_check_order_2_right.so -# ----------------------------------------------------------------------------- -libtest_check_order_2_right_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_2_right_cflags := -D__ANSWER=42 -module := libtest_check_order_2_right -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_a.so -# ----------------------------------------------------------------------------- -libtest_check_order_a_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_a_cflags := -D__ANSWER=1 -module := libtest_check_order_a -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_b.so -# ----------------------------------------------------------------------------- -libtest_check_order_b_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 -module := libtest_check_order_b -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_c.so -# ----------------------------------------------------------------------------- -libtest_check_order_3_c_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_3_c_cflags := -D__ANSWER=3 -module := libtest_check_order_3_c -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_d.so -# ----------------------------------------------------------------------------- -libtest_check_order_d_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_d_shared_libraries := libtest_check_order_b -libtest_check_order_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 -module := libtest_check_order_d -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_left.so -# ----------------------------------------------------------------------------- -libtest_check_order_1_left_src_files := \ - empty.cpp - -libtest_check_order_1_left_shared_libraries := libtest_check_order_a libtest_check_order_b - -module := libtest_check_order_1_left -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order.so -# ----------------------------------------------------------------------------- -libtest_check_order_src_files := \ - empty.cpp - -libtest_check_order_shared_libraries := libtest_check_order_1_left \ - libtest_check_order_2_right libtest_check_order_3_c - -module := libtest_check_order -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# Library with dependency loop used by dlfcn tests -# -# libtest_with_dependency_loop -> a -> b -> c -> a -# ----------------------------------------------------------------------------- -libtest_with_dependency_loop_src_files := empty.cpp - -libtest_with_dependency_loop_shared_libraries := \ - libtest_with_dependency_loop_a - -module := libtest_with_dependency_loop -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_with_dependency_loop_a.so -# ----------------------------------------------------------------------------- -libtest_with_dependency_loop_a_src_files := empty.cpp - -libtest_with_dependency_loop_a_shared_libraries := \ - libtest_with_dependency_loop_b_tmp - -module := libtest_with_dependency_loop_a -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_with_dependency_loop_b.so -# -# this is temporary placeholder - will be removed -# ----------------------------------------------------------------------------- -libtest_with_dependency_loop_b_tmp_src_files := empty.cpp -libtest_with_dependency_loop_b_tmp_ldflags := -Wl,-soname=libtest_with_dependency_loop_b.so - -module := libtest_with_dependency_loop_b_tmp -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_with_dependency_loop_b.so -# ----------------------------------------------------------------------------- -libtest_with_dependency_loop_b_src_files := empty.cpp -libtest_with_dependency_loop_b_shared_libraries := libtest_with_dependency_loop_c - -module := libtest_with_dependency_loop_b -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_with_dependency_loop_c.so -# ----------------------------------------------------------------------------- -libtest_with_dependency_loop_c_src_files := empty.cpp - -libtest_with_dependency_loop_c_shared_libraries := \ - libtest_with_dependency_loop_a - -module := libtest_with_dependency_loop_c -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - # ----------------------------------------------------------------------------- # libtest_relo_check_dt_needed_order.so # | diff --git a/tests/libs/dlopen_testlib_answer.cpp b/tests/libs/dlopen_testlib_answer.cpp deleted file mode 100644 index a4d75046e..000000000 --- a/tests/libs/dlopen_testlib_answer.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -extern "C" int dlopen_test_get_answer() { - return __ANSWER; -} - -#ifdef __ANSWER2 -extern "C" int dlopen_test_get_answer2() { - return __ANSWER2; -} -#endif diff --git a/tests/uniqueptr_test.cpp b/tests/uniqueptr_test.cpp deleted file mode 100644 index 4b6608af2..000000000 --- a/tests/uniqueptr_test.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include - -static int cCount = 0; -struct C { - C() { ++cCount; } - ~C() { --cCount; } -}; - -static bool freed = false; -struct Freer { - void operator() (int* p) { - ASSERT_EQ(123, *p); - free(p); - freed = true; - } -}; - -TEST(UniquePtr, smoke) { - // - // UniquePtr tests... - // - - // Can we free a single object? - { - UniquePtr c(new C); - ASSERT_TRUE(cCount == 1); - } - ASSERT_TRUE(cCount == 0); - // Does release work? - C* rawC; - { - UniquePtr c(new C); - ASSERT_TRUE(cCount == 1); - rawC = c.release(); - } - ASSERT_TRUE(cCount == 1); - delete rawC; - // Does reset work? - { - UniquePtr c(new C); - ASSERT_TRUE(cCount == 1); - c.reset(new C); - ASSERT_TRUE(cCount == 1); - } - ASSERT_TRUE(cCount == 0); - - // - // UniquePtr tests... - // - - // Can we free an array? - { - UniquePtr cs(new C[4]); - ASSERT_TRUE(cCount == 4); - } - ASSERT_TRUE(cCount == 0); - // Does release work? - { - UniquePtr c(new C[4]); - ASSERT_TRUE(cCount == 4); - rawC = c.release(); - } - ASSERT_TRUE(cCount == 4); - delete[] rawC; - // Does reset work? - { - UniquePtr c(new C[4]); - ASSERT_TRUE(cCount == 4); - c.reset(new C[2]); - ASSERT_TRUE(cCount == 2); - } - ASSERT_TRUE(cCount == 0); - - // - // Custom deleter tests... - // - ASSERT_TRUE(!freed); - { - UniquePtr i(reinterpret_cast(malloc(sizeof(int)))); - *i = 123; - } - ASSERT_TRUE(freed); -} From ae69a9584baf8dd6a28065538ca09d1924ebd9e4 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Fri, 5 Sep 2014 16:42:53 -0700 Subject: [PATCH 021/114] Load libraries in breadth-first order This patch fixes the problem with symbol search order for dlsym(RTLD_DEFAULT/RTLD_NEXT, .) by loading libraries and ld_preloads in correct order. Bug: https://code.google.com/p/android/issues/detail?id=74255 Attempt: 2 (cherry picked from commit 14669a939d113214a4a20b9318fca0992d5453f0) Change-Id: Id87540c96a2242220967b6fa5d84ddcd829e2b97 --- libc/private/UniquePtr.h | 140 +++++++++ linker/dlfcn.cpp | 1 + linker/linked_list.h | 9 - linker/linker.cpp | 447 +++++++++++++++++---------- linker/linker.h | 2 + linker/linker_phdr.cpp | 29 +- linker/linker_phdr.h | 3 +- linker/tests/linked_list_test.cpp | 4 - tests/Android.mk | 1 + tests/dlfcn_test.cpp | 49 +++ tests/libs/Android.mk | 154 +++++++++ tests/libs/dlopen_testlib_answer.cpp | 25 ++ tests/uniqueptr_test.cpp | 101 ++++++ 13 files changed, 763 insertions(+), 202 deletions(-) create mode 100644 libc/private/UniquePtr.h create mode 100644 tests/libs/dlopen_testlib_answer.cpp create mode 100644 tests/uniqueptr_test.cpp diff --git a/libc/private/UniquePtr.h b/libc/private/UniquePtr.h new file mode 100644 index 000000000..5ac7599a0 --- /dev/null +++ b/libc/private/UniquePtr.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UNIQUE_PTR_H_included +#define UNIQUE_PTR_H_included + +// Default deleter for pointer types. +template +struct DefaultDelete { + enum { type_must_be_complete = sizeof(T) }; + DefaultDelete() {} + void operator()(T* p) const { + delete p; + } +}; + +// Default deleter for array types. +template +struct DefaultDelete { + enum { type_must_be_complete = sizeof(T) }; + void operator()(T* p) const { + delete[] p; + } +}; + +// A smart pointer that deletes the given pointer on destruction. +// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr +// and boost::scoped_array). +// Named to be in keeping with Android style but also to avoid +// collision with any other implementation, until we can switch over +// to unique_ptr. +// Use thus: +// UniquePtr c(new C); +template > +class UniquePtr { +public: + // Construct a new UniquePtr, taking ownership of the given raw pointer. + explicit UniquePtr(T* ptr = nullptr) : mPtr(ptr) { } + + UniquePtr(UniquePtr&& that) { + mPtr = that.mPtr; + that.mPtr = nullptr; + } + + ~UniquePtr() { + reset(); + } + + // Accessors. + T& operator*() const { return *mPtr; } + T* operator->() const { return mPtr; } + T* get() const { return mPtr; } + + // Returns the raw pointer and hands over ownership to the caller. + // The pointer will not be deleted by UniquePtr. + T* release() __attribute__((warn_unused_result)) { + T* result = mPtr; + mPtr = nullptr; + return result; + } + + // Takes ownership of the given raw pointer. + // If this smart pointer previously owned a different raw pointer, that + // raw pointer will be freed. + void reset(T* ptr = nullptr) { + if (ptr != mPtr) { + D()(mPtr); + mPtr = ptr; + } + } + +private: + // The raw pointer. + T* mPtr; + + // Comparing unique pointers is probably a mistake, since they're unique. + template bool operator==(const UniquePtr& p) const = delete; + template bool operator!=(const UniquePtr& p) const = delete; + + // Disallow copy and assignment. + UniquePtr(const UniquePtr&) = delete; + void operator=(const UniquePtr&) = delete; +}; + +// Partial specialization for array types. Like std::unique_ptr, this removes +// operator* and operator-> but adds operator[]. +template +class UniquePtr { +public: + explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) { + } + UniquePtr(UniquePtr&& that) { + mPtr = that.mPtr; + that.mPtr = nullptr; + } + + ~UniquePtr() { + reset(); + } + + T& operator[](size_t i) const { + return mPtr[i]; + } + T* get() const { return mPtr; } + + T* release() __attribute__((warn_unused_result)) { + T* result = mPtr; + mPtr = NULL; + return result; + } + + void reset(T* ptr = NULL) { + if (ptr != mPtr) { + D()(mPtr); + mPtr = ptr; + } + } + +private: + T* mPtr; + + // Disallow copy and assignment. + UniquePtr(const UniquePtr&) = delete; + void operator=(const UniquePtr&) = delete; +}; + +#endif // UNIQUE_PTR_H_included diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 38484d995..3024b3c29 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -245,6 +245,7 @@ soinfo* get_libdl_info() { __libdl_info.bucket = g_libdl_buckets; __libdl_info.chain = g_libdl_chains; __libdl_info.has_DT_SYMBOLIC = true; + __libdl_info.ref_count = 1; } return &__libdl_info; diff --git a/linker/linked_list.h b/linker/linked_list.h index 5fbdc8ffb..4e62e208f 100644 --- a/linker/linked_list.h +++ b/linker/linked_list.h @@ -122,15 +122,6 @@ class LinkedList { } } - size_t size() const { - size_t sz = 0; - for (LinkedListEntry* e = head_; e != nullptr; e = e->next) { - ++sz; - } - - return sz; - } - size_t copy_to_array(T* array[], size_t array_length) const { size_t sz = 0; for (LinkedListEntry* e = head_; sz < array_length && e != nullptr; e = e->next) { diff --git a/linker/linker.cpp b/linker/linker.cpp index 2186b3d30..793ffd51e 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -44,6 +44,8 @@ #include "private/KernelArgumentBlock.h" #include "private/ScopedPthreadMutexLocker.h" #include "private/ScopedFd.h" +#include "private/ScopeGuard.h" +#include "private/UniquePtr.h" #include "linker.h" #include "linker_debug.h" @@ -170,7 +172,6 @@ DISALLOW_ALLOCATION(void, free, (void* u __unused)); DISALLOW_ALLOCATION(void*, realloc, (void* u1 __unused, size_t u2 __unused)); DISALLOW_ALLOCATION(void*, calloc, (size_t u1 __unused, size_t u2 __unused)); -static char tmp_err_buf[768]; static char __linker_dl_err_buf[768]; char* linker_get_error_buffer() { @@ -512,7 +513,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { unsigned elf_hash = elfhash(name); ElfW(Sym)* s = nullptr; - if (si != nullptr && somain != nullptr) { + if (somain != nullptr) { /* * Local scope is executable scope. Just start looking into it right away * for the shortcut. @@ -657,22 +658,47 @@ class TypeBasedAllocator { } }; +class LoadTask { + public: + struct deleter_t { + void operator()(LoadTask* t) { + TypeBasedAllocator::free(t); + } + }; + + typedef UniquePtr unique_ptr; + + static deleter_t deleter; + + static LoadTask* create(const char* name, soinfo* needed_by) { + LoadTask* ptr = TypeBasedAllocator::alloc(); + return new (ptr) LoadTask(name, needed_by); + } + + const char* get_name() const { + return name_; + } + + soinfo* get_needed_by() const { + return needed_by_; + } + private: + LoadTask(const char* name, soinfo* needed_by) + : name_(name), needed_by_(needed_by) {} + + const char* name_; + soinfo* needed_by_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask); +}; + template using linked_list_t = LinkedList>>; typedef linked_list_t SoinfoLinkedList; +typedef linked_list_t StringLinkedList; +typedef linked_list_t LoadTaskList; -static LinkerAllocator> g_soinfo_list_allocator_rw; -class SoinfoListAllocatorRW { - public: - static LinkedListEntry* alloc() { - return g_soinfo_list_allocator_rw.alloc(); - } - - static void free(LinkedListEntry* ptr) { - g_soinfo_list_allocator_rw.free(ptr); - } -}; // This is used by dlsym(3). It performs symbol lookup only within the // specified soinfo object and its dependencies in breadth first order. @@ -798,73 +824,80 @@ static int open_library(const char* name) { return fd; } -static soinfo* load_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { - int fd = -1; - ScopedFd file_guard(-1); - - if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { - fd = extinfo->library_fd; - } else { - // Open the file. - fd = open_library(name); - if (fd == -1) { - DL_ERR("library \"%s\" not found", name); - return nullptr; - } - - file_guard.reset(fd); +template +static void for_each_dt_needed(const soinfo* si, F action) { + for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { + if (d->d_tag == DT_NEEDED) { + action(si->strtab + d->d_un.d_val); } + } +} - ElfReader elf_reader(name, fd); +static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { + int fd = -1; + ScopedFd file_guard(-1); - struct stat file_stat; - if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { - DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); + if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { + fd = extinfo->library_fd; + } else { + // Open the file. + fd = open_library(name); + if (fd == -1) { + DL_ERR("library \"%s\" not found", name); return nullptr; } - // Check for symlink and other situations where - // file can have different names. - for (soinfo* si = solist; si != nullptr; si = si->next) { - if (si->get_st_dev() != 0 && - si->get_st_ino() != 0 && - si->get_st_dev() == file_stat.st_dev && - si->get_st_ino() == file_stat.st_ino) { - TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name); - return si; - } + file_guard.reset(fd); + } + + struct stat file_stat; + if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { + DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); + return nullptr; + } + + // Check for symlink and other situations where + // file can have different names. + for (soinfo* si = solist; si != nullptr; si = si->next) { + if (si->get_st_dev() != 0 && + si->get_st_ino() != 0 && + si->get_st_dev() == file_stat.st_dev && + si->get_st_ino() == file_stat.st_ino) { + TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name); + return si; } + } - if ((dlflags & RTLD_NOLOAD) != 0) { - return nullptr; - } + if ((dlflags & RTLD_NOLOAD) != 0) { + return nullptr; + } - // Read the ELF header and load the segments. - if (!elf_reader.Load(extinfo)) { - return nullptr; - } + // Read the ELF header and load the segments. + ElfReader elf_reader(name, fd); + if (!elf_reader.Load(extinfo)) { + return nullptr; + } - soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat); - if (si == nullptr) { - return nullptr; - } - si->base = elf_reader.load_start(); - si->size = elf_reader.load_size(); - si->load_bias = elf_reader.load_bias(); - si->phnum = elf_reader.phdr_count(); - si->phdr = elf_reader.loaded_phdr(); + soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat); + if (si == nullptr) { + return nullptr; + } + si->base = elf_reader.load_start(); + si->size = elf_reader.load_size(); + si->load_bias = elf_reader.load_bias(); + si->phnum = elf_reader.phdr_count(); + si->phdr = elf_reader.loaded_phdr(); - // At this point we know that whatever is loaded @ base is a valid ELF - // shared library whose segments are properly mapped in. - TRACE("[ load_library base=%p size=%zu name='%s' ]", - reinterpret_cast(si->base), si->size, si->name); + if (!si->PrelinkImage()) { + soinfo_free(si); + return nullptr; + } - if (!si->LinkImage(extinfo)) { - soinfo_free(si); - return nullptr; - } + for_each_dt_needed(si, [&] (const char* name) { + load_tasks.push_back(LoadTask::create(name, si)); + }); - return si; + return si; } static soinfo *find_loaded_library_by_name(const char* name) { @@ -877,33 +910,122 @@ static soinfo *find_loaded_library_by_name(const char* name) { return nullptr; } -static soinfo* find_library_internal(const char* name, int dlflags, const android_dlextinfo* extinfo) { - if (name == nullptr) { - return somain; - } +static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { soinfo* si = find_loaded_library_by_name(name); // Library might still be loaded, the accurate detection - // of this fact is done by load_library + // of this fact is done by load_library. if (si == nullptr) { TRACE("[ '%s' has not been found by name. Trying harder...]", name); - si = load_library(name, dlflags, extinfo); - } - - if (si != nullptr && (si->flags & FLAG_LINKED) == 0) { - DL_ERR("recursive link to \"%s\"", si->name); - return nullptr; + si = load_library(load_tasks, name, dlflags, extinfo); } return si; } -static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { - soinfo* si = find_library_internal(name, dlflags, extinfo); - if (si != nullptr) { - si->ref_count++; +static void soinfo_unload(soinfo* si); + +static bool is_recursive(soinfo* si, soinfo* parent) { + if (parent == nullptr) { + return false; } + + if (si == parent) { + DL_ERR("recursive link to \"%s\"", si->name); + return true; + } + + return !parent->get_parents().visit([&](soinfo* grandparent) { + return !is_recursive(si, grandparent); + }); +} + +static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[], + soinfo* ld_preloads[], size_t ld_preloads_size, int dlflags, const android_dlextinfo* extinfo) { + // Step 0: prepare. + LoadTaskList load_tasks; + for (size_t i = 0; i < library_names_size; ++i) { + const char* name = library_names[i]; + load_tasks.push_back(LoadTask::create(name, nullptr)); + } + + // Libraries added to this list in reverse order so that we can + // start linking from bottom-up - see step 2. + SoinfoLinkedList found_libs; + size_t soinfos_size = 0; + + auto failure_guard = create_scope_guard([&]() { + // Housekeeping + load_tasks.for_each([] (LoadTask* t) { + LoadTask::deleter(t); + }); + + for (size_t i = 0; iget_name(), dlflags, extinfo); + if (si == nullptr) { + return false; + } + + soinfo* needed_by = task->get_needed_by(); + + if (is_recursive(si, needed_by)) { + soinfo_free(si); + return false; + } + + si->ref_count++; + if (needed_by != nullptr) { + needed_by->add_child(si); + } + found_libs.push_front(si); + + // When ld_preloads is not null first + // ld_preloads_size libs are in fact ld_preloads. + if (ld_preloads != nullptr && soinfos_size < ld_preloads_size) { + ld_preloads[soinfos_size] = si; + } + + if (soinfos_sizeflags & FLAG_LINKED) == 0) { + if (!si->LinkImage(extinfo)) { + return false; + } + si->flags |= FLAG_LINKED; + } + } + + // All is well - found_libs and load_tasks are empty at this point + // and all libs are successfully linked. + failure_guard.disable(); + return true; +} + +static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { + if (name == nullptr) { + somain->ref_count++; + return somain; + } + + soinfo* si; + + if (!find_libraries(&name, 1, &si, nullptr, 0, dlflags, extinfo)) { + return nullptr; + } + return si; } @@ -913,32 +1035,23 @@ static void soinfo_unload(soinfo* si) { si->CallDestructors(); if (si->has_min_version(0)) { - // It is not safe to do si->get_children().for_each, because - // during soinfo_free the child will concurrently modify the si->children - // list, therefore we create a copy and use it to unload children. - size_t children_count = si->get_children().size(); - soinfo* children[children_count]; - si->get_children().copy_to_array(children, children_count); - - for (size_t i = 0; i < children_count; ++i) { - TRACE("%s needs to unload %s", si->name, children[i]->name); - soinfo_unload(children[i]); + soinfo* child = nullptr; + while ((child = si->get_children().pop_front()) != nullptr) { + TRACE("%s needs to unload %s", si->name, child->name); + soinfo_unload(child); } } else { - for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { - if (d->d_tag == DT_NEEDED) { - const char* library_name = si->strtab + d->d_un.d_val; - TRACE("%s needs to unload %s", si->name, library_name); - soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); - if (needed != nullptr) { - soinfo_unload(needed); - } else { - // Not found: for example if symlink was deleted between dlopen and dlclose - // Since we cannot really handle errors at this point - print and continue. - PRINT("warning: couldn't find %s needed by %s on unload.", library_name, si->name); - } + for_each_dt_needed(si, [&] (const char* library_name) { + TRACE("deprecated (old format of soinfo): %s needs to unload %s", si->name, library_name); + soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); + if (needed != nullptr) { + soinfo_unload(needed); + } else { + // Not found: for example if symlink was deleted between dlopen and dlclose + // Since we cannot really handle errors at this point - print and continue. + PRINT("warning: couldn't find %s needed by %s on unload.", library_name, si->name); } - } + }); } notify_gdb_of_unload(si); @@ -1047,9 +1160,6 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count) #if defined(USE_RELA) int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { - ElfW(Sym)* s; - soinfo* lsi; - for (size_t idx = 0; idx < count; ++idx, ++rela) { unsigned type = ELFW(R_TYPE)(rela->r_info); unsigned sym = ELFW(R_SYM)(rela->r_info); @@ -1061,6 +1171,10 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { if (type == 0) { // R_*_NONE continue; } + + ElfW(Sym)* s = nullptr; + soinfo* lsi = nullptr; + if (sym != 0) { sym_name = reinterpret_cast(strtab + symtab[sym].st_name); s = soinfo_do_lookup(this, sym_name, &lsi); @@ -1119,8 +1233,6 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { sym_addr = static_cast(s->st_value + lsi->load_bias); } count_relocation(kRelocSymbol); - } else { - s = nullptr; } switch (type) { @@ -1314,9 +1426,6 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { #else // REL, not RELA. int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { - ElfW(Sym)* s; - soinfo* lsi; - for (size_t idx = 0; idx < count; ++idx, ++rel) { unsigned type = ELFW(R_TYPE)(rel->r_info); // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. @@ -1329,6 +1438,10 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { if (type == 0) { // R_*_NONE continue; } + + ElfW(Sym)* s = nullptr; + soinfo* lsi = nullptr; + if (sym != 0) { sym_name = reinterpret_cast(strtab + symtab[sym].st_name); s = soinfo_do_lookup(this, sym_name, &lsi); @@ -1390,8 +1503,6 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { sym_addr = static_cast(s->st_value + lsi->load_bias); } count_relocation(kRelocSymbol); - } else { - s = nullptr; } switch (type) { @@ -1546,7 +1657,7 @@ static bool mips_relocate_got(soinfo* si) { for (size_t g = gotsym; g < symtabno; g++, sym++, got++) { // This is an undefined reference... try to locate it. const char* sym_name = si->strtab + sym->st_name; - soinfo* lsi; + soinfo* lsi = nullptr; ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. @@ -1643,6 +1754,9 @@ void soinfo::CallConstructors() { } void soinfo::CallDestructors() { + if (!constructors_called) { + return; + } TRACE("\"%s\": calling destructors", name); // DT_FINI_ARRAY must be parsed in reverse order. @@ -1728,7 +1842,7 @@ bool soinfo::get_has_ifuncs() { return false; } -// This is a return on get_children() in case +// This is a return on get_children()/get_parents() if // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -1740,6 +1854,14 @@ soinfo::soinfo_list_t& soinfo::get_children() { return g_empty_list; } +soinfo::soinfo_list_t& soinfo::get_parents() { + if ((this->flags & FLAG_NEW_SOINFO) == 0) { + return g_empty_list; + } + + return this->parents; +} + /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -1801,20 +1923,18 @@ static int nullify_closed_stdio() { return return_value; } -bool soinfo::LinkImage(const android_dlextinfo* extinfo) { - bool relocating_linker = (flags & FLAG_LINKER) != 0; +bool soinfo::PrelinkImage() { + phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic); - /* We can't debug anything until the linker is relocated */ + /* We can't log anything until the linker is relocated */ + bool relocating_linker = (flags & FLAG_LINKER) != 0; if (!relocating_linker) { INFO("[ linking %s ]", name); DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast(base), flags); } /* Extract dynamic section */ - size_t dynamic_count; - ElfW(Word) dynamic_flags; - phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, - &dynamic_count, &dynamic_flags); + ElfW(Word) dynamic_flags = phdr->p_flags; if (dynamic == nullptr) { if (!relocating_linker) { DL_ERR("missing PT_DYNAMIC in \"%s\"", name); @@ -1882,7 +2002,7 @@ bool soinfo::LinkImage(const android_dlextinfo* extinfo) { // if the dynamic table is writable // FIXME: not working currently for N64 // The flags for the LOAD and DYNAMIC program headers do not agree. -// The LOAD section containng the dynamic table has been mapped as +// The LOAD section containing the dynamic table has been mapped as // read-only, but the DYNAMIC header claims it is writable. #if !(defined(__mips__) && defined(__LP64__)) if ((dynamic_flags & PF_W) != 0) { @@ -2028,38 +2148,10 @@ bool soinfo::LinkImage(const android_dlextinfo* extinfo) { DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name); return false; } + return true; +} - // If this is the main executable, then load all of the libraries from LD_PRELOAD now. - if (flags & FLAG_EXE) { - memset(g_ld_preloads, 0, sizeof(g_ld_preloads)); - size_t preload_count = 0; - for (size_t i = 0; g_ld_preload_names[i] != nullptr; i++) { - soinfo* lsi = find_library(g_ld_preload_names[i], 0, nullptr); - if (lsi != nullptr) { - g_ld_preloads[preload_count++] = lsi; - } else { - // As with glibc, failure to load an LD_PRELOAD library is just a warning. - DL_WARN("could not load library \"%s\" from LD_PRELOAD for \"%s\"; caused by %s", - g_ld_preload_names[i], name, linker_get_error_buffer()); - } - } - } - - for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { - if (d->d_tag == DT_NEEDED) { - const char* library_name = strtab + d->d_un.d_val; - DEBUG("%s needs %s", name, library_name); - soinfo* lsi = find_library(library_name, 0, nullptr); - if (lsi == nullptr) { - strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf)); - DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s", - library_name, name, tmp_err_buf); - return false; - } - - add_child(lsi); - } - } +bool soinfo::LinkImage(const android_dlextinfo* extinfo) { #if !defined(__LP64__) if (has_text_relocations) { @@ -2121,7 +2213,6 @@ bool soinfo::LinkImage(const android_dlextinfo* extinfo) { } #endif - flags |= FLAG_LINKED; DEBUG("[ finished linking %s ]", name); #if !defined(__LP64__) @@ -2183,6 +2274,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->size = phdr_table_get_load_size(si->phdr, si->phnum); si->load_bias = get_elf_exec_load_bias(ehdr_vdso); + si->PrelinkImage(); si->LinkImage(nullptr); #endif } @@ -2216,7 +2308,7 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) { ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_base); ElfW(Phdr)* phdr = reinterpret_cast(linker_base + elf_hdr->e_phoff); phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, - &linker_soinfo_for_gdb.dynamic, nullptr, nullptr); + &linker_soinfo_for_gdb.dynamic); insert_soinfo_into_debug_map(&linker_soinfo_for_gdb); } @@ -2312,6 +2404,37 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( somain = si; + si->PrelinkImage(); + + // Load ld_preloads and dependencies. + StringLinkedList needed_library_name_list; + size_t needed_libraries_count = 0; + size_t ld_preloads_count = 0; + while (g_ld_preload_names[ld_preloads_count] != nullptr) { + needed_library_name_list.push_back(g_ld_preload_names[ld_preloads_count++]); + ++needed_libraries_count; + } + + for_each_dt_needed(si, [&](const char* name) { + needed_library_name_list.push_back(name); + ++needed_libraries_count; + }); + + const char* needed_library_names[needed_libraries_count]; + soinfo* needed_library_si[needed_libraries_count]; + + memset(needed_library_names, 0, sizeof(needed_library_names)); + needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); + + if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, 0, nullptr)) { + __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); + exit(EXIT_FAILURE); + } + + for (size_t i = 0; iadd_child(needed_library_si[i]); + } + if (!si->LinkImage(nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); @@ -2321,11 +2444,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( si->CallPreInitConstructors(); - for (size_t i = 0; g_ld_preloads[i] != nullptr; ++i) { - g_ld_preloads[i]->CallConstructors(); - } - - /* After the LinkImage, the si->load_bias is initialized. + /* After the PrelinkImage, the si->load_bias is initialized. * For so lib, the map->l_addr will be updated in notify_gdb_of_load. * We need to update this value for so exe here. So Unwind_Backtrace * for some arch like x86 could work correctly within so exe. @@ -2440,7 +2559,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - if (!linker_so.LinkImage(nullptr)) { + if (!(linker_so.PrelinkImage() && linker_so.LinkImage(nullptr))) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as diff --git a/linker/linker.h b/linker/linker.h index 6547d685e..3024d3ab2 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -204,6 +204,7 @@ struct soinfo { void CallConstructors(); void CallDestructors(); void CallPreInitConstructors(); + bool PrelinkImage(); bool LinkImage(const android_dlextinfo* extinfo); void add_child(soinfo* child); @@ -217,6 +218,7 @@ struct soinfo { bool get_has_ifuncs(); soinfo_list_t& get_children(); + soinfo_list_t& get_parents(); bool inline has_min_version(uint32_t min_version) { return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index 1bbd57778..436517271 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -702,34 +702,17 @@ int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, * load_bias -> load bias * Output: * dynamic -> address of table in memory (null on failure). - * dynamic_count -> number of items in table (0 on failure). - * dynamic_flags -> protection flags for section (unset on failure) * Return: * void */ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count, - ElfW(Addr) load_bias, - ElfW(Dyn)** dynamic, size_t* dynamic_count, ElfW(Word)* dynamic_flags) { - const ElfW(Phdr)* phdr = phdr_table; - const ElfW(Phdr)* phdr_limit = phdr + phdr_count; - - for (phdr = phdr_table; phdr < phdr_limit; phdr++) { - if (phdr->p_type != PT_DYNAMIC) { - continue; - } - - *dynamic = reinterpret_cast(load_bias + phdr->p_vaddr); - if (dynamic_count) { - *dynamic_count = (unsigned)(phdr->p_memsz / 8); - } - if (dynamic_flags) { - *dynamic_flags = phdr->p_flags; - } - return; - } + ElfW(Addr) load_bias, ElfW(Dyn)** dynamic) { *dynamic = nullptr; - if (dynamic_count) { - *dynamic_count = 0; + for (const ElfW(Phdr)* phdr = phdr_table, *phdr_limit = phdr + phdr_count; phdr < phdr_limit; phdr++) { + if (phdr->p_type == PT_DYNAMIC) { + *dynamic = reinterpret_cast(load_bias + phdr->p_vaddr); + return; + } } } diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h index 50708a0e6..d4c3ce85f 100644 --- a/linker/linker_phdr.h +++ b/linker/linker_phdr.h @@ -101,7 +101,6 @@ int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, El #endif void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count, - ElfW(Addr) load_bias, - ElfW(Dyn)** dynamic, size_t* dynamic_count, ElfW(Word)* dynamic_flags); + ElfW(Addr) load_bias, ElfW(Dyn)** dynamic); #endif /* LINKER_PHDR_H */ diff --git a/linker/tests/linked_list_test.cpp b/linker/tests/linked_list_test.cpp index a555edb33..09ad68766 100644 --- a/linker/tests/linked_list_test.cpp +++ b/linker/tests/linked_list_test.cpp @@ -139,7 +139,6 @@ TEST(linked_list, copy_to_array) { const char* buf[max_size]; memset(buf, 0, sizeof(buf)); - ASSERT_EQ(0U, list.size()); ASSERT_EQ(0U, list.copy_to_array(buf, max_size)); ASSERT_EQ(nullptr, buf[0]); @@ -149,7 +148,6 @@ TEST(linked_list, copy_to_array) { list.push_back("d"); memset(buf, 0, sizeof(buf)); - ASSERT_EQ(4U, list.size()); ASSERT_EQ(2U, list.copy_to_array(buf, 2)); ASSERT_STREQ("a", buf[0]); ASSERT_STREQ("b", buf[1]); @@ -166,7 +164,6 @@ TEST(linked_list, copy_to_array) { list.remove_if([](const char* c) { return *c != 'c'; }); - ASSERT_EQ(1U, list.size()); ASSERT_EQ(1U, list.copy_to_array(buf, max_size)); ASSERT_STREQ("c", buf[0]); ASSERT_EQ(nullptr, buf[1]); @@ -177,7 +174,6 @@ TEST(linked_list, copy_to_array) { return *c == 'c'; }); - ASSERT_EQ(0U, list.size()); ASSERT_EQ(0U, list.copy_to_array(buf, max_size)); ASSERT_EQ(nullptr, buf[0]); } diff --git a/tests/Android.mk b/tests/Android.mk index 38509654c..69ff8110a 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -112,6 +112,7 @@ libBionicStandardTests_src_files := \ system_properties_test.cpp \ time_test.cpp \ uchar_test.cpp \ + uniqueptr_test.cpp \ unistd_test.cpp \ wchar_test.cpp \ diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 15ba3414c..fb3bfc511 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -158,6 +158,55 @@ TEST(dlfcn, dlopen_check_relocation_dt_needed_order) { ASSERT_EQ(1, fn()); } +TEST(dlfcn, dlopen_check_order) { + // Here is how the test library and its dt_needed + // libraries are arranged + // + // libtest_check_order.so + // | + // +-> libtest_check_order_1_left.so + // | | + // | +-> libtest_check_order_a.so + // | | + // | +-> libtest_check_order_b.so + // | + // +-> libtest_check_order_2_right.so + // | | + // | +-> libtest_check_order_d.so + // | | + // | +-> libtest_check_order_b.so + // | + // +-> libtest_check_order_3_c.so + // + // load order should be (1, 2, 3, a, b, d) + // + // get_answer() is defined in (2, 3, a, b, c) + // get_answer2() is defined in (b, d) + void* sym = dlsym(RTLD_DEFAULT, "dlopen_test_get_answer"); + ASSERT_TRUE(sym == nullptr); + void* handle = dlopen("libtest_check_order.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr); + typedef int (*fn_t) (void); + fn_t fn, fn2; + fn = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer")); + ASSERT_TRUE(fn != NULL); + fn2 = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer2")); + ASSERT_TRUE(fn2 != NULL); + + ASSERT_EQ(42, fn()); + ASSERT_EQ(43, fn2()); + dlclose(handle); +} + +// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> +// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so -> +// libtest_with_dependency_loop_a.so +TEST(dlfcn, dlopen_check_loop) { + void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW); + ASSERT_TRUE(handle == NULL); + ASSERT_STREQ("dlopen failed: recursive link to \"libtest_with_dependency_loop_a.so\"", dlerror()); +} + TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 20bc263b0..21681eec9 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -101,6 +101,160 @@ build_type := target build_target := SHARED_LIBRARY include $(TEST_PATH)/Android.build.mk +# ----------------------------------------------------------------------------- +# Libraries used by dlfcn tests to verify correct load order: +# libtest_check_order_2_right.so +# ----------------------------------------------------------------------------- +libtest_check_order_2_right_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_2_right_cflags := -D__ANSWER=42 +module := libtest_check_order_2_right +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_a.so +# ----------------------------------------------------------------------------- +libtest_check_order_a_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_a_cflags := -D__ANSWER=1 +module := libtest_check_order_a +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_b.so +# ----------------------------------------------------------------------------- +libtest_check_order_b_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 +module := libtest_check_order_b +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_c.so +# ----------------------------------------------------------------------------- +libtest_check_order_3_c_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_3_c_cflags := -D__ANSWER=3 +module := libtest_check_order_3_c +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_d.so +# ----------------------------------------------------------------------------- +libtest_check_order_d_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_d_shared_libraries := libtest_check_order_b +libtest_check_order_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 +module := libtest_check_order_d +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_left.so +# ----------------------------------------------------------------------------- +libtest_check_order_1_left_src_files := \ + empty.cpp + +libtest_check_order_1_left_shared_libraries := libtest_check_order_a libtest_check_order_b + +module := libtest_check_order_1_left +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order.so +# ----------------------------------------------------------------------------- +libtest_check_order_src_files := \ + empty.cpp + +libtest_check_order_shared_libraries := libtest_check_order_1_left \ + libtest_check_order_2_right libtest_check_order_3_c + +module := libtest_check_order +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# Library with dependency loop used by dlfcn tests +# +# libtest_with_dependency_loop -> a -> b -> c -> a +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_src_files := empty.cpp + +libtest_with_dependency_loop_shared_libraries := \ + libtest_with_dependency_loop_a + +module := libtest_with_dependency_loop +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_a.so +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_a_src_files := empty.cpp + +libtest_with_dependency_loop_a_shared_libraries := \ + libtest_with_dependency_loop_b_tmp + +module := libtest_with_dependency_loop_a +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_b.so +# +# this is temporary placeholder - will be removed +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_b_tmp_src_files := empty.cpp +libtest_with_dependency_loop_b_tmp_ldflags := -Wl,-soname=libtest_with_dependency_loop_b.so + +module := libtest_with_dependency_loop_b_tmp +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_b.so +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_b_src_files := empty.cpp +libtest_with_dependency_loop_b_shared_libraries := libtest_with_dependency_loop_c + +module := libtest_with_dependency_loop_b +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_c.so +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_c_src_files := empty.cpp + +libtest_with_dependency_loop_c_shared_libraries := \ + libtest_with_dependency_loop_a + +module := libtest_with_dependency_loop_c +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + # ----------------------------------------------------------------------------- # libtest_relo_check_dt_needed_order.so # | diff --git a/tests/libs/dlopen_testlib_answer.cpp b/tests/libs/dlopen_testlib_answer.cpp new file mode 100644 index 000000000..a4d75046e --- /dev/null +++ b/tests/libs/dlopen_testlib_answer.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int dlopen_test_get_answer() { + return __ANSWER; +} + +#ifdef __ANSWER2 +extern "C" int dlopen_test_get_answer2() { + return __ANSWER2; +} +#endif diff --git a/tests/uniqueptr_test.cpp b/tests/uniqueptr_test.cpp new file mode 100644 index 000000000..4b6608af2 --- /dev/null +++ b/tests/uniqueptr_test.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +static int cCount = 0; +struct C { + C() { ++cCount; } + ~C() { --cCount; } +}; + +static bool freed = false; +struct Freer { + void operator() (int* p) { + ASSERT_EQ(123, *p); + free(p); + freed = true; + } +}; + +TEST(UniquePtr, smoke) { + // + // UniquePtr tests... + // + + // Can we free a single object? + { + UniquePtr c(new C); + ASSERT_TRUE(cCount == 1); + } + ASSERT_TRUE(cCount == 0); + // Does release work? + C* rawC; + { + UniquePtr c(new C); + ASSERT_TRUE(cCount == 1); + rawC = c.release(); + } + ASSERT_TRUE(cCount == 1); + delete rawC; + // Does reset work? + { + UniquePtr c(new C); + ASSERT_TRUE(cCount == 1); + c.reset(new C); + ASSERT_TRUE(cCount == 1); + } + ASSERT_TRUE(cCount == 0); + + // + // UniquePtr tests... + // + + // Can we free an array? + { + UniquePtr cs(new C[4]); + ASSERT_TRUE(cCount == 4); + } + ASSERT_TRUE(cCount == 0); + // Does release work? + { + UniquePtr c(new C[4]); + ASSERT_TRUE(cCount == 4); + rawC = c.release(); + } + ASSERT_TRUE(cCount == 4); + delete[] rawC; + // Does reset work? + { + UniquePtr c(new C[4]); + ASSERT_TRUE(cCount == 4); + c.reset(new C[2]); + ASSERT_TRUE(cCount == 2); + } + ASSERT_TRUE(cCount == 0); + + // + // Custom deleter tests... + // + ASSERT_TRUE(!freed); + { + UniquePtr i(reinterpret_cast(malloc(sizeof(int)))); + *i = 123; + } + ASSERT_TRUE(freed); +} From 61c4147fa8c8abb33ae6fecb85dd1ae1b60e1ed6 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 4 Sep 2014 12:47:07 -0700 Subject: [PATCH 022/114] Reset enviroment for math_tests Bug: 17390824 (cherry picked from commit 7b956ede3f0f40bd8a085a8ad3729bb3e0e030f2) Change-Id: I5d804ceb5e69533584161bfed6787529cd8296fb --- tests/math_test.cpp | 37 +++++++++++++++++++++++++++++++++++++ tests/string_test.cpp | 18 +++++++++--------- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/tests/math_test.cpp b/tests/math_test.cpp index b4f5b1427..ad4654e53 100644 --- a/tests/math_test.cpp +++ b/tests/math_test.cpp @@ -53,6 +53,8 @@ template inline int test_capture_isinf(const T in) { #include #include +#include + float float_subnormal() { union { float f; @@ -760,6 +762,10 @@ TEST(math, erfcl) { } TEST(math, lrint) { + auto guard = create_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); + fesetround(FE_UPWARD); // lrint/lrintf/lrintl obey the rounding mode. ASSERT_EQ(1235, lrint(1234.01)); ASSERT_EQ(1235, lrintf(1234.01f)); @@ -780,6 +786,10 @@ TEST(math, lrint) { } TEST(math, rint) { + auto guard = create_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); + fesetround(FE_UPWARD); // rint/rintf/rintl obey the rounding mode. feclearexcept(FE_ALL_EXCEPT); // rint/rintf/rintl do set the FE_INEXACT flag. ASSERT_EQ(1234.0, rint(1234.0)); @@ -806,6 +816,9 @@ TEST(math, rint) { } TEST(math, nearbyint) { + auto guard = create_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // nearbyint/nearbyintf/nearbyintl obey the rounding mode. feclearexcept(FE_ALL_EXCEPT); // nearbyint/nearbyintf/nearbyintl don't set the FE_INEXACT flag. ASSERT_EQ(1234.0, nearbyint(1234.0)); @@ -832,6 +845,9 @@ TEST(math, nearbyint) { } TEST(math, lround) { + auto guard = create_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // lround ignores the rounding mode. ASSERT_EQ(1234, lround(1234.01)); ASSERT_EQ(1234, lroundf(1234.01f)); @@ -839,6 +855,9 @@ TEST(math, lround) { } TEST(math, llround) { + auto guard = create_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // llround ignores the rounding mode. ASSERT_EQ(1234L, llround(1234.01)); ASSERT_EQ(1234L, llroundf(1234.01f)); @@ -933,6 +952,9 @@ TEST(math, fdiml) { } TEST(math, round) { + auto guard = create_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_TOWARDZERO); // round ignores the rounding mode and always rounds away from zero. ASSERT_DOUBLE_EQ(1.0, round(0.5)); ASSERT_DOUBLE_EQ(-1.0, round(-0.5)); @@ -943,6 +965,9 @@ TEST(math, round) { } TEST(math, roundf) { + auto guard = create_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_TOWARDZERO); // roundf ignores the rounding mode and always rounds away from zero. ASSERT_FLOAT_EQ(1.0f, roundf(0.5f)); ASSERT_FLOAT_EQ(-1.0f, roundf(-0.5f)); @@ -953,6 +978,9 @@ TEST(math, roundf) { } TEST(math, roundl) { + auto guard = create_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_TOWARDZERO); // roundl ignores the rounding mode and always rounds away from zero. ASSERT_DOUBLE_EQ(1.0L, roundl(0.5L)); ASSERT_DOUBLE_EQ(-1.0L, roundl(-0.5L)); @@ -963,6 +991,9 @@ TEST(math, roundl) { } TEST(math, trunc) { + auto guard = create_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // trunc ignores the rounding mode and always rounds toward zero. ASSERT_DOUBLE_EQ(1.0, trunc(1.5)); ASSERT_DOUBLE_EQ(-1.0, trunc(-1.5)); @@ -973,6 +1004,9 @@ TEST(math, trunc) { } TEST(math, truncf) { + auto guard = create_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // truncf ignores the rounding mode and always rounds toward zero. ASSERT_FLOAT_EQ(1.0f, truncf(1.5f)); ASSERT_FLOAT_EQ(-1.0f, truncf(-1.5f)); @@ -983,6 +1017,9 @@ TEST(math, truncf) { } TEST(math, truncl) { + auto guard = create_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // truncl ignores the rounding mode and always rounds toward zero. ASSERT_DOUBLE_EQ(1.0L, truncl(1.5L)); ASSERT_DOUBLE_EQ(-1.0L, truncl(-1.5L)); diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 73c94c602..f1ac9ddb4 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -173,7 +173,7 @@ struct StringTestState { const size_t MAX_LEN; Character *ptr, *ptr1, *ptr2; size_t n; - int len[ITER + 1]; + size_t len[ITER + 1]; private: Character *glob_ptr, *glob_ptr1, *glob_ptr2; @@ -186,7 +186,7 @@ struct StringTestState { n = 0; len[n++] = 0; for (size_t i = 1; i < ITER; ++i) { - int l = (int) exp(log((double) MAX_LEN) * i / ITER); + size_t l = static_cast(exp(log(static_cast(MAX_LEN)) * i / ITER)); if (l != len[n - 1]) { len[n++] = l; } @@ -392,7 +392,7 @@ TEST(string, strchr) { } state.ptr1[state.len[i] - 1] = '\0'; - int pos = random() % state.MAX_LEN; + size_t pos = random() % state.MAX_LEN; char* expected; if (pos >= state.len[i] - 1) { if (seek_char == 0) { @@ -421,7 +421,7 @@ TEST(string, strcmp) { state.ptr1[state.len[i] - 1] = '\0'; state.ptr2[state.len[i] - 1] = '\0'; - int pos = 1 + (random() % (state.MAX_LEN - 1)); + size_t pos = 1 + (random() % (state.MAX_LEN - 1)); int actual; int expected; if (pos >= state.len[i] - 1) { @@ -510,7 +510,7 @@ TEST(string, strlcat) { state.ptr2[state.MAX_LEN - 1] = '\0'; memcpy(state.ptr, state.ptr2, state.MAX_LEN + state.len[i]); - int pos = random() % state.MAX_LEN; + size_t pos = random() % state.MAX_LEN; memset(state.ptr1, '\3', pos); state.ptr1[pos] = '\0'; if (pos < state.len[i]) { @@ -604,7 +604,7 @@ TEST(string, strncmp) { state.ptr1[state.len[i] - 1] = '\0'; state.ptr2[state.len[i] - 1] = '\0'; - int pos = 1 + (random() % (state.MAX_LEN - 1)); + size_t pos = 1 + (random() % (state.MAX_LEN - 1)); int actual; int expected; if (pos >= state.len[i] - 1) { @@ -722,7 +722,7 @@ TEST(string, strrchr) { } state.ptr1[state.len[i] - 1] = '\0'; - int pos = random() % state.MAX_LEN; + size_t pos = random() % state.MAX_LEN; char* expected; if (pos >= state.len[i] - 1) { if (seek_char == 0) { @@ -749,7 +749,7 @@ TEST(string, memchr) { memset(state.ptr1, ~seek_char, state.len[i]); - int pos = random() % state.MAX_LEN; + size_t pos = random() % state.MAX_LEN; char* expected; if (pos >= state.len[i]) { expected = NULL; @@ -780,7 +780,7 @@ TEST(string, memrchr) { memset(state.ptr1, ~seek_char, state.len[i]); - int pos = random() % state.MAX_LEN; + size_t pos = random() % state.MAX_LEN; char* expected; if (pos >= state.len[i]) { expected = NULL; From ef1306d77718cc74a8df5673a15649dea317571d Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 8 Sep 2014 16:22:22 -0700 Subject: [PATCH 023/114] Refactoring: C++11 style DISABLE_ bionic marcos Enable the -std=gnu++11 flag for libstdc++ static and dynamic libs. ScopeGuard uses DISABLE_ macros instead of '= delete'; (cherry picked from commit d9ff7226613014056c9edd79a68dc5af939107a0) Change-Id: If2573d080770e18b36b56106f2369f7bb682cd3c --- libc/Android.mk | 2 ++ libc/private/ScopeGuard.h | 14 +++++++------- libc/private/bionic_macros.h | 6 +++--- linker/linker.cpp | 2 +- tests/dlfcn_test.cpp | 2 +- tests/math_test.cpp | 22 +++++++++++----------- tests/pthread_test.cpp | 2 +- 7 files changed, 26 insertions(+), 24 deletions(-) diff --git a/libc/Android.mk b/libc/Android.mk index fe1f31577..92ead2637 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -1164,6 +1164,7 @@ libstdcxx_common_src_files := \ include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(libc_common_c_includes) LOCAL_CFLAGS := $(libc_common_cflags) +LOCAL_CPPFLAGS := $(libc_common_cppflags) LOCAL_SRC_FILES := $(libstdcxx_common_src_files) LOCAL_MODULE:= libstdc++ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk @@ -1176,6 +1177,7 @@ include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(libc_common_c_includes) LOCAL_CFLAGS := $(libc_common_cflags) +LOCAL_CPPFLAGS := $(libc_common_cppflags) LOCAL_SRC_FILES := $(libstdcxx_common_src_files) LOCAL_MODULE:= libstdc++ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk diff --git a/libc/private/ScopeGuard.h b/libc/private/ScopeGuard.h index 183e322f7..d5a9235d1 100644 --- a/libc/private/ScopeGuard.h +++ b/libc/private/ScopeGuard.h @@ -14,8 +14,10 @@ * limitations under the License. */ -#ifndef SCOPE_GUARD_H -#define SCOPE_GUARD_H +#ifndef _SCOPE_GUARD_H +#define _SCOPE_GUARD_H + +#include "private/bionic_macros.h" // TODO: include explicit std::move when it becomes available template @@ -40,14 +42,12 @@ class ScopeGuard { F f_; bool active_; - ScopeGuard() = delete; - ScopeGuard(const ScopeGuard&) = delete; - ScopeGuard& operator=(const ScopeGuard&) = delete; + DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeGuard); }; template -ScopeGuard create_scope_guard(T f) { +ScopeGuard make_scope_guard(T f) { return ScopeGuard(f); } -#endif // SCOPE_GUARD_H +#endif // _SCOPE_GUARD_H diff --git a/libc/private/bionic_macros.h b/libc/private/bionic_macros.h index 61794bd54..491b3ace0 100644 --- a/libc/private/bionic_macros.h +++ b/libc/private/bionic_macros.h @@ -20,8 +20,8 @@ // DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions. // It goes in the private: declarations in a class. #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) + TypeName(const TypeName&) = delete; \ + void operator=(const TypeName&) = delete // A macro to disallow all the implicit constructors, namely the // default constructor, copy constructor and operator= functions. @@ -30,7 +30,7 @@ // that wants to prevent anyone from instantiating it. This is // especially useful for classes containing only static methods. #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ - TypeName(); \ + TypeName() = delete; \ DISALLOW_COPY_AND_ASSIGN(TypeName) #define BIONIC_ALIGN(value, alignment) \ diff --git a/linker/linker.cpp b/linker/linker.cpp index 793ffd51e..f436e85bd 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -955,7 +955,7 @@ static bool find_libraries(const char* const library_names[], size_t library_nam SoinfoLinkedList found_libs; size_t soinfos_size = 0; - auto failure_guard = create_scope_guard([&]() { + auto failure_guard = make_scope_guard([&]() { // Housekeeping load_tasks.for_each([] (LoadTask* t) { LoadTask::deleter(t); diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index fb3bfc511..bb9d8c0b8 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -145,7 +145,7 @@ TEST(dlfcn, dlopen_check_relocation_dt_needed_order) { // in both dt_needed libraries, the correct relocation should // use the function defined in libtest_relo_check_dt_needed_order_1.so void* handle = nullptr; - auto guard = create_scope_guard([&]() { + auto guard = make_scope_guard([&]() { dlclose(handle); }); diff --git a/tests/math_test.cpp b/tests/math_test.cpp index ad4654e53..2203db9f4 100644 --- a/tests/math_test.cpp +++ b/tests/math_test.cpp @@ -762,7 +762,7 @@ TEST(math, erfcl) { } TEST(math, lrint) { - auto guard = create_scope_guard([]() { + auto guard = make_scope_guard([]() { fesetenv(FE_DFL_ENV); }); @@ -786,7 +786,7 @@ TEST(math, lrint) { } TEST(math, rint) { - auto guard = create_scope_guard([]() { + auto guard = make_scope_guard([]() { fesetenv(FE_DFL_ENV); }); @@ -816,7 +816,7 @@ TEST(math, rint) { } TEST(math, nearbyint) { - auto guard = create_scope_guard([]() { + auto guard = make_scope_guard([]() { fesetenv(FE_DFL_ENV); }); fesetround(FE_UPWARD); // nearbyint/nearbyintf/nearbyintl obey the rounding mode. @@ -845,7 +845,7 @@ TEST(math, nearbyint) { } TEST(math, lround) { - auto guard = create_scope_guard([]() { + auto guard = make_scope_guard([]() { fesetenv(FE_DFL_ENV); }); fesetround(FE_UPWARD); // lround ignores the rounding mode. @@ -855,7 +855,7 @@ TEST(math, lround) { } TEST(math, llround) { - auto guard = create_scope_guard([]() { + auto guard = make_scope_guard([]() { fesetenv(FE_DFL_ENV); }); fesetround(FE_UPWARD); // llround ignores the rounding mode. @@ -952,7 +952,7 @@ TEST(math, fdiml) { } TEST(math, round) { - auto guard = create_scope_guard([]() { + auto guard = make_scope_guard([]() { fesetenv(FE_DFL_ENV); }); fesetround(FE_TOWARDZERO); // round ignores the rounding mode and always rounds away from zero. @@ -965,7 +965,7 @@ TEST(math, round) { } TEST(math, roundf) { - auto guard = create_scope_guard([]() { + auto guard = make_scope_guard([]() { fesetenv(FE_DFL_ENV); }); fesetround(FE_TOWARDZERO); // roundf ignores the rounding mode and always rounds away from zero. @@ -978,7 +978,7 @@ TEST(math, roundf) { } TEST(math, roundl) { - auto guard = create_scope_guard([]() { + auto guard = make_scope_guard([]() { fesetenv(FE_DFL_ENV); }); fesetround(FE_TOWARDZERO); // roundl ignores the rounding mode and always rounds away from zero. @@ -991,7 +991,7 @@ TEST(math, roundl) { } TEST(math, trunc) { - auto guard = create_scope_guard([]() { + auto guard = make_scope_guard([]() { fesetenv(FE_DFL_ENV); }); fesetround(FE_UPWARD); // trunc ignores the rounding mode and always rounds toward zero. @@ -1004,7 +1004,7 @@ TEST(math, trunc) { } TEST(math, truncf) { - auto guard = create_scope_guard([]() { + auto guard = make_scope_guard([]() { fesetenv(FE_DFL_ENV); }); fesetround(FE_UPWARD); // truncf ignores the rounding mode and always rounds toward zero. @@ -1017,7 +1017,7 @@ TEST(math, truncf) { } TEST(math, truncl) { - auto guard = create_scope_guard([]() { + auto guard = make_scope_guard([]() { fesetenv(FE_DFL_ENV); }); fesetround(FE_UPWARD); // truncl ignores the rounding mode and always rounds toward zero. diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp index 4a7c6bd88..32bb54c5d 100644 --- a/tests/pthread_test.cpp +++ b/tests/pthread_test.cpp @@ -869,7 +869,7 @@ TEST(pthread, pthread_attr_getstack__main_thread) { #endif EXPECT_EQ(rl.rlim_cur, stack_size); - auto guard = create_scope_guard([&rl, original_rlim_cur]() { + auto guard = make_scope_guard([&rl, original_rlim_cur]() { rl.rlim_cur = original_rlim_cur; ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl)); }); From f4cb6313645ef65cc0eea0a439e51b6788cd3439 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 11 Sep 2014 15:16:03 -0700 Subject: [PATCH 024/114] Add IFUNC support for arm64 and IRELATIVE reloc There are number of changes in the way IFUNC related relocations are done: 1. IRELATIVE relocations are now supported for x86/x86_64 and arm64. 2. IFUNC relocations are now relying on static linker to generate them in correct order - this removes necessety of additional relocation pass for ifuncs. 3. Related to 2: rela?.dyn relocations are preformed before .plt ones. 4. Ifunc are resolved on symbol lookup this approach allowed to avoid mprotect(PROT_WRITE) call on r-x program segments. Bug: 17399706 Bug: 17177284 (cherry picked from commit 9aea164457c269c475592da36b4655d45f55c7bc) Change-Id: Ie19d900fc203beb93faf8943b0d06d534a6de4ad --- libc/arch-arm64/include/machine/elf_machdep.h | 1 + libc/arch-x86/include/machine/elf_machdep.h | 1 + .../arch-x86_64/include/machine/elf_machdep.h | 2 + linker/dlfcn.cpp | 4 +- linker/linker.cpp | 174 ++++++------------ linker/linker.h | 8 +- tests/Android.build.mk | 4 + tests/dlfcn_test.cpp | 14 +- tests/libs/Android.mk | 10 +- tests/libs/dlopen_testlib_ifunc.c | 11 +- 10 files changed, 95 insertions(+), 134 deletions(-) diff --git a/libc/arch-arm64/include/machine/elf_machdep.h b/libc/arch-arm64/include/machine/elf_machdep.h index 2bf818920..6eab31327 100644 --- a/libc/arch-arm64/include/machine/elf_machdep.h +++ b/libc/arch-arm64/include/machine/elf_machdep.h @@ -99,6 +99,7 @@ #define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */ #define R_AARCH64_TLS_TPREL64 1030 #define R_AARCH64_TLS_DTPREL32 1031 +#define R_AARCH64_IRELATIVE 1032 #define R_TYPE(name) __CONCAT(R_AARCH64_,name) diff --git a/libc/arch-x86/include/machine/elf_machdep.h b/libc/arch-x86/include/machine/elf_machdep.h index 442c561a9..4bce933b8 100644 --- a/libc/arch-x86/include/machine/elf_machdep.h +++ b/libc/arch-x86/include/machine/elf_machdep.h @@ -59,5 +59,6 @@ #define R_386_TLS_GOTDESC 39 #define R_386_TLS_DESC_CALL 40 #define R_386_TLS_DESC 41 +#define R_386_IRELATIVE 42 #define R_TYPE(name) __CONCAT(R_386_,name) diff --git a/libc/arch-x86_64/include/machine/elf_machdep.h b/libc/arch-x86_64/include/machine/elf_machdep.h index 20f8c6d96..bf1f2739e 100644 --- a/libc/arch-x86_64/include/machine/elf_machdep.h +++ b/libc/arch-x86_64/include/machine/elf_machdep.h @@ -46,6 +46,8 @@ #define R_X86_64_GOTTPOFF 22 #define R_X86_64_TPOFF32 23 +#define R_X86_64_IRELATIVE 37 + #define R_TYPE(name) __CONCAT(R_X86_64_,name) #else /* !__i386__ */ diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 3024b3c29..9801fa172 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -118,7 +118,7 @@ void* dlsym(void* handle, const char* symbol) { unsigned bind = ELF_ST_BIND(sym->st_info); if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) { - return reinterpret_cast(sym->st_value + found->load_bias); + return reinterpret_cast(found->resolve_symbol_address(sym)); } __bionic_format_dlerror("symbol found but not global", symbol); @@ -148,7 +148,7 @@ int dladdr(const void* addr, Dl_info* info) { ElfW(Sym)* sym = dladdr_find_symbol(si, addr); if (sym != nullptr) { info->dli_sname = si->strtab + sym->st_name; - info->dli_saddr = reinterpret_cast(si->load_bias + sym->st_value); + info->dli_saddr = reinterpret_cast(si->resolve_symbol_address(sym)); } return 1; diff --git a/linker/linker.cpp b/linker/linker.cpp index f436e85bd..1b4fb6201 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -470,32 +470,6 @@ soinfo::soinfo(const char* name, const struct stat* file_stat) { } } -void soinfo::resolve_ifunc_symbols() { - if (!get_has_ifuncs()) { - return; - } - - phdr_table_unprotect_segments(phdr, phnum, load_bias); - - TRACE_TYPE(IFUNC, "CHECKING FOR IFUNCS AND PERFORMING SYMBOL UPDATES"); - - for (size_t i = 0; i < nchain; ++i) { - ElfW(Sym)* s = &symtab[i]; - if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { - // The address of the ifunc in the symbol table is the address of the - // function that chooses the function to which the ifunc will refer. - // In order to return the proper value, we run the choosing function - // in the linker and then return its result (minus the base offset). - TRACE_TYPE(IFUNC, "FOUND IFUNC"); - ElfW(Addr) (*ifunc_ptr)(); - ifunc_ptr = reinterpret_cast(s->st_value + base); - s->st_value = (ifunc_ptr() - base); - TRACE_TYPE(IFUNC, "NEW VALUE IS %p", (void*)s->st_value); - } - } - phdr_table_protect_segments(phdr, phnum, load_bias); -} - static unsigned elfhash(const char* _name) { const unsigned char* name = reinterpret_cast(_name); unsigned h = 0, g; @@ -1111,52 +1085,14 @@ void do_dlclose(soinfo* si) { protect_data(PROT_READ); } -// ifuncs are only defined for x86 -#if defined(__i386__) -static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count) { - for (size_t idx = 0; idx < count; ++idx, ++rel) { - ElfW(Sym)* s; - soinfo* lsi; - unsigned type = ELFW(R_TYPE)(rel->r_info); - unsigned sym = ELFW(R_SYM)(rel->r_info); - ElfW(Addr) reloc = static_cast(rel->r_offset + si->load_bias); - ElfW(Addr) sym_addr = 0; - const char* sym_name = nullptr; - sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); - s = soinfo_do_lookup(si, sym_name, &lsi); +static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) { + typedef ElfW(Addr) (*ifunc_resolver_t)(void); + ifunc_resolver_t ifunc_resolver = reinterpret_cast(resolver_addr); + ElfW(Addr) ifunc_addr = ifunc_resolver(); + TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p", ifunc_resolver, reinterpret_cast(ifunc_addr)); - if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_386_JMP_SLOT) { - TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr)); - ElfW(Addr) (*ifunc_ptr)(); - ifunc_ptr = reinterpret_cast(s->st_value + si->base); - *reinterpret_cast(reloc) = ifunc_ptr(); - } - } + return ifunc_addr; } -#endif - -#if defined(__x86_64__) -static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count) { - for (size_t idx = 0; idx < count; ++idx, ++rela) { - ElfW(Sym)* s; - soinfo* lsi; - unsigned type = ELFW(R_TYPE)(rela->r_info); - unsigned sym = ELFW(R_SYM)(rela->r_info); - ElfW(Addr) reloc = static_cast(rela->r_offset + si->load_bias); - ElfW(Addr) sym_addr = 0; - const char* sym_name = nullptr; - sym_name = reinterpret_cast(si->strtab + si->symtab[sym].st_name); - s = soinfo_do_lookup(si, sym_name, &lsi); - - if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_X86_64_JUMP_SLOT) { - TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr + rela->r_addend)); - ElfW(Addr) (*ifunc_ptr)(); - ifunc_ptr = reinterpret_cast(s->st_value + si->base); - *reinterpret_cast(reloc) = ifunc_ptr(); - } - } -} -#endif #if defined(USE_RELA) int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { @@ -1206,6 +1142,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { case R_AARCH64_ABS32: case R_AARCH64_ABS16: case R_AARCH64_RELATIVE: + case R_AARCH64_IRELATIVE: /* * The sym_addr was initialized to be zero above, or the relocation * code below does not care about value of sym_addr. @@ -1218,6 +1155,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { case R_X86_64_32: case R_X86_64_64: case R_X86_64_RELATIVE: + case R_X86_64_IRELATIVE: // No need to do anything. break; case R_X86_64_PC32: @@ -1230,7 +1168,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { } } else { // We got a definition. - sym_addr = static_cast(s->st_value + lsi->load_bias); + sym_addr = lsi->resolve_symbol_address(s); } count_relocation(kRelocSymbol); } @@ -1342,6 +1280,13 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { *reinterpret_cast(reloc) = (base + rela->r_addend); break; + case R_AARCH64_IRELATIVE: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend)); + *reinterpret_cast(reloc) = call_ifunc_resolver(base + rela->r_addend); + break; + case R_AARCH64_COPY: /* * ET_EXEC is not supported so this should not happen. @@ -1368,11 +1313,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { MARK(rela->r_offset); TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast(reloc), static_cast(sym_addr + rela->r_addend), sym_name); - if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { - set_has_ifuncs(true); - } else { - *reinterpret_cast(reloc) = sym_addr + rela->r_addend; - } + *reinterpret_cast(reloc) = sym_addr + rela->r_addend; break; case R_X86_64_GLOB_DAT: count_relocation(kRelocAbsolute); @@ -1392,6 +1333,12 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { static_cast(base)); *reinterpret_cast(reloc) = base + rela->r_addend; break; + case R_X86_64_IRELATIVE: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend)); + *reinterpret_cast(reloc) = call_ifunc_resolver(base + rela->r_addend); + break; case R_X86_64_32: count_relocation(kRelocRelative); MARK(rela->r_offset); @@ -1481,6 +1428,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { case R_386_GLOB_DAT: case R_386_32: case R_386_RELATIVE: /* Don't care. */ + case R_386_IRELATIVE: // sym_addr was initialized to be zero above or relocation // code below does not care about value of sym_addr. // No need to do anything. @@ -1500,7 +1448,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { } } else { // We got a definition. - sym_addr = static_cast(s->st_value + lsi->load_bias); + sym_addr = lsi->resolve_symbol_address(s); } count_relocation(kRelocSymbol); } @@ -1549,11 +1497,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { count_relocation(kRelocAbsolute); MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); - if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { - set_has_ifuncs(true); - } else { - *reinterpret_cast(reloc) = sym_addr; - } + *reinterpret_cast(reloc) = sym_addr; break; case R_386_GLOB_DAT: count_relocation(kRelocAbsolute); @@ -1614,6 +1558,14 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { reinterpret_cast(reloc), reinterpret_cast(base)); *reinterpret_cast(reloc) += base; break; +#if defined(__i386__) + case R_386_IRELATIVE: + count_relocation(kRelocRelative); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO IRELATIVE %p <- %p", reinterpret_cast(reloc), reinterpret_cast(base)); + *reinterpret_cast(reloc) = call_ifunc_resolver(base + *reinterpret_cast(reloc)); + break; +#endif default: DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx); @@ -1671,7 +1623,7 @@ static bool mips_relocate_got(soinfo* si) { // FIXME: is this sufficient? // For reference see NetBSD link loader // http://cvsweb.netbsd.org/bsdweb.cgi/src/libexec/ld.elf_so/arch/mips/mips_reloc.c?rev=1.53&content-type=text/x-cvsweb-markup - *got = reinterpret_cast(lsi->load_bias + s->st_value); + *got = reinterpret_cast(lsi->resolve_symbol_address(s)); } } return true; @@ -1749,8 +1701,6 @@ void soinfo::CallConstructors() { // DT_INIT should be called before DT_INIT_ARRAY if both are present. CallFunction("DT_INIT", init_func); CallArray("DT_INIT_ARRAY", init_array, init_array_count, false); - - resolve_ifunc_symbols(); } void soinfo::CallDestructors() { @@ -1812,12 +1762,6 @@ void soinfo::set_st_ino(ino_t ino) { } } -void soinfo::set_has_ifuncs(bool ifuncs) { - if (has_min_version(1)) { - has_ifuncs = ifuncs; - } -} - dev_t soinfo::get_st_dev() { if (has_min_version(0)) { return st_dev; @@ -1834,14 +1778,6 @@ ino_t soinfo::get_st_ino() { return 0; } -bool soinfo::get_has_ifuncs() { - if (has_min_version(1)) { - return has_ifuncs; - } - - return false; -} - // This is a return on get_children()/get_parents() if // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -1862,6 +1798,14 @@ soinfo::soinfo_list_t& soinfo::get_parents() { return this->parents; } +ElfW(Addr) soinfo::resolve_symbol_address(ElfW(Sym)* s) { + if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { + return call_ifunc_resolver(s->st_value + load_bias); + } + + return static_cast(s->st_value + load_bias); +} + /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -2168,44 +2112,32 @@ bool soinfo::LinkImage(const android_dlextinfo* extinfo) { #endif #if defined(USE_RELA) - if (plt_rela != nullptr) { - DEBUG("[ relocating %s plt ]\n", name); - if (Relocate(plt_rela, plt_rela_count)) { - return false; - } - } if (rela != nullptr) { - DEBUG("[ relocating %s ]\n", name); + DEBUG("[ relocating %s ]", name); if (Relocate(rela, rela_count)) { return false; } } -#else - if (plt_rel != nullptr) { + if (plt_rela != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rel, plt_rel_count)) { + if (Relocate(plt_rela, plt_rela_count)) { return false; } } +#else if (rel != nullptr) { DEBUG("[ relocating %s ]", name); if (Relocate(rel, rel_count)) { return false; } } -#endif - - // if there are ifuncs, we need to do an additional relocation pass. - // they cannot be resolved until the rest of the relocations are done - // because we need to call the resolution function which may be waiting - // on relocations. - if(get_has_ifuncs()) { -#if defined(__i386__) - soinfo_ifunc_relocate(this, plt_rel, plt_rel_count); -#elif defined(__x86_64__) - soinfo_ifunc_relocate(this, plt_rela, plt_rela_count); -#endif + if (plt_rel != nullptr) { + DEBUG("[ relocating %s plt ]", name); + if (Relocate(plt_rel, plt_rel_count)) { + return false; + } } +#endif #if defined(__mips__) if (!mips_relocate_got(this)) { diff --git a/linker/linker.h b/linker/linker.h index 3024d3ab2..37d513ea7 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -197,6 +197,8 @@ struct soinfo { #if !defined(__LP64__) bool has_text_relocations; #endif + // TODO: remove this flag, dynamic linker + // should not use it in any way. bool has_DT_SYMBOLIC; soinfo(const char* name, const struct stat* file_stat); @@ -212,21 +214,20 @@ struct soinfo { void set_st_dev(dev_t st_dev); void set_st_ino(ino_t st_ino); - void set_has_ifuncs(bool ifunc); ino_t get_st_ino(); dev_t get_st_dev(); - bool get_has_ifuncs(); soinfo_list_t& get_children(); soinfo_list_t& get_parents(); + ElfW(Addr) resolve_symbol_address(ElfW(Sym)* s); + bool inline has_min_version(uint32_t min_version) { return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; } private: void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); - void resolve_ifunc_symbols(); #if defined(USE_RELA) int Relocate(ElfW(Rela)* rela, unsigned count); #else @@ -247,7 +248,6 @@ struct soinfo { soinfo_list_t parents; // version >= 1 - bool has_ifuncs; }; extern soinfo* get_libdl_info(); diff --git a/tests/Android.build.mk b/tests/Android.build.mk index d4b03960d..d54c851b2 100644 --- a/tests/Android.build.mk +++ b/tests/Android.build.mk @@ -37,6 +37,10 @@ LOCAL_CLANG := $($(module)_clang_$(build_type)) LOCAL_FORCE_STATIC_EXECUTABLE := $($(module)_force_static_executable) +ifneq ($($(module)_multilib),) + LOCAL_MULTILIB := $($(module)_multilib) +endif + LOCAL_CFLAGS := \ $(common_cflags) \ $($(module)_cflags) \ diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index bb9d8c0b8..ea02c1a83 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -89,8 +89,8 @@ TEST(dlfcn, dlopen_noload) { ASSERT_EQ(0, dlclose(handle2)); } -// ifuncs are only supported on intel for now -#if defined(__i386__) || defined(__x86_64__) +// ifuncs are only supported on intel and arm64 for now +#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__) TEST(dlfcn, ifunc) { typedef const char* (*fn_ptr)(); @@ -124,9 +124,13 @@ TEST(dlfcn, ifunc_ctor_call) { typedef const char* (*fn_ptr)(); void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); - ASSERT_TRUE(handle != NULL) << dlerror(); - fn_ptr is_ctor_called = reinterpret_cast(dlsym(handle, "is_ctor_called")); - ASSERT_TRUE(is_ctor_called != NULL) << dlerror(); + ASSERT_TRUE(handle != nullptr) << dlerror(); + fn_ptr is_ctor_called = reinterpret_cast(dlsym(handle, "is_ctor_called_irelative")); + ASSERT_TRUE(is_ctor_called != nullptr) << dlerror(); + ASSERT_STREQ("false", is_ctor_called()); + + is_ctor_called = reinterpret_cast(dlsym(handle, "is_ctor_called_jump_slot")); + ASSERT_TRUE(is_ctor_called != nullptr) << dlerror(); ASSERT_STREQ("true", is_ctor_called()); dlclose(handle); } diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 21681eec9..1004b74e9 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -294,7 +294,7 @@ include $(TEST_PATH)/Android.build.mk # ----------------------------------------------------------------------------- # Library used by ifunc tests # ----------------------------------------------------------------------------- -ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64)) +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),arm64 x86 x86_64)) libtest_ifunc_src_files := \ dlopen_testlib_ifunc.c @@ -302,6 +302,14 @@ ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64)) module := libtest_ifunc build_type := target build_target := SHARED_LIBRARY + + ifeq ($(TARGET_ARCH),arm64) + libtest_ifunc_multilib := 64 + # TODO: This is a workaround - remove it once gcc + # removes its Android ifunc checks + libtest_ifunc_cflags := -mglibc + endif + include $(TEST_PATH)/Android.build.mk endif diff --git a/tests/libs/dlopen_testlib_ifunc.c b/tests/libs/dlopen_testlib_ifunc.c index 48748417d..b68a3dd0f 100644 --- a/tests/libs/dlopen_testlib_ifunc.c +++ b/tests/libs/dlopen_testlib_ifunc.c @@ -23,8 +23,17 @@ static void __attribute__((constructor)) init_flag() { g_flag = 1; } +static const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun"))); + const char* foo() __attribute__ ((ifunc ("foo_ifunc"))); -const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun"))); + +// Static linker creates GLOBAL/IFUNC symbol and JUMP_SLOT relocation type for plt segment +const char* is_ctor_called_jump_slot() __attribute__ ((ifunc("is_ctor_called_ifun"))); + +const char* is_ctor_called_irelative() { + // Call internal ifunc-resolved function with IRELATIVE reloc + return is_ctor_called(); +} const char* return_true() { return "true"; From 7d971ec14b80cac442aeea8d88e9eb2e3ab6f214 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 9 Sep 2014 10:21:42 -0700 Subject: [PATCH 025/114] Fix unload of recursively linked library Expanded test for recursive libs. Fixed bug with unnecessary soinfo_free of already loaded library. (cherry picked from commit a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5) Change-Id: I6907c723d9fbdf6b2777f3f236b1e29b0843edd6 --- linker/linker.cpp | 2 +- tests/dlfcn_test.cpp | 13 ++++++++++++- tests/libs/Android.mk | 10 +++++----- tests/libs/dlopen_testlib_invalid.cpp | 24 ++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 tests/libs/dlopen_testlib_invalid.cpp diff --git a/linker/linker.cpp b/linker/linker.cpp index 1b4fb6201..acbb1b091 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -843,6 +843,7 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl } if ((dlflags & RTLD_NOLOAD) != 0) { + DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name); return nullptr; } @@ -950,7 +951,6 @@ static bool find_libraries(const char* const library_names[], size_t library_nam soinfo* needed_by = task->get_needed_by(); if (is_recursive(si, needed_by)) { - soinfo_free(si); return false; } diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index ea02c1a83..756f2ff9d 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -207,8 +207,19 @@ TEST(dlfcn, dlopen_check_order) { // libtest_with_dependency_loop_a.so TEST(dlfcn, dlopen_check_loop) { void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW); - ASSERT_TRUE(handle == NULL); + ASSERT_TRUE(handle == nullptr); ASSERT_STREQ("dlopen failed: recursive link to \"libtest_with_dependency_loop_a.so\"", dlerror()); + // This symbol should never be exposed + void* f = dlsym(RTLD_DEFAULT, "dlopen_test_invalid_function"); + ASSERT_TRUE(f == nullptr); + ASSERT_SUBSTR("undefined symbol: dlopen_test_invalid_function", dlerror()); + + // dlopen second time to make sure that the library wasn't loaded even though dlopen returned null. + // This may happen if during cleanup the root library or one of the depended libs were not removed + // from soinfo list. + handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); + ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); } TEST(dlfcn, dlopen_failure) { diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 1004b74e9..548dce3ed 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -195,7 +195,7 @@ include $(TEST_PATH)/Android.build.mk # # libtest_with_dependency_loop -> a -> b -> c -> a # ----------------------------------------------------------------------------- -libtest_with_dependency_loop_src_files := empty.cpp +libtest_with_dependency_loop_src_files := dlopen_testlib_invalid.cpp libtest_with_dependency_loop_shared_libraries := \ libtest_with_dependency_loop_a @@ -208,7 +208,7 @@ include $(TEST_PATH)/Android.build.mk # ----------------------------------------------------------------------------- # libtest_with_dependency_loop_a.so # ----------------------------------------------------------------------------- -libtest_with_dependency_loop_a_src_files := empty.cpp +libtest_with_dependency_loop_a_src_files := dlopen_testlib_invalid.cpp libtest_with_dependency_loop_a_shared_libraries := \ libtest_with_dependency_loop_b_tmp @@ -223,7 +223,7 @@ include $(TEST_PATH)/Android.build.mk # # this is temporary placeholder - will be removed # ----------------------------------------------------------------------------- -libtest_with_dependency_loop_b_tmp_src_files := empty.cpp +libtest_with_dependency_loop_b_tmp_src_files := dlopen_testlib_invalid.cpp libtest_with_dependency_loop_b_tmp_ldflags := -Wl,-soname=libtest_with_dependency_loop_b.so module := libtest_with_dependency_loop_b_tmp @@ -234,7 +234,7 @@ include $(TEST_PATH)/Android.build.mk # ----------------------------------------------------------------------------- # libtest_with_dependency_loop_b.so # ----------------------------------------------------------------------------- -libtest_with_dependency_loop_b_src_files := empty.cpp +libtest_with_dependency_loop_b_src_files := dlopen_testlib_invalid.cpp libtest_with_dependency_loop_b_shared_libraries := libtest_with_dependency_loop_c module := libtest_with_dependency_loop_b @@ -245,7 +245,7 @@ include $(TEST_PATH)/Android.build.mk # ----------------------------------------------------------------------------- # libtest_with_dependency_loop_c.so # ----------------------------------------------------------------------------- -libtest_with_dependency_loop_c_src_files := empty.cpp +libtest_with_dependency_loop_c_src_files := dlopen_testlib_invalid.cpp libtest_with_dependency_loop_c_shared_libraries := \ libtest_with_dependency_loop_a diff --git a/tests/libs/dlopen_testlib_invalid.cpp b/tests/libs/dlopen_testlib_invalid.cpp new file mode 100644 index 000000000..f2039c646 --- /dev/null +++ b/tests/libs/dlopen_testlib_invalid.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +// This file is used for libraries that are not supposed to +// be successfully loaded/linked - therefore, this function should +// not be visible via dlsym - (we are going to use this fact in tests) +extern "C" int dlopen_test_invalid_function() { + abort(); +} From 1cd0c6777f35b531c9ce78397d0915aa521b3e87 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Wed, 1 Oct 2014 16:26:49 -0700 Subject: [PATCH 026/114] L-MR1 specific fixes Reset soinfo version to 0. Disable ifunc test for arm64 because of old toolchain in lmp-mr1-dev branch Note: this commit should be reverted in -plus-aosp branch. Change-Id: I2d6d996d43bc35d5d4975c745779f43a988b31e6 --- linker/linker.h | 2 +- tests/dlfcn_test.cpp | 2 +- tests/libs/Android.mk | 9 +-------- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/linker/linker.h b/linker/linker.h index 37d513ea7..3abab294f 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -89,7 +89,7 @@ #define FLAG_LINKER 0x00000010 // The linker itself #define FLAG_NEW_SOINFO 0x40000000 // new soinfo format -#define SOINFO_VERSION 1 +#define SOINFO_VERSION 0 #define SOINFO_NAME_LEN 128 diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 756f2ff9d..9c9fbdd12 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -90,7 +90,7 @@ TEST(dlfcn, dlopen_noload) { } // ifuncs are only supported on intel and arm64 for now -#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) TEST(dlfcn, ifunc) { typedef const char* (*fn_ptr)(); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 548dce3ed..b3554881e 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -294,7 +294,7 @@ include $(TEST_PATH)/Android.build.mk # ----------------------------------------------------------------------------- # Library used by ifunc tests # ----------------------------------------------------------------------------- -ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),arm64 x86 x86_64)) +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64)) libtest_ifunc_src_files := \ dlopen_testlib_ifunc.c @@ -303,13 +303,6 @@ ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),arm64 x86 x86_64)) build_type := target build_target := SHARED_LIBRARY - ifeq ($(TARGET_ARCH),arm64) - libtest_ifunc_multilib := 64 - # TODO: This is a workaround - remove it once gcc - # removes its Android ifunc checks - libtest_ifunc_cflags := -mglibc - endif - include $(TEST_PATH)/Android.build.mk endif From 145372b1bced73595d51405bcbda73cd092e2425 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 2 Oct 2014 12:49:42 -0700 Subject: [PATCH 027/114] Revert "L-MR1 specific fixes" This reverts commit 1cd0c6777f35b531c9ce78397d0915aa521b3e87. --- linker/linker.h | 2 +- tests/dlfcn_test.cpp | 2 +- tests/libs/Android.mk | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/linker/linker.h b/linker/linker.h index b985a9991..8afeb144d 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -89,7 +89,7 @@ #define FLAG_LINKER 0x00000010 // The linker itself #define FLAG_NEW_SOINFO 0x40000000 // new soinfo format -#define SOINFO_VERSION 0 +#define SOINFO_VERSION 1 #define SOINFO_NAME_LEN 128 diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index b54d13ae2..1bf186b4b 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -90,7 +90,7 @@ TEST(dlfcn, dlopen_noload) { } // ifuncs are only supported on intel and arm64 for now -#if defined(__i386__) || defined(__x86_64__) +#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__) TEST(dlfcn, ifunc) { typedef const char* (*fn_ptr)(); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index cac314021..53cd0c693 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -470,7 +470,7 @@ endif # ----------------------------------------------------------------------------- # Library used by ifunc tests # ----------------------------------------------------------------------------- -ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64)) +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),arm64 x86 x86_64)) libtest_ifunc_src_files := \ dlopen_testlib_ifunc.c @@ -479,6 +479,13 @@ ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64)) build_type := target build_target := SHARED_LIBRARY + ifeq ($(TARGET_ARCH),arm64) + libtest_ifunc_multilib := 64 + # TODO: This is a workaround - remove it once gcc + # removes its Android ifunc checks + libtest_ifunc_cflags := -mglibc + endif + include $(TEST_PATH)/Android.build.mk endif From 2cd77d301ff6860836428cda2ccd626b3bb6912e Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 2 Oct 2014 13:08:39 -0700 Subject: [PATCH 028/114] Undo the bad work of Automerger Change-Id: I585388aebc556a094db4c22e647edacea7cde129 --- tests/libs/Android.mk | 199 ------------------------------------------ 1 file changed, 199 deletions(-) diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 53cd0c693..bc5f1086d 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -254,183 +254,6 @@ include $(LOCAL_PATH)/Android.build.testlib.mk module := libtest_relo_check_dt_needed_order_2 include $(LOCAL_PATH)/Android.build.testlib.mk -# ----------------------------------------------------------------------------- -# Libraries used by dlfcn tests to verify correct load order: -# libtest_check_order_2_right.so -# ----------------------------------------------------------------------------- -libtest_check_order_2_right_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_2_right_cflags := -D__ANSWER=42 -module := libtest_check_order_2_right -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_a.so -# ----------------------------------------------------------------------------- -libtest_check_order_a_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_a_cflags := -D__ANSWER=1 -module := libtest_check_order_a -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_b.so -# ----------------------------------------------------------------------------- -libtest_check_order_b_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 -module := libtest_check_order_b -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_c.so -# ----------------------------------------------------------------------------- -libtest_check_order_3_c_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_3_c_cflags := -D__ANSWER=3 -module := libtest_check_order_3_c -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_d.so -# ----------------------------------------------------------------------------- -libtest_check_order_d_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_d_shared_libraries := libtest_check_order_b -libtest_check_order_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 -module := libtest_check_order_d -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_left.so -# ----------------------------------------------------------------------------- -libtest_check_order_1_left_src_files := \ - empty.cpp - -libtest_check_order_1_left_shared_libraries := libtest_check_order_a libtest_check_order_b - -module := libtest_check_order_1_left -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order.so -# ----------------------------------------------------------------------------- -libtest_check_order_src_files := \ - empty.cpp - -libtest_check_order_shared_libraries := libtest_check_order_1_left \ - libtest_check_order_2_right libtest_check_order_3_c - -module := libtest_check_order -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# Library with dependency loop used by dlfcn tests -# -# libtest_with_dependency_loop -> a -> b -> c -> a -# ----------------------------------------------------------------------------- -libtest_with_dependency_loop_src_files := dlopen_testlib_invalid.cpp - -libtest_with_dependency_loop_shared_libraries := \ - libtest_with_dependency_loop_a - -module := libtest_with_dependency_loop -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_with_dependency_loop_a.so -# ----------------------------------------------------------------------------- -libtest_with_dependency_loop_a_src_files := dlopen_testlib_invalid.cpp - -libtest_with_dependency_loop_a_shared_libraries := \ - libtest_with_dependency_loop_b_tmp - -module := libtest_with_dependency_loop_a -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_with_dependency_loop_b.so -# -# this is temporary placeholder - will be removed -# ----------------------------------------------------------------------------- -libtest_with_dependency_loop_b_tmp_src_files := dlopen_testlib_invalid.cpp -libtest_with_dependency_loop_b_tmp_ldflags := -Wl,-soname=libtest_with_dependency_loop_b.so - -module := libtest_with_dependency_loop_b_tmp -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_with_dependency_loop_b.so -# ----------------------------------------------------------------------------- -libtest_with_dependency_loop_b_src_files := dlopen_testlib_invalid.cpp -libtest_with_dependency_loop_b_shared_libraries := libtest_with_dependency_loop_c - -module := libtest_with_dependency_loop_b -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_with_dependency_loop_c.so -# ----------------------------------------------------------------------------- -libtest_with_dependency_loop_c_src_files := dlopen_testlib_invalid.cpp - -libtest_with_dependency_loop_c_shared_libraries := \ - libtest_with_dependency_loop_a - -module := libtest_with_dependency_loop_c -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- -# libtest_relo_check_dt_needed_order.so -# | -# +-> libtest_relo_check_dt_needed_order_1.so -# | -# +-> libtest_relo_check_dt_needed_order_2.so -# ----------------------------------------------------------------------------- -libtest_relo_check_dt_needed_order_shared_libraries := \ - libtest_relo_check_dt_needed_order_1 libtest_relo_check_dt_needed_order_2 - -libtest_relo_check_dt_needed_order_src_files := dlopen_testlib_relo_check_dt_needed_order.cpp -libtest_relo_check_dt_needed_order_1_src_files := dlopen_testlib_relo_check_dt_needed_order_1.cpp -libtest_relo_check_dt_needed_order_2_src_files := dlopen_testlib_relo_check_dt_needed_order_2.cpp -build_type := target -build_target := SHARED_LIBRARY - -module := libtest_relo_check_dt_needed_order -include $(TEST_PATH)/Android.build.mk -module := libtest_relo_check_dt_needed_order_1 -include $(TEST_PATH)/Android.build.mk -module := libtest_relo_check_dt_needed_order_2 -include $(TEST_PATH)/Android.build.mk - # ----------------------------------------------------------------------------- # Library with dependency used by dlfcn tests # ----------------------------------------------------------------------------- @@ -467,28 +290,6 @@ ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),arm64 x86 x86_64)) include $(TEST_PATH)/Android.build.mk endif -# ----------------------------------------------------------------------------- -# Library used by ifunc tests -# ----------------------------------------------------------------------------- -ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),arm64 x86 x86_64)) - libtest_ifunc_src_files := \ - dlopen_testlib_ifunc.c - - LOCAL_SDK_VERSION := current - module := libtest_ifunc - build_type := target - build_target := SHARED_LIBRARY - - ifeq ($(TARGET_ARCH),arm64) - libtest_ifunc_multilib := 64 - # TODO: This is a workaround - remove it once gcc - # removes its Android ifunc checks - libtest_ifunc_cflags := -mglibc - endif - - include $(TEST_PATH)/Android.build.mk -endif - # ----------------------------------------------------------------------------- # Library used by atexit tests # ----------------------------------------------------------------------------- From bbf86e6157ab98af7468ce5eb3292b6509a3cabd Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 2 Oct 2014 13:44:20 -0700 Subject: [PATCH 029/114] Fixes to linker code after the conflict resolution Change-Id: Icd0728604a865b73e7af0e0aee38971a612935f2 --- linker/linker.cpp | 16 ---------------- linker/linker.h | 2 -- linker/linker_phdr.cpp | 16 ---------------- 3 files changed, 34 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index fda168c52..6c30e1c32 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -779,22 +779,6 @@ static void for_each_dt_needed(const soinfo* si, F action) { } } -static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { - int fd = -1; - ScopedFd file_guard(-1); - - if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { - fd = extinfo->library_fd; - } else { - // Open the file. - fd = open_library(name); - if (fd == -1) { - DL_ERR("library \"%s\" not found", name); - return nullptr; - } - } -} - static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { int fd = -1; ScopedFd file_guard(-1); diff --git a/linker/linker.h b/linker/linker.h index 8afeb144d..f6e3a48ba 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -217,8 +217,6 @@ struct soinfo { ino_t get_st_ino(); dev_t get_st_dev(); - - int get_rtld_flags(); soinfo_list_t& get_children(); diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index 2d03ac354..44c8e9e70 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -718,22 +718,6 @@ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_co } return; } - - *dynamic = reinterpret_cast(load_bias + phdr->p_vaddr); - if (dynamic_count) { - *dynamic_count = (unsigned)(phdr->p_memsz / 8); - } - if (dynamic_flags) { - *dynamic_flags = phdr->p_flags; - } - return; - } - *dynamic = nullptr; - for (const ElfW(Phdr)* phdr = phdr_table, *phdr_limit = phdr + phdr_count; phdr < phdr_limit; phdr++) { - if (phdr->p_type == PT_DYNAMIC) { - *dynamic = reinterpret_cast(load_bias + phdr->p_vaddr); - return; - } } } From 04f5f4100cbabc8cf5b57ece0fd490217e1549bd Mon Sep 17 00:00:00 2001 From: Ningsheng Jian Date: Tue, 16 Sep 2014 15:22:10 +0800 Subject: [PATCH 030/114] Fix gdb could not get shared library list issue Get dynamic flags from phdr table's correct entry rather the first entry, so that the following DT_DEBUG entry can be set. Also fix the undefined reference to LoadTask::deleter issue under gcc -O0 option. Bug: 17524778 (cherry picked from commit e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0) Change-Id: I347792dab25c7b19c3fc690e03d20899ce1e26e0 --- linker/linker.cpp | 10 ++++++---- linker/linker_phdr.cpp | 7 ++++++- linker/linker_phdr.h | 3 ++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index acbb1b091..1befaa6a9 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -666,6 +666,8 @@ class LoadTask { DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask); }; +LoadTask::deleter_t LoadTask::deleter; + template using linked_list_t = LinkedList>>; @@ -1868,7 +1870,9 @@ static int nullify_closed_stdio() { } bool soinfo::PrelinkImage() { - phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic); + /* Extract dynamic section */ + ElfW(Word) dynamic_flags = 0; + phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags); /* We can't log anything until the linker is relocated */ bool relocating_linker = (flags & FLAG_LINKER) != 0; @@ -1877,8 +1881,6 @@ bool soinfo::PrelinkImage() { DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast(base), flags); } - /* Extract dynamic section */ - ElfW(Word) dynamic_flags = phdr->p_flags; if (dynamic == nullptr) { if (!relocating_linker) { DL_ERR("missing PT_DYNAMIC in \"%s\"", name); @@ -2240,7 +2242,7 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) { ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_base); ElfW(Phdr)* phdr = reinterpret_cast(linker_base + elf_hdr->e_phoff); phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, - &linker_soinfo_for_gdb.dynamic); + &linker_soinfo_for_gdb.dynamic, nullptr); insert_soinfo_into_debug_map(&linker_soinfo_for_gdb); } diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index 436517271..44c8e9e70 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -702,15 +702,20 @@ int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, * load_bias -> load bias * Output: * dynamic -> address of table in memory (null on failure). + * dynamic_flags -> protection flags for section (unset on failure) * Return: * void */ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count, - ElfW(Addr) load_bias, ElfW(Dyn)** dynamic) { + ElfW(Addr) load_bias, ElfW(Dyn)** dynamic, + ElfW(Word)* dynamic_flags) { *dynamic = nullptr; for (const ElfW(Phdr)* phdr = phdr_table, *phdr_limit = phdr + phdr_count; phdr < phdr_limit; phdr++) { if (phdr->p_type == PT_DYNAMIC) { *dynamic = reinterpret_cast(load_bias + phdr->p_vaddr); + if (dynamic_flags) { + *dynamic_flags = phdr->p_flags; + } return; } } diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h index d4c3ce85f..593fb5a20 100644 --- a/linker/linker_phdr.h +++ b/linker/linker_phdr.h @@ -101,6 +101,7 @@ int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, El #endif void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count, - ElfW(Addr) load_bias, ElfW(Dyn)** dynamic); + ElfW(Addr) load_bias, ElfW(Dyn)** dynamic, + ElfW(Word)* dynamic_flags); #endif /* LINKER_PHDR_H */ From 7ad2147a08b000e4bb6101bd24f055552f7a41aa Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Sat, 4 Oct 2014 15:20:00 -0700 Subject: [PATCH 031/114] string.h: remove unused variable (cherry picked from commit 48be71d02b6cc4e6493d38cdd6b7779032c38901) Bug: 17784968 Change-Id: Iac7732fb4f7fe42977cb9f62472bb636e17e5232 --- libc/include/string.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libc/include/string.h b/libc/include/string.h index 8df68e38d..6384d57cd 100644 --- a/libc/include/string.h +++ b/libc/include/string.h @@ -98,7 +98,6 @@ __BIONIC_FORTIFY_INLINE void* memcpy(void* __restrict dest, const void* __restrict src, size_t copy_amount) { char *d = (char *) dest; const char *s = (const char *) src; - size_t s_len = __bos0(s); size_t d_len = __bos0(d); return __builtin___memcpy_chk(dest, src, copy_amount, d_len); From db408bf421faffe6c0623ca652844edfffa3726c Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Sun, 5 Oct 2014 06:52:24 -0700 Subject: [PATCH 032/114] further cleanup memcpy fortify implementation Bug: 17784968 (cherry picked from commit b84f667e9312611536a564700daea11c12b6fcfa) Change-Id: I68fc2cc0a1ee7f0887edf3681eb83ef678de1383 --- libc/include/string.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libc/include/string.h b/libc/include/string.h index 6384d57cd..3d083710f 100644 --- a/libc/include/string.h +++ b/libc/include/string.h @@ -96,11 +96,7 @@ extern size_t strxfrm_l(char* __restrict, const char* __restrict, size_t, locale __BIONIC_FORTIFY_INLINE void* memcpy(void* __restrict dest, const void* __restrict src, size_t copy_amount) { - char *d = (char *) dest; - const char *s = (const char *) src; - size_t d_len = __bos0(d); - - return __builtin___memcpy_chk(dest, src, copy_amount, d_len); + return __builtin___memcpy_chk(dest, src, copy_amount, __bos0(dest)); } __BIONIC_FORTIFY_INLINE From d87d401ab134996d1f25f5b63cefb48b5b5877c8 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 18 Aug 2014 14:45:42 -0700 Subject: [PATCH 033/114] Improve . Fix and use __RENAME (and lose ___RENAME --- two underscores should be enough for anybody). This was the point of this change, because I want to use __RENAME to support the two basename variants and the two strerror_r variants. Lose a bunch of macros that weren't being used. Lose three dead files from the DNS code. Bug: 17784968 (cherry picked from commit 2cfb4e8e2e217ef0e4140dcbf9b3da809781158c) Change-Id: I5e96146f92c0521248c78c0933bec5e9a9818222 --- libc/dns/resolv/__dn_comp.c | 38 -------------- libc/dns/resolv/__res_close.c | 33 ------------ libc/dns/resolv/__res_send.c | 37 -------------- libc/include/fcntl.h | 4 +- libc/include/stdio.h | 2 +- libc/include/string.h | 6 +-- libc/include/sys/cdefs.h | 96 +++++++++-------------------------- libc/include/sys/cdefs_elf.h | 96 +++-------------------------------- libc/include/sys/socket.h | 3 +- libc/include/sys/stat.h | 2 +- libc/include/unistd.h | 3 +- 11 files changed, 39 insertions(+), 281 deletions(-) delete mode 100644 libc/dns/resolv/__dn_comp.c delete mode 100644 libc/dns/resolv/__res_close.c delete mode 100644 libc/dns/resolv/__res_send.c diff --git a/libc/dns/resolv/__dn_comp.c b/libc/dns/resolv/__dn_comp.c deleted file mode 100644 index 93d3f1988..000000000 --- a/libc/dns/resolv/__dn_comp.c +++ /dev/null @@ -1,38 +0,0 @@ -/* $NetBSD: __dn_comp.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */ - -/* - * written by matthew green, 22/04/97. - * public domain. - */ - -#include -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: __dn_comp.c,v 1.4 2005/09/13 01:44:10 christos Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#if defined(__indr_reference) -__indr_reference(__dn_comp,dn_comp) -#else - -#include -#include -#ifdef ANDROID_CHANGES -#include "resolv_private.h" -#else -#include -#endif - -/* XXX THIS IS A MESS! SEE XXX */ - -#undef dn_comp -int dn_comp(const char *, u_char *, int, u_char **, u_char **); - -int -dn_comp(const char *exp_dn, u_char *comp_dn, u_char **dnptrs, - u_char **lastdnptr, int length) -{ - - return __dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr); -} - -#endif diff --git a/libc/dns/resolv/__res_close.c b/libc/dns/resolv/__res_close.c deleted file mode 100644 index 3af50b06b..000000000 --- a/libc/dns/resolv/__res_close.c +++ /dev/null @@ -1,33 +0,0 @@ -/* $NetBSD: __res_close.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */ - -/* - * written by matthew green, 22/04/97. - * public domain. - */ - -#include -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: __res_close.c,v 1.4 2005/09/13 01:44:10 christos Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#if defined(__indr_reference) -__indr_reference(__res_close, res_close) -#else - -#include -#include -#include "resolv_private.h" - -/* XXX THIS IS A MESS! SEE XXX */ - -#undef res_close -void res_close(void); - -void -res_close(void) -{ - - __res_close(); -} - -#endif diff --git a/libc/dns/resolv/__res_send.c b/libc/dns/resolv/__res_send.c deleted file mode 100644 index 198b05c12..000000000 --- a/libc/dns/resolv/__res_send.c +++ /dev/null @@ -1,37 +0,0 @@ -/* $NetBSD: __res_send.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */ - -/* - * written by matthew green, 22/04/97. - * public domain. - */ - -#include -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: __res_send.c,v 1.4 2005/09/13 01:44:10 christos Exp $"); -#endif - -#if defined(__indr_reference) -__indr_reference(__res_send, res_send) -#else - -#include -#include -#ifdef ANDROID_CHANGES -#include "resolv_private.h" -#else -#include -#endif - -/* XXX THIS IS A MESS! SEE XXX */ - -#undef res_send -int res_send(const u_char *, int, u_char *, int); - -int -res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) -{ - - return __res_send(buf, buflen, ans, anssiz); -} - -#endif diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h index 8f89afbb4..87c848163 100644 --- a/libc/include/fcntl.h +++ b/libc/include/fcntl.h @@ -84,9 +84,9 @@ extern ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int); #if defined(__BIONIC_FORTIFY) extern int __open_2(const char*, int); -extern int __open_real(const char*, int, ...) __asm__(__USER_LABEL_PREFIX__ "open"); +extern int __open_real(const char*, int, ...) __RENAME(open); extern int __openat_2(int, const char*, int); -extern int __openat_real(int, const char*, int, ...) __asm__(__USER_LABEL_PREFIX__ "openat"); +extern int __openat_real(int, const char*, int, ...) __RENAME(openat); __errordecl(__creat_missing_mode, "called with O_CREAT, but missing mode"); __errordecl(__creat_too_many_args, "too many arguments"); diff --git a/libc/include/stdio.h b/libc/include/stdio.h index 43b0fbfe4..38a267771 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -412,7 +412,7 @@ int sprintf(char *dest, const char *format, ...) #endif extern char* __fgets_chk(char*, int, FILE*, size_t); -extern char* __fgets_real(char*, int, FILE*) __asm__(__USER_LABEL_PREFIX__ "fgets"); +extern char* __fgets_real(char*, int, FILE*) __RENAME(fgets); __errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer"); __errordecl(__fgets_too_small_error, "fgets called with size less than zero"); diff --git a/libc/include/string.h b/libc/include/string.h index 3d083710f..29717605a 100644 --- a/libc/include/string.h +++ b/libc/include/string.h @@ -175,8 +175,7 @@ void* memset(void *s, int c, size_t n) { return __builtin___memset_chk(s, c, n, __bos0(s)); } -extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t) - __asm__(__USER_LABEL_PREFIX__ "strlcpy"); +extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcpy); extern size_t __strlcpy_chk(char *, const char *, size_t, size_t); __BIONIC_FORTIFY_INLINE @@ -199,8 +198,7 @@ size_t strlcpy(char* __restrict dest, const char* __restrict src, size_t size) { return __strlcpy_chk(dest, src, size, bos); } -extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t) - __asm__(__USER_LABEL_PREFIX__ "strlcat"); +extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcat); extern size_t __strlcat_chk(char* __restrict, const char* __restrict, size_t, size_t); diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h index 9a8dfdd20..c764e9bf5 100644 --- a/libc/include/sys/cdefs.h +++ b/libc/include/sys/cdefs.h @@ -267,20 +267,6 @@ #endif /* NO_KERNEL_RCSIDS */ #endif /* _KERNEL */ -#if !defined(_STANDALONE) && !defined(_KERNEL) -#ifdef __GNUC__ -#define __RENAME(x) ___RENAME(x) -#else -#ifdef __lint__ -#define __RENAME(x) __symbolrename(x) -#else -#error "No function renaming possible" -#endif /* __lint__ */ -#endif /* __GNUC__ */ -#else /* _STANDALONE || _KERNEL */ -#define __RENAME(x) no renaming in kernel or standalone environment -#endif - /* * A barrier to stop the optimizer from moving code or assume live * register values. This is gcc specific, the version is more or less @@ -359,60 +345,15 @@ #endif /* - * Macros for manipulating "link sets". Link sets are arrays of pointers - * to objects, which are gathered up by the linker. - * - * Object format-specific code has provided us with the following macros: - * - * __link_set_add_text(set, sym) - * Add a reference to the .text symbol `sym' to `set'. - * - * __link_set_add_rodata(set, sym) - * Add a reference to the .rodata symbol `sym' to `set'. - * - * __link_set_add_data(set, sym) - * Add a reference to the .data symbol `sym' to `set'. - * - * __link_set_add_bss(set, sym) - * Add a reference to the .bss symbol `sym' to `set'. - * - * __link_set_decl(set, ptype) - * Provide an extern declaration of the set `set', which - * contains an array of the pointer type `ptype'. This - * macro must be used by any code which wishes to reference - * the elements of a link set. - * - * __link_set_start(set) - * This points to the first slot in the link set. - * - * __link_set_end(set) - * This points to the (non-existent) slot after the last - * entry in the link set. - * - * __link_set_count(set) - * Count the number of entries in link set `set'. - * - * In addition, we provide the following macros for accessing link sets: - * - * __link_set_foreach(pvar, set) - * Iterate over the link set `set'. Because a link set is - * an array of pointers, pvar must be declared as "type **pvar", - * and the actual entry accessed as "*pvar". - * - * __link_set_entry(set, idx) - * Access the link set entry at index `idx' from set `set'. + * Some BSD source needs these macros. + * Originally they embedded the rcs versions of each source file + * in the generated binary. We strip strings during build anyway,. */ -#define __link_set_foreach(pvar, set) \ - for (pvar = __link_set_start(set); pvar < __link_set_end(set); pvar++) - -#define __link_set_entry(set, idx) (__link_set_begin(set)[idx]) - -/* - * Some of the FreeBSD sources used in Bionic need this. - * Originally, this is used to embed the rcs versions of each source file - * in the generated binary. We certainly don't want this in Bionic. - */ -#define __FBSDID(s) /* nothing */ +#define __IDSTRING(_prefix,_s) /* nothing */ +#define __COPYRIGHT(_s) /* nothing */ +#define __FBSDID(_s) /* nothing */ +#define __RCSID(_s) /* nothing */ +#define __SCCSID(_s) /* nothing */ /*- * The following definitions are an extension of the behavior originally @@ -570,11 +511,24 @@ #endif #define __bos0(s) __builtin_object_size((s), 0) -#define __BIONIC_FORTIFY_INLINE \ - extern __inline__ \ - __attribute__ ((always_inline)) \ - __attribute__ ((gnu_inline)) +#define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline)) #endif #define __BIONIC_FORTIFY_UNKNOWN_SIZE ((size_t) -1) +/* Used to tag non-static symbols that are private and never exposed by the shared library. */ +#define __LIBC_HIDDEN__ __attribute__((visibility("hidden"))) + +/* Like __LIBC_HIDDEN__, but preserves binary compatibility for LP32. */ +#ifdef __LP64__ +#define __LIBC64_HIDDEN__ __LIBC_HIDDEN__ +#else +#define __LIBC64_HIDDEN__ __LIBC_ABI_PUBLIC__ +#endif + +/* Used to tag non-static symbols that are public and exposed by the shared library. */ +#define __LIBC_ABI_PUBLIC__ __attribute__((visibility ("default"))) + +/* Used to rename functions so that the compiler emits a call to 'x' rather than the function this was applied to. */ +#define __RENAME(x) __asm__(#x) + #endif /* !_SYS_CDEFS_H_ */ diff --git a/libc/include/sys/cdefs_elf.h b/libc/include/sys/cdefs_elf.h index 4dd7dc347..6bb0a5720 100644 --- a/libc/include/sys/cdefs_elf.h +++ b/libc/include/sys/cdefs_elf.h @@ -30,27 +30,13 @@ #ifndef _SYS_CDEFS_ELF_H_ #define _SYS_CDEFS_ELF_H_ -#ifdef __LEADING_UNDERSCORE -#define _C_LABEL(x) __CONCAT(_,x) -#define _C_LABEL_STRING(x) "_"x -#else -#define _C_LABEL(x) x -#define _C_LABEL_STRING(x) x -#endif +#define __strong_alias(alias, sym) \ + __asm__(".global " #alias "\n" \ + #alias " = " #sym); -#define ___RENAME(x) __asm__(___STRING(_C_LABEL(x))) - -#define __indr_reference(sym,alias) /* nada, since we do weak refs */ - -#define __strong_alias(alias,sym) \ - __asm__(".global " _C_LABEL_STRING(#alias) "\n" \ - _C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym)); - -#define __weak_alias(alias,sym) \ - __asm__(".weak " _C_LABEL_STRING(#alias) "\n" \ - _C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym)); -#define __weak_extern(sym) \ - __asm__(".weak " _C_LABEL_STRING(#sym)); +#define __weak_alias(alias,sym) \ + __asm__(".weak " #alias "\n" \ + #alias " = " #sym); /* We use __warnattr instead of __warn_references. * TODO: remove this and put an empty definition in one of the upstream-* compatibility headers. @@ -58,74 +44,4 @@ #define __warn_references(sym,msg) \ /*__asm__(".section .gnu.warning." #sym "\n\t.ascii \"" msg "\"\n\t.text");*/ -#define __SECTIONSTRING(_sec, _str) \ - __asm__(".section " #_sec "\n\t.asciz \"" _str "\"\n\t.previous") - -/* Used to tag non-static symbols that are private and never exposed by the shared library. */ -#define __LIBC_HIDDEN__ __attribute__((visibility ("hidden"))) - -/* Like __LIBC_HIDDEN__, but preserves binary compatibility for LP32. */ -#ifdef __LP64__ -#define __LIBC64_HIDDEN__ __LIBC_HIDDEN__ -#else -#define __LIBC64_HIDDEN__ __LIBC_ABI_PUBLIC__ -#endif - -/* Used to tag non-static symbols that are public and exposed by the shared library. */ -#define __LIBC_ABI_PUBLIC__ __attribute__((visibility ("default"))) - -#define __IDSTRING(_n,_s) __SECTIONSTRING(.ident,_s) - -#define __RCSID(_s) __IDSTRING(rcsid,_s) -#define __SCCSID(_s) -#define __SCCSID2(_s) -#if 0 /* XXX userland __COPYRIGHTs have \ns in them */ -#define __COPYRIGHT(_s) __SECTIONSTRING(.copyright,_s) -#else -#define __COPYRIGHT(_s) \ - static const char copyright[] \ - __attribute__((__unused__,__section__(".copyright"))) = _s -#endif - -#define __KERNEL_RCSID(_n, _s) __RCSID(_s) -#define __KERNEL_SCCSID(_n, _s) -#if 0 /* XXX see above */ -#define __KERNEL_COPYRIGHT(_n, _s) __COPYRIGHT(_s) -#else -#define __KERNEL_COPYRIGHT(_n, _s) __SECTIONSTRING(.copyright, _s) -#endif - -#ifndef __lint__ -#define __link_set_make_entry(set, sym) \ - static void const * const __link_set_##set##_sym_##sym \ - __section("link_set_" #set) __used = &sym -#define __link_set_make_entry2(set, sym, n) \ - static void const * const __link_set_##set##_sym_##sym##_##n \ - __section("link_set_" #set) __used = &sym[n] -#else -#define __link_set_make_entry(set, sym) \ - extern void const * const __link_set_##set##_sym_##sym -#define __link_set_make_entry2(set, sym, n) \ - extern void const * const __link_set_##set##_sym_##sym##_##n -#endif /* __lint__ */ - -#define __link_set_add_text(set, sym) __link_set_make_entry(set, sym) -#define __link_set_add_rodata(set, sym) __link_set_make_entry(set, sym) -#define __link_set_add_data(set, sym) __link_set_make_entry(set, sym) -#define __link_set_add_bss(set, sym) __link_set_make_entry(set, sym) -#define __link_set_add_text2(set, sym, n) __link_set_make_entry2(set, sym, n) -#define __link_set_add_rodata2(set, sym, n) __link_set_make_entry2(set, sym, n) -#define __link_set_add_data2(set, sym, n) __link_set_make_entry2(set, sym, n) -#define __link_set_add_bss2(set, sym, n) __link_set_make_entry2(set, sym, n) - -#define __link_set_decl(set, ptype) \ - extern ptype * const __start_link_set_##set[]; \ - extern ptype * const __stop_link_set_##set[] \ - -#define __link_set_start(set) (__start_link_set_##set) -#define __link_set_end(set) (__stop_link_set_##set) - -#define __link_set_count(set) \ - (__link_set_end(set) - __link_set_start(set)) - #endif /* !_SYS_CDEFS_ELF_H_ */ diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h index ae2f2381e..a8840ff46 100644 --- a/libc/include/sys/socket.h +++ b/libc/include/sys/socket.h @@ -294,8 +294,7 @@ __socketcall ssize_t recvfrom(int, void*, size_t, int, const struct sockaddr*, s #if defined(__BIONIC_FORTIFY) __errordecl(__recvfrom_error, "recvfrom called with size bigger than buffer"); extern ssize_t __recvfrom_chk(int, void*, size_t, size_t, int, const struct sockaddr*, socklen_t*); -extern ssize_t __recvfrom_real(int, void*, size_t, int, const struct sockaddr*, socklen_t*) - __asm__(__USER_LABEL_PREFIX__ "recvfrom"); +extern ssize_t __recvfrom_real(int, void*, size_t, int, const struct sockaddr*, socklen_t*) __RENAME(recvfrom); __BIONIC_FORTIFY_INLINE ssize_t recvfrom(int fd, void* buf, size_t len, int flags, const struct sockaddr* src_addr, socklen_t* addr_len) { diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h index c0c168b2e..a6cc368cf 100644 --- a/libc/include/sys/stat.h +++ b/libc/include/sys/stat.h @@ -162,7 +162,7 @@ extern mode_t umask(mode_t); #if defined(__BIONIC_FORTIFY) extern mode_t __umask_chk(mode_t); -extern mode_t __umask_real(mode_t) __asm__(__USER_LABEL_PREFIX__ "umask"); +extern mode_t __umask_real(mode_t) __RENAME(umask); __errordecl(__umask_invalid_mode, "umask called with invalid mode"); __BIONIC_FORTIFY_INLINE diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 7fbafdf27..781fc4435 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -201,8 +201,7 @@ extern int tcsetpgrp(int fd, pid_t _pid); extern ssize_t __read_chk(int, void*, size_t, size_t); __errordecl(__read_dest_size_error, "read called with size bigger than destination"); __errordecl(__read_count_toobig_error, "read called with count > SSIZE_MAX"); -extern ssize_t __read_real(int, void*, size_t) - __asm__(__USER_LABEL_PREFIX__ "read"); +extern ssize_t __read_real(int, void*, size_t) __RENAME(read); __BIONIC_FORTIFY_INLINE ssize_t read(int fd, void* buf, size_t count) { From b5e7eba6d1b97e471996fcfe7dbde7cbba7512ef Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 7 Oct 2014 16:02:11 -0700 Subject: [PATCH 034/114] Work around a bug in Immersion's libImmEmulatorJ.so. This library calls pthread_mutex_lock and pthread_mutex_unlock with a NULL pthread_mutex_t*. This gives them (and their users) one release to fix things. Bug: 17443936 (cherry picked from commit 7d3f553f989f830976efa92ddc3c84661d4d42aa) Change-Id: Ie26bbecd3a74d61113b51c18832872499b97ee86 --- libc/bionic/pthread_mutex.cpp | 12 ++++++++++++ libc/include/pthread.h | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp index 546166166..ae2557f08 100644 --- a/libc/bionic/pthread_mutex.cpp +++ b/libc/bionic/pthread_mutex.cpp @@ -440,6 +440,12 @@ static inline __always_inline int _recursive_increment(pthread_mutex_t* mutex, i } int pthread_mutex_lock(pthread_mutex_t* mutex) { +#if !defined(__LP64__) + if (mutex == NULL) { + return EINVAL; + } +#endif + int mvalue, mtype, tid, shared; mvalue = mutex->value; @@ -516,6 +522,12 @@ int pthread_mutex_lock(pthread_mutex_t* mutex) { } int pthread_mutex_unlock(pthread_mutex_t* mutex) { +#if !defined(__LP64__) + if (mutex == NULL) { + return EINVAL; + } +#endif + int mvalue, mtype, tid, shared; mvalue = mutex->value; diff --git a/libc/include/pthread.h b/libc/include/pthread.h index 86a10051e..c32890b03 100644 --- a/libc/include/pthread.h +++ b/libc/include/pthread.h @@ -206,10 +206,10 @@ int pthread_mutexattr_settype(pthread_mutexattr_t*, int) __nonnull((1)); int pthread_mutex_destroy(pthread_mutex_t*) __nonnull((1)); int pthread_mutex_init(pthread_mutex_t*, const pthread_mutexattr_t*) __nonnull((1)); -int pthread_mutex_lock(pthread_mutex_t*) __nonnull((1)); +int pthread_mutex_lock(pthread_mutex_t*) /* __nonnull((1)) */; int pthread_mutex_timedlock(pthread_mutex_t*, const struct timespec*) __nonnull((1, 2)); int pthread_mutex_trylock(pthread_mutex_t*) __nonnull((1)); -int pthread_mutex_unlock(pthread_mutex_t*) __nonnull((1)); +int pthread_mutex_unlock(pthread_mutex_t*) /* __nonnull((1)) */; int pthread_once(pthread_once_t*, void (*)(void)) __nonnull((1, 2)); From ce92b41a00fb86656055eceab9648a858721c3b1 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Mon, 6 Oct 2014 14:49:00 -0700 Subject: [PATCH 035/114] cdefs.h: add artificial attribute to FORTIFY_SOURCE functions Otherwise the gcc compiler warning doesn't show up. Add -Wno-error to fortify related tests. Fortify related tests are expected to be examples of bad programs, and in many cases shouldn't compile cleanly. Rewriting them to compile cleanly isn't feasible nor desirable. Bug: 17784968 (cherry picked from commit 1aaa17802c92d99ae170245c2b2f15a6c27b133e) Change-Id: Ib6df1a3f44b55b1fff222e78395c10c51cd39817 --- libc/include/sys/cdefs.h | 7 +++++++ tests/Android.mk | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h index c764e9bf5..504e4396c 100644 --- a/libc/include/sys/cdefs.h +++ b/libc/include/sys/cdefs.h @@ -53,6 +53,9 @@ #ifndef __has_builtin #define __has_builtin(x) 0 #endif +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif /* @@ -511,8 +514,12 @@ #endif #define __bos0(s) __builtin_object_size((s), 0) +#if __GNUC_PREREQ(4,3) || __has_attribute(__artificial__) +#define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline)) __attribute__((__artificial__)) +#else #define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline)) #endif +#endif #define __BIONIC_FORTIFY_UNKNOWN_SIZE ((size_t) -1) /* Used to tag non-static symbols that are private and never exposed by the shared library. */ diff --git a/tests/Android.mk b/tests/Android.mk index 69ff8110a..dd430490b 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -171,11 +171,10 @@ $(foreach compiler,gcc clang, \ $(foreach test,1 2, \ $(eval fortify$(test)-tests-$(compiler)_cflags := \ $(test_cflags) \ + -Wno-error \ -U_FORTIFY_SOURCE \ -D_FORTIFY_SOURCE=$(test) \ -DTEST_NAME=Fortify$(test)_$(compiler)); \ - $(eval fortify$(test)-tests-$(compiler)_cflags_host := \ - -Wno-error); \ $(eval fortify$(test)-tests-$(compiler)_src_files := \ fortify_test.cpp); \ $(eval fortify_libs += fortify$(test)-tests-$(compiler)); \ From 55ee845b8ec0861d09197b32fbb5f2d34320155d Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Tue, 7 Oct 2014 11:10:36 -0700 Subject: [PATCH 036/114] Inline helpers need to be exported unmangled. __open_2() is used by the fortify implementation of open(2) in fcntl.h, and as such needs an unmangled C name. For some reason (inlining?), this doesn't cause problems at the default optimization level, but does for -O0. The rest of these didn't cause build failures, but they look suspect and probably will, we just haven't caught them yet. (cherry-pick of 658727e111ed6dee7be5239494f0764f7b1b02f8 with conflicts in stdio.h and string.h.) Bug: 17784968 Change-Id: I7391a7a8999ee204eaf6abd14a3d5373ea419d5b --- libc/bionic/__fgets_chk.cpp | 4 ++-- libc/bionic/__recvfrom_chk.cpp | 6 +++--- libc/include/fcntl.h | 4 ++-- libc/include/stdio.h | 32 ++++++++++---------------------- libc/include/string.h | 17 +++++++---------- libc/include/sys/select.h | 3 ++- libc/include/sys/socket.h | 3 ++- libc/include/sys/stat.h | 4 ++-- libc/include/unistd.h | 3 ++- 9 files changed, 32 insertions(+), 44 deletions(-) diff --git a/libc/bionic/__fgets_chk.cpp b/libc/bionic/__fgets_chk.cpp index c09f6c531..75e4ca0f0 100644 --- a/libc/bionic/__fgets_chk.cpp +++ b/libc/bionic/__fgets_chk.cpp @@ -43,8 +43,8 @@ * This fgets check is called if _FORTIFY_SOURCE is defined and * greater than 0. */ -extern "C" char* __fgets_chk(char* dest, int supplied_size, - FILE* stream, size_t dest_len_from_compiler) { +char* __fgets_chk(char* dest, int supplied_size, FILE* stream, + size_t dest_len_from_compiler) { if (supplied_size < 0) { __fortify_chk_fail("fgets: buffer size < 0", 0); } diff --git a/libc/bionic/__recvfrom_chk.cpp b/libc/bionic/__recvfrom_chk.cpp index 48baa8e2d..9c894b078 100644 --- a/libc/bionic/__recvfrom_chk.cpp +++ b/libc/bionic/__recvfrom_chk.cpp @@ -32,9 +32,9 @@ #include #include "private/libc_logging.h" -extern "C" -ssize_t __recvfrom_chk(int socket, void* buf, size_t len, size_t buflen, unsigned int flags, - const struct sockaddr* src_addr, socklen_t* addrlen) { +ssize_t __recvfrom_chk(int socket, void* buf, size_t len, size_t buflen, + int flags, const struct sockaddr* src_addr, + socklen_t* addrlen) { if (__predict_false(len > buflen)) { __fortify_chk_fail("recvfrom: prevented write past end of buffer", 0); } diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h index 87c848163..794e62c03 100644 --- a/libc/include/fcntl.h +++ b/libc/include/fcntl.h @@ -81,8 +81,6 @@ extern ssize_t tee(int, int, size_t, unsigned int); extern int unlinkat(int, const char*, int); extern ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int); -#if defined(__BIONIC_FORTIFY) - extern int __open_2(const char*, int); extern int __open_real(const char*, int, ...) __RENAME(open); extern int __openat_2(int, const char*, int); @@ -90,6 +88,8 @@ extern int __openat_real(int, const char*, int, ...) __RENAME(openat); __errordecl(__creat_missing_mode, "called with O_CREAT, but missing mode"); __errordecl(__creat_too_many_args, "too many arguments"); +#if defined(__BIONIC_FORTIFY) + #if !defined(__clang__) __BIONIC_FORTIFY_INLINE diff --git a/libc/include/stdio.h b/libc/include/stdio.h index 38a267771..a0161dec4 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -47,6 +47,8 @@ #define __need_NULL #include +__BEGIN_DECLS + #define _FSTDIO /* Define for new stdio with functions. */ typedef off_t fpos_t; /* stdio file position type */ @@ -136,9 +138,7 @@ typedef struct __sFILE { fpos_t _offset; /* current lseek offset */ } FILE; -__BEGIN_DECLS extern FILE __sF[]; -__END_DECLS #define __SLBF 0x0001 /* line buffered */ #define __SNBF 0x0002 /* unbuffered */ @@ -208,7 +208,6 @@ __END_DECLS /* * Functions defined in ANSI C standard. */ -__BEGIN_DECLS void clearerr(FILE *); int fclose(FILE *); int feof(FILE *); @@ -296,16 +295,12 @@ int vsscanf(const char * __restrict, const char * __restrict, __va_list) __scanflike(2, 0); #endif /* __ISO_C_VISIBLE >= 1999 || __BSD_VISIBLE */ -__END_DECLS - - /* * Functions defined in POSIX 1003.1. */ #if __BSD_VISIBLE || __POSIX_VISIBLE || __XPG_VISIBLE #define L_ctermid 1024 /* size for ctermid(); PATH_MAX */ -__BEGIN_DECLS FILE *fdopen(int, const char *); int fileno(FILE *); @@ -329,15 +324,12 @@ int putc_unlocked(int, FILE *); int putchar_unlocked(int); #endif /* __POSIX_VISIBLE >= 199506 */ -__END_DECLS - #endif /* __BSD_VISIBLE || __POSIX_VISIBLE || __XPG_VISIBLE */ /* * Routines that are purely local. */ #if __BSD_VISIBLE -__BEGIN_DECLS int asprintf(char ** __restrict, const char * __restrict, ...) __printflike(2, 3); char *fgetln(FILE * __restrict, size_t * __restrict); @@ -347,25 +339,26 @@ int setlinebuf(FILE *); int vasprintf(char ** __restrict, const char * __restrict, __va_list) __printflike(2, 0); -__END_DECLS /* * Stdio function-access interface. */ -__BEGIN_DECLS FILE *funopen(const void *, int (*)(void *, char *, int), int (*)(void *, const char *, int), fpos_t (*)(void *, fpos_t, int), int (*)(void *)); -__END_DECLS + #define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0) #define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0) #endif /* __BSD_VISIBLE */ -#if defined(__BIONIC_FORTIFY) +extern char* __fgets_chk(char*, int, FILE*, size_t); +extern char* __fgets_real(char*, int, FILE*) __RENAME(fgets); +__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer"); +__errordecl(__fgets_too_small_error, "fgets called with size less than zero"); -__BEGIN_DECLS +#if defined(__BIONIC_FORTIFY) __BIONIC_FORTIFY_INLINE __printflike(3, 0) @@ -411,11 +404,6 @@ int sprintf(char *dest, const char *format, ...) } #endif -extern char* __fgets_chk(char*, int, FILE*, size_t); -extern char* __fgets_real(char*, int, FILE*) __RENAME(fgets); -__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer"); -__errordecl(__fgets_too_small_error, "fgets called with size less than zero"); - #if !defined(__clang__) __BIONIC_FORTIFY_INLINE @@ -450,8 +438,8 @@ char *fgets(char* dest, int size, FILE* stream) { #endif /* !defined(__clang__) */ -__END_DECLS - #endif /* defined(__BIONIC_FORTIFY) */ +__END_DECLS + #endif /* _STDIO_H_ */ diff --git a/libc/include/string.h b/libc/include/string.h index 29717605a..f2f6dd2e6 100644 --- a/libc/include/string.h +++ b/libc/include/string.h @@ -92,6 +92,13 @@ extern size_t strxfrm(char* __restrict, const char* __restrict, size_t); extern int strcoll_l(const char *, const char *, locale_t) __purefunc; extern size_t strxfrm_l(char* __restrict, const char* __restrict, size_t, locale_t); +extern char* __stpncpy_chk2(char* __restrict, const char* __restrict, size_t, size_t, size_t); +extern char* __strncpy_chk2(char* __restrict, const char* __restrict, size_t, size_t, size_t); +extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcpy); +extern size_t __strlcpy_chk(char *, const char *, size_t, size_t); +extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcat); +extern size_t __strlcat_chk(char* __restrict, const char* __restrict, size_t, size_t); + #if defined(__BIONIC_FORTIFY) __BIONIC_FORTIFY_INLINE @@ -114,8 +121,6 @@ char* strcpy(char* __restrict dest, const char* __restrict src) { return __builtin___strcpy_chk(dest, src, __bos(dest)); } -extern char* __stpncpy_chk2(char* __restrict, const char* __restrict, size_t, size_t, size_t); - __BIONIC_FORTIFY_INLINE char* stpncpy(char* __restrict dest, const char* __restrict src, size_t n) { size_t bos_dest = __bos(dest); @@ -137,8 +142,6 @@ char* stpncpy(char* __restrict dest, const char* __restrict src, size_t n) { return __stpncpy_chk2(dest, src, n, bos_dest, bos_src); } -extern char* __strncpy_chk2(char* __restrict, const char* __restrict, size_t, size_t, size_t); - __BIONIC_FORTIFY_INLINE char* strncpy(char* __restrict dest, const char* __restrict src, size_t n) { size_t bos_dest = __bos(dest); @@ -175,9 +178,6 @@ void* memset(void *s, int c, size_t n) { return __builtin___memset_chk(s, c, n, __bos0(s)); } -extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcpy); -extern size_t __strlcpy_chk(char *, const char *, size_t, size_t); - __BIONIC_FORTIFY_INLINE size_t strlcpy(char* __restrict dest, const char* __restrict src, size_t size) { size_t bos = __bos(dest); @@ -198,9 +198,6 @@ size_t strlcpy(char* __restrict dest, const char* __restrict src, size_t size) { return __strlcpy_chk(dest, src, size, bos); } -extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcat); -extern size_t __strlcat_chk(char* __restrict, const char* __restrict, size_t, size_t); - __BIONIC_FORTIFY_INLINE size_t strlcat(char* __restrict dest, const char* __restrict src, size_t size) { diff --git a/libc/include/sys/select.h b/libc/include/sys/select.h index 4ddcb6a31..32c1206f1 100644 --- a/libc/include/sys/select.h +++ b/libc/include/sys/select.h @@ -51,10 +51,11 @@ typedef struct { #define FD_ZERO(set) (memset(set, 0, sizeof(*(fd_set*)(set)))) -#if defined(__BIONIC_FORTIFY) extern void __FD_CLR_chk(int, fd_set*, size_t); extern void __FD_SET_chk(int, fd_set*, size_t); extern int __FD_ISSET_chk(int, fd_set*, size_t); + +#if defined(__BIONIC_FORTIFY) #define FD_CLR(fd, set) __FD_CLR_chk(fd, set, __bos(set)) #define FD_SET(fd, set) __FD_SET_chk(fd, set, __bos(set)) #define FD_ISSET(fd, set) __FD_ISSET_chk(fd, set, __bos(set)) diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h index a8840ff46..43d15865f 100644 --- a/libc/include/sys/socket.h +++ b/libc/include/sys/socket.h @@ -291,11 +291,12 @@ extern ssize_t recv(int, void*, size_t, int); __socketcall ssize_t sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t); __socketcall ssize_t recvfrom(int, void*, size_t, int, const struct sockaddr*, socklen_t*); -#if defined(__BIONIC_FORTIFY) __errordecl(__recvfrom_error, "recvfrom called with size bigger than buffer"); extern ssize_t __recvfrom_chk(int, void*, size_t, size_t, int, const struct sockaddr*, socklen_t*); extern ssize_t __recvfrom_real(int, void*, size_t, int, const struct sockaddr*, socklen_t*) __RENAME(recvfrom); +#if defined(__BIONIC_FORTIFY) + __BIONIC_FORTIFY_INLINE ssize_t recvfrom(int fd, void* buf, size_t len, int flags, const struct sockaddr* src_addr, socklen_t* addr_len) { size_t bos = __bos0(buf); diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h index a6cc368cf..9c7373ac6 100644 --- a/libc/include/sys/stat.h +++ b/libc/include/sys/stat.h @@ -159,12 +159,12 @@ extern int stat64(const char*, struct stat64*); extern int mknod(const char*, mode_t, dev_t); extern mode_t umask(mode_t); -#if defined(__BIONIC_FORTIFY) - extern mode_t __umask_chk(mode_t); extern mode_t __umask_real(mode_t) __RENAME(umask); __errordecl(__umask_invalid_mode, "umask called with invalid mode"); +#if defined(__BIONIC_FORTIFY) + __BIONIC_FORTIFY_INLINE mode_t umask(mode_t mode) { #if !defined(__clang__) diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 781fc4435..9b9adcead 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -197,12 +197,13 @@ extern int tcsetpgrp(int fd, pid_t _pid); } while (_rc == -1 && errno == EINTR); \ _rc; }) -#if defined(__BIONIC_FORTIFY) extern ssize_t __read_chk(int, void*, size_t, size_t); __errordecl(__read_dest_size_error, "read called with size bigger than destination"); __errordecl(__read_count_toobig_error, "read called with count > SSIZE_MAX"); extern ssize_t __read_real(int, void*, size_t) __RENAME(read); +#if defined(__BIONIC_FORTIFY) + __BIONIC_FORTIFY_INLINE ssize_t read(int fd, void* buf, size_t count) { size_t bos = __bos0(buf); From 2f25cf373ca7c875956a7c06483b30d381296817 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 9 Oct 2014 14:01:47 -0700 Subject: [PATCH 037/114] Fix pthread_attr_getstack under valgrind. valgrind seems to mess with the stack enough that the kernel will report "[stack:pid]" rather than "[stack]" in /proc/self/maps, so switch to the task-specific file instead to force "[stack]". (There are two conditions in the kernel code that decides which form to output.) Bug: 17897476 (cherry picked from commit 9afb2f2106a5d659854c175c574c1c31e0e205a2) Change-Id: I92c331ef6fb5868af49e75bc595710d290a95f5b --- libc/bionic/pthread_attr.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp index c93970a19..c65ccc132 100644 --- a/libc/bionic/pthread_attr.cpp +++ b/libc/bionic/pthread_attr.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "private/bionic_string_utils.h" #include "private/ErrnoRestorer.h" @@ -126,8 +127,12 @@ static int __pthread_attr_getstack_main_thread(void** stack_base, size_t* stack_ stack_limit.rlim_cur = 8 * 1024 * 1024; } - // It doesn't matter which thread we are; we're just looking for "[stack]". - FILE* fp = fopen("/proc/self/maps", "re"); + // It shouldn't matter which thread we are because we're just looking for "[stack]", but + // valgrind seems to mess with the stack enough that the kernel will report "[stack:pid]" + // instead if you look in /proc/self/maps, so we need to look in /proc/pid/task/pid/maps. + char path[64]; + snprintf(path, sizeof(path), "/proc/self/task/%d/maps", getpid()); + FILE* fp = fopen(path, "re"); if (fp == NULL) { return errno; } @@ -143,7 +148,7 @@ static int __pthread_attr_getstack_main_thread(void** stack_base, size_t* stack_ } } } - __libc_fatal("No [stack] line found in /proc/self/maps!"); + __libc_fatal("No [stack] line found in \"%s\"!", path); } int pthread_attr_getstack(const pthread_attr_t* attr, void** stack_base, size_t* stack_size) { From f4ada9c9ce31c7e56146a4cb703747385bc043a5 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Fri, 10 Oct 2014 08:40:21 -0700 Subject: [PATCH 038/114] Return total footprint, not high water mark. The mallinfo usmblks value returned by dlmalloc is a little misleading. It's not the current max, it's the historical high water mark. This leads to dumpsys meminfo producing native memory numbers that don't add up. Change this to the real total footprint, not this high water mark. Bug: 17265653 Change-Id: Id0293a1b50c9b0be8795405049f537a51ab0e8b7 --- libc/upstream-dlmalloc/malloc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libc/upstream-dlmalloc/malloc.c b/libc/upstream-dlmalloc/malloc.c index 4362f49ff..3c9d36bf4 100644 --- a/libc/upstream-dlmalloc/malloc.c +++ b/libc/upstream-dlmalloc/malloc.c @@ -3526,7 +3526,9 @@ static struct mallinfo internal_mallinfo(mstate m) { nm.arena = sum; nm.ordblks = nfree; nm.hblkhd = m->footprint - sum; - nm.usmblks = m->max_footprint; + /* BEGIN android-changed: usmblks set to footprint from max_footprint */ + nm.usmblks = m->footprint; + /* END android-changed */ nm.uordblks = m->footprint - mfree; nm.fordblks = mfree; nm.keepcost = m->topsize; From c712ceeec4c15da8488c5ce143fcc6b0a02d74f3 Mon Sep 17 00:00:00 2001 From: Hans Boehm Date: Tue, 30 Sep 2014 18:31:04 -0700 Subject: [PATCH 039/114] Make memory_order_acquire visible in global namespace We were missing that using directive when including . Bug:17736764 Change-Id: Ie8ca92a952749415567bcd5fa21d56629a364660 (cherry picked from commit 76ac4d0853c3bba0c65edc98a9cdf932c452e252) --- libc/include/stdatomic.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libc/include/stdatomic.h b/libc/include/stdatomic.h index 3db25a78e..bcea85924 100644 --- a/libc/include/stdatomic.h +++ b/libc/include/stdatomic.h @@ -89,6 +89,7 @@ using std::atomic_signal_fence; using std::memory_order; using std::memory_order_relaxed; using std::memory_order_consume; +using std::memory_order_acquire; using std::memory_order_release; using std::memory_order_acq_rel; using std::memory_order_seq_cst; From de01780f46e4e4540c7a1ea7d0302f460c880e9d Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Fri, 3 Oct 2014 17:52:44 -0700 Subject: [PATCH 040/114] Add file_offset parameter to android_extinfo Bug: 17762003 (cherry picked from commit 07e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514) Change-Id: I72d527831384ff5dde013a4c8dfe639fbec165f5 --- libc/include/android/dlext.h | 10 ++- linker/dlfcn.cpp | 2 +- linker/linker.cpp | 68 ++++++++++------- linker/linker.h | 8 +- linker/linker_phdr.cpp | 17 +++-- linker/linker_phdr.h | 3 +- tests/dlext_test.cpp | 91 ++++++++++++++++++----- tests/libs/Android.build.dlext_testzip.mk | 48 ++++++++++++ tests/libs/Android.mk | 17 +++++ 9 files changed, 206 insertions(+), 58 deletions(-) create mode 100644 tests/libs/Android.build.dlext_testzip.mk diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h index 5c3a206a4..f81ec70d5 100644 --- a/libc/include/android/dlext.h +++ b/libc/include/android/dlext.h @@ -54,12 +54,19 @@ enum { */ ANDROID_DLEXT_USE_LIBRARY_FD = 0x10, + /* When opening library using library_fd read it starting with library_offset + * This flag is only valid when ANDROID_DLEXT_USE_LIBRARY_FD is set. + */ + + ANDROID_DLEXT_USE_LIBRARY_OFFSET = 0x20, + /* Mask of valid bits */ ANDROID_DLEXT_VALID_FLAG_BITS = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT | ANDROID_DLEXT_WRITE_RELRO | ANDROID_DLEXT_USE_RELRO | - ANDROID_DLEXT_USE_LIBRARY_FD, + ANDROID_DLEXT_USE_LIBRARY_FD | + ANDROID_DLEXT_USE_LIBRARY_OFFSET, }; typedef struct { @@ -68,6 +75,7 @@ typedef struct { size_t reserved_size; int relro_fd; int library_fd; + off64_t library_offset; } android_dlextinfo; extern void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo); diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 9801fa172..3631d2fe1 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -232,7 +232,7 @@ static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 }; static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; #endif -static soinfo __libdl_info("libdl.so", nullptr); +static soinfo __libdl_info("libdl.so", nullptr, 0); // This is used by the dynamic linker. Every process gets these symbols for free. soinfo* get_libdl_info() { diff --git a/linker/linker.cpp b/linker/linker.cpp index 1befaa6a9..d6d5f35f6 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -285,13 +285,13 @@ static void protect_data(int protection) { g_soinfo_links_allocator.protect_all(protection); } -static soinfo* soinfo_alloc(const char* name, struct stat* file_stat) { +static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset) { if (strlen(name) >= SOINFO_NAME_LEN) { DL_ERR("library name \"%s\" too long", name); return nullptr; } - soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat); + soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset); sonext->next = si; sonext = si; @@ -457,7 +457,7 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) return nullptr; } -soinfo::soinfo(const char* name, const struct stat* file_stat) { +soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset) { memset(this, 0, sizeof(*this)); strlcpy(this->name, name, sizeof(this->name)); @@ -465,8 +465,9 @@ soinfo::soinfo(const char* name, const struct stat* file_stat) { version = SOINFO_VERSION; if (file_stat != nullptr) { - set_st_dev(file_stat->st_dev); - set_st_ino(file_stat->st_ino); + this->st_dev = file_stat->st_dev; + this->st_ino = file_stat->st_ino; + this->file_offset = file_offset; } } @@ -811,10 +812,14 @@ static void for_each_dt_needed(const soinfo* si, F action) { static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { int fd = -1; + off64_t file_offset = 0; ScopedFd file_guard(-1); if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { fd = extinfo->library_fd; + if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_OFFSET) != 0) { + file_offset = extinfo->library_offset; + } } else { // Open the file. fd = open_library(name); @@ -826,6 +831,11 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl file_guard.reset(fd); } + if ((file_offset % PAGE_SIZE) != 0) { + DL_ERR("file offset for the library %s is not page-aligned: %" PRId64, name, file_offset); + return nullptr; + } + struct stat file_stat; if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); @@ -838,7 +848,8 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl if (si->get_st_dev() != 0 && si->get_st_ino() != 0 && si->get_st_dev() == file_stat.st_dev && - si->get_st_ino() == file_stat.st_ino) { + si->get_st_ino() == file_stat.st_ino && + si->get_file_offset() == file_offset) { TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name); return si; } @@ -850,12 +861,12 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl } // Read the ELF header and load the segments. - ElfReader elf_reader(name, fd); + ElfReader elf_reader(name, fd, file_offset); if (!elf_reader.Load(extinfo)) { return nullptr; } - soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat); + soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset); if (si == nullptr) { return nullptr; } @@ -1068,9 +1079,16 @@ soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) DL_ERR("invalid flags to dlopen: %x", flags); return nullptr; } - if (extinfo != nullptr && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) { - DL_ERR("invalid extended flags to android_dlopen_ext: %" PRIx64, extinfo->flags); - return nullptr; + if (extinfo != nullptr) { + if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) { + DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags); + return nullptr; + } + if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 && + (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_OFFSET) != 0) { + DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags); + return nullptr; + } } protect_data(PROT_READ | PROT_WRITE); soinfo* si = find_library(name, flags, extinfo); @@ -1752,18 +1770,6 @@ void soinfo::remove_all_links() { children.clear(); } -void soinfo::set_st_dev(dev_t dev) { - if (has_min_version(0)) { - st_dev = dev; - } -} - -void soinfo::set_st_ino(ino_t ino) { - if (has_min_version(0)) { - st_ino = ino; - } -} - dev_t soinfo::get_st_dev() { if (has_min_version(0)) { return st_dev; @@ -1780,6 +1786,14 @@ ino_t soinfo::get_st_ino() { return 0; } +off64_t soinfo::get_file_offset() { + if (has_min_version(1)) { + return file_offset; + } + + return 0; +} + // This is a return on get_children()/get_parents() if // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -2200,7 +2214,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { return; } - soinfo* si = soinfo_alloc("[vdso]", nullptr); + soinfo* si = soinfo_alloc("[vdso]", nullptr, 0); si->phdr = reinterpret_cast(reinterpret_cast(ehdr_vdso) + ehdr_vdso->e_phoff); si->phnum = ehdr_vdso->e_phnum; @@ -2221,7 +2235,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { #else #define LINKER_PATH "/system/bin/linker" #endif -static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr); +static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0); /* gdb expects the linker to be in the debug shared object list. * Without this, gdb has trouble locating the linker's ".text" @@ -2285,7 +2299,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( INFO("[ android linker & debugger ]"); - soinfo* si = soinfo_alloc(args.argv[0], nullptr); + soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0); if (si == nullptr) { exit(EXIT_FAILURE); } @@ -2473,7 +2487,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_addr); ElfW(Phdr)* phdr = reinterpret_cast(linker_addr + elf_hdr->e_phoff); - soinfo linker_so("[dynamic linker]", nullptr); + soinfo linker_so("[dynamic linker]", nullptr, 0); // If the linker is not acting as PT_INTERP entry_point is equal to // _start. Which means that the linker is running as an executable and diff --git a/linker/linker.h b/linker/linker.h index 3abab294f..3b140ac24 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -197,11 +197,9 @@ struct soinfo { #if !defined(__LP64__) bool has_text_relocations; #endif - // TODO: remove this flag, dynamic linker - // should not use it in any way. bool has_DT_SYMBOLIC; - soinfo(const char* name, const struct stat* file_stat); + soinfo(const char* name, const struct stat* file_stat, off64_t file_offset); void CallConstructors(); void CallDestructors(); @@ -212,10 +210,9 @@ struct soinfo { void add_child(soinfo* child); void remove_all_links(); - void set_st_dev(dev_t st_dev); - void set_st_ino(ino_t st_ino); ino_t get_st_ino(); dev_t get_st_dev(); + off64_t get_file_offset(); soinfo_list_t& get_children(); soinfo_list_t& get_parents(); @@ -248,6 +245,7 @@ struct soinfo { soinfo_list_t parents; // version >= 1 + off64_t file_offset; }; extern soinfo* get_libdl_info(); diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index 44c8e9e70..e0d6d0e78 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -119,8 +119,8 @@ MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \ MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE)) -ElfReader::ElfReader(const char* name, int fd) - : name_(name), fd_(fd), +ElfReader::ElfReader(const char* name, int fd, off64_t file_offset) + : name_(name), fd_(fd), file_offset_(file_offset), phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0), load_start_(nullptr), load_size_(0), load_bias_(0), loaded_phdr_(nullptr) { @@ -142,6 +142,13 @@ bool ElfReader::Load(const android_dlextinfo* extinfo) { } bool ElfReader::ReadElfHeader() { + off64_t actual_offset = lseek64(fd_, file_offset_, SEEK_SET); + + if (actual_offset != file_offset_) { + DL_ERR("seek to %" PRId64 " failed: %s", file_offset_, strerror(errno)); + return false; + } + ssize_t rc = TEMP_FAILURE_RETRY(read(fd_, &header_, sizeof(header_))); if (rc < 0) { DL_ERR("can't read file \"%s\": %s", name_, strerror(errno)); @@ -225,7 +232,7 @@ bool ElfReader::ReadProgramHeader() { phdr_size_ = page_max - page_min; - void* mmap_result = mmap(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min); + void* mmap_result = mmap64(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, file_offset_ + page_min); if (mmap_result == MAP_FAILED) { DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno)); return false; @@ -356,12 +363,12 @@ bool ElfReader::LoadSegments() { ElfW(Addr) file_length = file_end - file_page_start; if (file_length != 0) { - void* seg_addr = mmap(reinterpret_cast(seg_page_start), + void* seg_addr = mmap64(reinterpret_cast(seg_page_start), file_length, PFLAGS_TO_PROT(phdr->p_flags), MAP_FIXED|MAP_PRIVATE, fd_, - file_page_start); + file_offset_ + file_page_start); if (seg_addr == MAP_FAILED) { DL_ERR("couldn't map \"%s\" segment %zd: %s", name_, i, strerror(errno)); return false; diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h index 593fb5a20..65d302cdb 100644 --- a/linker/linker_phdr.h +++ b/linker/linker_phdr.h @@ -39,7 +39,7 @@ class ElfReader { public: - ElfReader(const char* name, int fd); + ElfReader(const char* name, int fd, off64_t file_offset); ~ElfReader(); bool Load(const android_dlextinfo* extinfo); @@ -61,6 +61,7 @@ class ElfReader { const char* name_; int fd_; + off64_t file_offset_; ElfW(Ehdr) header_; size_t phdr_num_; diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index da630463d..5206965e4 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -31,7 +31,7 @@ #define ASSERT_DL_NOTNULL(ptr) \ - ASSERT_TRUE(ptr != NULL) << "dlerror: " << dlerror() + ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror() #define ASSERT_DL_ZERO(i) \ ASSERT_EQ(0, i) << "dlerror: " << dlerror() @@ -46,23 +46,31 @@ typedef int (*fn)(void); #define LIBSIZE 1024*1024 // how much address space to reserve for it #if defined(__LP64__) -#define LIBPATH "%s/nativetest64/libdlext_test_fd/libdlext_test_fd.so" +#define LIBPATH_PREFIX "%s/nativetest64/libdlext_test_fd/" #else -#define LIBPATH "%s/nativetest/libdlext_test_fd/libdlext_test_fd.so" +#define LIBPATH_PREFIX "%s/nativetest/libdlext_test_fd/" #endif +#define LIBPATH LIBPATH_PREFIX "libdlext_test_fd.so" +#define LIBZIPPATH LIBPATH_PREFIX "dlext_test.zip" + +#define LIBZIP_OFFSET 2*PAGE_SIZE + class DlExtTest : public ::testing::Test { protected: virtual void SetUp() { - handle_ = NULL; + handle_ = nullptr; // verify that we don't have the library loaded already - ASSERT_EQ(NULL, dlsym(RTLD_DEFAULT, "getRandomNumber")); + void* h = dlopen(LIBNAME, RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(h == nullptr); + h = dlopen(LIBNAME_NORELRO, RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(h == nullptr); // call dlerror() to swallow the error, and check it was the one we wanted - ASSERT_STREQ("undefined symbol: getRandomNumber", dlerror()); + ASSERT_STREQ("dlopen failed: library \"" LIBNAME_NORELRO "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); } virtual void TearDown() { - if (handle_ != NULL) { + if (handle_ != nullptr) { ASSERT_DL_ZERO(dlclose(handle_)); } } @@ -71,7 +79,7 @@ protected: }; TEST_F(DlExtTest, ExtInfoNull) { - handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, NULL); + handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, nullptr); ASSERT_DL_NOTNULL(handle_); fn f = reinterpret_cast(dlsym(handle_, "getRandomNumber")); ASSERT_DL_NOTNULL(f); @@ -90,7 +98,7 @@ TEST_F(DlExtTest, ExtInfoNoFlags) { TEST_F(DlExtTest, ExtInfoUseFd) { const char* android_data = getenv("ANDROID_DATA"); - ASSERT_TRUE(android_data != NULL); + ASSERT_TRUE(android_data != nullptr); char lib_path[PATH_MAX]; snprintf(lib_path, sizeof(lib_path), LIBPATH, android_data); @@ -105,8 +113,55 @@ TEST_F(DlExtTest, ExtInfoUseFd) { EXPECT_EQ(4, f()); } +TEST_F(DlExtTest, ExtInfoUseFdWithOffset) { + const char* android_data = getenv("ANDROID_DATA"); + ASSERT_TRUE(android_data != nullptr); + + char lib_path[PATH_MAX]; + snprintf(lib_path, sizeof(lib_path), LIBZIPPATH, android_data); + + android_dlextinfo extinfo; + extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_OFFSET; + extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC)); + extinfo.library_offset = LIBZIP_OFFSET; + + handle_ = android_dlopen_ext(lib_path, RTLD_NOW, &extinfo); + ASSERT_DL_NOTNULL(handle_); + + fn f = reinterpret_cast(dlsym(handle_, "getRandomNumber")); + ASSERT_DL_NOTNULL(f); + EXPECT_EQ(4, f()); +} + +TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) { + const char* android_data = getenv("ANDROID_DATA"); + ASSERT_TRUE(android_data != nullptr); + + char lib_path[PATH_MAX]; + snprintf(lib_path, sizeof(lib_path), LIBZIPPATH, android_data); + + android_dlextinfo extinfo; + extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_OFFSET; + extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC)); + extinfo.library_offset = 17; + + handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); + ASSERT_TRUE(handle_ == nullptr); + ASSERT_STREQ("dlopen failed: file offset for the library libname_placeholder is not page-aligned: 17", dlerror()); +} + +TEST_F(DlExtTest, ExtInfoUseOffsetWihtoutFd) { + android_dlextinfo extinfo; + extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_OFFSET; + extinfo.library_offset = LIBZIP_OFFSET; + + handle_ = android_dlopen_ext("/some/lib/that/does_not_exist", RTLD_NOW, &extinfo); + ASSERT_TRUE(handle_ == nullptr); + ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror()); +} + TEST_F(DlExtTest, Reserved) { - void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, + void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; @@ -124,7 +179,7 @@ TEST_F(DlExtTest, Reserved) { } TEST_F(DlExtTest, ReservedTooSmall) { - void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, + void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; @@ -132,11 +187,11 @@ TEST_F(DlExtTest, ReservedTooSmall) { extinfo.reserved_addr = start; extinfo.reserved_size = PAGE_SIZE; handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); - EXPECT_EQ(NULL, handle_); + EXPECT_EQ(nullptr, handle_); } TEST_F(DlExtTest, ReservedHint) { - void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, + void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; @@ -154,7 +209,7 @@ TEST_F(DlExtTest, ReservedHint) { } TEST_F(DlExtTest, ReservedHintTooSmall) { - void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, + void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; @@ -174,7 +229,7 @@ class DlExtRelroSharingTest : public DlExtTest { protected: virtual void SetUp() { DlExtTest::SetUp(); - void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, + void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS; @@ -183,7 +238,7 @@ protected: extinfo_.relro_fd = -1; const char* android_data = getenv("ANDROID_DATA"); - ASSERT_TRUE(android_data != NULL); + ASSERT_TRUE(android_data != nullptr); snprintf(relro_file_, sizeof(relro_file_), "%s/local/tmp/libdlext_test.relro", android_data); } @@ -204,7 +259,7 @@ protected: extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO; extinfo_.relro_fd = relro_fd; void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_); - if (handle == NULL) { + if (handle == nullptr) { fprintf(stderr, "in child: %s\n", dlerror()); exit(1); } @@ -327,7 +382,7 @@ void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool sha } else { handle = dlopen(lib, RTLD_NOW); } - if (handle == NULL) { + if (handle == nullptr) { fprintf(stderr, "in child: %s\n", dlerror()); exit(1); } diff --git a/tests/libs/Android.build.dlext_testzip.mk b/tests/libs/Android.build.dlext_testzip.mk new file mode 100644 index 000000000..e672091a1 --- /dev/null +++ b/tests/libs/Android.build.dlext_testzip.mk @@ -0,0 +1,48 @@ +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# ----------------------------------------------------------------------------- +# Library used by dlext tests - zipped and aligned +# ----------------------------------------------------------------------------- + +# TODO: It there simple way to do this? +$(bionic_2nd_arch_prefix)bionic_dlext_test_zip := \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATES)/libdlext_test_fd/dlext_test_origin.zip +$(bionic_2nd_arch_prefix)bionic_dlext_test_zip_aligned := \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_fd/dlext_test.zip +ALL_MODULES += $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip_aligned) + +$(bionic_2nd_arch_prefix)bionic_dlext_built_shared_libraries := \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libdlext_test_fd.so + +bionic_dlext_test_zip_alignment := 4096 # PAGE_SIZE + +$(bionic_2nd_arch_prefix)bionic_dlext_test_zip_tmpdir := $(dir $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip)) + +$($(bionic_2nd_arch_prefix)bionic_dlext_test_zip)_prepare: $($(bionic_2nd_arch_prefix)bionic_dlext_built_shared_libraries) + $(hide) mkdir -p $(dir $@) + $(hide) cp -p $< $(dir $@) + +$($(bionic_2nd_arch_prefix)bionic_dlext_test_zip): $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip)_prepare + @echo "Zip: $@" + $(hide) (cd $(dir $@) && touch empty_file.txt && zip -rD0 $(notdir $@) empty_file.txt libdlext_test_fd.so) + +$($(bionic_2nd_arch_prefix)bionic_dlext_test_zip_aligned): $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip) | $(ZIPALIGN) + $(hide) rm -rf $@ + $(hide) mkdir -p $(dir $@) + @echo "Zipalign $(bionic_dlext_test_zip_alignment): $@" + $(hide) zipalign $(bionic_dlext_test_zip_alignment) $< $@ + diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index b3554881e..ee97c618a 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -90,6 +90,17 @@ build_type := target build_target := SHARED_LIBRARY include $(TEST_PATH)/Android.build.mk +# ----------------------------------------------------------------------------- +# Library used by dlext tests - zipped and aligned +# ----------------------------------------------------------------------------- +include $(CLEAR_VARS) +bionic_2nd_arch_prefix := +include $(LOCAL_PATH)/Android.build.dlext_testzip.mk +ifneq ($(TARGET_2ND_ARCH),) + bionic_2nd_arch_prefix := $(TARGET_2ND_ARCH_VAR_PREFIX) + include $(LOCAL_PATH)/Android.build.dlext_testzip.mk +endif + # ----------------------------------------------------------------------------- # Library used by dlfcn tests # ----------------------------------------------------------------------------- @@ -332,3 +343,9 @@ build_type := target include $(TEST_PATH)/Android.build.mk build_type := host include $(TEST_PATH)/Android.build.mk + +LOCAL_ADDITIONAL_DEPENDENCIES := \ + $(LOCAL_PATH)/Android.mk \ + $(LOCAL_PATH)/Android.build.dlext_testzip.mk \ + $(LOCAL_PATH)/Android.build.testlib.mk \ + $(TEST_PATH)/Android.build.mk From 0724132c3263145f2a667f453a199d313a5b3d9f Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Mon, 20 Oct 2014 19:09:19 -0700 Subject: [PATCH 041/114] Fix race condition in timer disarm/delete. When setting a repeat timer using the SIGEV_THREAD mechanism, it's possible that the callback can be called after the timer is disarmed or deleted. This happens because the kernel can generate signals that the timer thread will continue to handle even after the timer is supposed to be off. Add two new tests to verify that disarming/deleting doesn't continue to call the callback. Modify the repeat test to finish more quickly than before. Refactor the Counter implementation a bit. Bug: 18039727 Change-Id: I73192c915cdacf608521b1792c54e5af14a34907 --- libc/bionic/posix_timers.cpp | 20 +++++++- tests/time_test.cpp | 95 ++++++++++++++++++++++++++++++------ 2 files changed, 97 insertions(+), 18 deletions(-) diff --git a/libc/bionic/posix_timers.cpp b/libc/bionic/posix_timers.cpp index 7ad0ef1fb..3c664d9c8 100644 --- a/libc/bionic/posix_timers.cpp +++ b/libc/bionic/posix_timers.cpp @@ -62,6 +62,7 @@ struct PosixTimer { pthread_t callback_thread; void (*callback)(sigval_t); sigval_t callback_argument; + volatile bool armed; }; static __kernel_timer_t to_kernel_timer_id(timer_t timer) { @@ -83,7 +84,7 @@ static void* __timer_thread_start(void* arg) { continue; } - if (si.si_code == SI_TIMER) { + if (si.si_code == SI_TIMER && timer->armed) { // This signal was sent because a timer fired, so call the callback. timer->callback(timer->callback_argument); } else if (si.si_code == SI_TKILL) { @@ -95,6 +96,9 @@ static void* __timer_thread_start(void* arg) { } static void __timer_thread_stop(PosixTimer* timer) { + // Immediately mark the timer as disarmed so even if some events + // continue to happen, the callback won't be called. + timer->armed = false; pthread_kill(timer->callback_thread, TIMER_SIGNAL); } @@ -121,6 +125,7 @@ int timer_create(clockid_t clock_id, sigevent* evp, timer_t* timer_id) { // Otherwise, this must be SIGEV_THREAD timer... timer->callback = evp->sigev_notify_function; timer->callback_argument = evp->sigev_value; + timer->armed = false; // Check arguments that the kernel doesn't care about but we do. if (timer->callback == NULL) { @@ -200,7 +205,18 @@ int timer_gettime(timer_t id, itimerspec* ts) { // http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_getoverrun.html int timer_settime(timer_t id, int flags, const itimerspec* ts, itimerspec* ots) { - return __timer_settime(to_kernel_timer_id(id), flags, ts, ots); + PosixTimer* timer= reinterpret_cast(id); + int rc = __timer_settime(timer->kernel_timer_id, flags, ts, ots); + if (rc == 0) { + // Mark the timer as either being armed or disarmed. This avoids the + // callback being called after the disarm for SIGEV_THREAD timers only. + if (ts->it_value.tv_sec != 0 || ts->it_value.tv_nsec != 0) { + timer->armed = true; + } else { + timer->armed = false; + } + } + return rc; } // http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_getoverrun.html diff --git a/tests/time_test.cpp b/tests/time_test.cpp index 241c4a0c4..d637df226 100644 --- a/tests/time_test.cpp +++ b/tests/time_test.cpp @@ -205,24 +205,46 @@ struct Counter { volatile int value; timer_t timer_id; sigevent_t se; + bool timer_valid; - Counter(void (*fn)(sigval_t)) : value(0) { + Counter(void (*fn)(sigval_t)) : value(0), timer_valid(false) { memset(&se, 0, sizeof(se)); se.sigev_notify = SIGEV_THREAD; se.sigev_notify_function = fn; se.sigev_value.sival_ptr = this; + Create(); } void Create() { + ASSERT_FALSE(timer_valid); ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &timer_id)); + timer_valid = true; + } + + void DeleteTimer() { + ASSERT_TRUE(timer_valid); + ASSERT_EQ(0, timer_delete(timer_id)); + timer_valid = false; } ~Counter() { - if (timer_delete(timer_id) != 0) { - abort(); + if (timer_valid) { + DeleteTimer(); } } + void SetTime(time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) { + ::SetTime(timer_id, value_s, value_ns, interval_s, interval_ns); + } + + bool ValueUpdated() { + volatile int current_value = value; + time_t start = time(NULL); + while (current_value == value && (time(NULL) - start) < 5) { + } + return current_value != value; + } + static void CountNotifyFunction(sigval_t value) { Counter* cd = reinterpret_cast(value.sival_ptr); ++cd->value; @@ -233,17 +255,17 @@ struct Counter { ++cd->value; // Setting the initial expiration time to 0 disarms the timer. - SetTime(cd->timer_id, 0, 0, 1, 0); + cd->SetTime(0, 0, 1, 0); } }; TEST(time, timer_settime_0) { Counter counter(Counter::CountAndDisarmNotifyFunction); - counter.Create(); + ASSERT_TRUE(counter.timer_valid); ASSERT_EQ(0, counter.value); - SetTime(counter.timer_id, 0, 1, 1, 0); + counter.SetTime(0, 1, 1, 0); usleep(500000); // The count should just be 1 because we disarmed the timer the first time it fired. @@ -252,15 +274,14 @@ TEST(time, timer_settime_0) { TEST(time, timer_settime_repeats) { Counter counter(Counter::CountNotifyFunction); - counter.Create(); + ASSERT_TRUE(counter.timer_valid); ASSERT_EQ(0, counter.value); - SetTime(counter.timer_id, 0, 1, 0, 10); - usleep(500000); - - // The count should just be > 1 because we let the timer repeat. - ASSERT_GT(counter.value, 1); + counter.SetTime(0, 1, 0, 10); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); } static int timer_create_NULL_signal_handler_invocation_count = 0; @@ -320,17 +341,17 @@ TEST(time, timer_delete_multiple) { TEST(time, timer_create_multiple) { Counter counter1(Counter::CountNotifyFunction); - counter1.Create(); + ASSERT_TRUE(counter1.timer_valid); Counter counter2(Counter::CountNotifyFunction); - counter2.Create(); + ASSERT_TRUE(counter2.timer_valid); Counter counter3(Counter::CountNotifyFunction); - counter3.Create(); + ASSERT_TRUE(counter3.timer_valid); ASSERT_EQ(0, counter1.value); ASSERT_EQ(0, counter2.value); ASSERT_EQ(0, counter3.value); - SetTime(counter2.timer_id, 0, 1, 0, 0); + counter2.SetTime(0, 1, 0, 0); usleep(500000); EXPECT_EQ(0, counter1.value); @@ -403,3 +424,45 @@ TEST(time, clock_gettime) { ASSERT_EQ(0, ts2.tv_sec); ASSERT_LT(ts2.tv_nsec, 1000000); } + +// Test to verify that disarming a repeatable timer disables the +// callbacks. +TEST(time, timer_disarm_terminates) { + Counter counter(Counter::CountNotifyFunction); + ASSERT_TRUE(counter.timer_valid); + + ASSERT_EQ(0, counter.value); + + counter.SetTime(0, 1, 0, 1); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); + + counter.SetTime(0, 0, 1, 0); + volatile int value = counter.value; + usleep(500000); + + // Verify the counter has not been incremented. + ASSERT_EQ(value, counter.value); +} + +// Test to verify that deleting a repeatable timer disables the +// callbacks. +TEST(time, timer_delete_terminates) { + Counter counter(Counter::CountNotifyFunction); + ASSERT_TRUE(counter.timer_valid); + + ASSERT_EQ(0, counter.value); + + counter.SetTime(0, 1, 0, 1); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); + + counter.DeleteTimer(); + volatile int value = counter.value; + usleep(500000); + + // Verify the counter has not been incremented. + ASSERT_EQ(value, counter.value); +} From 3c5c720b0b46ecd801329c09d23bb6e7098d76d3 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Wed, 8 Oct 2014 16:22:03 -0700 Subject: [PATCH 042/114] Build dlext_testzip as custom module. Use $(BUILD_SYSTEM)/base_rules to build it as custom module, so that it's exposed to utilities like mm/mmma etc. Bug: 17887283 Bug: 17762003 (cherry picked from commit 667853d47770fbdb54aaf0b3261b0d4882725770) Change-Id: I405797d16f20dc09e5d84b93b6727b634db2fc2c --- tests/dlext_test.cpp | 2 +- tests/libs/Android.build.dlext_testzip.mk | 41 ++++++++++------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index 5206965e4..55b064297 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -52,7 +52,7 @@ typedef int (*fn)(void); #endif #define LIBPATH LIBPATH_PREFIX "libdlext_test_fd.so" -#define LIBZIPPATH LIBPATH_PREFIX "dlext_test.zip" +#define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_fd_zipaligned.zip" #define LIBZIP_OFFSET 2*PAGE_SIZE diff --git a/tests/libs/Android.build.dlext_testzip.mk b/tests/libs/Android.build.dlext_testzip.mk index e672091a1..d05927ec2 100644 --- a/tests/libs/Android.build.dlext_testzip.mk +++ b/tests/libs/Android.build.dlext_testzip.mk @@ -18,31 +18,24 @@ # Library used by dlext tests - zipped and aligned # ----------------------------------------------------------------------------- -# TODO: It there simple way to do this? -$(bionic_2nd_arch_prefix)bionic_dlext_test_zip := \ - $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATES)/libdlext_test_fd/dlext_test_origin.zip -$(bionic_2nd_arch_prefix)bionic_dlext_test_zip_aligned := \ - $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_fd/dlext_test.zip -ALL_MODULES += $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip_aligned) +include $(CLEAR_VARS) -$(bionic_2nd_arch_prefix)bionic_dlext_built_shared_libraries := \ - $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libdlext_test_fd.so +LOCAL_MODULE_CLASS := SHARED_LIBRARIES +LOCAL_MODULE := libdlext_test_fd_zipaligned +LOCAL_MODULE_SUFFIX := .zip +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_fd +LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix) -bionic_dlext_test_zip_alignment := 4096 # PAGE_SIZE +include $(BUILD_SYSTEM)/base_rules.mk -$(bionic_2nd_arch_prefix)bionic_dlext_test_zip_tmpdir := $(dir $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip)) - -$($(bionic_2nd_arch_prefix)bionic_dlext_test_zip)_prepare: $($(bionic_2nd_arch_prefix)bionic_dlext_built_shared_libraries) - $(hide) mkdir -p $(dir $@) - $(hide) cp -p $< $(dir $@) - -$($(bionic_2nd_arch_prefix)bionic_dlext_test_zip): $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip)_prepare - @echo "Zip: $@" - $(hide) (cd $(dir $@) && touch empty_file.txt && zip -rD0 $(notdir $@) empty_file.txt libdlext_test_fd.so) - -$($(bionic_2nd_arch_prefix)bionic_dlext_test_zip_aligned): $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip) | $(ZIPALIGN) - $(hide) rm -rf $@ - $(hide) mkdir -p $(dir $@) - @echo "Zipalign $(bionic_dlext_test_zip_alignment): $@" - $(hide) zipalign $(bionic_dlext_test_zip_alignment) $< $@ +my_shared_libs := \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libdlext_test_fd.so +$(LOCAL_BUILT_MODULE): PRIVATE_ALIGNMENT := 4096 # PAGE_SIZE +$(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN) + @echo "Zipalign $(PRIVATE_ALIGNMENT): $@" + $(hide) rm -rf $(dir $@) && mkdir -p $(dir $@) + $(hide) cp $^ $(dir $@) + $(hide) (cd $(dir $@) && touch empty_file.txt && zip -rD0 $(notdir $@).unaligned empty_file.txt *.so) + $(hide) $(ZIPALIGN) $(PRIVATE_ALIGNMENT) $@.unaligned $@ From 702ab5b37e77684ee352300d32b078606ee388d0 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 21 Oct 2014 12:09:18 -0700 Subject: [PATCH 043/114] Rename library_offset to library_fd_offset replace lseek() and use pread() instead add test for library_fd_offset > file_size case Bug: 17762003 (cherry picked from commit a6c1279098f24a675d0df74ce1946f5d534b425e) Change-Id: Ie117c745081ee33d07db5341115ff6c8e98b0dec --- libc/include/android/dlext.h | 8 ++++---- linker/linker.cpp | 12 ++++++------ linker/linker_phdr.cpp | 10 ++-------- tests/dlext_test.cpp | 25 +++++++++++++++++-------- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h index f81ec70d5..f27e4e5ab 100644 --- a/libc/include/android/dlext.h +++ b/libc/include/android/dlext.h @@ -54,11 +54,11 @@ enum { */ ANDROID_DLEXT_USE_LIBRARY_FD = 0x10, - /* When opening library using library_fd read it starting with library_offset + /* If opening a library using library_fd read it starting at library_fd_offset. * This flag is only valid when ANDROID_DLEXT_USE_LIBRARY_FD is set. */ - ANDROID_DLEXT_USE_LIBRARY_OFFSET = 0x20, + ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET = 0x20, /* Mask of valid bits */ ANDROID_DLEXT_VALID_FLAG_BITS = ANDROID_DLEXT_RESERVED_ADDRESS | @@ -66,7 +66,7 @@ enum { ANDROID_DLEXT_WRITE_RELRO | ANDROID_DLEXT_USE_RELRO | ANDROID_DLEXT_USE_LIBRARY_FD | - ANDROID_DLEXT_USE_LIBRARY_OFFSET, + ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET, }; typedef struct { @@ -75,7 +75,7 @@ typedef struct { size_t reserved_size; int relro_fd; int library_fd; - off64_t library_offset; + off64_t library_fd_offset; } android_dlextinfo; extern void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo); diff --git a/linker/linker.cpp b/linker/linker.cpp index d6d5f35f6..9425c9d3b 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -817,8 +817,8 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { fd = extinfo->library_fd; - if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_OFFSET) != 0) { - file_offset = extinfo->library_offset; + if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) { + file_offset = extinfo->library_fd_offset; } } else { // Open the file. @@ -832,13 +832,13 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl } if ((file_offset % PAGE_SIZE) != 0) { - DL_ERR("file offset for the library %s is not page-aligned: %" PRId64, name, file_offset); + DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset); return nullptr; } struct stat file_stat; if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { - DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); + DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno)); return nullptr; } @@ -1085,8 +1085,8 @@ soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) return nullptr; } if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 && - (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_OFFSET) != 0) { - DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags); + (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) { + DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags); return nullptr; } } diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index e0d6d0e78..4b1c0cad1 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -142,18 +142,12 @@ bool ElfReader::Load(const android_dlextinfo* extinfo) { } bool ElfReader::ReadElfHeader() { - off64_t actual_offset = lseek64(fd_, file_offset_, SEEK_SET); - - if (actual_offset != file_offset_) { - DL_ERR("seek to %" PRId64 " failed: %s", file_offset_, strerror(errno)); - return false; - } - - ssize_t rc = TEMP_FAILURE_RETRY(read(fd_, &header_, sizeof(header_))); + ssize_t rc = TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_)); if (rc < 0) { DL_ERR("can't read file \"%s\": %s", name_, strerror(errno)); return false; } + if (rc != sizeof(header_)) { DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_, static_cast(rc)); diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index 55b064297..7f706c186 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -121,9 +121,9 @@ TEST_F(DlExtTest, ExtInfoUseFdWithOffset) { snprintf(lib_path, sizeof(lib_path), LIBZIPPATH, android_data); android_dlextinfo extinfo; - extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_OFFSET; + extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC)); - extinfo.library_offset = LIBZIP_OFFSET; + extinfo.library_fd_offset = LIBZIP_OFFSET; handle_ = android_dlopen_ext(lib_path, RTLD_NOW, &extinfo); ASSERT_DL_NOTNULL(handle_); @@ -141,23 +141,32 @@ TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) { snprintf(lib_path, sizeof(lib_path), LIBZIPPATH, android_data); android_dlextinfo extinfo; - extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_OFFSET; + extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC)); - extinfo.library_offset = 17; + extinfo.library_fd_offset = 17; handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); ASSERT_TRUE(handle_ == nullptr); - ASSERT_STREQ("dlopen failed: file offset for the library libname_placeholder is not page-aligned: 17", dlerror()); + ASSERT_STREQ("dlopen failed: file offset for the library \"libname_placeholder\" is not page-aligned: 17", dlerror()); + + extinfo.library_fd_offset = (5LL<<58) + PAGE_SIZE; + handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); + + ASSERT_TRUE(handle_ == nullptr); + // TODO: Better error message when reading with offset > file_size + ASSERT_STREQ("dlopen failed: \"libname_placeholder\" has bad ELF magic", dlerror()); + + close(extinfo.library_fd); } TEST_F(DlExtTest, ExtInfoUseOffsetWihtoutFd) { android_dlextinfo extinfo; - extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_OFFSET; - extinfo.library_offset = LIBZIP_OFFSET; + extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; + extinfo.library_fd_offset = LIBZIP_OFFSET; handle_ = android_dlopen_ext("/some/lib/that/does_not_exist", RTLD_NOW, &extinfo); ASSERT_TRUE(handle_ == nullptr); - ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror()); + ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror()); } TEST_F(DlExtTest, Reserved) { From f13e1eb92ff54db8dc4bf4e988066b3c37eff29d Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Fri, 17 Oct 2014 14:08:54 -0700 Subject: [PATCH 044/114] Fix generic __memcpy_chk implementation. - Clean up the labels (add .L to make them local). - Change to using cfi directives. - Fix unwinding of the __memcpy_chk fail path. Bug: 18033671 (cherry pick from commit 7123d4371a5e04337b1de5f8cdf6cdc1e08e9cad) Change-Id: Ife93bcbfc1949ef29fc8e2dc515b7120632b82b1 --- libc/arch-arm/generic/bionic/memcpy.S | 74 +++++++++++++++------------ 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/libc/arch-arm/generic/bionic/memcpy.S b/libc/arch-arm/generic/bionic/memcpy.S index cd4a13d12..b0c79abf7 100644 --- a/libc/arch-arm/generic/bionic/memcpy.S +++ b/libc/arch-arm/generic/bionic/memcpy.S @@ -39,7 +39,7 @@ ENTRY(__memcpy_chk) cmp r2, r3 - bgt fortify_check_failed + bhi __memcpy_chk_fail // Fall through to memcpy... END(__memcpy_chk) @@ -49,11 +49,14 @@ ENTRY(memcpy) * ARM ABI. Since we have to save R0, we might as well save R4 * which we can use for better pipelining of the reads below */ - .save {r0, r4, lr} stmfd sp!, {r0, r4, lr} + .cfi_def_cfa_offset 12 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r4, 4 + .cfi_rel_offset lr, 8 /* Making room for r5-r11 which will be spilled later */ - .pad #28 sub sp, sp, #28 + .cfi_adjust_cfa_offset 28 // preload the destination because we'll align it to a cache line // with small writes. Also start the source "pump". @@ -63,14 +66,14 @@ ENTRY(memcpy) /* it simplifies things to take care of len<4 early */ cmp r2, #4 - blo copy_last_3_and_return + blo .Lcopy_last_3_and_return /* compute the offset to align the source * offset = (4-(src&3))&3 = -src & 3 */ rsb r3, r1, #0 ands r3, r3, #3 - beq src_aligned + beq .Lsrc_aligned /* align source to 32 bits. We need to insert 2 instructions between * a ldr[b|h] and str[b|h] because byte and half-word instructions @@ -85,12 +88,12 @@ ENTRY(memcpy) strcsb r4, [r0], #1 strcsb r12,[r0], #1 -src_aligned: +.Lsrc_aligned: /* see if src and dst are aligned together (congruent) */ eor r12, r0, r1 tst r12, #3 - bne non_congruent + bne .Lnon_congruent /* Use post-incriment mode for stm to spill r5-r11 to reserved stack * frame. Don't update sp. @@ -100,7 +103,7 @@ src_aligned: /* align the destination to a cache-line */ rsb r3, r0, #0 ands r3, r3, #0x1C - beq congruent_aligned32 + beq .Lcongruent_aligned32 cmp r3, r2 andhi r3, r2, #0x1C @@ -115,14 +118,14 @@ src_aligned: strne r10,[r0], #4 sub r2, r2, r3 -congruent_aligned32: +.Lcongruent_aligned32: /* * here source is aligned to 32 bytes. */ -cached_aligned32: +.Lcached_aligned32: subs r2, r2, #32 - blo less_than_32_left + blo .Lless_than_32_left /* * We preload a cache-line up to 64 bytes ahead. On the 926, this will @@ -160,10 +163,7 @@ cached_aligned32: add r2, r2, #32 - - - -less_than_32_left: +.Lless_than_32_left: /* * less than 32 bytes left at this point (length in r2) */ @@ -197,7 +197,7 @@ less_than_32_left: /********************************************************************/ -non_congruent: +.Lnon_congruent: /* * here source is aligned to 4 bytes * but destination is not. @@ -207,9 +207,9 @@ non_congruent: * partial words in the shift queue) */ cmp r2, #4 - blo copy_last_3_and_return + blo .Lcopy_last_3_and_return - /* Use post-incriment mode for stm to spill r5-r11 to reserved stack + /* Use post-increment mode for stm to spill r5-r11 to reserved stack * frame. Don't update sp. */ stmea sp, {r5-r11} @@ -236,7 +236,7 @@ non_congruent: movcs r3, r3, lsr #8 cmp r2, #4 - blo partial_word_tail + blo .Lpartial_word_tail /* Align destination to 32 bytes (cache line boundary) */ 1: tst r0, #0x1c @@ -248,11 +248,11 @@ non_congruent: str r4, [r0], #4 cmp r2, #4 bhs 1b - blo partial_word_tail + blo .Lpartial_word_tail /* copy 32 bytes at a time */ 2: subs r2, r2, #32 - blo less_than_thirtytwo + blo .Lless_than_thirtytwo /* Use immediate mode for the shifts, because there is an extra cycle * for register shifts, which could account for up to 50% of @@ -260,11 +260,11 @@ non_congruent: */ cmp r12, #24 - beq loop24 + beq .Lloop24 cmp r12, #8 - beq loop8 + beq .Lloop8 -loop16: +.Lloop16: ldr r12, [r1], #4 1: mov r4, r12 ldmia r1!, { r5,r6,r7, r8,r9,r10,r11} @@ -289,9 +289,9 @@ loop16: stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10} mov r3, r11, lsr #16 bhs 1b - b less_than_thirtytwo + b .Lless_than_thirtytwo -loop8: +.Lloop8: ldr r12, [r1], #4 1: mov r4, r12 ldmia r1!, { r5,r6,r7, r8,r9,r10,r11} @@ -316,9 +316,9 @@ loop8: stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10} mov r3, r11, lsr #8 bhs 1b - b less_than_thirtytwo + b .Lless_than_thirtytwo -loop24: +.Lloop24: ldr r12, [r1], #4 1: mov r4, r12 ldmia r1!, { r5,r6,r7, r8,r9,r10,r11} @@ -345,12 +345,12 @@ loop24: bhs 1b -less_than_thirtytwo: +.Lless_than_thirtytwo: /* copy the last 0 to 31 bytes of the source */ rsb r12, lr, #32 /* we corrupted r12, recompute it */ add r2, r2, #32 cmp r2, #4 - blo partial_word_tail + blo .Lpartial_word_tail 1: ldr r5, [r1], #4 sub r2, r2, #4 @@ -360,7 +360,7 @@ less_than_thirtytwo: cmp r2, #4 bhs 1b -partial_word_tail: +.Lpartial_word_tail: /* we have a partial word in the input buffer */ movs r5, lr, lsl #(31-3) strmib r3, [r0], #1 @@ -372,7 +372,7 @@ partial_word_tail: /* Refill spilled registers from the stack. Don't update sp. */ ldmfd sp, {r5-r11} -copy_last_3_and_return: +.Lcopy_last_3_and_return: movs r2, r2, lsl #31 /* copy remaining 0, 1, 2 or 3 bytes */ ldrmib r2, [r1], #1 ldrcsb r3, [r1], #1 @@ -385,9 +385,15 @@ copy_last_3_and_return: add sp, sp, #28 ldmfd sp!, {r0, r4, lr} bx lr +END(memcpy) // Only reached when the __memcpy_chk check fails. -fortify_check_failed: +ENTRY_PRIVATE(__memcpy_chk_fail) + // Preserve lr for backtrace. + push {lr} + .cfi_def_cfa_offset 4 + .cfi_rel_offset lr, 0 + ldr r0, error_message ldr r1, error_code 1: @@ -397,7 +403,7 @@ error_code: .word BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW error_message: .word error_string-(1b+8) -END(memcpy) +END(__memcpy_chk_fail) .data error_string: From 8fab8119dd176a280b62e9e8f2b4f08c0d76f36d Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 22 Oct 2014 12:31:02 -0700 Subject: [PATCH 045/114] Update bionic to tzdata2014i. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the release notes: Changes affecting future time stamps Pacific/Fiji will observe DST from 2014-11-02 02:00 to 2015-01-18 03:00. (Thanks to Ken Rylander for the heads-up.) Guess that future years will use a similar pattern. A new Zone Pacific/Bougainville, for the part of Papua New Guinea that plans to switch from UTC+10 to UTC+11 on 2014-12-28 at 02:00. (Thanks to Kiley Walbom for the heads-up.) Changes affecting time zone abbreviations Since Belarus is not changing its clocks even though Moscow is, the time zone abbreviation in Europe/Minsk is changing from FET to its more-traditional value MSK on 2014-10-26 at 01:00. (Thanks to Alexander Bokovoy for the heads-up about Belarus.) The new abbreviation IDT stands for the pre-1976 use of UT+8 in Indochina, to distinguish it better from ICT (UT+7). Changes affecting past time stamps Many time stamps have been corrected for Asia/Ho_Chi_Minh before 1976 (thanks to Trần Ngọc Quân for an indirect pointer to Trần Tiến Bình's authoritative book). Asia/Ho_Chi_Minh has been added to zone1970.tab, to give tzselect users in Vietnam two choices, since north and south Vietnam disagreed after our 1970 cutoff. Asia/Phnom_Penh and Asia/Vientiane have been turned into links, as they differed from existing zones only for older time stamps. As usual, these changes affect pre-1970 time stamps only. Their old contents have been moved to the 'backzone' file. Bug: 18085936 (cherry picked from commit a05c2a2a705c8298154db6665cbbb4dbe3cdbbd5) Change-Id: If0253cc1515e1bc98e99c6e24eec797836ca7c27 --- libc/zoneinfo/tzdata | Bin 565331 -> 565358 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata index 33bfe6b88d2ea23fc55e4d52a60669dec57dddcd..e9cf16428fd3a6bd6e022ff8f460ee134f9c9a41 100644 GIT binary patch delta 9519 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 Am;e9( delta 9407 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 B`q}^h From aa6cd5819c8ebd254d995388798a4b51af7ca933 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 23 Oct 2014 20:29:42 -0700 Subject: [PATCH 046/114] Use mxcr_mask instead of mxcsr_mask to match glibc. Bug: 18097559 (cherry picked from commit f485547b9267263e1de220a3cc368deaec367191) Change-Id: I242105faa8210abc9635a951b25b127cd64ed23c --- libc/include/sys/user.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/include/sys/user.h b/libc/include/sys/user.h index 18684f183..66b371d50 100644 --- a/libc/include/sys/user.h +++ b/libc/include/sys/user.h @@ -108,7 +108,7 @@ struct user_fpregs_struct { __u64 rip; __u64 rdp; __u32 mxcsr; - __u32 mxcsr_mask; + __u32 mxcr_mask; __u32 st_space[32]; __u32 xmm_space[64]; __u32 padding[24]; From 4c30130a2155c37e80af4c3b53bf4f6ce832e760 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 27 Oct 2014 13:38:21 -0700 Subject: [PATCH 047/114] Disable tzdata in $ANDROID_DATA. Bug: 18139284 Change-Id: I2670dc1791d635139a5d39a438dc08777439476b --- libc/tzcode/localtime.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c index 3bbed9086..28d13f417 100644 --- a/libc/tzcode/localtime.c +++ b/libc/tzcode/localtime.c @@ -2252,14 +2252,11 @@ static int __bionic_open_tzdata_path(const char* path_prefix_variable, const cha } static int __bionic_open_tzdata(const char* olson_id, int* data_size) { - int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/tzdata", olson_id, data_size); - if (fd < 0) { - fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata", olson_id, data_size); - if (fd == -2) { - // The first thing that 'recovery' does is try to format the current time. It doesn't have - // any tzdata available, so we must not abort here --- doing so breaks the recovery image! - fprintf(stderr, "%s: couldn't find any tzdata when looking for %s!\n", __FUNCTION__, olson_id); - } + int fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata", olson_id, data_size); + if (fd == -2) { + // The first thing that 'recovery' does is try to format the current time. It doesn't have + // any tzdata available, so we must not abort here --- doing so breaks the recovery image! + fprintf(stderr, "%s: couldn't find any tzdata when looking for %s!\n", __FUNCTION__, olson_id); } return fd; } From 7dc2b7b30ddc158a5e7aa6945526eb65d354b96c Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 10 Sep 2014 15:20:40 -0700 Subject: [PATCH 048/114] Fix signal trampolines. * LP32 should use sa_restorer too. gdb expects this, and future (>= 3.15) x86 kernels will apparently stop supporting the case where SA_RESTORER isn't set. * gdb and libunwind care about the exact instruction sequences, so we need to modify the code slightly in a few cases to match what they're looking for. * gdb also cares about the exact function names (for some architectures), so we need to use __restore and __restore_rt rather than __sigreturn and __rt_sigreturn. * It's possible that we don't have a VDSO; dl_iterate_phdr shouldn't assume that getauxval(AT_SYSINFO_EHDR) will return a non-null pointer. This fixes unwinding through a signal handler in gdb for all architectures. It doesn't fix libunwind for arm and arm64. I'll keep investigating that... (cherry picked from commit 36f451a6d93b6807944d99fa23396e039c47e845) Bug: 17436734 Change-Id: Ic1ea1184db6655c5d96180dc07bcc09628e647cb --- libc/arch-arm/arm.mk | 2 + libc/arch-arm/bionic/__restore.S | 35 ++++++++++++++++++ libc/arch-arm/bionic/__restore_rt.S | 35 ++++++++++++++++++ libc/arch-arm64/arm64.mk | 2 +- .../{__rt_sigreturn.S => __restore_rt.S} | 9 +++-- libc/arch-x86/bionic/__restore.S | 37 +++++++++++++++++++ libc/arch-x86/bionic/__restore_rt.S | 36 ++++++++++++++++++ libc/arch-x86/x86.mk | 2 + .../{__rt_sigreturn.S => __restore_rt.S} | 8 ++-- libc/arch-x86_64/x86_64.mk | 2 +- libc/bionic/dl_iterate_phdr_static.cpp | 5 +++ libc/bionic/sigaction.cpp | 22 +++++++++-- 12 files changed, 183 insertions(+), 12 deletions(-) create mode 100644 libc/arch-arm/bionic/__restore.S create mode 100644 libc/arch-arm/bionic/__restore_rt.S rename libc/arch-arm64/bionic/{__rt_sigreturn.S => __restore_rt.S} (89%) create mode 100644 libc/arch-x86/bionic/__restore.S create mode 100644 libc/arch-x86/bionic/__restore_rt.S rename libc/arch-x86_64/bionic/{__rt_sigreturn.S => __restore_rt.S} (87%) diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk index 70cc8eba6..fbde87cef 100644 --- a/libc/arch-arm/arm.mk +++ b/libc/arch-arm/arm.mk @@ -55,6 +55,8 @@ libc_bionic_src_files_arm += \ arch-arm/bionic/_exit_with_stack_teardown.S \ arch-arm/bionic/libgcc_compat.c \ arch-arm/bionic/memcmp.S \ + arch-arm/bionic/__restore_rt.S \ + arch-arm/bionic/__restore.S \ arch-arm/bionic/_setjmp.S \ arch-arm/bionic/setjmp.S \ arch-arm/bionic/sigsetjmp.S \ diff --git a/libc/arch-arm/bionic/__restore.S b/libc/arch-arm/bionic/__restore.S new file mode 100644 index 000000000..e76628e16 --- /dev/null +++ b/libc/arch-arm/bionic/__restore.S @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +// This function must have exactly this instruction sequence for gdb and libunwind. +ENTRY_PRIVATE(__restore) + mov r7, #__NR_sigreturn + swi #0 +END(__restore) diff --git a/libc/arch-arm/bionic/__restore_rt.S b/libc/arch-arm/bionic/__restore_rt.S new file mode 100644 index 000000000..5a1fca182 --- /dev/null +++ b/libc/arch-arm/bionic/__restore_rt.S @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +// This function must have exactly this instruction sequence for gdb and libunwind. +ENTRY_PRIVATE(__restore_rt) + mov r7, #__NR_rt_sigreturn + swi #0 +END(__restore_rt) diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk index 6c4f6a6e8..91cd9fb1c 100644 --- a/libc/arch-arm64/arm64.mk +++ b/libc/arch-arm64/arm64.mk @@ -29,7 +29,7 @@ libc_common_src_files_arm64 += \ libc_bionic_src_files_arm64 := \ arch-arm64/bionic/__bionic_clone.S \ arch-arm64/bionic/_exit_with_stack_teardown.S \ - arch-arm64/bionic/__rt_sigreturn.S \ + arch-arm64/bionic/__restore_rt.S \ arch-arm64/bionic/_setjmp.S \ arch-arm64/bionic/setjmp.S \ arch-arm64/bionic/__set_tls.c \ diff --git a/libc/arch-arm64/bionic/__rt_sigreturn.S b/libc/arch-arm64/bionic/__restore_rt.S similarity index 89% rename from libc/arch-arm64/bionic/__rt_sigreturn.S rename to libc/arch-arm64/bionic/__restore_rt.S index 8fb6f0c28..95064903e 100644 --- a/libc/arch-arm64/bionic/__rt_sigreturn.S +++ b/libc/arch-arm64/bionic/__restore_rt.S @@ -28,7 +28,8 @@ #include -ENTRY_PRIVATE(__rt_sigreturn) - mov x8, __NR_rt_sigreturn - svc #0 -END(__rt_sigreturn) +// This function must have exactly this instruction sequence for gdb and libunwind. +ENTRY_PRIVATE(__restore_rt) + mov x8, __NR_rt_sigreturn + svc #0 +END(__restore_rt) diff --git a/libc/arch-x86/bionic/__restore.S b/libc/arch-x86/bionic/__restore.S new file mode 100644 index 000000000..755c3f8e5 --- /dev/null +++ b/libc/arch-x86/bionic/__restore.S @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +// This function must have exactly this instruction sequence for gdb and libunwind. +// This function must have exactly this name for gdb. +ENTRY(__restore) + popl %eax + movl $__NR_sigreturn, %eax + int $0x80 +END(__restore) diff --git a/libc/arch-x86/bionic/__restore_rt.S b/libc/arch-x86/bionic/__restore_rt.S new file mode 100644 index 000000000..0cd808125 --- /dev/null +++ b/libc/arch-x86/bionic/__restore_rt.S @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +// This function must have exactly this instruction sequence for gdb and libunwind. +// This function must have exactly this name for gdb. +ENTRY(__restore_rt) + movl $__NR_rt_sigreturn, %eax + int $0x80 +END(__restore_rt) diff --git a/libc/arch-x86/x86.mk b/libc/arch-x86/x86.mk index 2a0609dde..905519745 100644 --- a/libc/arch-x86/x86.mk +++ b/libc/arch-x86/x86.mk @@ -26,6 +26,8 @@ libc_bionic_src_files_x86 += \ arch-x86/bionic/__bionic_clone.S \ arch-x86/bionic/_exit_with_stack_teardown.S \ arch-x86/bionic/libgcc_compat.c \ + arch-x86/bionic/__restore_rt.S \ + arch-x86/bionic/__restore.S \ arch-x86/bionic/_setjmp.S \ arch-x86/bionic/setjmp.S \ arch-x86/bionic/__set_tls.c \ diff --git a/libc/arch-x86_64/bionic/__rt_sigreturn.S b/libc/arch-x86_64/bionic/__restore_rt.S similarity index 87% rename from libc/arch-x86_64/bionic/__rt_sigreturn.S rename to libc/arch-x86_64/bionic/__restore_rt.S index eddceb15b..d84be219a 100644 --- a/libc/arch-x86_64/bionic/__rt_sigreturn.S +++ b/libc/arch-x86_64/bionic/__restore_rt.S @@ -28,7 +28,9 @@ #include -ENTRY_PRIVATE(__rt_sigreturn) - movl $__NR_rt_sigreturn, %eax +// This function must have exactly this instruction sequence for gdb and libunwind. +// This function must have exactly this name for gdb. +ENTRY(__restore_rt) + mov $__NR_rt_sigreturn, %rax syscall -END(__rt_sigreturn) +END(__restore_rt) diff --git a/libc/arch-x86_64/x86_64.mk b/libc/arch-x86_64/x86_64.mk index b001b5e98..5f12a49d7 100644 --- a/libc/arch-x86_64/x86_64.mk +++ b/libc/arch-x86_64/x86_64.mk @@ -30,7 +30,7 @@ libc_common_src_files_x86_64 += \ libc_bionic_src_files_x86_64 := \ arch-x86_64/bionic/__bionic_clone.S \ arch-x86_64/bionic/_exit_with_stack_teardown.S \ - arch-x86_64/bionic/__rt_sigreturn.S \ + arch-x86_64/bionic/__restore_rt.S \ arch-x86_64/bionic/_setjmp.S \ arch-x86_64/bionic/setjmp.S \ arch-x86_64/bionic/__set_tls.c \ diff --git a/libc/bionic/dl_iterate_phdr_static.cpp b/libc/bionic/dl_iterate_phdr_static.cpp index 155a7a00a..2196ac8b2 100644 --- a/libc/bionic/dl_iterate_phdr_static.cpp +++ b/libc/bionic/dl_iterate_phdr_static.cpp @@ -62,6 +62,11 @@ int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data // Try the VDSO if that didn't work. ElfW(Ehdr)* ehdr_vdso = reinterpret_cast(getauxval(AT_SYSINFO_EHDR)); + if (ehdr_vdso == nullptr) { + // There is no VDSO, so there's nowhere left to look. + return rc; + } + struct dl_phdr_info vdso_info; vdso_info.dlpi_addr = 0; vdso_info.dlpi_name = NULL; diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp index 225a8233e..8ba4e2a2d 100644 --- a/libc/bionic/sigaction.cpp +++ b/libc/bionic/sigaction.cpp @@ -28,8 +28,10 @@ #include +extern "C" void __restore_rt(void); +extern "C" void __restore(void); + #if __LP64__ -extern "C" void __rt_sigreturn(void); extern "C" int __rt_sigaction(int, const struct __kernel_sigaction*, struct __kernel_sigaction*, size_t); #else extern "C" int __sigaction(int, const struct sigaction*, struct sigaction*); @@ -47,7 +49,7 @@ int sigaction(int signal, const struct sigaction* bionic_new_action, struct siga if (!(kernel_new_action.sa_flags & SA_RESTORER)) { kernel_new_action.sa_flags |= SA_RESTORER; - kernel_new_action.sa_restorer = &__rt_sigreturn; + kernel_new_action.sa_restorer = &__restore_rt; } #endif } @@ -75,6 +77,20 @@ int sigaction(int signal, const struct sigaction* bionic_new_action, struct siga #else // The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t. // TODO: if we also had correct struct sigaction definitions available, we could copy in and out. - return __sigaction(signal, bionic_new_action, bionic_old_action); + struct sigaction kernel_new_action; + if (bionic_new_action != NULL) { + kernel_new_action.sa_flags = bionic_new_action->sa_flags; + kernel_new_action.sa_handler = bionic_new_action->sa_handler; + kernel_new_action.sa_mask = bionic_new_action->sa_mask; +#ifdef SA_RESTORER + kernel_new_action.sa_restorer = bionic_new_action->sa_restorer; + + if (!(kernel_new_action.sa_flags & SA_RESTORER)) { + kernel_new_action.sa_flags |= SA_RESTORER; + kernel_new_action.sa_restorer = (kernel_new_action.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore; + } +#endif + } + return __sigaction(signal, (bionic_new_action != NULL) ? &kernel_new_action : NULL, bionic_old_action); #endif } From 5054e1a121fc5aca814815625fe230c4a8abd5a5 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 16 Sep 2014 13:57:39 -0700 Subject: [PATCH 049/114] Fix 32-bit arm unwinding through signal frames. gdb was already okay; libgcc and libunwind need a little extra help. Bug: 17436734 (cherry picked from commit 148dff3ec6114a03acc722ae43990f1b342abad9) Change-Id: I2cc997017acc57c930284af5264f353656b98c7b --- libc/arch-arm/arm.mk | 1 - libc/arch-arm/bionic/__restore.S | 28 ++++++++++++++++++++++- libc/arch-arm/bionic/__restore_rt.S | 35 ----------------------------- 3 files changed, 27 insertions(+), 37 deletions(-) delete mode 100644 libc/arch-arm/bionic/__restore_rt.S diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk index fbde87cef..b1edfccf3 100644 --- a/libc/arch-arm/arm.mk +++ b/libc/arch-arm/arm.mk @@ -55,7 +55,6 @@ libc_bionic_src_files_arm += \ arch-arm/bionic/_exit_with_stack_teardown.S \ arch-arm/bionic/libgcc_compat.c \ arch-arm/bionic/memcmp.S \ - arch-arm/bionic/__restore_rt.S \ arch-arm/bionic/__restore.S \ arch-arm/bionic/_setjmp.S \ arch-arm/bionic/setjmp.S \ diff --git a/libc/arch-arm/bionic/__restore.S b/libc/arch-arm/bionic/__restore.S index e76628e16..98981256b 100644 --- a/libc/arch-arm/bionic/__restore.S +++ b/libc/arch-arm/bionic/__restore.S @@ -28,8 +28,34 @@ #include -// This function must have exactly this instruction sequence for gdb and libunwind. +// gdb is smart enough to unwind through signal frames with just the regular +// CFI information but libgcc and libunwind both need extra help. We do this +// by using .fnstart/.fnend and inserting a nop before both __restore and +// __restore_rt (but covered by the .fnstart/.fnend) so that although they're +// not inside the functions from objdump's point of view, an unwinder that +// blindly looks at the previous instruction (but is then smart enough to check +// the DWARF information to find out where it landed) gets the right answer. + +// We need to place .fnstart ourselves (but we may as well keep the free .fnend). +#undef __bionic_asm_custom_entry +#define __bionic_asm_custom_entry(f) + + .fnstart + .save {r0-r15} + .pad #32 + nop ENTRY_PRIVATE(__restore) + // This function must have exactly this instruction sequence. mov r7, #__NR_sigreturn swi #0 END(__restore) + + .fnstart + .save {r0-r15} + .pad #160 + nop +ENTRY_PRIVATE(__restore_rt) + // This function must have exactly this instruction sequence. + mov r7, #__NR_rt_sigreturn + swi #0 +END(__restore_rt) diff --git a/libc/arch-arm/bionic/__restore_rt.S b/libc/arch-arm/bionic/__restore_rt.S deleted file mode 100644 index 5a1fca182..000000000 --- a/libc/arch-arm/bionic/__restore_rt.S +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -// This function must have exactly this instruction sequence for gdb and libunwind. -ENTRY_PRIVATE(__restore_rt) - mov r7, #__NR_rt_sigreturn - swi #0 -END(__restore_rt) From e5e61a0a920a8e6560735b2e565c3bd7a1e35ba5 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 16 Sep 2014 15:49:50 -0700 Subject: [PATCH 050/114] Use the kernel's sa_restorer for aarch64. gdb was happy with what we had, but libgcc and libunwind weren't. libgcc is happy with the kernel's restorer (because of the extra nop), though libunwind looks like it's going to need code changes regardless. We could make our restorer more like the kernel's one, but why bother when we can just let the kernel supply the canonical one? Bug: 17436734 (cherry picked from commit 1cff9a89645a8f362a9ce19c7f9544e98c1fd9e7) Change-Id: Ie13d73fd97395e1979a67c2294e036a97c50000d --- libc/arch-arm64/arm64.mk | 1 - libc/arch-arm64/bionic/__restore_rt.S | 35 --------------------------- libc/bionic/sigaction.cpp | 34 +++++++++++++++++--------- 3 files changed, 22 insertions(+), 48 deletions(-) delete mode 100644 libc/arch-arm64/bionic/__restore_rt.S diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk index 91cd9fb1c..eb65cfd1f 100644 --- a/libc/arch-arm64/arm64.mk +++ b/libc/arch-arm64/arm64.mk @@ -29,7 +29,6 @@ libc_common_src_files_arm64 += \ libc_bionic_src_files_arm64 := \ arch-arm64/bionic/__bionic_clone.S \ arch-arm64/bionic/_exit_with_stack_teardown.S \ - arch-arm64/bionic/__restore_rt.S \ arch-arm64/bionic/_setjmp.S \ arch-arm64/bionic/setjmp.S \ arch-arm64/bionic/__set_tls.c \ diff --git a/libc/arch-arm64/bionic/__restore_rt.S b/libc/arch-arm64/bionic/__restore_rt.S deleted file mode 100644 index 95064903e..000000000 --- a/libc/arch-arm64/bionic/__restore_rt.S +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -// This function must have exactly this instruction sequence for gdb and libunwind. -ENTRY_PRIVATE(__restore_rt) - mov x8, __NR_rt_sigreturn - svc #0 -END(__restore_rt) diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp index 8ba4e2a2d..9038bd544 100644 --- a/libc/bionic/sigaction.cpp +++ b/libc/bionic/sigaction.cpp @@ -31,26 +31,29 @@ extern "C" void __restore_rt(void); extern "C" void __restore(void); -#if __LP64__ +#if defined(__LP64__) + extern "C" int __rt_sigaction(int, const struct __kernel_sigaction*, struct __kernel_sigaction*, size_t); -#else -extern "C" int __sigaction(int, const struct sigaction*, struct sigaction*); -#endif int sigaction(int signal, const struct sigaction* bionic_new_action, struct sigaction* bionic_old_action) { -#if __LP64__ __kernel_sigaction kernel_new_action; if (bionic_new_action != NULL) { kernel_new_action.sa_flags = bionic_new_action->sa_flags; kernel_new_action.sa_handler = bionic_new_action->sa_handler; kernel_new_action.sa_mask = bionic_new_action->sa_mask; -#ifdef SA_RESTORER +#if defined(SA_RESTORER) kernel_new_action.sa_restorer = bionic_new_action->sa_restorer; - +#if defined(__aarch64__) + // arm64 has sa_restorer, but unwinding works best if you just let the + // kernel supply the default restorer from [vdso]. gdb doesn't care, but + // libgcc needs the nop that the kernel includes before the actual code. + // (We could add that ourselves, but why bother?) +#else if (!(kernel_new_action.sa_flags & SA_RESTORER)) { kernel_new_action.sa_flags |= SA_RESTORER; kernel_new_action.sa_restorer = &__restore_rt; } +#endif #endif } @@ -64,7 +67,7 @@ int sigaction(int signal, const struct sigaction* bionic_new_action, struct siga bionic_old_action->sa_flags = kernel_old_action.sa_flags; bionic_old_action->sa_handler = kernel_old_action.sa_handler; bionic_old_action->sa_mask = kernel_old_action.sa_mask; -#ifdef SA_RESTORER +#if defined(SA_RESTORER) bionic_old_action->sa_restorer = kernel_old_action.sa_restorer; if (bionic_old_action->sa_restorer == &__rt_sigreturn) { @@ -74,15 +77,21 @@ int sigaction(int signal, const struct sigaction* bionic_new_action, struct siga } return result; +} + #else - // The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t. - // TODO: if we also had correct struct sigaction definitions available, we could copy in and out. + +extern "C" int __sigaction(int, const struct sigaction*, struct sigaction*); + +int sigaction(int signal, const struct sigaction* bionic_new_action, struct sigaction* bionic_old_action) { + // The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t, + // so we have to use sigaction(2) rather than rt_sigaction(2). struct sigaction kernel_new_action; if (bionic_new_action != NULL) { kernel_new_action.sa_flags = bionic_new_action->sa_flags; kernel_new_action.sa_handler = bionic_new_action->sa_handler; kernel_new_action.sa_mask = bionic_new_action->sa_mask; -#ifdef SA_RESTORER +#if defined(SA_RESTORER) kernel_new_action.sa_restorer = bionic_new_action->sa_restorer; if (!(kernel_new_action.sa_flags & SA_RESTORER)) { @@ -92,5 +101,6 @@ int sigaction(int signal, const struct sigaction* bionic_new_action, struct siga #endif } return __sigaction(signal, (bionic_new_action != NULL) ? &kernel_new_action : NULL, bionic_old_action); -#endif } + +#endif From 190dce9e56c750be6b8d113ffdd32a9c20c19e3d Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 17 Sep 2014 17:21:20 -0700 Subject: [PATCH 051/114] Stack unwinding unit tests. Bug: 17436734 (cherry picked from commit bee1993a14b47bc7acda544242f405ae45e42566) Change-Id: I7205a862ba2c3b474e287f5e9c8982cef4610af9 --- tests/Android.mk | 30 +++-------- tests/stack_unwinding_test.cpp | 83 +++++++++++++++++++++++++++---- tests/stack_unwinding_test_impl.c | 51 +++++++++---------- 3 files changed, 104 insertions(+), 60 deletions(-) diff --git a/tests/Android.mk b/tests/Android.mk index dd430490b..23a2cb3ed 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -88,7 +88,6 @@ libBionicStandardTests_src_files := \ search_test.cpp \ signal_test.cpp \ stack_protector_test.cpp \ - stack_unwinding_test.cpp \ stdatomic_test.cpp \ stdint_test.cpp \ stdio_test.cpp \ @@ -134,9 +133,6 @@ libBionicStandardTests_c_includes := \ libBionicStandardTests_ldlibs_host := \ -lrt \ -libBionicStandardTests_whole_static_libraries := \ - libBionicUnwindTest \ - module := libBionicStandardTests module_tag := optional build_type := target @@ -145,25 +141,6 @@ include $(LOCAL_PATH)/Android.build.mk build_type := host include $(LOCAL_PATH)/Android.build.mk -# ----------------------------------------------------------------------------- -# Special stack unwinding test library compiled with special flags. -# ----------------------------------------------------------------------------- -libBionicUnwindTest_cflags := \ - $(test_cflags) \ - -fexceptions \ - -fnon-call-exceptions \ - -libBionicUnwindTest_src_files := \ - stack_unwinding_test_impl.c \ - -module := libBionicUnwindTest -module_tag := optional -build_type := target -build_target := STATIC_TEST_LIBRARY -include $(LOCAL_PATH)/Android.build.mk -build_type := host -include $(LOCAL_PATH)/Android.build.mk - # ----------------------------------------------------------------------------- # Fortify tests. # ----------------------------------------------------------------------------- @@ -247,8 +224,15 @@ bionic-unit-tests_src_files := \ atexit_test.cpp \ dlext_test.cpp \ dlfcn_test.cpp \ + stack_unwinding_test.cpp \ + stack_unwinding_test_impl.c \ bionic-unit-tests_cflags := $(test_cflags) + +bionic-unit-tests_conlyflags := \ + -fexceptions \ + -fnon-call-exceptions \ + bionic-unit-tests_cppflags := $(test_cppflags) bionic-unit-tests_ldflags := \ diff --git a/tests/stack_unwinding_test.cpp b/tests/stack_unwinding_test.cpp index 1024f28f1..017a5f2e8 100644 --- a/tests/stack_unwinding_test.cpp +++ b/tests/stack_unwinding_test.cpp @@ -20,18 +20,83 @@ #include -extern "C" { - void do_test(); +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ScopedSignalHandler.h" + +#define noinline __attribute__((noinline)) + +static _Unwind_Reason_Code FrameCounter(_Unwind_Context* ctx __unused, void* arg) { + int* count_ptr = reinterpret_cast(arg); + +#if SHOW_FRAME_LOCATIONS + void* ip = reinterpret_cast(_Unwind_GetIP(ctx)); + + const char* symbol = ""; + int offset = 0; + + Dl_info info; + memset(&info, 0, sizeof(info)); + if (dladdr(ip, &info) != 0) { + symbol = info.dli_sname; + if (info.dli_saddr != nullptr) { + offset = static_cast(reinterpret_cast(ip) - reinterpret_cast(info.dli_saddr)); + } + } + + fprintf(stderr, " #%02d %p %s%+d (%s)\n", *count_ptr, ip, symbol, offset, info.dli_fname ? info.dli_fname : "??"); + fflush(stderr); +#endif + + ++*count_ptr; + return _URC_NO_REASON; } +static int noinline unwind_one_frame_deeper() { + int count = 0; + _Unwind_Backtrace(FrameCounter, &count); + return count; +} + +TEST(stack_unwinding, easy) { + int count = 0; + _Unwind_Backtrace(FrameCounter, &count); + int deeper_count = unwind_one_frame_deeper(); + ASSERT_EQ(count + 1, deeper_count); +} + +static int killer_count = 0; +static int handler_count = 0; +static int handler_one_deeper_count = 0; + +static void noinline UnwindSignalHandler(int) { + _Unwind_Backtrace(FrameCounter, &handler_count); + ASSERT_GT(handler_count, killer_count); + + handler_one_deeper_count = unwind_one_frame_deeper(); + ASSERT_EQ(handler_count + 1, handler_one_deeper_count); +} + +TEST(stack_unwinding, unwind_through_signal_frame) { + ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler); + + _Unwind_Backtrace(FrameCounter, &killer_count); + + ASSERT_EQ(0, kill(getpid(), SIGUSR1)); +} + +extern "C" void unwind_through_frame_with_cleanup_function(); + // We have to say "DeathTest" here so gtest knows to run this test (which exits) // in its own process. -TEST(stack_unwinding_DeathTest, unwinding_through_signal_frame) { -// Only our x86 unwinding is good enough. Switch to libunwind? -#if defined(__BIONIC__) && defined(__i386__) +TEST(stack_unwinding_DeathTest, unwind_through_frame_with_cleanup_function) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - ASSERT_EXIT(do_test(), ::testing::ExitedWithCode(42), ""); -#else // __i386__ - GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif // __i386__ + ASSERT_EXIT(unwind_through_frame_with_cleanup_function(), ::testing::ExitedWithCode(42), ""); } diff --git a/tests/stack_unwinding_test_impl.c b/tests/stack_unwinding_test_impl.c index 7518a2cdd..2e0393847 100644 --- a/tests/stack_unwinding_test_impl.c +++ b/tests/stack_unwinding_test_impl.c @@ -18,52 +18,47 @@ * Contributed by: Intel Corporation */ -#include +#include #include +#include #include #include +#include #include #define noinline __attribute__((__noinline__)) -#define unused __attribute__((__unused__)) -static noinline _Unwind_Reason_Code stop_fn(int a unused, +#ifndef __unused +#define __unused __attribute__((__unused__)) +#endif + +static noinline _Unwind_Reason_Code cleanup_unwind_fn(int a __unused, _Unwind_Action action, - _Unwind_Exception_Class b unused, struct _Unwind_Exception* c unused, - struct _Unwind_Context* d unused, void* e unused) { + _Unwind_Exception_Class b __unused, + struct _Unwind_Exception* c __unused, + struct _Unwind_Context* ctx __unused, + void* e __unused) { if ((action & _UA_END_OF_STACK) != 0) { - // We reached the end of the stack without executing foo_cleanup. Test failed. - abort(); + abort(); // We reached the end of the stack without executing foo_cleanup (which would have exited). Test failed. } return _URC_NO_REASON; } -static void noinline foo_cleanup(char* param unused) { +static void noinline foo_cleanup(char* param __unused) { exit(42); } -static void noinline do_crash() { - char* ptr = NULL; - *ptr = 0; // Deliberately cause a SIGSEGV. +static void noinline function_with_cleanup_function() { + char c __attribute__((cleanup(foo_cleanup))) __unused; + *((int*) 1) = 0; } -static void noinline foo() { - char c1 __attribute__((cleanup(foo_cleanup))) unused; - do_crash(); +static void noinline cleanup_sigsegv_handler(int param __unused) { + struct _Unwind_Exception* exception = (struct _Unwind_Exception*) calloc(1, sizeof(*exception)); + _Unwind_ForcedUnwind(exception, cleanup_unwind_fn, 0); } -// It's SEGSEGV handler. We start forced stack unwinding here. -// If libgcc don't find dso for signal frame stack unwinding will be finished. -// libgcc pass to stop_fn _UA_END_OF_STACK flag. -// Test pass condition: stack unwinding through signal frame and foo1_handler execution. -static void noinline sigsegv_handler(int param unused) { - struct _Unwind_Exception* exception = (struct _Unwind_Exception*) malloc(sizeof(*exception)); - memset(&exception->exception_class, 0, sizeof(exception->exception_class)); - exception->exception_cleanup = 0; - _Unwind_ForcedUnwind(exception, stop_fn, 0); -} - -void do_test() { - signal(SIGSEGV, &sigsegv_handler); - foo(); +void unwind_through_frame_with_cleanup_function() { + signal(SIGSEGV, &cleanup_sigsegv_handler); + function_with_cleanup_function(); } From 8eb8c3929974060e0d8b5063886d6ed250198d41 Mon Sep 17 00:00:00 2001 From: Pavel Chupin Date: Fri, 26 Sep 2014 16:02:09 +0400 Subject: [PATCH 052/114] [x86,x86_64] Fix libgcc unwinding through signal This change provides __restore/__restore_rt on x86 and __restore_rt on x86_64 with unwinding information to be able to unwind through signal frame via libgcc provided unwinding interface. See comments inlined for more details. Also remove the test that had a dependency on __attribute__((cleanup(foo_cleanup))). It doesn't provide us with any better test coverage than we have from the newer tests, and it doesn't work well across a variety architectures (presumably because no one uses this attribute in the real world). Tested this on host via bionic-unit-tests-run-on-host on both x86 and x86-64. Bug: 17436734 Signed-off-by: Pavel Chupin (cherry picked from commit 50321e2e66f19998970e59d666bc9af387345b3a) Change-Id: Iba90e36958b00c7cc7db5eeebf888dc89ce4d619 --- libc/arch-x86/bionic/__restore.S | 104 ++++++++++++++++++++++- libc/arch-x86/bionic/__restore_rt.S | 36 -------- libc/arch-x86/x86.mk | 1 - libc/arch-x86_64/bionic/__restore_rt.S | 113 ++++++++++++++++++++++++- tests/Android.mk | 3 +- tests/ScopedSignalHandler.h | 5 +- tests/stack_unwinding_test.cpp | 17 ++-- tests/stack_unwinding_test_impl.c | 64 -------------- 8 files changed, 225 insertions(+), 118 deletions(-) delete mode 100644 libc/arch-x86/bionic/__restore_rt.S delete mode 100644 tests/stack_unwinding_test_impl.c diff --git a/libc/arch-x86/bionic/__restore.S b/libc/arch-x86/bionic/__restore.S index 755c3f8e5..cb18fd027 100644 --- a/libc/arch-x86/bionic/__restore.S +++ b/libc/arch-x86/bionic/__restore.S @@ -28,10 +28,108 @@ #include -// This function must have exactly this instruction sequence for gdb and libunwind. -// This function must have exactly this name for gdb. -ENTRY(__restore) +// DWARF constants. +#define DW_CFA_def_cfa_expression 0x0f +#define DW_CFA_expression 0x10 +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_sdata4 0x0b +#define DW_OP_breg4 0x74 +#define DW_OP_deref 0x06 + +// Offsets into struct sigcontext. +#define OFFSET_EDI 16 +#define OFFSET_ESI 20 +#define OFFSET_EBP 24 +#define OFFSET_ESP 28 +#define OFFSET_EBX 32 +#define OFFSET_EDX 36 +#define OFFSET_ECX 40 +#define OFFSET_EAX 44 +#define OFFSET_EIP 56 + +// Non-standard DWARF constants for the x86 registers. +#define DW_x86_REG_EAX 0 +#define DW_x86_REG_ECX 1 +#define DW_x86_REG_EDX 2 +#define DW_x86_REG_EBX 3 +#define DW_x86_REG_EBP 5 +#define DW_x86_REG_ESI 6 +#define DW_x86_REG_EDI 7 +#define DW_x86_REG_EIP 8 + +#define cfi_signal_frame_start(f) \ +.section .eh_frame,"a",@progbits; \ +.L ## f ## _START_EH_FRAME: \ + .long 2f - 1f; /* CIE length. */ \ +1:.long 0; /* CIE ID. */ \ + .byte 1; /* Version. */ \ + .string "zRS"; /* Augmentation string. */ \ + .uleb128 1; /* Code alignment factor. */ \ + .sleb128 -4; /* Data alignment factor. */ \ + .uleb128 DW_x86_REG_EIP; /* Return address register. */ \ + .uleb128 1; /* 1 byte of augmentation data. */ \ + .byte (DW_EH_PE_pcrel|DW_EH_PE_sdata4); /* FDE encoding. */ \ + .align 8; \ +2: \ + .long .L ## f ## _END_FDE - .L ## f ## _START_FDE; /* FDE length. */ \ +.L ## f ## _START_FDE: \ + .long .L ## f ## _START_FDE - .L ## f ## _START_EH_FRAME; /* CIE location. */ \ + .long (.L ## f ## _START - 1) - .; /* pcrel start address (see FDE encoding above). */ \ + .long .L ## f ## _END - (.L ## f ## _START - 1); /* Function this FDE applies to. */ \ + .uleb128 0; /* FDE augmentation length. */ \ + +#define cfi_signal_frame_end(f) \ +.L ## f ## _END_FDE: \ + +#define cfi_def_cfa(offset) \ + .byte DW_CFA_def_cfa_expression; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg4; \ + .sleb128 offset; \ + .byte DW_OP_deref; \ +2: \ + +#define cfi_offset(reg_number,offset) \ + .byte DW_CFA_expression; \ + .uleb128 reg_number; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg4; \ + .sleb128 offset; \ +2: \ + +ENTRY_PRIVATE(__restore) +.L__restore_START: popl %eax movl $__NR_sigreturn, %eax int $0x80 +.L__restore_END: END(__restore) +cfi_signal_frame_start(__restore) + cfi_def_cfa(OFFSET_ESP + 4) + cfi_offset(DW_x86_REG_EDI, OFFSET_EDI + 4) + cfi_offset(DW_x86_REG_ESI, OFFSET_ESI + 4) + cfi_offset(DW_x86_REG_EBP, OFFSET_EBP + 4) + cfi_offset(DW_x86_REG_EBX, OFFSET_EBX + 4) + cfi_offset(DW_x86_REG_EDX, OFFSET_EDX + 4) + cfi_offset(DW_x86_REG_ECX, OFFSET_ECX + 4) + cfi_offset(DW_x86_REG_EAX, OFFSET_EAX + 4) + cfi_offset(DW_x86_REG_EIP, OFFSET_EIP + 4) +cfi_signal_frame_end(__restore) + +ENTRY_PRIVATE(__restore_rt) +.L__restore_rt_START: + movl $__NR_rt_sigreturn, %eax + int $0x80 +.L__restore_rt_END: +END(__restore_rt) +cfi_signal_frame_start(__restore_rt) + cfi_def_cfa(OFFSET_ESP + 160) + cfi_offset(DW_x86_REG_EDI, OFFSET_EDI + 160) + cfi_offset(DW_x86_REG_ESI, OFFSET_ESI + 160) + cfi_offset(DW_x86_REG_EBP, OFFSET_EBP + 160) + cfi_offset(DW_x86_REG_EBX, OFFSET_EBX + 160) + cfi_offset(DW_x86_REG_EDX, OFFSET_EDX + 160) + cfi_offset(DW_x86_REG_ECX, OFFSET_ECX + 160) + cfi_offset(DW_x86_REG_EAX, OFFSET_EAX + 160) + cfi_offset(DW_x86_REG_EIP, OFFSET_EIP + 160) +cfi_signal_frame_end(__restore_rt) diff --git a/libc/arch-x86/bionic/__restore_rt.S b/libc/arch-x86/bionic/__restore_rt.S deleted file mode 100644 index 0cd808125..000000000 --- a/libc/arch-x86/bionic/__restore_rt.S +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -// This function must have exactly this instruction sequence for gdb and libunwind. -// This function must have exactly this name for gdb. -ENTRY(__restore_rt) - movl $__NR_rt_sigreturn, %eax - int $0x80 -END(__restore_rt) diff --git a/libc/arch-x86/x86.mk b/libc/arch-x86/x86.mk index 905519745..d90b1ceec 100644 --- a/libc/arch-x86/x86.mk +++ b/libc/arch-x86/x86.mk @@ -26,7 +26,6 @@ libc_bionic_src_files_x86 += \ arch-x86/bionic/__bionic_clone.S \ arch-x86/bionic/_exit_with_stack_teardown.S \ arch-x86/bionic/libgcc_compat.c \ - arch-x86/bionic/__restore_rt.S \ arch-x86/bionic/__restore.S \ arch-x86/bionic/_setjmp.S \ arch-x86/bionic/setjmp.S \ diff --git a/libc/arch-x86_64/bionic/__restore_rt.S b/libc/arch-x86_64/bionic/__restore_rt.S index d84be219a..785b3b378 100644 --- a/libc/arch-x86_64/bionic/__restore_rt.S +++ b/libc/arch-x86_64/bionic/__restore_rt.S @@ -28,9 +28,116 @@ #include -// This function must have exactly this instruction sequence for gdb and libunwind. -// This function must have exactly this name for gdb. -ENTRY(__restore_rt) +// DWARF constants. +#define DW_CFA_def_cfa_expression 0x0f +#define DW_CFA_expression 0x10 +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_sdata4 0x0b +#define DW_OP_breg4 0x74 +#define DW_OP_breg7 0x77 +#define DW_OP_deref 0x06 + +// Offsets into struct ucontext_t of uc_mcontext.gregs[x]. +#define OFFSET_R8 40 +#define OFFSET_R9 48 +#define OFFSET_R10 56 +#define OFFSET_R11 64 +#define OFFSET_R12 72 +#define OFFSET_R13 80 +#define OFFSET_R14 88 +#define OFFSET_R15 96 +#define OFFSET_RDI 104 +#define OFFSET_RSI 112 +#define OFFSET_RBP 120 +#define OFFSET_RSP 160 +#define OFFSET_RBX 128 +#define OFFSET_RDX 136 +#define OFFSET_RAX 144 +#define OFFSET_RCX 152 +#define OFFSET_RIP 168 + +// Non-standard DWARF constants for the x86-64 registers. +#define DW_x86_64_RAX 0 +#define DW_x86_64_RDX 1 +#define DW_x86_64_RCX 2 +#define DW_x86_64_RBX 3 +#define DW_x86_64_RSI 4 +#define DW_x86_64_RDI 5 +#define DW_x86_64_RBP 6 +#define DW_x86_64_RSP 7 +#define DW_x86_64_R8 8 +#define DW_x86_64_R9 9 +#define DW_x86_64_R10 10 +#define DW_x86_64_R11 11 +#define DW_x86_64_R12 12 +#define DW_x86_64_R13 13 +#define DW_x86_64_R14 14 +#define DW_x86_64_R15 15 +#define DW_x86_64_RIP 16 + +#define cfi_signal_frame_start(f) \ +.section .eh_frame,"a",@progbits; \ +.L ## f ## _START_EH_FRAME: \ + .long 2f - 1f; /* CIE length. */ \ +1:.long 0; /* CIE ID. */ \ + .byte 1; /* Version. */ \ + .string "zRS"; /* Augmentation string. */ \ + .uleb128 1; /* Code alignment factor. */ \ + .sleb128 -8; /* Data alignment factor. */ \ + .uleb128 DW_x86_64_RIP; /* Return address register. */ \ + .uleb128 1; /* 1 byte of augmentation data. */ \ + .byte (DW_EH_PE_pcrel | DW_EH_PE_sdata4); /* FDE encoding. */ \ + .align 8; \ +2: \ + .long .L ## f ## _END_FDE - .L ## f ## _START_FDE; /* FDE length. */ \ +.L ## f ## _START_FDE: \ + .long .L ## f ## _START_FDE - .L ## f ## _START_EH_FRAME; /* CIE location. */ \ + .long (.L ## f ## _START - 1) - .; /* pcrel start address (see FDE encoding above). */ \ + .long .L ## f ## _END - (.L ## f ## _START - 1); /* Function this FDE applies to. */ \ + .uleb128 0; /* FDE augmentation length. */ \ + +#define cfi_signal_frame_end(f) \ +.L ## f ## _END_FDE: \ + +#define cfi_def_cfa(offset) \ + .byte DW_CFA_def_cfa_expression; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg7; \ + .sleb128 offset; \ + .byte DW_OP_deref; \ +2: \ + +#define cfi_offset(reg_number,offset) \ + .byte DW_CFA_expression; \ + .uleb128 reg_number; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg7; \ + .sleb128 offset; \ +2: \ + +ENTRY_PRIVATE(__restore_rt) +.L__restore_rt_START: mov $__NR_rt_sigreturn, %rax syscall +.L__restore_rt_END: END(__restore_rt) +cfi_signal_frame_start(__restore_rt) + cfi_def_cfa(OFFSET_RSP) + cfi_offset(DW_x86_64_R8, OFFSET_R8) + cfi_offset(DW_x86_64_R9, OFFSET_R9) + cfi_offset(DW_x86_64_R10, OFFSET_R10) + cfi_offset(DW_x86_64_R11, OFFSET_R11) + cfi_offset(DW_x86_64_R12, OFFSET_R12) + cfi_offset(DW_x86_64_R13, OFFSET_R13) + cfi_offset(DW_x86_64_R14, OFFSET_R14) + cfi_offset(DW_x86_64_R15, OFFSET_R15) + cfi_offset(DW_x86_64_RDI, OFFSET_RDI) + cfi_offset(DW_x86_64_RSI, OFFSET_RSI) + cfi_offset(DW_x86_64_RBP, OFFSET_RBP) + cfi_offset(DW_x86_64_RSP, OFFSET_RSP) + cfi_offset(DW_x86_64_RBX, OFFSET_RBX) + cfi_offset(DW_x86_64_RDX, OFFSET_RDX) + cfi_offset(DW_x86_64_RAX, OFFSET_RAX) + cfi_offset(DW_x86_64_RCX, OFFSET_RCX) + cfi_offset(DW_x86_64_RIP, OFFSET_RIP) +cfi_signal_frame_end(__restore_rt) diff --git a/tests/Android.mk b/tests/Android.mk index 23a2cb3ed..407f21bc5 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -88,6 +88,7 @@ libBionicStandardTests_src_files := \ search_test.cpp \ signal_test.cpp \ stack_protector_test.cpp \ + stack_unwinding_test.cpp \ stdatomic_test.cpp \ stdint_test.cpp \ stdio_test.cpp \ @@ -224,8 +225,6 @@ bionic-unit-tests_src_files := \ atexit_test.cpp \ dlext_test.cpp \ dlfcn_test.cpp \ - stack_unwinding_test.cpp \ - stack_unwinding_test_impl.c \ bionic-unit-tests_cflags := $(test_cflags) diff --git a/tests/ScopedSignalHandler.h b/tests/ScopedSignalHandler.h index 89a14a6b2..3ec23b0d8 100644 --- a/tests/ScopedSignalHandler.h +++ b/tests/ScopedSignalHandler.h @@ -21,9 +21,10 @@ class ScopedSignalHandler { public: - ScopedSignalHandler(int signal_number, void (*handler)(int)) : signal_number_(signal_number) { + ScopedSignalHandler(int signal_number, void (*handler)(int), int sa_flags = 0) + : signal_number_(signal_number) { sigemptyset(&action_.sa_mask); - action_.sa_flags = 0; + action_.sa_flags = sa_flags; action_.sa_handler = handler; sigaction(signal_number_, &action_, &old_action_); } diff --git a/tests/stack_unwinding_test.cpp b/tests/stack_unwinding_test.cpp index 017a5f2e8..3fc45c537 100644 --- a/tests/stack_unwinding_test.cpp +++ b/tests/stack_unwinding_test.cpp @@ -31,7 +31,8 @@ #include "ScopedSignalHandler.h" -#define noinline __attribute__((noinline)) +#define noinline __attribute__((__noinline__)) +#define __unused __attribute__((__unused__)) static _Unwind_Reason_Code FrameCounter(_Unwind_Context* ctx __unused, void* arg) { int* count_ptr = reinterpret_cast(arg); @@ -85,6 +86,7 @@ static void noinline UnwindSignalHandler(int) { } TEST(stack_unwinding, unwind_through_signal_frame) { + killer_count = handler_count = handler_one_deeper_count = 0; ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler); _Unwind_Backtrace(FrameCounter, &killer_count); @@ -92,11 +94,12 @@ TEST(stack_unwinding, unwind_through_signal_frame) { ASSERT_EQ(0, kill(getpid(), SIGUSR1)); } -extern "C" void unwind_through_frame_with_cleanup_function(); +// On LP32, the SA_SIGINFO flag gets you __restore_rt instead of __restore. +TEST(stack_unwinding, unwind_through_signal_frame_SA_SIGINFO) { + killer_count = handler_count = handler_one_deeper_count = 0; + ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler, SA_SIGINFO); -// We have to say "DeathTest" here so gtest knows to run this test (which exits) -// in its own process. -TEST(stack_unwinding_DeathTest, unwind_through_frame_with_cleanup_function) { - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - ASSERT_EXIT(unwind_through_frame_with_cleanup_function(), ::testing::ExitedWithCode(42), ""); + _Unwind_Backtrace(FrameCounter, &killer_count); + + ASSERT_EQ(0, kill(getpid(), SIGUSR1)); } diff --git a/tests/stack_unwinding_test_impl.c b/tests/stack_unwinding_test_impl.c deleted file mode 100644 index 2e0393847..000000000 --- a/tests/stack_unwinding_test_impl.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Contributed by: Intel Corporation - */ - -#include -#include -#include -#include -#include -#include -#include - -#define noinline __attribute__((__noinline__)) - -#ifndef __unused -#define __unused __attribute__((__unused__)) -#endif - -static noinline _Unwind_Reason_Code cleanup_unwind_fn(int a __unused, - _Unwind_Action action, - _Unwind_Exception_Class b __unused, - struct _Unwind_Exception* c __unused, - struct _Unwind_Context* ctx __unused, - void* e __unused) { - if ((action & _UA_END_OF_STACK) != 0) { - abort(); // We reached the end of the stack without executing foo_cleanup (which would have exited). Test failed. - } - return _URC_NO_REASON; -} - -static void noinline foo_cleanup(char* param __unused) { - exit(42); -} - -static void noinline function_with_cleanup_function() { - char c __attribute__((cleanup(foo_cleanup))) __unused; - *((int*) 1) = 0; -} - -static void noinline cleanup_sigsegv_handler(int param __unused) { - struct _Unwind_Exception* exception = (struct _Unwind_Exception*) calloc(1, sizeof(*exception)); - _Unwind_ForcedUnwind(exception, cleanup_unwind_fn, 0); -} - -void unwind_through_frame_with_cleanup_function() { - signal(SIGSEGV, &cleanup_sigsegv_handler); - function_with_cleanup_function(); -} From 28ea229bb29f3ee82991ca8b5ac5f7a9b7b89fdc Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 4 Sep 2014 13:54:42 -0700 Subject: [PATCH 053/114] Don't mask out SA_RESTORER from sa_flags. glibc doesn't do this, and we probably shouldn't either. Bug: 16703540 Bug: 17436734 (cherry picked from commit afe58ad9892de27a7acb0aaded6312ee0f958314) Change-Id: Iada5d0ae814f438cb276f056b2b5e3675f0e3666 --- libc/bionic/sigaction.cpp | 4 ---- tests/signal_test.cpp | 16 +++++++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp index 9038bd544..0633748bf 100644 --- a/libc/bionic/sigaction.cpp +++ b/libc/bionic/sigaction.cpp @@ -69,10 +69,6 @@ int sigaction(int signal, const struct sigaction* bionic_new_action, struct siga bionic_old_action->sa_mask = kernel_old_action.sa_mask; #if defined(SA_RESTORER) bionic_old_action->sa_restorer = kernel_old_action.sa_restorer; - - if (bionic_old_action->sa_restorer == &__rt_sigreturn) { - bionic_old_action->sa_flags &= ~SA_RESTORER; - } #endif } diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp index 89b808838..e53fd3af6 100644 --- a/tests/signal_test.cpp +++ b/tests/signal_test.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#include +#include #include -#include +#include #include "ScopedSignalHandler.h" @@ -198,13 +198,19 @@ static void EmptySignalHandler(int) {} static void EmptySignalAction(int, siginfo_t*, void*) {} TEST(signal, sigaction) { + // Both bionic and glibc set SA_RESTORER when talking to the kernel on arm, + // arm64, x86, and x86-64. The version of glibc we're using also doesn't + // define SA_RESTORER, but luckily it's the same value everywhere, and mips + // doesn't use the bit for anything. + static const int sa_restorer = 0x4000000; + // See what's currently set for SIGALRM. struct sigaction original_sa; memset(&original_sa, 0, sizeof(original_sa)); ASSERT_EQ(0, sigaction(SIGALRM, NULL, &original_sa)); ASSERT_TRUE(original_sa.sa_handler == NULL); ASSERT_TRUE(original_sa.sa_sigaction == NULL); - ASSERT_TRUE(original_sa.sa_flags == 0); + ASSERT_EQ(0, original_sa.sa_flags & ~sa_restorer); // Set a traditional sa_handler signal handler. struct sigaction sa; @@ -219,7 +225,7 @@ TEST(signal, sigaction) { ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa)); ASSERT_TRUE(sa.sa_handler == EmptySignalHandler); ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler); - ASSERT_TRUE(sa.sa_flags == SA_ONSTACK); + ASSERT_EQ(SA_ONSTACK, sa.sa_flags & ~sa_restorer); // Set a new-style sa_sigaction signal handler. memset(&sa, 0, sizeof(sa)); @@ -233,7 +239,7 @@ TEST(signal, sigaction) { ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa)); ASSERT_TRUE(sa.sa_sigaction == EmptySignalAction); ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler); - ASSERT_TRUE(sa.sa_flags == (SA_ONSTACK | SA_SIGINFO)); + ASSERT_EQ((SA_ONSTACK | SA_SIGINFO), sa.sa_flags & ~sa_restorer); // Put everything back how it was. ASSERT_EQ(0, sigaction(SIGALRM, &original_sa, NULL)); From 43dc3a9aae7ad1f16a251e3c1e22dced82b811e3 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 23 Sep 2014 18:31:45 -0700 Subject: [PATCH 054/114] Remove the unnecessary generic-neon code. Bug: 18156619 (cherry picked from commit 2169e17482da91865e412e55b52b88d7c8db47f6) Change-Id: I4a7f5bb9ad4c27b274f3a3c86c1617ca0578b98f --- libc/arch-arm64/arm64.mk | 2 +- libc/arch-arm64/generic-neon/bionic/memcpy.S | 179 ------------------- libc/arch-arm64/generic-neon/generic-neon.mk | 13 -- 3 files changed, 1 insertion(+), 193 deletions(-) delete mode 100644 libc/arch-arm64/generic-neon/bionic/memcpy.S delete mode 100644 libc/arch-arm64/generic-neon/generic-neon.mk diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk index eb65cfd1f..692aaf606 100644 --- a/libc/arch-arm64/arm64.mk +++ b/libc/arch-arm64/arm64.mk @@ -52,7 +52,7 @@ ifeq ($(strip $(TARGET_CPU_VARIANT)),) endif cpu_variant_mk := $(LOCAL_PATH)/arch-arm64/$(TARGET_CPU_VARIANT)/$(TARGET_CPU_VARIANT).mk ifeq ($(wildcard $(cpu_variant_mk)),) -$(error "TARGET_CPU_VARIANT not set or set to an unknown value. Possible values are generic, generic-neon, denver64. Use generic for devices that do not have a CPU similar to any of the supported cpu variants.") +$(error "TARGET_CPU_VARIANT not set or set to an unknown value. Possible values are generic, denver64. Use generic for devices that do not have a CPU similar to any of the supported cpu variants.") endif include $(cpu_variant_mk) libc_common_additional_dependencies += $(cpu_variank_mk) diff --git a/libc/arch-arm64/generic-neon/bionic/memcpy.S b/libc/arch-arm64/generic-neon/bionic/memcpy.S deleted file mode 100644 index 320f74896..000000000 --- a/libc/arch-arm64/generic-neon/bionic/memcpy.S +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright (c) 2012, Linaro Limited - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Linaro nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* Assumptions: - * - * ARMv8-a, AArch64 - * Unaligned accesses - * - */ - -#include - -#define dstin x0 -#define src x1 -#define count x2 -#define tmp1 x3 -#define tmp1w w3 -#define tmp2 x4 -#define tmp2w w4 -#define tmp3 x5 -#define tmp3w w5 -#define dst x6 - -#define A_l x7 -#define A_h x8 -#define B_l x9 -#define B_h x10 -#define C_l x11 -#define C_h x12 -#define D_l x13 -#define D_h x14 - -#define QA_l q0 -#define QA_h q1 -#define QB_l q2 -#define QB_h q3 - -ENTRY(memcpy) - - mov dst, dstin - cmp count, #64 - b.ge .Lcpy_not_short - cmp count, #15 - b.le .Ltail15tiny - - /* Deal with small copies quickly by dropping straight into the - * exit block. */ -.Ltail63: - /* Copy up to 48 bytes of data. At this point we only need the - * bottom 6 bits of count to be accurate. */ - ands tmp1, count, #0x30 - b.eq .Ltail15 - add dst, dst, tmp1 - add src, src, tmp1 - cmp tmp1w, #0x20 - b.eq 1f - b.lt 2f - ldp A_l, A_h, [src, #-48] - stp A_l, A_h, [dst, #-48] -1: - ldp A_l, A_h, [src, #-32] - stp A_l, A_h, [dst, #-32] -2: - ldp A_l, A_h, [src, #-16] - stp A_l, A_h, [dst, #-16] - -.Ltail15: - ands count, count, #15 - beq 1f - add src, src, count - ldp A_l, A_h, [src, #-16] - add dst, dst, count - stp A_l, A_h, [dst, #-16] -1: - ret - -.Ltail15tiny: - /* Copy up to 15 bytes of data. Does not assume additional data - being copied. */ - tbz count, #3, 1f - ldr tmp1, [src], #8 - str tmp1, [dst], #8 -1: - tbz count, #2, 1f - ldr tmp1w, [src], #4 - str tmp1w, [dst], #4 -1: - tbz count, #1, 1f - ldrh tmp1w, [src], #2 - strh tmp1w, [dst], #2 -1: - tbz count, #0, 1f - ldrb tmp1w, [src] - strb tmp1w, [dst] -1: - ret - -.Lcpy_not_short: - /* We don't much care about the alignment of DST, but we want SRC - * to be 128-bit (16 byte) aligned so that we don't cross cache line - * boundaries on both loads and stores. */ - neg tmp2, src - ands tmp2, tmp2, #15 /* Bytes to reach alignment. */ - b.eq 2f - sub count, count, tmp2 - /* Copy more data than needed; it's faster than jumping - * around copying sub-Quadword quantities. We know that - * it can't overrun. */ - ldp A_l, A_h, [src] - add src, src, tmp2 - stp A_l, A_h, [dst] - add dst, dst, tmp2 - /* There may be less than 63 bytes to go now. */ - cmp count, #63 - b.le .Ltail63 -2: - subs count, count, #128 - b.ge .Lcpy_body_large - /* Less than 128 bytes to copy, so handle 64 here and then jump - * to the tail. */ - ldp QA_l, QA_h, [src] - ldp QB_l, QB_h, [src, #32] - stp QA_l, QA_h, [dst] - stp QB_l, QB_h, [dst, #32] - tst count, #0x3f - add src, src, #64 - add dst, dst, #64 - b.ne .Ltail63 - ret - - /* Critical loop. Start at a new cache line boundary. Assuming - * 64 bytes per line this ensures the entire loop is in one line. */ - .p2align 6 -.Lcpy_body_large: - /* There are at least 128 bytes to copy. */ - ldp QA_l, QA_h, [src, #0] - sub dst, dst, #32 /* Pre-bias. */ - ldp QB_l, QB_h, [src, #32]! /* src += 64 - Pre-bias. */ -1: - stp QA_l, QA_h, [dst, #32] - ldp QA_l, QA_h, [src, #32] - stp QB_l, QB_h, [dst, #64]! - ldp QB_l, QB_h, [src, #64]! - - subs count, count, #64 - b.ge 1b - - stp QA_l, QA_h, [dst, #32] - stp QB_l, QB_h, [dst, #64] - add src, src, #32 - add dst, dst, #64 + 32 - tst count, #0x3f - b.ne .Ltail63 - ret -END(memcpy) diff --git a/libc/arch-arm64/generic-neon/generic-neon.mk b/libc/arch-arm64/generic-neon/generic-neon.mk deleted file mode 100644 index 77e3861ea..000000000 --- a/libc/arch-arm64/generic-neon/generic-neon.mk +++ /dev/null @@ -1,13 +0,0 @@ -libc_bionic_src_files_arm64 += \ - arch-arm64/generic/bionic/memchr.S \ - arch-arm64/generic/bionic/memcmp.S \ - arch-arm64/generic/bionic/memmove.S \ - arch-arm64/generic/bionic/memset.S \ - arch-arm64/generic/bionic/stpcpy.S \ - arch-arm64/generic/bionic/strchr.S \ - arch-arm64/generic/bionic/strcmp.S \ - arch-arm64/generic/bionic/strcpy.S \ - arch-arm64/generic/bionic/strlen.S \ - arch-arm64/generic/bionic/strncmp.S \ - arch-arm64/generic/bionic/strnlen.S \ - arch-arm64/generic-neon/bionic/memcpy.S \ From 22e2c9d963e0dde19e5876ab8dfc3576efc42ccc Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 4 Sep 2014 15:43:10 -0700 Subject: [PATCH 055/114] Fix mips signed/unsigned signal_test.cpp build breakage. (cherry picked from commit aa13e839f06231b9299bb683a71abd954294b49b) Bug: 17436734 Change-Id: I167fc5d74c49cca7031c5739bc53fdf3bde71887 --- tests/signal_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp index e53fd3af6..8fd8b72f7 100644 --- a/tests/signal_test.cpp +++ b/tests/signal_test.cpp @@ -202,7 +202,7 @@ TEST(signal, sigaction) { // arm64, x86, and x86-64. The version of glibc we're using also doesn't // define SA_RESTORER, but luckily it's the same value everywhere, and mips // doesn't use the bit for anything. - static const int sa_restorer = 0x4000000; + static const unsigned sa_restorer = 0x4000000; // See what's currently set for SIGALRM. struct sigaction original_sa; @@ -210,7 +210,7 @@ TEST(signal, sigaction) { ASSERT_EQ(0, sigaction(SIGALRM, NULL, &original_sa)); ASSERT_TRUE(original_sa.sa_handler == NULL); ASSERT_TRUE(original_sa.sa_sigaction == NULL); - ASSERT_EQ(0, original_sa.sa_flags & ~sa_restorer); + ASSERT_EQ(0U, original_sa.sa_flags & ~sa_restorer); // Set a traditional sa_handler signal handler. struct sigaction sa; @@ -225,7 +225,7 @@ TEST(signal, sigaction) { ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa)); ASSERT_TRUE(sa.sa_handler == EmptySignalHandler); ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler); - ASSERT_EQ(SA_ONSTACK, sa.sa_flags & ~sa_restorer); + ASSERT_EQ(static_cast(SA_ONSTACK), sa.sa_flags & ~sa_restorer); // Set a new-style sa_sigaction signal handler. memset(&sa, 0, sizeof(sa)); @@ -239,7 +239,7 @@ TEST(signal, sigaction) { ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa)); ASSERT_TRUE(sa.sa_sigaction == EmptySignalAction); ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler); - ASSERT_EQ((SA_ONSTACK | SA_SIGINFO), sa.sa_flags & ~sa_restorer); + ASSERT_EQ(static_cast(SA_ONSTACK | SA_SIGINFO), sa.sa_flags & ~sa_restorer); // Put everything back how it was. ASSERT_EQ(0, sigaction(SIGALRM, &original_sa, NULL)); From b378c27226cc264c9273c5011235ec78a8b256da Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 16 Sep 2014 16:27:35 -0700 Subject: [PATCH 056/114] No arm source refers to SOFTFLOAT. So why bother #defining it? Bug: 18160821 (cherry picked from commit b1a6c319c40674d71e30313040d3b33b8bddf24b) Change-Id: I9cd9c144ba7071fddda12fa16d1232ad861b66be --- libc/arch-arm/arm.mk | 2 -- 1 file changed, 2 deletions(-) diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk index b1edfccf3..8c5e68174 100644 --- a/libc/arch-arm/arm.mk +++ b/libc/arch-arm/arm.mk @@ -44,8 +44,6 @@ libc_common_src_files_arm += \ # bionic/__strcpy_chk.cpp \ # bionic/__strcat_chk.cpp \ -libc_common_cflags_arm := -DSOFTFLOAT - ########################################## ### CPU specific source files libc_bionic_src_files_arm += \ From 86d16a053eeff3bd432695471d8942e99b2db598 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 16 Sep 2014 19:06:31 -0700 Subject: [PATCH 057/114] Clean up the architecture-specific makefiles. Group things appropriately and name each group. Bug: 18160821 (cherry picked from commit 7c02d9428ca18ac600f7ba7d51bb24ca71e733f6) Change-Id: I863242515af44058154d03e2d8c34678e682d66a --- libc/Android.mk | 2 ++ libc/arch-arm/arm.mk | 44 ++++++++++++++++-------------- libc/arch-arm64/arm64.mk | 29 ++++++++++++-------- libc/arch-mips/mips.mk | 56 +++++++++++++++++++++++--------------- libc/arch-mips64/mips64.mk | 49 +++++++++++++++++---------------- libc/arch-x86/x86.mk | 36 +++++++++++++++--------- libc/arch-x86_64/x86_64.mk | 44 ++++++++++++++++++------------ 7 files changed, 153 insertions(+), 107 deletions(-) diff --git a/libc/Android.mk b/libc/Android.mk index 92ead2637..61bdf7e23 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -692,6 +692,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies) LOCAL_SYSTEM_SHARED_LIBRARIES := $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags)) +$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_freebsd_src_files)) include $(BUILD_STATIC_LIBRARY) @@ -760,6 +761,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies) LOCAL_SYSTEM_SHARED_LIBRARIES := $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags)) +$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_openbsd_src_files)) include $(BUILD_STATIC_LIBRARY) diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk index 8c5e68174..b5ed7f0e0 100644 --- a/libc/arch-arm/arm.mk +++ b/libc/arch-arm/arm.mk @@ -1,22 +1,35 @@ -# arm specific configs +# 32-bit arm. -# These are used by the 32-bit targets, but not the 64-bit ones. -libc_common_src_files_arm := \ +# +# Various kinds of LP32 cruft. +# + +libc_bionic_src_files_arm += \ + bionic/mmap.cpp \ + +libc_common_src_files_arm += \ bionic/legacy_32_bit_support.cpp \ bionic/ndk_cruft.cpp \ bionic/time64.c \ + +libc_netbsd_src_files_arm += \ + upstream-netbsd/common/lib/libc/hash/sha1/sha1.c \ + +libc_openbsd_src_files_arm += \ upstream-openbsd/lib/libc/stdio/putw.c \ -# These are shared by all the 32-bit targets, but not the 64-bit ones. -libc_bionic_src_files_arm := \ - bionic/mmap.cpp +# +# Default implementations of functions that are commonly optimized. +# -libc_common_src_files_arm += \ +libc_bionic_src_files_arm += \ bionic/memchr.c \ bionic/memrchr.c \ bionic/strchr.cpp \ bionic/strnlen.c \ bionic/strrchr.cpp \ + +libc_freebsd_src_files_arm += \ upstream-freebsd/lib/libc/string/wcscat.c \ upstream-freebsd/lib/libc/string/wcschr.c \ upstream-freebsd/lib/libc/string/wcscmp.c \ @@ -25,6 +38,8 @@ libc_common_src_files_arm += \ upstream-freebsd/lib/libc/string/wcsrchr.c \ upstream-freebsd/lib/libc/string/wmemcmp.c \ upstream-freebsd/lib/libc/string/wmemmove.c \ + +libc_openbsd_src_files_arm += \ upstream-openbsd/lib/libc/string/bcopy.c \ upstream-openbsd/lib/libc/string/stpcpy.c \ upstream-openbsd/lib/libc/string/stpncpy.c \ @@ -34,18 +49,10 @@ libc_common_src_files_arm += \ upstream-openbsd/lib/libc/string/strncmp.c \ upstream-openbsd/lib/libc/string/strncpy.c \ -# The C++ fortify function implementations for which there is an -# arm assembler version. # -# Fortify implementations of libc functions. -# libc_common_src_files_arm += -# bionic/__memcpy_chk.cpp \ -# bionic/__memset_chk.cpp \ -# bionic/__strcpy_chk.cpp \ -# bionic/__strcat_chk.cpp \ +# Inherently architecture-specific code. +# -########################################## -### CPU specific source files libc_bionic_src_files_arm += \ arch-arm/bionic/abort_arm.S \ arch-arm/bionic/atomics_arm.c \ @@ -62,9 +69,6 @@ libc_bionic_src_files_arm += \ libc_arch_static_src_files_arm := arch-arm/bionic/exidx_static.c libc_arch_dynamic_src_files_arm := arch-arm/bionic/exidx_dynamic.c -libc_netbsd_src_files_arm := \ - upstream-netbsd/common/lib/libc/hash/sha1/sha1.c \ - ## CPU variant specific source files ifeq ($(strip $(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT)),) $(warning TARGET_$(my_2nd_arch_prefix)ARCH is arm, but TARGET_$(my_2nd_arch_prefix)CPU_VARIANT is not defined) diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk index 692aaf606..cdb2777b1 100644 --- a/libc/arch-arm64/arm64.mk +++ b/libc/arch-arm64/arm64.mk @@ -1,8 +1,18 @@ -# arm64 specific configs +# 64-bit arm. -libc_common_src_files_arm64 := \ +# +# Default implementations of functions that are commonly optimized. +# + +libc_bionic_src_files_arm64 += \ + bionic/__memcpy_chk.cpp \ + bionic/__memset_chk.cpp \ + bionic/__strcpy_chk.cpp \ + bionic/__strcat_chk.cpp \ bionic/memrchr.c \ bionic/strrchr.cpp \ + +libc_freebsd_src_files_arm64 += \ upstream-freebsd/lib/libc/string/wcscat.c \ upstream-freebsd/lib/libc/string/wcschr.c \ upstream-freebsd/lib/libc/string/wcscmp.c \ @@ -10,6 +20,8 @@ libc_common_src_files_arm64 := \ upstream-freebsd/lib/libc/string/wcslen.c \ upstream-freebsd/lib/libc/string/wcsrchr.c \ upstream-freebsd/lib/libc/string/wmemcmp.c \ + +libc_openbsd_src_files_arm64 += \ upstream-openbsd/lib/libc/string/stpncpy.c \ upstream-openbsd/lib/libc/string/strcat.c \ upstream-openbsd/lib/libc/string/strlcat.c \ @@ -17,16 +29,11 @@ libc_common_src_files_arm64 := \ upstream-openbsd/lib/libc/string/strncat.c \ upstream-openbsd/lib/libc/string/strncpy.c \ -# Fortify implementations of libc functions. -libc_common_src_files_arm64 += \ - bionic/__memcpy_chk.cpp \ - bionic/__memset_chk.cpp \ - bionic/__strcpy_chk.cpp \ - bionic/__strcat_chk.cpp \ +# +# Inherently architecture-specific code. +# -########################################## -### CPU specific source files -libc_bionic_src_files_arm64 := \ +libc_bionic_src_files_arm64 += \ arch-arm64/bionic/__bionic_clone.S \ arch-arm64/bionic/_exit_with_stack_teardown.S \ arch-arm64/bionic/_setjmp.S \ diff --git a/libc/arch-mips/mips.mk b/libc/arch-mips/mips.mk index 31a1f32fd..ac75a4bbb 100644 --- a/libc/arch-mips/mips.mk +++ b/libc/arch-mips/mips.mk @@ -1,17 +1,32 @@ -# mips specific configs +# 32-bit mips. -# These are shared by all the 32-bit targets, but not the 64-bit ones. -libc_common_src_files_mips := \ +# +# Various kinds of LP32 cruft. +# + +libc_bionic_src_files_mips += \ + bionic/mmap.cpp \ + +libc_common_src_files_mips += \ bionic/legacy_32_bit_support.cpp \ bionic/ndk_cruft.cpp \ bionic/time64.c \ + +libc_netbsd_src_files_mips += \ + upstream-netbsd/common/lib/libc/hash/sha1/sha1.c \ + +libc_openbsd_src_files_mips += \ upstream-openbsd/lib/libc/stdio/putw.c \ -# These are shared by all the 32-bit targets, but not the 64-bit ones. -libc_bionic_src_files_mips += \ - bionic/mmap.cpp +# +# Default implementations of functions that are commonly optimized. +# -libc_common_src_files_mips += \ +libc_bionic_src_files_mips += \ + bionic/__memcpy_chk.cpp \ + bionic/__memset_chk.cpp \ + bionic/__strcpy_chk.cpp \ + bionic/__strcat_chk.cpp \ bionic/memchr.c \ bionic/memcmp.c \ bionic/memmove.c \ @@ -19,6 +34,8 @@ libc_common_src_files_mips += \ bionic/strchr.cpp \ bionic/strnlen.c \ bionic/strrchr.cpp \ + +libc_freebsd_src_files_mips += \ upstream-freebsd/lib/libc/string/wcscat.c \ upstream-freebsd/lib/libc/string/wcschr.c \ upstream-freebsd/lib/libc/string/wcscmp.c \ @@ -27,6 +44,8 @@ libc_common_src_files_mips += \ upstream-freebsd/lib/libc/string/wcsrchr.c \ upstream-freebsd/lib/libc/string/wmemcmp.c \ upstream-freebsd/lib/libc/string/wmemmove.c \ + +libc_openbsd_src_files_mips += \ upstream-openbsd/lib/libc/string/bcopy.c \ upstream-openbsd/lib/libc/string/stpcpy.c \ upstream-openbsd/lib/libc/string/stpncpy.c \ @@ -39,16 +58,10 @@ libc_common_src_files_mips += \ upstream-openbsd/lib/libc/string/strncmp.c \ upstream-openbsd/lib/libc/string/strncpy.c \ -# Fortify implementations of libc functions. -libc_common_src_files_mips += \ - bionic/__memcpy_chk.cpp \ - bionic/__memset_chk.cpp \ - bionic/__strcpy_chk.cpp \ - bionic/__strcat_chk.cpp \ +# +# Inherently architecture-specific code. +# - -########################################## -### CPU specific source files libc_bionic_src_files_mips += \ arch-mips/bionic/__bionic_clone.S \ arch-mips/bionic/bzero.S \ @@ -69,13 +82,12 @@ libc_bionic_src_files_mips += \ else libc_bionic_src_files_mips += \ bionic/memcpy.cpp \ - bionic/memset.c -libc_common_src_files_mips += \ - upstream-openbsd/lib/libc/string/strlen.c -endif + bionic/memset.c \ -libc_netbsd_src_files_mips := \ - upstream-netbsd/common/lib/libc/hash/sha1/sha1.c \ +libc_openbsd_src_files_mips += \ + upstream-openbsd/lib/libc/string/strlen.c \ + +endif libc_crt_target_cflags_mips := \ $($(my_2nd_arch_prefix)TARGET_GLOBAL_CFLAGS) \ diff --git a/libc/arch-mips64/mips64.mk b/libc/arch-mips64/mips64.mk index 230cb26c5..0d4b72742 100644 --- a/libc/arch-mips64/mips64.mk +++ b/libc/arch-mips64/mips64.mk @@ -1,13 +1,25 @@ -# mips64 specific configs +# 64-bit mips. -libc_common_src_files_mips64 := \ +# +# Default implementations of functions that are commonly optimized. +# + +libc_bionic_src_files_mips64 += \ + bionic/__memcpy_chk.cpp \ + bionic/__memset_chk.cpp \ + bionic/__strcpy_chk.cpp \ + bionic/__strcat_chk.cpp \ bionic/memchr.c \ bionic/memcmp.c \ + bionic/memcpy.cpp \ bionic/memmove.c \ bionic/memrchr.c \ + bionic/memset.c \ bionic/strchr.cpp \ bionic/strnlen.c \ bionic/strrchr.cpp \ + +libc_freebsd_src_files_mips64 += \ upstream-freebsd/lib/libc/string/wcscat.c \ upstream-freebsd/lib/libc/string/wcschr.c \ upstream-freebsd/lib/libc/string/wcscmp.c \ @@ -16,6 +28,8 @@ libc_common_src_files_mips64 := \ upstream-freebsd/lib/libc/string/wcsrchr.c \ upstream-freebsd/lib/libc/string/wmemcmp.c \ upstream-freebsd/lib/libc/string/wmemmove.c \ + +libc_openbsd_src_files_mips64 += \ upstream-openbsd/lib/libc/string/stpcpy.c \ upstream-openbsd/lib/libc/string/stpncpy.c \ upstream-openbsd/lib/libc/string/strcat.c \ @@ -28,17 +42,11 @@ libc_common_src_files_mips64 := \ upstream-openbsd/lib/libc/string/strncmp.c \ upstream-openbsd/lib/libc/string/strncpy.c \ -# Fortify implementations of libc functions. -libc_common_src_files_mips64 += \ - bionic/__memcpy_chk.cpp \ - bionic/__memset_chk.cpp \ - bionic/__strcpy_chk.cpp \ - bionic/__strcat_chk.cpp \ +# +# Inherently architecture-specific code. +# - -########################################## -### CPU specific source files -libc_bionic_src_files_mips64 := \ +libc_bionic_src_files_mips64 += \ arch-mips64/bionic/__bionic_clone.S \ arch-mips64/bionic/_exit_with_stack_teardown.S \ arch-mips64/bionic/__get_sp.S \ @@ -48,25 +56,18 @@ libc_bionic_src_files_mips64 := \ arch-mips64/bionic/syscall.S \ arch-mips64/bionic/vfork.S \ -# FIXME TODO -## libc_bionic_src_files_mips64 += arch-mips64/string/memcpy.S -## libc_bionic_src_files_mips64 += arch-mips64/string/memset.S -libc_bionic_src_files_mips64 += bionic/memcpy.cpp -libc_bionic_src_files_mips64 += bionic/memset.c - - libc_crt_target_cflags_mips64 := \ $($(my_2nd_arch_prefix)TARGET_GLOBAL_CFLAGS) \ - -I$(LOCAL_PATH)/arch-mips64/include + -I$(LOCAL_PATH)/arch-mips64/include \ libc_crt_target_crtbegin_file_mips64 := \ - $(LOCAL_PATH)/arch-mips64/bionic/crtbegin.c + $(LOCAL_PATH)/arch-mips64/bionic/crtbegin.c \ libc_crt_target_crtbegin_so_file_mips64 := \ - $(LOCAL_PATH)/arch-common/bionic/crtbegin_so.c + $(LOCAL_PATH)/arch-common/bionic/crtbegin_so.c \ libc_crt_target_so_cflags_mips64 := \ - -fPIC + -fPIC \ libc_crt_target_ldflags_mips64 := \ - -melf64ltsmip + -melf64ltsmip \ diff --git a/libc/arch-x86/x86.mk b/libc/arch-x86/x86.mk index d90b1ceec..2c90317db 100644 --- a/libc/arch-x86/x86.mk +++ b/libc/arch-x86/x86.mk @@ -1,27 +1,40 @@ -# x86 specific configs +# 32-bit x86. -# These are shared by all the 32-bit targets, but not the 64-bit ones. -libc_common_src_files_x86 := \ +# +# Various kinds of LP32 cruft. +# + +libc_bionic_src_files_x86 += \ + bionic/mmap.cpp \ + +libc_common_src_files_x86 += \ bionic/legacy_32_bit_support.cpp \ bionic/ndk_cruft.cpp \ bionic/time64.c \ + +libc_netbsd_src_files_x86 += \ + upstream-netbsd/common/lib/libc/hash/sha1/sha1.c \ + +libc_openbsd_src_files_x86 += \ upstream-openbsd/lib/libc/stdio/putw.c \ -# Fortify implementations of libc functions. +# +# Default implementations of functions that are commonly optimized. +# + libc_common_src_files_x86 += \ bionic/__memcpy_chk.cpp \ bionic/__memset_chk.cpp \ bionic/__strcpy_chk.cpp \ bionic/__strcat_chk.cpp \ + +libc_freebsd_src_files_x86 += \ upstream-freebsd/lib/libc/string/wmemmove.c \ +# +# Inherently architecture-specific functions. +# -# These are shared by all the 32-bit targets, but not the 64-bit ones. -libc_bionic_src_files_x86 := \ - bionic/mmap.cpp - -########################################## -### CPU specific source files libc_bionic_src_files_x86 += \ arch-x86/bionic/__bionic_clone.S \ arch-x86/bionic/_exit_with_stack_teardown.S \ @@ -42,9 +55,6 @@ endif include $(arch_variant_mk) libc_common_additional_dependencies += $(arch_variant_mk) -libc_netbsd_src_files_x86 := \ - upstream-netbsd/common/lib/libc/hash/sha1/sha1.c \ - arch_variant_mk := libc_crt_target_cflags_x86 := \ diff --git a/libc/arch-x86_64/x86_64.mk b/libc/arch-x86_64/x86_64.mk index 5f12a49d7..8675ef45a 100644 --- a/libc/arch-x86_64/x86_64.mk +++ b/libc/arch-x86_64/x86_64.mk @@ -1,11 +1,21 @@ -# x86_64 specific configs +# 64-bit x86. -libc_common_src_files_x86_64 := \ +# +# Default implementations of functions that are commonly optimized. +# + +libc_bionic_src_files_x86_64 += \ + bionic/__memcpy_chk.cpp \ + bionic/__memset_chk.cpp \ + bionic/__strcpy_chk.cpp \ + bionic/__strcat_chk.cpp \ bionic/memchr.c \ bionic/memrchr.c \ bionic/strchr.cpp \ bionic/strnlen.c \ bionic/strrchr.cpp \ + +libc_freebsd_src_files_x86_64 += \ upstream-freebsd/lib/libc/string/wcscat.c \ upstream-freebsd/lib/libc/string/wcschr.c \ upstream-freebsd/lib/libc/string/wcscmp.c \ @@ -14,20 +24,16 @@ libc_common_src_files_x86_64 := \ upstream-freebsd/lib/libc/string/wcsrchr.c \ upstream-freebsd/lib/libc/string/wmemcmp.c \ upstream-freebsd/lib/libc/string/wmemmove.c \ + +libc_openbsd_src_files_x86_64 += \ upstream-openbsd/lib/libc/string/strlcat.c \ upstream-openbsd/lib/libc/string/strlcpy.c \ -# Fortify implementations of libc functions. -libc_common_src_files_x86_64 += \ - bionic/__memcpy_chk.cpp \ - bionic/__memset_chk.cpp \ - bionic/__strcpy_chk.cpp \ - bionic/__strcat_chk.cpp \ +# +# Inherently architecture-specific code. +# - -########################################## -### CPU specific source files -libc_bionic_src_files_x86_64 := \ +libc_bionic_src_files_x86_64 += \ arch-x86_64/bionic/__bionic_clone.S \ arch-x86_64/bionic/_exit_with_stack_teardown.S \ arch-x86_64/bionic/__restore_rt.S \ @@ -38,6 +44,10 @@ libc_bionic_src_files_x86_64 := \ arch-x86_64/bionic/syscall.S \ arch-x86_64/bionic/vfork.S \ +# +# Optimized memory/string functions. +# + libc_bionic_src_files_x86_64 += \ arch-x86_64/string/sse2-memcpy-slm.S \ arch-x86_64/string/sse2-memmove-slm.S \ @@ -55,15 +65,15 @@ libc_bionic_src_files_x86_64 += \ libc_crt_target_cflags_x86_64 += \ -m64 \ - -I$(LOCAL_PATH)/arch-x86_64/include + -I$(LOCAL_PATH)/arch-x86_64/include \ -libc_crt_target_ldflags_x86_64 := -melf_x86_64 +libc_crt_target_ldflags_x86_64 := -melf_x86_64 \ libc_crt_target_crtbegin_file_x86_64 := \ - $(LOCAL_PATH)/arch-common/bionic/crtbegin.c + $(LOCAL_PATH)/arch-common/bionic/crtbegin.c \ libc_crt_target_crtbegin_so_file_x86_64 := \ - $(LOCAL_PATH)/arch-common/bionic/crtbegin_so.c + $(LOCAL_PATH)/arch-common/bionic/crtbegin_so.c \ libc_crt_target_so_cflags_x86_64 := \ - -fPIC + -fPIC \ From 0cc59dd303205de7110e298e9b90b1c3b98f4711 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 24 Sep 2014 17:05:20 -0700 Subject: [PATCH 058/114] Add __memcpy_chk assembly for 64 bit. Bug: 17623887 (cherry picked from commit 8cf61dab5f11ed5654a5760ab47cec0239caafe0) Change-Id: I91e66ca0c26f04b50308059f9c89d388d55f6e3a --- libc/arch-arm64/arm64.mk | 1 - libc/arch-arm64/denver64/bionic/memcpy.S | 248 ++++-------------- libc/arch-arm64/denver64/bionic/memcpy_base.S | 199 ++++++++++++++ libc/arch-arm64/generic/bionic/memcpy.S | 227 ++++------------ libc/arch-arm64/generic/bionic/memcpy_base.S | 179 +++++++++++++ 5 files changed, 484 insertions(+), 370 deletions(-) create mode 100644 libc/arch-arm64/denver64/bionic/memcpy_base.S create mode 100644 libc/arch-arm64/generic/bionic/memcpy_base.S diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk index cdb2777b1..bb6ca6303 100644 --- a/libc/arch-arm64/arm64.mk +++ b/libc/arch-arm64/arm64.mk @@ -5,7 +5,6 @@ # libc_bionic_src_files_arm64 += \ - bionic/__memcpy_chk.cpp \ bionic/__memset_chk.cpp \ bionic/__strcpy_chk.cpp \ bionic/__strcat_chk.cpp \ diff --git a/libc/arch-arm64/denver64/bionic/memcpy.S b/libc/arch-arm64/denver64/bionic/memcpy.S index 700f0d011..85129fee9 100644 --- a/libc/arch-arm64/denver64/bionic/memcpy.S +++ b/libc/arch-arm64/denver64/bionic/memcpy.S @@ -1,205 +1,63 @@ -/* Copyright (c) 2012, Linaro Limited - All rights reserved. - Copyright (c) 2014, NVIDIA Corporation. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Linaro nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* Assumptions: +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. * - * denver, ARMv8-a, AArch64 - * Unaligned accesses + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ +// Prototype: void *memcpy (void *dst, const void *src, size_t count). + #include +#include -#define dstin x0 -#define src x1 -#define count x2 -#define tmp1 x3 -#define tmp1w w3 -#define tmp2 x4 -#define tmp2w w4 -#define tmp3 x5 -#define tmp3w w5 -#define dst x6 +ENTRY(__memcpy_chk) + cmp x2, x3 + b.hi __memcpy_chk_fail -#define A_l x7 -#define A_h x8 -#define B_l x9 -#define B_h x10 -#define C_l x11 -#define C_h x12 -#define D_l x13 -#define D_h x14 - -#define QA_l q0 -#define QA_h q1 -#define QB_l q2 -#define QB_h q3 + // Fall through to memcpy... +END(__memcpy_chk) ENTRY(memcpy) - - mov dst, dstin - cmp count, #64 - b.ge .Lcpy_not_short - cmp count, #15 - b.le .Ltail15tiny - - /* Deal with small copies quickly by dropping straight into the - * exit block. */ -.Ltail63: - /* Copy up to 48 bytes of data. At this point we only need the - * bottom 6 bits of count to be accurate. */ - ands tmp1, count, #0x30 - b.eq .Ltail15 - add dst, dst, tmp1 - add src, src, tmp1 - cmp tmp1w, #0x20 - b.eq 1f - b.lt 2f - ldp A_l, A_h, [src, #-48] - stp A_l, A_h, [dst, #-48] -1: - ldp A_l, A_h, [src, #-32] - stp A_l, A_h, [dst, #-32] -2: - ldp A_l, A_h, [src, #-16] - stp A_l, A_h, [dst, #-16] - -.Ltail15: - ands count, count, #15 - beq 1f - add src, src, count - ldp A_l, A_h, [src, #-16] - add dst, dst, count - stp A_l, A_h, [dst, #-16] -1: - ret - -.Ltail15tiny: - /* Copy up to 15 bytes of data. Does not assume additional data - being copied. */ - tbz count, #3, 1f - ldr tmp1, [src], #8 - str tmp1, [dst], #8 -1: - tbz count, #2, 1f - ldr tmp1w, [src], #4 - str tmp1w, [dst], #4 -1: - tbz count, #1, 1f - ldrh tmp1w, [src], #2 - strh tmp1w, [dst], #2 -1: - tbz count, #0, 1f - ldrb tmp1w, [src] - strb tmp1w, [dst] -1: - ret - -.Lcpy_not_short: - /* We don't much care about the alignment of DST, but we want SRC - * to be 128-bit (16 byte) aligned so that we don't cross cache line - * boundaries on both loads and stores. */ - neg tmp2, src - ands tmp2, tmp2, #15 /* Bytes to reach alignment. */ - b.eq 2f - sub count, count, tmp2 - /* Copy more data than needed; it's faster than jumping - * around copying sub-Quadword quantities. We know that - * it can't overrun. */ - ldp A_l, A_h, [src] - add src, src, tmp2 - stp A_l, A_h, [dst] - add dst, dst, tmp2 - /* There may be less than 63 bytes to go now. */ - cmp count, #63 - b.le .Ltail63 -2: - subs count, count, #128 - b.ge .Lcpy_body_large - /* Less than 128 bytes to copy, so handle 64 here and then jump - * to the tail. */ - ldp QA_l, QA_h, [src] - ldp QB_l, QB_h, [src, #32] - stp QA_l, QA_h, [dst] - stp QB_l, QB_h, [dst, #32] - tst count, #0x3f - add src, src, #64 - add dst, dst, #64 - b.ne .Ltail63 - ret - - /* Critical loop. Start at a new cache line boundary. Assuming - * 64 bytes per line this ensures the entire loop is in one line. */ - .p2align 6 -.Lcpy_body_large: - cmp count, 65536 - bhi .Lcpy_body_huge - /* There are at least 128 bytes to copy. */ - ldp QA_l, QA_h, [src, #0] - sub dst, dst, #32 /* Pre-bias. */ - ldp QB_l, QB_h, [src, #32]! /* src += 64 - Pre-bias. */ -1: - stp QA_l, QA_h, [dst, #32] - ldp QA_l, QA_h, [src, #32] - stp QB_l, QB_h, [dst, #64]! - ldp QB_l, QB_h, [src, #64]! - - subs count, count, #64 - b.ge 1b - - stp QA_l, QA_h, [dst, #32] - stp QB_l, QB_h, [dst, #64] - add src, src, #32 - add dst, dst, #64 + 32 - tst count, #0x3f - b.ne .Ltail63 - ret -.Lcpy_body_huge: - /* There are at least 128 bytes to copy. */ - ldp QA_l, QA_h, [src, #0] - sub dst, dst, #32 /* Pre-bias. */ - ldp QB_l, QB_h, [src, #32]! -1: - stnp QA_l, QA_h, [dst, #32] - stnp QB_l, QB_h, [dst, #64] - ldp QA_l, QA_h, [src, #32] - ldp QB_l, QB_h, [src, #64]! - add dst, dst, #64 - - subs count, count, #64 - b.ge 1b - - stnp QA_l, QA_h, [dst, #32] - stnp QB_l, QB_h, [dst, #64] - add src, src, #32 - add dst, dst, #64 + 32 - tst count, #0x3f - b.ne .Ltail63 - ret - + #include "memcpy_base.S" END(memcpy) + +ENTRY_PRIVATE(__memcpy_chk_fail) + // Preserve for accurate backtrace. + stp x29, x30, [sp, -16]! + .cfi_def_cfa_offset 16 + .cfi_rel_offset x29, 0 + .cfi_rel_offset x30, 8 + + adrp x0, error_string + add x0, x0, :lo12:error_string + ldr x1, error_code + bl __fortify_chk_fail +error_code: + .word BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW +END(__memcpy_chk_fail) + + .data + .align 2 +error_string: + .string "memcpy: prevented write past end of buffer" diff --git a/libc/arch-arm64/denver64/bionic/memcpy_base.S b/libc/arch-arm64/denver64/bionic/memcpy_base.S new file mode 100644 index 000000000..3d7e9dd79 --- /dev/null +++ b/libc/arch-arm64/denver64/bionic/memcpy_base.S @@ -0,0 +1,199 @@ +/* Copyright (c) 2012, Linaro Limited + All rights reserved. + Copyright (c) 2014, NVIDIA Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Linaro nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Assumptions: + * + * denver, ARMv8-a, AArch64 + * Unaligned accesses + * + */ + +#define dstin x0 +#define src x1 +#define count x2 +#define tmp1 x3 +#define tmp1w w3 +#define tmp2 x4 +#define tmp2w w4 +#define tmp3 x5 +#define tmp3w w5 +#define dst x6 + +#define A_l x7 +#define A_h x8 +#define B_l x9 +#define B_h x10 +#define C_l x11 +#define C_h x12 +#define D_l x13 +#define D_h x14 + +#define QA_l q0 +#define QA_h q1 +#define QB_l q2 +#define QB_h q3 + + mov dst, dstin + cmp count, #64 + b.ge .Lcpy_not_short + cmp count, #15 + b.le .Ltail15tiny + + /* Deal with small copies quickly by dropping straight into the + * exit block. */ +.Ltail63: + /* Copy up to 48 bytes of data. At this point we only need the + * bottom 6 bits of count to be accurate. */ + ands tmp1, count, #0x30 + b.eq .Ltail15 + add dst, dst, tmp1 + add src, src, tmp1 + cmp tmp1w, #0x20 + b.eq 1f + b.lt 2f + ldp A_l, A_h, [src, #-48] + stp A_l, A_h, [dst, #-48] +1: + ldp A_l, A_h, [src, #-32] + stp A_l, A_h, [dst, #-32] +2: + ldp A_l, A_h, [src, #-16] + stp A_l, A_h, [dst, #-16] + +.Ltail15: + ands count, count, #15 + beq 1f + add src, src, count + ldp A_l, A_h, [src, #-16] + add dst, dst, count + stp A_l, A_h, [dst, #-16] +1: + ret + +.Ltail15tiny: + /* Copy up to 15 bytes of data. Does not assume additional data + being copied. */ + tbz count, #3, 1f + ldr tmp1, [src], #8 + str tmp1, [dst], #8 +1: + tbz count, #2, 1f + ldr tmp1w, [src], #4 + str tmp1w, [dst], #4 +1: + tbz count, #1, 1f + ldrh tmp1w, [src], #2 + strh tmp1w, [dst], #2 +1: + tbz count, #0, 1f + ldrb tmp1w, [src] + strb tmp1w, [dst] +1: + ret + +.Lcpy_not_short: + /* We don't much care about the alignment of DST, but we want SRC + * to be 128-bit (16 byte) aligned so that we don't cross cache line + * boundaries on both loads and stores. */ + neg tmp2, src + ands tmp2, tmp2, #15 /* Bytes to reach alignment. */ + b.eq 2f + sub count, count, tmp2 + /* Copy more data than needed; it's faster than jumping + * around copying sub-Quadword quantities. We know that + * it can't overrun. */ + ldp A_l, A_h, [src] + add src, src, tmp2 + stp A_l, A_h, [dst] + add dst, dst, tmp2 + /* There may be less than 63 bytes to go now. */ + cmp count, #63 + b.le .Ltail63 +2: + subs count, count, #128 + b.ge .Lcpy_body_large + /* Less than 128 bytes to copy, so handle 64 here and then jump + * to the tail. */ + ldp QA_l, QA_h, [src] + ldp QB_l, QB_h, [src, #32] + stp QA_l, QA_h, [dst] + stp QB_l, QB_h, [dst, #32] + tst count, #0x3f + add src, src, #64 + add dst, dst, #64 + b.ne .Ltail63 + ret + + /* Critical loop. Start at a new cache line boundary. Assuming + * 64 bytes per line this ensures the entire loop is in one line. */ + .p2align 6 +.Lcpy_body_large: + cmp count, 65536 + bhi .Lcpy_body_huge + /* There are at least 128 bytes to copy. */ + ldp QA_l, QA_h, [src, #0] + sub dst, dst, #32 /* Pre-bias. */ + ldp QB_l, QB_h, [src, #32]! /* src += 64 - Pre-bias. */ +1: + stp QA_l, QA_h, [dst, #32] + ldp QA_l, QA_h, [src, #32] + stp QB_l, QB_h, [dst, #64]! + ldp QB_l, QB_h, [src, #64]! + + subs count, count, #64 + b.ge 1b + + stp QA_l, QA_h, [dst, #32] + stp QB_l, QB_h, [dst, #64] + add src, src, #32 + add dst, dst, #64 + 32 + tst count, #0x3f + b.ne .Ltail63 + ret +.Lcpy_body_huge: + /* There are at least 128 bytes to copy. */ + ldp QA_l, QA_h, [src, #0] + sub dst, dst, #32 /* Pre-bias. */ + ldp QB_l, QB_h, [src, #32]! +1: + stnp QA_l, QA_h, [dst, #32] + stnp QB_l, QB_h, [dst, #64] + ldp QA_l, QA_h, [src, #32] + ldp QB_l, QB_h, [src, #64]! + add dst, dst, #64 + + subs count, count, #64 + b.ge 1b + + stnp QA_l, QA_h, [dst, #32] + stnp QB_l, QB_h, [dst, #64] + add src, src, #32 + add dst, dst, #64 + 32 + tst count, #0x3f + b.ne .Ltail63 + ret diff --git a/libc/arch-arm64/generic/bionic/memcpy.S b/libc/arch-arm64/generic/bionic/memcpy.S index e1b1a727c..85129fee9 100644 --- a/libc/arch-arm64/generic/bionic/memcpy.S +++ b/libc/arch-arm64/generic/bionic/memcpy.S @@ -1,184 +1,63 @@ -/* Copyright (c) 2012, Linaro Limited - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Linaro nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* Assumptions: +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. * - * ARMv8-a, AArch64 - * Unaligned accesses + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ +// Prototype: void *memcpy (void *dst, const void *src, size_t count). + #include +#include -#define dstin x0 -#define src x1 -#define count x2 -#define tmp1 x3 -#define tmp1w w3 -#define tmp2 x4 -#define tmp2w w4 -#define tmp3 x5 -#define tmp3w w5 -#define dst x6 +ENTRY(__memcpy_chk) + cmp x2, x3 + b.hi __memcpy_chk_fail -#define A_l x7 -#define A_h x8 -#define B_l x9 -#define B_h x10 -#define C_l x11 -#define C_h x12 -#define D_l x13 -#define D_h x14 + // Fall through to memcpy... +END(__memcpy_chk) ENTRY(memcpy) - - mov dst, dstin - cmp count, #64 - b.ge .Lcpy_not_short - cmp count, #15 - b.le .Ltail15tiny - - /* Deal with small copies quickly by dropping straight into the - * exit block. */ -.Ltail63: - /* Copy up to 48 bytes of data. At this point we only need the - * bottom 6 bits of count to be accurate. */ - ands tmp1, count, #0x30 - b.eq .Ltail15 - add dst, dst, tmp1 - add src, src, tmp1 - cmp tmp1w, #0x20 - b.eq 1f - b.lt 2f - ldp A_l, A_h, [src, #-48] - stp A_l, A_h, [dst, #-48] -1: - ldp A_l, A_h, [src, #-32] - stp A_l, A_h, [dst, #-32] -2: - ldp A_l, A_h, [src, #-16] - stp A_l, A_h, [dst, #-16] - -.Ltail15: - ands count, count, #15 - beq 1f - add src, src, count - ldp A_l, A_h, [src, #-16] - add dst, dst, count - stp A_l, A_h, [dst, #-16] -1: - ret - -.Ltail15tiny: - /* Copy up to 15 bytes of data. Does not assume additional data - being copied. */ - tbz count, #3, 1f - ldr tmp1, [src], #8 - str tmp1, [dst], #8 -1: - tbz count, #2, 1f - ldr tmp1w, [src], #4 - str tmp1w, [dst], #4 -1: - tbz count, #1, 1f - ldrh tmp1w, [src], #2 - strh tmp1w, [dst], #2 -1: - tbz count, #0, 1f - ldrb tmp1w, [src] - strb tmp1w, [dst] -1: - ret - -.Lcpy_not_short: - /* We don't much care about the alignment of DST, but we want SRC - * to be 128-bit (16 byte) aligned so that we don't cross cache line - * boundaries on both loads and stores. */ - neg tmp2, src - ands tmp2, tmp2, #15 /* Bytes to reach alignment. */ - b.eq 2f - sub count, count, tmp2 - /* Copy more data than needed; it's faster than jumping - * around copying sub-Quadword quantities. We know that - * it can't overrun. */ - ldp A_l, A_h, [src] - add src, src, tmp2 - stp A_l, A_h, [dst] - add dst, dst, tmp2 - /* There may be less than 63 bytes to go now. */ - cmp count, #63 - b.le .Ltail63 -2: - subs count, count, #128 - b.ge .Lcpy_body_large - /* Less than 128 bytes to copy, so handle 64 here and then jump - * to the tail. */ - ldp A_l, A_h, [src] - ldp B_l, B_h, [src, #16] - ldp C_l, C_h, [src, #32] - ldp D_l, D_h, [src, #48] - stp A_l, A_h, [dst] - stp B_l, B_h, [dst, #16] - stp C_l, C_h, [dst, #32] - stp D_l, D_h, [dst, #48] - tst count, #0x3f - add src, src, #64 - add dst, dst, #64 - b.ne .Ltail63 - ret - - /* Critical loop. Start at a new cache line boundary. Assuming - * 64 bytes per line this ensures the entire loop is in one line. */ - .p2align 6 -.Lcpy_body_large: - /* There are at least 128 bytes to copy. */ - ldp A_l, A_h, [src, #0] - sub dst, dst, #16 /* Pre-bias. */ - ldp B_l, B_h, [src, #16] - ldp C_l, C_h, [src, #32] - ldp D_l, D_h, [src, #48]! /* src += 64 - Pre-bias. */ -1: - stp A_l, A_h, [dst, #16] - ldp A_l, A_h, [src, #16] - stp B_l, B_h, [dst, #32] - ldp B_l, B_h, [src, #32] - stp C_l, C_h, [dst, #48] - ldp C_l, C_h, [src, #48] - stp D_l, D_h, [dst, #64]! - ldp D_l, D_h, [src, #64]! - subs count, count, #64 - b.ge 1b - stp A_l, A_h, [dst, #16] - stp B_l, B_h, [dst, #32] - stp C_l, C_h, [dst, #48] - stp D_l, D_h, [dst, #64] - add src, src, #16 - add dst, dst, #64 + 16 - tst count, #0x3f - b.ne .Ltail63 - ret + #include "memcpy_base.S" END(memcpy) + +ENTRY_PRIVATE(__memcpy_chk_fail) + // Preserve for accurate backtrace. + stp x29, x30, [sp, -16]! + .cfi_def_cfa_offset 16 + .cfi_rel_offset x29, 0 + .cfi_rel_offset x30, 8 + + adrp x0, error_string + add x0, x0, :lo12:error_string + ldr x1, error_code + bl __fortify_chk_fail +error_code: + .word BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW +END(__memcpy_chk_fail) + + .data + .align 2 +error_string: + .string "memcpy: prevented write past end of buffer" diff --git a/libc/arch-arm64/generic/bionic/memcpy_base.S b/libc/arch-arm64/generic/bionic/memcpy_base.S new file mode 100644 index 000000000..c5d42ce1d --- /dev/null +++ b/libc/arch-arm64/generic/bionic/memcpy_base.S @@ -0,0 +1,179 @@ +/* Copyright (c) 2012, Linaro Limited + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Linaro nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Assumptions: + * + * ARMv8-a, AArch64 + * Unaligned accesses + * + */ + +#define dstin x0 +#define src x1 +#define count x2 +#define tmp1 x3 +#define tmp1w w3 +#define tmp2 x4 +#define tmp2w w4 +#define tmp3 x5 +#define tmp3w w5 +#define dst x6 + +#define A_l x7 +#define A_h x8 +#define B_l x9 +#define B_h x10 +#define C_l x11 +#define C_h x12 +#define D_l x13 +#define D_h x14 + + mov dst, dstin + cmp count, #64 + b.ge .Lcpy_not_short + cmp count, #15 + b.le .Ltail15tiny + + /* Deal with small copies quickly by dropping straight into the + * exit block. */ +.Ltail63: + /* Copy up to 48 bytes of data. At this point we only need the + * bottom 6 bits of count to be accurate. */ + ands tmp1, count, #0x30 + b.eq .Ltail15 + add dst, dst, tmp1 + add src, src, tmp1 + cmp tmp1w, #0x20 + b.eq 1f + b.lt 2f + ldp A_l, A_h, [src, #-48] + stp A_l, A_h, [dst, #-48] +1: + ldp A_l, A_h, [src, #-32] + stp A_l, A_h, [dst, #-32] +2: + ldp A_l, A_h, [src, #-16] + stp A_l, A_h, [dst, #-16] + +.Ltail15: + ands count, count, #15 + beq 1f + add src, src, count + ldp A_l, A_h, [src, #-16] + add dst, dst, count + stp A_l, A_h, [dst, #-16] +1: + ret + +.Ltail15tiny: + /* Copy up to 15 bytes of data. Does not assume additional data + being copied. */ + tbz count, #3, 1f + ldr tmp1, [src], #8 + str tmp1, [dst], #8 +1: + tbz count, #2, 1f + ldr tmp1w, [src], #4 + str tmp1w, [dst], #4 +1: + tbz count, #1, 1f + ldrh tmp1w, [src], #2 + strh tmp1w, [dst], #2 +1: + tbz count, #0, 1f + ldrb tmp1w, [src] + strb tmp1w, [dst] +1: + ret + +.Lcpy_not_short: + /* We don't much care about the alignment of DST, but we want SRC + * to be 128-bit (16 byte) aligned so that we don't cross cache line + * boundaries on both loads and stores. */ + neg tmp2, src + ands tmp2, tmp2, #15 /* Bytes to reach alignment. */ + b.eq 2f + sub count, count, tmp2 + /* Copy more data than needed; it's faster than jumping + * around copying sub-Quadword quantities. We know that + * it can't overrun. */ + ldp A_l, A_h, [src] + add src, src, tmp2 + stp A_l, A_h, [dst] + add dst, dst, tmp2 + /* There may be less than 63 bytes to go now. */ + cmp count, #63 + b.le .Ltail63 +2: + subs count, count, #128 + b.ge .Lcpy_body_large + /* Less than 128 bytes to copy, so handle 64 here and then jump + * to the tail. */ + ldp A_l, A_h, [src] + ldp B_l, B_h, [src, #16] + ldp C_l, C_h, [src, #32] + ldp D_l, D_h, [src, #48] + stp A_l, A_h, [dst] + stp B_l, B_h, [dst, #16] + stp C_l, C_h, [dst, #32] + stp D_l, D_h, [dst, #48] + tst count, #0x3f + add src, src, #64 + add dst, dst, #64 + b.ne .Ltail63 + ret + + /* Critical loop. Start at a new cache line boundary. Assuming + * 64 bytes per line this ensures the entire loop is in one line. */ + .p2align 6 +.Lcpy_body_large: + /* There are at least 128 bytes to copy. */ + ldp A_l, A_h, [src, #0] + sub dst, dst, #16 /* Pre-bias. */ + ldp B_l, B_h, [src, #16] + ldp C_l, C_h, [src, #32] + ldp D_l, D_h, [src, #48]! /* src += 64 - Pre-bias. */ +1: + stp A_l, A_h, [dst, #16] + ldp A_l, A_h, [src, #16] + stp B_l, B_h, [dst, #32] + ldp B_l, B_h, [src, #32] + stp C_l, C_h, [dst, #48] + ldp C_l, C_h, [src, #48] + stp D_l, D_h, [dst, #64]! + ldp D_l, D_h, [src, #64]! + subs count, count, #64 + b.ge 1b + stp A_l, A_h, [dst, #16] + stp B_l, B_h, [dst, #32] + stp C_l, C_h, [dst, #48] + stp D_l, D_h, [dst, #64] + add src, src, #16 + add dst, dst, #64 + 16 + tst count, #0x3f + b.ne .Ltail63 + ret From 69377b890966af4a679857caea983e4702e3b764 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 28 Oct 2014 16:58:11 -0700 Subject: [PATCH 059/114] Fix merge-induced makefile error. Change-Id: I6ac7e5e3b9d55108681916044cf2de0e01bca0b2 --- tests/Android.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Android.mk b/tests/Android.mk index f65d82b9f..9026762c1 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -235,7 +235,6 @@ bionic-unit-tests_src_files := \ dlext_test.cpp \ dlfcn_test.cpp \ stack_unwinding_test.cpp \ - stack_unwinding_test_impl.c \ bionic-unit-tests_cflags := $(test_cflags) From 1c8ea807ebb54c1533040b60c0a6394abc77e339 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Mon, 29 Sep 2014 15:34:20 -0700 Subject: [PATCH 060/114] Cleanup arm assembly. Remove the old arm directives. Change the non-local labels to .L labels. Add cfi directives to strcpy.S. Bug: 18157900 (cherry picked from commit c8bd2abab24afe563240297018c4fa79944f193b) Change-Id: Ifa1c3d16553d142eaa0d744af040f0352538106c --- .../arch-arm/cortex-a15/bionic/__strcat_chk.S | 5 - .../arch-arm/cortex-a15/bionic/__strcpy_chk.S | 2 - libc/arch-arm/cortex-a15/bionic/memcpy.S | 2 - libc/arch-arm/cortex-a15/bionic/memcpy_base.S | 5 - libc/arch-arm/cortex-a15/bionic/memset.S | 2 - libc/arch-arm/cortex-a15/bionic/strcmp.S | 1 - libc/arch-arm/cortex-a15/bionic/strcpy.S | 213 +++++++++--------- libc/arch-arm/cortex-a9/bionic/__strcat_chk.S | 4 - libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S | 2 - libc/arch-arm/cortex-a9/bionic/memcpy.S | 2 - libc/arch-arm/cortex-a9/bionic/memcpy_base.S | 3 - libc/arch-arm/cortex-a9/bionic/memset.S | 3 - libc/arch-arm/cortex-a9/bionic/strcmp.S | 1 - libc/arch-arm/cortex-a9/bionic/strcpy.S | 193 ++++++++-------- libc/arch-arm/denver/bionic/__strcat_chk.S | 5 - libc/arch-arm/denver/bionic/__strcpy_chk.S | 2 - libc/arch-arm/denver/bionic/memcpy.S | 2 - libc/arch-arm/krait/bionic/__strcat_chk.S | 4 - libc/arch-arm/krait/bionic/__strcpy_chk.S | 2 - libc/arch-arm/krait/bionic/memcpy.S | 2 - libc/arch-arm/krait/bionic/memcpy_base.S | 1 - libc/arch-arm/krait/bionic/memset.S | 2 - libc/arch-arm/krait/bionic/strcmp.S | 1 - 23 files changed, 208 insertions(+), 251 deletions(-) diff --git a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S index 36da2d9d8..a2e9c229e 100644 --- a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S +++ b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S @@ -40,12 +40,10 @@ ENTRY(__strcat_chk) pld [r0, #0] push {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 push {r4, r5} - .save {r4, r5} .cfi_adjust_cfa_offset 8 .cfi_rel_offset r4, 0 .cfi_rel_offset r5, 4 @@ -195,9 +193,6 @@ END(__strcat_chk) #include "memcpy_base.S" ENTRY_PRIVATE(__strcat_chk_failed) - .save {r0, lr} - .save {r4, r5} - .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 diff --git a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S index c3e3e14fa..db766863a 100644 --- a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S +++ b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S @@ -39,7 +39,6 @@ ENTRY(__strcpy_chk) pld [r0, #0] push {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 @@ -161,7 +160,6 @@ END(__strcpy_chk) #include "memcpy_base.S" ENTRY_PRIVATE(__strcpy_chk_failed) - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy.S b/libc/arch-arm/cortex-a15/bionic/memcpy.S index da4f3dd79..410b663e2 100644 --- a/libc/arch-arm/cortex-a15/bionic/memcpy.S +++ b/libc/arch-arm/cortex-a15/bionic/memcpy.S @@ -72,7 +72,6 @@ END(__memcpy_chk) ENTRY(memcpy) pld [r1, #64] push {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 @@ -85,7 +84,6 @@ END(memcpy) ENTRY_PRIVATE(__memcpy_chk_fail) // Preserve lr for backtrace. push {lr} - .save {lr} .cfi_def_cfa_offset 4 .cfi_rel_offset lr, 0 diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy_base.S b/libc/arch-arm/cortex-a15/bionic/memcpy_base.S index 6ba4931f9..2a7385247 100644 --- a/libc/arch-arm/cortex-a15/bionic/memcpy_base.S +++ b/libc/arch-arm/cortex-a15/bionic/memcpy_base.S @@ -54,7 +54,6 @@ */ ENTRY_PRIVATE(MEMCPY_BASE) - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 @@ -172,7 +171,6 @@ ENTRY_PRIVATE(MEMCPY_BASE) END(MEMCPY_BASE) ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED) - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 @@ -181,17 +179,14 @@ ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED) // i.e., not keeping the stack looking like users expect // (highest numbered register at highest address). strd r4, r5, [sp, #-8]! - .save {r4, r5} .cfi_adjust_cfa_offset 8 .cfi_rel_offset r4, 0 .cfi_rel_offset r5, 4 strd r6, r7, [sp, #-8]! - .save {r6, r7} .cfi_adjust_cfa_offset 8 .cfi_rel_offset r6, 0 .cfi_rel_offset r7, 0 strd r8, r9, [sp, #-8]! - .save {r8, r9} .cfi_adjust_cfa_offset 8 .cfi_rel_offset r8, 0 .cfi_rel_offset r9, 4 diff --git a/libc/arch-arm/cortex-a15/bionic/memset.S b/libc/arch-arm/cortex-a15/bionic/memset.S index 12c68d6a9..e4a1ec869 100644 --- a/libc/arch-arm/cortex-a15/bionic/memset.S +++ b/libc/arch-arm/cortex-a15/bionic/memset.S @@ -44,7 +44,6 @@ ENTRY(__memset_chk) bls .L_done // Preserve lr for backtrace. - .save {lr} push {lr} .cfi_def_cfa_offset 4 .cfi_rel_offset lr, 0 @@ -68,7 +67,6 @@ ENTRY(bzero) END(bzero) ENTRY(memset) - .save {r0} stmfd sp!, {r0} .cfi_def_cfa_offset 4 .cfi_rel_offset r0, 0 diff --git a/libc/arch-arm/cortex-a15/bionic/strcmp.S b/libc/arch-arm/cortex-a15/bionic/strcmp.S index 12da1158d..acedf0ec6 100644 --- a/libc/arch-arm/cortex-a15/bionic/strcmp.S +++ b/libc/arch-arm/cortex-a15/bionic/strcmp.S @@ -168,7 +168,6 @@ ENTRY(strcmp) bne .L_do_align /* Fast path. */ - .save {r4-r7} init .L_doubleword_aligned: diff --git a/libc/arch-arm/cortex-a15/bionic/strcpy.S b/libc/arch-arm/cortex-a15/bionic/strcpy.S index cb878c44f..2cfdb1931 100644 --- a/libc/arch-arm/cortex-a15/bionic/strcpy.S +++ b/libc/arch-arm/cortex-a15/bionic/strcpy.S @@ -62,6 +62,11 @@ .macro m_push push {r0, r4, r5, lr} + .cfi_def_cfa_offset 16 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r4, 4 + .cfi_rel_offset r5, 8 + .cfi_rel_offset lr, 12 .endm // m_push .macro m_pop @@ -78,61 +83,61 @@ ENTRY(strcpy) // For short copies, hard-code checking the first 8 bytes since this // new code doesn't win until after about 8 bytes. m_push - m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r5, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r5, cmd=cbnz, label=strcpy_continue + m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r5, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r5, cmd=cbnz, label=.Lstrcpy_continue -strcpy_finish: +.Lstrcpy_finish: m_pop -strcpy_continue: +.Lstrcpy_continue: pld [r1, #0] ands r3, r0, #7 - beq strcpy_check_src_align + beq .Lstrcpy_check_src_align // Align to a double word (64 bits). rsb r3, r3, #8 lsls ip, r3, #31 - beq strcpy_align_to_32 + beq .Lstrcpy_align_to_32 ldrb r2, [r1], #1 strb r2, [r0], #1 - cbz r2, strcpy_complete + cbz r2, .Lstrcpy_complete -strcpy_align_to_32: - bcc strcpy_align_to_64 +.Lstrcpy_align_to_32: + bcc .Lstrcpy_align_to_64 ldrb r2, [r1], #1 strb r2, [r0], #1 - cbz r2, strcpy_complete + cbz r2, .Lstrcpy_complete ldrb r2, [r1], #1 strb r2, [r0], #1 - cbz r2, strcpy_complete + cbz r2, .Lstrcpy_complete -strcpy_align_to_64: +.Lstrcpy_align_to_64: tst r3, #4 - beq strcpy_check_src_align + beq .Lstrcpy_check_src_align ldr r2, [r1], #4 sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register str r2, [r0], #4 -strcpy_check_src_align: +.Lstrcpy_check_src_align: // At this point dst is aligned to a double word, check if src // is also aligned to a double word. ands r3, r1, #7 - bne strcpy_unaligned_copy + bne .Lstrcpy_unaligned_copy .p2align 2 -strcpy_mainloop: +.Lstrcpy_mainloop: ldrd r2, r3, [r1], #8 pld [r1, #64] @@ -140,128 +145,128 @@ strcpy_mainloop: sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register strd r2, r3, [r0], #8 - b strcpy_mainloop + b .Lstrcpy_mainloop -strcpy_complete: +.Lstrcpy_complete: m_pop -strcpy_zero_in_first_register: +.Lstrcpy_zero_in_first_register: lsls lr, ip, #17 - bne strcpy_copy1byte - bcs strcpy_copy2bytes + bne .Lstrcpy_copy1byte + bcs .Lstrcpy_copy2bytes lsls ip, ip, #1 - bne strcpy_copy3bytes + bne .Lstrcpy_copy3bytes -strcpy_copy4bytes: +.Lstrcpy_copy4bytes: // Copy 4 bytes to the destiniation. str r2, [r0] m_pop -strcpy_copy1byte: +.Lstrcpy_copy1byte: strb r2, [r0] m_pop -strcpy_copy2bytes: +.Lstrcpy_copy2bytes: strh r2, [r0] m_pop -strcpy_copy3bytes: +.Lstrcpy_copy3bytes: strh r2, [r0], #2 lsr r2, #16 strb r2, [r0] m_pop -strcpy_zero_in_second_register: +.Lstrcpy_zero_in_second_register: lsls lr, ip, #17 - bne strcpy_copy5bytes - bcs strcpy_copy6bytes + bne .Lstrcpy_copy5bytes + bcs .Lstrcpy_copy6bytes lsls ip, ip, #1 - bne strcpy_copy7bytes + bne .Lstrcpy_copy7bytes // Copy 8 bytes to the destination. strd r2, r3, [r0] m_pop -strcpy_copy5bytes: +.Lstrcpy_copy5bytes: str r2, [r0], #4 strb r3, [r0] m_pop -strcpy_copy6bytes: +.Lstrcpy_copy6bytes: str r2, [r0], #4 strh r3, [r0] m_pop -strcpy_copy7bytes: +.Lstrcpy_copy7bytes: str r2, [r0], #4 strh r3, [r0], #2 lsr r3, #16 strb r3, [r0] m_pop -strcpy_unaligned_copy: +.Lstrcpy_unaligned_copy: // Dst is aligned to a double word, while src is at an unknown alignment. // There are 7 different versions of the unaligned copy code // to prevent overreading the src. The mainloop of every single version // will store 64 bits per loop. The difference is how much of src can // be read without potentially crossing a page boundary. tbb [pc, r3] -strcpy_unaligned_branchtable: +.Lstrcpy_unaligned_branchtable: .byte 0 - .byte ((strcpy_unalign7 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign6 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign5 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign4 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign3 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign2 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign1 - strcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign7 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign6 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign5 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign4 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign3 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign2 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign1 - .Lstrcpy_unaligned_branchtable)/2) .p2align 2 // Can read 7 bytes before possibly crossing a page. -strcpy_unalign7: +.Lstrcpy_unalign7: ldr r2, [r1], #4 sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register ldrb r3, [r1] - cbz r3, strcpy_unalign7_copy5bytes + cbz r3, .Lstrcpy_unalign7_copy5bytes ldrb r4, [r1, #1] - cbz r4, strcpy_unalign7_copy6bytes + cbz r4, .Lstrcpy_unalign7_copy6bytes ldrb r5, [r1, #2] - cbz r5, strcpy_unalign7_copy7bytes + cbz r5, .Lstrcpy_unalign7_copy7bytes ldr r3, [r1], #4 pld [r1, #64] lsrs ip, r3, #24 strd r2, r3, [r0], #8 - beq strcpy_unalign_return - b strcpy_unalign7 + beq .Lstrcpy_unalign_return + b .Lstrcpy_unalign7 -strcpy_unalign7_copy5bytes: +.Lstrcpy_unalign7_copy5bytes: str r2, [r0], #4 strb r3, [r0] -strcpy_unalign_return: +.Lstrcpy_unalign_return: m_pop -strcpy_unalign7_copy6bytes: +.Lstrcpy_unalign7_copy6bytes: str r2, [r0], #4 strb r3, [r0], #1 strb r4, [r0], #1 m_pop -strcpy_unalign7_copy7bytes: +.Lstrcpy_unalign7_copy7bytes: str r2, [r0], #4 strb r3, [r0], #1 strb r4, [r0], #1 @@ -270,41 +275,41 @@ strcpy_unalign7_copy7bytes: .p2align 2 // Can read 6 bytes before possibly crossing a page. -strcpy_unalign6: +.Lstrcpy_unalign6: ldr r2, [r1], #4 sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register ldrb r4, [r1] - cbz r4, strcpy_unalign_copy5bytes + cbz r4, .Lstrcpy_unalign_copy5bytes ldrb r5, [r1, #1] - cbz r5, strcpy_unalign_copy6bytes + cbz r5, .Lstrcpy_unalign_copy6bytes ldr r3, [r1], #4 pld [r1, #64] tst r3, #0xff0000 - beq strcpy_copy7bytes + beq .Lstrcpy_copy7bytes lsrs ip, r3, #24 strd r2, r3, [r0], #8 - beq strcpy_unalign_return - b strcpy_unalign6 + beq .Lstrcpy_unalign_return + b .Lstrcpy_unalign6 .p2align 2 // Can read 5 bytes before possibly crossing a page. -strcpy_unalign5: +.Lstrcpy_unalign5: ldr r2, [r1], #4 sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register ldrb r4, [r1] - cbz r4, strcpy_unalign_copy5bytes + cbz r4, .Lstrcpy_unalign_copy5bytes ldr r3, [r1], #4 @@ -313,17 +318,17 @@ strcpy_unalign5: sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register strd r2, r3, [r0], #8 - b strcpy_unalign5 + b .Lstrcpy_unalign5 -strcpy_unalign_copy5bytes: +.Lstrcpy_unalign_copy5bytes: str r2, [r0], #4 strb r4, [r0] m_pop -strcpy_unalign_copy6bytes: +.Lstrcpy_unalign_copy6bytes: str r2, [r0], #4 strb r4, [r0], #1 strb r5, [r0] @@ -331,13 +336,13 @@ strcpy_unalign_copy6bytes: .p2align 2 // Can read 4 bytes before possibly crossing a page. -strcpy_unalign4: +.Lstrcpy_unalign4: ldr r2, [r1], #4 sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register ldr r3, [r1], #4 pld [r1, #64] @@ -345,20 +350,20 @@ strcpy_unalign4: sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register strd r2, r3, [r0], #8 - b strcpy_unalign4 + b .Lstrcpy_unalign4 .p2align 2 // Can read 3 bytes before possibly crossing a page. -strcpy_unalign3: +.Lstrcpy_unalign3: ldrb r2, [r1] - cbz r2, strcpy_unalign3_copy1byte + cbz r2, .Lstrcpy_unalign3_copy1byte ldrb r3, [r1, #1] - cbz r3, strcpy_unalign3_copy2bytes + cbz r3, .Lstrcpy_unalign3_copy2bytes ldrb r4, [r1, #2] - cbz r4, strcpy_unalign3_copy3bytes + cbz r4, .Lstrcpy_unalign3_copy3bytes ldr r2, [r1], #4 ldr r3, [r1], #4 @@ -366,26 +371,26 @@ strcpy_unalign3: pld [r1, #64] lsrs lr, r2, #24 - beq strcpy_copy4bytes + beq .Lstrcpy_copy4bytes sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register strd r2, r3, [r0], #8 - b strcpy_unalign3 + b .Lstrcpy_unalign3 -strcpy_unalign3_copy1byte: +.Lstrcpy_unalign3_copy1byte: strb r2, [r0] m_pop -strcpy_unalign3_copy2bytes: +.Lstrcpy_unalign3_copy2bytes: strb r2, [r0], #1 strb r3, [r0] m_pop -strcpy_unalign3_copy3bytes: +.Lstrcpy_unalign3_copy3bytes: strb r2, [r0], #1 strb r3, [r0], #1 strb r4, [r0] @@ -393,34 +398,34 @@ strcpy_unalign3_copy3bytes: .p2align 2 // Can read 2 bytes before possibly crossing a page. -strcpy_unalign2: +.Lstrcpy_unalign2: ldrb r2, [r1] - cbz r2, strcpy_unalign_copy1byte + cbz r2, .Lstrcpy_unalign_copy1byte ldrb r4, [r1, #1] - cbz r4, strcpy_unalign_copy2bytes + cbz r4, .Lstrcpy_unalign_copy2bytes ldr r2, [r1], #4 ldr r3, [r1], #4 pld [r1, #64] tst r2, #0xff0000 - beq strcpy_copy3bytes + beq .Lstrcpy_copy3bytes lsrs ip, r2, #24 - beq strcpy_copy4bytes + beq .Lstrcpy_copy4bytes sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register strd r2, r3, [r0], #8 - b strcpy_unalign2 + b .Lstrcpy_unalign2 .p2align 2 // Can read 1 byte before possibly crossing a page. -strcpy_unalign1: +.Lstrcpy_unalign1: ldrb r2, [r1] - cbz r2, strcpy_unalign_copy1byte + cbz r2, .Lstrcpy_unalign_copy1byte ldr r2, [r1], #4 ldr r3, [r1], #4 @@ -430,21 +435,21 @@ strcpy_unalign1: sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register strd r2, r3, [r0], #8 - b strcpy_unalign1 + b .Lstrcpy_unalign1 -strcpy_unalign_copy1byte: +.Lstrcpy_unalign_copy1byte: strb r2, [r0] m_pop -strcpy_unalign_copy2bytes: +.Lstrcpy_unalign_copy2bytes: strb r2, [r0], #1 strb r4, [r0] m_pop diff --git a/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S index 651aefc7d..45517f146 100644 --- a/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S +++ b/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S @@ -40,12 +40,10 @@ ENTRY(__strcat_chk) pld [r0, #0] push {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 push {r4, r5} - .save {r4, r5} .cfi_adjust_cfa_offset 8 .cfi_rel_offset r4, 0 .cfi_rel_offset r5, 4 @@ -199,8 +197,6 @@ END(__strcat_chk) #include "memcpy_base.S" ENTRY_PRIVATE(__strcat_chk_fail) - .save {r0, lr} - .save {r4, r5} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 diff --git a/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S index 244778024..67eca086e 100644 --- a/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S +++ b/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S @@ -39,7 +39,6 @@ ENTRY(__strcpy_chk) pld [r0, #0] push {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 @@ -165,7 +164,6 @@ END(__strcpy_chk) #include "memcpy_base.S" ENTRY_PRIVATE(__strcpy_chk_fail) - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 diff --git a/libc/arch-arm/cortex-a9/bionic/memcpy.S b/libc/arch-arm/cortex-a9/bionic/memcpy.S index 8dcd937fc..db3e26fea 100644 --- a/libc/arch-arm/cortex-a9/bionic/memcpy.S +++ b/libc/arch-arm/cortex-a9/bionic/memcpy.S @@ -50,7 +50,6 @@ END(__memcpy_chk) ENTRY(memcpy) pld [r1, #0] stmfd sp!, {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 @@ -64,7 +63,6 @@ END(memcpy) ENTRY_PRIVATE(__memcpy_chk_fail) // Preserve lr for backtrace. push {lr} - .save {lr} .cfi_def_cfa_offset 4 .cfi_rel_offset lr, 0 diff --git a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S index c385657ca..5e813050a 100644 --- a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S +++ b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S @@ -33,7 +33,6 @@ */ ENTRY_PRIVATE(MEMCPY_BASE) - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 @@ -139,14 +138,12 @@ ENTRY_PRIVATE(MEMCPY_BASE) END(MEMCPY_BASE) ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED) - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 /* Simple arm-only copy loop to handle aligned copy operations */ stmfd sp!, {r4-r8} - .save {r4-r8} .cfi_adjust_cfa_offset 20 .cfi_rel_offset r4, 0 .cfi_rel_offset r5, 4 diff --git a/libc/arch-arm/cortex-a9/bionic/memset.S b/libc/arch-arm/cortex-a9/bionic/memset.S index a5057eb04..299f5a2d2 100644 --- a/libc/arch-arm/cortex-a9/bionic/memset.S +++ b/libc/arch-arm/cortex-a9/bionic/memset.S @@ -42,7 +42,6 @@ ENTRY(__memset_chk) // Preserve lr for backtrace. push {lr} - .save {lr} .cfi_def_cfa_offset 4 .cfi_rel_offset lr, 0 @@ -72,7 +71,6 @@ ENTRY(memset) bhi __memset_large_copy stmfd sp!, {r0} - .save {r0} .cfi_def_cfa_offset 4 .cfi_rel_offset r0, 0 @@ -114,7 +112,6 @@ ENTRY_PRIVATE(__memset_large_copy) * offset = (4-(src&3))&3 = -src & 3 */ stmfd sp!, {r0, r4-r7, lr} - .save {r0, r4-r7, lr} .cfi_def_cfa_offset 24 .cfi_rel_offset r0, 0 .cfi_rel_offset r4, 4 diff --git a/libc/arch-arm/cortex-a9/bionic/strcmp.S b/libc/arch-arm/cortex-a9/bionic/strcmp.S index 2411c654c..4ff26c005 100644 --- a/libc/arch-arm/cortex-a9/bionic/strcmp.S +++ b/libc/arch-arm/cortex-a9/bionic/strcmp.S @@ -168,7 +168,6 @@ ENTRY(strcmp) bne .L_do_align /* Fast path. */ - .save {r4-r7} init .L_doubleword_aligned: diff --git a/libc/arch-arm/cortex-a9/bionic/strcpy.S b/libc/arch-arm/cortex-a9/bionic/strcpy.S index 9e9610bf3..d705aa354 100644 --- a/libc/arch-arm/cortex-a9/bionic/strcpy.S +++ b/libc/arch-arm/cortex-a9/bionic/strcpy.S @@ -62,6 +62,11 @@ .macro m_push push {r0, r4, r5, lr} + .cfi_def_cfa_offset 16 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r4, 4 + .cfi_rel_offset r5, 8 + .cfi_rel_offset lr, 12 .endm // m_push .macro m_ret inst @@ -77,31 +82,31 @@ ENTRY(strcpy) // Unroll the first 8 bytes that will be copied. m_push - m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r5, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish - m_copy_byte reg=r5, cmd=cbnz, label=strcpy_continue + m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r5, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r5, cmd=cbnz, label=.Lstrcpy_continue -strcpy_finish: +.Lstrcpy_finish: m_ret inst=pop -strcpy_continue: +.Lstrcpy_continue: pld [r1, #0] ands r3, r0, #7 - bne strcpy_align_dst + bne .Lstrcpy_align_dst -strcpy_check_src_align: +.Lstrcpy_check_src_align: // At this point dst is aligned to a double word, check if src // is also aligned to a double word. ands r3, r1, #7 - bne strcpy_unaligned_copy + bne .Lstrcpy_unaligned_copy .p2align 2 -strcpy_mainloop: +.Lstrcpy_mainloop: ldmia r1!, {r2, r3} pld [r1, #64] @@ -109,17 +114,17 @@ strcpy_mainloop: sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register stmia r0!, {r2, r3} - b strcpy_mainloop + b .Lstrcpy_mainloop -strcpy_zero_in_first_register: +.Lstrcpy_zero_in_first_register: lsls lr, ip, #17 itt ne strbne r2, [r0] @@ -136,7 +141,7 @@ strcpy_zero_in_first_register: strb r3, [r0] m_ret inst=pop -strcpy_zero_in_second_register: +.Lstrcpy_zero_in_second_register: lsls lr, ip, #17 ittt ne stmiane r0!, {r2} @@ -156,18 +161,18 @@ strcpy_zero_in_second_register: strb r4, [r0] m_ret inst=pop -strcpy_align_dst: +.Lstrcpy_align_dst: // Align to a double word (64 bits). rsb r3, r3, #8 lsls ip, r3, #31 - beq strcpy_align_to_32 + beq .Lstrcpy_align_to_32 ldrb r2, [r1], #1 strb r2, [r0], #1 - cbz r2, strcpy_complete + cbz r2, .Lstrcpy_complete -strcpy_align_to_32: - bcc strcpy_align_to_64 +.Lstrcpy_align_to_32: + bcc .Lstrcpy_align_to_64 ldrb r4, [r1], #1 strb r4, [r0], #1 @@ -180,76 +185,76 @@ strcpy_align_to_32: it eq m_ret inst=popeq -strcpy_align_to_64: +.Lstrcpy_align_to_64: tst r3, #4 - beq strcpy_check_src_align + beq .Lstrcpy_check_src_align ldr r2, [r1], #4 sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register stmia r0!, {r2} - b strcpy_check_src_align + b .Lstrcpy_check_src_align -strcpy_complete: +.Lstrcpy_complete: m_ret inst=pop -strcpy_unaligned_copy: +.Lstrcpy_unaligned_copy: // Dst is aligned to a double word, while src is at an unknown alignment. // There are 7 different versions of the unaligned copy code // to prevent overreading the src. The mainloop of every single version // will store 64 bits per loop. The difference is how much of src can // be read without potentially crossing a page boundary. tbb [pc, r3] -strcpy_unaligned_branchtable: +.Lstrcpy_unaligned_branchtable: .byte 0 - .byte ((strcpy_unalign7 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign6 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign5 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign4 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign3 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign2 - strcpy_unaligned_branchtable)/2) - .byte ((strcpy_unalign1 - strcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign7 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign6 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign5 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign4 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign3 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign2 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign1 - .Lstrcpy_unaligned_branchtable)/2) .p2align 2 // Can read 7 bytes before possibly crossing a page. -strcpy_unalign7: +.Lstrcpy_unalign7: ldr r2, [r1], #4 sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register ldrb r3, [r1] - cbz r3, strcpy_unalign7_copy5bytes + cbz r3, .Lstrcpy_unalign7_copy5bytes ldrb r4, [r1, #1] - cbz r4, strcpy_unalign7_copy6bytes + cbz r4, .Lstrcpy_unalign7_copy6bytes ldrb r5, [r1, #2] - cbz r5, strcpy_unalign7_copy7bytes + cbz r5, .Lstrcpy_unalign7_copy7bytes ldr r3, [r1], #4 pld [r1, #64] lsrs ip, r3, #24 stmia r0!, {r2, r3} - beq strcpy_unalign_return - b strcpy_unalign7 + beq .Lstrcpy_unalign_return + b .Lstrcpy_unalign7 -strcpy_unalign7_copy5bytes: +.Lstrcpy_unalign7_copy5bytes: stmia r0!, {r2} strb r3, [r0] -strcpy_unalign_return: +.Lstrcpy_unalign_return: m_ret inst=pop -strcpy_unalign7_copy6bytes: +.Lstrcpy_unalign7_copy6bytes: stmia r0!, {r2} strb r3, [r0], #1 strb r4, [r0], #1 m_ret inst=pop -strcpy_unalign7_copy7bytes: +.Lstrcpy_unalign7_copy7bytes: stmia r0!, {r2} strb r3, [r0], #1 strb r4, [r0], #1 @@ -258,30 +263,30 @@ strcpy_unalign7_copy7bytes: .p2align 2 // Can read 6 bytes before possibly crossing a page. -strcpy_unalign6: +.Lstrcpy_unalign6: ldr r2, [r1], #4 sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register ldrb r4, [r1] - cbz r4, strcpy_unalign_copy5bytes + cbz r4, .Lstrcpy_unalign_copy5bytes ldrb r5, [r1, #1] - cbz r5, strcpy_unalign_copy6bytes + cbz r5, .Lstrcpy_unalign_copy6bytes ldr r3, [r1], #4 pld [r1, #64] tst r3, #0xff0000 - beq strcpy_unalign6_copy7bytes + beq .Lstrcpy_unalign6_copy7bytes lsrs ip, r3, #24 stmia r0!, {r2, r3} - beq strcpy_unalign_return - b strcpy_unalign6 + beq .Lstrcpy_unalign_return + b .Lstrcpy_unalign6 -strcpy_unalign6_copy7bytes: +.Lstrcpy_unalign6_copy7bytes: stmia r0!, {r2} strh r3, [r0], #2 lsr r3, #16 @@ -290,16 +295,16 @@ strcpy_unalign6_copy7bytes: .p2align 2 // Can read 5 bytes before possibly crossing a page. -strcpy_unalign5: +.Lstrcpy_unalign5: ldr r2, [r1], #4 sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register ldrb r4, [r1] - cbz r4, strcpy_unalign_copy5bytes + cbz r4, .Lstrcpy_unalign_copy5bytes ldr r3, [r1], #4 @@ -308,17 +313,17 @@ strcpy_unalign5: sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register stmia r0!, {r2, r3} - b strcpy_unalign5 + b .Lstrcpy_unalign5 -strcpy_unalign_copy5bytes: +.Lstrcpy_unalign_copy5bytes: stmia r0!, {r2} strb r4, [r0] m_ret inst=pop -strcpy_unalign_copy6bytes: +.Lstrcpy_unalign_copy6bytes: stmia r0!, {r2} strb r4, [r0], #1 strb r5, [r0] @@ -326,13 +331,13 @@ strcpy_unalign_copy6bytes: .p2align 2 // Can read 4 bytes before possibly crossing a page. -strcpy_unalign4: +.Lstrcpy_unalign4: ldmia r1!, {r2} sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register ldmia r1!, {r3} pld [r1, #64] @@ -340,20 +345,20 @@ strcpy_unalign4: sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register stmia r0!, {r2, r3} - b strcpy_unalign4 + b .Lstrcpy_unalign4 .p2align 2 // Can read 3 bytes before possibly crossing a page. -strcpy_unalign3: +.Lstrcpy_unalign3: ldrb r2, [r1] - cbz r2, strcpy_unalign3_copy1byte + cbz r2, .Lstrcpy_unalign3_copy1byte ldrb r3, [r1, #1] - cbz r3, strcpy_unalign3_copy2bytes + cbz r3, .Lstrcpy_unalign3_copy2bytes ldrb r4, [r1, #2] - cbz r4, strcpy_unalign3_copy3bytes + cbz r4, .Lstrcpy_unalign3_copy3bytes ldr r2, [r1], #4 ldr r3, [r1], #4 @@ -361,26 +366,26 @@ strcpy_unalign3: pld [r1, #64] lsrs lr, r2, #24 - beq strcpy_unalign_copy4bytes + beq .Lstrcpy_unalign_copy4bytes sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register stmia r0!, {r2, r3} - b strcpy_unalign3 + b .Lstrcpy_unalign3 -strcpy_unalign3_copy1byte: +.Lstrcpy_unalign3_copy1byte: strb r2, [r0] m_ret inst=pop -strcpy_unalign3_copy2bytes: +.Lstrcpy_unalign3_copy2bytes: strb r2, [r0], #1 strb r3, [r0] m_ret inst=pop -strcpy_unalign3_copy3bytes: +.Lstrcpy_unalign3_copy3bytes: strb r2, [r0], #1 strb r3, [r0], #1 strb r4, [r0] @@ -388,34 +393,34 @@ strcpy_unalign3_copy3bytes: .p2align 2 // Can read 2 bytes before possibly crossing a page. -strcpy_unalign2: +.Lstrcpy_unalign2: ldrb r2, [r1] - cbz r2, strcpy_unalign_copy1byte + cbz r2, .Lstrcpy_unalign_copy1byte ldrb r3, [r1, #1] - cbz r3, strcpy_unalign_copy2bytes + cbz r3, .Lstrcpy_unalign_copy2bytes ldr r2, [r1], #4 ldr r3, [r1], #4 pld [r1, #64] tst r2, #0xff0000 - beq strcpy_unalign_copy3bytes + beq .Lstrcpy_unalign_copy3bytes lsrs ip, r2, #24 - beq strcpy_unalign_copy4bytes + beq .Lstrcpy_unalign_copy4bytes sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register stmia r0!, {r2, r3} - b strcpy_unalign2 + b .Lstrcpy_unalign2 .p2align 2 // Can read 1 byte before possibly crossing a page. -strcpy_unalign1: +.Lstrcpy_unalign1: ldrb r2, [r1] - cbz r2, strcpy_unalign_copy1byte + cbz r2, .Lstrcpy_unalign_copy1byte ldr r2, [r1], #4 ldr r3, [r1], #4 @@ -425,32 +430,32 @@ strcpy_unalign1: sub ip, r2, #0x01010101 bic ip, ip, r2 ands ip, ip, #0x80808080 - bne strcpy_zero_in_first_register + bne .Lstrcpy_zero_in_first_register sub ip, r3, #0x01010101 bic ip, ip, r3 ands ip, ip, #0x80808080 - bne strcpy_zero_in_second_register + bne .Lstrcpy_zero_in_second_register stmia r0!, {r2, r3} - b strcpy_unalign1 + b .Lstrcpy_unalign1 -strcpy_unalign_copy1byte: +.Lstrcpy_unalign_copy1byte: strb r2, [r0] m_ret inst=pop -strcpy_unalign_copy2bytes: +.Lstrcpy_unalign_copy2bytes: strb r2, [r0], #1 strb r3, [r0] m_ret inst=pop -strcpy_unalign_copy3bytes: +.Lstrcpy_unalign_copy3bytes: strh r2, [r0], #2 lsr r2, #16 strb r2, [r0] m_ret inst=pop -strcpy_unalign_copy4bytes: +.Lstrcpy_unalign_copy4bytes: stmia r0, {r2} m_ret inst=pop END(strcpy) diff --git a/libc/arch-arm/denver/bionic/__strcat_chk.S b/libc/arch-arm/denver/bionic/__strcat_chk.S index 36da2d9d8..a2e9c229e 100644 --- a/libc/arch-arm/denver/bionic/__strcat_chk.S +++ b/libc/arch-arm/denver/bionic/__strcat_chk.S @@ -40,12 +40,10 @@ ENTRY(__strcat_chk) pld [r0, #0] push {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 push {r4, r5} - .save {r4, r5} .cfi_adjust_cfa_offset 8 .cfi_rel_offset r4, 0 .cfi_rel_offset r5, 4 @@ -195,9 +193,6 @@ END(__strcat_chk) #include "memcpy_base.S" ENTRY_PRIVATE(__strcat_chk_failed) - .save {r0, lr} - .save {r4, r5} - .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 diff --git a/libc/arch-arm/denver/bionic/__strcpy_chk.S b/libc/arch-arm/denver/bionic/__strcpy_chk.S index c3e3e14fa..db766863a 100644 --- a/libc/arch-arm/denver/bionic/__strcpy_chk.S +++ b/libc/arch-arm/denver/bionic/__strcpy_chk.S @@ -39,7 +39,6 @@ ENTRY(__strcpy_chk) pld [r0, #0] push {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 @@ -161,7 +160,6 @@ END(__strcpy_chk) #include "memcpy_base.S" ENTRY_PRIVATE(__strcpy_chk_failed) - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 diff --git a/libc/arch-arm/denver/bionic/memcpy.S b/libc/arch-arm/denver/bionic/memcpy.S index da4f3dd79..410b663e2 100644 --- a/libc/arch-arm/denver/bionic/memcpy.S +++ b/libc/arch-arm/denver/bionic/memcpy.S @@ -72,7 +72,6 @@ END(__memcpy_chk) ENTRY(memcpy) pld [r1, #64] push {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 @@ -85,7 +84,6 @@ END(memcpy) ENTRY_PRIVATE(__memcpy_chk_fail) // Preserve lr for backtrace. push {lr} - .save {lr} .cfi_def_cfa_offset 4 .cfi_rel_offset lr, 0 diff --git a/libc/arch-arm/krait/bionic/__strcat_chk.S b/libc/arch-arm/krait/bionic/__strcat_chk.S index 34becdbbf..246f159c0 100644 --- a/libc/arch-arm/krait/bionic/__strcat_chk.S +++ b/libc/arch-arm/krait/bionic/__strcat_chk.S @@ -40,12 +40,10 @@ ENTRY(__strcat_chk) pld [r0, #0] push {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 push {r4, r5} - .save {r4, r5} .cfi_adjust_cfa_offset 8 .cfi_rel_offset r4, 0 .cfi_rel_offset r5, 4 @@ -194,8 +192,6 @@ END(__strcat_chk) #include "memcpy_base.S" ENTRY_PRIVATE(__strcat_chk_failed) - .save {r0, lr} - .save {r4, r5} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 diff --git a/libc/arch-arm/krait/bionic/__strcpy_chk.S b/libc/arch-arm/krait/bionic/__strcpy_chk.S index c3e3e14fa..db766863a 100644 --- a/libc/arch-arm/krait/bionic/__strcpy_chk.S +++ b/libc/arch-arm/krait/bionic/__strcpy_chk.S @@ -39,7 +39,6 @@ ENTRY(__strcpy_chk) pld [r0, #0] push {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 @@ -161,7 +160,6 @@ END(__strcpy_chk) #include "memcpy_base.S" ENTRY_PRIVATE(__strcpy_chk_failed) - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 diff --git a/libc/arch-arm/krait/bionic/memcpy.S b/libc/arch-arm/krait/bionic/memcpy.S index 0b7b27659..9ff46a8ac 100644 --- a/libc/arch-arm/krait/bionic/memcpy.S +++ b/libc/arch-arm/krait/bionic/memcpy.S @@ -53,7 +53,6 @@ END(__memcpy_chk) ENTRY(memcpy) pld [r1, #64] stmfd sp!, {r0, lr} - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 @@ -66,7 +65,6 @@ END(memcpy) ENTRY_PRIVATE(__memcpy_chk_fail) // Preserve lr for backtrace. push {lr} - .save {lr} .cfi_def_cfa_offset 4 .cfi_rel_offset lr, 0 diff --git a/libc/arch-arm/krait/bionic/memcpy_base.S b/libc/arch-arm/krait/bionic/memcpy_base.S index 99fc255f3..035dcf126 100644 --- a/libc/arch-arm/krait/bionic/memcpy_base.S +++ b/libc/arch-arm/krait/bionic/memcpy_base.S @@ -36,7 +36,6 @@ // Assumes neon instructions and a cache line size of 32 bytes. ENTRY_PRIVATE(MEMCPY_BASE) - .save {r0, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r0, 0 .cfi_rel_offset lr, 4 diff --git a/libc/arch-arm/krait/bionic/memset.S b/libc/arch-arm/krait/bionic/memset.S index 5d1943b72..e9f643133 100644 --- a/libc/arch-arm/krait/bionic/memset.S +++ b/libc/arch-arm/krait/bionic/memset.S @@ -43,7 +43,6 @@ ENTRY(__memset_chk) bls .L_done // Preserve lr for backtrace. - .save {lr} push {lr} .cfi_def_cfa_offset 4 .cfi_rel_offset lr, 0 @@ -69,7 +68,6 @@ END(bzero) /* memset() returns its first argument. */ ENTRY(memset) - .save {r0} stmfd sp!, {r0} .cfi_def_cfa_offset 4 .cfi_rel_offset r0, 0 diff --git a/libc/arch-arm/krait/bionic/strcmp.S b/libc/arch-arm/krait/bionic/strcmp.S index eacb82a6e..9121c01de 100644 --- a/libc/arch-arm/krait/bionic/strcmp.S +++ b/libc/arch-arm/krait/bionic/strcmp.S @@ -168,7 +168,6 @@ ENTRY(strcmp) bne .L_do_align /* Fast path. */ - .save {r4-r7} init .L_doubleword_aligned: From 98d57c95bc7b0042d60b0f7f426ee40b60a67198 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 30 Sep 2014 11:53:13 -0700 Subject: [PATCH 061/114] Add stpcpy assembler version. For generic, continue to use the C version of the code. Bug: 13746695 (cherry picked from commit 7d849ac378515efa1522e538e6e1d3b546cae97d) Change-Id: Iae44785f37f9bb59103ab78fb9f74c92f8a95c7f --- libc/arch-arm/arm.mk | 1 - libc/arch-arm/cortex-a15/bionic/stpcpy.S | 30 + libc/arch-arm/cortex-a15/bionic/strcpy.S | 432 +------------- libc/arch-arm/cortex-a15/bionic/string_copy.S | 513 +++++++++++++++++ libc/arch-arm/cortex-a15/cortex-a15.mk | 5 +- libc/arch-arm/cortex-a9/bionic/stpcpy.S | 30 + libc/arch-arm/cortex-a9/bionic/strcpy.S | 437 +------------- libc/arch-arm/cortex-a9/bionic/string_copy.S | 535 ++++++++++++++++++ libc/arch-arm/cortex-a9/cortex-a9.mk | 5 +- libc/arch-arm/denver/denver.mk | 3 +- libc/arch-arm/generic/generic.mk | 1 + libc/arch-arm/krait/krait.mk | 1 + 12 files changed, 1124 insertions(+), 869 deletions(-) create mode 100644 libc/arch-arm/cortex-a15/bionic/stpcpy.S create mode 100644 libc/arch-arm/cortex-a15/bionic/string_copy.S create mode 100644 libc/arch-arm/cortex-a9/bionic/stpcpy.S create mode 100644 libc/arch-arm/cortex-a9/bionic/string_copy.S diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk index b5ed7f0e0..cca4ed020 100644 --- a/libc/arch-arm/arm.mk +++ b/libc/arch-arm/arm.mk @@ -41,7 +41,6 @@ libc_freebsd_src_files_arm += \ libc_openbsd_src_files_arm += \ upstream-openbsd/lib/libc/string/bcopy.c \ - upstream-openbsd/lib/libc/string/stpcpy.c \ upstream-openbsd/lib/libc/string/stpncpy.c \ upstream-openbsd/lib/libc/string/strlcat.c \ upstream-openbsd/lib/libc/string/strlcpy.c \ diff --git a/libc/arch-arm/cortex-a15/bionic/stpcpy.S b/libc/arch-arm/cortex-a15/bionic/stpcpy.S new file mode 100644 index 000000000..740523b5d --- /dev/null +++ b/libc/arch-arm/cortex-a15/bionic/stpcpy.S @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define STPCPY +#include "string_copy.S" diff --git a/libc/arch-arm/cortex-a15/bionic/strcpy.S b/libc/arch-arm/cortex-a15/bionic/strcpy.S index 2cfdb1931..951face01 100644 --- a/libc/arch-arm/cortex-a15/bionic/strcpy.S +++ b/libc/arch-arm/cortex-a15/bionic/strcpy.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,432 +25,6 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -/* - * Copyright (c) 2013 ARM Ltd - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the company may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include - - .syntax unified - - .thumb - .thumb_func - - .macro m_push - push {r0, r4, r5, lr} - .cfi_def_cfa_offset 16 - .cfi_rel_offset r0, 0 - .cfi_rel_offset r4, 4 - .cfi_rel_offset r5, 8 - .cfi_rel_offset lr, 12 - .endm // m_push - - .macro m_pop - pop {r0, r4, r5, pc} - .endm // m_pop - - .macro m_copy_byte reg, cmd, label - ldrb \reg, [r1], #1 - strb \reg, [r0], #1 - \cmd \reg, \label - .endm // m_copy_byte - -ENTRY(strcpy) - // For short copies, hard-code checking the first 8 bytes since this - // new code doesn't win until after about 8 bytes. - m_push - m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r5, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r5, cmd=cbnz, label=.Lstrcpy_continue - -.Lstrcpy_finish: - m_pop - -.Lstrcpy_continue: - pld [r1, #0] - ands r3, r0, #7 - beq .Lstrcpy_check_src_align - - // Align to a double word (64 bits). - rsb r3, r3, #8 - lsls ip, r3, #31 - beq .Lstrcpy_align_to_32 - - ldrb r2, [r1], #1 - strb r2, [r0], #1 - cbz r2, .Lstrcpy_complete - -.Lstrcpy_align_to_32: - bcc .Lstrcpy_align_to_64 - - ldrb r2, [r1], #1 - strb r2, [r0], #1 - cbz r2, .Lstrcpy_complete - ldrb r2, [r1], #1 - strb r2, [r0], #1 - cbz r2, .Lstrcpy_complete - -.Lstrcpy_align_to_64: - tst r3, #4 - beq .Lstrcpy_check_src_align - ldr r2, [r1], #4 - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - str r2, [r0], #4 - -.Lstrcpy_check_src_align: - // At this point dst is aligned to a double word, check if src - // is also aligned to a double word. - ands r3, r1, #7 - bne .Lstrcpy_unaligned_copy - - .p2align 2 -.Lstrcpy_mainloop: - ldrd r2, r3, [r1], #8 - - pld [r1, #64] - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - strd r2, r3, [r0], #8 - b .Lstrcpy_mainloop - -.Lstrcpy_complete: - m_pop - -.Lstrcpy_zero_in_first_register: - lsls lr, ip, #17 - bne .Lstrcpy_copy1byte - bcs .Lstrcpy_copy2bytes - lsls ip, ip, #1 - bne .Lstrcpy_copy3bytes - -.Lstrcpy_copy4bytes: - // Copy 4 bytes to the destiniation. - str r2, [r0] - m_pop - -.Lstrcpy_copy1byte: - strb r2, [r0] - m_pop - -.Lstrcpy_copy2bytes: - strh r2, [r0] - m_pop - -.Lstrcpy_copy3bytes: - strh r2, [r0], #2 - lsr r2, #16 - strb r2, [r0] - m_pop - -.Lstrcpy_zero_in_second_register: - lsls lr, ip, #17 - bne .Lstrcpy_copy5bytes - bcs .Lstrcpy_copy6bytes - lsls ip, ip, #1 - bne .Lstrcpy_copy7bytes - - // Copy 8 bytes to the destination. - strd r2, r3, [r0] - m_pop - -.Lstrcpy_copy5bytes: - str r2, [r0], #4 - strb r3, [r0] - m_pop - -.Lstrcpy_copy6bytes: - str r2, [r0], #4 - strh r3, [r0] - m_pop - -.Lstrcpy_copy7bytes: - str r2, [r0], #4 - strh r3, [r0], #2 - lsr r3, #16 - strb r3, [r0] - m_pop - -.Lstrcpy_unaligned_copy: - // Dst is aligned to a double word, while src is at an unknown alignment. - // There are 7 different versions of the unaligned copy code - // to prevent overreading the src. The mainloop of every single version - // will store 64 bits per loop. The difference is how much of src can - // be read without potentially crossing a page boundary. - tbb [pc, r3] -.Lstrcpy_unaligned_branchtable: - .byte 0 - .byte ((.Lstrcpy_unalign7 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign6 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign5 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign4 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign3 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign2 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign1 - .Lstrcpy_unaligned_branchtable)/2) - - .p2align 2 - // Can read 7 bytes before possibly crossing a page. -.Lstrcpy_unalign7: - ldr r2, [r1], #4 - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - ldrb r3, [r1] - cbz r3, .Lstrcpy_unalign7_copy5bytes - ldrb r4, [r1, #1] - cbz r4, .Lstrcpy_unalign7_copy6bytes - ldrb r5, [r1, #2] - cbz r5, .Lstrcpy_unalign7_copy7bytes - - ldr r3, [r1], #4 - pld [r1, #64] - - lsrs ip, r3, #24 - strd r2, r3, [r0], #8 - beq .Lstrcpy_unalign_return - b .Lstrcpy_unalign7 - -.Lstrcpy_unalign7_copy5bytes: - str r2, [r0], #4 - strb r3, [r0] -.Lstrcpy_unalign_return: - m_pop - -.Lstrcpy_unalign7_copy6bytes: - str r2, [r0], #4 - strb r3, [r0], #1 - strb r4, [r0], #1 - m_pop - -.Lstrcpy_unalign7_copy7bytes: - str r2, [r0], #4 - strb r3, [r0], #1 - strb r4, [r0], #1 - strb r5, [r0], #1 - m_pop - - .p2align 2 - // Can read 6 bytes before possibly crossing a page. -.Lstrcpy_unalign6: - ldr r2, [r1], #4 - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - ldrb r4, [r1] - cbz r4, .Lstrcpy_unalign_copy5bytes - ldrb r5, [r1, #1] - cbz r5, .Lstrcpy_unalign_copy6bytes - - ldr r3, [r1], #4 - pld [r1, #64] - - tst r3, #0xff0000 - beq .Lstrcpy_copy7bytes - lsrs ip, r3, #24 - strd r2, r3, [r0], #8 - beq .Lstrcpy_unalign_return - b .Lstrcpy_unalign6 - - .p2align 2 - // Can read 5 bytes before possibly crossing a page. -.Lstrcpy_unalign5: - ldr r2, [r1], #4 - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - ldrb r4, [r1] - cbz r4, .Lstrcpy_unalign_copy5bytes - - ldr r3, [r1], #4 - - pld [r1, #64] - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - strd r2, r3, [r0], #8 - b .Lstrcpy_unalign5 - -.Lstrcpy_unalign_copy5bytes: - str r2, [r0], #4 - strb r4, [r0] - m_pop - -.Lstrcpy_unalign_copy6bytes: - str r2, [r0], #4 - strb r4, [r0], #1 - strb r5, [r0] - m_pop - - .p2align 2 - // Can read 4 bytes before possibly crossing a page. -.Lstrcpy_unalign4: - ldr r2, [r1], #4 - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - ldr r3, [r1], #4 - pld [r1, #64] - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - strd r2, r3, [r0], #8 - b .Lstrcpy_unalign4 - - .p2align 2 - // Can read 3 bytes before possibly crossing a page. -.Lstrcpy_unalign3: - ldrb r2, [r1] - cbz r2, .Lstrcpy_unalign3_copy1byte - ldrb r3, [r1, #1] - cbz r3, .Lstrcpy_unalign3_copy2bytes - ldrb r4, [r1, #2] - cbz r4, .Lstrcpy_unalign3_copy3bytes - - ldr r2, [r1], #4 - ldr r3, [r1], #4 - - pld [r1, #64] - - lsrs lr, r2, #24 - beq .Lstrcpy_copy4bytes - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - strd r2, r3, [r0], #8 - b .Lstrcpy_unalign3 - -.Lstrcpy_unalign3_copy1byte: - strb r2, [r0] - m_pop - -.Lstrcpy_unalign3_copy2bytes: - strb r2, [r0], #1 - strb r3, [r0] - m_pop - -.Lstrcpy_unalign3_copy3bytes: - strb r2, [r0], #1 - strb r3, [r0], #1 - strb r4, [r0] - m_pop - - .p2align 2 - // Can read 2 bytes before possibly crossing a page. -.Lstrcpy_unalign2: - ldrb r2, [r1] - cbz r2, .Lstrcpy_unalign_copy1byte - ldrb r4, [r1, #1] - cbz r4, .Lstrcpy_unalign_copy2bytes - - ldr r2, [r1], #4 - ldr r3, [r1], #4 - pld [r1, #64] - - tst r2, #0xff0000 - beq .Lstrcpy_copy3bytes - lsrs ip, r2, #24 - beq .Lstrcpy_copy4bytes - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - strd r2, r3, [r0], #8 - b .Lstrcpy_unalign2 - - .p2align 2 - // Can read 1 byte before possibly crossing a page. -.Lstrcpy_unalign1: - ldrb r2, [r1] - cbz r2, .Lstrcpy_unalign_copy1byte - - ldr r2, [r1], #4 - ldr r3, [r1], #4 - - pld [r1, #64] - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - strd r2, r3, [r0], #8 - b .Lstrcpy_unalign1 - -.Lstrcpy_unalign_copy1byte: - strb r2, [r0] - m_pop - -.Lstrcpy_unalign_copy2bytes: - strb r2, [r0], #1 - strb r4, [r0] - m_pop -END(strcpy) +#define STRCPY +#include "string_copy.S" diff --git a/libc/arch-arm/cortex-a15/bionic/string_copy.S b/libc/arch-arm/cortex-a15/bionic/string_copy.S new file mode 100644 index 000000000..20f0e91b0 --- /dev/null +++ b/libc/arch-arm/cortex-a15/bionic/string_copy.S @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright (c) 2013 ARM Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !defined(STPCPY) && !defined(STRCPY) +#error "Either STPCPY or STRCPY must be defined." +#endif + +#include + + .syntax unified + + .thumb + .thumb_func + +#if defined(STPCPY) + .macro m_push + push {r4, r5, lr} + .cfi_def_cfa_offset 12 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + .cfi_rel_offset lr, 8 + .endm // m_push +#else + .macro m_push + push {r0, r4, r5, lr} + .cfi_def_cfa_offset 16 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r4, 4 + .cfi_rel_offset r5, 8 + .cfi_rel_offset lr, 12 + .endm // m_push +#endif + +#if defined(STPCPY) + .macro m_pop + pop {r4, r5, pc} + .endm // m_pop +#else + .macro m_pop + pop {r0, r4, r5, pc} + .endm // m_pop +#endif + + .macro m_copy_byte reg, cmd, label + ldrb \reg, [r1], #1 + strb \reg, [r0], #1 + \cmd \reg, \label + .endm // m_copy_byte + +#if defined(STPCPY) +ENTRY(stpcpy) +#else +ENTRY(strcpy) +#endif + // For short copies, hard-code checking the first 8 bytes since this + // new code doesn't win until after about 8 bytes. + m_push + m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r5, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r5, cmd=cbnz, label=.Lstringcopy_continue + +.Lstringcopy_finish: +#if defined(STPCPY) + sub r0, r0, #1 +#endif + m_pop + +.Lstringcopy_continue: + pld [r1, #0] + ands r3, r0, #7 + beq .Lstringcopy_check_src_align + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .Lstringcopy_align_to_32 + + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + +.Lstringcopy_align_to_32: + bcc .Lstringcopy_align_to_64 + + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + +.Lstringcopy_align_to_64: + tst r3, #4 + beq .Lstringcopy_check_src_align + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + str r2, [r0], #4 + +.Lstringcopy_check_src_align: + // At this point dst is aligned to a double word, check if src + // is also aligned to a double word. + ands r3, r1, #7 + bne .Lstringcopy_unaligned_copy + + .p2align 2 +.Lstringcopy_mainloop: + ldrd r2, r3, [r1], #8 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_mainloop + +.Lstringcopy_complete: +#if defined(STPCPY) + sub r0, r0, #1 +#endif + m_pop + +.Lstringcopy_zero_in_first_register: + lsls lr, ip, #17 + bne .Lstringcopy_copy1byte + bcs .Lstringcopy_copy2bytes + lsls ip, ip, #1 + bne .Lstringcopy_copy3bytes + +.Lstringcopy_copy4bytes: + // Copy 4 bytes to the destiniation. +#if defined(STPCPY) + str r2, [r0], #3 +#else + str r2, [r0] +#endif + m_pop + +.Lstringcopy_copy1byte: + strb r2, [r0] + m_pop + +.Lstringcopy_copy2bytes: +#if defined(STPCPY) + strh r2, [r0], #1 +#else + strh r2, [r0] +#endif + m_pop + +.Lstringcopy_copy3bytes: + strh r2, [r0], #2 + lsr r2, #16 + strb r2, [r0] + m_pop + +.Lstringcopy_zero_in_second_register: + lsls lr, ip, #17 + bne .Lstringcopy_copy5bytes + bcs .Lstringcopy_copy6bytes + lsls ip, ip, #1 + bne .Lstringcopy_copy7bytes + + // Copy 8 bytes to the destination. + strd r2, r3, [r0] +#if defined(STPCPY) + add r0, r0, #7 +#endif + m_pop + +.Lstringcopy_copy5bytes: + str r2, [r0], #4 + strb r3, [r0] + m_pop + +.Lstringcopy_copy6bytes: + str r2, [r0], #4 +#if defined(STPCPY) + strh r3, [r0], #1 +#else + strh r3, [r0] +#endif + m_pop + +.Lstringcopy_copy7bytes: + str r2, [r0], #4 + strh r3, [r0], #2 + lsr r3, #16 + strb r3, [r0] + m_pop + +.Lstringcopy_unaligned_copy: + // Dst is aligned to a double word, while src is at an unknown alignment. + // There are 7 different versions of the unaligned copy code + // to prevent overreading the src. The mainloop of every single version + // will store 64 bits per loop. The difference is how much of src can + // be read without potentially crossing a page boundary. + tbb [pc, r3] +.Lstringcopy_unaligned_branchtable: + .byte 0 + .byte ((.Lstringcopy_unalign7 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign6 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign5 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign4 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign3 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign2 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign1 - .Lstringcopy_unaligned_branchtable)/2) + + .p2align 2 + // Can read 7 bytes before possibly crossing a page. +.Lstringcopy_unalign7: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r3, [r1] + cbz r3, .Lstringcopy_unalign7_copy5bytes + ldrb r4, [r1, #1] + cbz r4, .Lstringcopy_unalign7_copy6bytes + ldrb r5, [r1, #2] + cbz r5, .Lstringcopy_unalign7_copy7bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + lsrs ip, r3, #24 + strd r2, r3, [r0], #8 +#if defined(STPCPY) + beq .Lstringcopy_finish +#else + beq .Lstringcopy_unalign_return +#endif + b .Lstringcopy_unalign7 + +.Lstringcopy_unalign7_copy5bytes: + str r2, [r0], #4 + strb r3, [r0] +.Lstringcopy_unalign_return: + m_pop + +.Lstringcopy_unalign7_copy6bytes: + str r2, [r0], #4 + strb r3, [r0], #1 + strb r4, [r0] + m_pop + +.Lstringcopy_unalign7_copy7bytes: + str r2, [r0], #4 + strb r3, [r0], #1 + strb r4, [r0], #1 + strb r5, [r0] + m_pop + + .p2align 2 + // Can read 6 bytes before possibly crossing a page. +.Lstringcopy_unalign6: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .Lstringcopy_unalign_copy5bytes + ldrb r5, [r1, #1] + cbz r5, .Lstringcopy_unalign_copy6bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + tst r3, #0xff0000 + beq .Lstringcopy_copy7bytes + lsrs ip, r3, #24 + strd r2, r3, [r0], #8 +#if defined(STPCPY) + beq .Lstringcopy_finish +#else + beq .Lstringcopy_unalign_return +#endif + b .Lstringcopy_unalign6 + + .p2align 2 + // Can read 5 bytes before possibly crossing a page. +.Lstringcopy_unalign5: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .Lstringcopy_unalign_copy5bytes + + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_unalign5 + +.Lstringcopy_unalign_copy5bytes: + str r2, [r0], #4 + strb r4, [r0] + m_pop + +.Lstringcopy_unalign_copy6bytes: + str r2, [r0], #4 + strb r4, [r0], #1 + strb r5, [r0] + m_pop + + .p2align 2 + // Can read 4 bytes before possibly crossing a page. +.Lstringcopy_unalign4: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldr r3, [r1], #4 + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_unalign4 + + .p2align 2 + // Can read 3 bytes before possibly crossing a page. +.Lstringcopy_unalign3: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign3_copy1byte + ldrb r3, [r1, #1] + cbz r3, .Lstringcopy_unalign3_copy2bytes + ldrb r4, [r1, #2] + cbz r4, .Lstringcopy_unalign3_copy3bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + lsrs lr, r2, #24 + beq .Lstringcopy_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_unalign3 + +.Lstringcopy_unalign3_copy1byte: + strb r2, [r0] + m_pop + +.Lstringcopy_unalign3_copy2bytes: + strb r2, [r0], #1 + strb r3, [r0] + m_pop + +.Lstringcopy_unalign3_copy3bytes: + strb r2, [r0], #1 + strb r3, [r0], #1 + strb r4, [r0] + m_pop + + .p2align 2 + // Can read 2 bytes before possibly crossing a page. +.Lstringcopy_unalign2: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign_copy1byte + ldrb r4, [r1, #1] + cbz r4, .Lstringcopy_unalign_copy2bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + pld [r1, #64] + + tst r2, #0xff0000 + beq .Lstringcopy_copy3bytes + lsrs ip, r2, #24 + beq .Lstringcopy_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_unalign2 + + .p2align 2 + // Can read 1 byte before possibly crossing a page. +.Lstringcopy_unalign1: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign_copy1byte + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_unalign1 + +.Lstringcopy_unalign_copy1byte: + strb r2, [r0] + m_pop + +.Lstringcopy_unalign_copy2bytes: + strb r2, [r0], #1 + strb r4, [r0] + m_pop +#if defined(STPCPY) +END(stpcpy) +#else +END(strcpy) +#endif diff --git a/libc/arch-arm/cortex-a15/cortex-a15.mk b/libc/arch-arm/cortex-a15/cortex-a15.mk index 552811ebc..f1abe3231 100644 --- a/libc/arch-arm/cortex-a15/cortex-a15.mk +++ b/libc/arch-arm/cortex-a15/cortex-a15.mk @@ -1,10 +1,11 @@ libc_bionic_src_files_arm += \ arch-arm/cortex-a15/bionic/memcpy.S \ arch-arm/cortex-a15/bionic/memset.S \ + arch-arm/cortex-a15/bionic/stpcpy.S \ arch-arm/cortex-a15/bionic/strcat.S \ + arch-arm/cortex-a15/bionic/__strcat_chk.S \ arch-arm/cortex-a15/bionic/strcmp.S \ arch-arm/cortex-a15/bionic/strcpy.S \ - arch-arm/cortex-a15/bionic/strlen.S \ - arch-arm/cortex-a15/bionic/__strcat_chk.S \ arch-arm/cortex-a15/bionic/__strcpy_chk.S \ + arch-arm/cortex-a15/bionic/strlen.S \ bionic/memmove.c \ diff --git a/libc/arch-arm/cortex-a9/bionic/stpcpy.S b/libc/arch-arm/cortex-a9/bionic/stpcpy.S new file mode 100644 index 000000000..740523b5d --- /dev/null +++ b/libc/arch-arm/cortex-a9/bionic/stpcpy.S @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define STPCPY +#include "string_copy.S" diff --git a/libc/arch-arm/cortex-a9/bionic/strcpy.S b/libc/arch-arm/cortex-a9/bionic/strcpy.S index d705aa354..951face01 100644 --- a/libc/arch-arm/cortex-a9/bionic/strcpy.S +++ b/libc/arch-arm/cortex-a9/bionic/strcpy.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,437 +25,6 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -/* - * Copyright (c) 2013 ARM Ltd - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the company may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include - - .syntax unified - - .thumb - .thumb_func - - .macro m_push - push {r0, r4, r5, lr} - .cfi_def_cfa_offset 16 - .cfi_rel_offset r0, 0 - .cfi_rel_offset r4, 4 - .cfi_rel_offset r5, 8 - .cfi_rel_offset lr, 12 - .endm // m_push - - .macro m_ret inst - \inst {r0, r4, r5, pc} - .endm // m_ret - - .macro m_copy_byte reg, cmd, label - ldrb \reg, [r1], #1 - strb \reg, [r0], #1 - \cmd \reg, \label - .endm // m_copy_byte - -ENTRY(strcpy) - // Unroll the first 8 bytes that will be copied. - m_push - m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r5, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish - m_copy_byte reg=r5, cmd=cbnz, label=.Lstrcpy_continue - -.Lstrcpy_finish: - m_ret inst=pop - -.Lstrcpy_continue: - pld [r1, #0] - ands r3, r0, #7 - bne .Lstrcpy_align_dst - -.Lstrcpy_check_src_align: - // At this point dst is aligned to a double word, check if src - // is also aligned to a double word. - ands r3, r1, #7 - bne .Lstrcpy_unaligned_copy - - .p2align 2 -.Lstrcpy_mainloop: - ldmia r1!, {r2, r3} - - pld [r1, #64] - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - stmia r0!, {r2, r3} - b .Lstrcpy_mainloop - -.Lstrcpy_zero_in_first_register: - lsls lr, ip, #17 - itt ne - strbne r2, [r0] - m_ret inst=popne - itt cs - strhcs r2, [r0] - m_ret inst=popcs - lsls ip, ip, #1 - itt eq - streq r2, [r0] - m_ret inst=popeq - strh r2, [r0], #2 - lsr r3, r2, #16 - strb r3, [r0] - m_ret inst=pop - -.Lstrcpy_zero_in_second_register: - lsls lr, ip, #17 - ittt ne - stmiane r0!, {r2} - strbne r3, [r0] - m_ret inst=popne - ittt cs - strcs r2, [r0], #4 - strhcs r3, [r0] - m_ret inst=popcs - lsls ip, ip, #1 - itt eq - stmiaeq r0, {r2, r3} - m_ret inst=popeq - stmia r0!, {r2} - strh r3, [r0], #2 - lsr r4, r3, #16 - strb r4, [r0] - m_ret inst=pop - -.Lstrcpy_align_dst: - // Align to a double word (64 bits). - rsb r3, r3, #8 - lsls ip, r3, #31 - beq .Lstrcpy_align_to_32 - - ldrb r2, [r1], #1 - strb r2, [r0], #1 - cbz r2, .Lstrcpy_complete - -.Lstrcpy_align_to_32: - bcc .Lstrcpy_align_to_64 - - ldrb r4, [r1], #1 - strb r4, [r0], #1 - cmp r4, #0 - it eq - m_ret inst=popeq - ldrb r5, [r1], #1 - strb r5, [r0], #1 - cmp r5, #0 - it eq - m_ret inst=popeq - -.Lstrcpy_align_to_64: - tst r3, #4 - beq .Lstrcpy_check_src_align - ldr r2, [r1], #4 - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - stmia r0!, {r2} - b .Lstrcpy_check_src_align - -.Lstrcpy_complete: - m_ret inst=pop - -.Lstrcpy_unaligned_copy: - // Dst is aligned to a double word, while src is at an unknown alignment. - // There are 7 different versions of the unaligned copy code - // to prevent overreading the src. The mainloop of every single version - // will store 64 bits per loop. The difference is how much of src can - // be read without potentially crossing a page boundary. - tbb [pc, r3] -.Lstrcpy_unaligned_branchtable: - .byte 0 - .byte ((.Lstrcpy_unalign7 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign6 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign5 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign4 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign3 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign2 - .Lstrcpy_unaligned_branchtable)/2) - .byte ((.Lstrcpy_unalign1 - .Lstrcpy_unaligned_branchtable)/2) - - .p2align 2 - // Can read 7 bytes before possibly crossing a page. -.Lstrcpy_unalign7: - ldr r2, [r1], #4 - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - ldrb r3, [r1] - cbz r3, .Lstrcpy_unalign7_copy5bytes - ldrb r4, [r1, #1] - cbz r4, .Lstrcpy_unalign7_copy6bytes - ldrb r5, [r1, #2] - cbz r5, .Lstrcpy_unalign7_copy7bytes - - ldr r3, [r1], #4 - pld [r1, #64] - - lsrs ip, r3, #24 - stmia r0!, {r2, r3} - beq .Lstrcpy_unalign_return - b .Lstrcpy_unalign7 - -.Lstrcpy_unalign7_copy5bytes: - stmia r0!, {r2} - strb r3, [r0] -.Lstrcpy_unalign_return: - m_ret inst=pop - -.Lstrcpy_unalign7_copy6bytes: - stmia r0!, {r2} - strb r3, [r0], #1 - strb r4, [r0], #1 - m_ret inst=pop - -.Lstrcpy_unalign7_copy7bytes: - stmia r0!, {r2} - strb r3, [r0], #1 - strb r4, [r0], #1 - strb r5, [r0], #1 - m_ret inst=pop - - .p2align 2 - // Can read 6 bytes before possibly crossing a page. -.Lstrcpy_unalign6: - ldr r2, [r1], #4 - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - ldrb r4, [r1] - cbz r4, .Lstrcpy_unalign_copy5bytes - ldrb r5, [r1, #1] - cbz r5, .Lstrcpy_unalign_copy6bytes - - ldr r3, [r1], #4 - pld [r1, #64] - - tst r3, #0xff0000 - beq .Lstrcpy_unalign6_copy7bytes - lsrs ip, r3, #24 - stmia r0!, {r2, r3} - beq .Lstrcpy_unalign_return - b .Lstrcpy_unalign6 - -.Lstrcpy_unalign6_copy7bytes: - stmia r0!, {r2} - strh r3, [r0], #2 - lsr r3, #16 - strb r3, [r0] - m_ret inst=pop - - .p2align 2 - // Can read 5 bytes before possibly crossing a page. -.Lstrcpy_unalign5: - ldr r2, [r1], #4 - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - ldrb r4, [r1] - cbz r4, .Lstrcpy_unalign_copy5bytes - - ldr r3, [r1], #4 - - pld [r1, #64] - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - stmia r0!, {r2, r3} - b .Lstrcpy_unalign5 - -.Lstrcpy_unalign_copy5bytes: - stmia r0!, {r2} - strb r4, [r0] - m_ret inst=pop - -.Lstrcpy_unalign_copy6bytes: - stmia r0!, {r2} - strb r4, [r0], #1 - strb r5, [r0] - m_ret inst=pop - - .p2align 2 - // Can read 4 bytes before possibly crossing a page. -.Lstrcpy_unalign4: - ldmia r1!, {r2} - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - ldmia r1!, {r3} - pld [r1, #64] - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - stmia r0!, {r2, r3} - b .Lstrcpy_unalign4 - - .p2align 2 - // Can read 3 bytes before possibly crossing a page. -.Lstrcpy_unalign3: - ldrb r2, [r1] - cbz r2, .Lstrcpy_unalign3_copy1byte - ldrb r3, [r1, #1] - cbz r3, .Lstrcpy_unalign3_copy2bytes - ldrb r4, [r1, #2] - cbz r4, .Lstrcpy_unalign3_copy3bytes - - ldr r2, [r1], #4 - ldr r3, [r1], #4 - - pld [r1, #64] - - lsrs lr, r2, #24 - beq .Lstrcpy_unalign_copy4bytes - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - stmia r0!, {r2, r3} - b .Lstrcpy_unalign3 - -.Lstrcpy_unalign3_copy1byte: - strb r2, [r0] - m_ret inst=pop - -.Lstrcpy_unalign3_copy2bytes: - strb r2, [r0], #1 - strb r3, [r0] - m_ret inst=pop - -.Lstrcpy_unalign3_copy3bytes: - strb r2, [r0], #1 - strb r3, [r0], #1 - strb r4, [r0] - m_ret inst=pop - - .p2align 2 - // Can read 2 bytes before possibly crossing a page. -.Lstrcpy_unalign2: - ldrb r2, [r1] - cbz r2, .Lstrcpy_unalign_copy1byte - ldrb r3, [r1, #1] - cbz r3, .Lstrcpy_unalign_copy2bytes - - ldr r2, [r1], #4 - ldr r3, [r1], #4 - pld [r1, #64] - - tst r2, #0xff0000 - beq .Lstrcpy_unalign_copy3bytes - lsrs ip, r2, #24 - beq .Lstrcpy_unalign_copy4bytes - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - stmia r0!, {r2, r3} - b .Lstrcpy_unalign2 - - .p2align 2 - // Can read 1 byte before possibly crossing a page. -.Lstrcpy_unalign1: - ldrb r2, [r1] - cbz r2, .Lstrcpy_unalign_copy1byte - - ldr r2, [r1], #4 - ldr r3, [r1], #4 - - pld [r1, #64] - - sub ip, r2, #0x01010101 - bic ip, ip, r2 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_first_register - - sub ip, r3, #0x01010101 - bic ip, ip, r3 - ands ip, ip, #0x80808080 - bne .Lstrcpy_zero_in_second_register - - stmia r0!, {r2, r3} - b .Lstrcpy_unalign1 - -.Lstrcpy_unalign_copy1byte: - strb r2, [r0] - m_ret inst=pop - -.Lstrcpy_unalign_copy2bytes: - strb r2, [r0], #1 - strb r3, [r0] - m_ret inst=pop - -.Lstrcpy_unalign_copy3bytes: - strh r2, [r0], #2 - lsr r2, #16 - strb r2, [r0] - m_ret inst=pop - -.Lstrcpy_unalign_copy4bytes: - stmia r0, {r2} - m_ret inst=pop -END(strcpy) +#define STRCPY +#include "string_copy.S" diff --git a/libc/arch-arm/cortex-a9/bionic/string_copy.S b/libc/arch-arm/cortex-a9/bionic/string_copy.S new file mode 100644 index 000000000..caf5a11fe --- /dev/null +++ b/libc/arch-arm/cortex-a9/bionic/string_copy.S @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright (c) 2013 ARM Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !defined(STPCPY) && !defined(STRCPY) +#error "Either STPCPY or STRCPY must be defined." +#endif + +#include + + .syntax unified + + .thumb + .thumb_func + +#if defined(STPCPY) + .macro m_push + push {r4, r5, lr} + .cfi_def_cfa_offset 12 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + .cfi_rel_offset lr, 8 + .endm // m_push +#else + .macro m_push + push {r0, r4, r5, lr} + .cfi_def_cfa_offset 16 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r4, 4 + .cfi_rel_offset r5, 8 + .cfi_rel_offset lr, 12 + .endm // m_push +#endif + +#if defined(STPCPY) + .macro m_ret inst + \inst {r4, r5, pc} + .endm // m_ret +#else + .macro m_ret inst + \inst {r0, r4, r5, pc} + .endm // m_ret +#endif + + .macro m_copy_byte reg, cmd, label + ldrb \reg, [r1], #1 + strb \reg, [r0], #1 + \cmd \reg, \label + .endm // m_copy_byte + +#if defined(STPCPY) +ENTRY(stpcpy) +#else +ENTRY(strcpy) +#endif + // Unroll the first 8 bytes that will be copied. + m_push + m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r5, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r5, cmd=cbnz, label=.Lstringcopy_continue + +.Lstringcopy_finish: +#if defined(STPCPY) + sub r0, r0, #1 +#endif + m_ret inst=pop + +.Lstringcopy_continue: + pld [r1, #0] + ands r3, r0, #7 + bne .Lstringcopy_align_dst + +.Lstringcopy_check_src_align: + // At this point dst is aligned to a double word, check if src + // is also aligned to a double word. + ands r3, r1, #7 + bne .Lstringcopy_unaligned_copy + + .p2align 2 +.Lstringcopy_mainloop: + ldmia r1!, {r2, r3} + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_mainloop + +.Lstringcopy_zero_in_first_register: + lsls lr, ip, #17 + itt ne + strbne r2, [r0] + m_ret inst=popne + itt cs +#if defined(STPCPY) + strhcs r2, [r0], #1 +#else + strhcs r2, [r0] +#endif + m_ret inst=popcs + lsls ip, ip, #1 + itt eq +#if defined(STPCPY) + streq r2, [r0], #3 +#else + streq r2, [r0] +#endif + m_ret inst=popeq + strh r2, [r0], #2 + lsr r3, r2, #16 + strb r3, [r0] + m_ret inst=pop + +.Lstringcopy_zero_in_second_register: + lsls lr, ip, #17 + ittt ne + stmiane r0!, {r2} + strbne r3, [r0] + m_ret inst=popne + ittt cs + strcs r2, [r0], #4 +#if defined(STPCPY) + strhcs r3, [r0], #1 +#else + strhcs r3, [r0] +#endif + m_ret inst=popcs + lsls ip, ip, #1 +#if defined(STPCPY) + ittt eq +#else + itt eq +#endif + stmiaeq r0, {r2, r3} +#if defined(STPCPY) + addeq r0, r0, #7 +#endif + m_ret inst=popeq + stmia r0!, {r2} + strh r3, [r0], #2 + lsr r4, r3, #16 + strb r4, [r0] + m_ret inst=pop + +.Lstringcopy_align_dst: + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .Lstringcopy_align_to_32 + + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + +.Lstringcopy_align_to_32: + bcc .Lstringcopy_align_to_64 + + ldrb r4, [r1], #1 + strb r4, [r0], #1 + cmp r4, #0 +#if defined(STPCPY) + itt eq + subeq r0, r0, #1 +#else + it eq +#endif + m_ret inst=popeq + ldrb r5, [r1], #1 + strb r5, [r0], #1 + cmp r5, #0 +#if defined(STPCPY) + itt eq + subeq r0, r0, #1 +#else + it eq +#endif + m_ret inst=popeq + +.Lstringcopy_align_to_64: + tst r3, #4 + beq .Lstringcopy_check_src_align + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + stmia r0!, {r2} + b .Lstringcopy_check_src_align + +.Lstringcopy_complete: +#if defined(STPCPY) + sub r0, r0, #1 +#endif + m_ret inst=pop + +.Lstringcopy_unaligned_copy: + // Dst is aligned to a double word, while src is at an unknown alignment. + // There are 7 different versions of the unaligned copy code + // to prevent overreading the src. The mainloop of every single version + // will store 64 bits per loop. The difference is how much of src can + // be read without potentially crossing a page boundary. + tbb [pc, r3] +.Lstringcopy_unaligned_branchtable: + .byte 0 + .byte ((.Lstringcopy_unalign7 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign6 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign5 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign4 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign3 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign2 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign1 - .Lstringcopy_unaligned_branchtable)/2) + + .p2align 2 + // Can read 7 bytes before possibly crossing a page. +.Lstringcopy_unalign7: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r3, [r1] + cbz r3, .Lstringcopy_unalign7_copy5bytes + ldrb r4, [r1, #1] + cbz r4, .Lstringcopy_unalign7_copy6bytes + ldrb r5, [r1, #2] + cbz r5, .Lstringcopy_unalign7_copy7bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + lsrs ip, r3, #24 + stmia r0!, {r2, r3} +#if defined(STPCPY) + beq .Lstringcopy_finish +#else + beq .Lstringcopy_unalign_return +#endif + b .Lstringcopy_unalign7 + +.Lstringcopy_unalign7_copy5bytes: + stmia r0!, {r2} + strb r3, [r0] +.Lstringcopy_unalign_return: + m_ret inst=pop + +.Lstringcopy_unalign7_copy6bytes: + stmia r0!, {r2} + strb r3, [r0], #1 + strb r4, [r0] + m_ret inst=pop + +.Lstringcopy_unalign7_copy7bytes: + stmia r0!, {r2} + strb r3, [r0], #1 + strb r4, [r0], #1 + strb r5, [r0] + m_ret inst=pop + + .p2align 2 + // Can read 6 bytes before possibly crossing a page. +.Lstringcopy_unalign6: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .Lstringcopy_unalign_copy5bytes + ldrb r5, [r1, #1] + cbz r5, .Lstringcopy_unalign_copy6bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + tst r3, #0xff0000 + beq .Lstringcopy_unalign6_copy7bytes + lsrs ip, r3, #24 + stmia r0!, {r2, r3} +#if defined(STPCPY) + beq .Lstringcopy_finish +#else + beq .Lstringcopy_unalign_return +#endif + b .Lstringcopy_unalign6 + +.Lstringcopy_unalign6_copy7bytes: + stmia r0!, {r2} + strh r3, [r0], #2 + lsr r3, #16 + strb r3, [r0] + m_ret inst=pop + + .p2align 2 + // Can read 5 bytes before possibly crossing a page. +.Lstringcopy_unalign5: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .Lstringcopy_unalign_copy5bytes + + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_unalign5 + +.Lstringcopy_unalign_copy5bytes: + stmia r0!, {r2} + strb r4, [r0] + m_ret inst=pop + +.Lstringcopy_unalign_copy6bytes: + stmia r0!, {r2} + strb r4, [r0], #1 + strb r5, [r0] + m_ret inst=pop + + .p2align 2 + // Can read 4 bytes before possibly crossing a page. +.Lstringcopy_unalign4: + ldmia r1!, {r2} + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldmia r1!, {r3} + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_unalign4 + + .p2align 2 + // Can read 3 bytes before possibly crossing a page. +.Lstringcopy_unalign3: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign3_copy1byte + ldrb r3, [r1, #1] + cbz r3, .Lstringcopy_unalign3_copy2bytes + ldrb r4, [r1, #2] + cbz r4, .Lstringcopy_unalign3_copy3bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + lsrs lr, r2, #24 + beq .Lstringcopy_unalign_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_unalign3 + +.Lstringcopy_unalign3_copy1byte: + strb r2, [r0] + m_ret inst=pop + +.Lstringcopy_unalign3_copy2bytes: + strb r2, [r0], #1 + strb r3, [r0] + m_ret inst=pop + +.Lstringcopy_unalign3_copy3bytes: + strb r2, [r0], #1 + strb r3, [r0], #1 + strb r4, [r0] + m_ret inst=pop + + .p2align 2 + // Can read 2 bytes before possibly crossing a page. +.Lstringcopy_unalign2: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign_copy1byte + ldrb r3, [r1, #1] + cbz r3, .Lstringcopy_unalign_copy2bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + pld [r1, #64] + + tst r2, #0xff0000 + beq .Lstringcopy_unalign_copy3bytes + lsrs ip, r2, #24 + beq .Lstringcopy_unalign_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_unalign2 + + .p2align 2 + // Can read 1 byte before possibly crossing a page. +.Lstringcopy_unalign1: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign_copy1byte + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_unalign1 + +.Lstringcopy_unalign_copy1byte: + strb r2, [r0] + m_ret inst=pop + +.Lstringcopy_unalign_copy2bytes: + strb r2, [r0], #1 + strb r3, [r0] + m_ret inst=pop + +.Lstringcopy_unalign_copy3bytes: + strh r2, [r0], #2 + lsr r2, #16 + strb r2, [r0] + m_ret inst=pop + +.Lstringcopy_unalign_copy4bytes: + stmia r0, {r2} +#if defined(STPCPY) + add r0, r0, #3 +#endif + m_ret inst=pop +#if defined(STPCPY) +END(stpcpy) +#else +END(strcpy) +#endif diff --git a/libc/arch-arm/cortex-a9/cortex-a9.mk b/libc/arch-arm/cortex-a9/cortex-a9.mk index 9b99387b1..c82db3b4d 100644 --- a/libc/arch-arm/cortex-a9/cortex-a9.mk +++ b/libc/arch-arm/cortex-a9/cortex-a9.mk @@ -1,10 +1,11 @@ libc_bionic_src_files_arm += \ arch-arm/cortex-a9/bionic/memcpy.S \ arch-arm/cortex-a9/bionic/memset.S \ + arch-arm/cortex-a9/bionic/stpcpy.S \ arch-arm/cortex-a9/bionic/strcat.S \ + arch-arm/cortex-a9/bionic/__strcat_chk.S \ arch-arm/cortex-a9/bionic/strcmp.S \ arch-arm/cortex-a9/bionic/strcpy.S \ - arch-arm/cortex-a9/bionic/strlen.S \ - arch-arm/cortex-a9/bionic/__strcat_chk.S \ arch-arm/cortex-a9/bionic/__strcpy_chk.S \ + arch-arm/cortex-a9/bionic/strlen.S \ bionic/memmove.c \ diff --git a/libc/arch-arm/denver/denver.mk b/libc/arch-arm/denver/denver.mk index 6989187bf..0bc52a27b 100644 --- a/libc/arch-arm/denver/denver.mk +++ b/libc/arch-arm/denver/denver.mk @@ -7,7 +7,8 @@ libc_bionic_src_files_arm += \ # Use cortex-a15 versions of strcat/strcpy/strlen. libc_bionic_src_files_arm += \ + arch-arm/cortex-a15/bionic/stpcpy.S \ arch-arm/cortex-a15/bionic/strcat.S \ + arch-arm/cortex-a15/bionic/strcmp.S \ arch-arm/cortex-a15/bionic/strcpy.S \ arch-arm/cortex-a15/bionic/strlen.S \ - arch-arm/cortex-a15/bionic/strcmp.S \ diff --git a/libc/arch-arm/generic/generic.mk b/libc/arch-arm/generic/generic.mk index 2456e6e4c..95be867cd 100644 --- a/libc/arch-arm/generic/generic.mk +++ b/libc/arch-arm/generic/generic.mk @@ -7,4 +7,5 @@ libc_bionic_src_files_arm += \ bionic/memmove.c \ bionic/__strcat_chk.cpp \ bionic/__strcpy_chk.cpp \ + upstream-openbsd/lib/libc/string/stpcpy.c \ upstream-openbsd/lib/libc/string/strcat.c \ diff --git a/libc/arch-arm/krait/krait.mk b/libc/arch-arm/krait/krait.mk index 631ab6879..1bb7b0a07 100644 --- a/libc/arch-arm/krait/krait.mk +++ b/libc/arch-arm/krait/krait.mk @@ -7,6 +7,7 @@ libc_bionic_src_files_arm += \ # Use cortex-a15 versions of strcat/strcpy/strlen and standard memmove libc_bionic_src_files_arm += \ + arch-arm/cortex-a15/bionic/stpcpy.S \ arch-arm/cortex-a15/bionic/strcat.S \ arch-arm/cortex-a15/bionic/strcpy.S \ arch-arm/cortex-a15/bionic/strlen.S \ From eedbf70e8eae18ab28a36017632b80e23c398e53 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 19 Aug 2014 12:43:50 -0700 Subject: [PATCH 062/114] Add in_port_t and move it and in_addr_t to the correct header file. No one's reported this, but I saw it in an Android port of fuser(1). We still have lots of problems in our network headers because we get most of the structs direct from the kernel, and it doesn't use types like this (which is why we've got away without this one for so long). One day we should probably look at cleaning that up, but doing so can wait. (cherry picked from commit 35d226e05d92824c6eb992e7a64ea22efc8bae03) Bug: 18172268 Change-Id: Ice490bfe84afb04722d738128053d4c533b8a664 --- libc/include/arpa/inet.h | 3 +-- libc/include/netinet/in.h | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libc/include/arpa/inet.h b/libc/include/arpa/inet.h index 067be1fe9..86265bf24 100644 --- a/libc/include/arpa/inet.h +++ b/libc/include/arpa/inet.h @@ -25,6 +25,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + #ifndef _ARPA_INET_H_ #define _ARPA_INET_H_ @@ -34,8 +35,6 @@ __BEGIN_DECLS -typedef uint32_t in_addr_t; - in_addr_t inet_addr(const char*); int inet_aton(const char*, struct in_addr*); in_addr_t inet_lnaof(struct in_addr); diff --git a/libc/include/netinet/in.h b/libc/include/netinet/in.h index bf3b498c4..44c7fc1a6 100644 --- a/libc/include/netinet/in.h +++ b/libc/include/netinet/in.h @@ -25,6 +25,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + #ifndef _NETINET_IN_H_ #define _NETINET_IN_H_ @@ -43,6 +44,9 @@ __BEGIN_DECLS #define INET_ADDRSTRLEN 16 +typedef uint16_t in_port_t; +typedef uint32_t in_addr_t; + extern int bindresvport (int sd, struct sockaddr_in *sin); static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; From ab4d5cf24220f3b5d8f53b2b3bd635f23dcc9bc5 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 12 Sep 2014 20:04:40 -0700 Subject: [PATCH 063/114] POSIX says gets you ucontext_t. POSIX also says that ucontext_t's uc_sigmask has type sigset_t. MIPS64 strace needs this. The #define is to keep chromium off our lawn; otherwise it tries to redefine all this stuff itself. We should probably clean that up and remove the #define. (cherry picked from commit 26a8eb50a84e131d34d10d5d167d67e9995399bd) Bug: 18172268 Change-Id: I49d7d09dabfc6c6926a8e1f4b235d041e2f2fc4d --- libc/include/signal.h | 3 +++ libc/include/sys/ucontext.h | 12 ++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libc/include/signal.h b/libc/include/signal.h index f1849c5d4..e23e65b80 100644 --- a/libc/include/signal.h +++ b/libc/include/signal.h @@ -48,6 +48,9 @@ # include #endif +#include +#define __BIONIC_HAVE_UCONTEXT_T + __BEGIN_DECLS typedef int sig_atomic_t; diff --git a/libc/include/sys/ucontext.h b/libc/include/sys/ucontext.h index f62380d8a..b8d4d5812 100644 --- a/libc/include/sys/ucontext.h +++ b/libc/include/sys/ucontext.h @@ -68,11 +68,9 @@ typedef struct ucontext { struct ucontext* uc_link; stack_t uc_stack; mcontext_t uc_mcontext; + sigset_t uc_sigmask; // Android has a wrong (smaller) sigset_t on ARM. - union { - sigset_t bionic; - uint32_t kernel[2]; - } uc_sigmask; + uint32_t __padding_rt_sigset; // The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM. char __padding[120]; unsigned long uc_regspace[128] __attribute__((__aligned__(8))); @@ -152,11 +150,9 @@ typedef struct ucontext { struct ucontext* uc_link; stack_t uc_stack; mcontext_t uc_mcontext; + sigset_t uc_sigmask; // Android has a wrong (smaller) sigset_t on x86. - union { - sigset_t bionic; - uint32_t kernel[2]; - } uc_sigmask; + uint32_t __padding_rt_sigset; struct _libc_fpstate __fpregs_mem; } ucontext_t; From d0fb6a2940a43122f193be156ddff28c377e5163 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 19 Sep 2014 10:31:49 -0700 Subject: [PATCH 064/114] Add greg_t for arm64. This was already present for the other architectures. I think we skipped this because glibc seems to have an incorrect definition (int rather than long), but the kernel has the sane definition (just not in a uapi header). (cherry picked from commit 8e4d371091e5738346f5c6ad395b8487c2a5ec67) Bug: 18172268 Change-Id: I22d13fdeb6431ea122dd028a229782dcaf2286b2 --- libc/include/sys/ucontext.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libc/include/sys/ucontext.h b/libc/include/sys/ucontext.h index b8d4d5812..dd2a0bba6 100644 --- a/libc/include/sys/ucontext.h +++ b/libc/include/sys/ucontext.h @@ -78,6 +78,10 @@ typedef struct ucontext { #elif defined(__aarch64__) +#define NGREG 34 /* x0..x30 + sp + pc + pstate */ +typedef unsigned long greg_t; +typedef greg_t gregset_t[NGREG]; + #include typedef struct sigcontext mcontext_t; From 0c4e98adbe57fc616651831c4d78c2b627ea5f5d Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 24 Oct 2014 20:57:09 -0700 Subject: [PATCH 065/114] Fix the type of u_ar0 in . (cherry picked from commit e03950fa0c5567edf70d011b856a027e03b1c0f7) Bug: 18172268 Change-Id: I0feda6b253882f68f47bcf30fad998286cc7f620 --- libc/include/sys/user.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libc/include/sys/user.h b/libc/include/sys/user.h index 66b371d50..0e368250f 100644 --- a/libc/include/sys/user.h +++ b/libc/include/sys/user.h @@ -91,7 +91,7 @@ struct user { unsigned long start_stack; long int signal; int reserved; - unsigned long u_ar0; + struct user_regs_struct* u_ar0; struct user_fpregs_struct* u_fpstate; unsigned long magic; char u_comm[32]; @@ -155,7 +155,7 @@ struct user { long int signal; int reserved; int pad1; - unsigned long u_ar0; + struct user_regs_struct* u_ar0; struct user_fpregs_struct* u_fpstate; unsigned long magic; char u_comm[32]; @@ -175,7 +175,7 @@ struct user { unsigned long start_data; unsigned long start_stack; long int signal; - unsigned long u_ar0; + void* u_ar0; unsigned long magic; char u_comm[32]; }; From 653263a96459c5c1811623bd84201c324a870280 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Thu, 16 Oct 2014 07:52:51 -0700 Subject: [PATCH 066/114] Only use for C++11 and newer. Any pre-C++11 clients of stdatomic.h that use libc++ are being forced over to , which they don't have the language support to use. Bug:17736764 Change-Id: I62445c1f2541410a1569498c09433c7196635537 (cherry picked from commit 3ce0769aa5f9a991af1d167f730d987dd002253c) --- libc/include/stdatomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/include/stdatomic.h b/libc/include/stdatomic.h index bcea85924..58cb1bc0e 100644 --- a/libc/include/stdatomic.h +++ b/libc/include/stdatomic.h @@ -33,7 +33,7 @@ #include -#if defined(__cplusplus) && defined(_USING_LIBCXX) +#if defined(__cplusplus) && __cplusplus >= 201103L && defined(_USING_LIBCXX) # ifdef __clang__ # if __has_feature(cxx_atomic) # define _STDATOMIC_HAVE_ATOMIC From 926797a8a92a009184556ed45e02f3292066a296 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Fri, 12 Sep 2014 09:43:13 -0700 Subject: [PATCH 067/114] Reformatting No functional changes. Bug: 18186310 (cherry picked from commit 6abf624d122bec8c80cc9fe1b692265bf1b28b1b)] Change-Id: I0acf52d8ee7fe2d4f44bc832cbe9fabe1782f03f --- linker/linker.cpp | 2078 ++++++++++++++++++++++----------------------- 1 file changed, 1037 insertions(+), 1041 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 9425c9d3b..37e01893f 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -88,7 +88,7 @@ static LinkerAllocator> g_soinfo_links_allocator; static soinfo* solist; static soinfo* sonext; -static soinfo* somain; /* main process, always the one after libdl_info */ +static soinfo* somain; // main process, always the one after libdl_info static const char* const kDefaultLdPaths[] = { #if defined(__LP64__) @@ -120,22 +120,22 @@ __LIBC_HIDDEN__ int g_ld_debug_verbosity; __LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd. enum RelocationKind { - kRelocAbsolute = 0, - kRelocRelative, - kRelocCopy, - kRelocSymbol, - kRelocMax + kRelocAbsolute = 0, + kRelocRelative, + kRelocCopy, + kRelocSymbol, + kRelocMax }; #if STATS struct linker_stats_t { - int count[kRelocMax]; + int count[kRelocMax]; }; static linker_stats_t linker_stats; static void count_relocation(RelocationKind kind) { - ++linker_stats.count[kind]; + ++linker_stats.count[kind]; } #else static void count_relocation(RelocationKind) { @@ -147,13 +147,13 @@ static unsigned bitmask[4096]; #if defined(__LP64__) #define MARK(offset) \ do { \ - if ((((offset) >> 12) >> 5) < 4096) \ - bitmask[((offset) >> 12) >> 5] |= (1 << (((offset) >> 12) & 31)); \ + if ((((offset) >> 12) >> 5) < 4096) \ + bitmask[((offset) >> 12) >> 5] |= (1 << (((offset) >> 12) & 31)); \ } while (0) #else #define MARK(offset) \ do { \ - bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \ + bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \ } while (0) #endif #else @@ -165,7 +165,7 @@ static unsigned bitmask[4096]; #define DISALLOW_ALLOCATION(return_type, name, ...) \ return_type name __VA_ARGS__ \ { \ - __libc_fatal("ERROR: " #name " called from the dynamic linker!\n"); \ + __libc_fatal("ERROR: " #name " called from the dynamic linker!\n"); \ } DISALLOW_ALLOCATION(void*, malloc, (size_t u __unused)); DISALLOW_ALLOCATION(void, free, (void* u __unused)); @@ -182,10 +182,8 @@ size_t linker_get_error_buffer_size() { return sizeof(__linker_dl_err_buf); } -/* - * This function is an empty stub where GDB locates a breakpoint to get notified - * about linker activity. - */ +// This function is an empty stub where GDB locates a breakpoint to get notified +// about linker activity. extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity(); static pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -193,76 +191,75 @@ static r_debug _r_debug = {1, nullptr, reinterpret_cast(&rtld_db_dlac static link_map* r_debug_tail = 0; static void insert_soinfo_into_debug_map(soinfo* info) { - // Copy the necessary fields into the debug structure. - link_map* map = &(info->link_map_head); - map->l_addr = info->load_bias; - map->l_name = reinterpret_cast(info->name); - map->l_ld = info->dynamic; + // Copy the necessary fields into the debug structure. + link_map* map = &(info->link_map_head); + map->l_addr = info->load_bias; + map->l_name = reinterpret_cast(info->name); + map->l_ld = info->dynamic; - /* Stick the new library at the end of the list. - * gdb tends to care more about libc than it does - * about leaf libraries, and ordering it this way - * reduces the back-and-forth over the wire. - */ - if (r_debug_tail) { - r_debug_tail->l_next = map; - map->l_prev = r_debug_tail; - map->l_next = 0; - } else { - _r_debug.r_map = map; - map->l_prev = 0; - map->l_next = 0; - } - r_debug_tail = map; + // Stick the new library at the end of the list. + // gdb tends to care more about libc than it does + // about leaf libraries, and ordering it this way + // reduces the back-and-forth over the wire. + if (r_debug_tail) { + r_debug_tail->l_next = map; + map->l_prev = r_debug_tail; + map->l_next = 0; + } else { + _r_debug.r_map = map; + map->l_prev = 0; + map->l_next = 0; + } + r_debug_tail = map; } static void remove_soinfo_from_debug_map(soinfo* info) { - link_map* map = &(info->link_map_head); + link_map* map = &(info->link_map_head); - if (r_debug_tail == map) { - r_debug_tail = map->l_prev; - } + if (r_debug_tail == map) { + r_debug_tail = map->l_prev; + } - if (map->l_prev) { - map->l_prev->l_next = map->l_next; - } - if (map->l_next) { - map->l_next->l_prev = map->l_prev; - } + if (map->l_prev) { + map->l_prev->l_next = map->l_next; + } + if (map->l_next) { + map->l_next->l_prev = map->l_prev; + } } static void notify_gdb_of_load(soinfo* info) { - if (info->flags & FLAG_EXE) { - // GDB already knows about the main executable - return; - } + if (info->flags & FLAG_EXE) { + // GDB already knows about the main executable + return; + } - ScopedPthreadMutexLocker locker(&g__r_debug_mutex); + ScopedPthreadMutexLocker locker(&g__r_debug_mutex); - _r_debug.r_state = r_debug::RT_ADD; - rtld_db_dlactivity(); + _r_debug.r_state = r_debug::RT_ADD; + rtld_db_dlactivity(); - insert_soinfo_into_debug_map(info); + insert_soinfo_into_debug_map(info); - _r_debug.r_state = r_debug::RT_CONSISTENT; - rtld_db_dlactivity(); + _r_debug.r_state = r_debug::RT_CONSISTENT; + rtld_db_dlactivity(); } static void notify_gdb_of_unload(soinfo* info) { - if (info->flags & FLAG_EXE) { - // GDB already knows about the main executable - return; - } + if (info->flags & FLAG_EXE) { + // GDB already knows about the main executable + return; + } - ScopedPthreadMutexLocker locker(&g__r_debug_mutex); + ScopedPthreadMutexLocker locker(&g__r_debug_mutex); - _r_debug.r_state = r_debug::RT_DELETE; - rtld_db_dlactivity(); + _r_debug.r_state = r_debug::RT_DELETE; + rtld_db_dlactivity(); - remove_soinfo_from_debug_map(info); + remove_soinfo_from_debug_map(info); - _r_debug.r_state = r_debug::RT_CONSISTENT; - rtld_db_dlactivity(); + _r_debug.r_state = r_debug::RT_CONSISTENT; + rtld_db_dlactivity(); } void notify_gdb_of_libraries() { @@ -301,41 +298,41 @@ static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t fi } static void soinfo_free(soinfo* si) { - if (si == nullptr) { - return; + if (si == nullptr) { + return; + } + + if (si->base != 0 && si->size != 0) { + munmap(reinterpret_cast(si->base), si->size); + } + + soinfo *prev = nullptr, *trav; + + TRACE("name %s: freeing soinfo @ %p", si->name, si); + + for (trav = solist; trav != nullptr; trav = trav->next) { + if (trav == si) { + break; } + prev = trav; + } + if (trav == nullptr) { + // si was not in solist + DL_ERR("name \"%s\" is not in solist!", si->name); + return; + } - if (si->base != 0 && si->size != 0) { - munmap(reinterpret_cast(si->base), si->size); - } + // clear links to/from si + si->remove_all_links(); - soinfo *prev = nullptr, *trav; + // prev will never be null, because the first entry in solist is + // always the static libdl_info. + prev->next = si->next; + if (si == sonext) { + sonext = prev; + } - TRACE("name %s: freeing soinfo @ %p", si->name, si); - - for (trav = solist; trav != nullptr; trav = trav->next) { - if (trav == si) - break; - prev = trav; - } - if (trav == nullptr) { - /* si was not in solist */ - DL_ERR("name \"%s\" is not in solist!", si->name); - return; - } - - // clear links to/from si - si->remove_all_links(); - - /* prev will never be null, because the first entry in solist is - always the static libdl_info. - */ - prev->next = si->next; - if (si == sonext) { - sonext = prev; - } - - g_soinfo_allocator.free(si); + g_soinfo_allocator.free(si); } @@ -377,46 +374,45 @@ static void parse_LD_PRELOAD(const char* path) { #if defined(__arm__) -/* For a given PC, find the .so that it belongs to. - * Returns the base address of the .ARM.exidx section - * for that .so, and the number of 8-byte entries - * in that section (via *pcount). - * - * Intended to be called by libc's __gnu_Unwind_Find_exidx(). - * - * This function is exposed via dlfcn.cpp and libdl.so. - */ +// For a given PC, find the .so that it belongs to. +// Returns the base address of the .ARM.exidx section +// for that .so, and the number of 8-byte entries +// in that section (via *pcount). +// +// Intended to be called by libc's __gnu_Unwind_Find_exidx(). +// +// This function is exposed via dlfcn.cpp and libdl.so. _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) { - unsigned addr = (unsigned)pc; + unsigned addr = (unsigned)pc; - for (soinfo* si = solist; si != 0; si = si->next) { - if ((addr >= si->base) && (addr < (si->base + si->size))) { - *pcount = si->ARM_exidx_count; - return (_Unwind_Ptr)si->ARM_exidx; - } + for (soinfo* si = solist; si != 0; si = si->next) { + if ((addr >= si->base) && (addr < (si->base + si->size))) { + *pcount = si->ARM_exidx_count; + return (_Unwind_Ptr)si->ARM_exidx; } - *pcount = 0; - return nullptr; + } + *pcount = 0; + return nullptr; } #endif -/* Here, we only have to provide a callback to iterate across all the - * loaded libraries. gcc_eh does the rest. */ +// Here, we only have to provide a callback to iterate across all the +// loaded libraries. gcc_eh does the rest. int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) { - int rv = 0; - for (soinfo* si = solist; si != nullptr; si = si->next) { - dl_phdr_info dl_info; - dl_info.dlpi_addr = si->link_map_head.l_addr; - dl_info.dlpi_name = si->link_map_head.l_name; - dl_info.dlpi_phdr = si->phdr; - dl_info.dlpi_phnum = si->phnum; - rv = cb(&dl_info, sizeof(dl_phdr_info), data); - if (rv != 0) { - break; - } + int rv = 0; + for (soinfo* si = solist; si != nullptr; si = si->next) { + dl_phdr_info dl_info; + dl_info.dlpi_addr = si->link_map_head.l_addr; + dl_info.dlpi_name = si->link_map_head.l_name; + dl_info.dlpi_phdr = si->phdr; + dl_info.dlpi_phnum = si->phnum; + rv = cb(&dl_info, sizeof(dl_phdr_info), data); + if (rv != 0) { + break; } - return rv; + } + return rv; } static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) { @@ -430,7 +426,7 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) ElfW(Sym)* s = symtab + n; if (strcmp(strtab + s->st_name, name)) continue; - /* only concern ourselves with global and weak symbol definitions */ + // only concern ourselves with global and weak symbol definitions switch (ELF_ST_BIND(s->st_info)) { case STB_GLOBAL: case STB_WEAK: @@ -472,134 +468,134 @@ soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offs } static unsigned elfhash(const char* _name) { - const unsigned char* name = reinterpret_cast(_name); - unsigned h = 0, g; + const unsigned char* name = reinterpret_cast(_name); + unsigned h = 0, g; - while (*name) { - h = (h << 4) + *name++; - g = h & 0xf0000000; - h ^= g; - h ^= g >> 24; - } - return h; + while (*name) { + h = (h << 4) + *name++; + g = h & 0xf0000000; + h ^= g; + h ^= g >> 24; + } + return h; } static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { - unsigned elf_hash = elfhash(name); - ElfW(Sym)* s = nullptr; + unsigned elf_hash = elfhash(name); + ElfW(Sym)* s = nullptr; - if (somain != nullptr) { - /* - * Local scope is executable scope. Just start looking into it right away - * for the shortcut. - */ + if (somain != nullptr) { + /* + * Local scope is executable scope. Just start looking into it right away + * for the shortcut. + */ - if (si == somain) { - s = soinfo_elf_lookup(si, elf_hash, name); - if (s != nullptr) { - *lsi = si; - goto done; - } + if (si == somain) { + s = soinfo_elf_lookup(si, elf_hash, name); + if (s != nullptr) { + *lsi = si; + goto done; + } - /* Next, look for it in the preloads list */ - for (int i = 0; g_ld_preloads[i] != NULL; i++) { - s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); - if (s != NULL) { - *lsi = g_ld_preloads[i]; - goto done; - } - } - } else { - /* Order of symbol lookup is controlled by DT_SYMBOLIC flag */ - - /* - * If this object was built with symbolic relocations disabled, the - * first place to look to resolve external references is the main - * executable. - */ - - if (!si->has_DT_SYMBOLIC) { - DEBUG("%s: looking up %s in executable %s", - si->name, name, somain->name); - s = soinfo_elf_lookup(somain, elf_hash, name); - if (s != nullptr) { - *lsi = somain; - goto done; - } - - /* Next, look for it in the preloads list */ - for (int i = 0; g_ld_preloads[i] != NULL; i++) { - s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); - if (s != NULL) { - *lsi = g_ld_preloads[i]; - goto done; - } - } - } - - /* Look for symbols in the local scope (the object who is - * searching). This happens with C++ templates on x86 for some - * reason. - * - * Notes on weak symbols: - * The ELF specs are ambiguous about treatment of weak definitions in - * dynamic linking. Some systems return the first definition found - * and some the first non-weak definition. This is system dependent. - * Here we return the first definition found for simplicity. */ - - s = soinfo_elf_lookup(si, elf_hash, name); - if (s != nullptr) { - *lsi = si; - goto done; - } - - /* - * If this object was built with -Bsymbolic and symbol is not found - * in the local scope, try to find the symbol in the main executable. - */ - - if (si->has_DT_SYMBOLIC) { - DEBUG("%s: looking up %s in executable %s after local scope", - si->name, name, somain->name); - s = soinfo_elf_lookup(somain, elf_hash, name); - if (s != nullptr) { - *lsi = somain; - goto done; - } - - /* Next, look for it in the preloads list */ - for (int i = 0; g_ld_preloads[i] != NULL; i++) { - s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); - if (s != NULL) { - *lsi = g_ld_preloads[i]; - goto done; - } - } - } + /* Next, look for it in the preloads list */ + for (int i = 0; g_ld_preloads[i] != NULL; i++) { + s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); + if (s != NULL) { + *lsi = g_ld_preloads[i]; + goto done; } - } + } + } else { + /* Order of symbol lookup is controlled by DT_SYMBOLIC flag */ - si->get_children().visit([&](soinfo* child) { - DEBUG("%s: looking up %s in %s", si->name, name, child->name); - s = soinfo_elf_lookup(child, elf_hash, name); + /* + * If this object was built with symbolic relocations disabled, the + * first place to look to resolve external references is the main + * executable. + */ + + if (!si->has_DT_SYMBOLIC) { + DEBUG("%s: looking up %s in executable %s", + si->name, name, somain->name); + s = soinfo_elf_lookup(somain, elf_hash, name); if (s != nullptr) { - *lsi = child; - return false; + *lsi = somain; + goto done; } - return true; - }); + + /* Next, look for it in the preloads list */ + for (int i = 0; g_ld_preloads[i] != NULL; i++) { + s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); + if (s != NULL) { + *lsi = g_ld_preloads[i]; + goto done; + } + } + } + + /* Look for symbols in the local scope (the object who is + * searching). This happens with C++ templates on x86 for some + * reason. + * + * Notes on weak symbols: + * The ELF specs are ambiguous about treatment of weak definitions in + * dynamic linking. Some systems return the first definition found + * and some the first non-weak definition. This is system dependent. + * Here we return the first definition found for simplicity. */ + + s = soinfo_elf_lookup(si, elf_hash, name); + if (s != nullptr) { + *lsi = si; + goto done; + } + + /* + * If this object was built with -Bsymbolic and symbol is not found + * in the local scope, try to find the symbol in the main executable. + */ + + if (si->has_DT_SYMBOLIC) { + DEBUG("%s: looking up %s in executable %s after local scope", + si->name, name, somain->name); + s = soinfo_elf_lookup(somain, elf_hash, name); + if (s != nullptr) { + *lsi = somain; + goto done; + } + + /* Next, look for it in the preloads list */ + for (int i = 0; g_ld_preloads[i] != NULL; i++) { + s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); + if (s != NULL) { + *lsi = g_ld_preloads[i]; + goto done; + } + } + } + } + } + + si->get_children().visit([&](soinfo* child) { + DEBUG("%s: looking up %s in %s", si->name, name, child->name); + s = soinfo_elf_lookup(child, elf_hash, name); + if (s != nullptr) { + *lsi = child; + return false; + } + return true; + }); done: - if (s != nullptr) { - TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " - "found in %s, base = %p, load bias = %p", - si->name, name, reinterpret_cast(s->st_value), - (*lsi)->name, reinterpret_cast((*lsi)->base), - reinterpret_cast((*lsi)->load_bias)); - return s; - } + if (s != nullptr) { + TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " + "found in %s, base = %p, load bias = %p", + si->name, name, reinterpret_cast(s->st_value), + (*lsi)->name, reinterpret_cast((*lsi)->base), + reinterpret_cast((*lsi)->load_bias)); + return s; + } - return nullptr; + return nullptr; } // Each size has it's own allocator. @@ -1156,35 +1152,35 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { switch (type) { #if defined(__aarch64__) - case R_AARCH64_JUMP_SLOT: - case R_AARCH64_GLOB_DAT: - case R_AARCH64_ABS64: - case R_AARCH64_ABS32: - case R_AARCH64_ABS16: - case R_AARCH64_RELATIVE: - case R_AARCH64_IRELATIVE: - /* - * The sym_addr was initialized to be zero above, or the relocation - * code below does not care about value of sym_addr. - * No need to do anything. - */ - break; + case R_AARCH64_JUMP_SLOT: + case R_AARCH64_GLOB_DAT: + case R_AARCH64_ABS64: + case R_AARCH64_ABS32: + case R_AARCH64_ABS16: + case R_AARCH64_RELATIVE: + case R_AARCH64_IRELATIVE: + /* + * The sym_addr was initialized to be zero above, or the relocation + * code below does not care about value of sym_addr. + * No need to do anything. + */ + break; #elif defined(__x86_64__) - case R_X86_64_JUMP_SLOT: - case R_X86_64_GLOB_DAT: - case R_X86_64_32: - case R_X86_64_64: - case R_X86_64_RELATIVE: - case R_X86_64_IRELATIVE: - // No need to do anything. - break; - case R_X86_64_PC32: - sym_addr = reloc; - break; + case R_X86_64_JUMP_SLOT: + case R_X86_64_GLOB_DAT: + case R_X86_64_32: + case R_X86_64_64: + case R_X86_64_RELATIVE: + case R_X86_64_IRELATIVE: + // No need to do anything. + break; + case R_X86_64_PC32: + sym_addr = reloc; + break; #endif - default: - DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rela, idx); - return -1; + default: + DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rela, idx); + return -1; } } else { // We got a definition. @@ -1195,119 +1191,119 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { switch (type) { #if defined(__aarch64__) - case R_AARCH64_JUMP_SLOT: + case R_AARCH64_JUMP_SLOT: count_relocation(kRelocAbsolute); MARK(rela->r_offset); TRACE_TYPE(RELO, "RELO JMP_SLOT %16llx <- %16llx %s\n", reloc, (sym_addr + rela->r_addend), sym_name); *reinterpret_cast(reloc) = (sym_addr + rela->r_addend); break; - case R_AARCH64_GLOB_DAT: + case R_AARCH64_GLOB_DAT: count_relocation(kRelocAbsolute); MARK(rela->r_offset); TRACE_TYPE(RELO, "RELO GLOB_DAT %16llx <- %16llx %s\n", reloc, (sym_addr + rela->r_addend), sym_name); *reinterpret_cast(reloc) = (sym_addr + rela->r_addend); break; - case R_AARCH64_ABS64: + case R_AARCH64_ABS64: count_relocation(kRelocAbsolute); MARK(rela->r_offset); TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n", reloc, (sym_addr + rela->r_addend), sym_name); *reinterpret_cast(reloc) += (sym_addr + rela->r_addend); break; - case R_AARCH64_ABS32: + case R_AARCH64_ABS32: count_relocation(kRelocAbsolute); MARK(rela->r_offset); TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n", reloc, (sym_addr + rela->r_addend), sym_name); if ((static_cast(INT32_MIN) <= (*reinterpret_cast(reloc) + (sym_addr + rela->r_addend))) && ((*reinterpret_cast(reloc) + (sym_addr + rela->r_addend)) <= static_cast(UINT32_MAX))) { - *reinterpret_cast(reloc) += (sym_addr + rela->r_addend); + *reinterpret_cast(reloc) += (sym_addr + rela->r_addend); } else { - DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", - (*reinterpret_cast(reloc) + (sym_addr + rela->r_addend)), - static_cast(INT32_MIN), - static_cast(UINT32_MAX)); - return -1; + DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", + (*reinterpret_cast(reloc) + (sym_addr + rela->r_addend)), + static_cast(INT32_MIN), + static_cast(UINT32_MAX)); + return -1; } break; - case R_AARCH64_ABS16: + case R_AARCH64_ABS16: count_relocation(kRelocAbsolute); MARK(rela->r_offset); TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n", reloc, (sym_addr + rela->r_addend), sym_name); if ((static_cast(INT16_MIN) <= (*reinterpret_cast(reloc) + (sym_addr + rela->r_addend))) && ((*reinterpret_cast(reloc) + (sym_addr + rela->r_addend)) <= static_cast(UINT16_MAX))) { - *reinterpret_cast(reloc) += (sym_addr + rela->r_addend); + *reinterpret_cast(reloc) += (sym_addr + rela->r_addend); } else { - DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", - (*reinterpret_cast(reloc) + (sym_addr + rela->r_addend)), - static_cast(INT16_MIN), - static_cast(UINT16_MAX)); - return -1; + DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", + (*reinterpret_cast(reloc) + (sym_addr + rela->r_addend)), + static_cast(INT16_MIN), + static_cast(UINT16_MAX)); + return -1; } break; - case R_AARCH64_PREL64: + case R_AARCH64_PREL64: count_relocation(kRelocRelative); MARK(rela->r_offset); TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n", reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name); *reinterpret_cast(reloc) += (sym_addr + rela->r_addend) - rela->r_offset; break; - case R_AARCH64_PREL32: + case R_AARCH64_PREL32: count_relocation(kRelocRelative); MARK(rela->r_offset); TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n", reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name); if ((static_cast(INT32_MIN) <= (*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) && ((*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= static_cast(UINT32_MAX))) { - *reinterpret_cast(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset); + *reinterpret_cast(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset); } else { - DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", - (*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)), - static_cast(INT32_MIN), - static_cast(UINT32_MAX)); - return -1; + DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", + (*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)), + static_cast(INT32_MIN), + static_cast(UINT32_MAX)); + return -1; } break; - case R_AARCH64_PREL16: + case R_AARCH64_PREL16: count_relocation(kRelocRelative); MARK(rela->r_offset); TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n", reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name); if ((static_cast(INT16_MIN) <= (*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) && ((*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= static_cast(UINT16_MAX))) { - *reinterpret_cast(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset); + *reinterpret_cast(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset); } else { - DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", - (*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)), - static_cast(INT16_MIN), - static_cast(UINT16_MAX)); - return -1; + DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", + (*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)), + static_cast(INT16_MIN), + static_cast(UINT16_MAX)); + return -1; } break; - case R_AARCH64_RELATIVE: + case R_AARCH64_RELATIVE: count_relocation(kRelocRelative); MARK(rela->r_offset); if (sym) { - DL_ERR("odd RELATIVE form..."); - return -1; + DL_ERR("odd RELATIVE form..."); + return -1; } TRACE_TYPE(RELO, "RELO RELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend)); *reinterpret_cast(reloc) = (base + rela->r_addend); break; - case R_AARCH64_IRELATIVE: - count_relocation(kRelocRelative); - MARK(rela->r_offset); - TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend)); - *reinterpret_cast(reloc) = call_ifunc_resolver(base + rela->r_addend); - break; + case R_AARCH64_IRELATIVE: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend)); + *reinterpret_cast(reloc) = call_ifunc_resolver(base + rela->r_addend); + break; - case R_AARCH64_COPY: + case R_AARCH64_COPY: /* * ET_EXEC is not supported so this should not happen. * @@ -1319,73 +1315,73 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { */ DL_ERR("%s R_AARCH64_COPY relocations are not supported", name); return -1; - case R_AARCH64_TLS_TPREL64: + case R_AARCH64_TLS_TPREL64: TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n", reloc, (sym_addr + rela->r_addend), rela->r_offset); break; - case R_AARCH64_TLS_DTPREL32: + case R_AARCH64_TLS_DTPREL32: TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n", reloc, (sym_addr + rela->r_addend), rela->r_offset); break; #elif defined(__x86_64__) - case R_X86_64_JUMP_SLOT: - count_relocation(kRelocAbsolute); - MARK(rela->r_offset); - TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast(reloc), - static_cast(sym_addr + rela->r_addend), sym_name); - *reinterpret_cast(reloc) = sym_addr + rela->r_addend; - break; - case R_X86_64_GLOB_DAT: - count_relocation(kRelocAbsolute); - MARK(rela->r_offset); - TRACE_TYPE(RELO, "RELO GLOB_DAT %08zx <- %08zx %s", static_cast(reloc), - static_cast(sym_addr + rela->r_addend), sym_name); - *reinterpret_cast(reloc) = sym_addr + rela->r_addend; - break; - case R_X86_64_RELATIVE: - count_relocation(kRelocRelative); - MARK(rela->r_offset); - if (sym) { - DL_ERR("odd RELATIVE form..."); - return -1; - } - TRACE_TYPE(RELO, "RELO RELATIVE %08zx <- +%08zx", static_cast(reloc), - static_cast(base)); - *reinterpret_cast(reloc) = base + rela->r_addend; - break; - case R_X86_64_IRELATIVE: - count_relocation(kRelocRelative); - MARK(rela->r_offset); - TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend)); - *reinterpret_cast(reloc) = call_ifunc_resolver(base + rela->r_addend); - break; - case R_X86_64_32: - count_relocation(kRelocRelative); - MARK(rela->r_offset); - TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast(reloc), - static_cast(sym_addr), sym_name); - *reinterpret_cast(reloc) = sym_addr + rela->r_addend; - break; - case R_X86_64_64: - count_relocation(kRelocRelative); - MARK(rela->r_offset); - TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast(reloc), - static_cast(sym_addr), sym_name); - *reinterpret_cast(reloc) = sym_addr + rela->r_addend; - break; - case R_X86_64_PC32: - count_relocation(kRelocRelative); - MARK(rela->r_offset); - TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s", - static_cast(reloc), static_cast(sym_addr - reloc), - static_cast(sym_addr), static_cast(reloc), sym_name); - *reinterpret_cast(reloc) = sym_addr + rela->r_addend - reloc; - break; + case R_X86_64_JUMP_SLOT: + count_relocation(kRelocAbsolute); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast(reloc), + static_cast(sym_addr + rela->r_addend), sym_name); + *reinterpret_cast(reloc) = sym_addr + rela->r_addend; + break; + case R_X86_64_GLOB_DAT: + count_relocation(kRelocAbsolute); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO GLOB_DAT %08zx <- %08zx %s", static_cast(reloc), + static_cast(sym_addr + rela->r_addend), sym_name); + *reinterpret_cast(reloc) = sym_addr + rela->r_addend; + break; + case R_X86_64_RELATIVE: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + if (sym) { + DL_ERR("odd RELATIVE form..."); + return -1; + } + TRACE_TYPE(RELO, "RELO RELATIVE %08zx <- +%08zx", static_cast(reloc), + static_cast(base)); + *reinterpret_cast(reloc) = base + rela->r_addend; + break; + case R_X86_64_IRELATIVE: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend)); + *reinterpret_cast(reloc) = call_ifunc_resolver(base + rela->r_addend); + break; + case R_X86_64_32: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast(reloc), + static_cast(sym_addr), sym_name); + *reinterpret_cast(reloc) = sym_addr + rela->r_addend; + break; + case R_X86_64_64: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast(reloc), + static_cast(sym_addr), sym_name); + *reinterpret_cast(reloc) = sym_addr + rela->r_addend; + break; + case R_X86_64_PC32: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s", + static_cast(reloc), static_cast(sym_addr - reloc), + static_cast(sym_addr), static_cast(reloc), sym_name); + *reinterpret_cast(reloc) = sym_addr + rela->r_addend - reloc; + break; #endif - default: - DL_ERR("unknown reloc type %d @ %p (%zu)", type, rela, idx); - return -1; + default: + DL_ERR("unknown reloc type %d @ %p (%zu)", type, rela, idx); + return -1; } } return 0; @@ -1393,260 +1389,260 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { #else // REL, not RELA. int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { - for (size_t idx = 0; idx < count; ++idx, ++rel) { - unsigned type = ELFW(R_TYPE)(rel->r_info); - // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. - unsigned sym = ELFW(R_SYM)(rel->r_info); - ElfW(Addr) reloc = static_cast(rel->r_offset + load_bias); - ElfW(Addr) sym_addr = 0; - const char* sym_name = nullptr; + for (size_t idx = 0; idx < count; ++idx, ++rel) { + unsigned type = ELFW(R_TYPE)(rel->r_info); + // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. + unsigned sym = ELFW(R_SYM)(rel->r_info); + ElfW(Addr) reloc = static_cast(rel->r_offset + load_bias); + ElfW(Addr) sym_addr = 0; + const char* sym_name = nullptr; - DEBUG("Processing '%s' relocation at index %zd", name, idx); - if (type == 0) { // R_*_NONE - continue; + DEBUG("Processing '%s' relocation at index %zd", name, idx); + if (type == 0) { // R_*_NONE + continue; + } + + ElfW(Sym)* s = nullptr; + soinfo* lsi = nullptr; + + if (sym != 0) { + sym_name = reinterpret_cast(strtab + symtab[sym].st_name); + s = soinfo_do_lookup(this, sym_name, &lsi); + if (s == nullptr) { + // We only allow an undefined symbol if this is a weak reference... + s = &symtab[sym]; + if (ELF_ST_BIND(s->st_info) != STB_WEAK) { + DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name); + return -1; } - ElfW(Sym)* s = nullptr; - soinfo* lsi = nullptr; + /* IHI0044C AAELF 4.5.1.1: - if (sym != 0) { - sym_name = reinterpret_cast(strtab + symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi); - if (s == nullptr) { - // We only allow an undefined symbol if this is a weak reference... - s = &symtab[sym]; - if (ELF_ST_BIND(s->st_info) != STB_WEAK) { - DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name); - return -1; - } + Libraries are not searched to resolve weak references. + It is not an error for a weak reference to remain + unsatisfied. - /* IHI0044C AAELF 4.5.1.1: - - Libraries are not searched to resolve weak references. - It is not an error for a weak reference to remain - unsatisfied. - - During linking, the value of an undefined weak reference is: - - Zero if the relocation type is absolute - - The address of the place if the relocation is pc-relative - - The address of nominal base address if the relocation - type is base-relative. - */ - - switch (type) { -#if defined(__arm__) - case R_ARM_JUMP_SLOT: - case R_ARM_GLOB_DAT: - case R_ARM_ABS32: - case R_ARM_RELATIVE: /* Don't care. */ - // sym_addr was initialized to be zero above or relocation - // code below does not care about value of sym_addr. - // No need to do anything. - break; -#elif defined(__i386__) - case R_386_JMP_SLOT: - case R_386_GLOB_DAT: - case R_386_32: - case R_386_RELATIVE: /* Don't care. */ - case R_386_IRELATIVE: - // sym_addr was initialized to be zero above or relocation - // code below does not care about value of sym_addr. - // No need to do anything. - break; - case R_386_PC32: - sym_addr = reloc; - break; -#endif - -#if defined(__arm__) - case R_ARM_COPY: - // Fall through. Can't really copy if weak symbol is not found at run-time. -#endif - default: - DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx); - return -1; - } - } else { - // We got a definition. - sym_addr = lsi->resolve_symbol_address(s); - } - count_relocation(kRelocSymbol); - } + During linking, the value of an undefined weak reference is: + - Zero if the relocation type is absolute + - The address of the place if the relocation is pc-relative + - The address of nominal base address if the relocation + type is base-relative. + */ switch (type) { #if defined(__arm__) - case R_ARM_JUMP_SLOT: - count_relocation(kRelocAbsolute); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); - *reinterpret_cast(reloc) = sym_addr; + case R_ARM_JUMP_SLOT: + case R_ARM_GLOB_DAT: + case R_ARM_ABS32: + case R_ARM_RELATIVE: /* Don't care. */ + // sym_addr was initialized to be zero above or relocation + // code below does not care about value of sym_addr. + // No need to do anything. break; - case R_ARM_GLOB_DAT: - count_relocation(kRelocAbsolute); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name); - *reinterpret_cast(reloc) = sym_addr; - break; - case R_ARM_ABS32: - count_relocation(kRelocAbsolute); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name); - *reinterpret_cast(reloc) += sym_addr; - break; - case R_ARM_REL32: - count_relocation(kRelocRelative); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s", - reloc, sym_addr, rel->r_offset, sym_name); - *reinterpret_cast(reloc) += sym_addr - rel->r_offset; - break; - case R_ARM_COPY: - /* - * ET_EXEC is not supported so this should not happen. - * - * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf - * - * Section 4.7.1.10 "Dynamic relocations" - * R_ARM_COPY may only appear in executable objects where e_type is - * set to ET_EXEC. - */ - DL_ERR("%s R_ARM_COPY relocations are not supported", name); - return -1; #elif defined(__i386__) - case R_386_JMP_SLOT: - count_relocation(kRelocAbsolute); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); - *reinterpret_cast(reloc) = sym_addr; + case R_386_JMP_SLOT: + case R_386_GLOB_DAT: + case R_386_32: + case R_386_RELATIVE: /* Don't care. */ + case R_386_IRELATIVE: + // sym_addr was initialized to be zero above or relocation + // code below does not care about value of sym_addr. + // No need to do anything. break; - case R_386_GLOB_DAT: - count_relocation(kRelocAbsolute); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name); - *reinterpret_cast(reloc) = sym_addr; - break; - case R_386_32: - count_relocation(kRelocRelative); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name); - *reinterpret_cast(reloc) += sym_addr; - break; - case R_386_PC32: - count_relocation(kRelocRelative); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s", - reloc, (sym_addr - reloc), sym_addr, reloc, sym_name); - *reinterpret_cast(reloc) += (sym_addr - reloc); - break; -#elif defined(__mips__) - case R_MIPS_REL32: -#if defined(__LP64__) - // MIPS Elf64_Rel entries contain compound relocations - // We only handle the R_MIPS_NONE|R_MIPS_64|R_MIPS_REL32 case - if (ELF64_R_TYPE2(rel->r_info) != R_MIPS_64 || - ELF64_R_TYPE3(rel->r_info) != R_MIPS_NONE) { - DL_ERR("Unexpected compound relocation type:%d type2:%d type3:%d @ %p (%zu)", - type, (unsigned)ELF64_R_TYPE2(rel->r_info), - (unsigned)ELF64_R_TYPE3(rel->r_info), rel, idx); - return -1; - } -#endif - count_relocation(kRelocAbsolute); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "RELO REL32 %08zx <- %08zx %s", static_cast(reloc), - static_cast(sym_addr), sym_name ? sym_name : "*SECTIONHDR*"); - if (s) { - *reinterpret_cast(reloc) += sym_addr; - } else { - *reinterpret_cast(reloc) += base; - } + case R_386_PC32: + sym_addr = reloc; break; #endif #if defined(__arm__) - case R_ARM_RELATIVE: -#elif defined(__i386__) - case R_386_RELATIVE: + case R_ARM_COPY: + // Fall through. Can't really copy if weak symbol is not found at run-time. #endif - count_relocation(kRelocRelative); - MARK(rel->r_offset); - if (sym) { - DL_ERR("odd RELATIVE form..."); - return -1; - } - TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p", - reinterpret_cast(reloc), reinterpret_cast(base)); - *reinterpret_cast(reloc) += base; - break; -#if defined(__i386__) - case R_386_IRELATIVE: - count_relocation(kRelocRelative); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "RELO IRELATIVE %p <- %p", reinterpret_cast(reloc), reinterpret_cast(base)); - *reinterpret_cast(reloc) = call_ifunc_resolver(base + *reinterpret_cast(reloc)); - break; -#endif - - default: - DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx); + default: + DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx); return -1; } + } else { + // We got a definition. + sym_addr = lsi->resolve_symbol_address(s); + } + count_relocation(kRelocSymbol); } - return 0; + + switch (type) { +#if defined(__arm__) + case R_ARM_JUMP_SLOT: + count_relocation(kRelocAbsolute); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); + *reinterpret_cast(reloc) = sym_addr; + break; + case R_ARM_GLOB_DAT: + count_relocation(kRelocAbsolute); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name); + *reinterpret_cast(reloc) = sym_addr; + break; + case R_ARM_ABS32: + count_relocation(kRelocAbsolute); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name); + *reinterpret_cast(reloc) += sym_addr; + break; + case R_ARM_REL32: + count_relocation(kRelocRelative); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s", + reloc, sym_addr, rel->r_offset, sym_name); + *reinterpret_cast(reloc) += sym_addr - rel->r_offset; + break; + case R_ARM_COPY: + /* + * ET_EXEC is not supported so this should not happen. + * + * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf + * + * Section 4.7.1.10 "Dynamic relocations" + * R_ARM_COPY may only appear in executable objects where e_type is + * set to ET_EXEC. + */ + DL_ERR("%s R_ARM_COPY relocations are not supported", name); + return -1; +#elif defined(__i386__) + case R_386_JMP_SLOT: + count_relocation(kRelocAbsolute); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); + *reinterpret_cast(reloc) = sym_addr; + break; + case R_386_GLOB_DAT: + count_relocation(kRelocAbsolute); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name); + *reinterpret_cast(reloc) = sym_addr; + break; + case R_386_32: + count_relocation(kRelocRelative); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name); + *reinterpret_cast(reloc) += sym_addr; + break; + case R_386_PC32: + count_relocation(kRelocRelative); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s", + reloc, (sym_addr - reloc), sym_addr, reloc, sym_name); + *reinterpret_cast(reloc) += (sym_addr - reloc); + break; +#elif defined(__mips__) + case R_MIPS_REL32: +#if defined(__LP64__) + // MIPS Elf64_Rel entries contain compound relocations + // We only handle the R_MIPS_NONE|R_MIPS_64|R_MIPS_REL32 case + if (ELF64_R_TYPE2(rel->r_info) != R_MIPS_64 || + ELF64_R_TYPE3(rel->r_info) != R_MIPS_NONE) { + DL_ERR("Unexpected compound relocation type:%d type2:%d type3:%d @ %p (%zu)", + type, (unsigned)ELF64_R_TYPE2(rel->r_info), + (unsigned)ELF64_R_TYPE3(rel->r_info), rel, idx); + return -1; + } +#endif + count_relocation(kRelocAbsolute); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO REL32 %08zx <- %08zx %s", static_cast(reloc), + static_cast(sym_addr), sym_name ? sym_name : "*SECTIONHDR*"); + if (s) { + *reinterpret_cast(reloc) += sym_addr; + } else { + *reinterpret_cast(reloc) += base; + } + break; +#endif + +#if defined(__arm__) + case R_ARM_RELATIVE: +#elif defined(__i386__) + case R_386_RELATIVE: +#endif + count_relocation(kRelocRelative); + MARK(rel->r_offset); + if (sym) { + DL_ERR("odd RELATIVE form..."); + return -1; + } + TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p", + reinterpret_cast(reloc), reinterpret_cast(base)); + *reinterpret_cast(reloc) += base; + break; +#if defined(__i386__) + case R_386_IRELATIVE: + count_relocation(kRelocRelative); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO IRELATIVE %p <- %p", reinterpret_cast(reloc), reinterpret_cast(base)); + *reinterpret_cast(reloc) = call_ifunc_resolver(base + *reinterpret_cast(reloc)); + break; +#endif + + default: + DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx); + return -1; + } + } + return 0; } #endif #if defined(__mips__) static bool mips_relocate_got(soinfo* si) { - ElfW(Addr)** got = si->plt_got; - if (got == nullptr) { - return true; - } - unsigned local_gotno = si->mips_local_gotno; - unsigned gotsym = si->mips_gotsym; - unsigned symtabno = si->mips_symtabno; - ElfW(Sym)* symtab = si->symtab; - - // got[0] is the address of the lazy resolver function. - // got[1] may be used for a GNU extension. - // Set it to a recognizable address in case someone calls it (should be _rtld_bind_start). - // FIXME: maybe this should be in a separate routine? - if ((si->flags & FLAG_LINKER) == 0) { - size_t g = 0; - got[g++] = reinterpret_cast(0xdeadbeef); - if (reinterpret_cast(got[g]) < 0) { - got[g++] = reinterpret_cast(0xdeadfeed); - } - // Relocate the local GOT entries. - for (; g < local_gotno; g++) { - got[g] = reinterpret_cast(reinterpret_cast(got[g]) + si->load_bias); - } - } - - // Now for the global GOT entries... - ElfW(Sym)* sym = symtab + gotsym; - got = si->plt_got + local_gotno; - for (size_t g = gotsym; g < symtabno; g++, sym++, got++) { - // This is an undefined reference... try to locate it. - const char* sym_name = si->strtab + sym->st_name; - soinfo* lsi = nullptr; - ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); - if (s == nullptr) { - // We only allow an undefined symbol if this is a weak reference. - s = &symtab[g]; - if (ELF_ST_BIND(s->st_info) != STB_WEAK) { - DL_ERR("cannot locate \"%s\"...", sym_name); - return false; - } - *got = 0; - } else { - // FIXME: is this sufficient? - // For reference see NetBSD link loader - // http://cvsweb.netbsd.org/bsdweb.cgi/src/libexec/ld.elf_so/arch/mips/mips_reloc.c?rev=1.53&content-type=text/x-cvsweb-markup - *got = reinterpret_cast(lsi->resolve_symbol_address(s)); - } - } + ElfW(Addr)** got = si->plt_got; + if (got == nullptr) { return true; + } + unsigned local_gotno = si->mips_local_gotno; + unsigned gotsym = si->mips_gotsym; + unsigned symtabno = si->mips_symtabno; + ElfW(Sym)* symtab = si->symtab; + + // got[0] is the address of the lazy resolver function. + // got[1] may be used for a GNU extension. + // Set it to a recognizable address in case someone calls it (should be _rtld_bind_start). + // FIXME: maybe this should be in a separate routine? + if ((si->flags & FLAG_LINKER) == 0) { + size_t g = 0; + got[g++] = reinterpret_cast(0xdeadbeef); + if (reinterpret_cast(got[g]) < 0) { + got[g++] = reinterpret_cast(0xdeadfeed); + } + // Relocate the local GOT entries. + for (; g < local_gotno; g++) { + got[g] = reinterpret_cast(reinterpret_cast(got[g]) + si->load_bias); + } + } + + // Now for the global GOT entries... + ElfW(Sym)* sym = symtab + gotsym; + got = si->plt_got + local_gotno; + for (size_t g = gotsym; g < symtabno; g++, sym++, got++) { + // This is an undefined reference... try to locate it. + const char* sym_name = si->strtab + sym->st_name; + soinfo* lsi = nullptr; + ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); + if (s == nullptr) { + // We only allow an undefined symbol if this is a weak reference. + s = &symtab[g]; + if (ELF_ST_BIND(s->st_info) != STB_WEAK) { + DL_ERR("cannot locate \"%s\"...", sym_name); + return false; + } + *got = 0; + } else { + // FIXME: is this sufficient? + // For reference see NetBSD link loader + // http://cvsweb.netbsd.org/bsdweb.cgi/src/libexec/ld.elf_so/arch/mips/mips_reloc.c?rev=1.53&content-type=text/x-cvsweb-markup + *got = reinterpret_cast(lsi->resolve_symbol_address(s)); + } + } + return true; } #endif @@ -1825,62 +1821,62 @@ ElfW(Addr) soinfo::resolve_symbol_address(ElfW(Sym)* s) { /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { - int dev_null, i, status; - int return_value = 0; + int dev_null, i, status; + int return_value = 0; - dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); - if (dev_null < 0) { - DL_ERR("cannot open /dev/null: %s", strerror(errno)); - return -1; - } - TRACE("[ Opened /dev/null file-descriptor=%d]", dev_null); + dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); + if (dev_null < 0) { + DL_ERR("cannot open /dev/null: %s", strerror(errno)); + return -1; + } + TRACE("[ Opened /dev/null file-descriptor=%d]", dev_null); - /* If any of the stdio file descriptors is valid and not associated - with /dev/null, dup /dev/null to it. */ - for (i = 0; i < 3; i++) { - /* If it is /dev/null already, we are done. */ - if (i == dev_null) { - continue; - } - - TRACE("[ Nullifying stdio file descriptor %d]", i); - status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL)); - - /* If file is opened, we are good. */ - if (status != -1) { - continue; - } - - /* The only error we allow is that the file descriptor does not - exist, in which case we dup /dev/null to it. */ - if (errno != EBADF) { - DL_ERR("fcntl failed: %s", strerror(errno)); - return_value = -1; - continue; - } - - /* Try dupping /dev/null to this stdio file descriptor and - repeat if there is a signal. Note that any errors in closing - the stdio descriptor are lost. */ - status = TEMP_FAILURE_RETRY(dup2(dev_null, i)); - if (status < 0) { - DL_ERR("dup2 failed: %s", strerror(errno)); - return_value = -1; - continue; - } + /* If any of the stdio file descriptors is valid and not associated + with /dev/null, dup /dev/null to it. */ + for (i = 0; i < 3; i++) { + /* If it is /dev/null already, we are done. */ + if (i == dev_null) { + continue; } - /* If /dev/null is not one of the stdio file descriptors, close it. */ - if (dev_null > 2) { - TRACE("[ Closing /dev/null file-descriptor=%d]", dev_null); - status = TEMP_FAILURE_RETRY(close(dev_null)); - if (status == -1) { - DL_ERR("close failed: %s", strerror(errno)); - return_value = -1; - } + TRACE("[ Nullifying stdio file descriptor %d]", i); + status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL)); + + /* If file is opened, we are good. */ + if (status != -1) { + continue; } - return return_value; + /* The only error we allow is that the file descriptor does not + exist, in which case we dup /dev/null to it. */ + if (errno != EBADF) { + DL_ERR("fcntl failed: %s", strerror(errno)); + return_value = -1; + continue; + } + + /* Try dupping /dev/null to this stdio file descriptor and + repeat if there is a signal. Note that any errors in closing + the stdio descriptor are lost. */ + status = TEMP_FAILURE_RETRY(dup2(dev_null, i)); + if (status < 0) { + DL_ERR("dup2 failed: %s", strerror(errno)); + return_value = -1; + continue; + } + } + + /* If /dev/null is not one of the stdio file descriptors, close it. */ + if (dev_null > 2) { + TRACE("[ Closing /dev/null file-descriptor=%d]", dev_null); + status = TEMP_FAILURE_RETRY(close(dev_null)); + if (status == -1) { + DL_ERR("close failed: %s", strerror(errno)); + return_value = -1; + } + } + + return return_value; } bool soinfo::PrelinkImage() { @@ -1888,318 +1884,318 @@ bool soinfo::PrelinkImage() { ElfW(Word) dynamic_flags = 0; phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags); - /* We can't log anything until the linker is relocated */ - bool relocating_linker = (flags & FLAG_LINKER) != 0; - if (!relocating_linker) { - INFO("[ linking %s ]", name); - DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast(base), flags); - } + /* We can't log anything until the linker is relocated */ + bool relocating_linker = (flags & FLAG_LINKER) != 0; + if (!relocating_linker) { + INFO("[ linking %s ]", name); + DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast(base), flags); + } - if (dynamic == nullptr) { - if (!relocating_linker) { - DL_ERR("missing PT_DYNAMIC in \"%s\"", name); - } - return false; - } else { - if (!relocating_linker) { - DEBUG("dynamic = %p", dynamic); - } + if (dynamic == nullptr) { + if (!relocating_linker) { + DL_ERR("missing PT_DYNAMIC in \"%s\"", name); } + return false; + } else { + if (!relocating_linker) { + DEBUG("dynamic = %p", dynamic); + } + } #if defined(__arm__) - (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias, - &ARM_exidx, &ARM_exidx_count); + (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias, + &ARM_exidx, &ARM_exidx_count); #endif - // Extract useful information from dynamic section. - uint32_t needed_count = 0; - for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { - DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", - d, reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); - switch (d->d_tag) { - case DT_HASH: - nbucket = reinterpret_cast(load_bias + d->d_un.d_ptr)[0]; - nchain = reinterpret_cast(load_bias + d->d_un.d_ptr)[1]; - bucket = reinterpret_cast(load_bias + d->d_un.d_ptr + 8); - chain = reinterpret_cast(load_bias + d->d_un.d_ptr + 8 + nbucket * 4); - break; - case DT_STRTAB: - strtab = reinterpret_cast(load_bias + d->d_un.d_ptr); - break; - case DT_SYMTAB: - symtab = reinterpret_cast(load_bias + d->d_un.d_ptr); - break; + // Extract useful information from dynamic section. + uint32_t needed_count = 0; + for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { + DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", + d, reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); + switch (d->d_tag) { + case DT_HASH: + nbucket = reinterpret_cast(load_bias + d->d_un.d_ptr)[0]; + nchain = reinterpret_cast(load_bias + d->d_un.d_ptr)[1]; + bucket = reinterpret_cast(load_bias + d->d_un.d_ptr + 8); + chain = reinterpret_cast(load_bias + d->d_un.d_ptr + 8 + nbucket * 4); + break; + case DT_STRTAB: + strtab = reinterpret_cast(load_bias + d->d_un.d_ptr); + break; + case DT_SYMTAB: + symtab = reinterpret_cast(load_bias + d->d_un.d_ptr); + break; #if !defined(__LP64__) - case DT_PLTREL: - if (d->d_un.d_val != DT_REL) { - DL_ERR("unsupported DT_RELA in \"%s\"", name); - return false; - } - break; + case DT_PLTREL: + if (d->d_un.d_val != DT_REL) { + DL_ERR("unsupported DT_RELA in \"%s\"", name); + return false; + } + break; #endif - case DT_JMPREL: + case DT_JMPREL: #if defined(USE_RELA) - plt_rela = reinterpret_cast(load_bias + d->d_un.d_ptr); + plt_rela = reinterpret_cast(load_bias + d->d_un.d_ptr); #else - plt_rel = reinterpret_cast(load_bias + d->d_un.d_ptr); + plt_rel = reinterpret_cast(load_bias + d->d_un.d_ptr); #endif - break; - case DT_PLTRELSZ: + break; + case DT_PLTRELSZ: #if defined(USE_RELA) - plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); + plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); #else - plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); + plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); #endif - break; + break; #if defined(__mips__) - case DT_PLTGOT: - // Used by mips and mips64. - plt_got = reinterpret_cast(load_bias + d->d_un.d_ptr); - break; + case DT_PLTGOT: + // Used by mips and mips64. + plt_got = reinterpret_cast(load_bias + d->d_un.d_ptr); + break; #endif - case DT_DEBUG: - // Set the DT_DEBUG entry to the address of _r_debug for GDB - // if the dynamic table is writable + case DT_DEBUG: + // Set the DT_DEBUG entry to the address of _r_debug for GDB + // if the dynamic table is writable // FIXME: not working currently for N64 // The flags for the LOAD and DYNAMIC program headers do not agree. // The LOAD section containing the dynamic table has been mapped as // read-only, but the DYNAMIC header claims it is writable. #if !(defined(__mips__) && defined(__LP64__)) - if ((dynamic_flags & PF_W) != 0) { - d->d_un.d_val = reinterpret_cast(&_r_debug); - } - break; + if ((dynamic_flags & PF_W) != 0) { + d->d_un.d_val = reinterpret_cast(&_r_debug); + } + break; #endif #if defined(USE_RELA) - case DT_RELA: - rela = reinterpret_cast(load_bias + d->d_un.d_ptr); - break; - case DT_RELASZ: - rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); - break; - case DT_REL: - DL_ERR("unsupported DT_REL in \"%s\"", name); - return false; - case DT_RELSZ: - DL_ERR("unsupported DT_RELSZ in \"%s\"", name); - return false; + case DT_RELA: + rela = reinterpret_cast(load_bias + d->d_un.d_ptr); + break; + case DT_RELASZ: + rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); + break; + case DT_REL: + DL_ERR("unsupported DT_REL in \"%s\"", name); + return false; + case DT_RELSZ: + DL_ERR("unsupported DT_RELSZ in \"%s\"", name); + return false; #else - case DT_REL: - rel = reinterpret_cast(load_bias + d->d_un.d_ptr); - break; - case DT_RELSZ: - rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); - break; - case DT_RELA: - DL_ERR("unsupported DT_RELA in \"%s\"", name); - return false; + case DT_REL: + rel = reinterpret_cast(load_bias + d->d_un.d_ptr); + break; + case DT_RELSZ: + rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); + break; + case DT_RELA: + DL_ERR("unsupported DT_RELA in \"%s\"", name); + return false; #endif - case DT_INIT: - init_func = reinterpret_cast(load_bias + d->d_un.d_ptr); - DEBUG("%s constructors (DT_INIT) found at %p", name, init_func); - break; - case DT_FINI: - fini_func = reinterpret_cast(load_bias + d->d_un.d_ptr); - DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func); - break; - case DT_INIT_ARRAY: - init_array = reinterpret_cast(load_bias + d->d_un.d_ptr); - DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array); - break; - case DT_INIT_ARRAYSZ: - init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); - break; - case DT_FINI_ARRAY: - fini_array = reinterpret_cast(load_bias + d->d_un.d_ptr); - DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array); - break; - case DT_FINI_ARRAYSZ: - fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); - break; - case DT_PREINIT_ARRAY: - preinit_array = reinterpret_cast(load_bias + d->d_un.d_ptr); - DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array); - break; - case DT_PREINIT_ARRAYSZ: - preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); - break; - case DT_TEXTREL: + case DT_INIT: + init_func = reinterpret_cast(load_bias + d->d_un.d_ptr); + DEBUG("%s constructors (DT_INIT) found at %p", name, init_func); + break; + case DT_FINI: + fini_func = reinterpret_cast(load_bias + d->d_un.d_ptr); + DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func); + break; + case DT_INIT_ARRAY: + init_array = reinterpret_cast(load_bias + d->d_un.d_ptr); + DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array); + break; + case DT_INIT_ARRAYSZ: + init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); + break; + case DT_FINI_ARRAY: + fini_array = reinterpret_cast(load_bias + d->d_un.d_ptr); + DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array); + break; + case DT_FINI_ARRAYSZ: + fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); + break; + case DT_PREINIT_ARRAY: + preinit_array = reinterpret_cast(load_bias + d->d_un.d_ptr); + DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array); + break; + case DT_PREINIT_ARRAYSZ: + preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); + break; + case DT_TEXTREL: #if defined(__LP64__) - DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name); - return false; + DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name); + return false; #else - has_text_relocations = true; - break; + has_text_relocations = true; + break; #endif - case DT_SYMBOLIC: - has_DT_SYMBOLIC = true; - break; - case DT_NEEDED: - ++needed_count; - break; - case DT_FLAGS: - if (d->d_un.d_val & DF_TEXTREL) { + case DT_SYMBOLIC: + has_DT_SYMBOLIC = true; + break; + case DT_NEEDED: + ++needed_count; + break; + case DT_FLAGS: + if (d->d_un.d_val & DF_TEXTREL) { #if defined(__LP64__) - DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", name); - return false; + DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", name); + return false; #else - has_text_relocations = true; + has_text_relocations = true; #endif - } - if (d->d_un.d_val & DF_SYMBOLIC) { - has_DT_SYMBOLIC = true; - } - break; -#if defined(__mips__) - case DT_STRSZ: - case DT_SYMENT: - case DT_RELENT: - break; - case DT_MIPS_RLD_MAP: - // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. - { - r_debug** dp = reinterpret_cast(load_bias + d->d_un.d_ptr); - *dp = &_r_debug; - } - break; - case DT_MIPS_RLD_VERSION: - case DT_MIPS_FLAGS: - case DT_MIPS_BASE_ADDRESS: - case DT_MIPS_UNREFEXTNO: - break; - - case DT_MIPS_SYMTABNO: - mips_symtabno = d->d_un.d_val; - break; - - case DT_MIPS_LOCAL_GOTNO: - mips_local_gotno = d->d_un.d_val; - break; - - case DT_MIPS_GOTSYM: - mips_gotsym = d->d_un.d_val; - break; -#endif - - default: - DEBUG("Unused DT entry: type %p arg %p", - reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); - break; } - } + if (d->d_un.d_val & DF_SYMBOLIC) { + has_DT_SYMBOLIC = true; + } + break; +#if defined(__mips__) + case DT_STRSZ: + case DT_SYMENT: + case DT_RELENT: + break; + case DT_MIPS_RLD_MAP: + // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. + { + r_debug** dp = reinterpret_cast(load_bias + d->d_un.d_ptr); + *dp = &_r_debug; + } + break; + case DT_MIPS_RLD_VERSION: + case DT_MIPS_FLAGS: + case DT_MIPS_BASE_ADDRESS: + case DT_MIPS_UNREFEXTNO: + break; - DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", - reinterpret_cast(base), strtab, symtab); + case DT_MIPS_SYMTABNO: + mips_symtabno = d->d_un.d_val; + break; - // Sanity checks. - if (relocating_linker && needed_count != 0) { - DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries"); - return false; + case DT_MIPS_LOCAL_GOTNO: + mips_local_gotno = d->d_un.d_val; + break; + + case DT_MIPS_GOTSYM: + mips_gotsym = d->d_un.d_val; + break; +#endif + + default: + DEBUG("Unused DT entry: type %p arg %p", + reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); + break; } - if (nbucket == 0) { - DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", name); - return false; - } - if (strtab == 0) { - DL_ERR("empty/missing DT_STRTAB in \"%s\"", name); - return false; - } - if (symtab == 0) { - DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name); - return false; - } - return true; + } + + DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", + reinterpret_cast(base), strtab, symtab); + + // Sanity checks. + if (relocating_linker && needed_count != 0) { + DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries"); + return false; + } + if (nbucket == 0) { + DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", name); + return false; + } + if (strtab == 0) { + DL_ERR("empty/missing DT_STRTAB in \"%s\"", name); + return false; + } + if (symtab == 0) { + DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name); + return false; + } + return true; } bool soinfo::LinkImage(const android_dlextinfo* extinfo) { #if !defined(__LP64__) - if (has_text_relocations) { - // Make segments writable to allow text relocations to work properly. We will later call - // phdr_table_protect_segments() after all of them are applied and all constructors are run. - DL_WARN("%s has text relocations. This is wasting memory and prevents " - "security hardening. Please fix.", name); - if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { - DL_ERR("can't unprotect loadable segments for \"%s\": %s", - name, strerror(errno)); - return false; - } + if (has_text_relocations) { + // Make segments writable to allow text relocations to work properly. We will later call + // phdr_table_protect_segments() after all of them are applied and all constructors are run. + DL_WARN("%s has text relocations. This is wasting memory and prevents " + "security hardening. Please fix.", name); + if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { + DL_ERR("can't unprotect loadable segments for \"%s\": %s", + name, strerror(errno)); + return false; } + } #endif #if defined(USE_RELA) - if (rela != nullptr) { - DEBUG("[ relocating %s ]", name); - if (Relocate(rela, rela_count)) { - return false; - } + if (rela != nullptr) { + DEBUG("[ relocating %s ]", name); + if (Relocate(rela, rela_count)) { + return false; } - if (plt_rela != nullptr) { - DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rela, plt_rela_count)) { - return false; - } + } + if (plt_rela != nullptr) { + DEBUG("[ relocating %s plt ]", name); + if (Relocate(plt_rela, plt_rela_count)) { + return false; } + } #else - if (rel != nullptr) { - DEBUG("[ relocating %s ]", name); - if (Relocate(rel, rel_count)) { - return false; - } + if (rel != nullptr) { + DEBUG("[ relocating %s ]", name); + if (Relocate(rel, rel_count)) { + return false; } - if (plt_rel != nullptr) { - DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rel, plt_rel_count)) { - return false; - } + } + if (plt_rel != nullptr) { + DEBUG("[ relocating %s plt ]", name); + if (Relocate(plt_rel, plt_rel_count)) { + return false; } + } #endif #if defined(__mips__) - if (!mips_relocate_got(this)) { - return false; - } + if (!mips_relocate_got(this)) { + return false; + } #endif - DEBUG("[ finished linking %s ]", name); + DEBUG("[ finished linking %s ]", name); #if !defined(__LP64__) - if (has_text_relocations) { - // All relocations are done, we can protect our segments back to read-only. - if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { - DL_ERR("can't protect segments for \"%s\": %s", - name, strerror(errno)); - return false; - } + if (has_text_relocations) { + // All relocations are done, we can protect our segments back to read-only. + if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { + DL_ERR("can't protect segments for \"%s\": %s", + name, strerror(errno)); + return false; } + } #endif - /* We can also turn on GNU RELRO protection */ - if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) { - DL_ERR("can't enable GNU RELRO protection for \"%s\": %s", - name, strerror(errno)); - return false; - } + /* We can also turn on GNU RELRO protection */ + if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) { + DL_ERR("can't enable GNU RELRO protection for \"%s\": %s", + name, strerror(errno)); + return false; + } - /* Handle serializing/sharing the RELRO segment */ - if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) { - if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias, - extinfo->relro_fd) < 0) { - DL_ERR("failed serializing GNU RELRO section for \"%s\": %s", - name, strerror(errno)); - return false; - } - } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) { - if (phdr_table_map_gnu_relro(phdr, phnum, load_bias, - extinfo->relro_fd) < 0) { - DL_ERR("failed mapping GNU RELRO section for \"%s\": %s", - name, strerror(errno)); - return false; - } + /* Handle serializing/sharing the RELRO segment */ + if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) { + if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias, + extinfo->relro_fd) < 0) { + DL_ERR("failed serializing GNU RELRO section for \"%s\": %s", + name, strerror(errno)); + return false; } + } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) { + if (phdr_table_map_gnu_relro(phdr, phnum, load_bias, + extinfo->relro_fd) < 0) { + DL_ERR("failed mapping GNU RELRO section for \"%s\": %s", + name, strerror(errno)); + return false; + } + } - notify_gdb_of_load(this); - return true; + notify_gdb_of_load(this); + return true; } /* @@ -2267,182 +2263,182 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) { */ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) { #if TIMING - struct timeval t0, t1; - gettimeofday(&t0, 0); + struct timeval t0, t1; + gettimeofday(&t0, 0); #endif - // Initialize environment functions, and get to the ELF aux vectors table. - linker_env_init(args); + // Initialize environment functions, and get to the ELF aux vectors table. + linker_env_init(args); - // If this is a setuid/setgid program, close the security hole described in - // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc - if (get_AT_SECURE()) { - nullify_closed_stdio(); + // If this is a setuid/setgid program, close the security hole described in + // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc + if (get_AT_SECURE()) { + nullify_closed_stdio(); + } + + debuggerd_init(); + + // Get a few environment variables. + const char* LD_DEBUG = linker_env_get("LD_DEBUG"); + if (LD_DEBUG != nullptr) { + g_ld_debug_verbosity = atoi(LD_DEBUG); + } + + // Normally, these are cleaned by linker_env_init, but the test + // doesn't cost us anything. + const char* ldpath_env = nullptr; + const char* ldpreload_env = nullptr; + if (!get_AT_SECURE()) { + ldpath_env = linker_env_get("LD_LIBRARY_PATH"); + ldpreload_env = linker_env_get("LD_PRELOAD"); + } + + INFO("[ android linker & debugger ]"); + + soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0); + if (si == nullptr) { + exit(EXIT_FAILURE); + } + + /* bootstrap the link map, the main exe always needs to be first */ + si->flags |= FLAG_EXE; + link_map* map = &(si->link_map_head); + + map->l_addr = 0; + map->l_name = args.argv[0]; + map->l_prev = nullptr; + map->l_next = nullptr; + + _r_debug.r_map = map; + r_debug_tail = map; + + init_linker_info_for_gdb(linker_base); + + // Extract information passed from the kernel. + si->phdr = reinterpret_cast(args.getauxval(AT_PHDR)); + si->phnum = args.getauxval(AT_PHNUM); + si->entry = args.getauxval(AT_ENTRY); + + /* Compute the value of si->base. We can't rely on the fact that + * the first entry is the PHDR because this will not be true + * for certain executables (e.g. some in the NDK unit test suite) + */ + si->base = 0; + si->size = phdr_table_get_load_size(si->phdr, si->phnum); + si->load_bias = 0; + for (size_t i = 0; i < si->phnum; ++i) { + if (si->phdr[i].p_type == PT_PHDR) { + si->load_bias = reinterpret_cast(si->phdr) - si->phdr[i].p_vaddr; + si->base = reinterpret_cast(si->phdr) - si->phdr[i].p_offset; + break; } + } + si->dynamic = nullptr; + si->ref_count = 1; - debuggerd_init(); + ElfW(Ehdr)* elf_hdr = reinterpret_cast(si->base); + if (elf_hdr->e_type != ET_DYN) { + __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n"); + exit(EXIT_FAILURE); + } - // Get a few environment variables. - const char* LD_DEBUG = linker_env_get("LD_DEBUG"); - if (LD_DEBUG != nullptr) { - g_ld_debug_verbosity = atoi(LD_DEBUG); - } + // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid). + parse_LD_LIBRARY_PATH(ldpath_env); + parse_LD_PRELOAD(ldpreload_env); - // Normally, these are cleaned by linker_env_init, but the test - // doesn't cost us anything. - const char* ldpath_env = nullptr; - const char* ldpreload_env = nullptr; - if (!get_AT_SECURE()) { - ldpath_env = linker_env_get("LD_LIBRARY_PATH"); - ldpreload_env = linker_env_get("LD_PRELOAD"); - } + somain = si; - INFO("[ android linker & debugger ]"); + si->PrelinkImage(); - soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0); - if (si == nullptr) { - exit(EXIT_FAILURE); - } + // Load ld_preloads and dependencies. + StringLinkedList needed_library_name_list; + size_t needed_libraries_count = 0; + size_t ld_preloads_count = 0; + while (g_ld_preload_names[ld_preloads_count] != nullptr) { + needed_library_name_list.push_back(g_ld_preload_names[ld_preloads_count++]); + ++needed_libraries_count; + } - /* bootstrap the link map, the main exe always needs to be first */ - si->flags |= FLAG_EXE; - link_map* map = &(si->link_map_head); + for_each_dt_needed(si, [&](const char* name) { + needed_library_name_list.push_back(name); + ++needed_libraries_count; + }); - map->l_addr = 0; - map->l_name = args.argv[0]; - map->l_prev = nullptr; - map->l_next = nullptr; + const char* needed_library_names[needed_libraries_count]; + soinfo* needed_library_si[needed_libraries_count]; - _r_debug.r_map = map; - r_debug_tail = map; + memset(needed_library_names, 0, sizeof(needed_library_names)); + needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); - init_linker_info_for_gdb(linker_base); + if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, 0, nullptr)) { + __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); + exit(EXIT_FAILURE); + } - // Extract information passed from the kernel. - si->phdr = reinterpret_cast(args.getauxval(AT_PHDR)); - si->phnum = args.getauxval(AT_PHNUM); - si->entry = args.getauxval(AT_ENTRY); + for (size_t i = 0; iadd_child(needed_library_si[i]); + } - /* Compute the value of si->base. We can't rely on the fact that - * the first entry is the PHDR because this will not be true - * for certain executables (e.g. some in the NDK unit test suite) - */ - si->base = 0; - si->size = phdr_table_get_load_size(si->phdr, si->phnum); - si->load_bias = 0; - for (size_t i = 0; i < si->phnum; ++i) { - if (si->phdr[i].p_type == PT_PHDR) { - si->load_bias = reinterpret_cast(si->phdr) - si->phdr[i].p_vaddr; - si->base = reinterpret_cast(si->phdr) - si->phdr[i].p_offset; - break; - } - } - si->dynamic = nullptr; - si->ref_count = 1; + if (!si->LinkImage(nullptr)) { + __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); + exit(EXIT_FAILURE); + } - ElfW(Ehdr)* elf_hdr = reinterpret_cast(si->base); - if (elf_hdr->e_type != ET_DYN) { - __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n"); - exit(EXIT_FAILURE); - } + add_vdso(args); - // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid). - parse_LD_LIBRARY_PATH(ldpath_env); - parse_LD_PRELOAD(ldpreload_env); + si->CallPreInitConstructors(); - somain = si; - - si->PrelinkImage(); - - // Load ld_preloads and dependencies. - StringLinkedList needed_library_name_list; - size_t needed_libraries_count = 0; - size_t ld_preloads_count = 0; - while (g_ld_preload_names[ld_preloads_count] != nullptr) { - needed_library_name_list.push_back(g_ld_preload_names[ld_preloads_count++]); - ++needed_libraries_count; - } - - for_each_dt_needed(si, [&](const char* name) { - needed_library_name_list.push_back(name); - ++needed_libraries_count; - }); - - const char* needed_library_names[needed_libraries_count]; - soinfo* needed_library_si[needed_libraries_count]; - - memset(needed_library_names, 0, sizeof(needed_library_names)); - needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); - - if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, 0, nullptr)) { - __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); - exit(EXIT_FAILURE); - } - - for (size_t i = 0; iadd_child(needed_library_si[i]); - } - - if (!si->LinkImage(nullptr)) { - __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); - exit(EXIT_FAILURE); - } - - add_vdso(args); - - si->CallPreInitConstructors(); - - /* After the PrelinkImage, the si->load_bias is initialized. - * For so lib, the map->l_addr will be updated in notify_gdb_of_load. - * We need to update this value for so exe here. So Unwind_Backtrace - * for some arch like x86 could work correctly within so exe. - */ - map->l_addr = si->load_bias; - si->CallConstructors(); + /* After the PrelinkImage, the si->load_bias is initialized. + * For so lib, the map->l_addr will be updated in notify_gdb_of_load. + * We need to update this value for so exe here. So Unwind_Backtrace + * for some arch like x86 could work correctly within so exe. + */ + map->l_addr = si->load_bias; + si->CallConstructors(); #if TIMING - gettimeofday(&t1, nullptr); - PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) ( - (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - - (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec))); + gettimeofday(&t1, nullptr); + PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) ( + (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - + (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec))); #endif #if STATS - PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0], - linker_stats.count[kRelocAbsolute], - linker_stats.count[kRelocRelative], - linker_stats.count[kRelocCopy], - linker_stats.count[kRelocSymbol]); + PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0], + linker_stats.count[kRelocAbsolute], + linker_stats.count[kRelocRelative], + linker_stats.count[kRelocCopy], + linker_stats.count[kRelocSymbol]); #endif #if COUNT_PAGES - { - unsigned n; - unsigned i; - unsigned count = 0; - for (n = 0; n < 4096; n++) { - if (bitmask[n]) { - unsigned x = bitmask[n]; + { + unsigned n; + unsigned i; + unsigned count = 0; + for (n = 0; n < 4096; n++) { + if (bitmask[n]) { + unsigned x = bitmask[n]; #if defined(__LP64__) - for (i = 0; i < 32; i++) { + for (i = 0; i < 32; i++) { #else - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) { #endif - if (x & 1) { - count++; - } - x >>= 1; - } - } + if (x & 1) { + count++; + } + x >>= 1; } - PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4); + } } + PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4); + } #endif #if TIMING || STATS || COUNT_PAGES - fflush(stdout); + fflush(stdout); #endif - TRACE("[ Ready to execute '%s' @ %p ]", si->name, reinterpret_cast(si->entry)); - return si->entry; + TRACE("[ Ready to execute '%s' @ %p ]", si->name, reinterpret_cast(si->entry)); + return si->entry; } /* Compute the load-bias of an existing executable. This shall only From c85e82dde5c4b2accc50a9e17740b9005dfbae6a Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 15 Sep 2014 17:00:10 -0700 Subject: [PATCH 068/114] Fix dlsym() to take into account RTLD_GLOBAL/LOCAL Symbols from libraries opened with RTLD_LOCAL (default) should not be visible via dlsym(RLTD_DEFAULT/RTLD_NEXT, .) Bug: 17512583 Bug: 18186310 (cherry picked from commit e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8) Change-Id: Idf6bbe2233fb2bfc0c88677e7d1fc518fb3f7a8b --- linker/dlfcn.cpp | 2 +- linker/linker.cpp | 48 ++++++++++++++++++---------- linker/linker.h | 5 ++- tests/dlfcn_test.cpp | 36 +++++++++++++++++++++ tests/libs/dlopen_testlib_simple.cpp | 2 +- 5 files changed, 73 insertions(+), 20 deletions(-) diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 3631d2fe1..59f673ad5 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -232,7 +232,7 @@ static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 }; static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; #endif -static soinfo __libdl_info("libdl.so", nullptr, 0); +static soinfo __libdl_info("libdl.so", nullptr, 0, RTLD_GLOBAL); // This is used by the dynamic linker. Every process gets these symbols for free. soinfo* get_libdl_info() { diff --git a/linker/linker.cpp b/linker/linker.cpp index 37e01893f..bd05498b0 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -282,13 +282,13 @@ static void protect_data(int protection) { g_soinfo_links_allocator.protect_all(protection); } -static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset) { +static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, int rtld_flags) { if (strlen(name) >= SOINFO_NAME_LEN) { DL_ERR("library name \"%s\" too long", name); return nullptr; } - soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset); + soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags); sonext->next = si; sonext = si; @@ -453,7 +453,7 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) return nullptr; } -soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset) { +soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags) { memset(this, 0, sizeof(*this)); strlcpy(this->name, name, sizeof(this->name)); @@ -465,6 +465,8 @@ soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offs this->st_ino = file_stat->st_ino; this->file_offset = file_offset; } + + this->rtld_flags = rtld_flags; } static unsigned elfhash(const char* _name) { @@ -716,6 +718,10 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) ElfW(Sym)* s = nullptr; for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) { + if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) { + continue; + } + s = soinfo_elf_lookup(si, elf_hash, name); if (s != nullptr) { *found = si; @@ -806,7 +812,7 @@ static void for_each_dt_needed(const soinfo* si, F action) { } } -static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { +static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { int fd = -1; off64_t file_offset = 0; ScopedFd file_guard(-1); @@ -851,7 +857,7 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl } } - if ((dlflags & RTLD_NOLOAD) != 0) { + if ((rtld_flags & RTLD_NOLOAD) != 0) { DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name); return nullptr; } @@ -862,7 +868,7 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl return nullptr; } - soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset); + soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset, rtld_flags); if (si == nullptr) { return nullptr; } @@ -894,7 +900,7 @@ static soinfo *find_loaded_library_by_name(const char* name) { return nullptr; } -static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { +static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { soinfo* si = find_loaded_library_by_name(name); @@ -902,7 +908,7 @@ static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, // of this fact is done by load_library. if (si == nullptr) { TRACE("[ '%s' has not been found by name. Trying harder...]", name); - si = load_library(load_tasks, name, dlflags, extinfo); + si = load_library(load_tasks, name, rtld_flags, extinfo); } return si; @@ -926,7 +932,7 @@ static bool is_recursive(soinfo* si, soinfo* parent) { } static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[], - soinfo* ld_preloads[], size_t ld_preloads_size, int dlflags, const android_dlextinfo* extinfo) { + soinfo* ld_preloads[], size_t ld_preloads_size, int rtld_flags, const android_dlextinfo* extinfo) { // Step 0: prepare. LoadTaskList load_tasks; for (size_t i = 0; i < library_names_size; ++i) { @@ -952,7 +958,7 @@ static bool find_libraries(const char* const library_names[], size_t library_nam // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order. for (LoadTask::unique_ptr task(load_tasks.pop_front()); task.get() != nullptr; task.reset(load_tasks.pop_front())) { - soinfo* si = find_library_internal(load_tasks, task->get_name(), dlflags, extinfo); + soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo); if (si == nullptr) { return false; } @@ -997,7 +1003,7 @@ static bool find_libraries(const char* const library_names[], size_t library_nam return true; } -static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { +static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) { if (name == nullptr) { somain->ref_count++; return somain; @@ -1005,7 +1011,7 @@ static soinfo* find_library(const char* name, int dlflags, const android_dlextin soinfo* si; - if (!find_libraries(&name, 1, &si, nullptr, 0, dlflags, extinfo)) { + if (!find_libraries(&name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { return nullptr; } @@ -1790,6 +1796,14 @@ off64_t soinfo::get_file_offset() { return 0; } +int soinfo::get_rtld_flags() { + if (has_min_version(1)) { + return rtld_flags; + } + + return 0; +} + // This is a return on get_children()/get_parents() if // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -2210,7 +2224,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { return; } - soinfo* si = soinfo_alloc("[vdso]", nullptr, 0); + soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0); si->phdr = reinterpret_cast(reinterpret_cast(ehdr_vdso) + ehdr_vdso->e_phoff); si->phnum = ehdr_vdso->e_phnum; @@ -2231,7 +2245,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { #else #define LINKER_PATH "/system/bin/linker" #endif -static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0); +static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0, 0); /* gdb expects the linker to be in the debug shared object list. * Without this, gdb has trouble locating the linker's ".text" @@ -2295,7 +2309,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( INFO("[ android linker & debugger ]"); - soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0); + soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL); if (si == nullptr) { exit(EXIT_FAILURE); } @@ -2370,7 +2384,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( memset(needed_library_names, 0, sizeof(needed_library_names)); needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); - if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, 0, nullptr)) { + if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); } @@ -2483,7 +2497,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_addr); ElfW(Phdr)* phdr = reinterpret_cast(linker_addr + elf_hdr->e_phoff); - soinfo linker_so("[dynamic linker]", nullptr, 0); + soinfo linker_so("[dynamic linker]", nullptr, 0, 0); // If the linker is not acting as PT_INTERP entry_point is equal to // _start. Which means that the linker is running as an executable and diff --git a/linker/linker.h b/linker/linker.h index 3b140ac24..ef2fbcd6c 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -199,7 +199,7 @@ struct soinfo { #endif bool has_DT_SYMBOLIC; - soinfo(const char* name, const struct stat* file_stat, off64_t file_offset); + soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags); void CallConstructors(); void CallDestructors(); @@ -214,6 +214,8 @@ struct soinfo { dev_t get_st_dev(); off64_t get_file_offset(); + int get_rtld_flags(); + soinfo_list_t& get_children(); soinfo_list_t& get_parents(); @@ -246,6 +248,7 @@ struct soinfo { // version >= 1 off64_t file_offset; + int rtld_flags; }; extern soinfo* get_libdl_info(); diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 9c9fbdd12..a55b36420 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -202,6 +202,42 @@ TEST(dlfcn, dlopen_check_order) { dlclose(handle); } +TEST(dlfcn, dlopen_check_rtld_local) { + void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym == nullptr); + + // implicit RTLD_LOCAL + void* handle = dlopen("libtest_simple.so", RTLD_NOW); + sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym == nullptr); + ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror()); + sym = dlsym(handle, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym != nullptr); + ASSERT_TRUE(reinterpret_cast(sym)()); + dlclose(handle); + + // explicit RTLD_LOCAL + handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL); + sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym == nullptr); + ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror()); + sym = dlsym(handle, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym != nullptr); + ASSERT_TRUE(reinterpret_cast(sym)()); + dlclose(handle); +} + +TEST(dlfcn, dlopen_check_rtld_global) { + void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym == nullptr); + + void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL); + sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym != nullptr) << dlerror(); + ASSERT_TRUE(reinterpret_cast(sym)()); + dlclose(handle); +} + // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> // libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so -> // libtest_with_dependency_loop_a.so diff --git a/tests/libs/dlopen_testlib_simple.cpp b/tests/libs/dlopen_testlib_simple.cpp index afe54b4c0..06253e1f4 100644 --- a/tests/libs/dlopen_testlib_simple.cpp +++ b/tests/libs/dlopen_testlib_simple.cpp @@ -18,6 +18,6 @@ uint32_t dlopen_testlib_taxicab_number = 1729; -bool dlopen_testlib_simple_func() { +extern "C" bool dlopen_testlib_simple_func() { return true; } From b364d9538073716a256b37a790ff7bf3ddbb4f1b Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 16 Sep 2014 14:31:06 -0700 Subject: [PATCH 069/114] Remove has_DT_SYMBOLIC flag From the elf-spec: "Symbolically bound shared objects are identified by the .dynamic entry DT_SYMBOLIC. This tag is informational only; the runtime linker processes symbol lookups from these objects in the same manner as any other object." Bug: 18186310 (cherry picked from commit 8f61d991831f0ea515fa50a5c38dbbcfbab0dd28) Change-Id: I37024799ac8d1837993c8ae78780a448bedd6539 --- linker/dlfcn.cpp | 1 - linker/linker.cpp | 131 ++++++++++++++-------------------------------- linker/linker.h | 2 +- 3 files changed, 40 insertions(+), 94 deletions(-) diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 59f673ad5..c02bfb89a 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -244,7 +244,6 @@ soinfo* get_libdl_info() { __libdl_info.nchain = sizeof(g_libdl_chains)/sizeof(unsigned); __libdl_info.bucket = g_libdl_buckets; __libdl_info.chain = g_libdl_chains; - __libdl_info.has_DT_SYMBOLIC = true; __libdl_info.ref_count = 1; } diff --git a/linker/linker.cpp b/linker/linker.cpp index bd05498b0..246475b4e 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -487,117 +487,65 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { ElfW(Sym)* s = nullptr; if (somain != nullptr) { - /* - * Local scope is executable scope. Just start looking into it right away - * for the shortcut. - */ + DEBUG("%s: looking up %s in executable %s", + si->name, name, somain->name); - if (si == somain) { - s = soinfo_elf_lookup(si, elf_hash, name); - if (s != nullptr) { - *lsi = si; - goto done; - } + // 1. Look for it in the main executable + s = soinfo_elf_lookup(somain, elf_hash, name); + if (s != nullptr) { + *lsi = somain; + } - /* Next, look for it in the preloads list */ + // 2. Look for it in the ld_preloads + if (s == nullptr) { for (int i = 0; g_ld_preloads[i] != NULL; i++) { s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); - if (s != NULL) { - *lsi = g_ld_preloads[i]; - goto done; - } - } - } else { - /* Order of symbol lookup is controlled by DT_SYMBOLIC flag */ - - /* - * If this object was built with symbolic relocations disabled, the - * first place to look to resolve external references is the main - * executable. - */ - - if (!si->has_DT_SYMBOLIC) { - DEBUG("%s: looking up %s in executable %s", - si->name, name, somain->name); - s = soinfo_elf_lookup(somain, elf_hash, name); if (s != nullptr) { - *lsi = somain; - goto done; - } - - /* Next, look for it in the preloads list */ - for (int i = 0; g_ld_preloads[i] != NULL; i++) { - s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); - if (s != NULL) { - *lsi = g_ld_preloads[i]; - goto done; - } + *lsi = g_ld_preloads[i]; + break; } } + } - /* Look for symbols in the local scope (the object who is - * searching). This happens with C++ templates on x86 for some - * reason. - * - * Notes on weak symbols: - * The ELF specs are ambiguous about treatment of weak definitions in - * dynamic linking. Some systems return the first definition found - * and some the first non-weak definition. This is system dependent. - * Here we return the first definition found for simplicity. */ + /* Look for symbols in the local scope (the object who is + * searching). This happens with C++ templates on x86 for some + * reason. + * + * Notes on weak symbols: + * The ELF specs are ambiguous about treatment of weak definitions in + * dynamic linking. Some systems return the first definition found + * and some the first non-weak definition. This is system dependent. + * Here we return the first definition found for simplicity. */ + if (s == nullptr) { s = soinfo_elf_lookup(si, elf_hash, name); if (s != nullptr) { *lsi = si; - goto done; - } - - /* - * If this object was built with -Bsymbolic and symbol is not found - * in the local scope, try to find the symbol in the main executable. - */ - - if (si->has_DT_SYMBOLIC) { - DEBUG("%s: looking up %s in executable %s after local scope", - si->name, name, somain->name); - s = soinfo_elf_lookup(somain, elf_hash, name); - if (s != nullptr) { - *lsi = somain; - goto done; - } - - /* Next, look for it in the preloads list */ - for (int i = 0; g_ld_preloads[i] != NULL; i++) { - s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); - if (s != NULL) { - *lsi = g_ld_preloads[i]; - goto done; - } - } } } } - si->get_children().visit([&](soinfo* child) { - DEBUG("%s: looking up %s in %s", si->name, name, child->name); - s = soinfo_elf_lookup(child, elf_hash, name); - if (s != nullptr) { - *lsi = child; - return false; - } - return true; - }); + if (s == nullptr) { + si->get_children().visit([&](soinfo* child) { + DEBUG("%s: looking up %s in %s", si->name, name, child->name); + s = soinfo_elf_lookup(child, elf_hash, name); + if (s != nullptr) { + *lsi = child; + return false; + } + return true; + }); + } -done: if (s != nullptr) { TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " "found in %s, base = %p, load bias = %p", si->name, name, reinterpret_cast(s->st_value), (*lsi)->name, reinterpret_cast((*lsi)->base), reinterpret_cast((*lsi)->load_bias)); - return s; } - return nullptr; + return s; } // Each size has it's own allocator. @@ -2042,7 +1990,7 @@ bool soinfo::PrelinkImage() { break; #endif case DT_SYMBOLIC: - has_DT_SYMBOLIC = true; + // ignored break; case DT_NEEDED: ++needed_count; @@ -2056,9 +2004,6 @@ bool soinfo::PrelinkImage() { has_text_relocations = true; #endif } - if (d->d_un.d_val & DF_SYMBOLIC) { - has_DT_SYMBOLIC = true; - } break; #if defined(__mips__) case DT_STRSZ: @@ -2092,8 +2037,10 @@ bool soinfo::PrelinkImage() { #endif default: - DEBUG("Unused DT entry: type %p arg %p", - reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); + if (!relocating_linker) { + DL_WARN("%s: unused DT entry: type %p arg %p", name, + reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); + } break; } } diff --git a/linker/linker.h b/linker/linker.h index ef2fbcd6c..e39585006 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -197,7 +197,7 @@ struct soinfo { #if !defined(__LP64__) bool has_text_relocations; #endif - bool has_DT_SYMBOLIC; + bool unused4; // DO NOT USE, maintained for compatibility soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags); From 634a045c5c2ca1df35f582ed24bb3af0dc1d7151 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 16 Sep 2014 15:51:25 -0700 Subject: [PATCH 070/114] Fix some unused DT_ warnings * DT_PLTGOT - ignored for non-mips * DT_RELCOUNT/RELACOUNT - ignored * DT_RELENT/RELAENT - sanity checks * DT_SYMENT - sanity check * DT_SONAME - ignore for now. Bug: 18186310 (cherry picked from commit 4a6e9a835a84aca965f0170f604381dae7f130be) Change-Id: Ib40095f0770d65628fc7abac5a471378de35ebe7 --- linker/linker.cpp | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 246475b4e..875335f6c 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -1875,6 +1875,10 @@ bool soinfo::PrelinkImage() { DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", d, reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); switch (d->d_tag) { + case DT_SONAME: + // TODO: glibc dynamic linker uses this name for + // initial library lookup; consider doing the same here. + break; case DT_HASH: nbucket = reinterpret_cast(load_bias + d->d_un.d_ptr)[0]; nchain = reinterpret_cast(load_bias + d->d_un.d_ptr)[1]; @@ -1887,6 +1891,12 @@ bool soinfo::PrelinkImage() { case DT_SYMTAB: symtab = reinterpret_cast(load_bias + d->d_un.d_ptr); break; + case DT_SYMENT: + if (d->d_un.d_val != sizeof(ElfW(Sym))) { + DL_ERR("invalid DT_SYMENT: %d", d->d_un.d_val); + return false; + } + break; #if !defined(__LP64__) case DT_PLTREL: if (d->d_un.d_val != DT_REL) { @@ -1909,12 +1919,13 @@ bool soinfo::PrelinkImage() { plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); #endif break; -#if defined(__mips__) case DT_PLTGOT: +#if defined(__mips__) // Used by mips and mips64. plt_got = reinterpret_cast(load_bias + d->d_un.d_ptr); - break; #endif + // Ignore for other platforms... (because RTLD_LAZY is not supported) + break; case DT_DEBUG: // Set the DT_DEBUG entry to the address of _r_debug for GDB // if the dynamic table is writable @@ -1935,6 +1946,15 @@ bool soinfo::PrelinkImage() { case DT_RELASZ: rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); break; + case DT_RELAENT: + if (d->d_un.d_val != sizeof(ElfW(Rela))) { + DL_ERR("invalid DT_RELAENT: %d", d->d_un.d_val); + return false; + } + break; + case DT_RELACOUNT: + // ignored (see DT_RELCOUNT comments for details) + break; case DT_REL: DL_ERR("unsupported DT_REL in \"%s\"", name); return false; @@ -1948,6 +1968,19 @@ bool soinfo::PrelinkImage() { case DT_RELSZ: rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); break; + case DT_RELENT: + if (d->d_un.d_val != sizeof(ElfW(Rel))) { + DL_ERR("invalid DT_RELENT: %d", d->d_un.d_val); + return false; + } + break; + case DT_RELCOUNT: + // "Indicates that all RELATIVE relocations have been concatenated together, + // and specifies the RELATIVE relocation count." + // + // TODO: Spec also mentions that this can be used to optimize relocation process; + // Not currently used by bionic linker - ignored. + break; case DT_RELA: DL_ERR("unsupported DT_RELA in \"%s\"", name); return false; @@ -2007,8 +2040,6 @@ bool soinfo::PrelinkImage() { break; #if defined(__mips__) case DT_STRSZ: - case DT_SYMENT: - case DT_RELENT: break; case DT_MIPS_RLD_MAP: // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. From 09608848edf42fb999d08e59c8c81a62a79a6941 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 16 Sep 2014 23:34:20 -0700 Subject: [PATCH 071/114] Fix 64bit build Bug: 18186310 (cherry picked from commit f240aa8089ea1574a7d799720efb66528f6ceb99) Change-Id: Id46f1f9be90a17a58fb44d3540095c8c685c9726 --- linker/linker.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 875335f6c..f8974eb6c 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -1893,7 +1893,7 @@ bool soinfo::PrelinkImage() { break; case DT_SYMENT: if (d->d_un.d_val != sizeof(ElfW(Sym))) { - DL_ERR("invalid DT_SYMENT: %d", d->d_un.d_val); + DL_ERR("invalid DT_SYMENT: %zd", static_cast(d->d_un.d_val)); return false; } break; @@ -1948,7 +1948,7 @@ bool soinfo::PrelinkImage() { break; case DT_RELAENT: if (d->d_un.d_val != sizeof(ElfW(Rela))) { - DL_ERR("invalid DT_RELAENT: %d", d->d_un.d_val); + DL_ERR("invalid DT_RELAENT: %zd", static_cast(d->d_un.d_val)); return false; } break; @@ -1970,7 +1970,7 @@ bool soinfo::PrelinkImage() { break; case DT_RELENT: if (d->d_un.d_val != sizeof(ElfW(Rel))) { - DL_ERR("invalid DT_RELENT: %d", d->d_un.d_val); + DL_ERR("invalid DT_RELENT: %zd", static_cast(d->d_un.d_val)); return false; } break; From d5eb10875affb316c4dfc3b6ceb91df244518956 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Wed, 17 Sep 2014 16:46:40 -0700 Subject: [PATCH 072/114] Temporary disable DL_WARNs for unused DT_* Bug: 17552334 Bug: 18186310 (cherry picked from commit 1b77423eff21e916186fcb208f138e436e9f3052) Change-Id: I8a9d05195a862bc287fff7156913606f0311b8bb --- linker/linker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index f8974eb6c..c3178cba4 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -2069,7 +2069,7 @@ bool soinfo::PrelinkImage() { default: if (!relocating_linker) { - DL_WARN("%s: unused DT entry: type %p arg %p", name, + DEBUG("%s: unused DT entry: type %p arg %p", name, reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); } break; From 748fbe5c41d97433dc756a50812e1caf6a6ef727 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 22 Sep 2014 17:43:09 -0700 Subject: [PATCH 073/114] Fix a couple more cases of missing CLOEXEC. The debuggerd case can probably never happen, because you're crashing at this point anyway. The system property one seems possible though. Bug: 18186310 (cherry picked from commit 0dc39f9952c5e3a3121ea77357bb264ef0f8ded7) Change-Id: I3e84488fc246f6c28cbd82e96d0cd4343a12c28a --- libc/bionic/system_properties.cpp | 4 ++-- linker/debugger.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp index a564c3939..0e16bf314 100644 --- a/libc/bionic/system_properties.cpp +++ b/libc/bionic/system_properties.cpp @@ -475,8 +475,8 @@ static const prop_info *find_property(prop_bt *const trie, const char *name, static int send_prop_msg(const prop_msg *msg) { - const int fd = socket(AF_LOCAL, SOCK_STREAM, 0); - if (fd < 0) { + const int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd == -1) { return -1; } diff --git a/linker/debugger.cpp b/linker/debugger.cpp index 6565985b5..ac466a5b4 100644 --- a/linker/debugger.cpp +++ b/linker/debugger.cpp @@ -215,7 +215,7 @@ static void send_debuggerd_packet(siginfo_t* info) { return; } - int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM); + int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM | SOCK_CLOEXEC); if (s == -1) { __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s", strerror(errno)); From f90e21004e57e46b49c3338781eb3d58cc4bb517 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 29 Sep 2014 12:10:36 -0700 Subject: [PATCH 074/114] Return has_DT_SYMBOLIC flag. This reverts commit 8f61d991831f0ea515fa50a5c38dbbcfbab0dd28 Despite the fact that static linker does all the work while linking -Bsymbolic executables, according to the SCO doc following DT_SYMBOLIC and DF_SYMBOLIC flags is still a requirement for the dynamic linker as well. (see http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html) Bug: 18186310 (cherry picked from commit 96bc37f2e1093416a432135265fd7a4db6c3df17) Change-Id: Ie217be4f3305d877066e4cfe91975ae1c7768330 --- linker/linker.cpp | 68 ++++++++++++++++++++++++++++++++--------------- linker/linker.h | 2 +- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index c3178cba4..30731090c 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -486,14 +486,34 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { unsigned elf_hash = elfhash(name); ElfW(Sym)* s = nullptr; - if (somain != nullptr) { - DEBUG("%s: looking up %s in executable %s", - si->name, name, somain->name); - - // 1. Look for it in the main executable - s = soinfo_elf_lookup(somain, elf_hash, name); + /* "This element's presence in a shared object library alters the dynamic linker's + * symbol resolution algorithm for references within the library. Instead of starting + * a symbol search with the executable file, the dynamic linker starts from the shared + * object itself. If the shared object fails to supply the referenced symbol, the + * dynamic linker then searches the executable file and other shared objects as usual." + * + * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html + * + * Note that this is unlikely since static linker avoids generating + * relocations for -Bsymbolic linked dynamic executables. + */ + if (si->has_DT_SYMBOLIC) { + DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si->name, name); + s = soinfo_elf_lookup(si, elf_hash, name); if (s != nullptr) { - *lsi = somain; + *lsi = si; + } + } + + if (s == nullptr && somain != nullptr) { + // 1. Look for it in the main executable unless we already did. + if (si != somain || !si->has_DT_SYMBOLIC) { + DEBUG("%s: looking up %s in executable %s", + si->name, name, somain->name); + s = soinfo_elf_lookup(somain, elf_hash, name); + if (s != nullptr) { + *lsi = somain; + } } // 2. Look for it in the ld_preloads @@ -506,22 +526,23 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { } } } + } - /* Look for symbols in the local scope (the object who is - * searching). This happens with C++ templates on x86 for some - * reason. - * - * Notes on weak symbols: - * The ELF specs are ambiguous about treatment of weak definitions in - * dynamic linking. Some systems return the first definition found - * and some the first non-weak definition. This is system dependent. - * Here we return the first definition found for simplicity. */ + /* Look for symbols in the local scope (the object who is + * searching). This happens with C++ templates on x86 for some + * reason. + * + * Notes on weak symbols: + * The ELF specs are ambiguous about treatment of weak definitions in + * dynamic linking. Some systems return the first definition found + * and some the first non-weak definition. This is system dependent. + * Here we return the first definition found for simplicity. */ - if (s == nullptr) { - s = soinfo_elf_lookup(si, elf_hash, name); - if (s != nullptr) { - *lsi = si; - } + if (s == nullptr && !si->has_DT_SYMBOLIC) { + DEBUG("%s: looking up %s in local scope", si->name, name); + s = soinfo_elf_lookup(si, elf_hash, name); + if (s != nullptr) { + *lsi = si; } } @@ -2023,7 +2044,7 @@ bool soinfo::PrelinkImage() { break; #endif case DT_SYMBOLIC: - // ignored + has_DT_SYMBOLIC = true; break; case DT_NEEDED: ++needed_count; @@ -2037,6 +2058,9 @@ bool soinfo::PrelinkImage() { has_text_relocations = true; #endif } + if (d->d_un.d_val & DF_SYMBOLIC) { + has_DT_SYMBOLIC = true; + } break; #if defined(__mips__) case DT_STRSZ: diff --git a/linker/linker.h b/linker/linker.h index e39585006..ef2fbcd6c 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -197,7 +197,7 @@ struct soinfo { #if !defined(__LP64__) bool has_text_relocations; #endif - bool unused4; // DO NOT USE, maintained for compatibility + bool has_DT_SYMBOLIC; soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags); From 0f47d9c1ce3e75709f9d6ecb6b540bb518ee323a Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 29 Sep 2014 19:14:45 -0700 Subject: [PATCH 075/114] Fix unused DT entry warnings. DT_STRSZ Implement strtab boundary checks DT_FLAGS_1 Warn if flags other than DF_1_NOW|DF_1_GLOBAL are set Bug: 17552334 Bug: 18186310 (cherry picked from commit 6cdeb5234d7f4523fe9d83974f265d80f10512a6) Change-Id: I7ffc7bc600798308a77ad949a644949b64250ae2 --- libc/include/elf.h | 29 +++++++++++++++++++++++++++++ linker/dlfcn.cpp | 3 ++- linker/linker.cpp | 34 +++++++++++++++++++++++++++------- linker/linker.h | 9 ++++++++- 4 files changed, 66 insertions(+), 9 deletions(-) diff --git a/libc/include/elf.h b/libc/include/elf.h index 7a9485aea..7de464e0f 100644 --- a/libc/include/elf.h +++ b/libc/include/elf.h @@ -54,6 +54,35 @@ typedef struct { #define DF_BIND_NOW 0x00000008 #define DF_STATIC_TLS 0x00000010 +#define DF_1_NOW 0x00000001 // Perform complete relocation processing. +#define DF_1_GLOBAL 0x00000002 // implies RTLD_GLOBAL +#define DF_1_GROUP 0x00000004 +#define DF_1_NODELETE 0x00000008 // implies RTLD_NODELETE +#define DF_1_LOADFLTR 0x00000010 +#define DF_1_INITFIRST 0x00000020 +#define DF_1_NOOPEN 0x00000040 // Object can not be used with dlopen(3) +#define DF_1_ORIGIN 0x00000080 +#define DF_1_DIRECT 0x00000100 +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 +#define DF_1_NODEFLIB 0x00000800 +#define DF_1_NODUMP 0x00001000 // Object cannot be dumped with dldump(3) +#define DF_1_CONFALT 0x00002000 +#define DF_1_ENDFILTEE 0x00004000 +#define DF_1_DISPRELDNE 0x00008000 +#define DF_1_DISPRELPND 0x00010000 +#define DF_1_NODIRECT 0x00020000 +#define DF_1_IGNMULDEF 0x00040000 // Internal use +#define DF_1_NOKSYMS 0x00080000 // Internal use +#define DF_1_NOHDR 0x00100000 // Internal use +#define DF_1_EDITED 0x00200000 +#define DF_1_NORELOC 0x00400000 // Internal use +#define DF_1_SYMINTPOSE 0x00800000 +#define DF_1_GLOBAUDIT 0x01000000 +#define DF_1_SINGLETON 0x02000000 +#define DF_1_STUB 0x04000000 +#define DF_1_PIE 0x08000000 + #define DT_BIND_NOW 24 #define DT_INIT_ARRAY 25 #define DT_FINI_ARRAY 26 diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index c02bfb89a..367179d8d 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -147,7 +147,7 @@ int dladdr(const void* addr, Dl_info* info) { // Determine if any symbol in the library contains the specified address. ElfW(Sym)* sym = dladdr_find_symbol(si, addr); if (sym != nullptr) { - info->dli_sname = si->strtab + sym->st_name; + info->dli_sname = si->get_string(sym->st_name); info->dli_saddr = reinterpret_cast(si->resolve_symbol_address(sym)); } @@ -245,6 +245,7 @@ soinfo* get_libdl_info() { __libdl_info.bucket = g_libdl_buckets; __libdl_info.chain = g_libdl_chains; __libdl_info.ref_count = 1; + __libdl_info.strtab_size = sizeof(ANDROID_LIBDL_STRTAB); } return &__libdl_info; diff --git a/linker/linker.cpp b/linker/linker.cpp index 30731090c..9e26cf840 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -417,14 +417,13 @@ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) { ElfW(Sym)* symtab = si->symtab; - const char* strtab = si->strtab; TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd", name, si->name, reinterpret_cast(si->base), hash, hash % si->nbucket); for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) { ElfW(Sym)* s = symtab + n; - if (strcmp(strtab + s->st_name, name)) continue; + if (strcmp(si->get_string(s->st_name), name)) continue; // only concern ourselves with global and weak symbol definitions switch (ELF_ST_BIND(s->st_info)) { @@ -776,7 +775,7 @@ template static void for_each_dt_needed(const soinfo* si, F action) { for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { if (d->d_tag == DT_NEEDED) { - action(si->strtab + d->d_un.d_val); + action(si->get_string(d->d_un.d_val)); } } } @@ -1103,7 +1102,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { soinfo* lsi = nullptr; if (sym != 0) { - sym_name = reinterpret_cast(strtab + symtab[sym].st_name); + sym_name = get_string(symtab[sym].st_name); s = soinfo_do_lookup(this, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... @@ -1381,7 +1380,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { soinfo* lsi = nullptr; if (sym != 0) { - sym_name = reinterpret_cast(strtab + symtab[sym].st_name); + sym_name = get_string(symtab[sym].st_name); s = soinfo_do_lookup(this, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... @@ -1599,7 +1598,7 @@ static bool mips_relocate_got(soinfo* si) { got = si->plt_got + local_gotno; for (size_t g = gotsym; g < symtabno; g++, sym++, got++) { // This is an undefined reference... try to locate it. - const char* sym_name = si->strtab + sym->st_name; + const char* sym_name = si->get_string(sym->st_name); soinfo* lsi = nullptr; ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); if (s == nullptr) { @@ -1801,6 +1800,14 @@ ElfW(Addr) soinfo::resolve_symbol_address(ElfW(Sym)* s) { return static_cast(s->st_value + load_bias); } +const char* soinfo::get_string(ElfW(Word) index) const { + if (has_min_version(1) && (index >= strtab_size)) { + __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d", name, strtab_size, index); + } + + return strtab + index; +} + /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -1909,6 +1916,9 @@ bool soinfo::PrelinkImage() { case DT_STRTAB: strtab = reinterpret_cast(load_bias + d->d_un.d_ptr); break; + case DT_STRSZ: + strtab_size = d->d_un.d_val; + break; case DT_SYMTAB: symtab = reinterpret_cast(load_bias + d->d_un.d_ptr); break; @@ -2062,6 +2072,16 @@ bool soinfo::PrelinkImage() { has_DT_SYMBOLIC = true; } break; + case DT_FLAGS_1: + if ((d->d_un.d_val & DF_1_GLOBAL) != 0) { + rtld_flags |= RTLD_GLOBAL; + } + // TODO: Implement other flags + + if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL)) != 0) { + DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast(d->d_un.d_val)); + } + break; #if defined(__mips__) case DT_STRSZ: break; @@ -2093,7 +2113,7 @@ bool soinfo::PrelinkImage() { default: if (!relocating_linker) { - DEBUG("%s: unused DT entry: type %p arg %p", name, + DL_WARN("%s: unused DT entry: type %p arg %p", name, reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); } break; diff --git a/linker/linker.h b/linker/linker.h index ef2fbcd6c..6329efda6 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -136,7 +136,9 @@ struct soinfo { soinfo* next; unsigned flags; + private: const char* strtab; + public: ElfW(Sym)* symtab; size_t nbucket; @@ -221,7 +223,9 @@ struct soinfo { ElfW(Addr) resolve_symbol_address(ElfW(Sym)* s); - bool inline has_min_version(uint32_t min_version) { + const char* get_string(ElfW(Word) index) const; + + bool inline has_min_version(uint32_t min_version) const { return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; } private: @@ -249,6 +253,9 @@ struct soinfo { // version >= 1 off64_t file_offset; int rtld_flags; + size_t strtab_size; + + friend soinfo* get_libdl_info(); }; extern soinfo* get_libdl_info(); From 210ff1b27b67bd2aa29b35a46f48430b7714a802 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 30 Sep 2014 16:30:22 -0700 Subject: [PATCH 076/114] Fix mips build Bug: 18186310 (cherry picked from commit ecf532fa1cfe91ca946243c11ef154c602870ba6) Change-Id: Ia12f2fa28c8cd3204eb7d6b4c7d872f4e81fb8ef --- linker/linker.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 9e26cf840..d918bb56e 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -2083,8 +2083,6 @@ bool soinfo::PrelinkImage() { } break; #if defined(__mips__) - case DT_STRSZ: - break; case DT_MIPS_RLD_MAP: // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. { From c87f65d2cd0690d81665f8b241c1d763f72b6f80 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 19 May 2014 15:06:58 -0700 Subject: [PATCH 077/114] Add RTLD_NODELETE flag support Bug: 18186310 Bug: https://code.google.com/p/android/issues/detail?id=64069 (cherry picked from commit 1b20dafdbe65e43b9f4c95057e8482380833ea91) Change-Id: Ic02eec22a7c322ece65eb40730a3404f611526b1 --- libc/include/dlfcn.h | 1 + linker/linker.cpp | 16 ++++- linker/linker.h | 18 ++--- tests/dlfcn_test.cpp | 80 +++++++++++++++++++++++ tests/libs/Android.mk | 29 ++++++++ tests/libs/dlopen_nodelete_1.cpp | 31 +++++++++ tests/libs/dlopen_nodelete_2.cpp | 31 +++++++++ tests/libs/dlopen_nodelete_dt_flags_1.cpp | 30 +++++++++ 8 files changed, 226 insertions(+), 10 deletions(-) create mode 100644 tests/libs/dlopen_nodelete_1.cpp create mode 100644 tests/libs/dlopen_nodelete_2.cpp create mode 100644 tests/libs/dlopen_nodelete_dt_flags_1.cpp diff --git a/libc/include/dlfcn.h b/libc/include/dlfcn.h index 8dde08cf5..afa76878f 100644 --- a/libc/include/dlfcn.h +++ b/libc/include/dlfcn.h @@ -64,6 +64,7 @@ enum { RTLD_GLOBAL = 2, #endif RTLD_NOLOAD = 4, + RTLD_NODELETE = 0x01000, }; #if defined (__LP64__) diff --git a/linker/linker.cpp b/linker/linker.cpp index d918bb56e..7b27cd79e 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -987,6 +987,11 @@ static soinfo* find_library(const char* name, int rtld_flags, const android_dlex } static void soinfo_unload(soinfo* si) { + if (!si->can_unload()) { + TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->name); + return; + } + if (si->ref_count == 1) { TRACE("unloading '%s'", si->name); si->CallDestructors(); @@ -1045,7 +1050,7 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) { } soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) { - if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NOLOAD)) != 0) { + if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) { DL_ERR("invalid flags to dlopen: %x", flags); return nullptr; } @@ -1808,6 +1813,9 @@ const char* soinfo::get_string(ElfW(Word) index) const { return strtab + index; } +bool soinfo::can_unload() const { + return (rtld_flags & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; +} /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -2076,9 +2084,13 @@ bool soinfo::PrelinkImage() { if ((d->d_un.d_val & DF_1_GLOBAL) != 0) { rtld_flags |= RTLD_GLOBAL; } + + if ((d->d_un.d_val & DF_1_NODELETE) != 0) { + rtld_flags |= RTLD_NODELETE; + } // TODO: Implement other flags - if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL)) != 0) { + if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)) != 0) { DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast(d->d_un.d_val)); } break; diff --git a/linker/linker.h b/linker/linker.h index 6329efda6..ebb4793af 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -134,7 +134,7 @@ struct soinfo { #endif soinfo* next; - unsigned flags; + uint32_t flags; private: const char* strtab; @@ -143,8 +143,8 @@ struct soinfo { size_t nbucket; size_t nchain; - unsigned* bucket; - unsigned* chain; + uint32_t* bucket; + uint32_t* chain; #if defined(__mips__) || !defined(__LP64__) // This is only used by mips and mips64, but needs to be here for @@ -179,12 +179,12 @@ struct soinfo { #if defined(__arm__) // ARM EABI section used for stack unwinding. - unsigned* ARM_exidx; + uint32_t* ARM_exidx; size_t ARM_exidx_count; #elif defined(__mips__) - unsigned mips_symtabno; - unsigned mips_local_gotno; - unsigned mips_gotsym; + uint32_t mips_symtabno; + uint32_t mips_local_gotno; + uint32_t mips_gotsym; #endif size_t ref_count; @@ -224,10 +224,12 @@ struct soinfo { ElfW(Addr) resolve_symbol_address(ElfW(Sym)* s); const char* get_string(ElfW(Word) index) const; + bool can_unload() const; bool inline has_min_version(uint32_t min_version) const { return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; } + private: void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); @@ -258,7 +260,7 @@ struct soinfo { friend soinfo* get_libdl_info(); }; -extern soinfo* get_libdl_info(); +soinfo* get_libdl_info(); void do_android_get_LD_LIBRARY_PATH(char*, size_t); void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path); diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index a55b36420..e7787b4a4 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -232,10 +232,15 @@ TEST(dlfcn, dlopen_check_rtld_global) { ASSERT_TRUE(sym == nullptr); void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); ASSERT_TRUE(sym != nullptr) << dlerror(); ASSERT_TRUE(reinterpret_cast(sym)()); dlclose(handle); + + // RTLD_GLOBAL implies RTLD_NODELETE, let's check that + void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_EQ(sym, sym_after_dlclose); } // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> @@ -258,6 +263,81 @@ TEST(dlfcn, dlopen_check_loop) { ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); } +TEST(dlfcn, dlopen_nodelete) { + static bool is_unloaded = false; + + void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE); + ASSERT_TRUE(handle != nullptr) << dlerror(); + void (*set_unload_flag_ptr)(bool*); + set_unload_flag_ptr = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr")); + ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); + set_unload_flag_ptr(&is_unloaded); + + uint32_t* taxicab_number = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); + ASSERT_TRUE(taxicab_number != nullptr) << dlerror(); + ASSERT_EQ(1729U, *taxicab_number); + *taxicab_number = 2; + + dlclose(handle); + ASSERT_TRUE(!is_unloaded); + + uint32_t* taxicab_number_after_dlclose = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); + ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number); + ASSERT_EQ(2U, *taxicab_number_after_dlclose); + + + handle = dlopen("libtest_nodelete_1.so", RTLD_NOW); + uint32_t* taxicab_number2 = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); + ASSERT_EQ(taxicab_number2, taxicab_number); + + ASSERT_EQ(2U, *taxicab_number2); + + dlclose(handle); + ASSERT_TRUE(!is_unloaded); +} + +TEST(dlfcn, dlopen_nodelete_on_second_dlopen) { + static bool is_unloaded = false; + + void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr) << dlerror(); + void (*set_unload_flag_ptr)(bool*); + set_unload_flag_ptr = reinterpret_cast(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr")); + ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); + set_unload_flag_ptr(&is_unloaded); + + uint32_t* taxicab_number = reinterpret_cast(dlsym(handle, "dlopen_nodelete_2_taxicab_number")); + ASSERT_TRUE(taxicab_number != nullptr) << dlerror(); + + ASSERT_EQ(1729U, *taxicab_number); + *taxicab_number = 2; + + // This RTLD_NODELETE should be ignored + void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE); + ASSERT_TRUE(handle1 != nullptr) << dlerror(); + ASSERT_EQ(handle, handle1); + + dlclose(handle1); + dlclose(handle); + + ASSERT_TRUE(is_unloaded); +} + +TEST(dlfcn, dlopen_nodelete_dt_flags_1) { + static bool is_unloaded = false; + + void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr) << dlerror(); + void (*set_unload_flag_ptr)(bool*); + set_unload_flag_ptr = reinterpret_cast(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr")); + ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); + set_unload_flag_ptr(&is_unloaded); + + dlclose(handle); + ASSERT_TRUE(!is_unloaded); +} + + TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index ee97c618a..b7335d59e 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -112,6 +112,35 @@ build_type := target build_target := SHARED_LIBRARY include $(TEST_PATH)/Android.build.mk +# ----------------------------------------------------------------------------- +# Library used by dlfcn nodelete tests +# ----------------------------------------------------------------------------- +libtest_nodelete_1_src_files := \ + dlopen_nodelete_1.cpp + +module := libtest_nodelete_1 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# Library used by dlfcn nodelete tests +# ----------------------------------------------------------------------------- +libtest_nodelete_2_src_files := \ + dlopen_nodelete_2.cpp + +module := libtest_nodelete_2 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# Library used by dlfcn nodelete tests +# ----------------------------------------------------------------------------- +libtest_nodelete_dt_flags_1_src_files := \ + dlopen_nodelete_dt_flags_1.cpp + +libtest_nodelete_dt_flags_1_ldflags := -Wl,-z,nodelete + +module := libtest_nodelete_dt_flags_1 +include $(LOCAL_PATH)/Android.build.testlib.mk + # ----------------------------------------------------------------------------- # Libraries used by dlfcn tests to verify correct load order: # libtest_check_order_2_right.so diff --git a/tests/libs/dlopen_nodelete_1.cpp b/tests/libs/dlopen_nodelete_1.cpp new file mode 100644 index 000000000..943897815 --- /dev/null +++ b/tests/libs/dlopen_nodelete_1.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +uint32_t dlopen_nodelete_1_taxicab_number = 1729; +static bool* unload_flag_ptr = nullptr; + +extern "C" void dlopen_nodelete_1_set_unload_flag_ptr(bool* ptr) { + unload_flag_ptr = ptr; +} + +static void __attribute__((destructor)) unload_guard() { + if (unload_flag_ptr != nullptr) { + *unload_flag_ptr = true; + } +} diff --git a/tests/libs/dlopen_nodelete_2.cpp b/tests/libs/dlopen_nodelete_2.cpp new file mode 100644 index 000000000..b5ab5c1ae --- /dev/null +++ b/tests/libs/dlopen_nodelete_2.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +uint32_t dlopen_nodelete_2_taxicab_number = 1729; +static bool* unload_flag_ptr = nullptr; + +extern "C" void dlopen_nodelete_2_set_unload_flag_ptr(bool* ptr) { + unload_flag_ptr = ptr; +} + +static void __attribute__((destructor)) unload_guard() { + if (unload_flag_ptr != nullptr) { + *unload_flag_ptr = true; + } +} diff --git a/tests/libs/dlopen_nodelete_dt_flags_1.cpp b/tests/libs/dlopen_nodelete_dt_flags_1.cpp new file mode 100644 index 000000000..39c0a7ea6 --- /dev/null +++ b/tests/libs/dlopen_nodelete_dt_flags_1.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +static bool* unload_flag_ptr = nullptr; + +extern "C" void dlopen_nodelete_dt_flags_1_set_unload_flag_ptr(bool* ptr) { + unload_flag_ptr = ptr; +} + +static void __attribute__((destructor)) unload_guard() { + if (unload_flag_ptr != nullptr) { + *unload_flag_ptr = true; + } +} From 1d3e81a9e7795a320406cd903ef1767072ae122e Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 6 Oct 2014 11:30:43 -0700 Subject: [PATCH 078/114] Resolve "unused DT entry" warnings for x86_64 Bug: 18186310 (cherry picked from commit 513e29e16f16a6ffa1636ba282d599fd6b437aeb) Change-Id: I1e4c5af2cdc09dc978c7a78fcdcf8796c919751e --- linker/linker.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 7b27cd79e..d2bf4e570 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -1936,14 +1936,19 @@ bool soinfo::PrelinkImage() { return false; } break; -#if !defined(__LP64__) case DT_PLTREL: - if (d->d_un.d_val != DT_REL) { - DL_ERR("unsupported DT_RELA in \"%s\"", name); +#if defined(USE_RELA) + if (d->d_un.d_val != DT_RELA) { + DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", name); + return false; + } +#else + if (d->d_un.d_val != DT_REL) { + DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", name); return false; } - break; #endif + break; case DT_JMPREL: #if defined(USE_RELA) plt_rela = reinterpret_cast(load_bias + d->d_un.d_ptr); @@ -2120,6 +2125,11 @@ bool soinfo::PrelinkImage() { mips_gotsym = d->d_un.d_val; break; #endif + case DT_VERSYM: + case DT_VERDEF: + case DT_VERDEFNUM: + // Ignore: bionic does not support symbol versioning... + break; default: if (!relocating_linker) { From e4bc6f026a10648756da031b5d765c78c9e70864 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Wed, 15 Oct 2014 14:59:01 -0700 Subject: [PATCH 079/114] Ignore DT_BIND_NOW (0x18) Bug: 18186310 Bug: 17552334 (cherry picked from commit ea6eae182ad64312f80b9adddac511d8938e23e7) Change-Id: I07d6f6fbb462fea329581d0da02f6d88be1c262f --- linker/linker.cpp | 49 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index d2bf4e570..41557e231 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -1915,27 +1915,33 @@ bool soinfo::PrelinkImage() { // TODO: glibc dynamic linker uses this name for // initial library lookup; consider doing the same here. break; + case DT_HASH: nbucket = reinterpret_cast(load_bias + d->d_un.d_ptr)[0]; nchain = reinterpret_cast(load_bias + d->d_un.d_ptr)[1]; bucket = reinterpret_cast(load_bias + d->d_un.d_ptr + 8); chain = reinterpret_cast(load_bias + d->d_un.d_ptr + 8 + nbucket * 4); break; + case DT_STRTAB: strtab = reinterpret_cast(load_bias + d->d_un.d_ptr); break; + case DT_STRSZ: strtab_size = d->d_un.d_val; break; + case DT_SYMTAB: symtab = reinterpret_cast(load_bias + d->d_un.d_ptr); break; + case DT_SYMENT: if (d->d_un.d_val != sizeof(ElfW(Sym))) { DL_ERR("invalid DT_SYMENT: %zd", static_cast(d->d_un.d_val)); return false; } break; + case DT_PLTREL: #if defined(USE_RELA) if (d->d_un.d_val != DT_RELA) { @@ -1949,6 +1955,7 @@ bool soinfo::PrelinkImage() { } #endif break; + case DT_JMPREL: #if defined(USE_RELA) plt_rela = reinterpret_cast(load_bias + d->d_un.d_ptr); @@ -1956,6 +1963,7 @@ bool soinfo::PrelinkImage() { plt_rel = reinterpret_cast(load_bias + d->d_un.d_ptr); #endif break; + case DT_PLTRELSZ: #if defined(USE_RELA) plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); @@ -1963,6 +1971,7 @@ bool soinfo::PrelinkImage() { plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); #endif break; + case DT_PLTGOT: #if defined(__mips__) // Used by mips and mips64. @@ -1970,6 +1979,7 @@ bool soinfo::PrelinkImage() { #endif // Ignore for other platforms... (because RTLD_LAZY is not supported) break; + case DT_DEBUG: // Set the DT_DEBUG entry to the address of _r_debug for GDB // if the dynamic table is writable @@ -1987,21 +1997,26 @@ bool soinfo::PrelinkImage() { case DT_RELA: rela = reinterpret_cast(load_bias + d->d_un.d_ptr); break; + case DT_RELASZ: rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); break; + case DT_RELAENT: if (d->d_un.d_val != sizeof(ElfW(Rela))) { DL_ERR("invalid DT_RELAENT: %zd", static_cast(d->d_un.d_val)); return false; } break; + + // ignored (see DT_RELCOUNT comments for details) case DT_RELACOUNT: - // ignored (see DT_RELCOUNT comments for details) break; + case DT_REL: DL_ERR("unsupported DT_REL in \"%s\"", name); return false; + case DT_RELSZ: DL_ERR("unsupported DT_RELSZ in \"%s\"", name); return false; @@ -2009,21 +2024,24 @@ bool soinfo::PrelinkImage() { case DT_REL: rel = reinterpret_cast(load_bias + d->d_un.d_ptr); break; + case DT_RELSZ: rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); break; + case DT_RELENT: if (d->d_un.d_val != sizeof(ElfW(Rel))) { DL_ERR("invalid DT_RELENT: %zd", static_cast(d->d_un.d_val)); return false; } break; + + // "Indicates that all RELATIVE relocations have been concatenated together, + // and specifies the RELATIVE relocation count." + // + // TODO: Spec also mentions that this can be used to optimize relocation process; + // Not currently used by bionic linker - ignored. case DT_RELCOUNT: - // "Indicates that all RELATIVE relocations have been concatenated together, - // and specifies the RELATIVE relocation count." - // - // TODO: Spec also mentions that this can be used to optimize relocation process; - // Not currently used by bionic linker - ignored. break; case DT_RELA: DL_ERR("unsupported DT_RELA in \"%s\"", name); @@ -2033,31 +2051,39 @@ bool soinfo::PrelinkImage() { init_func = reinterpret_cast(load_bias + d->d_un.d_ptr); DEBUG("%s constructors (DT_INIT) found at %p", name, init_func); break; + case DT_FINI: fini_func = reinterpret_cast(load_bias + d->d_un.d_ptr); DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func); break; + case DT_INIT_ARRAY: init_array = reinterpret_cast(load_bias + d->d_un.d_ptr); DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array); break; + case DT_INIT_ARRAYSZ: init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); break; + case DT_FINI_ARRAY: fini_array = reinterpret_cast(load_bias + d->d_un.d_ptr); DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array); break; + case DT_FINI_ARRAYSZ: fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); break; + case DT_PREINIT_ARRAY: preinit_array = reinterpret_cast(load_bias + d->d_un.d_ptr); DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array); break; + case DT_PREINIT_ARRAYSZ: preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); break; + case DT_TEXTREL: #if defined(__LP64__) DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name); @@ -2066,12 +2092,15 @@ bool soinfo::PrelinkImage() { has_text_relocations = true; break; #endif + case DT_SYMBOLIC: has_DT_SYMBOLIC = true; break; + case DT_NEEDED: ++needed_count; break; + case DT_FLAGS: if (d->d_un.d_val & DF_TEXTREL) { #if defined(__LP64__) @@ -2085,6 +2114,7 @@ bool soinfo::PrelinkImage() { has_DT_SYMBOLIC = true; } break; + case DT_FLAGS_1: if ((d->d_un.d_val & DF_1_GLOBAL) != 0) { rtld_flags |= RTLD_GLOBAL; @@ -2107,6 +2137,7 @@ bool soinfo::PrelinkImage() { *dp = &_r_debug; } break; + case DT_MIPS_RLD_VERSION: case DT_MIPS_FLAGS: case DT_MIPS_BASE_ADDRESS: @@ -2125,10 +2156,14 @@ bool soinfo::PrelinkImage() { mips_gotsym = d->d_un.d_val; break; #endif + // Ignored: "Its use has been superseded by the DF_BIND_NOW flag" + case DT_BIND_NOW: + break; + + // Ignore: bionic does not support symbol versioning... case DT_VERSYM: case DT_VERDEF: case DT_VERDEFNUM: - // Ignore: bionic does not support symbol versioning... break; default: From 382e06ce8eab506276aaad39da3fbd533ef898d2 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 30 Oct 2014 23:42:45 -0700 Subject: [PATCH 080/114] Add dlfcn_test to glibc test suite. Bug: 18186310 (cherry picked from commit eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bf) Change-Id: I1d608dfa12dbafbdcdb8bc6d818c5872404c19e0 --- tests/Android.mk | 5 ++ tests/dlfcn_test.cpp | 11 ++- tests/libs/Android.build.testlib.mk | 22 +++++ tests/libs/Android.mk | 121 ++++++++++----------------- tests/libs/dlopen_testlib_simple.cpp | 1 + 5 files changed, 81 insertions(+), 79 deletions(-) create mode 100644 tests/libs/Android.build.testlib.mk diff --git a/tests/Android.mk b/tests/Android.mk index 407f21bc5..f20eb7d82 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -283,6 +283,7 @@ ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x bionic-unit-tests-glibc_src_files := \ atexit_test.cpp \ + dlfcn_test.cpp \ bionic-unit-tests-glibc_whole_static_libraries := \ libBionicStandardTests \ @@ -290,8 +291,12 @@ bionic-unit-tests-glibc_whole_static_libraries := \ bionic-unit-tests-glibc_ldlibs := \ -lrt -ldl \ +bionic-unit-tests-glibc_c_includes := \ + bionic/libc \ + bionic-unit-tests-glibc_cflags := $(test_cflags) bionic-unit-tests-glibc_cppflags := $(test_cppflags) +bionic-unit-tests-glibc_ldflags := -Wl,--export-dynamic module := bionic-unit-tests-glibc module_tag := optional diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index e7787b4a4..f1ec0f131 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -188,14 +188,14 @@ TEST(dlfcn, dlopen_check_order) { // get_answer2() is defined in (b, d) void* sym = dlsym(RTLD_DEFAULT, "dlopen_test_get_answer"); ASSERT_TRUE(sym == nullptr); - void* handle = dlopen("libtest_check_order.so", RTLD_NOW); + void* handle = dlopen("libtest_check_order.so", RTLD_NOW | RTLD_GLOBAL); ASSERT_TRUE(handle != nullptr); typedef int (*fn_t) (void); fn_t fn, fn2; fn = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer")); - ASSERT_TRUE(fn != NULL); + ASSERT_TRUE(fn != NULL) << dlerror(); fn2 = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer2")); - ASSERT_TRUE(fn2 != NULL); + ASSERT_TRUE(fn2 != NULL) << dlerror(); ASSERT_EQ(42, fn()); ASSERT_EQ(43, fn2()); @@ -248,6 +248,7 @@ TEST(dlfcn, dlopen_check_rtld_global) { // libtest_with_dependency_loop_a.so TEST(dlfcn, dlopen_check_loop) { void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW); +#if defined(__BIONIC__) ASSERT_TRUE(handle == nullptr); ASSERT_STREQ("dlopen failed: recursive link to \"libtest_with_dependency_loop_a.so\"", dlerror()); // This symbol should never be exposed @@ -261,6 +262,10 @@ TEST(dlfcn, dlopen_check_loop) { handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD); ASSERT_TRUE(handle == nullptr); ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); +#else // glibc allows recursive links + ASSERT_TRUE(handle != nullptr); + dlclose(handle); +#endif } TEST(dlfcn, dlopen_nodelete) { diff --git a/tests/libs/Android.build.testlib.mk b/tests/libs/Android.build.testlib.mk new file mode 100644 index 000000000..5b688e4d9 --- /dev/null +++ b/tests/libs/Android.build.testlib.mk @@ -0,0 +1,22 @@ +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +build_target := SHARED_LIBRARY +build_type := host +include $(TEST_PATH)/Android.build.mk +build_type := target +include $(TEST_PATH)/Android.build.mk + diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index b7335d59e..8746ff298 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -29,9 +29,7 @@ no-elf-hash-table-library_ldflags := \ module := no-elf-hash-table-library module_tag := optional -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk endif # ----------------------------------------------------------------------------- @@ -45,15 +43,13 @@ libdlext_test_ldflags := \ module := libdlext_test module_tag := optional -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # create symlink to libdlext_test.so for symlink test # ----------------------------------------------------------------------------- # Use = instead of := to defer the evaluation of $@ -$(LOCAL_INSTALLED_MODULE): PRIVATE_POST_INSTALL_CMD = \ +$(TARGET_OUT)/lib/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \ $(hide) cd $(dir $@) && ln -sf $(notdir $@) libdlext_test_v2.so ifneq ($(TARGET_2ND_ARCH),) @@ -62,6 +58,13 @@ $(TARGET_OUT)/lib64/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \ $(hide) cd $(dir $@) && ln -sf $(notdir $@) libdlext_test_v2.so endif +# host symlinks +$(HOST_OUT)/lib64/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \ + $(hide) cd $(dir $@) && ln -sf $(notdir $@) libdlext_test_v2.so + +$(HOST_OUT)/lib/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \ + $(hide) cd $(dir $@) && ln -sf $(notdir $@) libdlext_test_v2.so + # ----------------------------------------------------------------------------- # Library used by dlext tests - without GNU RELRO program header # ----------------------------------------------------------------------------- @@ -108,9 +111,7 @@ libtest_simple_src_files := \ dlopen_testlib_simple.cpp module := libtest_simple -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # Library used by dlfcn nodelete tests @@ -150,9 +151,7 @@ libtest_check_order_2_right_src_files := \ libtest_check_order_2_right_cflags := -D__ANSWER=42 module := libtest_check_order_2_right -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # libtest_check_order_a.so @@ -162,9 +161,7 @@ libtest_check_order_a_src_files := \ libtest_check_order_a_cflags := -D__ANSWER=1 module := libtest_check_order_a -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # libtest_check_order_b.so @@ -174,9 +171,7 @@ libtest_check_order_b_src_files := \ libtest_check_order_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 module := libtest_check_order_b -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # libtest_check_order_c.so @@ -186,9 +181,7 @@ libtest_check_order_3_c_src_files := \ libtest_check_order_3_c_cflags := -D__ANSWER=3 module := libtest_check_order_3_c -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # libtest_check_order_d.so @@ -199,9 +192,7 @@ libtest_check_order_d_src_files := \ libtest_check_order_d_shared_libraries := libtest_check_order_b libtest_check_order_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 module := libtest_check_order_d -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # libtest_check_order_left.so @@ -212,9 +203,7 @@ libtest_check_order_1_left_src_files := \ libtest_check_order_1_left_shared_libraries := libtest_check_order_a libtest_check_order_b module := libtest_check_order_1_left -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # libtest_check_order.so @@ -226,9 +215,7 @@ libtest_check_order_shared_libraries := libtest_check_order_1_left \ libtest_check_order_2_right libtest_check_order_3_c module := libtest_check_order -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # Library with dependency loop used by dlfcn tests @@ -241,9 +228,7 @@ libtest_with_dependency_loop_shared_libraries := \ libtest_with_dependency_loop_a module := libtest_with_dependency_loop -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # libtest_with_dependency_loop_a.so @@ -254,9 +239,7 @@ libtest_with_dependency_loop_a_shared_libraries := \ libtest_with_dependency_loop_b_tmp module := libtest_with_dependency_loop_a -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # libtest_with_dependency_loop_b.so @@ -267,9 +250,7 @@ libtest_with_dependency_loop_b_tmp_src_files := dlopen_testlib_invalid.cpp libtest_with_dependency_loop_b_tmp_ldflags := -Wl,-soname=libtest_with_dependency_loop_b.so module := libtest_with_dependency_loop_b_tmp -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # libtest_with_dependency_loop_b.so @@ -278,9 +259,7 @@ libtest_with_dependency_loop_b_src_files := dlopen_testlib_invalid.cpp libtest_with_dependency_loop_b_shared_libraries := libtest_with_dependency_loop_c module := libtest_with_dependency_loop_b -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # libtest_with_dependency_loop_c.so @@ -291,9 +270,7 @@ libtest_with_dependency_loop_c_shared_libraries := \ libtest_with_dependency_loop_a module := libtest_with_dependency_loop_c -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # libtest_relo_check_dt_needed_order.so @@ -308,15 +285,13 @@ libtest_relo_check_dt_needed_order_shared_libraries := \ libtest_relo_check_dt_needed_order_src_files := dlopen_testlib_relo_check_dt_needed_order.cpp libtest_relo_check_dt_needed_order_1_src_files := dlopen_testlib_relo_check_dt_needed_order_1.cpp libtest_relo_check_dt_needed_order_2_src_files := dlopen_testlib_relo_check_dt_needed_order_2.cpp -build_type := target -build_target := SHARED_LIBRARY module := libtest_relo_check_dt_needed_order -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk module := libtest_relo_check_dt_needed_order_1 -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk module := libtest_relo_check_dt_needed_order_2 -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # Library with dependency used by dlfcn tests @@ -327,22 +302,30 @@ libtest_with_dependency_src_files := \ libtest_with_dependency_shared_libraries := libdlext_test module := libtest_with_dependency -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # Library used by ifunc tests # ----------------------------------------------------------------------------- +libtest_ifunc_src_files := \ + dlopen_testlib_ifunc.c + +libtest_ifunc_clang_host := false +module := libtest_ifunc +build_target := SHARED_LIBRARY + +build_type := host +include $(TEST_PATH)/Android.build.mk + ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64)) - libtest_ifunc_src_files := \ - dlopen_testlib_ifunc.c + ifeq ($(TARGET_ARCH),arm64) + libtest_ifunc_multilib := 64 + # TODO: This is a workaround - remove it once gcc + # removes its Android ifunc checks + libtest_ifunc_cflags := -mglibc + endif - LOCAL_SDK_VERSION := current - module := libtest_ifunc build_type := target - build_target := SHARED_LIBRARY - include $(TEST_PATH)/Android.build.mk endif @@ -354,11 +337,7 @@ libtest_atexit_src_files := \ atexit_testlib.cpp module := libtest_atexit -build_target := SHARED_LIBRARY -build_type := target -include $(TEST_PATH)/Android.build.mk -build_type := host -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # Library with weak function @@ -367,14 +346,4 @@ libtest_dlsym_weak_func_src_files := \ dlsym_weak_function.cpp module := libtest_dlsym_weak_func -build_target := SHARED_LIBRARY -build_type := target -include $(TEST_PATH)/Android.build.mk -build_type := host -include $(TEST_PATH)/Android.build.mk - -LOCAL_ADDITIONAL_DEPENDENCIES := \ - $(LOCAL_PATH)/Android.mk \ - $(LOCAL_PATH)/Android.build.dlext_testzip.mk \ - $(LOCAL_PATH)/Android.build.testlib.mk \ - $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk diff --git a/tests/libs/dlopen_testlib_simple.cpp b/tests/libs/dlopen_testlib_simple.cpp index 06253e1f4..32269557a 100644 --- a/tests/libs/dlopen_testlib_simple.cpp +++ b/tests/libs/dlopen_testlib_simple.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include uint32_t dlopen_testlib_taxicab_number = 1729; From 4d0c1f673f8a22f5415b9a879e4544f6bcfe419c Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Fri, 17 Oct 2014 11:47:18 -0700 Subject: [PATCH 081/114] Correct way to specify additional dependencies Previous one was not covering all the targets Bug: 17548097 Bug: 18186310 (cherry picked from commit 4a9e1937c56511aef579312bf39ab345f9179230) Change-Id: I2cd9e58893555d16cbfe291b2d1279621489d5ad --- tests/Android.build.mk | 1 + tests/Android.mk | 2 ++ tests/libs/Android.mk | 7 +++++++ 3 files changed, 10 insertions(+) diff --git a/tests/Android.build.mk b/tests/Android.build.mk index d54c851b2..63729dace 100644 --- a/tests/Android.build.mk +++ b/tests/Android.build.mk @@ -15,6 +15,7 @@ # include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(common_additional_dependencies) LOCAL_MODULE := $(module) LOCAL_MODULE_TAGS := $(module_tag) diff --git a/tests/Android.mk b/tests/Android.mk index f20eb7d82..8b0b0a0e0 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -28,6 +28,8 @@ else build_host := false endif +common_additional_dependencies := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/Android.build.mk + # ----------------------------------------------------------------------------- # All standard tests. # ----------------------------------------------------------------------------- diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 8746ff298..175a63539 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -17,6 +17,13 @@ LOCAL_PATH := $(call my-dir) TEST_PATH := $(LOCAL_PATH)/.. +common_cppflags += -std=gnu++11 +common_additional_dependencies := \ + $(LOCAL_PATH)/Android.mk \ + $(LOCAL_PATH)/Android.build.dlext_testzip.mk \ + $(LOCAL_PATH)/Android.build.testlib.mk \ + $(TEST_PATH)/Android.build.mk + # ----------------------------------------------------------------------------- # Library used by dlfcn tests. # ----------------------------------------------------------------------------- From fd2747bb585fc51b5ad56db09c0e9b66c7091a92 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 21 Oct 2014 09:23:18 -0700 Subject: [PATCH 082/114] Fix relocation to look for symbols in local group The local group is a sequence of libraries in default (breadth-first) order. It allows RTLD_LOCALLY loaded library to correctly relocate symbols within its group (see test-cases). Local group lookup is performed after main executable and ld_preloads. Bug: 2643900 Bug: 15432753 Bug: 18186310 (cherry picked from commit cfa97f172dc1b10d650fefbb6ccffd88ce72a5fb) Change-Id: I5fa8c673f929e4652c738912c7ae078d7ec286d2 --- linker/linked_list.h | 4 +- linker/linker.cpp | 193 +++++++++++------- linker/linker.h | 6 +- tests/dlfcn_test.cpp | 186 +++++++++++++++-- .../Android.build.dlopen_check_order_dlsym.mk | 90 ++++++++ ...lopen_check_order_reloc_main_executable.mk | 56 +++++ ...build.dlopen_check_order_reloc_siblings.mk | 133 ++++++++++++ tests/libs/Android.mk | 75 +------ ...pp => dlopen_check_order_dlsym_answer.cpp} | 4 +- .../libs/dlopen_check_order_reloc_answer.cpp | 23 +++ .../dlopen_check_order_reloc_answer_impl.cpp | 19 ++ ...dlopen_check_order_reloc_nephew_answer.cpp | 21 ++ .../dlopen_check_order_reloc_root_answer.cpp | 21 ++ ...pen_check_order_reloc_root_answer_impl.cpp | 19 ++ 14 files changed, 688 insertions(+), 162 deletions(-) create mode 100644 tests/libs/Android.build.dlopen_check_order_dlsym.mk create mode 100644 tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk create mode 100644 tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk rename tests/libs/{dlopen_testlib_answer.cpp => dlopen_check_order_dlsym_answer.cpp} (87%) create mode 100644 tests/libs/dlopen_check_order_reloc_answer.cpp create mode 100644 tests/libs/dlopen_check_order_reloc_answer_impl.cpp create mode 100644 tests/libs/dlopen_check_order_reloc_nephew_answer.cpp create mode 100644 tests/libs/dlopen_check_order_reloc_root_answer.cpp create mode 100644 tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp diff --git a/linker/linked_list.h b/linker/linked_list.h index 4e62e208f..72a32b4ba 100644 --- a/linker/linked_list.h +++ b/linker/linked_list.h @@ -86,7 +86,7 @@ class LinkedList { } template - void for_each(F action) { + void for_each(F action) const { visit([&] (T* si) { action(si); return true; @@ -94,7 +94,7 @@ class LinkedList { } template - bool visit(F action) { + bool visit(F action) const { for (LinkedListEntry* e = head_; e != nullptr; e = e->next) { if (!action(e->element)) { return false; diff --git a/linker/linker.cpp b/linker/linker.cpp index 41557e231..eb1a483ae 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -415,7 +415,7 @@ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void return rv; } -static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) { +static ElfW(Sym)* soinfo_elf_lookup(const soinfo* si, unsigned hash, const char* name) { ElfW(Sym)* symtab = si->symtab; TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd", @@ -481,7 +481,7 @@ static unsigned elfhash(const char* _name) { return h; } -static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { +static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, const soinfo::soinfo_list_t& local_group) { unsigned elf_hash = elfhash(name); ElfW(Sym)* s = nullptr; @@ -527,16 +527,21 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { } } - /* Look for symbols in the local scope (the object who is - * searching). This happens with C++ templates on x86 for some - * reason. - * - * Notes on weak symbols: - * The ELF specs are ambiguous about treatment of weak definitions in - * dynamic linking. Some systems return the first definition found - * and some the first non-weak definition. This is system dependent. - * Here we return the first definition found for simplicity. */ + // 3. Look for it in the local group + if (s == nullptr) { + local_group.visit([&](soinfo* local_si) { + DEBUG("%s: looking up %s in %s (from local group)", si->name, name, local_si->name); + s = soinfo_elf_lookup(local_si, elf_hash, name); + if (s != nullptr) { + *lsi = local_si; + return false; + } + return true; + }); + } + + // 4. Look for it in this library (unless we already did it because of DT_SYMBOLIC) if (s == nullptr && !si->has_DT_SYMBOLIC) { DEBUG("%s: looking up %s in local scope", si->name, name); s = soinfo_elf_lookup(si, elf_hash, name); @@ -545,6 +550,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { } } + // 5. Dependencies if (s == nullptr) { si->get_children().visit([&](soinfo* child) { DEBUG("%s: looking up %s in %s", si->name, name, child->name); @@ -643,33 +649,61 @@ typedef linked_list_t StringLinkedList; typedef linked_list_t LoadTaskList; -// This is used by dlsym(3). It performs symbol lookup only within the -// specified soinfo object and its dependencies in breadth first order. -ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { +// This function walks down the tree of soinfo dependencies +// in breadth-first order and +// * calls action(soinfo* si) for each node, and +// * terminates walk if action returns false. +// +// walk_dependencies_tree returns false if walk was terminated +// by the action and true otherwise. +template +static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) { SoinfoLinkedList visit_list; SoinfoLinkedList visited; - visit_list.push_back(si); - soinfo* current_soinfo; - while ((current_soinfo = visit_list.pop_front()) != nullptr) { - if (visited.contains(current_soinfo)) { + for (size_t i = 0; i < root_soinfos_size; ++i) { + visit_list.push_back(root_soinfos[i]); + } + + soinfo* si; + while ((si = visit_list.pop_front()) != nullptr) { + if (visited.contains(si)) { continue; } - ElfW(Sym)* result = soinfo_elf_lookup(current_soinfo, elfhash(name), name); - - if (result != nullptr) { - *found = current_soinfo; - return result; + if (!action(si)) { + return false; } - visited.push_back(current_soinfo); - current_soinfo->get_children().for_each([&](soinfo* child) { + visited.push_back(si); + + si->get_children().for_each([&](soinfo* child) { visit_list.push_back(child); }); } - return nullptr; + return true; +} + + +// This is used by dlsym(3). It performs symbol lookup only within the +// specified soinfo object and its dependencies in breadth first order. +ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { + ElfW(Sym)* result = nullptr; + uint32_t elf_hash = elfhash(name); + + + walk_dependencies_tree(&si, 1, [&](soinfo* current_soinfo) { + result = soinfo_elf_lookup(current_soinfo, elf_hash, name); + if (result != nullptr) { + *found = current_soinfo; + return false; + } + + return true; + }); + + return result; } /* This is used by dlsym(3) to performs a global symbol lookup. If the @@ -899,19 +933,30 @@ static bool is_recursive(soinfo* si, soinfo* parent) { }); } -static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[], - soinfo* ld_preloads[], size_t ld_preloads_size, int rtld_flags, const android_dlextinfo* extinfo) { +static bool find_libraries(soinfo* start_with, const char* const library_names[], size_t library_names_count, soinfo* soinfos[], + soinfo* ld_preloads[], size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) { // Step 0: prepare. LoadTaskList load_tasks; - for (size_t i = 0; i < library_names_size; ++i) { + for (size_t i = 0; i < library_names_count; ++i) { const char* name = library_names[i]; - load_tasks.push_back(LoadTask::create(name, nullptr)); + load_tasks.push_back(LoadTask::create(name, start_with)); } - // Libraries added to this list in reverse order so that we can - // start linking from bottom-up - see step 2. - SoinfoLinkedList found_libs; - size_t soinfos_size = 0; + // If soinfos array is null allocate one on stack. + // The array is needed in case of failure; for example + // when library_names[] = {libone.so, libtwo.so} and libone.so + // is loaded correctly but libtwo.so failed for some reason. + // In this case libone.so should be unloaded on return. + // See also implementation of failure_guard below. + + if (soinfos == nullptr) { + size_t soinfos_size = sizeof(soinfo*)*library_names_count; + soinfos = reinterpret_cast(alloca(soinfos_size)); + memset(soinfos, 0, soinfos_size); + } + + // list of libraries to link - see step 2. + size_t soinfos_count = 0; auto failure_guard = make_scope_guard([&]() { // Housekeeping @@ -919,7 +964,7 @@ static bool find_libraries(const char* const library_names[], size_t library_nam LoadTask::deleter(t); }); - for (size_t i = 0; iadd_child(si); } - found_libs.push_front(si); - // When ld_preloads is not null first - // ld_preloads_size libs are in fact ld_preloads. - if (ld_preloads != nullptr && soinfos_size < ld_preloads_size) { - ld_preloads[soinfos_size] = si; + // When ld_preloads is not null, the first + // ld_preloads_count libs are in fact ld_preloads. + if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) { + ld_preloads[soinfos_count] = si; } - if (soinfos_sizeflags & FLAG_LINKED) == 0) { - if (!si->LinkImage(extinfo)) { + if (!si->LinkImage(local_group, extinfo)) { return false; } si->flags |= FLAG_LINKED; } + + return true; + }); + + if (linked) { + failure_guard.disable(); } - // All is well - found_libs and load_tasks are empty at this point - // and all libs are successfully linked. - failure_guard.disable(); - return true; + return linked; } static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) { @@ -979,7 +1034,7 @@ static soinfo* find_library(const char* name, int rtld_flags, const android_dlex soinfo* si; - if (!find_libraries(&name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { + if (!find_libraries(nullptr, &name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { return nullptr; } @@ -1090,7 +1145,7 @@ static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) { } #if defined(USE_RELA) -int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { +int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group) { for (size_t idx = 0; idx < count; ++idx, ++rela) { unsigned type = ELFW(R_TYPE)(rela->r_info); unsigned sym = ELFW(R_SYM)(rela->r_info); @@ -1108,7 +1163,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi); + s = soinfo_do_lookup(this, sym_name, &lsi, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1367,7 +1422,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { } #else // REL, not RELA. -int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { +int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group) { for (size_t idx = 0; idx < count; ++idx, ++rel) { unsigned type = ELFW(R_TYPE)(rel->r_info); // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. @@ -1386,7 +1441,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi); + s = soinfo_do_lookup(this, sym_name, &lsi, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1572,7 +1627,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { #endif #if defined(__mips__) -static bool mips_relocate_got(soinfo* si) { +static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& local_group) { ElfW(Addr)** got = si->plt_got; if (got == nullptr) { return true; @@ -1605,7 +1660,7 @@ static bool mips_relocate_got(soinfo* si) { // This is an undefined reference... try to locate it. const char* sym_name = si->get_string(sym->st_name); soinfo* lsi = nullptr; - ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); + ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. s = &symtab[g]; @@ -2198,7 +2253,7 @@ bool soinfo::PrelinkImage() { return true; } -bool soinfo::LinkImage(const android_dlextinfo* extinfo) { +bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo) { #if !defined(__LP64__) if (has_text_relocations) { @@ -2217,26 +2272,26 @@ bool soinfo::LinkImage(const android_dlextinfo* extinfo) { #if defined(USE_RELA) if (rela != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rela, rela_count)) { + if (Relocate(rela, rela_count, local_group)) { return false; } } if (plt_rela != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rela, plt_rela_count)) { + if (Relocate(plt_rela, plt_rela_count, local_group)) { return false; } } #else if (rel != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rel, rel_count)) { + if (Relocate(rel, rel_count, local_group)) { return false; } } if (plt_rel != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rel, plt_rel_count)) { + if (Relocate(plt_rel, plt_rel_count, local_group)) { return false; } } @@ -2310,7 +2365,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->load_bias = get_elf_exec_load_bias(ehdr_vdso); si->PrelinkImage(); - si->LinkImage(nullptr); + si->LinkImage(g_empty_list, nullptr); #endif } @@ -2456,21 +2511,11 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( }); const char* needed_library_names[needed_libraries_count]; - soinfo* needed_library_si[needed_libraries_count]; memset(needed_library_names, 0, sizeof(needed_library_names)); needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); - if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { - __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); - exit(EXIT_FAILURE); - } - - for (size_t i = 0; iadd_child(needed_library_si[i]); - } - - if (!si->LinkImage(nullptr)) { + if (needed_libraries_count > 0 && !find_libraries(si, needed_library_names, needed_libraries_count, nullptr, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); } @@ -2594,7 +2639,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - if (!(linker_so.PrelinkImage() && linker_so.LinkImage(nullptr))) { + if (!(linker_so.PrelinkImage() && linker_so.LinkImage(g_empty_list, nullptr))) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as diff --git a/linker/linker.h b/linker/linker.h index ebb4793af..222aca11e 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -207,7 +207,7 @@ struct soinfo { void CallDestructors(); void CallPreInitConstructors(); bool PrelinkImage(); - bool LinkImage(const android_dlextinfo* extinfo); + bool LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo); void add_child(soinfo* child); void remove_all_links(); @@ -234,9 +234,9 @@ struct soinfo { void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); #if defined(USE_RELA) - int Relocate(ElfW(Rela)* rela, unsigned count); + int Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group); #else - int Relocate(ElfW(Rel)* rel, unsigned count); + int Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group); #endif private: diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index f1ec0f131..e604f5abe 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -162,39 +162,39 @@ TEST(dlfcn, dlopen_check_relocation_dt_needed_order) { ASSERT_EQ(1, fn()); } -TEST(dlfcn, dlopen_check_order) { +TEST(dlfcn, dlopen_check_order_dlsym) { // Here is how the test library and its dt_needed // libraries are arranged // - // libtest_check_order.so + // libtest_check_order_children.so // | - // +-> libtest_check_order_1_left.so + // +-> ..._1_left.so // | | - // | +-> libtest_check_order_a.so + // | +-> ..._a.so // | | - // | +-> libtest_check_order_b.so + // | +-> ...r_b.so // | - // +-> libtest_check_order_2_right.so + // +-> ..._2_right.so // | | - // | +-> libtest_check_order_d.so + // | +-> ..._d.so // | | - // | +-> libtest_check_order_b.so + // | +-> ..._b.so // | - // +-> libtest_check_order_3_c.so + // +-> ..._3_c.so // // load order should be (1, 2, 3, a, b, d) // // get_answer() is defined in (2, 3, a, b, c) // get_answer2() is defined in (b, d) - void* sym = dlsym(RTLD_DEFAULT, "dlopen_test_get_answer"); + void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"); ASSERT_TRUE(sym == nullptr); - void* handle = dlopen("libtest_check_order.so", RTLD_NOW | RTLD_GLOBAL); - ASSERT_TRUE(handle != nullptr); + void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); typedef int (*fn_t) (void); fn_t fn, fn2; - fn = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer")); + fn = reinterpret_cast(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer")); ASSERT_TRUE(fn != NULL) << dlerror(); - fn2 = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer2")); + fn2 = reinterpret_cast(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2")); ASSERT_TRUE(fn2 != NULL) << dlerror(); ASSERT_EQ(42, fn()); @@ -202,6 +202,163 @@ TEST(dlfcn, dlopen_check_order) { dlclose(handle); } +TEST(dlfcn, dlopen_check_order_reloc_siblings) { + // This is how this one works: + // we lookup and call get_answer which is defined in '_2.so' + // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so' + // the correct _impl() is implemented by '_a.so'; + // + // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?) + // + // Here is the picture: + // + // libtest_check_order_reloc_siblings.so + // | + // +-> ..._1.so <- empty + // | | + // | +-> ..._a.so <- exports correct answer_impl() + // | | + // | +-> ..._b.so <- every other letter exporting incorrect one. + // | + // +-> ..._2.so <- empty + // | | + // | +-> ..._c.so + // | | + // | +-> ..._d.so + // | + // +-> ..._3.so <- empty + // | + // +-> ..._e.so + // | + // +-> ..._f.so <- exports get_answer() that calls get_anser_impl(); + // implements incorrect get_answer_impl() + + void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); +#ifdef __BIONIC__ + // TODO: glibc returns nullptr on dlerror() here. Is it bug? + ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); +#endif + + handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + typedef int (*fn_t) (void); + fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_get_answer")); + ASSERT_TRUE(fn != nullptr) << dlerror(); + ASSERT_EQ(42, fn()); + + ASSERT_EQ(0, dlclose(handle)); +} + +TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) { + // This test uses the same library as dlopen_check_order_reloc_siblings. + // Unlike dlopen_check_order_reloc_siblings it preloads + // libtest_check_order_reloc_siblings_1.so (first dependency) prior to + // dlopen(libtest_check_order_reloc_siblings.so) + + void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); + handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); + + void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(handle_for_1 != nullptr) << dlerror(); + + handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + ASSERT_EQ(0, dlclose(handle_for_1)); + + typedef int (*fn_t) (void); + fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_get_answer")); + ASSERT_TRUE(fn != nullptr) << dlerror(); + ASSERT_EQ(42, fn()); + + ASSERT_EQ(0, dlclose(handle)); +} + +TEST(dlfcn, dlopen_check_order_reloc_nephew) { + // This is how this one works: + // we lookup and call nephew_get_answer which is defined in '_2.so' + // and in turn calls external get_answer_impl() defined in '_[a-f].so' + // the correct _impl() is implemented by '_a.so'; + // + // Here is the picture: + // + // libtest_check_order_reloc_siblings.so + // | + // +-> ..._1.so <- empty + // | | + // | +-> ..._a.so <- exports correct answer_impl() + // | | + // | +-> ..._b.so <- every other letter exporting incorrect one. + // | + // +-> ..._2.so <- empty + // | | + // | +-> ..._c.so + // | | + // | +-> ..._d.so + // | + // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl(); + // | + // +-> ..._e.so + // | + // +-> ..._f.so + + void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); +#ifdef __BIONIC__ + // TODO: glibc returns nullptr on dlerror() here. Is it bug? + ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); +#endif + + handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + typedef int (*fn_t) (void); + fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_nephew_get_answer")); + ASSERT_TRUE(fn != nullptr) << dlerror(); + ASSERT_EQ(42, fn()); + + ASSERT_EQ(0, dlclose(handle)); +} + +extern "C" int check_order_reloc_root_get_answer_impl() { + return 42; +} + +TEST(dlfcn, dlopen_check_order_reloc_main_executable) { + // This is how this one works: + // we lookup and call get_answer3 which is defined in 'root.so' + // and in turn calls external root_get_answer_impl() defined in _2.so and + // above the correct _impl() is one in the executable. + // + // libtest_check_order_reloc_root.so + // | + // +-> ..._1.so <- empty + // | + // +-> ..._2.so <- gives incorrect answer for answer_main_impl() + // + + void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); +#ifdef __BIONIC__ + // TODO: glibc returns nullptr on dlerror() here. Is it bug? + ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); +#endif + + handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + typedef int (*fn_t) (void); + fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_root_get_answer")); + ASSERT_TRUE(fn != nullptr) << dlerror(); + ASSERT_EQ(42, fn()); + + ASSERT_EQ(0, dlclose(handle)); +} + TEST(dlfcn, dlopen_check_rtld_local) { void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); ASSERT_TRUE(sym == nullptr); @@ -342,7 +499,6 @@ TEST(dlfcn, dlopen_nodelete_dt_flags_1) { ASSERT_TRUE(!is_unloaded); } - TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.build.dlopen_check_order_dlsym.mk b/tests/libs/Android.build.dlopen_check_order_dlsym.mk new file mode 100644 index 000000000..73d8c1a83 --- /dev/null +++ b/tests/libs/Android.build.dlopen_check_order_dlsym.mk @@ -0,0 +1,90 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# ----------------------------------------------------------------------------- +# Libraries used by dlfcn tests to verify correct load order: +# libtest_check_order_2_right.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_2_right_src_files := \ + dlopen_check_order_dlsym_answer.cpp + +libtest_check_order_dlsym_2_right_cflags := -D__ANSWER=42 +module := libtest_check_order_dlsym_2_right +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_a.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_a_src_files := \ + dlopen_check_order_dlsym_answer.cpp + +libtest_check_order_dlsym_a_cflags := -D__ANSWER=1 +module := libtest_check_order_dlsym_a +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_b.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_b_src_files := \ + dlopen_check_order_dlsym_answer.cpp + +libtest_check_order_dlsym_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 +module := libtest_check_order_dlsym_b +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_c.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_3_c_src_files := \ + dlopen_check_order_dlsym_answer.cpp + +libtest_check_order_dlsym_3_c_cflags := -D__ANSWER=3 +module := libtest_check_order_dlsym_3_c +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_d.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_d_src_files := \ + dlopen_check_order_dlsym_answer.cpp + +libtest_check_order_dlsym_d_shared_libraries := libtest_check_order_dlsym_b +libtest_check_order_dlsym_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 +module := libtest_check_order_dlsym_d +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_left.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_1_left_src_files := \ + empty.cpp + +libtest_check_order_dlsym_1_left_shared_libraries := libtest_check_order_dlsym_a libtest_check_order_dlsym_b + +module := libtest_check_order_dlsym_1_left +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_src_files := \ + empty.cpp + +libtest_check_order_dlsym_shared_libraries := libtest_check_order_dlsym_1_left \ + libtest_check_order_dlsym_2_right libtest_check_order_dlsym_3_c + +module := libtest_check_order_dlsym +include $(LOCAL_PATH)/Android.build.testlib.mk diff --git a/tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk b/tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk new file mode 100644 index 000000000..639696b25 --- /dev/null +++ b/tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk @@ -0,0 +1,56 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# ----------------------------------------------------------------------------- +# Libraries used by dlfcn tests to verify correct relocation order: +# libtest_check_order_reloc_root*.so +# ----------------------------------------------------------------------------- + + +# ----------------------------------------------------------------------------- +# ..._1.so - empty +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_root_1_src_files := \ + empty.cpp + + +module := libtest_check_order_reloc_root_1 +include $(LOCAL_PATH)/Android.build.testlib.mk + + +# ----------------------------------------------------------------------------- +# ..._2.so - this one has the incorrect answer +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_root_2_src_files := \ + dlopen_check_order_reloc_root_answer_impl.cpp + +libtest_check_order_reloc_root_2_cflags := -D__ANSWER=2 + +module := libtest_check_order_reloc_root_2 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_reloc_root.so <- implements get_answer3() +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_root_src_files := \ + dlopen_check_order_reloc_root_answer.cpp + +libtest_check_order_reloc_root_shared_libraries := \ + libtest_check_order_reloc_root_1 \ + libtest_check_order_reloc_root_2 + +module := libtest_check_order_reloc_root +include $(LOCAL_PATH)/Android.build.testlib.mk diff --git a/tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk b/tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk new file mode 100644 index 000000000..0f1a2b4da --- /dev/null +++ b/tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk @@ -0,0 +1,133 @@ +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# ----------------------------------------------------------------------------- +# Libraries used by dlfcn tests to verify correct relocation order: +# libtest_check_order_reloc_siblings*.so +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# ..._1.so - empty +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_1_src_files := \ + empty.cpp + +libtest_check_order_reloc_siblings_1_shared_libraries := \ + libtest_check_order_reloc_siblings_a \ + libtest_check_order_reloc_siblings_b + +module := libtest_check_order_reloc_siblings_1 +include $(LOCAL_PATH)/Android.build.testlib.mk + + +# ----------------------------------------------------------------------------- +# ..._2.so - empty +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_2_src_files := \ + empty.cpp + +libtest_check_order_reloc_siblings_2_shared_libraries := \ + libtest_check_order_reloc_siblings_c \ + libtest_check_order_reloc_siblings_d + +module := libtest_check_order_reloc_siblings_2 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._3.so - get_answer2(); +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_3_src_files := \ + dlopen_check_order_reloc_nephew_answer.cpp + +libtest_check_order_reloc_siblings_3_shared_libraries := \ + libtest_check_order_reloc_siblings_e \ + libtest_check_order_reloc_siblings_f + +module := libtest_check_order_reloc_siblings_3 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._a.so <- correct impl +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_a_src_files := \ + dlopen_check_order_reloc_answer_impl.cpp + +libtest_check_order_reloc_siblings_a_cflags := -D__ANSWER=42 +module := libtest_check_order_reloc_siblings_a +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._b.so +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_b_src_files := \ + dlopen_check_order_reloc_answer_impl.cpp + +libtest_check_order_reloc_siblings_b_cflags := -D__ANSWER=1 +module := libtest_check_order_reloc_siblings_b +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._c.so +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_c_src_files := \ + dlopen_check_order_reloc_answer_impl.cpp + +libtest_check_order_reloc_siblings_c_cflags := -D__ANSWER=2 +module := libtest_check_order_reloc_siblings_c +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._d.so +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_d_src_files := \ + dlopen_check_order_reloc_answer_impl.cpp + +libtest_check_order_reloc_siblings_d_cflags := -D__ANSWER=3 +module := libtest_check_order_reloc_siblings_d +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._e.so +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_e_src_files := \ + dlopen_check_order_reloc_answer_impl.cpp + +libtest_check_order_reloc_siblings_e_cflags := -D__ANSWER=4 +module := libtest_check_order_reloc_siblings_e +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._f.so <- get_answer() +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_f_src_files := \ + dlopen_check_order_reloc_answer.cpp + +module := libtest_check_order_reloc_siblings_f +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_reloc_siblings.so +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_src_files := \ + empty.cpp + +libtest_check_order_reloc_siblings_shared_libraries := \ + libtest_check_order_reloc_siblings_1 \ + libtest_check_order_reloc_siblings_2 \ + libtest_check_order_reloc_siblings_3 + +module := libtest_check_order_reloc_siblings +include $(LOCAL_PATH)/Android.build.testlib.mk diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 175a63539..05e7113ba 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -21,6 +21,9 @@ common_cppflags += -std=gnu++11 common_additional_dependencies := \ $(LOCAL_PATH)/Android.mk \ $(LOCAL_PATH)/Android.build.dlext_testzip.mk \ + $(LOCAL_PATH)/Android.build.dlopen_check_order_dlsym.mk \ + $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_siblings.mk \ + $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_main_executable.mk \ $(LOCAL_PATH)/Android.build.testlib.mk \ $(TEST_PATH)/Android.build.mk @@ -150,79 +153,19 @@ module := libtest_nodelete_dt_flags_1 include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- -# Libraries used by dlfcn tests to verify correct load order: -# libtest_check_order_2_right.so +# Build libtest_check_order_dlsym.so with its dependencies. # ----------------------------------------------------------------------------- -libtest_check_order_2_right_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_2_right_cflags := -D__ANSWER=42 -module := libtest_check_order_2_right -include $(LOCAL_PATH)/Android.build.testlib.mk +include $(LOCAL_PATH)/Android.build.dlopen_check_order_dlsym.mk # ----------------------------------------------------------------------------- -# libtest_check_order_a.so +# Build libtest_check_order_siblings.so with its dependencies. # ----------------------------------------------------------------------------- -libtest_check_order_a_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_a_cflags := -D__ANSWER=1 -module := libtest_check_order_a -include $(LOCAL_PATH)/Android.build.testlib.mk +include $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_siblings.mk # ----------------------------------------------------------------------------- -# libtest_check_order_b.so +# Build libtest_check_order_root.so with its dependencies. # ----------------------------------------------------------------------------- -libtest_check_order_b_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 -module := libtest_check_order_b -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_c.so -# ----------------------------------------------------------------------------- -libtest_check_order_3_c_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_3_c_cflags := -D__ANSWER=3 -module := libtest_check_order_3_c -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_d.so -# ----------------------------------------------------------------------------- -libtest_check_order_d_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_d_shared_libraries := libtest_check_order_b -libtest_check_order_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 -module := libtest_check_order_d -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_left.so -# ----------------------------------------------------------------------------- -libtest_check_order_1_left_src_files := \ - empty.cpp - -libtest_check_order_1_left_shared_libraries := libtest_check_order_a libtest_check_order_b - -module := libtest_check_order_1_left -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order.so -# ----------------------------------------------------------------------------- -libtest_check_order_src_files := \ - empty.cpp - -libtest_check_order_shared_libraries := libtest_check_order_1_left \ - libtest_check_order_2_right libtest_check_order_3_c - -module := libtest_check_order -include $(LOCAL_PATH)/Android.build.testlib.mk +include $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_main_executable.mk # ----------------------------------------------------------------------------- # Library with dependency loop used by dlfcn tests diff --git a/tests/libs/dlopen_testlib_answer.cpp b/tests/libs/dlopen_check_order_dlsym_answer.cpp similarity index 87% rename from tests/libs/dlopen_testlib_answer.cpp rename to tests/libs/dlopen_check_order_dlsym_answer.cpp index a4d75046e..2ae6cf79e 100644 --- a/tests/libs/dlopen_testlib_answer.cpp +++ b/tests/libs/dlopen_check_order_dlsym_answer.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -extern "C" int dlopen_test_get_answer() { +extern "C" int check_order_dlsym_get_answer() { return __ANSWER; } #ifdef __ANSWER2 -extern "C" int dlopen_test_get_answer2() { +extern "C" int check_order_dlsym_get_answer2() { return __ANSWER2; } #endif diff --git a/tests/libs/dlopen_check_order_reloc_answer.cpp b/tests/libs/dlopen_check_order_reloc_answer.cpp new file mode 100644 index 000000000..036670bee --- /dev/null +++ b/tests/libs/dlopen_check_order_reloc_answer.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int __attribute__((weak)) check_order_reloc_get_answer_impl() { + return 0; +} + +extern "C" int check_order_reloc_get_answer() { + return check_order_reloc_get_answer_impl(); +} diff --git a/tests/libs/dlopen_check_order_reloc_answer_impl.cpp b/tests/libs/dlopen_check_order_reloc_answer_impl.cpp new file mode 100644 index 000000000..324b905da --- /dev/null +++ b/tests/libs/dlopen_check_order_reloc_answer_impl.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int check_order_reloc_get_answer_impl() { + return __ANSWER; +} diff --git a/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp b/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp new file mode 100644 index 000000000..065d1bef7 --- /dev/null +++ b/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int check_order_reloc_get_answer_impl(); + +extern "C" int check_order_reloc_nephew_get_answer() { + return check_order_reloc_get_answer_impl(); +} diff --git a/tests/libs/dlopen_check_order_reloc_root_answer.cpp b/tests/libs/dlopen_check_order_reloc_root_answer.cpp new file mode 100644 index 000000000..b21abd77a --- /dev/null +++ b/tests/libs/dlopen_check_order_reloc_root_answer.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int check_order_reloc_root_get_answer_impl(); + +extern "C" int check_order_reloc_root_get_answer() { + return check_order_reloc_root_get_answer_impl(); +} diff --git a/tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp b/tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp new file mode 100644 index 000000000..25fb9aca9 --- /dev/null +++ b/tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int check_order_reloc_root_get_answer_impl() { + return __ANSWER; +} From 6442dbd3bcadbd5e522465743a8d8cf56338ae1c Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 23 Oct 2014 14:19:07 -0700 Subject: [PATCH 083/114] Remove unnecessary lookups during relocations local_group includes this library and its dependencies. Bug: 18186310 (cherry picked from commit e47b3f8456fc34ac136e9fddef59a9ae37febcbe) Change-Id: I93c2d873e924df7319569307444bf603d7d27bf0 --- linker/linker.cpp | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index eb1a483ae..c63ac35bb 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -530,6 +530,11 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c // 3. Look for it in the local group if (s == nullptr) { local_group.visit([&](soinfo* local_si) { + if (local_si == si && si->has_DT_SYMBOLIC) { + // we already did this - skip + return true; + } + DEBUG("%s: looking up %s in %s (from local group)", si->name, name, local_si->name); s = soinfo_elf_lookup(local_si, elf_hash, name); if (s != nullptr) { @@ -541,28 +546,6 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c }); } - // 4. Look for it in this library (unless we already did it because of DT_SYMBOLIC) - if (s == nullptr && !si->has_DT_SYMBOLIC) { - DEBUG("%s: looking up %s in local scope", si->name, name); - s = soinfo_elf_lookup(si, elf_hash, name); - if (s != nullptr) { - *lsi = si; - } - } - - // 5. Dependencies - if (s == nullptr) { - si->get_children().visit([&](soinfo* child) { - DEBUG("%s: looking up %s in %s", si->name, name, child->name); - s = soinfo_elf_lookup(child, elf_hash, name); - if (s != nullptr) { - *lsi = child; - return false; - } - return true; - }); - } - if (s != nullptr) { TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " "found in %s, base = %p, load bias = %p", From bf3d5ef5fd240d4c5fbde1b32f9084dbc720840b Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 23 Oct 2014 14:34:12 -0700 Subject: [PATCH 084/114] Fix mips build Bug: 18186310 (cherry picked from commit 90b74fb8671db6f5512821a033e12a6248e5c804) Change-Id: I8d4ed254e5c421b65b62c401abdb1ee07e5dc3b2 --- linker/linker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index c63ac35bb..f8963b59c 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -2281,7 +2281,7 @@ bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo #endif #if defined(__mips__) - if (!mips_relocate_got(this)) { + if (!mips_relocate_got(this, local_group)) { return false; } #endif From 976402cca13a1f4f3aa988fd301575e134ef5f2c Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 28 Aug 2014 14:12:12 -0700 Subject: [PATCH 085/114] Fix symbol lookup order during relocation Relocate symbol against DF_1_GLOBAL shared libraries loaded before this shared library. This includes main executable, ld_preloads and other libraries that have DF_1_GLOBAL flag set. Bug: 2643900 Bug: 15432753 Bug: 18186310 (cherry picked from commit d225a5e65223b375a63548c4b780f04d8f3d7b60) Change-Id: I4e889cdf2dfbf8230b0790053d311ee6b0d0ee2d --- linker/linked_list.h | 12 +++ linker/linker.cpp | 162 +++++++++++++++++----------- linker/linker.h | 23 ++-- tests/Android.mk | 13 ++- tests/dl_test.cpp | 72 +++++++++++++ tests/dlfcn_test.cpp | 14 +++ tests/libs/Android.mk | 36 +++++++ tests/libs/dl_df_1_global.cpp | 19 ++++ tests/libs/dl_df_1_use_global.cpp | 23 ++++ tests/libs/dl_preempt_library_1.cpp | 45 ++++++++ tests/libs/dl_preempt_library_2.cpp | 37 +++++++ 11 files changed, 385 insertions(+), 71 deletions(-) create mode 100644 tests/dl_test.cpp create mode 100644 tests/libs/dl_df_1_global.cpp create mode 100644 tests/libs/dl_df_1_use_global.cpp create mode 100644 tests/libs/dl_preempt_library_1.cpp create mode 100644 tests/libs/dl_preempt_library_2.cpp diff --git a/linker/linked_list.h b/linker/linked_list.h index 72a32b4ba..b08806161 100644 --- a/linker/linked_list.h +++ b/linker/linked_list.h @@ -36,6 +36,12 @@ class LinkedList { clear(); } + LinkedList(LinkedList&& that) { + this->head_ = that.head_; + this->tail_ = that.tail_; + that.head_ = that.tail_ = nullptr; + } + void push_front(T* const element) { LinkedListEntry* new_entry = Allocator::alloc(); new_entry->next = head_; @@ -140,6 +146,12 @@ class LinkedList { return false; } + static LinkedList make_list(T* const element) { + LinkedList one_element_list; + one_element_list.push_back(element); + return one_element_list; + } + private: LinkedListEntry* head_; LinkedListEntry* tail_; diff --git a/linker/linker.cpp b/linker/linker.cpp index f8963b59c..ef6e3e127 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -282,7 +282,7 @@ static void protect_data(int protection) { g_soinfo_links_allocator.protect_all(protection); } -static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, int rtld_flags) { +static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, uint32_t rtld_flags) { if (strlen(name) >= SOINFO_NAME_LEN) { DL_ERR("library name \"%s\" too long", name); return nullptr; @@ -481,7 +481,8 @@ static unsigned elfhash(const char* _name) { return h; } -static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, const soinfo::soinfo_list_t& local_group) { +static ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found_in, + const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) { unsigned elf_hash = elfhash(name); ElfW(Sym)* s = nullptr; @@ -496,49 +497,40 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c * Note that this is unlikely since static linker avoids generating * relocations for -Bsymbolic linked dynamic executables. */ - if (si->has_DT_SYMBOLIC) { - DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si->name, name); - s = soinfo_elf_lookup(si, elf_hash, name); + if (si_from->has_DT_SYMBOLIC) { + DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->name, name); + s = soinfo_elf_lookup(si_from, elf_hash, name); if (s != nullptr) { - *lsi = si; + *si_found_in = si_from; } } - if (s == nullptr && somain != nullptr) { - // 1. Look for it in the main executable unless we already did. - if (si != somain || !si->has_DT_SYMBOLIC) { - DEBUG("%s: looking up %s in executable %s", - si->name, name, somain->name); - s = soinfo_elf_lookup(somain, elf_hash, name); + // 1. Look for it in global_group + if (s == nullptr) { + global_group.visit([&](soinfo* global_si) { + DEBUG("%s: looking up %s in %s (from global group)", si_from->name, name, global_si->name); + s = soinfo_elf_lookup(global_si, elf_hash, name); if (s != nullptr) { - *lsi = somain; + *si_found_in = global_si; + return false; } - } - // 2. Look for it in the ld_preloads - if (s == nullptr) { - for (int i = 0; g_ld_preloads[i] != NULL; i++) { - s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); - if (s != nullptr) { - *lsi = g_ld_preloads[i]; - break; - } - } - } + return true; + }); } - // 3. Look for it in the local group + // 2. Look for it in the local group if (s == nullptr) { local_group.visit([&](soinfo* local_si) { - if (local_si == si && si->has_DT_SYMBOLIC) { + if (local_si == si_from && si_from->has_DT_SYMBOLIC) { // we already did this - skip return true; } - DEBUG("%s: looking up %s in %s (from local group)", si->name, name, local_si->name); + DEBUG("%s: looking up %s in %s (from local group)", si_from->name, name, local_si->name); s = soinfo_elf_lookup(local_si, elf_hash, name); if (s != nullptr) { - *lsi = local_si; + *si_found_in = local_si; return false; } @@ -549,9 +541,9 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c if (s != nullptr) { TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " "found in %s, base = %p, load bias = %p", - si->name, name, reinterpret_cast(s->st_value), - (*lsi)->name, reinterpret_cast((*lsi)->base), - reinterpret_cast((*lsi)->load_bias)); + si_from->name, name, reinterpret_cast(s->st_value), + (*si_found_in)->name, reinterpret_cast((*si_found_in)->base), + reinterpret_cast((*si_found_in)->load_bias)); } return s; @@ -916,6 +908,24 @@ static bool is_recursive(soinfo* si, soinfo* parent) { }); } +// TODO: this is slightly unusual way to construct +// the global group for relocation. Not every RTLD_GLOBAL +// library is included in this group for backwards-compatibility +// reasons. +// +// This group consists of the main executable, LD_PRELOADs +// and libraries with the DF_1_GLOBAL flag set. +static soinfo::soinfo_list_t make_global_group() { + soinfo::soinfo_list_t global_group; + for (soinfo* si = somain; si != nullptr; si = si->next) { + if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) { + global_group.push_back(si); + } + } + + return global_group; +} + static bool find_libraries(soinfo* start_with, const char* const library_names[], size_t library_names_count, soinfo* soinfos[], soinfo* ld_preloads[], size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) { // Step 0: prepare. @@ -925,6 +935,9 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[] load_tasks.push_back(LoadTask::create(name, start_with)); } + // Construct global_group. + soinfo::soinfo_list_t global_group = make_global_group(); + // If soinfos array is null allocate one on stack. // The array is needed in case of failure; for example // when library_names[] = {libone.so, libtwo.so} and libone.so @@ -973,6 +986,11 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[] // When ld_preloads is not null, the first // ld_preloads_count libs are in fact ld_preloads. if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) { + // Add LD_PRELOADed libraries to the global group for future runs. + // There is no need to explicitly add them to the global group + // for this run because they are going to appear in the local + // group in the correct order. + si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); ld_preloads[soinfos_count] = si; } @@ -993,7 +1011,7 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[] bool linked = local_group.visit([&](soinfo* si) { if ((si->flags & FLAG_LINKED) == 0) { - if (!si->LinkImage(local_group, extinfo)) { + if (!si->LinkImage(global_group, local_group, extinfo)) { return false; } si->flags |= FLAG_LINKED; @@ -1128,7 +1146,7 @@ static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) { } #if defined(USE_RELA) -int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group) { +int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group) { for (size_t idx = 0; idx < count; ++idx, ++rela) { unsigned type = ELFW(R_TYPE)(rela->r_info); unsigned sym = ELFW(R_SYM)(rela->r_info); @@ -1146,7 +1164,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& loca if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi, local_group); + s = soinfo_do_lookup(this, sym_name, &lsi, global_group,local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1405,7 +1423,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& loca } #else // REL, not RELA. -int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group) { +int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group) { for (size_t idx = 0; idx < count; ++idx, ++rel) { unsigned type = ELFW(R_TYPE)(rel->r_info); // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. @@ -1424,7 +1442,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_ if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi, local_group); + s = soinfo_do_lookup(this, sym_name, &lsi, global_group, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1610,7 +1628,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_ #endif #if defined(__mips__) -static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& local_group) { +static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) { ElfW(Addr)** got = si->plt_got; if (got == nullptr) { return true; @@ -1643,7 +1661,7 @@ static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& local_gro // This is an undefined reference... try to locate it. const char* sym_name = si->get_string(sym->st_name); soinfo* lsi = nullptr; - ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, local_group); + ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, global_group, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. s = &symtab[g]; @@ -1783,7 +1801,7 @@ void soinfo::remove_all_links() { children.clear(); } -dev_t soinfo::get_st_dev() { +dev_t soinfo::get_st_dev() const { if (has_min_version(0)) { return st_dev; } @@ -1791,7 +1809,7 @@ dev_t soinfo::get_st_dev() { return 0; }; -ino_t soinfo::get_st_ino() { +ino_t soinfo::get_st_ino() const { if (has_min_version(0)) { return st_ino; } @@ -1799,7 +1817,7 @@ ino_t soinfo::get_st_ino() { return 0; } -off64_t soinfo::get_file_offset() { +off64_t soinfo::get_file_offset() const { if (has_min_version(1)) { return file_offset; } @@ -1807,7 +1825,7 @@ off64_t soinfo::get_file_offset() { return 0; } -int soinfo::get_rtld_flags() { +uint32_t soinfo::get_rtld_flags() const { if (has_min_version(1)) { return rtld_flags; } @@ -1815,6 +1833,27 @@ int soinfo::get_rtld_flags() { return 0; } +uint32_t soinfo::get_dt_flags_1() const { + if (has_min_version(1)) { + return dt_flags_1; + } + + return 0; +} +void soinfo::set_dt_flags_1(uint32_t dt_flags_1) { + if (has_min_version(1)) { + if ((dt_flags_1 & DF_1_GLOBAL) != 0) { + rtld_flags |= RTLD_GLOBAL; + } + + if ((dt_flags_1 & DF_1_NODELETE) != 0) { + rtld_flags |= RTLD_NODELETE; + } + + this->dt_flags_1 = dt_flags_1; + } +} + // This is a return on get_children()/get_parents() if // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -1852,8 +1891,9 @@ const char* soinfo::get_string(ElfW(Word) index) const { } bool soinfo::can_unload() const { - return (rtld_flags & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; + return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; } + /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -2154,16 +2194,9 @@ bool soinfo::PrelinkImage() { break; case DT_FLAGS_1: - if ((d->d_un.d_val & DF_1_GLOBAL) != 0) { - rtld_flags |= RTLD_GLOBAL; - } + set_dt_flags_1(d->d_un.d_val); - if ((d->d_un.d_val & DF_1_NODELETE) != 0) { - rtld_flags |= RTLD_NODELETE; - } - // TODO: Implement other flags - - if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)) != 0) { + if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) { DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast(d->d_un.d_val)); } break; @@ -2236,7 +2269,7 @@ bool soinfo::PrelinkImage() { return true; } -bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo) { +bool soinfo::LinkImage(const soinfo_list_t& global_group, const soinfo_list_t& local_group, const android_dlextinfo* extinfo) { #if !defined(__LP64__) if (has_text_relocations) { @@ -2255,33 +2288,33 @@ bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo #if defined(USE_RELA) if (rela != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rela, rela_count, local_group)) { + if (Relocate(rela, rela_count, global_group, local_group)) { return false; } } if (plt_rela != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rela, plt_rela_count, local_group)) { + if (Relocate(plt_rela, plt_rela_count, global_group, local_group)) { return false; } } #else if (rel != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rel, rel_count, local_group)) { + if (Relocate(rel, rel_count, global_group, local_group)) { return false; } } if (plt_rel != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rel, plt_rel_count, local_group)) { + if (Relocate(plt_rel, plt_rel_count, global_group, local_group)) { return false; } } #endif #if defined(__mips__) - if (!mips_relocate_got(this, local_group)) { + if (!mips_relocate_got(this, global_group, local_group)) { return false; } #endif @@ -2348,7 +2381,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->load_bias = get_elf_exec_load_bias(ehdr_vdso); si->PrelinkImage(); - si->LinkImage(g_empty_list, nullptr); + si->LinkImage(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr); #endif } @@ -2479,6 +2512,9 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( si->PrelinkImage(); + // add somain to global group + si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); + // Load ld_preloads and dependencies. StringLinkedList needed_library_name_list; size_t needed_libraries_count = 0; @@ -2622,7 +2658,13 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - if (!(linker_so.PrelinkImage() && linker_so.LinkImage(g_empty_list, nullptr))) { + // This might not be obvious... The reasons why we pass g_empty_list + // in place of local_group here are (1) we do not really need it, because + // linker is built with DT_SYMBOLIC and therefore relocates its symbols against + // itself without having to look into local_group and (2) allocators + // are not yet initialized, and therefore we cannot use linked_list.push_* + // functions at this point. + if (!(linker_so.PrelinkImage() && linker_so.LinkImage(g_empty_list, g_empty_list, nullptr))) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as diff --git a/linker/linker.h b/linker/linker.h index 222aca11e..0a98b40dc 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -89,7 +89,9 @@ #define FLAG_LINKER 0x00000010 // The linker itself #define FLAG_NEW_SOINFO 0x40000000 // new soinfo format -#define SOINFO_VERSION 0 +#define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE) + +#define SOINFO_VERSION 1 #define SOINFO_NAME_LEN 128 @@ -207,16 +209,18 @@ struct soinfo { void CallDestructors(); void CallPreInitConstructors(); bool PrelinkImage(); - bool LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo); + bool LinkImage(const soinfo_list_t& global_group, const soinfo_list_t& local_group, const android_dlextinfo* extinfo); void add_child(soinfo* child); void remove_all_links(); - ino_t get_st_ino(); - dev_t get_st_dev(); - off64_t get_file_offset(); + ino_t get_st_ino() const; + dev_t get_st_dev() const; + off64_t get_file_offset() const; - int get_rtld_flags(); + uint32_t get_rtld_flags() const; + uint32_t get_dt_flags_1() const; + void set_dt_flags_1(uint32_t dt_flags_1); soinfo_list_t& get_children(); soinfo_list_t& get_parents(); @@ -234,9 +238,9 @@ struct soinfo { void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); #if defined(USE_RELA) - int Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group); + int Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group); #else - int Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group); + int Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group); #endif private: @@ -254,7 +258,8 @@ struct soinfo { // version >= 1 off64_t file_offset; - int rtld_flags; + uint32_t rtld_flags; + uint32_t dt_flags_1; size_t strtab_size; friend soinfo* get_libdl_info(); diff --git a/tests/Android.mk b/tests/Android.mk index 8b0b0a0e0..6423df183 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -225,6 +225,7 @@ bionic-unit-tests_whole_static_libraries := \ bionic-unit-tests_src_files := \ atexit_test.cpp \ + dl_test.cpp \ dlext_test.cpp \ dlfcn_test.cpp \ @@ -237,8 +238,7 @@ bionic-unit-tests_conlyflags := \ bionic-unit-tests_cppflags := $(test_cppflags) bionic-unit-tests_ldflags := \ - -Wl,--export-dynamic \ - -Wl,-u,DlSymTestFunction \ + -Wl,--export-dynamic bionic-unit-tests_c_includes := \ bionic/libc \ @@ -247,6 +247,9 @@ bionic-unit-tests_c_includes := \ bionic-unit-tests_shared_libraries_target := \ libdl \ libpagemap \ + libdl_preempt_test_1 \ + libdl_preempt_test_2 \ + libdl_test_df_1_global module := bionic-unit-tests module_tag := optional @@ -286,6 +289,12 @@ ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x bionic-unit-tests-glibc_src_files := \ atexit_test.cpp \ dlfcn_test.cpp \ + dl_test.cpp \ + +bionic-unit-tests-glibc_shared_libraries := \ + libdl_preempt_test_1 \ + libdl_preempt_test_2 \ + libdl_test_df_1_global bionic-unit-tests-glibc_whole_static_libraries := \ libBionicStandardTests \ diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp new file mode 100644 index 000000000..74c7b510f --- /dev/null +++ b/tests/dl_test.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include + +#include + +extern "C" int main_global_default_serial() { + return 3370318; +} + +extern "C" int main_global_protected_serial() { + return 2716057; +} + +// The following functions are defined in DT_NEEDED +// libdl_preempt_test.so library. + +// This one calls main_global_default_serial +extern "C" int main_global_default_get_serial(); + +// This one calls main_global_protected_serial +extern "C" int main_global_protected_get_serial(); + +// This one calls lib_global_default_serial +extern "C" int lib_global_default_get_serial(); + +// This one calls lib_global_protected_serial +extern "C" int lib_global_protected_get_serial(); + +// This test verifies that the global default function +// main_global_default_serial() is preempted by +// the function defined above. +TEST(dl, main_preempts_global_default) { + ASSERT_EQ(3370318, main_global_default_get_serial()); +} + +// This one makes sure that the global protected +// symbols do not get preempted +TEST(dl, main_does_not_preempt_global_protected) { + ASSERT_EQ(3370318, main_global_protected_get_serial()); +} + +// check same things for lib +TEST(dl, lib_preempts_global_default) { + ASSERT_EQ(3370318, lib_global_default_get_serial()); +} + +TEST(dl, lib_does_not_preempt_global_protected) { + ASSERT_EQ(3370318, lib_global_protected_get_serial()); +} + +// TODO: Add tests for LD_PRELOADs diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index e604f5abe..a7fe2f852 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -499,6 +499,20 @@ TEST(dlfcn, dlopen_nodelete_dt_flags_1) { ASSERT_TRUE(!is_unloaded); } +TEST(dlfcn, dlsym_df_1_global) { +#if !defined(__arm__) + void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr) << dlerror(); + int (*get_answer)(); + get_answer = reinterpret_cast(dlsym(handle, "dl_df_1_global_get_answer")); + ASSERT_TRUE(get_answer != nullptr) << dlerror(); + ASSERT_EQ(42, get_answer()); + ASSERT_EQ(0, dlclose(handle)); +#else + GTEST_LOG_(INFO) << "This test does nothing on arm (to be reenabled once b/18137520 or b/18130452 are fixed).\n"; +#endif +} + TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 05e7113ba..f45e5a80f 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -289,6 +289,42 @@ libtest_atexit_src_files := \ module := libtest_atexit include $(LOCAL_PATH)/Android.build.testlib.mk +# ----------------------------------------------------------------------------- +# This library is used by dl_load test to check symbol preempting +# by main executable +# ----------------------------------------------------------------------------- +libdl_preempt_test_1_src_files := dl_preempt_library_1.cpp + +module := libdl_preempt_test_1 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# This library is used by dl_load test to check symbol preempting +# by libdl_preempt_test_1.so +# ----------------------------------------------------------------------------- +libdl_preempt_test_2_src_files := dl_preempt_library_2.cpp + +module := libdl_preempt_test_2 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# Library with DF_1_GLOBAL +# ----------------------------------------------------------------------------- +# TODO: re-enable arm once b/18137520 or b/18130452 are fixed +ifeq ($(filter $(TARGET_ARCH),arm),) +libdl_test_df_1_global_src_files := dl_df_1_global.cpp +libdl_test_df_1_global_ldflags := -fuse-ld=bfd -Wl,-z,global +module := libdl_test_df_1_global +include $(LOCAL_PATH)/Android.build.testlib.mk +endif + +# ----------------------------------------------------------------------------- +# Library using symbol from libdl_test_df_1_global +# ----------------------------------------------------------------------------- +libtest_dlsym_df_1_global_src_files := dl_df_1_use_global.cpp +module := libtest_dlsym_df_1_global +include $(LOCAL_PATH)/Android.build.testlib.mk + # ----------------------------------------------------------------------------- # Library with weak function # ----------------------------------------------------------------------------- diff --git a/tests/libs/dl_df_1_global.cpp b/tests/libs/dl_df_1_global.cpp new file mode 100644 index 000000000..39856fd50 --- /dev/null +++ b/tests/libs/dl_df_1_global.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int dl_df_1_global_get_answer_impl() { + return 42; +} diff --git a/tests/libs/dl_df_1_use_global.cpp b/tests/libs/dl_df_1_use_global.cpp new file mode 100644 index 000000000..e14910d1c --- /dev/null +++ b/tests/libs/dl_df_1_use_global.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int __attribute__((weak)) dl_df_1_global_get_answer_impl() { + return 0; +} + +extern "C" int dl_df_1_global_get_answer() { + return dl_df_1_global_get_answer_impl(); +} diff --git a/tests/libs/dl_preempt_library_1.cpp b/tests/libs/dl_preempt_library_1.cpp new file mode 100644 index 000000000..b4d81d5ac --- /dev/null +++ b/tests/libs/dl_preempt_library_1.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This one should be preempted by the function +// defined in the main executable. +extern "C" int __attribute__((weak)) main_global_default_serial() { + return 2716057; +} + +// Even though this one is defined by the main +// executable it should not be preempted +// because of protected visibility +extern "C" int __attribute__((weak, visibility("protected"))) main_global_protected_serial() { + return 3370318; +} + +extern "C" int main_global_default_get_serial() { + return main_global_default_serial(); +} + +extern "C" int main_global_protected_get_serial() { + return main_global_protected_serial(); +} + +// Trying to preempt functions from a DT_NEEDED .so +extern "C" int lib_global_default_serial() { + return 3370318; +} + +extern "C" int lib_global_protected_serial() { + return 2716057; +} diff --git a/tests/libs/dl_preempt_library_2.cpp b/tests/libs/dl_preempt_library_2.cpp new file mode 100644 index 000000000..8df9a1667 --- /dev/null +++ b/tests/libs/dl_preempt_library_2.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This one should be preempted by the function +// defined in libdl_preempt_test_1.so +extern "C" int __attribute__((weak)) lib_global_default_serial() { + return 2716057; +} + +// Even though this one is defined by +// libdl_preempt_test_1.so it should not be +// preempted because of protected visibility +extern "C" int __attribute__((weak,visibility("protected"))) lib_global_protected_serial() { + return 3370318; +} + +extern "C" int lib_global_default_get_serial() { + return lib_global_default_serial(); +} + +extern "C" int lib_global_protected_get_serial() { + return lib_global_protected_serial(); +} + From 445111a1c977e94a4233efd54f3690defa4a7582 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Fri, 31 Oct 2014 17:27:02 -0700 Subject: [PATCH 086/114] Fix arm64 and arm builds. Bug: 18186310 (cherry picked from commit 4e446b19d8710cd2004785db4a00f18f249fe73f) Change-Id: Ibc77a9ade36dc6b9bf5a316b5ab9ae5f0a70e826 --- tests/Android.mk | 14 ++++++++++---- tests/dlfcn_test.cpp | 4 ++-- tests/libs/Android.mk | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/Android.mk b/tests/Android.mk index 6423df183..5a1127b96 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -248,8 +248,11 @@ bionic-unit-tests_shared_libraries_target := \ libdl \ libpagemap \ libdl_preempt_test_1 \ - libdl_preempt_test_2 \ - libdl_test_df_1_global + libdl_preempt_test_2 + +ifneq ($(filter $(TARGET_ARCH),arm arm64),$(TARGET_ARCH)) +bionic-unit-tests_shared_libraries_target += libdl_test_df_1_global +endif module := bionic-unit-tests module_tag := optional @@ -293,8 +296,11 @@ bionic-unit-tests-glibc_src_files := \ bionic-unit-tests-glibc_shared_libraries := \ libdl_preempt_test_1 \ - libdl_preempt_test_2 \ - libdl_test_df_1_global + libdl_preempt_test_2 + +ifneq ($(filter $(TARGET_ARCH),arm arm64),$(TARGET_ARCH)) +bionic-unit-tests-glibc_shared_libraries += libdl_test_df_1_global +endif bionic-unit-tests-glibc_whole_static_libraries := \ libBionicStandardTests \ diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index a7fe2f852..2f0d430f6 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -500,7 +500,7 @@ TEST(dlfcn, dlopen_nodelete_dt_flags_1) { } TEST(dlfcn, dlsym_df_1_global) { -#if !defined(__arm__) +#if !defined(__arm__) && !defined(__aarch64__) void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW); ASSERT_TRUE(handle != nullptr) << dlerror(); int (*get_answer)(); @@ -509,7 +509,7 @@ TEST(dlfcn, dlsym_df_1_global) { ASSERT_EQ(42, get_answer()); ASSERT_EQ(0, dlclose(handle)); #else - GTEST_LOG_(INFO) << "This test does nothing on arm (to be reenabled once b/18137520 or b/18130452 are fixed).\n"; + GTEST_LOG_(INFO) << "This test does nothing on arm/arm64 (to be reenabled once b/18137520 or b/18130452 are fixed).\n"; #endif } diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index f45e5a80f..7d959d484 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -311,7 +311,7 @@ include $(LOCAL_PATH)/Android.build.testlib.mk # Library with DF_1_GLOBAL # ----------------------------------------------------------------------------- # TODO: re-enable arm once b/18137520 or b/18130452 are fixed -ifeq ($(filter $(TARGET_ARCH),arm),) +ifeq ($(filter $(TARGET_ARCH),arm arm64),) libdl_test_df_1_global_src_files := dl_df_1_global.cpp libdl_test_df_1_global_ldflags := -fuse-ld=bfd -Wl,-z,global module := libdl_test_df_1_global From d18f4b25785761c022906b93b2123b3be90182e8 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 3 Nov 2014 12:32:17 -0800 Subject: [PATCH 087/114] Ensure we initialize stdin/stdout/stderr's recursive mutexes. (cherry-pick of 6a03abcfd23f31d1df06eb0059830e22621282bb.) Bug: 18208568 Change-Id: I9da16ce0f9375bc363d1d02be706d73fd3b1e150 --- libc/Android.mk | 2 +- .../lib/libc => }/stdio/findfp.c | 25 ++++++++++++------- tests/stdio_test.cpp | 17 +++++++++++++ 3 files changed, 34 insertions(+), 10 deletions(-) rename libc/{upstream-openbsd/lib/libc => }/stdio/findfp.c (90%) diff --git a/libc/Android.mk b/libc/Android.mk index 61bdf7e23..045556ea9 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -60,6 +60,7 @@ libc_common_src_files := \ bionic/siginterrupt.c \ bionic/sigsetmask.c \ bionic/system_properties_compat.c \ + stdio/findfp.c \ stdio/snprintf.c\ stdio/sprintf.c \ @@ -389,7 +390,6 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/stdio/fgetwc.c \ upstream-openbsd/lib/libc/stdio/fgetws.c \ upstream-openbsd/lib/libc/stdio/fileno.c \ - upstream-openbsd/lib/libc/stdio/findfp.c \ upstream-openbsd/lib/libc/stdio/fprintf.c \ upstream-openbsd/lib/libc/stdio/fpurge.c \ upstream-openbsd/lib/libc/stdio/fputc.c \ diff --git a/libc/upstream-openbsd/lib/libc/stdio/findfp.c b/libc/stdio/findfp.c similarity index 90% rename from libc/upstream-openbsd/lib/libc/stdio/findfp.c rename to libc/stdio/findfp.c index b8c7dc137..0c2ee7cee 100644 --- a/libc/upstream-openbsd/lib/libc/stdio/findfp.c +++ b/libc/stdio/findfp.c @@ -49,10 +49,8 @@ int __sdidinit; #define NDYNAMIC 10 /* add ten more whenever necessary */ #define std(flags, file) \ - {0,0,0,flags,file,{0,0},0,__sF+file,__sclose,__sread,__sseek,__swrite, \ - {(unsigned char *)(__sFext+file), 0},NULL,0,{0,0,0},{0},{0,0},0,0} -/* p r w flags file _bf z cookie close read seek write - ext */ + {0,0,0,flags,file,{0},0,__sF+file,__sclose,__sread,__sseek,__swrite, \ + {(unsigned char *)(__sFext+file), 0},NULL,0,{0},{0},{0},0,0} /* the usual - (stdin + stdout + stderr) */ static FILE usual[FOPEN_MAX - 3]; @@ -165,17 +163,26 @@ void __sinit(void) { _THREAD_PRIVATE_MUTEX(__sinit_mutex); - int i; _THREAD_PRIVATE_MUTEX_LOCK(__sinit_mutex); - if (__sdidinit) - goto out; /* bail out if caller lost the race */ - for (i = 0; i < FOPEN_MAX - 3; i++) { + if (__sdidinit) { + /* bail out if caller lost the race */ + _THREAD_PRIVATE_MUTEX_UNLOCK(__sinit_mutex); + return; + } + + /* Initialize stdin/stdout/stderr (for the recursive mutex). http://b/18208568. */ + for (size_t i = 0; i < 3; ++i) { + _FILEEXT_SETUP(__sF+i, __sFext+i); + } + /* Initialize the pre-allocated (but initially unused) streams. */ + for (size_t i = 0; i < FOPEN_MAX - 3; ++i) { _FILEEXT_SETUP(usual+i, usualext+i); } + /* make sure we clean up on exit */ __atexit_register_cleanup(_cleanup); /* conservative */ __sdidinit = 1; -out: + _THREAD_PRIVATE_MUTEX_UNLOCK(__sinit_mutex); } diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index 8c8c235ad..6a2991f57 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -29,6 +29,23 @@ #include "TemporaryFile.h" +TEST(stdio, flockfile_18208568_stderr) { + // Check that we have a _recursive_ mutex for flockfile. + flockfile(stderr); + feof(stderr); // We don't care about the result, but this needs to take the lock. + funlockfile(stderr); +} + +TEST(stdio, flockfile_18208568_regular) { + // We never had a bug for streams other than stdin/stdout/stderr, but test anyway. + FILE* fp = fopen("/dev/null", "w"); + ASSERT_TRUE(fp != NULL); + flockfile(fp); + feof(fp); + funlockfile(fp); + fclose(fp); +} + TEST(stdio, tmpfile_fileno_fprintf_rewind_fgets) { FILE* fp = tmpfile(); ASSERT_TRUE(fp != NULL); From 494bee796aa60131981308493e0e295493537e12 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 3 Nov 2014 21:13:55 -0800 Subject: [PATCH 088/114] Revert "Fix arm64 and arm builds." This reverts commit 445111a1c977e94a4233efd54f3690defa4a7582. Bug: 18222321 Bug: 18211780 Change-Id: I4fa9e1b63ec9b528f8bfed73c2ec15046c43a2fe --- tests/Android.mk | 14 ++++---------- tests/dlfcn_test.cpp | 4 ++-- tests/libs/Android.mk | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/tests/Android.mk b/tests/Android.mk index 5a1127b96..6423df183 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -248,11 +248,8 @@ bionic-unit-tests_shared_libraries_target := \ libdl \ libpagemap \ libdl_preempt_test_1 \ - libdl_preempt_test_2 - -ifneq ($(filter $(TARGET_ARCH),arm arm64),$(TARGET_ARCH)) -bionic-unit-tests_shared_libraries_target += libdl_test_df_1_global -endif + libdl_preempt_test_2 \ + libdl_test_df_1_global module := bionic-unit-tests module_tag := optional @@ -296,11 +293,8 @@ bionic-unit-tests-glibc_src_files := \ bionic-unit-tests-glibc_shared_libraries := \ libdl_preempt_test_1 \ - libdl_preempt_test_2 - -ifneq ($(filter $(TARGET_ARCH),arm arm64),$(TARGET_ARCH)) -bionic-unit-tests-glibc_shared_libraries += libdl_test_df_1_global -endif + libdl_preempt_test_2 \ + libdl_test_df_1_global bionic-unit-tests-glibc_whole_static_libraries := \ libBionicStandardTests \ diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 2f0d430f6..a7fe2f852 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -500,7 +500,7 @@ TEST(dlfcn, dlopen_nodelete_dt_flags_1) { } TEST(dlfcn, dlsym_df_1_global) { -#if !defined(__arm__) && !defined(__aarch64__) +#if !defined(__arm__) void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW); ASSERT_TRUE(handle != nullptr) << dlerror(); int (*get_answer)(); @@ -509,7 +509,7 @@ TEST(dlfcn, dlsym_df_1_global) { ASSERT_EQ(42, get_answer()); ASSERT_EQ(0, dlclose(handle)); #else - GTEST_LOG_(INFO) << "This test does nothing on arm/arm64 (to be reenabled once b/18137520 or b/18130452 are fixed).\n"; + GTEST_LOG_(INFO) << "This test does nothing on arm (to be reenabled once b/18137520 or b/18130452 are fixed).\n"; #endif } diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 7d959d484..f45e5a80f 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -311,7 +311,7 @@ include $(LOCAL_PATH)/Android.build.testlib.mk # Library with DF_1_GLOBAL # ----------------------------------------------------------------------------- # TODO: re-enable arm once b/18137520 or b/18130452 are fixed -ifeq ($(filter $(TARGET_ARCH),arm arm64),) +ifeq ($(filter $(TARGET_ARCH),arm),) libdl_test_df_1_global_src_files := dl_df_1_global.cpp libdl_test_df_1_global_ldflags := -fuse-ld=bfd -Wl,-z,global module := libdl_test_df_1_global From f947be2889639defc6424b1813ccc779528b7598 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 3 Nov 2014 21:14:07 -0800 Subject: [PATCH 089/114] Revert "Fix symbol lookup order during relocation" This reverts commit 976402cca13a1f4f3aa988fd301575e134ef5f2c. Bug: 18222321 Bug: 18211780 Change-Id: Iafdd3d843db7b1cf288be9a0232022816622c944 --- linker/linked_list.h | 12 --- linker/linker.cpp | 162 +++++++++++----------------- linker/linker.h | 23 ++-- tests/Android.mk | 13 +-- tests/dl_test.cpp | 72 ------------- tests/dlfcn_test.cpp | 14 --- tests/libs/Android.mk | 36 ------- tests/libs/dl_df_1_global.cpp | 19 ---- tests/libs/dl_df_1_use_global.cpp | 23 ---- tests/libs/dl_preempt_library_1.cpp | 45 -------- tests/libs/dl_preempt_library_2.cpp | 37 ------- 11 files changed, 71 insertions(+), 385 deletions(-) delete mode 100644 tests/dl_test.cpp delete mode 100644 tests/libs/dl_df_1_global.cpp delete mode 100644 tests/libs/dl_df_1_use_global.cpp delete mode 100644 tests/libs/dl_preempt_library_1.cpp delete mode 100644 tests/libs/dl_preempt_library_2.cpp diff --git a/linker/linked_list.h b/linker/linked_list.h index b08806161..72a32b4ba 100644 --- a/linker/linked_list.h +++ b/linker/linked_list.h @@ -36,12 +36,6 @@ class LinkedList { clear(); } - LinkedList(LinkedList&& that) { - this->head_ = that.head_; - this->tail_ = that.tail_; - that.head_ = that.tail_ = nullptr; - } - void push_front(T* const element) { LinkedListEntry* new_entry = Allocator::alloc(); new_entry->next = head_; @@ -146,12 +140,6 @@ class LinkedList { return false; } - static LinkedList make_list(T* const element) { - LinkedList one_element_list; - one_element_list.push_back(element); - return one_element_list; - } - private: LinkedListEntry* head_; LinkedListEntry* tail_; diff --git a/linker/linker.cpp b/linker/linker.cpp index ef6e3e127..f8963b59c 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -282,7 +282,7 @@ static void protect_data(int protection) { g_soinfo_links_allocator.protect_all(protection); } -static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, uint32_t rtld_flags) { +static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, int rtld_flags) { if (strlen(name) >= SOINFO_NAME_LEN) { DL_ERR("library name \"%s\" too long", name); return nullptr; @@ -481,8 +481,7 @@ static unsigned elfhash(const char* _name) { return h; } -static ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found_in, - const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) { +static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, const soinfo::soinfo_list_t& local_group) { unsigned elf_hash = elfhash(name); ElfW(Sym)* s = nullptr; @@ -497,40 +496,49 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** s * Note that this is unlikely since static linker avoids generating * relocations for -Bsymbolic linked dynamic executables. */ - if (si_from->has_DT_SYMBOLIC) { - DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->name, name); - s = soinfo_elf_lookup(si_from, elf_hash, name); + if (si->has_DT_SYMBOLIC) { + DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si->name, name); + s = soinfo_elf_lookup(si, elf_hash, name); if (s != nullptr) { - *si_found_in = si_from; + *lsi = si; } } - // 1. Look for it in global_group - if (s == nullptr) { - global_group.visit([&](soinfo* global_si) { - DEBUG("%s: looking up %s in %s (from global group)", si_from->name, name, global_si->name); - s = soinfo_elf_lookup(global_si, elf_hash, name); + if (s == nullptr && somain != nullptr) { + // 1. Look for it in the main executable unless we already did. + if (si != somain || !si->has_DT_SYMBOLIC) { + DEBUG("%s: looking up %s in executable %s", + si->name, name, somain->name); + s = soinfo_elf_lookup(somain, elf_hash, name); if (s != nullptr) { - *si_found_in = global_si; - return false; + *lsi = somain; } + } - return true; - }); + // 2. Look for it in the ld_preloads + if (s == nullptr) { + for (int i = 0; g_ld_preloads[i] != NULL; i++) { + s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); + if (s != nullptr) { + *lsi = g_ld_preloads[i]; + break; + } + } + } } - // 2. Look for it in the local group + // 3. Look for it in the local group if (s == nullptr) { local_group.visit([&](soinfo* local_si) { - if (local_si == si_from && si_from->has_DT_SYMBOLIC) { + if (local_si == si && si->has_DT_SYMBOLIC) { // we already did this - skip return true; } - DEBUG("%s: looking up %s in %s (from local group)", si_from->name, name, local_si->name); + DEBUG("%s: looking up %s in %s (from local group)", si->name, name, local_si->name); s = soinfo_elf_lookup(local_si, elf_hash, name); if (s != nullptr) { - *si_found_in = local_si; + *lsi = local_si; return false; } @@ -541,9 +549,9 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** s if (s != nullptr) { TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " "found in %s, base = %p, load bias = %p", - si_from->name, name, reinterpret_cast(s->st_value), - (*si_found_in)->name, reinterpret_cast((*si_found_in)->base), - reinterpret_cast((*si_found_in)->load_bias)); + si->name, name, reinterpret_cast(s->st_value), + (*lsi)->name, reinterpret_cast((*lsi)->base), + reinterpret_cast((*lsi)->load_bias)); } return s; @@ -908,24 +916,6 @@ static bool is_recursive(soinfo* si, soinfo* parent) { }); } -// TODO: this is slightly unusual way to construct -// the global group for relocation. Not every RTLD_GLOBAL -// library is included in this group for backwards-compatibility -// reasons. -// -// This group consists of the main executable, LD_PRELOADs -// and libraries with the DF_1_GLOBAL flag set. -static soinfo::soinfo_list_t make_global_group() { - soinfo::soinfo_list_t global_group; - for (soinfo* si = somain; si != nullptr; si = si->next) { - if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) { - global_group.push_back(si); - } - } - - return global_group; -} - static bool find_libraries(soinfo* start_with, const char* const library_names[], size_t library_names_count, soinfo* soinfos[], soinfo* ld_preloads[], size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) { // Step 0: prepare. @@ -935,9 +925,6 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[] load_tasks.push_back(LoadTask::create(name, start_with)); } - // Construct global_group. - soinfo::soinfo_list_t global_group = make_global_group(); - // If soinfos array is null allocate one on stack. // The array is needed in case of failure; for example // when library_names[] = {libone.so, libtwo.so} and libone.so @@ -986,11 +973,6 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[] // When ld_preloads is not null, the first // ld_preloads_count libs are in fact ld_preloads. if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) { - // Add LD_PRELOADed libraries to the global group for future runs. - // There is no need to explicitly add them to the global group - // for this run because they are going to appear in the local - // group in the correct order. - si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); ld_preloads[soinfos_count] = si; } @@ -1011,7 +993,7 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[] bool linked = local_group.visit([&](soinfo* si) { if ((si->flags & FLAG_LINKED) == 0) { - if (!si->LinkImage(global_group, local_group, extinfo)) { + if (!si->LinkImage(local_group, extinfo)) { return false; } si->flags |= FLAG_LINKED; @@ -1146,7 +1128,7 @@ static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) { } #if defined(USE_RELA) -int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group) { +int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group) { for (size_t idx = 0; idx < count; ++idx, ++rela) { unsigned type = ELFW(R_TYPE)(rela->r_info); unsigned sym = ELFW(R_SYM)(rela->r_info); @@ -1164,7 +1146,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& glob if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi, global_group,local_group); + s = soinfo_do_lookup(this, sym_name, &lsi, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1423,7 +1405,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& glob } #else // REL, not RELA. -int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group) { +int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group) { for (size_t idx = 0; idx < count; ++idx, ++rel) { unsigned type = ELFW(R_TYPE)(rel->r_info); // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. @@ -1442,7 +1424,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& global if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi, global_group, local_group); + s = soinfo_do_lookup(this, sym_name, &lsi, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1628,7 +1610,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& global #endif #if defined(__mips__) -static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) { +static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& local_group) { ElfW(Addr)** got = si->plt_got; if (got == nullptr) { return true; @@ -1661,7 +1643,7 @@ static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& global_gr // This is an undefined reference... try to locate it. const char* sym_name = si->get_string(sym->st_name); soinfo* lsi = nullptr; - ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, global_group, local_group); + ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. s = &symtab[g]; @@ -1801,7 +1783,7 @@ void soinfo::remove_all_links() { children.clear(); } -dev_t soinfo::get_st_dev() const { +dev_t soinfo::get_st_dev() { if (has_min_version(0)) { return st_dev; } @@ -1809,7 +1791,7 @@ dev_t soinfo::get_st_dev() const { return 0; }; -ino_t soinfo::get_st_ino() const { +ino_t soinfo::get_st_ino() { if (has_min_version(0)) { return st_ino; } @@ -1817,7 +1799,7 @@ ino_t soinfo::get_st_ino() const { return 0; } -off64_t soinfo::get_file_offset() const { +off64_t soinfo::get_file_offset() { if (has_min_version(1)) { return file_offset; } @@ -1825,7 +1807,7 @@ off64_t soinfo::get_file_offset() const { return 0; } -uint32_t soinfo::get_rtld_flags() const { +int soinfo::get_rtld_flags() { if (has_min_version(1)) { return rtld_flags; } @@ -1833,27 +1815,6 @@ uint32_t soinfo::get_rtld_flags() const { return 0; } -uint32_t soinfo::get_dt_flags_1() const { - if (has_min_version(1)) { - return dt_flags_1; - } - - return 0; -} -void soinfo::set_dt_flags_1(uint32_t dt_flags_1) { - if (has_min_version(1)) { - if ((dt_flags_1 & DF_1_GLOBAL) != 0) { - rtld_flags |= RTLD_GLOBAL; - } - - if ((dt_flags_1 & DF_1_NODELETE) != 0) { - rtld_flags |= RTLD_NODELETE; - } - - this->dt_flags_1 = dt_flags_1; - } -} - // This is a return on get_children()/get_parents() if // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -1891,9 +1852,8 @@ const char* soinfo::get_string(ElfW(Word) index) const { } bool soinfo::can_unload() const { - return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; + return (rtld_flags & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; } - /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -2194,9 +2154,16 @@ bool soinfo::PrelinkImage() { break; case DT_FLAGS_1: - set_dt_flags_1(d->d_un.d_val); + if ((d->d_un.d_val & DF_1_GLOBAL) != 0) { + rtld_flags |= RTLD_GLOBAL; + } - if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) { + if ((d->d_un.d_val & DF_1_NODELETE) != 0) { + rtld_flags |= RTLD_NODELETE; + } + // TODO: Implement other flags + + if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)) != 0) { DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast(d->d_un.d_val)); } break; @@ -2269,7 +2236,7 @@ bool soinfo::PrelinkImage() { return true; } -bool soinfo::LinkImage(const soinfo_list_t& global_group, const soinfo_list_t& local_group, const android_dlextinfo* extinfo) { +bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo) { #if !defined(__LP64__) if (has_text_relocations) { @@ -2288,33 +2255,33 @@ bool soinfo::LinkImage(const soinfo_list_t& global_group, const soinfo_list_t& l #if defined(USE_RELA) if (rela != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rela, rela_count, global_group, local_group)) { + if (Relocate(rela, rela_count, local_group)) { return false; } } if (plt_rela != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rela, plt_rela_count, global_group, local_group)) { + if (Relocate(plt_rela, plt_rela_count, local_group)) { return false; } } #else if (rel != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rel, rel_count, global_group, local_group)) { + if (Relocate(rel, rel_count, local_group)) { return false; } } if (plt_rel != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rel, plt_rel_count, global_group, local_group)) { + if (Relocate(plt_rel, plt_rel_count, local_group)) { return false; } } #endif #if defined(__mips__) - if (!mips_relocate_got(this, global_group, local_group)) { + if (!mips_relocate_got(this, local_group)) { return false; } #endif @@ -2381,7 +2348,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->load_bias = get_elf_exec_load_bias(ehdr_vdso); si->PrelinkImage(); - si->LinkImage(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr); + si->LinkImage(g_empty_list, nullptr); #endif } @@ -2512,9 +2479,6 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( si->PrelinkImage(); - // add somain to global group - si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); - // Load ld_preloads and dependencies. StringLinkedList needed_library_name_list; size_t needed_libraries_count = 0; @@ -2658,13 +2622,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - // This might not be obvious... The reasons why we pass g_empty_list - // in place of local_group here are (1) we do not really need it, because - // linker is built with DT_SYMBOLIC and therefore relocates its symbols against - // itself without having to look into local_group and (2) allocators - // are not yet initialized, and therefore we cannot use linked_list.push_* - // functions at this point. - if (!(linker_so.PrelinkImage() && linker_so.LinkImage(g_empty_list, g_empty_list, nullptr))) { + if (!(linker_so.PrelinkImage() && linker_so.LinkImage(g_empty_list, nullptr))) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as diff --git a/linker/linker.h b/linker/linker.h index 0a98b40dc..222aca11e 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -89,9 +89,7 @@ #define FLAG_LINKER 0x00000010 // The linker itself #define FLAG_NEW_SOINFO 0x40000000 // new soinfo format -#define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE) - -#define SOINFO_VERSION 1 +#define SOINFO_VERSION 0 #define SOINFO_NAME_LEN 128 @@ -209,18 +207,16 @@ struct soinfo { void CallDestructors(); void CallPreInitConstructors(); bool PrelinkImage(); - bool LinkImage(const soinfo_list_t& global_group, const soinfo_list_t& local_group, const android_dlextinfo* extinfo); + bool LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo); void add_child(soinfo* child); void remove_all_links(); - ino_t get_st_ino() const; - dev_t get_st_dev() const; - off64_t get_file_offset() const; + ino_t get_st_ino(); + dev_t get_st_dev(); + off64_t get_file_offset(); - uint32_t get_rtld_flags() const; - uint32_t get_dt_flags_1() const; - void set_dt_flags_1(uint32_t dt_flags_1); + int get_rtld_flags(); soinfo_list_t& get_children(); soinfo_list_t& get_parents(); @@ -238,9 +234,9 @@ struct soinfo { void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); #if defined(USE_RELA) - int Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group); + int Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group); #else - int Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group); + int Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group); #endif private: @@ -258,8 +254,7 @@ struct soinfo { // version >= 1 off64_t file_offset; - uint32_t rtld_flags; - uint32_t dt_flags_1; + int rtld_flags; size_t strtab_size; friend soinfo* get_libdl_info(); diff --git a/tests/Android.mk b/tests/Android.mk index 6423df183..8b0b0a0e0 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -225,7 +225,6 @@ bionic-unit-tests_whole_static_libraries := \ bionic-unit-tests_src_files := \ atexit_test.cpp \ - dl_test.cpp \ dlext_test.cpp \ dlfcn_test.cpp \ @@ -238,7 +237,8 @@ bionic-unit-tests_conlyflags := \ bionic-unit-tests_cppflags := $(test_cppflags) bionic-unit-tests_ldflags := \ - -Wl,--export-dynamic + -Wl,--export-dynamic \ + -Wl,-u,DlSymTestFunction \ bionic-unit-tests_c_includes := \ bionic/libc \ @@ -247,9 +247,6 @@ bionic-unit-tests_c_includes := \ bionic-unit-tests_shared_libraries_target := \ libdl \ libpagemap \ - libdl_preempt_test_1 \ - libdl_preempt_test_2 \ - libdl_test_df_1_global module := bionic-unit-tests module_tag := optional @@ -289,12 +286,6 @@ ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x bionic-unit-tests-glibc_src_files := \ atexit_test.cpp \ dlfcn_test.cpp \ - dl_test.cpp \ - -bionic-unit-tests-glibc_shared_libraries := \ - libdl_preempt_test_1 \ - libdl_preempt_test_2 \ - libdl_test_df_1_global bionic-unit-tests-glibc_whole_static_libraries := \ libBionicStandardTests \ diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp deleted file mode 100644 index 74c7b510f..000000000 --- a/tests/dl_test.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include -#include -#include -#include - -#include - -extern "C" int main_global_default_serial() { - return 3370318; -} - -extern "C" int main_global_protected_serial() { - return 2716057; -} - -// The following functions are defined in DT_NEEDED -// libdl_preempt_test.so library. - -// This one calls main_global_default_serial -extern "C" int main_global_default_get_serial(); - -// This one calls main_global_protected_serial -extern "C" int main_global_protected_get_serial(); - -// This one calls lib_global_default_serial -extern "C" int lib_global_default_get_serial(); - -// This one calls lib_global_protected_serial -extern "C" int lib_global_protected_get_serial(); - -// This test verifies that the global default function -// main_global_default_serial() is preempted by -// the function defined above. -TEST(dl, main_preempts_global_default) { - ASSERT_EQ(3370318, main_global_default_get_serial()); -} - -// This one makes sure that the global protected -// symbols do not get preempted -TEST(dl, main_does_not_preempt_global_protected) { - ASSERT_EQ(3370318, main_global_protected_get_serial()); -} - -// check same things for lib -TEST(dl, lib_preempts_global_default) { - ASSERT_EQ(3370318, lib_global_default_get_serial()); -} - -TEST(dl, lib_does_not_preempt_global_protected) { - ASSERT_EQ(3370318, lib_global_protected_get_serial()); -} - -// TODO: Add tests for LD_PRELOADs diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index a7fe2f852..e604f5abe 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -499,20 +499,6 @@ TEST(dlfcn, dlopen_nodelete_dt_flags_1) { ASSERT_TRUE(!is_unloaded); } -TEST(dlfcn, dlsym_df_1_global) { -#if !defined(__arm__) - void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW); - ASSERT_TRUE(handle != nullptr) << dlerror(); - int (*get_answer)(); - get_answer = reinterpret_cast(dlsym(handle, "dl_df_1_global_get_answer")); - ASSERT_TRUE(get_answer != nullptr) << dlerror(); - ASSERT_EQ(42, get_answer()); - ASSERT_EQ(0, dlclose(handle)); -#else - GTEST_LOG_(INFO) << "This test does nothing on arm (to be reenabled once b/18137520 or b/18130452 are fixed).\n"; -#endif -} - TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index f45e5a80f..05e7113ba 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -289,42 +289,6 @@ libtest_atexit_src_files := \ module := libtest_atexit include $(LOCAL_PATH)/Android.build.testlib.mk -# ----------------------------------------------------------------------------- -# This library is used by dl_load test to check symbol preempting -# by main executable -# ----------------------------------------------------------------------------- -libdl_preempt_test_1_src_files := dl_preempt_library_1.cpp - -module := libdl_preempt_test_1 -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# This library is used by dl_load test to check symbol preempting -# by libdl_preempt_test_1.so -# ----------------------------------------------------------------------------- -libdl_preempt_test_2_src_files := dl_preempt_library_2.cpp - -module := libdl_preempt_test_2 -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# Library with DF_1_GLOBAL -# ----------------------------------------------------------------------------- -# TODO: re-enable arm once b/18137520 or b/18130452 are fixed -ifeq ($(filter $(TARGET_ARCH),arm),) -libdl_test_df_1_global_src_files := dl_df_1_global.cpp -libdl_test_df_1_global_ldflags := -fuse-ld=bfd -Wl,-z,global -module := libdl_test_df_1_global -include $(LOCAL_PATH)/Android.build.testlib.mk -endif - -# ----------------------------------------------------------------------------- -# Library using symbol from libdl_test_df_1_global -# ----------------------------------------------------------------------------- -libtest_dlsym_df_1_global_src_files := dl_df_1_use_global.cpp -module := libtest_dlsym_df_1_global -include $(LOCAL_PATH)/Android.build.testlib.mk - # ----------------------------------------------------------------------------- # Library with weak function # ----------------------------------------------------------------------------- diff --git a/tests/libs/dl_df_1_global.cpp b/tests/libs/dl_df_1_global.cpp deleted file mode 100644 index 39856fd50..000000000 --- a/tests/libs/dl_df_1_global.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -extern "C" int dl_df_1_global_get_answer_impl() { - return 42; -} diff --git a/tests/libs/dl_df_1_use_global.cpp b/tests/libs/dl_df_1_use_global.cpp deleted file mode 100644 index e14910d1c..000000000 --- a/tests/libs/dl_df_1_use_global.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -extern "C" int __attribute__((weak)) dl_df_1_global_get_answer_impl() { - return 0; -} - -extern "C" int dl_df_1_global_get_answer() { - return dl_df_1_global_get_answer_impl(); -} diff --git a/tests/libs/dl_preempt_library_1.cpp b/tests/libs/dl_preempt_library_1.cpp deleted file mode 100644 index b4d81d5ac..000000000 --- a/tests/libs/dl_preempt_library_1.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// This one should be preempted by the function -// defined in the main executable. -extern "C" int __attribute__((weak)) main_global_default_serial() { - return 2716057; -} - -// Even though this one is defined by the main -// executable it should not be preempted -// because of protected visibility -extern "C" int __attribute__((weak, visibility("protected"))) main_global_protected_serial() { - return 3370318; -} - -extern "C" int main_global_default_get_serial() { - return main_global_default_serial(); -} - -extern "C" int main_global_protected_get_serial() { - return main_global_protected_serial(); -} - -// Trying to preempt functions from a DT_NEEDED .so -extern "C" int lib_global_default_serial() { - return 3370318; -} - -extern "C" int lib_global_protected_serial() { - return 2716057; -} diff --git a/tests/libs/dl_preempt_library_2.cpp b/tests/libs/dl_preempt_library_2.cpp deleted file mode 100644 index 8df9a1667..000000000 --- a/tests/libs/dl_preempt_library_2.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// This one should be preempted by the function -// defined in libdl_preempt_test_1.so -extern "C" int __attribute__((weak)) lib_global_default_serial() { - return 2716057; -} - -// Even though this one is defined by -// libdl_preempt_test_1.so it should not be -// preempted because of protected visibility -extern "C" int __attribute__((weak,visibility("protected"))) lib_global_protected_serial() { - return 3370318; -} - -extern "C" int lib_global_default_get_serial() { - return lib_global_default_serial(); -} - -extern "C" int lib_global_protected_get_serial() { - return lib_global_protected_serial(); -} - From 4402804c35c5c5992c728c6f3cee3bdbd325819e Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 3 Nov 2014 21:14:31 -0800 Subject: [PATCH 090/114] Revert "Fix mips build" This reverts commit bf3d5ef5fd240d4c5fbde1b32f9084dbc720840b. Bug: 18222321 Bug: 18211780 Change-Id: I902ed888197b358c77303f1acb6d5ffd7ae6dcd3 --- linker/linker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index f8963b59c..c63ac35bb 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -2281,7 +2281,7 @@ bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo #endif #if defined(__mips__) - if (!mips_relocate_got(this, local_group)) { + if (!mips_relocate_got(this)) { return false; } #endif From eae09772558016836f1356816f4d1d0be498d74c Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 3 Nov 2014 21:15:15 -0800 Subject: [PATCH 091/114] Revert "Remove unnecessary lookups during relocations" This reverts commit 6442dbd3bcadbd5e522465743a8d8cf56338ae1c. Bug: 18222321 Bug: 18211780 Change-Id: I87b18a32238a1f75afe56149221b6691f50d9f56 --- linker/linker.cpp | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index c63ac35bb..eb1a483ae 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -530,11 +530,6 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c // 3. Look for it in the local group if (s == nullptr) { local_group.visit([&](soinfo* local_si) { - if (local_si == si && si->has_DT_SYMBOLIC) { - // we already did this - skip - return true; - } - DEBUG("%s: looking up %s in %s (from local group)", si->name, name, local_si->name); s = soinfo_elf_lookup(local_si, elf_hash, name); if (s != nullptr) { @@ -546,6 +541,28 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c }); } + // 4. Look for it in this library (unless we already did it because of DT_SYMBOLIC) + if (s == nullptr && !si->has_DT_SYMBOLIC) { + DEBUG("%s: looking up %s in local scope", si->name, name); + s = soinfo_elf_lookup(si, elf_hash, name); + if (s != nullptr) { + *lsi = si; + } + } + + // 5. Dependencies + if (s == nullptr) { + si->get_children().visit([&](soinfo* child) { + DEBUG("%s: looking up %s in %s", si->name, name, child->name); + s = soinfo_elf_lookup(child, elf_hash, name); + if (s != nullptr) { + *lsi = child; + return false; + } + return true; + }); + } + if (s != nullptr) { TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " "found in %s, base = %p, load bias = %p", From 00dce525530c5d26c20750863f3e9890b468787a Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 3 Nov 2014 21:15:25 -0800 Subject: [PATCH 092/114] Revert "Fix relocation to look for symbols in local group" This reverts commit fd2747bb585fc51b5ad56db09c0e9b66c7091a92. Bug: 18222321 Bug: 18211780 Change-Id: I2d4ebab1e73b7277161af76b99f8249825b22d65 --- linker/linked_list.h | 4 +- linker/linker.cpp | 193 +++++++----------- linker/linker.h | 6 +- tests/dlfcn_test.cpp | 186 ++--------------- .../Android.build.dlopen_check_order_dlsym.mk | 90 -------- ...lopen_check_order_reloc_main_executable.mk | 56 ----- ...build.dlopen_check_order_reloc_siblings.mk | 133 ------------ tests/libs/Android.mk | 75 ++++++- .../libs/dlopen_check_order_reloc_answer.cpp | 23 --- .../dlopen_check_order_reloc_answer_impl.cpp | 19 -- ...dlopen_check_order_reloc_nephew_answer.cpp | 21 -- .../dlopen_check_order_reloc_root_answer.cpp | 21 -- ...pen_check_order_reloc_root_answer_impl.cpp | 19 -- ...m_answer.cpp => dlopen_testlib_answer.cpp} | 4 +- 14 files changed, 162 insertions(+), 688 deletions(-) delete mode 100644 tests/libs/Android.build.dlopen_check_order_dlsym.mk delete mode 100644 tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk delete mode 100644 tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk delete mode 100644 tests/libs/dlopen_check_order_reloc_answer.cpp delete mode 100644 tests/libs/dlopen_check_order_reloc_answer_impl.cpp delete mode 100644 tests/libs/dlopen_check_order_reloc_nephew_answer.cpp delete mode 100644 tests/libs/dlopen_check_order_reloc_root_answer.cpp delete mode 100644 tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp rename tests/libs/{dlopen_check_order_dlsym_answer.cpp => dlopen_testlib_answer.cpp} (87%) diff --git a/linker/linked_list.h b/linker/linked_list.h index 72a32b4ba..4e62e208f 100644 --- a/linker/linked_list.h +++ b/linker/linked_list.h @@ -86,7 +86,7 @@ class LinkedList { } template - void for_each(F action) const { + void for_each(F action) { visit([&] (T* si) { action(si); return true; @@ -94,7 +94,7 @@ class LinkedList { } template - bool visit(F action) const { + bool visit(F action) { for (LinkedListEntry* e = head_; e != nullptr; e = e->next) { if (!action(e->element)) { return false; diff --git a/linker/linker.cpp b/linker/linker.cpp index eb1a483ae..41557e231 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -415,7 +415,7 @@ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void return rv; } -static ElfW(Sym)* soinfo_elf_lookup(const soinfo* si, unsigned hash, const char* name) { +static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) { ElfW(Sym)* symtab = si->symtab; TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd", @@ -481,7 +481,7 @@ static unsigned elfhash(const char* _name) { return h; } -static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, const soinfo::soinfo_list_t& local_group) { +static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { unsigned elf_hash = elfhash(name); ElfW(Sym)* s = nullptr; @@ -527,21 +527,16 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c } } - // 3. Look for it in the local group - if (s == nullptr) { - local_group.visit([&](soinfo* local_si) { - DEBUG("%s: looking up %s in %s (from local group)", si->name, name, local_si->name); - s = soinfo_elf_lookup(local_si, elf_hash, name); - if (s != nullptr) { - *lsi = local_si; - return false; - } + /* Look for symbols in the local scope (the object who is + * searching). This happens with C++ templates on x86 for some + * reason. + * + * Notes on weak symbols: + * The ELF specs are ambiguous about treatment of weak definitions in + * dynamic linking. Some systems return the first definition found + * and some the first non-weak definition. This is system dependent. + * Here we return the first definition found for simplicity. */ - return true; - }); - } - - // 4. Look for it in this library (unless we already did it because of DT_SYMBOLIC) if (s == nullptr && !si->has_DT_SYMBOLIC) { DEBUG("%s: looking up %s in local scope", si->name, name); s = soinfo_elf_lookup(si, elf_hash, name); @@ -550,7 +545,6 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c } } - // 5. Dependencies if (s == nullptr) { si->get_children().visit([&](soinfo* child) { DEBUG("%s: looking up %s in %s", si->name, name, child->name); @@ -649,61 +643,33 @@ typedef linked_list_t StringLinkedList; typedef linked_list_t LoadTaskList; -// This function walks down the tree of soinfo dependencies -// in breadth-first order and -// * calls action(soinfo* si) for each node, and -// * terminates walk if action returns false. -// -// walk_dependencies_tree returns false if walk was terminated -// by the action and true otherwise. -template -static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) { +// This is used by dlsym(3). It performs symbol lookup only within the +// specified soinfo object and its dependencies in breadth first order. +ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { SoinfoLinkedList visit_list; SoinfoLinkedList visited; - for (size_t i = 0; i < root_soinfos_size; ++i) { - visit_list.push_back(root_soinfos[i]); - } - - soinfo* si; - while ((si = visit_list.pop_front()) != nullptr) { - if (visited.contains(si)) { + visit_list.push_back(si); + soinfo* current_soinfo; + while ((current_soinfo = visit_list.pop_front()) != nullptr) { + if (visited.contains(current_soinfo)) { continue; } - if (!action(si)) { - return false; + ElfW(Sym)* result = soinfo_elf_lookup(current_soinfo, elfhash(name), name); + + if (result != nullptr) { + *found = current_soinfo; + return result; } + visited.push_back(current_soinfo); - visited.push_back(si); - - si->get_children().for_each([&](soinfo* child) { + current_soinfo->get_children().for_each([&](soinfo* child) { visit_list.push_back(child); }); } - return true; -} - - -// This is used by dlsym(3). It performs symbol lookup only within the -// specified soinfo object and its dependencies in breadth first order. -ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { - ElfW(Sym)* result = nullptr; - uint32_t elf_hash = elfhash(name); - - - walk_dependencies_tree(&si, 1, [&](soinfo* current_soinfo) { - result = soinfo_elf_lookup(current_soinfo, elf_hash, name); - if (result != nullptr) { - *found = current_soinfo; - return false; - } - - return true; - }); - - return result; + return nullptr; } /* This is used by dlsym(3) to performs a global symbol lookup. If the @@ -933,30 +899,19 @@ static bool is_recursive(soinfo* si, soinfo* parent) { }); } -static bool find_libraries(soinfo* start_with, const char* const library_names[], size_t library_names_count, soinfo* soinfos[], - soinfo* ld_preloads[], size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) { +static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[], + soinfo* ld_preloads[], size_t ld_preloads_size, int rtld_flags, const android_dlextinfo* extinfo) { // Step 0: prepare. LoadTaskList load_tasks; - for (size_t i = 0; i < library_names_count; ++i) { + for (size_t i = 0; i < library_names_size; ++i) { const char* name = library_names[i]; - load_tasks.push_back(LoadTask::create(name, start_with)); + load_tasks.push_back(LoadTask::create(name, nullptr)); } - // If soinfos array is null allocate one on stack. - // The array is needed in case of failure; for example - // when library_names[] = {libone.so, libtwo.so} and libone.so - // is loaded correctly but libtwo.so failed for some reason. - // In this case libone.so should be unloaded on return. - // See also implementation of failure_guard below. - - if (soinfos == nullptr) { - size_t soinfos_size = sizeof(soinfo*)*library_names_count; - soinfos = reinterpret_cast(alloca(soinfos_size)); - memset(soinfos, 0, soinfos_size); - } - - // list of libraries to link - see step 2. - size_t soinfos_count = 0; + // Libraries added to this list in reverse order so that we can + // start linking from bottom-up - see step 2. + SoinfoLinkedList found_libs; + size_t soinfos_size = 0; auto failure_guard = make_scope_guard([&]() { // Housekeeping @@ -964,7 +919,7 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[] LoadTask::deleter(t); }); - for (size_t i = 0; iadd_child(si); } + found_libs.push_front(si); - // When ld_preloads is not null, the first - // ld_preloads_count libs are in fact ld_preloads. - if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) { - ld_preloads[soinfos_count] = si; + // When ld_preloads is not null first + // ld_preloads_size libs are in fact ld_preloads. + if (ld_preloads != nullptr && soinfos_size < ld_preloads_size) { + ld_preloads[soinfos_size] = si; } - if (soinfos_count < library_names_count) { - soinfos[soinfos_count++] = si; + if (soinfos_sizeflags & FLAG_LINKED) == 0) { - if (!si->LinkImage(local_group, extinfo)) { + if (!si->LinkImage(extinfo)) { return false; } si->flags |= FLAG_LINKED; } - - return true; - }); - - if (linked) { - failure_guard.disable(); } - return linked; + // All is well - found_libs and load_tasks are empty at this point + // and all libs are successfully linked. + failure_guard.disable(); + return true; } static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) { @@ -1034,7 +979,7 @@ static soinfo* find_library(const char* name, int rtld_flags, const android_dlex soinfo* si; - if (!find_libraries(nullptr, &name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { + if (!find_libraries(&name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { return nullptr; } @@ -1145,7 +1090,7 @@ static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) { } #if defined(USE_RELA) -int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group) { +int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { for (size_t idx = 0; idx < count; ++idx, ++rela) { unsigned type = ELFW(R_TYPE)(rela->r_info); unsigned sym = ELFW(R_SYM)(rela->r_info); @@ -1163,7 +1108,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& loca if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi, local_group); + s = soinfo_do_lookup(this, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1422,7 +1367,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& loca } #else // REL, not RELA. -int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group) { +int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { for (size_t idx = 0; idx < count; ++idx, ++rel) { unsigned type = ELFW(R_TYPE)(rel->r_info); // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. @@ -1441,7 +1386,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_ if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi, local_group); + s = soinfo_do_lookup(this, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1627,7 +1572,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_ #endif #if defined(__mips__) -static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& local_group) { +static bool mips_relocate_got(soinfo* si) { ElfW(Addr)** got = si->plt_got; if (got == nullptr) { return true; @@ -1660,7 +1605,7 @@ static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& local_gro // This is an undefined reference... try to locate it. const char* sym_name = si->get_string(sym->st_name); soinfo* lsi = nullptr; - ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, local_group); + ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. s = &symtab[g]; @@ -2253,7 +2198,7 @@ bool soinfo::PrelinkImage() { return true; } -bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo) { +bool soinfo::LinkImage(const android_dlextinfo* extinfo) { #if !defined(__LP64__) if (has_text_relocations) { @@ -2272,26 +2217,26 @@ bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo #if defined(USE_RELA) if (rela != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rela, rela_count, local_group)) { + if (Relocate(rela, rela_count)) { return false; } } if (plt_rela != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rela, plt_rela_count, local_group)) { + if (Relocate(plt_rela, plt_rela_count)) { return false; } } #else if (rel != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rel, rel_count, local_group)) { + if (Relocate(rel, rel_count)) { return false; } } if (plt_rel != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rel, plt_rel_count, local_group)) { + if (Relocate(plt_rel, plt_rel_count)) { return false; } } @@ -2365,7 +2310,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->load_bias = get_elf_exec_load_bias(ehdr_vdso); si->PrelinkImage(); - si->LinkImage(g_empty_list, nullptr); + si->LinkImage(nullptr); #endif } @@ -2511,11 +2456,21 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( }); const char* needed_library_names[needed_libraries_count]; + soinfo* needed_library_si[needed_libraries_count]; memset(needed_library_names, 0, sizeof(needed_library_names)); needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); - if (needed_libraries_count > 0 && !find_libraries(si, needed_library_names, needed_libraries_count, nullptr, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { + if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { + __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); + exit(EXIT_FAILURE); + } + + for (size_t i = 0; iadd_child(needed_library_si[i]); + } + + if (!si->LinkImage(nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); } @@ -2639,7 +2594,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - if (!(linker_so.PrelinkImage() && linker_so.LinkImage(g_empty_list, nullptr))) { + if (!(linker_so.PrelinkImage() && linker_so.LinkImage(nullptr))) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as diff --git a/linker/linker.h b/linker/linker.h index 222aca11e..ebb4793af 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -207,7 +207,7 @@ struct soinfo { void CallDestructors(); void CallPreInitConstructors(); bool PrelinkImage(); - bool LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo); + bool LinkImage(const android_dlextinfo* extinfo); void add_child(soinfo* child); void remove_all_links(); @@ -234,9 +234,9 @@ struct soinfo { void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); #if defined(USE_RELA) - int Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group); + int Relocate(ElfW(Rela)* rela, unsigned count); #else - int Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group); + int Relocate(ElfW(Rel)* rel, unsigned count); #endif private: diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index e604f5abe..f1ec0f131 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -162,39 +162,39 @@ TEST(dlfcn, dlopen_check_relocation_dt_needed_order) { ASSERT_EQ(1, fn()); } -TEST(dlfcn, dlopen_check_order_dlsym) { +TEST(dlfcn, dlopen_check_order) { // Here is how the test library and its dt_needed // libraries are arranged // - // libtest_check_order_children.so + // libtest_check_order.so // | - // +-> ..._1_left.so + // +-> libtest_check_order_1_left.so // | | - // | +-> ..._a.so + // | +-> libtest_check_order_a.so // | | - // | +-> ...r_b.so + // | +-> libtest_check_order_b.so // | - // +-> ..._2_right.so + // +-> libtest_check_order_2_right.so // | | - // | +-> ..._d.so + // | +-> libtest_check_order_d.so // | | - // | +-> ..._b.so + // | +-> libtest_check_order_b.so // | - // +-> ..._3_c.so + // +-> libtest_check_order_3_c.so // // load order should be (1, 2, 3, a, b, d) // // get_answer() is defined in (2, 3, a, b, c) // get_answer2() is defined in (b, d) - void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"); + void* sym = dlsym(RTLD_DEFAULT, "dlopen_test_get_answer"); ASSERT_TRUE(sym == nullptr); - void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL); - ASSERT_TRUE(handle != nullptr) << dlerror(); + void* handle = dlopen("libtest_check_order.so", RTLD_NOW | RTLD_GLOBAL); + ASSERT_TRUE(handle != nullptr); typedef int (*fn_t) (void); fn_t fn, fn2; - fn = reinterpret_cast(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer")); + fn = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer")); ASSERT_TRUE(fn != NULL) << dlerror(); - fn2 = reinterpret_cast(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2")); + fn2 = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer2")); ASSERT_TRUE(fn2 != NULL) << dlerror(); ASSERT_EQ(42, fn()); @@ -202,163 +202,6 @@ TEST(dlfcn, dlopen_check_order_dlsym) { dlclose(handle); } -TEST(dlfcn, dlopen_check_order_reloc_siblings) { - // This is how this one works: - // we lookup and call get_answer which is defined in '_2.so' - // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so' - // the correct _impl() is implemented by '_a.so'; - // - // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?) - // - // Here is the picture: - // - // libtest_check_order_reloc_siblings.so - // | - // +-> ..._1.so <- empty - // | | - // | +-> ..._a.so <- exports correct answer_impl() - // | | - // | +-> ..._b.so <- every other letter exporting incorrect one. - // | - // +-> ..._2.so <- empty - // | | - // | +-> ..._c.so - // | | - // | +-> ..._d.so - // | - // +-> ..._3.so <- empty - // | - // +-> ..._e.so - // | - // +-> ..._f.so <- exports get_answer() that calls get_anser_impl(); - // implements incorrect get_answer_impl() - - void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); - ASSERT_TRUE(handle == nullptr); -#ifdef __BIONIC__ - // TODO: glibc returns nullptr on dlerror() here. Is it bug? - ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); -#endif - - handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); - ASSERT_TRUE(handle != nullptr) << dlerror(); - - typedef int (*fn_t) (void); - fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_get_answer")); - ASSERT_TRUE(fn != nullptr) << dlerror(); - ASSERT_EQ(42, fn()); - - ASSERT_EQ(0, dlclose(handle)); -} - -TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) { - // This test uses the same library as dlopen_check_order_reloc_siblings. - // Unlike dlopen_check_order_reloc_siblings it preloads - // libtest_check_order_reloc_siblings_1.so (first dependency) prior to - // dlopen(libtest_check_order_reloc_siblings.so) - - void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); - ASSERT_TRUE(handle == nullptr); - handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD); - ASSERT_TRUE(handle == nullptr); - - void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL); - ASSERT_TRUE(handle_for_1 != nullptr) << dlerror(); - - handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); - ASSERT_TRUE(handle != nullptr) << dlerror(); - - ASSERT_EQ(0, dlclose(handle_for_1)); - - typedef int (*fn_t) (void); - fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_get_answer")); - ASSERT_TRUE(fn != nullptr) << dlerror(); - ASSERT_EQ(42, fn()); - - ASSERT_EQ(0, dlclose(handle)); -} - -TEST(dlfcn, dlopen_check_order_reloc_nephew) { - // This is how this one works: - // we lookup and call nephew_get_answer which is defined in '_2.so' - // and in turn calls external get_answer_impl() defined in '_[a-f].so' - // the correct _impl() is implemented by '_a.so'; - // - // Here is the picture: - // - // libtest_check_order_reloc_siblings.so - // | - // +-> ..._1.so <- empty - // | | - // | +-> ..._a.so <- exports correct answer_impl() - // | | - // | +-> ..._b.so <- every other letter exporting incorrect one. - // | - // +-> ..._2.so <- empty - // | | - // | +-> ..._c.so - // | | - // | +-> ..._d.so - // | - // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl(); - // | - // +-> ..._e.so - // | - // +-> ..._f.so - - void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); - ASSERT_TRUE(handle == nullptr); -#ifdef __BIONIC__ - // TODO: glibc returns nullptr on dlerror() here. Is it bug? - ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); -#endif - - handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); - ASSERT_TRUE(handle != nullptr) << dlerror(); - - typedef int (*fn_t) (void); - fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_nephew_get_answer")); - ASSERT_TRUE(fn != nullptr) << dlerror(); - ASSERT_EQ(42, fn()); - - ASSERT_EQ(0, dlclose(handle)); -} - -extern "C" int check_order_reloc_root_get_answer_impl() { - return 42; -} - -TEST(dlfcn, dlopen_check_order_reloc_main_executable) { - // This is how this one works: - // we lookup and call get_answer3 which is defined in 'root.so' - // and in turn calls external root_get_answer_impl() defined in _2.so and - // above the correct _impl() is one in the executable. - // - // libtest_check_order_reloc_root.so - // | - // +-> ..._1.so <- empty - // | - // +-> ..._2.so <- gives incorrect answer for answer_main_impl() - // - - void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD); - ASSERT_TRUE(handle == nullptr); -#ifdef __BIONIC__ - // TODO: glibc returns nullptr on dlerror() here. Is it bug? - ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); -#endif - - handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL); - ASSERT_TRUE(handle != nullptr) << dlerror(); - - typedef int (*fn_t) (void); - fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_root_get_answer")); - ASSERT_TRUE(fn != nullptr) << dlerror(); - ASSERT_EQ(42, fn()); - - ASSERT_EQ(0, dlclose(handle)); -} - TEST(dlfcn, dlopen_check_rtld_local) { void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); ASSERT_TRUE(sym == nullptr); @@ -499,6 +342,7 @@ TEST(dlfcn, dlopen_nodelete_dt_flags_1) { ASSERT_TRUE(!is_unloaded); } + TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.build.dlopen_check_order_dlsym.mk b/tests/libs/Android.build.dlopen_check_order_dlsym.mk deleted file mode 100644 index 73d8c1a83..000000000 --- a/tests/libs/Android.build.dlopen_check_order_dlsym.mk +++ /dev/null @@ -1,90 +0,0 @@ -# -# Copyright (C) 2012 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# ----------------------------------------------------------------------------- -# Libraries used by dlfcn tests to verify correct load order: -# libtest_check_order_2_right.so -# ----------------------------------------------------------------------------- -libtest_check_order_dlsym_2_right_src_files := \ - dlopen_check_order_dlsym_answer.cpp - -libtest_check_order_dlsym_2_right_cflags := -D__ANSWER=42 -module := libtest_check_order_dlsym_2_right -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_a.so -# ----------------------------------------------------------------------------- -libtest_check_order_dlsym_a_src_files := \ - dlopen_check_order_dlsym_answer.cpp - -libtest_check_order_dlsym_a_cflags := -D__ANSWER=1 -module := libtest_check_order_dlsym_a -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_b.so -# ----------------------------------------------------------------------------- -libtest_check_order_dlsym_b_src_files := \ - dlopen_check_order_dlsym_answer.cpp - -libtest_check_order_dlsym_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 -module := libtest_check_order_dlsym_b -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_c.so -# ----------------------------------------------------------------------------- -libtest_check_order_dlsym_3_c_src_files := \ - dlopen_check_order_dlsym_answer.cpp - -libtest_check_order_dlsym_3_c_cflags := -D__ANSWER=3 -module := libtest_check_order_dlsym_3_c -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_d.so -# ----------------------------------------------------------------------------- -libtest_check_order_dlsym_d_src_files := \ - dlopen_check_order_dlsym_answer.cpp - -libtest_check_order_dlsym_d_shared_libraries := libtest_check_order_dlsym_b -libtest_check_order_dlsym_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 -module := libtest_check_order_dlsym_d -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_left.so -# ----------------------------------------------------------------------------- -libtest_check_order_dlsym_1_left_src_files := \ - empty.cpp - -libtest_check_order_dlsym_1_left_shared_libraries := libtest_check_order_dlsym_a libtest_check_order_dlsym_b - -module := libtest_check_order_dlsym_1_left -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order.so -# ----------------------------------------------------------------------------- -libtest_check_order_dlsym_src_files := \ - empty.cpp - -libtest_check_order_dlsym_shared_libraries := libtest_check_order_dlsym_1_left \ - libtest_check_order_dlsym_2_right libtest_check_order_dlsym_3_c - -module := libtest_check_order_dlsym -include $(LOCAL_PATH)/Android.build.testlib.mk diff --git a/tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk b/tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk deleted file mode 100644 index 639696b25..000000000 --- a/tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright (C) 2012 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# ----------------------------------------------------------------------------- -# Libraries used by dlfcn tests to verify correct relocation order: -# libtest_check_order_reloc_root*.so -# ----------------------------------------------------------------------------- - - -# ----------------------------------------------------------------------------- -# ..._1.so - empty -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_root_1_src_files := \ - empty.cpp - - -module := libtest_check_order_reloc_root_1 -include $(LOCAL_PATH)/Android.build.testlib.mk - - -# ----------------------------------------------------------------------------- -# ..._2.so - this one has the incorrect answer -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_root_2_src_files := \ - dlopen_check_order_reloc_root_answer_impl.cpp - -libtest_check_order_reloc_root_2_cflags := -D__ANSWER=2 - -module := libtest_check_order_reloc_root_2 -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_reloc_root.so <- implements get_answer3() -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_root_src_files := \ - dlopen_check_order_reloc_root_answer.cpp - -libtest_check_order_reloc_root_shared_libraries := \ - libtest_check_order_reloc_root_1 \ - libtest_check_order_reloc_root_2 - -module := libtest_check_order_reloc_root -include $(LOCAL_PATH)/Android.build.testlib.mk diff --git a/tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk b/tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk deleted file mode 100644 index 0f1a2b4da..000000000 --- a/tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk +++ /dev/null @@ -1,133 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# ----------------------------------------------------------------------------- -# Libraries used by dlfcn tests to verify correct relocation order: -# libtest_check_order_reloc_siblings*.so -# ----------------------------------------------------------------------------- - -# ----------------------------------------------------------------------------- -# ..._1.so - empty -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_siblings_1_src_files := \ - empty.cpp - -libtest_check_order_reloc_siblings_1_shared_libraries := \ - libtest_check_order_reloc_siblings_a \ - libtest_check_order_reloc_siblings_b - -module := libtest_check_order_reloc_siblings_1 -include $(LOCAL_PATH)/Android.build.testlib.mk - - -# ----------------------------------------------------------------------------- -# ..._2.so - empty -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_siblings_2_src_files := \ - empty.cpp - -libtest_check_order_reloc_siblings_2_shared_libraries := \ - libtest_check_order_reloc_siblings_c \ - libtest_check_order_reloc_siblings_d - -module := libtest_check_order_reloc_siblings_2 -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# ..._3.so - get_answer2(); -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_siblings_3_src_files := \ - dlopen_check_order_reloc_nephew_answer.cpp - -libtest_check_order_reloc_siblings_3_shared_libraries := \ - libtest_check_order_reloc_siblings_e \ - libtest_check_order_reloc_siblings_f - -module := libtest_check_order_reloc_siblings_3 -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# ..._a.so <- correct impl -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_siblings_a_src_files := \ - dlopen_check_order_reloc_answer_impl.cpp - -libtest_check_order_reloc_siblings_a_cflags := -D__ANSWER=42 -module := libtest_check_order_reloc_siblings_a -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# ..._b.so -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_siblings_b_src_files := \ - dlopen_check_order_reloc_answer_impl.cpp - -libtest_check_order_reloc_siblings_b_cflags := -D__ANSWER=1 -module := libtest_check_order_reloc_siblings_b -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# ..._c.so -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_siblings_c_src_files := \ - dlopen_check_order_reloc_answer_impl.cpp - -libtest_check_order_reloc_siblings_c_cflags := -D__ANSWER=2 -module := libtest_check_order_reloc_siblings_c -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# ..._d.so -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_siblings_d_src_files := \ - dlopen_check_order_reloc_answer_impl.cpp - -libtest_check_order_reloc_siblings_d_cflags := -D__ANSWER=3 -module := libtest_check_order_reloc_siblings_d -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# ..._e.so -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_siblings_e_src_files := \ - dlopen_check_order_reloc_answer_impl.cpp - -libtest_check_order_reloc_siblings_e_cflags := -D__ANSWER=4 -module := libtest_check_order_reloc_siblings_e -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# ..._f.so <- get_answer() -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_siblings_f_src_files := \ - dlopen_check_order_reloc_answer.cpp - -module := libtest_check_order_reloc_siblings_f -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_reloc_siblings.so -# ----------------------------------------------------------------------------- -libtest_check_order_reloc_siblings_src_files := \ - empty.cpp - -libtest_check_order_reloc_siblings_shared_libraries := \ - libtest_check_order_reloc_siblings_1 \ - libtest_check_order_reloc_siblings_2 \ - libtest_check_order_reloc_siblings_3 - -module := libtest_check_order_reloc_siblings -include $(LOCAL_PATH)/Android.build.testlib.mk diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 05e7113ba..175a63539 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -21,9 +21,6 @@ common_cppflags += -std=gnu++11 common_additional_dependencies := \ $(LOCAL_PATH)/Android.mk \ $(LOCAL_PATH)/Android.build.dlext_testzip.mk \ - $(LOCAL_PATH)/Android.build.dlopen_check_order_dlsym.mk \ - $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_siblings.mk \ - $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_main_executable.mk \ $(LOCAL_PATH)/Android.build.testlib.mk \ $(TEST_PATH)/Android.build.mk @@ -153,19 +150,79 @@ module := libtest_nodelete_dt_flags_1 include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- -# Build libtest_check_order_dlsym.so with its dependencies. +# Libraries used by dlfcn tests to verify correct load order: +# libtest_check_order_2_right.so # ----------------------------------------------------------------------------- -include $(LOCAL_PATH)/Android.build.dlopen_check_order_dlsym.mk +libtest_check_order_2_right_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_2_right_cflags := -D__ANSWER=42 +module := libtest_check_order_2_right +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- -# Build libtest_check_order_siblings.so with its dependencies. +# libtest_check_order_a.so # ----------------------------------------------------------------------------- -include $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_siblings.mk +libtest_check_order_a_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_a_cflags := -D__ANSWER=1 +module := libtest_check_order_a +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- -# Build libtest_check_order_root.so with its dependencies. +# libtest_check_order_b.so # ----------------------------------------------------------------------------- -include $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_main_executable.mk +libtest_check_order_b_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 +module := libtest_check_order_b +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_c.so +# ----------------------------------------------------------------------------- +libtest_check_order_3_c_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_3_c_cflags := -D__ANSWER=3 +module := libtest_check_order_3_c +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_d.so +# ----------------------------------------------------------------------------- +libtest_check_order_d_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_d_shared_libraries := libtest_check_order_b +libtest_check_order_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 +module := libtest_check_order_d +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_left.so +# ----------------------------------------------------------------------------- +libtest_check_order_1_left_src_files := \ + empty.cpp + +libtest_check_order_1_left_shared_libraries := libtest_check_order_a libtest_check_order_b + +module := libtest_check_order_1_left +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order.so +# ----------------------------------------------------------------------------- +libtest_check_order_src_files := \ + empty.cpp + +libtest_check_order_shared_libraries := libtest_check_order_1_left \ + libtest_check_order_2_right libtest_check_order_3_c + +module := libtest_check_order +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # Library with dependency loop used by dlfcn tests diff --git a/tests/libs/dlopen_check_order_reloc_answer.cpp b/tests/libs/dlopen_check_order_reloc_answer.cpp deleted file mode 100644 index 036670bee..000000000 --- a/tests/libs/dlopen_check_order_reloc_answer.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -extern "C" int __attribute__((weak)) check_order_reloc_get_answer_impl() { - return 0; -} - -extern "C" int check_order_reloc_get_answer() { - return check_order_reloc_get_answer_impl(); -} diff --git a/tests/libs/dlopen_check_order_reloc_answer_impl.cpp b/tests/libs/dlopen_check_order_reloc_answer_impl.cpp deleted file mode 100644 index 324b905da..000000000 --- a/tests/libs/dlopen_check_order_reloc_answer_impl.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -extern "C" int check_order_reloc_get_answer_impl() { - return __ANSWER; -} diff --git a/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp b/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp deleted file mode 100644 index 065d1bef7..000000000 --- a/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -extern "C" int check_order_reloc_get_answer_impl(); - -extern "C" int check_order_reloc_nephew_get_answer() { - return check_order_reloc_get_answer_impl(); -} diff --git a/tests/libs/dlopen_check_order_reloc_root_answer.cpp b/tests/libs/dlopen_check_order_reloc_root_answer.cpp deleted file mode 100644 index b21abd77a..000000000 --- a/tests/libs/dlopen_check_order_reloc_root_answer.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -extern "C" int check_order_reloc_root_get_answer_impl(); - -extern "C" int check_order_reloc_root_get_answer() { - return check_order_reloc_root_get_answer_impl(); -} diff --git a/tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp b/tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp deleted file mode 100644 index 25fb9aca9..000000000 --- a/tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -extern "C" int check_order_reloc_root_get_answer_impl() { - return __ANSWER; -} diff --git a/tests/libs/dlopen_check_order_dlsym_answer.cpp b/tests/libs/dlopen_testlib_answer.cpp similarity index 87% rename from tests/libs/dlopen_check_order_dlsym_answer.cpp rename to tests/libs/dlopen_testlib_answer.cpp index 2ae6cf79e..a4d75046e 100644 --- a/tests/libs/dlopen_check_order_dlsym_answer.cpp +++ b/tests/libs/dlopen_testlib_answer.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -extern "C" int check_order_dlsym_get_answer() { +extern "C" int dlopen_test_get_answer() { return __ANSWER; } #ifdef __ANSWER2 -extern "C" int check_order_dlsym_get_answer2() { +extern "C" int dlopen_test_get_answer2() { return __ANSWER2; } #endif From 69c5d108a5cb44167a04d42ffdad6a39648ed235 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 3 Nov 2014 22:08:31 -0800 Subject: [PATCH 093/114] Revert "Add RTLD_NODELETE flag support" This reverts commit c87f65d2cd0690d81665f8b241c1d763f72b6f80. Bug: 18222321 Bug: 18211780 Change-Id: I00252e26a28a41ab9f1e2dd3b32f0f80d86297f1 --- libc/include/dlfcn.h | 1 - linker/linker.cpp | 16 +---- linker/linker.h | 18 +++-- tests/dlfcn_test.cpp | 80 ----------------------- tests/libs/Android.mk | 29 -------- tests/libs/dlopen_nodelete_1.cpp | 31 --------- tests/libs/dlopen_nodelete_2.cpp | 31 --------- tests/libs/dlopen_nodelete_dt_flags_1.cpp | 30 --------- 8 files changed, 10 insertions(+), 226 deletions(-) delete mode 100644 tests/libs/dlopen_nodelete_1.cpp delete mode 100644 tests/libs/dlopen_nodelete_2.cpp delete mode 100644 tests/libs/dlopen_nodelete_dt_flags_1.cpp diff --git a/libc/include/dlfcn.h b/libc/include/dlfcn.h index afa76878f..8dde08cf5 100644 --- a/libc/include/dlfcn.h +++ b/libc/include/dlfcn.h @@ -64,7 +64,6 @@ enum { RTLD_GLOBAL = 2, #endif RTLD_NOLOAD = 4, - RTLD_NODELETE = 0x01000, }; #if defined (__LP64__) diff --git a/linker/linker.cpp b/linker/linker.cpp index 41557e231..636541297 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -987,11 +987,6 @@ static soinfo* find_library(const char* name, int rtld_flags, const android_dlex } static void soinfo_unload(soinfo* si) { - if (!si->can_unload()) { - TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->name); - return; - } - if (si->ref_count == 1) { TRACE("unloading '%s'", si->name); si->CallDestructors(); @@ -1050,7 +1045,7 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) { } soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) { - if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) { + if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NOLOAD)) != 0) { DL_ERR("invalid flags to dlopen: %x", flags); return nullptr; } @@ -1813,9 +1808,6 @@ const char* soinfo::get_string(ElfW(Word) index) const { return strtab + index; } -bool soinfo::can_unload() const { - return (rtld_flags & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; -} /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -2119,13 +2111,9 @@ bool soinfo::PrelinkImage() { if ((d->d_un.d_val & DF_1_GLOBAL) != 0) { rtld_flags |= RTLD_GLOBAL; } - - if ((d->d_un.d_val & DF_1_NODELETE) != 0) { - rtld_flags |= RTLD_NODELETE; - } // TODO: Implement other flags - if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)) != 0) { + if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL)) != 0) { DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast(d->d_un.d_val)); } break; diff --git a/linker/linker.h b/linker/linker.h index ebb4793af..6329efda6 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -134,7 +134,7 @@ struct soinfo { #endif soinfo* next; - uint32_t flags; + unsigned flags; private: const char* strtab; @@ -143,8 +143,8 @@ struct soinfo { size_t nbucket; size_t nchain; - uint32_t* bucket; - uint32_t* chain; + unsigned* bucket; + unsigned* chain; #if defined(__mips__) || !defined(__LP64__) // This is only used by mips and mips64, but needs to be here for @@ -179,12 +179,12 @@ struct soinfo { #if defined(__arm__) // ARM EABI section used for stack unwinding. - uint32_t* ARM_exidx; + unsigned* ARM_exidx; size_t ARM_exidx_count; #elif defined(__mips__) - uint32_t mips_symtabno; - uint32_t mips_local_gotno; - uint32_t mips_gotsym; + unsigned mips_symtabno; + unsigned mips_local_gotno; + unsigned mips_gotsym; #endif size_t ref_count; @@ -224,12 +224,10 @@ struct soinfo { ElfW(Addr) resolve_symbol_address(ElfW(Sym)* s); const char* get_string(ElfW(Word) index) const; - bool can_unload() const; bool inline has_min_version(uint32_t min_version) const { return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; } - private: void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); @@ -260,7 +258,7 @@ struct soinfo { friend soinfo* get_libdl_info(); }; -soinfo* get_libdl_info(); +extern soinfo* get_libdl_info(); void do_android_get_LD_LIBRARY_PATH(char*, size_t); void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path); diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index f1ec0f131..c9c856a37 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -232,15 +232,10 @@ TEST(dlfcn, dlopen_check_rtld_global) { ASSERT_TRUE(sym == nullptr); void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL); - ASSERT_TRUE(handle != nullptr) << dlerror(); sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); ASSERT_TRUE(sym != nullptr) << dlerror(); ASSERT_TRUE(reinterpret_cast(sym)()); dlclose(handle); - - // RTLD_GLOBAL implies RTLD_NODELETE, let's check that - void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); - ASSERT_EQ(sym, sym_after_dlclose); } // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> @@ -268,81 +263,6 @@ TEST(dlfcn, dlopen_check_loop) { #endif } -TEST(dlfcn, dlopen_nodelete) { - static bool is_unloaded = false; - - void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE); - ASSERT_TRUE(handle != nullptr) << dlerror(); - void (*set_unload_flag_ptr)(bool*); - set_unload_flag_ptr = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr")); - ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); - set_unload_flag_ptr(&is_unloaded); - - uint32_t* taxicab_number = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); - ASSERT_TRUE(taxicab_number != nullptr) << dlerror(); - ASSERT_EQ(1729U, *taxicab_number); - *taxicab_number = 2; - - dlclose(handle); - ASSERT_TRUE(!is_unloaded); - - uint32_t* taxicab_number_after_dlclose = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); - ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number); - ASSERT_EQ(2U, *taxicab_number_after_dlclose); - - - handle = dlopen("libtest_nodelete_1.so", RTLD_NOW); - uint32_t* taxicab_number2 = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); - ASSERT_EQ(taxicab_number2, taxicab_number); - - ASSERT_EQ(2U, *taxicab_number2); - - dlclose(handle); - ASSERT_TRUE(!is_unloaded); -} - -TEST(dlfcn, dlopen_nodelete_on_second_dlopen) { - static bool is_unloaded = false; - - void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW); - ASSERT_TRUE(handle != nullptr) << dlerror(); - void (*set_unload_flag_ptr)(bool*); - set_unload_flag_ptr = reinterpret_cast(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr")); - ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); - set_unload_flag_ptr(&is_unloaded); - - uint32_t* taxicab_number = reinterpret_cast(dlsym(handle, "dlopen_nodelete_2_taxicab_number")); - ASSERT_TRUE(taxicab_number != nullptr) << dlerror(); - - ASSERT_EQ(1729U, *taxicab_number); - *taxicab_number = 2; - - // This RTLD_NODELETE should be ignored - void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE); - ASSERT_TRUE(handle1 != nullptr) << dlerror(); - ASSERT_EQ(handle, handle1); - - dlclose(handle1); - dlclose(handle); - - ASSERT_TRUE(is_unloaded); -} - -TEST(dlfcn, dlopen_nodelete_dt_flags_1) { - static bool is_unloaded = false; - - void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW); - ASSERT_TRUE(handle != nullptr) << dlerror(); - void (*set_unload_flag_ptr)(bool*); - set_unload_flag_ptr = reinterpret_cast(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr")); - ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); - set_unload_flag_ptr(&is_unloaded); - - dlclose(handle); - ASSERT_TRUE(!is_unloaded); -} - - TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 175a63539..af3e070a8 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -120,35 +120,6 @@ libtest_simple_src_files := \ module := libtest_simple include $(LOCAL_PATH)/Android.build.testlib.mk -# ----------------------------------------------------------------------------- -# Library used by dlfcn nodelete tests -# ----------------------------------------------------------------------------- -libtest_nodelete_1_src_files := \ - dlopen_nodelete_1.cpp - -module := libtest_nodelete_1 -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# Library used by dlfcn nodelete tests -# ----------------------------------------------------------------------------- -libtest_nodelete_2_src_files := \ - dlopen_nodelete_2.cpp - -module := libtest_nodelete_2 -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# Library used by dlfcn nodelete tests -# ----------------------------------------------------------------------------- -libtest_nodelete_dt_flags_1_src_files := \ - dlopen_nodelete_dt_flags_1.cpp - -libtest_nodelete_dt_flags_1_ldflags := -Wl,-z,nodelete - -module := libtest_nodelete_dt_flags_1 -include $(LOCAL_PATH)/Android.build.testlib.mk - # ----------------------------------------------------------------------------- # Libraries used by dlfcn tests to verify correct load order: # libtest_check_order_2_right.so diff --git a/tests/libs/dlopen_nodelete_1.cpp b/tests/libs/dlopen_nodelete_1.cpp deleted file mode 100644 index 943897815..000000000 --- a/tests/libs/dlopen_nodelete_1.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -uint32_t dlopen_nodelete_1_taxicab_number = 1729; -static bool* unload_flag_ptr = nullptr; - -extern "C" void dlopen_nodelete_1_set_unload_flag_ptr(bool* ptr) { - unload_flag_ptr = ptr; -} - -static void __attribute__((destructor)) unload_guard() { - if (unload_flag_ptr != nullptr) { - *unload_flag_ptr = true; - } -} diff --git a/tests/libs/dlopen_nodelete_2.cpp b/tests/libs/dlopen_nodelete_2.cpp deleted file mode 100644 index b5ab5c1ae..000000000 --- a/tests/libs/dlopen_nodelete_2.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -uint32_t dlopen_nodelete_2_taxicab_number = 1729; -static bool* unload_flag_ptr = nullptr; - -extern "C" void dlopen_nodelete_2_set_unload_flag_ptr(bool* ptr) { - unload_flag_ptr = ptr; -} - -static void __attribute__((destructor)) unload_guard() { - if (unload_flag_ptr != nullptr) { - *unload_flag_ptr = true; - } -} diff --git a/tests/libs/dlopen_nodelete_dt_flags_1.cpp b/tests/libs/dlopen_nodelete_dt_flags_1.cpp deleted file mode 100644 index 39c0a7ea6..000000000 --- a/tests/libs/dlopen_nodelete_dt_flags_1.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -static bool* unload_flag_ptr = nullptr; - -extern "C" void dlopen_nodelete_dt_flags_1_set_unload_flag_ptr(bool* ptr) { - unload_flag_ptr = ptr; -} - -static void __attribute__((destructor)) unload_guard() { - if (unload_flag_ptr != nullptr) { - *unload_flag_ptr = true; - } -} From 9d3382d97a2cdc8c8f78c7825ece16f09292fc36 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Mon, 3 Nov 2014 22:12:19 -0800 Subject: [PATCH 094/114] Revert "Fix dlsym() to take into account RTLD_GLOBAL/LOCAL" This reverts commit c85e82dde5c4b2accc50a9e17740b9005dfbae6a. Bug: 18222321 Bug: 18211780 Change-Id: I32f4048bd5ea85dc8a3dfccce8cf141b241ab692 --- linker/dlfcn.cpp | 2 +- linker/linker.cpp | 48 ++++++++++------------------ linker/linker.h | 4 +-- tests/dlfcn_test.cpp | 36 --------------------- tests/libs/dlopen_testlib_simple.cpp | 2 +- 5 files changed, 20 insertions(+), 72 deletions(-) diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 367179d8d..3eb5bea22 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -232,7 +232,7 @@ static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 }; static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; #endif -static soinfo __libdl_info("libdl.so", nullptr, 0, RTLD_GLOBAL); +static soinfo __libdl_info("libdl.so", nullptr, 0); // This is used by the dynamic linker. Every process gets these symbols for free. soinfo* get_libdl_info() { diff --git a/linker/linker.cpp b/linker/linker.cpp index 636541297..35c8cbdc8 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -282,13 +282,13 @@ static void protect_data(int protection) { g_soinfo_links_allocator.protect_all(protection); } -static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, int rtld_flags) { +static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset) { if (strlen(name) >= SOINFO_NAME_LEN) { DL_ERR("library name \"%s\" too long", name); return nullptr; } - soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags); + soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset); sonext->next = si; sonext = si; @@ -452,7 +452,7 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) return nullptr; } -soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags) { +soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset) { memset(this, 0, sizeof(*this)); strlcpy(this->name, name, sizeof(this->name)); @@ -464,8 +464,6 @@ soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offs this->st_ino = file_stat->st_ino; this->file_offset = file_offset; } - - this->rtld_flags = rtld_flags; } static unsigned elfhash(const char* _name) { @@ -686,10 +684,6 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) ElfW(Sym)* s = nullptr; for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) { - if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) { - continue; - } - s = soinfo_elf_lookup(si, elf_hash, name); if (s != nullptr) { *found = si; @@ -780,7 +774,7 @@ static void for_each_dt_needed(const soinfo* si, F action) { } } -static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { +static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { int fd = -1; off64_t file_offset = 0; ScopedFd file_guard(-1); @@ -825,7 +819,7 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld } } - if ((rtld_flags & RTLD_NOLOAD) != 0) { + if ((dlflags & RTLD_NOLOAD) != 0) { DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name); return nullptr; } @@ -836,7 +830,7 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld return nullptr; } - soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset, rtld_flags); + soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset); if (si == nullptr) { return nullptr; } @@ -868,7 +862,7 @@ static soinfo *find_loaded_library_by_name(const char* name) { return nullptr; } -static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { +static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { soinfo* si = find_loaded_library_by_name(name); @@ -876,7 +870,7 @@ static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, // of this fact is done by load_library. if (si == nullptr) { TRACE("[ '%s' has not been found by name. Trying harder...]", name); - si = load_library(load_tasks, name, rtld_flags, extinfo); + si = load_library(load_tasks, name, dlflags, extinfo); } return si; @@ -900,7 +894,7 @@ static bool is_recursive(soinfo* si, soinfo* parent) { } static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[], - soinfo* ld_preloads[], size_t ld_preloads_size, int rtld_flags, const android_dlextinfo* extinfo) { + soinfo* ld_preloads[], size_t ld_preloads_size, int dlflags, const android_dlextinfo* extinfo) { // Step 0: prepare. LoadTaskList load_tasks; for (size_t i = 0; i < library_names_size; ++i) { @@ -926,7 +920,7 @@ static bool find_libraries(const char* const library_names[], size_t library_nam // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order. for (LoadTask::unique_ptr task(load_tasks.pop_front()); task.get() != nullptr; task.reset(load_tasks.pop_front())) { - soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo); + soinfo* si = find_library_internal(load_tasks, task->get_name(), dlflags, extinfo); if (si == nullptr) { return false; } @@ -971,7 +965,7 @@ static bool find_libraries(const char* const library_names[], size_t library_nam return true; } -static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) { +static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { if (name == nullptr) { somain->ref_count++; return somain; @@ -979,7 +973,7 @@ static soinfo* find_library(const char* name, int rtld_flags, const android_dlex soinfo* si; - if (!find_libraries(&name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { + if (!find_libraries(&name, 1, &si, nullptr, 0, dlflags, extinfo)) { return nullptr; } @@ -1764,14 +1758,6 @@ off64_t soinfo::get_file_offset() { return 0; } -int soinfo::get_rtld_flags() { - if (has_min_version(1)) { - return rtld_flags; - } - - return 0; -} - // This is a return on get_children()/get_parents() if // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -2289,7 +2275,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { return; } - soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0); + soinfo* si = soinfo_alloc("[vdso]", nullptr, 0); si->phdr = reinterpret_cast(reinterpret_cast(ehdr_vdso) + ehdr_vdso->e_phoff); si->phnum = ehdr_vdso->e_phnum; @@ -2310,7 +2296,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { #else #define LINKER_PATH "/system/bin/linker" #endif -static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0, 0); +static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0); /* gdb expects the linker to be in the debug shared object list. * Without this, gdb has trouble locating the linker's ".text" @@ -2374,7 +2360,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( INFO("[ android linker & debugger ]"); - soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL); + soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0); if (si == nullptr) { exit(EXIT_FAILURE); } @@ -2449,7 +2435,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( memset(needed_library_names, 0, sizeof(needed_library_names)); needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); - if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { + if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, 0, nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); } @@ -2562,7 +2548,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_addr); ElfW(Phdr)* phdr = reinterpret_cast(linker_addr + elf_hdr->e_phoff); - soinfo linker_so("[dynamic linker]", nullptr, 0, 0); + soinfo linker_so("[dynamic linker]", nullptr, 0); // If the linker is not acting as PT_INTERP entry_point is equal to // _start. Which means that the linker is running as an executable and diff --git a/linker/linker.h b/linker/linker.h index 6329efda6..fa38c7fef 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -201,7 +201,7 @@ struct soinfo { #endif bool has_DT_SYMBOLIC; - soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags); + soinfo(const char* name, const struct stat* file_stat, off64_t file_offset); void CallConstructors(); void CallDestructors(); @@ -216,8 +216,6 @@ struct soinfo { dev_t get_st_dev(); off64_t get_file_offset(); - int get_rtld_flags(); - soinfo_list_t& get_children(); soinfo_list_t& get_parents(); diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index c9c856a37..e24af13c0 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -202,42 +202,6 @@ TEST(dlfcn, dlopen_check_order) { dlclose(handle); } -TEST(dlfcn, dlopen_check_rtld_local) { - void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); - ASSERT_TRUE(sym == nullptr); - - // implicit RTLD_LOCAL - void* handle = dlopen("libtest_simple.so", RTLD_NOW); - sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); - ASSERT_TRUE(sym == nullptr); - ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror()); - sym = dlsym(handle, "dlopen_testlib_simple_func"); - ASSERT_TRUE(sym != nullptr); - ASSERT_TRUE(reinterpret_cast(sym)()); - dlclose(handle); - - // explicit RTLD_LOCAL - handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL); - sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); - ASSERT_TRUE(sym == nullptr); - ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror()); - sym = dlsym(handle, "dlopen_testlib_simple_func"); - ASSERT_TRUE(sym != nullptr); - ASSERT_TRUE(reinterpret_cast(sym)()); - dlclose(handle); -} - -TEST(dlfcn, dlopen_check_rtld_global) { - void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); - ASSERT_TRUE(sym == nullptr); - - void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL); - sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); - ASSERT_TRUE(sym != nullptr) << dlerror(); - ASSERT_TRUE(reinterpret_cast(sym)()); - dlclose(handle); -} - // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> // libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so -> // libtest_with_dependency_loop_a.so diff --git a/tests/libs/dlopen_testlib_simple.cpp b/tests/libs/dlopen_testlib_simple.cpp index 32269557a..bf750b2a6 100644 --- a/tests/libs/dlopen_testlib_simple.cpp +++ b/tests/libs/dlopen_testlib_simple.cpp @@ -19,6 +19,6 @@ uint32_t dlopen_testlib_taxicab_number = 1729; -extern "C" bool dlopen_testlib_simple_func() { +bool dlopen_testlib_simple_func() { return true; } From 68a555b57e2bed1292bf28609be693a95b5fdc6b Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 4 Nov 2014 09:37:19 -0800 Subject: [PATCH 095/114] Revert "Revert "Fix dlsym() to take into account RTLD_GLOBAL/LOCAL"" This reverts commit 9d3382d97a2cdc8c8f78c7825ece16f09292fc36. --- linker/dlfcn.cpp | 2 +- linker/linker.cpp | 48 ++++++++++++++++++---------- linker/linker.h | 4 ++- tests/dlfcn_test.cpp | 36 +++++++++++++++++++++ tests/libs/dlopen_testlib_simple.cpp | 2 +- 5 files changed, 72 insertions(+), 20 deletions(-) diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 3eb5bea22..367179d8d 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -232,7 +232,7 @@ static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 }; static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; #endif -static soinfo __libdl_info("libdl.so", nullptr, 0); +static soinfo __libdl_info("libdl.so", nullptr, 0, RTLD_GLOBAL); // This is used by the dynamic linker. Every process gets these symbols for free. soinfo* get_libdl_info() { diff --git a/linker/linker.cpp b/linker/linker.cpp index 60dabacbe..eadfe5efe 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -282,13 +282,13 @@ static void protect_data(int protection) { g_soinfo_links_allocator.protect_all(protection); } -static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset) { +static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, int rtld_flags) { if (strlen(name) >= SOINFO_NAME_LEN) { DL_ERR("library name \"%s\" too long", name); return nullptr; } - soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset); + soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags); sonext->next = si; sonext = si; @@ -452,7 +452,7 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) return nullptr; } -soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset) { +soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags) { memset(this, 0, sizeof(*this)); strlcpy(this->name, name, sizeof(this->name)); @@ -464,6 +464,8 @@ soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offs this->st_ino = file_stat->st_ino; this->file_offset = file_offset; } + + this->rtld_flags = rtld_flags; } static unsigned elfhash(const char* _name) { @@ -684,6 +686,10 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) ElfW(Sym)* s = nullptr; for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) { + if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) { + continue; + } + s = soinfo_elf_lookup(si, elf_hash, name); if (s != nullptr) { *found = si; @@ -774,7 +780,7 @@ static void for_each_dt_needed(const soinfo* si, F action) { } } -static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { +static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { int fd = -1; off64_t file_offset = 0; ScopedFd file_guard(-1); @@ -819,7 +825,7 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl } } - if ((dlflags & RTLD_NOLOAD) != 0) { + if ((rtld_flags & RTLD_NOLOAD) != 0) { DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name); return nullptr; } @@ -830,7 +836,7 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl return nullptr; } - soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset); + soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset, rtld_flags); if (si == nullptr) { return nullptr; } @@ -862,7 +868,7 @@ static soinfo *find_loaded_library_by_name(const char* name) { return nullptr; } -static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) { +static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { soinfo* si = find_loaded_library_by_name(name); @@ -870,7 +876,7 @@ static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, // of this fact is done by load_library. if (si == nullptr) { TRACE("[ '%s' has not been found by name. Trying harder...]", name); - si = load_library(load_tasks, name, dlflags, extinfo); + si = load_library(load_tasks, name, rtld_flags, extinfo); } return si; @@ -894,7 +900,7 @@ static bool is_recursive(soinfo* si, soinfo* parent) { } static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[], - soinfo* ld_preloads[], size_t ld_preloads_size, int dlflags, const android_dlextinfo* extinfo) { + soinfo* ld_preloads[], size_t ld_preloads_size, int rtld_flags, const android_dlextinfo* extinfo) { // Step 0: prepare. LoadTaskList load_tasks; for (size_t i = 0; i < library_names_size; ++i) { @@ -920,7 +926,7 @@ static bool find_libraries(const char* const library_names[], size_t library_nam // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order. for (LoadTask::unique_ptr task(load_tasks.pop_front()); task.get() != nullptr; task.reset(load_tasks.pop_front())) { - soinfo* si = find_library_internal(load_tasks, task->get_name(), dlflags, extinfo); + soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo); if (si == nullptr) { return false; } @@ -965,7 +971,7 @@ static bool find_libraries(const char* const library_names[], size_t library_nam return true; } -static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { +static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) { if (name == nullptr) { somain->ref_count++; return somain; @@ -973,7 +979,7 @@ static soinfo* find_library(const char* name, int dlflags, const android_dlextin soinfo* si; - if (!find_libraries(&name, 1, &si, nullptr, 0, dlflags, extinfo)) { + if (!find_libraries(&name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { return nullptr; } @@ -1758,6 +1764,14 @@ off64_t soinfo::get_file_offset() { return 0; } +int soinfo::get_rtld_flags() { + if (has_min_version(1)) { + return rtld_flags; + } + + return 0; +} + // This is a return on get_children()/get_parents() if // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -2275,7 +2289,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { return; } - soinfo* si = soinfo_alloc("[vdso]", nullptr, 0); + soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0); si->phdr = reinterpret_cast(reinterpret_cast(ehdr_vdso) + ehdr_vdso->e_phoff); si->phnum = ehdr_vdso->e_phnum; @@ -2296,7 +2310,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { #else #define LINKER_PATH "/system/bin/linker" #endif -static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0); +static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0, 0); /* gdb expects the linker to be in the debug shared object list. * Without this, gdb has trouble locating the linker's ".text" @@ -2360,7 +2374,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( INFO("[ android linker & debugger ]"); - soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0); + soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL); if (si == nullptr) { exit(EXIT_FAILURE); } @@ -2435,7 +2449,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( memset(needed_library_names, 0, sizeof(needed_library_names)); needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); - if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, 0, nullptr)) { + if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); } @@ -2548,7 +2562,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_addr); ElfW(Phdr)* phdr = reinterpret_cast(linker_addr + elf_hdr->e_phoff); - soinfo linker_so("[dynamic linker]", nullptr, 0); + soinfo linker_so("[dynamic linker]", nullptr, 0, 0); // If the linker is not acting as PT_INTERP entry_point is equal to // _start. Which means that the linker is running as an executable and diff --git a/linker/linker.h b/linker/linker.h index fa38c7fef..6329efda6 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -201,7 +201,7 @@ struct soinfo { #endif bool has_DT_SYMBOLIC; - soinfo(const char* name, const struct stat* file_stat, off64_t file_offset); + soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags); void CallConstructors(); void CallDestructors(); @@ -216,6 +216,8 @@ struct soinfo { dev_t get_st_dev(); off64_t get_file_offset(); + int get_rtld_flags(); + soinfo_list_t& get_children(); soinfo_list_t& get_parents(); diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 504aca3fa..1bf186b4b 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -202,6 +202,42 @@ TEST(dlfcn, dlopen_check_order) { dlclose(handle); } +TEST(dlfcn, dlopen_check_rtld_local) { + void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym == nullptr); + + // implicit RTLD_LOCAL + void* handle = dlopen("libtest_simple.so", RTLD_NOW); + sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym == nullptr); + ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror()); + sym = dlsym(handle, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym != nullptr); + ASSERT_TRUE(reinterpret_cast(sym)()); + dlclose(handle); + + // explicit RTLD_LOCAL + handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL); + sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym == nullptr); + ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror()); + sym = dlsym(handle, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym != nullptr); + ASSERT_TRUE(reinterpret_cast(sym)()); + dlclose(handle); +} + +TEST(dlfcn, dlopen_check_rtld_global) { + void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym == nullptr); + + void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL); + sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym != nullptr) << dlerror(); + ASSERT_TRUE(reinterpret_cast(sym)()); + dlclose(handle); +} + // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> // libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so -> // libtest_with_dependency_loop_a.so diff --git a/tests/libs/dlopen_testlib_simple.cpp b/tests/libs/dlopen_testlib_simple.cpp index bf750b2a6..32269557a 100644 --- a/tests/libs/dlopen_testlib_simple.cpp +++ b/tests/libs/dlopen_testlib_simple.cpp @@ -19,6 +19,6 @@ uint32_t dlopen_testlib_taxicab_number = 1729; -bool dlopen_testlib_simple_func() { +extern "C" bool dlopen_testlib_simple_func() { return true; } From 7ca96a075b778f1fa2ad265350879238cbcb4d09 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 4 Nov 2014 09:37:28 -0800 Subject: [PATCH 096/114] Revert "Revert "Add RTLD_NODELETE flag support"" This reverts commit 69c5d108a5cb44167a04d42ffdad6a39648ed235. --- libc/include/dlfcn.h | 1 + linker/linker.cpp | 16 ++++- linker/linker.h | 18 ++--- tests/dlfcn_test.cpp | 80 +++++++++++++++++++++++ tests/libs/Android.mk | 29 ++++++++ tests/libs/dlopen_nodelete_1.cpp | 31 +++++++++ tests/libs/dlopen_nodelete_2.cpp | 31 +++++++++ tests/libs/dlopen_nodelete_dt_flags_1.cpp | 30 +++++++++ 8 files changed, 226 insertions(+), 10 deletions(-) create mode 100644 tests/libs/dlopen_nodelete_1.cpp create mode 100644 tests/libs/dlopen_nodelete_2.cpp create mode 100644 tests/libs/dlopen_nodelete_dt_flags_1.cpp diff --git a/libc/include/dlfcn.h b/libc/include/dlfcn.h index 8dde08cf5..afa76878f 100644 --- a/libc/include/dlfcn.h +++ b/libc/include/dlfcn.h @@ -64,6 +64,7 @@ enum { RTLD_GLOBAL = 2, #endif RTLD_NOLOAD = 4, + RTLD_NODELETE = 0x01000, }; #if defined (__LP64__) diff --git a/linker/linker.cpp b/linker/linker.cpp index eadfe5efe..9ae853cc2 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -987,6 +987,11 @@ static soinfo* find_library(const char* name, int rtld_flags, const android_dlex } static void soinfo_unload(soinfo* si) { + if (!si->can_unload()) { + TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->name); + return; + } + if (si->ref_count == 1) { TRACE("unloading '%s'", si->name); si->CallDestructors(); @@ -1045,7 +1050,7 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) { } soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) { - if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NOLOAD)) != 0) { + if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) { DL_ERR("invalid flags to dlopen: %x", flags); return nullptr; } @@ -1808,6 +1813,9 @@ const char* soinfo::get_string(ElfW(Word) index) const { return strtab + index; } +bool soinfo::can_unload() const { + return (rtld_flags & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; +} /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -2111,9 +2119,13 @@ bool soinfo::PrelinkImage() { if ((d->d_un.d_val & DF_1_GLOBAL) != 0) { rtld_flags |= RTLD_GLOBAL; } + + if ((d->d_un.d_val & DF_1_NODELETE) != 0) { + rtld_flags |= RTLD_NODELETE; + } // TODO: Implement other flags - if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL)) != 0) { + if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)) != 0) { DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast(d->d_un.d_val)); } break; diff --git a/linker/linker.h b/linker/linker.h index 6329efda6..ebb4793af 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -134,7 +134,7 @@ struct soinfo { #endif soinfo* next; - unsigned flags; + uint32_t flags; private: const char* strtab; @@ -143,8 +143,8 @@ struct soinfo { size_t nbucket; size_t nchain; - unsigned* bucket; - unsigned* chain; + uint32_t* bucket; + uint32_t* chain; #if defined(__mips__) || !defined(__LP64__) // This is only used by mips and mips64, but needs to be here for @@ -179,12 +179,12 @@ struct soinfo { #if defined(__arm__) // ARM EABI section used for stack unwinding. - unsigned* ARM_exidx; + uint32_t* ARM_exidx; size_t ARM_exidx_count; #elif defined(__mips__) - unsigned mips_symtabno; - unsigned mips_local_gotno; - unsigned mips_gotsym; + uint32_t mips_symtabno; + uint32_t mips_local_gotno; + uint32_t mips_gotsym; #endif size_t ref_count; @@ -224,10 +224,12 @@ struct soinfo { ElfW(Addr) resolve_symbol_address(ElfW(Sym)* s); const char* get_string(ElfW(Word) index) const; + bool can_unload() const; bool inline has_min_version(uint32_t min_version) const { return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; } + private: void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); @@ -258,7 +260,7 @@ struct soinfo { friend soinfo* get_libdl_info(); }; -extern soinfo* get_libdl_info(); +soinfo* get_libdl_info(); void do_android_get_LD_LIBRARY_PATH(char*, size_t); void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path); diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 1bf186b4b..1d7c29a54 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -232,10 +232,15 @@ TEST(dlfcn, dlopen_check_rtld_global) { ASSERT_TRUE(sym == nullptr); void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); ASSERT_TRUE(sym != nullptr) << dlerror(); ASSERT_TRUE(reinterpret_cast(sym)()); dlclose(handle); + + // RTLD_GLOBAL implies RTLD_NODELETE, let's check that + void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); + ASSERT_EQ(sym, sym_after_dlclose); } // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> @@ -263,6 +268,81 @@ TEST(dlfcn, dlopen_check_loop) { #endif } +TEST(dlfcn, dlopen_nodelete) { + static bool is_unloaded = false; + + void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE); + ASSERT_TRUE(handle != nullptr) << dlerror(); + void (*set_unload_flag_ptr)(bool*); + set_unload_flag_ptr = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr")); + ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); + set_unload_flag_ptr(&is_unloaded); + + uint32_t* taxicab_number = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); + ASSERT_TRUE(taxicab_number != nullptr) << dlerror(); + ASSERT_EQ(1729U, *taxicab_number); + *taxicab_number = 2; + + dlclose(handle); + ASSERT_TRUE(!is_unloaded); + + uint32_t* taxicab_number_after_dlclose = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); + ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number); + ASSERT_EQ(2U, *taxicab_number_after_dlclose); + + + handle = dlopen("libtest_nodelete_1.so", RTLD_NOW); + uint32_t* taxicab_number2 = reinterpret_cast(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); + ASSERT_EQ(taxicab_number2, taxicab_number); + + ASSERT_EQ(2U, *taxicab_number2); + + dlclose(handle); + ASSERT_TRUE(!is_unloaded); +} + +TEST(dlfcn, dlopen_nodelete_on_second_dlopen) { + static bool is_unloaded = false; + + void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr) << dlerror(); + void (*set_unload_flag_ptr)(bool*); + set_unload_flag_ptr = reinterpret_cast(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr")); + ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); + set_unload_flag_ptr(&is_unloaded); + + uint32_t* taxicab_number = reinterpret_cast(dlsym(handle, "dlopen_nodelete_2_taxicab_number")); + ASSERT_TRUE(taxicab_number != nullptr) << dlerror(); + + ASSERT_EQ(1729U, *taxicab_number); + *taxicab_number = 2; + + // This RTLD_NODELETE should be ignored + void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE); + ASSERT_TRUE(handle1 != nullptr) << dlerror(); + ASSERT_EQ(handle, handle1); + + dlclose(handle1); + dlclose(handle); + + ASSERT_TRUE(is_unloaded); +} + +TEST(dlfcn, dlopen_nodelete_dt_flags_1) { + static bool is_unloaded = false; + + void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr) << dlerror(); + void (*set_unload_flag_ptr)(bool*); + set_unload_flag_ptr = reinterpret_cast(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr")); + ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); + set_unload_flag_ptr(&is_unloaded); + + dlclose(handle); + ASSERT_TRUE(!is_unloaded); +} + + TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index e38f3dc11..67f6a3732 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -120,6 +120,35 @@ libtest_simple_src_files := \ module := libtest_simple include $(LOCAL_PATH)/Android.build.testlib.mk +# ----------------------------------------------------------------------------- +# Library used by dlfcn nodelete tests +# ----------------------------------------------------------------------------- +libtest_nodelete_1_src_files := \ + dlopen_nodelete_1.cpp + +module := libtest_nodelete_1 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# Library used by dlfcn nodelete tests +# ----------------------------------------------------------------------------- +libtest_nodelete_2_src_files := \ + dlopen_nodelete_2.cpp + +module := libtest_nodelete_2 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# Library used by dlfcn nodelete tests +# ----------------------------------------------------------------------------- +libtest_nodelete_dt_flags_1_src_files := \ + dlopen_nodelete_dt_flags_1.cpp + +libtest_nodelete_dt_flags_1_ldflags := -Wl,-z,nodelete + +module := libtest_nodelete_dt_flags_1 +include $(LOCAL_PATH)/Android.build.testlib.mk + # ----------------------------------------------------------------------------- # Libraries used by dlfcn tests to verify correct load order: # libtest_check_order_2_right.so diff --git a/tests/libs/dlopen_nodelete_1.cpp b/tests/libs/dlopen_nodelete_1.cpp new file mode 100644 index 000000000..943897815 --- /dev/null +++ b/tests/libs/dlopen_nodelete_1.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +uint32_t dlopen_nodelete_1_taxicab_number = 1729; +static bool* unload_flag_ptr = nullptr; + +extern "C" void dlopen_nodelete_1_set_unload_flag_ptr(bool* ptr) { + unload_flag_ptr = ptr; +} + +static void __attribute__((destructor)) unload_guard() { + if (unload_flag_ptr != nullptr) { + *unload_flag_ptr = true; + } +} diff --git a/tests/libs/dlopen_nodelete_2.cpp b/tests/libs/dlopen_nodelete_2.cpp new file mode 100644 index 000000000..b5ab5c1ae --- /dev/null +++ b/tests/libs/dlopen_nodelete_2.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +uint32_t dlopen_nodelete_2_taxicab_number = 1729; +static bool* unload_flag_ptr = nullptr; + +extern "C" void dlopen_nodelete_2_set_unload_flag_ptr(bool* ptr) { + unload_flag_ptr = ptr; +} + +static void __attribute__((destructor)) unload_guard() { + if (unload_flag_ptr != nullptr) { + *unload_flag_ptr = true; + } +} diff --git a/tests/libs/dlopen_nodelete_dt_flags_1.cpp b/tests/libs/dlopen_nodelete_dt_flags_1.cpp new file mode 100644 index 000000000..39c0a7ea6 --- /dev/null +++ b/tests/libs/dlopen_nodelete_dt_flags_1.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +static bool* unload_flag_ptr = nullptr; + +extern "C" void dlopen_nodelete_dt_flags_1_set_unload_flag_ptr(bool* ptr) { + unload_flag_ptr = ptr; +} + +static void __attribute__((destructor)) unload_guard() { + if (unload_flag_ptr != nullptr) { + *unload_flag_ptr = true; + } +} From c343cac62bfd2933e36357b206fdd81da7610164 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 4 Nov 2014 09:37:51 -0800 Subject: [PATCH 097/114] Revert "Revert "Fix relocation to look for symbols in local group"" This reverts commit 00dce525530c5d26c20750863f3e9890b468787a. --- linker/linked_list.h | 4 +- linker/linker.cpp | 193 +++++++++++------- linker/linker.h | 6 +- tests/dlfcn_test.cpp | 186 +++++++++++++++-- .../Android.build.dlopen_check_order_dlsym.mk | 90 ++++++++ ...lopen_check_order_reloc_main_executable.mk | 56 +++++ ...build.dlopen_check_order_reloc_siblings.mk | 133 ++++++++++++ tests/libs/Android.mk | 75 +------ ...pp => dlopen_check_order_dlsym_answer.cpp} | 4 +- .../libs/dlopen_check_order_reloc_answer.cpp | 23 +++ .../dlopen_check_order_reloc_answer_impl.cpp | 19 ++ ...dlopen_check_order_reloc_nephew_answer.cpp | 21 ++ .../dlopen_check_order_reloc_root_answer.cpp | 21 ++ ...pen_check_order_reloc_root_answer_impl.cpp | 19 ++ 14 files changed, 688 insertions(+), 162 deletions(-) create mode 100644 tests/libs/Android.build.dlopen_check_order_dlsym.mk create mode 100644 tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk create mode 100644 tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk rename tests/libs/{dlopen_testlib_answer.cpp => dlopen_check_order_dlsym_answer.cpp} (87%) create mode 100644 tests/libs/dlopen_check_order_reloc_answer.cpp create mode 100644 tests/libs/dlopen_check_order_reloc_answer_impl.cpp create mode 100644 tests/libs/dlopen_check_order_reloc_nephew_answer.cpp create mode 100644 tests/libs/dlopen_check_order_reloc_root_answer.cpp create mode 100644 tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp diff --git a/linker/linked_list.h b/linker/linked_list.h index 4e62e208f..72a32b4ba 100644 --- a/linker/linked_list.h +++ b/linker/linked_list.h @@ -86,7 +86,7 @@ class LinkedList { } template - void for_each(F action) { + void for_each(F action) const { visit([&] (T* si) { action(si); return true; @@ -94,7 +94,7 @@ class LinkedList { } template - bool visit(F action) { + bool visit(F action) const { for (LinkedListEntry* e = head_; e != nullptr; e = e->next) { if (!action(e->element)) { return false; diff --git a/linker/linker.cpp b/linker/linker.cpp index 9ae853cc2..48093f9d1 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -415,7 +415,7 @@ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void return rv; } -static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) { +static ElfW(Sym)* soinfo_elf_lookup(const soinfo* si, unsigned hash, const char* name) { ElfW(Sym)* symtab = si->symtab; TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd", @@ -481,7 +481,7 @@ static unsigned elfhash(const char* _name) { return h; } -static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { +static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, const soinfo::soinfo_list_t& local_group) { unsigned elf_hash = elfhash(name); ElfW(Sym)* s = nullptr; @@ -527,16 +527,21 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { } } - /* Look for symbols in the local scope (the object who is - * searching). This happens with C++ templates on x86 for some - * reason. - * - * Notes on weak symbols: - * The ELF specs are ambiguous about treatment of weak definitions in - * dynamic linking. Some systems return the first definition found - * and some the first non-weak definition. This is system dependent. - * Here we return the first definition found for simplicity. */ + // 3. Look for it in the local group + if (s == nullptr) { + local_group.visit([&](soinfo* local_si) { + DEBUG("%s: looking up %s in %s (from local group)", si->name, name, local_si->name); + s = soinfo_elf_lookup(local_si, elf_hash, name); + if (s != nullptr) { + *lsi = local_si; + return false; + } + return true; + }); + } + + // 4. Look for it in this library (unless we already did it because of DT_SYMBOLIC) if (s == nullptr && !si->has_DT_SYMBOLIC) { DEBUG("%s: looking up %s in local scope", si->name, name); s = soinfo_elf_lookup(si, elf_hash, name); @@ -545,6 +550,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { } } + // 5. Dependencies if (s == nullptr) { si->get_children().visit([&](soinfo* child) { DEBUG("%s: looking up %s in %s", si->name, name, child->name); @@ -643,33 +649,61 @@ typedef linked_list_t StringLinkedList; typedef linked_list_t LoadTaskList; -// This is used by dlsym(3). It performs symbol lookup only within the -// specified soinfo object and its dependencies in breadth first order. -ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { +// This function walks down the tree of soinfo dependencies +// in breadth-first order and +// * calls action(soinfo* si) for each node, and +// * terminates walk if action returns false. +// +// walk_dependencies_tree returns false if walk was terminated +// by the action and true otherwise. +template +static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) { SoinfoLinkedList visit_list; SoinfoLinkedList visited; - visit_list.push_back(si); - soinfo* current_soinfo; - while ((current_soinfo = visit_list.pop_front()) != nullptr) { - if (visited.contains(current_soinfo)) { + for (size_t i = 0; i < root_soinfos_size; ++i) { + visit_list.push_back(root_soinfos[i]); + } + + soinfo* si; + while ((si = visit_list.pop_front()) != nullptr) { + if (visited.contains(si)) { continue; } - ElfW(Sym)* result = soinfo_elf_lookup(current_soinfo, elfhash(name), name); - - if (result != nullptr) { - *found = current_soinfo; - return result; + if (!action(si)) { + return false; } - visited.push_back(current_soinfo); - current_soinfo->get_children().for_each([&](soinfo* child) { + visited.push_back(si); + + si->get_children().for_each([&](soinfo* child) { visit_list.push_back(child); }); } - return nullptr; + return true; +} + + +// This is used by dlsym(3). It performs symbol lookup only within the +// specified soinfo object and its dependencies in breadth first order. +ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { + ElfW(Sym)* result = nullptr; + uint32_t elf_hash = elfhash(name); + + + walk_dependencies_tree(&si, 1, [&](soinfo* current_soinfo) { + result = soinfo_elf_lookup(current_soinfo, elf_hash, name); + if (result != nullptr) { + *found = current_soinfo; + return false; + } + + return true; + }); + + return result; } /* This is used by dlsym(3) to performs a global symbol lookup. If the @@ -899,19 +933,30 @@ static bool is_recursive(soinfo* si, soinfo* parent) { }); } -static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[], - soinfo* ld_preloads[], size_t ld_preloads_size, int rtld_flags, const android_dlextinfo* extinfo) { +static bool find_libraries(soinfo* start_with, const char* const library_names[], size_t library_names_count, soinfo* soinfos[], + soinfo* ld_preloads[], size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) { // Step 0: prepare. LoadTaskList load_tasks; - for (size_t i = 0; i < library_names_size; ++i) { + for (size_t i = 0; i < library_names_count; ++i) { const char* name = library_names[i]; - load_tasks.push_back(LoadTask::create(name, nullptr)); + load_tasks.push_back(LoadTask::create(name, start_with)); } - // Libraries added to this list in reverse order so that we can - // start linking from bottom-up - see step 2. - SoinfoLinkedList found_libs; - size_t soinfos_size = 0; + // If soinfos array is null allocate one on stack. + // The array is needed in case of failure; for example + // when library_names[] = {libone.so, libtwo.so} and libone.so + // is loaded correctly but libtwo.so failed for some reason. + // In this case libone.so should be unloaded on return. + // See also implementation of failure_guard below. + + if (soinfos == nullptr) { + size_t soinfos_size = sizeof(soinfo*)*library_names_count; + soinfos = reinterpret_cast(alloca(soinfos_size)); + memset(soinfos, 0, soinfos_size); + } + + // list of libraries to link - see step 2. + size_t soinfos_count = 0; auto failure_guard = make_scope_guard([&]() { // Housekeeping @@ -919,7 +964,7 @@ static bool find_libraries(const char* const library_names[], size_t library_nam LoadTask::deleter(t); }); - for (size_t i = 0; iadd_child(si); } - found_libs.push_front(si); - // When ld_preloads is not null first - // ld_preloads_size libs are in fact ld_preloads. - if (ld_preloads != nullptr && soinfos_size < ld_preloads_size) { - ld_preloads[soinfos_size] = si; + // When ld_preloads is not null, the first + // ld_preloads_count libs are in fact ld_preloads. + if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) { + ld_preloads[soinfos_count] = si; } - if (soinfos_sizeflags & FLAG_LINKED) == 0) { - if (!si->LinkImage(extinfo)) { + if (!si->LinkImage(local_group, extinfo)) { return false; } si->flags |= FLAG_LINKED; } + + return true; + }); + + if (linked) { + failure_guard.disable(); } - // All is well - found_libs and load_tasks are empty at this point - // and all libs are successfully linked. - failure_guard.disable(); - return true; + return linked; } static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) { @@ -979,7 +1034,7 @@ static soinfo* find_library(const char* name, int rtld_flags, const android_dlex soinfo* si; - if (!find_libraries(&name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { + if (!find_libraries(nullptr, &name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { return nullptr; } @@ -1090,7 +1145,7 @@ static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) { } #if defined(USE_RELA) -int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { +int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group) { for (size_t idx = 0; idx < count; ++idx, ++rela) { unsigned type = ELFW(R_TYPE)(rela->r_info); unsigned sym = ELFW(R_SYM)(rela->r_info); @@ -1108,7 +1163,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi); + s = soinfo_do_lookup(this, sym_name, &lsi, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1367,7 +1422,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { } #else // REL, not RELA. -int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { +int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group) { for (size_t idx = 0; idx < count; ++idx, ++rel) { unsigned type = ELFW(R_TYPE)(rel->r_info); // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. @@ -1386,7 +1441,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi); + s = soinfo_do_lookup(this, sym_name, &lsi, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1572,7 +1627,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { #endif #if defined(__mips__) -static bool mips_relocate_got(soinfo* si) { +static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& local_group) { ElfW(Addr)** got = si->plt_got; if (got == nullptr) { return true; @@ -1605,7 +1660,7 @@ static bool mips_relocate_got(soinfo* si) { // This is an undefined reference... try to locate it. const char* sym_name = si->get_string(sym->st_name); soinfo* lsi = nullptr; - ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); + ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. s = &symtab[g]; @@ -2198,7 +2253,7 @@ bool soinfo::PrelinkImage() { return true; } -bool soinfo::LinkImage(const android_dlextinfo* extinfo) { +bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo) { #if !defined(__LP64__) if (has_text_relocations) { @@ -2217,26 +2272,26 @@ bool soinfo::LinkImage(const android_dlextinfo* extinfo) { #if defined(USE_RELA) if (rela != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rela, rela_count)) { + if (Relocate(rela, rela_count, local_group)) { return false; } } if (plt_rela != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rela, plt_rela_count)) { + if (Relocate(plt_rela, plt_rela_count, local_group)) { return false; } } #else if (rel != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rel, rel_count)) { + if (Relocate(rel, rel_count, local_group)) { return false; } } if (plt_rel != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rel, plt_rel_count)) { + if (Relocate(plt_rel, plt_rel_count, local_group)) { return false; } } @@ -2310,7 +2365,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->load_bias = get_elf_exec_load_bias(ehdr_vdso); si->PrelinkImage(); - si->LinkImage(nullptr); + si->LinkImage(g_empty_list, nullptr); #endif } @@ -2456,21 +2511,11 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( }); const char* needed_library_names[needed_libraries_count]; - soinfo* needed_library_si[needed_libraries_count]; memset(needed_library_names, 0, sizeof(needed_library_names)); needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); - if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { - __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); - exit(EXIT_FAILURE); - } - - for (size_t i = 0; iadd_child(needed_library_si[i]); - } - - if (!si->LinkImage(nullptr)) { + if (needed_libraries_count > 0 && !find_libraries(si, needed_library_names, needed_libraries_count, nullptr, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); } @@ -2594,7 +2639,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - if (!(linker_so.PrelinkImage() && linker_so.LinkImage(nullptr))) { + if (!(linker_so.PrelinkImage() && linker_so.LinkImage(g_empty_list, nullptr))) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as diff --git a/linker/linker.h b/linker/linker.h index ebb4793af..222aca11e 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -207,7 +207,7 @@ struct soinfo { void CallDestructors(); void CallPreInitConstructors(); bool PrelinkImage(); - bool LinkImage(const android_dlextinfo* extinfo); + bool LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo); void add_child(soinfo* child); void remove_all_links(); @@ -234,9 +234,9 @@ struct soinfo { void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); #if defined(USE_RELA) - int Relocate(ElfW(Rela)* rela, unsigned count); + int Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group); #else - int Relocate(ElfW(Rel)* rel, unsigned count); + int Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group); #endif private: diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 1d7c29a54..2ab3dc1ed 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -162,39 +162,39 @@ TEST(dlfcn, dlopen_check_relocation_dt_needed_order) { ASSERT_EQ(1, fn()); } -TEST(dlfcn, dlopen_check_order) { +TEST(dlfcn, dlopen_check_order_dlsym) { // Here is how the test library and its dt_needed // libraries are arranged // - // libtest_check_order.so + // libtest_check_order_children.so // | - // +-> libtest_check_order_1_left.so + // +-> ..._1_left.so // | | - // | +-> libtest_check_order_a.so + // | +-> ..._a.so // | | - // | +-> libtest_check_order_b.so + // | +-> ...r_b.so // | - // +-> libtest_check_order_2_right.so + // +-> ..._2_right.so // | | - // | +-> libtest_check_order_d.so + // | +-> ..._d.so // | | - // | +-> libtest_check_order_b.so + // | +-> ..._b.so // | - // +-> libtest_check_order_3_c.so + // +-> ..._3_c.so // // load order should be (1, 2, 3, a, b, d) // // get_answer() is defined in (2, 3, a, b, c) // get_answer2() is defined in (b, d) - void* sym = dlsym(RTLD_DEFAULT, "dlopen_test_get_answer"); + void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"); ASSERT_TRUE(sym == nullptr); - void* handle = dlopen("libtest_check_order.so", RTLD_NOW | RTLD_GLOBAL); - ASSERT_TRUE(handle != nullptr); + void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); typedef int (*fn_t) (void); fn_t fn, fn2; - fn = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer")); + fn = reinterpret_cast(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer")); ASSERT_TRUE(fn != NULL) << dlerror(); - fn2 = reinterpret_cast(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer2")); + fn2 = reinterpret_cast(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2")); ASSERT_TRUE(fn2 != NULL) << dlerror(); ASSERT_EQ(42, fn()); @@ -202,6 +202,163 @@ TEST(dlfcn, dlopen_check_order) { dlclose(handle); } +TEST(dlfcn, dlopen_check_order_reloc_siblings) { + // This is how this one works: + // we lookup and call get_answer which is defined in '_2.so' + // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so' + // the correct _impl() is implemented by '_a.so'; + // + // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?) + // + // Here is the picture: + // + // libtest_check_order_reloc_siblings.so + // | + // +-> ..._1.so <- empty + // | | + // | +-> ..._a.so <- exports correct answer_impl() + // | | + // | +-> ..._b.so <- every other letter exporting incorrect one. + // | + // +-> ..._2.so <- empty + // | | + // | +-> ..._c.so + // | | + // | +-> ..._d.so + // | + // +-> ..._3.so <- empty + // | + // +-> ..._e.so + // | + // +-> ..._f.so <- exports get_answer() that calls get_anser_impl(); + // implements incorrect get_answer_impl() + + void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); +#ifdef __BIONIC__ + // TODO: glibc returns nullptr on dlerror() here. Is it bug? + ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); +#endif + + handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + typedef int (*fn_t) (void); + fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_get_answer")); + ASSERT_TRUE(fn != nullptr) << dlerror(); + ASSERT_EQ(42, fn()); + + ASSERT_EQ(0, dlclose(handle)); +} + +TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) { + // This test uses the same library as dlopen_check_order_reloc_siblings. + // Unlike dlopen_check_order_reloc_siblings it preloads + // libtest_check_order_reloc_siblings_1.so (first dependency) prior to + // dlopen(libtest_check_order_reloc_siblings.so) + + void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); + handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); + + void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(handle_for_1 != nullptr) << dlerror(); + + handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + ASSERT_EQ(0, dlclose(handle_for_1)); + + typedef int (*fn_t) (void); + fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_get_answer")); + ASSERT_TRUE(fn != nullptr) << dlerror(); + ASSERT_EQ(42, fn()); + + ASSERT_EQ(0, dlclose(handle)); +} + +TEST(dlfcn, dlopen_check_order_reloc_nephew) { + // This is how this one works: + // we lookup and call nephew_get_answer which is defined in '_2.so' + // and in turn calls external get_answer_impl() defined in '_[a-f].so' + // the correct _impl() is implemented by '_a.so'; + // + // Here is the picture: + // + // libtest_check_order_reloc_siblings.so + // | + // +-> ..._1.so <- empty + // | | + // | +-> ..._a.so <- exports correct answer_impl() + // | | + // | +-> ..._b.so <- every other letter exporting incorrect one. + // | + // +-> ..._2.so <- empty + // | | + // | +-> ..._c.so + // | | + // | +-> ..._d.so + // | + // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl(); + // | + // +-> ..._e.so + // | + // +-> ..._f.so + + void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); +#ifdef __BIONIC__ + // TODO: glibc returns nullptr on dlerror() here. Is it bug? + ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); +#endif + + handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + typedef int (*fn_t) (void); + fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_nephew_get_answer")); + ASSERT_TRUE(fn != nullptr) << dlerror(); + ASSERT_EQ(42, fn()); + + ASSERT_EQ(0, dlclose(handle)); +} + +extern "C" int check_order_reloc_root_get_answer_impl() { + return 42; +} + +TEST(dlfcn, dlopen_check_order_reloc_main_executable) { + // This is how this one works: + // we lookup and call get_answer3 which is defined in 'root.so' + // and in turn calls external root_get_answer_impl() defined in _2.so and + // above the correct _impl() is one in the executable. + // + // libtest_check_order_reloc_root.so + // | + // +-> ..._1.so <- empty + // | + // +-> ..._2.so <- gives incorrect answer for answer_main_impl() + // + + void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); +#ifdef __BIONIC__ + // TODO: glibc returns nullptr on dlerror() here. Is it bug? + ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); +#endif + + handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + typedef int (*fn_t) (void); + fn_t fn = reinterpret_cast(dlsym(handle, "check_order_reloc_root_get_answer")); + ASSERT_TRUE(fn != nullptr) << dlerror(); + ASSERT_EQ(42, fn()); + + ASSERT_EQ(0, dlclose(handle)); +} + TEST(dlfcn, dlopen_check_rtld_local) { void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); ASSERT_TRUE(sym == nullptr); @@ -342,7 +499,6 @@ TEST(dlfcn, dlopen_nodelete_dt_flags_1) { ASSERT_TRUE(!is_unloaded); } - TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.build.dlopen_check_order_dlsym.mk b/tests/libs/Android.build.dlopen_check_order_dlsym.mk new file mode 100644 index 000000000..73d8c1a83 --- /dev/null +++ b/tests/libs/Android.build.dlopen_check_order_dlsym.mk @@ -0,0 +1,90 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# ----------------------------------------------------------------------------- +# Libraries used by dlfcn tests to verify correct load order: +# libtest_check_order_2_right.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_2_right_src_files := \ + dlopen_check_order_dlsym_answer.cpp + +libtest_check_order_dlsym_2_right_cflags := -D__ANSWER=42 +module := libtest_check_order_dlsym_2_right +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_a.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_a_src_files := \ + dlopen_check_order_dlsym_answer.cpp + +libtest_check_order_dlsym_a_cflags := -D__ANSWER=1 +module := libtest_check_order_dlsym_a +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_b.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_b_src_files := \ + dlopen_check_order_dlsym_answer.cpp + +libtest_check_order_dlsym_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 +module := libtest_check_order_dlsym_b +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_c.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_3_c_src_files := \ + dlopen_check_order_dlsym_answer.cpp + +libtest_check_order_dlsym_3_c_cflags := -D__ANSWER=3 +module := libtest_check_order_dlsym_3_c +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_d.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_d_src_files := \ + dlopen_check_order_dlsym_answer.cpp + +libtest_check_order_dlsym_d_shared_libraries := libtest_check_order_dlsym_b +libtest_check_order_dlsym_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 +module := libtest_check_order_dlsym_d +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_left.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_1_left_src_files := \ + empty.cpp + +libtest_check_order_dlsym_1_left_shared_libraries := libtest_check_order_dlsym_a libtest_check_order_dlsym_b + +module := libtest_check_order_dlsym_1_left +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order.so +# ----------------------------------------------------------------------------- +libtest_check_order_dlsym_src_files := \ + empty.cpp + +libtest_check_order_dlsym_shared_libraries := libtest_check_order_dlsym_1_left \ + libtest_check_order_dlsym_2_right libtest_check_order_dlsym_3_c + +module := libtest_check_order_dlsym +include $(LOCAL_PATH)/Android.build.testlib.mk diff --git a/tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk b/tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk new file mode 100644 index 000000000..639696b25 --- /dev/null +++ b/tests/libs/Android.build.dlopen_check_order_reloc_main_executable.mk @@ -0,0 +1,56 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# ----------------------------------------------------------------------------- +# Libraries used by dlfcn tests to verify correct relocation order: +# libtest_check_order_reloc_root*.so +# ----------------------------------------------------------------------------- + + +# ----------------------------------------------------------------------------- +# ..._1.so - empty +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_root_1_src_files := \ + empty.cpp + + +module := libtest_check_order_reloc_root_1 +include $(LOCAL_PATH)/Android.build.testlib.mk + + +# ----------------------------------------------------------------------------- +# ..._2.so - this one has the incorrect answer +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_root_2_src_files := \ + dlopen_check_order_reloc_root_answer_impl.cpp + +libtest_check_order_reloc_root_2_cflags := -D__ANSWER=2 + +module := libtest_check_order_reloc_root_2 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_reloc_root.so <- implements get_answer3() +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_root_src_files := \ + dlopen_check_order_reloc_root_answer.cpp + +libtest_check_order_reloc_root_shared_libraries := \ + libtest_check_order_reloc_root_1 \ + libtest_check_order_reloc_root_2 + +module := libtest_check_order_reloc_root +include $(LOCAL_PATH)/Android.build.testlib.mk diff --git a/tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk b/tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk new file mode 100644 index 000000000..0f1a2b4da --- /dev/null +++ b/tests/libs/Android.build.dlopen_check_order_reloc_siblings.mk @@ -0,0 +1,133 @@ +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# ----------------------------------------------------------------------------- +# Libraries used by dlfcn tests to verify correct relocation order: +# libtest_check_order_reloc_siblings*.so +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# ..._1.so - empty +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_1_src_files := \ + empty.cpp + +libtest_check_order_reloc_siblings_1_shared_libraries := \ + libtest_check_order_reloc_siblings_a \ + libtest_check_order_reloc_siblings_b + +module := libtest_check_order_reloc_siblings_1 +include $(LOCAL_PATH)/Android.build.testlib.mk + + +# ----------------------------------------------------------------------------- +# ..._2.so - empty +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_2_src_files := \ + empty.cpp + +libtest_check_order_reloc_siblings_2_shared_libraries := \ + libtest_check_order_reloc_siblings_c \ + libtest_check_order_reloc_siblings_d + +module := libtest_check_order_reloc_siblings_2 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._3.so - get_answer2(); +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_3_src_files := \ + dlopen_check_order_reloc_nephew_answer.cpp + +libtest_check_order_reloc_siblings_3_shared_libraries := \ + libtest_check_order_reloc_siblings_e \ + libtest_check_order_reloc_siblings_f + +module := libtest_check_order_reloc_siblings_3 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._a.so <- correct impl +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_a_src_files := \ + dlopen_check_order_reloc_answer_impl.cpp + +libtest_check_order_reloc_siblings_a_cflags := -D__ANSWER=42 +module := libtest_check_order_reloc_siblings_a +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._b.so +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_b_src_files := \ + dlopen_check_order_reloc_answer_impl.cpp + +libtest_check_order_reloc_siblings_b_cflags := -D__ANSWER=1 +module := libtest_check_order_reloc_siblings_b +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._c.so +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_c_src_files := \ + dlopen_check_order_reloc_answer_impl.cpp + +libtest_check_order_reloc_siblings_c_cflags := -D__ANSWER=2 +module := libtest_check_order_reloc_siblings_c +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._d.so +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_d_src_files := \ + dlopen_check_order_reloc_answer_impl.cpp + +libtest_check_order_reloc_siblings_d_cflags := -D__ANSWER=3 +module := libtest_check_order_reloc_siblings_d +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._e.so +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_e_src_files := \ + dlopen_check_order_reloc_answer_impl.cpp + +libtest_check_order_reloc_siblings_e_cflags := -D__ANSWER=4 +module := libtest_check_order_reloc_siblings_e +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# ..._f.so <- get_answer() +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_f_src_files := \ + dlopen_check_order_reloc_answer.cpp + +module := libtest_check_order_reloc_siblings_f +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_reloc_siblings.so +# ----------------------------------------------------------------------------- +libtest_check_order_reloc_siblings_src_files := \ + empty.cpp + +libtest_check_order_reloc_siblings_shared_libraries := \ + libtest_check_order_reloc_siblings_1 \ + libtest_check_order_reloc_siblings_2 \ + libtest_check_order_reloc_siblings_3 + +module := libtest_check_order_reloc_siblings +include $(LOCAL_PATH)/Android.build.testlib.mk diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 67f6a3732..e4fee6a6c 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -21,6 +21,9 @@ common_cppflags += -std=gnu++11 common_additional_dependencies := \ $(LOCAL_PATH)/Android.mk \ $(LOCAL_PATH)/Android.build.dlext_testzip.mk \ + $(LOCAL_PATH)/Android.build.dlopen_check_order_dlsym.mk \ + $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_siblings.mk \ + $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_main_executable.mk \ $(LOCAL_PATH)/Android.build.testlib.mk \ $(TEST_PATH)/Android.build.mk @@ -150,79 +153,19 @@ module := libtest_nodelete_dt_flags_1 include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- -# Libraries used by dlfcn tests to verify correct load order: -# libtest_check_order_2_right.so +# Build libtest_check_order_dlsym.so with its dependencies. # ----------------------------------------------------------------------------- -libtest_check_order_2_right_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_2_right_cflags := -D__ANSWER=42 -module := libtest_check_order_2_right -include $(LOCAL_PATH)/Android.build.testlib.mk +include $(LOCAL_PATH)/Android.build.dlopen_check_order_dlsym.mk # ----------------------------------------------------------------------------- -# libtest_check_order_a.so +# Build libtest_check_order_siblings.so with its dependencies. # ----------------------------------------------------------------------------- -libtest_check_order_a_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_a_cflags := -D__ANSWER=1 -module := libtest_check_order_a -include $(LOCAL_PATH)/Android.build.testlib.mk +include $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_siblings.mk # ----------------------------------------------------------------------------- -# libtest_check_order_b.so +# Build libtest_check_order_root.so with its dependencies. # ----------------------------------------------------------------------------- -libtest_check_order_b_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 -module := libtest_check_order_b -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_c.so -# ----------------------------------------------------------------------------- -libtest_check_order_3_c_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_3_c_cflags := -D__ANSWER=3 -module := libtest_check_order_3_c -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_d.so -# ----------------------------------------------------------------------------- -libtest_check_order_d_src_files := \ - dlopen_testlib_answer.cpp - -libtest_check_order_d_shared_libraries := libtest_check_order_b -libtest_check_order_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 -module := libtest_check_order_d -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order_left.so -# ----------------------------------------------------------------------------- -libtest_check_order_1_left_src_files := \ - empty.cpp - -libtest_check_order_1_left_shared_libraries := libtest_check_order_a libtest_check_order_b - -module := libtest_check_order_1_left -include $(LOCAL_PATH)/Android.build.testlib.mk - -# ----------------------------------------------------------------------------- -# libtest_check_order.so -# ----------------------------------------------------------------------------- -libtest_check_order_src_files := \ - empty.cpp - -libtest_check_order_shared_libraries := libtest_check_order_1_left \ - libtest_check_order_2_right libtest_check_order_3_c - -module := libtest_check_order -include $(LOCAL_PATH)/Android.build.testlib.mk +include $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_main_executable.mk # ----------------------------------------------------------------------------- # Library with dependency loop used by dlfcn tests diff --git a/tests/libs/dlopen_testlib_answer.cpp b/tests/libs/dlopen_check_order_dlsym_answer.cpp similarity index 87% rename from tests/libs/dlopen_testlib_answer.cpp rename to tests/libs/dlopen_check_order_dlsym_answer.cpp index a4d75046e..2ae6cf79e 100644 --- a/tests/libs/dlopen_testlib_answer.cpp +++ b/tests/libs/dlopen_check_order_dlsym_answer.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -extern "C" int dlopen_test_get_answer() { +extern "C" int check_order_dlsym_get_answer() { return __ANSWER; } #ifdef __ANSWER2 -extern "C" int dlopen_test_get_answer2() { +extern "C" int check_order_dlsym_get_answer2() { return __ANSWER2; } #endif diff --git a/tests/libs/dlopen_check_order_reloc_answer.cpp b/tests/libs/dlopen_check_order_reloc_answer.cpp new file mode 100644 index 000000000..036670bee --- /dev/null +++ b/tests/libs/dlopen_check_order_reloc_answer.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int __attribute__((weak)) check_order_reloc_get_answer_impl() { + return 0; +} + +extern "C" int check_order_reloc_get_answer() { + return check_order_reloc_get_answer_impl(); +} diff --git a/tests/libs/dlopen_check_order_reloc_answer_impl.cpp b/tests/libs/dlopen_check_order_reloc_answer_impl.cpp new file mode 100644 index 000000000..324b905da --- /dev/null +++ b/tests/libs/dlopen_check_order_reloc_answer_impl.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int check_order_reloc_get_answer_impl() { + return __ANSWER; +} diff --git a/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp b/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp new file mode 100644 index 000000000..065d1bef7 --- /dev/null +++ b/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int check_order_reloc_get_answer_impl(); + +extern "C" int check_order_reloc_nephew_get_answer() { + return check_order_reloc_get_answer_impl(); +} diff --git a/tests/libs/dlopen_check_order_reloc_root_answer.cpp b/tests/libs/dlopen_check_order_reloc_root_answer.cpp new file mode 100644 index 000000000..b21abd77a --- /dev/null +++ b/tests/libs/dlopen_check_order_reloc_root_answer.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int check_order_reloc_root_get_answer_impl(); + +extern "C" int check_order_reloc_root_get_answer() { + return check_order_reloc_root_get_answer_impl(); +} diff --git a/tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp b/tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp new file mode 100644 index 000000000..25fb9aca9 --- /dev/null +++ b/tests/libs/dlopen_check_order_reloc_root_answer_impl.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int check_order_reloc_root_get_answer_impl() { + return __ANSWER; +} From a42dfda53acc6127b5046672686b67a66be168eb Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 4 Nov 2014 09:38:00 -0800 Subject: [PATCH 098/114] Revert "Revert "Remove unnecessary lookups during relocations"" This reverts commit eae09772558016836f1356816f4d1d0be498d74c. --- linker/linker.cpp | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 48093f9d1..e6fc9eccd 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -530,6 +530,11 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c // 3. Look for it in the local group if (s == nullptr) { local_group.visit([&](soinfo* local_si) { + if (local_si == si && si->has_DT_SYMBOLIC) { + // we already did this - skip + return true; + } + DEBUG("%s: looking up %s in %s (from local group)", si->name, name, local_si->name); s = soinfo_elf_lookup(local_si, elf_hash, name); if (s != nullptr) { @@ -541,28 +546,6 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c }); } - // 4. Look for it in this library (unless we already did it because of DT_SYMBOLIC) - if (s == nullptr && !si->has_DT_SYMBOLIC) { - DEBUG("%s: looking up %s in local scope", si->name, name); - s = soinfo_elf_lookup(si, elf_hash, name); - if (s != nullptr) { - *lsi = si; - } - } - - // 5. Dependencies - if (s == nullptr) { - si->get_children().visit([&](soinfo* child) { - DEBUG("%s: looking up %s in %s", si->name, name, child->name); - s = soinfo_elf_lookup(child, elf_hash, name); - if (s != nullptr) { - *lsi = child; - return false; - } - return true; - }); - } - if (s != nullptr) { TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " "found in %s, base = %p, load bias = %p", From 1c095774c0527027bf3f7013ba15e9913d5f1853 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 4 Nov 2014 09:38:10 -0800 Subject: [PATCH 099/114] Revert "Revert "Fix mips build"" This reverts commit 4402804c35c5c5992c728c6f3cee3bdbd325819e. --- linker/linker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index e6fc9eccd..f14d8b48d 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -2281,7 +2281,7 @@ bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo #endif #if defined(__mips__) - if (!mips_relocate_got(this)) { + if (!mips_relocate_got(this, local_group)) { return false; } #endif From 0416d88f9c90dcb1b97947a27a7c05f3627484c4 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 4 Nov 2014 09:38:18 -0800 Subject: [PATCH 100/114] Revert "Revert "Fix symbol lookup order during relocation"" This reverts commit f947be2889639defc6424b1813ccc779528b7598. --- linker/linked_list.h | 12 +++ linker/linker.cpp | 162 +++++++++++++++++----------- linker/linker.h | 23 ++-- tests/Android.mk | 13 ++- tests/dl_test.cpp | 72 +++++++++++++ tests/dlfcn_test.cpp | 14 +++ tests/libs/Android.mk | 36 +++++++ tests/libs/dl_df_1_global.cpp | 19 ++++ tests/libs/dl_df_1_use_global.cpp | 23 ++++ tests/libs/dl_preempt_library_1.cpp | 45 ++++++++ tests/libs/dl_preempt_library_2.cpp | 37 +++++++ 11 files changed, 385 insertions(+), 71 deletions(-) create mode 100644 tests/dl_test.cpp create mode 100644 tests/libs/dl_df_1_global.cpp create mode 100644 tests/libs/dl_df_1_use_global.cpp create mode 100644 tests/libs/dl_preempt_library_1.cpp create mode 100644 tests/libs/dl_preempt_library_2.cpp diff --git a/linker/linked_list.h b/linker/linked_list.h index 72a32b4ba..b08806161 100644 --- a/linker/linked_list.h +++ b/linker/linked_list.h @@ -36,6 +36,12 @@ class LinkedList { clear(); } + LinkedList(LinkedList&& that) { + this->head_ = that.head_; + this->tail_ = that.tail_; + that.head_ = that.tail_ = nullptr; + } + void push_front(T* const element) { LinkedListEntry* new_entry = Allocator::alloc(); new_entry->next = head_; @@ -140,6 +146,12 @@ class LinkedList { return false; } + static LinkedList make_list(T* const element) { + LinkedList one_element_list; + one_element_list.push_back(element); + return one_element_list; + } + private: LinkedListEntry* head_; LinkedListEntry* tail_; diff --git a/linker/linker.cpp b/linker/linker.cpp index f14d8b48d..ab0fc0762 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -282,7 +282,7 @@ static void protect_data(int protection) { g_soinfo_links_allocator.protect_all(protection); } -static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, int rtld_flags) { +static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, uint32_t rtld_flags) { if (strlen(name) >= SOINFO_NAME_LEN) { DL_ERR("library name \"%s\" too long", name); return nullptr; @@ -481,7 +481,8 @@ static unsigned elfhash(const char* _name) { return h; } -static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, const soinfo::soinfo_list_t& local_group) { +static ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found_in, + const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) { unsigned elf_hash = elfhash(name); ElfW(Sym)* s = nullptr; @@ -496,49 +497,40 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c * Note that this is unlikely since static linker avoids generating * relocations for -Bsymbolic linked dynamic executables. */ - if (si->has_DT_SYMBOLIC) { - DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si->name, name); - s = soinfo_elf_lookup(si, elf_hash, name); + if (si_from->has_DT_SYMBOLIC) { + DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->name, name); + s = soinfo_elf_lookup(si_from, elf_hash, name); if (s != nullptr) { - *lsi = si; + *si_found_in = si_from; } } - if (s == nullptr && somain != nullptr) { - // 1. Look for it in the main executable unless we already did. - if (si != somain || !si->has_DT_SYMBOLIC) { - DEBUG("%s: looking up %s in executable %s", - si->name, name, somain->name); - s = soinfo_elf_lookup(somain, elf_hash, name); + // 1. Look for it in global_group + if (s == nullptr) { + global_group.visit([&](soinfo* global_si) { + DEBUG("%s: looking up %s in %s (from global group)", si_from->name, name, global_si->name); + s = soinfo_elf_lookup(global_si, elf_hash, name); if (s != nullptr) { - *lsi = somain; + *si_found_in = global_si; + return false; } - } - // 2. Look for it in the ld_preloads - if (s == nullptr) { - for (int i = 0; g_ld_preloads[i] != NULL; i++) { - s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); - if (s != nullptr) { - *lsi = g_ld_preloads[i]; - break; - } - } - } + return true; + }); } - // 3. Look for it in the local group + // 2. Look for it in the local group if (s == nullptr) { local_group.visit([&](soinfo* local_si) { - if (local_si == si && si->has_DT_SYMBOLIC) { + if (local_si == si_from && si_from->has_DT_SYMBOLIC) { // we already did this - skip return true; } - DEBUG("%s: looking up %s in %s (from local group)", si->name, name, local_si->name); + DEBUG("%s: looking up %s in %s (from local group)", si_from->name, name, local_si->name); s = soinfo_elf_lookup(local_si, elf_hash, name); if (s != nullptr) { - *lsi = local_si; + *si_found_in = local_si; return false; } @@ -549,9 +541,9 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, c if (s != nullptr) { TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " "found in %s, base = %p, load bias = %p", - si->name, name, reinterpret_cast(s->st_value), - (*lsi)->name, reinterpret_cast((*lsi)->base), - reinterpret_cast((*lsi)->load_bias)); + si_from->name, name, reinterpret_cast(s->st_value), + (*si_found_in)->name, reinterpret_cast((*si_found_in)->base), + reinterpret_cast((*si_found_in)->load_bias)); } return s; @@ -916,6 +908,24 @@ static bool is_recursive(soinfo* si, soinfo* parent) { }); } +// TODO: this is slightly unusual way to construct +// the global group for relocation. Not every RTLD_GLOBAL +// library is included in this group for backwards-compatibility +// reasons. +// +// This group consists of the main executable, LD_PRELOADs +// and libraries with the DF_1_GLOBAL flag set. +static soinfo::soinfo_list_t make_global_group() { + soinfo::soinfo_list_t global_group; + for (soinfo* si = somain; si != nullptr; si = si->next) { + if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) { + global_group.push_back(si); + } + } + + return global_group; +} + static bool find_libraries(soinfo* start_with, const char* const library_names[], size_t library_names_count, soinfo* soinfos[], soinfo* ld_preloads[], size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) { // Step 0: prepare. @@ -925,6 +935,9 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[] load_tasks.push_back(LoadTask::create(name, start_with)); } + // Construct global_group. + soinfo::soinfo_list_t global_group = make_global_group(); + // If soinfos array is null allocate one on stack. // The array is needed in case of failure; for example // when library_names[] = {libone.so, libtwo.so} and libone.so @@ -973,6 +986,11 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[] // When ld_preloads is not null, the first // ld_preloads_count libs are in fact ld_preloads. if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) { + // Add LD_PRELOADed libraries to the global group for future runs. + // There is no need to explicitly add them to the global group + // for this run because they are going to appear in the local + // group in the correct order. + si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); ld_preloads[soinfos_count] = si; } @@ -993,7 +1011,7 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[] bool linked = local_group.visit([&](soinfo* si) { if ((si->flags & FLAG_LINKED) == 0) { - if (!si->LinkImage(local_group, extinfo)) { + if (!si->LinkImage(global_group, local_group, extinfo)) { return false; } si->flags |= FLAG_LINKED; @@ -1128,7 +1146,7 @@ static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) { } #if defined(USE_RELA) -int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group) { +int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group) { for (size_t idx = 0; idx < count; ++idx, ++rela) { unsigned type = ELFW(R_TYPE)(rela->r_info); unsigned sym = ELFW(R_SYM)(rela->r_info); @@ -1146,7 +1164,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& loca if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi, local_group); + s = soinfo_do_lookup(this, sym_name, &lsi, global_group,local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1405,7 +1423,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& loca } #else // REL, not RELA. -int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group) { +int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group) { for (size_t idx = 0; idx < count; ++idx, ++rel) { unsigned type = ELFW(R_TYPE)(rel->r_info); // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. @@ -1424,7 +1442,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_ if (sym != 0) { sym_name = get_string(symtab[sym].st_name); - s = soinfo_do_lookup(this, sym_name, &lsi, local_group); + s = soinfo_do_lookup(this, sym_name, &lsi, global_group, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab[sym]; @@ -1610,7 +1628,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_ #endif #if defined(__mips__) -static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& local_group) { +static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) { ElfW(Addr)** got = si->plt_got; if (got == nullptr) { return true; @@ -1643,7 +1661,7 @@ static bool mips_relocate_got(soinfo* si, const soinfo::soinfo_list_t& local_gro // This is an undefined reference... try to locate it. const char* sym_name = si->get_string(sym->st_name); soinfo* lsi = nullptr; - ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, local_group); + ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, global_group, local_group); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. s = &symtab[g]; @@ -1783,7 +1801,7 @@ void soinfo::remove_all_links() { children.clear(); } -dev_t soinfo::get_st_dev() { +dev_t soinfo::get_st_dev() const { if (has_min_version(0)) { return st_dev; } @@ -1791,7 +1809,7 @@ dev_t soinfo::get_st_dev() { return 0; }; -ino_t soinfo::get_st_ino() { +ino_t soinfo::get_st_ino() const { if (has_min_version(0)) { return st_ino; } @@ -1799,7 +1817,7 @@ ino_t soinfo::get_st_ino() { return 0; } -off64_t soinfo::get_file_offset() { +off64_t soinfo::get_file_offset() const { if (has_min_version(1)) { return file_offset; } @@ -1807,7 +1825,7 @@ off64_t soinfo::get_file_offset() { return 0; } -int soinfo::get_rtld_flags() { +uint32_t soinfo::get_rtld_flags() const { if (has_min_version(1)) { return rtld_flags; } @@ -1815,6 +1833,27 @@ int soinfo::get_rtld_flags() { return 0; } +uint32_t soinfo::get_dt_flags_1() const { + if (has_min_version(1)) { + return dt_flags_1; + } + + return 0; +} +void soinfo::set_dt_flags_1(uint32_t dt_flags_1) { + if (has_min_version(1)) { + if ((dt_flags_1 & DF_1_GLOBAL) != 0) { + rtld_flags |= RTLD_GLOBAL; + } + + if ((dt_flags_1 & DF_1_NODELETE) != 0) { + rtld_flags |= RTLD_NODELETE; + } + + this->dt_flags_1 = dt_flags_1; + } +} + // This is a return on get_children()/get_parents() if // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -1852,8 +1891,9 @@ const char* soinfo::get_string(ElfW(Word) index) const { } bool soinfo::can_unload() const { - return (rtld_flags & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; + return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; } + /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -2154,16 +2194,9 @@ bool soinfo::PrelinkImage() { break; case DT_FLAGS_1: - if ((d->d_un.d_val & DF_1_GLOBAL) != 0) { - rtld_flags |= RTLD_GLOBAL; - } + set_dt_flags_1(d->d_un.d_val); - if ((d->d_un.d_val & DF_1_NODELETE) != 0) { - rtld_flags |= RTLD_NODELETE; - } - // TODO: Implement other flags - - if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)) != 0) { + if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) { DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast(d->d_un.d_val)); } break; @@ -2236,7 +2269,7 @@ bool soinfo::PrelinkImage() { return true; } -bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo) { +bool soinfo::LinkImage(const soinfo_list_t& global_group, const soinfo_list_t& local_group, const android_dlextinfo* extinfo) { #if !defined(__LP64__) if (has_text_relocations) { @@ -2255,33 +2288,33 @@ bool soinfo::LinkImage(const soinfo_list_t& local_group, const android_dlextinfo #if defined(USE_RELA) if (rela != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rela, rela_count, local_group)) { + if (Relocate(rela, rela_count, global_group, local_group)) { return false; } } if (plt_rela != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rela, plt_rela_count, local_group)) { + if (Relocate(plt_rela, plt_rela_count, global_group, local_group)) { return false; } } #else if (rel != nullptr) { DEBUG("[ relocating %s ]", name); - if (Relocate(rel, rel_count, local_group)) { + if (Relocate(rel, rel_count, global_group, local_group)) { return false; } } if (plt_rel != nullptr) { DEBUG("[ relocating %s plt ]", name); - if (Relocate(plt_rel, plt_rel_count, local_group)) { + if (Relocate(plt_rel, plt_rel_count, global_group, local_group)) { return false; } } #endif #if defined(__mips__) - if (!mips_relocate_got(this, local_group)) { + if (!mips_relocate_got(this, global_group, local_group)) { return false; } #endif @@ -2348,7 +2381,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->load_bias = get_elf_exec_load_bias(ehdr_vdso); si->PrelinkImage(); - si->LinkImage(g_empty_list, nullptr); + si->LinkImage(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr); #endif } @@ -2479,6 +2512,9 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( si->PrelinkImage(); + // add somain to global group + si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); + // Load ld_preloads and dependencies. StringLinkedList needed_library_name_list; size_t needed_libraries_count = 0; @@ -2622,7 +2658,13 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - if (!(linker_so.PrelinkImage() && linker_so.LinkImage(g_empty_list, nullptr))) { + // This might not be obvious... The reasons why we pass g_empty_list + // in place of local_group here are (1) we do not really need it, because + // linker is built with DT_SYMBOLIC and therefore relocates its symbols against + // itself without having to look into local_group and (2) allocators + // are not yet initialized, and therefore we cannot use linked_list.push_* + // functions at this point. + if (!(linker_so.PrelinkImage() && linker_so.LinkImage(g_empty_list, g_empty_list, nullptr))) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as diff --git a/linker/linker.h b/linker/linker.h index 222aca11e..0a98b40dc 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -89,7 +89,9 @@ #define FLAG_LINKER 0x00000010 // The linker itself #define FLAG_NEW_SOINFO 0x40000000 // new soinfo format -#define SOINFO_VERSION 0 +#define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE) + +#define SOINFO_VERSION 1 #define SOINFO_NAME_LEN 128 @@ -207,16 +209,18 @@ struct soinfo { void CallDestructors(); void CallPreInitConstructors(); bool PrelinkImage(); - bool LinkImage(const soinfo_list_t& local_group, const android_dlextinfo* extinfo); + bool LinkImage(const soinfo_list_t& global_group, const soinfo_list_t& local_group, const android_dlextinfo* extinfo); void add_child(soinfo* child); void remove_all_links(); - ino_t get_st_ino(); - dev_t get_st_dev(); - off64_t get_file_offset(); + ino_t get_st_ino() const; + dev_t get_st_dev() const; + off64_t get_file_offset() const; - int get_rtld_flags(); + uint32_t get_rtld_flags() const; + uint32_t get_dt_flags_1() const; + void set_dt_flags_1(uint32_t dt_flags_1); soinfo_list_t& get_children(); soinfo_list_t& get_parents(); @@ -234,9 +238,9 @@ struct soinfo { void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); #if defined(USE_RELA) - int Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& local_group); + int Relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group); #else - int Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& local_group); + int Relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group); #endif private: @@ -254,7 +258,8 @@ struct soinfo { // version >= 1 off64_t file_offset; - int rtld_flags; + uint32_t rtld_flags; + uint32_t dt_flags_1; size_t strtab_size; friend soinfo* get_libdl_info(); diff --git a/tests/Android.mk b/tests/Android.mk index 2f182654e..82eae3da4 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -233,6 +233,7 @@ bionic-unit-tests_static_libraries := \ bionic-unit-tests_src_files := \ atexit_test.cpp \ + dl_test.cpp \ dlext_test.cpp \ dlfcn_test.cpp \ @@ -245,8 +246,7 @@ bionic-unit-tests_conlyflags := \ bionic-unit-tests_cppflags := $(test_cppflags) bionic-unit-tests_ldflags := \ - -Wl,--export-dynamic \ - -Wl,-u,DlSymTestFunction \ + -Wl,--export-dynamic bionic-unit-tests_c_includes := \ bionic/libc \ @@ -255,6 +255,9 @@ bionic-unit-tests_c_includes := \ bionic-unit-tests_shared_libraries_target := \ libdl \ libpagemap \ + libdl_preempt_test_1 \ + libdl_preempt_test_2 \ + libdl_test_df_1_global module := bionic-unit-tests module_tag := optional @@ -302,6 +305,12 @@ ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x bionic-unit-tests-glibc_src_files := \ atexit_test.cpp \ dlfcn_test.cpp \ + dl_test.cpp \ + +bionic-unit-tests-glibc_shared_libraries := \ + libdl_preempt_test_1 \ + libdl_preempt_test_2 \ + libdl_test_df_1_global bionic-unit-tests-glibc_whole_static_libraries := \ libBionicStandardTests \ diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp new file mode 100644 index 000000000..74c7b510f --- /dev/null +++ b/tests/dl_test.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include + +#include + +extern "C" int main_global_default_serial() { + return 3370318; +} + +extern "C" int main_global_protected_serial() { + return 2716057; +} + +// The following functions are defined in DT_NEEDED +// libdl_preempt_test.so library. + +// This one calls main_global_default_serial +extern "C" int main_global_default_get_serial(); + +// This one calls main_global_protected_serial +extern "C" int main_global_protected_get_serial(); + +// This one calls lib_global_default_serial +extern "C" int lib_global_default_get_serial(); + +// This one calls lib_global_protected_serial +extern "C" int lib_global_protected_get_serial(); + +// This test verifies that the global default function +// main_global_default_serial() is preempted by +// the function defined above. +TEST(dl, main_preempts_global_default) { + ASSERT_EQ(3370318, main_global_default_get_serial()); +} + +// This one makes sure that the global protected +// symbols do not get preempted +TEST(dl, main_does_not_preempt_global_protected) { + ASSERT_EQ(3370318, main_global_protected_get_serial()); +} + +// check same things for lib +TEST(dl, lib_preempts_global_default) { + ASSERT_EQ(3370318, lib_global_default_get_serial()); +} + +TEST(dl, lib_does_not_preempt_global_protected) { + ASSERT_EQ(3370318, lib_global_protected_get_serial()); +} + +// TODO: Add tests for LD_PRELOADs diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 2ab3dc1ed..060f7e09c 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -499,6 +499,20 @@ TEST(dlfcn, dlopen_nodelete_dt_flags_1) { ASSERT_TRUE(!is_unloaded); } +TEST(dlfcn, dlsym_df_1_global) { +#if !defined(__arm__) + void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr) << dlerror(); + int (*get_answer)(); + get_answer = reinterpret_cast(dlsym(handle, "dl_df_1_global_get_answer")); + ASSERT_TRUE(get_answer != nullptr) << dlerror(); + ASSERT_EQ(42, get_answer()); + ASSERT_EQ(0, dlclose(handle)); +#else + GTEST_LOG_(INFO) << "This test does nothing on arm (to be reenabled once b/18137520 or b/18130452 are fixed).\n"; +#endif +} + TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index e4fee6a6c..a45442031 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -290,6 +290,42 @@ libtest_atexit_src_files := \ module := libtest_atexit include $(LOCAL_PATH)/Android.build.testlib.mk +# ----------------------------------------------------------------------------- +# This library is used by dl_load test to check symbol preempting +# by main executable +# ----------------------------------------------------------------------------- +libdl_preempt_test_1_src_files := dl_preempt_library_1.cpp + +module := libdl_preempt_test_1 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# This library is used by dl_load test to check symbol preempting +# by libdl_preempt_test_1.so +# ----------------------------------------------------------------------------- +libdl_preempt_test_2_src_files := dl_preempt_library_2.cpp + +module := libdl_preempt_test_2 +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# Library with DF_1_GLOBAL +# ----------------------------------------------------------------------------- +# TODO: re-enable arm once b/18137520 or b/18130452 are fixed +ifeq ($(filter $(TARGET_ARCH),arm),) +libdl_test_df_1_global_src_files := dl_df_1_global.cpp +libdl_test_df_1_global_ldflags := -fuse-ld=bfd -Wl,-z,global +module := libdl_test_df_1_global +include $(LOCAL_PATH)/Android.build.testlib.mk +endif + +# ----------------------------------------------------------------------------- +# Library using symbol from libdl_test_df_1_global +# ----------------------------------------------------------------------------- +libtest_dlsym_df_1_global_src_files := dl_df_1_use_global.cpp +module := libtest_dlsym_df_1_global +include $(LOCAL_PATH)/Android.build.testlib.mk + # ----------------------------------------------------------------------------- # Library with weak function # ----------------------------------------------------------------------------- diff --git a/tests/libs/dl_df_1_global.cpp b/tests/libs/dl_df_1_global.cpp new file mode 100644 index 000000000..39856fd50 --- /dev/null +++ b/tests/libs/dl_df_1_global.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int dl_df_1_global_get_answer_impl() { + return 42; +} diff --git a/tests/libs/dl_df_1_use_global.cpp b/tests/libs/dl_df_1_use_global.cpp new file mode 100644 index 000000000..e14910d1c --- /dev/null +++ b/tests/libs/dl_df_1_use_global.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" int __attribute__((weak)) dl_df_1_global_get_answer_impl() { + return 0; +} + +extern "C" int dl_df_1_global_get_answer() { + return dl_df_1_global_get_answer_impl(); +} diff --git a/tests/libs/dl_preempt_library_1.cpp b/tests/libs/dl_preempt_library_1.cpp new file mode 100644 index 000000000..b4d81d5ac --- /dev/null +++ b/tests/libs/dl_preempt_library_1.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This one should be preempted by the function +// defined in the main executable. +extern "C" int __attribute__((weak)) main_global_default_serial() { + return 2716057; +} + +// Even though this one is defined by the main +// executable it should not be preempted +// because of protected visibility +extern "C" int __attribute__((weak, visibility("protected"))) main_global_protected_serial() { + return 3370318; +} + +extern "C" int main_global_default_get_serial() { + return main_global_default_serial(); +} + +extern "C" int main_global_protected_get_serial() { + return main_global_protected_serial(); +} + +// Trying to preempt functions from a DT_NEEDED .so +extern "C" int lib_global_default_serial() { + return 3370318; +} + +extern "C" int lib_global_protected_serial() { + return 2716057; +} diff --git a/tests/libs/dl_preempt_library_2.cpp b/tests/libs/dl_preempt_library_2.cpp new file mode 100644 index 000000000..8df9a1667 --- /dev/null +++ b/tests/libs/dl_preempt_library_2.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This one should be preempted by the function +// defined in libdl_preempt_test_1.so +extern "C" int __attribute__((weak)) lib_global_default_serial() { + return 2716057; +} + +// Even though this one is defined by +// libdl_preempt_test_1.so it should not be +// preempted because of protected visibility +extern "C" int __attribute__((weak,visibility("protected"))) lib_global_protected_serial() { + return 3370318; +} + +extern "C" int lib_global_default_get_serial() { + return lib_global_default_serial(); +} + +extern "C" int lib_global_protected_get_serial() { + return lib_global_protected_serial(); +} + From ca564e2a994df5976869ec655c7d4056deefcaa2 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 4 Nov 2014 09:38:27 -0800 Subject: [PATCH 101/114] Revert "Revert "Fix arm64 and arm builds."" This reverts commit 494bee796aa60131981308493e0e295493537e12. --- tests/Android.mk | 14 ++++++++++---- tests/dlfcn_test.cpp | 4 ++-- tests/libs/Android.mk | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/Android.mk b/tests/Android.mk index 82eae3da4..66b165541 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -256,8 +256,11 @@ bionic-unit-tests_shared_libraries_target := \ libdl \ libpagemap \ libdl_preempt_test_1 \ - libdl_preempt_test_2 \ - libdl_test_df_1_global + libdl_preempt_test_2 + +ifneq ($(filter $(TARGET_ARCH),arm arm64),$(TARGET_ARCH)) +bionic-unit-tests_shared_libraries_target += libdl_test_df_1_global +endif module := bionic-unit-tests module_tag := optional @@ -309,8 +312,11 @@ bionic-unit-tests-glibc_src_files := \ bionic-unit-tests-glibc_shared_libraries := \ libdl_preempt_test_1 \ - libdl_preempt_test_2 \ - libdl_test_df_1_global + libdl_preempt_test_2 + +ifneq ($(filter $(TARGET_ARCH),arm arm64),$(TARGET_ARCH)) +bionic-unit-tests-glibc_shared_libraries += libdl_test_df_1_global +endif bionic-unit-tests-glibc_whole_static_libraries := \ libBionicStandardTests \ diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 060f7e09c..3af9e12a5 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -500,7 +500,7 @@ TEST(dlfcn, dlopen_nodelete_dt_flags_1) { } TEST(dlfcn, dlsym_df_1_global) { -#if !defined(__arm__) +#if !defined(__arm__) && !defined(__aarch64__) void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW); ASSERT_TRUE(handle != nullptr) << dlerror(); int (*get_answer)(); @@ -509,7 +509,7 @@ TEST(dlfcn, dlsym_df_1_global) { ASSERT_EQ(42, get_answer()); ASSERT_EQ(0, dlclose(handle)); #else - GTEST_LOG_(INFO) << "This test does nothing on arm (to be reenabled once b/18137520 or b/18130452 are fixed).\n"; + GTEST_LOG_(INFO) << "This test does nothing on arm/arm64 (to be reenabled once b/18137520 or b/18130452 are fixed).\n"; #endif } diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index a45442031..2fb0b1225 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -312,7 +312,7 @@ include $(LOCAL_PATH)/Android.build.testlib.mk # Library with DF_1_GLOBAL # ----------------------------------------------------------------------------- # TODO: re-enable arm once b/18137520 or b/18130452 are fixed -ifeq ($(filter $(TARGET_ARCH),arm),) +ifeq ($(filter $(TARGET_ARCH),arm arm64),) libdl_test_df_1_global_src_files := dl_df_1_global.cpp libdl_test_df_1_global_ldflags := -fuse-ld=bfd -Wl,-z,global module := libdl_test_df_1_global From 371dcc189f62dbf5bc861aed41754a0ef1008ee5 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 11 Nov 2014 14:10:51 -0800 Subject: [PATCH 102/114] Fix tzdata update tools for 'backzone'. To maintain the status quo, we need to pull in backzone file. This file can't be built on its own, so the easiest fix is to give zic(1) all the files at once. We also now have a situation where we have links to links, so we need to dereference them until we find actual data. Bug: 18330681 (cherry picked from commit 2c2463bd3065f0a5fef34a47e3eb94aad64b0cea) Change-Id: I654b80518a7144038d8b3ea7223f49e2b1d2ad13 --- libc/tools/zoneinfo/ZoneCompactor.java | 10 ++++++++-- libc/tools/zoneinfo/update-tzdata.py | 22 +++++++++++++--------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/libc/tools/zoneinfo/ZoneCompactor.java b/libc/tools/zoneinfo/ZoneCompactor.java index bf3153eff..2d598fec0 100644 --- a/libc/tools/zoneinfo/ZoneCompactor.java +++ b/libc/tools/zoneinfo/ZoneCompactor.java @@ -132,9 +132,15 @@ public class ZoneCompactor { throw new RuntimeException("zone filename too long: " + zoneName.length()); } + // Follow the chain of links to work out where the real data for this zone lives. + String actualZoneName = zoneName; + while (links.get(actualZoneName) != null) { + actualZoneName = links.get(actualZoneName); + } + f.write(toAscii(new byte[MAXNAME], zoneName)); - f.writeInt(offsets.get(zoneName)); - f.writeInt(lengths.get(zoneName)); + f.writeInt(offsets.get(actualZoneName)); + f.writeInt(lengths.get(actualZoneName)); f.writeInt(0); // Used to be raw GMT offset. No longer used. } diff --git a/libc/tools/zoneinfo/update-tzdata.py b/libc/tools/zoneinfo/update-tzdata.py index f5681beb2..330f1662d 100755 --- a/libc/tools/zoneinfo/update-tzdata.py +++ b/libc/tools/zoneinfo/update-tzdata.py @@ -13,8 +13,11 @@ import sys import tarfile import tempfile -regions = ['africa', 'antarctica', 'asia', 'australasia', 'backward', - 'etcetera', 'europe', 'northamerica', 'southamerica'] +regions = ['africa', 'antarctica', 'asia', 'australasia', + 'etcetera', 'europe', 'northamerica', 'southamerica', + # These two deliberately come last so they override what came + # before (and each other). + 'backward', 'backzone' ] def CheckDirExists(dir, dirname): if not os.path.isdir(dir): @@ -49,16 +52,16 @@ def WriteSetupFile(): fields = line.split() if fields: if fields[0] == 'Link': - links.append('%s %s %s\n' % (fields[0], fields[1], fields[2])) + links.append('%s %s %s' % (fields[0], fields[1], fields[2])) zones.append(fields[2]) elif fields[0] == 'Zone': zones.append(fields[1]) zones.sort() setup = open('setup', 'w') - for link in links: - setup.write(link) - for zone in zones: + for link in sorted(set(links)): + setup.write('%s\n' % link) + for zone in sorted(set(zones)): setup.write('%s\n' % zone) setup.close() @@ -165,9 +168,10 @@ def BuildBionicToolsAndData(data_filename): print 'Calling zic(1)...' os.mkdir('data') - for region in regions: - if region != 'backward': - subprocess.check_call(['zic', '-d', 'data', 'extracted/%s' % region]) + zic_inputs = [ 'extracted/%s' % x for x in regions ] + zic_cmd = ['zic', '-d', 'data' ] + zic_cmd.extend(zic_inputs) + subprocess.check_call(zic_cmd) WriteSetupFile() From 1ca3350f4c7b60afdb95784c9cb3ea5ba5ce591f Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 11 Nov 2014 16:44:21 -0800 Subject: [PATCH 103/114] Upgrade bionic to tzdata2014j. From the release notes: Changes affecting current and future time stamps Turks & Caicos' switch from US eastern time to UTC-4 year-round did not occur on 2014-11-02 at 02:00. It's currently scheduled for 2015-11-01 at 02:00. (Thanks to Chris Walton.) Changes affecting past time stamps Many pre-1989 time stamps have been corrected for Asia/Seoul and Asia/Pyongyang, based on sources for the Korean-language Wikipedia entry for time in Korea. (Thanks to Sanghyuk Jung.) Also, no longer guess that Pyongyang mimicked Seoul time after World War II, as this is politically implausible. Some more zones have been turned into links, when they differed from existing zones only for older time stamps. As usual, these changes affect UTC offsets in pre-1970 time stamps only. Their old contents have been moved to the 'backzone' file. The affected zones are: Africa/Addis_Ababa, Africa/Asmara, Africa/Dar_es_Salaam, Africa/Djibouti, Africa/Kampala, Africa/Mogadishu, Indian/Antananarivo, Indian/Comoro, and Indian/Mayotte. Bug: 18330681 (cherry picked from commit b11d8e057c86c3926128af9d07180d9328e144c6) Change-Id: Ifd48e7446e400dccae3afd5cbef96ca843775477 --- libc/zoneinfo/tzdata | Bin 565358 -> 498091 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata index e9cf16428fd3a6bd6e022ff8f460ee134f9c9a41..fc6c5babb83b74177bbaa18f47f38cd5de8d7c5b 100644 GIT binary patch delta 11777 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 xe6%ic7PGA90&X8_>5AUpRU-&vC;aZ)}Jf3 z8Zl#p)Z51|nxhXpj+^Po8TGrm&MrwJxvB8=@v3z?sl;#`^^3%g_x$HDgdZsc z-z7Qx7{SPg*a=dh`z#VdL4$F6%M+v$qxT%wBZF)f#FPE(TH|s3#dn(X~BEFpx^R$mpb> zq|m^VMLy639p)y%IYjEA)T2-`hShChh#_)4k|}7gNN+zVXnAiVAj(K8>0w37pCzeA zoSMiF*TJ6Qw9;4sZ=t3A;*b35OY%-l4xr8AF8VEV`xY&np#L^ zox~8Gsi$P#kAFt1ydn&ZZ0M=|*CVbS&4;pTs;v=p`e-u?$_GBrdkVk5lFHgr$+qv#&8b4W-XT!uJ`efcD>j#QF;guWSUNEOW=E+LNQ zQbBD)!YPhMkfjtSZAd=FDKAn*q1j2CEu_Mk1QJ0(uU5Q;R8oAC8i~L|T zSw+09DeDjt#b{rfq*&vnFQI6-C&@-CX-;1~A(8mocnTh?$T%Axktm>?q}oV@<;RGY z!gD4O+e!r=8S%H3O4?{S&UqY(vGtS;_UAa$XtIMIj>(|c{TeB=^lv$rA%_VpyokI@%oDpW&tjXTE~ z525NQY*q#YPUi1|mjscPN>Ipj%iLRa zdI~|iNOD6gUqsQT9r-~q#GZIJk_zL>NEF3X3z9-Hw*x7mSYVvgm|n@Cq{j70@5a`` zS_K)`SSm@OFBN^WrZ@H!wj>fQjcn~e7pYB*Ts(!{p~T-sD(sm~CQ|G@M$#$hGcI+J zO0;+Adu|#rZQ?297?OY{QsGb+5<`*Ooa|^Kl^h>MU!{qpoaWD7C8n-Y;oL?dbCpUi zPC{a~tLHy8vgqMIpGB^o!i}E9ys1s!xZu)y8m{Mf?8Roe87>eqfa9nLy^4tyYXuD>}gy<2cM_w~J&E1DQXY?3B z9Gg>mMw4(xzrJKCBfXdM8M_LksyT`{yGw<>DiT3KFGoDZuR5_4I&dMKAVtq zir+D$)W=687OfygQp#-!BtYt8C>D33rH_yqQV)^X=nL5)rFS0vn9#%2myR%SJu(?WR_|n;Cm&qPR>g8;V9sQ2sZHbj19b?~z1o_dNeKncwM{|xr9M`xnsq~{K z-;G$cq@fP<_GvtYgtYW96pxb7sRKw{OAkwN)KGddE7(2VaeDL!uiz;&Ny9;QBs`*) zFs_nRvZ)hY>5zlOv6Y8N67-FPw4y7;+$M3YXl@$)XyR^={8qH=bb&5mK&t3C@diWU z*qY`y%VLkFjSqdCnN_ zLL7re8ybXX)AjO5d=Onj8Bg+qXs+KVQpGsTggAGh9DbNYFw%TH3@jn>pd3ksL*C+qD?w;(sC8az4WTYR+CEca;J29yT9k;PQ@ng*BOUCs; ztB^`TKN__Z^jkpOQ~zP=-;*^kWMa>Me^&44>B&A=OKFAdc+t+!WOd{fGD^eChSIz8BOhYLTrV&}FkGa7iOZt8GiH+_uc23L; z!jEt<GsF_9Lz>g%4k*@cg@yvAM*qiYk31>VTOO}FPNIql1JW>Vz zBF=rN7cL?ZjOREK4=TtB@E56JJimar^kw`(1~OilM-sqqM8ine{qTow5!8$3kVvqa zDF3kV55F*898FsEqaOjqL{4#U1xfBl-{=zzNDTeFe0PK7~X)kdoH+XKcTfO#I{NjP$d* z^p6`2@-dWzZKgMDC6NuHuVOz1i5W!445e-AAe>hjQ(DS&Fy)*+M8>%E5t+fbRz&tN z(k03nH+mBDA(UGtlAs~9^xk{4^eHlb2>WO~PO?~z-rG9H{2s(A5=#U}Ql-y%K4Zx` zl0(BcrKB=aDyc}M1tN&!P)`;K8H(|7L#2|+M>KJSwX|77#&okX1I@`p$q*%)4-6p$vs4d z%^b);ITlWk(;>b|L?ibxqb~#Pz@pe4(XA7^9aP!?K`hWKiO zApMbs2%$DyKB;>_C!7(obdmS1>6VNk8Q12jCAHGwe)%;Nu<> zzfttOf?`S3C_282H%S3ckdje!OxK=tOd1hK(J@`06Tc`rrrR>>{dapmdo1nUY0tig z=2#0?&Nw54n2+?=?8ehvMm`B)+_sd& zji+O_(>}&2mE@17W6oS6&spy5K;k%ovY?qKI6HDr0NfyCsIG}Kq4m6 zTIZk9^EyEiCem8;s-0lDqM4+I@nS>bGKsN(3}h_6N)i|^ohBN_k`?3wiBTxL3h zE>5qnY{tKS9GyMG13%91p(*y`efbR94y`5Tu|Bowv!ttkW2ewB;-B}9K@n|+W7*=> zBrDd(^v`D$8#I7C3~@6tEE`F0?A|Ouv=Qu9HKb#y%~bgu7kTB*n|W45a%NiD8*8%P zrO-CZh5bz&*W8;k=ol0l!FB1V>TM#X?~SuoK4!n^qw{n7d`1kXy|4@ILoti~*i2^` zhtNrXW=0VI^d=;%*fh8M-0Q;s%PN{QQ&so^v2oy^l@b`Em#a+~^(%_#Vl%Mh42~{I zPuB0Jt1wCWyT<--$EQpTho?E0bP_RjHOYiF#7lqxTf8oJ#i=$5K7?*hE z!Y^UmcTb^ z&cQd`JOJOEz8ju;SP4&yQ>;W_%lc^uY?V)dr!QP9=jbD&dwe+KwqaA{jN6-yhwljN z3*TuR0^jA-629w&Cw%uWTlk)f=J37Ge03asWFBgvW!!hcTF02BNUDv%{#~CDI54#a zp1u4IJg4_{_`xy9;fH+k;JIDX;CU7s;D^1A$vOHs{4F<}QC%lh4&Gf4&#ztxKYDBy z{Mc1FTycEUAOucicS7Lg+;;F&YhB={2iJ#dX3KOOeVpmc{!)zo4eh{2I>v&=4)8*M zG5nnH6Mo+IDg6AS3iyT3Mew4tXW$ogPvjiODY)W&55nmIcS&=B1-O#c8u;b(z3?j& zw!yE)t%hrRE`?u{Pl8`}9|ON33xk)M1jBDOo1o+96<+qji#mP( z-^p`B;O<2W47itE3tqnGJ^cRkD)@sWb2&#J6+?}~8Ff?N$r&F8yn;XKT?&8fco|;l za|B-bBOCtIA_e}md>#DR+qrVKKKJ~@bOc`9-Jqk&z1+E0%lPWpY#n3OvZ?Ubn+C(* zjP47so*MwK>CzJZcCZutT@zdQ`?ehXgZL}_W8?aAjy^uVu?c7VEc}+U^|{ZNzaa4C z(L*`&ulw)9znv|Be_wL~{$txt_|HjO;J+5Hfd3ASW6pCEw(A)AR;gM>q31HV$Yvp2 z>^>GQ{v?M>Ou8!&klgBofZ;25xX}?8xbY=3c&!Z*xJh1fIY$edDjJ6~nkAdUYY#Vo z*O~qXZXWmyZqZi@uj_OXZs~gnZux5;+}crbMaR)X*3T|z8Et;#z-=$=h1-=U!R>di zhSxhW1MaY565KJhKfM0fFu2ove|Up#K5*yJ{p1|2+t9mLIAfzOt>KN$z2Pp3CiV!p z)YL`5Rs0?9di4XmY2|&mTlOt@v&&y~94*v5<(-z%eg8dpi`k`ck2NRZo&%4-y(Vpi zd;6!reL@$(rFL`S3SW;=2>5=9M4+WjoSdVDTRxl<&e-bHNOA)Bql^!3f@d1P>34eF^U%dkmKim*_ZJw_~&4T1o}qDeyT0osA!|03YO33=euy z0PpfE3*PnOPI$KmiSXdPE8yKP?2~hJUXP?5;fy_ZuYre5TMiFhF$LbM&p3G4*xvAP zX%FfOj_=*g7lA%?TVO!nrq=Mj?`p&QnfvHCTDaf6=32)7HJ0!J$4%h_uYQCN+VloK zIQuqy$XqQva_v$0(7}h`!)D)-bF|Lz&R4_P{m;t><|8no@xgGG80o(WK1xL3QFim; zQIBKcqrVJ;k0}@cA6q7akK5h`9(^WK$I&|D6Z&ZxCu9V|Cr)e)pR~vsJ~_l*%kF=E z$_N30829fOFjZCwpJs9&KHd2|eEO@?@L1!=a*oc6EiDgcocZD$d{*8m`0R_j;d7GH z;dA${gwLC?7(RdH1o(o8D186(3#YBnakP-4eVmptu1_?4QT>td#nPVe#Xp1KOY3^T zm)>`UFMC%9zWk&Se8si5@c7i1@Ri4F%Q;$i)pEmd#?_l@;0dD@FA!KW_c{WJT`s}b z4$gxso9u_LYr6rSWUv-a8XwYev=Di-Ps_Molnh^gWet48Pfhq8mf`RajiM`>Q zwzq|ER!sIqAa#i&0%^Uh;aeuQk#n^0*4EN+#`F*ec!sSNe4G1E__j}<;5$qz;5%-W z!FRqo1K)Mz7<~7o?eIMtQsH~^PU|>YSCOg6*Rq3s$r%V_4c`RcKVu2}K!^G8>F=XZpa_}Eki!nsu?`Dq7gjrCwe^oa8ZYFj@CbNA1xlQ-h&p8&p%m9PU8yx zXuJpmj-^(y0DpY!6ZnbwSKueRU4Wm8%z>Y7x)-kLf*y}QV~!q=KilMhj?F(?vs=qp zXn-D%FVv#NrhWz=Q3CLeK7eSrg|3%7B1TG#xkH;6!L665@O6)6Vg-QmY$Kx+g zZVA8A#xtD7ulBNqYwgkF@z*@Q!moXKhx`q*d+-}&rSQ^EpLHCack@h*mhslDJ38F| zw==FIP<8}89)D*MdOZH_hBQpLH(~?w}jOqXyKRB9kh(E z;>GZ)K0o2F$3BI>kygN~yP?P9YwDuMo&?a043On|??z6}1MX0Jld(ZU~( zZwqJqq+JdFym=}7OU@+t*Lh>$-;`nS??cez@jqgG;6K|nNB-9!^mzPlm#$il?z(Yp zymXAb7%iS4*jvDb%38>az9`V+3E~3uc!ELMO$?B1zk&gV`D(b)k{q~k26{Z9)B(Xf`4RUc1FQc%6>4$D?s`)9G-FhLLcKs(x@wMXlL7Ho)@cR4t>` zOZ0ex^ zsQ)FL(OHTXPjLQ;7Ee$#s#|~ojqabofX468;|VS&(c=kCuCGAeH4QzU(DYC=+-<=~ zjBmCXJ)Y2f40=4leco6dM;B_*RgM$z7}6c?>DmeI)ebG5;4MLmrx1J`%rL;`sRRRj z#m(icfbZ4DSir9mJ)Y1q8$F)Ts^AUstrMRi@4sCOZ!`HKyzLV7ctX2g```hil96xk zxdt8>lB45j{SLN!we0>EWG#{qkbPcF1Dw#wbOyZB?Md*?Rp{}AAaxkLONl@7T~$8t zZioBH*}UMmUg3=0*SCiEkfX;FddAwrLu7T44~_T^@73S~zW;?VzxxP;{l0|(y{%5e zdspPc`~1A8<7nZ&MddT0CL=AhdYGgvrIoPi#}5z<^1;vJjYTzY{*iGZ8-J z>k9bP+A;8{ccS6b-t>V_KiU&M<2HIcA$A*jJYlA~x16I3&sy9goN>0w7d~esT0CLy zENl3@PKw$XFu(t21Qs-`fiIL<>Nq-4VS*k{h->f>9{2K%mc zf@0$k^mxLinDZF0x!q|DNDbcuPjkqCZ)t-bPuMC(k0+$tqsJ4{E79W#8DCe**#g@N z7l$)$zk?o6*s&uDzVm1(^1GIHh40?z#atomiE=|=@8X_18W1u=(c=mGMtZ=rJY2Ob zzP}TCJmG*DdORV!;alXht6n01kiP*xSW*H%^s+|I=H(uKf%(Sx~M>6wh zp5FiJ*!>ugziI;}9PPIjer)_~`0FO*XM-u3qE7Qg;WPDP&C#G3tXIs9#1Il ziXKn6G^7Ig64x^1FSk1bzal}8CtP*d4!`;|6?yIVW$L>8WC07&(RI1S92~Vo_{^r$vpH@t5lz z_^-EU@kE^DICBwqEsy0zyy9sZ0>Z%!2#C%r;No@Y@k9o@M!+Rg2P1E|7CoNGXfS#_ zk?|Dtc%oWu(c_6s!aB)0TG+H+yKqJ`FBiDkH?(-7I&~!QI(L2}uP}e}907}?4-u$a zh8|C3xeYy@$V&ZG$I(L8iz{#fHmV}H?Z`85yIJV*ME0G~49(K6&6Wqajp zetnZ|sPE*A7Ek2#3N4;OzB>ts_f+jj7uylKyJ0YzRu|`H$6M3yuS9#*;4wnuKQXh_dqpfp zHl|9kX=1(hqaoeJFx{|EWaLr%$o3mqx6%~a>bhe}d4Z=pAEmSu+j0?eoNE?m#P&bB zbd2CS(Jh-1?F^m&ncA*4+dN^@8CeO&|CciT*al8p+jZ}+o6_~%X8g0BekHaq)XMIE zNk)*i>5bVF&b3h;k*K!H1S1d2gKsJv^UiM4-b!0u_AH@W1TWBk+R8aa{Zp6z3l2B7 zn?s+C8If&wz}3Or_Ll6N*?dM;gOSx?{C}xMI;1=0YSM1A%`Q_{fiB7Z7$4bwCHz@J zk1~25>{8MPJq7VUm+{Zem#Ip=Ph{3I=0wyNwj7(IUzW~euSD~BHc|gduxIceuY`UJ zjBZ7dtczuZGJ*SGz)tFW3_#1t;ne2 zhx7s%k(ejL{xzOGAH!V7ryc+6%=DM-KcAEGUo-U2W!TIA&vP-=UrqAs`WbTb^_G7> zBYNG)?=qv@k~hQu$5mss*j0N$X1HgIu?t`^2g{Jnx|X#Pd@P@a$FTT?Hfc zJVX8yukttJT~yWIMU4^U?NpxU_}Qu)UTC6P(OuZ6{#}dr6);LY%#8Q9R%sfEObzDI z+Q#bLjra^f72cfpR%M(OIsIo!-GpBwMvCWESH(h0b|a|IH|Nh8s=_}BrYc20dJ0>m z{B>S6%a3c5lOYHk=a~t6h`$#e%9wOOYjeY9@lHv$`mm&k?c4nu{B>oSqroSf7<@&bYYE zIQWtQ3*k%cd%%~qmcy3|W5E@+o%DRv9gP3%0!l@X(;SV6Mv|Ft1G{cvw6NJkn^kk}YtgvI{(47!1!ZYzja6C;)zJe`io}{HzlW zPONDHp4`TPrzRPKrx!f}H6bs+Gvj}ovjxt!xCAfg@ep2Ux*vY7c>(;~$71k8t(|(_ z%mRyEt^h9{PGqDT>o>M5S;0%|V~{AxT?W4#+XsGyjD=qvHW}1T?+#uI3X=bOviCeh1(B3*ftu``~-qO7KIA(|UeB z4}P+~r)2d%-QHu4`~UODlL&lKufl+@H@CvSsV2g|A6^9i5f=~sTt5o@B_9v|j_tz8 zbFvVSA2!mQx!~*x7X=2v#hf|Zz{wSE@WMlZ1IaHV(C}g%(CGe4(0I>Vu-3^E&?No_ zXu9jUk}Y61?l8Re@?vSH4(J5SPxpc#_0K0F$)Jab=H`(f;QI% z!ELLj!0isUgWF&24X?LpAn1_o3p&ni3)Ww24LS{W1RG5L3_7>@1vVULsbuvV+3Vnq zTYrQ%R(w5+Koi^B2sC;00CfF)6l{7{1G?Sb3^v=g4Q#H-H)jRi7cYgkNZ$na7&!*+ z88;v9)hQV6EguH=aUTszWin9VYtjt|e$I{beANtWWgMtv3$(gq0&o4o8SbC?8s6rj z0B@UY47S@-2?k7m1-6er4+i$V40af|2bB3{gB^RHGpF_G#=7M?1UmcdW&ytQ`|0p5 z7AxUh%9UW(w-dl_C#HeH*FwSWsS#k0W6?@Bzvui`@Q_VC;h~Xs@LqF0;9*_-!0^F! zDA~q(6B`8jw0R5m6@LLE>~H8J<=E)SNsc%-e3TZ&vP(m^(MqVgHI$s;gkAZgioGcf%~7I68IE}n7(JgsZK@U zG~exd{>lVrST57^K>`^2BSXm+n0ab4d{+4q`0Op=@Hr<&!{@G;2+m9G2F@Sb3tTY2 znF0q3yLp3((Ou11!MLV%;fuPs!52$Dz?U?s1z%EQ0WK3)>3Q`%xV-WTxFY)|7+;tJ zu3W1ISM4uRvihs1Y=kGQQ5-;EP1rmH5+^C)YyDNAGISca&TbBvA@B?Ez!Ly~^!JKX`;K91?;Gw1xJ>Qvud6MUPUaJNV*NBy@{*i;% z;OeVS;rZ)wnbVE+>>>n?&Akd9Uz-V@7<>>sIVAx+)s}##!zP28da>Xc|JCMffivF* zzzggq!3*xTffs%WgP$wt51udc0WWO#r(_%J`IZP=Tv87#&hS#Qf|o}AfR`+?fM4$P z0DeXO9)8vR8>p4t1h1KtgV&wadcHaZmU0{Qyp#^!d~w8_)xWiGvHt$QeK7@rvei)- zaA)sa_}v+czI?As!9wuG{7c}=O%Ki4xL1+;;Z<`B;I9ML!ru(u39oLF z1=h4(0lqaz1mD$**7HdW`2Jf@@WZ)2`j5hokH;$60-tvJA@RAOJN(Ns8~E4l?(lDu zrQr7^X5f!rR^ZQ()!;9WPvGwmQ*&BR;LOUH3%vUqIRE+>Tx6n!i*6}y<3RlC5NL4Z zC@8s<3>t3O3>xj52^!B_0M<%QQnJD({fEO%XUu?`wdx439nl|Nr@>Ir+|OUn-yOiZ zR`v8$R5Zka<UI?OzYtbegG6}K&3eAu2KF&rpy&0aVBeZe=4^q8Lu26m zwDaNplY-#`a)!YN&KnI5Qp&)=L%M-OVj6*w?V5o@!^Qai7lt{QATYd*vyv?^{M&2z z2zvoO;_g-W$S;-fQ3bESsIv3m=)_)T?S@b2JRLr9 z#7YGMlN$F!U~2-5fQ1M|4d{Nyz_@dG{_~LgP z;7d-XflIH?2A8GjpV;z4gW)R{i~!@40>G6+JA1cSy6)AjMRX6x{buVy7Ni%S# z${XC3WdiP=RhN-&tgn8Jz~25Jz|7cM=4^p|t!}}yBC6o~ZSvs<{I0+c{Jsh1Smo$h zp#~3rNCFR?-U#O2KcHmw^0v-{A3mvsA5jdY&NkN5rXi3&ZVq^KK?Ha#cnElWXe;o9 zTYK! z+5^0CTW-$kmu_rkLrKieEJXZ3!5Ukv|kp924V zFN(Q{`#P67-B>@~6#?N+Bm$xxqd@V|K+s@m7f`a%88nP)3K}gAP_hEXLB{Y}Bc0$T zjbFh{J8^I`GefX;!$*2ny#USmLQr8|atQ|(4|joev-X3Q#RcYU0jq?yaO=#SaGQx! z;kK(*!0q}ag7)L1!FnxYK!+YZK}YL8V13`QN>;D_M?ZK2%kIn@h#K6qLBRRFI|ej7 zB?TMZFjMkk)xlUH^Z&X%i!Iwp$$V?R7Fl=C#o!XHW~`3h$oq&@>1lj(RsW~FqbmFk z-N7iKsaooFuR1D||7Ne>x9|=Sj8xMK`SGeP!T-4>phCjq9KQ<*_1ANJqC~%$ zu#ujGfr{=+SgADSys0|Bg#S(dos+w@}{?<~?{-Sx+JMe_TWZ{mAC$`1#nJQq#?;^MZa5-C@yh&Zy$r7#OMY z+VU2-oT|_o-bj5fM9}E3sj9+HY^1IV6I%THN_yhl2e5NjFYPB><@pd*Mti}Qoql5j zeSGr(!Cmwxu6{aL7}Jn#q8corlMK~E=L;tVm9s)=>ak0Oun7G#|MxzUitZy#RY%+r2K?`vN%p*Yv>+VkRhRG6e-Vf+C;F^wsVc-m z6S}u#t;&8Nr0U<;bLrx>)R7g!HbGVEk)4* zkN(}HtR*&9Cq5JCTaxY58O);P4Akl0g;+u5@Jnc*IxtJz_)j$Im(W{`sJdJbUH;0XZCf?07a7 zzN?`Ve3y2qjK%lx9DGmC82Db@BY37V7`{(a2+vZ)G)G{6`Yr?xgqy;%R~C44^pWHB z27WMlC;X6oEe(t3c3%O{{Za)#+$~7*G;@4}N*mK=_sJC*fC@%*de=IIZ-q zjPcs2{_yK{Prz?<_J`kiw*`K)aXt9W>v8bg!VmcELnGm3RrcO&eeObJ%?BNZO!56qw;Ps{HfI< z_|t-CG8TXKVN?!VpL@RjA_6Z;yI{b}CHvs7@|wb{My-LrP7Cs;!?`z|r@*ThxWa2% ztk$sj+o4AAcczoz?*m@K-&cjfKRTAcKbH8wKm9o1&DQ5WXIUcfrCf;tUsr#Ge><0z z!}8xJ+=l3q1P zwyy#K$;lKAOBlYfh8v~Lg&SY~46n5y5^l2p4%~ETAlz)tad_?a&hR=jZ|88dj(L3n zZqffJyso5yjKwWmZH8Mu<>A&giUkN*pL>je&8OjT+nwj&cDFjh?U(I_*E>DTo1=vs zCKqTJ9k%v(lTRb-Zoz;6C9K z;6A^#8WvahdWRz5TX6`1mgZjYmZy{9t!gabt+&pE``_`%VH4XZ2EyAOtpjg2E>_0k z0V!|c?Sluv183iWcW`S1mkm4&?`Y(}oNitDs}Sh)>?Z~UHO%v-2|nmT1-vW20p2y| zyN1QPJ)8{>R^EqqKQkEKBjz-`XGQ=#Bs>Eiy2uIM%Xfn?;R80h!3SQi@MiM{&8Y<+eCP~($VgWW zi$^AHhY#&!1RpkS8GLxdml}5e^YT7p5g5UjV8BReclgMM2jEc-qjOlHs546V=0*4SbXfgX7F*V*21HYo5079p9-I_={0;}kG}9pOKW+vd6S#Bl(GAtpE9Znff&o) z8s<|wUx813?+c&aI0ruchBZ7^lmw4G^cg<$@eKH^q&x80CCVI*)|oTyIDBr_H2AzB zWil3@pAZ3G(C(N5frS%WA)s(bg~x^1!Q;L!gfDjg248$n4qs|*>&?+ZOAF^~7?*wc z3SYis7<@(PJ$U?58GL2lN%*R$M)1|iTj2>o3NZp}797vvXraW$PvL8arookFA{mRX zYp;N>t9k+_^+&)-$pv`w&(84mS$p9d?l*y}5>~@g&Uf@8Ek6Ool5mhn6C+FEJc}toBFX`)8rY;}6tNfoBgukH_ao(Btt3Tl;u( zbfJS!H)t4hZPDZLx#wrY^FDn<{_w8B@FTZw!_~_J;Q6QD=g@g{>uQV>0>`%AWC8wo z7#^|5V=LiTY`ep+_U5pl zmK!5uf?w02$K!99qsQZKXqqEmTC)rJo9Srr_*>d|eE;*e6>l)0?C4G`aA&v{ zes?2!JpNuVdOW^-PBilO-L7ajy5NIB=<)apqa3)djR*3&=jieHNA`8#kBVj>Un#if zuz8hx`oo_*GRwjJ|8(7S8B07nQ;h-7r}l%t$Uu+BzwC`3kAJl&7x^k5d*ok_*Lt&g zZ_K~Lt9ziwwJ_&0(ckN@5YJs$sKdc7QuF7&feoQ&~TAM|+i?*v9N7dYtymKV53L2#k2 z1}>a+g^Ru`?z062@xD$PMuU5&;gZ!ZaKqynaH9zlxbfyC@LE04;|V77M#D{;7b9;L zwJ3+9b!ykjg4YS6Js$Ns?=Q+2EnK?5EpDL26D$?trU+Q(uE7ASN@KV+nF6;dcm=ne z-WzVW-^iO4vhV8)ub1!=?ht?;PjH-A0hkWxO^mu}MtPQ+{ z%Y5WLhWUE4I-cTTaIZkLc!JmKxf&X$zY|*jGY0rvj${Er`tuIlcRzYO!SDWYc*`~D z@q|_<)8MTq2^jCc>u3&}*QS318Drb!o8j$R@$i5#3*haoAHxH?4u=PRJV%{vUAcBd zKz4IC26U=3%$uWyIvrjK?_7-@PYBwwQ^Vq2t~Nrx>%tZAZrNgZ@UUoj_r$009)alb zgr1X&;2};P$cGLWv;xnDqG!22Almk0(sgp~s{D(dNP4tk6`= zX$|AFx9IVN>FF8p8P}YUkBvi*C(Jy^!Dq=wBR_i+T0CKntQ&mpoL@MBdCe5)@r3z< zbOVw(bwhh#e1rdU-D?XH=DOK$w5mW}!fF6ZCk(rGAO<67hTFF9&8~!ON95 z;a8m!;8!odlW}wb?Jx9r!nOUS@aqrI;t4m_9D$dflH&VcxH$X>uC;X7@g8!&7MgEsF?eXZiUsuuMi8yXNa}k$~ z7LRUSy+DsA64oAK6GWnm=ptudhPHS~BQ%SHBZtAp#2 zx0a*F6WMG!Y>FGIbB4H zrw}#x=7<5#dlz9q!^i$PtWcw*Ei%T&1@+)A)6nCInr!<4ckMG0`KF7}k4=8dEc9(b==<>!9Cp3;)y)&u@;a0PN+!+26!Ep&;Td$ezgSdv*|fpdTBJ= zcP@H7k>9><@RozKkZ+YdDu>N$-8K>KKcfr0P2+ts7H=ET6y8pR7Ecu5XABQ`JVnMi z(E)*$uMh|<=#2>-ej0hRiL&j!s*l8?SjAC1%I~-{%#li-7fgMUGR6i;O}<9-|d3G+Xa8O3;u2w{M|12|8u)w@KMo1 zmGY6na8-Ike)|7}){^vS5M;|Ls4~4I~KOMe$&s;F! zWIu3Cd?c8d)>?sswc`Rod#{n; z4*O_ur)Q9!UweYPYrE=s#{=B+xs#5gkG)6hz%y^V!1rx)2eTAv2@duzHUkfAcn)Td zs0MRp7J~;nUIPyeet=_+frM{78d+@FOn|f$HCD!2IH5@My&p@L1+d zP;vZpZycOhH4r?xXOfPik5l8@!cWJC!8LvRgJ;J1fMUHR zFBsm|^ZEm@sOE#5qmPS+G|cI51!!-{=>d0X^L?-+Cm*~#?=*Ntxe2^FBm>mO%m=Tv zTLNAml%nJ48X#0`52?aCb*j@ZM1Y zEMIC2-rv?h&e6w%QLo??i+Q*%)Chby;xYKB#Y^yU$8%t%X$knG;ch*v4uH>U73etn zcvhm6v-P>>FLxsFB5RtQD)+K@g^uyn`b4lQGa7sy8w0*s)f24l*9WW_?*YDT=?A{+ z+e6OL$9roV_y^w>@DCrpz&}~mhJSisEobX-qjdhtFR5+WUUM|-QfV5O=$$yUh)&H6D9`DM^%6po=?HLozH-lwTnQj z7WZ`=t#9>4k%@qf>1hOPZl4Ejt1>`4^&Zf^WC>VLwF-2|8Vx$mnh4fkzgW)Ef=&Z^ z!5hRz!JS)s!yESN3UA~b3N~)(2D&IXFB~+nuBE5W0(AXQ1vWkX9&~$Pq~quU&9>fz zH$V9j?jHXZY>`$1dW^dPdM-EsdIcW_y@x76A2$^!?Ydvi(RvDBqd5rpxvoXP@A(jT zE6G%Nt825t)=&F_{s#wxZO*p@+pY@$+wHOi1ExBG?brJ1IJ!V!Zw}sJiZxu;))DO3 z>oX($tpNL92z2(mqvuy0*roPyJ@1?ayS_;SyB*yD2H!p==ja06H!g?wP^ZFsF5V7? zs1|~uBbR}_X34>@PGiCF0i7t>Zv`~!jzAyTFdat=_7&XW5zaDr#3M6!f36X{|D|T& z0G${dxX%O}bowbcc-3og$krk-a{N_rX#5j7N9zykaS%Ry+y&hKyxjK+5+j25f+H<+ zz)^0i^?aWMjy9U4=ZzWQn71o+94$CDw?BN`wF&TO;twBxFcdyvegrsiofkMMvK2Ua zs)df-|NN8yI|O3F--A;fzJb%)n#(zwpZ2{RKEwVUd`9J0F!pOHIJ58`IP1<4aQ2Rq z;GCl=;M}EK!Fe0!g7c#mfeRLI(BJc&_wWy@r6V{UhF)536Y zvm$kjoTCL(he;7gn;#6{5@-eA8rdA4-qZ)o2rvb=8Crtd9p32q^dq?AyB6Ge{x-O) zvP#F%`nz`>h3_f60^hs#CaB2Vk%NPMQ`BJA(j;(y*hcU`)C@4&YaW;r)E_)pXDE2c zW4fH93mmHM0M9e)2hY3O5PtY|Yxt4;Ku~?z9?Va1W~9Frko6sbW3vVDc*1?~#DGfh zWb9WRM;AEN`aJw}zk6_v^CR#~%ah<)t`ID+-m0f=7g+dl5qM4$51zj{3cQd$o|63s ztxm}KJ=QR=eL>Q<2t?dygLxAto8+;9BV7b{r|KqOvllJ&o((C@jTxL z{$kEA_{$Va_^VO%z^Yjv!PlLBfNuue2CExA0Bc$w1>Xu9@SXE5IY;Zid$bMyfy;+~ zxO7^9gO9pR;HP~V;AhQz@XP8Y;MeqF;I|2*!S8W0@JG*X;Lqqt9Y+`V<=zbbyL%w> z|I^-mhDDKf|GuxTZlZ#iz$}Ov5k$p=ia9G{&KNKU%-IGJF^izKVn9@ksEDCeRKOfi zF$WBQIb#l}?7F{5G5>S+zV>-}Ug&epEI#YLtE$_vVLkJk>XxNK&8V76_SyAw1*+CU z&aOA~7JQ+5@q}u!?={u*n#M;`PGA;x37hYIj4j6R!IsNT<2=2SsCmb3rCNFHrdoHL zPt8{%glbc5M0Wi(j#{8taH^!7zkvRJXBq{64x>@%v>&zby*5So z;rXb=d~K=41FQH*$_Yy}{feO{6waSR@RA={o)T(XjQeA8t zQC*!%h^qWonO_}gxD~47qcmir=i<0Vd>LxZ>%Xb)5jtwEeUGTMXFa3V2}`8b z?R$<|Z^naENjaZKgB`ej?|9sx)FRx_BT})rE5K|U3yn$yX4mHnsEvR5Qk$F|No{(+ z1-04M_SEL52l+_K1zH5V;+9d(aVx)e)Yd^2scpPmsBL{MsqI|zQ`wg zCmLQ=%~K`CUhi*WZ>v|>`-%~FdYgnhAG%KMa%nfU>#76PZo5LL-KQ9+Jr<9n_Ut~D z+H2BMA4xfX@7ld^pRQwll6rM4fonhdL>A2zBz-#?&d}T2ZG4m!(egcA`!n zqBrG>8E#h8nOY8C6eI(_C zYn_hcb**mT^?5enh)M@>#OGtwNQ+h3^+p7B?<*tCxo;0@i=}+A;&V#zMeiLf6cPZ+wlI5to-K6aL+l(5MKRvtNe@Wf@Gs{O( zE)aY4BHni|4eyV7K|OHfB=um>1*M9+0>Yzc9P*8(9-bCVJ<@CmHE!UhR7pAE(Q;Fu2Wgkhoz}Zn> zSva>SFFxO`AoaqCchrmSU#LlKlBt($Z&NQj#b(#9hpEYhE~iS$`I2v~!B;=W;A;nG z;_Ej;@r{Vpsd`D-cys>*8n^V*skfJRrQYe+hkAEHZR)*-4XG)8y7)-Sara9*;0N_< z;fLl8sEL)W=(&==tKw(Rk|9;4{=`Q7NgCa)IYVw&52+ z$M8$9Q`A?!5!BbNTc~fE1yJAG%%i?5H!!NeCbyUSC*PIab!TVhWA-XkCN$Ea7-pS3?wGrO6lO3DR(6}gUoyT8DHH1DZd zwimK%+Er1t(${FJMxVHkFXUTGsM^RCR9*Z|A4%D05-=H?Ml8l={d-_@{TOV~dJ@&L zUq@=5%H64X8&;=US=OammoA)LUzMQRm{&`cl=JIt&i|p2|3yI>1@;xA7CiffS}61v zweZ&4RNHY6sdmAKsYSdKs6~gYp%!!7NG(`eU!vivdF&%87jQkf2UklwjoqS?sMQmFUaS^I=73oc{GI-~8hvYT8l%;(pL|4UUq7UZJVozH0E zGf52g^^`X?@=DT9(ioC1X^R+2gzGE}ZPJyuc@m#ylD%B~vUZaEpXDRT$}I*79Zd6@ zRF@WKb6A+zA2xT^7N9{IlsC^eC`k1Y?|ukXbh?QbVvWQx2cP+rqTFQJ6bE=qp6Ug z&L3?{L;Eb{qdk-l4>E*I(ped9{n3s#w9e8x8pmX5ms;}PO@=*n%*+i1EOoUFUY5Gz zVfXL+{e%_zt1NYG=^M@R=zc37@uJ)-!COEX9j$exw1(&t+Jee`7s|~NfyVy%bs;*v z@?0eUoD`+`S}$QWMJYcEt0{`94-Wd9qRf3iBU$VZ&Ph?O^u=n5vd0svDaz6^SWQvJ z==3zy6s7$$tfnZnwO--^YKmg_6z8NUE54n@IVp*v!@Qxu;OSWQtp+hH|Dv3J30iX!F5QGZjEEibEji3@DaNm0(*U^PYA_7Uf%DD!U6 zP*aql2eF!>v|NSN6s6k!WN`sCMajPs=cFhHK1{)CigL9lR#TL{9ym8e3Gd-0PN=3R z)9PV0Md?`*t0_vIEUcy|MbmIjigN15NqqWmigG6XQL;Gy*_;&RL?X^jQ8sR(p{6La zgRq*S3>bpd6s64^FL6ROMR6L8)f6R9OPrIU+KF|*McEvI)f8n;09I3! zQR}_L1=SR#oxgByisC!~t0{_AQ=F5c=-!scCTfaut8ub8ftsQmEQ{3?Wu+-rQ zu$rQDxq#IarDil%QNQJgZ9h1C=#&jXy3qKtnXkJS|AVkA~ml%0WCO;Hy5 zVl_pXFxyLM}TIVs99bF8K) zYhPhCMVXO=)fA<-em4y@Mezv1YKl^BmzTJJnxdF2#W^WT*we9CO;JvF!fJ{VRTHZz zN{}7SO;JWyPZk$YQR#TLf zjCh*d6lKyZHmE5|S7tnonxeQjW?fBDN;BhWa#EDNSvLt0{^ZGoB_VMLF?&6zeB*Qk1hDu$rR8 zj7S#e&rMN6+R;!`6hCG>jhdo(G2>~}6vgEe`_&Yss0|m$Nl~tTXU0=gl%kYKo%qz-fO|l=QSx_;F5( zk|^Qa6lDi9UT%sqKg&y;P)$*WrC~KiX~m4EQB#ykQLL*eN`XW!kdvZ(_{fN-rYN7T z1+ku+qQo-eY19-Yv=tlF6lI(fR#TK-Exp78R8y3Cm9d(l6wfQHrYO?ScUbeeLaOM? z_mZ(zO;Jw1Nfrxgin8f4R#TL~7_6o!1DWw;HAQJMfps-SaqNoK6eaI?FL8dGzbQ)o zH;j1yNl}t&u|Z8yqM7kzHAPvN$-0`NjCg?66s7ZzWN`sCMX8a3)fA-=Bc7a-qS$|C z#FNz&rOb^04sgs#QI4(W0&0q~ju|gEMVUE(bu~rl!;B}ZDN6nFtg9(XNpq~GD5i{f zxhYDuXQs*G8K^1B=@(c{QKFdfWHm(zie_C+QAVHV0&0rVo*6GUMX9=&bu~q?9;5g_ zDT?PiW<0r3PKt85ItQpJijf&lR#OxMGhS|rGPz)~cmisQ(v=xcR#O!B+pMc8itS;3 z{;MfUhb(41HAU(8=nxM;O;O^*v6`YpFyqN;ilXn!x|*U4oyG;#6s2WvtfnXx8zhUL z|G6oOIWwM|lcM;%V8)aC=cFiSpKt;-McJ$2f@+Eq!i<-jqWGO=T}@HE81ZB^MRA?a z&wp7>QEWzVKu(G><_9yLoRgxAy*rEtpr$B?+h8?CS4@Qn@Z0)D*?C1kOoOmVRQ!lSBTdD9f%h{NZ zpo(lzQ$UB`FE3DM~aWo~))Qix~0b z+!STxI1W%#lrBrTfSRJzWX8))Q3`irJtsvu{-q|)Nl_AR+Tp~U6lMPptfnaI8S&)Y z6lLbOWbq8t6s6BytfnaSqFiRglhqVu_YU^w zrYHtxJXuXqCNtyZrYPMO@_^J7r4}=utfnY-9avXW6lnw(c=tC&d7sLNmz$y_xUim^ zqHM@dLrqci%y_bzqV&7Tx|*W2{OBcqOVt#mA~RlYiei3{^_&#t&x=(!D%S>V zzPnjCH$^#|Mng?eR-eRbiZV3{t0_v4V63JnjW;EW3#chdnINpDDDn`TlcJPLXTfDN1E#Jgu6dSjMuRlcG3(5+mM! zQWTf#%y_ve%Dzx#gQQhclrUyIt(u~Y@5;KGqI9Z_)fB~}ij4G~EKA>B9tpAdL-1{m1B?14EfPYEAza-#a67Vkx_?HCy zO9K8S0soSKe@VcSvjUe8lTH@?vSW4*J~ zx>ILEco|(KK54s|aw47aMj72ijlrRUuBc&A9W&)av)AP{$zBO9tD7&gB3rgJbac^` z5R1ma6?E=eZq_gn_e@wAcU9KuHF;Z!hvD6ZzZrIV=&EFY#&u(5i={EBiY`<(IJ)Rc z8kHL;0yJS>C-Sb`skJcNbJaN*l#hfj7*^+mqrqpV*2>VlnywNpt!1}Xh7Zkk6-<`! zNDo)jrOSrM8p&--SE=f_XO3vRu{3nO~tMG2;U;)})l26#!t3q6gc{p@Lk z=r7=9Ej|22BeY*M4y#xSFK@U6uP~SJ%8ENO#J-i!)A1_vMR?WOQ+V}@(KtLNP1&V< z*z`Fsyf)+{Ubju}Mq|BS6pe^^h42QiU>rHNnxFV$qw6rdsbfLB*`^JSa{Yp%ehl#! zjjcAf@z%So@V1P@c>7@|yyNc846$$LYAYPAKWwD2Ysz~XyH~Hqd%9o6F;l1Gy^Y=} zhe=Xwk3M*xLo(i9ry)L|iNy!Y^!5{9986n|56KPip~Ok}aJoG{vLn=AH1u&NWEw{o zOrUWr@(DgZyep0mID->f*T#v%(=(Lgq!X2k;ghXT;ZqjB@af81@aa!Q#Wv}zq{@5l%Vl4dI=j|U8;35r6(t7=JAs?$nFKW=#?6{m|?53P5H3tJ+`>Sjz+muXMeG={I_+uLP9=V@iyNn zmA94pfGa1g$q@UT^w)8f4KuNGzXQ0ce?RQf(12Zi8sTac_bZ1<8aGcztlSW>l12@C z6B;#MOu_CJW&FfO_j5gQt(Q7ndz%NYbM6_gyR5sv*jI1cIqWgEF0Mas2X4@@1a3HV z5%zTbgBx|+mZ2P{+z?@tN~1}&1)`y8l5qkz%Rdq~yZcCKOPb~%+T#|76LHI{uDI3e zO}O=uc79@Co2fy#ZMX|=*JB87KP^A*&^XXv?DOjJNijD>_|ovMbCV67B|K!`I6U-1Ivy6*84ut0 zCqwKTG2R`I3`@nMIu*gA$Dha$uRrC6h?+`~G=7~nvteurJ3OxXTs$uG2cA%HD4vj# zf+zk8@)O5RiaUlU-yedftck!=kG8_o=EV7nebd)E;TeP0;h8h6vj0@iYO1H9_pOv6 zHu{(Cj{}6MrX)bv>vwqpn_^mx`k{j7>VpNJIKmo#4&8I*?W8mQKHC@n*pv_d91-9z_GQjy##3&H z7>IulxX$_?CuTfNR-5-3%05}jBW65F);KZZ$(q*|Ses`b>&gug<&|~i!=_&|)i)Dz7g^n`g$%XI#!nSK`ux@wsAuck*78hO1j3*cKt*#s< z$;D?dDjDK|tg7aX2z4-w8+nT+aYnRw=4e% zw{NkIpZ{_P8)iJ&s{%g_l^Y^H_=^*HoAu`a?9sf4Ogwo;3Q^VaAjDefPlqi!kHK z{qK~*1HPZ*0S!#7>#sEAL3egw-^dbp@S#O`i2olvG;$jk9OlD_Cl3!`#FIyOo?v}s z|B-q&jI!TMV|1hTc#H)zp6ut~iv3JiuKTw%y@FxJbA^* z6L{t9pX@hm+Kg8XxR3R#1Lx8RZ}USrPWiCufkW|Hrxd)dNo%}54>O(|QH2>#j(8ox zdSqT^JUQ}W0N(h<$xobT)Bbh-qHa#I!coihc+1ZBcsCO>iFX*Yc0DI=bIayKKMeCjkKo^nG(HF14OJ`=Tp1I~^vsGLWV z&n-E|1^Tj%p08{`Y&5B06QyjE|0yCw~rc#$RG?`-ua;`sKslLJs5aJ)HbS|A*fi{IiY~&h(mz ze-(L;f7e-^A@=?LuFQB!%__=>CuiMZ#M4SY`iOPqhKNHe#0IT=w;>H}Br~2?cbFMZ zxglb?vaEdA^lB~ZX8k8&^V#-(qHoctJGLAk<2(*^ao$Exu$5(3f3eTnfe}x+A%YQ4 zYolSrQ{GnULNPYvPg}qN1-Adf1utyL5C;~T{}316F%R1gOTcyuhT|gM%y`Tkt>R}DK|tkW4(On0oE(@s(>p_zsdzG)nmrfR_?VAI~9A)dX;)Bu(QrwIlc03 zQpLrH#|;t8cv_dt9&B(unZ$-_PbT?^jc%Km@wC-XG2>}#1ctC)b2BrZ)_veOTx(7V z_SbI9jHj(L@DHwA#m`@yr(Tm(?2*?S*RP_CcrMC9{WmpeG|bD4r)`*Ii#^{YWQYSB z9jLApN!vJSV}`+}j&AAy_TC3qTkS-H-wcyJh7WagC3GUf5dY4%AexBJ3FH$kRroZe73UN&UyQ{FzRiE@OM zF{_a-Qe!YG$%0{TOS$ZSmvl{ayJVJ(sm*mYHUG^y%C}T<4#VD7${iU-CExg)e*9^r z3zW0F(;Dh5jr-c_YMTA`upgboVLsje=V4d7h{NcL!whq~>y)?3`Y0DN9PX}jHoWQn zH;>8gx%JT1&+div(3KYHiHZ29uf#AtbPX)MT6R)$pq5I!6Xq)3@#?Fb*Thm;HZe5n zsheR#3Z!o7)Y*8mr>;LjPAtW zZ9LWBvAU}!hWho*EIfn4W=)CtvpD0>oc&WycB$ug&85FzdWT9G88xT)Ym|S3s?}*F zY4SYfoYJfiNyp!nD=1$pzmz{$hSF1%i|?MS{6kdURx7WUcy{9FV1DrkhRyX|E2_AN zsNzDRii?RVE-0$FsHoz?qH=LrT-?O)d$O*ya#=rr!?MXr3RQE8uB5fzTDgLmxXS zXsmdi%EcCK&{(xm{(-e_V)#8*=PLdr>&16x@staThdpfWAfDF$_30`PQtZ!py5hkK ziw7*Kc>1D>2dF*DBrjnOeuc-E(VoWwnNnYjpEiGAiFc z%uRU+2LCELb7TA#U6{tueVeYFp=7Ksk72EarbzCxMN#ov7n$R`ELPusvyZ|6TSp>UPMv%f>24bS*uy zf4`dX`xW$6iC_)Ce=6Tkl{c+3X|6QQj2*t~Hp_+|KXs*z#WHnWfAXe!h6amG&5d)u zn51b8Bfgn98`3(Ox|wuP4zMv^{bu5%&HhKDEZG~%XPQ_W-7`%Vbk6>U+D_SJWxU$K z^t#3n)6vu=`+F@SYx<_N^5p3#VD4JxN&#=Uxe2@IkdUCMoKKVcEw-%T>{P&@lFBA_YZIP*y zA^N_lg`vV@ZSm~ix9rE$WU=yi4E;h(U9;CiDx2yI)vlOk{}VHw4>9$tlf7U3p|>`+ zzF@jeV|aVf)F~`7t=xZCypl{KWmYtjp?p)*TE^a2Oh*(G@wvgKhM9%ivQL*jr&mu% zNZ)zbQ~CZRNmUjpr<5wYif@gzJvGYr0`ax@&fTn$_^XrQ!v|Amaj=!AI9UAQ6epnm ze?CcPgbE&FseLnBEQ`CgoRSwqJ>I`<;~hsDlebvM*D z#=bVaFWY`fE}|S>d1%fv$bQs0hyQOEvkzbV&a{b}p-xk?zi)Q<-rmekYbbI``L6+Z zv%^`&@@38D{mu4gEs7Br2yp)BDeCOLqj8|s4LqmCLRZnB^Y$Q~TVWKQd+S<)=+86j zfae|DkLN$Hh8L_{i5H$Nh!;(of){W3f|qpdsi(0tB!7&g{0edRz{|#b!l9*mc#3{l zhnqMos~%qAV#F&RmBfa8tFhsD7GCv!I$pg#4Ts-Z zP8j$y_zzH$R0aCKtJx@`u4(y7r6*!8oH>r)Ue_W4mIu^q> zuleKK@-KWlb^yNfrl>3b-}-K7QyTX!W-1LO+n?@}AnN^{5AcItjq$^U@%T}_vN&}_ zBu*=CiqqQ!;`E;{@RJ%5F_QA@$-N8sS)l;@?BsJ#(SQDVV2t?x_R@<@=V`pW(TokR z0(auq`zzo#0~h1B>zcYM+og9+#^Coe%j1kH3ll{DLmzYeG4Ck+$>SCN^ri#;QX&a| zNvejw{@U#-t}lIyE=c41{SY?%Soj71JRKb))-y-k#=oML;NP7;dy4*_AU~W{|J4OzHS<}xbzKM&g_lz z?7EBd_Gy5v7RO=h`t~^Aq}wr)avqzKGS1)iFfL$P+Eerky05_npJ{MmTm4KLg-<`G zVf(cowu?HAi`;62iw14Q#p3(AO3I0fk3N|oYKaI>T(W%>E~PJnOIHoX_Wg9&!Fm`j z)8H8{^R5jptFI`>NXm)IUUsHY-s}l3Z*1);`W2p^!4(ZvaHX@`aOKI?*lFtmT%~IU zb`BnitGZvqE`IY}CFMM>w)=54uMxOfR&s*q>#MuAqfz})ERC8rF1Tj=a_pXwAJ>YQ zglpe*ju8je(Rasn59h=6hEDVpeUDWiaQ&9uaDyq=al?vruxIxJxRH5rVI|wIZJ^Qk z`ENEfb=dE!ENGgZeT189R^sL{nF*rbB5ew88S((PO6-YS`^Donksi3MS0rv1Pztwq z4a6OW*Nu^s^LQ2A;3;1JnvShY(CGMMw$f1E?6A@w-0AKh+{GdlcRAb~cYS#RcUxT% zcfapTnyJ@%q>Jcn_h`Uz5a!0dB4E zfVACsP;uWFaiT$qA=o#w1s=R(m#63tNvVW~E?A0(#pS`nhmXZ0!r$VNtvlgSb1YrO zaic5O^c1gu&6t62X!sTEm>@j1$z?qDQ*}JvF$RynUKmf*hT@5_-|(cz6Y%8FyLd`c zNQ|VMXX>~(JS}=0p5E(@r|8dE)EUpLcSKKP)<}06`r>P`f7>G1KXVqI?er7RPVvEW z3fs9#%8BNjnvo!C(B~g`?&iKY_(lqzH^&pt-+v4*7*qx?TpocJHP!2AES?z`BPl0Z z;`j_N?XwPtSZO^)e_4G!UiRiG4lCIohb5iG%YQe)E26jKl@H2c!=iZr5#BcQBi_DyG}iCvbA!gtC0;b5>mS6sCNtw{c9&d*_jF^% z)5MrE<7xKRs^%&w7ux%5WrC>t?3nR1`_4?k`@eo+{lJ!<_~5PE*f`e%ABz7Jqa3GX z`-4l-I1+JFG&FG?nDI16^~`vhV=g53TAAI8SNqowj z8BcR+cN9MTf)P)1#*mmGDd#(Tu7NAB|8tW!(Kx@28BcSeTM)iDPgXWanxtAo@TDP7 z@MXJJ_)15K3noj0J;lDOuIcz{Dl?wux(zd)=6XV9)^B8NVg2R?Mm)`} zW5b=pQC#3|zhr!GH8Y+jr6n_-=Kj=StUsuDIYCk`_^<~vp5~Ex3{I`%%zEkzW;{)L z(R?`l+yvI2$WAfhxF_4X;-~3WF}(htEgSDC7M>@*XTyuJUGU3DW<1TSj?8$P*8%%j ze^ad}>u-lAyNcu9*<|APt(oyO?|<4Qi2jGl%US<$_XqxD$%v=HyNti5sDHef@ibZT0AX2j zdnndrDZMF{3nXCqM0u>u)ISgxlyy5BCx~j25|2$6mc?dqk=T5MDYjS>h%H+)oZ z`{KNnFR*SkC?G~s&SPyEjq^2CW<16DKArazHGkP=IRAA?!)?Zu;T!bC~hu3I~|+*Z=Czp+QNR;>qp)CwH{lhC80M_7r{Z zZ_Iddr!5({^X-wWcbR()cTJe@D)x07ydQVpFar1Jkend;J^kC^UM`Gya&I3O+$Z1i z1o8Tp`+73t$$j5X;sBr0pV;7Yg&9vCV399I>>IGBF6#qdFyqOCRx#trzUQv9K6nZ< zo;+k5GoC!OdvQ;3+^~5D)`!>njYkZfibvW#;^)6Ssv|R=JnCB_8^%;)#*@dSGULf( z^Y?TWCmNd&pCIbE56pP-_zjVG!qrl&PxNQTlPB$!@MIrf)~AFs;>lAzTi|I^|L_2& zSJE@%$uoMS(wJ${+*496FslwTo;>SiMeJX6Gwc56nepU+A9L~SZEsi)OyA@xj++x| zo*-(_i6A_8>?<6+kr7Xx*D(ptpUsG;Wc$^a@#KXAoH$@n{tz}SZqtGbEdDSKFLkPf zm)>K>lb7YmgO?p)#*;%|G2_W$;hj7s#`S8?DPM`k>EZKqJYPX3l4`s=Gt!0XfR;td76;teO_aOAIXF=F4wjqC8H`*B6;PVrsIl+Z;%y{y}E=zEd?i1^m8tmYL zm!90jS4u6yS1x_@l#~l3|6#_HukN~muRUbMldms6h;JNsEEDdERgjM=~CPxK`{CFKH7_pFW)^;zF6{Cw$j{Gve`emSNOepTuue%+xVe*Gs3 zzpc%TC%=83m>?C;xD5=_&d@eNM5SX~T>s|MJ{|e`Vxl{g1se<0n)78Bc4ny^X8rn|6;$5Y=qHGd8asiYWNvC~%b-Pg^jcC@!>j z1?z=;jymbM0TDJST8b-8BbfZ(vJkuFV=Gs>%}cnaEZFzafz45aH(R9c-m6u z8S#{C|7Qs{*l!PDgTv$6G2%pJLf3nW>UgpkE<27HPg`!|FI?Vx0P7WIGvjG1x;4d> z1|+avxj=dB)aHS!q@2g;qd9hVV#L!rr-%_x$@X3HM6$sp&QxhgTG!WsxLWuN>~_%? zSD(g=r>(KG1+LjMnsxW(17pN-wdyXxwI?*gbsTqkihkYB6>vQ*Bc9fyh6VO`JjPRU zP&PCu_?kw8lN~vr;cs(SaiHg>>Yf^1*s@in43{gK`587iXvP~t(oOpPAHNDq-fd!N zP|2*Vp`%t)cBPeUZoE;+%wB6~RmH5JNVbgyoy~@7!s?$WC2QS`YpR-k*XWf?N&Y4e zd_)cKua`=F8t)@&pijwE>gh-yQG*(0rBb5;eMAi|ot8=s^7RpQUe?J}QRn-%@DX*v zqo`C-7q%ZrU3Bh*kMQEE&G3?KoAor7T34VEGH)&pd1rw`hYrP|mtN!LEnDN|Msw=Q zYJ=&oT=@#G%HI;Nnv{fBf2fSZyY9wouI9yS-9zxY82vjM>utx;hzLo>5m`&9kyGE& zk9_2ZH}$xJH^qD7s5*ObR74HDwP+aLs<*}4eoVyM`+mne(w9+pwk%9PT7P0Zja?PK z(b&DQ3*KXP7st%5g=3z_;n)F1aqQW3cz>fzyg%kJ^`KJ``UgYS;6s)_@gcvN`0%Uy z_=s0OtdF~JoW@btMl_D?*np4QIO6yPvvK?nPio@$_4E_(mcb`G`Qwv^b@+7k0r>Q) zXZUQvrugiXbNJk+^7wrJC!#6|!2KpZ$`{hbMrTq*O*&f6N7PFW+fqfnyw=P|)GL|= zsiG!Nf9XR_8<{HVwO$u}sEO@UMZHmPmk)Kv2-=m;IW-2~uk;B&*xV66w77{MEgqd+KYpN}Hp&a9UAvASw{ydfV-Mh`&V}&P zPy>FR_bYxrZfdHyzVzbF9U3ott)#xX`8ic-ORwuq!EX-S!f%WB#P3!d!tXLYaK^-N zoRLxrf9x^?e~gpx=bC--=glRkUrSA=|26PWs<^)N?N1*X-v_3q3jcW65dUm)0%sm~ zz`qXoj&YJlYXT8}Zszx(JlS)kr!rJDKu{L@LHYtA^n=ER@>tADLx|N36 zNGCR!Kbwy&+FD`DGb3=Gnw6+|_spYjRX7i}UOF6Ge}0Q?#2c1*zUVEF489y7rmWyS03T^=`Wd(x_1}kwy*WzZ;R1e}?Y)AJTW9 z+#lEakbrA%y9i>gK_<@FLA@MEpfwCQ);80gG67iX%zp0 zMw7bDMMKjh;sS0~tRilvkH*b^TH+S{mf)6m-{4j)cTiiOw4mRn;v(F3<7?c`d^B!9 z`x0*d!V7y1*rQlU0KCq*(eQ4(j1At~3gOOW#^cV*s!_Y#?}I*B9L5 zVkg|w^)~LcvnK9sa~StoXove`tik;z)bJ6ne@(x;Mi%;awq>FJ;njFx_3wD#>gm|G z;63a+wGSTr=_nr3qahx8eLWu5xHon9(IfOnlxcuRu3d{q$@X~kj9I+?HKWsI8h*Wf z*x;A=1dsD*jK@Wu!4pc9#S<2!Qzw};qCaW)DLnb9Bc9TF3!Zw~1W&6x4^Q9x9M7;E zj%Us}pZ)ru`6-wM{ivrb=&ujM0qxG>fPHOnp!0Sd80L(FtQO*+@%ixFx1(^d_Xj-h zQU^TW!-~4#;7Ixli@(Qzw8ESN!>iR}Pwl4G(YNRZY9&)yEIw@UnIB8vXiJG}h`$&{#KX8eaFdHZ@|1fqulL zVmPwJR2&)o3va5>3vXKV5J#ES$5A5_@RsML@z%B*@wT%XyuD^TRlg&qBnvwWN79I1 znuVjk1mfLe((vw^zBs1CNgQ*a1&(!z!m%qV;r;o7@%~xOs0Y4prhl++1#G-C7awY1 zA*>_-hlbKPQu4KEXyR72#&N$d;bT*(;A0Q=;P~#=IQ~o$HL+1;`iWb1&3^sgzE+FIomz2hxEos(-?LkX zQ1Agk`nEm>H zc5gO~=bk2PcyVM9ep#su_0=YS`mZf?_)Xvd{N}|o{BB@V{O;U2oYAB_&e*mCe{?j* zALlK?pXFEh^Vn^AzWDOSjD@cq7vOIfU*hl8M&chkFXEs1+vCiIyKv?QSNwa#QvCZ~ zJ8D+vo%FMgxCqOd8jFQxO?ZB+Ei?ver|Lh^(0%Sm!=%SeY3yl#p=v{{cL+N{ z!_nG-hU56nxa>PEF4t);E`RAMu26j_uDI(gu2dq3T6yJT`jvkT!Br-m##QdO!d1I& z#Z`|wVORJ0!pgsaS!+eZ&31%n$ZkQEsMWLP(XZi~2iJTw9J@Dti)+QV#kI>`!F3|4 z;<~!MxSrky*LxC%>-YVL>tBkYHf(9F^u^tMyFzI+s*s^HB)QSz3Al;bHQZ!WSKRdZ ze%!2GZQT6qO5DP^7;YJ}kJ`%Coqp?(6}a`+BDk&JWZd@VPu$+C2d{s*{ek;5yj<(C z!E42F>}^vLd(TRtcKT6=e&@c&aF@Hqan}YBxZ9!MxO=Gp++)=v+~dzc+-piA?)9)4 z?$dn}uYbAE+5Rl_Ym~r3zpYJhe}|2@e{eZGP%{S)9AbtCr47cu&0pfdi7oLES5xZH z9fRl(%l85gU(g&6e}4gw9A1&vzdZ6vG>y@%E!i-7&l2oc=?(T<>W9Z!T*l+Zc;oRe zWAKFTqp1_GU7|m!wilipy9ZAx;)bV&F2hs57sAuW>BrNUe)}tpnciLS%*29JeZ8^t z^&7t6fa0BSfd6egJF_MZ^f`>@q}bsg&oy}NksmnNekPt5o`UCFtfnr|2YzQ^!OQ71 z77e_I7oG2emozzwmuzo{Lmb!RkogWcRO^pJhiP%xo3+&C-uCoYB+bGr-DGTt_Q9+2 zKf(IdiyG5d{oxFaH6zR7HCMOcb!|=Yx+ABk5j7p@M}%*|k%dig`Bzn8tQ(8|sdk+r@&sf#gcR^gMKOW;$Nr{UAp|75@Z&+P6^ z<7~lHHk>m|&91+G(Z4Xc7rt=+Ax`R6A1576z?W;4#+TP_#L0FVoIGO=zWVhszUCWA zz5XbR{*7jVK6**{t-cwbM&njFUpCy1IEn9=w7_@uQTXoDN;suoFitt02R~>y3_sXi zf%>T8T>6ieSl~4Cp*U^SYn=X~HGbUglAgwsb5&?Ob>4%YZL`MDZIh@kmQ|+z;_Ghw zYHVKo>Q)GTM z{#x1=e_K5ffBW+t|Crhh|9E&0XZEOrGmjs|zZ-YSu3PWY&ni<3X9dRzYc+CFVI=_= zvW|wFmPtd~LXUNc53osv{@64!9-Gh|1Lzm3{R|i0*A&|pIfw1S%456lJ8;qQ=D6sc zMYy>4D_lHr8?~f|8U2!x3vlV;FNKu^AYdd7`^<}?p>^or9+yekg&iBY;<9l|aXE(q zxcr*2xPqk%wc?z`^eeu~k1G!vgDao^gsU{|h^uVBiK~{au2|gNH{VFZRack|uESR2 zYH!`BZr%szSHDyU*Kjl7n$cgedx5FA)}lMO*2iAB&d4LU&b9iuUfZ>}UR+OV{hEhT zr4Gt7uD`~EM#IA4Y-~8a6!!cw12^g=;l?-n;wE*|anl2yxLL7NxcQ1QsfLa%G)99@ z3(dCw`L{rWcU7};-05f7;Av)OY+TLE#6;Y3 Date: Mon, 10 Nov 2014 16:59:57 -0800 Subject: [PATCH 104/114] bionic: libc: Added path to vendor build properties file. Signed-off-by: Daniel Rosenberg (cherry picked from commit 71d220c1de1372e20c8bbec4ccf387991a3bb549) Bug: 18281574 Change-Id: I2843f23ecb4c4ca79b230d8041bbca02dbedeadc --- libc/include/sys/_system_properties.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libc/include/sys/_system_properties.h b/libc/include/sys/_system_properties.h index 5a681df72..0349e4c3d 100644 --- a/libc/include/sys/_system_properties.h +++ b/libc/include/sys/_system_properties.h @@ -81,6 +81,7 @@ struct prop_msg #define PROP_PATH_RAMDISK_DEFAULT "/default.prop" #define PROP_PATH_SYSTEM_BUILD "/system/build.prop" #define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop" +#define PROP_PATH_VENDOR_BUILD "/vendor/build.prop" #define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop" #define PROP_PATH_FACTORY "/factory/factory.prop" From 047d943ee90c7582c08bafe6c2a6de132f12502f Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 14 Nov 2014 15:14:44 -0800 Subject: [PATCH 105/114] sysconf(3) returns long. On LP32, this makes no difference. Not an ABI change. On LP64, results are going to be in %rax or x0 whether they're 32- or 64-bit, and the only difference is going to be whether the top bits are clobbered. (cherry picked from commit 60d84af1726225320b26683b726e5e735d9d76e8) Bug: 18390956 Change-Id: I722461498bc5494e2972fb07d5189dffe76e8993 --- libc/bionic/sysconf.cpp | 2 +- libc/include/sys/sysconf.h | 2 +- libc/include/unistd.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp index 8309f087a..7734e40bd 100644 --- a/libc/bionic/sysconf.cpp +++ b/libc/bionic/sysconf.cpp @@ -150,7 +150,7 @@ static int __sysconf_monotonic_clock() { return (rc == -1) ? -1 : _POSIX_VERSION; } -int sysconf(int name) { +long sysconf(int name) { switch (name) { #ifdef _POSIX_ARG_MAX case _SC_ARG_MAX: return _POSIX_ARG_MAX; diff --git a/libc/include/sys/sysconf.h b/libc/include/sys/sysconf.h index 0a46e7aab..3d058d748 100644 --- a/libc/include/sys/sysconf.h +++ b/libc/include/sys/sysconf.h @@ -129,7 +129,7 @@ __BEGIN_DECLS #define _SC_AVPHYS_PAGES 0x0063 #define _SC_MONOTONIC_CLOCK 0x0064 -extern int sysconf(int name); +long sysconf(int); __END_DECLS diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 9b9adcead..1bfdb0e4c 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -177,7 +177,7 @@ extern int acct(const char* filepath); int getpagesize(void); -extern int sysconf(int name); +long sysconf(int); extern int daemon(int, int); From 432f645887466ed7099addb20fa8915c8a29fcab Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 19 Nov 2014 15:16:51 -0800 Subject: [PATCH 106/114] Fix flockfile(3) and friends for stdin/stdout/stderr too. stdin/stdout/stderr are special; their mutexes are initialized by __sinit. There's no unit test for this, because __sinit has already been called by the time the first unit test runs, but you could reproduce this failure with a trivial main() that calls flockfile or ftrylockfile on one of the standard streams before otherwise using stdio. Bug: 18208568 (cherry picked from commit c48c3e4bb3d1665f3e9fa2785daafa72dfe59399) Change-Id: Ia0c43ed4ac69daea8152aee9516415a6e3f8a042 --- libc/bionic/flockfile.cpp | 12 ++++++++++++ libc/stdio/fileext.h | 4 ++++ libc/stdio/glue.h | 6 ++++++ libc/stdio/local.h | 4 ++++ libc/stdio/wcio.h | 6 ++++++ 5 files changed, 32 insertions(+) diff --git a/libc/bionic/flockfile.cpp b/libc/bionic/flockfile.cpp index 3381e8eb9..b73907cbc 100644 --- a/libc/bionic/flockfile.cpp +++ b/libc/bionic/flockfile.cpp @@ -36,12 +36,20 @@ // struct __sfileext (see fileext.h). void flockfile(FILE* fp) { + if (!__sdidinit) { + __sinit(); + } + if (fp != NULL) { pthread_mutex_lock(&_FLOCK(fp)); } } int ftrylockfile(FILE* fp) { + if (!__sdidinit) { + __sinit(); + } + // The specification for ftrylockfile() says it returns 0 on success, // or non-zero on error. So return an errno code directly on error. if (fp == NULL) { @@ -52,6 +60,10 @@ int ftrylockfile(FILE* fp) { } void funlockfile(FILE* fp) { + if (!__sdidinit) { + __sinit(); + } + if (fp != NULL) { pthread_mutex_unlock(&_FLOCK(fp)); } diff --git a/libc/stdio/fileext.h b/libc/stdio/fileext.h index 1f2a3a31e..c074b4b6d 100644 --- a/libc/stdio/fileext.h +++ b/libc/stdio/fileext.h @@ -34,6 +34,8 @@ #include +__BEGIN_DECLS + /* * file extension */ @@ -63,4 +65,6 @@ do { \ _FILEEXT_INIT(f); \ } while (0) +__END_DECLS + #endif /* _FILEEXT_H_ */ diff --git a/libc/stdio/glue.h b/libc/stdio/glue.h index 4ead20a81..a9e5d1030 100644 --- a/libc/stdio/glue.h +++ b/libc/stdio/glue.h @@ -32,6 +32,10 @@ * SUCH DAMAGE. */ +#include + +__BEGIN_DECLS + /* * The first few FILEs are statically allocated; others are dynamically * allocated and linked in via this glue structure. @@ -44,3 +48,5 @@ struct glue { /* This was referenced by a couple of different pieces of middleware and the Crystax NDK. */ __LIBC64_HIDDEN__ extern struct glue __sglue; + +__END_DECLS diff --git a/libc/stdio/local.h b/libc/stdio/local.h index 13188ee1b..46b11f13a 100644 --- a/libc/stdio/local.h +++ b/libc/stdio/local.h @@ -41,6 +41,8 @@ #include "wcio.h" #include "fileext.h" +__BEGIN_DECLS + /* * Android <= KitKat had getc/putc macros in that referred * to __srget/__swbuf, so those symbols need to be public for LP32 @@ -137,3 +139,5 @@ extern int __sfvwrite(FILE *, struct __suio *); wint_t __fputwc_unlock(wchar_t wc, FILE *fp); #pragma GCC visibility pop + +__END_DECLS diff --git a/libc/stdio/wcio.h b/libc/stdio/wcio.h index 584a3f209..2c1fa3c17 100644 --- a/libc/stdio/wcio.h +++ b/libc/stdio/wcio.h @@ -32,6 +32,10 @@ #ifndef _WCIO_H_ #define _WCIO_H_ +#include + +__BEGIN_DECLS + /* minimal requirement of SUSv2 */ #define WCIO_UNGETWC_BUFSIZE 1 @@ -78,4 +82,6 @@ do {\ #define WCIO_INIT(fp) \ memset(&(_EXT(fp)->_wcio), 0, sizeof(struct wchar_io_data)) +__END_DECLS + #endif /*_WCIO_H_*/ From e5477f83b0a639b86d8cbe710f25d9808a8f72af Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 28 Nov 2014 20:03:23 +0900 Subject: [PATCH 107/114] Fail queries fast if no DNS servers are configured. When no DNS servers are configured (and thus there is no chance that the DNS query will suceed), res_nsend returns early, but it does not tell the cache that the query has failed. Therefore, if the caller retries the query, it will block for PENDING_REQUEST_TIMEOUT (= 20 seconds) waiting for the "existing query" (which isn't actually doing anything) to complete. Bug: 18240188 Bug: 18327075 Change-Id: I0df13ff4a17ee65e640be96695a3af31b020963a --- libc/dns/resolv/res_send.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libc/dns/resolv/res_send.c b/libc/dns/resolv/res_send.c index 6439e31ce..a8da3ac75 100644 --- a/libc/dns/resolv/res_send.c +++ b/libc/dns/resolv/res_send.c @@ -402,6 +402,10 @@ res_nsend(res_state statp, } if (statp->nscount == 0) { + // We have no nameservers configured, so there's no point trying. + // Tell the cache the query failed, or any retries and anyone else asking the same + // question will block for PENDING_REQUEST_TIMEOUT seconds instead of failing fast. + _resolv_cache_query_failed(statp->netid, buf, buflen); errno = ESRCH; return (-1); } From 111461aaaec2b7d9ffa5f3baabb1bd019d2e0c1d Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 1 Dec 2014 21:27:59 -0800 Subject: [PATCH 108/114] Put stdin/stdout/stderr symbols in place. To help with future binary compatibility. Bug: 18553223 Change-Id: Ia8103b4f189c18528b11948ac9e520f61b9ccc0e --- libc/stdio/findfp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libc/stdio/findfp.c b/libc/stdio/findfp.c index 0c2ee7cee..cfbb66bb8 100644 --- a/libc/stdio/findfp.c +++ b/libc/stdio/findfp.c @@ -44,6 +44,10 @@ #define ALIGNBYTES (sizeof(uintptr_t) - 1) #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) +#undef stdin +#undef stdout +#undef stderr + int __sdidinit; #define NDYNAMIC 10 /* add ten more whenever necessary */ @@ -65,6 +69,9 @@ FILE __sF[3] = { std(__SWR, STDOUT_FILENO), /* stdout */ std(__SWR|__SNBF, STDERR_FILENO) /* stderr */ }; +FILE* stdin = &__sF[0]; +FILE* stdout = &__sF[1]; +FILE* stderr = &__sF[2]; struct glue __sglue = { &uglue, 3, __sF }; static struct glue * From 6c1e3f6e56364141dc0afd467e3dd414bee99412 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 2 Dec 2014 14:50:20 -0800 Subject: [PATCH 109/114] Remove unnecessary #undefs from AOSP. This is a manual revert of 111461aaaec2b7d9ffa5f3baabb1bd019d2e0c1d. git revert does the wrong thing because that patch shares lines (that we want to keep) with 168667c972a1e9ede5b64ad6cee0666e9b96d4d8 and git revert just removes them. Change-Id: I83ac8c95e5c90a4137b7742a9b7536e1627f1ac7 --- libc/stdio/findfp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libc/stdio/findfp.c b/libc/stdio/findfp.c index 7a537c8fe..5e51198a7 100644 --- a/libc/stdio/findfp.c +++ b/libc/stdio/findfp.c @@ -44,10 +44,6 @@ #define ALIGNBYTES (sizeof(uintptr_t) - 1) #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) -#undef stdin -#undef stdout -#undef stderr - int __sdidinit; #define NDYNAMIC 10 /* add ten more whenever necessary */ From 27d276f3a6d81d29fab13de96496efb7bc072773 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 1 Dec 2014 16:13:30 -0800 Subject: [PATCH 110/114] Avoid pathological behavior in OpenBSD's fread. (cherry picked from commit 20841a137beac5caa824e3586c7bd91d879ff92e) Bug: https://code.google.com/p/android/issues/detail?id=81155 Bug: 18556607 Change-Id: Ibdfebc20dce4c34ad565014523c9b074e90ea665 --- libc/Android.mk | 2 +- .../lib/libc => }/stdio/fread.c | 18 ++++++++++- tests/stdio_test.cpp | 31 +++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) rename libc/{upstream-openbsd/lib/libc => }/stdio/fread.c (85%) diff --git a/libc/Android.mk b/libc/Android.mk index 045556ea9..30050922b 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -61,6 +61,7 @@ libc_common_src_files := \ bionic/sigsetmask.c \ bionic/system_properties_compat.c \ stdio/findfp.c \ + stdio/fread.c \ stdio/snprintf.c\ stdio/sprintf.c \ @@ -396,7 +397,6 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/stdio/fputs.c \ upstream-openbsd/lib/libc/stdio/fputwc.c \ upstream-openbsd/lib/libc/stdio/fputws.c \ - upstream-openbsd/lib/libc/stdio/fread.c \ upstream-openbsd/lib/libc/stdio/freopen.c \ upstream-openbsd/lib/libc/stdio/fscanf.c \ upstream-openbsd/lib/libc/stdio/fseek.c \ diff --git a/libc/upstream-openbsd/lib/libc/stdio/fread.c b/libc/stdio/fread.c similarity index 85% rename from libc/upstream-openbsd/lib/libc/stdio/fread.c rename to libc/stdio/fread.c index 8a592f6d3..e052128cc 100644 --- a/libc/upstream-openbsd/lib/libc/stdio/fread.c +++ b/libc/stdio/fread.c @@ -68,7 +68,23 @@ fread(void *buf, size_t size, size_t count, FILE *fp) fp->_r = 0; total = resid; p = buf; - while (resid > (r = fp->_r)) { + + // BEGIN android-added + // Avoid pathological behavior on unbuffered files. OpenBSD + // will loop reading one byte then memcpying one byte! + if ((fp->_flags & __SNBF) != 0) { + // We know if we're unbuffered that our buffer is empty, so + // we can just read directly. + while (resid > 0 && (r = (*fp->_read)(fp->_cookie, p, resid)) > 0) { + p += r; + resid -= r; + } + FUNLOCKFILE(fp); + return ((total - resid) / size); + } + // END android-added + + while (resid > (size_t)(r = fp->_r)) { (void)memcpy((void *)p, (void *)fp->_p, (size_t)r); fp->_p += r; /* fp->_r = 0 ... done in __srefill */ diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index 6a2991f57..bba744a4b 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -694,3 +694,34 @@ TEST(stdio, fpos_t_and_seek) { fclose(fp); } + +// https://code.google.com/p/android/issues/detail?id=81155 +// http://b/18556607 +TEST(stdio, fread_unbuffered_pathological_performance) { + FILE* fp = fopen("/dev/zero", "r"); + ASSERT_TRUE(fp != NULL); + + // Make this stream unbuffered. + setvbuf(fp, 0, _IONBF, 0); + + char buf[65*1024]; + memset(buf, 0xff, sizeof(buf)); + + time_t t0 = time(NULL); + for (size_t i = 0; i < 1024; ++i) { + fread(buf, 64*1024, 1, fp); + } + time_t t1 = time(NULL); + + fclose(fp); + + // 1024 64KiB reads should have been very quick. + ASSERT_LE(t1 - t0, 1); + + for (size_t i = 0; i < 64*1024; ++i) { + ASSERT_EQ('\0', buf[i]); + } + for (size_t i = 64*1024; i < 65*1024; ++i) { + ASSERT_EQ('\xff', buf[i]); + } +} From c7450f7738b0d1edf832fc881ef63546d45428cb Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 4 Dec 2014 12:39:46 -0800 Subject: [PATCH 111/114] Restore symbols from . Bug: 18627252 Bug: https://code.google.com/p/android/issues/detail?id=81690 (cherry picked from commit 42804c4b30e813d3140cba877d3ae6bbef0d3a17) Change-Id: Idd33578b31bba9a4afdfd15c7b193d10974aea90 --- libc/include/arpa/nameser.h | 119 ++++++++++++++---------------------- 1 file changed, 45 insertions(+), 74 deletions(-) diff --git a/libc/include/arpa/nameser.h b/libc/include/arpa/nameser.h index a87ac913a..91561ce35 100644 --- a/libc/include/arpa/nameser.h +++ b/libc/include/arpa/nameser.h @@ -518,9 +518,8 @@ typedef enum __ns_cert_types { (cp) += NS_INT32SZ; \ } while (/*CONSTCOND*/0) -/* - * ANSI C identifier hiding for bind's lib/nameser. - */ +#if !defined(__LP64__) +/* Annoyingly, LP32 shipped with __ names. */ #define ns_msg_getflag __ns_msg_getflag #define ns_get16 __ns_get16 #define ns_get32 __ns_get32 @@ -564,101 +563,73 @@ typedef enum __ns_cert_types { #define ns_subdomain __ns_subdomain #define ns_makecanon __ns_makecanon #define ns_samename __ns_samename -#define ns_newmsg_init __ns_newmsg_init -#define ns_newmsg_copy __ns_newmsg_copy -#define ns_newmsg_id __ns_newmsg_id -#define ns_newmsg_flag __ns_newmsg_flag -#define ns_newmsg_q __ns_newmsg_q -#define ns_newmsg_rr __ns_newmsg_rr -#define ns_newmsg_done __ns_newmsg_done -#define ns_rdata_unpack __ns_rdata_unpack -#define ns_rdata_equal __ns_rdata_equal -#define ns_rdata_refers __ns_rdata_refers +#endif __BEGIN_DECLS -int ns_msg_getflag(ns_msg, int); -uint16_t ns_get16(const u_char *); -uint32_t ns_get32(const u_char *); -void ns_put16(uint16_t, u_char *); -void ns_put32(uint32_t, u_char *); -int ns_initparse(const u_char *, int, ns_msg *); -int ns_skiprr(const u_char *, const u_char *, ns_sect, int); -int ns_parserr(ns_msg *, ns_sect, int, ns_rr *); -int ns_parserr2(ns_msg *, ns_sect, int, ns_rr2 *); +int ns_msg_getflag(ns_msg, int) __LIBC_ABI_PUBLIC__; +uint16_t ns_get16(const u_char *) __LIBC_ABI_PUBLIC__; +uint32_t ns_get32(const u_char *) __LIBC_ABI_PUBLIC__; +void ns_put16(uint16_t, u_char *) __LIBC_ABI_PUBLIC__; +void ns_put32(uint32_t, u_char *) __LIBC_ABI_PUBLIC__; +int ns_initparse(const u_char *, int, ns_msg *) __LIBC_ABI_PUBLIC__; +int ns_skiprr(const u_char *, const u_char *, ns_sect, int) __LIBC_ABI_PUBLIC__; +int ns_parserr(ns_msg *, ns_sect, int, ns_rr *) __LIBC_ABI_PUBLIC__; +int ns_parserr2(ns_msg *, ns_sect, int, ns_rr2 *) __LIBC_HIDDEN__; int ns_sprintrr(const ns_msg *, const ns_rr *, - const char *, const char *, char *, size_t); + const char *, const char *, char *, size_t) __LIBC_ABI_PUBLIC__; int ns_sprintrrf(const u_char *, size_t, const char *, ns_class, ns_type, u_long, const u_char *, size_t, const char *, const char *, - char *, size_t); -int ns_format_ttl(u_long, char *, size_t); -int ns_parse_ttl(const char *, u_long *); -uint32_t ns_datetosecs(const char *cp, int *errp); -int ns_name_ntol(const u_char *, u_char *, size_t); -int ns_name_ntop(const u_char *, char *, size_t); -int ns_name_pton(const char *, u_char *, size_t); -int ns_name_pton2(const char *, u_char *, size_t, size_t *); + char *, size_t) __LIBC_ABI_PUBLIC__; +int ns_format_ttl(u_long, char *, size_t) __LIBC_ABI_PUBLIC__; +int ns_parse_ttl(const char *, u_long *) __LIBC_ABI_PUBLIC__; +uint32_t ns_datetosecs(const char *cp, int *errp) __LIBC_ABI_PUBLIC__; +int ns_name_ntol(const u_char *, u_char *, size_t) __LIBC_ABI_PUBLIC__; +int ns_name_ntop(const u_char *, char *, size_t) __LIBC_ABI_PUBLIC__; +int ns_name_pton(const char *, u_char *, size_t) __LIBC_ABI_PUBLIC__; +int ns_name_pton2(const char *, u_char *, size_t, size_t *) __LIBC_HIDDEN__; int ns_name_unpack(const u_char *, const u_char *, - const u_char *, u_char *, size_t); + const u_char *, u_char *, size_t) __LIBC_ABI_PUBLIC__; int ns_name_unpack2(const u_char *, const u_char *, const u_char *, u_char *, size_t, - size_t *); + size_t *) __LIBC_HIDDEN__; int ns_name_pack(const u_char *, u_char *, int, - const u_char **, const u_char **); + const u_char **, const u_char **) __LIBC_ABI_PUBLIC__; int ns_name_uncompress(const u_char *, const u_char *, - const u_char *, char *, size_t); + const u_char *, char *, size_t) __LIBC_ABI_PUBLIC__; int ns_name_compress(const char *, u_char *, size_t, - const u_char **, const u_char **); -int ns_name_skip(const u_char **, const u_char *); + const u_char **, const u_char **) __LIBC_ABI_PUBLIC__; +int ns_name_skip(const u_char **, const u_char *) __LIBC_ABI_PUBLIC__; void ns_name_rollback(const u_char *, const u_char **, - const u_char **); + const u_char **) __LIBC_ABI_PUBLIC__; int ns_sign(u_char *, int *, int, int, void *, - const u_char *, int, u_char *, int *, time_t); + const u_char *, int, u_char *, int *, time_t) __LIBC_ABI_PUBLIC__; int ns_sign2(u_char *, int *, int, int, void *, const u_char *, int, u_char *, int *, time_t, - u_char **, u_char **); -ssize_t ns_name_length(ns_nname_ct, size_t); -int ns_name_eq(ns_nname_ct, size_t, ns_nname_ct, size_t); -int ns_name_owned(ns_namemap_ct, int, ns_namemap_ct, int); -int ns_name_map(ns_nname_ct, size_t, ns_namemap_t, int); -int ns_name_labels(ns_nname_ct, size_t); + u_char **, u_char **) __LIBC_ABI_PUBLIC__; +ssize_t ns_name_length(ns_nname_ct, size_t) __LIBC_HIDDEN__; +int ns_name_eq(ns_nname_ct, size_t, ns_nname_ct, size_t) __LIBC_HIDDEN__; +int ns_name_owned(ns_namemap_ct, int, ns_namemap_ct, int) __LIBC_HIDDEN__; +int ns_name_map(ns_nname_ct, size_t, ns_namemap_t, int) __LIBC_HIDDEN__; +int ns_name_labels(ns_nname_ct, size_t) __LIBC_HIDDEN__; int ns_sign_tcp(u_char *, int *, int, int, - ns_tcp_tsig_state *, int); + ns_tcp_tsig_state *, int) __LIBC_ABI_PUBLIC__; int ns_sign_tcp2(u_char *, int *, int, int, ns_tcp_tsig_state *, int, - u_char **, u_char **); + u_char **, u_char **) __LIBC_ABI_PUBLIC__; int ns_sign_tcp_init(void *, const u_char *, int, - ns_tcp_tsig_state *); -u_char *ns_find_tsig(u_char *, u_char *); + ns_tcp_tsig_state *) __LIBC_ABI_PUBLIC__; +u_char *ns_find_tsig(u_char *, u_char *) __LIBC_ABI_PUBLIC__; int ns_verify(u_char *, int *, void *, const u_char *, int, u_char *, int *, - time_t *, int); + time_t *, int) __LIBC_ABI_PUBLIC__; int ns_verify_tcp(u_char *, int *, ns_tcp_tsig_state *, int); int ns_verify_tcp_init(void *, const u_char *, int, - ns_tcp_tsig_state *); -int ns_samedomain(const char *, const char *); -int ns_subdomain(const char *, const char *); -int ns_makecanon(const char *, char *, size_t); -int ns_samename(const char *, const char *); -int ns_newmsg_init(u_char *buffer, size_t bufsiz, ns_newmsg *); -int ns_newmsg_copy(ns_newmsg *, ns_msg *); -void ns_newmsg_id(ns_newmsg *handle, uint16_t id); -void ns_newmsg_flag(ns_newmsg *handle, ns_flag flag, u_int value); -int ns_newmsg_q(ns_newmsg *handle, ns_nname_ct qname, - ns_type qtype, ns_class qclass); -int ns_newmsg_rr(ns_newmsg *handle, ns_sect sect, - ns_nname_ct name, ns_type type, - ns_class rr_class, uint32_t ttl, - uint16_t rdlen, const u_char *rdata); -size_t ns_newmsg_done(ns_newmsg *handle); -ssize_t ns_rdata_unpack(const u_char *, const u_char *, ns_type, - const u_char *, size_t, u_char *, size_t); -int ns_rdata_equal(ns_type, - const u_char *, size_t, - const u_char *, size_t); -int ns_rdata_refers(ns_type, - const u_char *, size_t, - const u_char *); + ns_tcp_tsig_state *) __LIBC_ABI_PUBLIC__; +int ns_samedomain(const char *, const char *) __LIBC_ABI_PUBLIC__; +int ns_subdomain(const char *, const char *) __LIBC_ABI_PUBLIC__; +int ns_makecanon(const char *, char *, size_t) __LIBC_ABI_PUBLIC__; +int ns_samename(const char *, const char *) __LIBC_ABI_PUBLIC__; __END_DECLS #ifdef BIND_4_COMPAT From d9e211ca1fcf8bb78a1e1de9e54fe7c8d0a01518 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Wed, 7 Jan 2015 11:16:58 -0800 Subject: [PATCH 112/114] Print error when prelink fails for main executable Bug: 18931021 Change-Id: Ieefdcf60f1506af522714300030754a4ed61c08e --- linker/linker.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 35c8cbdc8..54867dce2 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -2413,7 +2413,10 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( somain = si; - si->PrelinkImage(); + if (!si->PrelinkImage()) { + __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); + exit(EXIT_FAILURE); + } // Load ld_preloads and dependencies. StringLinkedList needed_library_name_list; From 700eb048fb6df8805245097d73a87384108fdf67 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Mon, 2 Feb 2015 11:24:22 +0000 Subject: [PATCH 113/114] Update tzdata to tzdata2015a Time Zone Data v. 2015a (Released 2015-01-29) http://www.iana.org/time-zones/repository/releases/tzdata2015a.tar.gz Information from NEWS: Release 2015a - 2015-01-29 22:35:20 -0800 Changes affecting future time stamps The Mexican state of Quintana Roo, represented by America/Cancun, will shift from Central Time with DST to Eastern Time without DST on 2015-02-01 at 02:00. (Thanks to Steffen Thorsen and Gwillim Law.) Chile will not change clocks in April or thereafter; its new standard time will be its old daylight saving time. This affects America/Santiago, Pacific/Easter, and Antarctica/Palmer. (Thanks to Juan Correa.) New leap second 2015-06-30 23:59:60 UTC as per IERS Bulletin C 49. (Thanks to Tim Parenti.) Changes affecting past time stamps Iceland observed DST in 1919 and 1921, and its 1939 fallback transition was Oct. 29, not Nov. 29. Remove incorrect data from Shanks about time in Iceland between 1837 and 1908. Some more zones have been turned into links, when they differed from existing zones only for older time stamps. As usual, these changes affect UTC offsets in pre-1970 time stamps only. Their old contents have been moved to the 'backzone' file. The affected zones are: Asia/Aden, Asia/Bahrain, Asia/Kuwait, and Asia/Muscat. Changes affecting code tzalloc now scrubs time zone abbreviations compatibly with the way that tzset always has, by replacing invalid bytes with '_' and by shortening too-long abbreviations. tzselect ports to POSIX awk implementations, no longer mishandles POSIX TZ settings when GNU awk is used, and reports POSIX TZ settings to the user. (Thanks to Stefan Kuhn.) Changes affecting build procedure 'make check' now checks for links to links in the data. One such link (for Africa/Asmera) has been fixed. (Thanks to Stephen Colebourne for pointing out the problem.) Changes affecting commentary The leapseconds file commentary now mentions the expiration date. (Problem reported by Martin Burnicki.) Update Mexican Library of Congress URL. Bug: 19212588 Change-Id: Idc07ac862901500d4a1dbd0f4aadcfd0aa9d10b8 --- libc/zoneinfo/tzdata | Bin 498091 -> 494904 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata index fc6c5babb83b74177bbaa18f47f38cd5de8d7c5b..b9a66210eb8eb2a94d5db930cb3ac727921251b8 100644 GIT binary patch delta 4585 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 From 4177bd8d16e0dc2d0d541fc54f81518c57651e55 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Mon, 2 Feb 2015 16:50:05 +0000 Subject: [PATCH 114/114] Fixes to the update-tzdata.py tool We build one too many times. Creating a missing directory is sufficient. The tz2icu needs some files in the CWD. Added symlinks. Bug: 19230091 (cherry-pick of commit 0662c3e5b33840e19f4c14b85bf619c33b3a0d0f) Change-Id: Ie21d848f1b776ec745473b9122e003fdf0acf105 --- libc/tools/zoneinfo/update-tzdata.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libc/tools/zoneinfo/update-tzdata.py b/libc/tools/zoneinfo/update-tzdata.py index 330f1662d..4847356df 100755 --- a/libc/tools/zoneinfo/update-tzdata.py +++ b/libc/tools/zoneinfo/update-tzdata.py @@ -117,13 +117,20 @@ def BuildIcuToolsAndData(data_filename): # Build the ICU tools. print 'Configuring ICU tools...' subprocess.check_call(['%s/runConfigureICU' % icu_dir, 'Linux']) - print 'Making ICU tools...' - subprocess.check_call(['make', '-j32']) # Run the ICU tools. os.chdir('tools/tzcode') + + # The tz2icu tool only picks up icuregions and icuzones in they are in the CWD + for icu_data_file in [ 'icuregions', 'icuzones']: + icu_data_file_source = '%s/tools/tzcode/%s' % (icu_dir, icu_data_file) + icu_data_file_symlink = './%s' % icu_data_file + os.symlink(icu_data_file_source, icu_data_file_symlink) + shutil.copyfile('%s/%s' % (original_working_dir, data_filename), data_filename) print 'Making ICU data...' + # The Makefile assumes the existence of the bin directory. + os.mkdir('%s/bin' % icu_working_dir) subprocess.check_call(['make']) # Copy the source file to its ultimate destination.