Compare commits

..

No commits in common. "main" and "android-4.4w_r1" have entirely different histories.

4901 changed files with 154393 additions and 550478 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

15
ABI-bugs.txt Normal file
View File

@ -0,0 +1,15 @@
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
Too few TLS slots mean we can't allocate 128 pthread_key_t instances,
which POSIX says should be the minimum.
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

View File

@ -44,10 +44,6 @@
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
# Switching to jemalloc requires deleting these files.
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libc_*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libc_*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************

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

@ -1,130 +0,0 @@
#
# Copyright (C) 2013 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
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.
# -----------------------------------------------------------------------------
benchmark_src_files := \
math_benchmark.cpp \
property_benchmark.cpp \
pthread_benchmark.cpp \
semaphore_benchmark.cpp \
stdio_benchmark.cpp \
string_benchmark.cpp \
time_benchmark.cpp \
unistd_benchmark.cpp \
# Build benchmarks for the device (with bionic's .so). Run with:
# adb shell bionic-benchmarks32
# adb shell bionic-benchmarks64
include $(CLEAR_VARS)
LOCAL_MODULE := bionic-benchmarks
LOCAL_MODULE_STEM_32 := bionic-benchmarks32
LOCAL_MODULE_STEM_64 := bionic-benchmarks64
LOCAL_MULTILIB := both
LOCAL_CFLAGS := $(benchmark_cflags)
LOCAL_CPPFLAGS := $(benchmark_cppflags)
LOCAL_SRC_FILES := $(benchmark_src_files)
LOCAL_STATIC_LIBRARIES := libbenchmark libbase
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))
include $(LOCAL_PATH)/../build/run-on-host.mk
ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64))
bionic-benchmarks-run-on-host32: bionic-benchmarks bionic-prepare-run-on-host
ANDROID_DATA=$(TARGET_OUT_DATA) \
ANDROID_ROOT=$(TARGET_OUT) \
$(TARGET_OUT_EXECUTABLES)/bionic-benchmarks32 $(BIONIC_BENCHMARKS_FLAGS)
endif
ifeq ($(TARGET_IS_64_BIT),true)
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

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

@ -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

@ -1,286 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <fenv.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.
volatile double d;
volatile double v;
BENCHMARK_NO_ARG(BM_math_sqrt);
void BM_math_sqrt::Run(int iters) {
StartBenchmarkTiming();
d = 0.0;
v = 2.0;
for (int i = 0; i < iters; ++i) {
d += sqrt(v);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_math_log10);
void BM_math_log10::Run(int iters) {
StartBenchmarkTiming();
d = 0.0;
v = 1234.0;
for (int i = 0; i < iters; ++i) {
d += log10(v);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_math_logb);
void BM_math_logb::Run(int iters) {
StartBenchmarkTiming();
d = 0.0;
v = 1234.0;
for (int i = 0; i < iters; ++i) {
d += logb(v);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_math_isfinite_macro, double)->AT_COMMON_VALS;
void BM_math_isfinite_macro::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
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) {
d += (isinf)(v);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_math_isnan_macro, double)->AT_COMMON_VALS;
void BM_math_isnan_macro::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) {
d += isnan(v);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_math_isnan, double)->AT_COMMON_VALS;
void BM_math_isnan::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) {
d += (isnan)(v);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_math_isnormal_macro, double)->AT_COMMON_VALS;
void BM_math_isnormal_macro::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) {
d += isnormal(v);
}
StopBenchmarkTiming();
}
#if defined(__BIONIC__)
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();
d = 1.0;
for (int i = 0; i < iters; ++i) {
d += sin(d);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_math_sin_feupdateenv);
void BM_math_sin_feupdateenv::Run(int iters) {
StartBenchmarkTiming();
d = 1.0;
for (int i = 0; i < iters; ++i) {
fenv_t __libc_save_rm;
feholdexcept(&__libc_save_rm);
fesetround(FE_TONEAREST);
d += sin(d);
feupdateenv(&__libc_save_rm);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_math_sin_fesetenv);
void BM_math_sin_fesetenv::Run(int iters) {
StartBenchmarkTiming();
d = 1.0;
for (int i = 0; i < iters; ++i) {
fenv_t __libc_save_rm;
feholdexcept(&__libc_save_rm);
fesetround(FE_TONEAREST);
d += sin(d);
fesetenv(&__libc_save_rm);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_math_fpclassify, double)->AT_COMMON_VALS;
void BM_math_fpclassify::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) {
d += fpclassify(v);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_math_signbit_macro, double)->AT_COMMON_VALS;
void BM_math_signbit_macro::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) {
d += signbit(v);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_math_signbit, double)->AT_COMMON_VALS;
void BM_math_signbit::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) {
d += (__signbit)(v);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_math_fabs_macro, double)->AT_COMMON_VALS;
void BM_math_fabs_macro::Run(int iters, double value) {
StartBenchmarkTiming();
d = 0.0;
v = value;
for (int i = 0; i < iters; ++i) {
d += fabs(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();
}

View File

@ -1,233 +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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#if defined(__BIONIC__)
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
#include <benchmark/Benchmark.h>
extern void* __system_property_area__;
// Do not exceed 512, that is about the largest number of properties
// that can be created with the current property area size.
#define TEST_NUM_PROPS \
Arg(1)->Arg(4)->Arg(16)->Arg(64)->Arg(128)->Arg(256)->Arg(512)
struct LocalPropertyTestState {
LocalPropertyTestState(int nprops) : nprops(nprops), valid(false) {
static const char prop_name_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
const char* android_data = getenv("ANDROID_DATA");
if (android_data == NULL) {
printf("ANDROID_DATA environment variable not set\n");
return;
}
char dir_template[PATH_MAX];
snprintf(dir_template, sizeof(dir_template), "%s/local/tmp/prop-XXXXXX", android_data);
char* dirname = mkdtemp(dir_template);
if (!dirname) {
printf("making temp file for test state failed (is %s/local/tmp writable?): %s\n",
android_data, strerror(errno));
return;
}
old_pa = __system_property_area__;
__system_property_area__ = NULL;
pa_dirname = dirname;
pa_filename = pa_dirname + "/__properties__";
__system_property_set_filename(pa_filename.c_str());
__system_property_area_init();
names = new char* [nprops];
name_lens = new int[nprops];
values = new char* [nprops];
value_lens = new int[nprops];
srandom(nprops);
for (int i = 0; i < nprops; i++) {
// Make sure the name has at least 10 characters to make
// it very unlikely to generate the same random name.
name_lens[i] = (random() % (PROP_NAME_MAX - 10)) + 10;
names[i] = new char[PROP_NAME_MAX + 1];
size_t prop_name_len = sizeof(prop_name_chars) - 1;
for (int j = 0; j < name_lens[i]; j++) {
if (j == 0 || names[i][j-1] == '.' || j == name_lens[i] - 1) {
// Certain values are not allowed:
// - Don't start name with '.'
// - Don't allow '.' to appear twice in a row
// - Don't allow the name to end with '.'
// This assumes that '.' is the last character in the
// array so that decrementing the length by one removes
// the value from the possible values.
prop_name_len--;
}
names[i][j] = prop_name_chars[random() % prop_name_len];
}
names[i][name_lens[i]] = 0;
// Make sure the value contains at least 1 character.
value_lens[i] = (random() % (PROP_VALUE_MAX - 1)) + 1;
values[i] = new char[PROP_VALUE_MAX];
for (int j = 0; j < value_lens[i]; j++) {
values[i][j] = prop_name_chars[random() % (sizeof(prop_name_chars) - 1)];
}
if (__system_property_add(names[i], name_lens[i], values[i], value_lens[i]) < 0) {
printf("Failed to add a property, terminating...\n");
printf("%s = %.*s\n", names[i], value_lens[i], values[i]);
exit(1);
}
}
valid = true;
}
~LocalPropertyTestState() {
if (!valid)
return;
__system_property_area__ = old_pa;
__system_property_set_filename(PROP_FILENAME);
unlink(pa_filename.c_str());
rmdir(pa_dirname.c_str());
for (int i = 0; i < nprops; i++) {
delete names[i];
delete values[i];
}
delete[] names;
delete[] name_lens;
delete[] values;
delete[] value_lens;
}
public:
const int nprops;
char** names;
int* name_lens;
char** values;
int* value_lens;
bool valid;
private:
std::string pa_dirname;
std::string pa_filename;
void* old_pa;
};
BENCHMARK_WITH_ARG(BM_property_get, int)->TEST_NUM_PROPS;
void BM_property_get::Run(int iters, int nprops) {
StopBenchmarkTiming();
LocalPropertyTestState pa(nprops);
char value[PROP_VALUE_MAX];
if (!pa.valid)
return;
srandom(iters * nprops);
StartBenchmarkTiming();
for (int i = 0; i < iters; i++) {
__system_property_get(pa.names[random() % nprops], value);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_property_find, int)->TEST_NUM_PROPS;
void BM_property_find::Run(int iters, int nprops) {
StopBenchmarkTiming();
LocalPropertyTestState pa(nprops);
if (!pa.valid)
return;
srandom(iters * nprops);
StartBenchmarkTiming();
for (int i = 0; i < iters; i++) {
__system_property_find(pa.names[random() % nprops]);
}
StopBenchmarkTiming();
}
BENCHMARK_WITH_ARG(BM_property_read, int)->TEST_NUM_PROPS;
void BM_property_read::Run(int iters, int nprops) {
StopBenchmarkTiming();
LocalPropertyTestState pa(nprops);
if (!pa.valid)
return;
srandom(iters * nprops);
const prop_info** pinfo = new const prop_info*[iters];
char propvalue[PROP_VALUE_MAX];
for (int i = 0; i < iters; i++) {
pinfo[i] = __system_property_find(pa.names[random() % nprops]);
}
StartBenchmarkTiming();
for (int i = 0; i < iters; i++) {
__system_property_read(pinfo[i], 0, propvalue);
}
StopBenchmarkTiming();
delete[] pinfo;
}
BENCHMARK_WITH_ARG(BM_property_serial, int)->TEST_NUM_PROPS;
void BM_property_serial::Run(int iters, int nprops) {
StopBenchmarkTiming();
LocalPropertyTestState pa(nprops);
if (!pa.valid)
return;
srandom(iters * nprops);
const prop_info** pinfo = new const prop_info*[iters];
for (int i = 0; i < iters; i++) {
pinfo[i] = __system_property_find(pa.names[random() % nprops]);
}
StartBenchmarkTiming();
for (int i = 0; i < iters; i++) {
__system_property_serial(pinfo[i]);
}
StopBenchmarkTiming();
delete[] pinfo;
}
#endif // __BIONIC__

View File

@ -1,233 +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 <pthread.h>
#include <benchmark/Benchmark.h>
// Stop GCC optimizing out our pure function.
/* Must not be static! */ pthread_t (*pthread_self_fp)() = pthread_self;
BENCHMARK_NO_ARG(BM_pthread_self);
void BM_pthread_self::Run(int iters) {
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
pthread_self_fp();
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_pthread_getspecific);
void BM_pthread_getspecific::Run(int iters) {
StopBenchmarkTiming();
pthread_key_t key;
pthread_key_create(&key, NULL);
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
pthread_getspecific(key);
}
StopBenchmarkTiming();
pthread_key_delete(key);
}
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() {
}
BENCHMARK_NO_ARG(BM_pthread_once);
void BM_pthread_once::Run(int iters) {
StopBenchmarkTiming();
pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_once(&once, DummyPthreadOnceInitFunction);
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
pthread_once(&once, DummyPthreadOnceInitFunction);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_pthread_mutex_lock);
void BM_pthread_mutex_lock::Run(int iters) {
StopBenchmarkTiming();
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_pthread_mutex_lock_ERRORCHECK);
void BM_pthread_mutex_lock_ERRORCHECK::Run(int iters) {
StopBenchmarkTiming();
pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_pthread_mutex_lock_RECURSIVE);
void BM_pthread_mutex_lock_RECURSIVE::Run(int iters) {
StopBenchmarkTiming();
pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
}
StopBenchmarkTiming();
}
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

@ -1,143 +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 <pthread.h>
#include <semaphore.h>
#include <stdatomic.h>
#include <stdio.h>
#include <benchmark/Benchmark.h>
BENCHMARK_NO_ARG(BM_semaphore_sem_getvalue);
void BM_semaphore_sem_getvalue::Run(int iters) {
StopBenchmarkTiming();
sem_t semaphore;
sem_init(&semaphore, 1, 1);
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
int dummy;
sem_getvalue(&semaphore, &dummy);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_semaphore_sem_wait_sem_post);
void BM_semaphore_sem_wait_sem_post::Run(int iters) {
StopBenchmarkTiming();
sem_t semaphore;
sem_init(&semaphore, 1, 1);
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
sem_wait(&semaphore);
sem_post(&semaphore);
}
StopBenchmarkTiming();
}
/*
* 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

@ -1,94 +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 <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <benchmark/Benchmark.h>
#define KB 1024
#define MB 1024*KB
#define AT_COMMON_SIZES \
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)
template <typename Fn>
void ReadWriteTest(::testing::Benchmark* benchmark, int iters, int chunk_size, Fn f, bool buffered) {
benchmark->StopBenchmarkTiming();
FILE* fp = fopen("/dev/zero", "rw");
__fsetlocking(fp, FSETLOCKING_BYCALLER);
char* buf = new char[chunk_size];
benchmark->StartBenchmarkTiming();
if (!buffered) {
setvbuf(fp, 0, _IONBF, 0);
}
for (int i = 0; i < iters; ++i) {
f(buf, chunk_size, 1, fp);
}
benchmark->StopBenchmarkTiming();
benchmark->SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(chunk_size));
delete[] buf;
fclose(fp);
}
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;
void BM_stdio_fwrite::Run(int iters, int chunk_size) {
ReadWriteTest(this, iters, chunk_size, fwrite, true);
}
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) {
FILE* fp = fopen("/proc/version", "re");
if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER);
if (fgets(buf, sizeof(buf), fp) == nullptr) abort();
fclose(fp);
}
}
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

@ -1,113 +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 <stdint.h>
#include <string.h>
#include <benchmark/Benchmark.h>
#define KB 1024
#define MB 1024*KB
#define AT_COMMON_SIZES \
Arg(8)->Arg(64)->Arg(512)->Arg(1*KB)->Arg(8*KB)->Arg(16*KB)->Arg(32*KB)->Arg(64*KB)
// TODO: test unaligned operation too? (currently everything will be 8-byte aligned by malloc.)
BENCHMARK_WITH_ARG(BM_string_memcmp, int)->AT_COMMON_SIZES;
void BM_string_memcmp::Run(int iters, int nbytes) {
StopBenchmarkTiming();
char* src = new char[nbytes]; char* dst = new char[nbytes];
memset(src, 'x', nbytes);
memset(dst, 'x', nbytes);
StartBenchmarkTiming();
volatile int c __attribute__((unused)) = 0;
for (int i = 0; i < iters; ++i) {
c += memcmp(dst, src, nbytes);
}
StopBenchmarkTiming();
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes));
delete[] src;
delete[] dst;
}
BENCHMARK_WITH_ARG(BM_string_memcpy, int)->AT_COMMON_SIZES;
void BM_string_memcpy::Run(int iters, int nbytes) {
StopBenchmarkTiming();
char* src = new char[nbytes]; char* dst = new char[nbytes];
memset(src, 'x', nbytes);
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
memcpy(dst, src, nbytes);
}
StopBenchmarkTiming();
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes));
delete[] src;
delete[] dst;
}
BENCHMARK_WITH_ARG(BM_string_memmove, int)->AT_COMMON_SIZES;
void BM_string_memmove::Run(int iters, int nbytes) {
StopBenchmarkTiming();
char* buf = new char[nbytes + 64];
memset(buf, 'x', nbytes + 64);
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
memmove(buf, buf + 1, nbytes); // Worst-case overlap.
}
StopBenchmarkTiming();
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes));
delete[] buf;
}
BENCHMARK_WITH_ARG(BM_string_memset, int)->AT_COMMON_SIZES;
void BM_string_memset::Run(int iters, int nbytes) {
StopBenchmarkTiming();
char* dst = new char[nbytes];
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
memset(dst, 0, nbytes);
}
StopBenchmarkTiming();
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes));
delete[] dst;
}
BENCHMARK_WITH_ARG(BM_string_strlen, int)->AT_COMMON_SIZES;
void BM_string_strlen::Run(int iters, int nbytes) {
StopBenchmarkTiming();
char* s = new char[nbytes];
memset(s, 'x', nbytes);
s[nbytes - 1] = 0;
StartBenchmarkTiming();
volatile int c __attribute__((unused)) = 0;
for (int i = 0; i < iters; ++i) {
c += strlen(s);
}
StopBenchmarkTiming();
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes));
delete[] s;
}

View File

@ -1,81 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/syscall.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <benchmark/Benchmark.h>
BENCHMARK_NO_ARG(BM_time_clock_gettime);
void BM_time_clock_gettime::Run(int iters) {
StartBenchmarkTiming();
timespec t;
for (int i = 0; i < iters; ++i) {
clock_gettime(CLOCK_MONOTONIC, &t);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_time_clock_gettime_syscall);
void BM_time_clock_gettime_syscall::Run(int iters) {
StartBenchmarkTiming();
timespec t;
for (int i = 0; i < iters; ++i) {
syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &t);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_time_gettimeofday);
void BM_time_gettimeofday::Run(int iters) {
StartBenchmarkTiming();
timeval tv;
for (int i = 0; i < iters; ++i) {
gettimeofday(&tv, NULL);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_time_gettimeofday_syscall);
void BM_time_gettimeofday_syscall::Run(int iters) {
StartBenchmarkTiming();
timeval tv;
for (int i = 0; i < iters; ++i) {
syscall(__NR_gettimeofday, &tv, NULL);
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_time_time);
void BM_time_time::Run(int iters) {
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
time(NULL);
}
StopBenchmarkTiming();
}

View File

@ -1,71 +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 <sys/syscall.h>
#include <unistd.h>
#include <benchmark/Benchmark.h>
BENCHMARK_NO_ARG(BM_unistd_getpid);
void BM_unistd_getpid::Run(int iters) {
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
getpid();
}
StopBenchmarkTiming();
}
BENCHMARK_NO_ARG(BM_unistd_getpid_syscall);
void BM_unistd_getpid_syscall::Run(int iters) {
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
syscall(__NR_getpid);
}
StopBenchmarkTiming();
}
#if defined(__BIONIC__)
// Stop GCC optimizing out our pure function.
/* Must not be static! */ pid_t (*gettid_fp)() = gettid;
BENCHMARK_NO_ARG(BM_unistd_gettid);
void BM_unistd_gettid::Run(int iters) {
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
gettid_fp();
}
StopBenchmarkTiming();
}
#endif
BENCHMARK_NO_ARG(BM_unistd_gettid_syscall);
void BM_unistd_gettid_syscall::Run(int iters) {
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
syscall(__NR_gettid);
}
StopBenchmarkTiming();
}

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,26 +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_UTILS_H
#define BENCHMARKS_UTILS_H
#include <stddef.h>
#include <string>
int Round(int n);
std::string PrettyInt(long value, size_t base);
#endif // BENCHMARKS_UTILS_H

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

26
libc/CAVEATS Normal file
View File

