Skip to contentSkip to conversation

x86_64: Add "-m elf_i386" when linking i386 object files.

PATCH Superseded Tri Vo 4 participants 5 messages Jan 11, 2019 – Jan 12, 2019 1 message not in the archive x86

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): CAKwvOdnr1=Q=mL-P2icMTP8do3CVH+KF8564fKmpK_OshKxKwg@mail.gmail.com

Tri Vo

author
#1 lore raw

PATCH v2 1/1 x86_64: Add "-m elf_i386" when linking i386 object files.

From: George Rimar <[email protected]>

Linux kernel uses OUTPUT_FORMAT in it's linker scripts. Most of the time -m option is passed to the linker with correct architecture, but sometimes (at least for x86_64) the -m option contradicts OUTPUT_FORMAT directive. Specifically, arch/x86/boot and arch/x86/realmode/rm modules have i386 object files, but are linked with -m elf_x86_64 linker flag when building for x86_64.

"man ld" doesn't explicitly state any tie-breakers between -m and OUTPUT_FORMAT. BFD and Gold linkers override -m value with OUTPUT_FORMAT. But LLVM lld has a different behavior. When supplied with contradicting -m and OUTPUT_FORMAT values it fails with the following error message:

ld.lld: error: arch/x86/realmode/rm/header.o is incompatible with elf_x86_64

Suggested fix: just add correct -m after incorrect one (it overrides it), so the linker invocation looks like this: ld -m elf_x86_64 -z max-page-size=0x200000 -m elf_i386 --emit-relocs -T realmode.lds header.o trampoline_64.o stack.o reboot.o -o realmode.elf

This is not a functional change for GNU ld, because (although not explicitly documented) it already overrides -m EMULATION with OUTPUT_FORMAT.

Tested by building x86_64 kernel with GNU gcc/ld toolchain and booting it in QEMU.

---
 arch/x86/boot/Makefile        | 2 +-
 arch/x86/realmode/rm/Makefile | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/boot/Makefile +1 -1
