diff mbox series

[RFC] kbuild: pass objects instead of archives to linker

Message ID 20221102091308.11568-1-masahiroy@kernel.org (mailing list archive)
State New, archived
Headers show
Series [RFC] kbuild: pass objects instead of archives to linker | expand

Commit Message

Masahiro Yamada Nov. 2, 2022, 9:13 a.m. UTC
This is an experimental patch, driven by the feedback from Jiri Slaby
and Michael Matz. [1]

Michael Matz says:
 "I know of no linker (outside LTO-like modes) that processes
  archives in a different order than first-to-last-member (under
  whole-archive), but that's not guaranteed anywhere. So relying on
  member-order within archives is always brittle."

It is pretty easy to pass the list of objects instead of a thin archive
because the linker supports the '@file' syntax, where command line
arguments are read from 'file'.

Without this patch, the linker receives

  --whole-archive vmlinux.a --no-whole-archive

With this patch, the linker will receive

  @vmlinux.order

Here, vmlinux.order is a text file that lists built-in objects in the
correct link order.

I am not a toolchain expert. I just want to know if this makes any
difference from the linker perspective and from (non-upstreamed) GCC-LTO
perspective.

(I know this patch does not work for Clang LTO because I did not touch
scripts/generate_initcall_order.pl)

This patch may be unneeded because more correct patches were submitted [2]
but I am still curious about "thin archive vs direct object list".

[1]: https://lore.kernel.org/linux-kbuild/alpine.LSU.2.20.2210251210140.29399@wotan.suse.de/
[2]: https://lore.kernel.org/all/20221101161529.1634188-1-alexandr.lobakin@intel.com/

Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
---

 Makefile                                    | 21 ++++++++++-----------
 scripts/Makefile.modpost                    |  5 +++--
 scripts/Makefile.vmlinux_o                  |  6 +++---
 scripts/clang-tools/gen_compile_commands.py | 21 ++++++++++++++++++++-
 scripts/link-vmlinux.sh                     |  8 ++++----
 5 files changed, 40 insertions(+), 21 deletions(-)

Comments

Ard Biesheuvel Nov. 2, 2022, 9:21 a.m. UTC | #1
Hello Masahiro,

On Wed, 2 Nov 2022 at 10:13, Masahiro Yamada <masahiroy@kernel.org> wrote:
>
> This is an experimental patch, driven by the feedback from Jiri Slaby
> and Michael Matz. [1]
>
> Michael Matz says:
>  "I know of no linker (outside LTO-like modes) that processes
>   archives in a different order than first-to-last-member (under
>   whole-archive), but that's not guaranteed anywhere. So relying on
>   member-order within archives is always brittle."
>
> It is pretty easy to pass the list of objects instead of a thin archive
> because the linker supports the '@file' syntax, where command line
> arguments are read from 'file'.
>

Can you explain which problem is solved by doing this?

If we can only produce a working kernel if each object is linked in
the order it appears in the archive, I think we have bigger problems
that need solving regardless. And for the .head.text objects that need
to appear at the start of the binary image, I think the reported issue
with __head annotated C functions on x86 needs to be addressed by
getting rid of __head entirely (which seems to have been introduced
without proper justification)


