Compare commits

..

No commits in common. "main" and "lollipop-mr1-cts-dev" have entirely different histories.

1867 changed files with 58895 additions and 343772 deletions

View File

@ -1,15 +0,0 @@
BasedOnStyle: Google
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
IndentWidth: 2
ContinuationIndentWidth: 2
PointerAlignment: Left
TabWidth: 2
UseTab: Never
PenaltyExcessCharacter: 32
Cpp11BracedListStyle: false

12
ABI-bugs.txt Normal file
View File

@ -0,0 +1,12 @@
KNOWN ABI BUGS
--------------
time_t is 32-bit. http://b/5819737
off_t is 32-bit. There is off64_t, but no _FILE_OFFSET_BITS support.
sigset_t is too small on ARM and x86 (but correct on MIPS), so support
for real-time signals is broken. http://b/5828899
atexit(3) handlers registered by a shared library aren't called on
dlclose(3); this only affects ARM. http://b/4998315

View File

@ -1 +0,0 @@
subdirs = ["*"]

View File

@ -1,2 +0,0 @@
set noparent
filter=-build/header_guard,-runtime/int,-readability/function

162
HACKING.txt Normal file
View File

@ -0,0 +1,162 @@
Working on bionic
=================
What are the big pieces of bionic?
----------------------------------
libc/ --- libc.so, libc.a
The C library. Stuff like fopen(3) and kill(2).
libm/ --- libm.so, libm.a
The math library. Traditionally Unix systems kept stuff like sin(3) and
cos(3) in a separate library to save space in the days before shared
libraries.
libdl/ --- libdl.so
The dynamic linker interface library. This is actually just a bunch of
stubs that the dynamic linker replaces with pointers to its own
implementation at runtime. This is where stuff like dlopen(3) lives.
libstdc++/ --- libstdc++.so
The C++ ABI support functions. The C++ compiler doesn't know how to
implement thread-safe static initialization and the like, so it just calls
functions that are supplied by the system. Stuff like __cxa_guard_acquire
and __cxa_pure_virtual live here.
linker/ --- /system/bin/linker and /system/bin/linker64
The dynamic linker. When you run a dynamically-linked executable, its ELF
file has a DT_INTERP entry that says "use the following program to start me".
On Android, that's either linker or linker64 (depending on whether it's a
32-bit or 64-bit executable). It's responsible for loading the ELF executable
into memory and resolving references to symbols (so that when your code tries
to jump to fopen(3), say, it lands in the right place).
tests/ --- unit tests
The tests/ directory contains unit tests. Roughly arranged as one file per
publicly-exported header file.
benchmarks/ --- benchmarks
The benchmarks/ directory contains benchmarks.
What's in libc/?
----------------
libc/
arch-arm/
arch-arm64/
arch-common/
arch-mips/
arch-mips64/
arch-x86/
arch-x86_64/
# Each architecture has its own subdirectory for stuff that isn't shared
# because it's architecture-specific. There will be a .mk file in here that
# drags in all the architecture-specific files.
bionic/
# Every architecture needs a handful of machine-specific assembler files.
# They live here.
include/
machine/
# The majority of header files are actually in libc/include/, but many
# of them pull in a <machine/something.h> for things like limits,
# endianness, and how floating point numbers are represented. Those
# headers live here.
string/
# Most architectures have a handful of optional assembler files
# implementing optimized versions of various routines. The <string.h>
# functions are particular favorites.
syscalls/
# The syscalls directories contain script-generated assembler files.
# See 'Adding system calls' later.
include/
# The public header files on everyone's include path. These are a mixture of
# files written by us and files taken from BSD.
kernel/
# The kernel uapi header files. These are scrubbed copies of the originals
# in external/kernel-headers/. These files must not be edited directly. The
# generate_uapi_headers.sh script should be used to go from a kernel tree to
# external/kernel-headers/ --- this takes care of the architecture-specific
# details. The update_all.py script should be used to regenerate bionic's
# scrubbed headers from external/kernel-headers/.
private/
# These are private header files meant for use within bionic itself.
dns/
# Contains the DNS resolver (originates from NetBSD code).
upstream-dlmalloc/
upstream-freebsd/
upstream-netbsd/
upstream-openbsd/
# These directories contain unmolested upstream source. Any time we can
# just use a BSD implementation of something unmodified, we should.
# The structure under these directories mimics the upstream tree,
# but there's also...
android/
include/
# This is where we keep the hacks necessary to build BSD source
# in our world. The *-compat.h files are automatically included
# using -include, but we also provide equivalents for missing
# header/source files needed by the BSD implementation.
bionic/
# This is the biggest mess. The C++ files are files we own, typically
# because the Linux kernel interface is sufficiently different that we
# can't use any of the BSD implementations. The C files are usually
# legacy mess that needs to be sorted out, either by replacing it with
# current upstream source in one of the upstream directories or by
# switching the file to C++ and cleaning it up.
stdio/
# These are legacy files of dubious provenance. We're working to clean
# this mess up, and this directory should disappear.
tools/
# Various tools used to maintain bionic.
tzcode/
# A modified superset of the IANA tzcode. Most of the modifications relate
# to Android's use of a single file (with corresponding index) to contain
# time zone data.
zoneinfo/
# Android-format time zone data.
# See 'Updating tzdata' later.
Adding system calls
-------------------
Adding a system call usually involves:
1. Add entries to SYSCALLS.TXT.
See SYSCALLS.TXT itself for documentation on the format.
2. Run the gensyscalls.py script.
3. Add constants (and perhaps types) to the appropriate header file.
Note that you should check to see whether the constants are already in
kernel uapi header files, in which case you just need to make sure that
the appropriate POSIX header file in libc/include/ includes the
relevant file or files.
4. Add function declarations to the appropriate header file.
5. Add at least basic tests. Even a test that deliberately supplies
an invalid argument helps check that we're generating the right symbol
and have the right declaration in the header file. (And strace(1) can
confirm that the correct system call is being made.)
Updating kernel header files
----------------------------
As mentioned above, this is currently a two-step process:
1. Use generate_uapi_headers.sh to go from a Linux source tree to appropriate
contents for external/kernel-headers/.
2. Run update_all.py to scrub those headers and import them into bionic.
Updating tzdata
---------------
This is fully automated:
1. Run update-tzdata.py.

290
README.md
View File

@ -1,290 +0,0 @@
Working on bionic
=================
What are the big pieces of bionic?
----------------------------------
#### libc/ --- libc.so, libc.a
The C library. Stuff like `fopen(3)` and `kill(2)`.
#### libm/ --- libm.so, libm.a
The math library. Traditionally Unix systems kept stuff like `sin(3)` and
`cos(3)` in a separate library to save space in the days before shared
libraries.
#### libdl/ --- libdl.so
The dynamic linker interface library. This is actually just a bunch of stubs
that the dynamic linker replaces with pointers to its own implementation at
runtime. This is where stuff like `dlopen(3)` lives.
#### libstdc++/ --- libstdc++.so
The C++ ABI support functions. The C++ compiler doesn't know how to implement
thread-safe static initialization and the like, so it just calls functions that
are supplied by the system. Stuff like `__cxa_guard_acquire` and
`__cxa_pure_virtual` live here.
#### linker/ --- /system/bin/linker and /system/bin/linker64
The dynamic linker. When you run a dynamically-linked executable, its ELF file
has a `DT_INTERP` entry that says "use the following program to start me". On
Android, that's either `linker` or `linker64` (depending on whether it's a
32-bit or 64-bit executable). It's responsible for loading the ELF executable
into memory and resolving references to symbols (so that when your code tries to
jump to `fopen(3)`, say, it lands in the right place).
#### tests/ --- unit tests
The `tests/` directory contains unit tests. Roughly arranged as one file per
publicly-exported header file.
#### benchmarks/ --- benchmarks
The `benchmarks/` directory contains benchmarks.
What's in libc/?
----------------
<pre>
libc/
arch-arm/
arch-arm64/
arch-common/
arch-mips/
arch-mips64/
arch-x86/
arch-x86_64/
# Each architecture has its own subdirectory for stuff that isn't shared
# because it's architecture-specific. There will be a .mk file in here that
# drags in all the architecture-specific files.
bionic/
# Every architecture needs a handful of machine-specific assembler files.
# They live here.
include/
machine/
# The majority of header files are actually in libc/include/, but many
# of them pull in a <machine/something.h> for things like limits,
# endianness, and how floating point numbers are represented. Those
# headers live here.
string/
# Most architectures have a handful of optional assembler files
# implementing optimized versions of various routines. The <string.h>
# functions are particular favorites.
syscalls/
# The syscalls directories contain script-generated assembler files.
# See 'Adding system calls' later.
include/
# The public header files on everyone's include path. These are a mixture of
# files written by us and files taken from BSD.
kernel/
# The kernel uapi header files. These are scrubbed copies of the originals
# in external/kernel-headers/. These files must not be edited directly. The
# generate_uapi_headers.sh script should be used to go from a kernel tree to
# external/kernel-headers/ --- this takes care of the architecture-specific
# details. The update_all.py script should be used to regenerate bionic's
# scrubbed headers from external/kernel-headers/.
private/
# These are private header files meant for use within bionic itself.
dns/
# Contains the DNS resolver (originates from NetBSD code).
upstream-dlmalloc/
upstream-freebsd/
upstream-netbsd/
upstream-openbsd/
# These directories contain unmolested upstream source. Any time we can
# just use a BSD implementation of something unmodified, we should.
# The structure under these directories mimics the upstream tree,
# but there's also...
android/
include/
# This is where we keep the hacks necessary to build BSD source
# in our world. The *-compat.h files are automatically included
# using -include, but we also provide equivalents for missing
# header/source files needed by the BSD implementation.
bionic/
# This is the biggest mess. The C++ files are files we own, typically
# because the Linux kernel interface is sufficiently different that we
# can't use any of the BSD implementations. The C files are usually
# legacy mess that needs to be sorted out, either by replacing it with
# current upstream source in one of the upstream directories or by
# switching the file to C++ and cleaning it up.
stdio/
# These are legacy files of dubious provenance. We're working to clean
# this mess up, and this directory should disappear.
tools/
# Various tools used to maintain bionic.
tzcode/
# A modified superset of the IANA tzcode. Most of the modifications relate
# to Android's use of a single file (with corresponding index) to contain
# time zone data.
zoneinfo/
# Android-format time zone data.
# See 'Updating tzdata' later.
</pre>
Adding system calls
-------------------
Adding a system call usually involves:
1. Add entries to SYSCALLS.TXT.
See SYSCALLS.TXT itself for documentation on the format.
2. Run the gensyscalls.py script.
3. Add constants (and perhaps types) to the appropriate header file.
Note that you should check to see whether the constants are already in
kernel uapi header files, in which case you just need to make sure that
the appropriate POSIX header file in libc/include/ includes the
relevant file or files.
4. Add function declarations to the appropriate header file.
5. Add at least basic tests. Even a test that deliberately supplies
an invalid argument helps check that we're generating the right symbol
and have the right declaration in the header file. (And strace(1) can
confirm that the correct system call is being made.)
Updating kernel header files
----------------------------
As mentioned above, this is currently a two-step process:
1. Use generate_uapi_headers.sh to go from a Linux source tree to appropriate
contents for external/kernel-headers/.
2. Run update_all.py to scrub those headers and import them into bionic.
Updating tzdata
---------------
This is fully automated (and these days handled by the libcore team, because
they own icu, and that needs to be updated in sync with bionic):
1. Run update-tzdata.py in external/icu/tools/.
Verifying changes
-----------------
If you make a change that is likely to have a wide effect on the tree (such as a
libc header change), you should run `make checkbuild`. A regular `make` will
_not_ build the entire tree; just the minimum number of projects that are
required for the device. Tests, additional developer tools, and various other
modules will not be built. Note that `make checkbuild` will not be complete
either, as `make tests` covers a few additional modules, but generally speaking
`make checkbuild` is enough.
Running the tests
-----------------
The tests are all built from the tests/ directory.
### Device tests
$ mma
$ adb remount
$ adb sync
$ adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests32
$ adb shell \
/data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static32
# Only for 64-bit targets
$ adb shell /data/nativetest64/bionic-unit-tests/bionic-unit-tests64
$ adb shell \
/data/nativetest64/bionic-unit-tests-static/bionic-unit-tests-static64
### Host tests
The host tests require that you have `lunch`ed either an x86 or x86_64 target.
$ mma
$ mm bionic-unit-tests-run-on-host32
$ mm bionic-unit-tests-run-on-host64 # For 64-bit *targets* only.
### Against glibc
As a way to check that our tests do in fact test the correct behavior (and not
just the behavior we think is correct), it is possible to run the tests against
the host's glibc. The executables are already in your path.
$ mma
$ bionic-unit-tests-glibc32
$ bionic-unit-tests-glibc64
Gathering test coverage
-----------------------
For either host or target coverage, you must first:
* `$ export NATIVE_COVERAGE=true`
* Note that the build system is ignorant to this flag being toggled, i.e. if
you change this flag, you will have to manually rebuild bionic.
* Set `bionic_coverage=true` in `libc/Android.mk` and `libm/Android.mk`.
### Coverage from device tests
$ mma
$ adb sync
$ adb shell \
GCOV_PREFIX=/data/local/tmp/gcov \
GCOV_PREFIX_STRIP=`echo $ANDROID_BUILD_TOP | grep -o / | wc -l` \
/data/nativetest/bionic-unit-tests/bionic-unit-tests32
$ acov
`acov` will pull all coverage information from the device, push it to the right
directories, run `lcov`, and open the coverage report in your browser.
### Coverage from host tests
First, build and run the host tests as usual (see above).
$ croot
$ lcov -c -d $ANDROID_PRODUCT_OUT -o coverage.info
$ genhtml -o covreport coverage.info # or lcov --list coverage.info
The coverage report is now available at `covreport/index.html`.
Attaching GDB to the tests
--------------------------
Bionic's test runner will run each test in its own process by default to prevent
tests failures from impacting other tests. This also has the added benefit of
running them in parallel, so they are much faster.
However, this also makes it difficult to run the tests under GDB. To prevent
each test from being forked, run the tests with the flag `--no-isolate`.
32-bit ABI bugs
---------------
This probably belongs in the NDK documentation rather than here, but these
are the known ABI bugs in the 32-bit ABI:
* `time_t` is 32-bit. <http://b/5819737>. In the 64-bit ABI, time_t is
64-bit.
* `off_t` is 32-bit. There is `off64_t`, and in newer releases there is
almost-complete support for `_FILE_OFFSET_BITS`. Unfortunately our stdio
implementation uses 32-bit offsets and -- worse -- function pointers to
functions that use 32-bit offsets, so there's no good way to implement
the last few pieces <http://b/24807045>. In the 64-bit ABI, off_t is
off64_t.
* `sigset_t` is too small on ARM and x86 (but correct on MIPS), so support
for real-time signals is broken. <http://b/5828899> In the 64-bit ABI,
`sigset_t` is the correct size for every architecture.

View File

@ -14,55 +14,23 @@
# limitations under the License. # limitations under the License.
# #
ifneq ($(BUILD_TINY_ANDROID), true)
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
# -----------------------------------------------------------------------------
# Benchmarks library, usable by projects outside this directory.
# -----------------------------------------------------------------------------
benchmark_cflags := \
-O2 \
-fno-builtin \
-Wall \
-Wextra \
-Werror \
-Wunused \
benchmark_cppflags := \
benchmarklib_src_files := \
Benchmark.cpp \
utils.cpp \
main.cpp \
include $(CLEAR_VARS)
LOCAL_MODULE := libbenchmark
LOCAL_CFLAGS := $(benchmark_cflags)
LOCAL_CPPFLAGS := $(benchmark_cppflags)
LOCAL_SRC_FILES := $(benchmarklib_src_files)
LOCAL_C_INCLUDES := $(benchmark_c_includes)
LOCAL_STATIC_LIBRARIES := libbase
include $(BUILD_STATIC_LIBRARY)
# Only supported on linux systems.
ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
LOCAL_MODULE := libbenchmark
LOCAL_CFLAGS := $(benchmark_cflags)
LOCAL_CPPFLAGS := $(benchmark_cppflags)
LOCAL_SRC_FILES := $(benchmarklib_src_files)
LOCAL_C_INCLUDES := $(benchmark_c_includes)
LOCAL_MULTILIB := both
LOCAL_STATIC_LIBRARIES := libbase
include $(BUILD_HOST_STATIC_LIBRARY)
endif
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Benchmarks. # Benchmarks.
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
benchmark_src_files := \
benchmark_c_flags = \
-O2 \
-Wall -Wextra -Wunused \
-Werror \
-fno-builtin \
-std=gnu++11 \
benchmark_src_files = \
benchmark_main.cpp \
math_benchmark.cpp \ math_benchmark.cpp \
property_benchmark.cpp \ property_benchmark.cpp \
pthread_benchmark.cpp \ pthread_benchmark.cpp \
@ -73,58 +41,40 @@ benchmark_src_files := \
unistd_benchmark.cpp \ unistd_benchmark.cpp \
# Build benchmarks for the device (with bionic's .so). Run with: # Build benchmarks for the device (with bionic's .so). Run with:
# adb shell bionic-benchmarks32 # adb shell bionic-benchmarks
# adb shell bionic-benchmarks64
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := bionic-benchmarks LOCAL_MODULE := bionic-benchmarks
LOCAL_MODULE_STEM_32 := bionic-benchmarks32 LOCAL_MODULE_STEM_32 := bionic-benchmarks32
LOCAL_MODULE_STEM_64 := bionic-benchmarks64 LOCAL_MODULE_STEM_64 := bionic-benchmarks64
LOCAL_MULTILIB := both LOCAL_MULTILIB := both
LOCAL_CFLAGS := $(benchmark_cflags) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CPPFLAGS := $(benchmark_cppflags) LOCAL_CFLAGS += $(benchmark_c_flags)
LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
LOCAL_SHARED_LIBRARIES += libstlport
LOCAL_SRC_FILES := $(benchmark_src_files) LOCAL_SRC_FILES := $(benchmark_src_files)
LOCAL_STATIC_LIBRARIES := libbenchmark libbase
include $(BUILD_EXECUTABLE) include $(BUILD_EXECUTABLE)
# We don't build a static benchmark executable because it's not usually
# useful. If you're trying to run the current benchmarks on an older
# release, it's (so far at least) always because you want to measure the
# performance of the old release's libc, and a static benchmark isn't
# going to let you do that.
# Only supported on linux systems.
ifeq ($(HOST_OS),linux)
# Build benchmarks for the host (against glibc!). Run with:
include $(CLEAR_VARS)
LOCAL_MODULE := bionic-benchmarks-glibc
LOCAL_MODULE_STEM_32 := bionic-benchmarks-glibc32
LOCAL_MODULE_STEM_64 := bionic-benchmarks-glibc64
LOCAL_MULTILIB := both
LOCAL_CFLAGS := $(benchmark_cflags)
LOCAL_CPPFLAGS := $(benchmark_cppflags)
LOCAL_LDFLAGS := -lrt
LOCAL_SRC_FILES := $(benchmark_src_files)
LOCAL_STATIC_LIBRARIES := libbenchmark libbase
include $(BUILD_HOST_EXECUTABLE)
endif
ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64)) ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
include $(LOCAL_PATH)/../build/run-on-host.mk ifeq ($(TARGET_ARCH),x86)
LINKER = linker
NATIVE_SUFFIX=32
else
LINKER = linker64
NATIVE_SUFFIX=64
endif
ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64)) bionic-benchmarks-run-on-host: bionic-benchmarks $(TARGET_OUT_EXECUTABLES)/$(LINKER) $(TARGET_OUT_EXECUTABLES)/sh
bionic-benchmarks-run-on-host32: bionic-benchmarks bionic-prepare-run-on-host 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_DATA=$(TARGET_OUT_DATA) \
ANDROID_ROOT=$(TARGET_OUT) \ ANDROID_ROOT=$(TARGET_OUT) \
$(TARGET_OUT_EXECUTABLES)/bionic-benchmarks32 $(BIONIC_BENCHMARKS_FLAGS) LD_LIBRARY_PATH=$(TARGET_OUT_SHARED_LIBRARIES) \
endif $(TARGET_OUT_EXECUTABLES)/bionic-benchmarks$(NATIVE_SUFFIX) $(BIONIC_BENCHMARKS_FLAGS)
endif # linux-x86
ifeq ($(TARGET_IS_64_BIT),true) endif # !BUILD_TINY_ANDROID
bionic-benchmarks-run-on-host64: bionic-benchmarks bionic-prepare-run-on-host
ANDROID_DATA=$(TARGET_OUT_DATA) \
ANDROID_ROOT=$(TARGET_OUT) \
$(TARGET_OUT_EXECUTABLES)/bionic-benchmarks64 $(BIONIC_BENCHMARKS_FLAGS)
endif
endif

View File

@ -1,159 +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 <inttypes.h>
#include <regex.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <vector>
#include <android-base/stringprintf.h>
#include <benchmark/Benchmark.h>
#include "utils.h"
namespace testing {
static uint64_t NanoTime() {
struct timespec t;
t.tv_sec = t.tv_nsec = 0;
clock_gettime(CLOCK_MONOTONIC, &t);
return static_cast<uint64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
}
bool Benchmark::header_printed_;
std::vector<Benchmark*>& Benchmark::List() {
static std::vector<Benchmark*> list;
return list;
}
int Benchmark::MaxNameColumnWidth() {
size_t max = 20;
for (auto& benchmark : List()) {
max = std::max(max, benchmark->NameColumnWidth());
}
return static_cast<int>(max);
}
size_t Benchmark::RunAll(std::vector<regex_t*>& regs) {
size_t benchmarks_run = 0;
header_printed_ = false;
for (auto& benchmark : List()) {
benchmarks_run += benchmark->RunAllArgs(regs);
}
return benchmarks_run;
}
void Benchmark::PrintHeader() {
if (!header_printed_) {
printf("%-*s %10s %10s\n", MaxNameColumnWidth(), "", "iterations", "ns/op");
header_printed_ = true;
}
}
template <typename T>
bool BenchmarkT<T>::ShouldRun(std::vector<regex_t*>& regs, T arg) {
if (regs.empty()) {
return true;
}
for (const auto& re : regs) {
if (regexec(re, GetNameStr(arg).c_str(), 0, NULL, 0) != REG_NOMATCH) {
return true;
}
}
return false;
}
void Benchmark::StopBenchmarkTiming() {
if (start_time_ns_ != 0) {
total_time_ns_ += NanoTime() - start_time_ns_;
}
start_time_ns_ = 0;
}
void Benchmark::StartBenchmarkTiming() {
if (start_time_ns_ == 0) {
start_time_ns_ = NanoTime();
}
}
std::string BenchmarkWithoutArg::GetNameStr(void*) {
return Name();
}
template <>
std::string BenchmarkWithArg<int>::GetNameStr(int arg) {
return Name() + "/" + PrettyInt(arg, 2);
}
template <>
std::string BenchmarkWithArg<double>::GetNameStr(double arg) {
return Name() + "/" + android::base::StringPrintf("%0.6f", arg);
}
template<typename T>
void BenchmarkT<T>::RunWithArg(T arg) {
int new_iterations = 1;
int iterations;
while (new_iterations < 1e8) {
bytes_processed_ = 0;
total_time_ns_ = 0;
start_time_ns_ = 0;
iterations = new_iterations;
RunIterations(iterations, arg);
if (total_time_ns_ >= 1e9) {
break;
}
if (total_time_ns_/iterations == 0) {
new_iterations = 1e9;
} else {
new_iterations = 1e9/ (total_time_ns_/iterations);
}
new_iterations = std::max(iterations + 1,
std::min(new_iterations + new_iterations/2, 100*iterations));
new_iterations = Round(new_iterations);
}
printf("%-*s %10s %10" PRId64, MaxNameColumnWidth(), GetNameStr(arg).c_str(),
PrettyInt(iterations, 10).c_str(), total_time_ns_/iterations);
if (total_time_ns_ > 0 && bytes_processed_ > 0) {
double gib_processed = static_cast<double>(bytes_processed_)/1e9;
double seconds = static_cast<double>(total_time_ns_)/1e9;
printf(" %8.3f GiB/s", gib_processed/seconds);
}
printf("\n");
fflush(stdout);
}
template class BenchmarkT<int>;
template class BenchmarkT<double>;
template class BenchmarkT<void*>;
template class BenchmarkWithArg<int>;
template class BenchmarkWithArg<double>;
} // namespace testing

61
benchmarks/benchmark.h Normal file
View File

@ -0,0 +1,61 @@
/*
* 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 <stdint.h>
#include <vector>
namespace testing {
class Benchmark {
public:
Benchmark(const char* name, void (*fn)(int)) {
Register(name, fn, NULL);
}
Benchmark(const char* name, void (*fn_range)(int, int)) {
Register(name, NULL, fn_range);
}
Benchmark* Arg(int x);
const char* Name();
bool ShouldRun(int argc, char* argv[]);
void Run();
private:
const char* name_;
void (*fn_)(int);
void (*fn_range_)(int, int);
std::vector<int> args_;
void Register(const char* name, void (*fn)(int), void (*fn_range)(int, int));
void RunRepeatedlyWithArg(int iterations, int arg);
void RunWithArg(int arg);
};
} // namespace testing
void SetBenchmarkBytesProcessed(int64_t);
void StopBenchmarkTiming();
void StartBenchmarkTiming();
#define BENCHMARK(f) \
static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = \
(new ::testing::Benchmark(#f, f))

View File

@ -1,169 +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.
*/
#ifndef BENCHMARKS_BENCHMARK_H_
#define BENCHMARKS_BENCHMARK_H_
#include <regex.h>
#include <stdint.h>
#include <string>
#include <vector>
namespace testing {
class Benchmark {
public:
Benchmark() {
List().push_back(this);
}
virtual ~Benchmark() {}
virtual std::string Name() = 0;
virtual size_t RunAllArgs(std::vector<regex_t*>&) = 0;
void SetBenchmarkBytesProcessed(uint64_t bytes) { bytes_processed_ += bytes; }
void StopBenchmarkTiming();
void StartBenchmarkTiming();
// Run all of the benchmarks that have registered.
static size_t RunAll(std::vector<regex_t*>&);
static std::vector<Benchmark*>& List();
static int MaxNameColumnWidth();
protected:
virtual size_t NameColumnWidth() = 0;
uint64_t bytes_processed_;
uint64_t total_time_ns_;
uint64_t start_time_ns_;
static bool header_printed_;
static void PrintHeader();
};
template <typename T>
class BenchmarkT : public Benchmark {
public:
BenchmarkT() {}
virtual ~BenchmarkT() {}
protected:
bool ShouldRun(std::vector<regex_t*>&, T arg);
void RunWithArg(T arg);
virtual void RunIterations(int, T) = 0;
virtual std::string GetNameStr(T) = 0;
};
class BenchmarkWithoutArg : public BenchmarkT<void*> {
public:
BenchmarkWithoutArg() {}
virtual ~BenchmarkWithoutArg() {}
protected:
virtual size_t RunAllArgs(std::vector<regex_t*>& regs) override {
size_t benchmarks_run = 0;
if (BenchmarkT<void*>::ShouldRun(regs, nullptr)) {
PrintHeader();
RunWithArg(nullptr);
benchmarks_run++;
}
return benchmarks_run;
}
virtual void RunIterations(int iters, void*) override {
Run(iters);
}
virtual void Run(int) = 0;
virtual size_t NameColumnWidth() override {
return Name().size();
}
virtual std::string GetNameStr(void *) override;
};
template<typename T>
class BenchmarkWithArg : public BenchmarkT<T> {
public:
BenchmarkWithArg() {}
virtual ~BenchmarkWithArg() {}
BenchmarkWithArg* Arg(T arg) {
args_.push_back(arg);
return this;
}
protected:
virtual size_t NameColumnWidth() override {
size_t max = 0;
for (const auto& arg : args_) {
max = std::max(max, GetNameStr(arg).size());
}
return max;
}
std::string GetNameStr(T arg) override;
virtual size_t RunAllArgs(std::vector<regex_t*>& regs) override {
size_t benchmarks_run = 0;
for (T& arg : args_) {
if (BenchmarkT<T>::ShouldRun(regs, arg)) {
Benchmark::PrintHeader();
BenchmarkT<T>::RunWithArg(arg);
benchmarks_run++;
}
}
return benchmarks_run;
}
virtual void RunIterations(int iters, T arg) override {
Run(iters, arg);
}
virtual void Run(int iters, T arg) = 0;
private:
std::vector<T> args_;
};
} // namespace testing
#define BENCHMARK_START(f, super_class) \
class f : public super_class { \
public: \
f() {} \
virtual ~f() {} \
virtual std::string Name() override { return #f; } \
#define BENCHMARK_NO_ARG(f) \
BENCHMARK_START(f, ::testing::BenchmarkWithoutArg) \
virtual void Run(int) override; \
}; \
static ::testing::Benchmark* __benchmark_##f = new f()
#define BENCHMARK_WITH_ARG(f, arg_type) \
BENCHMARK_START(f, ::testing::BenchmarkWithArg<arg_type>) \
virtual void Run(int, arg_type) override; \
}; \
static ::testing::BenchmarkWithArg<arg_type>* __benchmark_##f = (new f())
#endif // BENCHMARKS_BENCHMARK_H_

View File

@ -0,0 +1,226 @@
/*
* 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 "benchmark.h"
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <map>
#include <inttypes.h>
static int64_t g_bytes_processed;
static int64_t g_benchmark_total_time_ns;
static int64_t g_benchmark_start_time_ns;
typedef std::map<std::string, ::testing::Benchmark*> BenchmarkMap;
typedef BenchmarkMap::iterator BenchmarkMapIt;
static BenchmarkMap g_benchmarks;
static int g_name_column_width = 20;
static int Round(int n) {
int base = 1;
while (base*10 < n) {
base *= 10;
}
if (n < 2*base) {
return 2*base;
}
if (n < 5*base) {
return 5*base;
}
return 10*base;
}
static int64_t NanoTime() {
struct timespec t;
t.tv_sec = t.tv_nsec = 0;
clock_gettime(CLOCK_MONOTONIC, &t);
return static_cast<int64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
}
namespace testing {
Benchmark* Benchmark::Arg(int arg) {
args_.push_back(arg);
return this;
}
const char* Benchmark::Name() {
return name_;
}
bool Benchmark::ShouldRun(int argc, char* argv[]) {
if (argc == 1) {
return true; // With no arguments, we run all benchmarks.
}
// Otherwise, we interpret each argument as a regular expression and
// see if any of our benchmarks match.
for (int i = 1; i < argc; i++) {
regex_t re;
if (regcomp(&re, argv[i], 0) != 0) {
fprintf(stderr, "couldn't compile \"%s\" as a regular expression!\n", argv[i]);
exit(EXIT_FAILURE);
}
int match = regexec(&re, name_, 0, NULL, 0);
regfree(&re);
if (match != REG_NOMATCH) {
return true;
}
}
return false;
}
void Benchmark::Register(const char* name, void (*fn)(int), void (*fn_range)(int, int)) {
name_ = name;
fn_ = fn;
fn_range_ = fn_range;
if (fn_ == NULL && fn_range_ == NULL) {
fprintf(stderr, "%s: missing function\n", name_);
exit(EXIT_FAILURE);
}
g_benchmarks.insert(std::make_pair(name, this));
}
void Benchmark::Run() {
if (fn_ != NULL) {
RunWithArg(0);
} else {
if (args_.empty()) {
fprintf(stderr, "%s: no args!\n", name_);
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < args_.size(); ++i) {
RunWithArg(args_[i]);
}
}
}
void Benchmark::RunRepeatedlyWithArg(int iterations, int arg) {
g_bytes_processed = 0;
g_benchmark_total_time_ns = 0;
g_benchmark_start_time_ns = NanoTime();
if (fn_ != NULL) {
fn_(iterations);
} else {
fn_range_(iterations, arg);
}
if (g_benchmark_start_time_ns != 0) {
g_benchmark_total_time_ns += NanoTime() - g_benchmark_start_time_ns;
}
}
void Benchmark::RunWithArg(int arg) {
// run once in case it's expensive
int iterations = 1;
RunRepeatedlyWithArg(iterations, arg);
while (g_benchmark_total_time_ns < 1e9 && iterations < 1e9) {
int last = iterations;
if (g_benchmark_total_time_ns/iterations == 0) {
iterations = 1e9;
} else {
iterations = 1e9 / (g_benchmark_total_time_ns/iterations);
}
iterations = std::max(last + 1, std::min(iterations + iterations/2, 100*last));
iterations = Round(iterations);
RunRepeatedlyWithArg(iterations, arg);
}
char throughput[100];
throughput[0] = '\0';
if (g_benchmark_total_time_ns > 0 && g_bytes_processed > 0) {
double mib_processed = static_cast<double>(g_bytes_processed)/1e6;
double seconds = static_cast<double>(g_benchmark_total_time_ns)/1e9;
snprintf(throughput, sizeof(throughput), " %8.2f MiB/s", mib_processed/seconds);
}
char full_name[100];
if (fn_range_ != NULL) {
if (arg >= (1<<20)) {
snprintf(full_name, sizeof(full_name), "%s/%dM", name_, arg/(1<<20));
} else if (arg >= (1<<10)) {
snprintf(full_name, sizeof(full_name), "%s/%dK", name_, arg/(1<<10));
} else {
snprintf(full_name, sizeof(full_name), "%s/%d", name_, arg);
}
} else {
snprintf(full_name, sizeof(full_name), "%s", name_);
}
printf("%-*s %10d %10" PRId64 "%s\n", g_name_column_width, full_name,
iterations, g_benchmark_total_time_ns/iterations, throughput);
fflush(stdout);
}
} // namespace testing
void SetBenchmarkBytesProcessed(int64_t x) {
g_bytes_processed = x;
}
void StopBenchmarkTiming() {
if (g_benchmark_start_time_ns != 0) {
g_benchmark_total_time_ns += NanoTime() - g_benchmark_start_time_ns;
}
g_benchmark_start_time_ns = 0;
}
void StartBenchmarkTiming() {
if (g_benchmark_start_time_ns == 0) {
g_benchmark_start_time_ns = NanoTime();
}
}
int main(int argc, char* argv[]) {
if (g_benchmarks.empty()) {
fprintf(stderr, "No benchmarks registered!\n");
exit(EXIT_FAILURE);
}
for (BenchmarkMapIt it = g_benchmarks.begin(); it != g_benchmarks.end(); ++it) {
int name_width = static_cast<int>(strlen(it->second->Name()));
g_name_column_width = std::max(g_name_column_width, name_width);
}
bool need_header = true;
for (BenchmarkMapIt it = g_benchmarks.begin(); it != g_benchmarks.end(); ++it) {
::testing::Benchmark* b = it->second;
if (b->ShouldRun(argc, argv)) {
if (need_header) {
printf("%-*s %10s %10s\n", g_name_column_width, "", "iterations", "ns/op");
fflush(stdout);
need_header = false;
}
b->Run();
}
}
if (need_header) {
fprintf(stderr, "No matching benchmarks!\n");
fprintf(stderr, "Available benchmarks:\n");
for (BenchmarkMapIt it = g_benchmarks.begin(); it != g_benchmarks.end(); ++it) {
fprintf(stderr, " %s\n", it->second->Name());
}
exit(EXIT_FAILURE);
}
return 0;
}

View File

@ -1,61 +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 <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <benchmark/Benchmark.h>
int main(int argc, char* argv[]) {
if (::testing::Benchmark::List().empty()) {
fprintf(stderr, "No benchmarks registered!\n");
exit(EXIT_FAILURE);
}
std::vector<regex_t*> regs;
for (int i = 1; i < argc; i++) {
regex_t* re = new regex_t;
int errcode = regcomp(re, argv[i], 0);
if (errcode != 0) {
size_t errbuf_size = regerror(errcode, re, NULL, 0);
if (errbuf_size > 0) {
char* errbuf = new char[errbuf_size];
regerror(errcode, re, errbuf, errbuf_size);
fprintf(stderr, "Couldn't compile \"%s\" as a regular expression: %s\n",
argv[i], errbuf);
} else {
fprintf(stderr, "Unknown compile error for \"%s\" as a regular expression!\n", argv[i]);
}
exit(EXIT_FAILURE);
}
regs.push_back(re);
}
if (::testing::Benchmark::RunAll(regs) == 0) {
fprintf(stderr, "No matching benchmarks!\n");
fprintf(stderr, "Available benchmarks:\n");
for (const auto& benchmark : ::testing::Benchmark::List()) {
fprintf(stderr, " %s\n", benchmark->Name().c_str());
}
exit(EXIT_FAILURE);
}
return 0;
}

View File

@ -14,20 +14,16 @@
* limitations under the License. * limitations under the License.
*/ */
#include "benchmark.h"
#include <fenv.h> #include <fenv.h>
#include <math.h> #include <math.h>
#include <benchmark/Benchmark.h>
#define AT_COMMON_VALS \
Arg(1234.0)->Arg(nan(""))->Arg(HUGE_VAL)->Arg(0.0)
// Avoid optimization. // Avoid optimization.
volatile double d; double d;
volatile double v; double v;
BENCHMARK_NO_ARG(BM_math_sqrt); static void BM_math_sqrt(int iters) {
void BM_math_sqrt::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 0.0; d = 0.0;
@ -38,9 +34,9 @@ void BM_math_sqrt::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_sqrt);
BENCHMARK_NO_ARG(BM_math_log10); static void BM_math_log10(int iters) {
void BM_math_log10::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 0.0; d = 0.0;
@ -51,9 +47,9 @@ void BM_math_log10::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_log10);
BENCHMARK_NO_ARG(BM_math_logb); static void BM_math_logb(int iters) {
void BM_math_logb::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 0.0; d = 0.0;
@ -64,120 +60,61 @@ void BM_math_logb::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_logb);
BENCHMARK_WITH_ARG(BM_math_isfinite_macro, double)->AT_COMMON_VALS; static void BM_math_isinf_NORMAL(int iters) {
void BM_math_isfinite_macro::Run(int iters, double value) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 0.0; d = 0.0;
v = value; v = 1234.0; // FP_NORMAL
for (int i = 0; i < iters; ++i) {
d += isfinite(v);
}
StopBenchmarkTiming();
}
#if defined(__BIONIC__)
#define test_isfinite __isfinite
#else
#define test_isfinite __finite
#endif
BENCHMARK_WITH_ARG(BM_math_isfinite, double)->AT_COMMON_VALS;
void BM_math_isfinite::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) {
d += test_isfinite(v);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_math_isinf_macro, double)->AT_COMMON_VALS;
void BM_math_isinf_macro::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) {
d += isinf(v);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_math_isinf, double)->AT_COMMON_VALS;
void BM_math_isinf::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
d += (isinf)(v); d += (isinf)(v);
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_isinf_NORMAL);
BENCHMARK_WITH_ARG(BM_math_isnan_macro, double)->AT_COMMON_VALS; static void BM_math_isinf_NAN(int iters) {
void BM_math_isnan_macro::Run(int iters, double value) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 0.0; d = 0.0;
v = value; v = nan(""); // FP_NAN
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
d += isnan(v); d += (isinf)(v);
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_isinf_NAN);
BENCHMARK_WITH_ARG(BM_math_isnan, double)->AT_COMMON_VALS; static void BM_math_isinf_INFINITE(int iters) {
void BM_math_isnan::Run(int iters, double value) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 0.0; d = 0.0;
v = value; v = HUGE_VAL; // FP_INFINITE
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
d += (isnan)(v); d += (isinf)(v);
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_isinf_INFINITE);
BENCHMARK_WITH_ARG(BM_math_isnormal_macro, double)->AT_COMMON_VALS; static void BM_math_isinf_ZERO(int iters) {
void BM_math_isnormal_macro::Run(int iters, double value) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 0.0; d = 0.0;
v = value; v = 0.0; // FP_ZERO
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
d += isnormal(v); d += (isinf)(v);
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_isinf_ZERO);
#if defined(__BIONIC__) static void BM_math_sin_fast(int iters) {
BENCHMARK_WITH_ARG(BM_math_isnormal, double)->AT_COMMON_VALS;
void BM_math_isnormal::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) {
d += (__isnormal)(v);
}
StopBenchmarkTiming();
}
#endif
BENCHMARK_NO_ARG(BM_math_sin_fast);
void BM_math_sin_fast::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 1.0; d = 1.0;
@ -187,9 +124,9 @@ void BM_math_sin_fast::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_sin_fast);
BENCHMARK_NO_ARG(BM_math_sin_feupdateenv); static void BM_math_sin_feupdateenv(int iters) {
void BM_math_sin_feupdateenv::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 1.0; d = 1.0;
@ -203,9 +140,9 @@ void BM_math_sin_feupdateenv::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_sin_feupdateenv);
BENCHMARK_NO_ARG(BM_math_sin_fesetenv); static void BM_math_sin_fesetenv(int iters) {
void BM_math_sin_fesetenv::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 1.0; d = 1.0;
@ -219,68 +156,56 @@ void BM_math_sin_fesetenv::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_sin_fesetenv);
BENCHMARK_WITH_ARG(BM_math_fpclassify, double)->AT_COMMON_VALS; static void BM_math_fpclassify_NORMAL(int iters) {
void BM_math_fpclassify::Run(int iters, double value) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 0.0; d = 0.0;
v = value; v = 1234.0; // FP_NORMAL
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
d += fpclassify(v); d += fpclassify(v);
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_fpclassify_NORMAL);
BENCHMARK_WITH_ARG(BM_math_signbit_macro, double)->AT_COMMON_VALS; static void BM_math_fpclassify_NAN(int iters) {
void BM_math_signbit_macro::Run(int iters, double value) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 0.0; d = 0.0;
v = value; v = nan(""); // FP_NAN
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
d += signbit(v); d += fpclassify(v);
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_fpclassify_NAN);
BENCHMARK_WITH_ARG(BM_math_signbit, double)->AT_COMMON_VALS; static void BM_math_fpclassify_INFINITE(int iters) {
void BM_math_signbit::Run(int iters, double value) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 0.0; d = 0.0;
v = value; v = HUGE_VAL; // FP_INFINITE
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
d += (__signbit)(v); d += fpclassify(v);
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_fpclassify_INFINITE);
BENCHMARK_WITH_ARG(BM_math_fabs_macro, double)->AT_COMMON_VALS; static void BM_math_fpclassify_ZERO(int iters) {
void BM_math_fabs_macro::Run(int iters, double value) {
StartBenchmarkTiming(); StartBenchmarkTiming();
d = 0.0; d = 0.0;
v = value; v = 0.0; // FP_ZERO
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
d += fabs(v); d += fpclassify(v);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_math_fabs, double)->AT_COMMON_VALS;
void BM_math_fabs::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) {
d += (fabs)(v);
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_math_fpclassify_ZERO);

