1 /* TODO: 2 1. check the ARM EABI version--this works for versions 1 and 2. 3 2. use a more-intelligent approach to finding the symbol table, 4 symbol-string table, and the .dynamic section. 5 3. fix the determination of the host and ELF-file endianness 6 4. write the help screen 7 */ 8 9 #include <stdio.h> 10 #include <common.h> 11 #include <debug.h> 12 #include <libelf.h> 13 #include <elf.h> 14 #include <gelf.h> 15 #include <cmdline.h> 16 #include <string.h> 17 #include <errno.h> 18 #include <string.h> 19 #include <sys/types.h> 20 #include <sys/stat.h> 21 #include <fcntl.h> 22 #include <unistd.h> 23 #include <apriori.h> 24 #include <prelinkmap.h> 25 26 /* Flag set by --verbose. This variable is global as it is accessed by the 27 macro INFO() in multiple compilation unites. */ 28 int verbose_flag = 0; 29 /* Flag set by --quiet. This variable is global as it is accessed by the 30 macro PRINT() in multiple compilation unites. */ 31 int quiet_flag = 0; 32 static void print_dynamic_symbols(Elf *elf, const char *symtab_name); 33 34 static unsigned s_next_link_addr; 35 static off_t s_addr_increment; 36 37 static void report_library_size_in_memory(const char *name, off_t fsize) 38 { 39 ASSERT(s_next_link_addr != -1UL); 40 INFO("Setting next link address (current is at 0x%08x):\n", 41 s_next_link_addr); 42 if (s_addr_increment) { 43 FAILIF(s_addr_increment < fsize, 44 "Command-line-specified address increment of 0x%08llx (%lld) " 45 "less than file [%s]'s size of %lld bytes!\n", 46 s_addr_increment, s_addr_increment, name, fsize); 47 FAILIF(s_next_link_addr % 4096, 48 "User-provided address increment 0x%08lx " 49 "is not page-aligned!\n", 50 s_addr_increment); 51 INFO("\tignoring file size, adjusting by address increment.\n"); 52 s_next_link_addr += s_addr_increment; 53 } 54 else { 55 INFO("\tuser address increment is zero, adjusting by file size.\n"); 56 s_next_link_addr += fsize; 57 s_next_link_addr &= ~(4096 - 1); 58 } 59 INFO("\t[%s] file size 0x%08lx\n", 60 name, 61 fsize); 62 INFO("\tnext prelink address: 0x%08x\n", s_next_link_addr); 63 ASSERT(!(s_next_link_addr % 4096)); /* New address must be page-aligned */ 64 } 65 66 static unsigned get_next_link_address(const char *name) { 67 return s_next_link_addr; 68 } 69 70 int main(int argc, char **argv) { 71 /* Do not issue INFO() statements before you call get_options() to set 72 the verbose flag as necessary. 73 */ 74 75 char **lookup_dirs, **default_libs; 76 char *mapfile, *output, *prelinkmap; 77 int start_addr, inc_addr, locals_only, num_lookup_dirs, 78 num_default_libs, dry_run; 79 int first = get_options(argc, argv, 80 &start_addr, &inc_addr, &locals_only, 81 &quiet_flag, 82 &dry_run, 83 &lookup_dirs, &num_lookup_dirs, 84 &default_libs, &num_default_libs, 85 &verbose_flag, 86 &mapfile, 87 &output, 88 &prelinkmap); 89 90 /* Perform some command-line-parameter checks. */ 91 int cmdline_err = 0; 92 if (first == argc) { 93 ERROR("You must specify at least one input ELF file!\n"); 94 cmdline_err++; 95 } 96 /* We complain when the user does not specify a start address for 97 prelinking when the user does not pass the locals_only switch. The 98 reason is that we will have a collection of executables, which we always 99 prelink to zero, and shared libraries, which we prelink at the specified 100 prelink address. When the user passes the locals_only switch, we do not 101 fail if the user does not specify start_addr, because the file to 102 prelink may be an executable, and not a shared library. At this moment, 103 we do not know what the case is. We find that out when we call function 104 init_source(). 105 */ 106 if (!locals_only && start_addr == -1) { 107 ERROR("You must specify --start-addr!\n"); 108 cmdline_err++; 109 } 110 if (start_addr == -1 && inc_addr != -1) { 111 ERROR("You must provide a start address if you provide an " 112 "address increment!\n"); 113 cmdline_err++; 114 } 115 if (prelinkmap != NULL && start_addr != -1) { 116 ERROR("You may not provide a prelink-map file (-p) and use -s/-i " 117 "at the same time!\n"); 118 cmdline_err++; 119 } 120 if (inc_addr == 0) { 121 ERROR("You may not specify a link-address increment of zero!\n"); 122 cmdline_err++; 123 } 124 if (locals_only) { 125 if (argc - first == 1) { 126 if (inc_addr != -1) { 127 ERROR("You are prelinking a single file; there is no point in " 128 "specifying a prelink-address increment!\n"); 129 /* This is nonfatal error, but paranoia is healthy. */ 130 cmdline_err++; 131 } 132 } 133 if (lookup_dirs != NULL || default_libs != NULL) { 134 ERROR("You are prelinking local relocations only; there is " 135 "no point in specifying lookup directories!\n"); 136 /* This is nonfatal error, but paranoia is healthy. */ 137 cmdline_err++; 138 } 139 } 140 141 /* If there is an output option, then that must specify a file, if there is 142 a single input file, or a directory, if there are multiple input 143 files. */ 144 if (output != NULL) { 145 struct stat output_st; 146 FAILIF(stat(output, &output_st) < 0 && errno != ENOENT, 147 "stat(%s): %s (%d)\n", 148 output, 149 strerror(errno), 150 errno); 151 152 if (argc - first == 1) { 153 FAILIF(!errno && !S_ISREG(output_st.st_mode), 154 "you have a single input file: -o must specify a " 155 "file name!\n"); 156 } 157 else { 158 FAILIF(errno == ENOENT, 159 "you have multiple input files: -o must specify a " 160 "directory name, but %s does not exist!\n", 161 output); 162 FAILIF(!S_ISDIR(output_st.st_mode), 163 "you have multiple input files: -o must specify a " 164 "directory name, but %s is not a directory!\n", 165 output); 166 } 167 } 168 169 if (cmdline_err) { 170 print_help(argv[0]); 171 FAILIF(1, "There are command-line-option errors.\n"); 172 } 173 174 /* Check to see whether the ELF library is current. */ 175 FAILIF (elf_version(EV_CURRENT) == EV_NONE, "libelf is out of date!\n"); 176 177 if (inc_addr < 0) { 178 if (!locals_only) 179 PRINT("User has not provided an increment address, " 180 "will use library size to calculate successive " 181 "prelink addresses.\n"); 182 inc_addr = 0; 183 } 184 185 void (*func_report_library_size_in_memory)(const char *name, off_t fsize); 186 unsigned (*func_get_next_link_address)(const char *name); 187 188 if (prelinkmap != NULL) { 189 INFO("Reading prelink addresses from prelink-map file [%s].\n", 190 prelinkmap); 191 pm_init(prelinkmap); 192 func_report_library_size_in_memory = pm_report_library_size_in_memory; 193 func_get_next_link_address = pm_get_next_link_address; 194 } 195 else { 196 INFO("Start address: 0x%x\n", start_addr); 197 INFO("Increment address: 0x%x\n", inc_addr); 198 s_next_link_addr = start_addr; 199 s_addr_increment = inc_addr; 200 func_report_library_size_in_memory = report_library_size_in_memory; 201 func_get_next_link_address = get_next_link_address; 202 } 203 204 /* Prelink... */ 205 apriori(&argv[first], argc - first, output, 206 func_report_library_size_in_memory, func_get_next_link_address, 207 locals_only, 208 dry_run, 209 lookup_dirs, num_lookup_dirs, 210 default_libs, num_default_libs, 211 mapfile); 212 213 FREEIF(mapfile); 214 FREEIF(output); 215 if (lookup_dirs) { 216 ASSERT(num_lookup_dirs); 217 while (num_lookup_dirs--) 218 FREE(lookup_dirs[num_lookup_dirs]); 219 FREE(lookup_dirs); 220 } 221 if (default_libs) { 222 ASSERT(num_default_libs); 223 while (num_default_libs--) 224 FREE(default_libs[num_default_libs]); 225 FREE(default_libs); 226 } 227 228 return 0; 229 } 230