/* 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;
}
}