diff --git a/arm-gen.c b/arm-gen.c
index bf3c2cf9..c11d9474 100644
--- a/arm-gen.c
+++ b/arm-gen.c
@@ -1717,8 +1717,12 @@ void gen_opi(int op)
 	uint32_t x;
 	x=stuff_const(opc|0x2000000|(c<<16),vtop->c.i);
 	if(x) {
-	  r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
-	  o(x|(r<<12));
+	  if ((x & 0xfff00000) == 0xe3500000)   // cmp rx,#c
+	    o(x);
+	  else {
+	    r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
+	    o(x|(r<<12));
+	  }
 	  goto done;
 	}
       }
@@ -1728,8 +1732,12 @@ void gen_opi(int op)
         c=intr(gv(RC_INT));
         vswap();
       }
-      r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
-      o(opc|(c<<16)|(r<<12)|fr);
+      if ((opc & 0xfff00000) == 0xe1500000) // cmp rx,ry
+	o(opc|(c<<16)|fr);
+      else {
+        r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
+        o(opc|(c<<16)|(r<<12)|fr);
+      }
 done:
       vtop--;
       if (op >= TOK_ULT && op <= TOK_GT)
diff --git a/arm-link.c b/arm-link.c
index 8e19a904..420639a0 100644
--- a/arm-link.c
+++ b/arm-link.c
@@ -12,8 +12,8 @@
 
 #define R_NUM       R_ARM_NUM
 
-#define ELF_START_ADDR 0x00008000
-#define ELF_PAGE_SIZE  0x1000
+#define ELF_START_ADDR 0x00010000
+#define ELF_PAGE_SIZE  0x10000
 
 #define PCRELATIVE_DLLPLT 1
 #define RELOCATE_DLLPLT 1
@@ -133,7 +133,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
         write32le(p,   0x4778); /* bx pc */
         write32le(p+2, 0x46c0); /* nop   */
     }
-    p = section_ptr_add(plt, 12);
+    p = section_ptr_add(plt, 16);
     /* save GOT offset for relocate_plt */
     write32le(p + 4, got_offset);
     return plt_offset;
@@ -159,10 +159,11 @@ ST_FUNC void relocate_plt(TCCState *s1)
 	    unsigned off = x  + read32le(p + 4) + (s1->plt->data - p) + 4;
             if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */
                 p += 4;
-            write32le(p, 0xe28fc600 | ((off >> 20) & 0xff));     // add ip, pc, #0xNN00000
-            write32le(p + 4, 0xe28cca00 | ((off >> 12) & 0xff)); // add ip, ip, #0xNN000
-            write32le(p + 8, 0xe5bcf000 | (off & 0xfff));	 // ldr pc, [ip, #0xNNN]!
-            p += 12;
+            write32le(p, 0xe28fc200 | ((off >> 28) & 0xf));      // add ip, pc, #0xN0000000
+            write32le(p + 4, 0xe28cc600 | ((off >> 20) & 0xff)); // add ip, pc, #0xNN00000
+            write32le(p + 8, 0xe28cca00 | ((off >> 12) & 0xff)); // add ip, ip, #0xNN000
+            write32le(p + 12, 0xe5bcf000 | (off & 0xfff));	 // ldr pc, [ip, #0xNNN]!
+            p += 16;
         }
     }
 
@@ -378,6 +379,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
                     tcc_error("can't relocate value at %x,%d",addr, type);
                 (*(int *)ptr) |= x & 0x7fffffff;
             }