> Without this patch, the linker receives
>
>   --whole-archive vmlinux.a --no-whole-archive
>
> With this patch, the linker will receive
>
>   @vmlinux.order
>
> Here, vmlinux.order is a text file that lists built-in objects in the
> correct link order.
>
> I am not a toolchain expert. I just want to know if this makes any
> difference from the linker perspective and from (non-upstreamed) GCC-LTO
> perspective.
>
> (I know this patch does not work for Clang LTO because I did not touch
> scripts/generate_initcall_order.pl)
>
> This patch may be unneeded because more correct patches were submitted [2]
> but I am still curious about "thin archive vs direct object list".
>
> [1]: https://lore.kernel.org/linux-kbuild/alpine.LSU.2.20.2210251210140.29399@wotan.suse.de/
> [2]: https://lore.kernel.org/all/20221101161529.1634188-1-alexandr.lobakin@intel.com/
>
> Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
> ---
>
>  Makefile                                    | 21 ++++++++++-----------
>  scripts/Makefile.modpost                    |  5 +++--
>  scripts/Makefile.vmlinux_o                  |  6 +++---
>  scripts/clang-tools/gen_compile_commands.py | 21 ++++++++++++++++++++-
>  scripts/link-vmlinux.sh                     |  8 ++++----
>  5 files changed, 40 insertions(+), 21 deletions(-)
>
> diff --git a/Makefile b/Makefile
> index e9e7eff906a5..511484a3dacb 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1213,19 +1213,18 @@ quiet_cmd_autoksyms_h = GEN     $@
>  $(autoksyms_h):
>         $(call cmd,autoksyms_h)
>
> -# '$(AR) mPi' needs 'T' to workaround the bug of llvm-ar <= 14
> -quiet_cmd_ar_vmlinux.a = AR      $@
> -      cmd_ar_vmlinux.a = \
> -       rm -f $@; \
> -       $(AR) cDPrST $@ $(KBUILD_VMLINUX_OBJS); \
> -       $(AR) mPiT $$($(AR) t $@ | sed -n 1p) $@ $$($(AR) t $@ | grep -F -f $(srctree)/scripts/head-object-list.txt)
> +quiet_cmd_vmlinux_order = GEN     $@
> +      cmd_vmlinux_order = \
> +       { $(foreach m, $(KBUILD_VMLINUX_OBJS), $(AR) t $m;) :; } > $(tmp-target) ; \
> +       grep -F -f $(srctree)/scripts/head-object-list.txt $(tmp-target) > $@; \
> +       grep -F -f $(srctree)/scripts/head-object-list.txt $(tmp-target) -v >> $@
>
> -targets += vmlinux.a
> -vmlinux.a: $(KBUILD_VMLINUX_OBJS) scripts/head-object-list.txt autoksyms_recursive FORCE
> -       $(call if_changed,ar_vmlinux.a)
> +targets += vmlinux.order
> +vmlinux.order: $(KBUILD_VMLINUX_OBJS) scripts/head-object-list.txt autoksyms_recursive FORCE
> +       $(call if_changed,vmlinux_order)
>
>  PHONY += vmlinux_o
> -vmlinux_o: vmlinux.a $(KBUILD_VMLINUX_LIBS)
> +vmlinux_o: vmlinux.order $(KBUILD_VMLINUX_LIBS)
>         $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux_o
>
>  vmlinux.o modules.builtin.modinfo modules.builtin: vmlinux_o
> @@ -2037,7 +2036,7 @@ quiet_cmd_gen_compile_commands = GEN     $@
>        cmd_gen_compile_commands = $(PYTHON3) $< -a $(AR) -o $@ $(filter-out $<, $(real-prereqs))
>
>  $(extmod_prefix)compile_commands.json: scripts/clang-tools/gen_compile_commands.py \
> -       $(if $(KBUILD_EXTMOD),, vmlinux.a $(KBUILD_VMLINUX_LIBS)) \
> +       $(if $(KBUILD_EXTMOD),, vmlinux.order $(KBUILD_VMLINUX_LIBS)) \
>         $(if $(CONFIG_MODULES), $(MODORDER)) FORCE
>         $(call if_changed,gen_compile_commands)
>
> diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
> index e41dee64d429..1d6847da39bd 100644
> --- a/scripts/Makefile.modpost
> +++ b/scripts/Makefile.modpost
> @@ -70,12 +70,13 @@ quiet_cmd_vmlinux_objs = GEN     $@
>         for f in $(real-prereqs); do    \
>                 case $${f} in           \
>                 *libgcc.a) ;;           \
> -               *) $(AR) t $${f} ;;     \
> +               *.a) $(AR) t $${f} ;;   \
> +               *) cat $${f} ;;         \
>                 esac                    \
>         done > $@
>
>  targets += .vmlinux.objs
> -.vmlinux.objs: vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
> +.vmlinux.objs: vmlinux.order $(KBUILD_VMLINUX_LIBS) FORCE
>         $(call if_changed,vmlinux_objs)
>
>  vmlinux.o-if-present := $(wildcard vmlinux.o)
> diff --git a/scripts/Makefile.vmlinux_o b/scripts/Makefile.vmlinux_o
> index 0edfdb40364b..6eb07f2bb39f 100644
> --- a/scripts/Makefile.vmlinux_o
> +++ b/scripts/Makefile.vmlinux_o
> @@ -18,7 +18,7 @@ quiet_cmd_gen_initcalls_lds = GEN     $@
>         $(PERL) $(real-prereqs) > $@
>
>  .tmp_initcalls.lds: $(srctree)/scripts/generate_initcall_order.pl \
> -               vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
> +               vmlinux.order $(KBUILD_VMLINUX_LIBS) FORCE
>         $(call if_changed,gen_initcalls_lds)
>
>  targets := .tmp_initcalls.lds
> @@ -48,7 +48,7 @@ quiet_cmd_ld_vmlinux.o = LD      $@
>        cmd_ld_vmlinux.o = \
>         $(LD) ${KBUILD_LDFLAGS} -r -o $@ \
>         $(addprefix -T , $(initcalls-lds)) \
> -       --whole-archive vmlinux.a --no-whole-archive \
> +       @vmlinux.order \
>         --start-group $(KBUILD_VMLINUX_LIBS) --end-group \
>         $(cmd_objtool)
>
> @@ -57,7 +57,7 @@ define rule_ld_vmlinux.o
>         $(call cmd,gen_objtooldep)
>  endef
>
> -vmlinux.o: $(initcalls-lds) vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
> +vmlinux.o: $(initcalls-lds) vmlinux.order $(KBUILD_VMLINUX_LIBS) FORCE
>         $(call if_changed_rule,ld_vmlinux.o)
>
>  targets += vmlinux.o
> diff --git a/scripts/clang-tools/gen_compile_commands.py b/scripts/clang-tools/gen_compile_commands.py
> index d800b2c0af97..c8ba9f084bd0 100755
> --- a/scripts/clang-tools/gen_compile_commands.py
> +++ b/scripts/clang-tools/gen_compile_commands.py
> @@ -57,7 +57,7 @@ def parse_arguments():
>      parser.add_argument('-a', '--ar', type=str, default='llvm-ar', help=ar_help)
>
>      paths_help = ('directories to search or files to parse '
> -                  '(files should be *.o, *.a, or modules.order). '
> +                  '(files should be *.o, *.a, or *.order). '
>                    'If nothing is specified, the current directory is searched')
>      parser.add_argument('paths', type=str, nargs='*', help=paths_help)
>
> @@ -124,6 +124,23 @@ def cmdfiles_for_a(archive, ar):
>          yield to_cmdfile(obj)
>
>
> +def cmdfiles_for_vmlinux_order(vmlinux_order):
> +    """Generate the iterator of .cmd files associated with the vmlinux.order.
> +
> +    Parse the given vmlinux.order, and yield every .cmd file used to build the
> +    contained modules.
> +
> +    Args:
> +        vmlinux_order: The vmlinux.order file to parse
> +
> +    Yields:
> +        The path to every .cmd file found
> +    """
> +    with open(vmlinux_order) as f:
> +        for line in f:
> +            yield to_cmdfile(line.rstrip())
> +
> +
>  def cmdfiles_for_modorder(modorder):
>      """Generate the iterator of .cmd files associated with the modules.order.
>
> @@ -203,6 +220,8 @@ def main():
>              cmdfiles = cmdfiles_in_dir(path)
>          elif path.endswith('.a'):
>              cmdfiles = cmdfiles_for_a(path, ar)
> +        elif path.endswith('vmlinux.order'):
> +            cmdfiles = cmdfiles_for_vmlinux_order(path)
>          elif path.endswith('modules.order'):
>              cmdfiles = cmdfiles_for_modorder(path)
>          else:
> diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
> index 918470d768e9..617ed443e377 100755
> --- a/scripts/link-vmlinux.sh
> +++ b/scripts/link-vmlinux.sh
> @@ -3,15 +3,15 @@
>  #
>  # link vmlinux
>  #
> -# vmlinux is linked from the objects in vmlinux.a and $(KBUILD_VMLINUX_LIBS).
> -# vmlinux.a contains objects that are linked unconditionally.
> +# vmlinux is linked from the objects in vmlinux.order and $(KBUILD_VMLINUX_LIBS).
> +# vmlinux.order is a text file that contains objects that are linked unconditionally.
>  # $(KBUILD_VMLINUX_LIBS) are archives which are linked conditionally
>  # (not within --whole-archive), and do not require symbol indexes added.
>  #
>  # vmlinux
>  #   ^
>  #   |
> -#   +--< vmlinux.a
> +#   +--< vmlinux.order
>  #   |
>  #   +--< $(KBUILD_VMLINUX_LIBS)
>  #   |    +--< lib/lib.a + more
> @@ -65,7 +65,7 @@ vmlinux_link()
>                 objs=vmlinux.o
>                 libs=
>         else
> -               objs=vmlinux.a
> +               objs=@vmlinux.order
>                 libs="${KBUILD_VMLINUX_LIBS}"
>         fi
>
> --
> 2.34.1
>
Masahiro Yamada Nov. 2, 2022, 9:44 a.m. UTC | #2
On Wed, Nov 2, 2022 at 6:21 PM Ard Biesheuvel <ardb@kernel.org> wrote:
>
> Hello Masahiro,
>
> On Wed, 2 Nov 2022 at 10:13, Masahiro Yamada <masahiroy@kernel.org> wrote:
> >
> > This is an experimental patch, driven by the feedback from Jiri Slaby
> > and Michael Matz. [1]
> >
> > Michael Matz says:
> >  "I know of no linker (outside LTO-like modes) that processes
> >   archives in a different order than first-to-last-member (under
> >   whole-archive), but that's not guaranteed anywhere. So relying on
> >   member-order within archives is always brittle."
> >
> > It is pretty easy to pass the list of objects instead of a thin archive
> > because the linker supports the '@file' syntax, where command line
> > arguments are read from 'file'.
> >
>
> Can you explain which problem is solved by doing this?


Jiri Slaby reported that the (not-upstreamed) GCC-LTO tree got broken
due to 321648455061 ("kbuild: use obj-y instead extra-y for objects
placed at the head")

https://lore.kernel.org/linux-kbuild/ea468b86-abb7-bb2b-1e0a-4c8959d23f1c@kernel.org/


I am not pretty sure because I did not check the downstream code.


If I understood his report correctly, the reason for the breakage is
because I put all objects into the thin archive, expecting
the linker would preserve the object order in the archive.

By specifying the object order directly in the command line,
GCC-LTO should get back working again.






>
> If we can only produce a working kernel if each object is linked in
> the order it appears in the archive, I think we have bigger problems
> that need solving regardless. And for the .head.text objects that need
> to appear at the start of the binary image, I think the reported issue
> with __head annotated C functions on x86 needs to be addressed by
> getting rid of __head entirely (which seems to have been introduced
> without proper justification)


I agree that it is the correct approach.


I think my patch is unneeded (hence RFC), but I just wanted to know
if linkers (gnu ld and lld) see any difference.






--
Best Regards
Masahiro Yamada
Jiri Slaby Nov. 3, 2022, 7:22 a.m. UTC | #3
On 02. 11. 22, 10:44, Masahiro Yamada wrote:
> Jiri Slaby reported that the (not-upstreamed) GCC-LTO tree got broken
> due to 321648455061 ("kbuild: use obj-y instead extra-y for objects
> placed at the head")
> 
> https://lore.kernel.org/linux-kbuild/ea468b86-abb7-bb2b-1e0a-4c8959d23f1c@kernel.org/
> 
> 
> I am not pretty sure because I did not check the downstream code.
> 
> 
> If I understood his report correctly, the reason for the breakage is
> because I put all objects into the thin archive, expecting
> the linker would preserve the object order in the archive.
> 
> By specifying the object order directly in the command line,
> GCC-LTO should get back working again.

...

> I think my patch is unneeded (hence RFC), but I just wanted to know
> if linkers (gnu ld and lld) see any difference.

Yes, including your patch (instead of vmlinux.S and /compressed/* 
changes) also fixes the issue. So the linker (gcc-ld) indeed respects 
command line, but not order of objects in .a.

thanks,
Masahiro Yamada Nov. 3, 2022, 2:47 p.m. UTC | #4
On Thu, Nov 3, 2022 at 4:22 PM Jiri Slaby <jirislaby@kernel.org> wrote:
>
> On 02. 11. 22, 10:44, Masahiro Yamada wrote:
> > Jiri Slaby reported that the (not-upstreamed) GCC-LTO tree got broken
> > due to 321648455061 ("kbuild: use obj-y instead extra-y for objects
> > placed at the head")
> >
> > https://lore.kernel.org/linux-kbuild/ea468b86-abb7-bb2b-1e0a-4c8959d23f1c@kernel.org/
> >
> >
> > I am not pretty sure because I did not check the downstream code.
> >
> >
> > If I understood his report correctly, the reason for the breakage is
> > because I put all objects into the thin archive, expecting
> > the linker would preserve the object order in the archive.
> >
> > By specifying the object order directly in the command line,
> > GCC-LTO should get back working again.
>
> ...
>
> > I think my patch is unneeded (hence RFC), but I just wanted to know
> > if linkers (gnu ld and lld) see any difference.
>
> Yes, including your patch (instead of vmlinux.S and /compressed/*
> changes) also fixes the issue. So the linker (gcc-ld) indeed respects
> command line, but not order of objects in .a.
>


Can I see your LTO implementation somewhere in public?


I know Andy Kleen's GCC-LTO, the latest version is 5.13-ish.

https://github.com/andikleen/linux-misc.git





> thanks,
> --
> js
> suse labs
>
Jiri Slaby Nov. 7, 2022, 6:12 a.m. UTC | #5
On 03. 11. 22, 15:47, Masahiro Yamada wrote:
> Can I see your LTO implementation somewhere in public?

Sure:
https://git.kernel.org/pub/scm/linux/kernel/git/jirislaby/linux.git/commit/?h=lto

FWIW, I plan to send a v1 for comments soon as I finished the patch 
order, CCs and commit logs finally.

thanks,
diff mbox series

Patch

diff --git a/Makefile b/Makefile
index e9e7eff906a5..511484a3dacb 100644
--- a/Makefile
+++ b/Makefile
@@ -1213,19 +1213,18 @@  quiet_cmd_autoksyms_h = GEN     $@
 $(autoksyms_h):
 	$(call cmd,autoksyms_h)
 
-# '$(AR) mPi' needs 'T' to workaround the bug of llvm-ar <= 14
-quiet_cmd_ar_vmlinux.a = AR      $@
-      cmd_ar_vmlinux.a = \
-	rm -f $@; \
-	$(AR) cDPrST $@ $(KBUILD_VMLINUX_OBJS); \
-	$(AR) mPiT $$($(AR) t $@ | sed -n 1p) $@ $$($(AR) t $@ | grep -F -f $(srctree)/scripts/head-object-list.txt)
+quiet_cmd_vmlinux_order = GEN     $@
+      cmd_vmlinux_order = \
+	{ $(foreach m, $(KBUILD_VMLINUX_OBJS), $(AR) t $m;) :; } > $(tmp-target) ; \
+	grep -F -f $(srctree)/scripts/head-object-list.txt $(tmp-target) > $@; \
+	grep -F -f $(srctree)/scripts/head-object-list.txt $(tmp-target) -v >> $@
 
-targets += vmlinux.a
-vmlinux.a: $(KBUILD_VMLINUX_OBJS) scripts/head-object-list.txt autoksyms_recursive FORCE
-	$(call if_changed,ar_vmlinux.a)
+targets += vmlinux.order
+vmlinux.order: $(KBUILD_VMLINUX_OBJS) scripts/head-object-list.txt autoksyms_recursive FORCE
+	$(call if_changed,vmlinux_order)
 
 PHONY += vmlinux_o
-vmlinux_o: vmlinux.a $(KBUILD_VMLINUX_LIBS)
+vmlinux_o: vmlinux.order $(KBUILD_VMLINUX_LIBS)
 	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux_o
 
 vmlinux.o modules.builtin.modinfo modules.builtin: vmlinux_o
@@ -2037,7 +2036,7 @@  quiet_cmd_gen_compile_commands = GEN     $@
       cmd_gen_compile_commands = $(PYTHON3) $< -a $(AR) -o $@ $(filter-out $<, $(real-prereqs))
 
 $(extmod_prefix)compile_commands.json: scripts/clang-tools/gen_compile_commands.py \
-	$(if $(KBUILD_EXTMOD),, vmlinux.a $(KBUILD_VMLINUX_LIBS)) \
+	$(if $(KBUILD_EXTMOD),, vmlinux.order $(KBUILD_VMLINUX_LIBS)) \
 	$(if $(CONFIG_MODULES), $(MODORDER)) FORCE
 	$(call if_changed,gen_compile_commands)
 
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index e41dee64d429..1d6847da39bd 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -70,12 +70,13 @@  quiet_cmd_vmlinux_objs = GEN     $@
 	for f in $(real-prereqs); do	\
 		case $${f} in		\
 		*libgcc.a) ;;		\
-		*) $(AR) t $${f} ;;	\
+		*.a) $(AR) t $${f} ;;	\
+		*) cat $${f} ;;		\
 		esac			\
 	done > $@
 
 targets += .vmlinux.objs
-.vmlinux.objs: vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
+.vmlinux.objs: vmlinux.order $(KBUILD_VMLINUX_LIBS) FORCE
 	$(call if_changed,vmlinux_objs)
 
 vmlinux.o-if-present := $(wildcard vmlinux.o)
diff --git a/scripts/Makefile.vmlinux_o b/scripts/Makefile.vmlinux_o
index 0edfdb40364b..6eb07f2bb39f 100644
--- a/scripts/Makefile.vmlinux_o
+++ b/scripts/Makefile.vmlinux_o
@@ -18,7 +18,7 @@  quiet_cmd_gen_initcalls_lds = GEN     $@
 	$(PERL) $(real-prereqs) > $@
 
 .tmp_initcalls.lds: $(srctree)/scripts/generate_initcall_order.pl \
-		vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
+		vmlinux.order $(KBUILD_VMLINUX_LIBS) FORCE
 	$(call if_changed,gen_initcalls_lds)
 
 targets := .tmp_initcalls.lds
@@ -48,7 +48,7 @@  quiet_cmd_ld_vmlinux.o = LD      $@
       cmd_ld_vmlinux.o = \
 	$(LD) ${KBUILD_LDFLAGS} -r -o $@ \
 	$(addprefix -T , $(initcalls-lds)) \
-	--whole-archive vmlinux.a --no-whole-archive \
+	@vmlinux.order \
 	--start-group $(KBUILD_VMLINUX_LIBS) --end-group \
 	$(cmd_objtool)
 
@@ -57,7 +57,7 @@  define rule_ld_vmlinux.o
 	$(call cmd,gen_objtooldep)
 endef
 
-vmlinux.o: $(initcalls-lds) vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
+vmlinux.o: $(initcalls-lds) vmlinux.order $(KBUILD_VMLINUX_LIBS) FORCE
 	$(call if_changed_rule,ld_vmlinux.o)
 
 targets += vmlinux.o
diff --git a/scripts/clang-tools/gen_compile_commands.py b/scripts/clang-tools/gen_compile_commands.py
index d800b2c0af97..c8ba9f084bd0 100755
--- a/scripts/clang-tools/gen_compile_commands.py
+++ b/scripts/clang-tools/gen_compile_commands.py
@@ -57,7 +57,7 @@  def parse_arguments():
     parser.add_argument('-a', '--ar', type=str, default='llvm-ar', help=ar_help)
 
     paths_help = ('directories to search or files to parse '
-                  '(files should be *.o, *.a, or modules.order). '
+                  '(files should be *.o, *.a, or *.order). '
                   'If nothing is specified, the current directory is searched')
     parser.add_argument('paths', type=str, nargs='*', help=paths_help)
 
@@ -124,6 +124,23 @@  def cmdfiles_for_a(archive, ar):
         yield to_cmdfile(obj)
 
 
+def cmdfiles_for_vmlinux_order(vmlinux_order):
+    """Generate the iterator of .cmd files associated with the vmlinux.order.
+
+    Parse the given vmlinux.order, and yield every .cmd file used to build the
+    contained modules.
+
+    Args:
+        vmlinux_order: The vmlinux.order file to parse
+
+    Yields:
+        The path to every .cmd file found
+    """
+    with open(vmlinux_order) as f:
+        for line in f:
+            yield to_cmdfile(line.rstrip())
+
+
 def cmdfiles_for_modorder(modorder):
     """Generate the iterator of .cmd files associated with the modules.order.
 