@ -0,0 +1,26 @@
Bionic is a very small C library because we have decided to *not* implement various features
of the POSIX standard. we only add functions on a as-needed basis, and there are a few things
we wish we'll never put in there.
this file is here to document explicitely what we don't want to support in Bionic:
- C++ exceptions are not supported. on embedded systems, they lead to extremely larger and
slower code for no good reason (even when so-called zero-cost exception schemes are
implemented, they enforce very large numbers of registers spills to the stack, even
in functions that do not throw an exception themselves).
- pthread cancellation is *not* supported. this seemingly simple "feature" is the source
of much bloat and complexity in a C library. Besides, you'd better write correct
multi-threaded code instead of relying on this stuff.
- pthread_once() doesn't support C++ exceptions thrown from the init function, or the init
function doing a fork().
- locales and wide characters are not supported. we use ICU for all this i18n stuff, which
is much better than the ill-designed related C libraries functions.
- at the moment, several user-account-related functions like getpwd are stubbed and return
the values corresponding to root. this will be fixed when we'll be able to have distinct
users on the Android filesystem. :-(
see bionic/stubs.c for the details

File diff suppressed because it is too large Load Diff

View File

@ -1,348 +1,326 @@
# This file is used to automatically generate bionic's system call stubs.
# This file is used to automatically generate bionic's the system calls stubs.
#
# Each non-blank, non-comment line has the following format:
# Each non comment line has the following format:
#
# return_type func_name[|alias_list][:syscall_name[:socketcall_id]]([parameter_list]) arch_list
# return_type func_name[:syscall_name[:call_id]]([parameter_list]) (1|-1|"stub")
#
# where:
# arch_list ::= "all" | arch+
# arch ::= "arm" | "arm64" | "mips" | "mips64" | "x86" | "x86_64"
#
# Note:
# Note that:
# - syscall_name corresponds to the name of the syscall, which may differ from
# the exported function name (example: the exit syscall is implemented by the _exit()
# function, which is not the same as the standard C exit() function which calls it)
#
# - alias_list is optional comma separated list of function aliases.
#
# - The call_id parameter, given that func_name and syscall_name have
# The call_id parameter, given that func_name and syscall_name have
# been provided, allows the user to specify dispatch style syscalls.
# For example, socket() syscall on i386 actually becomes:
# socketcall(__NR_socket, 1, *(rest of args on stack)).
#
# - Each parameter type is assumed to be stored in 32 bits.
# - each parameter type is assumed to be stored on 32 bits, there is no plan to support
# 64-bit architectures at the moment
#
# - the final field can be "1", meaning: generate a stub for each architecture,
# taking the constants from the kernel header files.
#
# - the final field can be "stub" meaning: do not generate any stubs ---
# in this case, a hand-written custom stub must be provided.
# TODO: replace this with something like "custom" or "none", or remove
# it entirely.
#
# - the final field can be a three-element list of 1s and -1 meaning:
# this system call is only available on some of the architectures (1),
# and no stub should be generated for those architectures marked with -1.
# the order is arm,x86,mips.
# TODO: replace this with something more readable like "-arm,-mips" (meaning x86 only).
#
# This file is processed by a python script named gensyscalls.py.
#
int execve(const char*, char* const*, char* const*) all
# process management
void _exit:exit_group (int) 1
void _exit_thread:exit (int) 1
pid_t __fork:fork (void) 1
pid_t _waitpid:waitpid (pid_t, int*, int, struct rusage*) -1,1,1
int __waitid:waitid(int, pid_t, struct siginfo_t*, int,void*) 1
pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) 1
uid_t getuid:getuid32() arm,x86
uid_t getuid:getuid() arm64,mips,mips64,x86_64
gid_t getgid:getgid32() arm,x86
gid_t getgid:getgid() arm64,mips,mips64,x86_64
uid_t geteuid:geteuid32() arm,x86
uid_t geteuid:geteuid() arm64,mips,mips64,x86_64
gid_t getegid:getegid32() arm,x86
gid_t getegid:getegid() arm64,mips,mips64,x86_64
uid_t getresuid:getresuid32(uid_t* ruid, uid_t* euid, uid_t* suid) arm,x86
uid_t getresuid:getresuid(uid_t* ruid, uid_t* euid, uid_t* suid) arm64,mips,mips64,x86_64
gid_t getresgid:getresgid32(gid_t* rgid, gid_t* egid, gid_t* sgid) arm,x86
gid_t getresgid:getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid) arm64,mips,mips64,x86_64
ssize_t readahead(int, off64_t, size_t) all
int getgroups:getgroups32(int, gid_t*) arm,x86
int getgroups:getgroups(int, gid_t*) arm64,mips,mips64,x86_64
pid_t getpgid(pid_t) all
pid_t getppid() all
pid_t getsid(pid_t) all
pid_t setsid() all
int setgid:setgid32(gid_t) arm,x86
int setgid:setgid(gid_t) arm64,mips,mips64,x86_64
int setuid:setuid32(uid_t) arm,x86
int setuid:setuid(uid_t) arm64,mips,mips64,x86_64
int setreuid:setreuid32(uid_t, uid_t) arm,x86
int setreuid:setreuid(uid_t, uid_t) arm64,mips,mips64,x86_64
int setresuid:setresuid32(uid_t, uid_t, uid_t) arm,x86
int setresuid:setresuid(uid_t, uid_t, uid_t) arm64,mips,mips64,x86_64
int setresgid:setresgid32(gid_t, gid_t, gid_t) arm,x86
int setresgid:setresgid(gid_t, gid_t, gid_t) arm64,mips,mips64,x86_64
void* __brk:brk(void*) all
int kill(pid_t, int) all
int tgkill(pid_t tgid, pid_t tid, int sig) all
int __ptrace:ptrace(int request, int pid, void* addr, void* data) all
# NOTE: this system call is never called directly, but we list it there
# to have __NR_clone properly defined.
#
pid_t __sys_clone:clone (int, void*, int*, void*, int*) 1
# <sys/resource.h>
int getrusage(int, struct rusage*) all
int __getpriority:getpriority(int, int) all
int setpriority(int, int, int) all
# On LP64, rlimit and rlimit64 are the same.
# On 32-bit systems we use prlimit64 to implement the rlimit64 functions.
int getrlimit:ugetrlimit(int, struct rlimit*) arm,x86
int getrlimit(int, struct rlimit*) mips
int getrlimit|getrlimit64(int, struct rlimit*) arm64,mips64,x86_64
int setrlimit(int, const struct rlimit*) arm,mips,x86
int setrlimit|setrlimit64(int, const struct rlimit*) arm64,mips64,x86_64
int prlimit64|prlimit(pid_t, int, struct rlimit64*, const struct rlimit64*) arm64,mips64,x86_64
int prlimit64(pid_t, int, struct rlimit64*, const struct rlimit64*) arm,mips,x86
int execve (const char*, char* const*, char* const*) 1
int setgroups:setgroups32(int, const gid_t*) arm,x86
int setgroups:setgroups(int, const gid_t*) arm64,mips,mips64,x86_64
int setpgid(pid_t, pid_t) all
int setregid:setregid32(gid_t, gid_t) arm,x86
int setregid:setregid(gid_t, gid_t) arm64,mips,mips64,x86_64
int chroot(const char*) all
int prctl(int, unsigned long, unsigned long, unsigned long, unsigned long) all
long __arch_prctl:arch_prctl(int, unsigned long) x86_64
int capget(cap_user_header_t header, cap_user_data_t data) all
int capset(cap_user_header_t header, const cap_user_data_t data) all
int sigaltstack(const stack_t*, stack_t*) all
int acct(const char* filepath) all
int __setuid:setuid32 (uid_t) 1,1,-1
int __setuid:setuid (uid_t) -1,-1,1
uid_t getuid:getuid32 () 1,1,-1
uid_t getuid:getuid () -1,-1,1
gid_t getgid:getgid32 () 1,1,-1
gid_t getgid:getgid () -1,-1,1
uid_t geteuid:geteuid32 () 1,1,-1
uid_t geteuid:geteuid () -1,-1,1
gid_t getegid:getegid32 () 1,1,-1
gid_t getegid:getegid () -1,-1,1
uid_t getresuid:getresuid32 (uid_t *ruid, uid_t *euid, uid_t *suid) 1,1,-1
uid_t getresuid:getresuid (uid_t *ruid, uid_t *euid, uid_t *suid) -1,-1,1
gid_t getresgid:getresgid32 (gid_t *rgid, gid_t *egid, gid_t *sgid) 1,1,-1
gid_t getresgid:getresgid (gid_t *rgid, gid_t *egid, gid_t *sgid) -1,-1,1
pid_t gettid() 1
ssize_t readahead(int, off64_t, size_t) 1
int getgroups:getgroups32(int, gid_t *) 1,1,-1
int getgroups:getgroups(int, gid_t *) -1,-1,1
pid_t getpgid(pid_t) 1
pid_t getppid() 1
pid_t getsid(pid_t) 1
pid_t setsid() 1
int setgid:setgid32(gid_t) 1,1,-1
int setgid:setgid(gid_t) -1,-1,1
int seteuid:seteuid32(uid_t) stub
int __setreuid:setreuid32(uid_t, uid_t) 1,1,-1
int __setreuid:setreuid(uid_t, uid_t) -1,-1,1
int __setresuid:setresuid32(uid_t, uid_t, uid_t) 1,1,-1
int __setresuid:setresuid(uid_t, uid_t, uid_t) -1,-1,1
int setresgid:setresgid32(gid_t, gid_t, gid_t) 1,1,-1
int setresgid:setresgid(gid_t, gid_t, gid_t) -1,-1,1
void* __brk:brk(void*) 1
# see comments in arch-arm/bionic/kill.S to understand why we don't generate an ARM stub for kill/tkill
int kill(pid_t, int) -1,1,1
int tkill(pid_t tid, int sig) -1,1,1
int tgkill(pid_t tgid, pid_t tid, int sig) -1,1,1
int __ptrace:ptrace(int request, int pid, void* addr, void* data) 1
int __set_thread_area:set_thread_area(void* user_desc) -1,1,1
int __getpriority:getpriority(int, int) 1
int setpriority(int, int, int) 1
int setrlimit(int resource, const struct rlimit *rlp) 1
int getrlimit:ugetrlimit(int resource, struct rlimit *rlp) 1,1,-1
int getrlimit:getrlimit(int resource, struct rlimit *rlp) -1,-1,1
int getrusage(int who, struct rusage* r_usage) 1
int setgroups:setgroups32(int, const gid_t *) 1,1,-1
int setgroups:setgroups(int, const gid_t *) -1,-1,1
pid_t getpgrp(void) stub
int setpgid(pid_t, pid_t) 1
pid_t vfork(void) 1,-1,-1
int setregid:setregid32(gid_t, gid_t) 1,1,-1
int setregid:setregid(gid_t, gid_t) -1,-1,1
int chroot(const char *) 1
# IMPORTANT: Even though <sys/prctl.h> declares prctl(int,...), the syscall stub must take 6 arguments
# to match the kernel implementation.
int prctl(int option, unsigned int arg2, unsigned int arg3, unsigned int arg4, unsigned int arg5) 1
int capget(cap_user_header_t header, cap_user_data_t data) 1
int capset(cap_user_header_t header, const cap_user_data_t data) 1
int sigaltstack(const stack_t*, stack_t*) 1
int acct(const char* filepath) 1
# file descriptors
ssize_t read(int, void*, size_t) all
ssize_t write(int, const void*, size_t) all
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 pwrite64(int, void*, size_t, off64_t) arm,mips,x86
ssize_t pwrite64|pwrite(int, void*, size_t, off_t) arm64,mips64,x86_64
# 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
int munmap(void*, size_t) all
void* ___mremap:mremap(void*, size_t, size_t, int, void*) all
int msync(const void*, size_t, int) all
int mprotect(const void*, size_t, int) all
int madvise(void*, size_t, int) all
int mlock(const void* addr, size_t len) all
int munlock(const void* addr, size_t len) all
int mlockall(int flags) all
int munlockall() all
int mincore(void* start, size_t length, unsigned char* vec) all
int __ioctl:ioctl(int, int, void*) all
int readv(int, const struct iovec*, int) all
int writev(int, const struct iovec*, int) all
int __fcntl64:fcntl64(int, int, void*) arm,mips,x86
int fcntl(int, int, void*) arm64,mips64,x86_64
int flock(int, int) all
int ___fchmod:fchmod(int, mode_t) all
int dup(int) all
int pipe2(int*, int) all
int dup3(int, int, int) all
int fsync(int) all
int fdatasync(int) all
int fchown:fchown32(int, uid_t, gid_t) arm,x86
int fchown:fchown(int, uid_t, gid_t) arm64,mips,mips64,x86_64
void sync(void) all
int ___fsetxattr:fsetxattr(int, const char*, const void*, size_t, int) all
ssize_t ___fgetxattr:fgetxattr(int, const char*, void*, size_t) all
ssize_t ___flistxattr:flistxattr(int, char*, size_t) all
int fremovexattr(int, const char*) all
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 ___faccessat:faccessat(int, const char*, int) all
int ___fchmodat:fchmodat(int, const char*, mode_t) 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:newfstatat(int, const char*, struct stat*, int) arm64,x86_64
int linkat(int, const char*, int, const char*, int) all
int mkdirat(int, const char*, mode_t) all
int mknodat(int, const char*, mode_t, dev_t) all
int readlinkat(int, const char*, char*, size_t) all
int renameat(int, const char*, int, const char*) all
int symlinkat(const char*, int, const char*) all
int unlinkat(int, const char*, int) all
int utimensat(int, const char*, const struct timespec times[2], int) all
# Paired off_t/off64_t system calls. On 64-bit systems,
# sizeof(off_t) == sizeof(off64_t), so there we emit two symbols that are
# aliases. On 32-bit systems, we have two different system calls.
# That means that every system call in this section should take three lines.
off_t lseek(int, off_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
int ftruncate64(int, off64_t) arm,mips,x86
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 sendfile64(int out_fd, int in_fd, off64_t* offset, size_t count) arm,mips,x86
ssize_t sendfile|sendfile64(int out_fd, int in_fd, off_t* offset, size_t count) arm64,mips64,x86_64
int truncate(const char*, off_t) arm,mips,x86
int truncate64(const char*, off64_t) arm,mips,x86
int truncate|truncate64(const char*, off_t) arm64,mips64,x86_64
# (mmap only gets two lines because we only used the 64-bit variant on 32-bit systems.)
void* __mmap2:mmap2(void*, size_t, int, int, int, long) arm,mips,x86
void* mmap|mmap64(void*, size_t, int, int, int, off_t) arm64,mips64,x86_64
# (fallocate only gets two lines because there is no 32-bit variant.)
int fallocate64:fallocate(int, int, off64_t, off64_t) arm,mips,x86
int fallocate|fallocate64(int, int, off_t, off_t) arm64,mips64,x86_64
# posix_fadvise64 is awkward: arm has shuffled arguments,
# the POSIX functions don't set errno, and no architecture has posix_fadvise.
int __arm_fadvise64_64:arm_fadvise64_64(int, int, off64_t, off64_t) arm
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 __fstatfs64:fstatfs64(int, size_t, struct statfs*) arm,mips,x86
int __fstatfs:fstatfs(int, struct statfs*) arm64,mips64,x86_64
int __statfs64:statfs64(const char*, size_t, struct statfs*) arm,mips,x86
int __statfs:statfs(const char*, struct statfs*) arm64,mips64,x86_64
int fstat64|fstat:fstat64(int, struct stat*) arm,mips,x86
int fstat64|fstat:fstat(int, struct stat*) arm64,x86_64
ssize_t read (int, void*, size_t) 1
ssize_t write (int, const void*, size_t) 1
ssize_t pread64 (int, void *, size_t, off64_t) 1
ssize_t pwrite64 (int, void *, size_t, off64_t) 1
int __open:open (const char*, int, mode_t) 1
int __openat:openat (int, const char*, int, mode_t) 1
int close (int) 1
int creat(const char*, mode_t) stub
off_t lseek(int, off_t, int) 1
int __llseek:_llseek (int, unsigned long, unsigned long, loff_t*, int) 1
pid_t getpid () 1
void * mmap(void *, size_t, int, int, int, long) stub
void * __mmap2:mmap2(void*, size_t, int, int, int, long) 1
int munmap(void *, size_t) 1
void * mremap(void *, size_t, size_t, unsigned long) 1
int msync(const void *, size_t, int) 1
int mprotect(const void *, size_t, int) 1
int madvise(const void *, size_t, int) 1
int mlock(const void *addr, size_t len) 1
int munlock(const void *addr, size_t len) 1
int mlockall(int flags) 1
int munlockall() 1
int mincore(void* start, size_t length, unsigned char* vec) 1
int __ioctl:ioctl(int, int, void *) 1
int readv(int, const struct iovec *, int) 1
int writev(int, const struct iovec *, int) 1
int __fcntl:fcntl(int, int, void*) 1
int flock(int, int) 1
int fchmod(int, mode_t) 1
int dup(int) 1
int pipe(int *) 1,1,-1
int pipe2(int *, int) 1
int dup2(int, int) 1
int select:_newselect(int, struct fd_set *, struct fd_set *, struct fd_set *, struct timeval *) 1
int ftruncate(int, off_t) 1
int ftruncate64(int, off64_t) 1
int getdents:getdents64(unsigned int, struct dirent *, unsigned int) 1
int fsync(int) 1
int fdatasync(int) 1
int fchown:fchown32(int, uid_t, gid_t) 1,1,-1
int fchown:fchown(int, uid_t, gid_t) -1,-1,1
void sync(void) 1
int __fcntl64:fcntl64(int, int, void *) 1
int __fstatfs64:fstatfs64(int, size_t, struct statfs *) 1
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count) 1
int fstatat:fstatat64(int dirfd, const char *path, struct stat *buf, int flags) 1
int mkdirat(int dirfd, const char *pathname, mode_t mode) 1
int fchownat(int dirfd, const char *path, uid_t owner, gid_t group, int flags) 1
int fchmodat(int dirfd, const char *path, mode_t mode, int flags) 1
int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) 1
int fsetxattr(int, const char *, const void *, size_t, int) 1
ssize_t fgetxattr(int, const char *, void *, size_t) 1
ssize_t flistxattr(int, char *, size_t) 1
int fremovexattr(int, const char *) 1
# file system
int chdir(const char*) all
int mount(const char*, const char*, const char*, unsigned long, const void*) all
int umount2(const char*, int) all
int __getcwd:getcwd(char* buf, size_t size) all
int fchdir(int) all
int setxattr(const char*, const char*, const void*, size_t, int) all
int lsetxattr(const char*, const char*, const void*, size_t, int) all
ssize_t getxattr(const char*, const char*, void*, size_t) all
ssize_t lgetxattr(const char*, const char*, void*, size_t) all
ssize_t listxattr(const char*, char*, size_t) all
ssize_t llistxattr(const char*, char*, size_t) all
int removexattr(const char*, const char*) all
int lremovexattr(const char*, const char*) all
int swapon(const char*, int) all
int swapoff(const char*) all
int link (const char*, const char*) 1
int unlink (const char*) 1
int unlinkat (int, const char *, int) 1
int chdir (const char*) 1
int mknod (const char*, mode_t, dev_t) 1
int chmod (const char*,mode_t) 1
int chown:chown32(const char *, uid_t, gid_t) 1,1,-1
int chown:chown(const char *, uid_t, gid_t) -1,-1,1
int lchown:lchown32 (const char*, uid_t, gid_t) 1,1,-1
int lchown:lchown (const char*, uid_t, gid_t) -1,-1,1
int mount (const char*, const char*, const char*, unsigned long, const void*) 1
int umount(const char*) stub
int umount2 (const char*, int) 1
int fstat:fstat64(int, struct stat*) 1
int stat:stat64(const char *, struct stat *) 1
int lstat:lstat64(const char *, struct stat *) 1
int mkdir(const char *, mode_t) 1
int readlink(const char *, char *, size_t) 1
int rmdir(const char *) 1
int rename(const char *, const char *) 1
int __getcwd:getcwd(char * buf, size_t size) 1
int access(const char *, int) 1
int faccessat(int, const char *, int, int) 1
int symlink(const char *, const char *) 1
int fchdir(int) 1
int truncate(const char*, off_t) 1
int setxattr(const char *, const char *, const void *, size_t, int) 1
int lsetxattr(const char *, const char *, const void *, size_t, int) 1
ssize_t getxattr(const char *, const char *, void *, size_t) 1
ssize_t lgetxattr(const char *, const char *, void *, size_t) 1
ssize_t listxattr(const char *, char *, size_t) 1
ssize_t llistxattr(const char *, char *, size_t) 1
int removexattr(const char *, const char *) 1
int lremovexattr(const char *, const char *) 1
int __statfs64:statfs64(const char *, size_t, struct statfs *) 1
long unshare(unsigned long) 1
int swapon(const char *, int) 1
int swapoff(const char *) 1
# time
int settimeofday(const struct timeval*, const struct timezone*) all
clock_t times(struct tms*) all
int nanosleep(const struct timespec*, struct timespec*) all
int clock_settime(clockid_t, const struct timespec*) all
int clock_getres(clockid_t, struct timespec*) all
int ___clock_nanosleep:clock_nanosleep(clockid_t, int, const struct timespec*, struct timespec*) all
int getitimer(int, const 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_settime:timer_settime(__kernel_timer_t, int, const struct itimerspec*, struct itimerspec*) all
int __timer_gettime:timer_gettime(__kernel_timer_t, struct itimerspec*) all
int __timer_getoverrun:timer_getoverrun(__kernel_timer_t) all
int __timer_delete:timer_delete(__kernel_timer_t) all
int timerfd_create(clockid_t, int) all
int timerfd_settime(int, int, const struct itimerspec*, struct itimerspec*) all
int timerfd_gettime(int, struct itimerspec*) all
int pause () 1
int gettimeofday(struct timeval*, struct timezone*) 1
int settimeofday(const struct timeval*, const struct timezone*) 1
clock_t times(struct tms *) 1
int nanosleep(const struct timespec *, struct timespec *) 1
int clock_gettime(clockid_t clk_id, struct timespec *tp) 1
int clock_settime(clockid_t clk_id, const struct timespec *tp) 1
int clock_getres(clockid_t clk_id, struct timespec *res) 1
int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *req, struct timespec *rem) 1
int getitimer(int, const struct itimerval *) 1
int setitimer(int, const struct itimerval *, struct itimerval *) 1
int __timer_create:timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) 1
int __timer_settime:timer_settime(timer_t, int, const struct itimerspec*, struct itimerspec*) 1
int __timer_gettime:timer_gettime(timer_t, struct itimerspec*) 1
int __timer_getoverrun:timer_getoverrun(timer_t) 1
int __timer_delete:timer_delete(timer_t) 1
int utimes(const char*, const struct timeval tvp[2]) 1
int utimensat(int, const char *, const struct timespec times[2], int) 1
int timerfd_create(clockid_t, int) 1
int timerfd_settime(int, int, const struct itimerspec *, struct itimerspec *) 1
int timerfd_gettime(int, struct itimerspec *) 1
# signals
int __sigaction:sigaction(int, const struct sigaction*, struct sigaction*) arm,mips,x86
int __rt_sigaction:rt_sigaction(int, const struct sigaction*, struct sigaction*, size_t) all
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_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_sigqueueinfo:rt_sigqueueinfo(pid_t, int, siginfo_t*) all
int __signalfd4:signalfd4(int, const sigset_t*, size_t, int) all
int sigaction(int, const struct sigaction *, struct sigaction *) 1
int sigprocmask(int, const sigset_t *, sigset_t *) 1
int __sigsuspend:sigsuspend(int unused1, int unused2, unsigned mask) 1,1,-1
int __sigsuspend:sigsuspend(const sigset_t *mask) -1,-1,1
int __rt_sigaction:rt_sigaction (int sig, const struct sigaction *act, struct sigaction *oact, size_t sigsetsize) 1
int __rt_sigprocmask:rt_sigprocmask (int how, const sigset_t *set, sigset_t *oset, size_t sigsetsize) 1
int __rt_sigtimedwait:rt_sigtimedwait(const sigset_t *set, struct siginfo_t *info, struct timespec_t *timeout, size_t sigset_size) 1
int sigpending(sigset_t *) 1
int signalfd4(int fd, const sigset_t *mask, size_t sizemask, int flags) 1
# sockets
int __socket:socket(int, int, int) arm,arm64,mips,mips64,x86_64
int socketpair(int, int, int, int*) arm,arm64,mips,mips64,x86_64
int bind(int, struct sockaddr*, int) arm,arm64,mips,mips64,x86_64
int __connect:connect(int, struct sockaddr*, socklen_t) arm,arm64,mips,mips64,x86_64
int listen(int, int) arm,arm64,mips,mips64,x86_64
int __accept4:accept4(int, struct sockaddr*, socklen_t*, int) arm,arm64,mips,mips64,x86_64
int getsockname(int, struct sockaddr*, socklen_t*) arm,arm64,mips,mips64,x86_64
int getpeername(int, struct sockaddr*, socklen_t*) arm,arm64,mips,mips64,x86_64
int sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t) arm,arm64,mips,mips64,x86_64
int recvfrom(int, void*, size_t, unsigned int, struct sockaddr*, socklen_t*) arm,arm64,mips,mips64,x86_64
int shutdown(int, int) arm,arm64,mips,mips64,x86_64
int setsockopt(int, int, int, const void*, socklen_t) arm,arm64,mips,mips64,x86_64
int getsockopt(int, int, int, void*, socklen_t*) arm,arm64,mips,mips64,x86_64
int sendmsg(int, const struct msghdr*, unsigned int) arm,arm64,mips,mips64,x86_64
int recvmsg(int, struct msghdr*, unsigned int) arm,arm64,mips,mips64,x86_64
int recvmmsg(int, struct mmsghdr*, unsigned int, int, const struct timespec*) arm,arm64,mips,mips64,x86_64
int sendmmsg(int, struct mmsghdr*, unsigned int, int) arm,arm64,mips,mips64,x86_64
int socket(int, int, int) 1,-1,1
int socketpair(int, int, int, int*) 1,-1,1
int bind(int, struct sockaddr *, int) 1,-1,1
int connect(int, struct sockaddr *, socklen_t) 1,-1,1
int listen(int, int) 1,-1,1
int accept(int, struct sockaddr *, socklen_t *) 1,-1,1
int getsockname(int, struct sockaddr *, socklen_t *) 1,-1,1
int getpeername(int, struct sockaddr *, socklen_t *) 1,-1,1
int sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t) 1,-1,1
int recvfrom(int, void *, size_t, unsigned int, struct sockaddr *, socklen_t *) 1,-1,1
int shutdown(int, int) 1,-1,1
int setsockopt(int, int, int, const void *, socklen_t) 1,-1,1
int getsockopt(int, int, int, void *, socklen_t *) 1,-1,1
int sendmsg(int, const struct msghdr *, unsigned int) 1,-1,1
int recvmsg(int, struct msghdr *, unsigned int) 1,-1,1
# sockets for x86. These are done as an "indexed" call to socketcall syscall.
int __socket:socketcall:1(int, int, int) x86
int bind:socketcall:2(int, struct sockaddr*, int) x86
int __connect:socketcall:3(int, struct sockaddr*, socklen_t) x86
int listen:socketcall:4(int, int) x86
int getsockname:socketcall:6(int, struct sockaddr*, socklen_t*) x86
int getpeername:socketcall:7(int, struct sockaddr*, socklen_t*) x86
int socketpair:socketcall:8(int, int, int, int*) x86
int sendto:socketcall:11(int, const void*, size_t, int, const struct sockaddr*, socklen_t) x86
int recvfrom:socketcall:12(int, void*, size_t, unsigned int, struct sockaddr*, socklen_t*) x86
int shutdown:socketcall:13(int, int) x86
int setsockopt:socketcall:14(int, int, int, const void*, socklen_t) x86
int getsockopt:socketcall:15(int, int, int, void*, socklen_t*) x86
int sendmsg:socketcall:16(int, const struct msghdr*, unsigned int) x86
int recvmsg:socketcall:17(int, struct msghdr*, unsigned int) x86
int __accept4:socketcall:18(int, struct sockaddr*, socklen_t*, int) x86
int recvmmsg:socketcall:19(int, struct mmsghdr*, unsigned int, int, const struct timespec*) x86
int sendmmsg:socketcall:20(int, struct mmsghdr*, unsigned int, int) x86
int socket:socketcall:1 (int, int, int) -1,1,-1
int bind:socketcall:2 (int, struct sockaddr *, int) -1,1,-1
int connect:socketcall:3(int, struct sockaddr *, socklen_t) -1,1,-1
int listen:socketcall:4(int, int) -1,1,-1
int accept:socketcall:5(int, struct sockaddr *, socklen_t *) -1,1,-1
int getsockname:socketcall:6(int, struct sockaddr *, socklen_t *) -1,1,-1
int getpeername:socketcall:7(int, struct sockaddr *, socklen_t *) -1,1,-1
int socketpair:socketcall:8(int, int, int, int*) -1,1,-1
int sendto:socketcall:11(int, const void *, size_t, int, const struct sockaddr *, socklen_t) -1,1,-1
int recvfrom:socketcall:12(int, void *, size_t, unsigned int, struct sockaddr *, socklen_t *) -1,1,-1
int shutdown:socketcall:13(int, int) -1,1,-1
int setsockopt:socketcall:14(int, int, int, const void *, socklen_t) -1,1,-1
int getsockopt:socketcall:15(int, int, int, void *, socklen_t *) -1,1,-1
int sendmsg:socketcall:16(int, const struct msghdr *, unsigned int) -1,1,-1
int recvmsg:socketcall:17(int, struct msghdr *, unsigned int) -1,1,-1
# scheduler & real-time
int sched_setscheduler(pid_t pid, int policy, const struct sched_param* param) all
int sched_getscheduler(pid_t pid) all
int sched_yield(void) all
int sched_setparam(pid_t pid, const struct sched_param* param) all
int sched_getparam(pid_t pid, struct sched_param* param) all
int sched_get_priority_max(int policy) all
int sched_get_priority_min(int policy) all
int sched_rr_get_interval(pid_t pid, struct timespec* interval) all
int sched_setaffinity(pid_t pid, size_t setsize, const cpu_set_t* set) all
int setns(int, int) all
int unshare(int) all
int __sched_getaffinity:sched_getaffinity(pid_t pid, size_t setsize, cpu_set_t* set) all
int __getcpu:getcpu(unsigned*, unsigned*, void*) all
int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param) 1
int sched_getscheduler(pid_t pid) 1
int sched_yield(void) 1
int sched_setparam(pid_t pid, const struct sched_param *param) 1
int sched_getparam(pid_t pid, struct sched_param *param) 1
int sched_get_priority_max(int policy) 1
int sched_get_priority_min(int policy) 1
int sched_rr_get_interval(pid_t pid, struct timespec *interval) 1
int sched_setaffinity(pid_t pid, size_t setsize, const cpu_set_t* set) 1
int __sched_getaffinity:sched_getaffinity(pid_t pid, size_t setsize, cpu_set_t* set) 1
int __getcpu:getcpu(unsigned *cpu, unsigned *node, void *unused) 1
# io priorities
int ioprio_set(int which, int who, int ioprio) 1
int ioprio_get(int which, int who) 1
# other
int uname(struct utsname*) all
mode_t umask(mode_t) all
int __reboot:reboot(int, int, int, void*) all
int init_module(void*, unsigned long, const char*) all
int delete_module(const char*, unsigned int) all
int klogctl:syslog(int, char*, int) all
int sysinfo(struct sysinfo*) all
int personality(unsigned long) all
int uname(struct utsname *) 1
mode_t umask(mode_t) 1
int __reboot:reboot(int, int, int, void *) 1
int __syslog:syslog(int, char *, int) 1
int init_module(void *, unsigned long, const char *) 1
int delete_module(const char*, unsigned int) 1
int klogctl:syslog(int, char *, int) 1
int sysinfo(struct sysinfo *) 1
int personality(unsigned long) 1
long perf_event_open(struct perf_event_attr *attr_uptr, pid_t pid, int cpu, int group_fd, unsigned long flags) 1
ssize_t tee(int, int, size_t, unsigned int) all
ssize_t splice(int, off64_t*, int, off64_t*, size_t, unsigned int) all
ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int) all
# futex
int futex(void *, int, int, void *, void *, int) 1
int epoll_create1(int) all
int epoll_ctl(int, int op, int, struct epoll_event*) all
int __epoll_pwait:epoll_pwait(int, struct epoll_event*, int, int, const sigset_t*, size_t) all
# epoll
int epoll_create(int size) 1
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) 1
int epoll_wait(int epfd, struct epoll_event *events, int max, int timeout) 1
int eventfd:eventfd2(unsigned int, int) all
int inotify_init(void) 1
int inotify_add_watch(int, const char *, unsigned int) 1
int inotify_rm_watch(int, unsigned int) 1
void _exit|_Exit:exit_group(int) all
void __exit:exit(int) all
int poll(struct pollfd *, unsigned int, long) 1
int inotify_init1(int) all
int inotify_add_watch(int, const char*, unsigned int) all
int inotify_rm_watch(int, unsigned int) all
int eventfd:eventfd2(unsigned int, int) 1
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
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 setfsgid(gid_t) all
int setfsuid(uid_t) all
int sethostname(const char*, size_t) all
pid_t wait4(pid_t, int*, int, struct rusage*) all
int __waitid:waitid(int, pid_t, struct siginfo_t*, int, void*) all
# ARM-specific
int __set_tls:__ARM_NR_set_tls(void*) arm
int cacheflush:__ARM_NR_cacheflush(long start, long end, long flags) arm
# ARM-specific ARM_NR_BASE == 0x0f0000 == 983040
int __set_tls:__ARM_NR_set_tls(void*) 1,-1,-1
int cacheflush:__ARM_NR_cacheflush(long start, long end, long flags) 1,-1,-1
# MIPS-specific
int _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips
int __set_tls:set_thread_area(void*) mips,mips64
# x86-specific
int __set_thread_area:set_thread_area(void*) x86
# vdso stuff.
int clock_gettime(clockid_t, timespec*) arm,mips,mips64
int __clock_gettime:clock_gettime(clockid_t, timespec*) arm64,x86,x86_64
int gettimeofday(timeval*, timezone*) arm,mips,mips64
int __gettimeofday:gettimeofday(timeval*, timezone*) arm64,x86,x86_64
int _flush_cache:cacheflush(char *addr, const int nbytes, const int op) -1,-1,1
int syscall(int number,...) -1,-1,1

