Compare commits
109 Commits
main
...
lollipop-m
Author | SHA1 | Date | |
---|---|---|---|
![]() |
63d2f6db2e | ||
![]() |
f0b38a3fc9 | ||
![]() |
ecb7dcc084 | ||
![]() |
f6f04b82e2 | ||
![]() |
25726c8ce4 | ||
![]() |
fffca9eb3d | ||
![]() |
d602328201 | ||
![]() |
fa06d6dba7 | ||
![]() |
5831077f76 | ||
![]() |
5553ed1e85 | ||
![]() |
4107b7d092 | ||
![]() |
b8e430701e | ||
![]() |
e4ae96ffd3 | ||
![]() |
d84897d4a3 | ||
![]() |
189ac9f142 | ||
![]() |
8bf7353b79 | ||
![]() |
8b952f5552 | ||
![]() |
86fdf8f09b | ||
![]() |
b9f21a08f3 | ||
![]() |
0c7105c69f | ||
![]() |
99e148e30c | ||
![]() |
b0daba3da1 | ||
![]() |
13baf92d93 | ||
![]() |
09fa97fd17 | ||
![]() |
609f5cb21d | ||
![]() |
05c3adbabf | ||
![]() |
b50945d935 | ||
![]() |
fa29966094 | ||
![]() |
5c9ba49803 | ||
![]() |
0e5f7b9b3c | ||
![]() |
ddedd3a38d | ||
![]() |
75f6f21a75 | ||
![]() |
0f17126b24 | ||
![]() |
eca44bc1f3 | ||
![]() |
99415296ac | ||
![]() |
f020640c09 | ||
![]() |
466c8cbd50 | ||
![]() |
c9b1201be1 | ||
![]() |
91221be747 | ||
![]() |
d60cda85b9 | ||
![]() |
50d615236d | ||
![]() |
d67e1d8ae9 | ||
![]() |
bc9cee7f58 | ||
![]() |
f51bbbe319 | ||
![]() |
26df9bf109 | ||
![]() |
4877fe15c2 | ||
![]() |
975164af3c | ||
![]() |
1f5a9a4b35 | ||
![]() |
dd4b377612 | ||
![]() |
f9c31b1115 | ||
![]() |
e09a9d77d2 | ||
![]() |
bc04ede139 | ||
![]() |
fe054482cc | ||
![]() |
a950f53fc3 | ||
![]() |
e647a62805 | ||
![]() |
bc2fb531b7 | ||
![]() |
460c53d4d4 | ||
![]() |
8f0c298a3d | ||
![]() |
d830465de8 | ||
![]() |
306d80e339 | ||
![]() |
6078d68321 | ||
![]() |
277c1b00f5 | ||
![]() |
50982fd0c4 | ||
![]() |
25232c43fc | ||
![]() |
1d12f186ed | ||
![]() |
fab4d76b46 | ||
![]() |
604b2f5789 | ||
![]() |
ddca20bda4 | ||
![]() |
d0beefdcd3 | ||
![]() |
ee809b90e8 | ||
![]() |
b2c6088b1e | ||
![]() |
dc3814bcf9 | ||
![]() |
d9bead2357 | ||
![]() |
8c673ec8e9 | ||
![]() |
daebe2764b | ||
![]() |
2fcb94d52c | ||
![]() |
20dc3f8fa4 | ||
![]() |
54a6221cc2 | ||
![]() |
489b5d23fd | ||
![]() |
5f17e16e92 | ||
![]() |
3bd669c605 | ||
![]() |
cb278332cb | ||
![]() |
fe9787ece9 | ||
![]() |
bae5898f3d | ||
![]() |
08f6f664ed | ||
![]() |
a0108accb2 | ||
![]() |
58df7d814e | ||
![]() |
147ce71ddc | ||
![]() |
2e7c8634b7 | ||
![]() |
25ffdd7b9f | ||
![]() |
e9f34a3ee7 | ||
![]() |
c323d5efb8 | ||
![]() |
6cde02273f | ||
![]() |
e3ff5fca61 | ||
![]() |
b5e0854284 | ||
![]() |
6b9b454d55 | ||
![]() |
5984773a8d | ||
![]() |
b4725def2e | ||
![]() |
b8d00ef3ba | ||
![]() |
39978ccb7f | ||
![]() |
6447d2f4de | ||
![]() |
1183762969 | ||
![]() |
bdf601894f | ||
![]() |
6a20f051a2 | ||
![]() |
8bc74887c1 | ||
![]() |
1b710ff000 | ||
![]() |
13fb0584e1 | ||
![]() |
4514aa630c | ||
![]() |
0caf70e98e |
@ -1,15 +0,0 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: NOLINT:.*
|
||||
DerivePointerAlignment: false
|
||||
IndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
PointerAlignment: Left
|
||||
TabWidth: 2
|
||||
UseTab: Never
|
||||
PenaltyExcessCharacter: 32
|
||||
|
||||
Cpp11BracedListStyle: false
|
12
ABI-bugs.txt
Normal file
12
ABI-bugs.txt
Normal file
@ -0,0 +1,12 @@
|
||||
KNOWN ABI BUGS
|
||||
--------------
|
||||
|
||||
time_t is 32-bit. http://b/5819737
|
||||
|
||||
off_t is 32-bit. There is off64_t, but no _FILE_OFFSET_BITS support.
|
||||
|
||||
sigset_t is too small on ARM and x86 (but correct on MIPS), so support
|
||||
for real-time signals is broken. http://b/5828899
|
||||
|
||||
atexit(3) handlers registered by a shared library aren't called on
|
||||
dlclose(3); this only affects ARM. http://b/4998315
|
@ -1 +0,0 @@
|
||||
subdirs = ["*"]
|
@ -1,2 +0,0 @@
|
||||
set noparent
|
||||
filter=-build/header_guard,-runtime/int,-readability/function
|
162
HACKING.txt
Normal file
162
HACKING.txt
Normal file
@ -0,0 +1,162 @@
|
||||
Working on bionic
|
||||
=================
|
||||
|
||||
What are the big pieces of bionic?
|
||||
----------------------------------
|
||||
|
||||
libc/ --- libc.so, libc.a
|
||||
The C library. Stuff like fopen(3) and kill(2).
|
||||
libm/ --- libm.so, libm.a
|
||||
The math library. Traditionally Unix systems kept stuff like sin(3) and
|
||||
cos(3) in a separate library to save space in the days before shared
|
||||
libraries.
|
||||
libdl/ --- libdl.so
|
||||
The dynamic linker interface library. This is actually just a bunch of
|
||||
stubs that the dynamic linker replaces with pointers to its own
|
||||
implementation at runtime. This is where stuff like dlopen(3) lives.
|
||||
libstdc++/ --- libstdc++.so
|
||||
The C++ ABI support functions. The C++ compiler doesn't know how to
|
||||
implement thread-safe static initialization and the like, so it just calls
|
||||
functions that are supplied by the system. Stuff like __cxa_guard_acquire
|
||||
and __cxa_pure_virtual live here.
|
||||
|
||||
linker/ --- /system/bin/linker and /system/bin/linker64
|
||||
The dynamic linker. When you run a dynamically-linked executable, its ELF
|
||||
file has a DT_INTERP entry that says "use the following program to start me".
|
||||
On Android, that's either linker or linker64 (depending on whether it's a
|
||||
32-bit or 64-bit executable). It's responsible for loading the ELF executable
|
||||
into memory and resolving references to symbols (so that when your code tries
|
||||
to jump to fopen(3), say, it lands in the right place).
|
||||
|
||||
tests/ --- unit tests
|
||||
The tests/ directory contains unit tests. Roughly arranged as one file per
|
||||
publicly-exported header file.
|
||||
benchmarks/ --- benchmarks
|
||||
The benchmarks/ directory contains benchmarks.
|
||||
|
||||
|
||||
What's in libc/?
|
||||
----------------
|
||||
|
||||
libc/
|
||||
arch-arm/
|
||||
arch-arm64/
|
||||
arch-common/
|
||||
arch-mips/
|
||||
arch-mips64/
|
||||
arch-x86/
|
||||
arch-x86_64/
|
||||
# Each architecture has its own subdirectory for stuff that isn't shared
|
||||
# because it's architecture-specific. There will be a .mk file in here that
|
||||
# drags in all the architecture-specific files.
|
||||
bionic/
|
||||
# Every architecture needs a handful of machine-specific assembler files.
|
||||
# They live here.
|
||||
include/
|
||||
machine/
|
||||
# The majority of header files are actually in libc/include/, but many
|
||||
# of them pull in a <machine/something.h> for things like limits,
|
||||
# endianness, and how floating point numbers are represented. Those
|
||||
# headers live here.
|
||||
string/
|
||||
# Most architectures have a handful of optional assembler files
|
||||
# implementing optimized versions of various routines. The <string.h>
|
||||
# functions are particular favorites.
|
||||
syscalls/
|
||||
# The syscalls directories contain script-generated assembler files.
|
||||
# See 'Adding system calls' later.
|
||||
|
||||
include/
|
||||
# The public header files on everyone's include path. These are a mixture of
|
||||
# files written by us and files taken from BSD.
|
||||
|
||||
kernel/
|
||||
# The kernel uapi header files. These are scrubbed copies of the originals
|
||||
# in external/kernel-headers/. These files must not be edited directly. The
|
||||
# generate_uapi_headers.sh script should be used to go from a kernel tree to
|
||||
# external/kernel-headers/ --- this takes care of the architecture-specific
|
||||
# details. The update_all.py script should be used to regenerate bionic's
|
||||
# scrubbed headers from external/kernel-headers/.
|
||||
|
||||
private/
|
||||
# These are private header files meant for use within bionic itself.
|
||||
|
||||
dns/
|
||||
# Contains the DNS resolver (originates from NetBSD code).
|
||||
|
||||
upstream-dlmalloc/
|
||||
upstream-freebsd/
|
||||
upstream-netbsd/
|
||||
upstream-openbsd/
|
||||
# These directories contain unmolested upstream source. Any time we can
|
||||
# just use a BSD implementation of something unmodified, we should.
|
||||
# The structure under these directories mimics the upstream tree,
|
||||
# but there's also...
|
||||
android/
|
||||
include/
|
||||
# This is where we keep the hacks necessary to build BSD source
|
||||
# in our world. The *-compat.h files are automatically included
|
||||
# using -include, but we also provide equivalents for missing
|
||||
# header/source files needed by the BSD implementation.
|
||||
|
||||
bionic/
|
||||
# This is the biggest mess. The C++ files are files we own, typically
|
||||
# because the Linux kernel interface is sufficiently different that we
|
||||
# can't use any of the BSD implementations. The C files are usually
|
||||
# legacy mess that needs to be sorted out, either by replacing it with
|
||||
# current upstream source in one of the upstream directories or by
|
||||
# switching the file to C++ and cleaning it up.
|
||||
|
||||
stdio/
|
||||
# These are legacy files of dubious provenance. We're working to clean
|
||||
# this mess up, and this directory should disappear.
|
||||
|
||||
tools/
|
||||
# Various tools used to maintain bionic.
|
||||
|
||||
tzcode/
|
||||
# A modified superset of the IANA tzcode. Most of the modifications relate
|
||||
# to Android's use of a single file (with corresponding index) to contain
|
||||
# time zone data.
|
||||
zoneinfo/
|
||||
# Android-format time zone data.
|
||||
# See 'Updating tzdata' later.
|
||||
|
||||
|
||||
Adding system calls
|
||||
-------------------
|
||||
|
||||
Adding a system call usually involves:
|
||||
|
||||
1. Add entries to SYSCALLS.TXT.
|
||||
See SYSCALLS.TXT itself for documentation on the format.
|
||||
2. Run the gensyscalls.py script.
|
||||
3. Add constants (and perhaps types) to the appropriate header file.
|
||||
Note that you should check to see whether the constants are already in
|
||||
kernel uapi header files, in which case you just need to make sure that
|
||||
the appropriate POSIX header file in libc/include/ includes the
|
||||
relevant file or files.
|
||||
4. Add function declarations to the appropriate header file.
|
||||
5. Add at least basic tests. Even a test that deliberately supplies
|
||||
an invalid argument helps check that we're generating the right symbol
|
||||
and have the right declaration in the header file. (And strace(1) can
|
||||
confirm that the correct system call is being made.)
|
||||
|
||||
|
||||
Updating kernel header files
|
||||
----------------------------
|
||||
|
||||
As mentioned above, this is currently a two-step process:
|
||||
|
||||
1. Use generate_uapi_headers.sh to go from a Linux source tree to appropriate
|
||||
contents for external/kernel-headers/.
|
||||
2. Run update_all.py to scrub those headers and import them into bionic.
|
||||
|
||||
|
||||
Updating tzdata
|
||||
---------------
|
||||
|
||||
This is fully automated:
|
||||
|
||||
1. Run update-tzdata.py.
|
||||
|
290
README.md
290
README.md
@ -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.
|
@ -14,55 +14,23 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
ifneq ($(BUILD_TINY_ANDROID), true)
|
||||
|
||||
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 := \
|
||||
|
||||
benchmark_c_flags = \
|
||||
-O2 \
|
||||
-Wall -Wextra -Wunused \
|
||||
-Werror \
|
||||
-fno-builtin \
|
||||
-std=gnu++11 \
|
||||
|
||||
benchmark_src_files = \
|
||||
benchmark_main.cpp \
|
||||
math_benchmark.cpp \
|
||||
property_benchmark.cpp \
|
||||
pthread_benchmark.cpp \
|
||||
@ -73,58 +41,40 @@ benchmark_src_files := \
|
||||
unistd_benchmark.cpp \
|
||||
|
||||
# Build benchmarks for the device (with bionic's .so). Run with:
|
||||
# adb shell bionic-benchmarks32
|
||||
# adb shell bionic-benchmarks64
|
||||
# adb shell bionic-benchmarks
|
||||
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_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||
LOCAL_CFLAGS += $(benchmark_c_flags)
|
||||
LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
|
||||
LOCAL_SHARED_LIBRARIES += libstlport
|
||||
LOCAL_SRC_FILES := $(benchmark_src_files)
|
||||
LOCAL_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),x86)
|
||||
LINKER = linker
|
||||
NATIVE_SUFFIX=32
|
||||
else
|
||||
LINKER = linker64
|
||||
NATIVE_SUFFIX=64
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64))
|
||||
bionic-benchmarks-run-on-host32: bionic-benchmarks bionic-prepare-run-on-host
|
||||
bionic-benchmarks-run-on-host: bionic-benchmarks $(TARGET_OUT_EXECUTABLES)/$(LINKER) $(TARGET_OUT_EXECUTABLES)/sh
|
||||
if [ ! -d /system -o ! -d /system/bin ]; then \
|
||||
echo "Attempting to create /system/bin"; \
|
||||
sudo mkdir -p -m 0777 /system/bin; \
|
||||
fi
|
||||
mkdir -p $(TARGET_OUT_DATA)/local/tmp
|
||||
cp $(TARGET_OUT_EXECUTABLES)/$(LINKER) /system/bin
|
||||
cp $(TARGET_OUT_EXECUTABLES)/sh /system/bin
|
||||
ANDROID_DATA=$(TARGET_OUT_DATA) \
|
||||
ANDROID_ROOT=$(TARGET_OUT) \
|
||||
$(TARGET_OUT_EXECUTABLES)/bionic-benchmarks32 $(BIONIC_BENCHMARKS_FLAGS)
|
||||
endif
|
||||
LD_LIBRARY_PATH=$(TARGET_OUT_SHARED_LIBRARIES) \
|
||||
$(TARGET_OUT_EXECUTABLES)/bionic-benchmarks$(NATIVE_SUFFIX) $(BIONIC_BENCHMARKS_FLAGS)
|
||||
endif # linux-x86
|
||||
|
||||
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
|
||||
endif # !BUILD_TINY_ANDROID
|
||||
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
|
||||
#include <benchmark/Benchmark.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
static uint64_t NanoTime() {
|
||||
struct timespec t;
|
||||
t.tv_sec = t.tv_nsec = 0;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
return static_cast<uint64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
|
||||
}
|
||||
|
||||
bool Benchmark::header_printed_;
|
||||
|
||||
std::vector<Benchmark*>& Benchmark::List() {
|
||||
static std::vector<Benchmark*> list;
|
||||
return list;
|
||||
}
|
||||
|
||||
int Benchmark::MaxNameColumnWidth() {
|
||||
size_t max = 20;
|
||||
for (auto& benchmark : List()) {
|
||||
max = std::max(max, benchmark->NameColumnWidth());
|
||||
}
|
||||
return static_cast<int>(max);
|
||||
}
|
||||
|
||||
size_t Benchmark::RunAll(std::vector<regex_t*>& regs) {
|
||||
size_t benchmarks_run = 0;
|
||||
header_printed_ = false;
|
||||
for (auto& benchmark : List()) {
|
||||
benchmarks_run += benchmark->RunAllArgs(regs);
|
||||
}
|
||||
return benchmarks_run;
|
||||
}
|
||||
|
||||
void Benchmark::PrintHeader() {
|
||||
if (!header_printed_) {
|
||||
printf("%-*s %10s %10s\n", MaxNameColumnWidth(), "", "iterations", "ns/op");
|
||||
header_printed_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool BenchmarkT<T>::ShouldRun(std::vector<regex_t*>& regs, T arg) {
|
||||
if (regs.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& re : regs) {
|
||||
if (regexec(re, GetNameStr(arg).c_str(), 0, NULL, 0) != REG_NOMATCH) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Benchmark::StopBenchmarkTiming() {
|
||||
if (start_time_ns_ != 0) {
|
||||
total_time_ns_ += NanoTime() - start_time_ns_;
|
||||
}
|
||||
start_time_ns_ = 0;
|
||||
}
|
||||
|
||||
void Benchmark::StartBenchmarkTiming() {
|
||||
if (start_time_ns_ == 0) {
|
||||
start_time_ns_ = NanoTime();
|
||||
}
|
||||
}
|
||||
|
||||
std::string BenchmarkWithoutArg::GetNameStr(void*) {
|
||||
return Name();
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string BenchmarkWithArg<int>::GetNameStr(int arg) {
|
||||
return Name() + "/" + PrettyInt(arg, 2);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string BenchmarkWithArg<double>::GetNameStr(double arg) {
|
||||
return Name() + "/" + android::base::StringPrintf("%0.6f", arg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void BenchmarkT<T>::RunWithArg(T arg) {
|
||||
int new_iterations = 1;
|
||||
int iterations;
|
||||
while (new_iterations < 1e8) {
|
||||
bytes_processed_ = 0;
|
||||
total_time_ns_ = 0;
|
||||
start_time_ns_ = 0;
|
||||
|
||||
iterations = new_iterations;
|
||||
RunIterations(iterations, arg);
|
||||
if (total_time_ns_ >= 1e9) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (total_time_ns_/iterations == 0) {
|
||||
new_iterations = 1e9;
|
||||
} else {
|
||||
new_iterations = 1e9/ (total_time_ns_/iterations);
|
||||
}
|
||||
new_iterations = std::max(iterations + 1,
|
||||
std::min(new_iterations + new_iterations/2, 100*iterations));
|
||||
|
||||
new_iterations = Round(new_iterations);
|
||||
}
|
||||
|
||||
printf("%-*s %10s %10" PRId64, MaxNameColumnWidth(), GetNameStr(arg).c_str(),
|
||||
PrettyInt(iterations, 10).c_str(), total_time_ns_/iterations);
|
||||
|
||||
if (total_time_ns_ > 0 && bytes_processed_ > 0) {
|
||||
double gib_processed = static_cast<double>(bytes_processed_)/1e9;
|
||||
double seconds = static_cast<double>(total_time_ns_)/1e9;
|
||||
printf(" %8.3f GiB/s", gib_processed/seconds);
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
template class BenchmarkT<int>;
|
||||
template class BenchmarkT<double>;
|
||||
template class BenchmarkT<void*>;
|
||||
|
||||
template class BenchmarkWithArg<int>;
|
||||
template class BenchmarkWithArg<double>;
|
||||
|
||||
} // namespace testing
|
61
benchmarks/benchmark.h
Normal file
61
benchmarks/benchmark.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace testing {
|
||||
|
||||
class Benchmark {
|
||||
public:
|
||||
Benchmark(const char* name, void (*fn)(int)) {
|
||||
Register(name, fn, NULL);
|
||||
}
|
||||
|
||||
Benchmark(const char* name, void (*fn_range)(int, int)) {
|
||||
Register(name, NULL, fn_range);
|
||||
}
|
||||
|
||||
Benchmark* Arg(int x);
|
||||
|
||||
const char* Name();
|
||||
|
||||
bool ShouldRun(int argc, char* argv[]);
|
||||
void Run();
|
||||
|
||||
private:
|
||||
const char* name_;
|
||||
|
||||
void (*fn_)(int);
|
||||
void (*fn_range_)(int, int);
|
||||
|
||||
std::vector<int> args_;
|
||||
|
||||
void Register(const char* name, void (*fn)(int), void (*fn_range)(int, int));
|
||||
void RunRepeatedlyWithArg(int iterations, int arg);
|
||||
void RunWithArg(int arg);
|
||||
};
|
||||
|
||||
} // namespace testing
|
||||
|
||||
void SetBenchmarkBytesProcessed(int64_t);
|
||||
void StopBenchmarkTiming();
|
||||
void StartBenchmarkTiming();
|
||||
|
||||
#define BENCHMARK(f) \
|
||||
static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = \
|
||||
(new ::testing::Benchmark(#f, f))
|
@ -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_
|
226
benchmarks/benchmark_main.cpp
Normal file
226
benchmarks/benchmark_main.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "benchmark.h"
|
||||
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
static int64_t g_bytes_processed;
|
||||
static int64_t g_benchmark_total_time_ns;
|
||||
static int64_t g_benchmark_start_time_ns;
|
||||
|
||||
typedef std::map<std::string, ::testing::Benchmark*> BenchmarkMap;
|
||||
typedef BenchmarkMap::iterator BenchmarkMapIt;
|
||||
static BenchmarkMap g_benchmarks;
|
||||
static int g_name_column_width = 20;
|
||||
|
||||
static int Round(int n) {
|
||||
int base = 1;
|
||||
while (base*10 < n) {
|
||||
base *= 10;
|
||||
}
|
||||
if (n < 2*base) {
|
||||
return 2*base;
|
||||
}
|
||||
if (n < 5*base) {
|
||||
return 5*base;
|
||||
}
|
||||
return 10*base;
|
||||
}
|
||||
|
||||
static int64_t NanoTime() {
|
||||
struct timespec t;
|
||||
t.tv_sec = t.tv_nsec = 0;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
return static_cast<int64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
|
||||
}
|
||||
|
||||
namespace testing {
|
||||
|
||||
Benchmark* Benchmark::Arg(int arg) {
|
||||
args_.push_back(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
const char* Benchmark::Name() {
|
||||
return name_;
|
||||
}
|
||||
|
||||
bool Benchmark::ShouldRun(int argc, char* argv[]) {
|
||||
if (argc == 1) {
|
||||
return true; // With no arguments, we run all benchmarks.
|
||||
}
|
||||
// Otherwise, we interpret each argument as a regular expression and
|
||||
// see if any of our benchmarks match.
|
||||
for (int i = 1; i < argc; i++) {
|
||||
regex_t re;
|
||||
if (regcomp(&re, argv[i], 0) != 0) {
|
||||
fprintf(stderr, "couldn't compile \"%s\" as a regular expression!\n", argv[i]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int match = regexec(&re, name_, 0, NULL, 0);
|
||||
regfree(&re);
|
||||
if (match != REG_NOMATCH) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Benchmark::Register(const char* name, void (*fn)(int), void (*fn_range)(int, int)) {
|
||||
name_ = name;
|
||||
fn_ = fn;
|
||||
fn_range_ = fn_range;
|
||||
|
||||
if (fn_ == NULL && fn_range_ == NULL) {
|
||||
fprintf(stderr, "%s: missing function\n", name_);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
g_benchmarks.insert(std::make_pair(name, this));
|
||||
}
|
||||
|
||||
void Benchmark::Run() {
|
||||
if (fn_ != NULL) {
|
||||
RunWithArg(0);
|
||||
} else {
|
||||
if (args_.empty()) {
|
||||
fprintf(stderr, "%s: no args!\n", name_);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for (size_t i = 0; i < args_.size(); ++i) {
|
||||
RunWithArg(args_[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Benchmark::RunRepeatedlyWithArg(int iterations, int arg) {
|
||||
g_bytes_processed = 0;
|
||||
g_benchmark_total_time_ns = 0;
|
||||
g_benchmark_start_time_ns = NanoTime();
|
||||
if (fn_ != NULL) {
|
||||
fn_(iterations);
|
||||
} else {
|
||||
fn_range_(iterations, arg);
|
||||
}
|
||||
if (g_benchmark_start_time_ns != 0) {
|
||||
g_benchmark_total_time_ns += NanoTime() - g_benchmark_start_time_ns;
|
||||
}
|
||||
}
|
||||
|
||||
void Benchmark::RunWithArg(int arg) {
|
||||
// run once in case it's expensive
|
||||
int iterations = 1;
|
||||
RunRepeatedlyWithArg(iterations, arg);
|
||||
while (g_benchmark_total_time_ns < 1e9 && iterations < 1e9) {
|
||||
int last = iterations;
|
||||
if (g_benchmark_total_time_ns/iterations == 0) {
|
||||
iterations = 1e9;
|
||||
} else {
|
||||
iterations = 1e9 / (g_benchmark_total_time_ns/iterations);
|
||||
}
|
||||
iterations = std::max(last + 1, std::min(iterations + iterations/2, 100*last));
|
||||
iterations = Round(iterations);
|
||||
RunRepeatedlyWithArg(iterations, arg);
|
||||
}
|
||||
|
||||
char throughput[100];
|
||||
throughput[0] = '\0';
|
||||
if (g_benchmark_total_time_ns > 0 && g_bytes_processed > 0) {
|
||||
double mib_processed = static_cast<double>(g_bytes_processed)/1e6;
|
||||
double seconds = static_cast<double>(g_benchmark_total_time_ns)/1e9;
|
||||
snprintf(throughput, sizeof(throughput), " %8.2f MiB/s", mib_processed/seconds);
|
||||
}
|
||||
|
||||
char full_name[100];
|
||||
if (fn_range_ != NULL) {
|
||||
if (arg >= (1<<20)) {
|
||||
snprintf(full_name, sizeof(full_name), "%s/%dM", name_, arg/(1<<20));
|
||||
} else if (arg >= (1<<10)) {
|
||||
snprintf(full_name, sizeof(full_name), "%s/%dK", name_, arg/(1<<10));
|
||||
} else {
|
||||
snprintf(full_name, sizeof(full_name), "%s/%d", name_, arg);
|
||||
}
|
||||
} else {
|
||||
snprintf(full_name, sizeof(full_name), "%s", name_);
|
||||
}
|
||||
|
||||
printf("%-*s %10d %10" PRId64 "%s\n", g_name_column_width, full_name,
|
||||
iterations, g_benchmark_total_time_ns/iterations, throughput);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
void SetBenchmarkBytesProcessed(int64_t x) {
|
||||
g_bytes_processed = x;
|
||||
}
|
||||
|
||||
void StopBenchmarkTiming() {
|
||||
if (g_benchmark_start_time_ns != 0) {
|
||||
g_benchmark_total_time_ns += NanoTime() - g_benchmark_start_time_ns;
|
||||
}
|
||||
g_benchmark_start_time_ns = 0;
|
||||
}
|
||||
|
||||
void StartBenchmarkTiming() {
|
||||
if (g_benchmark_start_time_ns == 0) {
|
||||
g_benchmark_start_time_ns = NanoTime();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (g_benchmarks.empty()) {
|
||||
fprintf(stderr, "No benchmarks registered!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (BenchmarkMapIt it = g_benchmarks.begin(); it != g_benchmarks.end(); ++it) {
|
||||
int name_width = static_cast<int>(strlen(it->second->Name()));
|
||||
g_name_column_width = std::max(g_name_column_width, name_width);
|
||||
}
|
||||
|
||||
bool need_header = true;
|
||||
for (BenchmarkMapIt it = g_benchmarks.begin(); it != g_benchmarks.end(); ++it) {
|
||||
::testing::Benchmark* b = it->second;
|
||||
if (b->ShouldRun(argc, argv)) {
|
||||
if (need_header) {
|
||||
printf("%-*s %10s %10s\n", g_name_column_width, "", "iterations", "ns/op");
|
||||
fflush(stdout);
|
||||
need_header = false;
|
||||
}
|
||||
b->Run();
|
||||
}
|
||||
}
|
||||
|
||||
if (need_header) {
|
||||
fprintf(stderr, "No matching benchmarks!\n");
|
||||
fprintf(stderr, "Available benchmarks:\n");
|
||||
for (BenchmarkMapIt it = g_benchmarks.begin(); it != g_benchmarks.end(); ++it) {
|
||||
fprintf(stderr, " %s\n", it->second->Name());
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -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;
|
||||
}
|
@ -14,20 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "benchmark.h"
|
||||
|
||||
#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;
|
||||
double d;
|
||||
double v;
|
||||
|
||||
BENCHMARK_NO_ARG(BM_math_sqrt);
|
||||
void BM_math_sqrt::Run(int iters) {
|
||||
static void BM_math_sqrt(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 0.0;
|
||||
@ -38,9 +34,9 @@ void BM_math_sqrt::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_sqrt);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_math_log10);
|
||||
void BM_math_log10::Run(int iters) {
|
||||
static void BM_math_log10(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 0.0;
|
||||
@ -51,9 +47,9 @@ void BM_math_log10::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_log10);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_math_logb);
|
||||
void BM_math_logb::Run(int iters) {
|
||||
static void BM_math_logb(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 0.0;
|
||||
@ -64,120 +60,61 @@ void BM_math_logb::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_logb);
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_math_isfinite_macro, double)->AT_COMMON_VALS;
|
||||
void BM_math_isfinite_macro::Run(int iters, double value) {
|
||||
static void BM_math_isinf_NORMAL(int iters) {
|
||||
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;
|
||||
v = 1234.0; // FP_NORMAL
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
d += (isinf)(v);
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_isinf_NORMAL);
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_math_isnan_macro, double)->AT_COMMON_VALS;
|
||||
void BM_math_isnan_macro::Run(int iters, double value) {
|
||||
static void BM_math_isinf_NAN(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 0.0;
|
||||
v = value;
|
||||
v = nan(""); // FP_NAN
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
d += isnan(v);
|
||||
d += (isinf)(v);
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_isinf_NAN);
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_math_isnan, double)->AT_COMMON_VALS;
|
||||
void BM_math_isnan::Run(int iters, double value) {
|
||||
static void BM_math_isinf_INFINITE(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 0.0;
|
||||
v = value;
|
||||
v = HUGE_VAL; // FP_INFINITE
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
d += (isnan)(v);
|
||||
d += (isinf)(v);
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_isinf_INFINITE);
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_math_isnormal_macro, double)->AT_COMMON_VALS;
|
||||
void BM_math_isnormal_macro::Run(int iters, double value) {
|
||||
static void BM_math_isinf_ZERO(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 0.0;
|
||||
v = value;
|
||||
v = 0.0; // FP_ZERO
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
d += isnormal(v);
|
||||
d += (isinf)(v);
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_isinf_ZERO);
|
||||
|
||||
#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) {
|
||||
static void BM_math_sin_fast(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 1.0;
|
||||
@ -187,9 +124,9 @@ void BM_math_sin_fast::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_sin_fast);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_math_sin_feupdateenv);
|
||||
void BM_math_sin_feupdateenv::Run(int iters) {
|
||||
static void BM_math_sin_feupdateenv(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 1.0;
|
||||
@ -203,9 +140,9 @@ void BM_math_sin_feupdateenv::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_sin_feupdateenv);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_math_sin_fesetenv);
|
||||
void BM_math_sin_fesetenv::Run(int iters) {
|
||||
static void BM_math_sin_fesetenv(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 1.0;
|
||||
@ -219,68 +156,56 @@ void BM_math_sin_fesetenv::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_sin_fesetenv);
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_math_fpclassify, double)->AT_COMMON_VALS;
|
||||
void BM_math_fpclassify::Run(int iters, double value) {
|
||||
static void BM_math_fpclassify_NORMAL(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 0.0;
|
||||
v = value;
|
||||
v = 1234.0; // FP_NORMAL
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
d += fpclassify(v);
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_fpclassify_NORMAL);
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_math_signbit_macro, double)->AT_COMMON_VALS;
|
||||
void BM_math_signbit_macro::Run(int iters, double value) {
|
||||
static void BM_math_fpclassify_NAN(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 0.0;
|
||||
v = value;
|
||||
v = nan(""); // FP_NAN
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
d += signbit(v);
|
||||
d += fpclassify(v);
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_fpclassify_NAN);
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_math_signbit, double)->AT_COMMON_VALS;
|
||||
void BM_math_signbit::Run(int iters, double value) {
|
||||
static void BM_math_fpclassify_INFINITE(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 0.0;
|
||||
v = value;
|
||||
v = HUGE_VAL; // FP_INFINITE
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
d += (__signbit)(v);
|
||||
d += fpclassify(v);
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_fpclassify_INFINITE);
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_math_fabs_macro, double)->AT_COMMON_VALS;
|
||||
void BM_math_fabs_macro::Run(int iters, double value) {
|
||||
static void BM_math_fpclassify_ZERO(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
d = 0.0;
|
||||
v = value;
|
||||
v = 0.0; // FP_ZERO
|
||||
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);
|
||||
d += fpclassify(v);
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_math_fpclassify_ZERO);
|
||||
|
@ -14,21 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "benchmark.h"
|
||||
#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>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
extern void* __system_property_area__;
|
||||
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.
|
||||
@ -36,198 +34,200 @@ extern void* __system_property_area__;
|
||||
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-_.";
|
||||
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--;
|
||||
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;
|
||||
}
|
||||
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)];
|
||||
}
|
||||
old_pa = __system_property_area__;
|
||||
__system_property_area__ = NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
valid = true;
|
||||
}
|
||||
~LocalPropertyTestState() {
|
||||
if (!valid)
|
||||
return;
|
||||
|
||||
~LocalPropertyTestState() {
|
||||
if (!valid)
|
||||
return;
|
||||
__system_property_area__ = old_pa;
|
||||
|
||||
__system_property_area__ = old_pa;
|
||||
__system_property_set_filename(PROP_FILENAME);
|
||||
unlink(pa_filename.c_str());
|
||||
rmdir(pa_dirname.c_str());
|
||||
|
||||
__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];
|
||||
for (int i = 0; i < nprops; i++) {
|
||||
delete names[i];
|
||||
delete values[i];
|
||||
}
|
||||
delete[] names;
|
||||
delete[] name_lens;
|
||||
delete[] values;
|
||||
delete[] value_lens;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
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();
|
||||
static void BM_property_get(int iters, int nprops)
|
||||
{
|
||||
StopBenchmarkTiming();
|
||||
|
||||
LocalPropertyTestState pa(nprops);
|
||||
char value[PROP_VALUE_MAX];
|
||||
LocalPropertyTestState pa(nprops);
|
||||
char value[PROP_VALUE_MAX];
|
||||
|
||||
if (!pa.valid)
|
||||
return;
|
||||
if (!pa.valid)
|
||||
return;
|
||||
|
||||
srandom(iters * nprops);
|
||||
srandom(iters * nprops);
|
||||
|
||||
StartBenchmarkTiming();
|
||||
StartBenchmarkTiming();
|
||||
|
||||
for (int i = 0; i < iters; i++) {
|
||||
__system_property_get(pa.names[random() % nprops], value);
|
||||
}
|
||||
StopBenchmarkTiming();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
__system_property_get(pa.names[random() % nprops], value);
|
||||
}
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_property_get)->TEST_NUM_PROPS;
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_property_find, int)->TEST_NUM_PROPS;
|
||||
void BM_property_find::Run(int iters, int nprops) {
|
||||
StopBenchmarkTiming();
|
||||
static void BM_property_find(int iters, int nprops)
|
||||
{
|
||||
StopBenchmarkTiming();
|
||||
|
||||
LocalPropertyTestState pa(nprops);
|
||||
LocalPropertyTestState pa(nprops);
|
||||
|
||||
if (!pa.valid)
|
||||
return;
|
||||
if (!pa.valid)
|
||||
return;
|
||||
|
||||
srandom(iters * nprops);
|
||||
srandom(iters * nprops);
|
||||
|
||||
StartBenchmarkTiming();
|
||||
StartBenchmarkTiming();
|
||||
|
||||
for (int i = 0; i < iters; i++) {
|
||||
__system_property_find(pa.names[random() % nprops]);
|
||||
}
|
||||
StopBenchmarkTiming();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
__system_property_find(pa.names[random() % nprops]);
|
||||
}
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_property_find)->TEST_NUM_PROPS;
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_property_read, int)->TEST_NUM_PROPS;
|
||||
void BM_property_read::Run(int iters, int nprops) {
|
||||
StopBenchmarkTiming();
|
||||
static void BM_property_read(int iters, int nprops)
|
||||
{
|
||||
StopBenchmarkTiming();
|
||||
|
||||
LocalPropertyTestState pa(nprops);
|
||||
LocalPropertyTestState pa(nprops);
|
||||
|
||||
if (!pa.valid)
|
||||
return;
|
||||
if (!pa.valid)
|
||||
return;
|
||||
|
||||
srandom(iters * nprops);
|
||||
const prop_info** pinfo = new const prop_info*[iters];
|
||||
char propvalue[PROP_VALUE_MAX];
|
||||
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]);
|
||||
}
|
||||
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();
|
||||
StartBenchmarkTiming();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
__system_property_read(pinfo[i], 0, propvalue);
|
||||
}
|
||||
StopBenchmarkTiming();
|
||||
|
||||
delete[] pinfo;
|
||||
delete[] pinfo;
|
||||
}
|
||||
BENCHMARK(BM_property_read)->TEST_NUM_PROPS;
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_property_serial, int)->TEST_NUM_PROPS;
|
||||
void BM_property_serial::Run(int iters, int nprops) {
|
||||
StopBenchmarkTiming();
|
||||
static void BM_property_serial(int iters, int nprops)
|
||||
{
|
||||
StopBenchmarkTiming();
|
||||
|
||||
LocalPropertyTestState pa(nprops);
|
||||
LocalPropertyTestState pa(nprops);
|
||||
|
||||
if (!pa.valid)
|
||||
return;
|
||||
if (!pa.valid)
|
||||
return;
|
||||
|
||||
srandom(iters * nprops);
|
||||
const prop_info** pinfo = new const prop_info*[iters];
|
||||
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]);
|
||||
}
|
||||
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();
|
||||
StartBenchmarkTiming();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
__system_property_serial(pinfo[i]);
|
||||
}
|
||||
StopBenchmarkTiming();
|
||||
|
||||
delete[] pinfo;
|
||||
delete[] pinfo;
|
||||
}
|
||||
|
||||
#endif // __BIONIC__
|
||||
BENCHMARK(BM_property_serial)->TEST_NUM_PROPS;
|
||||
|
@ -14,15 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include "benchmark.h"
|
||||
|
||||
#include <benchmark/Benchmark.h>
|
||||
#include <pthread.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) {
|
||||
static void BM_pthread_self(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
@ -31,9 +30,9 @@ void BM_pthread_self::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_pthread_self);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_pthread_getspecific);
|
||||
void BM_pthread_getspecific::Run(int iters) {
|
||||
static void BM_pthread_getspecific(int iters) {
|
||||
StopBenchmarkTiming();
|
||||
pthread_key_t key;
|
||||
pthread_key_create(&key, NULL);
|
||||
@ -46,27 +45,12 @@ void BM_pthread_getspecific::Run(int iters) {
|
||||
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);
|
||||
}
|
||||
BENCHMARK(BM_pthread_getspecific);
|
||||
|
||||
static void DummyPthreadOnceInitFunction() {
|
||||
}
|
||||
|
||||
BENCHMARK_NO_ARG(BM_pthread_once);
|
||||
void BM_pthread_once::Run(int iters) {
|
||||
static void BM_pthread_once(int iters) {
|
||||
StopBenchmarkTiming();
|
||||
pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
pthread_once(&once, DummyPthreadOnceInitFunction);
|
||||
@ -78,9 +62,9 @@ void BM_pthread_once::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_pthread_once);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_pthread_mutex_lock);
|
||||
void BM_pthread_mutex_lock::Run(int iters) {
|
||||
static void BM_pthread_mutex_lock(int iters) {
|
||||
StopBenchmarkTiming();
|
||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
StartBenchmarkTiming();
|
||||
@ -92,11 +76,11 @@ void BM_pthread_mutex_lock::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_pthread_mutex_lock);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_pthread_mutex_lock_ERRORCHECK);
|
||||
void BM_pthread_mutex_lock_ERRORCHECK::Run(int iters) {
|
||||
static void BM_pthread_mutex_lock_ERRORCHECK(int iters) {
|
||||
StopBenchmarkTiming();
|
||||
pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
|
||||
pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER;
|
||||
StartBenchmarkTiming();
|
||||
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
@ -106,11 +90,11 @@ void BM_pthread_mutex_lock_ERRORCHECK::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_pthread_mutex_lock_ERRORCHECK);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_pthread_mutex_lock_RECURSIVE);
|
||||
void BM_pthread_mutex_lock_RECURSIVE::Run(int iters) {
|
||||
static void BM_pthread_mutex_lock_RECURSIVE(int iters) {
|
||||
StopBenchmarkTiming();
|
||||
pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
|
||||
StartBenchmarkTiming();
|
||||
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
@ -120,114 +104,4 @@ void BM_pthread_mutex_lock_RECURSIVE::Run(int iters) {
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_pthread_mutex_lock_RECURSIVE);
|
||||
|
@ -14,15 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include "benchmark.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) {
|
||||
static void BM_semaphore_sem_getvalue(int iters) {
|
||||
StopBenchmarkTiming();
|
||||
sem_t semaphore;
|
||||
sem_init(&semaphore, 1, 1);
|
||||
@ -35,9 +31,9 @@ void BM_semaphore_sem_getvalue::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_semaphore_sem_getvalue);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_semaphore_sem_wait_sem_post);
|
||||
void BM_semaphore_sem_wait_sem_post::Run(int iters) {
|
||||
static void BM_semaphore_sem_wait_sem_post(int iters) {
|
||||
StopBenchmarkTiming();
|
||||
sem_t semaphore;
|
||||
sem_init(&semaphore, 1, 1);
|
||||
@ -50,94 +46,4 @@ void BM_semaphore_sem_wait_sem_post::Run(int iters) {
|
||||
|
||||
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, ¶m);
|
||||
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, ¶m);
|
||||
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, ¶m);
|
||||
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, ¶m);
|
||||
StartBenchmarkTiming();
|
||||
sem_post(&semaphore);
|
||||
StopBenchmarkTiming(); // Remember to subtract clock syscall overhead
|
||||
param.sched_priority = 0;
|
||||
sched_setscheduler((pid_t)0, SCHED_IDLE, ¶m);
|
||||
}
|
||||
sched_setscheduler((pid_t)0, SCHED_OTHER, ¶m);
|
||||
|
||||
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);
|
||||
}
|
||||
BENCHMARK(BM_semaphore_sem_wait_sem_post);
|
||||
|
@ -14,11 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdio_ext.h>
|
||||
#include <stdlib.h>
|
||||
#include "benchmark.h"
|
||||
|
||||
#include <benchmark/Benchmark.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define KB 1024
|
||||
#define MB 1024*KB
|
||||
@ -27,68 +25,37 @@
|
||||
Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(8)->Arg(16)->Arg(32)->Arg(64)->Arg(512)-> \
|
||||
Arg(1*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();
|
||||
static void BM_stdio_fread(int iters, int chunk_size) {
|
||||
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);
|
||||
}
|
||||
StartBenchmarkTiming();
|
||||
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
f(buf, chunk_size, 1, fp);
|
||||
fread(buf, chunk_size, 1, fp);
|
||||
}
|
||||
|
||||
benchmark->StopBenchmarkTiming();
|
||||
benchmark->SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(chunk_size));
|
||||
StopBenchmarkTiming();
|
||||
SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(chunk_size));
|
||||
delete[] buf;
|
||||
fclose(fp);
|
||||
}
|
||||
BENCHMARK(BM_stdio_fread)->AT_COMMON_SIZES;
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_stdio_fread, int)->AT_COMMON_SIZES;
|
||||
void BM_stdio_fread::Run(int iters, int chunk_size) {
|
||||
ReadWriteTest(this, iters, chunk_size, fread, true);
|
||||
}
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_stdio_fwrite, int)->AT_COMMON_SIZES;
|
||||
void BM_stdio_fwrite::Run(int iters, int chunk_size) {
|
||||
ReadWriteTest(this, iters, chunk_size, fwrite, true);
|
||||
}
|
||||
static void BM_stdio_fwrite(int iters, int chunk_size) {
|
||||
StopBenchmarkTiming();
|
||||
FILE* fp = fopen("/dev/zero", "rw");
|
||||
char* buf = new char[chunk_size];
|
||||
StartBenchmarkTiming();
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_stdio_fread_unbuffered, int)->AT_COMMON_SIZES;
|
||||
void BM_stdio_fread_unbuffered::Run(int iters, int chunk_size) {
|
||||
ReadWriteTest(this, iters, chunk_size, fread, false);
|
||||
}
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_stdio_fwrite_unbuffered, int)->AT_COMMON_SIZES;
|
||||
void BM_stdio_fwrite_unbuffered::Run(int iters, int chunk_size) {
|
||||
ReadWriteTest(this, iters, chunk_size, fwrite, false);
|
||||
}
|
||||
|
||||
static void FopenFgetsFclose(int iters, bool no_locking) {
|
||||
char buf[1024];
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
FILE* fp = fopen("/proc/version", "re");
|
||||
if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER);
|
||||
if (fgets(buf, sizeof(buf), fp) == nullptr) abort();
|
||||
fclose(fp);
|
||||
fwrite(buf, chunk_size, 1, 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();
|
||||
SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(chunk_size));
|
||||
delete[] buf;
|
||||
fclose(fp);
|
||||
}
|
||||
BENCHMARK(BM_stdio_fwrite)->AT_COMMON_SIZES;
|
||||
|
@ -14,10 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "benchmark.h"
|
||||
|
||||
#include <benchmark/Benchmark.h>
|
||||
#include <string.h>
|
||||
|
||||
#define KB 1024
|
||||
#define MB 1024*KB
|
||||
@ -27,8 +26,7 @@
|
||||
|
||||
// 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) {
|
||||
static void BM_string_memcmp(int iters, int nbytes) {
|
||||
StopBenchmarkTiming();
|
||||
char* src = new char[nbytes]; char* dst = new char[nbytes];
|
||||
memset(src, 'x', nbytes);
|
||||
@ -41,13 +39,13 @@ void BM_string_memcmp::Run(int iters, int nbytes) {
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes));
|
||||
SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
|
||||
delete[] src;
|
||||
delete[] dst;
|
||||
}
|
||||
BENCHMARK(BM_string_memcmp)->AT_COMMON_SIZES;
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_string_memcpy, int)->AT_COMMON_SIZES;
|
||||
void BM_string_memcpy::Run(int iters, int nbytes) {
|
||||
static void BM_string_memcpy(int iters, int nbytes) {
|
||||
StopBenchmarkTiming();
|
||||
char* src = new char[nbytes]; char* dst = new char[nbytes];
|
||||
memset(src, 'x', nbytes);
|
||||
@ -58,13 +56,13 @@ void BM_string_memcpy::Run(int iters, int nbytes) {
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes));
|
||||
SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
|
||||
delete[] src;
|
||||
delete[] dst;
|
||||
}
|
||||
BENCHMARK(BM_string_memcpy)->AT_COMMON_SIZES;
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_string_memmove, int)->AT_COMMON_SIZES;
|
||||
void BM_string_memmove::Run(int iters, int nbytes) {
|
||||
static void BM_string_memmove(int iters, int nbytes) {
|
||||
StopBenchmarkTiming();
|
||||
char* buf = new char[nbytes + 64];
|
||||
memset(buf, 'x', nbytes + 64);
|
||||
@ -75,12 +73,12 @@ void BM_string_memmove::Run(int iters, int nbytes) {
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes));
|
||||
SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
|
||||
delete[] buf;
|
||||
}
|
||||
BENCHMARK(BM_string_memmove)->AT_COMMON_SIZES;
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_string_memset, int)->AT_COMMON_SIZES;
|
||||
void BM_string_memset::Run(int iters, int nbytes) {
|
||||
static void BM_string_memset(int iters, int nbytes) {
|
||||
StopBenchmarkTiming();
|
||||
char* dst = new char[nbytes];
|
||||
StartBenchmarkTiming();
|
||||
@ -90,12 +88,12 @@ void BM_string_memset::Run(int iters, int nbytes) {
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes));
|
||||
SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
|
||||
delete[] dst;
|
||||
}
|
||||
BENCHMARK(BM_string_memset)->AT_COMMON_SIZES;
|
||||
|
||||
BENCHMARK_WITH_ARG(BM_string_strlen, int)->AT_COMMON_SIZES;
|
||||
void BM_string_strlen::Run(int iters, int nbytes) {
|
||||
static void BM_string_strlen(int iters, int nbytes) {
|
||||
StopBenchmarkTiming();
|
||||
char* s = new char[nbytes];
|
||||
memset(s, 'x', nbytes);
|
||||
@ -108,6 +106,7 @@ void BM_string_strlen::Run(int iters, int nbytes) {
|
||||
}
|
||||
|
||||
StopBenchmarkTiming();
|
||||
SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes));
|
||||
SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
|
||||
delete[] s;
|
||||
}
|
||||
BENCHMARK(BM_string_strlen)->AT_COMMON_SIZES;
|
||||
|
@ -14,15 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "benchmark.h"
|
||||
|
||||
#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) {
|
||||
static void BM_time_clock_gettime(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
timespec t;
|
||||
@ -32,9 +29,9 @@ void BM_time_clock_gettime::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_time_clock_gettime);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_time_clock_gettime_syscall);
|
||||
void BM_time_clock_gettime_syscall::Run(int iters) {
|
||||
static void BM_time_clock_gettime_syscall(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
timespec t;
|
||||
@ -44,9 +41,9 @@ void BM_time_clock_gettime_syscall::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_time_clock_gettime_syscall);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_time_gettimeofday);
|
||||
void BM_time_gettimeofday::Run(int iters) {
|
||||
static void BM_time_gettimeofday(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
timeval tv;
|
||||
@ -56,9 +53,9 @@ void BM_time_gettimeofday::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_time_gettimeofday);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_time_gettimeofday_syscall);
|
||||
void BM_time_gettimeofday_syscall::Run(int iters) {
|
||||
static void BM_time_gettimeofday_syscall(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
timeval tv;
|
||||
@ -68,9 +65,9 @@ void BM_time_gettimeofday_syscall::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_time_gettimeofday_syscall);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_time_time);
|
||||
void BM_time_time::Run(int iters) {
|
||||
static void BM_time_time(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
@ -79,3 +76,4 @@ void BM_time_time::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_time_time);
|
||||
|
@ -14,13 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "benchmark.h"
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <benchmark/Benchmark.h>
|
||||
|
||||
BENCHMARK_NO_ARG(BM_unistd_getpid);
|
||||
void BM_unistd_getpid::Run(int iters) {
|
||||
static void BM_unistd_getpid(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
@ -29,9 +28,9 @@ void BM_unistd_getpid::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_unistd_getpid);
|
||||
|
||||
BENCHMARK_NO_ARG(BM_unistd_getpid_syscall);
|
||||
void BM_unistd_getpid_syscall::Run(int iters) {
|
||||
static void BM_unistd_getpid_syscall(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
@ -40,14 +39,12 @@ void BM_unistd_getpid_syscall::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
|
||||
#if defined(__BIONIC__)
|
||||
BENCHMARK(BM_unistd_getpid_syscall);
|
||||
|
||||
// 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) {
|
||||
static void BM_unistd_gettid(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
@ -56,11 +53,9 @@ void BM_unistd_gettid::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_unistd_gettid);
|
||||
|
||||
#endif
|
||||
|
||||
BENCHMARK_NO_ARG(BM_unistd_gettid_syscall);
|
||||
void BM_unistd_gettid_syscall::Run(int iters) {
|
||||
static void BM_unistd_gettid_syscall(int iters) {
|
||||
StartBenchmarkTiming();
|
||||
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
@ -69,3 +64,4 @@ void BM_unistd_gettid_syscall::Run(int iters) {
|
||||
|
||||
StopBenchmarkTiming();
|
||||
}
|
||||
BENCHMARK(BM_unistd_gettid_syscall);
|
||||
|
@ -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]);
|
||||
}
|
@ -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
|
2160
libc/Android.bp
2160
libc/Android.bp
File diff suppressed because it is too large
Load Diff
757
libc/Android.mk
757
libc/Android.mk
File diff suppressed because it is too large
Load Diff
572
libc/NOTICE
572
libc/NOTICE
@ -307,6 +307,50 @@ SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2008-2010 The Android Open Source Project
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2009 The Android Open Source Project
|
||||
All rights reserved.
|
||||
|
||||
@ -410,6 +454,22 @@ Android adaptation and tweak by Jim Huang <jserv@0xlab.org>.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2011 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2011 The Android Open Source Project
|
||||
All rights reserved.
|
||||
|
||||
@ -628,50 +688,6 @@ SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1980, 1983, 1988, 1993
|
||||
The Regents of the University of California. All rights reserved.
|
||||
|
||||
@ -1663,6 +1679,35 @@ SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1990 Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the University nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1990 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
@ -2465,6 +2510,35 @@ SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1993
|
||||
The Regents of the University of California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the University nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1993
|
||||
The Regents of the University of California. All rights reserved.
|
||||
|
||||
@ -2494,6 +2568,33 @@ SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1993 Christopher G. Demetriou
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1993 Martin Birgmeier
|
||||
All rights reserved.
|
||||
|
||||
@ -2534,6 +2635,33 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1995, 1996 Carnegie-Mellon University.
|
||||
All rights reserved.
|
||||
|
||||
Author: Chris G. Demetriou
|
||||
|
||||
Permission to use, copy, modify and distribute this software and
|
||||
its documentation is hereby granted, provided that both the copyright
|
||||
notice and this permission notice appear in all copies of the
|
||||
software, derivative works or modified versions, and any portions
|
||||
thereof, and that both notices appear in supporting documentation.
|
||||
|
||||
CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
|
||||
CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
|
||||
FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
|
||||
Carnegie Mellon requests users of this software to return to
|
||||
|
||||
Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
||||
School of Computer Science
|
||||
Carnegie Mellon University
|
||||
Pittsburgh PA 15213-3890
|
||||
|
||||
any improvements or extensions that they make and grant Carnegie the
|
||||
rights to redistribute these changes.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1996 by Internet Software Consortium.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
@ -2586,6 +2714,63 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1996-2004 Per Fogelstrom, Opsycon AB
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1997 Mark Brinicombe
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. All advertising materials mentioning features or use of this software
|
||||
must display the following acknowledgement:
|
||||
This product includes software developed by Mark Brinicombe
|
||||
4. Neither the name of the University nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1997 Mark Brinicombe
|
||||
Copyright (c) 2010 Android Open Source Project.
|
||||
All rights reserved.
|
||||
@ -2946,6 +3131,38 @@ SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1999 Kungliga Tekniska Högskolan
|
||||
(Royal Institute of Technology, Stockholm, Sweden).
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of KTH nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2000 Ben Harris.
|
||||
Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
All rights reserved.
|
||||
@ -3209,6 +3426,34 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2002 Opsycon AB (www.opsycon.se / www.opsycon.com)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of Opsycon AB nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2002 The NetBSD Foundation, Inc.
|
||||
All rights reserved.
|
||||
|
||||
@ -3752,22 +3997,6 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007-2008 Michael G Schwern
|
||||
|
||||
This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
|
||||
@ -3857,22 +4086,6 @@ SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2008 Todd C. Miller <millert@openbsd.org>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
@ -3905,6 +4118,35 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2009
|
||||
MIPS Technologies, Inc., California.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the MIPS Technologies, Inc., nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2009 David Schultz <das@FreeBSD.org>
|
||||
All rights reserved.
|
||||
|
||||
@ -4180,39 +4422,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
|
||||
Copyright (c) 2009 Ted Unangst
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2011 The Android Open Source Project
|
||||
Copyright (c) 2008 ARM Ltd
|
||||
All rights reserved.
|
||||
@ -4386,64 +4595,6 @@ Copyright (c) 2012, Linaro Limited
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2012-2015
|
||||
MIPS Technologies, Inc., California.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the MIPS Technologies, Inc., nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2013
|
||||
MIPS Technologies, Inc., California.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the MIPS Technologies, Inc., nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2013 ARM Ltd
|
||||
All rights reserved.
|
||||
|
||||
@ -4488,61 +4639,35 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2013 The NetBSD Foundation, Inc.
|
||||
All rights reserved.
|
||||
Copyright (c) 2013, Linaro Limited
|
||||
All rights reserved.
|
||||
|
||||
This code is derived from software contributed to The NetBSD Foundation
|
||||
by Christos Zoulas.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
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.
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
* 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.
|
||||
|
||||
Copyright (c) 2014
|
||||
Imagination Technologies Limited.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the MIPS Technologies, Inc., nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IMAGINATION TECHNOLOGIES LIMITED ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL IMAGINATION TECHNOLOGIES LIMITED BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
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.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
@ -4728,20 +4853,9 @@ SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
|
||||
Copyright 2008 Damien Miller <djm@openbsd.org>
|
||||
Copyright 2000 David E. O'Brien, John D. Polstra.
|
||||
All rights reserved.
|
||||
|
||||
Theo de Raadt <deraadt@openbsd.org> came up with the idea of using
|
||||
such a mathematical system to generate more random (yet non-repeating)
|
||||
ids to solve the resolver/named problem. But Niels designed the
|
||||
actual system based on the constraints.
|
||||
|
||||
Later modified by Damien Miller to wrap the LCG output in a 15-bit
|
||||
permutation generator based on a Luby-Rackoff block cipher. This
|
||||
ensures the output is non-repeating and preserves the MSB twiddle
|
||||
trick, but makes it more resistant to LCG prediction.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
@ -77,6 +77,7 @@ int prlimit64(pid_t, int, struct rlimit64*, const struct rlimit64*) arm,mips,x8
|
||||
int setgroups:setgroups32(int, const gid_t*) arm,x86
|
||||
int setgroups:setgroups(int, const gid_t*) arm64,mips,mips64,x86_64
|
||||
int setpgid(pid_t, pid_t) all
|
||||
pid_t vfork(void) arm
|
||||
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
|
||||
@ -94,23 +95,13 @@ ssize_t pread64(int, void*, size_t, off64_t) arm,mips,x86
|
||||
ssize_t pread64|pread(int, void*, size_t, off_t) arm64,mips64,x86_64
|
||||
ssize_t 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
|
||||
int 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
|
||||
void* mremap(void*, size_t, size_t, unsigned long) 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 madvise(const 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
|
||||
@ -122,7 +113,7 @@ 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 fchmod(int, mode_t) all
|
||||
int dup(int) all
|
||||
int pipe2(int*, int) all
|
||||
int dup3(int, int, int) all
|
||||
@ -131,19 +122,19 @@ int fdatasync(int) all
|
||||
int fchown:fchown32(int, uid_t, gid_t) arm,x86
|
||||
int fchown: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 fsetxattr(int, const char*, const void*, size_t, int) all
|
||||
ssize_t fgetxattr(int, const char*, void*, size_t) all
|
||||
ssize_t 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 faccessat(int, const char*, int, int) all
|
||||
int fchmodat(int, const char*, mode_t, int) all
|
||||
int fchownat(int, const char*, uid_t, gid_t, int) all
|
||||
int fstatat64|fstatat:fstatat64(int, const char*, struct stat*, int) arm,mips,x86
|
||||
int fstatat64|fstatat:newfstatat(int, const char*, struct stat*, int) arm64,x86_64
|
||||
int fstatat64|fstatat:newfstatat(int, const char*, struct stat*, int) arm64,mips64,x86_64
|
||||
int linkat(int, const char*, int, const char*, int) all
|
||||
int mkdirat(int, const char*, mode_t) all
|
||||
int mknodat(int, const char*, mode_t, dev_t) all
|
||||
@ -160,6 +151,7 @@ int utimensat(int, const char*, const struct timespec times[2], int) all
|
||||
off_t lseek(int, off_t, int) arm,mips,x86
|
||||
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 ftruncate(int, off_t) arm,mips,x86
|
||||
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
|
||||
@ -182,12 +174,12 @@ int __fadvise64:fadvise64_64(int, off64_t, off64_t, int) x86
|
||||
int __fadvise64:fadvise64(int, off64_t, off64_t, int) arm64,mips,mips64,x86_64
|
||||
|
||||
int __fstatfs64:fstatfs64(int, size_t, struct statfs*) arm,mips,x86
|
||||
int __fstatfs:fstatfs(int, struct statfs*) arm64,mips64,x86_64
|
||||
int fstatfs64|fstatfs:fstatfs(int, struct statfs*) arm64,mips64,x86_64
|
||||
int __statfs64:statfs64(const char*, size_t, struct statfs*) arm,mips,x86
|
||||
int __statfs:statfs(const char*, struct statfs*) arm64,mips64,x86_64
|
||||
int statfs64|statfs:statfs(const char*, struct statfs*) arm64,mips64,x86_64
|
||||
|
||||
int fstat64|fstat:fstat64(int, struct stat*) arm,mips,x86
|
||||
int fstat64|fstat:fstat(int, struct stat*) arm64,x86_64
|
||||
int fstat64|fstat:fstat(int, struct stat*) arm64,mips64,x86_64
|
||||
|
||||
# file system
|
||||
int chdir(const char*) all
|
||||
@ -210,9 +202,9 @@ int swapoff(const char*) all
|
||||
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 clock_settime(clockid_t clk_id, const struct timespec* tp) all
|
||||
int clock_getres(clockid_t clk_id, struct timespec* res) all
|
||||
int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec* req, struct timespec* rem) all
|
||||
int getitimer(int, const struct itimerval*) all
|
||||
int setitimer(int, const struct itimerval*, struct itimerval*) all
|
||||
int __timer_create:timer_create(clockid_t clockid, struct sigevent* evp, __kernel_timer_t* timerid) all
|
||||
@ -231,7 +223,6 @@ int __rt_sigpending:rt_sigpending(sigset_t*, size_t) all
|
||||
int __rt_sigprocmask:rt_sigprocmask(int, const sigset_t*, sigset_t*, size_t) all
|
||||
int __rt_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
|
||||
|
||||
# sockets
|
||||
@ -317,16 +308,11 @@ int inotify_rm_watch(int, unsigned int) all
|
||||
int __pselect6:pselect6(int, fd_set*, fd_set*, fd_set*, timespec*, void*) all
|
||||
int __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
|
||||
|
||||
@ -335,14 +321,14 @@ int __set_tls:__ARM_NR_set_tls(void*) arm
|
||||
int cacheflush:__ARM_NR_cacheflush(long start, long end, long flags) arm
|
||||
|
||||
# MIPS-specific
|
||||
int _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips
|
||||
int _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips,mips64
|
||||
int __set_tls:set_thread_area(void*) mips,mips64
|
||||
|
||||
# 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 clock_gettime(clockid_t, timespec*) arm,mips,mips64,x86
|
||||
int __clock_gettime:clock_gettime(clockid_t, timespec*) arm64,x86_64
|
||||
int gettimeofday(timeval*, timezone*) arm,mips,mips64,x86
|
||||
int __gettimeofday:gettimeofday(timeval*, timezone*) arm64,x86_64
|
||||
|
@ -1,19 +1,52 @@
|
||||
# 32-bit arm.
|
||||
|
||||
#
|
||||
# Various kinds of LP32 cruft.
|
||||
#
|
||||
|
||||
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 \
|
||||
bionic/mmap.cpp \
|
||||
|
||||
libc_bionic_src_files_exclude_arm += \
|
||||
bionic/__memcpy_chk.cpp \
|
||||
bionic/__memset_chk.cpp \
|
||||
libc_common_src_files_arm += \
|
||||
bionic/legacy_32_bit_support.cpp \
|
||||
bionic/ndk_cruft.cpp \
|
||||
bionic/time64.c \
|
||||
|
||||
libc_openbsd_src_files_exclude_arm += \
|
||||
upstream-openbsd/lib/libc/string/strcpy.c \
|
||||
libc_netbsd_src_files_arm += \
|
||||
upstream-netbsd/common/lib/libc/hash/sha1/sha1.c \
|
||||
|
||||
libc_openbsd_src_files_arm += \
|
||||
upstream-openbsd/lib/libc/stdio/putw.c \
|
||||
|
||||
#
|
||||
# Default implementations of functions that are commonly optimized.
|
||||
#
|
||||
|
||||
libc_bionic_src_files_arm += \
|
||||
bionic/memchr.c \
|
||||
bionic/memrchr.c \
|
||||
bionic/strchr.cpp \
|
||||
bionic/strnlen.c \
|
||||
bionic/strrchr.cpp \
|
||||
|
||||
libc_freebsd_src_files_arm += \
|
||||
upstream-freebsd/lib/libc/string/wcscat.c \
|
||||
upstream-freebsd/lib/libc/string/wcschr.c \
|
||||
upstream-freebsd/lib/libc/string/wcscmp.c \
|
||||
upstream-freebsd/lib/libc/string/wcscpy.c \
|
||||
upstream-freebsd/lib/libc/string/wcslen.c \
|
||||
upstream-freebsd/lib/libc/string/wcsrchr.c \
|
||||
upstream-freebsd/lib/libc/string/wmemcmp.c \
|
||||
upstream-freebsd/lib/libc/string/wmemmove.c \
|
||||
|
||||
libc_openbsd_src_files_arm += \
|
||||
upstream-openbsd/lib/libc/string/bcopy.c \
|
||||
upstream-openbsd/lib/libc/string/stpncpy.c \
|
||||
upstream-openbsd/lib/libc/string/strlcat.c \
|
||||
upstream-openbsd/lib/libc/string/strlcpy.c \
|
||||
upstream-openbsd/lib/libc/string/strncat.c \
|
||||
upstream-openbsd/lib/libc/string/strncmp.c \
|
||||
upstream-openbsd/lib/libc/string/strncpy.c \
|
||||
|
||||
#
|
||||
# Inherently architecture-specific code.
|
||||
@ -25,11 +58,12 @@ libc_bionic_src_files_arm += \
|
||||
arch-arm/bionic/__bionic_clone.S \
|
||||
arch-arm/bionic/_exit_with_stack_teardown.S \
|
||||
arch-arm/bionic/libgcc_compat.c \
|
||||
arch-arm/bionic/popcount_tab.c \
|
||||
arch-arm/bionic/memcmp.S \
|
||||
arch-arm/bionic/__restore.S \
|
||||
arch-arm/bionic/_setjmp.S \
|
||||
arch-arm/bionic/setjmp.S \
|
||||
arch-arm/bionic/sigsetjmp.S \
|
||||
arch-arm/bionic/syscall.S \
|
||||
arch-arm/bionic/vfork.S \
|
||||
|
||||
libc_arch_static_src_files_arm := arch-arm/bionic/exidx_static.c
|
||||
libc_arch_dynamic_src_files_arm := arch-arm/bionic/exidx_dynamic.c
|
||||
@ -38,7 +72,6 @@ libc_arch_dynamic_src_files_arm := arch-arm/bionic/exidx_dynamic.c
|
||||
ifeq ($(strip $(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT)),)
|
||||
$(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.")
|
||||
@ -47,7 +80,6 @@ include $(cpu_variant_mk)
|
||||
libc_common_additional_dependencies += $(cpu_variant_mk)
|
||||
|
||||
cpu_variant_mk :=
|
||||
endif
|
||||
|
||||
|
||||
libc_crt_target_cflags_arm := \
|
||||
|
@ -39,9 +39,6 @@
|
||||
|
||||
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.
|
||||
@ -50,63 +47,35 @@ extern int __cxa_atexit(void (*)(void*), void*, void*);
|
||||
* 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_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) {
|
||||
__aeabi_atexit(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) {
|
||||
void __aeabi_memcpy8(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) {
|
||||
void __aeabi_memcpy4(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) {
|
||||
void __aeabi_memcpy(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) {
|
||||
void __aeabi_memmove8(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) {
|
||||
void __aeabi_memmove4(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) {
|
||||
void __aeabi_memmove(void *dest, const void *src, size_t n) {
|
||||
memmove(dest, src, n);
|
||||
}
|
||||
|
||||
@ -115,71 +84,27 @@ void __attribute__((weak)) __aeabi_memmove_impl2(void *dest, const void *src, si
|
||||
* This allows __aeabi_memclr to tail-call __aeabi_memset
|
||||
*/
|
||||
|
||||
void __attribute__((weak)) __aeabi_memset8_impl(void *dest, size_t n, int c) {
|
||||
void __aeabi_memset8(void *dest, size_t n, int c) {
|
||||
memset(dest, c, n);
|
||||
}
|
||||
|
||||
void __attribute__((weak)) __aeabi_memset4_impl(void *dest, size_t n, int c) {
|
||||
void __aeabi_memset4(void *dest, size_t n, int c) {
|
||||
memset(dest, c, n);
|
||||
}
|
||||
|
||||
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) {
|
||||
void __aeabi_memset(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 __aeabi_memclr8(void *dest, size_t n) {
|
||||
__aeabi_memset8(dest, n, 0);
|
||||
}
|
||||
|
||||
void __attribute__((weak)) __aeabi_memclr4_impl(void *dest, size_t n) {
|
||||
__aeabi_memset4_impl(dest, n, 0);
|
||||
void __aeabi_memclr4(void *dest, size_t n) {
|
||||
__aeabi_memset4(dest, n, 0);
|
||||
}
|
||||
|
||||
void __attribute__((weak)) __aeabi_memclr_impl(void *dest, size_t n) {
|
||||
__aeabi_memset_impl(dest, n, 0);
|
||||
void __aeabi_memclr(void *dest, size_t n) {
|
||||
__aeabi_memset(dest, n, 0);
|
||||
}
|
||||
|
||||
void __attribute__((weak)) __aeabi_memclr8_impl2(void *dest, size_t n) {
|
||||
__aeabi_memset8_impl(dest, n, 0);
|
||||
}
|
||||
|
||||
void __attribute__((weak)) __aeabi_memclr4_impl2(void *dest, size_t n) {
|
||||
__aeabi_memset4_impl(dest, n, 0);
|
||||
}
|
||||
|
||||
void __attribute__((weak)) __aeabi_memclr_impl2(void *dest, size_t n) {
|
||||
__aeabi_memset_impl(dest, n, 0);
|
||||
}
|
||||
|
||||
#define __AEABI_SYMVERS(fn_name) \
|
||||
__asm__(".symver " #fn_name "_impl, " #fn_name "@@LIBC_N"); \
|
||||
__asm__(".symver " #fn_name "_impl2, " #fn_name "@LIBC_PRIVATE")
|
||||
|
||||
__AEABI_SYMVERS(__aeabi_atexit);
|
||||
__AEABI_SYMVERS(__aeabi_memcpy8);
|
||||
__AEABI_SYMVERS(__aeabi_memcpy4);
|
||||
__AEABI_SYMVERS(__aeabi_memcpy);
|
||||
__AEABI_SYMVERS(__aeabi_memmove8);
|
||||
__AEABI_SYMVERS(__aeabi_memmove4);
|
||||
__AEABI_SYMVERS(__aeabi_memmove);
|
||||
__AEABI_SYMVERS(__aeabi_memset8);
|
||||
__AEABI_SYMVERS(__aeabi_memset4);
|
||||
__AEABI_SYMVERS(__aeabi_memset);
|
||||
__AEABI_SYMVERS(__aeabi_memclr8);
|
||||
__AEABI_SYMVERS(__aeabi_memclr4);
|
||||
__AEABI_SYMVERS(__aeabi_memclr);
|
||||
|
||||
#undef __AEABI_SYMVERS
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* Copyright (C) 2008-2010 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -42,14 +42,13 @@ ENTRY(__bionic_clone)
|
||||
# load extra parameters
|
||||
ldmfd ip, {r4, r5, r6}
|
||||
|
||||
# Push 'fn' and 'arg' onto the child stack.
|
||||
stmdb r1!, {r5, r6}
|
||||
# store 'fn' and 'arg' to the child stack
|
||||
str r5, [r1, #-4]
|
||||
str r6, [r1, #-8]
|
||||
|
||||
# Make the system call.
|
||||
# System call
|
||||
ldr r7, =__NR_clone
|
||||
swi #0
|
||||
|
||||
# Are we the child?
|
||||
movs r0, r0
|
||||
beq 1f
|
||||
|
||||
@ -63,8 +62,8 @@ ENTRY(__bionic_clone)
|
||||
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}
|
||||
ldr r0, [sp, #-4]
|
||||
ldr r1, [sp, #-8]
|
||||
b __start_thread
|
||||
END(__bionic_clone)
|
||||
.hidden __bionic_clone
|
||||
|
@ -34,9 +34,7 @@
|
||||
// __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.
|
||||
// the DWARF information to find out where it landed) gets the right answer.
|
||||
|
||||
// We need to place .fnstart ourselves (but we may as well keep the free .fnend).
|
||||
#undef __bionic_asm_custom_entry
|
||||
@ -46,18 +44,18 @@
|
||||
.save {r0-r15}
|
||||
.pad #32
|
||||
nop
|
||||
ENTRY_PRIVATE_NO_DWARF(__restore)
|
||||
ENTRY_PRIVATE(__restore)
|
||||
// This function must have exactly this instruction sequence.
|
||||
mov r7, #__NR_sigreturn
|
||||
swi #0
|
||||
END_NO_DWARF(__restore)
|
||||
END(__restore)
|
||||
|
||||
.fnstart
|
||||
.save {r0-r15}
|
||||
.pad #160
|
||||
nop
|
||||
ENTRY_PRIVATE_NO_DWARF(__restore_rt)
|
||||
ENTRY_PRIVATE(__restore_rt)
|
||||
// This function must have exactly this instruction sequence.
|
||||
mov r7, #__NR_rt_sigreturn
|
||||
swi #0
|
||||
END_NO_DWARF(__restore_rt)
|
||||
END(__restore_rt)
|
||||
|
113
libc/arch-arm/bionic/_setjmp.S
Normal file
113
libc/arch-arm/bionic/_setjmp.S
Normal file
@ -0,0 +1,113 @@
|
||||
/* $OpenBSD: _setjmp.S,v 1.2 2004/02/01 05:40:52 drahn Exp $ */
|
||||
/* $NetBSD: _setjmp.S,v 1.5 2003/04/05 23:08:51 bjh21 Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997 Mark Brinicombe
|
||||
* Copyright (c) 2010 Android Open Source Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Mark Brinicombe
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
#include <machine/setjmp.h>
|
||||
#include <machine/cpu-features.h>
|
||||
|
||||
/*
|
||||
* C library -- _setjmp, _longjmp
|
||||
*
|
||||
* _longjmp(a,v)
|
||||
* will generate a "return(v)" from the last call to
|
||||
* _setjmp(a)
|
||||
* by restoring registers from the stack.
|
||||
* The previous signal state is NOT restored.
|
||||
*
|
||||
* Note: r0 is the return value
|
||||
* r1-r3 are scratch registers in functions
|
||||
*/
|
||||
|
||||
ENTRY(_setjmp)
|
||||
ldr r1, .L_setjmp_magic
|
||||
str r1, [r0, #(_JB_MAGIC * 4)]
|
||||
|
||||
/* Store core registers */
|
||||
add r1, r0, #(_JB_CORE_BASE * 4)
|
||||
stmia r1, {r4-r14}
|
||||
|
||||
#ifdef __ARM_HAVE_VFP
|
||||
/* Store floating-point registers */
|
||||
add r1, r0, #(_JB_FLOAT_BASE * 4)
|
||||
vstmia r1, {d8-d15}
|
||||
/* Store floating-point state */
|
||||
fmrx r1, fpscr
|
||||
str r1, [r0, #(_JB_FLOAT_STATE * 4)]
|
||||
#endif /* __ARM_HAVE_VFP */
|
||||
|
||||
mov r0, #0x00000000
|
||||
bx lr
|
||||
END(_setjmp)
|
||||
|
||||
.L_setjmp_magic:
|
||||
.word _JB_MAGIC__SETJMP
|
||||
|
||||
ENTRY(_longjmp)
|
||||
ldr r2, .L_setjmp_magic
|
||||
ldr r3, [r0, #(_JB_MAGIC * 4)]
|
||||
teq r2, r3
|
||||
bne botch
|
||||
|
||||
#ifdef __ARM_HAVE_VFP
|
||||
/* Restore floating-point registers */
|
||||
add r2, r0, #(_JB_FLOAT_BASE * 4)
|
||||
vldmia r2, {d8-d15}
|
||||
/* Restore floating-point state */
|
||||
ldr r2, [r0, #(_JB_FLOAT_STATE * 4)]
|
||||
fmxr fpscr, r2
|
||||
#endif /* __ARM_HAVE_VFP */
|
||||
|
||||
/* Restore core registers */
|
||||
add r2, r0, #(_JB_CORE_BASE * 4)
|
||||
ldmia r2, {r4-r14}
|
||||
|
||||
/* Validate sp and r14 */
|
||||
teq sp, #0
|
||||
teqne r14, #0
|
||||
beq botch
|
||||
|
||||
/* Set return value */
|
||||
mov r0, r1
|
||||
teq r0, #0x00000000
|
||||
moveq r0, #0x00000001
|
||||
bx lr
|
||||
|
||||
/* validation failed, die die die. */
|
||||
botch:
|
||||
bl PIC_SYM(longjmperror, PLT)
|
||||
bl PIC_SYM(abort, PLT)
|
||||
b . - 8 /* Cannot get here */
|
||||
END(_longjmp)
|
@ -40,5 +40,5 @@ ENTRY(abort)
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r3, 0
|
||||
.cfi_rel_offset r14, 4
|
||||
bl __libc_android_abort
|
||||
bl PIC_SYM(__libc_android_abort, PLT)
|
||||
END(abort)
|
||||
|
@ -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");
|
||||
|
@ -40,8 +40,6 @@
|
||||
* Optimized memcmp() for Cortex-A9.
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
|
||||
ENTRY(memcmp)
|
||||
pld [r0, #(CACHE_LINE_SIZE * 0)]
|
||||
pld [r0, #(CACHE_LINE_SIZE * 1)]
|
||||
@ -163,25 +161,25 @@ ENTRY(memcmp)
|
||||
eors r0, r0, ip
|
||||
ldreq r0, [r4], #4
|
||||
ldreq ip, [r1, #4]!
|
||||
eorseq r0, r0, lr
|
||||
eoreqs r0, r0, lr
|
||||
ldreq r0, [r4], #4
|
||||
ldreq lr, [r1, #4]!
|
||||
eorseq r0, r0, ip
|
||||
eoreqs r0, r0, ip
|
||||
ldreq r0, [r4], #4
|
||||
ldreq ip, [r1, #4]!
|
||||
eorseq r0, r0, lr
|
||||
eoreqs r0, r0, lr
|
||||
ldreq r0, [r4], #4
|
||||
ldreq lr, [r1, #4]!
|
||||
eorseq r0, r0, ip
|
||||
eoreqs r0, r0, ip
|
||||
ldreq r0, [r4], #4
|
||||
ldreq ip, [r1, #4]!
|
||||
eorseq r0, r0, lr
|
||||
eoreqs r0, r0, lr
|
||||
ldreq r0, [r4], #4
|
||||
ldreq lr, [r1, #4]!
|
||||
eorseq r0, r0, ip
|
||||
eoreqs r0, r0, ip
|
||||
ldreq r0, [r4], #4
|
||||
ldreq ip, [r1, #4]!
|
||||
eorseq r0, r0, lr
|
||||
eoreqs r0, r0, lr
|
||||
bne 2f
|
||||
subs r2, r2, #32
|
||||
bhs 0b
|
||||
@ -221,7 +219,8 @@ ENTRY(memcmp)
|
||||
bne 8b
|
||||
|
||||
9: /* restore registers and return */
|
||||
ldmfd sp!, {r4, pc}
|
||||
ldmfd sp!, {r4, lr}
|
||||
bx lr
|
||||
|
||||
10: /* process less than 12 bytes */
|
||||
cmp r2, #0
|
||||
@ -264,17 +263,17 @@ ENTRY(memcmp)
|
||||
ldreq lr, [r1], #4
|
||||
ldreq r0, [r4], #4
|
||||
orreq ip, ip, lr, lsl #16
|
||||
eorseq r0, r0, ip
|
||||
eoreqs r0, r0, ip
|
||||
moveq ip, lr, lsr #16
|
||||
ldreq lr, [r1], #4
|
||||
ldreq r0, [r4], #4
|
||||
orreq ip, ip, lr, lsl #16
|
||||
eorseq r0, r0, ip
|
||||
eoreqs r0, r0, ip
|
||||
moveq ip, lr, lsr #16
|
||||
ldreq lr, [r1], #4
|
||||
ldreq r0, [r4], #4
|
||||
orreq ip, ip, lr, lsl #16
|
||||
eorseq r0, r0, ip
|
||||
eoreqs r0, r0, ip
|
||||
bne 7f
|
||||
subs r2, r2, #16
|
||||
bhs 6b
|
||||
@ -318,7 +317,7 @@ ENTRY(memcmp)
|
||||
ldreq r7, [r1], #4
|
||||
ldreq r0, [r4], #4
|
||||
orreq ip, ip, r7, lsl r6
|
||||
eorseq r0, r0, ip
|
||||
eoreqs r0, r0, ip
|
||||
bne 7f
|
||||
subs r2, r2, #8
|
||||
bhs 6b
|
686
libc/arch-arm/bionic/memcpy.S
Normal file
686
libc/arch-arm/bionic/memcpy.S
Normal file
@ -0,0 +1,686 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <machine/cpu-features.h>
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
#if defined(__ARM_NEON__) && !defined(ARCH_ARM_USE_NON_NEON_MEMCPY)
|
||||
|
||||
.text
|
||||
.fpu neon
|
||||
|
||||
#ifdef HAVE_32_BYTE_CACHE_LINE
|
||||
/* a prefetch distance of 2 cache-lines */
|
||||
#define CACHE_LINE_SIZE 32
|
||||
#else
|
||||
/* a prefetch distance of 4 cache-lines works best experimentally */
|
||||
#define CACHE_LINE_SIZE 64
|
||||
#endif
|
||||
|
||||
ENTRY(memcpy)
|
||||
.save {r0, lr}
|
||||
/* start preloading as early as possible */
|
||||
pld [r1, #(CACHE_LINE_SIZE * 0)]
|
||||
stmfd sp!, {r0, lr}
|
||||
pld [r1, #(CACHE_LINE_SIZE * 1)]
|
||||
|
||||
/* If Neon supports unaligned access then remove the align code,
|
||||
* unless a size limit has been specified.
|
||||
*/
|
||||
#ifndef NEON_UNALIGNED_ACCESS
|
||||
/* do we have at least 16-bytes to copy (needed for alignment below) */
|
||||
cmp r2, #16
|
||||
blo 5f
|
||||
|
||||
/* check if buffers are aligned. If so, run arm-only version */
|
||||
eor r3, r0, r1
|
||||
ands r3, r3, #0x3
|
||||
beq 11f
|
||||
|
||||
/* align destination to cache-line for the write-buffer */
|
||||
rsb r3, r0, #0
|
||||
ands r3, r3, #0xF
|
||||
beq 2f
|
||||
|
||||
/* copy up to 15-bytes (count in r3) */
|
||||
sub r2, r2, r3
|
||||
movs ip, r3, lsl #31
|
||||
ldrmib lr, [r1], #1
|
||||
strmib lr, [r0], #1
|
||||
ldrcsb ip, [r1], #1
|
||||
ldrcsb lr, [r1], #1
|
||||
strcsb ip, [r0], #1
|
||||
strcsb lr, [r0], #1
|
||||
movs ip, r3, lsl #29
|
||||
bge 1f
|
||||
// copies 4 bytes, destination 32-bits aligned
|
||||
vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]!
|
||||
vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]!
|
||||
1: bcc 2f
|
||||
// copies 8 bytes, destination 64-bits aligned
|
||||
vld1.8 {d0}, [r1]!
|
||||
vst1.8 {d0}, [r0, :64]!
|
||||
2:
|
||||
/* preload immediately the next cache line, which we may need */
|
||||
pld [r1, #(CACHE_LINE_SIZE * 0)]
|
||||
pld [r1, #(CACHE_LINE_SIZE * 1)]
|
||||
|
||||
#ifdef HAVE_32_BYTE_CACHE_LINE
|
||||
/* make sure we have at least 32 bytes to copy */
|
||||
subs r2, r2, #32
|
||||
blo 4f
|
||||
|
||||
/* preload all the cache lines we need.
|
||||
* NOTE: the number of pld below depends on PREFETCH_DISTANCE,
|
||||
* ideally would would increase the distance in the main loop to
|
||||
* avoid the goofy code below. In practice this doesn't seem to make
|
||||
* a big difference.
|
||||
*/
|
||||
pld [r1, #(PREFETCH_DISTANCE)]
|
||||
|
||||
1: /* The main loop copies 32 bytes at a time */
|
||||
vld1.8 {d0 - d3}, [r1]!
|
||||
pld [r1, #(PREFETCH_DISTANCE)]
|
||||
subs r2, r2, #32
|
||||
vst1.8 {d0 - d3}, [r0, :128]!
|
||||
bhs 1b
|
||||
#else
|
||||
/* make sure we have at least 64 bytes to copy */
|
||||
subs r2, r2, #64
|
||||
blo 2f
|
||||
|
||||
/* preload all the cache lines we need. */
|
||||
pld [r1, #(CACHE_LINE_SIZE * 2)]
|
||||
pld [r1, #(CACHE_LINE_SIZE * 3)]
|
||||
|
||||
1: /* The main loop copies 64 bytes at a time */
|
||||
vld1.8 {d0 - d3}, [r1]!
|
||||
vld1.8 {d4 - d7}, [r1]!
|
||||
#ifdef HAVE_32_BYTE_CACHE_LINE
|
||||
pld [r1, #(CACHE_LINE_SIZE * 2)]
|
||||
pld [r1, #(CACHE_LINE_SIZE * 3)]
|
||||
#else
|
||||
pld [r1, #(CACHE_LINE_SIZE * 3)]
|
||||
#endif
|
||||
subs r2, r2, #64
|
||||
vst1.8 {d0 - d3}, [r0, :128]!
|
||||
vst1.8 {d4 - d7}, [r0, :128]!
|
||||
bhs 1b
|
||||
|
||||
2: /* fix-up the remaining count and make sure we have >= 32 bytes left */
|
||||
add r2, r2, #64
|
||||
subs r2, r2, #32
|
||||
blo 4f
|
||||
|
||||
3: /* 32 bytes at a time. These cache lines were already preloaded */
|
||||
vld1.8 {d0 - d3}, [r1]!
|
||||
subs r2, r2, #32
|
||||
vst1.8 {d0 - d3}, [r0, :128]!
|
||||
bhs 3b
|
||||
#endif
|
||||
4: /* less than 32 left */
|
||||
add r2, r2, #32
|
||||
tst r2, #0x10
|
||||
beq 5f
|
||||
// copies 16 bytes, 128-bits aligned
|
||||
vld1.8 {d0, d1}, [r1]!
|
||||
vst1.8 {d0, d1}, [r0, :128]!
|
||||
5: /* copy up to 15-bytes (count in r2) */
|
||||
movs ip, r2, lsl #29
|
||||
bcc 1f
|
||||
vld1.8 {d0}, [r1]!
|
||||
vst1.8 {d0}, [r0]!
|
||||
1: bge 2f
|
||||
vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]!
|
||||
vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0]!
|
||||
2: movs ip, r2, lsl #31
|
||||
ldrmib r3, [r1], #1
|
||||
ldrcsb ip, [r1], #1
|
||||
ldrcsb lr, [r1], #1
|
||||
strmib r3, [r0], #1
|
||||
strcsb ip, [r0], #1
|
||||
strcsb lr, [r0], #1
|
||||
|
||||
ldmfd sp!, {r0, lr}
|
||||
bx lr
|
||||
|
||||
#else /* NEON_UNALIGNED_ACCESS */
|
||||
|
||||
// Check so divider is at least 16 bytes, needed for alignment code.
|
||||
cmp r2, #16
|
||||
blo 5f
|
||||
|
||||
#ifdef NEON_MEMCPY_ALIGNMENT_DIVIDER
|
||||
/* Check the upper size limit for Neon unaligned memory access in memcpy */
|
||||
#if NEON_MEMCPY_ALIGNMENT_DIVIDER >= 16
|
||||
cmp r2, #NEON_MEMCPY_ALIGNMENT_DIVIDER
|
||||
blo 3f
|
||||
#endif
|
||||
/* check if buffers are aligned. If so, run arm-only version */
|
||||
eor r3, r0, r1
|
||||
ands r3, r3, #0x3
|
||||
beq 11f
|
||||
|
||||
/* align destination to 16 bytes for the write-buffer */
|
||||
rsb r3, r0, #0
|
||||
ands r3, r3, #0xF
|
||||
beq 3f
|
||||
|
||||
/* copy up to 15-bytes (count in r3) */
|
||||
sub r2, r2, r3
|
||||
movs ip, r3, lsl #31
|
||||
ldrmib lr, [r1], #1
|
||||
strmib lr, [r0], #1
|
||||
ldrcsb ip, [r1], #1
|
||||
ldrcsb lr, [r1], #1
|
||||
strcsb ip, [r0], #1
|
||||
strcsb lr, [r0], #1
|
||||
movs ip, r3, lsl #29
|
||||
bge 1f
|
||||
// copies 4 bytes, destination 32-bits aligned
|
||||
vld1.32 {d0[0]}, [r1]!
|
||||
vst1.32 {d0[0]}, [r0, :32]!
|
||||
1: bcc 2f
|
||||
// copies 8 bytes, destination 64-bits aligned
|
||||
vld1.8 {d0}, [r1]!
|
||||
vst1.8 {d0}, [r0, :64]!
|
||||
2:
|
||||
/* preload immediately the next cache line, which we may need */
|
||||
pld [r1, #(CACHE_LINE_SIZE * 0)]
|
||||
pld [r1, #(CACHE_LINE_SIZE * 1)]
|
||||
3:
|
||||
#endif
|
||||
/* make sure we have at least 64 bytes to copy */
|
||||
subs r2, r2, #64
|
||||
blo 2f
|
||||
|
||||
/* preload all the cache lines we need */
|
||||
pld [r1, #(CACHE_LINE_SIZE * 2)]
|
||||
pld [r1, #(CACHE_LINE_SIZE * 3)]
|
||||
|
||||
1: /* The main loop copies 64 bytes at a time */
|
||||
vld1.8 {d0 - d3}, [r1]!
|
||||
vld1.8 {d4 - d7}, [r1]!
|
||||
#ifdef HAVE_32_BYTE_CACHE_LINE
|
||||
pld [r1, #(CACHE_LINE_SIZE * 2)]
|
||||
pld [r1, #(CACHE_LINE_SIZE * 3)]
|
||||
#else
|
||||
pld [r1, #(CACHE_LINE_SIZE * 3)]
|
||||
#endif
|
||||
subs r2, r2, #64
|
||||
vst1.8 {d0 - d3}, [r0]!
|
||||
vst1.8 {d4 - d7}, [r0]!
|
||||
bhs 1b
|
||||
|
||||
2: /* fix-up the remaining count and make sure we have >= 32 bytes left */
|
||||
add r2, r2, #64
|
||||
subs r2, r2, #32
|
||||
blo 4f
|
||||
|
||||
3: /* 32 bytes at a time. These cache lines were already preloaded */
|
||||
vld1.8 {d0 - d3}, [r1]!
|
||||
subs r2, r2, #32
|
||||
vst1.8 {d0 - d3}, [r0]!
|
||||
bhs 3b
|
||||
|
||||
4: /* less than 32 left */
|
||||
add r2, r2, #32
|
||||
tst r2, #0x10
|
||||
beq 5f
|
||||
// copies 16 bytes, 128-bits aligned
|
||||
vld1.8 {d0, d1}, [r1]!
|
||||
vst1.8 {d0, d1}, [r0]!
|
||||
5: /* copy up to 15-bytes (count in r2) */
|
||||
movs ip, r2, lsl #29
|
||||
bcc 1f
|
||||
vld1.8 {d0}, [r1]!
|
||||
vst1.8 {d0}, [r0]!
|
||||
1: bge 2f
|
||||
vld1.32 {d0[0]}, [r1]!
|
||||
vst1.32 {d0[0]}, [r0]!
|
||||
2: movs ip, r2, lsl #31
|
||||
ldrmib r3, [r1], #1
|
||||
ldrcsb ip, [r1], #1
|
||||
ldrcsb lr, [r1], #1
|
||||
strmib r3, [r0], #1
|
||||
strcsb ip, [r0], #1
|
||||
strcsb lr, [r0], #1
|
||||
|
||||
ldmfd sp!, {r0, lr}
|
||||
bx lr
|
||||
#endif /* NEON_UNALIGNED_ACCESS */
|
||||
11:
|
||||
/* Simple arm-only copy loop to handle aligned copy operations */
|
||||
stmfd sp!, {r4, r5, r6, r7, r8}
|
||||
pld [r1, #(CACHE_LINE_SIZE * 2)]
|
||||
|
||||
/* Check alignment */
|
||||
rsb r3, r1, #0
|
||||
ands r3, #3
|
||||
beq 2f
|
||||
|
||||
/* align source to 32 bits. We need to insert 2 instructions between
|
||||
* a ldr[b|h] and str[b|h] because byte and half-word instructions
|
||||
* stall 2 cycles.
|
||||
*/
|
||||
movs r12, r3, lsl #31
|
||||
sub r2, r2, r3 /* we know that r3 <= r2 because r2 >= 4 */
|
||||
ldrmib r3, [r1], #1
|
||||
ldrcsb r4, [r1], #1
|
||||
ldrcsb r5, [r1], #1
|
||||
strmib r3, [r0], #1
|
||||
strcsb r4, [r0], #1
|
||||
strcsb r5, [r0], #1
|
||||
2:
|
||||
subs r2, #32
|
||||
blt 5f
|
||||
pld [r1, #(CACHE_LINE_SIZE * 3)]
|
||||
3: /* Main copy loop, copying 32 bytes at a time */
|
||||
pld [r1, #(CACHE_LINE_SIZE * 4)]
|
||||
ldmia r1!, {r3, r4, r5, r6, r7, r8, r12, lr}
|
||||
subs r2, r2, #32
|
||||
stmia r0!, {r3, r4, r5, r6, r7, r8, r12, lr}
|
||||
bge 3b
|
||||
5: /* Handle any remaining bytes */
|
||||
adds r2, #32
|
||||
beq 6f
|
||||
|
||||
movs r12, r2, lsl #28
|
||||
ldmcsia r1!, {r3, r4, r5, r6} /* 16 bytes */
|
||||
ldmmiia r1!, {r7, r8} /* 8 bytes */
|
||||
stmcsia r0!, {r3, r4, r5, r6}
|
||||
stmmiia r0!, {r7, r8}
|
||||
movs r12, r2, lsl #30
|
||||
ldrcs r3, [r1], #4 /* 4 bytes */
|
||||
ldrmih r4, [r1], #2 /* 2 bytes */
|
||||
strcs r3, [r0], #4
|
||||
strmih r4, [r0], #2
|
||||
tst r2, #0x1
|
||||
ldrneb r3, [r1] /* last byte */
|
||||
strneb r3, [r0]
|
||||
6:
|
||||
ldmfd sp!, {r4, r5, r6, r7, r8}
|
||||
ldmfd sp!, {r0, pc}
|
||||
END(memcpy)
|
||||
|
||||
|
||||
#else /* __ARM_ARCH__ < 7 */
|
||||
|
||||
|
||||
/*
|
||||
* Optimized memcpy() for ARM.
|
||||
*
|
||||
* note that memcpy() always returns the destination pointer,
|
||||
* so we have to preserve R0.
|
||||
*/
|
||||
|
||||
ENTRY(memcpy)
|
||||
/* The stack must always be 64-bits aligned to be compliant with the
|
||||
* ARM ABI. Since we have to save R0, we might as well save R4
|
||||
* which we can use for better pipelining of the reads below
|
||||
*/
|
||||
.save {r0, r4, lr}
|
||||
stmfd sp!, {r0, r4, lr}
|
||||
/* Making room for r5-r11 which will be spilled later */
|
||||
.pad #28
|
||||
sub sp, sp, #28
|
||||
|
||||
// preload the destination because we'll align it to a cache line
|
||||
// with small writes. Also start the source "pump".
|
||||
pld [r0, #0]
|
||||
pld [r1, #0]
|
||||
pld [r1, #32]
|
||||
|
||||
/* it simplifies things to take care of len<4 early */
|
||||
cmp r2, #4
|
||||
blo copy_last_3_and_return
|
||||
|
||||
/* compute the offset to align the source
|
||||
* offset = (4-(src&3))&3 = -src & 3
|
||||
*/
|
||||
rsb r3, r1, #0
|
||||
ands r3, r3, #3
|
||||
beq src_aligned
|
||||
|
||||
/* align source to 32 bits. We need to insert 2 instructions between
|
||||
* a ldr[b|h] and str[b|h] because byte and half-word instructions
|
||||
* stall 2 cycles.
|
||||
*/
|
||||
movs r12, r3, lsl #31
|
||||
sub r2, r2, r3 /* we know that r3 <= r2 because r2 >= 4 */
|
||||
ldrmib r3, [r1], #1
|
||||
ldrcsb r4, [r1], #1
|
||||
ldrcsb r12,[r1], #1
|
||||
strmib r3, [r0], #1
|
||||
strcsb r4, [r0], #1
|
||||
strcsb r12,[r0], #1
|
||||
|
||||
src_aligned:
|
||||
|
||||
/* see if src and dst are aligned together (congruent) */
|
||||
eor r12, r0, r1
|
||||
tst r12, #3
|
||||
bne non_congruent
|
||||
|
||||
/* Use post-incriment mode for stm to spill r5-r11 to reserved stack
|
||||
* frame. Don't update sp.
|
||||
*/
|
||||
stmea sp, {r5-r11}
|
||||
|
||||
/* align the destination to a cache-line */
|
||||
rsb r3, r0, #0
|
||||
ands r3, r3, #0x1C
|
||||
beq congruent_aligned32
|
||||
cmp r3, r2
|
||||
andhi r3, r2, #0x1C
|
||||
|
||||
/* conditionnaly copies 0 to 7 words (length in r3) */
|
||||
movs r12, r3, lsl #28
|
||||
ldmcsia r1!, {r4, r5, r6, r7} /* 16 bytes */
|
||||
ldmmiia r1!, {r8, r9} /* 8 bytes */
|
||||
stmcsia r0!, {r4, r5, r6, r7}
|
||||
stmmiia r0!, {r8, r9}
|
||||
tst r3, #0x4
|
||||
ldrne r10,[r1], #4 /* 4 bytes */
|
||||
strne r10,[r0], #4
|
||||
sub r2, r2, r3
|
||||
|
||||
congruent_aligned32:
|
||||
/*
|
||||
* here source is aligned to 32 bytes.
|
||||
*/
|
||||
|
||||
cached_aligned32:
|
||||
subs r2, r2, #32
|
||||
blo less_than_32_left
|
||||
|
||||
/*
|
||||
* We preload a cache-line up to 64 bytes ahead. On the 926, this will
|
||||
* stall only until the requested world is fetched, but the linefill
|
||||
* continues in the the background.
|
||||
* While the linefill is going, we write our previous cache-line
|
||||
* into the write-buffer (which should have some free space).
|
||||
* When the linefill is done, the writebuffer will
|
||||
* start dumping its content into memory
|
||||
*
|
||||
* While all this is going, we then load a full cache line into
|
||||
* 8 registers, this cache line should be in the cache by now
|
||||
* (or partly in the cache).
|
||||
*
|
||||
* This code should work well regardless of the source/dest alignment.
|
||||
*
|
||||
*/
|
||||
|
||||
// Align the preload register to a cache-line because the cpu does
|
||||
// "critical word first" (the first word requested is loaded first).
|
||||
bic r12, r1, #0x1F
|
||||
add r12, r12, #64
|
||||
|
||||
1: ldmia r1!, { r4-r11 }
|
||||
pld [r12, #64]
|
||||
subs r2, r2, #32
|
||||
|
||||
// NOTE: if r12 is more than 64 ahead of r1, the following ldrhi
|
||||
// for ARM9 preload will not be safely guarded by the preceding subs.
|
||||
// When it is safely guarded the only possibility to have SIGSEGV here
|
||||
// is because the caller overstates the length.
|
||||
ldrhi r3, [r12], #32 /* cheap ARM9 preload */
|
||||
stmia r0!, { r4-r11 }
|
||||
bhs 1b
|
||||
|
||||
add r2, r2, #32
|
||||
|
||||
|
||||
|
||||
|
||||
less_than_32_left:
|
||||
/*
|
||||
* less than 32 bytes left at this point (length in r2)
|
||||
*/
|
||||
|
||||
/* skip all this if there is nothing to do, which should
|
||||
* be a common case (if not executed the code below takes
|
||||
* about 16 cycles)
|
||||
*/
|
||||
tst r2, #0x1F
|
||||
beq 1f
|
||||
|
||||
/* conditionnaly copies 0 to 31 bytes */
|
||||
movs r12, r2, lsl #28
|
||||
ldmcsia r1!, {r4, r5, r6, r7} /* 16 bytes */
|
||||
ldmmiia r1!, {r8, r9} /* 8 bytes */
|
||||
stmcsia r0!, {r4, r5, r6, r7}
|
||||
stmmiia r0!, {r8, r9}
|
||||
movs r12, r2, lsl #30
|
||||
ldrcs r3, [r1], #4 /* 4 bytes */
|
||||
ldrmih r4, [r1], #2 /* 2 bytes */
|
||||
strcs r3, [r0], #4
|
||||
strmih r4, [r0], #2
|
||||
tst r2, #0x1
|
||||
ldrneb r3, [r1] /* last byte */
|
||||
strneb r3, [r0]
|
||||
|
||||
/* we're done! restore everything and return */
|
||||
1: ldmfd sp!, {r5-r11}
|
||||
ldmfd sp!, {r0, r4, lr}
|
||||
bx lr
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
non_congruent:
|
||||
/*
|
||||
* here source is aligned to 4 bytes
|
||||
* but destination is not.
|
||||
*
|
||||
* in the code below r2 is the number of bytes read
|
||||
* (the number of bytes written is always smaller, because we have
|
||||
* partial words in the shift queue)
|
||||
*/
|
||||
cmp r2, #4
|
||||
blo copy_last_3_and_return
|
||||
|
||||
/* Use post-incriment mode for stm to spill r5-r11 to reserved stack
|
||||
* frame. Don't update sp.
|
||||
*/
|
||||
stmea sp, {r5-r11}
|
||||
|
||||
/* compute shifts needed to align src to dest */
|
||||
rsb r5, r0, #0
|
||||
and r5, r5, #3 /* r5 = # bytes in partial words */
|
||||
mov r12, r5, lsl #3 /* r12 = right */
|
||||
rsb lr, r12, #32 /* lr = left */
|
||||
|
||||
/* read the first word */
|
||||
ldr r3, [r1], #4
|
||||
sub r2, r2, #4
|
||||
|
||||
/* write a partial word (0 to 3 bytes), such that destination
|
||||
* becomes aligned to 32 bits (r5 = nb of words to copy for alignment)
|
||||
*/
|
||||
movs r5, r5, lsl #31
|
||||
strmib r3, [r0], #1
|
||||
movmi r3, r3, lsr #8
|
||||
strcsb r3, [r0], #1
|
||||
movcs r3, r3, lsr #8
|
||||
strcsb r3, [r0], #1
|
||||
movcs r3, r3, lsr #8
|
||||
|
||||
cmp r2, #4
|
||||
blo partial_word_tail
|
||||
|
||||
/* Align destination to 32 bytes (cache line boundary) */
|
||||
1: tst r0, #0x1c
|
||||
beq 2f
|
||||
ldr r5, [r1], #4
|
||||
sub r2, r2, #4
|
||||
orr r4, r3, r5, lsl lr
|
||||
mov r3, r5, lsr r12
|
||||
str r4, [r0], #4
|
||||
cmp r2, #4
|
||||
bhs 1b
|
||||
blo partial_word_tail
|
||||
|
||||
/* copy 32 bytes at a time */
|
||||
2: subs r2, r2, #32
|
||||
blo less_than_thirtytwo
|
||||
|
||||
/* Use immediate mode for the shifts, because there is an extra cycle
|
||||
* for register shifts, which could account for up to 50% of
|
||||
* performance hit.
|
||||
*/
|
||||
|
||||
cmp r12, #24
|
||||
beq loop24
|
||||
cmp r12, #8
|
||||
beq loop8
|
||||
|
||||
loop16:
|
||||
ldr r12, [r1], #4
|
||||
1: mov r4, r12
|
||||
ldmia r1!, { r5,r6,r7, r8,r9,r10,r11}
|
||||
pld [r1, #64]
|
||||
subs r2, r2, #32
|
||||
ldrhs r12, [r1], #4
|
||||
orr r3, r3, r4, lsl #16
|
||||
mov r4, r4, lsr #16
|
||||
orr r4, r4, r5, lsl #16
|
||||
mov r5, r5, lsr #16
|
||||
orr r5, r5, r6, lsl #16
|
||||
mov r6, r6, lsr #16
|
||||
orr r6, r6, r7, lsl #16
|
||||
mov r7, r7, lsr #16
|
||||
orr r7, r7, r8, lsl #16
|
||||
mov r8, r8, lsr #16
|
||||
orr r8, r8, r9, lsl #16
|
||||
mov r9, r9, lsr #16
|
||||
orr r9, r9, r10, lsl #16
|
||||
mov r10, r10, lsr #16
|
||||
orr r10, r10, r11, lsl #16
|
||||
stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10}
|
||||
mov r3, r11, lsr #16
|
||||
bhs 1b
|
||||
b less_than_thirtytwo
|
||||
|
||||
loop8:
|
||||
ldr r12, [r1], #4
|
||||
1: mov r4, r12
|
||||
ldmia r1!, { r5,r6,r7, r8,r9,r10,r11}
|
||||
pld [r1, #64]
|
||||
subs r2, r2, #32
|
||||
ldrhs r12, [r1], #4
|
||||
orr r3, r3, r4, lsl #24
|
||||
mov r4, r4, lsr #8
|
||||
orr r4, r4, r5, lsl #24
|
||||
mov r5, r5, lsr #8
|
||||
orr r5, r5, r6, lsl #24
|
||||
mov r6, r6, lsr #8
|
||||
orr r6, r6, r7, lsl #24
|
||||
mov r7, r7, lsr #8
|
||||
orr r7, r7, r8, lsl #24
|
||||
mov r8, r8, lsr #8
|
||||
orr r8, r8, r9, lsl #24
|
||||
mov r9, r9, lsr #8
|
||||
orr r9, r9, r10, lsl #24
|
||||
mov r10, r10, lsr #8
|
||||
orr r10, r10, r11, lsl #24
|
||||
stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10}
|
||||
mov r3, r11, lsr #8
|
||||
bhs 1b
|
||||
b less_than_thirtytwo
|
||||
|
||||
loop24:
|
||||
ldr r12, [r1], #4
|
||||
1: mov r4, r12
|
||||
ldmia r1!, { r5,r6,r7, r8,r9,r10,r11}
|
||||
pld [r1, #64]
|
||||
subs r2, r2, #32
|
||||
ldrhs r12, [r1], #4
|
||||
orr r3, r3, r4, lsl #8
|
||||
mov r4, r4, lsr #24
|
||||
orr r4, r4, r5, lsl #8
|
||||
mov r5, r5, lsr #24
|
||||
orr r5, r5, r6, lsl #8
|
||||
mov r6, r6, lsr #24
|
||||
orr r6, r6, r7, lsl #8
|
||||
mov r7, r7, lsr #24
|
||||
orr r7, r7, r8, lsl #8
|
||||
mov r8, r8, lsr #24
|
||||
orr r8, r8, r9, lsl #8
|
||||
mov r9, r9, lsr #24
|
||||
orr r9, r9, r10, lsl #8
|
||||
mov r10, r10, lsr #24
|
||||
orr r10, r10, r11, lsl #8
|
||||
stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10}
|
||||
mov r3, r11, lsr #24
|
||||
bhs 1b
|
||||
|
||||
|
||||
less_than_thirtytwo:
|
||||
/* copy the last 0 to 31 bytes of the source */
|
||||
rsb r12, lr, #32 /* we corrupted r12, recompute it */
|
||||
add r2, r2, #32
|
||||
cmp r2, #4
|
||||
blo partial_word_tail
|
||||
|
||||
1: ldr r5, [r1], #4
|
||||
sub r2, r2, #4
|
||||
orr r4, r3, r5, lsl lr
|
||||
mov r3, r5, lsr r12
|
||||
str r4, [r0], #4
|
||||
cmp r2, #4
|
||||
bhs 1b
|
||||
|
||||
partial_word_tail:
|
||||
/* we have a partial word in the input buffer */
|
||||
movs r5, lr, lsl #(31-3)
|
||||
strmib r3, [r0], #1
|
||||
movmi r3, r3, lsr #8
|
||||
strcsb r3, [r0], #1
|
||||
movcs r3, r3, lsr #8
|
||||
strcsb r3, [r0], #1
|
||||
|
||||
/* Refill spilled registers from the stack. Don't update sp. */
|
||||
ldmfd sp, {r5-r11}
|
||||
|
||||
copy_last_3_and_return:
|
||||
movs r2, r2, lsl #31 /* copy remaining 0, 1, 2 or 3 bytes */
|
||||
ldrmib r2, [r1], #1
|
||||
ldrcsb r3, [r1], #1
|
||||
ldrcsb r12,[r1]
|
||||
strmib r2, [r0], #1
|
||||
strcsb r3, [r0], #1
|
||||
strcsb r12,[r0]
|
||||
|
||||
/* we're done! restore sp and spilled registers and return */
|
||||
add sp, sp, #28
|
||||
ldmfd sp!, {r0, r4, lr}
|
||||
bx lr
|
||||
END(memcpy)
|
||||
|
||||
|
||||
#endif /* __ARM_ARCH__ < 7 */
|
614
libc/arch-arm/bionic/memcpy.a9.S
Normal file
614
libc/arch-arm/bionic/memcpy.a9.S
Normal file
@ -0,0 +1,614 @@
|
||||
/* Copyright (c) 2013, Linaro Limited
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Linaro Limited nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
This memcpy routine is optimised for Cortex-A15 cores and takes advantage
|
||||
of VFP or NEON when built with the appropriate flags.
|
||||
|
||||
Assumptions:
|
||||
|
||||
ARMv6 (ARMv7-a if using Neon)
|
||||
ARM state
|
||||
Unaligned accesses
|
||||
LDRD/STRD support unaligned word accesses
|
||||
|
||||
*/
|
||||
|
||||
#include <machine/cpu-features.h>
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
.syntax unified
|
||||
/* This implementation requires ARM state. */
|
||||
.arm
|
||||
|
||||
#ifdef __ARM_NEON__
|
||||
|
||||
.fpu neon
|
||||
.arch armv7-a
|
||||
# define FRAME_SIZE 4
|
||||
# define USE_VFP
|
||||
# define USE_NEON
|
||||
|
||||
#elif !defined (__SOFTFP__)
|
||||
|
||||
.arch armv6
|
||||
.fpu vfpv2
|
||||
# define FRAME_SIZE 32
|
||||
# define USE_VFP
|
||||
|
||||
#else
|
||||
.arch armv6
|
||||
# define FRAME_SIZE 32
|
||||
|
||||
#endif
|
||||
|
||||
/* Old versions of GAS incorrectly implement the NEON align semantics. */
|
||||
#ifdef BROKEN_ASM_NEON_ALIGN
|
||||
#define ALIGN(addr, align) addr,:align
|
||||
#else
|
||||
#define ALIGN(addr, align) addr:align
|
||||
#endif
|
||||
|
||||
#define PC_OFFSET 8 /* PC pipeline compensation. */
|
||||
#define INSN_SIZE 4
|
||||
|
||||
/* Call parameters. */
|
||||
#define dstin r0
|
||||
#define src r1
|
||||
#define count r2
|
||||
|
||||
/* Locals. */
|
||||
#define tmp1 r3
|
||||
#define dst ip
|
||||
#define tmp2 r10
|
||||
|
||||
#ifndef USE_NEON
|
||||
/* For bulk copies using GP registers. */
|
||||
#define A_l r2 /* Call-clobbered. */
|
||||
#define A_h r3 /* Call-clobbered. */
|
||||
#define B_l r4
|
||||
#define B_h r5
|
||||
#define C_l r6
|
||||
#define C_h r7
|
||||
#define D_l r8
|
||||
#define D_h r9
|
||||
#endif
|
||||
|
||||
/* Number of lines ahead to pre-fetch data. If you change this the code
|
||||
below will need adjustment to compensate. */
|
||||
|
||||
#define prefetch_lines 5
|
||||
|
||||
#ifdef USE_VFP
|
||||
.macro cpy_line_vfp vreg, base
|
||||
vstr \vreg, [dst, #\base]
|
||||
vldr \vreg, [src, #\base]
|
||||
vstr d0, [dst, #\base + 8]
|
||||
vldr d0, [src, #\base + 8]
|
||||
vstr d1, [dst, #\base + 16]
|
||||
vldr d1, [src, #\base + 16]
|
||||
vstr d2, [dst, #\base + 24]
|
||||
vldr d2, [src, #\base + 24]
|
||||
vstr \vreg, [dst, #\base + 32]
|
||||
vldr \vreg, [src, #\base + prefetch_lines * 64 - 32]
|
||||
vstr d0, [dst, #\base + 40]
|
||||
vldr d0, [src, #\base + 40]
|
||||
vstr d1, [dst, #\base + 48]
|
||||
vldr d1, [src, #\base + 48]
|
||||
vstr d2, [dst, #\base + 56]
|
||||
vldr d2, [src, #\base + 56]
|
||||
.endm
|
||||
|
||||
.macro cpy_tail_vfp vreg, base
|
||||
vstr \vreg, [dst, #\base]
|
||||
vldr \vreg, [src, #\base]
|
||||
vstr d0, [dst, #\base + 8]
|
||||
vldr d0, [src, #\base + 8]
|
||||
vstr d1, [dst, #\base + 16]
|
||||
vldr d1, [src, #\base + 16]
|
||||
vstr d2, [dst, #\base + 24]
|
||||
vldr d2, [src, #\base + 24]
|
||||
vstr \vreg, [dst, #\base + 32]
|
||||
vstr d0, [dst, #\base + 40]
|
||||
vldr d0, [src, #\base + 40]
|
||||
vstr d1, [dst, #\base + 48]
|
||||
vldr d1, [src, #\base + 48]
|
||||
vstr d2, [dst, #\base + 56]
|
||||
vldr d2, [src, #\base + 56]
|
||||
.endm
|
||||
#endif
|
||||
|
||||
.p2align 6
|
||||
ENTRY(memcpy)
|
||||
|
||||
mov dst, dstin /* Preserve dstin, we need to return it. */
|
||||
cmp count, #64
|
||||
bge .Lcpy_not_short
|
||||
/* Deal with small copies quickly by dropping straight into the
|
||||
exit block. */
|
||||
|
||||
.Ltail63unaligned:
|
||||
#ifdef USE_NEON
|
||||
and tmp1, count, #0x38
|
||||
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
|
||||
add pc, pc, tmp1
|
||||
vld1.8 {d0}, [src]! /* 14 words to go. */
|
||||
vst1.8 {d0}, [dst]!
|
||||
vld1.8 {d0}, [src]! /* 12 words to go. */
|
||||
vst1.8 {d0}, [dst]!
|
||||
vld1.8 {d0}, [src]! /* 10 words to go. */
|
||||
vst1.8 {d0}, [dst]!
|
||||
vld1.8 {d0}, [src]! /* 8 words to go. */
|
||||
vst1.8 {d0}, [dst]!
|
||||
vld1.8 {d0}, [src]! /* 6 words to go. */
|
||||
vst1.8 {d0}, [dst]!
|
||||
vld1.8 {d0}, [src]! /* 4 words to go. */
|
||||
vst1.8 {d0}, [dst]!
|
||||
vld1.8 {d0}, [src]! /* 2 words to go. */
|
||||
vst1.8 {d0}, [dst]!
|
||||
|
||||
tst count, #4
|
||||
ldrne tmp1, [src], #4
|
||||
strne tmp1, [dst], #4
|
||||
#else
|
||||
/* Copy up to 15 full words of data. May not be aligned. */
|
||||
/* Cannot use VFP for unaligned data. */
|
||||
and tmp1, count, #0x3c
|
||||
add dst, dst, tmp1
|
||||
add src, src, tmp1
|
||||
rsb tmp1, tmp1, #(60 - PC_OFFSET/2 + INSN_SIZE/2)
|
||||
/* Jump directly into the sequence below at the correct offset. */
|
||||
add pc, pc, tmp1, lsl #1
|
||||
|
||||
ldr tmp1, [src, #-60] /* 15 words to go. */
|
||||
str tmp1, [dst, #-60]
|
||||
|
||||
ldr tmp1, [src, #-56] /* 14 words to go. */
|
||||
str tmp1, [dst, #-56]
|
||||
ldr tmp1, [src, #-52]
|
||||
str tmp1, [dst, #-52]
|
||||
|
||||
ldr tmp1, [src, #-48] /* 12 words to go. */
|
||||
str tmp1, [dst, #-48]
|
||||
ldr tmp1, [src, #-44]
|
||||
str tmp1, [dst, #-44]
|
||||
|
||||
ldr tmp1, [src, #-40] /* 10 words to go. */
|
||||
str tmp1, [dst, #-40]
|
||||
ldr tmp1, [src, #-36]
|
||||
str tmp1, [dst, #-36]
|
||||
|
||||
ldr tmp1, [src, #-32] /* 8 words to go. */
|
||||
str tmp1, [dst, #-32]
|
||||
ldr tmp1, [src, #-28]
|
||||
str tmp1, [dst, #-28]
|
||||
|
||||
ldr tmp1, [src, #-24] /* 6 words to go. */
|
||||
str tmp1, [dst, #-24]
|
||||
ldr tmp1, [src, #-20]
|
||||
str tmp1, [dst, #-20]
|
||||
|
||||
ldr tmp1, [src, #-16] /* 4 words to go. */
|
||||
str tmp1, [dst, #-16]
|
||||
ldr tmp1, [src, #-12]
|
||||
str tmp1, [dst, #-12]
|
||||
|
||||
ldr tmp1, [src, #-8] /* 2 words to go. */
|
||||
str tmp1, [dst, #-8]
|
||||
ldr tmp1, [src, #-4]
|
||||
str tmp1, [dst, #-4]
|
||||
#endif
|
||||
|
||||
lsls count, count, #31
|
||||
ldrhcs tmp1, [src], #2
|
||||
ldrbne src, [src] /* Src is dead, use as a scratch. */
|
||||
strhcs tmp1, [dst], #2
|
||||
strbne src, [dst]
|
||||
bx lr
|
||||
|
||||
.Lcpy_not_short:
|
||||
/* At least 64 bytes to copy, but don't know the alignment yet. */
|
||||
str tmp2, [sp, #-FRAME_SIZE]!
|
||||
and tmp2, src, #7
|
||||
and tmp1, dst, #7
|
||||
cmp tmp1, tmp2
|
||||
bne .Lcpy_notaligned
|
||||
|
||||
#ifdef USE_VFP
|
||||
/* Magic dust alert! Force VFP on Cortex-A9. Experiments show
|
||||
that the FP pipeline is much better at streaming loads and
|
||||
stores. This is outside the critical loop. */
|
||||
vmov.f32 s0, s0
|
||||
#endif
|
||||
|
||||
/* SRC and DST have the same mutual 32-bit alignment, but we may
|
||||
still need to pre-copy some bytes to get to natural alignment.
|
||||
We bring DST into full 64-bit alignment. */
|
||||
lsls tmp2, dst, #29
|
||||
beq 1f
|
||||
rsbs tmp2, tmp2, #0
|
||||
sub count, count, tmp2, lsr #29
|
||||
ldrmi tmp1, [src], #4
|
||||
strmi tmp1, [dst], #4
|
||||
lsls tmp2, tmp2, #2
|
||||
ldrhcs tmp1, [src], #2
|
||||
ldrbne tmp2, [src], #1
|
||||
strhcs tmp1, [dst], #2
|
||||
strbne tmp2, [dst], #1
|
||||
|
||||
1:
|
||||
subs tmp2, count, #64 /* Use tmp2 for count. */
|
||||
blt .Ltail63aligned
|
||||
|
||||
cmp tmp2, #512
|
||||
bge .Lcpy_body_long
|
||||
|
||||
.Lcpy_body_medium: /* Count in tmp2. */
|
||||
#ifdef USE_VFP
|
||||
1:
|
||||
vldr d0, [src, #0]
|
||||
subs tmp2, tmp2, #64
|
||||
vldr d1, [src, #8]
|
||||
vstr d0, [dst, #0]
|
||||
vldr d0, [src, #16]
|
||||
vstr d1, [dst, #8]
|
||||
vldr d1, [src, #24]
|
||||
vstr d0, [dst, #16]
|
||||
vldr d0, [src, #32]
|
||||
vstr d1, [dst, #24]
|
||||
vldr d1, [src, #40]
|
||||
vstr d0, [dst, #32]
|
||||
vldr d0, [src, #48]
|
||||
vstr d1, [dst, #40]
|
||||
vldr d1, [src, #56]
|
||||
vstr d0, [dst, #48]
|
||||
add src, src, #64
|
||||
vstr d1, [dst, #56]
|
||||
add dst, dst, #64
|
||||
bge 1b
|
||||
tst tmp2, #0x3f
|
||||
beq .Ldone
|
||||
|
||||
.Ltail63aligned: /* Count in tmp2. */
|
||||
and tmp1, tmp2, #0x38
|
||||
add dst, dst, tmp1
|
||||
add src, src, tmp1
|
||||
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
|
||||
add pc, pc, tmp1
|
||||
|
||||
vldr d0, [src, #-56] /* 14 words to go. */
|
||||
vstr d0, [dst, #-56]
|
||||
vldr d0, [src, #-48] /* 12 words to go. */
|
||||
vstr d0, [dst, #-48]
|
||||
vldr d0, [src, #-40] /* 10 words to go. */
|
||||
vstr d0, [dst, #-40]
|
||||
vldr d0, [src, #-32] /* 8 words to go. */
|
||||
vstr d0, [dst, #-32]
|
||||
vldr d0, [src, #-24] /* 6 words to go. */
|
||||
vstr d0, [dst, #-24]
|
||||
vldr d0, [src, #-16] /* 4 words to go. */
|
||||
vstr d0, [dst, #-16]
|
||||
vldr d0, [src, #-8] /* 2 words to go. */
|
||||
vstr d0, [dst, #-8]
|
||||
#else
|
||||
sub src, src, #8
|
||||
sub dst, dst, #8
|
||||
1:
|
||||
ldrd A_l, A_h, [src, #8]
|
||||
strd A_l, A_h, [dst, #8]
|
||||
ldrd A_l, A_h, [src, #16]
|
||||
strd A_l, A_h, [dst, #16]
|
||||
ldrd A_l, A_h, [src, #24]
|
||||
strd A_l, A_h, [dst, #24]
|
||||
ldrd A_l, A_h, [src, #32]
|
||||
strd A_l, A_h, [dst, #32]
|
||||
ldrd A_l, A_h, [src, #40]
|
||||
strd A_l, A_h, [dst, #40]
|
||||
ldrd A_l, A_h, [src, #48]
|
||||
strd A_l, A_h, [dst, #48]
|
||||
ldrd A_l, A_h, [src, #56]
|
||||
strd A_l, A_h, [dst, #56]
|
||||
ldrd A_l, A_h, [src, #64]!
|
||||
strd A_l, A_h, [dst, #64]!
|
||||
subs tmp2, tmp2, #64
|
||||
bge 1b
|
||||
tst tmp2, #0x3f
|
||||
bne 1f
|
||||
ldr tmp2,[sp], #FRAME_SIZE
|
||||
bx lr
|
||||
1:
|
||||
add src, src, #8
|
||||
add dst, dst, #8
|
||||
|
||||
.Ltail63aligned: /* Count in tmp2. */
|
||||
/* Copy up to 7 d-words of data. Similar to Ltail63unaligned, but
|
||||
we know that the src and dest are 32-bit aligned so we can use
|
||||
LDRD/STRD to improve efficiency. */
|
||||
/* TMP2 is now negative, but we don't care about that. The bottom
|
||||
six bits still tell us how many bytes are left to copy. */
|
||||
|
||||
and tmp1, tmp2, #0x38
|
||||
add dst, dst, tmp1
|
||||
add src, src, tmp1
|
||||
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
|
||||
add pc, pc, tmp1
|
||||
ldrd A_l, A_h, [src, #-56] /* 14 words to go. */
|
||||
strd A_l, A_h, [dst, #-56]
|
||||
ldrd A_l, A_h, [src, #-48] /* 12 words to go. */
|
||||
strd A_l, A_h, [dst, #-48]
|
||||
ldrd A_l, A_h, [src, #-40] /* 10 words to go. */
|
||||
strd A_l, A_h, [dst, #-40]
|
||||
ldrd A_l, A_h, [src, #-32] /* 8 words to go. */
|
||||
strd A_l, A_h, [dst, #-32]
|
||||
ldrd A_l, A_h, [src, #-24] /* 6 words to go. */
|
||||
strd A_l, A_h, [dst, #-24]
|
||||
ldrd A_l, A_h, [src, #-16] /* 4 words to go. */
|
||||
strd A_l, A_h, [dst, #-16]
|
||||
ldrd A_l, A_h, [src, #-8] /* 2 words to go. */
|
||||
strd A_l, A_h, [dst, #-8]
|
||||
|
||||
#endif
|
||||
tst tmp2, #4
|
||||
ldrne tmp1, [src], #4
|
||||
strne tmp1, [dst], #4
|
||||
lsls tmp2, tmp2, #31 /* Count (tmp2) now dead. */
|
||||
ldrhcs tmp1, [src], #2
|
||||
ldrbne tmp2, [src]
|
||||
strhcs tmp1, [dst], #2
|
||||
strbne tmp2, [dst]
|
||||
|
||||
.Ldone:
|
||||
ldr tmp2, [sp], #FRAME_SIZE
|
||||
bx lr
|
||||
|
||||
.Lcpy_body_long: /* Count in tmp2. */
|
||||
|
||||
/* Long copy. We know that there's at least (prefetch_lines * 64)
|
||||
bytes to go. */
|
||||
#ifdef USE_VFP
|
||||
/* Don't use PLD. Instead, read some data in advance of the current
|
||||
copy position into a register. This should act like a PLD
|
||||
operation but we won't have to repeat the transfer. */
|
||||
|
||||
vldr d3, [src, #0]
|
||||
vldr d4, [src, #64]
|
||||
vldr d5, [src, #128]
|
||||
vldr d6, [src, #192]
|
||||
vldr d7, [src, #256]
|
||||
|
||||
vldr d0, [src, #8]
|
||||
vldr d1, [src, #16]
|
||||
vldr d2, [src, #24]
|
||||
add src, src, #32
|
||||
|
||||
subs tmp2, tmp2, #prefetch_lines * 64 * 2
|
||||
blt 2f
|
||||
1:
|
||||
cpy_line_vfp d3, 0
|
||||
cpy_line_vfp d4, 64
|
||||
cpy_line_vfp d5, 128
|
||||
add dst, dst, #3 * 64
|
||||
add src, src, #3 * 64
|
||||
cpy_line_vfp d6, 0
|
||||
cpy_line_vfp d7, 64
|
||||
add dst, dst, #2 * 64
|
||||
add src, src, #2 * 64
|
||||
subs tmp2, tmp2, #prefetch_lines * 64
|
||||
bge 1b
|
||||
|
||||
2:
|
||||
cpy_tail_vfp d3, 0
|
||||
cpy_tail_vfp d4, 64
|
||||
cpy_tail_vfp d5, 128
|
||||
add src, src, #3 * 64
|
||||
add dst, dst, #3 * 64
|
||||
cpy_tail_vfp d6, 0
|
||||
vstr d7, [dst, #64]
|
||||
vldr d7, [src, #64]
|
||||
vstr d0, [dst, #64 + 8]
|
||||
vldr d0, [src, #64 + 8]
|
||||
vstr d1, [dst, #64 + 16]
|
||||
vldr d1, [src, #64 + 16]
|
||||
vstr d2, [dst, #64 + 24]
|
||||
vldr d2, [src, #64 + 24]
|
||||
vstr d7, [dst, #64 + 32]
|
||||
add src, src, #96
|
||||
vstr d0, [dst, #64 + 40]
|
||||
vstr d1, [dst, #64 + 48]
|
||||
vstr d2, [dst, #64 + 56]
|
||||
add dst, dst, #128
|
||||
add tmp2, tmp2, #prefetch_lines * 64
|
||||
b .Lcpy_body_medium
|
||||
#else
|
||||
/* Long copy. Use an SMS style loop to maximize the I/O
|
||||
bandwidth of the core. We don't have enough spare registers
|
||||
to synthesise prefetching, so use PLD operations. */
|
||||
/* Pre-bias src and dst. */
|
||||
sub src, src, #8
|
||||
sub dst, dst, #8
|
||||
pld [src, #8]
|
||||
pld [src, #72]
|
||||
subs tmp2, tmp2, #64
|
||||
pld [src, #136]
|
||||
ldrd A_l, A_h, [src, #8]
|
||||
strd B_l, B_h, [sp, #8]
|
||||
ldrd B_l, B_h, [src, #16]
|
||||
strd C_l, C_h, [sp, #16]
|
||||
ldrd C_l, C_h, [src, #24]
|
||||
strd D_l, D_h, [sp, #24]
|
||||
pld [src, #200]
|
||||
ldrd D_l, D_h, [src, #32]!
|
||||
b 1f
|
||||
.p2align 6
|
||||
2:
|
||||
pld [src, #232]
|
||||
strd A_l, A_h, [dst, #40]
|
||||
ldrd A_l, A_h, [src, #40]
|
||||
strd B_l, B_h, [dst, #48]
|
||||
ldrd B_l, B_h, [src, #48]
|
||||
strd C_l, C_h, [dst, #56]
|
||||
ldrd C_l, C_h, [src, #56]
|
||||
strd D_l, D_h, [dst, #64]!
|
||||
ldrd D_l, D_h, [src, #64]!
|
||||
subs tmp2, tmp2, #64
|
||||
1:
|
||||
strd A_l, A_h, [dst, #8]
|
||||
ldrd A_l, A_h, [src, #8]
|
||||
strd B_l, B_h, [dst, #16]
|
||||
ldrd B_l, B_h, [src, #16]
|
||||
strd C_l, C_h, [dst, #24]
|
||||
ldrd C_l, C_h, [src, #24]
|
||||
strd D_l, D_h, [dst, #32]
|
||||
ldrd D_l, D_h, [src, #32]
|
||||
bcs 2b
|
||||
/* Save the remaining bytes and restore the callee-saved regs. */
|
||||
strd A_l, A_h, [dst, #40]
|
||||
add src, src, #40
|
||||
strd B_l, B_h, [dst, #48]
|
||||
ldrd B_l, B_h, [sp, #8]
|
||||
strd C_l, C_h, [dst, #56]
|
||||
ldrd C_l, C_h, [sp, #16]
|
||||
strd D_l, D_h, [dst, #64]
|
||||
ldrd D_l, D_h, [sp, #24]
|
||||
add dst, dst, #72
|
||||
tst tmp2, #0x3f
|
||||
bne .Ltail63aligned
|
||||
ldr tmp2, [sp], #FRAME_SIZE
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
.Lcpy_notaligned:
|
||||
pld [src]
|
||||
pld [src, #64]
|
||||
/* There's at least 64 bytes to copy, but there is no mutual
|
||||
alignment. */
|
||||
/* Bring DST to 64-bit alignment. */
|
||||
lsls tmp2, dst, #29
|
||||
pld [src, #(2 * 64)]
|
||||
beq 1f
|
||||
rsbs tmp2, tmp2, #0
|
||||
sub count, count, tmp2, lsr #29
|
||||
ldrmi tmp1, [src], #4
|
||||
strmi tmp1, [dst], #4
|
||||
lsls tmp2, tmp2, #2
|
||||
ldrbne tmp1, [src], #1
|
||||
ldrhcs tmp2, [src], #2
|
||||
strbne tmp1, [dst], #1
|
||||
strhcs tmp2, [dst], #2
|
||||
1:
|
||||
pld [src, #(3 * 64)]
|
||||
subs count, count, #64
|
||||
ldrmi tmp2, [sp], #FRAME_SIZE
|
||||
bmi .Ltail63unaligned
|
||||
pld [src, #(4 * 64)]
|
||||
|
||||
#ifdef USE_NEON
|
||||
vld1.8 {d0-d3}, [src]!
|
||||
vld1.8 {d4-d7}, [src]!
|
||||
subs count, count, #64
|
||||
bmi 2f
|
||||
1:
|
||||
pld [src, #(4 * 64)]
|
||||
vst1.8 {d0-d3}, [ALIGN (dst, 64)]!
|
||||
vld1.8 {d0-d3}, [src]!
|
||||
vst1.8 {d4-d7}, [ALIGN (dst, 64)]!
|
||||
vld1.8 {d4-d7}, [src]!
|
||||
subs count, count, #64
|
||||
bpl 1b
|
||||
2:
|
||||
vst1.8 {d0-d3}, [ALIGN (dst, 64)]!
|
||||
vst1.8 {d4-d7}, [ALIGN (dst, 64)]!
|
||||
ands count, count, #0x3f
|
||||
#else
|
||||
/* Use an SMS style loop to maximize the I/O bandwidth. */
|
||||
sub src, src, #4
|
||||
sub dst, dst, #8
|
||||
subs tmp2, count, #64 /* Use tmp2 for count. */
|
||||
ldr A_l, [src, #4]
|
||||
ldr A_h, [src, #8]
|
||||
strd B_l, B_h, [sp, #8]
|
||||
ldr B_l, [src, #12]
|
||||
ldr B_h, [src, #16]
|
||||
strd C_l, C_h, [sp, #16]
|
||||
ldr C_l, [src, #20]
|
||||
ldr C_h, [src, #24]
|
||||
strd D_l, D_h, [sp, #24]
|
||||
ldr D_l, [src, #28]
|
||||
ldr D_h, [src, #32]!
|
||||
b 1f
|
||||
.p2align 6
|
||||
2:
|
||||
pld [src, #(5 * 64) - (32 - 4)]
|
||||
strd A_l, A_h, [dst, #40]
|
||||
ldr A_l, [src, #36]
|
||||
ldr A_h, [src, #40]
|
||||
strd B_l, B_h, [dst, #48]
|
||||
ldr B_l, [src, #44]
|
||||
ldr B_h, [src, #48]
|
||||
strd C_l, C_h, [dst, #56]
|
||||
ldr C_l, [src, #52]
|
||||
ldr C_h, [src, #56]
|
||||
strd D_l, D_h, [dst, #64]!
|
||||
ldr D_l, [src, #60]
|
||||
ldr D_h, [src, #64]!
|
||||
subs tmp2, tmp2, #64
|
||||
1:
|
||||
strd A_l, A_h, [dst, #8]
|
||||
ldr A_l, [src, #4]
|
||||
ldr A_h, [src, #8]
|
||||
strd B_l, B_h, [dst, #16]
|
||||
ldr B_l, [src, #12]
|
||||
ldr B_h, [src, #16]
|
||||
strd C_l, C_h, [dst, #24]
|
||||
ldr C_l, [src, #20]
|
||||
ldr C_h, [src, #24]
|
||||
strd D_l, D_h, [dst, #32]
|
||||
ldr D_l, [src, #28]
|
||||
ldr D_h, [src, #32]
|
||||
bcs 2b
|
||||
|
||||
/* Save the remaining bytes and restore the callee-saved regs. */
|
||||
strd A_l, A_h, [dst, #40]
|
||||
add src, src, #36
|
||||
strd B_l, B_h, [dst, #48]
|
||||
ldrd B_l, B_h, [sp, #8]
|
||||
strd C_l, C_h, [dst, #56]
|
||||
ldrd C_l, C_h, [sp, #16]
|
||||
strd D_l, D_h, [dst, #64]
|
||||
ldrd D_l, D_h, [sp, #24]
|
||||
add dst, dst, #72
|
||||
ands count, tmp2, #0x3f
|
||||
#endif
|
||||
ldr tmp2, [sp], #FRAME_SIZE
|
||||
bne .Ltail63unaligned
|
||||
bx lr
|
||||
END(memcpy)
|
@ -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
|
||||
};
|
@ -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.
|
||||
@ -32,203 +35,119 @@
|
||||
*/
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
#include <machine/setjmp.h>
|
||||
#include <machine/cpu-features.h>
|
||||
|
||||
// According to the ARM AAPCS document, we only need to save
|
||||
// the following registers:
|
||||
//
|
||||
// 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}
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset r14, 4
|
||||
mov r0, #0x00000000
|
||||
|
||||
bl PIC_SYM(sigblock, PLT)
|
||||
mov r1, r0
|
||||
|
||||
ldmfd sp!, {r0, r14}
|
||||
.cfi_def_cfa_offset 0
|
||||
|
||||
/* 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}
|
||||
.cfi_def_cfa_offset 12
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset r1, 4
|
||||
.cfi_rel_offset r14, 8
|
||||
sub sp, sp, #4 /* align the stack */
|
||||
.cfi_adjust_cfa_offset 4
|
||||
|
||||
mov r0, r2
|
||||
bl PIC_SYM(sigsetmask, PLT)
|
||||
|
||||
add sp, sp, #4 /* unalign the stack */
|
||||
.cfi_adjust_cfa_offset -4
|
||||
ldmfd sp!, {r0, r1, r14}
|
||||
.cfi_def_cfa_offset 0
|
||||
|
||||
#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(longjmperror, PLT)
|
||||
bl PIC_SYM(abort, PLT)
|
||||
b . - 8 /* Cannot get here */
|
||||
END(longjmp)
|
||||
|
66
libc/arch-arm/bionic/sigsetjmp.S
Normal file
66
libc/arch-arm/bionic/sigsetjmp.S
Normal file
@ -0,0 +1,66 @@
|
||||
/* $OpenBSD: sigsetjmp.S,v 1.2 2004/02/01 05:40:52 drahn Exp $ */
|
||||
/* $NetBSD: sigsetjmp.S,v 1.3 2002/08/17 19:54:30 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997 Mark Brinicombe
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Mark Brinicombe
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define _ALIGN_TEXT .align 0
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
#include <machine/setjmp.h>
|
||||
|
||||
/*
|
||||
* C library -- sigsetjmp, siglongjmp
|
||||
*
|
||||
* longjmp(a,v)
|
||||
* will generate a "return(v)" from the last call to
|
||||
* setjmp(a, m)
|
||||
* by restoring registers from the stack.
|
||||
* The previous signal state is restored.
|
||||
*/
|
||||
|
||||
ENTRY(sigsetjmp)
|
||||
teq r1, #0
|
||||
beq PIC_SYM(_setjmp, PLT)
|
||||
b PIC_SYM(setjmp, PLT)
|
||||
END(sigsetjmp)
|
||||
|
||||
.L_setjmp_magic:
|
||||
.word _JB_MAGIC__SETJMP
|
||||
|
||||
ENTRY(siglongjmp)
|
||||
ldr r2, .L_setjmp_magic
|
||||
ldr r3, [r0]
|
||||
teq r2, r3
|
||||
beq PIC_SYM(_longjmp, PLT)
|
||||
b PIC_SYM(longjmp, PLT)
|
||||
END(siglongjmp)
|
317
libc/arch-arm/bionic/strcmp.S
Normal file
317
libc/arch-arm/bionic/strcmp.S
Normal file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The Android Open Source Project
|
||||
* Copyright (c) 2008 ARM Ltd
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the company may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <machine/cpu-features.h>
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
.text
|
||||
|
||||
#ifdef __ARMEB__
|
||||
#define SHFT2LSB lsl
|
||||
#define SHFT2LSBEQ lsleq
|
||||
#define SHFT2MSB lsr
|
||||
#define SHFT2MSBEQ lsreq
|
||||
#define MSB 0x000000ff
|
||||
#define LSB 0xff000000
|
||||
#else
|
||||
#define SHFT2LSB lsr
|
||||
#define SHFT2LSBEQ lsreq
|
||||
#define SHFT2MSB lsl
|
||||
#define SHFT2MSBEQ lsleq
|
||||
#define MSB 0xff000000
|
||||
#define LSB 0x000000ff
|
||||
#endif
|
||||
|
||||
#define magic1(REG) REG
|
||||
#define magic2(REG) REG, lsl #7
|
||||
|
||||
ENTRY(strcmp)
|
||||
pld [r0, #0]
|
||||
pld [r1, #0]
|
||||
eor r2, r0, r1
|
||||
tst r2, #3
|
||||
|
||||
/* Strings not at same byte offset from a word boundary. */
|
||||
bne .Lstrcmp_unaligned
|
||||
ands r2, r0, #3
|
||||
bic r0, r0, #3
|
||||
bic r1, r1, #3
|
||||
ldr ip, [r0], #4
|
||||
it eq
|
||||
ldreq r3, [r1], #4
|
||||
beq 1f
|
||||
|
||||
/* Although s1 and s2 have identical initial alignment, they are
|
||||
* not currently word aligned. Rather than comparing bytes,
|
||||
* make sure that any bytes fetched from before the addressed
|
||||
* bytes are forced to 0xff. Then they will always compare
|
||||
* equal.
|
||||
*/
|
||||
eor r2, r2, #3
|
||||
lsl r2, r2, #3
|
||||
mvn r3, #MSB
|
||||
SHFT2LSB r2, r3, r2
|
||||
ldr r3, [r1], #4
|
||||
orr ip, ip, r2
|
||||
orr r3, r3, r2
|
||||
1:
|
||||
/* Load the 'magic' constant 0x01010101. */
|
||||
str r4, [sp, #-4]!
|
||||
mov r4, #1
|
||||
orr r4, r4, r4, lsl #8
|
||||
orr r4, r4, r4, lsl #16
|
||||
.p2align 2
|
||||
4:
|
||||
pld [r0, #8]
|
||||
pld [r1, #8]
|
||||
sub r2, ip, magic1(r4)
|
||||
cmp ip, r3
|
||||
itttt eq
|
||||
|
||||
/* check for any zero bytes in first word */
|
||||
biceq r2, r2, ip
|
||||
tsteq r2, magic2(r4)
|
||||
ldreq ip, [r0], #4
|
||||
ldreq r3, [r1], #4
|
||||
beq 4b
|
||||
2:
|
||||
/* There's a zero or a different byte in the word */
|
||||
SHFT2MSB r0, ip, #24
|
||||
SHFT2LSB ip, ip, #8
|
||||
cmp r0, #1
|
||||
it cs
|
||||
cmpcs r0, r3, SHFT2MSB #24
|
||||
it eq
|
||||
SHFT2LSBEQ r3, r3, #8
|
||||
beq 2b
|
||||
/* On a big-endian machine, r0 contains the desired byte in bits
|
||||
* 0-7; on a little-endian machine they are in bits 24-31. In
|
||||
* both cases the other bits in r0 are all zero. For r3 the
|
||||
* interesting byte is at the other end of the word, but the
|
||||
* other bits are not necessarily zero. We need a signed result
|
||||
* representing the differnece in the unsigned bytes, so for the
|
||||
* little-endian case we can't just shift the interesting bits up.
|
||||
*/
|
||||
#ifdef __ARMEB__
|
||||
sub r0, r0, r3, lsr #24
|
||||
#else
|
||||
and r3, r3, #255
|
||||
/* No RSB instruction in Thumb2 */
|
||||
#ifdef __thumb2__
|
||||
lsr r0, r0, #24
|
||||
sub r0, r0, r3
|
||||
#else
|
||||
rsb r0, r3, r0, lsr #24
|
||||
#endif
|
||||
#endif
|
||||
ldr r4, [sp], #4
|
||||
bx lr
|
||||
|
||||
.Lstrcmp_unaligned:
|
||||
wp1 .req r0
|
||||
wp2 .req r1
|
||||
b1 .req r2
|
||||
w1 .req r4
|
||||
w2 .req r5
|
||||
t1 .req ip
|
||||
@ r3 is scratch
|
||||
|
||||
/* First of all, compare bytes until wp1(sp1) is word-aligned. */
|
||||
1:
|
||||
tst wp1, #3
|
||||
beq 2f
|
||||
ldrb r2, [wp1], #1
|
||||
ldrb r3, [wp2], #1
|
||||
cmp r2, #1
|
||||
it cs
|
||||
cmpcs r2, r3
|
||||
beq 1b
|
||||
sub r0, r2, r3
|
||||
bx lr
|
||||
|
||||
2:
|
||||
str r5, [sp, #-4]!
|
||||
str r4, [sp, #-4]!
|
||||
mov b1, #1
|
||||
orr b1, b1, b1, lsl #8
|
||||
orr b1, b1, b1, lsl #16
|
||||
|
||||
and t1, wp2, #3
|
||||
bic wp2, wp2, #3
|
||||
ldr w1, [wp1], #4
|
||||
ldr w2, [wp2], #4
|
||||
cmp t1, #2
|
||||
beq 2f
|
||||
bhi 3f
|
||||
|
||||
/* Critical inner Loop: Block with 3 bytes initial overlap */
|
||||
.p2align 2
|
||||
1:
|
||||
bic t1, w1, #MSB
|
||||
cmp t1, w2, SHFT2LSB #8
|
||||
sub r3, w1, b1
|
||||
bic r3, r3, w1
|
||||
bne 4f
|
||||
ands r3, r3, b1, lsl #7
|
||||
it eq
|
||||
ldreq w2, [wp2], #4
|
||||
bne 5f
|
||||
eor t1, t1, w1
|
||||
cmp t1, w2, SHFT2MSB #24
|
||||
bne 6f
|
||||
ldr w1, [wp1], #4
|
||||
b 1b
|
||||
4:
|
||||
SHFT2LSB w2, w2, #8
|
||||
b 8f
|
||||
|
||||
5:
|
||||
#ifdef __ARMEB__
|
||||
/* The syndrome value may contain false ones if the string ends
|
||||
* with the bytes 0x01 0x00
|
||||
*/
|
||||
tst w1, #0xff000000
|
||||
itt ne
|
||||
tstne w1, #0x00ff0000
|
||||
tstne w1, #0x0000ff00
|
||||
beq 7f
|
||||
#else
|
||||
bics r3, r3, #0xff000000
|
||||
bne 7f
|
||||
#endif
|
||||
ldrb w2, [wp2]
|
||||
SHFT2LSB t1, w1, #24
|
||||
#ifdef __ARMEB__
|
||||
lsl w2, w2, #24
|
||||
#endif
|
||||
b 8f
|
||||
|
||||
6:
|
||||
SHFT2LSB t1, w1, #24
|
||||
and w2, w2, #LSB
|
||||
b 8f
|
||||
|
||||
/* Critical inner Loop: Block with 2 bytes initial overlap */
|
||||
.p2align 2
|
||||
2:
|
||||
SHFT2MSB t1, w1, #16
|
||||
sub r3, w1, b1
|
||||
SHFT2LSB t1, t1, #16
|
||||
bic r3, r3, w1
|
||||
cmp t1, w2, SHFT2LSB #16
|
||||
bne 4f
|
||||
ands r3, r3, b1, lsl #7
|
||||
it eq
|
||||
ldreq w2, [wp2], #4
|
||||
bne 5f
|
||||
eor t1, t1, w1
|
||||
cmp t1, w2, SHFT2MSB #16
|
||||
bne 6f
|
||||
ldr w1, [wp1], #4
|
||||
b 2b
|
||||
|
||||
5:
|
||||
#ifdef __ARMEB__
|
||||
/* The syndrome value may contain false ones if the string ends
|
||||
* with the bytes 0x01 0x00
|
||||
*/
|
||||
tst w1, #0xff000000
|
||||
it ne
|
||||
tstne w1, #0x00ff0000
|
||||
beq 7f
|
||||
#else
|
||||
lsls r3, r3, #16
|
||||
bne 7f
|
||||
#endif
|
||||
ldrh w2, [wp2]
|
||||
SHFT2LSB t1, w1, #16
|
||||
#ifdef __ARMEB__
|
||||
lsl w2, w2, #16
|
||||
#endif
|
||||
b 8f
|
||||
|
||||
6:
|
||||
SHFT2MSB w2, w2, #16
|
||||
SHFT2LSB t1, w1, #16
|
||||
4:
|
||||
SHFT2LSB w2, w2, #16
|
||||
b 8f
|
||||
|
||||
/* Critical inner Loop: Block with 1 byte initial overlap */
|
||||
.p2align 2
|
||||
3:
|
||||
and t1, w1, #LSB
|
||||
cmp t1, w2, SHFT2LSB #24
|
||||
sub r3, w1, b1
|
||||
bic r3, r3, w1
|
||||
bne 4f
|
||||
ands r3, r3, b1, lsl #7
|
||||
it eq
|
||||
ldreq w2, [wp2], #4
|
||||
bne 5f
|
||||
eor t1, t1, w1
|
||||
cmp t1, w2, SHFT2MSB #8
|
||||
bne 6f
|
||||
ldr w1, [wp1], #4
|
||||
b 3b
|
||||
4:
|
||||
SHFT2LSB w2, w2, #24
|
||||
b 8f
|
||||
5:
|
||||
/* The syndrome value may contain false ones if the string ends
|
||||
* with the bytes 0x01 0x00
|
||||
*/
|
||||
tst w1, #LSB
|
||||
beq 7f
|
||||
ldr w2, [wp2], #4
|
||||
6:
|
||||
SHFT2LSB t1, w1, #8
|
||||
bic w2, w2, #MSB
|
||||
b 8f
|
||||
7:
|
||||
mov r0, #0
|
||||
ldr r4, [sp], #4
|
||||
ldr r5, [sp], #4
|
||||
bx lr
|
||||
|
||||
8:
|
||||
and r2, t1, #LSB
|
||||
and r0, w2, #LSB
|
||||
cmp r0, #1
|
||||
it cs
|
||||
cmpcs r0, r2
|
||||
itt eq
|
||||
SHFT2LSBEQ t1, t1, #8
|
||||
SHFT2LSBEQ w2, w2, #8
|
||||
beq 8b
|
||||
sub r0, r2, r0
|
||||
ldr r4, [sp], #4
|
||||
ldr r5, [sp], #4
|
||||
bx lr
|
||||
END(strcmp)
|
@ -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,191 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Indicate which memcpy base file to include.
|
||||
#define MEMCPY_BASE "memcpy_base.S"
|
||||
#include <private/bionic_asm.h>
|
||||
#include <private/libc_events.h>
|
||||
|
||||
#include "__strcat_chk_common.S"
|
||||
.syntax unified
|
||||
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
// Get the length of src string, then get the source of the dst string.
|
||||
// Check that the two lengths together don't exceed the threshold, then
|
||||
// do a memcpy of the data.
|
||||
ENTRY(__strcat_chk)
|
||||
pld [r0, #0]
|
||||
push {r0, lr}
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset lr, 4
|
||||
push {r4, r5}
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.cfi_rel_offset r4, 0
|
||||
.cfi_rel_offset r5, 4
|
||||
|
||||
mov lr, r2
|
||||
|
||||
// Save the dst register to r5
|
||||
mov r5, r0
|
||||
|
||||
// Zero out r4
|
||||
eor r4, r4, r4
|
||||
|
||||
// r1 contains the address of the string to count.
|
||||
.L_strlen_start:
|
||||
mov r0, r1
|
||||
ands r3, r1, #7
|
||||
beq .L_mainloop
|
||||
|
||||
// Align to a double word (64 bits).
|
||||
rsb r3, r3, #8
|
||||
lsls ip, r3, #31
|
||||
beq .L_align_to_32
|
||||
|
||||
ldrb r2, [r1], #1
|
||||
cbz r2, .L_update_count_and_finish
|
||||
|
||||
.L_align_to_32:
|
||||
bcc .L_align_to_64
|
||||
ands ip, r3, #2
|
||||
beq .L_align_to_64
|
||||
|
||||
ldrb r2, [r1], #1
|
||||
cbz r2, .L_update_count_and_finish
|
||||
ldrb r2, [r1], #1
|
||||
cbz r2, .L_update_count_and_finish
|
||||
|
||||
.L_align_to_64:
|
||||
tst r3, #4
|
||||
beq .L_mainloop
|
||||
ldr r3, [r1], #4
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne .L_zero_in_second_register
|
||||
|
||||
.p2align 2
|
||||
.L_mainloop:
|
||||
ldrd r2, r3, [r1], #8
|
||||
|
||||
pld [r1, #64]
|
||||
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne .L_zero_in_first_register
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne .L_zero_in_second_register
|
||||
b .L_mainloop
|
||||
|
||||
.L_update_count_and_finish:
|
||||
sub r3, r1, r0
|
||||
sub r3, r3, #1
|
||||
b .L_finish
|
||||
|
||||
.L_zero_in_first_register:
|
||||
sub r3, r1, r0
|
||||
lsls r2, ip, #17
|
||||
bne .L_sub8_and_finish
|
||||
bcs .L_sub7_and_finish
|
||||
lsls ip, ip, #1
|
||||
bne .L_sub6_and_finish
|
||||
|
||||
sub r3, r3, #5
|
||||
b .L_finish
|
||||
|
||||
.L_sub8_and_finish:
|
||||
sub r3, r3, #8
|
||||
b .L_finish
|
||||
|
||||
.L_sub7_and_finish:
|
||||
sub r3, r3, #7
|
||||
b .L_finish
|
||||
|
||||
.L_sub6_and_finish:
|
||||
sub r3, r3, #6
|
||||
b .L_finish
|
||||
|
||||
.L_zero_in_second_register:
|
||||
sub r3, r1, r0
|
||||
lsls r2, ip, #17
|
||||
bne .L_sub4_and_finish
|
||||
bcs .L_sub3_and_finish
|
||||
lsls ip, ip, #1
|
||||
bne .L_sub2_and_finish
|
||||
|
||||
sub r3, r3, #1
|
||||
b .L_finish
|
||||
|
||||
.L_sub4_and_finish:
|
||||
sub r3, r3, #4
|
||||
b .L_finish
|
||||
|
||||
.L_sub3_and_finish:
|
||||
sub r3, r3, #3
|
||||
b .L_finish
|
||||
|
||||
.L_sub2_and_finish:
|
||||
sub r3, r3, #2
|
||||
|
||||
.L_finish:
|
||||
cmp r4, #0
|
||||
bne .L_strlen_done
|
||||
|
||||
// Time to get the dst string length.
|
||||
mov r1, r5
|
||||
|
||||
// Save the original source address to r5.
|
||||
mov r5, r0
|
||||
|
||||
// Save the current length (adding 1 for the terminator).
|
||||
add r4, r3, #1
|
||||
b .L_strlen_start
|
||||
|
||||
// r0 holds the pointer to the dst string.
|
||||
// r3 holds the dst string length.
|
||||
// r4 holds the src string length + 1.
|
||||
.L_strlen_done:
|
||||
add r2, r3, r4
|
||||
cmp r2, lr
|
||||
bhi __strcat_chk_failed
|
||||
|
||||
// Set up the registers for the memcpy code.
|
||||
mov r1, r5
|
||||
pld [r1, #64]
|
||||
mov r2, r4
|
||||
add r0, r0, r3
|
||||
pop {r4, r5}
|
||||
END(__strcat_chk)
|
||||
|
||||
#define MEMCPY_BASE __strcat_chk_memcpy_base
|
||||
#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
|
||||
|
||||
#include "memcpy_base.S"
|
||||
|
||||
ENTRY_PRIVATE(__strcat_chk_failed)
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset lr, 4
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.cfi_rel_offset r4, 0
|
||||
.cfi_rel_offset r5, 4
|
||||
|
||||
ldr r0, error_message
|
||||
ldr r1, error_code
|
||||
1:
|
||||
add r0, pc
|
||||
bl __fortify_chk_fail
|
||||
error_code:
|
||||
.word BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
|
||||
error_message:
|
||||
.word error_string-(1b+4)
|
||||
END(__strcat_chk_failed)
|
||||
|
||||
.data
|
||||
error_string:
|
||||
.string "strcat: prevented write past end of buffer"
|
||||
|
@ -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"
|
@ -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,155 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Indicate which memcpy base file to include.
|
||||
#define MEMCPY_BASE "memcpy_base.S"
|
||||
#include <private/bionic_asm.h>
|
||||
#include <private/libc_events.h>
|
||||
|
||||
#include "__strcpy_chk_common.S"
|
||||
.syntax unified
|
||||
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
// Get the length of the source string first, then do a memcpy of the data
|
||||
// instead of a strcpy.
|
||||
ENTRY(__strcpy_chk)
|
||||
pld [r0, #0]
|
||||
push {r0, lr}
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset lr, 4
|
||||
|
||||
mov lr, r2
|
||||
mov r0, r1
|
||||
|
||||
ands r3, r1, #7
|
||||
beq .L_mainloop
|
||||
|
||||
// Align to a double word (64 bits).
|
||||
rsb r3, r3, #8
|
||||
lsls ip, r3, #31
|
||||
beq .L_align_to_32
|
||||
|
||||
ldrb r2, [r0], #1
|
||||
cbz r2, .L_update_count_and_finish
|
||||
|
||||
.L_align_to_32:
|
||||
bcc .L_align_to_64
|
||||
ands ip, r3, #2
|
||||
beq .L_align_to_64
|
||||
|
||||
ldrb r2, [r0], #1
|
||||
cbz r2, .L_update_count_and_finish
|
||||
ldrb r2, [r0], #1
|
||||
cbz r2, .L_update_count_and_finish
|
||||
|
||||
.L_align_to_64:
|
||||
tst r3, #4
|
||||
beq .L_mainloop
|
||||
ldr r3, [r0], #4
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne .L_zero_in_second_register
|
||||
|
||||
.p2align 2
|
||||
.L_mainloop:
|
||||
ldrd r2, r3, [r0], #8
|
||||
|
||||
pld [r0, #64]
|
||||
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne .L_zero_in_first_register
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne .L_zero_in_second_register
|
||||
b .L_mainloop
|
||||
|
||||
.L_update_count_and_finish:
|
||||
sub r3, r0, r1
|
||||
sub r3, r3, #1
|
||||
b .L_check_size
|
||||
|
||||
.L_zero_in_first_register:
|
||||
sub r3, r0, r1
|
||||
lsls r2, ip, #17
|
||||
bne .L_sub8_and_finish
|
||||
bcs .L_sub7_and_finish
|
||||
lsls ip, ip, #1
|
||||
bne .L_sub6_and_finish
|
||||
|
||||
sub r3, r3, #5
|
||||
b .L_check_size
|
||||
|
||||
.L_sub8_and_finish:
|
||||
sub r3, r3, #8
|
||||
b .L_check_size
|
||||
|
||||
.L_sub7_and_finish:
|
||||
sub r3, r3, #7
|
||||
b .L_check_size
|
||||
|
||||
.L_sub6_and_finish:
|
||||
sub r3, r3, #6
|
||||
b .L_check_size
|
||||
|
||||
.L_zero_in_second_register:
|
||||
sub r3, r0, r1
|
||||
lsls r2, ip, #17
|
||||
bne .L_sub4_and_finish
|
||||
bcs .L_sub3_and_finish
|
||||
lsls ip, ip, #1
|
||||
bne .L_sub2_and_finish
|
||||
|
||||
sub r3, r3, #1
|
||||
b .L_check_size
|
||||
|
||||
.L_sub4_and_finish:
|
||||
sub r3, r3, #4
|
||||
b .L_check_size
|
||||
|
||||
.L_sub3_and_finish:
|
||||
sub r3, r3, #3
|
||||
b .L_check_size
|
||||
|
||||
.L_sub2_and_finish:
|
||||
sub r3, r3, #2
|
||||
|
||||
.L_check_size:
|
||||
pld [r1, #0]
|
||||
pld [r1, #64]
|
||||
ldr r0, [sp]
|
||||
cmp r3, lr
|
||||
bhs __strcpy_chk_failed
|
||||
|
||||
// Add 1 for copy length to get the string terminator.
|
||||
add r2, r3, #1
|
||||
END(__strcpy_chk)
|
||||
|
||||
#define MEMCPY_BASE __strcpy_chk_memcpy_base
|
||||
#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
|
||||
#include "memcpy_base.S"
|
||||
|
||||
ENTRY_PRIVATE(__strcpy_chk_failed)
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset lr, 4
|
||||
|
||||
ldr r0, error_message
|
||||
ldr r1, error_code
|
||||
1:
|
||||
add r0, pc
|
||||
bl __fortify_chk_fail
|
||||
error_code:
|
||||
.word BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
|
||||
error_message:
|
||||
.word error_string-(1b+4)
|
||||
END(__strcpy_chk_failed)
|
||||
|
||||
.data
|
||||
error_string:
|
||||
.string "strcpy: prevented write past end of buffer"
|
||||
|
@ -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"
|
@ -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,79 @@
|
||||
* 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 <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"
|
||||
|
@ -53,7 +53,11 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
.L_memcpy_base:
|
||||
ENTRY_PRIVATE(MEMCPY_BASE)
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset lr, 4
|
||||
|
||||
// Assumes that n >= 0, and dst, src are valid pointers.
|
||||
// For any sizes less than 832 use the neon code that doesn't
|
||||
// care about the src alignment. This avoids any checks
|
||||
@ -164,6 +168,12 @@
|
||||
eor r3, r0, r1
|
||||
ands r3, r3, #0x3
|
||||
bne .L_copy_unknown_alignment
|
||||
END(MEMCPY_BASE)
|
||||
|
||||
ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED)
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset lr, 4
|
||||
|
||||
// To try and improve performance, stack layout changed,
|
||||
// i.e., not keeping the stack looking like users expect
|
||||
@ -175,7 +185,7 @@
|
||||
strd r6, r7, [sp, #-8]!
|
||||
.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]!
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.cfi_rel_offset r8, 0
|
||||
@ -281,28 +291,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
|
||||
@ -323,12 +315,4 @@
|
||||
|
||||
// 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
|
||||
END(MEMCPY_BASE_ALIGNED)
|
||||
|
@ -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"
|
@ -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)
|
||||
|
@ -149,20 +149,13 @@ ENTRY(strcpy)
|
||||
.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
|
||||
ldr r2, [r1], #4
|
||||
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne .Lstringcopy_zero_in_first_register
|
||||
str r2, [r0], #4
|
||||
|
||||
.Lstringcopy_check_src_align:
|
||||
// At this point dst is aligned to a double word, check if src
|
||||
|
@ -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)
|
||||
|
@ -1,17 +1,3 @@
|
||||
libc_openbsd_src_files_exclude_arm += \
|
||||
upstream-openbsd/lib/libc/string/memmove.c \
|
||||
upstream-openbsd/lib/libc/string/stpcpy.c \
|
||||
upstream-openbsd/lib/libc/string/strcat.c \
|
||||
|
||||
libc_bionic_src_files_exclude_arm += \
|
||||
arch-arm/generic/bionic/memcpy.S \
|
||||
arch-arm/generic/bionic/memset.S \
|
||||
arch-arm/generic/bionic/strcmp.S \
|
||||
arch-arm/generic/bionic/strcpy.S \
|
||||
arch-arm/generic/bionic/strlen.c \
|
||||
bionic/__strcat_chk.cpp \
|
||||
bionic/__strcpy_chk.cpp \
|
||||
|
||||
libc_bionic_src_files_arm += \
|
||||
arch-arm/cortex-a15/bionic/memcpy.S \
|
||||
arch-arm/cortex-a15/bionic/memset.S \
|
||||
@ -22,6 +8,4 @@ libc_bionic_src_files_arm += \
|
||||
arch-arm/cortex-a15/bionic/strcpy.S \
|
||||
arch-arm/cortex-a15/bionic/__strcpy_chk.S \
|
||||
arch-arm/cortex-a15/bionic/strlen.S \
|
||||
|
||||
libc_bionic_src_files_arm += \
|
||||
arch-arm/denver/bionic/memmove.S \
|
||||
bionic/memmove.c \
|
||||
|
@ -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 \
|
@ -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"
|
@ -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"
|
@ -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}
|
@ -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 \
|
@ -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"
|
@ -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
|
||||
|
@ -44,7 +44,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,7 +133,8 @@ ENTRY_PRIVATE(MEMCPY_BASE)
|
||||
strbcs ip, [r0], #1
|
||||
strbcs lr, [r0], #1
|
||||
|
||||
ldmfd sp!, {r0, pc}
|
||||
ldmfd sp!, {r0, lr}
|
||||
bx lr
|
||||
END(MEMCPY_BASE)
|
||||
|
||||
ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED)
|
||||
|
@ -35,7 +35,6 @@
|
||||
*/
|
||||
|
||||
.fpu neon
|
||||
.syntax unified
|
||||
|
||||
ENTRY(__memset_chk)
|
||||
cmp r2, r3
|
||||
@ -69,9 +68,12 @@ END(bzero)
|
||||
ENTRY(memset)
|
||||
// The neon memset only wins for less than 132.
|
||||
cmp r2, #132
|
||||
bhi .L_memset_large_copy
|
||||
bhi __memset_large_copy
|
||||
|
||||
stmfd sp!, {r0}
|
||||
.cfi_def_cfa_offset 4
|
||||
.cfi_rel_offset r0, 0
|
||||
|
||||
mov r3, r0
|
||||
vdup.8 q0, r1
|
||||
|
||||
/* make sure we have at least 32 bytes to write */
|
||||
@ -81,7 +83,7 @@ ENTRY(memset)
|
||||
|
||||
1: /* The main loop writes 32 bytes at a time */
|
||||
subs r2, r2, #32
|
||||
vst1.8 {d0 - d3}, [r3]!
|
||||
vst1.8 {d0 - d3}, [r0]!
|
||||
bhs 1b
|
||||
|
||||
2: /* less than 32 left */
|
||||
@ -90,20 +92,22 @@ 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
|
||||
END(memset)
|
||||
|
||||
.L_memset_large_copy:
|
||||
ENTRY_PRIVATE(__memset_large_copy)
|
||||
/* compute the offset to align the destination
|
||||
* offset = (4-(src&3))&3 = -src & 3
|
||||
*/
|
||||
@ -127,11 +131,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 +155,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,15 +172,16 @@ 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
|
||||
END(__memset_large_copy)
|
||||
|
||||
.data
|
||||
error_string:
|
||||
|
@ -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)
|
||||
|
@ -244,20 +244,13 @@ ENTRY(strcpy)
|
||||
.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
|
||||
ldr r2, [r1], #4
|
||||
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne .Lstringcopy_zero_in_first_register
|
||||
stmia r0!, {r2}
|
||||
b .Lstringcopy_check_src_align
|
||||
|
||||
.Lstringcopy_complete:
|
||||
|
@ -1,18 +1,3 @@
|
||||
libc_openbsd_src_files_exclude_arm += \
|
||||
upstream-openbsd/lib/libc/string/memmove.c \
|
||||
upstream-openbsd/lib/libc/string/stpcpy.c \
|
||||
upstream-openbsd/lib/libc/string/strcat.c \
|
||||
upstream-openbsd/lib/libc/string/strcpy.c \
|
||||
|
||||
libc_bionic_src_files_exclude_arm += \
|
||||
arch-arm/generic/bionic/memcpy.S \
|
||||
arch-arm/generic/bionic/memset.S \
|
||||
arch-arm/generic/bionic/strcmp.S \
|
||||
arch-arm/generic/bionic/strcpy.S \
|
||||
arch-arm/generic/bionic/strlen.c \
|
||||
bionic/__strcat_chk.cpp \
|
||||
bionic/__strcpy_chk.cpp \
|
||||
|
||||
libc_bionic_src_files_arm += \
|
||||
arch-arm/cortex-a9/bionic/memcpy.S \
|
||||
arch-arm/cortex-a9/bionic/memset.S \
|
||||
@ -23,6 +8,4 @@ libc_bionic_src_files_arm += \
|
||||
arch-arm/cortex-a9/bionic/strcpy.S \
|
||||
arch-arm/cortex-a9/bionic/__strcpy_chk.S \
|
||||
arch-arm/cortex-a9/bionic/strlen.S \
|
||||
|
||||
libc_bionic_src_files_arm += \
|
||||
arch-arm/denver/bionic/memmove.S \
|
||||
bionic/memmove.c \
|
||||
|
@ -37,7 +37,6 @@
|
||||
* memset() returns its first argument.
|
||||
*/
|
||||
|
||||
.cpu cortex-a15
|
||||
.fpu neon
|
||||
.syntax unified
|
||||
|
||||
|
@ -1,17 +1,3 @@
|
||||
libc_openbsd_src_files_exclude_arm += \
|
||||
upstream-openbsd/lib/libc/string/memmove.c \
|
||||
upstream-openbsd/lib/libc/string/stpcpy.c \
|
||||
upstream-openbsd/lib/libc/string/strcat.c \
|
||||
|
||||
libc_bionic_src_files_exclude_arm += \
|
||||
arch-arm/generic/bionic/memcpy.S \
|
||||
arch-arm/generic/bionic/memset.S \
|
||||
arch-arm/generic/bionic/strcmp.S \
|
||||
arch-arm/generic/bionic/strcpy.S \
|
||||
arch-arm/generic/bionic/strlen.c \
|
||||
bionic/__strcat_chk.cpp \
|
||||
bionic/__strcpy_chk.cpp \
|
||||
|
||||
libc_bionic_src_files_arm += \
|
||||
arch-arm/denver/bionic/memcpy.S \
|
||||
arch-arm/denver/bionic/memmove.S \
|
||||
|
@ -37,8 +37,6 @@
|
||||
* so we have to preserve R0.
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
|
||||
ENTRY(__memcpy_chk)
|
||||
cmp r2, r3
|
||||
bhi __memcpy_chk_fail
|
||||
@ -83,12 +81,12 @@ ENTRY(memcpy)
|
||||
*/
|
||||
movs r12, r3, lsl #31
|
||||
sub r2, r2, r3 /* we know that r3 <= r2 because r2 >= 4 */
|
||||
ldrbmi r3, [r1], #1
|
||||
ldrbcs r4, [r1], #1
|
||||
ldrbcs r12,[r1], #1
|
||||
strbmi r3, [r0], #1
|
||||
strbcs r4, [r0], #1
|
||||
strbcs r12,[r0], #1
|
||||
ldrmib r3, [r1], #1
|
||||
ldrcsb r4, [r1], #1
|
||||
ldrcsb r12,[r1], #1
|
||||
strmib r3, [r0], #1
|
||||
strcsb r4, [r0], #1
|
||||
strcsb r12,[r0], #1
|
||||
|
||||
.Lsrc_aligned:
|
||||
|
||||
@ -111,10 +109,10 @@ ENTRY(memcpy)
|
||||
|
||||
/* conditionally copies 0 to 7 words (length in r3) */
|
||||
movs r12, r3, lsl #28
|
||||
ldmcs r1!, {r4, r5, r6, r7} /* 16 bytes */
|
||||
ldmmi r1!, {r8, r9} /* 8 bytes */
|
||||
stmcs r0!, {r4, r5, r6, r7}
|
||||
stmmi r0!, {r8, r9}
|
||||
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
|
||||
@ -179,22 +177,23 @@ ENTRY(memcpy)
|
||||
|
||||
/* conditionnaly copies 0 to 31 bytes */
|
||||
movs r12, r2, lsl #28
|
||||
ldmcs r1!, {r4, r5, r6, r7} /* 16 bytes */
|
||||
ldmmi r1!, {r8, r9} /* 8 bytes */
|
||||
stmcs r0!, {r4, r5, r6, r7}
|
||||
stmmi r0!, {r8, r9}
|
||||
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 */
|
||||
ldrhmi r4, [r1], #2 /* 2 bytes */
|
||||
ldrmih r4, [r1], #2 /* 2 bytes */
|
||||
strcs r3, [r0], #4
|
||||
strhmi r4, [r0], #2
|
||||
strmih r4, [r0], #2
|
||||
tst r2, #0x1
|
||||
ldrbne r3, [r1] /* last byte */
|
||||
strbne r3, [r0]
|
||||
ldrneb r3, [r1] /* last byte */
|
||||
strneb r3, [r0]
|
||||
|
||||
/* we're done! restore everything and return */
|
||||
1: ldmfd sp!, {r5-r11}
|
||||
ldmfd sp!, {r0, r4, pc}
|
||||
ldmfd sp!, {r0, r4, lr}
|
||||
bx lr
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
@ -229,11 +228,11 @@ ENTRY(memcpy)
|
||||
* becomes aligned to 32 bits (r5 = nb of words to copy for alignment)
|
||||
*/
|
||||
movs r5, r5, lsl #31
|
||||
strbmi r3, [r0], #1
|
||||
strmib r3, [r0], #1
|
||||
movmi r3, r3, lsr #8
|
||||
strbcs r3, [r0], #1
|
||||
strcsb r3, [r0], #1
|
||||
movcs r3, r3, lsr #8
|
||||
strbcs r3, [r0], #1
|
||||
strcsb r3, [r0], #1
|
||||
movcs r3, r3, lsr #8
|
||||
|
||||
cmp r2, #4
|
||||
@ -364,27 +363,28 @@ ENTRY(memcpy)
|
||||
.Lpartial_word_tail:
|
||||
/* we have a partial word in the input buffer */
|
||||
movs r5, lr, lsl #(31-3)
|
||||
strbmi r3, [r0], #1
|
||||
strmib r3, [r0], #1
|
||||
movmi r3, r3, lsr #8
|
||||
strbcs r3, [r0], #1
|
||||
strcsb r3, [r0], #1
|
||||
movcs r3, r3, lsr #8
|
||||
strbcs r3, [r0], #1
|
||||
strcsb r3, [r0], #1
|
||||
|
||||
/* Refill spilled registers from the stack. Don't update sp. */
|
||||
ldmfd sp, {r5-r11}
|
||||
|
||||
.Lcopy_last_3_and_return:
|
||||
movs r2, r2, lsl #31 /* copy remaining 0, 1, 2 or 3 bytes */
|
||||
ldrbmi r2, [r1], #1
|
||||
ldrbcs r3, [r1], #1
|
||||
ldrbcs r12,[r1]
|
||||
strbmi r2, [r0], #1
|
||||
strbcs r3, [r0], #1
|
||||
strbcs r12,[r0]
|
||||
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, pc}
|
||||
ldmfd sp!, {r0, r4, lr}
|
||||
bx lr
|
||||
END(memcpy)
|
||||
|
||||
// Only reached when the __memcpy_chk check fails.
|
||||
|
@ -35,8 +35,6 @@
|
||||
* memset() returns its first argument.
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
|
||||
ENTRY(__memset_chk)
|
||||
cmp r2, r3
|
||||
bls done
|
||||
@ -78,11 +76,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
|
||||
@ -101,9 +100,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
|
||||
|
||||
@ -118,14 +117,15 @@ 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}
|
||||
strcsb r1, [r0]
|
||||
ldmfd sp!, {r0, r4-r7, lr}
|
||||
bx lr
|
||||
END(memset)
|
||||
|
||||
.data
|
||||
|
@ -32,8 +32,6 @@
|
||||
#include <machine/cpu-features.h>
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
.syntax unified
|
||||
|
||||
ENTRY(strcpy)
|
||||
pld [r1, #0]
|
||||
eor r2, r0, r1
|
||||
@ -110,15 +108,15 @@ ENTRY(strcpy)
|
||||
#ifdef __ARMEB__
|
||||
tst r2, #0xff00
|
||||
iteet ne
|
||||
strhne r2, [ip], #2
|
||||
strneh r2, [ip], #2
|
||||
lsreq r2, r2, #8
|
||||
strbeq r2, [ip]
|
||||
streqb r2, [ip]
|
||||
tstne r2, #0xff
|
||||
#else
|
||||
tst r2, #0xff
|
||||
itet ne
|
||||
strhne r2, [ip], #2
|
||||
strbeq r2, [ip]
|
||||
strneh r2, [ip], #2
|
||||
streqb r2, [ip]
|
||||
tstne r2, #0xff00
|
||||
#endif
|
||||
bne 5b
|
||||
|
11
libc/arch-arm/generic/generic.mk
Normal file
11
libc/arch-arm/generic/generic.mk
Normal file
@ -0,0 +1,11 @@
|
||||
libc_bionic_src_files_arm += \
|
||||
arch-arm/generic/bionic/memcpy.S \
|
||||
arch-arm/generic/bionic/memset.S \
|
||||
arch-arm/generic/bionic/strcmp.S \
|
||||
arch-arm/generic/bionic/strcpy.S \
|
||||
arch-arm/generic/bionic/strlen.c \
|
||||
bionic/memmove.c \
|
||||
bionic/__strcat_chk.cpp \
|
||||
bionic/__strcpy_chk.cpp \
|
||||
upstream-openbsd/lib/libc/string/stpcpy.c \
|
||||
upstream-openbsd/lib/libc/string/strcat.c \
|
@ -38,7 +38,9 @@
|
||||
#ifndef _ARM32_ASM_H_
|
||||
#define _ARM32_ASM_H_
|
||||
|
||||
#define __bionic_asm_align 0
|
||||
#ifndef _ALIGN_TEXT
|
||||
# define _ALIGN_TEXT .align 0
|
||||
#endif
|
||||
|
||||
#undef __bionic_asm_custom_entry
|
||||
#undef __bionic_asm_custom_end
|
||||
@ -48,4 +50,10 @@
|
||||
#undef __bionic_asm_function_type
|
||||
#define __bionic_asm_function_type #function
|
||||
|
||||
#if defined(__ELF__) && defined(PIC)
|
||||
#define PIC_SYM(x,y) x ## ( ## y ## )
|
||||
#else
|
||||
#define PIC_SYM(x,y) x
|
||||
#endif
|
||||
|
||||
#endif /* !_ARM_ASM_H_ */
|
||||
|
@ -28,6 +28,14 @@
|
||||
#ifndef _ARM_MACHINE_CPU_FEATURES_H
|
||||
#define _ARM_MACHINE_CPU_FEATURES_H
|
||||
|
||||
/* The purpose of this file is to define several macros corresponding
|
||||
* to CPU features that may or may not be available at build time on
|
||||
* on the target CPU.
|
||||
*
|
||||
* This is done to abstract us from the various ARM Architecture
|
||||
* quirks and alphabet soup.
|
||||
*/
|
||||
|
||||
/* __ARM_ARCH__ is a number corresponding to the ARM revision
|
||||
* we're going to support. Our toolchain doesn't define __ARM_ARCH__
|
||||
* so try to guess it.
|
||||
@ -45,4 +53,31 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* define __ARM_HAVE_HALFWORD_MULTIPLY when half-word multiply instructions
|
||||
* this means variants of: smul, smulw, smla, smlaw, smlal
|
||||
*/
|
||||
#define __ARM_HAVE_HALFWORD_MULTIPLY 1
|
||||
|
||||
/* define __ARM_HAVE_LDREXD for ARMv7 architecture
|
||||
* (also present in ARMv6K, but not implemented in ARMv7-M, neither of which
|
||||
* we care about)
|
||||
*/
|
||||
#if __ARM_ARCH__ >= 7
|
||||
# define __ARM_HAVE_LDREXD
|
||||
#endif
|
||||
|
||||
/* define _ARM_HAVE_VFP if we have VFPv3
|
||||
*/
|
||||
#if __ARM_ARCH__ >= 7 && defined __VFP_FP__
|
||||
# define __ARM_HAVE_VFP
|
||||
#endif
|
||||
|
||||
/* define _ARM_HAVE_NEON for ARMv7 architecture if we support the
|
||||
* Neon SIMD instruction set extensions. This also implies
|
||||
* that VFPv3-D32 is supported.
|
||||
*/
|
||||
#if __ARM_ARCH__ >= 7 && defined __ARM_NEON__
|
||||
# define __ARM_HAVE_NEON
|
||||
#endif
|
||||
|
||||
#endif /* _ARM_MACHINE_CPU_FEATURES_H */
|
||||
|
@ -102,8 +102,6 @@
|
||||
|
||||
/* 112-127 are reserved for private experiments. */
|
||||
|
||||
#define R_ARM_IRELATIVE 160
|
||||
|
||||
#define R_ARM_RXPC25 249
|
||||
#define R_ARM_RSBREL32 250
|
||||
#define R_ARM_THM_RPC22 251
|
||||
|
79
libc/arch-arm/include/machine/endian.h
Normal file
79
libc/arch-arm/include/machine/endian.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* $OpenBSD: endian.h,v 1.3 2005/12/13 00:35:23 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _ARM_ENDIAN_H_
|
||||
#define _ARM_ENDIAN_H_
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
/* According to RealView Assembler User's Guide, REV and REV16 are available
|
||||
* in Thumb code and 16-bit instructions when used in Thumb-2 code.
|
||||
*
|
||||
* REV Rd, Rm
|
||||
* Rd and Rm must both be Lo registers.
|
||||
*
|
||||
* REV16 Rd, Rm
|
||||
* Rd and Rm must both be Lo registers.
|
||||
*
|
||||
* The +l constraint takes care of this without constraining us in ARM mode.
|
||||
*/
|
||||
#define __swap16md(x) ({ \
|
||||
register u_int16_t _x = (x); \
|
||||
__asm__ __volatile__("rev16 %0, %0" : "+l" (_x)); \
|
||||
_x; \
|
||||
})
|
||||
|
||||
#define __swap32md(x) ({ \
|
||||
register u_int32_t _x = (x); \
|
||||
__asm__ __volatile__("rev %0, %0" : "+l" (_x)); \
|
||||
_x; \
|
||||
})
|
||||
|
||||
#define __swap64md(x) ({ \
|
||||
u_int64_t _swap64md_x = (x); \
|
||||
(u_int64_t) __swap32md(_swap64md_x >> 32) | \
|
||||
(u_int64_t) __swap32md(_swap64md_x & 0xffffffff) << 32; \
|
||||
})
|
||||
|
||||
/* Tell sys/endian.h we have MD variants of the swap macros. */
|
||||
#define MD_SWAP
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#if defined(__ARMEB__)
|
||||
#define _BYTE_ORDER _BIG_ENDIAN
|
||||
#else
|
||||
#define _BYTE_ORDER _LITTLE_ENDIAN
|
||||
#endif
|
||||
#define __STRICT_ALIGNMENT
|
||||
#include <sys/types.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#endif /* !_ARM_ENDIAN_H_ */
|
50
libc/arch-arm/include/machine/exec.h
Normal file
50
libc/arch-arm/include/machine/exec.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* $OpenBSD: exec.h,v 1.9 2003/04/17 03:42:14 drahn Exp $ */
|
||||
/* $NetBSD: exec.h,v 1.6 1994/10/27 04:16:05 cgd Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993 Christopher G. Demetriou
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _ARM_EXEC_H_
|
||||
#define _ARM_EXEC_H_
|
||||
|
||||
#define __LDPGSZ 4096
|
||||
|
||||
#define NATIVE_EXEC_ELF
|
||||
|
||||
#define ARCH_ELFSIZE 32
|
||||
|
||||
#define ELF_TARG_CLASS ELFCLASS32
|
||||
#define ELF_TARG_DATA ELFDATA2LSB
|
||||
#define ELF_TARG_MACH EM_ARM
|
||||
|
||||
#define _NLIST_DO_AOUT
|
||||
#define _NLIST_DO_ELF
|
||||
|
||||
#define _KERN_DO_AOUT
|
||||
#define _KERN_DO_ELF
|
||||
|
||||
#endif /* _ARM_EXEC_H_ */
|
@ -26,6 +26,10 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* machine/setjmp.h: machine dependent setjmp-related information.
|
||||
*/
|
||||
|
||||
/* _JBLEN is the size of a jmp_buf in longs.
|
||||
* Do not modify this value or you will break the ABI !
|
||||
*
|
||||
@ -33,3 +37,46 @@
|
||||
* that was replaced by this one.
|
||||
*/
|
||||
#define _JBLEN 64
|
||||
|
||||
/* According to the ARM AAPCS document, we only need to save
|
||||
* the following registers:
|
||||
*
|
||||
* Core r4-r14
|
||||
*
|
||||
* VFP d8-d15 (see section 5.1.2.1)
|
||||
*
|
||||
* Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine
|
||||
* calls; registers s0-s15 (d0-d7, q0-q3) do not need to be preserved
|
||||
* (and can be used for passing arguments or returning results in standard
|
||||
* procedure-call variants). Registers d16-d31 (q8-q15), if present, do
|
||||
* not need to be preserved.
|
||||
*
|
||||
* FPSCR saved because GLibc does saves it too.
|
||||
*
|
||||
*/
|
||||
|
||||
/* The internal structure of a jmp_buf is totally private.
|
||||
* Current layout (may change in the future):
|
||||
*
|
||||
* word name description
|
||||
* 0 magic magic number
|
||||
* 1 sigmask signal mask (not used with _setjmp / _longjmp)
|
||||
* 2 float_base base of float registers (d8 to d15)
|
||||
* 18 float_state floating-point status and control register
|
||||
* 19 core_base base of core registers (r4 to r14)
|
||||
* 30 reserved reserved entries (room to grow)
|
||||
* 64
|
||||
*
|
||||
* NOTE: float_base must be at an even word index, since the
|
||||
* FP registers will be loaded/stored with instructions
|
||||
* that expect 8-byte alignment.
|
||||
*/
|
||||
|
||||
#define _JB_MAGIC 0
|
||||
#define _JB_SIGMASK (_JB_MAGIC+1)
|
||||
#define _JB_FLOAT_BASE (_JB_SIGMASK+1)
|
||||
#define _JB_FLOAT_STATE (_JB_FLOAT_BASE + (15-8+1)*2)
|
||||
#define _JB_CORE_BASE (_JB_FLOAT_STATE+1)
|
||||
|
||||
#define _JB_MAGIC__SETJMP 0x4278f500
|
||||
#define _JB_MAGIC_SETJMP 0x4278f501
|
||||
|
@ -40,7 +40,7 @@
|
||||
ENTRY(__strcat_chk)
|
||||
pld [r0, #0]
|
||||
push {r0, lr}
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset lr, 4
|
||||
push {r4, r5}
|
||||
@ -177,7 +177,7 @@ ENTRY(__strcat_chk)
|
||||
.L_strlen_done:
|
||||
add r2, r3, r4
|
||||
cmp r2, lr
|
||||
bhi .L_strcat_chk_failed
|
||||
bhi __strcat_chk_failed
|
||||
|
||||
// Set up the registers for the memcpy code.
|
||||
mov r1, r5
|
||||
@ -185,17 +185,20 @@ ENTRY(__strcat_chk)
|
||||
mov r2, r4
|
||||
add r0, r0, r3
|
||||
pop {r4, r5}
|
||||
.cfi_adjust_cfa_offset -8
|
||||
.cfi_restore r4
|
||||
.cfi_restore r5
|
||||
END(__strcat_chk)
|
||||
|
||||
#define MEMCPY_BASE __strcat_chk_memcpy_base
|
||||
#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
|
||||
#include "memcpy_base.S"
|
||||
|
||||
// Undo the above cfi directives.
|
||||
ENTRY_PRIVATE(__strcat_chk_failed)
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset lr, 4
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.cfi_rel_offset r4, 0
|
||||
.cfi_rel_offset r5, 4
|
||||
.L_strcat_chk_failed:
|
||||
|
||||
ldr r0, error_message
|
||||
ldr r1, error_code
|
||||
1:
|
||||
@ -205,7 +208,7 @@ error_code:
|
||||
.word BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
|
||||
error_message:
|
||||
.word error_string-(1b+4)
|
||||
END(__strcat_chk)
|
||||
END(__strcat_chk_failed)
|
||||
|
||||
.data
|
||||
error_string:
|
||||
|
@ -39,7 +39,7 @@
|
||||
ENTRY(__strcpy_chk)
|
||||
pld [r0, #0]
|
||||
push {r0, lr}
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset lr, 4
|
||||
|
||||
@ -149,14 +149,21 @@ ENTRY(__strcpy_chk)
|
||||
pld [r1, #64]
|
||||
ldr r0, [sp]
|
||||
cmp r3, lr
|
||||
bhs .L_strcpy_chk_failed
|
||||
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"
|
||||
|
||||
.L_strcpy_chk_failed:
|
||||
ENTRY_PRIVATE(__strcpy_chk_failed)
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset lr, 4
|
||||
|
||||
ldr r0, error_message
|
||||
ldr r1, error_code
|
||||
1:
|
||||
@ -166,7 +173,7 @@ error_code:
|
||||
.word BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
|
||||
error_message:
|
||||
.word error_string-(1b+4)
|
||||
END(__strcpy_chk)
|
||||
END(__strcpy_chk_failed)
|
||||
|
||||
.data
|
||||
error_string:
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
ENTRY(__memcpy_chk)
|
||||
cmp r2, r3
|
||||
bhi .L_memcpy_chk_fail
|
||||
bhi __memcpy_chk_fail
|
||||
|
||||
// Fall through to memcpy...
|
||||
END(__memcpy_chk)
|
||||
@ -53,20 +53,19 @@ END(__memcpy_chk)
|
||||
ENTRY(memcpy)
|
||||
pld [r1, #64]
|
||||
stmfd sp!, {r0, lr}
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.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"
|
||||
|
||||
// Undo the cfi directives from above.
|
||||
.cfi_adjust_cfa_offset -8
|
||||
.cfi_restore r0
|
||||
.cfi_restore lr
|
||||
.L_memcpy_chk_fail:
|
||||
ENTRY_PRIVATE(__memcpy_chk_fail)
|
||||
// Preserve lr for backtrace.
|
||||
push {lr}
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_def_cfa_offset 4
|
||||
.cfi_rel_offset lr, 0
|
||||
|
||||
ldr r0, error_message
|
||||
@ -78,7 +77,7 @@ error_code:
|
||||
.word BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW
|
||||
error_message:
|
||||
.word error_string-(1b+4)
|
||||
END(memcpy)
|
||||
END(__memcpy_chk_fail)
|
||||
|
||||
.data
|
||||
error_string:
|
||||
|
@ -1,191 +1,123 @@
|
||||
/***************************************************************************
|
||||
Copyright (c) 2009-2013 The Linux Foundation. All rights reserved.
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of The Linux Foundation nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
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 code assumes it is running on a processor that supports all arm v7
|
||||
* instructions, that supports neon instructions, and that has a 32 byte
|
||||
* cache line.
|
||||
*/
|
||||
|
||||
/* Assumes neon instructions and a cache line size of 64 bytes. */
|
||||
// Assumes neon instructions and a cache line size of 32 bytes.
|
||||
|
||||
#include <machine/cpu-features.h>
|
||||
#include <machine/asm.h>
|
||||
ENTRY_PRIVATE(MEMCPY_BASE)
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset r0, 0
|
||||
.cfi_rel_offset lr, 4
|
||||
|
||||
#define PLDOFFS (10)
|
||||
#define PLDTHRESH (PLDOFFS)
|
||||
#define BBTHRESH (4096/64)
|
||||
#define PLDSIZE (64)
|
||||
/* do we have at least 16-bytes to copy (needed for alignment below) */
|
||||
cmp r2, #16
|
||||
blo 5f
|
||||
|
||||
#if (PLDOFFS < 1)
|
||||
#error Routine does not support offsets less than 1
|
||||
#endif
|
||||
/* align destination to cache-line for the write-buffer */
|
||||
rsb r3, r0, #0
|
||||
ands r3, r3, #0xF
|
||||
beq 2f
|
||||
|
||||
#if (PLDTHRESH < PLDOFFS)
|
||||
#error PLD threshold must be greater than or equal to the PLD offset
|
||||
#endif
|
||||
/* 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, 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]!
|
||||
|
||||
.text
|
||||
.fpu neon
|
||||
2: /* make sure we have at least 64 bytes to copy */
|
||||
subs r2, r2, #64
|
||||
blo 2f
|
||||
|
||||
.L_memcpy_base:
|
||||
cmp r2, #4
|
||||
blt .L_neon_lt4
|
||||
cmp r2, #16
|
||||
blt .L_neon_lt16
|
||||
cmp r2, #32
|
||||
blt .L_neon_16
|
||||
cmp r2, #64
|
||||
blt .L_neon_copy_32_a
|
||||
1: /* The main loop copies 64 bytes at a time */
|
||||
vld1.8 {d0 - d3}, [r1]!
|
||||
vld1.8 {d4 - d7}, [r1]!
|
||||
pld [r1, #(32*8)]
|
||||
subs r2, r2, #64
|
||||
vst1.8 {d0 - d3}, [r0, :128]!
|
||||
vst1.8 {d4 - d7}, [r0, :128]!
|
||||
bhs 1b
|
||||
|
||||
mov r12, r2, lsr #6
|
||||
cmp r12, #PLDTHRESH
|
||||
ble .L_neon_copy_64_loop_nopld
|
||||
2: /* fix-up the remaining count and make sure we have >= 32 bytes left */
|
||||
adds r2, r2, #32
|
||||
blo 4f
|
||||
|
||||
push {r9, r10}
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.cfi_rel_offset r9, 0
|
||||
.cfi_rel_offset r10, 4
|
||||
/* Copy 32 bytes. These cache lines were already preloaded */
|
||||
vld1.8 {d0 - d3}, [r1]!
|
||||
sub r2, r2, #32
|
||||
vst1.8 {d0 - d3}, [r0, :128]!
|
||||
|
||||
cmp r12, #BBTHRESH
|
||||
ble .L_neon_prime_pump
|
||||
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]!
|
||||
|
||||
add lr, r0, #0x400
|
||||
add r9, r1, #(PLDOFFS*PLDSIZE)
|
||||
sub lr, lr, r9
|
||||
lsl lr, lr, #21
|
||||
lsr lr, lr, #21
|
||||
add lr, lr, #(PLDOFFS*PLDSIZE)
|
||||
cmp r12, lr, lsr #6
|
||||
ble .L_neon_prime_pump
|
||||
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
|
||||
itt mi
|
||||
ldrbmi r3, [r1], #1
|
||||
strbmi r3, [r0], #1
|
||||
itttt cs
|
||||
ldrbcs ip, [r1], #1
|
||||
ldrbcs lr, [r1], #1
|
||||
strbcs ip, [r0], #1
|
||||
strbcs lr, [r0], #1
|
||||
|
||||
itt gt
|
||||
movgt r9, #(PLDOFFS)
|
||||
rsbsgt r9, r9, lr, lsr #6
|
||||
ble .L_neon_prime_pump
|
||||
|
||||
add r10, r1, lr
|
||||
bic r10, #0x3F
|
||||
|
||||
sub r12, r12, lr, lsr #6
|
||||
|
||||
cmp r9, r12
|
||||
itee le
|
||||
suble r12, r12, r9
|
||||
movgt r9, r12
|
||||
movgt r12, #0
|
||||
|
||||
pld [r1, #((PLDOFFS-1)*PLDSIZE)]
|
||||
.L_neon_copy_64_loop_outer_doublepld:
|
||||
pld [r1, #((PLDOFFS)*PLDSIZE)]
|
||||
vld1.32 {q0, q1}, [r1]!
|
||||
vld1.32 {q2, q3}, [r1]!
|
||||
ldr r3, [r10]
|
||||
subs r9, r9, #1
|
||||
vst1.32 {q0, q1}, [r0]!
|
||||
vst1.32 {q2, q3}, [r0]!
|
||||
add r10, #64
|
||||
bne .L_neon_copy_64_loop_outer_doublepld
|
||||
cmp r12, #0
|
||||
beq .L_neon_pop_before_nopld
|
||||
|
||||
cmp r12, #(512*1024/64)
|
||||
blt .L_neon_copy_64_loop_outer
|
||||
|
||||
.L_neon_copy_64_loop_ddr:
|
||||
vld1.32 {q0, q1}, [r1]!
|
||||
vld1.32 {q2, q3}, [r1]!
|
||||
pld [r10]
|
||||
subs r12, r12, #1
|
||||
vst1.32 {q0, q1}, [r0]!
|
||||
vst1.32 {q2, q3}, [r0]!
|
||||
add r10, #64
|
||||
bne .L_neon_copy_64_loop_ddr
|
||||
b .L_neon_pop_before_nopld
|
||||
|
||||
.L_neon_prime_pump:
|
||||
mov lr, #(PLDOFFS*PLDSIZE)
|
||||
add r10, r1, #(PLDOFFS*PLDSIZE)
|
||||
bic r10, #0x3F
|
||||
sub r12, r12, #PLDOFFS
|
||||
ldr r3, [r10, #(-1*PLDSIZE)]
|
||||
|
||||
.L_neon_copy_64_loop_outer:
|
||||
vld1.32 {q0, q1}, [r1]!
|
||||
vld1.32 {q2, q3}, [r1]!
|
||||
ldr r3, [r10]
|
||||
subs r12, r12, #1
|
||||
vst1.32 {q0, q1}, [r0]!
|
||||
vst1.32 {q2, q3}, [r0]!
|
||||
add r10, #64
|
||||
bne .L_neon_copy_64_loop_outer
|
||||
|
||||
.L_neon_pop_before_nopld:
|
||||
mov r12, lr, lsr #6
|
||||
pop {r9, r10}
|
||||
.cfi_adjust_cfa_offset -8
|
||||
.cfi_restore r9
|
||||
.cfi_restore r10
|
||||
|
||||
.L_neon_copy_64_loop_nopld:
|
||||
vld1.32 {q8, q9}, [r1]!
|
||||
vld1.32 {q10, q11}, [r1]!
|
||||
subs r12, r12, #1
|
||||
vst1.32 {q8, q9}, [r0]!
|
||||
vst1.32 {q10, q11}, [r0]!
|
||||
bne .L_neon_copy_64_loop_nopld
|
||||
ands r2, r2, #0x3f
|
||||
beq .L_neon_exit
|
||||
|
||||
.L_neon_copy_32_a:
|
||||
movs r3, r2, lsl #27
|
||||
bcc .L_neon_16
|
||||
vld1.32 {q0,q1}, [r1]!
|
||||
vst1.32 {q0,q1}, [r0]!
|
||||
|
||||
.L_neon_16:
|
||||
bpl .L_neon_lt16
|
||||
vld1.32 {q8}, [r1]!
|
||||
vst1.32 {q8}, [r0]!
|
||||
ands r2, r2, #0x0f
|
||||
beq .L_neon_exit
|
||||
|
||||
.L_neon_lt16:
|
||||
movs r3, r2, lsl #29
|
||||
bcc 1f
|
||||
vld1.8 {d0}, [r1]!
|
||||
vst1.8 {d0}, [r0]!
|
||||
1:
|
||||
bge .L_neon_lt4
|
||||
vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]!
|
||||
vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0]!
|
||||
|
||||
.L_neon_lt4:
|
||||
movs r2, r2, lsl #31
|
||||
itt cs
|
||||
ldrhcs r3, [r1], #2
|
||||
strhcs r3, [r0], #2
|
||||
itt mi
|
||||
ldrbmi r3, [r1]
|
||||
strbmi r3, [r0]
|
||||
|
||||
.L_neon_exit:
|
||||
pop {r0, pc}
|
||||
ldmfd sp!, {r0, lr}
|
||||
bx lr
|
||||
END(MEMCPY_BASE)
|
||||
|
@ -37,7 +37,6 @@
|
||||
*/
|
||||
|
||||
.fpu neon
|
||||
.syntax unified
|
||||
|
||||
ENTRY(__memset_chk)
|
||||
cmp r2, r3
|
||||
@ -69,7 +68,10 @@ END(bzero)
|
||||
|
||||
/* memset() returns its first argument. */
|
||||
ENTRY(memset)
|
||||
mov r3, r0
|
||||
stmfd sp!, {r0}
|
||||
.cfi_def_cfa_offset 4
|
||||
.cfi_rel_offset r0, 0
|
||||
|
||||
vdup.8 q0, r1
|
||||
|
||||
/* make sure we have at least 32 bytes to write */
|
||||
@ -79,7 +81,7 @@ ENTRY(memset)
|
||||
|
||||
1: /* The main loop writes 32 bytes at a time */
|
||||
subs r2, r2, #32
|
||||
vst1.8 {d0 - d3}, [r3]!
|
||||
vst1.8 {d0 - d3}, [r0]!
|
||||
bhs 1b
|
||||
|
||||
2: /* less than 32 left */
|
||||
@ -88,17 +90,18 @@ 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
|
||||
END(memset)
|
||||
|
||||
|
@ -1,18 +1,3 @@
|
||||
libc_openbsd_src_files_exclude_arm += \
|
||||
upstream-openbsd/lib/libc/string/memmove.c \
|
||||
upstream-openbsd/lib/libc/string/stpcpy.c \
|
||||
upstream-openbsd/lib/libc/string/stpcpy.c \
|
||||
upstream-openbsd/lib/libc/string/strcat.c \
|
||||
|
||||
libc_bionic_src_files_exclude_arm += \
|
||||
arch-arm/generic/bionic/memcpy.S \
|
||||
arch-arm/generic/bionic/memset.S \
|
||||
arch-arm/generic/bionic/strcmp.S \
|
||||
arch-arm/generic/bionic/strcpy.S \
|
||||
arch-arm/generic/bionic/strlen.c \
|
||||
bionic/__strcat_chk.cpp \
|
||||
bionic/__strcpy_chk.cpp \
|
||||
|
||||
libc_bionic_src_files_arm += \
|
||||
arch-arm/krait/bionic/memcpy.S \
|
||||
arch-arm/krait/bionic/memset.S \
|
||||
@ -26,6 +11,4 @@ libc_bionic_src_files_arm += \
|
||||
arch-arm/cortex-a15/bionic/strcat.S \
|
||||
arch-arm/cortex-a15/bionic/strcpy.S \
|
||||
arch-arm/cortex-a15/bionic/strlen.S \
|
||||
|
||||
libc_bionic_src_files_arm += \
|
||||
arch-arm/denver/bionic/memmove.S \
|
||||
bionic/memmove.c \
|
||||
|
@ -1,23 +0,0 @@
|
||||
/* Generated by gensyscalls.py. Do not edit. */
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(___mremap)
|
||||
mov ip, sp
|
||||
stmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_rel_offset r4, 0
|
||||
.cfi_rel_offset r5, 4
|
||||
.cfi_rel_offset r6, 8
|
||||
.cfi_rel_offset r7, 12
|
||||
ldmfd ip, {r4, r5, r6}
|
||||
ldr r7, =__NR_mremap
|
||||
swi #0
|
||||
ldmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 0
|
||||
cmn r0, #(MAX_ERRNO + 1)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(___mremap)
|
||||
.hidden ___mremap
|
@ -1,15 +0,0 @@
|
||||
/* Generated by gensyscalls.py. Do not edit. */
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(___rt_sigqueueinfo)
|
||||
mov ip, r7
|
||||
ldr r7, =__NR_rt_sigqueueinfo
|
||||
swi #0
|
||||
mov r7, ip
|
||||
cmn r0, #(MAX_ERRNO + 1)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(___rt_sigqueueinfo)
|
||||
.hidden ___rt_sigqueueinfo
|
@ -1,22 +0,0 @@
|
||||
/* Generated by gensyscalls.py. Do not edit. */
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(__preadv64)
|
||||
mov ip, sp
|
||||
stmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_rel_offset r4, 0
|
||||
.cfi_rel_offset r5, 4
|
||||
.cfi_rel_offset r6, 8
|
||||
.cfi_rel_offset r7, 12
|
||||
ldmfd ip, {r4, r5, r6}
|
||||
ldr r7, =__NR_preadv
|
||||
swi #0
|
||||
ldmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 0
|
||||
cmn r0, #(MAX_ERRNO + 1)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(__preadv64)
|
@ -1,22 +0,0 @@
|
||||
/* Generated by gensyscalls.py. Do not edit. */
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(__pwritev64)
|
||||
mov ip, sp
|
||||
stmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_rel_offset r4, 0
|
||||
.cfi_rel_offset r5, 4
|
||||
.cfi_rel_offset r6, 8
|
||||
.cfi_rel_offset r7, 12
|
||||
ldmfd ip, {r4, r5, r6}
|
||||
ldr r7, =__NR_pwritev
|
||||
swi #0
|
||||
ldmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 0
|
||||
cmn r0, #(MAX_ERRNO + 1)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(__pwritev64)
|
@ -13,4 +13,5 @@ ENTRY(_exit)
|
||||
b __set_errno_internal
|
||||
END(_exit)
|
||||
|
||||
ALIAS_SYMBOL(_Exit, _exit)
|
||||
.globl _Exit
|
||||
.equ _Exit, _exit
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(___clock_nanosleep)
|
||||
ENTRY(clock_nanosleep)
|
||||
mov ip, r7
|
||||
ldr r7, =__NR_clock_nanosleep
|
||||
swi #0
|
||||
@ -11,5 +11,4 @@ ENTRY(___clock_nanosleep)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(___clock_nanosleep)
|
||||
.hidden ___clock_nanosleep
|
||||
END(clock_nanosleep)
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(___close)
|
||||
ENTRY(close)
|
||||
mov ip, r7
|
||||
ldr r7, =__NR_close
|
||||
swi #0
|
||||
@ -11,5 +11,4 @@ ENTRY(___close)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(___close)
|
||||
.hidden ___close
|
||||
END(close)
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(___faccessat)
|
||||
ENTRY(faccessat)
|
||||
mov ip, r7
|
||||
ldr r7, =__NR_faccessat
|
||||
swi #0
|
||||
@ -11,5 +11,4 @@ ENTRY(___faccessat)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(___faccessat)
|
||||
.hidden ___faccessat
|
||||
END(faccessat)
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(___fchmod)
|
||||
ENTRY(fchmod)
|
||||
mov ip, r7
|
||||
ldr r7, =__NR_fchmod
|
||||
swi #0
|
||||
@ -11,5 +11,4 @@ ENTRY(___fchmod)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(___fchmod)
|
||||
.hidden ___fchmod
|
||||
END(fchmod)
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(___fchmodat)
|
||||
ENTRY(fchmodat)
|
||||
mov ip, r7
|
||||
ldr r7, =__NR_fchmodat
|
||||
swi #0
|
||||
@ -11,5 +11,4 @@ ENTRY(___fchmodat)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(___fchmodat)
|
||||
.hidden ___fchmodat
|
||||
END(fchmodat)
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(___fgetxattr)
|
||||
ENTRY(fgetxattr)
|
||||
mov ip, r7
|
||||
ldr r7, =__NR_fgetxattr
|
||||
swi #0
|
||||
@ -11,5 +11,4 @@ ENTRY(___fgetxattr)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(___fgetxattr)
|
||||
.hidden ___fgetxattr
|
||||
END(fgetxattr)
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(___flistxattr)
|
||||
ENTRY(flistxattr)
|
||||
mov ip, r7
|
||||
ldr r7, =__NR_flistxattr
|
||||
swi #0
|
||||
@ -11,5 +11,4 @@ ENTRY(___flistxattr)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(___flistxattr)
|
||||
.hidden ___flistxattr
|
||||
END(flistxattr)
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(___fsetxattr)
|
||||
ENTRY(fsetxattr)
|
||||
mov ip, sp
|
||||
stmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 16
|
||||
@ -19,5 +19,4 @@ ENTRY(___fsetxattr)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(___fsetxattr)
|
||||
.hidden ___fsetxattr
|
||||
END(fsetxattr)
|
@ -13,4 +13,5 @@ ENTRY(fstat64)
|
||||
b __set_errno_internal
|
||||
END(fstat64)
|
||||
|
||||
ALIAS_SYMBOL(fstat, fstat64)
|
||||
.globl fstat
|
||||
.equ fstat, fstat64
|
||||
|
@ -13,4 +13,5 @@ ENTRY(fstatat64)
|
||||
b __set_errno_internal
|
||||
END(fstatat64)
|
||||
|
||||
ALIAS_SYMBOL(fstatat, fstatat64)
|
||||
.globl fstatat
|
||||
.equ fstatat, fstatat64
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(sethostname)
|
||||
ENTRY(ftruncate)
|
||||
mov ip, r7
|
||||
ldr r7, =__NR_sethostname
|
||||
ldr r7, =__NR_ftruncate
|
||||
swi #0
|
||||
mov r7, ip
|
||||
cmn r0, #(MAX_ERRNO + 1)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(sethostname)
|
||||
END(ftruncate)
|
14
libc/arch-arm/syscalls/mremap.S
Normal file
14
libc/arch-arm/syscalls/mremap.S
Normal file
@ -0,0 +1,14 @@
|
||||
/* Generated by gensyscalls.py. Do not edit. */
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(mremap)
|
||||
mov ip, r7
|
||||
ldr r7, =__NR_mremap
|
||||
swi #0
|
||||
mov r7, ip
|
||||
cmn r0, #(MAX_ERRNO + 1)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(mremap)
|
@ -1,22 +0,0 @@
|
||||
/* Generated by gensyscalls.py. Do not edit. */
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(process_vm_readv)
|
||||
mov ip, sp
|
||||
stmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_rel_offset r4, 0
|
||||
.cfi_rel_offset r5, 4
|
||||
.cfi_rel_offset r6, 8
|
||||
.cfi_rel_offset r7, 12
|
||||
ldmfd ip, {r4, r5, r6}
|
||||
ldr r7, =__NR_process_vm_readv
|
||||
swi #0
|
||||
ldmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 0
|
||||
cmn r0, #(MAX_ERRNO + 1)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(process_vm_readv)
|
@ -1,22 +0,0 @@
|
||||
/* Generated by gensyscalls.py. Do not edit. */
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(process_vm_writev)
|
||||
mov ip, sp
|
||||
stmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_rel_offset r4, 0
|
||||
.cfi_rel_offset r5, 4
|
||||
.cfi_rel_offset r6, 8
|
||||
.cfi_rel_offset r7, 12
|
||||
ldmfd ip, {r4, r5, r6}
|
||||
ldr r7, =__NR_process_vm_writev
|
||||
swi #0
|
||||
ldmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 0
|
||||
cmn r0, #(MAX_ERRNO + 1)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(process_vm_writev)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user