@@ -203,6 +220,8 @@  def main():
             cmdfiles = cmdfiles_in_dir(path)
         elif path.endswith('.a'):
             cmdfiles = cmdfiles_for_a(path, ar)
+        elif path.endswith('vmlinux.order'):
+            cmdfiles = cmdfiles_for_vmlinux_order(path)
         elif path.endswith('modules.order'):
             cmdfiles = cmdfiles_for_modorder(path)
         else:
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 918470d768e9..617ed443e377 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -3,15 +3,15 @@ 
 #
 # link vmlinux
 #
-# vmlinux is linked from the objects in vmlinux.a and $(KBUILD_VMLINUX_LIBS).
-# vmlinux.a contains objects that are linked unconditionally.
+# vmlinux is linked from the objects in vmlinux.order and $(KBUILD_VMLINUX_LIBS).
+# vmlinux.order is a text file that contains objects that are linked unconditionally.
 # $(KBUILD_VMLINUX_LIBS) are archives which are linked conditionally
 # (not within --whole-archive), and do not require symbol indexes added.
 #
 # vmlinux
 #   ^
 #   |
-#   +--< vmlinux.a
+#   +--< vmlinux.order
 #   |
 #   +--< $(KBUILD_VMLINUX_LIBS)
 #   |    +--< lib/lib.a + more
@@ -65,7 +65,7 @@  vmlinux_link()
 		objs=vmlinux.o
 		libs=
 	else
-		objs=vmlinux.a
+		objs=@vmlinux.order
 		libs="${KBUILD_VMLINUX_LIBS}"
 	fi