[aot] move method_addresses to data.rel.so section to avoid text relocations (mono...
authorBernhard Urban <lewurm@gmail.com>
Tue, 10 Sep 2019 08:16:07 +0000 (10:16 +0200)
committermonojenkins <jo.shields+jenkins@xamarin.com>
Tue, 10 Sep 2019 08:16:07 +0000 (04:16 -0400)
[aot] move method_addresses to data.rel.so section to avoid text relocations

Another revert of a revert! ðŸŽ‰

After some discussions with @grendello and @radekdoulik, we came up with this solution. It's a better attempt to fix https://github.com/mono/mono/issues/16369 as it (1) works within the restrictions of Android 10 and (2) still works for armv7 AOT.

`.text` relocations aren't allowed in Android 10 (and this change shouldn't hurt on Linux).

AOT compilation:
```console
$ MONO_PATH=/Users/lewurm/Downloads/xamarin.android-oss-v10.0.99.136_Darwin-x86_64_pr_766265b9-Debug/bin/Debug/lib/xamarin.android/xbuild-frameworks/MonoAndroid/v1.0/ \
MONO_ENV_OPTIONS="" \
./sdks/out/android-cross-arm-release/bin/armv7-linux-android-mono-sgen \
--aot=keep-temps,outfile=here.dll.so,asmwriter,mtriple=armv7-linux-gnueabi,tool-prefix=/Users/lewurm/android-toolchain/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-,ld-flags= \
~/Downloads/xamarin.android-oss-v10.0.99.136_Darwin-x86_64_pr_766265b9-Debug/bin/Debug/lib/xamarin.android/xbuild-frameworks/MonoAndroid/v10.0/Mono.Android.dll

Mono Ahead of Time compiler - compiling assembly /Users/lewurm/Downloads/xamarin.android-oss-v10.0.99.136_Darwin-x86_64_pr_766265b9-Debug/bin/Debug/lib/xamarin.android/xbuild-frameworks/MonoAndroid/v10.0/Mono.Android.dll
AOTID 7DDD05DA-37E0-813A-8C27-3E1634391BB3
Compiled: 144382/144382
Executing the native assembler: "/Users/lewurm/android-toolchain/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-as"   -mfpu=vfp3 -o /var/folders/p3/5279mmgn1p575bz28j0ngfqw0000gn/T/mono_aot_550yHJ.o /var/folders/p3/5279mmgn1p575bz28j0ngfqw0000gn/T/mono_aot_550yHJ
Executing the native linker: "/Users/lewurm/android-toolchain/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld"  -shared -o here.dll.so.tmp  /var/folders/p3/5279mmgn1p575bz28j0ngfqw0000gn/T/mono_aot_550yHJ.o
Stripping the binary: "/Users/lewurm/android-toolchain/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-strip" --strip-symbol=\$a --strip-symbol=\$d here.dll.so.tmp
Retained input file.
JIT time: 15031 ms, Generation time: 7374 ms, Assembly+Link time: 75130 ms.
```

Before:
```console
$ grep -C 6 'method_addresses:' /var/folders/p3/5279mmgn1p575bz28j0ngfqw0000gn/T/mono_aot_550yHJ
        .align 3
jit_code_end:

        .byte 0,0,0,0
.text 1
        .align 3
method_addresses:
        .local method_addresses
        .type method_addresses,#function
ldr pc,=.Lm_0
.ltorg
ldr pc,=.Lm_1
.ltorg
$ arm-linux-androideabi-readelf -a here.dll.so | grep -i textrel
 0x00000016 (TEXTREL)                    0x0
 0x0000001e (FLAGS)                      TEXTREL
```

After switching to `.data.rel.so`:
```console
$ grep -C 6 'method_addresses:' /var/folders/p3/5279mmgn1p575bz28j0ngfqw0000gn/T/mono_aot_1YhAgn  # assembly file produced by AOT compiler
jit_code_end:

        .byte 0,0,0,0
.section ".data.rel.ro"
.subsection 0
        .align 3
method_addresses:
        .local method_addresses
        .type method_addresses,#object
ldr pc,=.Lm_0
.ltorg
ldr pc,=.Lm_1
.ltorg
$ arm-linux-androideabi-readelf -a here.dll.so | grep -i textrel
$ echo $?
1
```

Commit migrated from https://github.com/mono/mono/commit/e40e24b4cdc902c82cfe0a140cdb284611104242

src/mono/mono/mini/aot-compiler.c
src/mono/mono/mini/aot-runtime.c

