aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Ivanov <dimitry@google.com>2015-10-23 20:54:00 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-10-23 20:54:00 +0000
commite08ab4b4144b8c4c920221b403daa220b43df2fb (patch)
tree313de0e902979526985e97aec31aae9e13e05792
parentc45f3bf3e691f48af63c5ea2bf7a348a698013ac (diff)
parentcf1cbbe43293b05e564b9d044147efbcfbcc993e (diff)
downloadbionic-e08ab4b4144b8c4c920221b403daa220b43df2fb.tar.gz
Merge "refactoring: introduce MappedFileFragment"
-rw-r--r--linker/Android.mk1
-rw-r--r--linker/linker_debug.h7
-rw-r--r--linker/linker_mapped_file_fragment.cpp82
-rw-r--r--linker/linker_mapped_file_fragment.h41
-rw-r--r--linker/linker_phdr.cpp26
-rw-r--r--linker/linker_phdr.h7
6 files changed, 139 insertions, 25 deletions
diff --git a/linker/Android.mk b/linker/Android.mk
index 8be53a195..0188a4922 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -12,6 +12,7 @@ LOCAL_SRC_FILES := \
linker_sdk_versions.cpp \
linker_block_allocator.cpp \
linker_libc_support.c \
+ linker_mapped_file_fragment.cpp \
linker_memory.cpp \
linker_phdr.cpp \
linker_utils.cpp \
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 51f8d4c18..17c6986f0 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -58,6 +58,13 @@
__LIBC_HIDDEN__ extern int g_ld_debug_verbosity;
+#define CHECK(predicate) { \
+ if (!(predicate)) { \
+ __libc_fatal("%s:%d: %s CHECK '" #predicate "' failed", \
+ __FILE__, __LINE__, __FUNCTION__); \
+ } \
+ }
+
#if LINKER_DEBUG_TO_LOG
#define _PRINTVF(v, x...) \
do { \
diff --git a/linker/linker_mapped_file_fragment.cpp b/linker/linker_mapped_file_fragment.cpp
new file mode 100644
index 000000000..6a500ef1e
--- /dev/null
+++ b/linker/linker_mapped_file_fragment.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#include "linker_mapped_file_fragment.h"
+#include "linker_debug.h"
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+constexpr off64_t kPageMask = ~static_cast<off64_t>(PAGE_SIZE-1);
+
+static off64_t page_start(off64_t offset) {
+ return offset & kPageMask;
+}
+
+static bool safe_add(off64_t* out, off64_t a, size_t b) {
+ CHECK(a >= 0);
+ if (static_cast<uint64_t>(INT64_MAX - a) < b) {
+ return false;
+ }
+
+ *out = a + b;
+ return true;
+}
+
+static size_t page_offset(off64_t offset) {
+ return static_cast<size_t>(offset & (PAGE_SIZE-1));
+}
+
+MappedFileFragment::MappedFileFragment() : map_start_(nullptr), map_size_(0),
+ data_(nullptr), size_ (0)
+{ }
+
+MappedFileFragment::~MappedFileFragment() {
+ if (map_start_ != nullptr) {
+ munmap(map_start_, map_size_);
+ }
+}
+
+bool MappedFileFragment::Map(int fd, off64_t base_offset, size_t elf_offset, size_t size) {
+ off64_t offset;
+ CHECK(safe_add(&offset, base_offset, elf_offset));
+
+ off64_t page_min = page_start(offset);
+ off64_t end_offset;
+
+ CHECK(safe_add(&end_offset, offset, size));
+ CHECK(safe_add(&end_offset, end_offset, page_offset(offset)));
+
+ size_t map_size = static_cast<size_t>(end_offset - page_min);
+ CHECK(map_size >= size);
+
+ uint8_t* map_start = static_cast<uint8_t*>(
+ mmap64(nullptr, map_size, PROT_READ, MAP_PRIVATE, fd, page_min));
+
+ if (map_start == MAP_FAILED) {
+ return false;
+ }
+
+ map_start_ = map_start;
+ map_size_ = map_size;
+
+ data_ = map_start + page_offset(offset);
+ size_ = size;
+
+ return true;
+}
diff --git a/linker/linker_mapped_file_fragment.h b/linker/linker_mapped_file_fragment.h
new file mode 100644
index 000000000..91bd077bd
--- /dev/null
+++ b/linker/linker_mapped_file_fragment.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+#ifndef LINKER_MAPPED_FILE_FRAGMENT_H
+#define LINKER_MAPPED_FILE_FRAGMENT_H
+
+#include <unistd.h>
+
+#include "private/bionic_macros.h"
+
+class MappedFileFragment {
+ public:
+ MappedFileFragment();
+ ~MappedFileFragment();
+
+ bool Map(int fd, off64_t base_offset, size_t elf_offset, size_t size);
+
+ void* data() const { return data_; }
+ size_t size() const { return size_; }
+ private:
+ void* map_start_;
+ size_t map_size_;
+ void* data_;
+ size_t size_;
+
+ DISALLOW_COPY_AND_ASSIGN(MappedFileFragment);
+};
+
+#endif /* LINKER_MAPPED_FILE_FRAGMENT_H */
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 30bc6fabd..6fe808421 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -134,18 +134,11 @@ static int GetTargetElfMachine() {
MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
ElfReader::ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size)
- : name_(name), fd_(fd), file_offset_(file_offset), file_size_(file_size),
- phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0),
- load_start_(nullptr), load_size_(0), load_bias_(0),
+ : name_(name), fd_(fd), file_offset_(file_offset), file_size_(file_size), phdr_num_(0),
+ phdr_table_(nullptr), load_start_(nullptr), load_size_(0), load_bias_(0),
loaded_phdr_(nullptr) {
}
-ElfReader::~ElfReader() {
- if (phdr_mmap_ != nullptr) {
- munmap(phdr_mmap_, phdr_size_);
- }
-}
-
bool ElfReader::Load(const android_dlextinfo* extinfo) {
return ReadElfHeader() &&
VerifyElfHeader() &&
@@ -234,21 +227,12 @@ bool ElfReader::ReadProgramHeader() {
return false;
}
- ElfW(Addr) page_min = PAGE_START(header_.e_phoff);
- ElfW(Addr) page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(ElfW(Phdr))));
- ElfW(Addr) page_offset = PAGE_OFFSET(header_.e_phoff);
-
- phdr_size_ = page_max - page_min;
-
- void* mmap_result =
- mmap64(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, file_offset_ + page_min);
- if (mmap_result == MAP_FAILED) {
+ if (!phdr_fragment_.Map(fd_, file_offset_, header_.e_phoff, phdr_num_ * sizeof(ElfW(Phdr)))) {
DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
return false;
}
- phdr_mmap_ = mmap_result;
- phdr_table_ = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(mmap_result) + page_offset);
+ phdr_table_ = static_cast<ElfW(Phdr)*>(phdr_fragment_.data());
return true;
}
@@ -829,7 +813,7 @@ bool ElfReader::FindPhdr() {
bool ElfReader::CheckPhdr(ElfW(Addr) loaded) {
const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
ElfW(Addr) loaded_end = loaded + (phdr_num_ * sizeof(ElfW(Phdr)));
- for (ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
+ for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
if (phdr->p_type != PT_LOAD) {
continue;
}
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 55196fd9a..4e0219701 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -36,11 +36,11 @@
*/
#include "linker.h"
+#include "linker_mapped_file_fragment.h"
class ElfReader {
public:
ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size);
- ~ElfReader();
bool Load(const android_dlextinfo* extinfo);
@@ -67,9 +67,8 @@ class ElfReader {
ElfW(Ehdr) header_;
size_t phdr_num_;
- void* phdr_mmap_;
- ElfW(Phdr)* phdr_table_;
- ElfW(Addr) phdr_size_;
+ MappedFileFragment phdr_fragment_;
+ const ElfW(Phdr)* phdr_table_;
// First page of reserved address space.
void* load_start_;