View File

@ -14,19 +14,17 @@
* limitations under the License. * limitations under the License.
*/ */
#include "benchmark.h"
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string>
#if defined(__BIONIC__)
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h> #include <sys/_system_properties.h>
#include <benchmark/Benchmark.h> #include <vector>
#include <string>
extern void *__system_property_area__; extern void *__system_property_area__;
@ -140,8 +138,8 @@ private:
void *old_pa; void *old_pa;
}; };
BENCHMARK_WITH_ARG(BM_property_get, int)->TEST_NUM_PROPS; static void BM_property_get(int iters, int nprops)
void BM_property_get::Run(int iters, int nprops) { {
StopBenchmarkTiming(); StopBenchmarkTiming();
LocalPropertyTestState pa(nprops); LocalPropertyTestState pa(nprops);
@ -159,9 +157,10 @@ void BM_property_get::Run(int iters, int nprops) {
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_property_get)->TEST_NUM_PROPS;
BENCHMARK_WITH_ARG(BM_property_find, int)->TEST_NUM_PROPS; static void BM_property_find(int iters, int nprops)
void BM_property_find::Run(int iters, int nprops) { {
StopBenchmarkTiming(); StopBenchmarkTiming();
LocalPropertyTestState pa(nprops); LocalPropertyTestState pa(nprops);
@ -178,9 +177,10 @@ void BM_property_find::Run(int iters, int nprops) {
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_property_find)->TEST_NUM_PROPS;
BENCHMARK_WITH_ARG(BM_property_read, int)->TEST_NUM_PROPS; static void BM_property_read(int iters, int nprops)
void BM_property_read::Run(int iters, int nprops) { {
StopBenchmarkTiming(); StopBenchmarkTiming();
LocalPropertyTestState pa(nprops); LocalPropertyTestState pa(nprops);
@ -204,9 +204,10 @@ void BM_property_read::Run(int iters, int nprops) {
delete[] pinfo; delete[] pinfo;
} }
BENCHMARK(BM_property_read)->TEST_NUM_PROPS;
BENCHMARK_WITH_ARG(BM_property_serial, int)->TEST_NUM_PROPS; static void BM_property_serial(int iters, int nprops)
void BM_property_serial::Run(int iters, int nprops) { {
StopBenchmarkTiming(); StopBenchmarkTiming();
LocalPropertyTestState pa(nprops); LocalPropertyTestState pa(nprops);
@ -229,5 +230,4 @@ void BM_property_serial::Run(int iters, int nprops) {
delete[] pinfo; delete[] pinfo;
} }
BENCHMARK(BM_property_serial)->TEST_NUM_PROPS;
#endif // __BIONIC__

View File

@ -14,15 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
#include <pthread.h> #include "benchmark.h"
#include <benchmark/Benchmark.h> #include <pthread.h>
// Stop GCC optimizing out our pure function. // Stop GCC optimizing out our pure function.
/* Must not be static! */ pthread_t (*pthread_self_fp)() = pthread_self; /* Must not be static! */ pthread_t (*pthread_self_fp)() = pthread_self;
BENCHMARK_NO_ARG(BM_pthread_self); static void BM_pthread_self(int iters) {
void BM_pthread_self::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
@ -31,9 +30,9 @@ void BM_pthread_self::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_pthread_self);
BENCHMARK_NO_ARG(BM_pthread_getspecific); static void BM_pthread_getspecific(int iters) {
void BM_pthread_getspecific::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
pthread_key_t key; pthread_key_t key;
pthread_key_create(&key, NULL); pthread_key_create(&key, NULL);
@ -46,27 +45,12 @@ void BM_pthread_getspecific::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
pthread_key_delete(key); pthread_key_delete(key);
} }
BENCHMARK(BM_pthread_getspecific);
BENCHMARK_NO_ARG(BM_pthread_setspecific);
void BM_pthread_setspecific::Run(int iters) {
StopBenchmarkTiming();
pthread_key_t key;
pthread_key_create(&key, NULL);
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
pthread_setspecific(key, NULL);
}
StopBenchmarkTiming();
pthread_key_delete(key);
}
static void DummyPthreadOnceInitFunction() { static void DummyPthreadOnceInitFunction() {
} }
BENCHMARK_NO_ARG(BM_pthread_once); static void BM_pthread_once(int iters) {
void BM_pthread_once::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
pthread_once_t once = PTHREAD_ONCE_INIT; pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_once(&once, DummyPthreadOnceInitFunction); pthread_once(&once, DummyPthreadOnceInitFunction);
@ -78,9 +62,9 @@ void BM_pthread_once::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_pthread_once);
BENCHMARK_NO_ARG(BM_pthread_mutex_lock); static void BM_pthread_mutex_lock(int iters) {
void BM_pthread_mutex_lock::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
StartBenchmarkTiming(); StartBenchmarkTiming();
@ -92,11 +76,11 @@ void BM_pthread_mutex_lock::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_pthread_mutex_lock);
BENCHMARK_NO_ARG(BM_pthread_mutex_lock_ERRORCHECK); static void BM_pthread_mutex_lock_ERRORCHECK(int iters) {
void BM_pthread_mutex_lock_ERRORCHECK::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER;
StartBenchmarkTiming(); StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
@ -106,11 +90,11 @@ void BM_pthread_mutex_lock_ERRORCHECK::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_pthread_mutex_lock_ERRORCHECK);
BENCHMARK_NO_ARG(BM_pthread_mutex_lock_RECURSIVE); static void BM_pthread_mutex_lock_RECURSIVE(int iters) {
void BM_pthread_mutex_lock_RECURSIVE::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
StartBenchmarkTiming(); StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
@ -120,114 +104,4 @@ void BM_pthread_mutex_lock_RECURSIVE::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_pthread_mutex_lock_RECURSIVE);
BENCHMARK_NO_ARG(BM_pthread_rwlock_read);
void BM_pthread_rwlock_read::Run(int iters) {
StopBenchmarkTiming();
pthread_rwlock_t lock;
pthread_rwlock_init(&lock, NULL);
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
pthread_rwlock_rdlock(&lock);
pthread_rwlock_unlock(&lock);
}
StopBenchmarkTiming();
pthread_rwlock_destroy(&lock);
}
BENCHMARK_NO_ARG(BM_pthread_rwlock_write);
void BM_pthread_rwlock_write::Run(int iters) {
StopBenchmarkTiming();
pthread_rwlock_t lock;
pthread_rwlock_init(&lock, NULL);
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
pthread_rwlock_wrlock(&lock);
pthread_rwlock_unlock(&lock);
}
StopBenchmarkTiming();
pthread_rwlock_destroy(&lock);
}
static void* IdleThread(void*) {
return NULL;
}
BENCHMARK_NO_ARG(BM_pthread_create);
void BM_pthread_create::Run(int iters) {
StopBenchmarkTiming();
pthread_t thread;
for (int i = 0; i < iters; ++i) {
StartBenchmarkTiming();
pthread_create(&thread, NULL, IdleThread, NULL);
StopBenchmarkTiming();
pthread_join(thread, NULL);
}
}
static void* RunThread(void* arg) {
::testing::Benchmark* benchmark = reinterpret_cast<::testing::Benchmark*>(arg);
benchmark->StopBenchmarkTiming();
return NULL;
}
BENCHMARK_NO_ARG(BM_pthread_create_and_run);
void BM_pthread_create_and_run::Run(int iters) {
StopBenchmarkTiming();
pthread_t thread;
for (int i = 0; i < iters; ++i) {
StartBenchmarkTiming();
pthread_create(&thread, NULL, RunThread, this);
pthread_join(thread, NULL);
}
}
static void* ExitThread(void* arg) {
::testing::Benchmark* benchmark = reinterpret_cast<::testing::Benchmark*>(arg);
benchmark->StartBenchmarkTiming();
pthread_exit(NULL);
}
BENCHMARK_NO_ARG(BM_pthread_exit_and_join);
void BM_pthread_exit_and_join::Run(int iters) {
StopBenchmarkTiming();
pthread_t thread;
for (int i = 0; i < iters; ++i) {
pthread_create(&thread, NULL, ExitThread, this);
pthread_join(thread, NULL);
StopBenchmarkTiming();
}
}
BENCHMARK_NO_ARG(BM_pthread_key_create);
void BM_pthread_key_create::Run(int iters) {
StopBenchmarkTiming();
pthread_key_t key;
for (int i = 0; i < iters; ++i) {
StartBenchmarkTiming();
pthread_key_create(&key, NULL);
StopBenchmarkTiming();
pthread_key_delete(key);
}
}
BENCHMARK_NO_ARG(BM_pthread_key_delete);
void BM_pthread_key_delete::Run(int iters) {
StopBenchmarkTiming();
pthread_key_t key;
for (int i = 0; i < iters; ++i) {
pthread_key_create(&key, NULL);
StartBenchmarkTiming();
pthread_key_delete(key);
StopBenchmarkTiming();
}
}

View File

@ -14,15 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
#include <pthread.h> #include "benchmark.h"
#include <semaphore.h> #include <semaphore.h>
#include <stdatomic.h>
#include <stdio.h>
#include <benchmark/Benchmark.h> static void BM_semaphore_sem_getvalue(int iters) {
BENCHMARK_NO_ARG(BM_semaphore_sem_getvalue);
void BM_semaphore_sem_getvalue::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
sem_t semaphore; sem_t semaphore;
sem_init(&semaphore, 1, 1); sem_init(&semaphore, 1, 1);
@ -35,9 +31,9 @@ void BM_semaphore_sem_getvalue::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_semaphore_sem_getvalue);
BENCHMARK_NO_ARG(BM_semaphore_sem_wait_sem_post); static void BM_semaphore_sem_wait_sem_post(int iters) {
void BM_semaphore_sem_wait_sem_post::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
sem_t semaphore; sem_t semaphore;
sem_init(&semaphore, 1, 1); sem_init(&semaphore, 1, 1);
@ -50,94 +46,4 @@ void BM_semaphore_sem_wait_sem_post::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_semaphore_sem_wait_sem_post);
/*
* This test reports the overhead of the underlying futex wake syscall on
* the producer. It does not report the overhead from issuing the wake to the
* point where the posted consumer thread wakes up. It suffers from
* clock_gettime syscall overhead. Lock the CPU speed for consistent results
* as we may not reach >50% cpu utilization.
*
* We will run a background thread that catches the sem_post wakeup and
* loops immediately returning back to sleep in sem_wait for the next one. This
* thread is run with policy SCHED_OTHER (normal policy), a middle policy.
*
* The primary thread will run at SCHED_IDLE (lowest priority policy) when
* monitoring the background thread to detect when it hits sem_wait sleep. It
* will do so with no clock running. Once we are ready, we will switch to
* SCHED_FIFO (highest priority policy) to time the act of running sem_post
* with the benchmark clock running. This ensures nothing else in the system
* can preempt our timed activity, including the background thread. We are
* also protected with the scheduling policy of letting a process hit a
* resource limit rather than get hit with a context switch.
*
* The background thread will start executing either on another CPU, or
* after we back down from SCHED_FIFO, but certainly not in the context of
* the timing of the sem_post.
*/
static atomic_int BM_semaphore_sem_post_running;
static void *BM_semaphore_sem_post_start_thread(void *obj) {
sem_t *semaphore = reinterpret_cast<sem_t *>(obj);
while ((BM_semaphore_sem_post_running > 0) && !sem_wait(semaphore)) {
;
}
BM_semaphore_sem_post_running = -1;
return NULL;
}
BENCHMARK_NO_ARG(BM_semaphore_sem_post);
void BM_semaphore_sem_post::Run(int iters) {
StopBenchmarkTiming();
sem_t semaphore;
sem_init(&semaphore, 0, 0);
pthread_attr_t attr;
pthread_attr_init(&attr);
BM_semaphore_sem_post_running = 1;
struct sched_param param = { 0, };
pthread_attr_setschedparam(&attr, &param);
pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_t pthread;
pthread_create(&pthread, &attr, BM_semaphore_sem_post_start_thread, &semaphore);
pthread_attr_destroy(&attr);
sched_setscheduler((pid_t)0, SCHED_IDLE, &param);
for (int i = 0; i < iters; ++i) {
int trys = 3, dummy = 0;
do {
if (BM_semaphore_sem_post_running < 0) {
sched_setscheduler((pid_t)0, SCHED_OTHER, &param);
fprintf(stderr, "BM_semaphore_sem_post: start_thread died unexpectedly\n");
return;
}
sched_yield();
sem_getvalue(&semaphore, &dummy);
if (dummy < 0) { // POSIX.1-2001 possibility 1
break;
}
if (dummy == 0) { // POSIX.1-2001 possibility 2
--trys;
}
} while (trys);
param.sched_priority = 1;
sched_setscheduler((pid_t)0, SCHED_FIFO, &param);
StartBenchmarkTiming();
sem_post(&semaphore);
StopBenchmarkTiming(); // Remember to subtract clock syscall overhead
param.sched_priority = 0;
sched_setscheduler((pid_t)0, SCHED_IDLE, &param);
}
sched_setscheduler((pid_t)0, SCHED_OTHER, &param);
if (BM_semaphore_sem_post_running > 0) {
BM_semaphore_sem_post_running = 0;
}
do {
sem_post(&semaphore);
sched_yield();
} while (!BM_semaphore_sem_post_running);
}

View File

@ -14,11 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
#include <stdio.h> #include "benchmark.h"
#include <stdio_ext.h>
#include <stdlib.h>
#include <benchmark/Benchmark.h> #include <stdio.h>
#define KB 1024 #define KB 1024
#define MB 1024*KB #define MB 1024*KB
@ -27,68 +25,37 @@
Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(8)->Arg(16)->Arg(32)->Arg(64)->Arg(512)-> \ Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(8)->Arg(16)->Arg(32)->Arg(64)->Arg(512)-> \
Arg(1*KB)->Arg(4*KB)->Arg(8*KB)->Arg(16*KB)->Arg(64*KB) Arg(1*KB)->Arg(4*KB)->Arg(8*KB)->Arg(16*KB)->Arg(64*KB)
template <typename Fn> static void BM_stdio_fread(int iters, int chunk_size) {
void ReadWriteTest(::testing::Benchmark* benchmark, int iters, int chunk_size, Fn f, bool buffered) { StopBenchmarkTiming();
benchmark->StopBenchmarkTiming();
FILE* fp = fopen("/dev/zero", "rw"); FILE* fp = fopen("/dev/zero", "rw");
__fsetlocking(fp, FSETLOCKING_BYCALLER);
char* buf = new char[chunk_size]; char* buf = new char[chunk_size];
benchmark->StartBenchmarkTiming(); StartBenchmarkTiming();
if (!buffered) {
setvbuf(fp, 0, _IONBF, 0);
}
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
f(buf, chunk_size, 1, fp); fread(buf, chunk_size, 1, fp);
} }
benchmark->StopBenchmarkTiming(); StopBenchmarkTiming();
benchmark->SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(chunk_size)); SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(chunk_size));
delete[] buf; delete[] buf;
fclose(fp); fclose(fp);
} }
BENCHMARK(BM_stdio_fread)->AT_COMMON_SIZES;
BENCHMARK_WITH_ARG(BM_stdio_fread, int)->AT_COMMON_SIZES;
void BM_stdio_fread::Run(int iters, int chunk_size) {
ReadWriteTest(this, iters, chunk_size, fread, true);
}
BENCHMARK_WITH_ARG(BM_stdio_fwrite, int)->AT_COMMON_SIZES; static void BM_stdio_fwrite(int iters, int chunk_size) {
void BM_stdio_fwrite::Run(int iters, int chunk_size) { StopBenchmarkTiming();
ReadWriteTest(this, iters, chunk_size, fwrite, true); FILE* fp = fopen("/dev/zero", "rw");
} char* buf = new char[chunk_size];
StartBenchmarkTiming();
BENCHMARK_WITH_ARG(BM_stdio_fread_unbuffered, int)->AT_COMMON_SIZES;
void BM_stdio_fread_unbuffered::Run(int iters, int chunk_size) {
ReadWriteTest(this, iters, chunk_size, fread, false);
}
BENCHMARK_WITH_ARG(BM_stdio_fwrite_unbuffered, int)->AT_COMMON_SIZES;
void BM_stdio_fwrite_unbuffered::Run(int iters, int chunk_size) {
ReadWriteTest(this, iters, chunk_size, fwrite, false);
}
static void FopenFgetsFclose(int iters, bool no_locking) {
char buf[1024];
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
FILE* fp = fopen("/proc/version", "re"); fwrite(buf, chunk_size, 1, fp);
if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER); }
if (fgets(buf, sizeof(buf), fp) == nullptr) abort();
StopBenchmarkTiming();
SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(chunk_size));
delete[] buf;
fclose(fp); fclose(fp);
} }
} BENCHMARK(BM_stdio_fwrite)->AT_COMMON_SIZES;
BENCHMARK_NO_ARG(BM_stdio_fopen_fgets_fclose_locking);
void BM_stdio_fopen_fgets_fclose_locking::Run(int iters) {
StartBenchmarkTiming();
FopenFgetsFclose(iters, false);
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_stdio_fopen_fgets_fclose_no_locking);
void BM_stdio_fopen_fgets_fclose_no_locking::Run(int iters) {
StartBenchmarkTiming();
FopenFgetsFclose(iters, true);
StopBenchmarkTiming();
}

View File

@ -14,10 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
#include <stdint.h> #include "benchmark.h"
#include <string.h>
#include <benchmark/Benchmark.h> #include <string.h>
#define KB 1024 #define KB 1024
#define MB 1024*KB #define MB 1024*KB
@ -27,8 +26,7 @@
// TODO: test unaligned operation too? (currently everything will be 8-byte aligned by malloc.) // TODO: test unaligned operation too? (currently everything will be 8-byte aligned by malloc.)
BENCHMARK_WITH_ARG(BM_string_memcmp, int)->AT_COMMON_SIZES; static void BM_string_memcmp(int iters, int nbytes) {
void BM_string_memcmp::Run(int iters, int nbytes) {
StopBenchmarkTiming(); StopBenchmarkTiming();
char* src = new char[nbytes]; char* dst = new char[nbytes]; char* src = new char[nbytes]; char* dst = new char[nbytes];
memset(src, 'x', nbytes); memset(src, 'x', nbytes);
@ -41,13 +39,13 @@ void BM_string_memcmp::Run(int iters, int nbytes) {
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes)); SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
delete[] src; delete[] src;
delete[] dst; delete[] dst;
} }
BENCHMARK(BM_string_memcmp)->AT_COMMON_SIZES;
BENCHMARK_WITH_ARG(BM_string_memcpy, int)->AT_COMMON_SIZES; static void BM_string_memcpy(int iters, int nbytes) {
void BM_string_memcpy::Run(int iters, int nbytes) {
StopBenchmarkTiming(); StopBenchmarkTiming();
char* src = new char[nbytes]; char* dst = new char[nbytes]; char* src = new char[nbytes]; char* dst = new char[nbytes];
memset(src, 'x', nbytes); memset(src, 'x', nbytes);
@ -58,13 +56,13 @@ void BM_string_memcpy::Run(int iters, int nbytes) {
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes)); SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
delete[] src; delete[] src;
delete[] dst; delete[] dst;
} }
BENCHMARK(BM_string_memcpy)->AT_COMMON_SIZES;
BENCHMARK_WITH_ARG(BM_string_memmove, int)->AT_COMMON_SIZES; static void BM_string_memmove(int iters, int nbytes) {
void BM_string_memmove::Run(int iters, int nbytes) {
StopBenchmarkTiming(); StopBenchmarkTiming();
char* buf = new char[nbytes + 64]; char* buf = new char[nbytes + 64];
memset(buf, 'x', nbytes + 64); memset(buf, 'x', nbytes + 64);
@ -75,12 +73,12 @@ void BM_string_memmove::Run(int iters, int nbytes) {
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes)); SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
delete[] buf; delete[] buf;
} }
BENCHMARK(BM_string_memmove)->AT_COMMON_SIZES;
BENCHMARK_WITH_ARG(BM_string_memset, int)->AT_COMMON_SIZES; static void BM_string_memset(int iters, int nbytes) {
void BM_string_memset::Run(int iters, int nbytes) {
StopBenchmarkTiming(); StopBenchmarkTiming();
char* dst = new char[nbytes]; char* dst = new char[nbytes];
StartBenchmarkTiming(); StartBenchmarkTiming();
@ -90,12 +88,12 @@ void BM_string_memset::Run(int iters, int nbytes) {
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes)); SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
delete[] dst; delete[] dst;
} }
BENCHMARK(BM_string_memset)->AT_COMMON_SIZES;
BENCHMARK_WITH_ARG(BM_string_strlen, int)->AT_COMMON_SIZES; static void BM_string_strlen(int iters, int nbytes) {
void BM_string_strlen::Run(int iters, int nbytes) {
StopBenchmarkTiming(); StopBenchmarkTiming();
char* s = new char[nbytes]; char* s = new char[nbytes];
memset(s, 'x', nbytes); memset(s, 'x', nbytes);
@ -108,6 +106,7 @@ void BM_string_strlen::Run(int iters, int nbytes) {
} }
StopBenchmarkTiming(); StopBenchmarkTiming();
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes)); SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
delete[] s; delete[] s;
} }
BENCHMARK(BM_string_strlen)->AT_COMMON_SIZES;

View File

@ -14,15 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
#include "benchmark.h"
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/time.h>
#include <time.h> #include <time.h>
#include <unistd.h>
#include <benchmark/Benchmark.h> static void BM_time_clock_gettime(int iters) {
BENCHMARK_NO_ARG(BM_time_clock_gettime);
void BM_time_clock_gettime::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
timespec t; timespec t;
@ -32,9 +29,9 @@ void BM_time_clock_gettime::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_time_clock_gettime);
BENCHMARK_NO_ARG(BM_time_clock_gettime_syscall); static void BM_time_clock_gettime_syscall(int iters) {
void BM_time_clock_gettime_syscall::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
timespec t; timespec t;
@ -44,9 +41,9 @@ void BM_time_clock_gettime_syscall::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_time_clock_gettime_syscall);
BENCHMARK_NO_ARG(BM_time_gettimeofday); static void BM_time_gettimeofday(int iters) {
void BM_time_gettimeofday::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
timeval tv; timeval tv;
@ -56,9 +53,9 @@ void BM_time_gettimeofday::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_time_gettimeofday);
BENCHMARK_NO_ARG(BM_time_gettimeofday_syscall); static void BM_time_gettimeofday_syscall(int iters) {
void BM_time_gettimeofday_syscall::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
timeval tv; timeval tv;
@ -68,9 +65,9 @@ void BM_time_gettimeofday_syscall::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_time_gettimeofday_syscall);
BENCHMARK_NO_ARG(BM_time_time); static void BM_time_time(int iters) {
void BM_time_time::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
@ -79,3 +76,4 @@ void BM_time_time::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_time_time);

View File

@ -14,13 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
#include "benchmark.h"
#include <sys/syscall.h> #include <sys/syscall.h>
#include <unistd.h> #include <unistd.h>
#include <benchmark/Benchmark.h> static void BM_unistd_getpid(int iters) {
BENCHMARK_NO_ARG(BM_unistd_getpid);
void BM_unistd_getpid::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
@ -29,9 +28,9 @@ void BM_unistd_getpid::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_unistd_getpid);
BENCHMARK_NO_ARG(BM_unistd_getpid_syscall); static void BM_unistd_getpid_syscall(int iters) {
void BM_unistd_getpid_syscall::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
@ -40,14 +39,12 @@ void BM_unistd_getpid_syscall::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_unistd_getpid_syscall);
#if defined(__BIONIC__)
// Stop GCC optimizing out our pure function. // Stop GCC optimizing out our pure function.
/* Must not be static! */ pid_t (*gettid_fp)() = gettid; /* Must not be static! */ pid_t (*gettid_fp)() = gettid;
BENCHMARK_NO_ARG(BM_unistd_gettid); static void BM_unistd_gettid(int iters) {
void BM_unistd_gettid::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
@ -56,11 +53,9 @@ void BM_unistd_gettid::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_unistd_gettid);
#endif static void BM_unistd_gettid_syscall(int iters) {
BENCHMARK_NO_ARG(BM_unistd_gettid_syscall);
void BM_unistd_gettid_syscall::Run(int iters) {
StartBenchmarkTiming(); StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) { for (int i = 0; i < iters; ++i) {
@ -69,3 +64,4 @@ void BM_unistd_gettid_syscall::Run(int iters) {
StopBenchmarkTiming(); StopBenchmarkTiming();
} }
BENCHMARK(BM_unistd_gettid_syscall);

View File

@ -1,80 +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 "utils.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string>
#include <android-base/stringprintf.h>
int Round(int n) {
int base = 1;
while (base*10 < n) {
base *= 10;
}
if (n < 2*base) {
return 2*base;
}
if (n < 5*base) {
return 5*base;
}
return 10*base;
}
// Similar to the code in art, but supporting both binary and decimal prefixes.
std::string PrettyInt(long value, size_t base) {
if (base != 2 && base != 10) abort();
uint64_t count = static_cast<uint64_t>(value);
bool negative_number = false;
if (value < 0) {
negative_number = true;
count = static_cast<uint64_t>(-value);
}
// The byte thresholds at which we display amounts. A count is displayed
// in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1].
static const uint64_t kUnitThresholds2[] = {
1024*1024*1024 /* Gi */, 2*1024*1024 /* Mi */, 3*1024 /* Ki */, 0,
};
static const uint64_t kUnitThresholds10[] = {
1000*1000*1000 /* G */, 2*1000*1000 /* M */, 3*1000 /* k */, 0,
};
static const uint64_t kAmountPerUnit2[] = { 1024*1024*1024, 1024*1024, 1024, 1 };
static const uint64_t kAmountPerUnit10[] = { 1000*1000*1000, 1000*1000, 1000, 1 };
static const char* const kUnitStrings2[] = { "Gi", "Mi", "Ki", "" };
static const char* const kUnitStrings10[] = { "G", "M", "k", "" };
// Which set are we using?
const uint64_t* kUnitThresholds = ((base == 2) ? kUnitThresholds2 : kUnitThresholds10);
const uint64_t* kAmountPerUnit = ((base == 2) ? kAmountPerUnit2 : kAmountPerUnit10);
const char* const* kUnitStrings = ((base == 2) ? kUnitStrings2 : kUnitStrings10);
size_t i = 0;
for (; kUnitThresholds[i] != 0; ++i) {
if (count >= kUnitThresholds[i]) {
break;
}
}
return android::base::StringPrintf("%s%" PRId64 "%s",
negative_number ? "-" : "",
count / kAmountPerUnit[i], kUnitStrings[i]);
}

View File

@ -1,44 +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 once
ifneq ($(bionic_run_on_host_mk_included),true)
bionic_run_on_host_mk_included:=true
ifneq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),arm mips x86))
LINKER = linker64
else
LINKER = linker
endif
ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64))
# gtest needs ANDROID_DATA/local/tmp for death test output.
# Make sure to create ANDROID_DATA/local/tmp if doesn't exist.
# bionic itself should always work relative to ANDROID_DATA or ANDROID_ROOT.
bionic-prepare-run-on-host: $(TARGET_OUT_EXECUTABLES)/$(LINKER) $(TARGET_OUT)/etc/hosts $(TARGET_OUT_EXECUTABLES)/sh
if [ ! -d /system ]; then \
echo "Attempting to create /system"; \
sudo mkdir -p -m 0777 /system; \
fi
mkdir -p $(TARGET_OUT_DATA)/local/tmp
ln -fs `realpath $(TARGET_OUT)/bin` /system/
ln -fs `realpath $(TARGET_OUT)/etc` /system/
ln -fs `realpath $(TARGET_OUT)/lib` /system/
if [ -d "$(TARGET_OUT)/lib64" ]; then \
ln -fs `realpath $(TARGET_OUT)/lib64` /system/; \
fi
endif
endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -307,6 +307,50 @@ SUCH DAMAGE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (C) 2008-2010 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) 2009 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.
-------------------------------------------------------------------
Copyright (C) 2009 The Android Open Source Project Copyright (C) 2009 The Android Open Source Project
All rights reserved. All rights reserved.
@ -410,6 +454,22 @@ Android adaptation and tweak by Jim Huang <jserv@0xlab.org>.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (C) 2011 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.
-------------------------------------------------------------------
Copyright (C) 2011 The Android Open Source Project Copyright (C) 2011 The Android Open Source Project
All rights reserved. All rights reserved.
@ -628,50 +688,6 @@ SUCH DAMAGE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (C) 2015 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.
-------------------------------------------------------------------
Copyright (C) 2015 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) 1980, 1983, 1988, 1993 Copyright (c) 1980, 1983, 1988, 1993
The Regents of the University of California. All rights reserved. The Regents of the University of California. All rights reserved.
@ -1663,6 +1679,35 @@ SUCH DAMAGE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 1990 Regents of the University of California.
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. Neither the name of the University 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 REGENTS 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 REGENTS 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) 1990 The Regents of the University of California. Copyright (c) 1990 The Regents of the University of California.
All rights reserved. All rights reserved.
@ -2494,6 +2539,62 @@ SUCH DAMAGE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 1993
The Regents of the University of California. 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. Neither the name of the University 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 REGENTS 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 REGENTS 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) 1993 Christopher G. Demetriou
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 author may not be used to endorse or promote products
derived from this software without specific prior written permission
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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) 1993 Martin Birgmeier Copyright (c) 1993 Martin Birgmeier
All rights reserved. All rights reserved.
@ -2534,6 +2635,33 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 1995, 1996 Carnegie-Mellon University.
All rights reserved.
Author: Chris G. Demetriou
Permission to use, copy, modify and distribute this software and
its documentation is hereby granted, provided that both the copyright
notice and this permission notice appear in all copies of the
software, derivative works or modified versions, and any portions
thereof, and that both notices appear in supporting documentation.
CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
Carnegie Mellon requests users of this software to return to
Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
School of Computer Science
Carnegie Mellon University
Pittsburgh PA 15213-3890
any improvements or extensions that they make and grant Carnegie the
rights to redistribute these changes.
-------------------------------------------------------------------
Copyright (c) 1996 by Internet Software Consortium. Copyright (c) 1996 by Internet Software Consortium.
Permission to use, copy, modify, and distribute this software for any Permission to use, copy, modify, and distribute this software for any
@ -2586,6 +2714,63 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 1996-2004 Per Fogelstrom, Opsycon AB
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.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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) 1997 Mark Brinicombe
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. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by Mark Brinicombe
4. Neither the name of the University 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 AUTHOR 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 AUTHOR 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) 1997 Mark Brinicombe Copyright (c) 1997 Mark Brinicombe
Copyright (c) 2010 Android Open Source Project. Copyright (c) 2010 Android Open Source Project.
All rights reserved. All rights reserved.
@ -2946,6 +3131,38 @@ SUCH DAMAGE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 1999 Kungliga Tekniska Högskolan
(Royal Institute of Technology, Stockholm, Sweden).
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. Neither the name of KTH 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 KTH AND ITS 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 KTH OR ITS 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
-------------------------------------------------------------------
Copyright (c) 2000 Ben Harris. Copyright (c) 2000 Ben Harris.
Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
All rights reserved. All rights reserved.
@ -3209,6 +3426,34 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 2002 Opsycon AB (www.opsycon.se / www.opsycon.com)
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. Neither the name of Opsycon AB 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 AUTHOR ``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 AUTHOR 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) 2002 The NetBSD Foundation, Inc. Copyright (c) 2002 The NetBSD Foundation, Inc.
All rights reserved. All rights reserved.
@ -3752,22 +3997,6 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-------------------------------------------------------------------
Copyright (c) 2007-2008 Michael G Schwern Copyright (c) 2007-2008 Michael G Schwern
This software originally derived from Paul Sheer's pivotal_gmtime_r.c. This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
@ -3857,22 +4086,6 @@ SUCH DAMAGE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-------------------------------------------------------------------
Copyright (c) 2008 Todd C. Miller <millert@openbsd.org> Copyright (c) 2008 Todd C. Miller <millert@openbsd.org>
Permission to use, copy, modify, and distribute this software for any Permission to use, copy, modify, and distribute this software for any
@ -3905,6 +4118,35 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 2009
MIPS Technologies, Inc., California.
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. Neither the name of the MIPS Technologies, Inc., 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 MIPS TECHNOLOGIES, INC. ``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 MIPS TECHNOLOGIES, INC. 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) 2009 David Schultz <das@FreeBSD.org> Copyright (c) 2009 David Schultz <das@FreeBSD.org>
All rights reserved. All rights reserved.
@ -4180,39 +4422,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-------------------------------------------------------------------
Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
Copyright (c) 2009 Ted Unangst
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-------------------------------------------------------------------
Copyright (c) 2011 The Android Open Source Project Copyright (c) 2011 The Android Open Source Project
Copyright (c) 2008 ARM Ltd Copyright (c) 2008 ARM Ltd
All rights reserved. All rights reserved.
@ -4386,64 +4595,6 @@ Copyright (c) 2012, Linaro Limited
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 2012-2015
MIPS Technologies, Inc., California.
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. Neither the name of the MIPS Technologies, Inc., 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 MIPS TECHNOLOGIES, INC. ``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 MIPS TECHNOLOGIES, INC. 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
MIPS Technologies, Inc., California.
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. Neither the name of the MIPS Technologies, Inc., 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 MIPS TECHNOLOGIES, INC. ``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 MIPS TECHNOLOGIES, INC. 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 Copyright (c) 2013 ARM Ltd
All rights reserved. All rights reserved.
@ -4488,61 +4639,35 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright (c) 2013 The NetBSD Foundation, Inc. Copyright (c) 2013, Linaro Limited
All rights reserved. All rights reserved.
This code is derived from software contributed to The NetBSD Foundation
by Christos Zoulas.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
are met: are met:
1. Redistributions of source code must retain the above copyright
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * Neither the name of Linaro Limited nor the names of its
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED contributors may be used to endorse or promote products derived
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR from this software without specific prior written permission.
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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.
------------------------------------------------------------------- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Copyright (c) 2014 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Imagination Technologies Limited. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Redistribution and use in source and binary forms, with or without SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
modification, are permitted provided that the following conditions LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
are met: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1. Redistributions of source code must retain the above copyright THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
notice, this list of conditions and the following disclaimer. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2. Redistributions in binary form must reproduce the above copyright OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the MIPS Technologies, Inc., 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 IMAGINATION TECHNOLOGIES LIMITED ``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 IMAGINATION TECHNOLOGIES LIMITED 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.
------------------------------------------------------------------- -------------------------------------------------------------------
@ -4728,20 +4853,9 @@ SUCH DAMAGE.
------------------------------------------------------------------- -------------------------------------------------------------------
Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> Copyright 2000 David E. O'Brien, John D. Polstra.
Copyright 2008 Damien Miller <djm@openbsd.org>
All rights reserved. All rights reserved.
Theo de Raadt <deraadt@openbsd.org> came up with the idea of using
such a mathematical system to generate more random (yet non-repeating)
ids to solve the resolver/named problem. But Niels designed the
actual system based on the constraints.
Later modified by Damien Miller to wrap the LCG output in a 15-bit
permutation generator based on a Luby-Rackoff block cipher. This
ensures the output is non-repeating and preserves the MSB twiddle
trick, but makes it more resistant to LCG prediction.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
are met: are met:

