1
1
/* Copyright 2017 R. Thomas
2
2
* Copyright 2017 Quarkslab
3
+ * Copyright 2020, NVIDIA CORPORATION. All rights reserved.
3
4
*
4
5
* Licensed under the Apache License, Version 2.0 (the "License");
5
6
* you may not use this file except in compliance with the License.
14
15
* limitations under the License.
15
16
*/
16
17
#include < numeric>
18
+ #include < unordered_map>
17
19
18
20
#include " LIEF/logging++.hpp"
19
21
@@ -144,15 +146,16 @@ void Builder::build(void) {
144
146
145
147
}
146
148
147
-
148
149
template <typename T, typename HANDLER>
149
- std::vector<std::string> Builder::optimize (const HANDLER& container) {
150
+ std::vector<std::string> Builder::optimize (const HANDLER& container,
151
+ std::unordered_map<std::string, size_t > *of_map_p) {
150
152
151
153
std::set<std::string> string_table;
152
-
153
154
std::vector<std::string> string_table_optimized;
155
+ string_table_optimized.reserve (container.size ());
154
156
155
- // Insert all strings in a std::set<> ordered by size
157
+ // reverse all symbol names and sort them so we can merge then in the linear time:
158
+ // aaa, aadd, aaaa, cca, ca -> aaaa, aaa, acc, ac ddaa
156
159
std::transform (
157
160
std::begin (container),
158
161
std::end (container),
@@ -161,32 +164,73 @@ std::vector<std::string> Builder::optimize(const HANDLER& container) {
161
164
std::end (string_table)),
162
165
std::mem_fn (static_cast <const std::string& (T::*)(void ) const >(&T::name)));
163
166
164
- std::vector<std::string> sorted_table;
165
- sorted_table.reserve (container.size ());
166
- std::move (std::begin (string_table), std::end (string_table),
167
- std::back_inserter (sorted_table));
168
-
169
- std::stable_sort (std::begin (sorted_table), std::end (sorted_table),
170
- [] (const std::string& lhs, const std::string& rhs) {
171
- return lhs.size () >= rhs.size ();
172
- });
167
+ for (auto &val: string_table) {
168
+ string_table_optimized.emplace_back (std::move (val));
169
+ std::reverse (std::begin (string_table_optimized.back ()), std::end (string_table_optimized.back ()));
170
+ }
173
171
174
- // Optimize the string table
175
- std::copy_if (
176
- std::begin (sorted_table),
177
- std::end (sorted_table),
178
- std::back_inserter (string_table_optimized),
179
- [&string_table_optimized] (const std::string& name) {
180
- // Check if the given string **IS** the suffix of another string
181
- auto it = std::find_if (
182
- std::begin (string_table_optimized),
183
- std::end (string_table_optimized),
184
- [&name] (const std::string& nameOpti) {
185
- return nameOpti.substr (nameOpti.size () - name.size ()) == name ;
186
- });
187
- return (it == std::end (string_table_optimized));
172
+ std::sort (std::begin (string_table_optimized), std::end (string_table_optimized),
173
+ [] (const std::string& lhs, const std::string& rhs) {
174
+ bool ret = false ;
175
+ if (lhs.size () > rhs.size ()) {
176
+ auto res = lhs.compare (0 , rhs.size (), rhs);
177
+ ret = (res <= 0 );
178
+ } else {
179
+ auto res = rhs.compare (0 , lhs.size (), lhs);
180
+ ret = (res > 0 );
181
+ }
182
+ return ret;
188
183
});
189
184
185
+ // as all elements that can be merged are adjacent we can just go through the list once
186
+ // and memorize one we merged to calculate the offsets later
187
+ std::unordered_map<std::string, std::string> merged_map;
188
+ size_t to_set_idx = 0 , cur_elm_idx = 1 ;
189
+ for (; cur_elm_idx < string_table_optimized.size (); ++cur_elm_idx) {
190
+ auto &cur_elm = string_table_optimized[cur_elm_idx];
191
+ auto &to_set_elm = string_table_optimized[to_set_idx];
192
+ if (to_set_elm.size () >= cur_elm.size ()) {
193
+ auto ret = to_set_elm.compare (0 , cur_elm.size (), cur_elm);
194
+ if (ret == 0 ) {
195
+ // when memorizing reverse back symbol names
196
+ std::string rev_cur_elm = cur_elm;
197
+ std::string rev_to_set_elm = to_set_elm;
198
+ std::reverse (std::begin (rev_cur_elm), std::end (rev_cur_elm));
199
+ std::reverse (std::begin (rev_to_set_elm), std::end (rev_to_set_elm));
200
+ merged_map[rev_cur_elm] = rev_to_set_elm;
201
+ continue ;
202
+ }
203
+ }
204
+ ++to_set_idx;
205
+ std::swap (string_table_optimized[to_set_idx], cur_elm);
206
+ }
207
+ // if the first one is empty
208
+ if (string_table_optimized[0 ].size () == 0 ) {
209
+ std::swap (string_table_optimized[0 ], string_table_optimized[to_set_idx]);
210
+ --to_set_idx;
211
+ }
212
+ string_table_optimized.resize (to_set_idx + 1 );
213
+
214
+ // reverse symbols back and sort them again
215
+ for (auto &val: string_table_optimized) {
216
+ std::reverse (std::begin (val), std::end (val));
217
+ }
218
+ std::sort (std::begin (string_table_optimized), std::end (string_table_optimized));
219
+
220
+ if (of_map_p) {
221
+ std::unordered_map<std::string, size_t > offset_map;
222
+ offset_map[" " ] = 0 ;
223
+ size_t offset_counter = 1 ;
224
+ for (const auto &v : string_table_optimized) {
225
+ offset_map[v] = offset_counter;
226
+ offset_counter += v.size () + 1 ;
227
+ }
228
+ for (const auto &kv : merged_map) {
229
+ offset_map[kv.first ] = offset_map[kv.second ] + (kv.second .size () - kv.first .size ());
230
+ }
231
+ *of_map_p = std::move (offset_map);
232
+ }
233
+
190
234
return string_table_optimized;
191
235
}
192
236
@@ -442,10 +486,12 @@ void Builder::build_static_symbols(void) {
442
486
vector_iostream content (this ->should_swap ());
443
487
content.reserve (this ->binary_ ->static_symbols_ .size () * sizeof (Elf_Sym));
444
488
std::vector<uint8_t > string_table_raw;
489
+ std::unordered_map<std::string, size_t > offset_name_map;
445
490
446
491
// Container which will hold symbols name (optimized)
447
492
std::vector<std::string> string_table_optimize =
448
- this ->optimize <Symbol, decltype (this ->binary_ ->static_symbols_ )>(this ->binary_ ->static_symbols_ );
493
+ this ->optimize <Symbol, decltype (this ->binary_ ->static_symbols_ )>(this ->binary_ ->static_symbols_ ,
494
+ &offset_name_map);
449
495
450
496
// We can't start with a symbol name
451
497
string_table_raw.push_back (0 );
@@ -459,19 +505,13 @@ void Builder::build_static_symbols(void) {
459
505
VLOG (VDEBUG) << " Dealing with symbol: " << symbol->name ();
460
506
const std::string& name = symbol->name ();
461
507
462
- // Check if name is already pressent
463
- auto && it_name = std::search (
464
- std::begin (string_table_raw),
465
- std::end (string_table_raw),
466
- name.c_str (),
467
- name.c_str () + name.size () + 1 );
468
-
469
-
470
- if (it_name == std::end (string_table_raw)) {
471
- throw LIEF::not_found (" Unable to find symbol '" + name + " ' in the string table" );
508
+ auto offset_it = offset_name_map.find (name);
509
+ if (offset_it == std::end (offset_name_map)) {
510
+ throw LIEF::not_found (" Unable to find symbol '" + name + " ' in the string table" );
472
511
}
473
512
474
- const Elf_Off name_offset = static_cast <Elf_Off>(std::distance (std::begin (string_table_raw), it_name));
513
+ const Elf_Off name_offset = static_cast <Elf_Off>(offset_it->second );
514
+
475
515
476
516
Elf_Sym sym_hdr;
477
517
memset (&sym_hdr, 0 , sizeof (sym_hdr));
@@ -1052,33 +1092,29 @@ void Builder::build_dynamic_symbols(void) {
1052
1092
1053
1093
// Build symbols string table
1054
1094
std::vector<uint8_t > string_table_raw = string_table_section.content ();
1095
+ std::unordered_map<std::string, size_t > offset_name_map;
1096
+ size_t additional_offset = string_table_raw.size () - 1 ;
1055
1097
1056
1098
std::vector<std::string> string_table_optimized =
1057
- this ->optimize <Symbol, decltype (this ->binary_ ->dynamic_symbols_ )>(this ->binary_ ->dynamic_symbols_ );
1099
+ this ->optimize <Symbol, decltype (this ->binary_ ->dynamic_symbols_ )>(this ->binary_ ->dynamic_symbols_ ,
1100
+ &offset_name_map);
1058
1101
1059
1102
for (const std::string& name : string_table_optimized) {
1060
1103
string_table_raw.insert (std::end (string_table_raw), std::begin (name), std::end (name));
1061
1104
string_table_raw.push_back (0 );
1062
1105
}
1063
1106
1064
-
1065
1107
//
1066
1108
// Build symbols
1067
1109
//
1068
1110
vector_iostream symbol_table_raw (this ->should_swap ());
1069
1111
for (const Symbol* symbol : this ->binary_ ->dynamic_symbols_ ) {
1070
1112
const std::string& name = symbol->name ();
1071
- // Check if name is already pressent
1072
- auto && it_name = std::search (
1073
- std::begin (string_table_raw),
1074
- std::end (string_table_raw),
1075
- name.c_str (),
1076
- name.c_str () + name.size () + 1 );
1077
-
1078
- if (it_name == std::end (string_table_raw)) {
1113
+ auto offset_it = offset_name_map.find (name);
1114
+ if (offset_it == std::end (offset_name_map)) {
1079
1115
throw LIEF::not_found (" Unable to find the symbol in the string table" );
1080
1116
}
1081
- const Elf_Off name_offset = static_cast <Elf_Off>(std::distance ( std::begin (string_table_raw), it_name) );
1117
+ const Elf_Off name_offset = static_cast <Elf_Off>(offset_name_map[name] + additional_offset );
1082
1118
1083
1119
Elf_Sym sym_header;
1084
1120
@@ -1285,15 +1321,15 @@ void Builder::build_dynamic_relocations(void) {
1285
1321
VLOG (VDEBUG) << " [+] Building dynamic relocations" ;
1286
1322
1287
1323
it_dynamic_relocations dynamic_relocations = this ->binary_ ->dynamic_relocations ();
1288
-
1324
+ auto end_iter = std::end (dynamic_relocations);
1289
1325
bool isRela = dynamic_relocations[0 ].is_rela ();
1290
- if ( not std::all_of (
1291
- std::begin (dynamic_relocations),
1292
- std::end (dynamic_relocations),
1293
- [isRela] ( const Relocation& relocation) {
1294
- return relocation. is_rela () == isRela;
1295
- }) ) {
1296
- throw LIEF::type_error (" Relocation are not of the same type" );
1326
+ for (; dynamic_relocations != end_iter; ++dynamic_relocations) {
1327
+ if (dynamic_relocations-> is_rela () != isRela) {
1328
+ break ;
1329
+ }
1330
+ }
1331
+ if (dynamic_relocations != end_iter ) {
1332
+ throw LIEF::type_error (" Relocation are not of the same type" );
1297
1333
}
1298
1334
1299
1335
dynamic_entries_t ::iterator it_dyn_relocation;
0 commit comments