View File

@ -1,63 +1,44 @@
# 32-bit arm.
libc_bionic_src_files_arm += \
arch-arm/generic/bionic/memcmp.S \
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 += \
bionic/__memcpy_chk.cpp \
bionic/__memset_chk.cpp \
libc_openbsd_src_files_exclude_arm += \
upstream-openbsd/lib/libc/string/strcpy.c \
#
# Inherently architecture-specific code.
#
libc_bionic_src_files_arm += \
_LIBC_ARCH_COMMON_SRC_FILES := \
arch-arm/bionic/abort_arm.S \
arch-arm/bionic/atomics_arm.c \
arch-arm/bionic/__bionic_clone.S \
arch-arm/bionic/clone.S \
arch-arm/bionic/eabi.c \
arch-arm/bionic/_exit_with_stack_teardown.S \
arch-arm/bionic/ffs.S \
arch-arm/bionic/futex_arm.S \
arch-arm/bionic/__get_sp.S \
arch-arm/bionic/kill.S \
arch-arm/bionic/libgcc_compat.c \
arch-arm/bionic/popcount_tab.c \
arch-arm/bionic/__restore.S \
arch-arm/bionic/memcmp16.S \
arch-arm/bionic/memcmp.S \
arch-arm/bionic/_setjmp.S \
arch-arm/bionic/setjmp.S \
arch-arm/bionic/sigsetjmp.S \
arch-arm/bionic/syscall.S \
arch-arm/bionic/vfork.S \
arch-arm/bionic/tgkill.S \
arch-arm/bionic/tkill.S \
libc_arch_static_src_files_arm := arch-arm/bionic/exidx_static.c
libc_arch_dynamic_src_files_arm := arch-arm/bionic/exidx_dynamic.c
# These are used by the static and dynamic versions of the libc
# respectively.
_LIBC_ARCH_STATIC_SRC_FILES := \
arch-arm/bionic/exidx_static.c
## CPU variant specific source files
ifeq ($(strip $(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT)),)
$(warning TARGET_$(my_2nd_arch_prefix)ARCH is arm, but TARGET_$(my_2nd_arch_prefix)CPU_VARIANT is not defined)
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
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.")
endif
include $(cpu_variant_mk)
libc_common_additional_dependencies += $(cpu_variant_mk)
_LIBC_ARCH_DYNAMIC_SRC_FILES := \
arch-arm/bionic/exidx_dynamic.c
cpu_variant_mk :=
# Remove the C++ fortify function implementations for which there is an
# arm assembler version.
_LIBC_FORTIFY_FILES_TO_REMOVE := \
bionic/__memcpy_chk.cpp \
bionic/__memset_chk.cpp \
bionic/__strcpy_chk.cpp \
bionic/__strcat_chk.cpp \
libc_common_src_files := \
$(filter-out $(_LIBC_FORTIFY_FILES_TO_REMOVE),$(libc_common_src_files))
ifeq ($(strip $(wildcard bionic/libc/arch-arm/$(TARGET_CPU_VARIANT)/$(TARGET_CPU_VARIANT).mk)),)
$(error "TARGET_CPU_VARIANT not set or set to an unknown value. Possible values are cortex-a7, cortex-a8, cortex-a9, cortex-a15, krait. Use generic for devices that do not have a CPU similar to any of the supported cpu variants.")
endif
libc_crt_target_cflags_arm := \
-I$(LOCAL_PATH)/arch-arm/include \
-mthumb-interwork
libc_crt_target_so_cflags_arm :=
libc_crt_target_crtbegin_file_arm := \
$(LOCAL_PATH)/arch-common/bionic/crtbegin.c
libc_crt_target_crtbegin_so_file_arm := \
$(LOCAL_PATH)/arch-common/bionic/crtbegin_so.c
include bionic/libc/arch-arm/$(TARGET_CPU_VARIANT)/$(TARGET_CPU_VARIANT).mk

View File

