diff --git a/core/java/src/net/i2p/util/NativeBigInteger.java b/core/java/src/net/i2p/util/NativeBigInteger.java
index 9757755943bfa18a8c11e35cd3340e8ccb352fb0..c16af4076a28f02bf480439205a20b595528efb1 100644
--- a/core/java/src/net/i2p/util/NativeBigInteger.java
+++ b/core/java/src/net/i2p/util/NativeBigInteger.java
@@ -15,6 +15,8 @@ import java.io.InputStream;
 import java.math.BigInteger;
 import java.net.URL;
 import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Random;
 
 import freenet.support.CPUInformation.AMDCPUInfo;
@@ -127,6 +129,7 @@ public class NativeBigInteger extends BigInteger {
     private final static String JBIGI_OPTIMIZATION_COREI      = "corei";
     private final static String JBIGI_OPTIMIZATION_GEODE      = "geode";
     private final static String JBIGI_OPTIMIZATION_NANO       = "nano";
+    private final static String JBIGI_OPTIMIZATION_PENTIUMM   = "pentiumm";
     private final static String JBIGI_OPTIMIZATION_VIAC32     = "viac32";
 
     private static final boolean _isWin = System.getProperty("os.name").startsWith("Win");
@@ -135,6 +138,19 @@ public class NativeBigInteger extends BigInteger {
     private static final boolean _isLinux = System.getProperty("os.name").toLowerCase().contains("linux");
     private static final boolean _isFreebsd = System.getProperty("os.name").toLowerCase().contains("freebsd");
 
+    /*
+     * This isn't always correct.
+     * http://stackoverflow.com/questions/807263/how-do-i-detect-which-kind-of-jre-is-installed-32bit-vs-64bit
+     * http://mark.koli.ch/2009/10/javas-osarch-system-property-is-the-bitness-of-the-jre-not-the-operating-system.html
+     * http://mark.koli.ch/2009/10/reliably-checking-os-bitness-32-or-64-bit-on-windows-with-a-tiny-c-app.html
+     * sun.arch.data.model not on all JVMs
+     * sun.arch.data.model == 64 => 64 bit processor
+     * sun.arch.data.model == 32 => A 32 bit JVM but could be either 32 or 64 bit processor or libs
+     * os.arch contains "64" could be 32 or 64 bit libs
+     */
+    private static final boolean _is64 = "64".equals(System.getProperty("sun.arch.data.model")) ||
+                                         System.getProperty("os.arch").contains("64");
+
     /* libjbigi.so vs jbigi.dll */
     private static final String _libPrefix = (_isWin || _isOS2 ? "" : "lib");
     private static final String _libSuffix = (_isWin || _isOS2 ? ".dll" : _isMac ? ".jnilib" : ".so");
@@ -153,19 +169,7 @@ public class NativeBigInteger extends BigInteger {
       * @return A string containing the CPU-type or null if CPU type is unknown
       */
     private static String resolveCPUType() {
-        /*
-         * This isn't always correct.
-         * http://stackoverflow.com/questions/807263/how-do-i-detect-which-kind-of-jre-is-installed-32bit-vs-64bit
-         * http://mark.koli.ch/2009/10/javas-osarch-system-property-is-the-bitness-of-the-jre-not-the-operating-system.html
-         * http://mark.koli.ch/2009/10/reliably-checking-os-bitness-32-or-64-bit-on-windows-with-a-tiny-c-app.html
-         * sun.arch.data.model not on all JVMs
-         * sun.arch.data.model == 64 => 64 bit processor
-         * sun.arch.data.model == 32 => A 32 bit JVM but could be either 32 or 64 bit processor or libs
-         * os.arch contains "64" could be 32 or 64 bit libs
-         */
-        boolean is64 = "64".equals(System.getProperty("sun.arch.data.model")) ||
-                       System.getProperty("os.arch").contains("64");
-        if (is64) {
+        if (_is64) {
             // Test the 64 bit libjcpuid, even though we don't use it yet
             try {
                 CPUInfo c = CPUID.getInfo();
@@ -255,6 +259,7 @@ public class NativeBigInteger extends BigInteger {
     public NativeBigInteger(String val, int radix) {
         super(val, radix);
     }
+
     /**Creates a new NativeBigInteger with the same value
     *  as the supplied BigInteger. Warning!, not very efficent
     */
@@ -390,59 +395,65 @@ public class NativeBigInteger extends BigInteger {
      * it'll try to look in the classpath for the correct library (see loadFromResource).
      * If the user specifies -Djbigi.enable=false it'll skip all of this.</p>
      *
+     * <pre>
+     * Load order (using linux naming with cpu type "xxx")
+     * Old order 0.8.6 and earlier:
+     *   - filesystem libjbigi.so
+     *   - jbigi.jar libjbigi.so
+     *   - jbigi.jar libjbigi-linux-xxx.so
+     *   - filesystem libjbigi-linux-xxx.so
+     *   - jbigi.jar libjbigi-linux-none.so
+     *   - filesystem libjbigi-linux-none.so
+     *
+     * New order as of 0.8.7:
+     *   - filesystem libjbigi.so
+     *   - jbigi.jar libjbigi-linux-xxx_64.so if it may be 64 bit
+     *   - jbigi.jar libjbigi-linux-athlon64_64.so if it may be 64 bit
+     *   - jbigi.jar libjbigi-linux-xxx.so
+     *   - jbigi.jar libjbigi-linux-athlon64.so if it may be 64 bit
+     *   - jbigi.jar libjbigi-linux-yyy.so 0 or more other alternates
+     *   - jbigi.jar libjbigi-linux-none_64.so if it may be 64 bit
+     *   - jbigi.jar libjbigi-linux-none.so
+     * </pre>
      */
     private static final void loadNative() {
         try{
-        String wantedProp = System.getProperty("jbigi.enable", "true");
-        boolean wantNative = "true".equalsIgnoreCase(wantedProp);
-        if (wantNative) {
-            boolean loaded = loadGeneric("jbigi");
-            if (loaded) {
-                _nativeOk = true;
-                info("Locally optimized native BigInteger library loaded from the library path");
-            } else {
-                loaded = loadFromResource("jbigi");
+            String wantedProp = System.getProperty("jbigi.enable", "true");
+            boolean wantNative = "true".equalsIgnoreCase(wantedProp);
+            if (wantNative) {
+                debug("trying loadGeneric");
+                boolean loaded = loadGeneric("jbigi");
                 if (loaded) {
                     _nativeOk = true;
-                    info("Locally optimized native BigInteger library loaded from resource");
+                    info("Locally optimized native BigInteger library loaded from file");
                 } else {
-                    loaded = loadFromResource(true);
-                    if (loaded) {
-                        _nativeOk = true;
-                        info("Optimized native BigInteger library '"+getResourceName(true)+"' loaded from resource");
-                    } else {
-                        loaded = loadGeneric(true);
-                        if (loaded) {
+                    List<String> toTry = getResourceList();
+                    debug("loadResource list to try is: " + toTry);
+                    for (String s : toTry) {
+                        debug("trying loadResource " + s);
+                        if (loadFromResource(s)) {
                             _nativeOk = true;
-                            info("Optimized native BigInteger library '"+getMiddleName(true)+"' loaded from somewhere in the path");
-                        } else {
-                            loaded = loadFromResource(false);
-                            if (loaded) {
-                                _nativeOk = true;
-                                info("Non-optimized native BigInteger library '"+getResourceName(false)+"' loaded from resource");
-                            } else {
-                                loaded = loadGeneric(false);
-                                if (loaded) {
-                                    _nativeOk = true;
-                                    info("Non-optimized native BigInteger library '"+getMiddleName(false)+"' loaded from somewhere in the path");
-                                } else {
-                                    _nativeOk = false;          
-                                }
-                            }       
+                            info("Native BigInteger library " + s + " loaded from resource");
+                            break;
                         }
                     }
                 }
             }
+            if (!_nativeOk) {
+                warn("Native BigInteger library jbigi not loaded - using pure Java - " +
+                     "poor performance may result - see http://www.i2p2.i2p/jbigi for help");
+            }
+        } catch(Exception e) {
+            warn("Native BigInteger library jbigi not loaded, using pure java", e);
         }
-        if (!_nativeOk) {
-            warn("Native BigInteger library jbigi not loaded - using pure Java - " +
-                 "poor performance may result - see http://www.i2p2.i2p/jbigi.html for help");
-        }
-        }catch(Exception e){
-            warn("Native BigInteger library jbigi not loaded, reason: '"+e.getMessage()+"' - using pure java");
-        }
     }
     
+    /** @since 0.8.7 */
+    private static void debug(String s) {
+        I2PAppContext.getGlobalContext().logManager().getLog(NativeBigInteger.class).debug(s);
+    }
+
+    
     private static void info(String s) {
         if(_doLog)
             System.err.println("INFO: " + s);
@@ -451,10 +462,21 @@ public class NativeBigInteger extends BigInteger {
     }
 
     private static void warn(String s) {
-        if(_doLog)
+        warn(s, null);
+    }
+
+    /** @since 0.8.7 */
+    private static void warn(String s, Throwable t) {
+        if(_doLog) {
             System.err.println("WARNING: " + s);
-        I2PAppContext.getGlobalContext().logManager().getLog(NativeBigInteger.class).warn(s);
-        _loadStatus = s;
+            if (t != null)
+                t.printStackTrace();
+        }
+        I2PAppContext.getGlobalContext().logManager().getLog(NativeBigInteger.class).warn(s, t);
+        if (t != null)
+            _loadStatus = s + ' ' + t;
+        else
+            _loadStatus = s;
     }
 
     /** 
@@ -509,8 +531,7 @@ public class NativeBigInteger extends BigInteger {
         //URL resource = NativeBigInteger.class.getClassLoader().getResource(resourceName);
         URL resource = ClassLoader.getSystemResource(resourceName);
         if (resource == null) {
-            if (_doLog)
-                System.err.println("NOTICE: Resource name [" + resourceName + "] was not found");
+            info("Resource name [" + resourceName + "] was not found");
             return false;
         }
 
@@ -531,19 +552,13 @@ public class NativeBigInteger extends BigInteger {
             fos = null;
             System.load(outFile.getAbsolutePath()); //System.load requires an absolute path to the lib
         } catch (UnsatisfiedLinkError ule) {
-            if (_doLog) {
-                System.err.println("ERROR: The resource " + resourceName 
-                                   + " was not a valid library for this platform");
-                ule.printStackTrace();
-            }
+            // don't include the exception in the message - too much
+            warn("Failed to load the resource " + resourceName + " - not a valid library for this platform");
             if (outFile != null)
                 outFile.delete();
             return false;
         } catch (IOException ioe) {
-            if (_doLog) {
-                System.err.println("ERROR: Problem writing out the temporary native library data");
-                ioe.printStackTrace();
-            }
+            warn("Problem writing out the temporary native library data", ioe);
             if (outFile != null)
                 outFile.delete();
             return false;
@@ -558,6 +573,45 @@ public class NativeBigInteger extends BigInteger {
         return true;
     }
     
+    /**
+     *  Generate a list of resources to search for, in-order.
+     *  See loadNative() comments for more info.
+     *  @return non-null
+     *  @since 0.8.7
+     */
+    private static List<String> getResourceList() {
+        List<String> rv = new ArrayList(8);
+        String primary = getMiddleName2(true);
+        if (primary != null) {
+            if (_is64) {
+                // add 64 bit variants at the front
+                if (!primary.equals(JBIGI_OPTIMIZATION_ATHLON64))
+                    rv.add(_libPrefix + getMiddleName1() + primary + "_64" + _libSuffix);
+                // athlon64_64 is always a fallback for 64 bit
+                rv.add(_libPrefix + getMiddleName1() + JBIGI_OPTIMIZATION_ATHLON64 + "_64" + _libSuffix);
+            }
+            // the preferred selection
+            rv.add(_libPrefix + getMiddleName1() + primary + _libSuffix);
+            // athlon64 is always a fallback for 64 bit
+            if (_is64 && !primary.equals(JBIGI_OPTIMIZATION_ATHLON64))
+                rv.add(_libPrefix + getMiddleName1() + JBIGI_OPTIMIZATION_ATHLON64 + _libSuffix);
+            // Add fallbacks for any 32-bit that were added 0.8.7 or later here
+            if (primary.equals(JBIGI_OPTIMIZATION_ATOM))
+                rv.add(_libPrefix + getMiddleName1() + JBIGI_OPTIMIZATION_PENTIUM3 + _libSuffix);
+
+        } else {
+            if (_is64) {
+                rv.add(_libPrefix + getMiddleName1() + JBIGI_OPTIMIZATION_ATHLON64 + "_64" + _libSuffix);
+                rv.add(_libPrefix + getMiddleName1() + JBIGI_OPTIMIZATION_ATHLON64 + _libSuffix);
+            }
+        }
+        // add libjbigi-xxx-none.so
+        if (_is64)
+            rv.add(_libPrefix + getMiddleName1() + "none_64" + _libSuffix);
+        rv.add(getResourceName(false));
+        return rv;
+    }
+
     /**
      *  @return may be null if optimized is true
      */
@@ -572,6 +626,17 @@ public class NativeBigInteger extends BigInteger {
      *  @return may be null if optimized is true; returns jbigi-xxx-none if optimize is false
      */
     private static final String getMiddleName(boolean optimized) {
+        String m2 = getMiddleName2(optimized);
+        if (m2 == null)
+            return null;
+        return getMiddleName1() + m2;
+    }
+
+    /**
+     *  @return may be null if optimized is true; returns "none" if optimize is false
+     *  @since 0.8.7
+     */
+    private static final String getMiddleName2(boolean optimized) {
         String sAppend;
         if (optimized) {
             if (sCPUType == null)
@@ -580,28 +645,35 @@ public class NativeBigInteger extends BigInteger {
             // instead of adding duplicates to jbigi.jar
             if (sCPUType.equals(JBIGI_OPTIMIZATION_K6_3) && !_isWin)
                 // k62 and k63 identical except on windows
-                sAppend = "-" + JBIGI_OPTIMIZATION_K6_2;
+                sAppend = JBIGI_OPTIMIZATION_K6_2;
             else if (sCPUType.equals(JBIGI_OPTIMIZATION_VIAC32))
                 // viac32 and pentium3 identical
-                sAppend = "-" + JBIGI_OPTIMIZATION_PENTIUM3;
+                sAppend = JBIGI_OPTIMIZATION_PENTIUM3;
             //else if (sCPUType.equals(JBIGI_OPTIMIZATION_VIAC3) && _isWin)
                 // FIXME no viac3 available for windows, what to use instead?
             else
-                sAppend = "-" + sCPUType;        
+                sAppend = sCPUType;        
         } else {
-            sAppend = "-none";
+            sAppend = "none";
         }
+        return sAppend;
+    }
 
+    /**
+     *  @return "jbigi-xxx-"
+     *  @since 0.8.7
+     */
+    private static final String getMiddleName1() {
         if(_isWin)
-             return "jbigi-windows"+sAppend; // The convention on Windows
+             return "jbigi-windows-";
         if(_isFreebsd)
-            return "jbigi-freebsd"+sAppend; // The convention on freebsd...
+            return "jbigi-freebsd-";
         if(_isMac)
-            return "jbigi-osx"+sAppend;
+            return "jbigi-osx-";
         if(_isOS2)
-            return "jbigi-os2"+sAppend;
+            return "jbigi-os2-";
         //throw new RuntimeException("Dont know jbigi library name for os type '"+System.getProperty("os.name")+"'");
         // use linux as the default, don't throw exception
-        return "jbigi-linux" + sAppend;
+        return "jbigi-linux-";
     }
 }
diff --git a/history.txt b/history.txt
index 2f6a80d0af4a86c7900a3483cf4bfa785647df99..a62c93347cd3045d338595041f6e0d164e99edea 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,15 @@
+2011-05-27 zzz
+    * Console: Fix router.updateThroughProxy being set to false after saving
+               change on /configupdate when install dir is read-only.
+               (ticket #466)
+    * JBigI:
+      - Refactor to handle 64 bit libs and a list of fallback libs
+      - Logging tweaks
+      - Only check for one file name in library path
+    * CPUID:
+      - Recognize amd64 as x86
+      - Only check for one file name in library path
+
 2011-05-25 zzz
     * CPUID: Load 64-bit libcpuid if available
     * HTTP Proxy: Address helper refactoring, address book add form
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index a6204817e3d9e640632604f1432a96320e1992ce..f2522cd4ed540000a936a603d4922f4a287ece1f 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -18,7 +18,7 @@ public class RouterVersion {
     /** deprecated */
     public final static String ID = "Monotone";
     public final static String VERSION = CoreVersion.VERSION;
-    public final static long BUILD = 8;
+    public final static long BUILD = 9;
 
     /** for example "-test" */
     public final static String EXTRA = "";