A recent change to LLVM [1] by Rafael Avila de Espindola causes it to
emit references to intrinsics such as memset as "memset@PLT" rather
than simply "memset".  Per discussion on this change [2], this is
expected to be a non-change once the code is linked; the linker should
just degrade this to a normal "memset" reference when "memset" is a
locally-available symbol.  (And, in practice, that indeed appears to
be what standard Linux linkers do with it.)

However, this LLVM change causes Grub to complain about unsupported
relocation types, because it doesn't implement this ruie.

Also, this change of "memset" to "memset@PLT" causes gas (but not the
LLVM assembler) to emit an undefined _GLOBAL_OFFSET_TABLE_ reference
in the object files, which Grub will need to ignore.  As Rafael notes,
this is common situation; Linux already has similar code [3].

Rafael sent along a (very simple) Grub patch to implement this linking
rule [4, copy attached], which we've tested on several x86
architectures and confirmed appears to produce correct behavior.

However, I was talking about this with my coworker (and Grub
developer) Vladimir Serbinenko, and he's concerned that the
"memset@PLT" reference will instead require a full GOT implementation
in Grub.  I don't think that a full GOT implementation is the right
thing to do here (and it's not the intent of the LLVM change to
require such), but that's a question that needs to be resolved.

Anyway, regardless of when this (or another) patch lands, I'd like to
confirm that the Grub developers are happy with this general approach,
so that we can go ahead and accept this change into LLVM.

Thanks much!

[1] https://reviews.llvm.org/D42224

and subsequent messages


diff --git a/grub-core/efiemu/i386/loadcore32.c b/grub-core/efiemu/i386/loadcore32.c
index e746df8df..1f28995c8 100644
--- a/grub-core/efiemu/i386/loadcore32.c
+++ b/grub-core/efiemu/i386/loadcore32.c
@@ -97,6 +97,7 @@ grub_arch_efiemu_relocate_symbols32 (grub_efiemu_segment_t segs,
 		  case R_386_PC32:
+		  case R_386_PLT32:
 		    err = grub_efiemu_write_value (addr, sym.off + *addr
 						   - rel->r_offset
 						   - seg->off, sym.handle,
diff --git a/grub-core/genmoddep.awk b/grub-core/genmoddep.awk
index bd98d84cd..a8eeb3ce8 100644
--- a/grub-core/genmoddep.awk
+++ b/grub-core/genmoddep.awk
@@ -23,7 +23,7 @@ BEGIN {
   } else if ($1 == "undefined") {
     if ($3 in symtab)
       modtab[$2] = modtab[$2] " " symtab[$3];
-    else if ($3 != "__gnu_local_gp" && $3 != "_gp_disp") {
+    else if ($3 != "__gnu_local_gp" && $3 != "_gp_disp" && $3 != "_GLOBAL_OFFSET_TABLE_") {
       printf "%s in %s is not defined\n", $3, $2 >"/dev/stderr";
diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c
index 1346da5cc..ceb1bd1c1 100644
--- a/grub-core/kern/i386/dl.c
+++ b/grub-core/kern/i386/dl.c
@@ -68,6 +68,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
 	case R_386_PC32:
+	case R_386_PLT32:
 	  *addr += (sym->st_value - (grub_addr_t) addr);
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index e63f148e4..d7fb4570e 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -796,6 +796,7 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
 		case R_386_PC32:
+		case R_386_PLT32:
 		  /* This is relative.  */
 		  *target = grub_host_to_target32 (grub_target_to_host32 (*target)
 						   + addend + sym_addr
diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c
index 9179285a5..9759934d8 100644
--- a/util/grub-module-verifier.c
+++ b/util/grub-module-verifier.c
@@ -10,6 +10,7 @@ struct grub_module_verifier_arch archs[] = {
   { "i386", 4, 0, EM_386, GRUB_MODULE_VERIFY_SUPPORTS_REL, (int[]){
+      R_386_PLT32,
     } },
   { "x86_64", 8, 0, EM_X86_64, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){

Bug-grub mailing list

Reply via email to