about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2020-03-08 18:20:28 +0100
committervan Hauser <vh@thc.org>2020-03-08 18:20:28 +0100
commit8ff0161d587d70342948b02dd0c219fcba2c769c (patch)
tree3b6f2b7a4c322db603a7f7cc6adea35ed3a1f036
parent9f7bcca91e5362f98890db9cc896b863ebf378cd (diff)
downloadafl++-8ff0161d587d70342948b02dd0c219fcba2c769c.tar.gz
"fixed" symbol multiply defined problems with LTO
-rw-r--r--llvm_mode/README.lto.md36
-rw-r--r--llvm_mode/afl-ld.c18
2 files changed, 51 insertions, 3 deletions
diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md
index b7392adb..2fe29069 100644
--- a/llvm_mode/README.lto.md
+++ b/llvm_mode/README.lto.md
@@ -91,6 +91,15 @@ AR=llvm-ar RANLIB=llvm-ranlib CC=afl-clang-lto CXX=afl-clang-lto++ ./configure -
 ```
 and on some target you have to to AR=/RANLIB= even for make as the configure script does not save it ...
 
+### "linking globals named '...': symbol multiply defined" error
+
+The target program is using multiple global variables or functions with the
+same name. This is a common error when compiling a project with LTO, and
+the fix is `-Wl,--allow-multiple-definition` - however llvm-link which we
+need to link all llvm IR LTO files does not support this - yet (hopefully).
+Hence if you see this error either you have to remove the duplicate global
+variable (think `#ifdef` ...) or you are out of luck. :-(
+
 ### clang is hardcoded to /bin/ld
 
 Some clang packages have 'ld' hardcoded to /bin/ld. This is an issue as this
@@ -148,3 +157,30 @@ Known issues:
 * unrar-nonfree-5.6.6
 * exiv 0.27
 * jpeg-6b
+
+## History
+
+This was originally envisioned by hexcoder- in Summer 2019, however we saw no
+way to create a pass that is run at link time - although there is a option
+for this in the PassManager: EP_FullLinkTimeOptimizationLast
+("Fun" info - nobody knows what this is doing. And the developer who
+implemented this didn't respond to emails.)
+
+In December came then the idea to implement this as a pass that is run via
+the llvm "opt" program, which is performed via an own linker that afterwards
+calls the real linker.
+This was first implemented in January and work ... kinda.
+The LTO time instrumentation worked, however the "how" the basic blocks were
+instrumented was a problem, as reducing duplicates turned out to be very,
+very difficult with a program that has so many paths and therefore so many
+dependencies. At lot of stratgies were implemented - and failed.
+And then sat solvers were tried, but with over 10.000 variables that turned
+out to be a dead-end too.
+The final idea to solve this came from domenukk who proposed to insert a block
+into an edge and then just use incremental counters ... and this worked!
+After some trials and errors to implement this vanhauser-thc found out that
+there is actually an llvm function for this: SplitEdge() :-)
+Still more problems came up though as this only works without bugs from
+llvm 9 onwards, and with high optimization the link optimization ruins
+the instrumented control flow graph.
+As long as there are no larger changes in llvm this all should work well now ...
diff --git a/llvm_mode/afl-ld.c b/llvm_mode/afl-ld.c
index 65a75879..cdecaa9c 100644
--- a/llvm_mode/afl-ld.c
+++ b/llvm_mode/afl-ld.c
@@ -215,9 +215,12 @@ static void edit_params(int argc, char** argv) {
   link_params[link_param_cnt++] = linked_file;
 
   opt_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "opt");
-  if (getenv("AFL_DONT_OPTIMIZE") == NULL)
+  if (getenv("AFL_DONT_OPTIMIZE") == NULL) {
+
     opt_params[opt_param_cnt++] = "-O3";
-  else
+    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
@@ -599,7 +602,16 @@ 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) exit(WEXITSTATUS(status));
+      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");
+        exit(WEXITSTATUS(status));
+        
+      }
 
       /* then we perform an optimization on the collected objects files */
       if (!be_quiet)