@ -1,185 +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.
*/
#if defined(__clang__)
// clang interprets -fno-builtin more loosely than you might expect,
// and thinks it's okay to still substitute builtins as long as they're
// named __aeabi_* rather than __builtin_*, which causes infinite
// recursion if we have the fortified memcpy visible in this file.
#undef _FORTIFY_SOURCE
#endif
#include <stddef.h>
#include <string.h>
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,
* which are called from the .init_array, should manually call
* __aeabi_atexit() to register static destructors explicitly.
*
* Note that 'dso_handle' is the address of a magic linker-generate
* variable from the shared object that contains the constructor/destructor
*/
int __attribute__((weak))
__aeabi_atexit_impl(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);
}
void __attribute__((weak)) __aeabi_memcpy8_impl(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
}
void __attribute__((weak)) __aeabi_memcpy4_impl(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
}
void __attribute__((weak)) __aeabi_memcpy_impl(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);
}
void __attribute__((weak)) __aeabi_memmove8_impl(void *dest, const void *src, size_t n) {
memmove(dest, src, n);
}
void __attribute__((weak)) __aeabi_memmove4_impl(void *dest, const void *src, size_t n) {
memmove(dest, src, n);
}
void __attribute__((weak)) __aeabi_memmove_impl(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);
}
/*
* __aeabi_memset has the order of its second and third arguments reversed.
* This allows __aeabi_memclr to tail-call __aeabi_memset
*/
void __attribute__((weak)) __aeabi_memset8_impl(void *dest, size_t n, int c) {
memset(dest, c, n);
}
void __attribute__((weak)) __aeabi_memset4_impl(void *dest, size_t n, int c) {
memset(dest, c, n);
}
void __attribute__((weak)) __aeabi_memset_impl(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);
}
void __attribute__((weak)) __aeabi_memclr8_impl(void *dest, size_t n) {
__aeabi_memset8_impl(dest, n, 0);
}
void __attribute__((weak)) __aeabi_memclr4_impl(void *dest, size_t n) {
__aeabi_memset4_impl(dest, n, 0);
}
void __attribute__((weak)) __aeabi_memclr_impl(void *dest, size_t n) {
__aeabi_memset_impl(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,70 +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.
*/
#include <private/bionic_asm.h>
// pid_t __bionic_clone(int flags, void* child_stack, pid_t* parent_tid, void* tls, pid_t* child_tid, int (*fn)(void*), void* arg);
ENTRY(__bionic_clone)
mov ip, sp
# save registers to parent stack
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
# load extra parameters
ldmfd ip, {r4, r5, r6}
# Push 'fn' and 'arg' onto the child stack.
stmdb r1!, {r5, r6}
# Make the system call.
ldr r7, =__NR_clone
swi #0
# Are we the child?
movs r0, r0
beq 1f
# In the parent, reload saved registers then either return or set errno.
ldmfd sp!, {r4, r5, r6, r7}
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno_internal
1: # The child.
# Setting lr to 0 will make the unwinder stop at __start_thread
mov lr, #0
# Call __start_thread with the 'fn' and 'arg' we stored on the child stack.
pop {r0, r1}
b __start_thread
END(__bionic_clone)
.hidden __bionic_clone

View File

@ -0,0 +1,34 @@
/*
* 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/asm.h>
ENTRY(__get_sp)
mov r0, sp
bx lr
END(__get_sp)

View File

@ -1,63 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <private/bionic_asm.h>
// gdb is smart enough to unwind through signal frames with just the regular
// CFI information but libgcc and libunwind both need extra help. We do this
// by using .fnstart/.fnend and inserting a nop before both __restore and
// __restore_rt (but covered by the .fnstart/.fnend) so that although they're
// not inside the functions from objdump's point of view, an unwinder that
// blindly looks at the previous instruction (but is then smart enough to check
// the unwind 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).
#undef __bionic_asm_custom_entry
#define __bionic_asm_custom_entry(f)
.fnstart
.save {r0-r15}
.pad #32
nop
ENTRY_PRIVATE_NO_DWARF(__restore)
// This function must have exactly this instruction sequence.
mov r7, #__NR_sigreturn
swi #0
END_NO_DWARF(__restore)
.fnstart
.save {r0-r15}
.pad #160
nop
ENTRY_PRIVATE_NO_DWARF(__restore_rt)
// This function must have exactly this instruction sequence.
mov r7, #__NR_rt_sigreturn
swi #0
END_NO_DWARF(__restore_rt)

View File

@ -26,16 +26,19 @@
* SUCH DAMAGE.
*/
#include <private/bionic_asm.h>
#include <machine/asm.h>
#include <asm/unistd.h>
// void _exit_with_stack_teardown(void* stackBase, size_t stackSize)
ENTRY_PRIVATE(_exit_with_stack_teardown)
ldr r7, =__NR_munmap
swi #0
// If munmap failed, we ignore the failure and exit anyway.
// void _exit_with_stack_teardown(void* stackBase, int stackSize, int retCode)
ENTRY(_exit_with_stack_teardown)
mov lr, r2
ldr r7, =__NR_munmap
swi #0 // the stack is destroyed by this call
mov r0, lr
ldr r7, =__NR_exit
swi #0
mov r0, #0
ldr r7, =__NR_exit
swi #0
// The exit syscall does not return.
// exit() should never return, cause a crash if it does
mov r0, #0
ldr r0, [r0]
END(_exit_with_stack_teardown)

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 <machine/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(_C_LABEL(longjmperror), PLT)
bl PIC_SYM(_C_LABEL(abort), PLT)
b . - 8 /* Cannot get here */
END(_longjmp)

View File

@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
#include <private/bionic_asm.h>
#include <machine/asm.h>
/*
* Coding the abort function in assembly so that registers are guaranteed to
@ -36,9 +36,7 @@
* sequence when the crash happens.
*/
ENTRY(abort)
.save {r3, r14}
stmfd sp!, {r3, r14}
.cfi_def_cfa_offset 8
.cfi_rel_offset r3, 0
.cfi_rel_offset r14, 4
bl __libc_android_abort
bl PIC_SYM(_C_LABEL(__libc_android_abort), PLT)
END(abort)

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2012 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.
*/
extern void *__dso_handle;
__attribute__ ((visibility ("hidden")))
int atexit(void (*func)(void))
{
return (__cxa_atexit((void (*)(void *))func, (void *)0, &__dso_handle));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 The Android Open Source Project
* Copyright (c) 2012 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -27,10 +27,9 @@
*/
#include <sys/types.h>
#include <private/libc_logging.h>
#include <stdio.h>
#include "private/libc_logging.h"
/*
* This source file should only be included by libc.so, its purpose is
* to support legacy ARM binaries by exporting a publicly visible

View File

@ -0,0 +1,111 @@
/*
* 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.
*/
#include <linux/err.h>
#include <machine/asm.h>
#include <asm/unistd.h>
// int __pthread_clone(void* (*fn)(void*), void* child_stack, int flags, void* arg);
ENTRY(__pthread_clone)
# Push 'fn' and 'arg' onto 'child_stack'.
stmdb r1!, {r0, r3}
# The sys_clone system call only takes two arguments: 'flags' and 'child_stack'.
# 'child_stack' is already in r1, but we need to move 'flags' into position.
mov r0, r2
# System call.
mov ip, r7
ldr r7, =__NR_clone
swi #0
# Child?
movs r0, r0
beq 1f
# Parent.
mov r7, ip
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno
1: # Child.
# Pop 'fn' and 'arg' back off the stack and call __thread_entry.
pop {r0, r1}
# __thread_entry also needs our stack pointer.
mov r2, sp
b __thread_entry
END(__pthread_clone)
#
# This function is defined as:
#
# pid_t __bionic_clone( int flags, void *child_stack,
# pid_t *pid, void *tls, pid_t *ctid,
# int (*fn)(void *), void* arg );
#
# NOTE: This is not the same signature as the glibc
# __clone function. Placing 'fn' and 'arg'
# at the end of the parameter list makes the
# implementation much simpler.
#
ENTRY(__bionic_clone)
mov ip, sp
.save {r4, r5, r6, r7}
# save registers to parent stack
stmfd sp!, {r4, r5, r6, r7}
# load extra parameters
ldmfd ip, {r4, r5, r6}
# store 'fn' and 'arg' to the child stack
str r5, [r1, #-4]
str r6, [r1, #-8]
# System call
ldr r7, =__NR_clone
swi #0
movs r0, r0
beq 1f
# In the parent, reload saved registers then either return or set errno.
ldmfd sp!, {r4, r5, r6, r7}
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno
1: # The child.
ldr r0, [sp, #-4]
ldr r1, [sp, #-8]
b __bionic_clone_entry
END(__bionic_clone)

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2012 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 "../../bionic/libc_init_common.h"
#include <stddef.h>
#include <stdint.h>
__attribute__ ((section (".preinit_array")))
void (*__PREINIT_ARRAY__)(void) = (void (*)(void)) -1;
__attribute__ ((section (".init_array")))
void (*__INIT_ARRAY__)(void) = (void (*)(void)) -1;
__attribute__ ((section (".fini_array")))
void (*__FINI_ARRAY__)(void) = (void (*)(void)) -1;
__LIBC_HIDDEN__ void _start() {
structors_array_t array;
array.preinit_array = &__PREINIT_ARRAY__;
array.init_array = &__INIT_ARRAY__;
array.fini_array = &__FINI_ARRAY__;
void* raw_args = (void*) ((uintptr_t) __builtin_frame_address(0) + sizeof(void*));
__libc_init(raw_args, NULL, &main, &array);
}
#include "__dso_handle.h"
#include "atexit.h"

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2012 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.
*/
extern void __cxa_finalize(void *);
extern void *__dso_handle;
__attribute__((visibility("hidden"),destructor))
void __on_dlclose() {
__cxa_finalize(&__dso_handle);
}
/* CRT_LEGACY_WORKAROUND should only be defined when building
* this file as part of the platform's C library.
*
* The C library already defines a function named 'atexit()'
* for backwards compatibility with older NDK-generated binaries.
*
* For newer ones, 'atexit' is actually embedded in the C
* runtime objects that are linked into the final ELF
* binary (shared library or executable), and will call
* __cxa_atexit() in order to un-register any atexit()
* handler when a library is unloaded.
*
* This function must be global *and* hidden. Only the
* code inside the same ELF binary should be able to access it.
*/
#ifdef CRT_LEGACY_WORKAROUND
#include "__dso_handle.h"
#else
#include "__dso_handle_so.h"
#include "atexit.h"
#endif

View File

@ -0,0 +1,40 @@
/*
* 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.
*/
.section .preinit_array, "aw"
.long 0
.section .init_array, "aw"
.long 0
.section .fini_array, "aw"
.long 0
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif

View File

@ -0,0 +1,31 @@
/*
* 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.
*/
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif

103
libc/arch-arm/bionic/eabi.c Normal file
View File

@ -0,0 +1,103 @@
/*
* 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 <stddef.h>
#include <string.h>
extern int __cxa_atexit(void (*)(void*), void*, void* );
/* The "C++ ABI for ARM" document states that static C++ constructors,
* which are called from the .init_array, should manually call
* __aeabi_atexit() to register static destructors explicitely.
*
* Note that 'dso_handle' is the address of a magic linker-generate
* 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))
__aeabi_atexit (void *object, void (*destructor) (void *), void *dso_handle)
{
return __cxa_atexit(destructor, object, dso_handle);
}
void __aeabi_memcpy8(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
}
void __aeabi_memcpy4(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
}
void __aeabi_memcpy(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
}
void __aeabi_memmove8(void *dest, const void *src, size_t n) {
memmove(dest, src, n);
}
void __aeabi_memmove4(void *dest, const void *src, size_t n) {
memmove(dest, src, n);
}
void __aeabi_memmove(void *dest, const void *src, size_t n) {
memmove(dest, src, n);
}
/*
* __aeabi_memset has the order of its second and third arguments reversed.
* This allows __aeabi_memclr to tail-call __aeabi_memset
*/
void __aeabi_memset8(void *dest, size_t n, int c) {
memset(dest, c, n);
}
void __aeabi_memset4(void *dest, size_t n, int c) {
memset(dest, c, n);
}
void __aeabi_memset(void *dest, size_t n, int c) {
memset(dest, c, n);
}
void __aeabi_memclr8(void *dest, size_t n) {
__aeabi_memset8(dest, n, 0);
}
void __aeabi_memclr4(void *dest, size_t n) {
__aeabi_memset4(dest, n, 0);
}
void __aeabi_memclr(void *dest, size_t n) {
__aeabi_memset(dest, n, 0);
}

View File

@ -37,13 +37,7 @@
* the expectation that libc will define it and call through to
* 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);
}
_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

@ -0,0 +1,41 @@
/* $NetBSD: ffs.S,v 1.5 2003/04/05 23:08:52 bjh21 Exp $ */
/*
* Copyright (c) 2001 Christopher Gilbert
* 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 nor the name of the author 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 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/asm.h>
#include <machine/cpu-features.h>
ENTRY(ffs)
/* Standard trick to isolate bottom bit in r0 or 0 if r0 = 0 on entry */
rsb r1, r0, #0
ands r0, r0, r1
clzne r0, r0
rsbne r0, r0, #32
bx lr
END(ffs)

View File

@ -0,0 +1,70 @@
/*
* 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 <asm/unistd.h>
#include <machine/asm.h>
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
// __futex_syscall3(*ftx, op, val)
ENTRY(__futex_syscall3)
mov ip, r7
ldr r7, =__NR_futex
swi #0
mov r7, ip
bx lr
END(__futex_syscall3)
// __futex_syscall4(*ftx, op, val, *timespec)
ENTRY(__futex_syscall4)
b __futex_syscall3
END(__futex_syscall4)
// __futex_wait(*ftx, val, *timespec)
ENTRY(__futex_wait)
mov ip, r7
mov r3, r2
mov r2, r1
mov r1, #FUTEX_WAIT
ldr r7, =__NR_futex
swi #0
mov r7, ip
bx lr
END(__futex_wait)
// __futex_wake(*ftx, counter)
ENTRY(__futex_wake)
mov ip, r7
mov r2, r1
mov r1, #FUTEX_WAKE
ldr r7, =__NR_futex
swi #0
mov r7, ip
bx lr
END(__futex_wake)

View File

@ -0,0 +1,50 @@
/*
* 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 <linux/err.h>
#include <asm/unistd.h>
#include <machine/asm.h>
/* unlike our auto-generated syscall stubs, this code saves lr
on the stack, as well as a few other registers. this makes
our stack unwinder happy, when we generate debug stack
traces after the C library or other parts of the system
abort due to a fatal runtime error (e.g. detection
of a corrupted malloc heap).
*/
ENTRY(kill)
stmfd sp!, {r4-r7, ip, lr}
ldr r7, =__NR_kill
swi #0
ldmfd sp!, {r4-r7, ip, lr}
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno
END(kill)

View File

@ -1,159 +1,170 @@
/* Generated by genlibgcc_compat.py */
/*
* 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.
*/
extern char __adddf3;
extern char __addsf3;
extern char __aeabi_cdcmpeq;
extern char __aeabi_cdcmple;
extern char __aeabi_cdrcmple;
extern char __aeabi_d2f;
extern char __aeabi_d2iz;
extern char __aeabi_dadd;
extern char __aeabi_dcmpeq;
extern char __aeabi_dcmpge;
extern char __aeabi_dcmpgt;
extern char __aeabi_dcmple;
extern char __aeabi_dcmplt;
extern char __aeabi_dcmpun;
extern char __aeabi_ddiv;
extern char __aeabi_dmul;
extern char __aeabi_drsub;
extern char __aeabi_dsub;
extern char __aeabi_f2d;
extern char __aeabi_f2iz;
extern char __aeabi_f2uiz;
extern char __aeabi_fadd;
extern char __aeabi_fcmpun;
extern char __aeabi_fdiv;
extern char __aeabi_fmul;
extern char __aeabi_frsub;
extern char __aeabi_fsub;
extern char __aeabi_i2d;
extern char __aeabi_i2f;
extern char __aeabi_idiv;
extern char __aeabi_idivmod;
extern char __aeabi_l2d;
extern char __aeabi_l2f;
extern char __aeabi_lasr;
extern char __aeabi_ldivmod;
extern char __aeabi_llsl;
extern char __aeabi_llsr;
extern char __aeabi_lmul;
extern char __aeabi_ui2d;
extern char __aeabi_ui2f;
extern char __aeabi_uidiv;
extern char __aeabi_uidivmod;
extern char __aeabi_ul2d;
extern char __aeabi_ul2f;
extern char __aeabi_uldivmod;
extern char __aeabi_unwind_cpp_pr0;
extern char __aeabi_unwind_cpp_pr1;
extern char __cmpdf2;
extern char __divdf3;
extern char __divsf3;
extern char __eqdf2;
extern char __extendsfdf2;
extern char __fixdfsi;
extern char __fixsfsi;
extern char __floatdidf;
extern char __floatdisf;
extern char __floatsidf;
extern char __floatsisf;
extern char __floatundidf;
extern char __floatundisf;
extern char __floatunsidf;
extern char __floatunsisf;
extern char __gedf2;
extern char __gtdf2;
extern char __ledf2;
extern char __ltdf2;
extern char __muldf3;
extern char __muldi3;
extern char __mulsf3;
extern char __nedf2;
extern char __popcount_tab;
extern char __popcountsi2;
extern char __subdf3;
extern char __subsf3;
extern char __truncdfsf2;
extern char __unorddf2;
extern char __unordsf2;
/* This file contains dummy references to libgcc.a functions to force the
* dynamic linker to copy their definition into the final libc.so binary.
*
* They are required to ensure backwards binary compatibility with
* libc.so provided by the platform and binaries built with the NDK or
* different versions/configurations of toolchains.
*
* Now, for a more elaborate description of the issue:
*
* libgcc.a is a compiler-specific library containing various helper
* functions used to implement certain operations that are not necessarily
* supported by the target CPU. For example, integer division doesn't have a
* corresponding CPU instruction on ARMv5, and is instead implemented in the
* compiler-generated machine code as a call to an __idiv helper function.
*
* Normally, one has to place libgcc.a in the link command used to generate
* target binaries (shared libraries and executables) after all objects and
* static libraries, but before dependent shared libraries, i.e. something
* like:
* gcc <options> -o libfoo.so foo.a libgcc.a -lc -lm
*
* This ensures that any helper function needed by the code in foo.a is copied
* into the final libfoo.so. However, doing so will link a bunch of other __cxa
* functions from libgcc.a into each .so and executable, causing 4k+ increase
* in every binary. Therefore the Android platform build system has been
* using this instead:
*
* gcc <options> -o libfoo.so foo.a -lc -lm libgcc.a
*
* The problem with this is that if one helper function needed by foo.a has
* already been copied into libc.so or libm.so, then nothing will be copied
* into libfoo.so. Instead, a symbol import definition will be added to it
* so libfoo.so can directly call the one in libc.so at runtime.
*
* When refreshing toolchains for new versions or using different architecture
* flags, the set of helper functions copied to libc.so may change, which
* resulted in some native shared libraries generated with the NDK or prebuilts
* from vendors to fail to load properly.
*
* The NDK has been fixed after 1.6_r1 to use the correct link command, so
* any native shared library generated with it should now be safe from that
* problem. On the other hand, existing shared libraries distributed with
* applications that were generated with a previous version of the NDK
* still need all 1.5/1.6 helper functions in libc.so and libm.so
*
* After 3.2, the toolchain was updated again, adding __aeabi_f2uiz to the
* list of requirements. Technically, this is due to mis-linked NDK libraries
* but it is easier to add a single function here than asking several app
* developers to fix their build.
*
* The __aeabi_idiv function is added to the list since cortex-a15 supports
* HW idiv instructions so the system libc.so doesn't pull in the reference to
* __aeabi_idiv but legacy libraries built against cortex-a9 targets still need
* it.
*
* Final note: some of the functions below should really be in libm.so to
* completely reflect the state of 1.5/1.6 system images. However,
* since libm.so depends on libc.so, it's easier to put all of
* these in libc.so instead, since the dynamic linker will always
* search in libc.so before libm.so for dependencies.
*/
void* __bionic_libgcc_compat_symbols[] = {
&__adddf3,
&__addsf3,
&__aeabi_cdcmpeq,
&__aeabi_cdcmple,
&__aeabi_cdrcmple,
&__aeabi_d2f,
&__aeabi_d2iz,
&__aeabi_dadd,
&__aeabi_dcmpeq,
&__aeabi_dcmpge,
&__aeabi_dcmpgt,
&__aeabi_dcmple,
&__aeabi_dcmplt,
&__aeabi_dcmpun,
&__aeabi_ddiv,
&__aeabi_dmul,
&__aeabi_drsub,
&__aeabi_dsub,
&__aeabi_f2d,
&__aeabi_f2iz,
&__aeabi_f2uiz,
&__aeabi_fadd,
&__aeabi_fcmpun,
&__aeabi_fdiv,
&__aeabi_fmul,
&__aeabi_frsub,
&__aeabi_fsub,
&__aeabi_i2d,
&__aeabi_i2f,
&__aeabi_idiv,
&__aeabi_idivmod,
&__aeabi_l2d,
&__aeabi_l2f,
&__aeabi_lasr,
&__aeabi_ldivmod,
&__aeabi_llsl,
&__aeabi_llsr,
&__aeabi_lmul,
&__aeabi_ui2d,
&__aeabi_ui2f,
&__aeabi_uidiv,
&__aeabi_uidivmod,
&__aeabi_ul2d,
&__aeabi_ul2f,
&__aeabi_uldivmod,
&__aeabi_unwind_cpp_pr0,
&__aeabi_unwind_cpp_pr1,
&__cmpdf2,
&__divdf3,
&__divsf3,
&__eqdf2,
&__extendsfdf2,
&__fixdfsi,
&__fixsfsi,
&__floatdidf,
&__floatdisf,
&__floatsidf,
&__floatsisf,
&__floatundidf,
&__floatundisf,
&__floatunsidf,
&__floatunsisf,
&__gedf2,
&__gtdf2,
&__ledf2,
&__ltdf2,
&__muldf3,
&__muldi3,
&__mulsf3,
&__nedf2,
&__popcount_tab,
&__popcountsi2,
&__subdf3,
&__subsf3,
&__truncdfsf2,
&__unorddf2,
&__unordsf2,
};
#define COMPAT_FUNCTIONS_LIST \
XX(__adddf3) \
XX(__addsf3) \
XX(__aeabi_cdcmpeq) \
XX(__aeabi_cdcmple) \
XX(__aeabi_cdrcmple) \
XX(__aeabi_d2f) \
XX(__aeabi_d2iz) \
XX(__aeabi_dadd) \
XX(__aeabi_dcmpeq) \
XX(__aeabi_dcmpge) \
XX(__aeabi_dcmpgt) \
XX(__aeabi_dcmple) \
XX(__aeabi_dcmplt) \
XX(__aeabi_dcmpun) \
XX(__aeabi_ddiv) \
XX(__aeabi_dmul) \
XX(__aeabi_drsub) \
XX(__aeabi_dsub) \
XX(__aeabi_f2d) \
XX(__aeabi_f2iz) \
XX(__aeabi_f2uiz) \
XX(__aeabi_fadd) \
XX(__aeabi_fcmpun) \
XX(__aeabi_fdiv) \
XX(__aeabi_fmul) \
XX(__aeabi_frsub) \
XX(__aeabi_fsub) \
XX(__aeabi_i2d) \
XX(__aeabi_i2f) \
XX(__aeabi_idiv) \
XX(__aeabi_l2d) \
XX(__aeabi_l2f) \
XX(__aeabi_lasr) \
XX(__aeabi_lmul) \
XX(__aeabi_llsl) \
XX(__aeabi_llsr) \
XX(__aeabi_ui2d) \
XX(__aeabi_ui2f) \
XX(__aeabi_ul2d) \
XX(__aeabi_ul2f) \
XX(__cmpdf2) \
XX(__divdf3) \
XX(__divsf3) \
XX(__eqdf2) \
XX(__extendsfdf2) \
XX(__fixdfsi) \
XX(__fixsfsi) \
XX(__floatdidf) \
XX(__floatdisf) \
XX(__floatsidf) \
XX(__floatsisf) \
XX(__floatundidf) \
XX(__floatundisf) \
XX(__floatunsidf) \
XX(__floatunsisf) \
XX(__gedf2) \
XX(__gtdf2) \
XX(__ledf2) \
XX(__ltdf2) \
XX(__muldf3) \
XX(__muldi3) \
XX(__mulsf3) \
XX(__nedf2) \
XX(__subdf3) \
XX(__subsf3) \
XX(__truncdfsf2) \
XX(__unorddf2) \
XX(__unordsf2) \
#define XX(f) extern void f(void);
COMPAT_FUNCTIONS_LIST
#undef XX
void __bionic_libgcc_compat_hooks(void)
{
#define XX(f) f();
COMPAT_FUNCTIONS_LIST
#undef XX
}

View File

@ -0,0 +1,341 @@
/*
* 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 <machine/asm.h>
#ifdef HAVE_32_BYTE_CACHE_LINE
#define CACHE_LINE_SIZE 32
#else
#define CACHE_LINE_SIZE 64
#endif
/*
* Optimized memcmp() for Cortex-A9.
*/
ENTRY(memcmp)
pld [r0, #(CACHE_LINE_SIZE * 0)]
pld [r0, #(CACHE_LINE_SIZE * 1)]
/* take of the case where length is 0 or the buffers are the same */
cmp r0, r1
moveq r0, #0
bxeq lr
pld [r1, #(CACHE_LINE_SIZE * 0)]
pld [r1, #(CACHE_LINE_SIZE * 1)]
/* make sure we have at least 8+4 bytes, this simplify things below
* and avoid some overhead for small blocks
*/
cmp r2, #(8+4)
bmi 10f
/*
* Neon optimization
* Comparing 32 bytes at a time
*/
#if defined(__ARM_NEON__) && defined(NEON_UNALIGNED_ACCESS)
subs r2, r2, #32
blo 3f
/* preload all the cache lines we need. */
pld [r0, #(CACHE_LINE_SIZE * 2)]
pld [r1, #(CACHE_LINE_SIZE * 2)]
1: /* The main loop compares 32 bytes at a time */
vld1.8 {d0 - d3}, [r0]!
pld [r0, #(CACHE_LINE_SIZE * 2)]
vld1.8 {d4 - d7}, [r1]!
pld [r1, #(CACHE_LINE_SIZE * 2)]
/* Start subtracting the values and merge results */
vsub.i8 q0, q2
vsub.i8 q1, q3
vorr q2, q0, q1
vorr d4, d5
vmov r3, ip, d4
/* Check if there are any differences among the 32 bytes */
orrs r3, ip
bne 2f
subs r2, r2, #32
bhs 1b
b 3f
2:
/* Check if the difference was in the first or last 16 bytes */
sub r0, #32
vorr d0, d1
sub r1, #32
vmov r3, ip, d0
orrs r3, ip
/* if the first 16 bytes are equal, we only have to rewind 16 bytes */
ittt eq
subeq r2, #16
addeq r0, #16
addeq r1, #16
3: /* fix-up the remaining count */
add r2, r2, #32
cmp r2, #(8+4)
bmi 10f
#endif
.save {r4, lr}
/* save registers */
stmfd sp!, {r4, lr}
/* since r0 hold the result, move the first source
* pointer somewhere else
*/
mov r4, r0
/* align first pointer to word boundary
* offset = -src & 3
*/
rsb r3, r4, #0
ands r3, r3, #3
beq 0f
/* align first pointer */
sub r2, r2, r3
1: ldrb r0, [r4], #1
ldrb ip, [r1], #1
subs r0, r0, ip
bne 9f
subs r3, r3, #1
bne 1b
0: /* here the first pointer is aligned, and we have at least 4 bytes
* to process.
*/
/* see if the pointers are congruent */
eor r0, r4, r1
ands r0, r0, #3
bne 5f
/* congruent case, 32 bytes per iteration
* We need to make sure there are at least 32+4 bytes left
* because we effectively read ahead one word, and we could
* read past the buffer (and segfault) if we're not careful.
*/
ldr ip, [r1]
subs r2, r2, #(32 + 4)
bmi 1f
0: pld [r4, #(CACHE_LINE_SIZE * 2)]
pld [r1, #(CACHE_LINE_SIZE * 2)]
ldr r0, [r4], #4
ldr lr, [r1, #4]!
eors r0, r0, ip
ldreq r0, [r4], #4
ldreq ip, [r1, #4]!
eoreqs r0, r0, lr
ldreq r0, [r4], #4
ldreq lr, [r1, #4]!
eoreqs r0, r0, ip
ldreq r0, [r4], #4
ldreq ip, [r1, #4]!
eoreqs r0, r0, lr
ldreq r0, [r4], #4
ldreq lr, [r1, #4]!
eoreqs r0, r0, ip
ldreq r0, [r4], #4
ldreq ip, [r1, #4]!
eoreqs r0, r0, lr
ldreq r0, [r4], #4
ldreq lr, [r1, #4]!
eoreqs r0, r0, ip
ldreq r0, [r4], #4
ldreq ip, [r1, #4]!
eoreqs r0, r0, lr
bne 2f
subs r2, r2, #32
bhs 0b
/* do we have at least 4 bytes left? */
1: adds r2, r2, #(32 - 4 + 4)
bmi 4f
/* finish off 4 bytes at a time */
3: ldr r0, [r4], #4
ldr ip, [r1], #4
eors r0, r0, ip
bne 2f
subs r2, r2, #4
bhs 3b
/* are we done? */
4: adds r2, r2, #4
moveq r0, #0
beq 9f
/* finish off the remaining bytes */
b 8f
2: /* the last 4 bytes are different, restart them */
sub r4, r4, #4
sub r1, r1, #4
mov r2, #4
/* process the last few bytes */
8: ldrb r0, [r4], #1
ldrb ip, [r1], #1
// stall
subs r0, r0, ip
bne 9f
subs r2, r2, #1
bne 8b
9: /* restore registers and return */
ldmfd sp!, {r4, lr}
bx lr
10: /* process less than 12 bytes */
cmp r2, #0
moveq r0, #0
bxeq lr
mov r3, r0
11:
ldrb r0, [r3], #1
ldrb ip, [r1], #1
subs r0, ip
bxne lr
subs r2, r2, #1
bne 11b
bx lr
5: /*************** non-congruent case ***************/
and r0, r1, #3
cmp r0, #2
bne 4f
/* here, offset is 2 (16-bits aligned, special cased) */
/* make sure we have at least 16 bytes to process */
subs r2, r2, #16
addmi r2, r2, #16
bmi 8b
/* align the unaligned pointer */
bic r1, r1, #3
ldr lr, [r1], #4
6: pld [r1, #(CACHE_LINE_SIZE * 2)]
pld [r4, #(CACHE_LINE_SIZE * 2)]
mov ip, lr, lsr #16
ldr lr, [r1], #4
ldr r0, [r4], #4
orr ip, ip, lr, lsl #16
eors r0, r0, ip
moveq ip, lr, lsr #16
ldreq lr, [r1], #4
ldreq r0, [r4], #4
orreq ip, ip, lr, lsl #16
eoreqs r0, r0, ip
moveq ip, lr, lsr #16
ldreq lr, [r1], #4
ldreq r0, [r4], #4
orreq ip, ip, lr, lsl #16
eoreqs r0, r0, ip
moveq ip, lr, lsr #16
ldreq lr, [r1], #4
ldreq r0, [r4], #4
orreq ip, ip, lr, lsl #16
eoreqs r0, r0, ip
bne 7f
subs r2, r2, #16
bhs 6b
sub r1, r1, #2
/* are we done? */
adds r2, r2, #16
moveq r0, #0
beq 9b
/* finish off the remaining bytes */
b 8b
7: /* fix up the 2 pointers and fallthrough... */
sub r1, r1, #(4+2)
sub r4, r4, #4
mov r2, #4
b 8b
4: /*************** offset is 1 or 3 (less optimized) ***************/
stmfd sp!, {r5, r6, r7}
// r5 = rhs
// r6 = lhs
// r7 = scratch
mov r5, r0, lsl #3 /* r5 = right shift */
rsb r6, r5, #32 /* r6 = left shift */
/* align the unaligned pointer */
bic r1, r1, #3
ldr r7, [r1], #4
sub r2, r2, #8
6: mov ip, r7, lsr r5
ldr r7, [r1], #4
ldr r0, [r4], #4
orr ip, ip, r7, lsl r6
eors r0, r0, ip
moveq ip, r7, lsr r5
ldreq r7, [r1], #4
ldreq r0, [r4], #4
orreq ip, ip, r7, lsl r6
eoreqs r0, r0, ip
bne 7f
subs r2, r2, #8
bhs 6b
sub r1, r1, r6, lsr #3
ldmfd sp!, {r5, r6, r7}
/* are we done? */
adds r2, r2, #8
moveq r0, #0
beq 9b
/* finish off the remaining bytes */
b 8b
7: /* fix up the 2 pointers and fallthrough... */
sub r1, r1, #4
sub r1, r1, r6, lsr #3
sub r4, r4, #4
mov r2, #4
ldmfd sp!, {r5, r6, r7}
b 8b
END(memcmp)

View File

@ -0,0 +1,232 @@
/*
* 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 <machine/asm.h>
/*
* Optimized memcmp16() for ARM9.
* This would not be optimal on XScale or ARM11, where more prefetching
* and use of PLD will be needed.
* The 2 major optimzations here are
* (1) The main loop compares 16 bytes at a time
* (2) The loads are scheduled in a way they won't stall
*/
ENTRY(__memcmp16)
PLD (r0, #0)
PLD (r1, #0)
/* take of the case where length is nul or the buffers are the same */
cmp r0, r1
cmpne r2, #0
moveq r0, #0
bxeq lr
/* since r0 hold the result, move the first source
* pointer somewhere else
*/
mov r3, r0
/* make sure we have at least 12 words, this simplify things below
* and avoid some overhead for small blocks
*/
cmp r2, #12
bpl 0f
/* small blocks (less then 12 words) */
PLD (r0, #32)
PLD (r1, #32)
1: ldrh r0, [r3], #2
ldrh ip, [r1], #2
subs r0, r0, ip
bxne lr
subs r2, r2, #1
bne 1b
bx lr
.save {r4, lr}
/* save registers */
0: stmfd sp!, {r4, lr}
/* align first pointer to word boundary */
tst r3, #2
beq 0f
ldrh r0, [r3], #2
ldrh ip, [r1], #2
sub r2, r2, #1
subs r0, r0, ip
/* restore registers and return */
ldmnefd sp!, {r4, lr}
bxne lr
0: /* here the first pointer is aligned, and we have at least 3 words
* to process.
*/
/* see if the pointers are congruent */
eor r0, r3, r1
ands r0, r0, #2
bne 5f
/* congruent case, 16 half-words per iteration
* We need to make sure there are at least 16+2 words left
* because we effectively read ahead one long word, and we could
* read past the buffer (and segfault) if we're not careful.
*/
ldr ip, [r1]
subs r2, r2, #(16 + 2)
bmi 1f
0:
PLD (r3, #64)
PLD (r1, #64)
ldr r0, [r3], #4
ldr lr, [r1, #4]!
eors r0, r0, ip
ldreq r0, [r3], #4
ldreq ip, [r1, #4]!
eoreqs r0, r0, lr
ldreq r0, [r3], #4
ldreq lr, [r1, #4]!
eoreqs r0, r0, ip
ldreq r0, [r3], #4
ldreq ip, [r1, #4]!
eoreqs r0, r0, lr
ldreq r0, [r3], #4
ldreq lr, [r1, #4]!
eoreqs r0, r0, ip
ldreq r0, [r3], #4
ldreq ip, [r1, #4]!
eoreqs r0, r0, lr
ldreq r0, [r3], #4
ldreq lr, [r1, #4]!
eoreqs r0, r0, ip
ldreq r0, [r3], #4
ldreq ip, [r1, #4]!
eoreqs r0, r0, lr
bne 2f
subs r2, r2, #16
bhs 0b
/* do we have at least 2 words left? */
1: adds r2, r2, #(16 - 2 + 2)
bmi 4f
/* finish off 2 words at a time */
3: ldr r0, [r3], #4
ldr ip, [r1], #4
eors r0, r0, ip
bne 2f
subs r2, r2, #2
bhs 3b
/* are we done? */
4: adds r2, r2, #2
bne 8f
/* restore registers and return */
mov r0, #0
ldmfd sp!, {r4, lr}
bx lr
2: /* the last 2 words are different, restart them */
ldrh r0, [r3, #-4]
ldrh ip, [r1, #-4]
subs r0, r0, ip
ldreqh r0, [r3, #-2]
ldreqh ip, [r1, #-2]
subeqs r0, r0, ip
/* restore registers and return */
ldmfd sp!, {r4, lr}
bx lr
/* process the last few words */
8: ldrh r0, [r3], #2
ldrh ip, [r1], #2
subs r0, r0, ip
bne 9f
subs r2, r2, #1
bne 8b
9: /* restore registers and return */
ldmfd sp!, {r4, lr}
bx lr
5: /*************** non-congruent case ***************/
/* align the unaligned pointer */
bic r1, r1, #3
ldr lr, [r1], #4
sub r2, r2, #8
6:
PLD (r3, #64)
PLD (r1, #64)
mov ip, lr, lsr #16
ldr lr, [r1], #4
ldr r0, [r3], #4
orr ip, ip, lr, lsl #16
eors r0, r0, ip
moveq ip, lr, lsr #16
ldreq lr, [r1], #4
ldreq r0, [r3], #4
orreq ip, ip, lr, lsl #16
eoreqs r0, r0, ip
moveq ip, lr, lsr #16
ldreq lr, [r1], #4
ldreq r0, [r3], #4
orreq ip, ip, lr, lsl #16
eoreqs r0, r0, ip
moveq ip, lr, lsr #16
ldreq lr, [r1], #4
ldreq r0, [r3], #4
orreq ip, ip, lr, lsl #16
eoreqs r0, r0, ip
bne 7f
subs r2, r2, #8
bhs 6b
sub r1, r1, #2
/* are we done? */
adds r2, r2, #8
moveq r0, #0
beq 9b
/* finish off the remaining bytes */
b 8b
7: /* fix up the 2 pointers and fallthrough... */
sub r1, r1, #2
b 2b
END(__memcmp16)

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 <machine/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,406 @@
/*
* 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.
*/
/* Prototype: void *memcpy (void *dst, const void *src, size_t count). */
/* Use the version of memcpy implemented using LDRD and STRD.
This version is tuned for Cortex-A15.
This might not be the best for other ARMv7-A CPUs,
but there is no predefine to distinguish between
different CPUs in the same architecture,
and this version is better than the plain memcpy provided in newlib.
Therefore, we use this version for all ARMv7-A CPUS. */
/* To make the same code compile for both ARM and Thumb instruction
sets, switch to unified syntax at the beginning of this function.
However, by using the same code, we may be missing optimization
opportunities. For instance, in LDRD/STRD instructions, the first
destination register must be even and the second consecutive in
ARM state, but not in Thumb state. */
#include <machine/cpu-features.h>
#include <machine/asm.h>
.syntax unified
ENTRY(memcpy)
/* Assumes that n >= 0, and dst, src are valid pointers.
If there is at least 8 bytes to copy, use LDRD/STRD.
If src and dst are misaligned with different offsets,
first copy byte by byte until dst is aligned,
and then copy using LDRD/STRD and shift if needed.
When less than 8 left, copy a word and then byte by byte. */
/* Save registers (r0 holds the return value):
optimized push {r0, r4, r5, r6, r7, lr}.
To try and improve performance, stack layout changed,
i.e., not keeping the stack looking like users expect
(highest numbered register at highest address). */
.save {r0, lr}
push {r0, lr}
.save {r4, r5}
strd r4, r5, [sp, #-8]!
.save {r6, r7}
strd r6, r7, [sp, #-8]!
/* TODO: Add debug frame directives.
We don't need exception unwind directives, because the code below
does not throw any exceptions and does not call any other functions.
Generally, newlib functions like this lack debug information for
assembler source. */
/* Get copying of tiny blocks out of the way first. */
/* Is there at least 4 bytes to copy? */
subs r2, r2, #4
blt copy_less_than_4 /* If n < 4. */
/* Check word alignment. */
ands ip, r0, #3 /* ip = last 2 bits of dst. */
bne dst_not_word_aligned /* If dst is not word-aligned. */
/* Get here if dst is word-aligned. */
ands ip, r1, #3 /* ip = last 2 bits of src. */
bne src_not_word_aligned /* If src is not word-aligned. */
word_aligned:
/* Get here if source and dst both are word-aligned.
The number of bytes remaining to copy is r2+4. */
/* Is there is at least 64 bytes to copy? */
subs r2, r2, #60
blt copy_less_than_64 /* If r2 + 4 < 64. */
/* First, align the destination buffer to 8-bytes,
to make sure double loads and stores don't cross cache line boundary,
as they are then more expensive even if the data is in the cache
(require two load/store issue cycles instead of one).
If only one of the buffers is not 8-bytes aligned,
then it's more important to align dst than src,
because there is more penalty for stores
than loads that cross cacheline boundary.
This check and realignment are only worth doing
if there is a lot to copy. */
/* Get here if dst is word aligned,
i.e., the 2 least significant bits are 0.
If dst is not 2w aligned (i.e., the 3rd bit is not set in dst),
then copy 1 word (4 bytes). */
ands r3, r0, #4
beq 11f /* If dst already two-word aligned. */
ldr r3, [r1], #4
str r3, [r0], #4
subs r2, r2, #4
blt copy_less_than_64
11:
/* TODO: Align to cacheline (useful for PLD optimization). */
/* Every loop iteration copies 64 bytes. */
1:
.irp offset, #0, #8, #16, #24, #32, #40, #48, #56
ldrd r4, r5, [r1, \offset]
strd r4, r5, [r0, \offset]
.endr
add r0, r0, #64
add r1, r1, #64
subs r2, r2, #64
bge 1b /* If there is more to copy. */
copy_less_than_64:
/* Get here if less than 64 bytes to copy, -64 <= r2 < 0.
Restore the count if there is more than 7 bytes to copy. */
adds r2, r2, #56
blt copy_less_than_8
/* Copy 8 bytes at a time. */
2:
ldrd r4, r5, [r1], #8
strd r4, r5, [r0], #8
subs r2, r2, #8
bge 2b /* If there is more to copy. */
copy_less_than_8:
/* Get here if less than 8 bytes to copy, -8 <= r2 < 0.
Check if there is more to copy. */
cmn r2, #8
beq return /* If r2 + 8 == 0. */
/* Restore the count if there is more than 3 bytes to copy. */
adds r2, r2, #4
blt copy_less_than_4
/* Copy 4 bytes. */
ldr r3, [r1], #4
str r3, [r0], #4
copy_less_than_4:
/* Get here if less than 4 bytes to copy, -4 <= r2 < 0. */
/* Restore the count, check if there is more to copy. */
adds r2, r2, #4
beq return /* If r2 == 0. */
/* Get here with r2 is in {1,2,3}={01,10,11}. */
/* Logical shift left r2, insert 0s, update flags. */
lsls r2, r2, #31
/* Copy byte by byte.
Condition ne means the last bit of r2 is 0.
Condition cs means the second to last bit of r2 is set,
i.e., r2 is 1 or 3. */
itt ne
ldrbne r3, [r1], #1
strbne r3, [r0], #1
itttt cs
ldrbcs r4, [r1], #1
ldrbcs r5, [r1]
strbcs r4, [r0], #1
strbcs r5, [r0]
return:
/* Restore registers: optimized pop {r0, r4, r5, r6, r7, pc} */
/* This is the only return point of memcpy. */
ldrd r6, r7, [sp], #8
ldrd r4, r5, [sp], #8
pop {r0, pc}
#ifndef __ARM_FEATURE_UNALIGNED
/* The following assembly macro implements misaligned copy in software.
Assumes that dst is word aligned, src is at offset "pull" bits from
word, push = 32 - pull, and the number of bytes that remain to copy
is r2 + 4, r2 >= 0. */
/* In the code below, r2 is the number of bytes that remain to be
written. The number of bytes read is always larger, because we have
partial words in the shift queue. */
.macro miscopy pull push shiftleft shiftright
/* Align src to the previous word boundary. */
bic r1, r1, #3
/* Initialize the shift queue. */
ldr r5, [r1], #4 /* Load a word from source. */
subs r2, r2, #4
blt 6f /* Go to misaligned copy of less than 8 bytes. */
/* Get here if there is more than 8 bytes to copy.
The number of bytes to copy is r2+8, r2 >= 0. */
subs r2, r2, #56
blt 4f /* Go to misaligned copy of less than 64 bytes. */
3:
/* Get here if there is more than 64 bytes to copy.
The number of bytes to copy is r2+64, r2 >= 0. */
/* Copy 64 bytes in every iteration.
Use a partial word from the shift queue. */
.irp offset, #0, #8, #16, #24, #32, #40, #48, #56
mov r6, r5, \shiftleft #\pull
ldrd r4, r5, [r1, \offset]
orr r6, r6, r4, \shiftright #\push
mov r7, r4, \shiftleft #\pull
orr r7, r7, r5, \shiftright #\push
strd r6, r7, [r0, \offset]
.endr
add r1, r1, #64
add r0, r0, #64
subs r2, r2, #64
bge 3b
4:
/* Get here if there is less than 64 bytes to copy (-64 <= r2 < 0)
and they are misaligned. */
/* Restore the count if there is more than 7 bytes to copy. */
adds r2, r2, #56
blt 6f /* Go to misaligned copy of less than 8 bytes. */
5:
/* Copy 8 bytes at a time.
Use a partial word from the shift queue. */
mov r6, r5, \shiftleft #\pull
ldrd r4, r5, [r1], #8
orr r6, r6, r4, \shiftright #\push
mov r7, r4, \shiftleft #\pull
orr r7, r7, r5, \shiftright #\push
strd r6, r7, [r0], #8
subs r2, r2, #8
bge 5b /* If there is more to copy. */
6:
/* Get here if there less than 8 bytes to copy (-8 <= r2 < 0)
and they are misaligned. */
/* Check if there is more to copy. */
cmn r2, #8
beq return
/* Check if there is less than 4 bytes to copy. */
cmn r2, #4
itt lt
/* Restore src offset from word-align. */
sublt r1, r1, #(\push / 8)
blt copy_less_than_4
/* Use a partial word from the shift queue. */
mov r3, r5, \shiftleft #\pull
/* Load a word from src, but without writeback
(this word is not fully written to dst). */
ldr r5, [r1]
/* Restore src offset from word-align. */
add r1, r1, #(\pull / 8)
/* Shift bytes to create one dst word and store it. */
orr r3, r3, r5, \shiftright #\push
str r3, [r0], #4
/* Use single byte copying of the remaining bytes. */
b copy_less_than_4
.endm
#endif /* not __ARM_FEATURE_UNALIGNED */
dst_not_word_aligned:
/* Get here when dst is not aligned and ip has the last 2 bits of dst,
i.e., ip is the offset of dst from word.
The number of bytes that remains to copy is r2 + 4,
i.e., there are at least 4 bytes to copy.
Write a partial word (0 to 3 bytes), such that dst becomes
word-aligned. */
/* If dst is at ip bytes offset from a word (with 0 < ip < 4),
then there are (4 - ip) bytes to fill up to align dst to the next
word. */
rsb ip, ip, #4 /* ip = #4 - ip. */
cmp ip, #2
/* Copy byte by byte with conditionals. */
itt gt
ldrbgt r3, [r1], #1
strbgt r3, [r0], #1
itt ge
ldrbge r4, [r1], #1
strbge r4, [r0], #1
ldrb lr, [r1], #1
strb lr, [r0], #1
/* Update the count.
ip holds the number of bytes we have just copied. */
subs r2, r2, ip /* r2 = r2 - ip. */
blt copy_less_than_4 /* If r2 < ip. */
/* Get here if there are more than 4 bytes to copy.
Check if src is aligned. If beforehand src and dst were not word
aligned but congruent (same offset), then now they are both
word-aligned, and we can copy the rest efficiently (without
shifting). */
ands ip, r1, #3 /* ip = last 2 bits of src. */
beq word_aligned /* If r1 is word-aligned. */
src_not_word_aligned:
/* Get here when src is not word-aligned, but dst is word-aligned.
The number of bytes that remains to copy is r2+4. */
#ifdef __ARM_FEATURE_UNALIGNED
/* Copy word by word using LDR when alignment can be done in hardware,
i.e., SCTLR.A is set, supporting unaligned access in LDR and STR. */
subs r2, r2, #60
blt 8f
7:
/* Copy 64 bytes in every loop iteration. */
.irp offset, #0, #4, #8, #12, #16, #20, #24, #28, #32, #36, #40, #44, #48, #52, #56, #60
ldr r3, [r1, \offset]
str r3, [r0, \offset]
.endr
add r0, r0, #64
add r1, r1, #64
subs r2, r2, #64
bge 7b
8:
/* Get here if less than 64 bytes to copy, -64 <= r2 < 0.
Check if there is more than 3 bytes to copy. */
adds r2, r2, #60
blt copy_less_than_4
9:
/* Get here if there is less than 64 but at least 4 bytes to copy,
where the number of bytes to copy is r2+4. */
ldr r3, [r1], #4
str r3, [r0], #4
subs r2, r2, #4
bge 9b
b copy_less_than_4
#else /* not __ARM_FEATURE_UNALIGNED */
/* ip has last 2 bits of src,
i.e., ip is the offset of src from word, and ip > 0.
Compute shifts needed to copy from src to dst. */
cmp ip, #2
beq miscopy_16_16 /* If ip == 2. */
bge miscopy_24_8 /* If ip == 3. */
/* Get here if ip == 1. */
/* Endian independent macros for shifting bytes within registers. */
#ifndef __ARMEB__
miscopy_8_24: miscopy pull=8 push=24 shiftleft=lsr shiftright=lsl
miscopy_16_16: miscopy pull=16 push=16 shiftleft=lsr shiftright=lsl
miscopy_24_8: miscopy pull=24 push=8 shiftleft=lsr shiftright=lsl
#else /* not __ARMEB__ */
miscopy_8_24: miscopy pull=8 push=24 shiftleft=lsl shiftright=lsr
miscopy_16_16: miscopy pull=16 push=16 shiftleft=lsl shiftright=lsr
miscopy_24_8: miscopy pull=24 push=8 shiftleft=lsl shiftright=lsr
#endif /* not __ARMEB__ */
#endif /* not __ARM_FEATURE_UNALIGNED */
END(memcpy)

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 <machine/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

@ -0,0 +1,200 @@
/*
* 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 <machine/asm.h>
/*
* Optimized memset() for ARM.
*
* memset() returns its first argument.
*/
#if defined(__ARM_NEON__)
.fpu neon
#endif
ENTRY(bzero)
mov r2, r1
mov r1, #0
// Fall through to memset...
END(bzero)
ENTRY(memset)
#if defined(__ARM_NEON__)
#ifdef NEON_MEMSET_DIVIDER
cmp r2, #NEON_MEMSET_DIVIDER
bhi 11f
#endif
.save {r0}
stmfd sp!, {r0}
vdup.8 q0, r1
#ifndef NEON_UNALIGNED_ACCESS
/* do we have at least 16-bytes to write (needed for alignment below) */
cmp r2, #16
blo 3f
/* align destination to 16 bytes for the write-buffer */
rsb r3, r0, #0
ands r3, r3, #0xF
beq 2f
/* write up to 15-bytes (count in r3) */
sub r2, r2, r3
movs ip, r3, lsl #31
strmib r1, [r0], #1
strcsb r1, [r0], #1
strcsb r1, [r0], #1
movs ip, r3, lsl #29
bge 1f
// writes 4 bytes, 32-bits aligned
vst1.32 {d0[0]}, [r0, :32]!
1: bcc 2f
// writes 8 bytes, 64-bits aligned
vst1.8 {d0}, [r0, :64]!
2:
#endif
/* make sure we have at least 32 bytes to write */
subs r2, r2, #32
blo 2f
vmov q1, q0
1: /* The main loop writes 32 bytes at a time */
subs r2, r2, #32
#ifndef NEON_UNALIGNED_ACCESS
vst1.8 {d0 - d3}, [r0, :128]!
#else
vst1.8 {d0 - d3}, [r0]!
#endif
bhs 1b
2: /* less than 32 left */
add r2, r2, #32
tst r2, #0x10
beq 3f
// writes 16 bytes, 128-bits aligned
#ifndef NEON_UNALIGNED_ACCESS
vst1.8 {d0, d1}, [r0, :128]!
#else
vst1.8 {d0, d1}, [r0]!
#endif
3: /* write up to 15-bytes (count in r2) */
movs ip, r2, lsl #29
bcc 1f
vst1.8 {d0}, [r0]!
1: bge 2f
vst1.32 {d0[0]}, [r0]!
2: movs ip, r2, lsl #31
strmib r1, [r0], #1
strcsb r1, [r0], #1
strcsb r1, [r0], #1
ldmfd sp!, {r0}
bx lr
11:
#endif
/*
* Optimized memset() for ARM.
*
* memset() returns its first argument.
*/
/* compute the offset to align the destination
* offset = (4-(src&3))&3 = -src & 3
*/
.save {r0, r4-r7, lr}
stmfd sp!, {r0, r4-r7, lr}
rsb r3, r0, #0
ands r3, r3, #3
cmp r3, r2
movhi r3, r2
/* splat r1 */
mov r1, r1, lsl #24
orr r1, r1, r1, lsr #8
orr r1, r1, r1, lsr #16
movs r12, r3, lsl #31
strcsb r1, [r0], #1 /* can't use strh (alignment unknown) */
strcsb r1, [r0], #1
strmib r1, [r0], #1
subs r2, r2, r3
ldmlsfd sp!, {r0, r4-r7, lr} /* return */
bxls lr
/* align the destination to a cache-line */
mov r12, r1
mov lr, r1
mov r4, r1
mov r5, r1
mov r6, r1
mov r7, r1
rsb r3, r0, #0
ands r3, r3, #0x1C
beq 3f
cmp r3, r2
andhi r3, r2, #0x1C
sub r2, r2, r3
/* conditionally writes 0 to 7 words (length in r3) */
movs r3, r3, lsl #28
stmcsia r0!, {r1, lr}
stmcsia r0!, {r1, lr}
stmmiia r0!, {r1, lr}
movs r3, r3, lsl #2
strcs r1, [r0], #4
3:
subs r2, r2, #32
mov r3, r1
bmi 2f
1: subs r2, r2, #32
stmia r0!, {r1,r3,r4,r5,r6,r7,r12,lr}
bhs 1b
2: add r2, r2, #32
/* conditionally stores 0 to 31 bytes */
movs r2, r2, lsl #28
stmcsia r0!, {r1,r3,r12,lr}
stmmiia r0!, {r1, lr}
movs r2, r2, lsl #2
strcs r1, [r0], #4
strmih r1, [r0], #2
movs r2, r2, lsl #2
strcsb r1, [r0]
ldmfd sp!, {r0, r4-r7, lr}
bx lr
END(memset)

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) 2010 Android Open Source Project.
@ -31,204 +34,109 @@
* SUCH DAMAGE.
*/
#include <private/bionic_asm.h>
#include <machine/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:
//
// 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.
// 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)
/*
* 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 restored.
*/
ENTRY(setjmp)
mov r1, #1
b sigsetjmp
/* Block all signals and retrieve the old signal mask */
stmfd sp!, {r0, r14}
mov r0, #0x00000000
bl PIC_SYM(_C_LABEL(sigblock), PLT)
mov r1, r0
ldmfd sp!, {r0, r14}
/* Store signal mask */
str r1, [r0, #(_JB_SIGMASK * 4)]
ldr r1, .Lsetjmp_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)
ENTRY(_setjmp)
mov r1, #0
b sigsetjmp
END(_setjmp)
.Lsetjmp_magic:
.word _JB_MAGIC_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
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}
sub sp, sp, #4 /* align the stack */
mov r0, r2
bl PIC_SYM(_C_LABEL(sigsetmask), PLT)
add sp, sp, #4 /* unalign the stack */
ldmfd sp!, {r0, r1, r14}
#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
#ifdef __ARM_26__
mov r15, r14
#else
mov r15, r14
#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_rel_offset r0, 0
.cfi_rel_offset lr, 4
mov r0, r1
bl __bionic_setjmp_cookie_get
mov r1, r0
ldmfd sp, {r0}
// Save the setjmp cookie for later.
bic r2, r1, #1
stmfd sp!, {r2}
.cfi_adjust_cfa_offset 4
// Record the setjmp cookie and whether or not we're saving the signal mask.
str r1, [r0, #(_JB_SIGFLAG * 4)]
// Do we need to save the signal mask?
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)
m_mangle_registers r2
// ARM deprecates using sp in the register list for stmia.
stmia r1, {r4-r12, lr}
str sp, [r1, #(10 * 4)]
m_unmangle_registers r2
// Save floating-point registers.
add r1, r0, #(_JB_FLOAT_BASE * 4)
vstmia r1, {d8-d15}
// Save floating-point state.
fmrx r1, fpscr
str r1, [r0, #(_JB_FLOAT_STATE * 4)]
mov r0, #0
bx lr
END(sigsetjmp)
// void siglongjmp(sigjmp_buf env, int value);
ENTRY(siglongjmp)
stmfd sp!, {r0, r1, lr}
.cfi_def_cfa_offset 12
.cfi_rel_offset r0, 0
.cfi_rel_offset r1, 4
.cfi_rel_offset lr, 8
// Fetch the signal flag.
ldr r1, [r0, #(_JB_SIGFLAG * 4)]
// Do we need to restore the signal mask?
ands r1, r1, #1
beq 1f
// Restore the signal mask.
ldr r0, [r0, #(_JB_SIGMASK * 4)]
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)
vldmia r2, {d8-d15}
// Restore floating-point state.
ldr r2, [r0, #(_JB_FLOAT_STATE * 4)]
fmxr fpscr, r2
// Restore core registers.
ldr r3, [r0, #(_JB_SIGFLAG * 4)]
bic r3, r3, #1
add r2, r0, #(_JB_CORE_BASE * 4)
// ARM deprecates using sp in the register list for ldmia.
ldmia r2, {r4-r12, lr}
ldr sp, [r2, #(10 * 4)]
m_unmangle_registers r3
// Save the return value/address and check the setjmp cookie.
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.
ldmfd sp!, {r0, lr}
.cfi_adjust_cfa_offset -8
.cfi_restore lr
teq r0, #0
moveq r0, #1
bx lr
END(siglongjmp)
ALIAS_SYMBOL(longjmp, siglongjmp)
ALIAS_SYMBOL(_longjmp, siglongjmp)
/* validation failed, die die die. */
botch:
bl PIC_SYM(_C_LABEL(longjmperror), PLT)
bl PIC_SYM(_C_LABEL(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 <machine/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(_C_LABEL(_setjmp), PLT)
b PIC_SYM(_C_LABEL(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(_C_LABEL(_longjmp), PLT)
b PIC_SYM(_C_LABEL(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 <machine/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

@ -0,0 +1,787 @@
/*
* 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 "arm_asm.h"
#ifdef __ARMEB__
#define S2LOMEM lsl
#define S2LOMEMEQ lsleq
#define S2HIMEM lsr
#define MSB 0x000000ff
#define LSB 0xff000000
#define BYTE0_OFFSET 24
#define BYTE1_OFFSET 16
#define BYTE2_OFFSET 8
#define BYTE3_OFFSET 0
#else /* not __ARMEB__ */
#define S2LOMEM lsr
#define S2LOMEMEQ lsreq
#define S2HIMEM lsl
#define BYTE0_OFFSET 0
#define BYTE1_OFFSET 8
#define BYTE2_OFFSET 16
#define BYTE3_OFFSET 24
#define MSB 0xff000000
#define LSB 0x000000ff
#endif /* not __ARMEB__ */
.syntax unified
#if defined (__thumb__)
.thumb
.thumb_func
#endif
.global strcmp
.type strcmp, %function
strcmp:
#if (defined (__thumb__) && !defined (__thumb2__))
1:
ldrb r2, [r0]
ldrb r3, [r1]
adds r0, r0, #1
adds r1, r1, #1
cmp r2, #0
beq 2f
cmp r2, r3
beq 1b
2:
subs r0, r2, r3
bx lr
#elif (defined (__OPTIMIZE_SIZE__) || defined (PREFER_SIZE_OVER_SPEED))
1:
ldrb r2, [r0], #1
ldrb r3, [r1], #1
cmp r2, #1
it cs
cmpcs r2, r3
beq 1b
subs r0, r2, r3
RETURN
#elif (defined (_ISA_THUMB_2) || defined (_ISA_ARM_6))
/* Use LDRD whenever possible. */
/* The main thing to look out for when comparing large blocks is that
the loads do not cross a page boundary when loading past the index
of the byte with the first difference or the first string-terminator.
For example, if the strings are identical and the string-terminator
is at index k, byte by byte comparison will not load beyond address
s1+k and s2+k; word by word comparison may load up to 3 bytes beyond
k; double word - up to 7 bytes. If the load of these bytes crosses
a page boundary, it might cause a memory fault (if the page is not mapped)
that would not have happened in byte by byte comparison.
If an address is (double) word aligned, then a load of a (double) word
from that address will not cross a page boundary.
Therefore, the algorithm below considers word and double-word alignment
of strings separately. */
/* High-level description of the algorithm.
* The fast path: if both strings are double-word aligned,
use LDRD to load two words from each string in every loop iteration.
* If the strings have the same offset from a word boundary,
use LDRB to load and compare byte by byte until
the first string is aligned to a word boundary (at most 3 bytes).
This is optimized for quick return on short unaligned strings.
* If the strings have the same offset from a double-word boundary,
use LDRD to load two words from each string in every loop iteration, as in the fast path.
* If the strings do not have the same offset from a double-word boundary,
load a word from the second string before the loop to initialize the queue.
Use LDRD to load two words from every string in every loop iteration.
Inside the loop, load the second word from the second string only after comparing
the first word, using the queued value, to guarantee safety across page boundaries.
* If the strings do not have the same offset from a word boundary,
use LDR and a shift queue. Order of loads and comparisons matters,
similarly to the previous case.
* Use UADD8 and SEL to compare words, and use REV and CLZ to compute the return value.
* The only difference between ARM and Thumb modes is the use of CBZ instruction.
* The only difference between big and little endian is the use of REV in little endian
to compute the return value, instead of MOV.
* No preload. [TODO.]
*/
.macro m_cbz reg label
#ifdef __thumb2__
cbz \reg, \label
#else /* not defined __thumb2__ */
cmp \reg, #0
beq \label
#endif /* not defined __thumb2__ */
.endm /* m_cbz */
.macro m_cbnz reg label
#ifdef __thumb2__
cbnz \reg, \label
#else /* not defined __thumb2__ */
cmp \reg, #0
bne \label
#endif /* not defined __thumb2__ */
.endm /* m_cbnz */
.macro init
/* Macro to save temporary registers and prepare magic values. */
subs sp, sp, #16
strd r4, r5, [sp, #8]
strd r6, r7, [sp]
mvn r6, #0 /* all F */
mov r7, #0 /* all 0 */
.endm /* init */
.macro magic_compare_and_branch w1 w2 label
/* Macro to compare registers w1 and w2 and conditionally branch to label. */
cmp \w1, \w2 /* Are w1 and w2 the same? */
magic_find_zero_bytes \w1
it eq
cmpeq ip, #0 /* Is there a zero byte in w1? */
bne \label
.endm /* magic_compare_and_branch */
.macro magic_find_zero_bytes w1
/* Macro to find all-zero bytes in w1, result is in ip. */
#if (defined (__ARM_FEATURE_DSP))
uadd8 ip, \w1, r6
sel ip, r7, r6
#else /* not defined (__ARM_FEATURE_DSP) */
/* __ARM_FEATURE_DSP is not defined for some Cortex-M processors.
Coincidently, these processors only have Thumb-2 mode, where we can use the
the (large) magic constant available directly as an immediate in instructions.
Note that we cannot use the magic constant in ARM mode, where we need
to create the constant in a register. */
sub ip, \w1, #0x01010101
bic ip, ip, \w1
and ip, ip, #0x80808080
#endif /* not defined (__ARM_FEATURE_DSP) */
.endm /* magic_find_zero_bytes */
.macro setup_return w1 w2
#ifdef __ARMEB__
mov r1, \w1
mov r2, \w2
#else /* not __ARMEB__ */
rev r1, \w1
rev r2, \w2
#endif /* not __ARMEB__ */
.endm /* setup_return */
/*
optpld r0, #0
optpld r1, #0
*/
/* Are both strings double-word aligned? */
orr ip, r0, r1
tst ip, #7
bne do_align
/* Fast path. */
init
doubleword_aligned:
/* Get here when the strings to compare are double-word aligned. */
/* Compare two words in every iteration. */
.p2align 2
2:
/*
optpld r0, #16
optpld r1, #16
*/
/* Load the next double-word from each string. */
ldrd r2, r3, [r0], #8
ldrd r4, r5, [r1], #8
magic_compare_and_branch w1=r2, w2=r4, label=return_24
magic_compare_and_branch w1=r3, w2=r5, label=return_35
b 2b
do_align:
/* Is the first string word-aligned? */
ands ip, r0, #3
beq word_aligned_r0
/* Fast compare byte by byte until the first string is word-aligned. */
/* The offset of r0 from a word boundary is in ip. Thus, the number of bytes
to read until the next word boudnary is 4-ip. */
bic r0, r0, #3
ldr r2, [r0], #4
lsls ip, ip, #31
beq byte2
bcs byte3
byte1:
ldrb ip, [r1], #1
uxtb r3, r2, ror #BYTE1_OFFSET
subs ip, r3, ip
bne fast_return
m_cbz reg=r3, label=fast_return
byte2:
ldrb ip, [r1], #1
uxtb r3, r2, ror #BYTE2_OFFSET
subs ip, r3, ip
bne fast_return
m_cbz reg=r3, label=fast_return
byte3:
ldrb ip, [r1], #1
uxtb r3, r2, ror #BYTE3_OFFSET
subs ip, r3, ip
bne fast_return
m_cbnz reg=r3, label=word_aligned_r0
fast_return:
mov r0, ip
bx lr
word_aligned_r0:
init
/* The first string is word-aligned. */
/* Is the second string word-aligned? */
ands ip, r1, #3
bne strcmp_unaligned
word_aligned:
/* The strings are word-aligned. */
/* Is the first string double-word aligned? */
tst r0, #4
beq doubleword_aligned_r0
/* If r0 is not double-word aligned yet, align it by loading
and comparing the next word from each string. */
ldr r2, [r0], #4
ldr r4, [r1], #4
magic_compare_and_branch w1=r2 w2=r4 label=return_24
doubleword_aligned_r0:
/* Get here when r0 is double-word aligned. */
/* Is r1 doubleword_aligned? */
tst r1, #4
beq doubleword_aligned
/* Get here when the strings to compare are word-aligned,
r0 is double-word aligned, but r1 is not double-word aligned. */
/* Initialize the queue. */
ldr r5, [r1], #4
/* Compare two words in every iteration. */
.p2align 2
3:
/*
optpld r0, #16
optpld r1, #16
*/
/* Load the next double-word from each string and compare. */
ldrd r2, r3, [r0], #8
magic_compare_and_branch w1=r2 w2=r5 label=return_25
ldrd r4, r5, [r1], #8
magic_compare_and_branch w1=r3 w2=r4 label=return_34
b 3b
.macro miscmp_word offsetlo offsethi
/* Macro to compare misaligned strings. */
/* r0, r1 are word-aligned, and at least one of the strings
is not double-word aligned. */
/* Compare one word in every loop iteration. */
/* OFFSETLO is the original bit-offset of r1 from a word-boundary,
OFFSETHI is 32 - OFFSETLO (i.e., offset from the next word). */
/* Initialize the shift queue. */
ldr r5, [r1], #4
/* Compare one word from each string in every loop iteration. */
.p2align 2
7:
ldr r3, [r0], #4
S2LOMEM r5, r5, #\offsetlo
magic_find_zero_bytes w1=r3
cmp r7, ip, S2HIMEM #\offsetlo
and r2, r3, r6, S2LOMEM #\offsetlo
it eq
cmpeq r2, r5
bne return_25
ldr r5, [r1], #4
cmp ip, #0
eor r3, r2, r3
S2HIMEM r2, r5, #\offsethi
it eq
cmpeq r3, r2
bne return_32
b 7b
.endm /* miscmp_word */
strcmp_unaligned:
/* r0 is word-aligned, r1 is at offset ip from a word. */
/* Align r1 to the (previous) word-boundary. */
bic r1, r1, #3
/* Unaligned comparison word by word using LDRs. */
cmp ip, #2
beq miscmp_word_16 /* If ip == 2. */
bge miscmp_word_24 /* If ip == 3. */
miscmp_word offsetlo=8 offsethi=24 /* If ip == 1. */
miscmp_word_16: miscmp_word offsetlo=16 offsethi=16
miscmp_word_24: miscmp_word offsetlo=24 offsethi=8
return_32:
setup_return w1=r3, w2=r2
b do_return
return_34:
setup_return w1=r3, w2=r4
b do_return
return_25:
setup_return w1=r2, w2=r5
b do_return
return_35:
setup_return w1=r3, w2=r5
b do_return
return_24:
setup_return w1=r2, w2=r4
do_return:
#ifdef __ARMEB__
mov r0, ip
#else /* not __ARMEB__ */
rev r0, ip
#endif /* not __ARMEB__ */
/* Restore temporaries early, before computing the return value. */
ldrd r6, r7, [sp]
ldrd r4, r5, [sp, #8]
adds sp, sp, #16
/* There is a zero or a different byte between r1 and r2. */
/* r0 contains a mask of all-zero bytes in r1. */
/* Using r0 and not ip here because cbz requires low register. */
m_cbz reg=r0, label=compute_return_value
clz r0, r0
/* r0 contains the number of bits on the left of the first all-zero byte in r1. */
rsb r0, r0, #24
/* Here, r0 contains the number of bits on the right of the first all-zero byte in r1. */
lsr r1, r1, r0
lsr r2, r2, r0
compute_return_value:
movs r0, #1
cmp r1, r2
/* The return value is computed as follows.
If r1>r2 then (C==1 and Z==0) and LS doesn't hold and r0 is #1 at return.
If r1<r2 then (C==0 and Z==0) and we execute SBC with carry_in=0,
which means r0:=r0-r0-1 and r0 is #-1 at return.
If r1=r2 then (C==1 and Z==1) and we execute SBC with carry_in=1,
which means r0:=r0-r0 and r0 is #0 at return.
(C==0 and Z==1) cannot happen because the carry bit is "not borrow". */
it ls
sbcls r0, r0, r0
bx lr
#else /* !(defined (_ISA_THUMB_2) || defined (_ISA_ARM_6)
defined (__OPTIMIZE_SIZE__) || defined (PREFER_SIZE_OVER_SPEED) ||
(defined (__thumb__) && !defined (__thumb2__))) */
/* Use LDR whenever possible. */
#ifdef __thumb2__
#define magic1(REG) 0x01010101
#define magic2(REG) 0x80808080
#else
#define magic1(REG) REG
#define magic2(REG) REG, lsl #7
#endif
optpld r0
optpld r1
eor r2, r0, r1
tst r2, #3
/* Strings not at same byte offset from a word boundary. */
bne strcmp_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
S2LOMEM r2, r3, r2
ldr r3, [r1], #4
orr ip, ip, r2
orr r3, r3, r2
1:
#ifndef __thumb2__
/* Load the 'magic' constant 0x01010101. */
str r4, [sp, #-4]!
mov r4, #1
orr r4, r4, r4, lsl #8
orr r4, r4, r4, lsl #16
#endif
.p2align 2
4:
optpld r0, #8
optpld 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 */
S2HIMEM r0, ip, #24
S2LOMEM ip, ip, #8
cmp r0, #1
it cs
cmpcs r0, r3, S2HIMEM #24
it eq
S2LOMEMEQ 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
#ifdef __thumb2__
/* No RSB instruction in Thumb2 */
lsr r0, r0, #24
sub r0, r0, r3
#else
rsb r0, r3, r0, lsr #24
#endif
#endif
#ifndef __thumb2__
ldr r4, [sp], #4
#endif
RETURN
strcmp_unaligned:
#if 0
/* The assembly code below is based on the following alogrithm. */
#ifdef __ARMEB__
#define RSHIFT <<
#define LSHIFT >>
#else
#define RSHIFT >>
#define LSHIFT <<
#endif
#define body(shift) \
mask = 0xffffffffU RSHIFT shift; \
w1 = *wp1++; \
w2 = *wp2++; \
do \
{ \
t1 = w1 & mask; \
if (__builtin_expect(t1 != w2 RSHIFT shift, 0)) \
{ \
w2 RSHIFT= shift; \
break; \
} \
if (__builtin_expect(((w1 - b1) & ~w1) & (b1 << 7), 0)) \
{ \
/* See comment in assembler below re syndrome on big-endian */\
if ((((w1 - b1) & ~w1) & (b1 << 7)) & mask) \
w2 RSHIFT= shift; \
else \
{ \
w2 = *wp2; \
t1 = w1 RSHIFT (32 - shift); \
w2 = (w2 LSHIFT (32 - shift)) RSHIFT (32 - shift); \
} \
break; \
} \
w2 = *wp2++; \
t1 ^= w1; \
if (__builtin_expect(t1 != w2 LSHIFT (32 - shift), 0)) \
{ \
t1 = w1 >> (32 - shift); \
w2 = (w2 << (32 - shift)) RSHIFT (32 - shift); \
break; \
} \
w1 = *wp1++; \
} while (1)
const unsigned* wp1;
const unsigned* wp2;
unsigned w1, w2;
unsigned mask;
unsigned shift;
unsigned b1 = 0x01010101;
char c1, c2;
unsigned t1;
while (((unsigned) s1) & 3)
{
c1 = *s1++;
c2 = *s2++;
if (c1 == 0 || c1 != c2)
return c1 - (int)c2;
}
wp1 = (unsigned*) (((unsigned)s1) & ~3);
wp2 = (unsigned*) (((unsigned)s2) & ~3);
t1 = ((unsigned) s2) & 3;
if (t1 == 1)
{
body(8);
}
else if (t1 == 2)
{
body(16);
}
else
{
body (24);
}
do
{
#ifdef __ARMEB__
c1 = (char) t1 >> 24;
c2 = (char) w2 >> 24;
#else /* not __ARMEB__ */
c1 = (char) t1;
c2 = (char) w2;
#endif /* not __ARMEB__ */
t1 RSHIFT= 8;
w2 RSHIFT= 8;
} while (c1 != 0 && c1 == c2);
return c1 - c2;
#endif /* 0 */
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
RETURN
2:
str r5, [sp, #-4]!
str r4, [sp, #-4]!
//stmfd sp!, {r4, r5}
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, S2LOMEM #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, S2HIMEM #24
bne 6f
ldr w1, [wp1], #4
b 1b
4:
S2LOMEM 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]
S2LOMEM t1, w1, #24
#ifdef __ARMEB__
lsl w2, w2, #24
#endif
b 8f
6:
S2LOMEM t1, w1, #24
and w2, w2, LSB
b 8f
/* Critical inner Loop: Block with 2 bytes initial overlap */
.p2align 2
2:
S2HIMEM t1, w1, #16
sub r3, w1, b1
S2LOMEM t1, t1, #16
bic r3, r3, w1
cmp t1, w2, S2LOMEM #16
bne 4f
ands r3, r3, b1, lsl #7
it eq
ldreq w2, [wp2], #4
bne 5f
eor t1, t1, w1
cmp t1, w2, S2HIMEM #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]
S2LOMEM t1, w1, #16
#ifdef __ARMEB__
lsl w2, w2, #16
#endif
b 8f
6:
S2HIMEM w2, w2, #16
S2LOMEM t1, w1, #16
4:
S2LOMEM w2, w2, #16
b 8f
/* Critical inner Loop: Block with 1 byte initial overlap */
.p2align 2
3:
and t1, w1, LSB
cmp t1, w2, S2LOMEM #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, S2HIMEM #8
bne 6f
ldr w1, [wp1], #4
b 3b
4:
S2LOMEM 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:
S2LOMEM t1, w1, #8
bic w2, w2, MSB
b 8f
7:
mov r0, #0
//ldmfd sp!, {r4, r5}
ldr r4, [sp], #4
ldr r5, [sp], #4
RETURN
8:
and r2, t1, LSB
and r0, w2, LSB
cmp r0, #1
it cs
cmpcs r0, r2
itt eq
S2LOMEMEQ t1, t1, #8
S2LOMEMEQ w2, w2, #8
beq 8b
sub r0, r2, r0
//ldmfd sp!, {r4, r5}
ldr r4, [sp], #4
ldr r5, [sp], #4
RETURN
#endif /* !(defined (_ISA_THUMB_2) || defined (_ISA_ARM_6)
defined (__OPTIMIZE_SIZE__) || defined (PREFER_SIZE_OVER_SPEED) ||
(defined (__thumb__) && !defined (__thumb2__))) */

View File

@ -26,16 +26,12 @@
* SUCH DAMAGE.
*/
#include <private/bionic_asm.h>
#include <linux/err.h>
#include <machine/asm.h>
ENTRY(syscall)
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
mov r7, r0
mov r0, r1
mov r1, r2
@ -43,9 +39,8 @@ ENTRY(syscall)
ldmfd ip, {r3, r4, r5, r6}
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
b __set_errno
END(syscall)

View File

@ -0,0 +1,51 @@
/*
* 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 <linux/err.h>
#include <asm/unistd.h>
#include <machine/asm.h>
/* unlike our auto-generated syscall stubs, this code saves lr
on the stack, as well as a few other registers. this makes
our stack unwinder happy, when we generate debug stack
traces after the C library or other parts of the system
abort due to a fatal runtime error (e.g. detection
of a corrupted malloc heap).
*/
ENTRY(tgkill)
.save {r4-r7, ip, lr}
stmfd sp!, {r4-r7, ip, lr}
ldr r7, =__NR_tgkill
swi #0
ldmfd sp!, {r4-r7, ip, lr}
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno
END(tgkill)

View File

@ -0,0 +1,50 @@
/*
* 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 <linux/err.h>
#include <asm/unistd.h>
#include <machine/asm.h>
/* unlike our auto-generated syscall stubs, this code saves lr
on the stack, as well as a few other registers. this makes
our stack unwinder happy, when we generate debug stack
traces after the C library or other parts of the system
abort due to a fatal runtime error (e.g. detection
of a corrupted malloc heap).
*/
ENTRY(tkill)
stmfd sp!, {r4-r7, ip, lr}
ldr r7, =__NR_tkill
swi #0
ldmfd sp!, {r4-r7, ip, lr}
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno
END(tkill)

View File

@ -1,46 +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.
*/
#include <private/bionic_asm.h>
ENTRY(vfork)
// __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
mrc p15, 0, r3, c13, c0, 3
ldr r3, [r3, #4]
mov r0, #0
str r0, [r3, #12]
mov ip, r7
ldr r7, =__NR_vfork
swi #0
mov r7, ip
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno_internal
END(vfork)

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.
*
* Redistribution and use in source and binary forms, with or without
@ -26,7 +26,202 @@
* SUCH DAMAGE.
*/
// Indicate which memcpy base file to include.
#define MEMCPY_BASE "memcpy_base.S"
#include <machine/asm.h>
#include "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)
.cfi_startproc
pld [r0, #0]
push {r0, lr}
.save {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
push {r4, r5}
.save {r4, r5}
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
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}
.cfi_endproc
END(__strcat_chk)
#define MEMCPY_BASE __strcat_chk_memcpy_base
#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
#include "memcpy_base.S"
ENTRY(__strcat_chk_failed)
.cfi_startproc
.save {r0, lr}
.save {r4, r5}
.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)
.cfi_endproc
END(__strcat_chk_failed)
.data
error_string:
.string "strcat buffer overflow"

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.
*
* Redistribution and use in source and binary forms, with or without
@ -26,7 +26,163 @@
* SUCH DAMAGE.
*/
// Indicate which memcpy base file to include.
#define MEMCPY_BASE "memcpy_base.S"
#include <machine/asm.h>
#include "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)
.cfi_startproc
pld [r0, #0]
push {r0, lr}
.save {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
.cfi_endproc
END(__strcpy_chk)
#define MEMCPY_BASE __strcpy_chk_memcpy_base
#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
#include "memcpy_base.S"
ENTRY(__strcpy_chk_failed)
.cfi_startproc
.save {r0, lr}
.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)
.cfi_endproc
END(__strcpy_chk_failed)
.data
error_string:
.string "strcpy buffer overflow"

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.
*
* Redistribution and use in source and binary forms, with or without
@ -25,8 +25,88 @@
* 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.
*/
// Indicate which memcpy base file to include.
#define MEMCPY_BASE "memcpy_base.S"
// Prototype: void *memcpy (void *dst, const void *src, size_t count).
#include "memcpy_common.S"
#include <machine/asm.h>
#include "libc_events.h"
.text
.syntax unified
.fpu neon
ENTRY(__memcpy_chk)
.cfi_startproc
cmp r2, r3
bhi __memcpy_chk_fail
// Fall through to memcpy...
.cfi_endproc
END(__memcpy_chk)
ENTRY(memcpy)
.cfi_startproc
pld [r1, #64]
push {r0, lr}
.save {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
.cfi_endproc
END(memcpy)
#define MEMCPY_BASE __memcpy_base
#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
#include "memcpy_base.S"
ENTRY(__memcpy_chk_fail)
.cfi_startproc
// Preserve lr for backtrace.
push {lr}
.save {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)
.cfi_endproc
END(__memcpy_chk_fail)
.data
error_string:
.string "memcpy buffer overflow"

View File

@ -53,7 +53,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
.L_memcpy_base:
ENTRY(MEMCPY_BASE)
.cfi_startproc
.save {r0, lr}
.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.
// For any sizes less than 832 use the neon code that doesn't
// care about the src alignment. This avoids any checks
@ -165,18 +171,31 @@
ands r3, r3, #0x3
bne .L_copy_unknown_alignment
.cfi_endproc
END(MEMCPY_BASE)
ENTRY(MEMCPY_BASE_ALIGNED)
.cfi_startproc
.save {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
// To try and improve performance, stack layout changed,
// i.e., not keeping the stack looking like users expect
// (highest numbered register at highest address).
strd r4, r5, [sp, #-8]!
.save {r4, r5}
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
strd r6, r7, [sp, #-8]!
.save {r6, r7}
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r6, 0
.cfi_rel_offset r7, 4
.cfi_rel_offset r7, 0
strd r8, r9, [sp, #-8]!
.save {r8, r9}
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r8, 0
.cfi_rel_offset r9, 4
@ -281,28 +300,10 @@
// Restore registers: optimized pop {r0, pc}
ldrd r8, r9, [sp], #8
.cfi_adjust_cfa_offset -8
.cfi_restore r8
.cfi_restore r9
ldrd r6, r7, [sp], #8
.cfi_adjust_cfa_offset -8
.cfi_restore r6
.cfi_restore r7
ldrd r4, r5, [sp], #8
.cfi_adjust_cfa_offset -8
.cfi_restore r4
.cfi_restore r5
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:
// Align dst to word.
rsb ip, ip, #4
@ -324,11 +325,5 @@
// Src is guaranteed to be at least word aligned by this point.
b .L_word_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
.cfi_endproc
END(MEMCPY_BASE_ALIGNED)

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

@ -27,8 +27,8 @@
*/
#include <machine/cpu-features.h>
#include <private/bionic_asm.h>
#include <private/libc_events.h>
#include <machine/asm.h>
#include "libc_events.h"
/*
* Optimized memset() for ARM.
@ -40,10 +40,12 @@
.syntax unified
ENTRY(__memset_chk)
.cfi_startproc
cmp r2, r3
bls .L_done
// Preserve lr for backtrace.
.save {lr}
push {lr}
.cfi_def_cfa_offset 4
.cfi_rel_offset lr, 0
@ -57,16 +59,22 @@ error_code:
.word BIONIC_EVENT_MEMSET_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+8)
.cfi_endproc
END(__memset_chk)
ENTRY(bzero)
.cfi_startproc
mov r2, r1
mov r1, #0
.L_done:
// Fall through to memset...
.cfi_endproc
END(bzero)
ENTRY(memset)
.cfi_startproc
.save {r0}
stmfd sp!, {r0}
.cfi_def_cfa_offset 4
.cfi_rel_offset r0, 0
@ -184,8 +192,9 @@ ENTRY(memset)
strbcs r1, [r0], #1
ldmfd sp!, {r0}
bx lr
.cfi_endproc
END(memset)
.data
error_string:
.string "memset: prevented write past end of buffer"
.string "memset buffer overflow"

View File

@ -1,30 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#define STPCPY
#include "string_copy.S"

View File

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

View File

@ -27,7 +27,7 @@
*/
#include <machine/cpu-features.h>
#include <private/bionic_asm.h>
#include <machine/asm.h>
#ifdef __ARMEB__
#define S2LOMEM lsl
@ -145,8 +145,19 @@ ENTRY(strcmp)
.macro magic_find_zero_bytes w1
/* Macro to find all-zero bytes in w1, result is in ip. */
#if (defined (__ARM_FEATURE_DSP))
uadd8 ip, \w1, r6
sel ip, r7, r6
#else /* not defined (__ARM_FEATURE_DSP) */
/* __ARM_FEATURE_DSP is not defined for some Cortex-M processors.
Coincidently, these processors only have Thumb-2 mode, where we can use the
the (large) magic constant available directly as an immediate in instructions.
Note that we cannot use the magic constant in ARM mode, where we need
to create the constant in a register. */
sub ip, \w1, #0x01010101
bic ip, ip, \w1
and ip, ip, #0x80808080
#endif /* not defined (__ARM_FEATURE_DSP) */
.endm /* magic_find_zero_bytes */
.macro setup_return w1 w2
@ -159,6 +170,7 @@ ENTRY(strcmp)
#endif /* not __ARMEB__ */
.endm /* setup_return */
.cfi_startproc
pld [r0, #0]
pld [r1, #0]
@ -168,6 +180,7 @@ ENTRY(strcmp)
bne .L_do_align
/* Fast path. */
.save {r4-r7}
init
.L_doubleword_aligned:
@ -373,4 +386,5 @@ ENTRY(strcmp)
it ls
sbcls r0, r0, r0
bx lr
.cfi_endproc
END(strcmp)

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 The Android Open Source Project
* Copyright (C) 2013 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -25,6 +25,427 @@
* 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.
*/
#define STRCPY
#include "string_copy.S"
#include <machine/asm.h>
.syntax unified
.thumb
.thumb_func
.macro m_push
push {r0, r4, r5, lr}
.endm // m_push
.macro m_pop
pop {r0, r4, r5, pc}
.endm // m_pop
.macro m_copy_byte reg, cmd, label
ldrb \reg, [r1], #1
strb \reg, [r0], #1
\cmd \reg, \label
.endm // m_copy_byte
ENTRY(strcpy)
// For short copies, hard-code checking the first 8 bytes since this
// new code doesn't win until after about 8 bytes.
m_push
m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r5, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r5, cmd=cbnz, label=strcpy_continue
strcpy_finish:
m_pop
strcpy_continue:
pld [r1, #0]
ands r3, r0, #7
beq strcpy_check_src_align
// Align to a double word (64 bits).
rsb r3, r3, #8
lsls ip, r3, #31
beq strcpy_align_to_32
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, strcpy_complete
strcpy_align_to_32:
bcc strcpy_align_to_64
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, strcpy_complete
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, strcpy_complete
strcpy_align_to_64:
tst r3, #4
beq strcpy_check_src_align
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
str r2, [r0], #4
strcpy_check_src_align:
// At this point dst is aligned to a double word, check if src
// is also aligned to a double word.
ands r3, r1, #7
bne strcpy_unaligned_copy
.p2align 2
strcpy_mainloop:
ldrd r2, r3, [r1], #8
pld [r1, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8
b strcpy_mainloop
strcpy_complete:
m_pop
strcpy_zero_in_first_register:
lsls lr, ip, #17
bne strcpy_copy1byte
bcs strcpy_copy2bytes
lsls ip, ip, #1
bne strcpy_copy3bytes
strcpy_copy4bytes:
// Copy 4 bytes to the destiniation.
str r2, [r0]
m_pop
strcpy_copy1byte:
strb r2, [r0]
m_pop
strcpy_copy2bytes:
strh r2, [r0]
m_pop
strcpy_copy3bytes:
strh r2, [r0], #2
lsr r2, #16
strb r2, [r0]
m_pop
strcpy_zero_in_second_register:
lsls lr, ip, #17
bne strcpy_copy5bytes
bcs strcpy_copy6bytes
lsls ip, ip, #1
bne strcpy_copy7bytes
// Copy 8 bytes to the destination.
strd r2, r3, [r0]
m_pop
strcpy_copy5bytes:
str r2, [r0], #4
strb r3, [r0]
m_pop
strcpy_copy6bytes:
str r2, [r0], #4
strh r3, [r0]
m_pop
strcpy_copy7bytes:
str r2, [r0], #4
strh r3, [r0], #2
lsr r3, #16
strb r3, [r0]
m_pop
strcpy_unaligned_copy:
// Dst is aligned to a double word, while src is at an unknown alignment.
// There are 7 different versions of the unaligned copy code
// to prevent overreading the src. The mainloop of every single version
// will store 64 bits per loop. The difference is how much of src can
// be read without potentially crossing a page boundary.
tbb [pc, r3]
strcpy_unaligned_branchtable:
.byte 0
.byte ((strcpy_unalign7 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign6 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign5 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign4 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign3 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign2 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign1 - strcpy_unaligned_branchtable)/2)
.p2align 2
// Can read 7 bytes before possibly crossing a page.
strcpy_unalign7:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
ldrb r3, [r1]
cbz r3, strcpy_unalign7_copy5bytes
ldrb r4, [r1, #1]
cbz r4, strcpy_unalign7_copy6bytes
ldrb r5, [r1, #2]
cbz r5, strcpy_unalign7_copy7bytes
ldr r3, [r1], #4
pld [r1, #64]
lsrs ip, r3, #24
strd r2, r3, [r0], #8
beq strcpy_unalign_return
b strcpy_unalign7
strcpy_unalign7_copy5bytes:
str r2, [r0], #4
strb r3, [r0]
strcpy_unalign_return:
m_pop
strcpy_unalign7_copy6bytes:
str r2, [r0], #4
strb r3, [r0], #1
strb r4, [r0], #1
m_pop
strcpy_unalign7_copy7bytes:
str r2, [r0], #4
strb r3, [r0], #1
strb r4, [r0], #1
strb r5, [r0], #1
m_pop
.p2align 2
// Can read 6 bytes before possibly crossing a page.
strcpy_unalign6:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
ldrb r4, [r1]
cbz r4, strcpy_unalign_copy5bytes
ldrb r5, [r1, #1]
cbz r5, strcpy_unalign_copy6bytes
ldr r3, [r1], #4
pld [r1, #64]
tst r3, #0xff0000
beq strcpy_copy7bytes
lsrs ip, r3, #24
strd r2, r3, [r0], #8
beq strcpy_unalign_return
b strcpy_unalign6
.p2align 2
// Can read 5 bytes before possibly crossing a page.
strcpy_unalign5:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
ldrb r4, [r1]
cbz r4, strcpy_unalign_copy5bytes
ldr r3, [r1], #4
pld [r1, #64]
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8
b strcpy_unalign5
strcpy_unalign_copy5bytes:
str r2, [r0], #4
strb r4, [r0]
m_pop
strcpy_unalign_copy6bytes:
str r2, [r0], #4
strb r4, [r0], #1
strb r5, [r0]
m_pop
.p2align 2
// Can read 4 bytes before possibly crossing a page.
strcpy_unalign4:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
ldr r3, [r1], #4
pld [r1, #64]
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8
b strcpy_unalign4
.p2align 2
// Can read 3 bytes before possibly crossing a page.
strcpy_unalign3:
ldrb r2, [r1]
cbz r2, strcpy_unalign3_copy1byte
ldrb r3, [r1, #1]
cbz r3, strcpy_unalign3_copy2bytes
ldrb r4, [r1, #2]
cbz r4, strcpy_unalign3_copy3bytes
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
lsrs lr, r2, #24
beq strcpy_copy4bytes
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8
b strcpy_unalign3
strcpy_unalign3_copy1byte:
strb r2, [r0]
m_pop
strcpy_unalign3_copy2bytes:
strb r2, [r0], #1
strb r3, [r0]
m_pop
strcpy_unalign3_copy3bytes:
strb r2, [r0], #1
strb r3, [r0], #1
strb r4, [r0]
m_pop
.p2align 2
// Can read 2 bytes before possibly crossing a page.
strcpy_unalign2:
ldrb r2, [r1]
cbz r2, strcpy_unalign_copy1byte
ldrb r4, [r1, #1]
cbz r4, strcpy_unalign_copy2bytes
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
tst r2, #0xff0000
beq strcpy_copy3bytes
lsrs ip, r2, #24
beq strcpy_copy4bytes
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8
b strcpy_unalign2
.p2align 2
// Can read 1 byte before possibly crossing a page.
strcpy_unalign1:
ldrb r2, [r1]
cbz r2, strcpy_unalign_copy1byte
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
strd r2, r3, [r0], #8
b strcpy_unalign1
strcpy_unalign_copy1byte:
strb r2, [r0]
m_pop
strcpy_unalign_copy2bytes:
strb r2, [r0], #1
strb r4, [r0]
m_pop
END(strcpy)

View File

@ -1,520 +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.
*/
/*
* Copyright (c) 2013 ARM Ltd
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the company may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(STPCPY) && !defined(STRCPY)
#error "Either STPCPY or STRCPY must be defined."
#endif
#include <private/bionic_asm.h>
.syntax unified
.thumb
.thumb_func
#if defined(STPCPY)
.macro m_push
push {r4, r5, lr}
.cfi_def_cfa_offset 12
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
.cfi_rel_offset lr, 8
.endm // m_push
#else
.macro m_push
push {r0, r4, r5, lr}
.cfi_def_cfa_offset 16
.cfi_rel_offset r0, 0
.cfi_rel_offset r4, 4
.cfi_rel_offset r5, 8
.cfi_rel_offset lr, 12
.endm // m_push
#endif
#if defined(STPCPY)
.macro m_pop
pop {r4, r5, pc}
.endm // m_pop
#else
.macro m_pop
pop {r0, r4, r5, pc}
.endm // m_pop
#endif
.macro m_copy_byte reg, cmd, label
ldrb \reg, [r1], #1
strb \reg, [r0], #1
\cmd \reg, \label
.endm // m_copy_byte
#if defined(STPCPY)
ENTRY(stpcpy)
#else
ENTRY(strcpy)
#endif
// For short copies, hard-code checking the first 8 bytes since this
// new code doesn't win until after about 8 bytes.
m_push
m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r5, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r5, cmd=cbnz, label=.Lstringcopy_continue
.Lstringcopy_finish:
#if defined(STPCPY)
sub r0, r0, #1
#endif
m_pop
.Lstringcopy_continue:
pld [r1, #0]
ands r3, r0, #7
beq .Lstringcopy_check_src_align
// Align to a double word (64 bits).
rsb r3, r3, #8
lsls ip, r3, #31
beq .Lstringcopy_align_to_32
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .Lstringcopy_complete
.Lstringcopy_align_to_32:
bcc .Lstringcopy_align_to_64
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .Lstringcopy_complete
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .Lstringcopy_complete
.Lstringcopy_align_to_64:
tst r3, #4
beq .Lstringcopy_check_src_align
// Read one byte at a time since we don't have any idea about the alignment
// of the source and we don't want to read into a different page.
ldrb r2, [r1], #1
strb r2, [r0], #1
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
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .Lstringcopy_complete
.Lstringcopy_check_src_align:
// At this point dst is aligned to a double word, check if src
// is also aligned to a double word.
ands r3, r1, #7
bne .Lstringcopy_unaligned_copy
.p2align 2
.Lstringcopy_mainloop:
ldrd r2, r3, [r1], #8
pld [r1, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
strd r2, r3, [r0], #8
b .Lstringcopy_mainloop
.Lstringcopy_complete:
#if defined(STPCPY)
sub r0, r0, #1
#endif
m_pop
.Lstringcopy_zero_in_first_register:
lsls lr, ip, #17
bne .Lstringcopy_copy1byte
bcs .Lstringcopy_copy2bytes
lsls ip, ip, #1
bne .Lstringcopy_copy3bytes
.Lstringcopy_copy4bytes:
// Copy 4 bytes to the destiniation.
#if defined(STPCPY)
str r2, [r0], #3
#else
str r2, [r0]
#endif
m_pop
.Lstringcopy_copy1byte:
strb r2, [r0]
m_pop
.Lstringcopy_copy2bytes:
#if defined(STPCPY)
strh r2, [r0], #1
#else
strh r2, [r0]
#endif
m_pop
.Lstringcopy_copy3bytes:
strh r2, [r0], #2
lsr r2, #16
strb r2, [r0]
m_pop
.Lstringcopy_zero_in_second_register:
lsls lr, ip, #17
bne .Lstringcopy_copy5bytes
bcs .Lstringcopy_copy6bytes
lsls ip, ip, #1
bne .Lstringcopy_copy7bytes
// Copy 8 bytes to the destination.
strd r2, r3, [r0]
#if defined(STPCPY)
add r0, r0, #7
#endif
m_pop
.Lstringcopy_copy5bytes:
str r2, [r0], #4
strb r3, [r0]
m_pop
.Lstringcopy_copy6bytes:
str r2, [r0], #4
#if defined(STPCPY)
strh r3, [r0], #1
#else
strh r3, [r0]
#endif
m_pop
.Lstringcopy_copy7bytes:
str r2, [r0], #4
strh r3, [r0], #2
lsr r3, #16
strb r3, [r0]
m_pop
.Lstringcopy_unaligned_copy:
// Dst is aligned to a double word, while src is at an unknown alignment.
// There are 7 different versions of the unaligned copy code
// to prevent overreading the src. The mainloop of every single version
// will store 64 bits per loop. The difference is how much of src can
// be read without potentially crossing a page boundary.
tbb [pc, r3]
.Lstringcopy_unaligned_branchtable:
.byte 0
.byte ((.Lstringcopy_unalign7 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign6 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign5 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign4 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign3 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign2 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign1 - .Lstringcopy_unaligned_branchtable)/2)
.p2align 2
// Can read 7 bytes before possibly crossing a page.
.Lstringcopy_unalign7:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
ldrb r3, [r1]
cbz r3, .Lstringcopy_unalign7_copy5bytes
ldrb r4, [r1, #1]
cbz r4, .Lstringcopy_unalign7_copy6bytes
ldrb r5, [r1, #2]
cbz r5, .Lstringcopy_unalign7_copy7bytes
ldr r3, [r1], #4
pld [r1, #64]
lsrs ip, r3, #24
strd r2, r3, [r0], #8
#if defined(STPCPY)
beq .Lstringcopy_finish
#else
beq .Lstringcopy_unalign_return
#endif
b .Lstringcopy_unalign7
.Lstringcopy_unalign7_copy5bytes:
str r2, [r0], #4
strb r3, [r0]
.Lstringcopy_unalign_return:
m_pop
.Lstringcopy_unalign7_copy6bytes:
str r2, [r0], #4
strb r3, [r0], #1
strb r4, [r0]
m_pop
.Lstringcopy_unalign7_copy7bytes:
str r2, [r0], #4
strb r3, [r0], #1
strb r4, [r0], #1
strb r5, [r0]
m_pop
.p2align 2
// Can read 6 bytes before possibly crossing a page.
.Lstringcopy_unalign6:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
ldrb r4, [r1]
cbz r4, .Lstringcopy_unalign_copy5bytes
ldrb r5, [r1, #1]
cbz r5, .Lstringcopy_unalign_copy6bytes
ldr r3, [r1], #4
pld [r1, #64]
tst r3, #0xff0000
beq .Lstringcopy_copy7bytes
lsrs ip, r3, #24
strd r2, r3, [r0], #8
#if defined(STPCPY)
beq .Lstringcopy_finish
#else
beq .Lstringcopy_unalign_return
#endif
b .Lstringcopy_unalign6
.p2align 2
// Can read 5 bytes before possibly crossing a page.
.Lstringcopy_unalign5:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
ldrb r4, [r1]
cbz r4, .Lstringcopy_unalign_copy5bytes
ldr r3, [r1], #4
pld [r1, #64]
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
strd r2, r3, [r0], #8
b .Lstringcopy_unalign5
.Lstringcopy_unalign_copy5bytes:
str r2, [r0], #4
strb r4, [r0]
m_pop
.Lstringcopy_unalign_copy6bytes:
str r2, [r0], #4
strb r4, [r0], #1
strb r5, [r0]
m_pop
.p2align 2
// Can read 4 bytes before possibly crossing a page.
.Lstringcopy_unalign4:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
ldr r3, [r1], #4
pld [r1, #64]
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
strd r2, r3, [r0], #8
b .Lstringcopy_unalign4
.p2align 2
// Can read 3 bytes before possibly crossing a page.
.Lstringcopy_unalign3:
ldrb r2, [r1]
cbz r2, .Lstringcopy_unalign3_copy1byte
ldrb r3, [r1, #1]
cbz r3, .Lstringcopy_unalign3_copy2bytes
ldrb r4, [r1, #2]
cbz r4, .Lstringcopy_unalign3_copy3bytes
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
lsrs lr, r2, #24
beq .Lstringcopy_copy4bytes
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
strd r2, r3, [r0], #8
b .Lstringcopy_unalign3
.Lstringcopy_unalign3_copy1byte:
strb r2, [r0]
m_pop
.Lstringcopy_unalign3_copy2bytes:
strb r2, [r0], #1
strb r3, [r0]
m_pop
.Lstringcopy_unalign3_copy3bytes:
strb r2, [r0], #1
strb r3, [r0], #1
strb r4, [r0]
m_pop
.p2align 2
// Can read 2 bytes before possibly crossing a page.
.Lstringcopy_unalign2:
ldrb r2, [r1]
cbz r2, .Lstringcopy_unalign_copy1byte
ldrb r4, [r1, #1]
cbz r4, .Lstringcopy_unalign_copy2bytes
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
tst r2, #0xff0000
beq .Lstringcopy_copy3bytes
lsrs ip, r2, #24
beq .Lstringcopy_copy4bytes
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
strd r2, r3, [r0], #8
b .Lstringcopy_unalign2
.p2align 2
// Can read 1 byte before possibly crossing a page.
.Lstringcopy_unalign1:
ldrb r2, [r1]
cbz r2, .Lstringcopy_unalign_copy1byte
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
strd r2, r3, [r0], #8
b .Lstringcopy_unalign1
.Lstringcopy_unalign_copy1byte:
strb r2, [r0]
m_pop
.Lstringcopy_unalign_copy2bytes:
strb r2, [r0], #1
strb r4, [r0]
m_pop
#if defined(STPCPY)
END(stpcpy)
#else
END(strcpy)
#endif

View File

@ -53,7 +53,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <private/bionic_asm.h>
#include <machine/asm.h>
.syntax unified
@ -65,38 +65,38 @@ ENTRY(strlen)
mov r1, r0
ands r3, r0, #7
beq .L_mainloop
beq mainloop
// Align to a double word (64 bits).
rsb r3, r3, #8
lsls ip, r3, #31
beq .L_align_to_32
beq align_to_32
ldrb r2, [r1], #1
cbz r2, .L_update_count_and_return
cbz r2, update_count_and_return
.L_align_to_32:
bcc .L_align_to_64
align_to_32:
bcc align_to_64
ands ip, r3, #2
beq .L_align_to_64
beq align_to_64
ldrb r2, [r1], #1
cbz r2, .L_update_count_and_return
cbz r2, update_count_and_return
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
beq .L_mainloop
beq mainloop
ldr r3, [r1], #4
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .L_zero_in_second_register
bne zero_in_second_register
.p2align 2
.L_mainloop:
mainloop:
ldrd r2, r3, [r1], #8
pld [r1, #64]
@ -104,62 +104,62 @@ ENTRY(strlen)
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .L_zero_in_first_register
bne 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
bne zero_in_second_register
b mainloop
.L_update_count_and_return:
update_count_and_return:
sub r0, r1, r0
sub r0, r0, #1
bx lr
.L_zero_in_first_register:
zero_in_first_register:
sub r0, r1, r0
lsls r3, ip, #17
bne .L_sub8_and_return
bcs .L_sub7_and_return
bne sub8_and_return
bcs sub7_and_return
lsls ip, ip, #1
bne .L_sub6_and_return
bne sub6_and_return
sub r0, r0, #5
bx lr
.L_sub8_and_return:
sub8_and_return:
sub r0, r0, #8
bx lr
.L_sub7_and_return:
sub7_and_return:
sub r0, r0, #7
bx lr
.L_sub6_and_return:
sub6_and_return:
sub r0, r0, #6
bx lr
.L_zero_in_second_register:
zero_in_second_register:
sub r0, r1, r0
lsls r3, ip, #17
bne .L_sub4_and_return
bcs .L_sub3_and_return
bne sub4_and_return
bcs sub3_and_return
lsls ip, ip, #1
bne .L_sub2_and_return
bne sub2_and_return
sub r0, r0, #1
bx lr
.L_sub4_and_return:
sub4_and_return:
sub r0, r0, #4
bx lr
.L_sub3_and_return:
sub3_and_return:
sub r0, r0, #3
bx lr
.L_sub2_and_return:
sub2_and_return:
sub r0, r0, #2
bx lr
END(strlen)

View File

@ -1,27 +1,10 @@
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 \
$(call libc-add-cpu-variant-src,MEMCPY,arch-arm/cortex-a15/bionic/memcpy.S)
$(call libc-add-cpu-variant-src,MEMSET,arch-arm/cortex-a15/bionic/memset.S)
$(call libc-add-cpu-variant-src,STRCAT,arch-arm/cortex-a15/bionic/strcat.S)
$(call libc-add-cpu-variant-src,STRCMP,arch-arm/cortex-a15/bionic/strcmp.S)
$(call libc-add-cpu-variant-src,STRCPY,arch-arm/cortex-a15/bionic/strcpy.S)
$(call libc-add-cpu-variant-src,STRLEN,arch-arm/cortex-a15/bionic/strlen.S)
$(call libc-add-cpu-variant-src,__STRCAT_CHK,arch-arm/cortex-a15/bionic/__strcat_chk.S)
$(call libc-add-cpu-variant-src,__STRCPY_CHK,arch-arm/cortex-a15/bionic/__strcpy_chk.S)
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 \
include bionic/libc/arch-arm/generic/generic.mk

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,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/memcpy_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 += \
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 \
include bionic/libc/arch-arm/cortex-a15/cortex-a15.mk

View File

@ -26,8 +26,8 @@
* SUCH DAMAGE.
*/
#include <private/bionic_asm.h>
#include <private/libc_events.h>
#include <machine/asm.h>
#include "libc_events.h"
.syntax unified
.fpu neon
@ -38,12 +38,15 @@
// Check that the two lengths together don't exceed the threshold, then
// do a memcpy of the data.
ENTRY(__strcat_chk)
.cfi_startproc
pld [r0, #0]
push {r0, lr}
.save {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
push {r4, r5}
.save {r4, r5}
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
@ -190,13 +193,18 @@ ENTRY(__strcat_chk)
pop {r4, r5}
// Fall through into the memcpy_base function.
.cfi_endproc
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_fail)
ENTRY(__strcat_chk_fail)
.cfi_startproc
.save {r0, lr}
.save {r4, r5}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
@ -213,8 +221,10 @@ error_code:
.word BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+4)
.cfi_endproc
END(__strcat_chk_fail)
.data
error_string:
.string "strcat: prevented write past end of buffer"
.string "strcat buffer overflow"

View File

@ -26,8 +26,8 @@
* SUCH DAMAGE.
*/
#include <private/bionic_asm.h>
#include <private/libc_events.h>
#include <machine/asm.h>
#include "libc_events.h"
.syntax unified
.fpu neon
@ -37,8 +37,10 @@
// Get the length of the source string first, then do a memcpy of the data
// instead of a strcpy.
ENTRY(__strcpy_chk)
.cfi_startproc
pld [r0, #0]
push {r0, lr}
.save {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
@ -156,6 +158,8 @@ ENTRY(__strcpy_chk)
// Add 1 for copy length to get the string terminator.
add r2, r3, #1
.cfi_endproc
// Fall through into the memcpy_base function.
END(__strcpy_chk)
@ -163,7 +167,10 @@ END(__strcpy_chk)
#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
#include "memcpy_base.S"
ENTRY_PRIVATE(__strcpy_chk_fail)
ENTRY(__strcpy_chk_fail)
.cfi_startproc
.save {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
@ -178,8 +185,10 @@ error_code:
.word BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+4)
.cfi_endproc
END(__strcpy_chk_fail)
.data
error_string:
.string "strcpy: prevented write past end of buffer"
.string "strcpy buffer overflow"

View File

@ -26,8 +26,8 @@
* SUCH DAMAGE.
*/
#include <private/bionic_asm.h>
#include <private/libc_events.h>
#include <machine/asm.h>
#include "libc_events.h"
/*
* This code assumes it is running on a processor that supports all arm v7
@ -41,28 +41,37 @@
.thumb_func
ENTRY(__memcpy_chk)
.cfi_startproc
cmp r2, r3
bhi __memcpy_chk_fail
// Fall through to memcpy...
.cfi_endproc
END(__memcpy_chk)
ENTRY(memcpy)
.cfi_startproc
pld [r1, #0]
stmfd sp!, {r0, lr}
.save {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
pld [r1, #64]
.cfi_endproc
END(memcpy)
#define MEMCPY_BASE __memcpy_base
#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
#include "memcpy_base.S"
ENTRY_PRIVATE(__memcpy_chk_fail)
ENTRY(__memcpy_chk_fail)
.cfi_startproc
// Preserve lr for backtrace.
push {lr}
.save {lr}
.cfi_def_cfa_offset 4
.cfi_rel_offset lr, 0
@ -75,8 +84,9 @@ error_code:
.word BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+4)
.cfi_endproc
END(__memcpy_chk_fail)
.data
error_string:
.string "memcpy: prevented write past end of buffer"
.string "memcpy buffer overflow"

View File

@ -32,7 +32,9 @@
* cache line.
*/
ENTRY_PRIVATE(MEMCPY_BASE)
ENTRY(MEMCPY_BASE)
.cfi_startproc
.save {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
@ -44,7 +46,7 @@ ENTRY_PRIVATE(MEMCPY_BASE)
/* check if buffers are aligned. If so, run arm-only version */
eor r3, r0, r1
ands r3, r3, #0x3
beq MEMCPY_BASE_ALIGNED
beq __memcpy_base_aligned
/* Check the upper size limit for Neon unaligned memory access in memcpy */
cmp r2, #224
@ -133,16 +135,23 @@ ENTRY_PRIVATE(MEMCPY_BASE)
strbcs ip, [r0], #1
strbcs lr, [r0], #1
ldmfd sp!, {r0, pc}
ldmfd sp!, {r0, lr}
bx lr
.cfi_endproc
END(MEMCPY_BASE)
ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED)
ENTRY(MEMCPY_BASE_ALIGNED)
.cfi_startproc
.save {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
/* Simple arm-only copy loop to handle aligned copy operations */
stmfd sp!, {r4-r8}
.save {r4-r8}
.cfi_adjust_cfa_offset 20
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
@ -219,4 +228,6 @@ ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED)
6:
ldmfd sp!, {r4-r8}
ldmfd sp!, {r0, pc}
.cfi_endproc
END(MEMCPY_BASE_ALIGNED)

View File

@ -26,8 +26,9 @@
* SUCH DAMAGE.
*/
#include <private/bionic_asm.h>
#include <private/libc_events.h>
#include <machine/cpu-features.h>
#include <machine/asm.h>
#include "libc_events.h"
/*
* This code assumes it is running on a processor that supports all arm v7
@ -35,14 +36,15 @@
*/
.fpu neon
.syntax unified
ENTRY(__memset_chk)
.cfi_startproc
cmp r2, r3
bls .L_done
// Preserve lr for backtrace.
push {lr}
.save {lr}
.cfi_def_cfa_offset 4
.cfi_rel_offset lr, 0
@ -55,23 +57,33 @@ error_code:
.word BIONIC_EVENT_MEMSET_BUFFER_OVERFLOW
error_message:
.word error_string-(1b+8)
.cfi_endproc
END(__memset_chk)
ENTRY(bzero)
.cfi_startproc
mov r2, r1
mov r1, #0
.L_done:
// Fall through to memset...
.cfi_endproc
END(bzero)
/* memset() returns its first argument. */
ENTRY(memset)
// The neon memset only wins for less than 132.
cmp r2, #132
bhi .L_memset_large_copy
.cfi_startproc
# The neon memset only wins for less than 132.
cmp r2, #132
bhi __memset_large_copy
stmfd sp!, {r0}
.save {r0}
.cfi_def_cfa_offset 4
.cfi_rel_offset r0, 0
mov r3, r0
vdup.8 q0, r1
/* make sure we have at least 32 bytes to write */
@ -81,7 +93,7 @@ ENTRY(memset)
1: /* The main loop writes 32 bytes at a time */
subs r2, r2, #32
vst1.8 {d0 - d3}, [r3]!
vst1.8 {d0 - d3}, [r0]!
bhs 1b
2: /* less than 32 left */
@ -90,24 +102,31 @@ ENTRY(memset)
beq 3f
// 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) */
movs ip, r2, lsl #29
bcc 1f
vst1.8 {d0}, [r3]!
vst1.8 {d0}, [r0]!
1: bge 2f
vst1.32 {d0[0]}, [r3]!
vst1.32 {d0[0]}, [r0]!
2: movs ip, r2, lsl #31
strbmi r1, [r3], #1
strbcs r1, [r3], #1
strbcs r1, [r3], #1
strmib r1, [r0], #1
strcsb r1, [r0], #1
strcsb r1, [r0], #1
ldmfd sp!, {r0}
bx lr
.L_memset_large_copy:
.cfi_endproc
END(memset)
ENTRY(__memset_large_copy)
.cfi_startproc
/* compute the offset to align the destination
* offset = (4-(src&3))&3 = -src & 3
*/
stmfd sp!, {r0, r4-r7, lr}
.save {r0, r4-r7, lr}
.cfi_def_cfa_offset 24
.cfi_rel_offset r0, 0
.cfi_rel_offset r4, 4
@ -127,11 +146,12 @@ ENTRY(memset)
orr r1, r1, r1, lsr #16
movs r12, r3, lsl #31
strbcs r1, [r0], #1 /* can't use strh (alignment unknown) */
strbcs r1, [r0], #1
strbmi r1, [r0], #1
strcsb r1, [r0], #1 /* can't use strh (alignment unknown) */
strcsb r1, [r0], #1
strmib r1, [r0], #1
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 */
mov r12, r1
@ -150,9 +170,9 @@ ENTRY(memset)
/* conditionally writes 0 to 7 words (length in r3) */
movs r3, r3, lsl #28
stmcs r0!, {r1, lr}
stmcs r0!, {r1, lr}
stmmi r0!, {r1, lr}
stmcsia r0!, {r1, lr}
stmcsia r0!, {r1, lr}
stmmiia r0!, {r1, lr}
movs r3, r3, lsl #2
strcs r1, [r0], #4
@ -167,16 +187,18 @@ ENTRY(memset)
/* conditionally stores 0 to 31 bytes */
movs r2, r2, lsl #28
stmcs r0!, {r1,r3,r12,lr}
stmmi r0!, {r1, lr}
stmcsia r0!, {r1,r3,r12,lr}
stmmiia r0!, {r1, lr}
movs r2, r2, lsl #2
strcs r1, [r0], #4
strhmi r1, [r0], #2
strmih r1, [r0], #2
movs r2, r2, lsl #2
strbcs r1, [r0]
ldmfd sp!, {r0, r4-r7, pc}
END(memset)
strcsb r1, [r0]
ldmfd sp!, {r0, r4-r7, lr}
bx lr
.cfi_endproc
END(__memset_large_copy)
.data
error_string:
.string "memset: prevented write past end of buffer"
.string "memset buffer overflow"

View File

@ -1,30 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#define STPCPY
#include "string_copy.S"

View File

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

View File

@ -27,7 +27,7 @@
*/
#include <machine/cpu-features.h>
#include <private/bionic_asm.h>
#include <machine/asm.h>
#ifdef __ARMEB__
#define S2LOMEM lsl
@ -145,8 +145,19 @@ ENTRY(strcmp)
.macro magic_find_zero_bytes w1
/* Macro to find all-zero bytes in w1, result is in ip. */
#if (defined (__ARM_FEATURE_DSP))
uadd8 ip, \w1, r6
sel ip, r7, r6
#else /* not defined (__ARM_FEATURE_DSP) */
/* __ARM_FEATURE_DSP is not defined for some Cortex-M processors.
Coincidently, these processors only have Thumb-2 mode, where we can use the
the (large) magic constant available directly as an immediate in instructions.
Note that we cannot use the magic constant in ARM mode, where we need
to create the constant in a register. */
sub ip, \w1, #0x01010101
bic ip, ip, \w1
and ip, ip, #0x80808080
#endif /* not defined (__ARM_FEATURE_DSP) */
.endm /* magic_find_zero_bytes */
.macro setup_return w1 w2
@ -159,6 +170,7 @@ ENTRY(strcmp)
#endif /* not __ARMEB__ */
.endm /* setup_return */
.cfi_startproc
pld [r0, #0]
pld [r1, #0]
@ -168,6 +180,7 @@ ENTRY(strcmp)
bne .L_do_align
/* Fast path. */
.save {r4-r7}
init
.L_doubleword_aligned:
@ -545,4 +558,5 @@ ENTRY(strcmp)
adds sp, sp, #16
bx lr
.cfi_endproc
END(strcmp)

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 The Android Open Source Project
* Copyright (C) 2013 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -25,6 +25,432 @@
* 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.
*/
#define STRCPY
#include "string_copy.S"
#include <machine/asm.h>
.syntax unified
.thumb
.thumb_func
.macro m_push
push {r0, r4, r5, lr}
.endm // m_push
.macro m_ret inst
\inst {r0, r4, r5, pc}
.endm // m_ret
.macro m_copy_byte reg, cmd, label
ldrb \reg, [r1], #1
strb \reg, [r0], #1
\cmd \reg, \label
.endm // m_copy_byte
ENTRY(strcpy)
// Unroll the first 8 bytes that will be copied.
m_push
m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r5, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
m_copy_byte reg=r5, cmd=cbnz, label=strcpy_continue
strcpy_finish:
m_ret inst=pop
strcpy_continue:
pld [r1, #0]
ands r3, r0, #7
bne strcpy_align_dst
strcpy_check_src_align:
// At this point dst is aligned to a double word, check if src
// is also aligned to a double word.
ands r3, r1, #7
bne strcpy_unaligned_copy
.p2align 2
strcpy_mainloop:
ldmia r1!, {r2, r3}
pld [r1, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
stmia r0!, {r2, r3}
b strcpy_mainloop
strcpy_zero_in_first_register:
lsls lr, ip, #17
itt ne
strbne r2, [r0]
m_ret inst=popne
itt cs
strhcs r2, [r0]
m_ret inst=popcs
lsls ip, ip, #1
itt eq
streq r2, [r0]
m_ret inst=popeq
strh r2, [r0], #2
lsr r3, r2, #16
strb r3, [r0]
m_ret inst=pop
strcpy_zero_in_second_register:
lsls lr, ip, #17
ittt ne
stmiane r0!, {r2}
strbne r3, [r0]
m_ret inst=popne
ittt cs
strcs r2, [r0], #4
strhcs r3, [r0]
m_ret inst=popcs
lsls ip, ip, #1
itt eq
stmiaeq r0, {r2, r3}
m_ret inst=popeq
stmia r0!, {r2}
strh r3, [r0], #2
lsr r4, r3, #16
strb r4, [r0]
m_ret inst=pop
strcpy_align_dst:
// Align to a double word (64 bits).
rsb r3, r3, #8
lsls ip, r3, #31
beq strcpy_align_to_32
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, strcpy_complete
strcpy_align_to_32:
bcc strcpy_align_to_64
ldrb r4, [r1], #1
strb r4, [r0], #1
cmp r4, #0
it eq
m_ret inst=popeq
ldrb r5, [r1], #1
strb r5, [r0], #1
cmp r5, #0
it eq
m_ret inst=popeq
strcpy_align_to_64:
tst r3, #4
beq strcpy_check_src_align
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
stmia r0!, {r2}
b strcpy_check_src_align
strcpy_complete:
m_ret inst=pop
strcpy_unaligned_copy:
// Dst is aligned to a double word, while src is at an unknown alignment.
// There are 7 different versions of the unaligned copy code
// to prevent overreading the src. The mainloop of every single version
// will store 64 bits per loop. The difference is how much of src can
// be read without potentially crossing a page boundary.
tbb [pc, r3]
strcpy_unaligned_branchtable:
.byte 0
.byte ((strcpy_unalign7 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign6 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign5 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign4 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign3 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign2 - strcpy_unaligned_branchtable)/2)
.byte ((strcpy_unalign1 - strcpy_unaligned_branchtable)/2)
.p2align 2
// Can read 7 bytes before possibly crossing a page.
strcpy_unalign7:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
ldrb r3, [r1]
cbz r3, strcpy_unalign7_copy5bytes
ldrb r4, [r1, #1]
cbz r4, strcpy_unalign7_copy6bytes
ldrb r5, [r1, #2]
cbz r5, strcpy_unalign7_copy7bytes
ldr r3, [r1], #4
pld [r1, #64]
lsrs ip, r3, #24
stmia r0!, {r2, r3}
beq strcpy_unalign_return
b strcpy_unalign7
strcpy_unalign7_copy5bytes:
stmia r0!, {r2}
strb r3, [r0]
strcpy_unalign_return:
m_ret inst=pop
strcpy_unalign7_copy6bytes:
stmia r0!, {r2}
strb r3, [r0], #1
strb r4, [r0], #1
m_ret inst=pop
strcpy_unalign7_copy7bytes:
stmia r0!, {r2}
strb r3, [r0], #1
strb r4, [r0], #1
strb r5, [r0], #1
m_ret inst=pop
.p2align 2
// Can read 6 bytes before possibly crossing a page.
strcpy_unalign6:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
ldrb r4, [r1]
cbz r4, strcpy_unalign_copy5bytes
ldrb r5, [r1, #1]
cbz r5, strcpy_unalign_copy6bytes
ldr r3, [r1], #4
pld [r1, #64]
tst r3, #0xff0000
beq strcpy_unalign6_copy7bytes
lsrs ip, r3, #24
stmia r0!, {r2, r3}
beq strcpy_unalign_return
b strcpy_unalign6
strcpy_unalign6_copy7bytes:
stmia r0!, {r2}
strh r3, [r0], #2
lsr r3, #16
strb r3, [r0]
m_ret inst=pop
.p2align 2
// Can read 5 bytes before possibly crossing a page.
strcpy_unalign5:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
ldrb r4, [r1]
cbz r4, strcpy_unalign_copy5bytes
ldr r3, [r1], #4
pld [r1, #64]
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
stmia r0!, {r2, r3}
b strcpy_unalign5
strcpy_unalign_copy5bytes:
stmia r0!, {r2}
strb r4, [r0]
m_ret inst=pop
strcpy_unalign_copy6bytes:
stmia r0!, {r2}
strb r4, [r0], #1
strb r5, [r0]
m_ret inst=pop
.p2align 2
// Can read 4 bytes before possibly crossing a page.
strcpy_unalign4:
ldmia r1!, {r2}
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
ldmia r1!, {r3}
pld [r1, #64]
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
stmia r0!, {r2, r3}
b strcpy_unalign4
.p2align 2
// Can read 3 bytes before possibly crossing a page.
strcpy_unalign3:
ldrb r2, [r1]
cbz r2, strcpy_unalign3_copy1byte
ldrb r3, [r1, #1]
cbz r3, strcpy_unalign3_copy2bytes
ldrb r4, [r1, #2]
cbz r4, strcpy_unalign3_copy3bytes
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
lsrs lr, r2, #24
beq strcpy_unalign_copy4bytes
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
stmia r0!, {r2, r3}
b strcpy_unalign3
strcpy_unalign3_copy1byte:
strb r2, [r0]
m_ret inst=pop
strcpy_unalign3_copy2bytes:
strb r2, [r0], #1
strb r3, [r0]
m_ret inst=pop
strcpy_unalign3_copy3bytes:
strb r2, [r0], #1
strb r3, [r0], #1
strb r4, [r0]
m_ret inst=pop
.p2align 2
// Can read 2 bytes before possibly crossing a page.
strcpy_unalign2:
ldrb r2, [r1]
cbz r2, strcpy_unalign_copy1byte
ldrb r3, [r1, #1]
cbz r3, strcpy_unalign_copy2bytes
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
tst r2, #0xff0000
beq strcpy_unalign_copy3bytes
lsrs ip, r2, #24
beq strcpy_unalign_copy4bytes
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
stmia r0!, {r2, r3}
b strcpy_unalign2
.p2align 2
// Can read 1 byte before possibly crossing a page.
strcpy_unalign1:
ldrb r2, [r1]
cbz r2, strcpy_unalign_copy1byte
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne strcpy_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne strcpy_zero_in_second_register
stmia r0!, {r2, r3}
b strcpy_unalign1
strcpy_unalign_copy1byte:
strb r2, [r0]
m_ret inst=pop
strcpy_unalign_copy2bytes:
strb r2, [r0], #1
strb r3, [r0]
m_ret inst=pop
strcpy_unalign_copy3bytes:
strh r2, [r0], #2
lsr r2, #16
strb r2, [r0]
m_ret inst=pop
strcpy_unalign_copy4bytes:
stmia r0, {r2}
m_ret inst=pop
END(strcpy)

View File

@ -1,542 +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.
*/
/*
* Copyright (c) 2013 ARM Ltd
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the company may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(STPCPY) && !defined(STRCPY)
#error "Either STPCPY or STRCPY must be defined."
#endif
#include <private/bionic_asm.h>
.syntax unified
.thumb
.thumb_func
#if defined(STPCPY)
.macro m_push
push {r4, r5, lr}
.cfi_def_cfa_offset 12
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
.cfi_rel_offset lr, 8
.endm // m_push
#else
.macro m_push
push {r0, r4, r5, lr}
.cfi_def_cfa_offset 16
.cfi_rel_offset r0, 0
.cfi_rel_offset r4, 4
.cfi_rel_offset r5, 8
.cfi_rel_offset lr, 12
.endm // m_push
#endif
#if defined(STPCPY)
.macro m_ret inst
\inst {r4, r5, pc}
.endm // m_ret
#else
.macro m_ret inst
\inst {r0, r4, r5, pc}
.endm // m_ret
#endif
.macro m_copy_byte reg, cmd, label
ldrb \reg, [r1], #1
strb \reg, [r0], #1
\cmd \reg, \label
.endm // m_copy_byte
#if defined(STPCPY)
ENTRY(stpcpy)
#else
ENTRY(strcpy)
#endif
// Unroll the first 8 bytes that will be copied.
m_push
m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r5, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish
m_copy_byte reg=r5, cmd=cbnz, label=.Lstringcopy_continue
.Lstringcopy_finish:
#if defined(STPCPY)
sub r0, r0, #1
#endif
m_ret inst=pop
.Lstringcopy_continue:
pld [r1, #0]
ands r3, r0, #7
bne .Lstringcopy_align_dst
.Lstringcopy_check_src_align:
// At this point dst is aligned to a double word, check if src
// is also aligned to a double word.
ands r3, r1, #7
bne .Lstringcopy_unaligned_copy
.p2align 2
.Lstringcopy_mainloop:
ldmia r1!, {r2, r3}
pld [r1, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
stmia r0!, {r2, r3}
b .Lstringcopy_mainloop
.Lstringcopy_zero_in_first_register:
lsls lr, ip, #17
itt ne
strbne r2, [r0]
m_ret inst=popne
itt cs
#if defined(STPCPY)
strhcs r2, [r0], #1
#else
strhcs r2, [r0]
#endif
m_ret inst=popcs
lsls ip, ip, #1
itt eq
#if defined(STPCPY)
streq r2, [r0], #3
#else
streq r2, [r0]
#endif
m_ret inst=popeq
strh r2, [r0], #2
lsr r3, r2, #16
strb r3, [r0]
m_ret inst=pop
.Lstringcopy_zero_in_second_register:
lsls lr, ip, #17
ittt ne
stmiane r0!, {r2}
strbne r3, [r0]
m_ret inst=popne
ittt cs
strcs r2, [r0], #4
#if defined(STPCPY)
strhcs r3, [r0], #1
#else
strhcs r3, [r0]
#endif
m_ret inst=popcs
lsls ip, ip, #1
#if defined(STPCPY)
ittt eq
#else
itt eq
#endif
stmiaeq r0, {r2, r3}
#if defined(STPCPY)
addeq r0, r0, #7
#endif
m_ret inst=popeq
stmia r0!, {r2}
strh r3, [r0], #2
lsr r4, r3, #16
strb r4, [r0]
m_ret inst=pop
.Lstringcopy_align_dst:
// Align to a double word (64 bits).
rsb r3, r3, #8
lsls ip, r3, #31
beq .Lstringcopy_align_to_32
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .Lstringcopy_complete
.Lstringcopy_align_to_32:
bcc .Lstringcopy_align_to_64
ldrb r4, [r1], #1
strb r4, [r0], #1
cmp r4, #0
#if defined(STPCPY)
itt eq
subeq r0, r0, #1
#else
it eq
#endif
m_ret inst=popeq
ldrb r5, [r1], #1
strb r5, [r0], #1
cmp r5, #0
#if defined(STPCPY)
itt eq
subeq r0, r0, #1
#else
it eq
#endif
m_ret inst=popeq
.Lstringcopy_align_to_64:
tst r3, #4
beq .Lstringcopy_check_src_align
// Read one byte at a time since we don't have any idea about the alignment
// of the source and we don't want to read into a different page.
ldrb r2, [r1], #1
strb r2, [r0], #1
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
ldrb r2, [r1], #1
strb r2, [r0], #1
cbz r2, .Lstringcopy_complete
b .Lstringcopy_check_src_align
.Lstringcopy_complete:
#if defined(STPCPY)
sub r0, r0, #1
#endif
m_ret inst=pop
.Lstringcopy_unaligned_copy:
// Dst is aligned to a double word, while src is at an unknown alignment.
// There are 7 different versions of the unaligned copy code
// to prevent overreading the src. The mainloop of every single version
// will store 64 bits per loop. The difference is how much of src can
// be read without potentially crossing a page boundary.
tbb [pc, r3]
.Lstringcopy_unaligned_branchtable:
.byte 0
.byte ((.Lstringcopy_unalign7 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign6 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign5 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign4 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign3 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign2 - .Lstringcopy_unaligned_branchtable)/2)
.byte ((.Lstringcopy_unalign1 - .Lstringcopy_unaligned_branchtable)/2)
.p2align 2
// Can read 7 bytes before possibly crossing a page.
.Lstringcopy_unalign7:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
ldrb r3, [r1]
cbz r3, .Lstringcopy_unalign7_copy5bytes
ldrb r4, [r1, #1]
cbz r4, .Lstringcopy_unalign7_copy6bytes
ldrb r5, [r1, #2]
cbz r5, .Lstringcopy_unalign7_copy7bytes
ldr r3, [r1], #4
pld [r1, #64]
lsrs ip, r3, #24
stmia r0!, {r2, r3}
#if defined(STPCPY)
beq .Lstringcopy_finish
#else
beq .Lstringcopy_unalign_return
#endif
b .Lstringcopy_unalign7
.Lstringcopy_unalign7_copy5bytes:
stmia r0!, {r2}
strb r3, [r0]
.Lstringcopy_unalign_return:
m_ret inst=pop
.Lstringcopy_unalign7_copy6bytes:
stmia r0!, {r2}
strb r3, [r0], #1
strb r4, [r0]
m_ret inst=pop
.Lstringcopy_unalign7_copy7bytes:
stmia r0!, {r2}
strb r3, [r0], #1
strb r4, [r0], #1
strb r5, [r0]
m_ret inst=pop
.p2align 2
// Can read 6 bytes before possibly crossing a page.
.Lstringcopy_unalign6:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
ldrb r4, [r1]
cbz r4, .Lstringcopy_unalign_copy5bytes
ldrb r5, [r1, #1]
cbz r5, .Lstringcopy_unalign_copy6bytes
ldr r3, [r1], #4
pld [r1, #64]
tst r3, #0xff0000
beq .Lstringcopy_unalign6_copy7bytes
lsrs ip, r3, #24
stmia r0!, {r2, r3}
#if defined(STPCPY)
beq .Lstringcopy_finish
#else
beq .Lstringcopy_unalign_return
#endif
b .Lstringcopy_unalign6
.Lstringcopy_unalign6_copy7bytes:
stmia r0!, {r2}
strh r3, [r0], #2
lsr r3, #16
strb r3, [r0]
m_ret inst=pop
.p2align 2
// Can read 5 bytes before possibly crossing a page.
.Lstringcopy_unalign5:
ldr r2, [r1], #4
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
ldrb r4, [r1]
cbz r4, .Lstringcopy_unalign_copy5bytes
ldr r3, [r1], #4
pld [r1, #64]
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
stmia r0!, {r2, r3}
b .Lstringcopy_unalign5
.Lstringcopy_unalign_copy5bytes:
stmia r0!, {r2}
strb r4, [r0]
m_ret inst=pop
.Lstringcopy_unalign_copy6bytes:
stmia r0!, {r2}
strb r4, [r0], #1
strb r5, [r0]
m_ret inst=pop
.p2align 2
// Can read 4 bytes before possibly crossing a page.
.Lstringcopy_unalign4:
ldmia r1!, {r2}
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
ldmia r1!, {r3}
pld [r1, #64]
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
stmia r0!, {r2, r3}
b .Lstringcopy_unalign4
.p2align 2
// Can read 3 bytes before possibly crossing a page.
.Lstringcopy_unalign3:
ldrb r2, [r1]
cbz r2, .Lstringcopy_unalign3_copy1byte
ldrb r3, [r1, #1]
cbz r3, .Lstringcopy_unalign3_copy2bytes
ldrb r4, [r1, #2]
cbz r4, .Lstringcopy_unalign3_copy3bytes
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
lsrs lr, r2, #24
beq .Lstringcopy_unalign_copy4bytes
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
stmia r0!, {r2, r3}
b .Lstringcopy_unalign3
.Lstringcopy_unalign3_copy1byte:
strb r2, [r0]
m_ret inst=pop
.Lstringcopy_unalign3_copy2bytes:
strb r2, [r0], #1
strb r3, [r0]
m_ret inst=pop
.Lstringcopy_unalign3_copy3bytes:
strb r2, [r0], #1
strb r3, [r0], #1
strb r4, [r0]
m_ret inst=pop
.p2align 2
// Can read 2 bytes before possibly crossing a page.
.Lstringcopy_unalign2:
ldrb r2, [r1]
cbz r2, .Lstringcopy_unalign_copy1byte
ldrb r3, [r1, #1]
cbz r3, .Lstringcopy_unalign_copy2bytes
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
tst r2, #0xff0000
beq .Lstringcopy_unalign_copy3bytes
lsrs ip, r2, #24
beq .Lstringcopy_unalign_copy4bytes
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
stmia r0!, {r2, r3}
b .Lstringcopy_unalign2
.p2align 2
// Can read 1 byte before possibly crossing a page.
.Lstringcopy_unalign1:
ldrb r2, [r1]
cbz r2, .Lstringcopy_unalign_copy1byte
ldr r2, [r1], #4
ldr r3, [r1], #4
pld [r1, #64]
sub ip, r2, #0x01010101
bic ip, ip, r2
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_first_register
sub ip, r3, #0x01010101
bic ip, ip, r3
ands ip, ip, #0x80808080
bne .Lstringcopy_zero_in_second_register
stmia r0!, {r2, r3}
b .Lstringcopy_unalign1
.Lstringcopy_unalign_copy1byte:
strb r2, [r0]
m_ret inst=pop
.Lstringcopy_unalign_copy2bytes:
strb r2, [r0], #1
strb r3, [r0]
m_ret inst=pop
.Lstringcopy_unalign_copy3bytes:
strh r2, [r0], #2
lsr r2, #16
strb r2, [r0]
m_ret inst=pop
.Lstringcopy_unalign_copy4bytes:
stmia r0, {r2}
#if defined(STPCPY)
add r0, r0, #3
#endif
m_ret inst=pop
#if defined(STPCPY)
END(stpcpy)
#else
END(strcpy)
#endif

View File

@ -53,7 +53,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <private/bionic_asm.h>
#include <machine/asm.h>
.syntax unified

View File

@ -1,28 +1,10 @@
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 \
$(call libc-add-cpu-variant-src,MEMCPY,arch-arm/cortex-a9/bionic/memcpy.S)
$(call libc-add-cpu-variant-src,MEMSET,arch-arm/cortex-a9/bionic/memset.S)
$(call libc-add-cpu-variant-src,STRCAT,arch-arm/cortex-a9/bionic/strcat.S)
$(call libc-add-cpu-variant-src,STRCMP,arch-arm/cortex-a9/bionic/strcmp.S)
$(call libc-add-cpu-variant-src,STRCPY,arch-arm/cortex-a9/bionic/strcpy.S)
$(call libc-add-cpu-variant-src,STRLEN,arch-arm/cortex-a9/bionic/strlen.S)
$(call libc-add-cpu-variant-src,__STRCAT_CHK,arch-arm/cortex-a9/bionic/__strcat_chk.S)
$(call libc-add-cpu-variant-src,__STRCPY_CHK,arch-arm/cortex-a9/bionic/__strcpy_chk.S)
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-a9/bionic/memcpy.S \
arch-arm/cortex-a9/bionic/memset.S \
arch-arm/cortex-a9/bionic/stpcpy.S \
arch-arm/cortex-a9/bionic/strcat.S \
arch-arm/cortex-a9/bionic/__strcat_chk.S \
arch-arm/cortex-a9/bionic/strcmp.S \
arch-arm/cortex-a9/bionic/strcpy.S \
arch-arm/cortex-a9/bionic/__strcpy_chk.S \
arch-arm/cortex-a9/bionic/strlen.S \
libc_bionic_src_files_arm += \
arch-arm/denver/bionic/memmove.S \
include bionic/libc/arch-arm/generic/generic.mk

View File

@ -1,216 +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 __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,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 <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 __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,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.
*/
// Prototype: void *memcpy (void *dst, const void *src, size_t count).
#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"

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