index 9b5adae9cc40..e2839b5c246c 100644
@@ -100,7 +100,7 @@ $(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE
 AFLAGS_header.o += -I$(objtree)/$(obj)
 $(obj)/header.o: $(obj)/zoffset.h
 
-LDFLAGS_setup.elf	:= -T
+LDFLAGS_setup.elf	:= -m elf_i386 -T
 $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
 	$(call if_changed,ld)
 
arch/x86/realmode/rm/Makefile +1 -1
index 4463fa72db94..96cb20de08af 100644
@@ -47,7 +47,7 @@ $(obj)/pasyms.h: $(REALMODE_OBJS) FORCE
 targets += realmode.lds
 $(obj)/realmode.lds: $(obj)/pasyms.h
 
-LDFLAGS_realmode.elf := --emit-relocs -T
+LDFLAGS_realmode.elf := -m elf_i386 --emit-relocs -T
 CPPFLAGS_realmode.lds += -P -C -I$(objtree)/$(obj)
 
 targets += realmode.elf
Signature · 1 line
2.20.1.97.g81188d93c3-goog
#2 lore raw
Quoted 27 lines · Tri Vo

From: George Rimar <[email protected]>

Linux kernel uses OUTPUT_FORMAT in it's linker scripts. Most of the time -m option is passed to the linker with correct architecture, but sometimes (at least for x86_64) the -m option contradicts OUTPUT_FORMAT directive. Specifically, arch/x86/boot and arch/x86/realmode/rm modules have i386 object files, but are linked with -m elf_x86_64 linker flag when building for x86_64.

"man ld" doesn't explicitly state any tie-breakers between -m and OUTPUT_FORMAT. BFD and Gold linkers override -m value with OUTPUT_FORMAT. But LLVM lld has a different behavior. When supplied with contradicting -m and OUTPUT_FORMAT values it fails with the following error message:

ld.lld: error: arch/x86/realmode/rm/header.o is incompatible with elf_x86_64

Suggested fix: just add correct -m after incorrect one (it overrides it), so the linker invocation looks like this: ld -m elf_x86_64 -z max-page-size=0x200000 -m elf_i386 --emit-relocs -T realmode.lds header.o trampoline_64.o stack.o reboot.o -o realmode.elf

This is not a functional change for GNU ld, because (although not explicitly documented) it already overrides -m EMULATION with OUTPUT_FORMAT.

Quoted 5 lines

Tested by building x86_64 kernel with GNU gcc/ld toolchain and booting it in QEMU.

misspelled, and you may carry forward my tested by tag from v1.

Quoted 3 lines

---

So when making a change, you can put any text below this --- delimiter. For LKML, it's common practice to put something like:
v1 -> v2: updated commit message
That helps code review so reviewers know what to expect "inter-diff" when eyeballing patch files. Internally when using gerrit, it will highlight inter-version diffs (ie. what changed between v2 and v3 of a patch), but since we do things the hard way on LKML, this can help a lot. After git format-patch ..., I usually add such a comment to the patch file in vim before sending.

Quoted 33 lines
 arch/x86/boot/Makefile        | 2 +-
 arch/x86/realmode/rm/Makefile | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/boot/Makefile +1 -1
index 9b5adae9cc40..e2839b5c246c 100644
@@ -100,7 +100,7 @@ $(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE
 AFLAGS_header.o += -I$(objtree)/$(obj)
 $(obj)/header.o: $(obj)/zoffset.h
 
-LDFLAGS_setup.elf      := -T
+LDFLAGS_setup.elf      := -m elf_i386 -T
 $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
        $(call if_changed,ld)
 
arch/x86/realmode/rm/Makefile +1 -2
index 4463fa72db94..96cb20de08af 100644
@@ -47,7 +47,7 @@ $(obj)/pasyms.h: $(REALMODE_OBJS) FORCE
 targets += realmode.lds
 $(obj)/realmode.lds: $(obj)/pasyms.h
 
-LDFLAGS_realmode.elf := --emit-relocs -T
+LDFLAGS_realmode.elf := -m elf_i386 --emit-relocs -T
 CPPFLAGS_realmode.lds += -P -C -I$(objtree)/$(obj)
 
 targets += realmode.elf
--

2.20.1.97.g81188d93c3-goog

Signature · 2 lines
Thanks,
~Nick Desaulniers
author
#3 lore raw

PATCH v3 1/1 x86_64: Add "-m elf_i386" when linking i386 object files.

From: George Rimar <[email protected]>

Linux kernel uses OUTPUT_FORMAT in it's linker scripts. Most of the time -m option is passed to the linker with correct architecture, but sometimes (at least for x86_64) the -m option contradicts OUTPUT_FORMAT directive. Specifically, arch/x86/boot and arch/x86/realmode/rm modules have i386 object files, but are linked with -m elf_x86_64 linker flag when building for x86_64.

"man ld" doesn't explicitly state any tie-breakers between -m and OUTPUT_FORMAT. BFD and Gold linkers override -m value with OUTPUT_FORMAT. But LLVM lld has a different behavior. When supplied with contradicting -m and OUTPUT_FORMAT values it fails with the following error message:

ld.lld: error: arch/x86/realmode/rm/header.o is incompatible with elf_x86_64

Suggested fix: just add correct -m after incorrect one (it overrides it), so the linker invocation looks like this: ld -m elf_x86_64 -z max-page-size=0x200000 -m elf_i386 --emit-relocs -T realmode.lds header.o trampoline_64.o stack.o reboot.o -o realmode.elf

This is not a functional change for GNU ld, because (although not explicitly documented) it already overrides -m EMULATION with OUTPUT_FORMAT.

Tested by building x86_64 kernel with GNU gcc/ld toolchain and booting it in QEMU.

---
v2: updated commit message to clarify that ld documentation is ambiguous w.r.t
-m vs OUTPUT_FORMAT behavior.
v3: fixed/added SOB and "Tested-by" fields.

 arch/x86/boot/Makefile        | 2 +-
 arch/x86/realmode/rm/Makefile | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/boot/Makefile +1 -1
index 9b5adae9cc40..e2839b5c246c 100644
@@ -100,7 +100,7 @@ $(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE
 AFLAGS_header.o += -I$(objtree)/$(obj)
 $(obj)/header.o: $(obj)/zoffset.h
 
-LDFLAGS_setup.elf	:= -T
+LDFLAGS_setup.elf	:= -m elf_i386 -T
 $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
 	$(call if_changed,ld)
 
arch/x86/realmode/rm/Makefile +1 -1
index 4463fa72db94..96cb20de08af 100644
@@ -47,7 +47,7 @@ $(obj)/pasyms.h: $(REALMODE_OBJS) FORCE
 targets += realmode.lds
 $(obj)/realmode.lds: $(obj)/pasyms.h
 
-LDFLAGS_realmode.elf := --emit-relocs -T
+LDFLAGS_realmode.elf := -m elf_i386 --emit-relocs -T
 CPPFLAGS_realmode.lds += -P -C -I$(objtree)/$(obj)
 
 targets += realmode.elf

--
2.20.1.97.g81188d93c3-goog

#4 lore raw

[tip:x86/build] x86/build: Specify elf_i386 linker emulation explicitly for i386 objects

x86/build: Specify elf_i386 linker emulation explicitly for i386 objects
Commit-ID:  927185c124d62a9a4d35878d7f6d432a166b74e3
Gitweb:     https://git.kernel.org/tip/927185c124d62a9a4d35878d7f6d432a166b74e3
Author:     George Rimar <[email protected]>
AuthorDate: Fri, 11 Jan 2019 12:10:12 -0800
Committer:  Borislav Petkov <[email protected]>
CommitDate: Sat, 12 Jan 2019 00:11:39 +0100

x86/build: Specify elf_i386 linker emulation explicitly for i386 objects

The kernel uses the OUTPUT_FORMAT linker script command in it's linker scripts. Most of the time, the -m option is passed to the linker with correct architecture, but sometimes (at least for x86_64) the -m option contradicts the OUTPUT_FORMAT directive.

Specifically, arch/x86/boot and arch/x86/realmode/rm produce i386 object files, but are linked with the -m elf_x86_64 linker flag when building for x86_64.

The GNU linker manpage doesn't explicitly state any tie-breakers between -m and OUTPUT_FORMAT. But with BFD and Gold linkers, OUTPUT_FORMAT overrides the emulation value specified with the -m option.

LLVM lld has a different behavior, however. When supplied with contradicting -m and OUTPUT_FORMAT values it fails with the following error message:

ld.lld: error: arch/x86/realmode/rm/header.o is incompatible with elf_x86_64

Therefore, just add the correct -m after the incorrect one (it overrides it), so the linker invocation looks like this:

  ld -m elf_x86_64 -z max-page-size=0x200000 -m elf_i386 --emit-relocs -T \
    realmode.lds header.o trampoline_64.o stack.o reboot.o -o realmode.elf

This is not a functional change for GNU ld, because (although not explicitly documented) OUTPUT_FORMAT overrides -m EMULATION.

Tested by building x86_64 kernel with GNU gcc/ld toolchain and booting it in QEMU.

[ bp: massage and clarify text. ]

---
 arch/x86/boot/Makefile        | 2 +-
 arch/x86/realmode/rm/Makefile | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/boot/Makefile +1 -1
index 9b5adae9cc40..e2839b5c246c 100644
@@ -100,7 +100,7 @@ $(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE
 AFLAGS_header.o += -I$(objtree)/$(obj)
 $(obj)/header.o: $(obj)/zoffset.h
 
-LDFLAGS_setup.elf	:= -T
+LDFLAGS_setup.elf	:= -m elf_i386 -T
 $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
 	$(call if_changed,ld)
 
arch/x86/realmode/rm/Makefile +1 -1
index 4463fa72db94..96cb20de08af 100644
@@ -47,7 +47,7 @@ $(obj)/pasyms.h: $(REALMODE_OBJS) FORCE
 targets += realmode.lds
 $(obj)/realmode.lds: $(obj)/pasyms.h
 
-LDFLAGS_realmode.elf := --emit-relocs -T
+LDFLAGS_realmode.elf := -m elf_i386 --emit-relocs -T
 CPPFLAGS_realmode.lds += -P -C -I$(objtree)/$(obj)
 
 targets += realmode.elf
Tested-by Tri Vo Tested-by Nick Desaulniers on v3 1/1
#5 lore raw
In reply to Tri Vo

Best regards,
George | Developer | Access Softek, Inc

________________________________________
От: Tri Vo <[email protected]>
Отправлено: 11 января 2019 г. 23:10
Кому: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Копия: George Rimar; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Tri Vo Тема: [PATCH v3] x86_64: Add "-m elf_i386" when linking i386 object files.

CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe. If you suspect potential phishing or spam email, report it to [email protected]

From: George Rimar <[email protected]>

Linux kernel uses OUTPUT_FORMAT in it's linker scripts. Most of the time -m option is passed to the linker with correct architecture, but sometimes (at least for x86_64) the -m option contradicts OUTPUT_FORMAT directive. Specifically, arch/x86/boot and arch/x86/realmode/rm modules have i386 object files, but are linked with -m elf_x86_64 linker flag when building for x86_64.

"man ld" doesn't explicitly state any tie-breakers between -m and OUTPUT_FORMAT. BFD and Gold linkers override -m value with OUTPUT_FORMAT. But LLVM lld has a different behavior. When supplied with contradicting -m and OUTPUT_FORMAT values it fails with the following error message:

ld.lld: error: arch/x86/realmode/rm/header.o is incompatible with elf_x86_64

Suggested fix: just add correct -m after incorrect one (it overrides it), so the linker invocation looks like this: ld -m elf_x86_64 -z max-page-size=0x200000 -m elf_i386 --emit-relocs -T realmode.lds header.o trampoline_64.o stack.o reboot.o -o realmode.elf

This is not a functional change for GNU ld, because (although not explicitly documented) it already overrides -m EMULATION with OUTPUT_FORMAT.

Tested by building x86_64 kernel with GNU gcc/ld toolchain and booting it in QEMU.

---
v2: updated commit message to clarify that ld documentation is ambiguous w.r.t
-m vs OUTPUT_FORMAT behavior.
v3: fixed/added SOB and "Tested-by" fields.

 arch/x86/boot/Makefile        | 2 +-
 arch/x86/realmode/rm/Makefile | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/boot/Makefile +1 -1
index 9b5adae9cc40..e2839b5c246c 100644
@@ -100,7 +100,7 @@ $(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE
 AFLAGS_header.o += -I$(objtree)/$(obj)
 $(obj)/header.o: $(obj)/zoffset.h
 
-LDFLAGS_setup.elf      := -T
+LDFLAGS_setup.elf      := -m elf_i386 -T
 $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
        $(call if_changed,ld)
 
arch/x86/realmode/rm/Makefile +1 -1
index 4463fa72db94..96cb20de08af 100644
@@ -47,7 +47,7 @@ $(obj)/pasyms.h: $(REALMODE_OBJS) FORCE
 targets += realmode.lds
 $(obj)/realmode.lds: $(obj)/pasyms.h
 
-LDFLAGS_realmode.elf := --emit-relocs -T
+LDFLAGS_realmode.elf := -m elf_i386 --emit-relocs -T
 CPPFLAGS_realmode.lds += -P -C -I$(objtree)/$(obj)
 
 targets += realmode.elf

--
2.20.1.97.g81188d93c3-goog