index cc10599..0909752 100644 (file)
@@ -106,6 +106,12 @@ get_method_nofail (MonoClass *klass, const char *method_name, int param_count, i
 #define EMIT_WIN32_UNWIND_INFO
 #endif
 
+#if defined(TARGET_ANDROID) || defined(__linux__)
+#define RODATA_REL_SECT ".data.rel.ro"
+#else
+#define RODATA_REL_SECT ".text"
+#endif
+
 #if defined(__linux__)
 #define RODATA_SECT ".rodata"
 #elif defined(TARGET_MACH)
@@ -1595,6 +1601,21 @@ arch_emit_direct_call (MonoAotCompile *acfg, const char *target, gboolean extern
        g_assert_not_reached ();
 #endif
 }
+
+static void
+arch_emit_label_address (MonoAotCompile *acfg, const char *target, gboolean external_call, gboolean thumb, MonoJumpInfo *ji, int *call_size)
+{
+#if defined(TARGET_ARM) && defined(TARGET_ANDROID)
+       /* binutils ld does not support branch islands on arm32 */
+       if (!thumb) {
+               emit_unset_mode (acfg);
+               fprintf (acfg->fp, "ldr pc,=%s\n", target);
+               fprintf (acfg->fp, ".ltorg\n");
+               *call_size = 8;
+       } else
+#endif
+       arch_emit_direct_call (acfg, target, external_call, thumb, ji, call_size);
+}
 #endif
 
 /*
@@ -9923,13 +9944,18 @@ emit_code (MonoAotCompile *acfg)
         * To work around linker issues, we emit a table of branches, and disassemble them at runtime.
         * This is PIE code, and the linker can update it if needed.
         */
-       
+#if defined(TARGET_ANDROID) || defined(__linux__)
+       gboolean is_func = FALSE;
+#else
+       gboolean is_func = TRUE;
+#endif
+
        sprintf (symbol, "method_addresses");
-       emit_section_change (acfg, ".text", 1);
+       emit_section_change (acfg, RODATA_REL_SECT, !!is_func);
        emit_alignment_code (acfg, 8);
-       emit_info_symbol (acfg, symbol, TRUE);
+       emit_info_symbol (acfg, symbol, is_func);
        if (acfg->aot_opts.write_symbols)
-               emit_local_symbol (acfg, symbol, "method_addresses_end", TRUE);
+               emit_local_symbol (acfg, symbol, "method_addresses_end", is_func);
        emit_unset_mode (acfg);
        if (acfg->need_no_dead_strip)
                fprintf (acfg->fp, "    .no_dead_strip %s\n", symbol);
@@ -9939,9 +9965,9 @@ emit_code (MonoAotCompile *acfg)
                int call_size;
 
                if (!ignore_cfg (acfg->cfgs [i])) {
-                       arch_emit_direct_call (acfg, acfg->cfgs [i]->asm_symbol, FALSE, acfg->thumb_mixed && acfg->cfgs [i]->compile_llvm, NULL, &call_size);
+                       arch_emit_label_address (acfg, acfg->cfgs [i]->asm_symbol, FALSE, acfg->thumb_mixed && acfg->cfgs [i]->compile_llvm, NULL, &call_size);
                } else {
-                       arch_emit_direct_call (acfg, symbol, FALSE, FALSE, NULL, &call_size);
+                       arch_emit_label_address (acfg, symbol, FALSE, FALSE, NULL, &call_size);
                }
 #endif
        }
index bcf5e58..02dd224 100644 (file)
@@ -1940,6 +1940,11 @@ get_call_table_entry (void *table, int index)
        guint32 ins;
        gint32 offset;
 
+       ins_addr = (guint32 *)table + (index * 2);
+       if ((guint32) *ins_addr == (guint32 ) 0xe51ff004) { // ldr pc, =<label>
+               return *((char **) (ins_addr + 1));
+       }
+
        ins_addr = (guint32*)table + index;
        ins = *ins_addr;
        if ((ins >> ARMCOND_SHIFT) == ARMCOND_NV) {
@@ -1947,6 +1952,8 @@ get_call_table_entry (void *table, int index)
                offset = (((int)(((ins & 0xffffff) << 1) | ((ins >> 24) & 0x1))) << 7) >> 7;
                return (char*)ins_addr + (offset * 2) + 8 + 1;
        } else {
+               g_assert ((ins >> ARMCOND_SHIFT) == ARMCOND_AL);
+               /* bl */
                offset = (((int)ins & 0xffffff) << 8) >> 8;
                return (char*)ins_addr + (offset * 4) + 8;
        }