View File

@ -77,6 +77,7 @@ int prlimit64(pid_t, int, struct rlimit64*, const struct rlimit64*) arm,mips,x8
int setgroups:setgroups32(int, const gid_t*) arm,x86 int setgroups:setgroups32(int, const gid_t*) arm,x86
int setgroups:setgroups(int, const gid_t*) arm64,mips,mips64,x86_64 int setgroups:setgroups(int, const gid_t*) arm64,mips,mips64,x86_64
int setpgid(pid_t, pid_t) all int setpgid(pid_t, pid_t) all
pid_t vfork(void) arm
int setregid:setregid32(gid_t, gid_t) arm,x86 int setregid:setregid32(gid_t, gid_t) arm,x86
int setregid:setregid(gid_t, gid_t) arm64,mips,mips64,x86_64 int setregid:setregid(gid_t, gid_t) arm64,mips,mips64,x86_64
int chroot(const char*) all int chroot(const char*) all
@ -94,23 +95,13 @@ ssize_t pread64(int, void*, size_t, off64_t) arm,mips,x86
ssize_t pread64|pread(int, void*, size_t, off_t) arm64,mips64,x86_64 ssize_t pread64|pread(int, void*, size_t, off_t) arm64,mips64,x86_64
ssize_t pwrite64(int, void*, size_t, off64_t) arm,mips,x86 ssize_t pwrite64(int, void*, size_t, off64_t) arm,mips,x86
ssize_t pwrite64|pwrite(int, void*, size_t, off_t) arm64,mips64,x86_64 ssize_t pwrite64|pwrite(int, void*, size_t, off_t) arm64,mips64,x86_64
int close(int) all
# On LP32, preadv/pwritev don't use off64_t --- they use pairs of 32-bit
# arguments to avoid problems on architectures like ARM where 64-bit arguments
# must be in a register pair starting with an even-numbered register.
# See linux/fs/read_write.c and https://lwn.net/Articles/311630/.
ssize_t __preadv64:preadv(int, const struct iovec*, int, long, long) arm,mips,x86
ssize_t preadv|preadv64(int, const struct iovec*, int, off_t) arm64,mips64,x86_64
ssize_t __pwritev64:pwritev(int, const struct iovec*, int, long, long) arm,mips,x86
ssize_t pwritev|pwritev64(int, const struct iovec*, int, off_t) arm64,mips64,x86_64
int ___close:close(int) all
pid_t __getpid:getpid() all pid_t __getpid:getpid() all
int munmap(void*, size_t) all int munmap(void*, size_t) all
void* ___mremap:mremap(void*, size_t, size_t, int, void*) all void* mremap(void*, size_t, size_t, unsigned long) all
int msync(const void*, size_t, int) all int msync(const void*, size_t, int) all
int mprotect(const void*, size_t, int) all int mprotect(const void*, size_t, int) all
int madvise(void*, size_t, int) all int madvise(const void*, size_t, int) all
int mlock(const void* addr, size_t len) all int mlock(const void* addr, size_t len) all
int munlock(const void* addr, size_t len) all int munlock(const void* addr, size_t len) all
int mlockall(int flags) all int mlockall(int flags) all
@ -122,7 +113,7 @@ int writev(int, const struct iovec*, int) all
int __fcntl64:fcntl64(int, int, void*) arm,mips,x86 int __fcntl64:fcntl64(int, int, void*) arm,mips,x86
int fcntl(int, int, void*) arm64,mips64,x86_64 int fcntl(int, int, void*) arm64,mips64,x86_64
int flock(int, int) all int flock(int, int) all
int ___fchmod:fchmod(int, mode_t) all int fchmod(int, mode_t) all
int dup(int) all int dup(int) all
int pipe2(int*, int) all int pipe2(int*, int) all
int dup3(int, int, int) all int dup3(int, int, int) all
@ -131,19 +122,19 @@ int fdatasync(int) all
int fchown:fchown32(int, uid_t, gid_t) arm,x86 int fchown:fchown32(int, uid_t, gid_t) arm,x86
int fchown:fchown(int, uid_t, gid_t) arm64,mips,mips64,x86_64 int fchown:fchown(int, uid_t, gid_t) arm64,mips,mips64,x86_64
void sync(void) all void sync(void) all
int ___fsetxattr:fsetxattr(int, const char*, const void*, size_t, int) all int fsetxattr(int, const char*, const void*, size_t, int) all
ssize_t ___fgetxattr:fgetxattr(int, const char*, void*, size_t) all ssize_t fgetxattr(int, const char*, void*, size_t) all
ssize_t ___flistxattr:flistxattr(int, char*, size_t) all ssize_t flistxattr(int, char*, size_t) all
int fremovexattr(int, const char*) all int fremovexattr(int, const char*) all
int __getdents64:getdents64(unsigned int, struct dirent*, unsigned int) arm,arm64,mips,mips64,x86,x86_64 int __getdents64:getdents64(unsigned int, struct dirent*, unsigned int) arm,arm64,mips,mips64,x86,x86_64
int __openat:openat(int, const char*, int, mode_t) all int __openat:openat(int, const char*, int, mode_t) all
int ___faccessat:faccessat(int, const char*, int) all int faccessat(int, const char*, int, int) all
int ___fchmodat:fchmodat(int, const char*, mode_t) all int fchmodat(int, const char*, mode_t, int) all
int fchownat(int, const char*, uid_t, gid_t, int) all int fchownat(int, const char*, uid_t, gid_t, int) all
int fstatat64|fstatat:fstatat64(int, const char*, struct stat*, int) arm,mips,x86 int fstatat64|fstatat:fstatat64(int, const char*, struct stat*, int) arm,mips,x86
int fstatat64|fstatat:newfstatat(int, const char*, struct stat*, int) arm64,x86_64 int fstatat64|fstatat:newfstatat(int, const char*, struct stat*, int) arm64,mips64,x86_64
int linkat(int, const char*, int, const char*, int) all int linkat(int, const char*, int, const char*, int) all
int mkdirat(int, const char*, mode_t) all int mkdirat(int, const char*, mode_t) all
int mknodat(int, const char*, mode_t, dev_t) all int mknodat(int, const char*, mode_t, dev_t) all
@ -160,6 +151,7 @@ int utimensat(int, const char*, const struct timespec times[2], int) all
off_t lseek(int, off_t, int) arm,mips,x86 off_t lseek(int, off_t, int) arm,mips,x86
int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,mips,x86 int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,mips,x86
off_t lseek|lseek64(int, off_t, int) arm64,mips64,x86_64 off_t lseek|lseek64(int, off_t, int) arm64,mips64,x86_64
int ftruncate(int, off_t) arm,mips,x86
int ftruncate64(int, off64_t) arm,mips,x86 int ftruncate64(int, off64_t) arm,mips,x86
int ftruncate|ftruncate64(int, off_t) arm64,mips64,x86_64 int ftruncate|ftruncate64(int, off_t) arm64,mips64,x86_64
ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count) arm,mips,x86 ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count) arm,mips,x86
@ -182,12 +174,12 @@ int __fadvise64:fadvise64_64(int, off64_t, off64_t, int) x86
int __fadvise64:fadvise64(int, off64_t, off64_t, int) arm64,mips,mips64,x86_64 int __fadvise64:fadvise64(int, off64_t, off64_t, int) arm64,mips,mips64,x86_64
int __fstatfs64:fstatfs64(int, size_t, struct statfs*) arm,mips,x86 int __fstatfs64:fstatfs64(int, size_t, struct statfs*) arm,mips,x86
int __fstatfs:fstatfs(int, struct statfs*) arm64,mips64,x86_64 int fstatfs64|fstatfs:fstatfs(int, struct statfs*) arm64,mips64,x86_64
int __statfs64:statfs64(const char*, size_t, struct statfs*) arm,mips,x86 int __statfs64:statfs64(const char*, size_t, struct statfs*) arm,mips,x86
int __statfs:statfs(const char*, struct statfs*) arm64,mips64,x86_64 int statfs64|statfs:statfs(const char*, struct statfs*) arm64,mips64,x86_64
int fstat64|fstat:fstat64(int, struct stat*) arm,mips,x86 int fstat64|fstat:fstat64(int, struct stat*) arm,mips,x86
int fstat64|fstat:fstat(int, struct stat*) arm64,x86_64 int fstat64|fstat:fstat(int, struct stat*) arm64,mips64,x86_64
# file system # file system
int chdir(const char*) all int chdir(const char*) all
@ -210,9 +202,9 @@ int swapoff(const char*) all
int settimeofday(const struct timeval*, const struct timezone*) all int settimeofday(const struct timeval*, const struct timezone*) all
clock_t times(struct tms*) all clock_t times(struct tms*) all
int nanosleep(const struct timespec*, struct timespec*) all int nanosleep(const struct timespec*, struct timespec*) all
int clock_settime(clockid_t, const struct timespec*) all int clock_settime(clockid_t clk_id, const struct timespec* tp) all
int clock_getres(clockid_t, struct timespec*) all int clock_getres(clockid_t clk_id, struct timespec* res) all
int ___clock_nanosleep:clock_nanosleep(clockid_t, int, const struct timespec*, struct timespec*) all int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec* req, struct timespec* rem) all
int getitimer(int, const struct itimerval*) all int getitimer(int, const struct itimerval*) all
int setitimer(int, const struct itimerval*, struct itimerval*) all int setitimer(int, const struct itimerval*, struct itimerval*) all
int __timer_create:timer_create(clockid_t clockid, struct sigevent* evp, __kernel_timer_t* timerid) all int __timer_create:timer_create(clockid_t clockid, struct sigevent* evp, __kernel_timer_t* timerid) all
@ -231,7 +223,6 @@ int __rt_sigpending:rt_sigpending(sigset_t*, size_t) all
int __rt_sigprocmask:rt_sigprocmask(int, const sigset_t*, sigset_t*, size_t) all int __rt_sigprocmask:rt_sigprocmask(int, const sigset_t*, sigset_t*, size_t) all
int __rt_sigsuspend:rt_sigsuspend(const sigset_t*, size_t) all int __rt_sigsuspend:rt_sigsuspend(const sigset_t*, size_t) all
int __rt_sigtimedwait:rt_sigtimedwait(const sigset_t*, struct siginfo_t*, struct timespec_t*, size_t) all int __rt_sigtimedwait:rt_sigtimedwait(const sigset_t*, struct siginfo_t*, struct timespec_t*, size_t) all
int ___rt_sigqueueinfo:rt_sigqueueinfo(pid_t, int, siginfo_t*) all
int __signalfd4:signalfd4(int, const sigset_t*, size_t, int) all int __signalfd4:signalfd4(int, const sigset_t*, size_t, int) all
# sockets # sockets
@ -317,16 +308,11 @@ int inotify_rm_watch(int, unsigned int) all
int __pselect6:pselect6(int, fd_set*, fd_set*, fd_set*, timespec*, void*) all int __pselect6:pselect6(int, fd_set*, fd_set*, fd_set*, timespec*, void*) all
int __ppoll:ppoll(pollfd*, unsigned int, timespec*, const sigset_t*, size_t) all int __ppoll:ppoll(pollfd*, unsigned int, timespec*, const sigset_t*, size_t) all
ssize_t process_vm_readv(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long) all
ssize_t process_vm_writev(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long) all
int __set_tid_address:set_tid_address(int*) all int __set_tid_address:set_tid_address(int*) all
int setfsgid(gid_t) all int setfsgid(gid_t) all
int setfsuid(uid_t) all int setfsuid(uid_t) all
int sethostname(const char*, size_t) all
pid_t wait4(pid_t, int*, int, struct rusage*) all pid_t wait4(pid_t, int*, int, struct rusage*) all
int __waitid:waitid(int, pid_t, struct siginfo_t*, int, void*) all int __waitid:waitid(int, pid_t, struct siginfo_t*, int, void*) all
@ -335,14 +321,14 @@ int __set_tls:__ARM_NR_set_tls(void*) arm
int cacheflush:__ARM_NR_cacheflush(long start, long end, long flags) arm int cacheflush:__ARM_NR_cacheflush(long start, long end, long flags) arm
# MIPS-specific # MIPS-specific
int _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips int _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips,mips64
int __set_tls:set_thread_area(void*) mips,mips64 int __set_tls:set_thread_area(void*) mips,mips64
# x86-specific # x86-specific
int __set_thread_area:set_thread_area(void*) x86 int __set_thread_area:set_thread_area(void*) x86
# vdso stuff. # vdso stuff.
int clock_gettime(clockid_t, timespec*) arm,mips,mips64 int clock_gettime(clockid_t, timespec*) arm,mips,mips64,x86
int __clock_gettime:clock_gettime(clockid_t, timespec*) arm64,x86,x86_64 int __clock_gettime:clock_gettime(clockid_t, timespec*) arm64,x86_64
int gettimeofday(timeval*, timezone*) arm,mips,mips64 int gettimeofday(timeval*, timezone*) arm,mips,mips64,x86
int __gettimeofday:gettimeofday(timeval*, timezone*) arm64,x86,x86_64 int __gettimeofday:gettimeofday(timeval*, timezone*) arm64,x86_64

View File

@ -1,19 +1,52 @@
# 32-bit arm. # 32-bit arm.
#
# Various kinds of LP32 cruft.
#
libc_bionic_src_files_arm += \ libc_bionic_src_files_arm += \
arch-arm/generic/bionic/memcmp.S \ bionic/mmap.cpp \
arch-arm/generic/bionic/memcpy.S \
arch-arm/generic/bionic/memset.S \
arch-arm/generic/bionic/strcmp.S \
arch-arm/generic/bionic/strcpy.S \
arch-arm/generic/bionic/strlen.c \
libc_bionic_src_files_exclude_arm += \ libc_common_src_files_arm += \
bionic/__memcpy_chk.cpp \ bionic/legacy_32_bit_support.cpp \
bionic/__memset_chk.cpp \ bionic/ndk_cruft.cpp \
bionic/time64.c \
libc_openbsd_src_files_exclude_arm += \ libc_netbsd_src_files_arm += \
upstream-openbsd/lib/libc/string/strcpy.c \ upstream-netbsd/common/lib/libc/hash/sha1/sha1.c \
libc_openbsd_src_files_arm += \
upstream-openbsd/lib/libc/stdio/putw.c \
#
# Default implementations of functions that are commonly optimized.
#
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 \
upstream-freebsd/lib/libc/string/wcscpy.c \
upstream-freebsd/lib/libc/string/wcslen.c \
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/stpncpy.c \
upstream-openbsd/lib/libc/string/strlcat.c \
upstream-openbsd/lib/libc/string/strlcpy.c \
upstream-openbsd/lib/libc/string/strncat.c \
upstream-openbsd/lib/libc/string/strncmp.c \
upstream-openbsd/lib/libc/string/strncpy.c \
# #
# Inherently architecture-specific code. # Inherently architecture-specific code.
@ -25,11 +58,12 @@ libc_bionic_src_files_arm += \
arch-arm/bionic/__bionic_clone.S \ arch-arm/bionic/__bionic_clone.S \
arch-arm/bionic/_exit_with_stack_teardown.S \ arch-arm/bionic/_exit_with_stack_teardown.S \
arch-arm/bionic/libgcc_compat.c \ arch-arm/bionic/libgcc_compat.c \
arch-arm/bionic/popcount_tab.c \ arch-arm/bionic/memcmp.S \
arch-arm/bionic/__restore.S \ arch-arm/bionic/__restore.S \
arch-arm/bionic/_setjmp.S \
arch-arm/bionic/setjmp.S \ arch-arm/bionic/setjmp.S \
arch-arm/bionic/sigsetjmp.S \
arch-arm/bionic/syscall.S \ arch-arm/bionic/syscall.S \
arch-arm/bionic/vfork.S \
libc_arch_static_src_files_arm := arch-arm/bionic/exidx_static.c 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_arch_dynamic_src_files_arm := arch-arm/bionic/exidx_dynamic.c
@ -38,7 +72,6 @@ libc_arch_dynamic_src_files_arm := arch-arm/bionic/exidx_dynamic.c
ifeq ($(strip $(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT)),) 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) $(warning TARGET_$(my_2nd_arch_prefix)ARCH is arm, but TARGET_$(my_2nd_arch_prefix)CPU_VARIANT is not defined)
endif endif
ifneq ($(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT),generic)
cpu_variant_mk := $(LOCAL_PATH)/arch-arm/$(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT)/$(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT).mk cpu_variant_mk := $(LOCAL_PATH)/arch-arm/$(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT)/$(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT).mk
ifeq ($(wildcard $(cpu_variant_mk)),) ifeq ($(wildcard $(cpu_variant_mk)),)
$(error "TARGET_$(my_2nd_arch_prefix)CPU_VARIANT not set or set to an unknown value. Possible values are cortex-a7, cortex-a8, cortex-a9, cortex-a15, krait, denver. Use generic for devices that do not have a CPU similar to any of the supported cpu variants.") $(error "TARGET_$(my_2nd_arch_prefix)CPU_VARIANT not set or set to an unknown value. Possible values are cortex-a7, cortex-a8, cortex-a9, cortex-a15, krait, denver. Use generic for devices that do not have a CPU similar to any of the supported cpu variants.")
@ -47,7 +80,6 @@ include $(cpu_variant_mk)
libc_common_additional_dependencies += $(cpu_variant_mk) libc_common_additional_dependencies += $(cpu_variant_mk)
cpu_variant_mk := cpu_variant_mk :=
endif
libc_crt_target_cflags_arm := \ libc_crt_target_cflags_arm := \

View File