+            return;
         case R_ARM_ABS32:
         case R_ARM_TARGET1:
             if (s1->output_type == TCC_OUTPUT_DLL) {
diff --git a/tcc.h b/tcc.h
index 319845a1..afe696b7 100644
--- a/tcc.h
+++ b/tcc.h
@@ -94,6 +94,14 @@ extern long double strtold (const char *__nptr, char **__endptr);
 # undef CONFIG_TCC_STATIC
 #endif
 
+#ifndef PAGESIZE
+# ifdef _SC_PAGESIZE
+#   define PAGESIZE sysconf(_SC_PAGESIZE)
+# else
+#   define PAGESIZE 4096
+# endif
+#endif
+
 #ifndef O_BINARY
 # define O_BINARY 0
 #endif
diff --git a/tccelf.c b/tccelf.c
index 2119d9b6..0371ae59 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -47,10 +47,6 @@ struct sym_version {
 /* section is dynsymtab_section */
 #define SHF_DYNSYM 0x40000000
 
-#ifndef PAGESIZE
-# define PAGESIZE 4096
-#endif
-
 /* ------------------------------------------------------------------------- */
 
 ST_FUNC void tccelf_new(TCCState *s)
@@ -1036,6 +1032,7 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr)
         case R_X86_64_64:
 #elif defined(TCC_TARGET_ARM)
         case R_ARM_ABS32:
+        case R_ARM_TARGET1:
 #elif defined(TCC_TARGET_ARM64)
         case R_AARCH64_ABS32:
         case R_AARCH64_ABS64:
@@ -1452,6 +1449,9 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
                 tcc_add_dll(s1, TCC_LIBGCC, 0);
         }
 #endif
+#if TCC_TARGET_ARM && TARGETOS_FreeBSD
+        tcc_add_library_err(s1, "gcc_s"); // unwind code
+#endif
 #ifdef CONFIG_TCC_BCHECK
         if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
             tcc_add_library_err(s1, "pthread");
diff --git a/tccrun.c b/tccrun.c
index d59df8fa..318dd384 100644
--- a/tccrun.c
+++ b/tccrun.c
@@ -63,10 +63,6 @@ static void *win64_add_function_table(TCCState *s1);
 static void win64_del_function_table(void *);
 #endif
 
-#ifndef PAGESIZE
-# define PAGESIZE 4096
-#endif
-
 /* ------------------------------------------------------------- */
 /* Do all relocations (needed before using tcc_get_symbol())
    Returns -1 on error. */
@@ -333,7 +329,10 @@ static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length)
     if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC))
         tcc_error("mprotect failed: did you mean to configure --with-selinux?");
 # endif
-# if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
+/* XXX: BSD sometimes dump core with bad system call */
+# if (defined(TCC_TARGET_ARM) && \
+      !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)) || \
+     defined(TCC_TARGET_ARM64)
     __clear_cache(ptr, (char *)ptr + length);
 # endif
 #endif
@@ -667,6 +666,9 @@ static void rt_getcontext(ucontext_t *uc, rt_context *rc)
 #elif defined(__arm__) && defined(__OpenBSD__)
     rc->ip = uc->sc_pc;
     rc->fp = uc->sc_fpreg[29];
+#elif defined(__arm__) && defined(__FreeBSD__)
+    rc->ip = uc->uc_mcontext.__gregs[_REG_PC];
+    rc->fp = uc->uc_mcontext.__gregs[_REG_FP];
 #elif defined(__arm__)
     rc->ip = uc->uc_mcontext.arm_pc;
     rc->fp = uc->uc_mcontext.arm_fp;
@@ -830,8 +832,9 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
 #elif defined(__arm__)
 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
 {
-    /* XXX: only supports linux */
-#if !defined(__linux__)
+    /* XXX: only supports linux/bsd */
+#if !defined(__linux__) && \
+    !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
     return -1;
 #else
     if (level == 0) {
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 04c1e594..de2546f9 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -21,7 +21,9 @@
 typedef __SIZE_TYPE__ uintptr_t;
 #endif
 
-#if defined(_WIN32)
+#if defined(_WIN32) || \
+    (defined(__arm__) && \
+     (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)))
 #define LONG_LONG_FORMAT "%lld"
 #define ULONG_LONG_FORMAT "%llu"
 #else