/* Copyright (C) 2008 Emmanuel Varoquaux This file is part of XOS. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "dynamic_link.h" #include "load.h" #include "vars.h" #include "elf.h" #include "auxv.h" #include "xmalloc.h" #include "error.h" #include "sysvars.h" #include #include #include #include #define cannot_handle_program_error() fatal_error("cannot handle program") #define usage_error(...) nonfatal_error(__VA_ARGS__) void _start(); /* identifiants d'options longues */ enum {LO_LIST, LO_VERIFY, LO_LIBRARY_PATH}; /* modes */ enum {LM_VERIFY, LM_LIST, LM_RUN}; int program_skip_args; void *program_entry_point; void main(int argc, char **argv, char **envp, unsigned long *auxv); static void __attribute__ ((noreturn)) die_bad_usage() { fprintf(stderr, "Try `%s --help' for more information.\n", program_invocation_name); exit(EXIT_FAILURE); } static void print_help() { printf("Usage: %s [OPTION]... EXECUTABLE-FILE [ARGS...]\n", program_invocation_name); puts("Dynamic linker/loader."); putchar('\n'); puts(" --list list all dependencies and how they are resolved"); puts(" --verify verify that given object really is a dynamically"); puts(" linked object we can handle"); puts(" --library-path PATH use given PATH instead of content of the environment"); puts(" variable LD_LIBRARY_PATH"); puts(" -h, --help display this help and exit"); } static void loading_libraries_print_progname() { fprintf(stderr, "%s: error while loading shared libraries", executable_invocation_name); } void main(int argc, char **argv, char **envp, unsigned long *auxv) { int mode; struct auxiliary_vector_data_struct auxiliary_vector_data; struct program_data_struct program_data; int long_option_id; const struct option longopts[] = { {"list", no_argument, &long_option_id, LO_LIST}, {"verify", no_argument, &long_option_id, LO_VERIFY}, {"library-path", required_argument, &long_option_id, LO_LIBRARY_PATH}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; int c; /* configuration */ error_func = error; mode = LM_RUN; /* lecture du vecteur auxiliaire ELF */ read_auxiliary_vector(auxv, &auxiliary_vector_data); if (auxiliary_vector_data.contents.not_elf) fatal_error("program is not ELF"); /* parametres systeme */ page_size = auxiliary_vector_data.contents.page_size ? auxiliary_vector_data.page_size : (unsigned long)getpagesize(); /* environnement */ library_path = getenv("LD_LIBRARY_PATH") ? xstrdup(getenv("LD_LIBRARY_PATH")) : NULL; /* object partage dynamique virtuel */ if (auxiliary_vector_data.contents.vdso_elf_header) examine_vdso(auxiliary_vector_data.vdso_elf_header, &vdso_load_info); else { vdso_load_info.base_address = MAP_FAILED; vdso_load_info.load_address = MAP_FAILED; vdso_load_info.segment_table = NULL; vdso_load_info.segment_count = 0; vdso_load_info.entry_point = NULL; vdso_load_info.dynamic_array = NULL; vdso_load_info.interpreter_name = NULL; } if (auxiliary_vector_data.contents.program_entry_point && auxiliary_vector_data.program_entry_point != &_start) { /* ld.so a ete invoque par le systeme comme interpreteur d'un autre programme. */ if (!auxiliary_vector_data.contents.program_header_table || (auxiliary_vector_data.contents.program_header_entry_size && auxiliary_vector_data.program_header_entry_size != sizeof (Elf32_Phdr)) || !auxiliary_vector_data.contents.program_header_entry_number || !auxiliary_vector_data.contents.interpreter_base_address) cannot_handle_program_error(); program_skip_args = 0; program_entry_point = auxiliary_vector_data.program_entry_point; /* executable */ executable_invocation_name = argv[0]; examine_executable(auxiliary_vector_data.program_header_table, auxiliary_vector_data.program_header_entry_number, program_entry_point, executable_invocation_name, &executable_load_info); /* editeur de liens dynamique */ dynamic_linker_invocation_name = NULL; dynamic_linker_load_info.base_address = auxiliary_vector_data.interpreter_base_address; /* Je ne sais pas comment determiner l'adresse de chargement de l'interpeteur. Elle devrait etre egale a l'adresse de base augmentee de l'adresse virtuelle (vaddr) du premier segment. Comme nous sommes un objet partage (ET_DYN), vaddr a toutes les chances d'etre nulle et l'adresse de chargement de coincider avec l'adresse de base. La seule utilisation de dynamic_linker_load_address est dans l'affichage des dependances lorsque l'editeur de liens dynamique est appele avec l'option --list. A ce jour, ce mode n'est pas accessible par l'interpreteur. */ dynamic_linker_load_info.load_address = dynamic_linker_load_info.base_address; dynamic_linker_load_info.segment_table = NULL; dynamic_linker_load_info.segment_count = 0; dynamic_linker_load_info.entry_point = &_start; dynamic_linker_load_info.dynamic_array = NULL; dynamic_linker_load_info.interpreter_name = NULL; if (mode == LM_VERIFY) error_func = verify_error; else error_print_progname = loading_libraries_print_progname; } else { /* ld.so a ete invoque explicitement. */ if (!auxiliary_vector_data.contents.program_header_table || (auxiliary_vector_data.contents.program_header_entry_size && auxiliary_vector_data.program_header_entry_size != sizeof (Elf32_Phdr)) || !auxiliary_vector_data.contents.program_header_entry_number) cannot_handle_program_error(); /* editeur de liens dynamique */ dynamic_linker_invocation_name = argv[0]; read_program_header_table(auxiliary_vector_data.program_header_table, auxiliary_vector_data.program_header_entry_number, &program_data, dynamic_linker_invocation_name); if (!program_data.contents.dynamic_array) cannot_handle_program_error(); examine_dynamic_linker(auxiliary_vector_data.program_header_table, auxiliary_vector_data.program_header_entry_number, (void *)_DYNAMIC - program_data.dynamic_array_vaddr, program_entry_point, &dynamic_linker_load_info); /* lecture des arguments de la ligne de commande */ while ((c = getopt_long(argc, argv, "h", longopts, NULL)) != -1) switch (c) { case 0: switch (long_option_id) { case LO_LIST: mode = LM_LIST; break; case LO_VERIFY: mode = LM_VERIFY; break; case LO_LIBRARY_PATH: library_path = optarg; break; } break; case 'h': print_help(); exit(EXIT_SUCCESS); case '?': die_bad_usage(); } if (optind == argc) { usage_error("missing filename operand"); die_bad_usage(); } program_skip_args = optind; /* executable */ executable_invocation_name = argv[optind]; if (mode == LM_VERIFY) error_func = verify_error; else error_print_progname = loading_libraries_print_progname; /* chargement de l'executable */ load_object_file(executable_invocation_name, 0, &executable_load_info); program_entry_point = executable_load_info.entry_point; } switch (mode) { case LM_VERIFY: verify_executable(); case LM_LIST: list_dependencies(); exit(EXIT_SUCCESS); case LM_RUN: prepare_program(); break; } }