@ -39,9 +39,6 @@
extern int __cxa_atexit(void (*)(void*), void*, void*); extern int __cxa_atexit(void (*)(void*), void*, void*);
// All of these are weak symbols to avoid multiple definition errors when
// linking with libstdc++-v3 or compiler-rt.
/* The "C++ ABI for ARM" document states that static C++ constructors, /* The "C++ ABI for ARM" document states that static C++ constructors,
* which are called from the .init_array, should manually call * which are called from the .init_array, should manually call
* __aeabi_atexit() to register static destructors explicitly. * __aeabi_atexit() to register static destructors explicitly.
@ -50,63 +47,35 @@ extern int __cxa_atexit(void (*)(void*), void*, void*);
* variable from the shared object that contains the constructor/destructor * variable from the shared object that contains the constructor/destructor
*/ */
// Make this a weak symbol to avoid a multiple definition error when linking with libstdc++-v3.
int __attribute__((weak)) int __attribute__((weak))
__aeabi_atexit_impl(void *object, void (*destructor) (void *), void *dso_handle) { __aeabi_atexit(void *object, void (*destructor) (void *), void *dso_handle) {
return __cxa_atexit(destructor, object, dso_handle);
}
int __attribute__((weak))
__aeabi_atexit_impl2(void *object, void (*destructor) (void *), void *dso_handle) {
return __cxa_atexit(destructor, object, dso_handle); return __cxa_atexit(destructor, object, dso_handle);
} }
void __attribute__((weak)) __aeabi_memcpy8_impl(void *dest, const void *src, size_t n) { void __aeabi_memcpy8(void *dest, const void *src, size_t n) {
memcpy(dest, src, n); memcpy(dest, src, n);
} }
void __attribute__((weak)) __aeabi_memcpy4_impl(void *dest, const void *src, size_t n) { void __aeabi_memcpy4(void *dest, const void *src, size_t n) {
memcpy(dest, src, n); memcpy(dest, src, n);
} }
void __attribute__((weak)) __aeabi_memcpy_impl(void *dest, const void *src, size_t n) { void __aeabi_memcpy(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
}
void __attribute__((weak)) __aeabi_memcpy8_impl2(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
}
void __attribute__((weak)) __aeabi_memcpy4_impl2(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
}
void __attribute__((weak)) __aeabi_memcpy_impl2(void *dest, const void *src, size_t n) {
memcpy(dest, src, n); memcpy(dest, src, n);
} }
void __attribute__((weak)) __aeabi_memmove8_impl(void *dest, const void *src, size_t n) { void __aeabi_memmove8(void *dest, const void *src, size_t n) {
memmove(dest, src, n); memmove(dest, src, n);
} }
void __attribute__((weak)) __aeabi_memmove4_impl(void *dest, const void *src, size_t n) { void __aeabi_memmove4(void *dest, const void *src, size_t n) {
memmove(dest, src, n); memmove(dest, src, n);
} }
void __attribute__((weak)) __aeabi_memmove_impl(void *dest, const void *src, size_t n) { void __aeabi_memmove(void *dest, const void *src, size_t n) {
memmove(dest, src, n);
}
void __attribute__((weak)) __aeabi_memmove8_impl2(void *dest, const void *src, size_t n) {
memmove(dest, src, n);
}
void __attribute__((weak)) __aeabi_memmove4_impl2(void *dest, const void *src, size_t n) {
memmove(dest, src, n);
}
void __attribute__((weak)) __aeabi_memmove_impl2(void *dest, const void *src, size_t n) {
memmove(dest, src, n); memmove(dest, src, n);
} }
@ -115,71 +84,27 @@ void __attribute__((weak)) __aeabi_memmove_impl2(void *dest, const void *src, si
* This allows __aeabi_memclr to tail-call __aeabi_memset * This allows __aeabi_memclr to tail-call __aeabi_memset
*/ */
void __attribute__((weak)) __aeabi_memset8_impl(void *dest, size_t n, int c) { void __aeabi_memset8(void *dest, size_t n, int c) {
memset(dest, c, n); memset(dest, c, n);
} }
void __attribute__((weak)) __aeabi_memset4_impl(void *dest, size_t n, int c) { void __aeabi_memset4(void *dest, size_t n, int c) {
memset(dest, c, n); memset(dest, c, n);
} }
void __attribute__((weak)) __aeabi_memset_impl(void *dest, size_t n, int c) { void __aeabi_memset(void *dest, size_t n, int c) {
memset(dest, c, n);
}
void __attribute__((weak)) __aeabi_memset8_impl2(void *dest, size_t n, int c) {
memset(dest, c, n);
}
void __attribute__((weak)) __aeabi_memset4_impl2(void *dest, size_t n, int c) {
memset(dest, c, n);
}
void __attribute__((weak)) __aeabi_memset_impl2(void *dest, size_t n, int c) {
memset(dest, c, n); memset(dest, c, n);
} }
void __attribute__((weak)) __aeabi_memclr8_impl(void *dest, size_t n) { void __aeabi_memclr8(void *dest, size_t n) {
__aeabi_memset8_impl(dest, n, 0); __aeabi_memset8(dest, n, 0);
} }
void __attribute__((weak)) __aeabi_memclr4_impl(void *dest, size_t n) { void __aeabi_memclr4(void *dest, size_t n) {
__aeabi_memset4_impl(dest, n, 0); __aeabi_memset4(dest, n, 0);
} }
void __attribute__((weak)) __aeabi_memclr_impl(void *dest, size_t n) { void __aeabi_memclr(void *dest, size_t n) {
__aeabi_memset_impl(dest, n, 0); __aeabi_memset(dest, n, 0);
} }
void __attribute__((weak)) __aeabi_memclr8_impl2(void *dest, size_t n) {
__aeabi_memset8_impl(dest, n, 0);
}
void __attribute__((weak)) __aeabi_memclr4_impl2(void *dest, size_t n) {
__aeabi_memset4_impl(dest, n, 0);
}
void __attribute__((weak)) __aeabi_memclr_impl2(void *dest, size_t n) {
__aeabi_memset_impl(dest, n, 0);
}
#define __AEABI_SYMVERS(fn_name) \
__asm__(".symver " #fn_name "_impl, " #fn_name "@@LIBC_N"); \
__asm__(".symver " #fn_name "_impl2, " #fn_name "@LIBC_PRIVATE")
__AEABI_SYMVERS(__aeabi_atexit);
__AEABI_SYMVERS(__aeabi_memcpy8);
__AEABI_SYMVERS(__aeabi_memcpy4);
__AEABI_SYMVERS(__aeabi_memcpy);
__AEABI_SYMVERS(__aeabi_memmove8);
__AEABI_SYMVERS(__aeabi_memmove4);
__AEABI_SYMVERS(__aeabi_memmove);
__AEABI_SYMVERS(__aeabi_memset8);
__AEABI_SYMVERS(__aeabi_memset4);
__AEABI_SYMVERS(__aeabi_memset);
__AEABI_SYMVERS(__aeabi_memclr8);
__AEABI_SYMVERS(__aeabi_memclr4);
__AEABI_SYMVERS(__aeabi_memclr);
#undef __AEABI_SYMVERS

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2008 The Android Open Source Project * Copyright (C) 2008-2010 The Android Open Source Project
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -42,14 +42,13 @@ ENTRY(__bionic_clone)
# load extra parameters # load extra parameters
ldmfd ip, {r4, r5, r6} ldmfd ip, {r4, r5, r6}
# Push 'fn' and 'arg' onto the child stack. # store 'fn' and 'arg' to the child stack
stmdb r1!, {r5, r6} str r5, [r1, #-4]
str r6, [r1, #-8]
# Make the system call. # System call
ldr r7, =__NR_clone ldr r7, =__NR_clone
swi #0 swi #0
# Are we the child?
movs r0, r0 movs r0, r0
beq 1f beq 1f
@ -63,8 +62,8 @@ ENTRY(__bionic_clone)
1: # The child. 1: # The child.
# Setting lr to 0 will make the unwinder stop at __start_thread # Setting lr to 0 will make the unwinder stop at __start_thread
mov lr, #0 mov lr, #0
# Call __start_thread with the 'fn' and 'arg' we stored on the child stack. ldr r0, [sp, #-4]
pop {r0, r1} ldr r1, [sp, #-8]
b __start_thread b __start_thread
END(__bionic_clone) END(__bionic_clone)
.hidden __bionic_clone .hidden __bionic_clone

View File

@ -34,9 +34,7 @@
// __restore_rt (but covered by the .fnstart/.fnend) so that although they're // __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 // 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 // blindly looks at the previous instruction (but is then smart enough to check
// the unwind information to find out where it landed) gets the right answer. // the DWARF information to find out where it landed) gets the right answer.
// Make sure not to have both DWARF and ARM unwind information, so only
// use the ARM unwind information.
// We need to place .fnstart ourselves (but we may as well keep the free .fnend). // We need to place .fnstart ourselves (but we may as well keep the free .fnend).
#undef __bionic_asm_custom_entry #undef __bionic_asm_custom_entry
@ -46,18 +44,18 @@
.save {r0-r15} .save {r0-r15}
.pad #32 .pad #32
nop nop
ENTRY_PRIVATE_NO_DWARF(__restore) ENTRY_PRIVATE(__restore)
// This function must have exactly this instruction sequence. // This function must have exactly this instruction sequence.
mov r7, #__NR_sigreturn mov r7, #__NR_sigreturn
swi #0 swi #0
END_NO_DWARF(__restore) END(__restore)
.fnstart .fnstart
.save {r0-r15} .save {r0-r15}
.pad #160 .pad #160
nop nop
ENTRY_PRIVATE_NO_DWARF(__restore_rt) ENTRY_PRIVATE(__restore_rt)
// This function must have exactly this instruction sequence. // This function must have exactly this instruction sequence.
mov r7, #__NR_rt_sigreturn mov r7, #__NR_rt_sigreturn
swi #0 swi #0
END_NO_DWARF(__restore_rt) END(__restore_rt)

View File

@ -0,0 +1,113 @@
/* $OpenBSD: _setjmp.S,v 1.2 2004/02/01 05:40:52 drahn Exp $ */
/* $NetBSD: _setjmp.S,v 1.5 2003/04/05 23:08:51 bjh21 Exp $ */
/*
* Copyright (c) 1997 Mark Brinicombe
* Copyright (c) 2010 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:
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Mark Brinicombe
* 4. Neither the name of the University 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 AUTHOR 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 AUTHOR 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 <private/bionic_asm.h>
#include <machine/setjmp.h>
#include <machine/cpu-features.h>
/*
* C library -- _setjmp, _longjmp
*
* _longjmp(a,v)
* will generate a "return(v)" from the last call to
* _setjmp(a)
* by restoring registers from the stack.
* The previous signal state is NOT restored.
*
* Note: r0 is the return value
* r1-r3 are scratch registers in functions
*/
ENTRY(_setjmp)
ldr r1, .L_setjmp_magic
str r1, [r0, #(_JB_MAGIC * 4)]
/* Store core registers */
add r1, r0, #(_JB_CORE_BASE * 4)
stmia r1, {r4-r14}
#ifdef __ARM_HAVE_VFP
/* Store floating-point registers */
add r1, r0, #(_JB_FLOAT_BASE * 4)
vstmia r1, {d8-d15}
/* Store floating-point state */
fmrx r1, fpscr
str r1, [r0, #(_JB_FLOAT_STATE * 4)]
#endif /* __ARM_HAVE_VFP */
mov r0, #0x00000000
bx lr
END(_setjmp)
.L_setjmp_magic:
.word _JB_MAGIC__SETJMP
ENTRY(_longjmp)
ldr r2, .L_setjmp_magic
ldr r3, [r0, #(_JB_MAGIC * 4)]
teq r2, r3
bne botch
#ifdef __ARM_HAVE_VFP
/* Restore floating-point registers */
add r2, r0, #(_JB_FLOAT_BASE * 4)
vldmia r2, {d8-d15}
/* Restore floating-point state */
ldr r2, [r0, #(_JB_FLOAT_STATE * 4)]
fmxr fpscr, r2
#endif /* __ARM_HAVE_VFP */
/* Restore core registers */
add r2, r0, #(_JB_CORE_BASE * 4)
ldmia r2, {r4-r14}
/* Validate sp and r14 */
teq sp, #0
teqne r14, #0
beq botch
/* Set return value */
mov r0, r1
teq r0, #0x00000000
moveq r0, #0x00000001
bx lr
/* validation failed, die die die. */
botch:
bl PIC_SYM(longjmperror, PLT)
bl PIC_SYM(abort, PLT)
b . - 8 /* Cannot get here */
END(_longjmp)

View File

@ -40,5 +40,5 @@ ENTRY(abort)
.cfi_def_cfa_offset 8 .cfi_def_cfa_offset 8
.cfi_rel_offset r3, 0 .cfi_rel_offset r3, 0
.cfi_rel_offset r14, 4 .cfi_rel_offset r14, 4
bl __libc_android_abort bl PIC_SYM(__libc_android_abort, PLT)
END(abort) END(abort)

View File

@ -37,13 +37,7 @@
* the expectation that libc will define it and call through to * the expectation that libc will define it and call through to
* a differently-named function in the dynamic linker. * a differently-named function in the dynamic linker.
*/ */
_Unwind_Ptr __gnu_Unwind_Find_exidx_impl(_Unwind_Ptr pc, int *pcount) { _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr pc, int *pcount)
{
return dl_unwind_find_exidx(pc, pcount); return dl_unwind_find_exidx(pc, pcount);
} }
_Unwind_Ptr __gnu_Unwind_Find_exidx_impl2(_Unwind_Ptr pc, int *pcount) {
return dl_unwind_find_exidx(pc, pcount);
}
__asm__(".symver __gnu_Unwind_Find_exidx_impl,__gnu_Unwind_Find_exidx@LIBC_PRIVATE");
__asm__(".symver __gnu_Unwind_Find_exidx_impl2,__gnu_Unwind_Find_exidx@@LIBC_N");

View File

@ -40,8 +40,6 @@
* Optimized memcmp() for Cortex-A9. * Optimized memcmp() for Cortex-A9.
*/ */
.syntax unified
ENTRY(memcmp) ENTRY(memcmp)
pld [r0, #(CACHE_LINE_SIZE * 0)] pld [r0, #(CACHE_LINE_SIZE * 0)]
pld [r0, #(CACHE_LINE_SIZE * 1)] pld [r0, #(CACHE_LINE_SIZE * 1)]
@ -163,25 +161,25 @@ ENTRY(memcmp)
eors r0, r0, ip eors r0, r0, ip
ldreq r0, [r4], #4 ldreq r0, [r4], #4
ldreq ip, [r1, #4]! ldreq ip, [r1, #4]!
eorseq r0, r0, lr eoreqs r0, r0, lr
ldreq r0, [r4], #4 ldreq r0, [r4], #4
ldreq lr, [r1, #4]! ldreq lr, [r1, #4]!
eorseq r0, r0, ip eoreqs r0, r0, ip
ldreq r0, [r4], #4 ldreq r0, [r4], #4
ldreq ip, [r1, #4]! ldreq ip, [r1, #4]!
eorseq r0, r0, lr eoreqs r0, r0, lr
ldreq r0, [r4], #4 ldreq r0, [r4], #4
ldreq lr, [r1, #4]! ldreq lr, [r1, #4]!
eorseq r0, r0, ip eoreqs r0, r0, ip
ldreq r0, [r4], #4 ldreq r0, [r4], #4
ldreq ip, [r1, #4]! ldreq ip, [r1, #4]!
eorseq r0, r0, lr eoreqs r0, r0, lr
ldreq r0, [r4], #4 ldreq r0, [r4], #4
ldreq lr, [r1, #4]! ldreq lr, [r1, #4]!
eorseq r0, r0, ip eoreqs r0, r0, ip
ldreq r0, [r4], #4 ldreq r0, [r4], #4
ldreq ip, [r1, #4]! ldreq ip, [r1, #4]!
eorseq r0, r0, lr eoreqs r0, r0, lr
bne 2f bne 2f
subs r2, r2, #32 subs r2, r2, #32
bhs 0b bhs 0b
@ -221,7 +219,8 @@ ENTRY(memcmp)
bne 8b bne 8b
9: /* restore registers and return */ 9: /* restore registers and return */
ldmfd sp!, {r4, pc} ldmfd sp!, {r4, lr}
bx lr
10: /* process less than 12 bytes */ 10: /* process less than 12 bytes */
cmp r2, #0 cmp r2, #0
@ -264,17 +263,17 @@ ENTRY(memcmp)
ldreq lr, [r1], #4 ldreq lr, [r1], #4
ldreq r0, [r4], #4 ldreq r0, [r4], #4
orreq ip, ip, lr, lsl #16 orreq ip, ip, lr, lsl #16
eorseq r0, r0, ip eoreqs r0, r0, ip
moveq ip, lr, lsr #16 moveq ip, lr, lsr #16
ldreq lr, [r1], #4 ldreq lr, [r1], #4
ldreq r0, [r4], #4 ldreq r0, [r4], #4
orreq ip, ip, lr, lsl #16 orreq ip, ip, lr, lsl #16
eorseq r0, r0, ip eoreqs r0, r0, ip
moveq ip, lr, lsr #16 moveq ip, lr, lsr #16
ldreq lr, [r1], #4 ldreq lr, [r1], #4
ldreq r0, [r4], #4 ldreq r0, [r4], #4
orreq ip, ip, lr, lsl #16 orreq ip, ip, lr, lsl #16
eorseq r0, r0, ip eoreqs r0, r0, ip
bne 7f bne 7f
subs r2, r2, #16 subs r2, r2, #16
bhs 6b bhs 6b
@ -318,7 +317,7 @@ ENTRY(memcmp)
ldreq r7, [r1], #4 ldreq r7, [r1], #4
ldreq r0, [r4], #4 ldreq r0, [r4], #4
orreq ip, ip, r7, lsl r6 orreq ip, ip, r7, lsl r6
eorseq r0, r0, ip eoreqs r0, r0, ip
bne 7f bne 7f
subs r2, r2, #8 subs r2, r2, #8
bhs 6b bhs 6b

View File

@ -0,0 +1,686 @@
/*
* Copyright (C) 2008 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 <machine/cpu-features.h>
#include <private/bionic_asm.h>
#if defined(__ARM_NEON__) && !defined(ARCH_ARM_USE_NON_NEON_MEMCPY)
.text
.fpu neon
#ifdef HAVE_32_BYTE_CACHE_LINE
/* a prefetch distance of 2 cache-lines */
#define CACHE_LINE_SIZE 32
#else
/* a prefetch distance of 4 cache-lines works best experimentally */
#define CACHE_LINE_SIZE 64
#endif
ENTRY(memcpy)
.save {r0, lr}
/* start preloading as early as possible */
pld [r1, #(CACHE_LINE_SIZE * 0)]
stmfd sp!, {r0, lr}
pld [r1, #(CACHE_LINE_SIZE * 1)]
/* If Neon supports unaligned access then remove the align code,
* unless a size limit has been specified.
*/
#ifndef NEON_UNALIGNED_ACCESS
/* do we have at least 16-bytes to copy (needed for alignment below) */
cmp r2, #16
blo 5f
/* check if buffers are aligned. If so, run arm-only version */
eor r3, r0, r1
ands r3, r3, #0x3
beq 11f
/* align destination to cache-line for the write-buffer */
rsb r3, r0, #0
ands r3, r3, #0xF
beq 2f
/* copy up to 15-bytes (count in r3) */
sub r2, r2, r3
movs ip, r3, lsl #31
ldrmib lr, [r1], #1
strmib lr, [r0], #1
ldrcsb ip, [r1], #1
ldrcsb lr, [r1], #1
strcsb ip, [r0], #1
strcsb lr, [r0], #1
movs ip, r3, lsl #29
bge 1f
// copies 4 bytes, destination 32-bits aligned
vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]!
vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]!
1: bcc 2f
// copies 8 bytes, destination 64-bits aligned
vld1.8 {d0}, [r1]!
vst1.8 {d0}, [r0, :64]!
2:
/* preload immediately the next cache line, which we may need */
pld [r1, #(CACHE_LINE_SIZE * 0)]
pld [r1, #(CACHE_LINE_SIZE * 1)]
#ifdef HAVE_32_BYTE_CACHE_LINE
/* make sure we have at least 32 bytes to copy */
subs r2, r2, #32
blo 4f
/* preload all the cache lines we need.
* NOTE: the number of pld below depends on PREFETCH_DISTANCE,
* ideally would would increase the distance in the main loop to
* avoid the goofy code below. In practice this doesn't seem to make
* a big difference.
*/
pld [r1, #(PREFETCH_DISTANCE)]
1: /* The main loop copies 32 bytes at a time */
vld1.8 {d0 - d3}, [r1]!
pld [r1, #(PREFETCH_DISTANCE)]
subs r2, r2, #32
vst1.8 {d0 - d3}, [r0, :128]!
bhs 1b
#else
/* make sure we have at least 64 bytes to copy */
subs r2, r2, #64
blo 2f
/* preload all the cache lines we need. */
pld [r1, #(CACHE_LINE_SIZE * 2)]
pld [r1, #(CACHE_LINE_SIZE * 3)]
1: /* The main loop copies 64 bytes at a time */
vld1.8 {d0 - d3}, [r1]!
vld1.8 {d4 - d7}, [r1]!
#ifdef HAVE_32_BYTE_CACHE_LINE
pld [r1, #(CACHE_LINE_SIZE * 2)]
pld [r1, #(CACHE_LINE_SIZE * 3)]
#else
pld [r1, #(CACHE_LINE_SIZE * 3)]
#endif
subs r2, r2, #64
vst1.8 {d0 - d3}, [r0, :128]!
vst1.8 {d4 - d7}, [r0, :128]!
bhs 1b
2: /* fix-up the remaining count and make sure we have >= 32 bytes left */
add r2, r2, #64
subs r2, r2, #32
blo 4f
3: /* 32 bytes at a time. These cache lines were already preloaded */
vld1.8 {d0 - d3}, [r1]!
subs r2, r2, #32
vst1.8 {d0 - d3}, [r0, :128]!
bhs 3b
#endif
4: /* less than 32 left */
add r2, r2, #32
tst r2, #0x10
beq 5f
// copies 16 bytes, 128-bits aligned
vld1.8 {d0, d1}, [r1]!
vst1.8 {d0, d1}, [r0, :128]!
5: /* copy up to 15-bytes (count in r2) */
movs ip, r2, lsl #29
bcc 1f
vld1.8 {d0}, [r1]!
vst1.8 {d0}, [r0]!
1: bge 2f
vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]!
vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0]!
2: movs ip, r2, lsl #31
ldrmib r3, [r1], #1
ldrcsb ip, [r1], #1
ldrcsb lr, [r1], #1
strmib r3, [r0], #1
strcsb ip, [r0], #1
strcsb lr, [r0], #1
ldmfd sp!, {r0, lr}
bx lr
#else /* NEON_UNALIGNED_ACCESS */
// Check so divider is at least 16 bytes, needed for alignment code.
cmp r2, #16
blo 5f
#ifdef NEON_MEMCPY_ALIGNMENT_DIVIDER
/* Check the upper size limit for Neon unaligned memory access in memcpy */
#if NEON_MEMCPY_ALIGNMENT_DIVIDER >= 16
cmp r2, #NEON_MEMCPY_ALIGNMENT_DIVIDER
blo 3f
#endif
/* check if buffers are aligned. If so, run arm-only version */
eor r3, r0, r1
ands r3, r3, #0x3
beq 11f
/* align destination to 16 bytes for the write-buffer */
rsb r3, r0, #0
ands r3, r3, #0xF
beq 3f
/* copy up to 15-bytes (count in r3) */
sub r2, r2, r3
movs ip, r3, lsl #31
ldrmib lr, [r1], #1
strmib lr, [r0], #1
ldrcsb ip, [r1], #1
ldrcsb lr, [r1], #1
strcsb ip, [r0], #1
strcsb lr, [r0], #1
movs ip, r3, lsl #29
bge 1f
// copies 4 bytes, destination 32-bits aligned
vld1.32 {d0[0]}, [r1]!
vst1.32 {d0[0]}, [r0, :32]!
1: bcc 2f
// copies 8 bytes, destination 64-bits aligned
vld1.8 {d0}, [r1]!
vst1.8 {d0}, [r0, :64]!
2:
/* preload immediately the next cache line, which we may need */
pld [r1, #(CACHE_LINE_SIZE * 0)]
pld [r1, #(CACHE_LINE_SIZE * 1)]
3:
#endif
/* make sure we have at least 64 bytes to copy */
subs r2, r2, #64
blo 2f
/* preload all the cache lines we need */
pld [r1, #(CACHE_LINE_SIZE * 2)]
pld [r1, #(CACHE_LINE_SIZE * 3)]
1: /* The main loop copies 64 bytes at a time */
vld1.8 {d0 - d3}, [r1]!
vld1.8 {d4 - d7}, [r1]!
#ifdef HAVE_32_BYTE_CACHE_LINE
pld [r1, #(CACHE_LINE_SIZE * 2)]
pld [r1, #(CACHE_LINE_SIZE * 3)]
#else
pld [r1, #(CACHE_LINE_SIZE * 3)]
#endif
subs r2, r2, #64
vst1.8 {d0 - d3}, [r0]!
vst1.8 {d4 - d7}, [r0]!
bhs 1b
2: /* fix-up the remaining count and make sure we have >= 32 bytes left */
add r2, r2, #64
subs r2, r2, #32
blo 4f
3: /* 32 bytes at a time. These cache lines were already preloaded */
vld1.8 {d0 - d3}, [r1]!
subs r2, r2, #32
vst1.8 {d0 - d3}, [r0]!
bhs 3b
4: /* less than 32 left */
add r2, r2, #32
tst r2, #0x10
beq 5f
// copies 16 bytes, 128-bits aligned
vld1.8 {d0, d1}, [r1]!
vst1.8 {d0, d1}, [r0]!
5: /* copy up to 15-bytes (count in r2) */
movs ip, r2, lsl #29
bcc 1f
vld1.8 {d0}, [r1]!
vst1.8 {d0}, [r0]!
1: bge 2f
vld1.32 {d0[0]}, [r1]!
vst1.32 {d0[0]}, [r0]!
2: movs ip, r2, lsl #31
ldrmib r3, [r1], #1
ldrcsb ip, [r1], #1
ldrcsb lr, [r1], #1
strmib r3, [r0], #1
strcsb ip, [r0], #1
strcsb lr, [r0], #1
ldmfd sp!, {r0, lr}
bx lr
#endif /* NEON_UNALIGNED_ACCESS */
11:
/* Simple arm-only copy loop to handle aligned copy operations */
stmfd sp!, {r4, r5, r6, r7, r8}
pld [r1, #(CACHE_LINE_SIZE * 2)]
/* Check alignment */
rsb r3, r1, #0
ands r3, #3
beq 2f
/* 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
* stall 2 cycles.
*/
movs r12, r3, lsl #31
sub r2, r2, r3 /* we know that r3 <= r2 because r2 >= 4 */
ldrmib r3, [r1], #1
ldrcsb r4, [r1], #1
ldrcsb r5, [r1], #1
strmib r3, [r0], #1
strcsb r4, [r0], #1
strcsb r5, [r0], #1
2:
subs r2, #32
blt 5f
pld [r1, #(CACHE_LINE_SIZE * 3)]
3: /* Main copy loop, copying 32 bytes at a time */
pld [r1, #(CACHE_LINE_SIZE * 4)]
ldmia r1!, {r3, r4, r5, r6, r7, r8, r12, lr}
subs r2, r2, #32
stmia r0!, {r3, r4, r5, r6, r7, r8, r12, lr}
bge 3b
5: /* Handle any remaining bytes */
adds r2, #32
beq 6f
movs r12, r2, lsl #28
ldmcsia r1!, {r3, r4, r5, r6} /* 16 bytes */
ldmmiia r1!, {r7, r8} /* 8 bytes */
stmcsia r0!, {r3, r4, r5, r6}
stmmiia r0!, {r7, r8}
movs r12, r2, lsl #30
ldrcs r3, [r1], #4 /* 4 bytes */
ldrmih r4, [r1], #2 /* 2 bytes */
strcs r3, [r0], #4
strmih r4, [r0], #2
tst r2, #0x1
ldrneb r3, [r1] /* last byte */
strneb r3, [r0]
6:
ldmfd sp!, {r4, r5, r6, r7, r8}
ldmfd sp!, {r0, pc}
END(memcpy)
#else /* __ARM_ARCH__ < 7 */
/*
* Optimized memcpy() for ARM.
*
* note that memcpy() always returns the destination pointer,
* so we have to preserve R0.
*/
ENTRY(memcpy)
/* The stack must always be 64-bits aligned to be compliant with the
* 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}
/* Making room for r5-r11 which will be spilled later */
.pad #28
sub sp, sp, #28
// preload the destination because we'll align it to a cache line
// with small writes. Also start the source "pump".
pld [r0, #0]
pld [r1, #0]
pld [r1, #32]
/* it simplifies things to take care of len<4 early */
cmp r2, #4
blo copy_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
/* 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
* stall 2 cycles.
*/
movs r12, r3, lsl #31
sub r2, r2, r3 /* we know that r3 <= r2 because r2 >= 4 */
ldrmib r3, [r1], #1
ldrcsb r4, [r1], #1
ldrcsb r12,[r1], #1
strmib r3, [r0], #1
strcsb r4, [r0], #1
strcsb r12,[r0], #1
src_aligned:
/* see if src and dst are aligned together (congruent) */
eor r12, r0, r1
tst r12, #3
bne non_congruent
/* Use post-incriment mode for stm to spill r5-r11 to reserved stack
* frame. Don't update sp.
*/
stmea sp, {r5-r11}
/* align the destination to a cache-line */
rsb r3, r0, #0
ands r3, r3, #0x1C
beq congruent_aligned32
cmp r3, r2
andhi r3, r2, #0x1C
/* conditionnaly copies 0 to 7 words (length in r3) */
movs r12, r3, lsl #28
ldmcsia r1!, {r4, r5, r6, r7} /* 16 bytes */
ldmmiia r1!, {r8, r9} /* 8 bytes */
stmcsia r0!, {r4, r5, r6, r7}
stmmiia r0!, {r8, r9}
tst r3, #0x4
ldrne r10,[r1], #4 /* 4 bytes */
strne r10,[r0], #4
sub r2, r2, r3
congruent_aligned32:
/*
* here source is aligned to 32 bytes.
*/
cached_aligned32:
subs r2, r2, #32
blo less_than_32_left
/*
* We preload a cache-line up to 64 bytes ahead. On the 926, this will
* stall only until the requested world is fetched, but the linefill
* continues in the the background.
* While the linefill is going, we write our previous cache-line
* into the write-buffer (which should have some free space).
* When the linefill is done, the writebuffer will
* start dumping its content into memory
*
* While all this is going, we then load a full cache line into
* 8 registers, this cache line should be in the cache by now
* (or partly in the cache).
*
* This code should work well regardless of the source/dest alignment.
*
*/
// Align the preload register to a cache-line because the cpu does
// "critical word first" (the first word requested is loaded first).
bic r12, r1, #0x1F
add r12, r12, #64
1: ldmia r1!, { r4-r11 }
pld [r12, #64]
subs r2, r2, #32
// NOTE: if r12 is more than 64 ahead of r1, the following ldrhi
// for ARM9 preload will not be safely guarded by the preceding subs.
// When it is safely guarded the only possibility to have SIGSEGV here
// is because the caller overstates the length.
ldrhi r3, [r12], #32 /* cheap ARM9 preload */
stmia r0!, { r4-r11 }
bhs 1b
add r2, r2, #32
less_than_32_left:
/*
* less than 32 bytes left at this point (length in r2)
*/
/* skip all this if there is nothing to do, which should
* be a common case (if not executed the code below takes
* about 16 cycles)
*/
tst r2, #0x1F
beq 1f
/* conditionnaly copies 0 to 31 bytes */
movs r12, r2, lsl #28
ldmcsia r1!, {r4, r5, r6, r7} /* 16 bytes */
ldmmiia r1!, {r8, r9} /* 8 bytes */
stmcsia r0!, {r4, r5, r6, r7}
stmmiia r0!, {r8, r9}
movs r12, r2, lsl #30
ldrcs r3, [r1], #4 /* 4 bytes */
ldrmih r4, [r1], #2 /* 2 bytes */
strcs r3, [r0], #4
strmih r4, [r0], #2
tst r2, #0x1
ldrneb r3, [r1] /* last byte */
strneb r3, [r0]
/* we're done! restore everything and return */
1: ldmfd sp!, {r5-r11}
ldmfd sp!, {r0, r4, lr}
bx lr
/********************************************************************/
non_congruent:
/*
* here source is aligned to 4 bytes
* but destination is not.
*
* in the code below r2 is the number of bytes read
* (the number of bytes written is always smaller, because we have
* partial words in the shift queue)
*/
cmp r2, #4
blo copy_last_3_and_return
/* Use post-incriment mode for stm to spill r5-r11 to reserved stack
* frame. Don't update sp.
*/
stmea sp, {r5-r11}
/* compute shifts needed to align src to dest */
rsb r5, r0, #0
and r5, r5, #3 /* r5 = # bytes in partial words */
mov r12, r5, lsl #3 /* r12 = right */
rsb lr, r12, #32 /* lr = left */
/* read the first word */
ldr r3, [r1], #4
sub r2, r2, #4
/* write a partial word (0 to 3 bytes), such that destination
* becomes aligned to 32 bits (r5 = nb of words to copy for alignment)
*/
movs r5, r5, lsl #31
strmib r3, [r0], #1
movmi r3, r3, lsr #8
strcsb r3, [r0], #1
movcs r3, r3, lsr #8
strcsb r3, [r0], #1
movcs r3, r3, lsr #8
cmp r2, #4
blo partial_word_tail
/* Align destination to 32 bytes (cache line boundary) */
1: tst r0, #0x1c
beq 2f
ldr r5, [r1], #4
sub r2, r2, #4
orr r4, r3, r5, lsl lr
mov r3, r5, lsr r12
str r4, [r0], #4
cmp r2, #4
bhs 1b
blo partial_word_tail
/* copy 32 bytes at a time */
2: subs r2, r2, #32
blo less_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
* performance hit.
*/
cmp r12, #24
beq loop24
cmp r12, #8
beq loop8
loop16:
ldr r12, [r1], #4
1: mov r4, r12
ldmia r1!, { r5,r6,r7, r8,r9,r10,r11}
pld [r1, #64]
subs r2, r2, #32
ldrhs r12, [r1], #4
orr r3, r3, r4, lsl #16
mov r4, r4, lsr #16
orr r4, r4, r5, lsl #16
mov r5, r5, lsr #16
orr r5, r5, r6, lsl #16
mov r6, r6, lsr #16
orr r6, r6, r7, lsl #16
mov r7, r7, lsr #16
orr r7, r7, r8, lsl #16
mov r8, r8, lsr #16
orr r8, r8, r9, lsl #16
mov r9, r9, lsr #16
orr r9, r9, r10, lsl #16
mov r10, r10, lsr #16
orr r10, r10, r11, lsl #16
stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10}
mov r3, r11, lsr #16
bhs 1b
b less_than_thirtytwo
loop8:
ldr r12, [r1], #4
1: mov r4, r12
ldmia r1!, { r5,r6,r7, r8,r9,r10,r11}
pld [r1, #64]
subs r2, r2, #32
ldrhs r12, [r1], #4
orr r3, r3, r4, lsl #24
mov r4, r4, lsr #8
orr r4, r4, r5, lsl #24
mov r5, r5, lsr #8
orr r5, r5, r6, lsl #24
mov r6, r6, lsr #8
orr r6, r6, r7, lsl #24
mov r7, r7, lsr #8
orr r7, r7, r8, lsl #24
mov r8, r8, lsr #8
orr r8, r8, r9, lsl #24
mov r9, r9, lsr #8
orr r9, r9, r10, lsl #24
mov r10, r10, lsr #8
orr r10, r10, r11, lsl #24
stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10}
mov r3, r11, lsr #8
bhs 1b
b less_than_thirtytwo
loop24:
ldr r12, [r1], #4
1: mov r4, r12
ldmia r1!, { r5,r6,r7, r8,r9,r10,r11}
pld [r1, #64]
subs r2, r2, #32
ldrhs r12, [r1], #4
orr r3, r3, r4, lsl #8
mov r4, r4, lsr #24
orr r4, r4, r5, lsl #8
mov r5, r5, lsr #24
orr r5, r5, r6, lsl #8
mov r6, r6, lsr #24
orr r6, r6, r7, lsl #8
mov r7, r7, lsr #24
orr r7, r7, r8, lsl #8
mov r8, r8, lsr #24
orr r8, r8, r9, lsl #8
mov r9, r9, lsr #24
orr r9, r9, r10, lsl #8
mov r10, r10, lsr #24
orr r10, r10, r11, lsl #8
stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10}
mov r3, r11, lsr #24
bhs 1b
less_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
1: ldr r5, [r1], #4
sub r2, r2, #4
orr r4, r3, r5, lsl lr
mov r3, r5, lsr r12
str r4, [r0], #4
cmp r2, #4
bhs 1b
partial_word_tail:
/* we have a partial word in the input buffer */
movs r5, lr, lsl #(31-3)
strmib r3, [r0], #1
movmi r3, r3, lsr #8
strcsb r3, [r0], #1
movcs r3, r3, lsr #8
strcsb r3, [r0], #1
/* Refill spilled registers from the stack. Don't update sp. */
ldmfd sp, {r5-r11}
copy_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
ldrcsb r12,[r1]
strmib r2, [r0], #1
strcsb r3, [r0], #1
strcsb r12,[r0]
/* we're done! restore sp and spilled registers and return */
add sp, sp, #28
ldmfd sp!, {r0, r4, lr}
bx lr
END(memcpy)
#endif /* __ARM_ARCH__ < 7 */

View File

@ -0,0 +1,614 @@
/* Copyright (c) 2013, 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 Linaro Limited 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.
*/
/*
This memcpy routine is optimised for Cortex-A15 cores and takes advantage
of VFP or NEON when built with the appropriate flags.
Assumptions:
ARMv6 (ARMv7-a if using Neon)
ARM state
Unaligned accesses
LDRD/STRD support unaligned word accesses
*/
#include <machine/cpu-features.h>
#include <private/bionic_asm.h>
.syntax unified
/* This implementation requires ARM state. */
.arm
#ifdef __ARM_NEON__
.fpu neon
.arch armv7-a
# define FRAME_SIZE 4
# define USE_VFP
# define USE_NEON
#elif !defined (__SOFTFP__)
.arch armv6
.fpu vfpv2
# define FRAME_SIZE 32
# define USE_VFP
#else
.arch armv6
# define FRAME_SIZE 32
#endif
/* Old versions of GAS incorrectly implement the NEON align semantics. */
#ifdef BROKEN_ASM_NEON_ALIGN
#define ALIGN(addr, align) addr,:align
#else
#define ALIGN(addr, align) addr:align
#endif
#define PC_OFFSET 8 /* PC pipeline compensation. */
#define INSN_SIZE 4
/* Call parameters. */
#define dstin r0
#define src r1
#define count r2
/* Locals. */
#define tmp1 r3
#define dst ip
#define tmp2 r10
#ifndef USE_NEON
/* For bulk copies using GP registers. */
#define A_l r2 /* Call-clobbered. */
#define A_h r3 /* Call-clobbered. */
#define B_l r4
#define B_h r5
#define C_l r6
#define C_h r7
#define D_l r8
#define D_h r9
#endif
/* Number of lines ahead to pre-fetch data. If you change this the code
below will need adjustment to compensate. */
#define prefetch_lines 5
#ifdef USE_VFP
.macro cpy_line_vfp vreg, base
vstr \vreg, [dst, #\base]
vldr \vreg, [src, #\base]
vstr d0, [dst, #\base + 8]
vldr d0, [src, #\base + 8]
vstr d1, [dst, #\base + 16]
vldr d1, [src, #\base + 16]
vstr d2, [dst, #\base + 24]
vldr d2, [src, #\base + 24]
vstr \vreg, [dst, #\base + 32]
vldr \vreg, [src, #\base + prefetch_lines * 64 - 32]
vstr d0, [dst, #\base + 40]
vldr d0, [src, #\base + 40]
vstr d1, [dst, #\base + 48]
vldr d1, [src, #\base + 48]
vstr d2, [dst, #\base + 56]
vldr d2, [src, #\base + 56]
.endm
.macro cpy_tail_vfp vreg, base
vstr \vreg, [dst, #\base]
vldr \vreg, [src, #\base]
vstr d0, [dst, #\base + 8]
vldr d0, [src, #\base + 8]
vstr d1, [dst, #\base + 16]
vldr d1, [src, #\base + 16]
vstr d2, [dst, #\base + 24]
vldr d2, [src, #\base + 24]
vstr \vreg, [dst, #\base + 32]
vstr d0, [dst, #\base + 40]
vldr d0, [src, #\base + 40]
vstr d1, [dst, #\base + 48]
vldr d1, [src, #\base + 48]
vstr d2, [dst, #\base + 56]
vldr d2, [src, #\base + 56]
.endm
#endif
.p2align 6
ENTRY(memcpy)
mov dst, dstin /* Preserve dstin, we need to return it. */
cmp count, #64
bge .Lcpy_not_short
/* Deal with small copies quickly by dropping straight into the
exit block. */
.Ltail63unaligned:
#ifdef USE_NEON
and tmp1, count, #0x38
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
add pc, pc, tmp1
vld1.8 {d0}, [src]! /* 14 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 12 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 10 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 8 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 6 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 4 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 2 words to go. */
vst1.8 {d0}, [dst]!
tst count, #4
ldrne tmp1, [src], #4
strne tmp1, [dst], #4
#else
/* Copy up to 15 full words of data. May not be aligned. */
/* Cannot use VFP for unaligned data. */
and tmp1, count, #0x3c
add dst, dst, tmp1
add src, src, tmp1
rsb tmp1, tmp1, #(60 - PC_OFFSET/2 + INSN_SIZE/2)
/* Jump directly into the sequence below at the correct offset. */
add pc, pc, tmp1, lsl #1
ldr tmp1, [src, #-60] /* 15 words to go. */
str tmp1, [dst, #-60]
ldr tmp1, [src, #-56] /* 14 words to go. */
str tmp1, [dst, #-56]
ldr tmp1, [src, #-52]
str tmp1, [dst, #-52]
ldr tmp1, [src, #-48] /* 12 words to go. */
str tmp1, [dst, #-48]
ldr tmp1, [src, #-44]
str tmp1, [dst, #-44]
ldr tmp1, [src, #-40] /* 10 words to go. */
str tmp1, [dst, #-40]
ldr tmp1, [src, #-36]
str tmp1, [dst, #-36]
ldr tmp1, [src, #-32] /* 8 words to go. */
str tmp1, [dst, #-32]
ldr tmp1, [src, #-28]
str tmp1, [dst, #-28]
ldr tmp1, [src, #-24] /* 6 words to go. */
str tmp1, [dst, #-24]
ldr tmp1, [src, #-20]
str tmp1, [dst, #-20]
ldr tmp1, [src, #-16] /* 4 words to go. */
str tmp1, [dst, #-16]
ldr tmp1, [src, #-12]
str tmp1, [dst, #-12]
ldr tmp1, [src, #-8] /* 2 words to go. */
str tmp1, [dst, #-8]
ldr tmp1, [src, #-4]
str tmp1, [dst, #-4]
#endif
lsls count, count, #31
ldrhcs tmp1, [src], #2
ldrbne src, [src] /* Src is dead, use as a scratch. */
strhcs tmp1, [dst], #2
strbne src, [dst]
bx lr
.Lcpy_not_short:
/* At least 64 bytes to copy, but don't know the alignment yet. */
str tmp2, [sp, #-FRAME_SIZE]!
and tmp2, src, #7
and tmp1, dst, #7
cmp tmp1, tmp2
bne .Lcpy_notaligned
#ifdef USE_VFP
/* Magic dust alert! Force VFP on Cortex-A9. Experiments show
that the FP pipeline is much better at streaming loads and
stores. This is outside the critical loop. */
vmov.f32 s0, s0
#endif
/* SRC and DST have the same mutual 32-bit alignment, but we may
still need to pre-copy some bytes to get to natural alignment.
We bring DST into full 64-bit alignment. */
lsls tmp2, dst, #29
beq 1f
rsbs tmp2, tmp2, #0
sub count, count, tmp2, lsr #29
ldrmi tmp1, [src], #4
strmi tmp1, [dst], #4
lsls tmp2, tmp2, #2
ldrhcs tmp1, [src], #2
ldrbne tmp2, [src], #1
strhcs tmp1, [dst], #2
strbne tmp2, [dst], #1
1:
subs tmp2, count, #64 /* Use tmp2 for count. */
blt .Ltail63aligned
cmp tmp2, #512
bge .Lcpy_body_long
.Lcpy_body_medium: /* Count in tmp2. */
#ifdef USE_VFP
1:
vldr d0, [src, #0]
subs tmp2, tmp2, #64
vldr d1, [src, #8]
vstr d0, [dst, #0]
vldr d0, [src, #16]
vstr d1, [dst, #8]
vldr d1, [src, #24]
vstr d0, [dst, #16]
vldr d0, [src, #32]
vstr d1, [dst, #24]
vldr d1, [src, #40]
vstr d0, [dst, #32]
vldr d0, [src, #48]
vstr d1, [dst, #40]
vldr d1, [src, #56]
vstr d0, [dst, #48]
add src, src, #64
vstr d1, [dst, #56]
add dst, dst, #64
bge 1b
tst tmp2, #0x3f
beq .Ldone
.Ltail63aligned: /* Count in tmp2. */
and tmp1, tmp2, #0x38
add dst, dst, tmp1
add src, src, tmp1
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
add pc, pc, tmp1
vldr d0, [src, #-56] /* 14 words to go. */
vstr d0, [dst, #-56]
vldr d0, [src, #-48] /* 12 words to go. */
vstr d0, [dst, #-48]
vldr d0, [src, #-40] /* 10 words to go. */
vstr d0, [dst, #-40]
vldr d0, [src, #-32] /* 8 words to go. */
vstr d0, [dst, #-32]
vldr d0, [src, #-24] /* 6 words to go. */
vstr d0, [dst, #-24]
vldr d0, [src, #-16] /* 4 words to go. */
vstr d0, [dst, #-16]
vldr d0, [src, #-8] /* 2 words to go. */
vstr d0, [dst, #-8]
#else
sub src, src, #8
sub dst, dst, #8
1:
ldrd A_l, A_h, [src, #8]
strd A_l, A_h, [dst, #8]
ldrd A_l, A_h, [src, #16]
strd A_l, A_h, [dst, #16]
ldrd A_l, A_h, [src, #24]
strd A_l, A_h, [dst, #24]
ldrd A_l, A_h, [src, #32]
strd A_l, A_h, [dst, #32]
ldrd A_l, A_h, [src, #40]
strd A_l, A_h, [dst, #40]
ldrd A_l, A_h, [src, #48]
strd A_l, A_h, [dst, #48]
ldrd A_l, A_h, [src, #56]
strd A_l, A_h, [dst, #56]
ldrd A_l, A_h, [src, #64]!
strd A_l, A_h, [dst, #64]!
subs tmp2, tmp2, #64
bge 1b
tst tmp2, #0x3f
bne 1f
ldr tmp2,[sp], #FRAME_SIZE
bx lr
1:
add src, src, #8
add dst, dst, #8
.Ltail63aligned: /* Count in tmp2. */
/* Copy up to 7 d-words of data. Similar to Ltail63unaligned, but
we know that the src and dest are 32-bit aligned so we can use
LDRD/STRD to improve efficiency. */
/* TMP2 is now negative, but we don't care about that. The bottom
six bits still tell us how many bytes are left to copy. */
and tmp1, tmp2, #0x38
add dst, dst, tmp1
add src, src, tmp1
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
add pc, pc, tmp1
ldrd A_l, A_h, [src, #-56] /* 14 words to go. */
strd A_l, A_h, [dst, #-56]
ldrd A_l, A_h, [src, #-48] /* 12 words to go. */
strd A_l, A_h, [dst, #-48]
ldrd A_l, A_h, [src, #-40] /* 10 words to go. */
strd A_l, A_h, [dst, #-40]
ldrd A_l, A_h, [src, #-32] /* 8 words to go. */
strd A_l, A_h, [dst, #-32]
ldrd A_l, A_h, [src, #-24] /* 6 words to go. */
strd A_l, A_h, [dst, #-24]
ldrd A_l, A_h, [src, #-16] /* 4 words to go. */
strd A_l, A_h, [dst, #-16]
ldrd A_l, A_h, [src, #-8] /* 2 words to go. */
strd A_l, A_h, [dst, #-8]
#endif
tst tmp2, #4
ldrne tmp1, [src], #4
strne tmp1, [dst], #4
lsls tmp2, tmp2, #31 /* Count (tmp2) now dead. */
ldrhcs tmp1, [src], #2
ldrbne tmp2, [src]
strhcs tmp1, [dst], #2
strbne tmp2, [dst]
.Ldone:
ldr tmp2, [sp], #FRAME_SIZE
bx lr
.Lcpy_body_long: /* Count in tmp2. */
/* Long copy. We know that there's at least (prefetch_lines * 64)
bytes to go. */
#ifdef USE_VFP
/* Don't use PLD. Instead, read some data in advance of the current
copy position into a register. This should act like a PLD
operation but we won't have to repeat the transfer. */
vldr d3, [src, #0]
vldr d4, [src, #64]
vldr d5, [src, #128]
vldr d6, [src, #192]
vldr d7, [src, #256]
vldr d0, [src, #8]
vldr d1, [src, #16]
vldr d2, [src, #24]
add src, src, #32
subs tmp2, tmp2, #prefetch_lines * 64 * 2
blt 2f
1:
cpy_line_vfp d3, 0
cpy_line_vfp d4, 64
cpy_line_vfp d5, 128
add dst, dst, #3 * 64
add src, src, #3 * 64
cpy_line_vfp d6, 0
cpy_line_vfp d7, 64
add dst, dst, #2 * 64
add src, src, #2 * 64
subs tmp2, tmp2, #prefetch_lines * 64
bge 1b
2:
cpy_tail_vfp d3, 0
cpy_tail_vfp d4, 64
cpy_tail_vfp d5, 128
add src, src, #3 * 64
add dst, dst, #3 * 64
cpy_tail_vfp d6, 0
vstr d7, [dst, #64]
vldr d7, [src, #64]
vstr d0, [dst, #64 + 8]
vldr d0, [src, #64 + 8]
vstr d1, [dst, #64 + 16]
vldr d1, [src, #64 + 16]
vstr d2, [dst, #64 + 24]
vldr d2, [src, #64 + 24]
vstr d7, [dst, #64 + 32]
add src, src, #96
vstr d0, [dst, #64 + 40]
vstr d1, [dst, #64 + 48]
vstr d2, [dst, #64 + 56]
add dst, dst, #128
add tmp2, tmp2, #prefetch_lines * 64
b .Lcpy_body_medium
#else
/* Long copy. Use an SMS style loop to maximize the I/O
bandwidth of the core. We don't have enough spare registers
to synthesise prefetching, so use PLD operations. */
/* Pre-bias src and dst. */
sub src, src, #8
sub dst, dst, #8
pld [src, #8]
pld [src, #72]
subs tmp2, tmp2, #64
pld [src, #136]
ldrd A_l, A_h, [src, #8]
strd B_l, B_h, [sp, #8]
ldrd B_l, B_h, [src, #16]
strd C_l, C_h, [sp, #16]
ldrd C_l, C_h, [src, #24]
strd D_l, D_h, [sp, #24]
pld [src, #200]
ldrd D_l, D_h, [src, #32]!
b 1f
.p2align 6
2:
pld [src, #232]
strd A_l, A_h, [dst, #40]
ldrd A_l, A_h, [src, #40]
strd B_l, B_h, [dst, #48]
ldrd B_l, B_h, [src, #48]
strd C_l, C_h, [dst, #56]
ldrd C_l, C_h, [src, #56]
strd D_l, D_h, [dst, #64]!
ldrd D_l, D_h, [src, #64]!
subs tmp2, tmp2, #64
1:
strd A_l, A_h, [dst, #8]
ldrd A_l, A_h, [src, #8]
strd B_l, B_h, [dst, #16]
ldrd B_l, B_h, [src, #16]
strd C_l, C_h, [dst, #24]
ldrd C_l, C_h, [src, #24]
strd D_l, D_h, [dst, #32]
ldrd D_l, D_h, [src, #32]
bcs 2b
/* Save the remaining bytes and restore the callee-saved regs. */
strd A_l, A_h, [dst, #40]
add src, src, #40
strd B_l, B_h, [dst, #48]
ldrd B_l, B_h, [sp, #8]
strd C_l, C_h, [dst, #56]
ldrd C_l, C_h, [sp, #16]
strd D_l, D_h, [dst, #64]
ldrd D_l, D_h, [sp, #24]
add dst, dst, #72
tst tmp2, #0x3f
bne .Ltail63aligned
ldr tmp2, [sp], #FRAME_SIZE
bx lr
#endif
.Lcpy_notaligned:
pld [src]
pld [src, #64]
/* There's at least 64 bytes to copy, but there is no mutual
alignment. */
/* Bring DST to 64-bit alignment. */
lsls tmp2, dst, #29
pld [src, #(2 * 64)]
beq 1f
rsbs tmp2, tmp2, #0
sub count, count, tmp2, lsr #29
ldrmi tmp1, [src], #4
strmi tmp1, [dst], #4
lsls tmp2, tmp2, #2
ldrbne tmp1, [src], #1
ldrhcs tmp2, [src], #2
strbne tmp1, [dst], #1
strhcs tmp2, [dst], #2
1:
pld [src, #(3 * 64)]
subs count, count, #64
ldrmi tmp2, [sp], #FRAME_SIZE
bmi .Ltail63unaligned
pld [src, #(4 * 64)]
#ifdef USE_NEON
vld1.8 {d0-d3}, [src]!
vld1.8 {d4-d7}, [src]!
subs count, count, #64
bmi 2f
1:
pld [src, #(4 * 64)]
vst1.8 {d0-d3}, [ALIGN (dst, 64)]!
vld1.8 {d0-d3}, [src]!
vst1.8 {d4-d7}, [ALIGN (dst, 64)]!
vld1.8 {d4-d7}, [src]!
subs count, count, #64
bpl 1b
2:
vst1.8 {d0-d3}, [ALIGN (dst, 64)]!
vst1.8 {d4-d7}, [ALIGN (dst, 64)]!
ands count, count, #0x3f
#else
/* Use an SMS style loop to maximize the I/O bandwidth. */
sub src, src, #4
sub dst, dst, #8
subs tmp2, count, #64 /* Use tmp2 for count. */
ldr A_l, [src, #4]
ldr A_h, [src, #8]
strd B_l, B_h, [sp, #8]
ldr B_l, [src, #12]
ldr B_h, [src, #16]
strd C_l, C_h, [sp, #16]
ldr C_l, [src, #20]
ldr C_h, [src, #24]
strd D_l, D_h, [sp, #24]
ldr D_l, [src, #28]
ldr D_h, [src, #32]!
b 1f
.p2align 6
2:
pld [src, #(5 * 64) - (32 - 4)]
strd A_l, A_h, [dst, #40]
ldr A_l, [src, #36]
ldr A_h, [src, #40]
strd B_l, B_h, [dst, #48]
ldr B_l, [src, #44]
ldr B_h, [src, #48]
strd C_l, C_h, [dst, #56]
ldr C_l, [src, #52]
ldr C_h, [src, #56]
strd D_l, D_h, [dst, #64]!
ldr D_l, [src, #60]
ldr D_h, [src, #64]!
subs tmp2, tmp2, #64
1:
strd A_l, A_h, [dst, #8]
ldr A_l, [src, #4]
ldr A_h, [src, #8]
strd B_l, B_h, [dst, #16]
ldr B_l, [src, #12]
ldr B_h, [src, #16]
strd C_l, C_h, [dst, #24]
ldr C_l, [src, #20]
ldr C_h, [src, #24]
strd D_l, D_h, [dst, #32]
ldr D_l, [src, #28]
ldr D_h, [src, #32]
bcs 2b
/* Save the remaining bytes and restore the callee-saved regs. */
strd A_l, A_h, [dst, #40]
add src, src, #36
strd B_l, B_h, [dst, #48]
ldrd B_l, B_h, [sp, #8]
strd C_l, C_h, [dst, #56]
ldrd C_l, C_h, [sp, #16]
strd D_l, D_h, [dst, #64]
ldrd D_l, D_h, [sp, #24]
add dst, dst, #72
ands count, tmp2, #0x3f
#endif
ldr tmp2, [sp], #FRAME_SIZE
bne .Ltail63unaligned
bx lr
END(memcpy)

View File

@ -1,42 +0,0 @@
/*
* Copyright (C) 2015 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.
*/
// Export this to maintain ABI compatibilty with libgcc, since compiler-rt
// doesn't use a table-driven implementation of __popcount.
const unsigned char __popcount_tab[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3,
3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4,
3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4,
4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5,
3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2,
2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,
4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5,
5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5,
5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};

View File

@ -1,3 +1,6 @@
/* $OpenBSD: setjmp.S,v 1.2 2004/02/01 05:40:52 drahn Exp $ */
/* $NetBSD: setjmp.S,v 1.5 2003/04/05 23:08:51 bjh21 Exp $ */
/* /*
* Copyright (c) 1997 Mark Brinicombe * Copyright (c) 1997 Mark Brinicombe
* Copyright (c) 2010 Android Open Source Project. * Copyright (c) 2010 Android Open Source Project.
@ -32,203 +35,119 @@
*/ */
#include <private/bionic_asm.h> #include <private/bionic_asm.h>
#include <machine/setjmp.h>
#include <machine/cpu-features.h>
// According to the ARM AAPCS document, we only need to save /*
// the following registers: * C library -- setjmp, longjmp
// *
// Core r4-r14 * longjmp(a,v)
// * will generate a "return(v)" from the last call to
// VFP d8-d15 (see section 5.1.2.1) * setjmp(a)
// * by restoring registers from the stack.
// Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine * The previous signal state is restored.
// calls; registers s0-s15 (d0-d7, q0-q3) do not need to be preserved */
// (and can be used for passing arguments or returning results in standard
// procedure-call variants). Registers d16-d31 (q8-q15), if present, do
// not need to be preserved.
//
// FPSCR saved because glibc does.
// The internal structure of a jmp_buf is totally private.
// Current layout (may change in the future):
//
// word name description
// 0 sigflag/cookie setjmp cookie in top 31 bits, signal mask flag in low bit
// 1 sigmask signal mask (not used with _setjmp / _longjmp)
// 2 float_base base of float registers (d8 to d15)
// 18 float_state floating-point status and control register
// 19 core_base base of core registers (r4 to r14)
// 30 reserved reserved entries (room to grow)
// 64
//
// NOTE: float_base must be at an even word index, since the
// FP registers will be loaded/stored with instructions
// that expect 8-byte alignment.
#define _JB_SIGFLAG 0
#define _JB_SIGMASK (_JB_SIGFLAG+1)
#define _JB_FLOAT_BASE (_JB_SIGMASK+1)
#define _JB_FLOAT_STATE (_JB_FLOAT_BASE + (15-8+1)*2)
#define _JB_CORE_BASE (_JB_FLOAT_STATE+1)
ENTRY(setjmp) ENTRY(setjmp)
mov r1, #1 /* Block all signals and retrieve the old signal mask */
b sigsetjmp stmfd sp!, {r0, r14}
END(setjmp)
ENTRY(_setjmp)
mov r1, #0
b sigsetjmp
END(_setjmp)
#define MANGLE_REGISTERS 1
.macro m_mangle_registers reg
#if MANGLE_REGISTERS
eor r4, r4, \reg
eor r5, r5, \reg
eor r6, r6, \reg
eor r7, r7, \reg
eor r8, r8, \reg
eor r9, r9, \reg
eor r10, r10, \reg
eor r11, r11, \reg
eor r12, r12, \reg
eor r13, r13, \reg
eor r14, r14, \reg
#endif
.endm
.macro m_unmangle_registers reg
m_mangle_registers \reg
.endm
// int sigsetjmp(sigjmp_buf env, int save_signal_mask);
ENTRY(sigsetjmp)
stmfd sp!, {r0, lr}
.cfi_def_cfa_offset 8 .cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0 .cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4 .cfi_rel_offset r14, 4
mov r0, #0x00000000
mov r0, r1 bl PIC_SYM(sigblock, PLT)
bl __bionic_setjmp_cookie_get
mov r1, r0 mov r1, r0
ldmfd sp, {r0} ldmfd sp!, {r0, r14}
.cfi_def_cfa_offset 0
// Save the setjmp cookie for later. /* Store signal mask */
bic r2, r1, #1 str r1, [r0, #(_JB_SIGMASK * 4)]
stmfd sp!, {r2}
.cfi_adjust_cfa_offset 4
// Record the setjmp cookie and whether or not we're saving the signal mask. ldr r1, .Lsetjmp_magic
str r1, [r0, #(_JB_SIGFLAG * 4)] str r1, [r0, #(_JB_MAGIC * 4)]
// Do we need to save the signal mask? /* Store core registers */
tst r1, #1
beq 1f
// Align the stack.
sub sp, #4
.cfi_adjust_cfa_offset 4
// Save the current signal mask.
add r2, r0, #(_JB_SIGMASK * 4)
mov r0, #2 // SIG_SETMASK
mov r1, #0
bl sigprocmask
// Unalign the stack.
add sp, #4
.cfi_adjust_cfa_offset -4
1:
ldmfd sp!, {r2}
.cfi_adjust_cfa_offset -4
ldmfd sp!, {r0, lr}
.cfi_adjust_cfa_offset -8
.cfi_restore r0
.cfi_restore lr
// Save core registers.
add r1, r0, #(_JB_CORE_BASE * 4) add r1, r0, #(_JB_CORE_BASE * 4)
m_mangle_registers r2 stmia r1, {r4-r14}
// ARM deprecates using sp in the register list for stmia. #ifdef __ARM_HAVE_VFP
stmia r1, {r4-r12, lr} /* Store floating-point registers */
str sp, [r1, #(10 * 4)]
m_unmangle_registers r2
// Save floating-point registers.
add r1, r0, #(_JB_FLOAT_BASE * 4) add r1, r0, #(_JB_FLOAT_BASE * 4)
vstmia r1, {d8-d15} vstmia r1, {d8-d15}
/* Store floating-point state */
// Save floating-point state.
fmrx r1, fpscr fmrx r1, fpscr
str r1, [r0, #(_JB_FLOAT_STATE * 4)] str r1, [r0, #(_JB_FLOAT_STATE * 4)]
#endif /* __ARM_HAVE_VFP */
mov r0, #0 mov r0, #0x00000000
bx lr bx lr
END(sigsetjmp) END(setjmp)
// void siglongjmp(sigjmp_buf env, int value); .Lsetjmp_magic:
ENTRY(siglongjmp) .word _JB_MAGIC_SETJMP
stmfd sp!, {r0, r1, lr}
ENTRY(longjmp)
ldr r2, .Lsetjmp_magic
ldr r3, [r0, #(_JB_MAGIC * 4)]
teq r2, r3
bne botch
/* Fetch signal mask */
ldr r2, [r0, #(_JB_SIGMASK * 4)]
/* Set signal mask */
stmfd sp!, {r0, r1, r14}
.cfi_def_cfa_offset 12 .cfi_def_cfa_offset 12
.cfi_rel_offset r0, 0 .cfi_rel_offset r0, 0
.cfi_rel_offset r1, 4 .cfi_rel_offset r1, 4
.cfi_rel_offset lr, 8 .cfi_rel_offset r14, 8
sub sp, sp, #4 /* align the stack */
.cfi_adjust_cfa_offset 4
// Fetch the signal flag. mov r0, r2
ldr r1, [r0, #(_JB_SIGFLAG * 4)] bl PIC_SYM(sigsetmask, PLT)
// Do we need to restore the signal mask? add sp, sp, #4 /* unalign the stack */
ands r1, r1, #1 .cfi_adjust_cfa_offset -4
beq 1f ldmfd sp!, {r0, r1, r14}
.cfi_def_cfa_offset 0
// Restore the signal mask. #ifdef __ARM_HAVE_VFP
ldr r0, [r0, #(_JB_SIGMASK * 4)] /* Restore floating-point registers */
bl sigsetmask
1:
ldmfd sp!, {r0, r1, lr}
.cfi_adjust_cfa_offset -12
.cfi_restore r0
.cfi_restore r1
.cfi_restore lr
// Restore floating-point registers.
add r2, r0, #(_JB_FLOAT_BASE * 4) add r2, r0, #(_JB_FLOAT_BASE * 4)
vldmia r2, {d8-d15} vldmia r2, {d8-d15}
/* Restore floating-point state */
// Restore floating-point state.
ldr r2, [r0, #(_JB_FLOAT_STATE * 4)] ldr r2, [r0, #(_JB_FLOAT_STATE * 4)]
fmxr fpscr, r2 fmxr fpscr, r2
#endif /* __ARM_HAVE_VFP */
// Restore core registers. /* Restore core registers */
ldr r3, [r0, #(_JB_SIGFLAG * 4)]
bic r3, r3, #1
add r2, r0, #(_JB_CORE_BASE * 4) add r2, r0, #(_JB_CORE_BASE * 4)
ldmia r2, {r4-r14}
// ARM deprecates using sp in the register list for ldmia. /* Validate sp and r14 */
ldmia r2, {r4-r12, lr} teq sp, #0
ldr sp, [r2, #(10 * 4)] teqne r14, #0
m_unmangle_registers r3 beq botch
// Save the return value/address and check the setjmp cookie. /* Set return value */
stmfd sp!, {r1, lr}
.cfi_adjust_cfa_offset 8
.cfi_rel_offset lr, 4
mov r0, r3
bl __bionic_setjmp_cookie_check
// Restore return value/address. mov r0, r1
ldmfd sp!, {r0, lr} teq r0, #0x00000000
.cfi_adjust_cfa_offset -8 moveq r0, #0x00000001
.cfi_restore lr
teq r0, #0
moveq r0, #1
bx lr bx lr
END(siglongjmp) #ifdef __ARM_26__
mov r15, r14
#else
mov r15, r14
#endif
ALIAS_SYMBOL(longjmp, siglongjmp) /* validation failed, die die die. */
ALIAS_SYMBOL(_longjmp, siglongjmp) botch:
bl PIC_SYM(longjmperror, PLT)
bl PIC_SYM(abort, PLT)
b . - 8 /* Cannot get here */
END(longjmp)

View File

@ -0,0 +1,66 @@
/* $OpenBSD: sigsetjmp.S,v 1.2 2004/02/01 05:40:52 drahn Exp $ */
/* $NetBSD: sigsetjmp.S,v 1.3 2002/08/17 19:54:30 thorpej Exp $ */
/*
* Copyright (c) 1997 Mark Brinicombe
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Mark Brinicombe
* 4. Neither the name of the University 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 AUTHOR 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 AUTHOR 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 _ALIGN_TEXT .align 0
#include <private/bionic_asm.h>
#include <machine/setjmp.h>
/*
* C library -- sigsetjmp, siglongjmp
*
* longjmp(a,v)
* will generate a "return(v)" from the last call to
* setjmp(a, m)
* by restoring registers from the stack.
* The previous signal state is restored.
*/
ENTRY(sigsetjmp)
teq r1, #0
beq PIC_SYM(_setjmp, PLT)
b PIC_SYM(setjmp, PLT)
END(sigsetjmp)
.L_setjmp_magic:
.word _JB_MAGIC__SETJMP
ENTRY(siglongjmp)
ldr r2, .L_setjmp_magic
ldr r3, [r0]
teq r2, r3
beq PIC_SYM(_longjmp, PLT)
b PIC_SYM(longjmp, PLT)
END(siglongjmp)

View File

@ -0,0 +1,317 @@
/*
* Copyright (c) 2011 The Android Open Source Project
* Copyright (c) 2008 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 <machine/cpu-features.h>
#include <private/bionic_asm.h>
.text
#ifdef __ARMEB__
#define SHFT2LSB lsl
#define SHFT2LSBEQ lsleq
#define SHFT2MSB lsr
#define SHFT2MSBEQ lsreq
#define MSB 0x000000ff
#define LSB 0xff000000
#else
#define SHFT2LSB lsr
#define SHFT2LSBEQ lsreq
#define SHFT2MSB lsl
#define SHFT2MSBEQ lsleq
#define MSB 0xff000000
#define LSB 0x000000ff
#endif
#define magic1(REG) REG
#define magic2(REG) REG, lsl #7
ENTRY(strcmp)
pld [r0, #0]
pld [r1, #0]
eor r2, r0, r1
tst r2, #3
/* Strings not at same byte offset from a word boundary. */
bne .Lstrcmp_unaligned
ands r2, r0, #3
bic r0, r0, #3
bic r1, r1, #3
ldr ip, [r0], #4
it eq
ldreq r3, [r1], #4
beq 1f
/* Although s1 and s2 have identical initial alignment, they are
* not currently word aligned. Rather than comparing bytes,
* make sure that any bytes fetched from before the addressed
* bytes are forced to 0xff. Then they will always compare
* equal.
*/
eor r2, r2, #3
lsl r2, r2, #3
mvn r3, #MSB
SHFT2LSB r2, r3, r2
ldr r3, [r1], #4
orr ip, ip, r2
orr r3, r3, r2
1:
/* Load the 'magic' constant 0x01010101. */
str r4, [sp, #-4]!
mov r4, #1
orr r4, r4, r4, lsl #8
orr r4, r4, r4, lsl #16
.p2align 2
4:
pld [r0, #8]
pld [r1, #8]
sub r2, ip, magic1(r4)
cmp ip, r3
itttt eq
/* check for any zero bytes in first word */
biceq r2, r2, ip
tsteq r2, magic2(r4)
ldreq ip, [r0], #4
ldreq r3, [r1], #4
beq 4b
2:
/* There's a zero or a different byte in the word */
SHFT2MSB r0, ip, #24
SHFT2LSB ip, ip, #8
cmp r0, #1
it cs
cmpcs r0, r3, SHFT2MSB #24
it eq
SHFT2LSBEQ r3, r3, #8
beq 2b
/* On a big-endian machine, r0 contains the desired byte in bits
* 0-7; on a little-endian machine they are in bits 24-31. In
* both cases the other bits in r0 are all zero. For r3 the
* interesting byte is at the other end of the word, but the
* other bits are not necessarily zero. We need a signed result
* representing the differnece in the unsigned bytes, so for the
* little-endian case we can't just shift the interesting bits up.
*/
#ifdef __ARMEB__
sub r0, r0, r3, lsr #24
#else
and r3, r3, #255
/* No RSB instruction in Thumb2 */
#ifdef __thumb2__
lsr r0, r0, #24
sub r0, r0, r3
#else
rsb r0, r3, r0, lsr #24
#endif
#endif
ldr r4, [sp], #4
bx lr
.Lstrcmp_unaligned:
wp1 .req r0
wp2 .req r1
b1 .req r2
w1 .req r4
w2 .req r5
t1 .req ip
@ r3 is scratch
/* First of all, compare bytes until wp1(sp1) is word-aligned. */
1:
tst wp1, #3
beq 2f
ldrb r2, [wp1], #1
ldrb r3, [wp2], #1
cmp r2, #1
it cs
cmpcs r2, r3
beq 1b
sub r0, r2, r3
bx lr
2:
str r5, [sp, #-4]!
str r4, [sp, #-4]!
mov b1, #1
orr b1, b1, b1, lsl #8
orr b1, b1, b1, lsl #16
and t1, wp2, #3
bic wp2, wp2, #3
ldr w1, [wp1], #4
ldr w2, [wp2], #4
cmp t1, #2
beq 2f
bhi 3f
/* Critical inner Loop: Block with 3 bytes initial overlap */
.p2align 2
1:
bic t1, w1, #MSB
cmp t1, w2, SHFT2LSB #8
sub r3, w1, b1
bic r3, r3, w1
bne 4f
ands r3, r3, b1, lsl #7
it eq
ldreq w2, [wp2], #4
bne 5f
eor t1, t1, w1
cmp t1, w2, SHFT2MSB #24
bne 6f
ldr w1, [wp1], #4
b 1b
4:
SHFT2LSB w2, w2, #8
b 8f
5:
#ifdef __ARMEB__
/* The syndrome value may contain false ones if the string ends
* with the bytes 0x01 0x00
*/
tst w1, #0xff000000
itt ne
tstne w1, #0x00ff0000
tstne w1, #0x0000ff00
beq 7f
#else
bics r3, r3, #0xff000000
bne 7f
#endif
ldrb w2, [wp2]
SHFT2LSB t1, w1, #24
#ifdef __ARMEB__
lsl w2, w2, #24
#endif
b 8f
6:
SHFT2LSB t1, w1, #24
and w2, w2, #LSB
b 8f
/* Critical inner Loop: Block with 2 bytes initial overlap */
.p2align 2
2:
SHFT2MSB t1, w1, #16
sub r3, w1, b1
SHFT2LSB t1, t1, #16
bic r3, r3, w1
cmp t1, w2, SHFT2LSB #16
bne 4f
ands r3, r3, b1, lsl #7
it eq
ldreq w2, [wp2], #4
bne 5f
eor t1, t1, w1
cmp t1, w2, SHFT2MSB #16
bne 6f
ldr w1, [wp1], #4
b 2b
5:
#ifdef __ARMEB__
/* The syndrome value may contain false ones if the string ends
* with the bytes 0x01 0x00
*/
tst w1, #0xff000000
it ne
tstne w1, #0x00ff0000
beq 7f
#else
lsls r3, r3, #16
bne 7f
#endif
ldrh w2, [wp2]
SHFT2LSB t1, w1, #16
#ifdef __ARMEB__
lsl w2, w2, #16
#endif
b 8f
6:
SHFT2MSB w2, w2, #16
SHFT2LSB t1, w1, #16
4:
SHFT2LSB w2, w2, #16
b 8f
/* Critical inner Loop: Block with 1 byte initial overlap */
.p2align 2
3:
and t1, w1, #LSB
cmp t1, w2, SHFT2LSB #24
sub r3, w1, b1
bic r3, r3, w1
bne 4f
ands r3, r3, b1, lsl #7
it eq
ldreq w2, [wp2], #4
bne 5f
eor t1, t1, w1
cmp t1, w2, SHFT2MSB #8
bne 6f
ldr w1, [wp1], #4
b 3b
4:
SHFT2LSB w2, w2, #24
b 8f
5:
/* The syndrome value may contain false ones if the string ends
* with the bytes 0x01 0x00
*/
tst w1, #LSB
beq 7f
ldr w2, [wp2], #4
6:
SHFT2LSB t1, w1, #8
bic w2, w2, #MSB
b 8f
7:
mov r0, #0
ldr r4, [sp], #4
ldr r5, [sp], #4
bx lr
8:
and r2, t1, #LSB
and r0, w2, #LSB
cmp r0, #1
it cs
cmpcs r0, r2
itt eq
SHFT2LSBEQ t1, t1, #8
SHFT2LSBEQ w2, w2, #8
beq 8b
sub r0, r2, r0
ldr r4, [sp], #4
ldr r5, [sp], #4
bx lr
END(strcmp)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015 The Android Open Source Project * Copyright (C) 2013 The Android Open Source Project
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -26,7 +26,191 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
// Indicate which memcpy base file to include. #include <private/bionic_asm.h>
#define MEMCPY_BASE "memcpy_base.S" #include <private/libc_events.h>
#include "__strcat_chk_common.S" .syntax unified
.thumb
.thumb_func
// Get the length of src string, then get the source of the dst string.
// Check that the two lengths together don't exceed the threshold, then
// do a memcpy of the data.
ENTRY(__strcat_chk)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
push {r4, r5}
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
mov lr, r2
// Save the dst register to r5
mov r5, r0
// Zero out r4
eor r4, r4, r4
// r1 contains the address of the string to count.
.L_strlen_start:
mov r0, r1
ands r3, r1, #7
beq .L_mainloop
// Align to a double word (64 bits).
rsb r3, r3, #8
lsls ip, r3, #31
beq .L_align_to_32
ldrb r2, [r1], #1
cbz r2, .L_update_count_and_finish
.L_align_to_32:
bcc .L_align_to_64
ands ip, r3, #2
beq .L_align_to_64
ldrb r2, [r1], #1
cbz r2, .L_update_count_and_finish
ldrb r2, [r1], #1
cbz r2, .L_update_count_and_finish
.L_align_to_64:
tst r3, #4
beq .L_mainloop
ldr r3, [r1], #4
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .L_zero_in_second_register
.p2align 2
.L_mainloop:
ldrd r2, r3, [r1], #8
pld [r1, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .L_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .L_zero_in_second_register
b .L_mainloop
.L_update_count_and_finish:
sub r3, r1, r0
sub r3, r3, #1
b .L_finish
.L_zero_in_first_register:
sub r3, r1, r0
lsls r2, ip, #17
bne .L_sub8_and_finish
bcs .L_sub7_and_finish
lsls ip, ip, #1
bne .L_sub6_and_finish
sub r3, r3, #5
b .L_finish
.L_sub8_and_finish:
sub r3, r3, #8
b .L_finish
.L_sub7_and_finish:
sub r3, r3, #7
b .L_finish
.L_sub6_and_finish:
sub r3, r3, #6
b .L_finish
.L_zero_in_second_register:
sub r3, r1, r0
lsls r2, ip, #17
bne .L_sub4_and_finish
bcs .L_sub3_and_finish
lsls ip, ip, #1
bne .L_sub2_and_finish
sub r3, r3, #1
b .L_finish
.L_sub4_and_finish:
sub r3, r3, #4
b .L_finish
.L_sub3_and_finish:
sub r3, r3, #3
b .L_finish
.L_sub2_and_finish:
sub r3, r3, #2
.L_finish:
cmp r4, #0
bne .L_strlen_done
// Time to get the dst string length.
mov r1, r5
// Save the original source address to r5.
mov r5, r0
// Save the current length (adding 1 for the terminator).
add r4, r3, #1
b .L_strlen_start
// r0 holds the pointer to the dst string.
// r3 holds the dst string length.
// r4 holds the src string length + 1.
.L_strlen_done:
add r2, r3, r4
cmp r2, lr
bhi __strcat_chk_failed
// Set up the registers for the memcpy code.
mov r1, r5
pld [r1, #64]
mov r2, r4
add r0, r0, r3
pop {r4, r5}
END(__strcat_chk)
#define MEMCPY_BASE __strcat_chk_memcpy_base
#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
#include "memcpy_base.S"
ENTRY_PRIVATE(__strcat_chk_failed)
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
ldr r0, error_message
ldr r1, error_code
1:
add r0, pc
bl __fortify_chk_fail
error_code:
.word BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+4)
END(__strcat_chk_failed)
.data
error_string:
.string "strcat: prevented write past end of buffer"

View File

@ -1,212 +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 <private/bionic_asm.h>
#include <private/libc_events.h>
.syntax unified
.thumb
.thumb_func
// Get the length of src string, then get the source of the dst string.
// Check that the two lengths together don't exceed the threshold, then
// do a memcpy of the data.
ENTRY(__strcat_chk)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
push {r4, r5}
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
mov lr, r2
// Save the dst register to r5
mov r5, r0
// Zero out r4
eor r4, r4, r4
// r1 contains the address of the string to count.
.L_strlen_start:
mov r0, r1
ands r3, r1, #7
beq .L_mainloop
// Align to a double word (64 bits).
rsb r3, r3, #8
lsls ip, r3, #31
beq .L_align_to_32
ldrb r2, [r1], #1
cbz r2, .L_update_count_and_finish
.L_align_to_32:
bcc .L_align_to_64
ands ip, r3, #2
beq .L_align_to_64
ldrb r2, [r1], #1
cbz r2, .L_update_count_and_finish
ldrb r2, [r1], #1
cbz r2, .L_update_count_and_finish
.L_align_to_64:
tst r3, #4
beq .L_mainloop
ldr r3, [r1], #4
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .L_zero_in_second_register
.p2align 2
.L_mainloop:
ldrd r2, r3, [r1], #8
pld [r1, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .L_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .L_zero_in_second_register
b .L_mainloop
.L_update_count_and_finish:
sub r3, r1, r0
sub r3, r3, #1
b .L_finish
.L_zero_in_first_register:
sub r3, r1, r0
lsls r2, ip, #17
bne .L_sub8_and_finish
bcs .L_sub7_and_finish
lsls ip, ip, #1
bne .L_sub6_and_finish
sub r3, r3, #5
b .L_finish
.L_sub8_and_finish:
sub r3, r3, #8
b .L_finish
.L_sub7_and_finish:
sub r3, r3, #7
b .L_finish
.L_sub6_and_finish:
sub r3, r3, #6
b .L_finish
.L_zero_in_second_register:
sub r3, r1, r0
lsls r2, ip, #17
bne .L_sub4_and_finish
bcs .L_sub3_and_finish
lsls ip, ip, #1
bne .L_sub2_and_finish
sub r3, r3, #1
b .L_finish
.L_sub4_and_finish:
sub r3, r3, #4
b .L_finish
.L_sub3_and_finish:
sub r3, r3, #3
b .L_finish
.L_sub2_and_finish:
sub r3, r3, #2
.L_finish:
cmp r4, #0
bne .L_strlen_done
// Time to get the dst string length.
mov r1, r5
// Save the original source address to r5.
mov r5, r0
// Save the current length (adding 1 for the terminator).
add r4, r3, #1
b .L_strlen_start
// r0 holds the pointer to the dst string.
// r3 holds the dst string length.
// r4 holds the src string length + 1.
.L_strlen_done:
add r2, r3, r4
cmp r2, lr
bhi .L_strcat_chk_failed
// Set up the registers for the memcpy code.
mov r1, r5
pld [r1, #64]
mov r2, r4
add r0, r0, r3
pop {r4, r5}
.cfi_adjust_cfa_offset -8
.cfi_restore r4
.cfi_restore r5
#include MEMCPY_BASE
// Undo the above cfi directives
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
.L_strcat_chk_failed:
ldr r0, error_message
ldr r1, error_code
1:
add r0, pc
bl __fortify_chk_fail
error_code:
.word BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+4)
END(__strcat_chk)
.data
error_string:
.string "strcat: prevented write past end of buffer"

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015 The Android Open Source Project * Copyright (C) 2013 The Android Open Source Project
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -26,7 +26,155 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
// Indicate which memcpy base file to include. #include <private/bionic_asm.h>
#define MEMCPY_BASE "memcpy_base.S" #include <private/libc_events.h>
#include "__strcpy_chk_common.S" .syntax unified
.thumb
.thumb_func
// Get the length of the source string first, then do a memcpy of the data
// instead of a strcpy.
ENTRY(__strcpy_chk)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
mov lr, r2
mov r0, r1
ands r3, r1, #7
beq .L_mainloop
// Align to a double word (64 bits).
rsb r3, r3, #8
lsls ip, r3, #31
beq .L_align_to_32
ldrb r2, [r0], #1
cbz r2, .L_update_count_and_finish
.L_align_to_32:
bcc .L_align_to_64
ands ip, r3, #2
beq .L_align_to_64
ldrb r2, [r0], #1
cbz r2, .L_update_count_and_finish
ldrb r2, [r0], #1
cbz r2, .L_update_count_and_finish
.L_align_to_64:
tst r3, #4
beq .L_mainloop
ldr r3, [r0], #4
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .L_zero_in_second_register
.p2align 2
.L_mainloop:
ldrd r2, r3, [r0], #8
pld [r0, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .L_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .L_zero_in_second_register
b .L_mainloop
.L_update_count_and_finish:
sub r3, r0, r1
sub r3, r3, #1
b .L_check_size
.L_zero_in_first_register:
sub r3, r0, r1
lsls r2, ip, #17
bne .L_sub8_and_finish
bcs .L_sub7_and_finish
lsls ip, ip, #1
bne .L_sub6_and_finish
sub r3, r3, #5
b .L_check_size
.L_sub8_and_finish:
sub r3, r3, #8
b .L_check_size
.L_sub7_and_finish:
sub r3, r3, #7
b .L_check_size
.L_sub6_and_finish:
sub r3, r3, #6
b .L_check_size
.L_zero_in_second_register:
sub r3, r0, r1
lsls r2, ip, #17
bne .L_sub4_and_finish
bcs .L_sub3_and_finish
lsls ip, ip, #1
bne .L_sub2_and_finish
sub r3, r3, #1
b .L_check_size
.L_sub4_and_finish:
sub r3, r3, #4
b .L_check_size
.L_sub3_and_finish:
sub r3, r3, #3
b .L_check_size
.L_sub2_and_finish:
sub r3, r3, #2
.L_check_size:
pld [r1, #0]
pld [r1, #64]
ldr r0, [sp]
cmp r3, lr
bhs __strcpy_chk_failed
// Add 1 for copy length to get the string terminator.
add r2, r3, #1
END(__strcpy_chk)
#define MEMCPY_BASE __strcpy_chk_memcpy_base
#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
#include "memcpy_base.S"
ENTRY_PRIVATE(__strcpy_chk_failed)
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
ldr r0, error_message
ldr r1, error_code
1:
add r0, pc
bl __fortify_chk_fail
error_code:
.word BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+4)
END(__strcpy_chk_failed)
.data
error_string:
.string "strcpy: prevented write past end of buffer"

View File

@ -1,173 +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 <private/bionic_asm.h>
#include <private/libc_events.h>
.syntax unified
.thumb
.thumb_func
// Get the length of the source string first, then do a memcpy of the data
// instead of a strcpy.
ENTRY(__strcpy_chk)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
mov lr, r2
mov r0, r1
ands r3, r1, #7
beq .L_mainloop
// Align to a double word (64 bits).
rsb r3, r3, #8
lsls ip, r3, #31
beq .L_align_to_32
ldrb r2, [r0], #1
cbz r2, .L_update_count_and_finish
.L_align_to_32:
bcc .L_align_to_64
ands ip, r3, #2
beq .L_align_to_64
ldrb r2, [r0], #1
cbz r2, .L_update_count_and_finish
ldrb r2, [r0], #1
cbz r2, .L_update_count_and_finish
.L_align_to_64:
tst r3, #4
beq .L_mainloop
ldr r3, [r0], #4
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .L_zero_in_second_register
.p2align 2
.L_mainloop:
ldrd r2, r3, [r0], #8
pld [r0, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .L_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .L_zero_in_second_register
b .L_mainloop
.L_update_count_and_finish:
sub r3, r0, r1
sub r3, r3, #1
b .L_check_size
.L_zero_in_first_register:
sub r3, r0, r1
lsls r2, ip, #17
bne .L_sub8_and_finish
bcs .L_sub7_and_finish
lsls ip, ip, #1
bne .L_sub6_and_finish
sub r3, r3, #5
b .L_check_size
.L_sub8_and_finish:
sub r3, r3, #8
b .L_check_size
.L_sub7_and_finish:
sub r3, r3, #7
b .L_check_size
.L_sub6_and_finish:
sub r3, r3, #6
b .L_check_size
.L_zero_in_second_register:
sub r3, r0, r1
lsls r2, ip, #17
bne .L_sub4_and_finish
bcs .L_sub3_and_finish
lsls ip, ip, #1
bne .L_sub2_and_finish
sub r3, r3, #1
b .L_check_size
.L_sub4_and_finish:
sub r3, r3, #4
b .L_check_size
.L_sub3_and_finish:
sub r3, r3, #3
b .L_check_size
.L_sub2_and_finish:
sub r3, r3, #2
.L_check_size:
pld [r1, #0]
pld [r1, #64]
ldr r0, [sp]
cmp r3, lr
bhs .L_strcpy_chk_failed
// Add 1 for copy length to get the string terminator.
add r2, r3, #1
#include MEMCPY_BASE
.L_strcpy_chk_failed:
ldr r0, error_message
ldr r1, error_code
1:
add r0, pc
bl __fortify_chk_fail
error_code:
.word BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+4)
END(__strcpy_chk)
.data
error_string:
.string "strcpy: prevented write past end of buffer"

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015 The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -25,8 +25,79 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * 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.
*/
// Indicate which memcpy base file to include. // Prototype: void *memcpy (void *dst, const void *src, size_t count).
#define MEMCPY_BASE "memcpy_base.S"
#include "memcpy_common.S" #include <private/bionic_asm.h>
#include <private/libc_events.h>
.text
.syntax unified
.fpu neon
ENTRY(__memcpy_chk)
cmp r2, r3
bhi __memcpy_chk_fail
// Fall through to memcpy...
END(__memcpy_chk)
ENTRY(memcpy)
pld [r1, #64]
push {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
END(memcpy)
#define MEMCPY_BASE __memcpy_base
#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
#include "memcpy_base.S"
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:
add r0, pc
bl __fortify_chk_fail
error_code:
.word BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+8)
END(__memcpy_chk_fail)
.data
error_string:
.string "memcpy: prevented write past end of buffer"

View File

@ -53,7 +53,11 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
.L_memcpy_base: ENTRY_PRIVATE(MEMCPY_BASE)
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
// Assumes that n >= 0, and dst, src are valid pointers. // Assumes that n >= 0, and dst, src are valid pointers.
// For any sizes less than 832 use the neon code that doesn't // For any sizes less than 832 use the neon code that doesn't
// care about the src alignment. This avoids any checks // care about the src alignment. This avoids any checks
@ -164,6 +168,12 @@
eor r3, r0, r1 eor r3, r0, r1
ands r3, r3, #0x3 ands r3, r3, #0x3
bne .L_copy_unknown_alignment bne .L_copy_unknown_alignment
END(MEMCPY_BASE)
ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED)
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
// To try and improve performance, stack layout changed, // To try and improve performance, stack layout changed,
// i.e., not keeping the stack looking like users expect // i.e., not keeping the stack looking like users expect
@ -175,7 +185,7 @@
strd r6, r7, [sp, #-8]! strd r6, r7, [sp, #-8]!
.cfi_adjust_cfa_offset 8 .cfi_adjust_cfa_offset 8
.cfi_rel_offset r6, 0 .cfi_rel_offset r6, 0
.cfi_rel_offset r7, 4 .cfi_rel_offset r7, 0
strd r8, r9, [sp, #-8]! strd r8, r9, [sp, #-8]!
.cfi_adjust_cfa_offset 8 .cfi_adjust_cfa_offset 8
.cfi_rel_offset r8, 0 .cfi_rel_offset r8, 0
@ -281,28 +291,10 @@
// Restore registers: optimized pop {r0, pc} // Restore registers: optimized pop {r0, pc}
ldrd r8, r9, [sp], #8 ldrd r8, r9, [sp], #8
.cfi_adjust_cfa_offset -8
.cfi_restore r8
.cfi_restore r9
ldrd r6, r7, [sp], #8 ldrd r6, r7, [sp], #8
.cfi_adjust_cfa_offset -8
.cfi_restore r6
.cfi_restore r7
ldrd r4, r5, [sp], #8 ldrd r4, r5, [sp], #8
.cfi_adjust_cfa_offset -8
.cfi_restore r4
.cfi_restore r5
pop {r0, pc} pop {r0, pc}
// Put the cfi directives back for the below instructions.
.cfi_adjust_cfa_offset 24
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
.cfi_rel_offset r6, 8
.cfi_rel_offset r7, 12
.cfi_rel_offset r8, 16
.cfi_rel_offset r9, 20
.L_dst_not_word_aligned: .L_dst_not_word_aligned:
// Align dst to word. // Align dst to word.
rsb ip, ip, #4 rsb ip, ip, #4
@ -323,12 +315,4 @@
// Src is guaranteed to be at least word aligned by this point. // Src is guaranteed to be at least word aligned by this point.
b .L_word_aligned b .L_word_aligned
END(MEMCPY_BASE_ALIGNED)
// Undo any cfi directives from above.
.cfi_adjust_cfa_offset -24
.cfi_restore r4
.cfi_restore r5
.cfi_restore r6
.cfi_restore r7
.cfi_restore r8
.cfi_restore r9

View File

@ -1,103 +0,0 @@
/*
* Copyright (C) 2008 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.
*/
#include <private/bionic_asm.h>
#include <private/libc_events.h>
.text
.syntax unified
.fpu neon
ENTRY(__memcpy_chk)
cmp r2, r3
bhi .L_memcpy_chk_fail
// Fall through to memcpy...
END(__memcpy_chk)
// Prototype: void *memcpy (void *dst, const void *src, size_t count).
ENTRY(memcpy)
pld [r1, #64]
push {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
#include MEMCPY_BASE
// Undo the cfi instructions from above.
.cfi_def_cfa_offset 0
.cfi_restore r0
.cfi_restore lr
.L_memcpy_chk_fail:
// Preserve lr for backtrace.
push {lr}
.cfi_adjust_cfa_offset 4
.cfi_rel_offset lr, 0
ldr r0, error_message
ldr r1, error_code
1:
add r0, pc
bl __fortify_chk_fail
error_code:
.word BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+8)
END(memcpy)
.data
error_string:
.string "memcpy: prevented write past end of buffer"

View File

@ -70,7 +70,7 @@
.macro m_scan_byte .macro m_scan_byte
ldrb r3, [r0] ldrb r3, [r0]
cbz r3, .L_strcat_r0_scan_done cbz r3, strcat_r0_scan_done
add r0, #1 add r0, #1
.endm // m_scan_byte .endm // m_scan_byte
@ -84,10 +84,10 @@ ENTRY(strcat)
// Quick check to see if src is empty. // Quick check to see if src is empty.
ldrb r2, [r1] ldrb r2, [r1]
pld [r1, #0] pld [r1, #0]
cbnz r2, .L_strcat_continue cbnz r2, strcat_continue
bx lr bx lr
.L_strcat_continue: strcat_continue:
// To speed up really small dst strings, unroll checking the first 4 bytes. // To speed up really small dst strings, unroll checking the first 4 bytes.
m_push m_push
m_scan_byte m_scan_byte
@ -96,102 +96,95 @@ ENTRY(strcat)
m_scan_byte m_scan_byte
ands r3, r0, #7 ands r3, r0, #7
beq .L_strcat_mainloop beq strcat_mainloop
// Align to a double word (64 bits). // Align to a double word (64 bits).
rsb r3, r3, #8 rsb r3, r3, #8
lsls ip, r3, #31 lsls ip, r3, #31
beq .L_strcat_align_to_32 beq strcat_align_to_32
ldrb r5, [r0] ldrb r5, [r0]
cbz r5, .L_strcat_r0_scan_done cbz r5, strcat_r0_scan_done
add r0, r0, #1 add r0, r0, #1
.L_strcat_align_to_32: strcat_align_to_32:
bcc .L_strcat_align_to_64 bcc strcat_align_to_64
ldrb r2, [r0] ldrb r2, [r0]
cbz r2, .L_strcat_r0_scan_done cbz r2, strcat_r0_scan_done
add r0, r0, #1 add r0, r0, #1
ldrb r4, [r0] ldrb r4, [r0]
cbz r4, .L_strcat_r0_scan_done cbz r4, strcat_r0_scan_done
add r0, r0, #1 add r0, r0, #1
.L_strcat_align_to_64: strcat_align_to_64:
tst r3, #4 tst r3, #4
beq .L_strcat_mainloop beq strcat_mainloop
ldr r3, [r0], #4 ldr r3, [r0], #4
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcat_zero_in_second_register bne strcat_zero_in_second_register
b .L_strcat_mainloop b strcat_mainloop
.L_strcat_r0_scan_done: strcat_r0_scan_done:
// For short copies, hard-code checking the first 8 bytes since this // For short copies, hard-code checking the first 8 bytes since this
// new code doesn't win until after about 8 bytes. // new code doesn't win until after about 8 bytes.
m_copy_byte reg=r2, cmd=cbz, label=.L_strcpy_finish m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r3, cmd=cbz, label=.L_strcpy_finish m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r4, cmd=cbz, label=.L_strcpy_finish m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r5, cmd=cbz, label=.L_strcpy_finish m_copy_byte reg=r5, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r2, cmd=cbz, label=.L_strcpy_finish m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r3, cmd=cbz, label=.L_strcpy_finish m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r4, cmd=cbz, label=.L_strcpy_finish m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r5, cmd=cbnz, label=.L_strcpy_continue m_copy_byte reg=r5, cmd=cbnz, label=strcpy_continue
.L_strcpy_finish: strcpy_finish:
m_pop m_pop
.L_strcpy_continue: strcpy_continue:
ands r3, r0, #7 ands r3, r0, #7
beq .L_strcpy_check_src_align beq strcpy_check_src_align
// Align to a double word (64 bits). // Align to a double word (64 bits).
rsb r3, r3, #8 rsb r3, r3, #8
lsls ip, r3, #31 lsls ip, r3, #31
beq .L_strcpy_align_to_32 beq strcpy_align_to_32
ldrb r2, [r1], #1 ldrb r2, [r1], #1
strb r2, [r0], #1 strb r2, [r0], #1
cbz r2, .L_strcpy_complete cbz r2, strcpy_complete
.L_strcpy_align_to_32: strcpy_align_to_32:
bcc .L_strcpy_align_to_64 bcc strcpy_align_to_64
ldrb r2, [r1], #1 ldrb r2, [r1], #1
strb r2, [r0], #1 strb r2, [r0], #1
cbz r2, .L_strcpy_complete cbz r2, strcpy_complete
ldrb r2, [r1], #1 ldrb r2, [r1], #1
strb r2, [r0], #1 strb r2, [r0], #1
cbz r2, .L_strcpy_complete cbz r2, strcpy_complete
.L_strcpy_align_to_64: strcpy_align_to_64:
tst r3, #4 tst r3, #4
beq .L_strcpy_check_src_align beq strcpy_check_src_align
// Read one byte at a time since we don't know the src alignment ldr r2, [r1], #4
// and we don't want to read into a different page.
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .L_strcpy_complete
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .L_strcpy_complete
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .L_strcpy_complete
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .L_strcpy_complete
.L_strcpy_check_src_align: sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
str r2, [r0], #4
strcpy_check_src_align:
// At this point dst is aligned to a double word, check if src // At this point dst is aligned to a double word, check if src
// is also aligned to a double word. // is also aligned to a double word.
ands r3, r1, #7 ands r3, r1, #7
bne .L_strcpy_unaligned_copy bne strcpy_unaligned_copy
.p2align 2 .p2align 2
.L_strcpy_mainloop: strcpy_mainloop:
ldrd r2, r3, [r1], #8 ldrd r2, r3, [r1], #8
pld [r1, #64] pld [r1, #64]
@ -199,128 +192,128 @@ ENTRY(strcat)
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_first_register bne strcpy_zero_in_first_register
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_second_register bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8 strd r2, r3, [r0], #8
b .L_strcpy_mainloop b strcpy_mainloop
.L_strcpy_complete: strcpy_complete:
m_pop m_pop
.L_strcpy_zero_in_first_register: strcpy_zero_in_first_register:
lsls lr, ip, #17 lsls lr, ip, #17
bne .L_strcpy_copy1byte bne strcpy_copy1byte
bcs .L_strcpy_copy2bytes bcs strcpy_copy2bytes
lsls ip, ip, #1 lsls ip, ip, #1
bne .L_strcpy_copy3bytes bne strcpy_copy3bytes
.L_strcpy_copy4bytes: strcpy_copy4bytes:
// Copy 4 bytes to the destiniation. // Copy 4 bytes to the destiniation.
str r2, [r0] str r2, [r0]
m_pop m_pop
.L_strcpy_copy1byte: strcpy_copy1byte:
strb r2, [r0] strb r2, [r0]
m_pop m_pop
.L_strcpy_copy2bytes: strcpy_copy2bytes:
strh r2, [r0] strh r2, [r0]
m_pop m_pop
.L_strcpy_copy3bytes: strcpy_copy3bytes:
strh r2, [r0], #2 strh r2, [r0], #2
lsr r2, #16 lsr r2, #16
strb r2, [r0] strb r2, [r0]
m_pop m_pop
.L_strcpy_zero_in_second_register: strcpy_zero_in_second_register:
lsls lr, ip, #17 lsls lr, ip, #17
bne .L_strcpy_copy5bytes bne strcpy_copy5bytes
bcs .L_strcpy_copy6bytes bcs strcpy_copy6bytes
lsls ip, ip, #1 lsls ip, ip, #1
bne .L_strcpy_copy7bytes bne strcpy_copy7bytes
// Copy 8 bytes to the destination. // Copy 8 bytes to the destination.
strd r2, r3, [r0] strd r2, r3, [r0]
m_pop m_pop
.L_strcpy_copy5bytes: strcpy_copy5bytes:
str r2, [r0], #4 str r2, [r0], #4
strb r3, [r0] strb r3, [r0]
m_pop m_pop
.L_strcpy_copy6bytes: strcpy_copy6bytes:
str r2, [r0], #4 str r2, [r0], #4
strh r3, [r0] strh r3, [r0]
m_pop m_pop
.L_strcpy_copy7bytes: strcpy_copy7bytes:
str r2, [r0], #4 str r2, [r0], #4
strh r3, [r0], #2 strh r3, [r0], #2
lsr r3, #16 lsr r3, #16
strb r3, [r0] strb r3, [r0]
m_pop m_pop
.L_strcpy_unaligned_copy: strcpy_unaligned_copy:
// Dst is aligned to a double word, while src is at an unknown alignment. // Dst is aligned to a double word, while src is at an unknown alignment.
// There are 7 different versions of the unaligned copy code // There are 7 different versions of the unaligned copy code
// to prevent overreading the src. The mainloop of every single version // 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 // will store 64 bits per loop. The difference is how much of src can
// be read without potentially crossing a page boundary. // be read without potentially crossing a page boundary.
tbb [pc, r3] tbb [pc, r3]
.L_strcpy_unaligned_branchtable: strcpy_unaligned_branchtable:
.byte 0 .byte 0
.byte ((.L_strcpy_unalign7 - .L_strcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign7 - strcpy_unaligned_branchtable)/2)
.byte ((.L_strcpy_unalign6 - .L_strcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign6 - strcpy_unaligned_branchtable)/2)
.byte ((.L_strcpy_unalign5 - .L_strcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign5 - strcpy_unaligned_branchtable)/2)
.byte ((.L_strcpy_unalign4 - .L_strcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign4 - strcpy_unaligned_branchtable)/2)
.byte ((.L_strcpy_unalign3 - .L_strcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign3 - strcpy_unaligned_branchtable)/2)
.byte ((.L_strcpy_unalign2 - .L_strcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign2 - strcpy_unaligned_branchtable)/2)
.byte ((.L_strcpy_unalign1 - .L_strcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign1 - strcpy_unaligned_branchtable)/2)
.p2align 2 .p2align 2
// Can read 7 bytes before possibly crossing a page. // Can read 7 bytes before possibly crossing a page.
.L_strcpy_unalign7: strcpy_unalign7:
ldr r2, [r1], #4 ldr r2, [r1], #4
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_first_register bne strcpy_zero_in_first_register
ldrb r3, [r1] ldrb r3, [r1]
cbz r3, .L_strcpy_unalign7_copy5bytes cbz r3, strcpy_unalign7_copy5bytes
ldrb r4, [r1, #1] ldrb r4, [r1, #1]
cbz r4, .L_strcpy_unalign7_copy6bytes cbz r4, strcpy_unalign7_copy6bytes
ldrb r5, [r1, #2] ldrb r5, [r1, #2]
cbz r5, .L_strcpy_unalign7_copy7bytes cbz r5, strcpy_unalign7_copy7bytes
ldr r3, [r1], #4 ldr r3, [r1], #4
pld [r1, #64] pld [r1, #64]
lsrs ip, r3, #24 lsrs ip, r3, #24
strd r2, r3, [r0], #8 strd r2, r3, [r0], #8
beq .L_strcpy_unalign_return beq strcpy_unalign_return
b .L_strcpy_unalign7 b strcpy_unalign7
.L_strcpy_unalign7_copy5bytes: strcpy_unalign7_copy5bytes:
str r2, [r0], #4 str r2, [r0], #4
strb r3, [r0] strb r3, [r0]
.L_strcpy_unalign_return: strcpy_unalign_return:
m_pop m_pop
.L_strcpy_unalign7_copy6bytes: strcpy_unalign7_copy6bytes:
str r2, [r0], #4 str r2, [r0], #4
strb r3, [r0], #1 strb r3, [r0], #1
strb r4, [r0], #1 strb r4, [r0], #1
m_pop m_pop
.L_strcpy_unalign7_copy7bytes: strcpy_unalign7_copy7bytes:
str r2, [r0], #4 str r2, [r0], #4
strb r3, [r0], #1 strb r3, [r0], #1
strb r4, [r0], #1 strb r4, [r0], #1
@ -329,41 +322,41 @@ ENTRY(strcat)
.p2align 2 .p2align 2
// Can read 6 bytes before possibly crossing a page. // Can read 6 bytes before possibly crossing a page.
.L_strcpy_unalign6: strcpy_unalign6:
ldr r2, [r1], #4 ldr r2, [r1], #4
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_first_register bne strcpy_zero_in_first_register
ldrb r4, [r1] ldrb r4, [r1]
cbz r4, .L_strcpy_unalign_copy5bytes cbz r4, strcpy_unalign_copy5bytes
ldrb r5, [r1, #1] ldrb r5, [r1, #1]
cbz r5, .L_strcpy_unalign_copy6bytes cbz r5, strcpy_unalign_copy6bytes
ldr r3, [r1], #4 ldr r3, [r1], #4
pld [r1, #64] pld [r1, #64]
tst r3, #0xff0000 tst r3, #0xff0000
beq .L_strcpy_copy7bytes beq strcpy_copy7bytes
lsrs ip, r3, #24 lsrs ip, r3, #24
strd r2, r3, [r0], #8 strd r2, r3, [r0], #8
beq .L_strcpy_unalign_return beq strcpy_unalign_return
b .L_strcpy_unalign6 b strcpy_unalign6
.p2align 2 .p2align 2
// Can read 5 bytes before possibly crossing a page. // Can read 5 bytes before possibly crossing a page.
.L_strcpy_unalign5: strcpy_unalign5:
ldr r2, [r1], #4 ldr r2, [r1], #4
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_first_register bne strcpy_zero_in_first_register
ldrb r4, [r1] ldrb r4, [r1]
cbz r4, .L_strcpy_unalign_copy5bytes cbz r4, strcpy_unalign_copy5bytes
ldr r3, [r1], #4 ldr r3, [r1], #4
@ -372,17 +365,17 @@ ENTRY(strcat)
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_second_register bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8 strd r2, r3, [r0], #8
b .L_strcpy_unalign5 b strcpy_unalign5
.L_strcpy_unalign_copy5bytes: strcpy_unalign_copy5bytes:
str r2, [r0], #4 str r2, [r0], #4
strb r4, [r0] strb r4, [r0]
m_pop m_pop
.L_strcpy_unalign_copy6bytes: strcpy_unalign_copy6bytes:
str r2, [r0], #4 str r2, [r0], #4
strb r4, [r0], #1 strb r4, [r0], #1
strb r5, [r0] strb r5, [r0]
@ -390,13 +383,13 @@ ENTRY(strcat)
.p2align 2 .p2align 2
// Can read 4 bytes before possibly crossing a page. // Can read 4 bytes before possibly crossing a page.
.L_strcpy_unalign4: strcpy_unalign4:
ldr r2, [r1], #4 ldr r2, [r1], #4
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_first_register bne strcpy_zero_in_first_register
ldr r3, [r1], #4 ldr r3, [r1], #4
pld [r1, #64] pld [r1, #64]
@ -404,20 +397,20 @@ ENTRY(strcat)
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_second_register bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8 strd r2, r3, [r0], #8
b .L_strcpy_unalign4 b strcpy_unalign4
.p2align 2 .p2align 2
// Can read 3 bytes before possibly crossing a page. // Can read 3 bytes before possibly crossing a page.
.L_strcpy_unalign3: strcpy_unalign3:
ldrb r2, [r1] ldrb r2, [r1]
cbz r2, .L_strcpy_unalign3_copy1byte cbz r2, strcpy_unalign3_copy1byte
ldrb r3, [r1, #1] ldrb r3, [r1, #1]
cbz r3, .L_strcpy_unalign3_copy2bytes cbz r3, strcpy_unalign3_copy2bytes
ldrb r4, [r1, #2] ldrb r4, [r1, #2]
cbz r4, .L_strcpy_unalign3_copy3bytes cbz r4, strcpy_unalign3_copy3bytes
ldr r2, [r1], #4 ldr r2, [r1], #4
ldr r3, [r1], #4 ldr r3, [r1], #4
@ -425,26 +418,26 @@ ENTRY(strcat)
pld [r1, #64] pld [r1, #64]
lsrs lr, r2, #24 lsrs lr, r2, #24
beq .L_strcpy_copy4bytes beq strcpy_copy4bytes
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_second_register bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8 strd r2, r3, [r0], #8
b .L_strcpy_unalign3 b strcpy_unalign3
.L_strcpy_unalign3_copy1byte: strcpy_unalign3_copy1byte:
strb r2, [r0] strb r2, [r0]
m_pop m_pop
.L_strcpy_unalign3_copy2bytes: strcpy_unalign3_copy2bytes:
strb r2, [r0], #1 strb r2, [r0], #1
strb r3, [r0] strb r3, [r0]
m_pop m_pop
.L_strcpy_unalign3_copy3bytes: strcpy_unalign3_copy3bytes:
strb r2, [r0], #1 strb r2, [r0], #1
strb r3, [r0], #1 strb r3, [r0], #1
strb r4, [r0] strb r4, [r0]
@ -452,34 +445,34 @@ ENTRY(strcat)
.p2align 2 .p2align 2
// Can read 2 bytes before possibly crossing a page. // Can read 2 bytes before possibly crossing a page.
.L_strcpy_unalign2: strcpy_unalign2:
ldrb r2, [r1] ldrb r2, [r1]
cbz r2, .L_strcpy_unalign_copy1byte cbz r2, strcpy_unalign_copy1byte
ldrb r4, [r1, #1] ldrb r4, [r1, #1]
cbz r4, .L_strcpy_unalign_copy2bytes cbz r4, strcpy_unalign_copy2bytes
ldr r2, [r1], #4 ldr r2, [r1], #4
ldr r3, [r1], #4 ldr r3, [r1], #4
pld [r1, #64] pld [r1, #64]
tst r2, #0xff0000 tst r2, #0xff0000
beq .L_strcpy_copy3bytes beq strcpy_copy3bytes
lsrs ip, r2, #24 lsrs ip, r2, #24
beq .L_strcpy_copy4bytes beq strcpy_copy4bytes
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_second_register bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8 strd r2, r3, [r0], #8
b .L_strcpy_unalign2 b strcpy_unalign2
.p2align 2 .p2align 2
// Can read 1 byte before possibly crossing a page. // Can read 1 byte before possibly crossing a page.
.L_strcpy_unalign1: strcpy_unalign1:
ldrb r2, [r1] ldrb r2, [r1]
cbz r2, .L_strcpy_unalign_copy1byte cbz r2, strcpy_unalign_copy1byte
ldr r2, [r1], #4 ldr r2, [r1], #4
ldr r3, [r1], #4 ldr r3, [r1], #4
@ -489,27 +482,27 @@ ENTRY(strcat)
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_first_register bne strcpy_zero_in_first_register
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcpy_zero_in_second_register bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8 strd r2, r3, [r0], #8
b .L_strcpy_unalign1 b strcpy_unalign1
.L_strcpy_unalign_copy1byte: strcpy_unalign_copy1byte:
strb r2, [r0] strb r2, [r0]
m_pop m_pop
.L_strcpy_unalign_copy2bytes: strcpy_unalign_copy2bytes:
strb r2, [r0], #1 strb r2, [r0], #1
strb r4, [r0] strb r4, [r0]
m_pop m_pop
.p2align 2 .p2align 2
.L_strcat_mainloop: strcat_mainloop:
ldrd r2, r3, [r0], #8 ldrd r2, r3, [r0], #8
pld [r0, #64] pld [r0, #64]
@ -517,59 +510,59 @@ ENTRY(strcat)
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcat_zero_in_first_register bne strcat_zero_in_first_register
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_strcat_zero_in_second_register bne strcat_zero_in_second_register
b .L_strcat_mainloop b strcat_mainloop
.L_strcat_zero_in_first_register: strcat_zero_in_first_register:
// Prefetch the src now, it's going to be used soon. // Prefetch the src now, it's going to be used soon.
pld [r1, #0] pld [r1, #0]
lsls lr, ip, #17 lsls lr, ip, #17
bne .L_strcat_sub8 bne strcat_sub8
bcs .L_strcat_sub7 bcs strcat_sub7
lsls ip, ip, #1 lsls ip, ip, #1
bne .L_strcat_sub6 bne strcat_sub6
sub r0, r0, #5 sub r0, r0, #5
b .L_strcat_r0_scan_done b strcat_r0_scan_done
.L_strcat_sub8: strcat_sub8:
sub r0, r0, #8 sub r0, r0, #8
b .L_strcat_r0_scan_done b strcat_r0_scan_done
.L_strcat_sub7: strcat_sub7:
sub r0, r0, #7 sub r0, r0, #7
b .L_strcat_r0_scan_done b strcat_r0_scan_done
.L_strcat_sub6: strcat_sub6:
sub r0, r0, #6 sub r0, r0, #6
b .L_strcat_r0_scan_done b strcat_r0_scan_done
.L_strcat_zero_in_second_register: strcat_zero_in_second_register:
// Prefetch the src now, it's going to be used soon. // Prefetch the src now, it's going to be used soon.
pld [r1, #0] pld [r1, #0]
lsls lr, ip, #17 lsls lr, ip, #17
bne .L_strcat_sub4 bne strcat_sub4
bcs .L_strcat_sub3 bcs strcat_sub3
lsls ip, ip, #1 lsls ip, ip, #1
bne .L_strcat_sub2 bne strcat_sub2
sub r0, r0, #1 sub r0, r0, #1
b .L_strcat_r0_scan_done b strcat_r0_scan_done
.L_strcat_sub4: strcat_sub4:
sub r0, r0, #4 sub r0, r0, #4
b .L_strcat_r0_scan_done b strcat_r0_scan_done
.L_strcat_sub3: strcat_sub3:
sub r0, r0, #3 sub r0, r0, #3
b .L_strcat_r0_scan_done b strcat_r0_scan_done
.L_strcat_sub2: strcat_sub2:
sub r0, r0, #2 sub r0, r0, #2
b .L_strcat_r0_scan_done b strcat_r0_scan_done
END(strcat) END(strcat)

View File

@ -149,20 +149,13 @@ ENTRY(strcpy)
.Lstringcopy_align_to_64: .Lstringcopy_align_to_64:
tst r3, #4 tst r3, #4
beq .Lstringcopy_check_src_align beq .Lstringcopy_check_src_align
// Read one byte at a time since we don't have any idea about the alignment ldr r2, [r1], #4
// of the source and we don't want to read into a different page.
ldrb r2, [r1], #1 sub ip, r2, #0x01010101
strb r2, [r0], #1 bic ip, ip, r2
cbz r2, .Lstringcopy_complete ands ip, ip, #0x80808080
ldrb r2, [r1], #1 bne .Lstringcopy_zero_in_first_register
strb r2, [r0], #1 str r2, [r0], #4
cbz r2, .Lstringcopy_complete
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_check_src_align: .Lstringcopy_check_src_align:
// At this point dst is aligned to a double word, check if src // At this point dst is aligned to a double word, check if src

View File

@ -65,38 +65,38 @@ ENTRY(strlen)
mov r1, r0 mov r1, r0
ands r3, r0, #7 ands r3, r0, #7
beq .L_mainloop beq mainloop
// Align to a double word (64 bits). // Align to a double word (64 bits).
rsb r3, r3, #8 rsb r3, r3, #8
lsls ip, r3, #31 lsls ip, r3, #31
beq .L_align_to_32 beq align_to_32
ldrb r2, [r1], #1 ldrb r2, [r1], #1
cbz r2, .L_update_count_and_return cbz r2, update_count_and_return
.L_align_to_32: align_to_32:
bcc .L_align_to_64 bcc align_to_64
ands ip, r3, #2 ands ip, r3, #2
beq .L_align_to_64 beq align_to_64
ldrb r2, [r1], #1 ldrb r2, [r1], #1
cbz r2, .L_update_count_and_return cbz r2, update_count_and_return
ldrb r2, [r1], #1 ldrb r2, [r1], #1
cbz r2, .L_update_count_and_return cbz r2, update_count_and_return
.L_align_to_64: align_to_64:
tst r3, #4 tst r3, #4
beq .L_mainloop beq mainloop
ldr r3, [r1], #4 ldr r3, [r1], #4
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_zero_in_second_register bne zero_in_second_register
.p2align 2 .p2align 2
.L_mainloop: mainloop:
ldrd r2, r3, [r1], #8 ldrd r2, r3, [r1], #8
pld [r1, #64] pld [r1, #64]
@ -104,62 +104,62 @@ ENTRY(strlen)
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_zero_in_first_register bne zero_in_first_register
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .L_zero_in_second_register bne zero_in_second_register
b .L_mainloop b mainloop
.L_update_count_and_return: update_count_and_return:
sub r0, r1, r0 sub r0, r1, r0
sub r0, r0, #1 sub r0, r0, #1
bx lr bx lr
.L_zero_in_first_register: zero_in_first_register:
sub r0, r1, r0 sub r0, r1, r0
lsls r3, ip, #17 lsls r3, ip, #17
bne .L_sub8_and_return bne sub8_and_return
bcs .L_sub7_and_return bcs sub7_and_return
lsls ip, ip, #1 lsls ip, ip, #1
bne .L_sub6_and_return bne sub6_and_return
sub r0, r0, #5 sub r0, r0, #5
bx lr bx lr
.L_sub8_and_return: sub8_and_return:
sub r0, r0, #8 sub r0, r0, #8
bx lr bx lr
.L_sub7_and_return: sub7_and_return:
sub r0, r0, #7 sub r0, r0, #7
bx lr bx lr
.L_sub6_and_return: sub6_and_return:
sub r0, r0, #6 sub r0, r0, #6
bx lr bx lr
.L_zero_in_second_register: zero_in_second_register:
sub r0, r1, r0 sub r0, r1, r0
lsls r3, ip, #17 lsls r3, ip, #17
bne .L_sub4_and_return bne sub4_and_return
bcs .L_sub3_and_return bcs sub3_and_return
lsls ip, ip, #1 lsls ip, ip, #1
bne .L_sub2_and_return bne sub2_and_return
sub r0, r0, #1 sub r0, r0, #1
bx lr bx lr
.L_sub4_and_return: sub4_and_return:
sub r0, r0, #4 sub r0, r0, #4
bx lr bx lr
.L_sub3_and_return: sub3_and_return:
sub r0, r0, #3 sub r0, r0, #3
bx lr bx lr
.L_sub2_and_return: sub2_and_return:
sub r0, r0, #2 sub r0, r0, #2
bx lr bx lr
END(strlen) END(strlen)

View File

@ -1,17 +1,3 @@
libc_openbsd_src_files_exclude_arm += \
upstream-openbsd/lib/libc/string/memmove.c \
upstream-openbsd/lib/libc/string/stpcpy.c \
upstream-openbsd/lib/libc/string/strcat.c \
libc_bionic_src_files_exclude_arm += \
arch-arm/generic/bionic/memcpy.S \
arch-arm/generic/bionic/memset.S \
arch-arm/generic/bionic/strcmp.S \
arch-arm/generic/bionic/strcpy.S \
arch-arm/generic/bionic/strlen.c \
bionic/__strcat_chk.cpp \
bionic/__strcpy_chk.cpp \
libc_bionic_src_files_arm += \ libc_bionic_src_files_arm += \
arch-arm/cortex-a15/bionic/memcpy.S \ arch-arm/cortex-a15/bionic/memcpy.S \
arch-arm/cortex-a15/bionic/memset.S \ arch-arm/cortex-a15/bionic/memset.S \
@ -22,6 +8,4 @@ libc_bionic_src_files_arm += \
arch-arm/cortex-a15/bionic/strcpy.S \ arch-arm/cortex-a15/bionic/strcpy.S \
arch-arm/cortex-a15/bionic/__strcpy_chk.S \ arch-arm/cortex-a15/bionic/__strcpy_chk.S \
arch-arm/cortex-a15/bionic/strlen.S \ arch-arm/cortex-a15/bionic/strlen.S \
bionic/memmove.c \
libc_bionic_src_files_arm += \
arch-arm/denver/bionic/memmove.S \

View File

@ -1,32 +0,0 @@
# This file represents the best optimized routines that are the middle
# ground when running on a big/little system that is cortex-a57/cortex-a53.
# The cortex-a7 optimized routines, and the cortex-a53 optimized routines
# decrease performance on cortex-a57 processors by as much as 20%.
libc_openbsd_src_files_exclude_arm += \
upstream-openbsd/lib/libc/string/memmove.c \
upstream-openbsd/lib/libc/string/stpcpy.c \
upstream-openbsd/lib/libc/string/strcat.c \
libc_bionic_src_files_exclude_arm += \
arch-arm/generic/bionic/memcpy.S \
arch-arm/generic/bionic/memset.S \
arch-arm/generic/bionic/strcmp.S \
arch-arm/generic/bionic/strcpy.S \
arch-arm/generic/bionic/strlen.c \
bionic/__strcat_chk.cpp \
bionic/__strcpy_chk.cpp \
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/__strcpy_chk.S \
arch-arm/cortex-a15/bionic/strlen.S \
libc_bionic_src_files_arm += \
arch-arm/denver/bionic/memmove.S \

View File

@ -1,32 +0,0 @@
/*
* Copyright (C) 2015 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.
*/
// Indicate which memcpy base file to include.
#define MEMCPY_BASE "arch-arm/cortex-a53/bionic/memcpy_base.S"
#include "arch-arm/cortex-a15/bionic/__strcat_chk_common.S"

View File

@ -1,32 +0,0 @@
/*
* Copyright (C) 2015 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.
*/
// Indicate which memcpy base file to include.
#define MEMCPY_BASE "arch-arm/cortex-a53/bionic/memcpy_base.S"
#include "arch-arm/cortex-a15/bionic/__strcpy_chk_common.S"

View File

@ -1,143 +0,0 @@
/*
* Copyright (C) 2008 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.
*/
.L_memcpy_base:
// Assumes that n >= 0, and dst, src are valid pointers.
cmp r2, #16
blo .L_copy_less_than_16_unknown_align
.L_copy_unknown_alignment:
// Unknown alignment of src and dst.
// Assumes that the first few bytes have already been prefetched.
// Align destination to 128 bits. The mainloop store instructions
// require this alignment or they will throw an exception.
rsb r3, r0, #0
ands r3, r3, #0xF
beq 2f
// Copy up to 15 bytes (count in r3).
sub r2, r2, r3
movs ip, r3, lsl #31
itt mi
ldrbmi lr, [r1], #1
strbmi lr, [r0], #1
itttt cs
ldrbcs ip, [r1], #1
ldrbcs lr, [r1], #1
strbcs ip, [r0], #1
strbcs lr, [r0], #1
movs ip, r3, lsl #29
bge 1f
// Copies 4 bytes, dst 32 bits aligned before, at least 64 bits after.
vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]!
vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]!
1: bcc 2f
// Copies 8 bytes, dst 64 bits aligned before, at least 128 bits after.
vld1.8 {d0}, [r1]!
vst1.8 {d0}, [r0, :64]!
2: // Make sure we have at least 64 bytes to copy.
subs r2, r2, #64
blo 2f
1: // The main loop copies 64 bytes at a time.
vld1.8 {d0 - d3}, [r1]!
vld1.8 {d4 - d7}, [r1]!
subs r2, r2, #64
vstmia r0!, {d0 - d7}
pld [r1, #(64*10)]
bhs 1b
2: // Fix-up the remaining count and make sure we have >= 32 bytes left.
adds r2, r2, #32
blo 3f
// 32 bytes. These cache lines were already preloaded.
vld1.8 {d0 - d3}, [r1]!
sub r2, r2, #32
vst1.8 {d0 - d3}, [r0, :128]!
3: // Less than 32 left.
add r2, r2, #32
tst r2, #0x10
beq .L_copy_less_than_16_unknown_align
// Copies 16 bytes, destination 128 bits aligned.
vld1.8 {d0, d1}, [r1]!
vst1.8 {d0, d1}, [r0, :128]!
.L_copy_less_than_16_unknown_align:
// Copy up to 15 bytes (count in r2).
movs ip, r2, lsl #29
bcc 1f
vld1.8 {d0}, [r1]!
vst1.8 {d0}, [r0]!
1: bge 2f
vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]!
vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0]!
2: // Copy 0 to 4 bytes.
lsls r2, r2, #31
itt ne
ldrbne lr, [r1], #1
strbne lr, [r0], #1
itttt cs
ldrbcs ip, [r1], #1
ldrbcs lr, [r1]
strbcs ip, [r0], #1
strbcs lr, [r0]
pop {r0, pc}

View File

@ -1,31 +0,0 @@
libc_openbsd_src_files_exclude_arm += \
upstream-openbsd/lib/libc/string/memmove.c \
upstream-openbsd/lib/libc/string/stpcpy.c \
upstream-openbsd/lib/libc/string/strcat.c \
libc_bionic_src_files_exclude_arm += \
arch-arm/generic/bionic/memcpy.S \
arch-arm/generic/bionic/memset.S \
arch-arm/generic/bionic/strcmp.S \
arch-arm/generic/bionic/strcpy.S \
arch-arm/generic/bionic/strlen.c \
bionic/__strcat_chk.cpp \
bionic/__strcpy_chk.cpp \
libc_bionic_src_files_arm += \
arch-arm/cortex-a53/bionic/memcpy.S \
arch-arm/cortex-a53/bionic/__strcat_chk.S \
arch-arm/cortex-a53/bionic/__strcpy_chk.S \
libc_bionic_src_files_arm += \
arch-arm/cortex-a7/bionic/memset.S \
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 \
libc_bionic_src_files_arm += \
arch-arm/denver/bionic/memmove.S \

View File

@ -1,180 +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 <machine/cpu-features.h>
#include <private/bionic_asm.h>
#include <private/libc_events.h>
/*
* Optimized memset() for ARM.
*
* memset() returns its first argument.
*/
.fpu neon
.syntax unified
ENTRY(__memset_chk)
cmp r2, r3
bls .L_done
// 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:
add r0, pc
bl __fortify_chk_fail
error_code:
.word BIONIC_EVENT_MEMSET_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+8)
END(__memset_chk)
ENTRY(bzero)
mov r2, r1
mov r1, #0
.L_done:
// Fall through to memset...
END(bzero)
ENTRY(memset)
mov r3, r0
// At this point only d0, d1 are going to be used below.
vdup.8 q0, r1
cmp r2, #16
blo .L_set_less_than_16_unknown_align
.L_check_alignment:
// Align destination to a double word to avoid the store crossing
// a cache line boundary.
ands ip, r3, #7
bne .L_do_double_word_align
.L_double_word_aligned:
// Duplicate since the less than 64 can use d2, d3.
vmov q1, q0
subs r2, #64
blo .L_set_less_than_64
// Duplicate the copy value so that we can store 64 bytes at a time.
vmov q2, q0
vmov q3, q0
1: // Main loop stores 64 bytes at a time.
subs r2, #64
vstmia r3!, {d0 - d7}
bge 1b
.L_set_less_than_64:
// Restore r2 to the count of bytes left to set.
add r2, #64
lsls ip, r2, #27
bcc .L_set_less_than_32
// Set 32 bytes.
vstmia r3!, {d0 - d3}
.L_set_less_than_32:
bpl .L_set_less_than_16
// Set 16 bytes.
vstmia r3!, {d0, d1}
.L_set_less_than_16:
// Less than 16 bytes to set.
lsls ip, r2, #29
bcc .L_set_less_than_8
// Set 8 bytes.
vstmia r3!, {d0}
.L_set_less_than_8:
bpl .L_set_less_than_4
// Set 4 bytes
vst1.32 {d0[0]}, [r3]!
.L_set_less_than_4:
lsls ip, r2, #31
it ne
strbne r1, [r3], #1
itt cs
strbcs r1, [r3], #1
strbcs r1, [r3]
bx lr
.L_do_double_word_align:
rsb ip, ip, #8
sub r2, r2, ip
// Do this comparison now, otherwise we'll need to save a
// register to the stack since we've used all available
// registers.
cmp ip, #4
blo 1f
// Need to do a four byte copy.
movs ip, ip, lsl #31
it mi
strbmi r1, [r3], #1
itt cs
strbcs r1, [r3], #1
strbcs r1, [r3], #1
vst1.32 {d0[0]}, [r3]!
b .L_double_word_aligned
1:
// No four byte copy.
movs ip, ip, lsl #31
it mi
strbmi r1, [r3], #1
itt cs
strbcs r1, [r3], #1
strbcs r1, [r3], #1
b .L_double_word_aligned
.L_set_less_than_16_unknown_align:
// Set up to 15 bytes.
movs ip, r2, lsl #29
bcc 1f
vst1.8 {d0}, [r3]!
1: bge 2f
vst1.32 {d0[0]}, [r3]!
2: movs ip, r2, lsl #31
it mi
strbmi r1, [r3], #1
itt cs
strbcs r1, [r3], #1
strbcs r1, [r3], #1
bx lr
END(memset)
.data
error_string:
.string "memset: prevented write past end of buffer"

View File

@ -1,29 +1 @@
libc_openbsd_src_files_exclude_arm += \ include bionic/libc/arch-arm/cortex-a15/cortex-a15.mk
upstream-openbsd/lib/libc/string/memmove.c \
upstream-openbsd/lib/libc/string/stpcpy.c \
upstream-openbsd/lib/libc/string/strcat.c \
libc_bionic_src_files_exclude_arm += \
arch-arm/generic/bionic/memcpy.S \
arch-arm/generic/bionic/memset.S \
arch-arm/generic/bionic/strcmp.S \
arch-arm/generic/bionic/strcpy.S \
arch-arm/generic/bionic/strlen.c \
bionic/__strcat_chk.cpp \
bionic/__strcpy_chk.cpp \
libc_bionic_src_files_arm += \
arch-arm/cortex-a7/bionic/memset.S \
libc_bionic_src_files_arm += \
arch-arm/cortex-a15/bionic/memcpy.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/__strcpy_chk.S \
arch-arm/cortex-a15/bionic/strlen.S \
libc_bionic_src_files_arm += \
arch-arm/denver/bionic/memmove.S \

View File

@ -44,7 +44,7 @@ ENTRY_PRIVATE(MEMCPY_BASE)
/* check if buffers are aligned. If so, run arm-only version */ /* check if buffers are aligned. If so, run arm-only version */
eor r3, r0, r1 eor r3, r0, r1
ands r3, r3, #0x3 ands r3, r3, #0x3
beq MEMCPY_BASE_ALIGNED beq __memcpy_base_aligned
/* Check the upper size limit for Neon unaligned memory access in memcpy */ /* Check the upper size limit for Neon unaligned memory access in memcpy */
cmp r2, #224 cmp r2, #224
@ -133,7 +133,8 @@ ENTRY_PRIVATE(MEMCPY_BASE)
strbcs ip, [r0], #1 strbcs ip, [r0], #1
strbcs lr, [r0], #1 strbcs lr, [r0], #1
ldmfd sp!, {r0, pc} ldmfd sp!, {r0, lr}
bx lr
END(MEMCPY_BASE) END(MEMCPY_BASE)
ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED) ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED)

View File

@ -35,7 +35,6 @@
*/ */
.fpu neon .fpu neon
.syntax unified
ENTRY(__memset_chk) ENTRY(__memset_chk)
cmp r2, r3 cmp r2, r3
@ -69,9 +68,12 @@ END(bzero)
ENTRY(memset) ENTRY(memset)
// The neon memset only wins for less than 132. // The neon memset only wins for less than 132.
cmp r2, #132 cmp r2, #132
bhi .L_memset_large_copy bhi __memset_large_copy
stmfd sp!, {r0}
.cfi_def_cfa_offset 4
.cfi_rel_offset r0, 0
mov r3, r0
vdup.8 q0, r1 vdup.8 q0, r1
/* make sure we have at least 32 bytes to write */ /* make sure we have at least 32 bytes to write */
@ -81,7 +83,7 @@ ENTRY(memset)
1: /* The main loop writes 32 bytes at a time */ 1: /* The main loop writes 32 bytes at a time */
subs r2, r2, #32 subs r2, r2, #32
vst1.8 {d0 - d3}, [r3]! vst1.8 {d0 - d3}, [r0]!
bhs 1b bhs 1b
2: /* less than 32 left */ 2: /* less than 32 left */
@ -90,20 +92,22 @@ ENTRY(memset)
beq 3f beq 3f
// writes 16 bytes, 128-bits aligned // writes 16 bytes, 128-bits aligned
vst1.8 {d0, d1}, [r3]! vst1.8 {d0, d1}, [r0]!
3: /* write up to 15-bytes (count in r2) */ 3: /* write up to 15-bytes (count in r2) */
movs ip, r2, lsl #29 movs ip, r2, lsl #29
bcc 1f bcc 1f
vst1.8 {d0}, [r3]! vst1.8 {d0}, [r0]!
1: bge 2f 1: bge 2f
vst1.32 {d0[0]}, [r3]! vst1.32 {d0[0]}, [r0]!
2: movs ip, r2, lsl #31 2: movs ip, r2, lsl #31
strbmi r1, [r3], #1 strmib r1, [r0], #1
strbcs r1, [r3], #1 strcsb r1, [r0], #1
strbcs r1, [r3], #1 strcsb r1, [r0], #1
ldmfd sp!, {r0}
bx lr bx lr
END(memset)
.L_memset_large_copy: ENTRY_PRIVATE(__memset_large_copy)
/* compute the offset to align the destination /* compute the offset to align the destination
* offset = (4-(src&3))&3 = -src & 3 * offset = (4-(src&3))&3 = -src & 3
*/ */
@ -127,11 +131,12 @@ ENTRY(memset)
orr r1, r1, r1, lsr #16 orr r1, r1, r1, lsr #16
movs r12, r3, lsl #31 movs r12, r3, lsl #31
strbcs r1, [r0], #1 /* can't use strh (alignment unknown) */ strcsb r1, [r0], #1 /* can't use strh (alignment unknown) */
strbcs r1, [r0], #1 strcsb r1, [r0], #1
strbmi r1, [r0], #1 strmib r1, [r0], #1
subs r2, r2, r3 subs r2, r2, r3
popls {r0, r4-r7, pc} /* return */ ldmlsfd sp!, {r0, r4-r7, lr} /* return */
bxls lr
/* align the destination to a cache-line */ /* align the destination to a cache-line */
mov r12, r1 mov r12, r1
@ -150,9 +155,9 @@ ENTRY(memset)
/* conditionally writes 0 to 7 words (length in r3) */ /* conditionally writes 0 to 7 words (length in r3) */
movs r3, r3, lsl #28 movs r3, r3, lsl #28
stmcs r0!, {r1, lr} stmcsia r0!, {r1, lr}
stmcs r0!, {r1, lr} stmcsia r0!, {r1, lr}
stmmi r0!, {r1, lr} stmmiia r0!, {r1, lr}
movs r3, r3, lsl #2 movs r3, r3, lsl #2
strcs r1, [r0], #4 strcs r1, [r0], #4
@ -167,15 +172,16 @@ ENTRY(memset)
/* conditionally stores 0 to 31 bytes */ /* conditionally stores 0 to 31 bytes */
movs r2, r2, lsl #28 movs r2, r2, lsl #28
stmcs r0!, {r1,r3,r12,lr} stmcsia r0!, {r1,r3,r12,lr}
stmmi r0!, {r1, lr} stmmiia r0!, {r1, lr}
movs r2, r2, lsl #2 movs r2, r2, lsl #2
strcs r1, [r0], #4 strcs r1, [r0], #4
strhmi r1, [r0], #2 strmih r1, [r0], #2
movs r2, r2, lsl #2 movs r2, r2, lsl #2
strbcs r1, [r0] strcsb r1, [r0]
ldmfd sp!, {r0, r4-r7, pc} ldmfd sp!, {r0, r4-r7, lr}
END(memset) bx lr
END(__memset_large_copy)
.data .data
error_string: error_string:

View File

@ -70,7 +70,7 @@
.macro m_scan_byte .macro m_scan_byte
ldrb r3, [r0] ldrb r3, [r0]
cbz r3, .Lstrcat_r0_scan_done cbz r3, strcat_r0_scan_done
add r0, #1 add r0, #1
.endm // m_scan_byte .endm // m_scan_byte
@ -84,10 +84,10 @@ ENTRY(strcat)
// Quick check to see if src is empty. // Quick check to see if src is empty.
ldrb r2, [r1] ldrb r2, [r1]
pld [r1, #0] pld [r1, #0]
cbnz r2, .Lstrcat_continue cbnz r2, strcat_continue
bx lr bx lr
.Lstrcat_continue: strcat_continue:
// To speed up really small dst strings, unroll checking the first 4 bytes. // To speed up really small dst strings, unroll checking the first 4 bytes.
m_push m_push
m_scan_byte m_scan_byte
@ -96,10 +96,10 @@ ENTRY(strcat)
m_scan_byte m_scan_byte
ands r3, r0, #7 ands r3, r0, #7
bne .Lstrcat_align_src bne strcat_align_src
.p2align 2 .p2align 2
.Lstrcat_mainloop: strcat_mainloop:
ldmia r0!, {r2, r3} ldmia r0!, {r2, r3}
pld [r0, #64] pld [r0, #64]
@ -107,28 +107,28 @@ ENTRY(strcat)
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcat_zero_in_first_register bne strcat_zero_in_first_register
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcat_zero_in_second_register bne strcat_zero_in_second_register
b .Lstrcat_mainloop b strcat_mainloop
.Lstrcat_zero_in_first_register: strcat_zero_in_first_register:
sub r0, r0, #4 sub r0, r0, #4
.Lstrcat_zero_in_second_register: strcat_zero_in_second_register:
// Check for zero in byte 0. // Check for zero in byte 0.
tst ip, #0x80 tst ip, #0x80
it ne it ne
subne r0, r0, #4 subne r0, r0, #4
bne .Lstrcat_r0_scan_done bne strcat_r0_scan_done
// Check for zero in byte 1. // Check for zero in byte 1.
tst ip, #0x8000 tst ip, #0x8000
it ne it ne
subne r0, r0, #3 subne r0, r0, #3
bne .Lstrcat_r0_scan_done bne strcat_r0_scan_done
// Check for zero in byte 2. // Check for zero in byte 2.
tst ip, #0x800000 tst ip, #0x800000
it ne it ne
@ -137,33 +137,33 @@ ENTRY(strcat)
// Zero is in byte 3. // Zero is in byte 3.
subeq r0, r0, #1 subeq r0, r0, #1
.Lstrcat_r0_scan_done: strcat_r0_scan_done:
// Unroll the first 8 bytes that will be copied. // Unroll the first 8 bytes that will be copied.
m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r5, cmd=cbz, label=.Lstrcpy_finish m_copy_byte reg=r5, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r5, cmd=cbnz, label=.Lstrcpy_continue m_copy_byte reg=r5, cmd=cbnz, label=strcpy_continue
.Lstrcpy_finish: strcpy_finish:
m_ret inst=pop m_ret inst=pop
.Lstrcpy_continue: strcpy_continue:
pld [r1, #0] pld [r1, #0]
ands r3, r0, #7 ands r3, r0, #7
bne .Lstrcpy_align_dst bne strcpy_align_dst
.Lstrcpy_check_src_align: strcpy_check_src_align:
// At this point dst is aligned to a double word, check if src // At this point dst is aligned to a double word, check if src
// is also aligned to a double word. // is also aligned to a double word.
ands r3, r1, #7 ands r3, r1, #7
bne .Lstrcpy_unaligned_copy bne strcpy_unaligned_copy
.p2align 2 .p2align 2
.Lstrcpy_mainloop: strcpy_mainloop:
ldmia r1!, {r2, r3} ldmia r1!, {r2, r3}
pld [r1, #64] pld [r1, #64]
@ -171,17 +171,17 @@ ENTRY(strcat)
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_first_register bne strcpy_zero_in_first_register
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_second_register bne strcpy_zero_in_second_register
stmia r0!, {r2, r3} stmia r0!, {r2, r3}
b .Lstrcpy_mainloop b strcpy_mainloop
.Lstrcpy_zero_in_first_register: strcpy_zero_in_first_register:
lsls lr, ip, #17 lsls lr, ip, #17
itt ne itt ne
strbne r2, [r0] strbne r2, [r0]
@ -198,7 +198,7 @@ ENTRY(strcat)
strb r3, [r0] strb r3, [r0]
m_ret inst=pop m_ret inst=pop
.Lstrcpy_zero_in_second_register: strcpy_zero_in_second_register:
lsls lr, ip, #17 lsls lr, ip, #17
ittt ne ittt ne
stmiane r0!, {r2} stmiane r0!, {r2}
@ -218,18 +218,18 @@ ENTRY(strcat)
strb r4, [r0] strb r4, [r0]
m_ret inst=pop m_ret inst=pop
.Lstrcpy_align_dst: strcpy_align_dst:
// Align to a double word (64 bits). // Align to a double word (64 bits).
rsb r3, r3, #8 rsb r3, r3, #8
lsls ip, r3, #31 lsls ip, r3, #31
beq .Lstrcpy_align_to_32 beq strcpy_align_to_32
ldrb r2, [r1], #1 ldrb r2, [r1], #1
strb r2, [r0], #1 strb r2, [r0], #1
cbz r2, .Lstrcpy_complete cbz r2, strcpy_complete
.Lstrcpy_align_to_32: strcpy_align_to_32:
bcc .Lstrcpy_align_to_64 bcc strcpy_align_to_64
ldrb r4, [r1], #1 ldrb r4, [r1], #1
strb r4, [r0], #1 strb r4, [r0], #1
@ -242,83 +242,76 @@ ENTRY(strcat)
it eq it eq
m_ret inst=popeq m_ret inst=popeq
.Lstrcpy_align_to_64: strcpy_align_to_64:
tst r3, #4 tst r3, #4
beq .Lstrcpy_check_src_align beq strcpy_check_src_align
// Read one byte at a time since we don't know the src alignment ldr r2, [r1], #4
// and we don't want to read into a different page.
ldrb r4, [r1], #1
strb r4, [r0], #1
cbz r4, .Lstrcpy_complete
ldrb r5, [r1], #1
strb r5, [r0], #1
cbz r5, .Lstrcpy_complete
ldrb r4, [r1], #1
strb r4, [r0], #1
cbz r4, .Lstrcpy_complete
ldrb r5, [r1], #1
strb r5, [r0], #1
cbz r5, .Lstrcpy_complete
b .Lstrcpy_check_src_align
.Lstrcpy_complete: sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
stmia r0!, {r2}
b strcpy_check_src_align
strcpy_complete:
m_ret inst=pop m_ret inst=pop
.Lstrcpy_unaligned_copy: strcpy_unaligned_copy:
// Dst is aligned to a double word, while src is at an unknown alignment. // Dst is aligned to a double word, while src is at an unknown alignment.
// There are 7 different versions of the unaligned copy code // There are 7 different versions of the unaligned copy code
// to prevent overreading the src. The mainloop of every single version // 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 // will store 64 bits per loop. The difference is how much of src can
// be read without potentially crossing a page boundary. // be read without potentially crossing a page boundary.
tbb [pc, r3] tbb [pc, r3]
.Lstrcpy_unaligned_branchtable: strcpy_unaligned_branchtable:
.byte 0 .byte 0
.byte ((.Lstrcpy_unalign7 - .Lstrcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign7 - strcpy_unaligned_branchtable)/2)
.byte ((.Lstrcpy_unalign6 - .Lstrcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign6 - strcpy_unaligned_branchtable)/2)
.byte ((.Lstrcpy_unalign5 - .Lstrcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign5 - strcpy_unaligned_branchtable)/2)
.byte ((.Lstrcpy_unalign4 - .Lstrcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign4 - strcpy_unaligned_branchtable)/2)
.byte ((.Lstrcpy_unalign3 - .Lstrcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign3 - strcpy_unaligned_branchtable)/2)
.byte ((.Lstrcpy_unalign2 - .Lstrcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign2 - strcpy_unaligned_branchtable)/2)
.byte ((.Lstrcpy_unalign1 - .Lstrcpy_unaligned_branchtable)/2) .byte ((strcpy_unalign1 - strcpy_unaligned_branchtable)/2)
.p2align 2 .p2align 2
// Can read 7 bytes before possibly crossing a page. // Can read 7 bytes before possibly crossing a page.
.Lstrcpy_unalign7: strcpy_unalign7:
ldr r2, [r1], #4 ldr r2, [r1], #4
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_first_register bne strcpy_zero_in_first_register
ldrb r3, [r1] ldrb r3, [r1]
cbz r3, .Lstrcpy_unalign7_copy5bytes cbz r3, strcpy_unalign7_copy5bytes
ldrb r4, [r1, #1] ldrb r4, [r1, #1]
cbz r4, .Lstrcpy_unalign7_copy6bytes cbz r4, strcpy_unalign7_copy6bytes
ldrb r5, [r1, #2] ldrb r5, [r1, #2]
cbz r5, .Lstrcpy_unalign7_copy7bytes cbz r5, strcpy_unalign7_copy7bytes
ldr r3, [r1], #4 ldr r3, [r1], #4
pld [r1, #64] pld [r1, #64]
lsrs ip, r3, #24 lsrs ip, r3, #24
stmia r0!, {r2, r3} stmia r0!, {r2, r3}
beq .Lstrcpy_unalign_return beq strcpy_unalign_return
b .Lstrcpy_unalign7 b strcpy_unalign7
.Lstrcpy_unalign7_copy5bytes: strcpy_unalign7_copy5bytes:
stmia r0!, {r2} stmia r0!, {r2}
strb r3, [r0] strb r3, [r0]
.Lstrcpy_unalign_return: strcpy_unalign_return:
m_ret inst=pop m_ret inst=pop
.Lstrcpy_unalign7_copy6bytes: strcpy_unalign7_copy6bytes:
stmia r0!, {r2} stmia r0!, {r2}
strb r3, [r0], #1 strb r3, [r0], #1
strb r4, [r0], #1 strb r4, [r0], #1
m_ret inst=pop m_ret inst=pop
.Lstrcpy_unalign7_copy7bytes: strcpy_unalign7_copy7bytes:
stmia r0!, {r2} stmia r0!, {r2}
strb r3, [r0], #1 strb r3, [r0], #1
strb r4, [r0], #1 strb r4, [r0], #1
@ -327,30 +320,30 @@ ENTRY(strcat)
.p2align 2 .p2align 2
// Can read 6 bytes before possibly crossing a page. // Can read 6 bytes before possibly crossing a page.
.Lstrcpy_unalign6: strcpy_unalign6:
ldr r2, [r1], #4 ldr r2, [r1], #4
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_first_register bne strcpy_zero_in_first_register
ldrb r4, [r1] ldrb r4, [r1]
cbz r4, .Lstrcpy_unalign_copy5bytes cbz r4, strcpy_unalign_copy5bytes
ldrb r5, [r1, #1] ldrb r5, [r1, #1]
cbz r5, .Lstrcpy_unalign_copy6bytes cbz r5, strcpy_unalign_copy6bytes
ldr r3, [r1], #4 ldr r3, [r1], #4
pld [r1, #64] pld [r1, #64]
tst r3, #0xff0000 tst r3, #0xff0000
beq .Lstrcpy_unalign6_copy7bytes beq strcpy_unalign6_copy7bytes
lsrs ip, r3, #24 lsrs ip, r3, #24
stmia r0!, {r2, r3} stmia r0!, {r2, r3}
beq .Lstrcpy_unalign_return beq strcpy_unalign_return
b .Lstrcpy_unalign6 b strcpy_unalign6
.Lstrcpy_unalign6_copy7bytes: strcpy_unalign6_copy7bytes:
stmia r0!, {r2} stmia r0!, {r2}
strh r3, [r0], #2 strh r3, [r0], #2
lsr r3, #16 lsr r3, #16
@ -359,16 +352,16 @@ ENTRY(strcat)
.p2align 2 .p2align 2
// Can read 5 bytes before possibly crossing a page. // Can read 5 bytes before possibly crossing a page.
.Lstrcpy_unalign5: strcpy_unalign5:
ldr r2, [r1], #4 ldr r2, [r1], #4
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_first_register bne strcpy_zero_in_first_register
ldrb r4, [r1] ldrb r4, [r1]
cbz r4, .Lstrcpy_unalign_copy5bytes cbz r4, strcpy_unalign_copy5bytes
ldr r3, [r1], #4 ldr r3, [r1], #4
@ -377,17 +370,17 @@ ENTRY(strcat)
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_second_register bne strcpy_zero_in_second_register
stmia r0!, {r2, r3} stmia r0!, {r2, r3}
b .Lstrcpy_unalign5 b strcpy_unalign5
.Lstrcpy_unalign_copy5bytes: strcpy_unalign_copy5bytes:
stmia r0!, {r2} stmia r0!, {r2}
strb r4, [r0] strb r4, [r0]
m_ret inst=pop m_ret inst=pop
.Lstrcpy_unalign_copy6bytes: strcpy_unalign_copy6bytes:
stmia r0!, {r2} stmia r0!, {r2}
strb r4, [r0], #1 strb r4, [r0], #1
strb r5, [r0] strb r5, [r0]
@ -395,13 +388,13 @@ ENTRY(strcat)
.p2align 2 .p2align 2
// Can read 4 bytes before possibly crossing a page. // Can read 4 bytes before possibly crossing a page.
.Lstrcpy_unalign4: strcpy_unalign4:
ldmia r1!, {r2} ldmia r1!, {r2}
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_first_register bne strcpy_zero_in_first_register
ldmia r1!, {r3} ldmia r1!, {r3}
pld [r1, #64] pld [r1, #64]
@ -409,20 +402,20 @@ ENTRY(strcat)
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_second_register bne strcpy_zero_in_second_register
stmia r0!, {r2, r3} stmia r0!, {r2, r3}
b .Lstrcpy_unalign4 b strcpy_unalign4
.p2align 2 .p2align 2
// Can read 3 bytes before possibly crossing a page. // Can read 3 bytes before possibly crossing a page.
.Lstrcpy_unalign3: strcpy_unalign3:
ldrb r2, [r1] ldrb r2, [r1]
cbz r2, .Lstrcpy_unalign3_copy1byte cbz r2, strcpy_unalign3_copy1byte
ldrb r3, [r1, #1] ldrb r3, [r1, #1]
cbz r3, .Lstrcpy_unalign3_copy2bytes cbz r3, strcpy_unalign3_copy2bytes
ldrb r4, [r1, #2] ldrb r4, [r1, #2]
cbz r4, .Lstrcpy_unalign3_copy3bytes cbz r4, strcpy_unalign3_copy3bytes
ldr r2, [r1], #4 ldr r2, [r1], #4
ldr r3, [r1], #4 ldr r3, [r1], #4
@ -430,26 +423,26 @@ ENTRY(strcat)
pld [r1, #64] pld [r1, #64]
lsrs lr, r2, #24 lsrs lr, r2, #24
beq .Lstrcpy_unalign_copy4bytes beq strcpy_unalign_copy4bytes
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_second_register bne strcpy_zero_in_second_register
stmia r0!, {r2, r3} stmia r0!, {r2, r3}
b .Lstrcpy_unalign3 b strcpy_unalign3
.Lstrcpy_unalign3_copy1byte: strcpy_unalign3_copy1byte:
strb r2, [r0] strb r2, [r0]
m_ret inst=pop m_ret inst=pop
.Lstrcpy_unalign3_copy2bytes: strcpy_unalign3_copy2bytes:
strb r2, [r0], #1 strb r2, [r0], #1
strb r3, [r0] strb r3, [r0]
m_ret inst=pop m_ret inst=pop
.Lstrcpy_unalign3_copy3bytes: strcpy_unalign3_copy3bytes:
strb r2, [r0], #1 strb r2, [r0], #1
strb r3, [r0], #1 strb r3, [r0], #1
strb r4, [r0] strb r4, [r0]
@ -457,34 +450,34 @@ ENTRY(strcat)
.p2align 2 .p2align 2
// Can read 2 bytes before possibly crossing a page. // Can read 2 bytes before possibly crossing a page.
.Lstrcpy_unalign2: strcpy_unalign2:
ldrb r2, [r1] ldrb r2, [r1]
cbz r2, .Lstrcpy_unalign_copy1byte cbz r2, strcpy_unalign_copy1byte
ldrb r3, [r1, #1] ldrb r3, [r1, #1]
cbz r3, .Lstrcpy_unalign_copy2bytes cbz r3, strcpy_unalign_copy2bytes
ldr r2, [r1], #4 ldr r2, [r1], #4
ldr r3, [r1], #4 ldr r3, [r1], #4
pld [r1, #64] pld [r1, #64]
tst r2, #0xff0000 tst r2, #0xff0000
beq .Lstrcpy_unalign_copy3bytes beq strcpy_unalign_copy3bytes
lsrs ip, r2, #24 lsrs ip, r2, #24
beq .Lstrcpy_unalign_copy4bytes beq strcpy_unalign_copy4bytes
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_second_register bne strcpy_zero_in_second_register
stmia r0!, {r2, r3} stmia r0!, {r2, r3}
b .Lstrcpy_unalign2 b strcpy_unalign2
.p2align 2 .p2align 2
// Can read 1 byte before possibly crossing a page. // Can read 1 byte before possibly crossing a page.
.Lstrcpy_unalign1: strcpy_unalign1:
ldrb r2, [r1] ldrb r2, [r1]
cbz r2, .Lstrcpy_unalign_copy1byte cbz r2, strcpy_unalign_copy1byte
ldr r2, [r1], #4 ldr r2, [r1], #4
ldr r3, [r1], #4 ldr r3, [r1], #4
@ -494,62 +487,62 @@ ENTRY(strcat)
sub ip, r2, #0x01010101 sub ip, r2, #0x01010101
bic ip, ip, r2 bic ip, ip, r2
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_first_register bne strcpy_zero_in_first_register
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcpy_zero_in_second_register bne strcpy_zero_in_second_register
stmia r0!, {r2, r3} stmia r0!, {r2, r3}
b .Lstrcpy_unalign1 b strcpy_unalign1
.Lstrcpy_unalign_copy1byte: strcpy_unalign_copy1byte:
strb r2, [r0] strb r2, [r0]
m_ret inst=pop m_ret inst=pop
.Lstrcpy_unalign_copy2bytes: strcpy_unalign_copy2bytes:
strb r2, [r0], #1 strb r2, [r0], #1
strb r3, [r0] strb r3, [r0]
m_ret inst=pop m_ret inst=pop
.Lstrcpy_unalign_copy3bytes: strcpy_unalign_copy3bytes:
strh r2, [r0], #2 strh r2, [r0], #2
lsr r2, #16 lsr r2, #16
strb r2, [r0] strb r2, [r0]
m_ret inst=pop m_ret inst=pop
.Lstrcpy_unalign_copy4bytes: strcpy_unalign_copy4bytes:
stmia r0, {r2} stmia r0, {r2}
m_ret inst=pop m_ret inst=pop
.Lstrcat_align_src: strcat_align_src:
// Align to a double word (64 bits). // Align to a double word (64 bits).
rsb r3, r3, #8 rsb r3, r3, #8
lsls ip, r3, #31 lsls ip, r3, #31
beq .Lstrcat_align_to_32 beq strcat_align_to_32
ldrb r2, [r0], #1 ldrb r2, [r0], #1
cbz r2, .Lstrcat_r0_update cbz r2, strcat_r0_update
.Lstrcat_align_to_32: strcat_align_to_32:
bcc .Lstrcat_align_to_64 bcc strcat_align_to_64
ldrb r2, [r0], #1 ldrb r2, [r0], #1
cbz r2, .Lstrcat_r0_update cbz r2, strcat_r0_update
ldrb r2, [r0], #1 ldrb r2, [r0], #1
cbz r2, .Lstrcat_r0_update cbz r2, strcat_r0_update
.Lstrcat_align_to_64: strcat_align_to_64:
tst r3, #4 tst r3, #4
beq .Lstrcat_mainloop beq strcat_mainloop
ldr r3, [r0], #4 ldr r3, [r0], #4
sub ip, r3, #0x01010101 sub ip, r3, #0x01010101
bic ip, ip, r3 bic ip, ip, r3
ands ip, ip, #0x80808080 ands ip, ip, #0x80808080
bne .Lstrcat_zero_in_second_register bne strcat_zero_in_second_register
b .Lstrcat_mainloop b strcat_mainloop
.Lstrcat_r0_update: strcat_r0_update:
sub r0, r0, #1 sub r0, r0, #1
b .Lstrcat_r0_scan_done b strcat_r0_scan_done
END(strcat) END(strcat)

View File

@ -244,20 +244,13 @@ ENTRY(strcpy)
.Lstringcopy_align_to_64: .Lstringcopy_align_to_64:
tst r3, #4 tst r3, #4
beq .Lstringcopy_check_src_align beq .Lstringcopy_check_src_align
// Read one byte at a time since we don't have any idea about the alignment ldr r2, [r1], #4
// of the source and we don't want to read into a different page.
ldrb r2, [r1], #1 sub ip, r2, #0x01010101
strb r2, [r0], #1 bic ip, ip, r2
cbz r2, .Lstringcopy_complete ands ip, ip, #0x80808080
ldrb r2, [r1], #1 bne .Lstringcopy_zero_in_first_register
strb r2, [r0], #1 stmia r0!, {r2}
cbz r2, .Lstringcopy_complete
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .Lstringcopy_complete
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .Lstringcopy_complete
b .Lstringcopy_check_src_align b .Lstringcopy_check_src_align
.Lstringcopy_complete: .Lstringcopy_complete:

View File

@ -1,18 +1,3 @@
libc_openbsd_src_files_exclude_arm += \
upstream-openbsd/lib/libc/string/memmove.c \
upstream-openbsd/lib/libc/string/stpcpy.c \
upstream-openbsd/lib/libc/string/strcat.c \
upstream-openbsd/lib/libc/string/strcpy.c \
libc_bionic_src_files_exclude_arm += \
arch-arm/generic/bionic/memcpy.S \
arch-arm/generic/bionic/memset.S \
arch-arm/generic/bionic/strcmp.S \
arch-arm/generic/bionic/strcpy.S \
arch-arm/generic/bionic/strlen.c \
bionic/__strcat_chk.cpp \
bionic/__strcpy_chk.cpp \
libc_bionic_src_files_arm += \ libc_bionic_src_files_arm += \
arch-arm/cortex-a9/bionic/memcpy.S \ arch-arm/cortex-a9/bionic/memcpy.S \
arch-arm/cortex-a9/bionic/memset.S \ arch-arm/cortex-a9/bionic/memset.S \
@ -23,6 +8,4 @@ libc_bionic_src_files_arm += \
arch-arm/cortex-a9/bionic/strcpy.S \ arch-arm/cortex-a9/bionic/strcpy.S \
arch-arm/cortex-a9/bionic/__strcpy_chk.S \ arch-arm/cortex-a9/bionic/__strcpy_chk.S \
arch-arm/cortex-a9/bionic/strlen.S \ arch-arm/cortex-a9/bionic/strlen.S \
bionic/memmove.c \
libc_bionic_src_files_arm += \
arch-arm/denver/bionic/memmove.S \

View File

@ -37,7 +37,6 @@
* memset() returns its first argument. * memset() returns its first argument.
*/ */
.cpu cortex-a15
.fpu neon .fpu neon
.syntax unified .syntax unified

View File

@ -1,17 +1,3 @@
libc_openbsd_src_files_exclude_arm += \
upstream-openbsd/lib/libc/string/memmove.c \
upstream-openbsd/lib/libc/string/stpcpy.c \
upstream-openbsd/lib/libc/string/strcat.c \
libc_bionic_src_files_exclude_arm += \
arch-arm/generic/bionic/memcpy.S \
arch-arm/generic/bionic/memset.S \
arch-arm/generic/bionic/strcmp.S \
arch-arm/generic/bionic/strcpy.S \
arch-arm/generic/bionic/strlen.c \
bionic/__strcat_chk.cpp \
bionic/__strcpy_chk.cpp \
libc_bionic_src_files_arm += \ libc_bionic_src_files_arm += \
arch-arm/denver/bionic/memcpy.S \ arch-arm/denver/bionic/memcpy.S \
arch-arm/denver/bionic/memmove.S \ arch-arm/denver/bionic/memmove.S \

View File

@ -37,8 +37,6 @@
* so we have to preserve R0. * so we have to preserve R0.
*/ */
.syntax unified
ENTRY(__memcpy_chk) ENTRY(__memcpy_chk)
cmp r2, r3 cmp r2, r3
bhi __memcpy_chk_fail bhi __memcpy_chk_fail
@ -83,12 +81,12 @@ ENTRY(memcpy)
*/ */
movs r12, r3, lsl #31 movs r12, r3, lsl #31
sub r2, r2, r3 /* we know that r3 <= r2 because r2 >= 4 */ sub r2, r2, r3 /* we know that r3 <= r2 because r2 >= 4 */
ldrbmi r3, [r1], #1 ldrmib r3, [r1], #1
ldrbcs r4, [r1], #1 ldrcsb r4, [r1], #1
ldrbcs r12,[r1], #1 ldrcsb r12,[r1], #1
strbmi r3, [r0], #1 strmib r3, [r0], #1
strbcs r4, [r0], #1 strcsb r4, [r0], #1
strbcs r12,[r0], #1 strcsb r12,[r0], #1
.Lsrc_aligned: .Lsrc_aligned:
@ -111,10 +109,10 @@ ENTRY(memcpy)
/* conditionally copies 0 to 7 words (length in r3) */ /* conditionally copies 0 to 7 words (length in r3) */
movs r12, r3, lsl #28 movs r12, r3, lsl #28
ldmcs r1!, {r4, r5, r6, r7} /* 16 bytes */ ldmcsia r1!, {r4, r5, r6, r7} /* 16 bytes */
ldmmi r1!, {r8, r9} /* 8 bytes */ ldmmiia r1!, {r8, r9} /* 8 bytes */
stmcs r0!, {r4, r5, r6, r7} stmcsia r0!, {r4, r5, r6, r7}
stmmi r0!, {r8, r9} stmmiia r0!, {r8, r9}
tst r3, #0x4 tst r3, #0x4
ldrne r10,[r1], #4 /* 4 bytes */ ldrne r10,[r1], #4 /* 4 bytes */
strne r10,[r0], #4 strne r10,[r0], #4
@ -179,22 +177,23 @@ ENTRY(memcpy)
/* conditionnaly copies 0 to 31 bytes */ /* conditionnaly copies 0 to 31 bytes */
movs r12, r2, lsl #28 movs r12, r2, lsl #28
ldmcs r1!, {r4, r5, r6, r7} /* 16 bytes */ ldmcsia r1!, {r4, r5, r6, r7} /* 16 bytes */
ldmmi r1!, {r8, r9} /* 8 bytes */ ldmmiia r1!, {r8, r9} /* 8 bytes */
stmcs r0!, {r4, r5, r6, r7} stmcsia r0!, {r4, r5, r6, r7}
stmmi r0!, {r8, r9} stmmiia r0!, {r8, r9}
movs r12, r2, lsl #30 movs r12, r2, lsl #30
ldrcs r3, [r1], #4 /* 4 bytes */ ldrcs r3, [r1], #4 /* 4 bytes */
ldrhmi r4, [r1], #2 /* 2 bytes */ ldrmih r4, [r1], #2 /* 2 bytes */
strcs r3, [r0], #4 strcs r3, [r0], #4
strhmi r4, [r0], #2 strmih r4, [r0], #2
tst r2, #0x1 tst r2, #0x1
ldrbne r3, [r1] /* last byte */ ldrneb r3, [r1] /* last byte */
strbne r3, [r0] strneb r3, [r0]
/* we're done! restore everything and return */ /* we're done! restore everything and return */
1: ldmfd sp!, {r5-r11} 1: ldmfd sp!, {r5-r11}
ldmfd sp!, {r0, r4, pc} ldmfd sp!, {r0, r4, lr}
bx lr
/********************************************************************/ /********************************************************************/
@ -229,11 +228,11 @@ ENTRY(memcpy)
* becomes aligned to 32 bits (r5 = nb of words to copy for alignment) * becomes aligned to 32 bits (r5 = nb of words to copy for alignment)
*/ */
movs r5, r5, lsl #31 movs r5, r5, lsl #31
strbmi r3, [r0], #1 strmib r3, [r0], #1
movmi r3, r3, lsr #8 movmi r3, r3, lsr #8
strbcs r3, [r0], #1 strcsb r3, [r0], #1
movcs r3, r3, lsr #8 movcs r3, r3, lsr #8
strbcs r3, [r0], #1 strcsb r3, [r0], #1
movcs r3, r3, lsr #8 movcs r3, r3, lsr #8
cmp r2, #4 cmp r2, #4
@ -364,27 +363,28 @@ ENTRY(memcpy)
.Lpartial_word_tail: .Lpartial_word_tail:
/* we have a partial word in the input buffer */ /* we have a partial word in the input buffer */
movs r5, lr, lsl #(31-3) movs r5, lr, lsl #(31-3)
strbmi r3, [r0], #1 strmib r3, [r0], #1
movmi r3, r3, lsr #8 movmi r3, r3, lsr #8
strbcs r3, [r0], #1 strcsb r3, [r0], #1
movcs r3, r3, lsr #8 movcs r3, r3, lsr #8
strbcs r3, [r0], #1 strcsb r3, [r0], #1
/* Refill spilled registers from the stack. Don't update sp. */ /* Refill spilled registers from the stack. Don't update sp. */
ldmfd sp, {r5-r11} ldmfd sp, {r5-r11}
.Lcopy_last_3_and_return: .Lcopy_last_3_and_return:
movs r2, r2, lsl #31 /* copy remaining 0, 1, 2 or 3 bytes */ movs r2, r2, lsl #31 /* copy remaining 0, 1, 2 or 3 bytes */
ldrbmi r2, [r1], #1 ldrmib r2, [r1], #1
ldrbcs r3, [r1], #1 ldrcsb r3, [r1], #1
ldrbcs r12,[r1] ldrcsb r12,[r1]
strbmi r2, [r0], #1 strmib r2, [r0], #1
strbcs r3, [r0], #1 strcsb r3, [r0], #1
strbcs r12,[r0] strcsb r12,[r0]
/* we're done! restore sp and spilled registers and return */ /* we're done! restore sp and spilled registers and return */
add sp, sp, #28 add sp, sp, #28
ldmfd sp!, {r0, r4, pc} ldmfd sp!, {r0, r4, lr}
bx lr
END(memcpy) END(memcpy)
// Only reached when the __memcpy_chk check fails. // Only reached when the __memcpy_chk check fails.

View File

@ -35,8 +35,6 @@
* memset() returns its first argument. * memset() returns its first argument.
*/ */
.syntax unified
ENTRY(__memset_chk) ENTRY(__memset_chk)
cmp r2, r3 cmp r2, r3
bls done bls done
@ -78,11 +76,12 @@ ENTRY(memset)
orr r1, r1, r1, lsr #16 orr r1, r1, r1, lsr #16
movs r12, r3, lsl #31 movs r12, r3, lsl #31
strbcs r1, [r0], #1 /* can't use strh (alignment unknown) */ strcsb r1, [r0], #1 /* can't use strh (alignment unknown) */
strbcs r1, [r0], #1 strcsb r1, [r0], #1
strbmi r1, [r0], #1 strmib r1, [r0], #1
subs r2, r2, r3 subs r2, r2, r3
popls {r0, r4-r7, pc} /* return */ ldmlsfd sp!, {r0, r4-r7, lr} /* return */
bxls lr
/* align the destination to a cache-line */ /* align the destination to a cache-line */
mov r12, r1 mov r12, r1
@ -101,9 +100,9 @@ ENTRY(memset)
/* conditionally writes 0 to 7 words (length in r3) */ /* conditionally writes 0 to 7 words (length in r3) */
movs r3, r3, lsl #28 movs r3, r3, lsl #28
stmcs r0!, {r1, lr} stmcsia r0!, {r1, lr}
stmcs r0!, {r1, lr} stmcsia r0!, {r1, lr}
stmmi r0!, {r1, lr} stmmiia r0!, {r1, lr}
movs r3, r3, lsl #2 movs r3, r3, lsl #2
strcs r1, [r0], #4 strcs r1, [r0], #4
@ -118,14 +117,15 @@ ENTRY(memset)
/* conditionally stores 0 to 31 bytes */ /* conditionally stores 0 to 31 bytes */
movs r2, r2, lsl #28 movs r2, r2, lsl #28
stmcs r0!, {r1,r3,r12,lr} stmcsia r0!, {r1,r3,r12,lr}
stmmi r0!, {r1, lr} stmmiia r0!, {r1, lr}
movs r2, r2, lsl #2 movs r2, r2, lsl #2
strcs r1, [r0], #4 strcs r1, [r0], #4
strhmi r1, [r0], #2 strmih r1, [r0], #2
movs r2, r2, lsl #2 movs r2, r2, lsl #2
strbcs r1, [r0] strcsb r1, [r0]
ldmfd sp!, {r0, r4-r7, pc} ldmfd sp!, {r0, r4-r7, lr}
bx lr
END(memset) END(memset)
.data .data

View File

@ -32,8 +32,6 @@
#include <machine/cpu-features.h> #include <machine/cpu-features.h>
#include <private/bionic_asm.h> #include <private/bionic_asm.h>
.syntax unified
ENTRY(strcpy) ENTRY(strcpy)
pld [r1, #0] pld [r1, #0]
eor r2, r0, r1 eor r2, r0, r1
@ -110,15 +108,15 @@ ENTRY(strcpy)
#ifdef __ARMEB__ #ifdef __ARMEB__
tst r2, #0xff00 tst r2, #0xff00
iteet ne iteet ne
strhne r2, [ip], #2 strneh r2, [ip], #2
lsreq r2, r2, #8 lsreq r2, r2, #8
strbeq r2, [ip] streqb r2, [ip]
tstne r2, #0xff tstne r2, #0xff
#else #else
tst r2, #0xff tst r2, #0xff
itet ne itet ne
strhne r2, [ip], #2 strneh r2, [ip], #2
strbeq r2, [ip] streqb r2, [ip]
tstne r2, #0xff00 tstne r2, #0xff00
#endif #endif
bne 5b bne 5b

View File

@ -0,0 +1,11 @@
libc_bionic_src_files_arm += \
arch-arm/generic/bionic/memcpy.S \
arch-arm/generic/bionic/memset.S \
arch-arm/generic/bionic/strcmp.S \
arch-arm/generic/bionic/strcpy.S \
arch-arm/generic/bionic/strlen.c \
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 \

View File

@ -38,7 +38,9 @@
#ifndef _ARM32_ASM_H_ #ifndef _ARM32_ASM_H_
#define _ARM32_ASM_H_ #define _ARM32_ASM_H_
#define __bionic_asm_align 0 #ifndef _ALIGN_TEXT
# define _ALIGN_TEXT .align 0
#endif
#undef __bionic_asm_custom_entry #undef __bionic_asm_custom_entry
#undef __bionic_asm_custom_end #undef __bionic_asm_custom_end
@ -48,4 +50,10 @@
#undef __bionic_asm_function_type #undef __bionic_asm_function_type
#define __bionic_asm_function_type #function #define __bionic_asm_function_type #function
#if defined(__ELF__) && defined(PIC)
#define PIC_SYM(x,y) x ## ( ## y ## )
#else
#define PIC_SYM(x,y) x
#endif
#endif /* !_ARM_ASM_H_ */ #endif /* !_ARM_ASM_H_ */

View File

@ -28,6 +28,14 @@
#ifndef _ARM_MACHINE_CPU_FEATURES_H #ifndef _ARM_MACHINE_CPU_FEATURES_H
#define _ARM_MACHINE_CPU_FEATURES_H #define _ARM_MACHINE_CPU_FEATURES_H
/* The purpose of this file is to define several macros corresponding
* to CPU features that may or may not be available at build time on
* on the target CPU.
*
* This is done to abstract us from the various ARM Architecture
* quirks and alphabet soup.
*/
/* __ARM_ARCH__ is a number corresponding to the ARM revision /* __ARM_ARCH__ is a number corresponding to the ARM revision
* we're going to support. Our toolchain doesn't define __ARM_ARCH__ * we're going to support. Our toolchain doesn't define __ARM_ARCH__
* so try to guess it. * so try to guess it.
@ -45,4 +53,31 @@
# endif # endif
#endif #endif
/* define __ARM_HAVE_HALFWORD_MULTIPLY when half-word multiply instructions
* this means variants of: smul, smulw, smla, smlaw, smlal
*/
#define __ARM_HAVE_HALFWORD_MULTIPLY 1
/* define __ARM_HAVE_LDREXD for ARMv7 architecture
* (also present in ARMv6K, but not implemented in ARMv7-M, neither of which
* we care about)
*/
#if __ARM_ARCH__ >= 7
# define __ARM_HAVE_LDREXD
#endif
/* define _ARM_HAVE_VFP if we have VFPv3
*/
#if __ARM_ARCH__ >= 7 && defined __VFP_FP__
# define __ARM_HAVE_VFP
#endif
/* define _ARM_HAVE_NEON for ARMv7 architecture if we support the
* Neon SIMD instruction set extensions. This also implies
* that VFPv3-D32 is supported.
*/
#if __ARM_ARCH__ >= 7 && defined __ARM_NEON__
# define __ARM_HAVE_NEON
#endif
#endif /* _ARM_MACHINE_CPU_FEATURES_H */ #endif /* _ARM_MACHINE_CPU_FEATURES_H */

View File

@ -102,8 +102,6 @@
/* 112-127 are reserved for private experiments. */ /* 112-127 are reserved for private experiments. */
#define R_ARM_IRELATIVE 160
#define R_ARM_RXPC25 249 #define R_ARM_RXPC25 249
#define R_ARM_RSBREL32 250 #define R_ARM_RSBREL32 250
#define R_ARM_THM_RPC22 251 #define R_ARM_THM_RPC22 251

View File

@ -0,0 +1,79 @@
/* $OpenBSD: endian.h,v 1.3 2005/12/13 00:35:23 millert Exp $ */
/*
* Copyright (C) 2010 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.
*/
#ifndef _ARM_ENDIAN_H_
#define _ARM_ENDIAN_H_
#ifdef __GNUC__
/* According to RealView Assembler User's Guide, REV and REV16 are available
* in Thumb code and 16-bit instructions when used in Thumb-2 code.
*
* REV Rd, Rm
* Rd and Rm must both be Lo registers.
*
* REV16 Rd, Rm
* Rd and Rm must both be Lo registers.
*
* The +l constraint takes care of this without constraining us in ARM mode.
*/
#define __swap16md(x) ({ \
register u_int16_t _x = (x); \
__asm__ __volatile__("rev16 %0, %0" : "+l" (_x)); \
_x; \
})
#define __swap32md(x) ({ \
register u_int32_t _x = (x); \
__asm__ __volatile__("rev %0, %0" : "+l" (_x)); \
_x; \
})
#define __swap64md(x) ({ \
u_int64_t _swap64md_x = (x); \
(u_int64_t) __swap32md(_swap64md_x >> 32) | \
(u_int64_t) __swap32md(_swap64md_x & 0xffffffff) << 32; \
})
/* Tell sys/endian.h we have MD variants of the swap macros. */
#define MD_SWAP
#endif /* __GNUC__ */
#if defined(__ARMEB__)
#define _BYTE_ORDER _BIG_ENDIAN
#else
#define _BYTE_ORDER _LITTLE_ENDIAN
#endif
#define __STRICT_ALIGNMENT
#include <sys/types.h>
#include <sys/endian.h>
#endif /* !_ARM_ENDIAN_H_ */

View File

@ -0,0 +1,50 @@
/* $OpenBSD: exec.h,v 1.9 2003/04/17 03:42:14 drahn Exp $ */
/* $NetBSD: exec.h,v 1.6 1994/10/27 04:16:05 cgd Exp $ */
/*
* Copyright (c) 1993 Christopher G. Demetriou
* 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 author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#ifndef _ARM_EXEC_H_
#define _ARM_EXEC_H_
#define __LDPGSZ 4096
#define NATIVE_EXEC_ELF
#define ARCH_ELFSIZE 32
#define ELF_TARG_CLASS ELFCLASS32
#define ELF_TARG_DATA ELFDATA2LSB
#define ELF_TARG_MACH EM_ARM
#define _NLIST_DO_AOUT
#define _NLIST_DO_ELF
#define _KERN_DO_AOUT
#define _KERN_DO_ELF
#endif /* _ARM_EXEC_H_ */

View File

@ -26,6 +26,10 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
/*
* machine/setjmp.h: machine dependent setjmp-related information.
*/
/* _JBLEN is the size of a jmp_buf in longs. /* _JBLEN is the size of a jmp_buf in longs.
* Do not modify this value or you will break the ABI ! * Do not modify this value or you will break the ABI !
* *
@ -33,3 +37,46 @@
* that was replaced by this one. * that was replaced by this one.
*/ */
#define _JBLEN 64 #define _JBLEN 64
/* According to the ARM AAPCS document, we only need to save
* the following registers:
*
* Core r4-r14
*
* VFP d8-d15 (see section 5.1.2.1)
*
* Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine
* calls; registers s0-s15 (d0-d7, q0-q3) do not need to be preserved
* (and can be used for passing arguments or returning results in standard
* procedure-call variants). Registers d16-d31 (q8-q15), if present, do
* not need to be preserved.
*
* FPSCR saved because GLibc does saves it too.
*
*/
/* The internal structure of a jmp_buf is totally private.
* Current layout (may change in the future):
*
* word name description
* 0 magic magic number
* 1 sigmask signal mask (not used with _setjmp / _longjmp)
* 2 float_base base of float registers (d8 to d15)
* 18 float_state floating-point status and control register
* 19 core_base base of core registers (r4 to r14)
* 30 reserved reserved entries (room to grow)
* 64
*
* NOTE: float_base must be at an even word index, since the
* FP registers will be loaded/stored with instructions
* that expect 8-byte alignment.
*/
#define _JB_MAGIC 0
#define _JB_SIGMASK (_JB_MAGIC+1)
#define _JB_FLOAT_BASE (_JB_SIGMASK+1)
#define _JB_FLOAT_STATE (_JB_FLOAT_BASE + (15-8+1)*2)
#define _JB_CORE_BASE (_JB_FLOAT_STATE+1)
#define _JB_MAGIC__SETJMP 0x4278f500
#define _JB_MAGIC_SETJMP 0x4278f501

View File

@ -40,7 +40,7 @@
ENTRY(__strcat_chk) ENTRY(__strcat_chk)
pld [r0, #0] pld [r0, #0]
push {r0, lr} push {r0, lr}
.cfi_adjust_cfa_offset 8 .cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0 .cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4 .cfi_rel_offset lr, 4
push {r4, r5} push {r4, r5}
@ -177,7 +177,7 @@ ENTRY(__strcat_chk)
.L_strlen_done: .L_strlen_done:
add r2, r3, r4 add r2, r3, r4
cmp r2, lr cmp r2, lr
bhi .L_strcat_chk_failed bhi __strcat_chk_failed
// Set up the registers for the memcpy code. // Set up the registers for the memcpy code.
mov r1, r5 mov r1, r5
@ -185,17 +185,20 @@ ENTRY(__strcat_chk)
mov r2, r4 mov r2, r4
add r0, r0, r3 add r0, r0, r3
pop {r4, r5} pop {r4, r5}
.cfi_adjust_cfa_offset -8 END(__strcat_chk)
.cfi_restore r4
.cfi_restore r5
#define MEMCPY_BASE __strcat_chk_memcpy_base
#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
#include "memcpy_base.S" #include "memcpy_base.S"
// Undo the above cfi directives. ENTRY_PRIVATE(__strcat_chk_failed)
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
.cfi_adjust_cfa_offset 8 .cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0 .cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4 .cfi_rel_offset r5, 4
.L_strcat_chk_failed:
ldr r0, error_message ldr r0, error_message
ldr r1, error_code ldr r1, error_code
1: 1:
@ -205,7 +208,7 @@ error_code:
.word BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW .word BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
error_message: error_message:
.word error_string-(1b+4) .word error_string-(1b+4)
END(__strcat_chk) END(__strcat_chk_failed)
.data .data
error_string: error_string:

View File

@ -39,7 +39,7 @@
ENTRY(__strcpy_chk) ENTRY(__strcpy_chk)
pld [r0, #0] pld [r0, #0]
push {r0, lr} push {r0, lr}
.cfi_adjust_cfa_offset 8 .cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0 .cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4 .cfi_rel_offset lr, 4
@ -149,14 +149,21 @@ ENTRY(__strcpy_chk)
pld [r1, #64] pld [r1, #64]
ldr r0, [sp] ldr r0, [sp]
cmp r3, lr cmp r3, lr
bhs .L_strcpy_chk_failed bhs __strcpy_chk_failed
// Add 1 for copy length to get the string terminator. // Add 1 for copy length to get the string terminator.
add r2, r3, #1 add r2, r3, #1
END(__strcpy_chk)
#define MEMCPY_BASE __strcpy_chk_memcpy_base
#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
#include "memcpy_base.S" #include "memcpy_base.S"
.L_strcpy_chk_failed: ENTRY_PRIVATE(__strcpy_chk_failed)
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
ldr r0, error_message ldr r0, error_message
ldr r1, error_code ldr r1, error_code
1: 1:
@ -166,7 +173,7 @@ error_code:
.word BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW .word BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
error_message: error_message:
.word error_string-(1b+4) .word error_string-(1b+4)
END(__strcpy_chk) END(__strcpy_chk_failed)
.data .data
error_string: error_string:

View File

@ -45,7 +45,7 @@
ENTRY(__memcpy_chk) ENTRY(__memcpy_chk)
cmp r2, r3 cmp r2, r3
bhi .L_memcpy_chk_fail bhi __memcpy_chk_fail
// Fall through to memcpy... // Fall through to memcpy...
END(__memcpy_chk) END(__memcpy_chk)
@ -53,20 +53,19 @@ END(__memcpy_chk)
ENTRY(memcpy) ENTRY(memcpy)
pld [r1, #64] pld [r1, #64]
stmfd sp!, {r0, lr} stmfd sp!, {r0, lr}
.cfi_adjust_cfa_offset 8 .cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0 .cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4 .cfi_rel_offset lr, 4
END(memcpy)
#define MEMCPY_BASE __memcpy_base
#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
#include "memcpy_base.S" #include "memcpy_base.S"
// Undo the cfi directives from above. ENTRY_PRIVATE(__memcpy_chk_fail)
.cfi_adjust_cfa_offset -8
.cfi_restore r0
.cfi_restore lr
.L_memcpy_chk_fail:
// Preserve lr for backtrace. // Preserve lr for backtrace.
push {lr} push {lr}
.cfi_adjust_cfa_offset 4 .cfi_def_cfa_offset 4
.cfi_rel_offset lr, 0 .cfi_rel_offset lr, 0
ldr r0, error_message ldr r0, error_message
@ -78,7 +77,7 @@ error_code:
.word BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW .word BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW
error_message: error_message:
.word error_string-(1b+4) .word error_string-(1b+4)
END(memcpy) END(__memcpy_chk_fail)
.data .data
error_string: error_string:

View File

@ -1,191 +1,123 @@
/*************************************************************************** /*
Copyright (c) 2009-2013 The Linux Foundation. All rights reserved. * 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.
*/
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 Linux Foundation 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 * This code assumes it is running on a processor that supports all arm v7
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * instructions, that supports neon instructions, and that has a 32 byte
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * cache line.
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.
***************************************************************************/
/* Assumes neon instructions and a cache line size of 64 bytes. */ // Assumes neon instructions and a cache line size of 32 bytes.
#include <machine/cpu-features.h> ENTRY_PRIVATE(MEMCPY_BASE)
#include <machine/asm.h> .cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
#define PLDOFFS (10) /* do we have at least 16-bytes to copy (needed for alignment below) */
#define PLDTHRESH (PLDOFFS)
#define BBTHRESH (4096/64)
#define PLDSIZE (64)
#if (PLDOFFS < 1)
#error Routine does not support offsets less than 1
#endif
#if (PLDTHRESH < PLDOFFS)
#error PLD threshold must be greater than or equal to the PLD offset
#endif
.text
.fpu neon
.L_memcpy_base:
cmp r2, #4
blt .L_neon_lt4
cmp r2, #16 cmp r2, #16
blt .L_neon_lt16 blo 5f
cmp r2, #32
blt .L_neon_16
cmp r2, #64
blt .L_neon_copy_32_a
mov r12, r2, lsr #6 /* align destination to cache-line for the write-buffer */
cmp r12, #PLDTHRESH rsb r3, r0, #0
ble .L_neon_copy_64_loop_nopld ands r3, r3, #0xF
beq 2f
push {r9, r10} /* copy up to 15-bytes (count in r3) */
.cfi_adjust_cfa_offset 8 sub r2, r2, r3
.cfi_rel_offset r9, 0 movs ip, r3, lsl #31
.cfi_rel_offset r10, 4 itt mi
ldrbmi lr, [r1], #1
strbmi lr, [r0], #1
itttt cs
ldrbcs ip, [r1], #1
ldrbcs lr, [r1], #1
strbcs ip, [r0], #1
strbcs lr, [r0], #1
movs ip, r3, lsl #29
bge 1f
// copies 4 bytes, destination 32-bits aligned
vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]!
vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]!
1: bcc 2f
// copies 8 bytes, destination 64-bits aligned
vld1.8 {d0}, [r1]!
vst1.8 {d0}, [r0, :64]!
cmp r12, #BBTHRESH 2: /* make sure we have at least 64 bytes to copy */
ble .L_neon_prime_pump subs r2, r2, #64
blo 2f
add lr, r0, #0x400 1: /* The main loop copies 64 bytes at a time */
add r9, r1, #(PLDOFFS*PLDSIZE) vld1.8 {d0 - d3}, [r1]!
sub lr, lr, r9 vld1.8 {d4 - d7}, [r1]!
lsl lr, lr, #21 pld [r1, #(32*8)]
lsr lr, lr, #21 subs r2, r2, #64
add lr, lr, #(PLDOFFS*PLDSIZE) vst1.8 {d0 - d3}, [r0, :128]!
cmp r12, lr, lsr #6 vst1.8 {d4 - d7}, [r0, :128]!
ble .L_neon_prime_pump bhs 1b
itt gt 2: /* fix-up the remaining count and make sure we have >= 32 bytes left */
movgt r9, #(PLDOFFS) adds r2, r2, #32
rsbsgt r9, r9, lr, lsr #6 blo 4f
ble .L_neon_prime_pump
add r10, r1, lr /* Copy 32 bytes. These cache lines were already preloaded */
bic r10, #0x3F vld1.8 {d0 - d3}, [r1]!
sub r2, r2, #32
vst1.8 {d0 - d3}, [r0, :128]!
sub r12, r12, lr, lsr #6 4: /* less than 32 left */
add r2, r2, #32
tst r2, #0x10
beq 5f
// copies 16 bytes, 128-bits aligned
vld1.8 {d0, d1}, [r1]!
vst1.8 {d0, d1}, [r0, :128]!
cmp r9, r12 5: /* copy up to 15-bytes (count in r2) */
itee le movs ip, r2, lsl #29
suble r12, r12, r9
movgt r9, r12
movgt r12, #0
pld [r1, #((PLDOFFS-1)*PLDSIZE)]
.L_neon_copy_64_loop_outer_doublepld:
pld [r1, #((PLDOFFS)*PLDSIZE)]
vld1.32 {q0, q1}, [r1]!
vld1.32 {q2, q3}, [r1]!
ldr r3, [r10]
subs r9, r9, #1
vst1.32 {q0, q1}, [r0]!
vst1.32 {q2, q3}, [r0]!
add r10, #64
bne .L_neon_copy_64_loop_outer_doublepld
cmp r12, #0
beq .L_neon_pop_before_nopld
cmp r12, #(512*1024/64)
blt .L_neon_copy_64_loop_outer
.L_neon_copy_64_loop_ddr:
vld1.32 {q0, q1}, [r1]!
vld1.32 {q2, q3}, [r1]!
pld [r10]
subs r12, r12, #1
vst1.32 {q0, q1}, [r0]!
vst1.32 {q2, q3}, [r0]!
add r10, #64
bne .L_neon_copy_64_loop_ddr
b .L_neon_pop_before_nopld
.L_neon_prime_pump:
mov lr, #(PLDOFFS*PLDSIZE)
add r10, r1, #(PLDOFFS*PLDSIZE)
bic r10, #0x3F
sub r12, r12, #PLDOFFS
ldr r3, [r10, #(-1*PLDSIZE)]
.L_neon_copy_64_loop_outer:
vld1.32 {q0, q1}, [r1]!
vld1.32 {q2, q3}, [r1]!
ldr r3, [r10]
subs r12, r12, #1
vst1.32 {q0, q1}, [r0]!
vst1.32 {q2, q3}, [r0]!
add r10, #64
bne .L_neon_copy_64_loop_outer
.L_neon_pop_before_nopld:
mov r12, lr, lsr #6
pop {r9, r10}
.cfi_adjust_cfa_offset -8
.cfi_restore r9
.cfi_restore r10
.L_neon_copy_64_loop_nopld:
vld1.32 {q8, q9}, [r1]!
vld1.32 {q10, q11}, [r1]!
subs r12, r12, #1
vst1.32 {q8, q9}, [r0]!
vst1.32 {q10, q11}, [r0]!
bne .L_neon_copy_64_loop_nopld
ands r2, r2, #0x3f
beq .L_neon_exit
.L_neon_copy_32_a:
movs r3, r2, lsl #27
bcc .L_neon_16
vld1.32 {q0,q1}, [r1]!
vst1.32 {q0,q1}, [r0]!
.L_neon_16:
bpl .L_neon_lt16
vld1.32 {q8}, [r1]!
vst1.32 {q8}, [r0]!
ands r2, r2, #0x0f
beq .L_neon_exit
.L_neon_lt16:
movs r3, r2, lsl #29
bcc 1f bcc 1f
vld1.8 {d0}, [r1]! vld1.8 {d0}, [r1]!
vst1.8 {d0}, [r0]! vst1.8 {d0}, [r0]!
1: 1: bge 2f
bge .L_neon_lt4
vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]! vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]!
vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0]! vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0]!
2: movs ip, r2, lsl #31
.L_neon_lt4:
movs r2, r2, lsl #31
itt cs
ldrhcs r3, [r1], #2
strhcs r3, [r0], #2
itt mi itt mi
ldrbmi r3, [r1] ldrbmi r3, [r1], #1
strbmi r3, [r0] strbmi r3, [r0], #1
itttt cs
ldrbcs ip, [r1], #1
ldrbcs lr, [r1], #1
strbcs ip, [r0], #1
strbcs lr, [r0], #1
.L_neon_exit: ldmfd sp!, {r0, lr}
pop {r0, pc} bx lr
END(MEMCPY_BASE)

View File

@ -37,7 +37,6 @@
*/ */
.fpu neon .fpu neon
.syntax unified
ENTRY(__memset_chk) ENTRY(__memset_chk)
cmp r2, r3 cmp r2, r3
@ -69,7 +68,10 @@ END(bzero)
/* memset() returns its first argument. */ /* memset() returns its first argument. */
ENTRY(memset) ENTRY(memset)
mov r3, r0 stmfd sp!, {r0}
.cfi_def_cfa_offset 4
.cfi_rel_offset r0, 0
vdup.8 q0, r1 vdup.8 q0, r1
/* make sure we have at least 32 bytes to write */ /* make sure we have at least 32 bytes to write */
@ -79,7 +81,7 @@ ENTRY(memset)
1: /* The main loop writes 32 bytes at a time */ 1: /* The main loop writes 32 bytes at a time */
subs r2, r2, #32 subs r2, r2, #32
vst1.8 {d0 - d3}, [r3]! vst1.8 {d0 - d3}, [r0]!
bhs 1b bhs 1b
2: /* less than 32 left */ 2: /* less than 32 left */
@ -88,17 +90,18 @@ ENTRY(memset)
beq 3f beq 3f
// writes 16 bytes, 128-bits aligned // writes 16 bytes, 128-bits aligned
vst1.8 {d0, d1}, [r3]! vst1.8 {d0, d1}, [r0]!
3: /* write up to 15-bytes (count in r2) */ 3: /* write up to 15-bytes (count in r2) */
movs ip, r2, lsl #29 movs ip, r2, lsl #29
bcc 1f bcc 1f
vst1.8 {d0}, [r3]! vst1.8 {d0}, [r0]!
1: bge 2f 1: bge 2f
vst1.32 {d0[0]}, [r3]! vst1.32 {d0[0]}, [r0]!
2: movs ip, r2, lsl #31 2: movs ip, r2, lsl #31
strbmi r1, [r3], #1 strmib r1, [r0], #1
strbcs r1, [r3], #1 strcsb r1, [r0], #1
strbcs r1, [r3], #1 strcsb r1, [r0], #1
ldmfd sp!, {r0}
bx lr bx lr
END(memset) END(memset)

View File

@ -1,18 +1,3 @@
libc_openbsd_src_files_exclude_arm += \
upstream-openbsd/lib/libc/string/memmove.c \
upstream-openbsd/lib/libc/string/stpcpy.c \
upstream-openbsd/lib/libc/string/stpcpy.c \
upstream-openbsd/lib/libc/string/strcat.c \
libc_bionic_src_files_exclude_arm += \
arch-arm/generic/bionic/memcpy.S \
arch-arm/generic/bionic/memset.S \
arch-arm/generic/bionic/strcmp.S \
arch-arm/generic/bionic/strcpy.S \
arch-arm/generic/bionic/strlen.c \
bionic/__strcat_chk.cpp \
bionic/__strcpy_chk.cpp \
libc_bionic_src_files_arm += \ libc_bionic_src_files_arm += \
arch-arm/krait/bionic/memcpy.S \ arch-arm/krait/bionic/memcpy.S \
arch-arm/krait/bionic/memset.S \ arch-arm/krait/bionic/memset.S \
@ -26,6 +11,4 @@ libc_bionic_src_files_arm += \
arch-arm/cortex-a15/bionic/strcat.S \ arch-arm/cortex-a15/bionic/strcat.S \
arch-arm/cortex-a15/bionic/strcpy.S \ arch-arm/cortex-a15/bionic/strcpy.S \
arch-arm/cortex-a15/bionic/strlen.S \ arch-arm/cortex-a15/bionic/strlen.S \
bionic/memmove.c \
libc_bionic_src_files_arm += \
arch-arm/denver/bionic/memmove.S \

View File

@ -1,23 +0,0 @@
/* Generated by gensyscalls.py. Do not edit. */
#include <private/bionic_asm.h>
ENTRY(___mremap)
mov ip, sp
stmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 16
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
.cfi_rel_offset r6, 8
.cfi_rel_offset r7, 12
ldmfd ip, {r4, r5, r6}
ldr r7, =__NR_mremap
swi #0
ldmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 0
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno_internal
END(___mremap)
.hidden ___mremap

View File

@ -1,15 +0,0 @@
/* Generated by gensyscalls.py. Do not edit. */
#include <private/bionic_asm.h>
ENTRY(___rt_sigqueueinfo)
mov ip, r7
ldr r7, =__NR_rt_sigqueueinfo
swi #0
mov r7, ip
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno_internal
END(___rt_sigqueueinfo)
.hidden ___rt_sigqueueinfo

View File

@ -1,22 +0,0 @@
/* Generated by gensyscalls.py. Do not edit. */
#include <private/bionic_asm.h>
ENTRY(__preadv64)
mov ip, sp
stmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 16
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
.cfi_rel_offset r6, 8
.cfi_rel_offset r7, 12
ldmfd ip, {r4, r5, r6}
ldr r7, =__NR_preadv
swi #0
ldmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 0
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno_internal
END(__preadv64)

View File

@ -1,22 +0,0 @@
/* Generated by gensyscalls.py. Do not edit. */
#include <private/bionic_asm.h>
ENTRY(__pwritev64)
mov ip, sp
stmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 16
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
.cfi_rel_offset r6, 8
.cfi_rel_offset r7, 12
ldmfd ip, {r4, r5, r6}
ldr r7, =__NR_pwritev
swi #0
ldmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 0
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno_internal
END(__pwritev64)

View File

@ -13,4 +13,5 @@ ENTRY(_exit)
b __set_errno_internal b __set_errno_internal
END(_exit) END(_exit)
ALIAS_SYMBOL(_Exit, _exit) .globl _Exit
.equ _Exit, _exit

View File

@ -2,7 +2,7 @@
#include <private/bionic_asm.h> #include <private/bionic_asm.h>
ENTRY(___clock_nanosleep) ENTRY(clock_nanosleep)
mov ip, r7 mov ip, r7
ldr r7, =__NR_clock_nanosleep ldr r7, =__NR_clock_nanosleep
swi #0 swi #0
@ -11,5 +11,4 @@ ENTRY(___clock_nanosleep)
bxls lr bxls lr
neg r0, r0 neg r0, r0
b __set_errno_internal b __set_errno_internal
END(___clock_nanosleep) END(clock_nanosleep)
.hidden ___clock_nanosleep

View File

@ -2,7 +2,7 @@
#include <private/bionic_asm.h> #include <private/bionic_asm.h>
ENTRY(___close) ENTRY(close)
mov ip, r7 mov ip, r7
ldr r7, =__NR_close ldr r7, =__NR_close
swi #0 swi #0
@ -11,5 +11,4 @@ ENTRY(___close)
bxls lr bxls lr
neg r0, r0 neg r0, r0
b __set_errno_internal b __set_errno_internal
END(___close) END(close)
.hidden ___close

View File

@ -2,7 +2,7 @@
#include <private/bionic_asm.h> #include <private/bionic_asm.h>
ENTRY(___faccessat) ENTRY(faccessat)
mov ip, r7 mov ip, r7
ldr r7, =__NR_faccessat ldr r7, =__NR_faccessat
swi #0 swi #0
@ -11,5 +11,4 @@ ENTRY(___faccessat)
bxls lr bxls lr
neg r0, r0 neg r0, r0
b __set_errno_internal b __set_errno_internal
END(___faccessat) END(faccessat)
.hidden ___faccessat

View File

@ -2,7 +2,7 @@
#include <private/bionic_asm.h> #include <private/bionic_asm.h>
ENTRY(___fchmod) ENTRY(fchmod)
mov ip, r7 mov ip, r7
ldr r7, =__NR_fchmod ldr r7, =__NR_fchmod
swi #0 swi #0
@ -11,5 +11,4 @@ ENTRY(___fchmod)
bxls lr bxls lr
neg r0, r0 neg r0, r0
b __set_errno_internal b __set_errno_internal
END(___fchmod) END(fchmod)
.hidden ___fchmod

View File

@ -2,7 +2,7 @@
#include <private/bionic_asm.h> #include <private/bionic_asm.h>
ENTRY(___fchmodat) ENTRY(fchmodat)
mov ip, r7 mov ip, r7
ldr r7, =__NR_fchmodat ldr r7, =__NR_fchmodat
swi #0 swi #0
@ -11,5 +11,4 @@ ENTRY(___fchmodat)
bxls lr bxls lr
neg r0, r0 neg r0, r0
b __set_errno_internal b __set_errno_internal
END(___fchmodat) END(fchmodat)
.hidden ___fchmodat

View File

@ -2,7 +2,7 @@
#include <private/bionic_asm.h> #include <private/bionic_asm.h>
ENTRY(___fgetxattr) ENTRY(fgetxattr)
mov ip, r7 mov ip, r7
ldr r7, =__NR_fgetxattr ldr r7, =__NR_fgetxattr
swi #0 swi #0
@ -11,5 +11,4 @@ ENTRY(___fgetxattr)
bxls lr bxls lr
neg r0, r0 neg r0, r0
b __set_errno_internal b __set_errno_internal
END(___fgetxattr) END(fgetxattr)
.hidden ___fgetxattr

View File

@ -2,7 +2,7 @@
#include <private/bionic_asm.h> #include <private/bionic_asm.h>
ENTRY(___flistxattr) ENTRY(flistxattr)
mov ip, r7 mov ip, r7
ldr r7, =__NR_flistxattr ldr r7, =__NR_flistxattr
swi #0 swi #0
@ -11,5 +11,4 @@ ENTRY(___flistxattr)
bxls lr bxls lr
neg r0, r0 neg r0, r0
b __set_errno_internal b __set_errno_internal
END(___flistxattr) END(flistxattr)
.hidden ___flistxattr

View File

@ -2,7 +2,7 @@
#include <private/bionic_asm.h> #include <private/bionic_asm.h>
ENTRY(___fsetxattr) ENTRY(fsetxattr)
mov ip, sp mov ip, sp
stmfd sp!, {r4, r5, r6, r7} stmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 16 .cfi_def_cfa_offset 16
@ -19,5 +19,4 @@ ENTRY(___fsetxattr)
bxls lr bxls lr
neg r0, r0 neg r0, r0
b __set_errno_internal b __set_errno_internal
END(___fsetxattr) END(fsetxattr)
.hidden ___fsetxattr

View File

@ -13,4 +13,5 @@ ENTRY(fstat64)
b __set_errno_internal b __set_errno_internal
END(fstat64) END(fstat64)
ALIAS_SYMBOL(fstat, fstat64) .globl fstat
.equ fstat, fstat64

View File

@ -13,4 +13,5 @@ ENTRY(fstatat64)
b __set_errno_internal b __set_errno_internal
END(fstatat64) END(fstatat64)
ALIAS_SYMBOL(fstatat, fstatat64) .globl fstatat
.equ fstatat, fstatat64

View File

@ -2,13 +2,13 @@
#include <private/bionic_asm.h> #include <private/bionic_asm.h>
ENTRY(sethostname) ENTRY(ftruncate)
mov ip, r7 mov ip, r7
ldr r7, =__NR_sethostname ldr r7, =__NR_ftruncate
swi #0 swi #0
mov r7, ip mov r7, ip
cmn r0, #(MAX_ERRNO + 1) cmn r0, #(MAX_ERRNO + 1)
bxls lr bxls lr
neg r0, r0 neg r0, r0
b __set_errno_internal b __set_errno_internal
END(sethostname) END(ftruncate)

View File

@ -0,0 +1,14 @@
/* Generated by gensyscalls.py. Do not edit. */
#include <private/bionic_asm.h>
ENTRY(mremap)
mov ip, r7
ldr r7, =__NR_mremap
swi #0
mov r7, ip
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno_internal
END(mremap)

View File

@ -1,22 +0,0 @@
/* Generated by gensyscalls.py. Do not edit. */
#include <private/bionic_asm.h>
ENTRY(process_vm_readv)
mov ip, sp
stmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 16
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
.cfi_rel_offset r6, 8
.cfi_rel_offset r7, 12
ldmfd ip, {r4, r5, r6}
ldr r7, =__NR_process_vm_readv
swi #0
ldmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 0
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno_internal
END(process_vm_readv)

View File

@ -1,22 +0,0 @@
/* Generated by gensyscalls.py. Do not edit. */
#include <private/bionic_asm.h>
ENTRY(process_vm_writev)
mov ip, sp
stmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 16
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
.cfi_rel_offset r6, 8
.cfi_rel_offset r7, 12
ldmfd ip, {r4, r5, r6}
ldr r7, =__NR_process_vm_writev
swi #0
ldmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 0
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno_internal
END(process_vm_writev)

Some files were not shown because too many files have changed in this diff Show More