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
3 // found in the LICENSE file.
5 // Tool to pack and unpack relative relocations in a shared library.
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.
10 // Invoke with -v to trace actions taken when packing or unpacking.
11 // Invoke with -p to pad removed relocations with R_*_NONE. Suppresses
12 // shrinking of .rel.dyn.
13 // See PrintUsage() below for full usage details.
15 // NOTE: Breaks with libelf 0.152, which is buggy. libelf 0.158 works.
22 #include <sys/types.h>
28 #include "elf_traits.h"
31 #include "nativehelper/ScopedFd.h"
33 static void PrintUsage(const char* argv0
) {
34 std::string temporary
= argv0
;
35 const size_t last_slash
= temporary
.find_last_of("/");
36 if (last_slash
!= temporary
.npos
) {
37 temporary
.erase(0, last_slash
+ 1);
39 const char* basename
= temporary
.c_str();
42 "Usage: %s [-u] [-v] [-p] file\n\n"
43 "Pack or unpack relative relocations in a shared library.\n\n"
44 " -u, --unpack unpack previously packed relative relocations\n"
45 " -v, --verbose trace object file modifications (for debugging)\n"
46 " -p, --pad do not shrink relocations, but pad (for debugging)\n\n",
50 "Debug sections are not handled, so packing should not be used on\n"
51 "shared libraries compiled for debugging or otherwise unstripped.\n");
54 int main(int argc
, char* argv
[]) {
55 bool is_unpacking
= false;
56 bool is_verbose
= false;
57 bool is_padding
= false;
59 static const option options
[] = {
60 {"unpack", 0, 0, 'u'}, {"verbose", 0, 0, 'v'}, {"pad", 0, 0, 'p'},
61 {"help", 0, 0, 'h'}, {NULL
, 0, 0, 0}
63 bool has_options
= true;
65 int c
= getopt_long(argc
, argv
, "uvph", options
, NULL
);
80 LOG(INFO
) << "Try '" << argv
[0] << " --help' for more information.";
90 if (optind
!= argc
- 1) {
91 LOG(INFO
) << "Try '" << argv
[0] << " --help' for more information.";
95 if (elf_version(EV_CURRENT
) == EV_NONE
) {
96 LOG(WARNING
) << "Elf Library is out of date!";
99 const char* file
= argv
[argc
- 1];
100 ScopedFd
fd(open(file
, O_RDWR
));
101 if (fd
.get() == -1) {
102 LOG(ERROR
) << file
<< ": " << strerror(errno
);
107 relocation_packer::Logger::SetVerbose(1);
109 // We need to detect elf class in order to create
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
);
117 if (TEMP_FAILURE_RETRY(lseek(fd
.get(), 0, SEEK_SET
)) != 0) {
118 LOG(ERROR
) << file
<< ": lseek to 0 failed:" << strerror(errno
);
124 if (e_ident
[EI_CLASS
] == ELFCLASS32
) {
125 relocation_packer::ElfFile
<ELF32_traits
> elf_file(fd
.get());
126 elf_file
.SetPadding(is_padding
);
129 status
= elf_file
.UnpackRelocations();
131 status
= elf_file
.PackRelocations();
133 } else if (e_ident
[EI_CLASS
] == ELFCLASS64
) {
134 relocation_packer::ElfFile
<ELF64_traits
> elf_file(fd
.get());
135 elf_file
.SetPadding(is_padding
);
138 status
= elf_file
.UnpackRelocations();
140 status
= elf_file
.PackRelocations();
143 LOG(ERROR
) << file
<< ": unknown ELFCLASS: " << e_ident
[EI_CLASS
];
148 LOG(ERROR
) << file
<< ": failed to pack/unpack file";