2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 Copyright (c) 2008 Eliot Dresselhaus
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 #include <vppinfra/elf.h>
40 #include <sys/types.h>
52 char * set_interpreter;
58 /* for use in the optimized / simplified case */
60 u64 interpreter_offset;
64 static clib_error_t * elf_set_interpreter (elf_main_t * em,
70 char * interp = tm->set_interpreter;
72 switch (em->first_header.file_type)
78 if (tm->allow_elf_shared)
80 /* Note flowthrough */
82 return clib_error_return (0, "unacceptable file_type");
85 vec_foreach (g, em->segments)
87 if (g->header.type == ELF_SEGMENT_INTERP)
91 if (g >= vec_end (em->segments))
92 return clib_error_return (0, "interpreter not found");
94 if (g->header.memory_size < 1 + strlen (interp))
95 return clib_error_return (0, "given interpreter does not fit; must be less than %d bytes (`%s' given)",
96 g->header.memory_size, interp);
98 error = elf_get_section_by_start_address (em, g->header.virtual_address, &s);
102 /* Put in new null terminated string. */
103 memset (s->contents, 0, vec_len (s->contents));
104 clib_memcpy (s->contents, interp, strlen (interp));
110 delete_rpath_for_section (elf_main_t * em, elf_section_t * s)
112 elf64_dynamic_entry_t * e;
113 elf64_dynamic_entry_t * new_es = 0;
115 vec_foreach (e, em->dynamic_entries)
119 case ELF_DYNAMIC_ENTRY_RPATH:
120 case ELF_DYNAMIC_ENTRY_RUN_PATH:
124 vec_add1 (new_es, e[0]);
129 /* Pad so as to keep section size constant. */
131 elf64_dynamic_entry_t e_end;
132 e_end.type = ELF_DYNAMIC_ENTRY_END;
134 while (vec_len (new_es) < vec_len (em->dynamic_entries))
135 vec_add1 (new_es, e_end);
138 vec_free (em->dynamic_entries);
139 em->dynamic_entries = new_es;
141 elf_set_dynamic_entries (em);
144 static void delete_rpath (elf_main_t * em)
148 vec_foreach (s, em->sections)
150 switch (s->header.type)
152 case ELF_SECTION_DYNAMIC:
153 delete_rpath_for_section (em, s);
162 static clib_error_t *
163 set_rpath_for_section (elf_main_t * em, elf_section_t * s, char * new_rpath)
165 elf64_dynamic_entry_t * e;
167 int old_len, new_len = strlen (new_rpath);
168 u8 * new_string_table = vec_dup (em->dynamic_string_table);
170 vec_foreach (e, em->dynamic_entries)
174 case ELF_DYNAMIC_ENTRY_RPATH:
175 case ELF_DYNAMIC_ENTRY_RUN_PATH:
176 old_rpath = (char *) new_string_table + e->data;
177 old_len = strlen (old_rpath);
178 if (old_len < new_len)
179 return clib_error_return (0, "rpath of `%s' does not fit (old rpath `%s')",
180 new_rpath, old_rpath);
181 strcpy (old_rpath, new_rpath);
189 elf_set_section_contents (em, em->dynamic_string_table_section_index,
191 vec_bytes (new_string_table));
196 static clib_error_t *
197 set_rpath (elf_main_t * em, char * rpath)
199 clib_error_t * error = 0;
202 vec_foreach (s, em->sections)
204 switch (s->header.type)
206 case ELF_SECTION_DYNAMIC:
207 error = set_rpath_for_section (em, s, rpath);
220 static clib_error_t *
221 set_interpreter_rpath (elf_tool_main_t * tm)
223 int ifd = -1, ofd = -1;
225 u8 *idp = 0; /* warning be gone */
226 u64 mmap_length = 0, i;
229 u64 offset0 = 0, offset1 = 0;
230 clib_error_t * error = 0;
231 int fix_in_place = 0;
233 if (!strcmp (tm->input_file, tm->output_file))
236 ifd = open (tm->input_file, O_RDWR);
239 error = clib_error_return_unix (0, "open `%s'", tm->input_file);
243 if (fstat (ifd, &fd_stat) < 0)
245 error = clib_error_return_unix (0, "fstat `%s'", tm->input_file);
249 if (!(fd_stat.st_mode & S_IFREG))
251 error = clib_error_return (0, "%s is not a regular file", tm->input_file);
255 mmap_length = fd_stat.st_size;
258 error = clib_error_return (0, "%s too short", tm->input_file);
262 /* COW-mapping, since we intend to write the fixups */
264 idp = mmap (0, mmap_length, PROT_READ | PROT_WRITE, MAP_SHARED,
265 ifd, /* offset */ 0);
267 idp = mmap (0, mmap_length, PROT_READ | PROT_WRITE, MAP_PRIVATE,
268 ifd, /* offset */ 0);
269 if (~pointer_to_uword (idp) == 0)
272 error = clib_error_return_unix (0, "mmap `%s'", tm->input_file);
276 if (idp[0] != 0x7f || idp[1] != 'E' || idp[2] != 'L' || idp[3] != 'F')
278 error = clib_error_return (0, "not an ELF file '%s'", tm->input_file);
285 for (i = 0; i < mmap_length; i++)
299 if (in_run && run_length >= 16)
302 offset0 = (i - run_length);
303 else if (offset1 == 0)
305 offset1 = (i - run_length);
316 error = clib_error_return (0, "no fixup markers in %s",
323 clib_warning ("offset0 %lld (0x%llx), offset1 %lld (0x%llx)",
324 offset0, offset0, offset1, offset1);
326 /* Executable file case */
327 if (offset0 && offset1)
329 tm->interpreter_offset = offset0;
330 tm->rpath_offset = offset1;
332 else /* shared library case */
334 tm->interpreter_offset = 0;
335 tm->rpath_offset = offset0;
338 if (tm->interpreter_offset)
339 clib_memcpy (&idp[tm->interpreter_offset], tm->set_interpreter,
340 strlen (tm->set_interpreter)+1);
342 if (tm->rpath_offset)
343 clib_memcpy (&idp[tm->rpath_offset], tm->set_rpath,
344 strlen (tm->set_rpath)+1);
346 /* Write the output file... */
347 if (fix_in_place == 0)
349 ofd = open (tm->output_file, O_RDWR | O_CREAT | O_TRUNC, 0644);
352 error = clib_error_return_unix (0, "create `%s'", tm->output_file);
356 if (write (ofd, idp, mmap_length) != mmap_length)
357 error = clib_error_return_unix (0, "write `%s'", tm->output_file);
361 if (mmap_length > 0 && idp)
362 munmap (idp, mmap_length);
371 int main (int argc, char * argv[])
373 elf_tool_main_t _tm, * tm = &_tm;
374 elf_main_t * em = &tm->elf_main;
376 clib_error_t * error = 0;
378 memset (tm, 0, sizeof (tm[0]));
379 unformat_init_command_line (&i, argv);
381 while (unformat_check_input (&i) != UNFORMAT_END_OF_INPUT)
383 if (unformat (&i, "in %s", &tm->input_file))
385 else if (unformat (&i, "out %s", &tm->output_file))
387 else if (unformat (&i, "set-interpreter %s", &tm->set_interpreter))
389 else if (unformat (&i, "set-rpath %s", &tm->set_rpath))
391 else if (unformat (&i, "unset-rpath"))
393 else if (unformat (&i, "verbose"))
395 else if (unformat (&i, "verbose-symbols"))
396 tm->verbose |= FORMAT_ELF_MAIN_SYMBOLS;
397 else if (unformat (&i, "verbose-relocations"))
398 tm->verbose |= FORMAT_ELF_MAIN_RELOCATIONS;
399 else if (unformat (&i, "verbose-dynamic"))
400 tm->verbose |= FORMAT_ELF_MAIN_DYNAMIC;
401 else if (unformat (&i, "quiet"))
403 else if (unformat (&i, "allow-elf-shared"))
404 tm->allow_elf_shared = 1;
407 error = unformat_parse_error (&i);
412 if (! tm->input_file)
414 error = clib_error_return (0, "no input file");
418 /* Do the typical case a stone-simple way... */
419 if (tm->quiet && tm->set_interpreter && tm->set_rpath && tm->output_file)
421 error = set_interpreter_rpath (tm);
425 error = elf_read_file (em, tm->input_file);
431 fformat (stdout, "%U", format_elf_main, em, tm->verbose);
433 if (tm->set_interpreter)
435 error = elf_set_interpreter (em, tm);
442 error = set_rpath (em, tm->set_rpath);
451 error = elf_write_file (em, tm->output_file);
459 clib_error_report (error);