about summary refs log tree commit diff
path: root/llvm_mode/afl-ld.c
diff options
context:
space:
mode:
Diffstat (limited to 'llvm_mode/afl-ld.c')
-rw-r--r--llvm_mode/afl-ld.c98
1 files changed, 65 insertions, 33 deletions
diff --git a/llvm_mode/afl-ld.c b/llvm_mode/afl-ld.c
index 7cbf89dc..0e85795a 100644
--- a/llvm_mode/afl-ld.c
+++ b/llvm_mode/afl-ld.c
@@ -44,6 +44,8 @@
 
 #include <dirent.h>
 
+#define MAX_PARAM_COUNT 4096
+
 static u8 **ld_params,              /* Parameters passed to the real 'ld'   */
     **link_params,                  /* Parameters passed to 'llvm-link'     */
     **opt_params,                   /* Parameters passed to 'opt' opt       */
@@ -145,15 +147,21 @@ int is_llvm_file(const char* file) {
   int fd;
   u8  buf[5];
 
-  if ((fd = open(file, O_RDONLY)) < 0) return 0;
+  if ((fd = open(file, O_RDONLY)) < 0) {
+
+    if (debug) SAYF(cMGN "[D] " cRST "File %s not found", file);
+    return 0;
 
-  if (read(fd, buf, sizeof(buf)) != sizeof(buf)) return 0;
+  }
+
+  if (read(fd, buf, 4) != 4) return 0;
   buf[sizeof(buf) - 1] = 0;
 
   close(fd);
 
   if (strncmp(buf, "; Mo", 4) == 0) return 1;
-  if (buf[0] == 'B' && buf[1] == 'C' && buf[2] == 0xC0 && buf[3] == 0xDE)
+
+  if (buf[0] == 'B' && buf[1] == 'C' && buf[2] == 0xc0 && buf[3] == 0xde)
     return 1;
 
   return 0;
@@ -186,7 +194,7 @@ int is_duplicate(u8** params, u32 ld_param_cnt, u8* ar_file) {
 static void edit_params(int argc, char** argv) {
 
   u32 i, have_lto = 0, libdir_index;
-  u8 libdir_file[4096];
+  u8  libdir_file[4096];
 
   if (tmp_dir == NULL) {
 
@@ -204,13 +212,13 @@ static void edit_params(int argc, char** argv) {
   final_file =
       alloc_printf("%s/.afl-%u-%u-3.bc", tmp_dir, getpid(), (u32)time(NULL));
 
-  ld_params = ck_alloc((argc + 4096) * sizeof(u8*));
-  link_params = ck_alloc((argc + 4096) * sizeof(u8*));
+  ld_params = ck_alloc(4096 * sizeof(u8*));
+  link_params = ck_alloc(4096 * sizeof(u8*));
   inst_params = ck_alloc(12 * sizeof(u8*));
   opt_params = ck_alloc(12 * sizeof(u8*));
 
   ld_params[0] = (u8*)real_ld;
-  ld_params[argc] = 0;
+  ld_params[ld_param_cnt++] = "--allow-multiple-definition";
 
   link_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "llvm-link");
   link_params[link_param_cnt++] = "-S";  // we create the linked file as .ll
@@ -224,6 +232,7 @@ static void edit_params(int argc, char** argv) {
     opt_params[opt_param_cnt++] = "--polly";
 
   } else
+
     opt_params[opt_param_cnt++] = "-O0";
   // opt_params[opt_param_cnt++] = "-S"; // only when debugging
   opt_params[opt_param_cnt++] = linked_file;  // input: .ll file
@@ -243,11 +252,16 @@ static void edit_params(int argc, char** argv) {
   // first we must collect all library search paths
   for (i = 1; i < argc; i++)
     if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == 'L')
-        libdirs[libdir_cnt++] = argv[i] + 2;
+      libdirs[libdir_cnt++] = argv[i] + 2;
 
   // then we inspect all options to the target linker
   for (i = 1; i < argc; i++) {
 
+    if (ld_param_cnt >= MAX_PARAM_COUNT || link_param_cnt >= MAX_PARAM_COUNT)
+      FATAL(
+          "Too many command line parameters because of unpacking .a archives, "
+          "this would need to be done by hand ... sorry! :-(");
+
     if (strncmp(argv[i], "-flto", 5) == 0) have_lto = 1;
 
     if (!strcmp(argv[i], "-version")) {
@@ -266,23 +280,26 @@ static void edit_params(int argc, char** argv) {
       exit(0);
 
     }
-    
+
     // if a -l library is linked and no .so is found but an .a archive is there
     // then the archive will be used. So we have to emulate this and check
     // if an archive will be used and if yes we will instrument it too
     libdir_file[0] = 0;
     libdir_index = libdir_cnt;
-    if (strncmp(argv[i], "-l", 2) == 0 && libdir_cnt > 0 && strncmp(argv[i], "-lgcc", 5) != 0) {
-    
+    if (strncmp(argv[i], "-l", 2) == 0 && libdir_cnt > 0 &&
+        strncmp(argv[i], "-lgcc", 5) != 0) {
+
       u8 found = 0;
-    
+
       for (uint32_t j = 0; j < libdir_cnt && !found; j++) {
 
-        snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j], argv[i] + 2, ".so");
-        if (access(libdir_file, R_OK) != 0) { // no .so found?
+        snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j],
+                 argv[i] + 2, ".so");
+        if (access(libdir_file, R_OK) != 0) {  // no .so found?
 
-          snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j], argv[i] + 2, ".a");
-          if (access(libdir_file, R_OK) == 0) { // but .a found?
+          snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j],
+                   argv[i] + 2, ".a");
+          if (access(libdir_file, R_OK) == 0) {  // but .a found?
 
             libdir_index = j;
             found = 1;
@@ -294,16 +311,18 @@ static void edit_params(int argc, char** argv) {
 
           found = 1;
           if (debug) SAYF(cMGN "[D] " cRST "Found %s\n", libdir_file);
-        
+
         }
 
       }
-    
+
     }
 
     // is the parameter an .a AR archive? If so, unpack and check its files
-    if (libdir_index < libdir_cnt || (argv[i][0] != '-' && strlen(argv[i]) > 2 &&
-        argv[i][strlen(argv[i]) - 1] == 'a' && argv[i][strlen(argv[i]) - 2] == '.')) {
+    if (libdir_index < libdir_cnt ||
+        (argv[i][0] != '-' && strlen(argv[i]) > 2 &&
+         argv[i][strlen(argv[i]) - 1] == 'a' &&
+         argv[i][strlen(argv[i]) - 2] == '.')) {
 
       // This gets a bit odd. I encountered several .a files being linked and
       // where the same "foo.o" was in both .a archives. llvm-link does not
@@ -317,8 +336,7 @@ static void edit_params(int argc, char** argv) {
       DIR*           arx;
       struct dirent* dir_ent;
 
-      if (libdir_index < libdir_cnt)
-        file = libdir_file;
+      if (libdir_index < libdir_cnt) file = libdir_file;
 
       if (ar_dir_cnt == 0) {  // first archive, we setup up the basics
 
@@ -376,7 +394,7 @@ static void edit_params(int argc, char** argv) {
         if (dir_ent->d_name[strlen(dir_ent->d_name) - 1] == 'o' &&
             dir_ent->d_name[strlen(dir_ent->d_name) - 2] == '.') {
 
-          if (passthrough || argv[i][0] == '-' || is_llvm_file(ar_file) == 0) {
+          if (passthrough || is_llvm_file(ar_file) == 0) {
 
             if (is_duplicate(ld_params, ld_param_cnt, ar_file) == 0) {
 
@@ -428,7 +446,7 @@ static void edit_params(int argc, char** argv) {
         ld_params[ld_param_cnt++] = "-plugin-opt=O2";
       else
         ld_params[ld_param_cnt++] = argv[i];
-        
+
     } else {
 
       if (we_link == 0) {  // we have to honor order ...
@@ -618,7 +636,11 @@ int main(int argc, char** argv) {
 
   edit_params(argc, argv);  // here most of the magic happens :-)
 
-  if (debug) SAYF(cMGN "[D] " cRST "param counts: ar:%u lib:%u ld:%u link:%u opt:%u instr:%u\n", ar_dir_cnt, libdir_cnt, ld_param_cnt, link_param_cnt, opt_param_cnt, inst_param_cnt);
+  if (debug)
+    SAYF(cMGN "[D] " cRST
+              "param counts: ar:%u lib:%u ld:%u link:%u opt:%u instr:%u\n",
+         ar_dir_cnt, libdir_cnt, ld_param_cnt, link_param_cnt, opt_param_cnt,
+         inst_param_cnt);
 
   if (!just_version) {
 
@@ -650,15 +672,25 @@ int main(int argc, char** argv) {
 
       if (pid < 0) PFATAL("fork() failed");
       if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
-      if (WEXITSTATUS(status) != 0) { 
-      
-        SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD                                \
-         "\n[-] PROGRAM ABORT : " cRST);
-        SAYF(                    "llvm-link failed, if this is because of a \"linking globals\n"
-             " named '...': symbol multiply defined\" error then there is nothing we can do -\n"
-             "llvm-link is missing an important feature :-(\n\n");
+      if (WEXITSTATUS(status) != 0) {
+
+        SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD
+             "\n[-] PROGRAM ABORT : " cRST);
+        SAYF(
+            "llvm-link failed! Probable causes:\n\n"
+            " #1  If the error is \"linking globals named '...': symbol "
+            "multiply defined\"\n"
+            "     then there is nothing we can do - llvm-link is missing an "
+            "important feature\n\n"
+            " #2  If the error is \"expected top-level entity\" and then "
+            "binary output, this\n"
+            "     is because the same file is present in different .a archives "
+            "in different\n"
+            "     formats. This can be fixed by manual doing the steps afl-ld "
+            "is doing but\n"
+            "     programmatically - sorry!\n\n");
         exit(WEXITSTATUS(status));
-        
+
       }
 
       /* then we perform an optimization on the collected objects files */