OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Tool to pack and unpack relative relocations in a shared library. | 5 // Tool to pack and unpack relative relocations in a shared library. |
6 // | 6 // |
7 // Packing removes relative relocations from .rel.dyn and writes them | 7 // Packing removes relative relocations from .rel.dyn and writes them |
8 // in a more compact form to .android.rel.dyn. Unpacking does the reverse. | 8 // in a more compact form to .android.rel.dyn. Unpacking does the reverse. |
9 // | 9 // |
10 // Invoke with -v to trace actions taken when packing or unpacking. | 10 // Invoke with -v to trace actions taken when packing or unpacking. |
11 // Invoke with -p to pad removed relocations with R_*_NONE. Suppresses | 11 // Invoke with -p to pad removed relocations with R_*_NONE. Suppresses |
12 // shrinking of .rel.dyn. | 12 // shrinking of .rel.dyn. |
13 // See PrintUsage() below for full usage details. | 13 // See PrintUsage() below for full usage details. |
14 // | 14 // |
15 // NOTE: Breaks with libelf 0.152, which is buggy. libelf 0.158 works. | 15 // NOTE: Breaks with libelf 0.152, which is buggy. libelf 0.158 works. |
16 | 16 |
17 #include <errno.h> | 17 #include <errno.h> |
18 #include <fcntl.h> | 18 #include <fcntl.h> |
19 #include <getopt.h> | 19 #include <getopt.h> |
20 #include <stdio.h> | 20 #include <stdio.h> |
21 #include <stdlib.h> | 21 #include <stdlib.h> |
22 #include <sys/types.h> | 22 #include <sys/types.h> |
23 #include <unistd.h> | 23 #include <unistd.h> |
24 #include <string> | 24 #include <string> |
25 | 25 |
26 #include "debug.h" | 26 #include "debug.h" |
27 #include "elf_file.h" | 27 #include "elf_file.h" |
| 28 #include "elf_traits.h" |
28 #include "libelf.h" | 29 #include "libelf.h" |
29 | 30 |
30 namespace { | 31 #include "nativehelper/ScopedFd.h" |
31 | 32 |
32 void PrintUsage(const char* argv0) { | 33 static void PrintUsage(const char* argv0) { |
33 std::string temporary = argv0; | 34 std::string temporary = argv0; |
34 const size_t last_slash = temporary.find_last_of("/"); | 35 const size_t last_slash = temporary.find_last_of("/"); |
35 if (last_slash != temporary.npos) { | 36 if (last_slash != temporary.npos) { |
36 temporary.erase(0, last_slash + 1); | 37 temporary.erase(0, last_slash + 1); |
37 } | 38 } |
38 const char* basename = temporary.c_str(); | 39 const char* basename = temporary.c_str(); |
39 | 40 |
40 printf( | 41 printf( |
41 "Usage: %s [-u] [-v] [-p] file\n\n" | 42 "Usage: %s [-u] [-v] [-p] file\n\n" |
42 "Pack or unpack relative relocations in a shared library.\n\n" | 43 "Pack or unpack relative relocations in a shared library.\n\n" |
43 " -u, --unpack unpack previously packed relative relocations\n" | 44 " -u, --unpack unpack previously packed relative relocations\n" |
44 " -v, --verbose trace object file modifications (for debugging)\n" | 45 " -v, --verbose trace object file modifications (for debugging)\n" |
45 " -p, --pad do not shrink relocations, but pad (for debugging)\n\n", | 46 " -p, --pad do not shrink relocations, but pad (for debugging)\n\n", |
46 basename); | 47 basename); |
47 | 48 |
48 if (ELF::kMachine == EM_ARM) { | |
49 printf( | |
50 "Extracts relative relocations from the .rel.dyn section, packs them\n" | |
51 "into a more compact format, and stores the packed relocations in\n" | |
52 ".android.rel.dyn. Expands .android.rel.dyn to hold the packed\n" | |
53 "data, and shrinks .rel.dyn by the amount of unpacked data removed\n" | |
54 "from it.\n\n" | |
55 "Before being packed, a shared library needs to be prepared by adding\n" | |
56 "a null .android.rel.dyn section.\n\n" | |
57 "To pack relocations in a shared library:\n\n" | |
58 " echo -n 'NULL' >/tmp/small\n" | |
59 " arm-linux-androideabi-objcopy \\\n" | |
60 " --add-section .android.rel.dyn=/tmp/small \\\n" | |
61 " libchrome.<version>.so\n" | |
62 " rm /tmp/small\n" | |
63 " %s libchrome.<version>.so\n\n" | |
64 "To unpack and restore the shared library to its original state:\n\n" | |
65 " %s -u libchrome.<version>.so\n" | |
66 " arm-linux-androideabi-objcopy \\\n" | |
67 " --remove-section=.android.rel.dyn libchrome.<version>.so\n\n", | |
68 basename, basename); | |
69 } else if (ELF::kMachine == EM_AARCH64) { | |
70 printf( | |
71 "Extracts relative relocations from the .rela.dyn section, packs them\n" | |
72 "into a more compact format, and stores the packed relocations in\n" | |
73 ".android.rela.dyn. Expands .android.rela.dyn to hold the packed\n" | |
74 "data, and shrinks .rela.dyn by the amount of unpacked data removed\n" | |
75 "from it.\n\n" | |
76 "Before being packed, a shared library needs to be prepared by adding\n" | |
77 "a null .android.rela.dyn section.\n\n" | |
78 "To pack relocations in a shared library:\n\n" | |
79 " echo -n 'NULL' >/tmp/small\n" | |
80 " aarch64-linux-android-objcopy \\\n" | |
81 " --add-section .android.rela.dyn=/tmp/small \\\n" | |
82 " libchrome.<version>.so\n" | |
83 " rm /tmp/small\n" | |
84 " %s libchrome.<version>.so\n\n" | |
85 "To unpack and restore the shared library to its original state:\n\n" | |
86 " %s -u libchrome.<version>.so\n" | |
87 " aarch64-linux-android-objcopy \\\n" | |
88 " --remove-section=.android.rela.dyn libchrome.<version>.so\n\n", | |
89 basename, basename); | |
90 } else { | |
91 NOTREACHED(); | |
92 } | |
93 | |
94 printf( | 49 printf( |
95 "Debug sections are not handled, so packing should not be used on\n" | 50 "Debug sections are not handled, so packing should not be used on\n" |
96 "shared libraries compiled for debugging or otherwise unstripped.\n"); | 51 "shared libraries compiled for debugging or otherwise unstripped.\n"); |
97 } | 52 } |
98 | 53 |
99 } // namespace | |
100 | |
101 int main(int argc, char* argv[]) { | 54 int main(int argc, char* argv[]) { |
102 bool is_unpacking = false; | 55 bool is_unpacking = false; |
103 bool is_verbose = false; | 56 bool is_verbose = false; |
104 bool is_padding = false; | 57 bool is_padding = false; |
105 | 58 |
106 static const option options[] = { | 59 static const option options[] = { |
107 {"unpack", 0, 0, 'u'}, {"verbose", 0, 0, 'v'}, {"pad", 0, 0, 'p'}, | 60 {"unpack", 0, 0, 'u'}, {"verbose", 0, 0, 'v'}, {"pad", 0, 0, 'p'}, |
108 {"help", 0, 0, 'h'}, {NULL, 0, 0, 0} | 61 {"help", 0, 0, 'h'}, {NULL, 0, 0, 0} |
109 }; | 62 }; |
110 bool has_options = true; | 63 bool has_options = true; |
(...skipping 25 matching lines...) Expand all Loading... |
136 } | 89 } |
137 if (optind != argc - 1) { | 90 if (optind != argc - 1) { |
138 LOG(INFO) << "Try '" << argv[0] << " --help' for more information."; | 91 LOG(INFO) << "Try '" << argv[0] << " --help' for more information."; |
139 return 1; | 92 return 1; |
140 } | 93 } |
141 | 94 |
142 if (elf_version(EV_CURRENT) == EV_NONE) { | 95 if (elf_version(EV_CURRENT) == EV_NONE) { |
143 LOG(WARNING) << "Elf Library is out of date!"; | 96 LOG(WARNING) << "Elf Library is out of date!"; |
144 } | 97 } |
145 | 98 |
146 LOG(INFO) << "Configured for " << ELF::Machine(); | |
147 | |
148 const char* file = argv[argc - 1]; | 99 const char* file = argv[argc - 1]; |
149 const int fd = open(file, O_RDWR); | 100 ScopedFd fd(open(file, O_RDWR)); |
150 if (fd == -1) { | 101 if (fd.get() == -1) { |
151 LOG(ERROR) << file << ": " << strerror(errno); | 102 LOG(ERROR) << file << ": " << strerror(errno); |
152 return 1; | 103 return 1; |
153 } | 104 } |
154 | 105 |
155 if (is_verbose) | 106 if (is_verbose) |
156 relocation_packer::Logger::SetVerbose(1); | 107 relocation_packer::Logger::SetVerbose(1); |
157 | 108 |
158 relocation_packer::ElfFile elf_file(fd); | 109 // We need to detect elf class in order to create |
159 elf_file.SetPadding(is_padding); | 110 // correct implementation |
| 111 uint8_t e_ident[EI_NIDENT]; |
| 112 if (TEMP_FAILURE_RETRY(read(fd.get(), e_ident, EI_NIDENT) != EI_NIDENT)) { |
| 113 LOG(ERROR) << file << ": failed to read elf header:" << strerror(errno); |
| 114 return 1; |
| 115 } |
160 | 116 |
161 bool status; | 117 if (TEMP_FAILURE_RETRY(lseek(fd.get(), 0, SEEK_SET)) != 0) { |
162 if (is_unpacking) | 118 LOG(ERROR) << file << ": lseek to 0 failed:" << strerror(errno); |
163 status = elf_file.UnpackRelocations(); | 119 return 1; |
164 else | 120 } |
165 status = elf_file.PackRelocations(); | |
166 | 121 |
167 close(fd); | 122 bool status = false; |
| 123 |
| 124 if (e_ident[EI_CLASS] == ELFCLASS32) { |
| 125 relocation_packer::ElfFile<ELF32_traits> elf_file(fd.get()); |
| 126 elf_file.SetPadding(is_padding); |
| 127 |
| 128 if (is_unpacking) { |
| 129 status = elf_file.UnpackRelocations(); |
| 130 } else { |
| 131 status = elf_file.PackRelocations(); |
| 132 } |
| 133 } else if (e_ident[EI_CLASS] == ELFCLASS64) { |
| 134 relocation_packer::ElfFile<ELF64_traits> elf_file(fd.get()); |
| 135 elf_file.SetPadding(is_padding); |
| 136 |
| 137 if (is_unpacking) { |
| 138 status = elf_file.UnpackRelocations(); |
| 139 } else { |
| 140 status = elf_file.PackRelocations(); |
| 141 } |
| 142 } else { |
| 143 LOG(ERROR) << file << ": unknown ELFCLASS: " << e_ident[EI_CLASS]; |
| 144 return 1; |
| 145 } |
168 | 146 |
169 if (!status) { | 147 if (!status) { |
170 LOG(ERROR) << file << ": failed to pack/unpack file"; | 148 LOG(ERROR) << file << ": failed to pack/unpack file"; |
171 return 1; | 149 return 1; |
172 } | 150 } |
173 | 151 |
174 return 0; | 152 return 0; |
175 } | 153 } |
OLD | NEW |