This is an archive of the discontinued LLVM Phabricator instance.

[ELF] - Allow emulation to be different from input objects target.
AbandonedPublic

Authored by grimar on Jan 19 2017, 4:54 AM.

Details

Summary

I found that when tried to link "arch/x86/realmode/rm" component of linux kernel,
LLD reports:

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

All objects are i386, but invocation contains -m elf_x86_64 and we report a error.
That does not seem to be correct. Both gold and bfd allow to link that. Specification says:

-m emulation
              Emulate  the  emulation  linker.   You can list the
              available emulations with the --verbose or  -V  op-
              tions.   This  option overrides the compiled-in de-
              fault, which is the system for which you configured
              ld.

Patch makes target to be created basing on machine type inferred from
first object. If that is not possible then emulation option is used.

This is PR31678

Diff Detail

Event Timeline

grimar created this revision.Jan 19 2017, 4:54 AM
grimar updated this revision to Diff 84958.Jan 19 2017, 5:01 AM
  • Removed dead code.
ruiu edited edge metadata.Jan 19 2017, 11:27 AM

If I understand correctly, you are trying to do this thing in this patch: set alternative values to page size, max page size and image base if -m is specified. Is this correct?

If so, I think this patch does that in a convoluted way.

In D28898#650644, @ruiu wrote:

If I understand correctly, you are trying to do this thing in this patch: set alternative values to page size, max page size and image base if -m is specified. Is this correct?

Main aim of that patch was to allow combination of -m elf_x86_64 and i386 objects.
Previously LLD took machine type and other data from -m and ignored inferring from objects and reported a error finally.
Patch changes logic to check objects first. And only after that check -m if not inferred data.

Setting alternative values is secondary thing here. Though it is looks consistent with what bfd do
(https://llvm.org/bugs/show_bug.cgi?id=31678) and documentation in general I think.

grimar updated this revision to Diff 85119.EditedJan 20 2017, 4:22 AM
  • Simplified. Changed behavior to just override the emulation with parameters taken from object.

(test/ELF/mips-n32-emul.s is removed)

grimar edited the summary of this revision. (Show Details)Jan 20 2017, 4:23 AM
grimar added a reviewer: atanasyan.
ruiu added a comment.Jan 20 2017, 8:00 AM

I don't think this patch works if all object files are in static archives.

In D28898#651577, @ruiu wrote:

I don't think this patch works if all object files are in static archives.

Original code also does not work when all files in static archives, no ? It requires -m or at least one .o file.

ruiu added a comment.Jan 20 2017, 8:21 AM
In D28898#651577, @ruiu wrote:

I don't think this patch works if all object files are in static archives.

Original code also does not work when all files in static archives, no ? It requires -m or at least one .o file.

I think you actually changed the behavior. Now it needs at least one .o even if -m is given.

ELF/Driver.cpp
702–703

I think you could just remove this piece of code from inferMachineTypes to do the same thing, no?

grimar updated this revision to Diff 85146.Jan 20 2017, 9:21 AM
  • Added testcase.
In D28898#651627, @ruiu wrote:
In D28898#651577, @ruiu wrote:

I don't think this patch works if all object files are in static archives.

Original code also does not work when all files in static archives, no ? It requires -m or at least one .o file.

I think you actually changed the behavior. Now it needs at least one .o even if -m is given.

No, it does not need. I added a testcase for demonstration.

ELF/Driver.cpp
702–703

Since current logic is "assign parameters from -m and right after that override them with values from objects", I think it is better to localize this logic in a single place.

Its even may be worth some refactoring. I believe it is possible to get rid of that overriding. What we could to is check that -m is one of supported early. Then logic could be in different, correct order: first try to set machine type from files and then, if not successed - set it from -m. I had to use overriding only because we still want (I think) to check -m values even if it is ignored.

ruiu added a comment.Jan 21 2017, 3:54 PM

Are you sure that this is the right thing to do? It seems alarming -- it doesn't feel right to me to handle the -m option like that. It doesn't make sense, and I cannot justify why it should be like that. Can you give me an explanation why this is correct?

ruiu added a comment.Jan 21 2017, 3:57 PM

I found that arch/x86/realmode/rm/realmode.lds.S has an OUTPUT_FORMAT directive, which is ignored by LLD at the moment. Isn't this the cause of the problem?

In D28898#652502, @ruiu wrote:

I found that arch/x86/realmode/rm/realmode.lds.S has an OUTPUT_FORMAT directive, which is ignored by LLD at the moment. Isn't this the cause of the problem?

I think it is not. GNU linkers are very inconsistent. Ignoring OUTPUT_FORMAT seems to be OK.
See my experiments results:

Lets say we have next 4 scripts and trying to link i386 objects with -m elf_x86_64 (just like PR31678):
1) First that has OUTPUT_FORMAT and OUTPUT_ARCH

OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
SECTIONS { ... }

Linker: result
BFD: YES
GOLD: YES, output is i386 in both cases.

2) Second has only OUTPUT_FORMAT:

OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
SECTIONS { ... }

BFD: YES and output is x86_64. That looks wierd result for i386 objects inputs, right ?
And if I add --emit-relocs, I see that it emits tons of NONE relocations instead of i386 ones:

Relocation section '.rel.text' at offset 0x2061b8 contains 131 entries:
  Offset          Info           Type           Sym. Value    Sym. Name
000000000000  000000000000 R_X86_64_NONE    
000000000000  000000000000 R_X86_64_NONE    
000000000000  000000000000 R_X86_64_NONE

So it looks output is some kind of 'forced'.

GOLD: YES and output is i386.

3) Third has only OUTPUT_ARCH:

OUTPUT_ARCH(i386)
SECTIONS { ... }

BFD: NO
ld.bfd: i386 architecture of input file `home/umb/linux_kernel/linux/linux/arch/x86/realmode/rm/header.o' is incompatible with i386:x86-64 output

GOLD: YES and output is i386.

4) Fourth has nothing:

SECTIONS { ... }

BFD: NO

ld.bfd: i386 architecture of input file `home/umb/linux_kernel/linux/linux/arch/x86/realmode/rm/header.o' is incompatible with i386:x86-64 output

GOLD: YES, output is i386

So looks gold takes output format from inputs and ignores OUTPUT_FORMAT/OUTPUT_ARCH, just like we do.
Taking machine format from inputs and overriding -m seems very simple logic that is easy to understand and solves initial problem,
it is consistent with gold.
In my opinion gold behavior is much simpler than what bfd tries to do and we can try to stick to it.

grimar updated this revision to Diff 85563.Jan 24 2017, 4:33 AM
  • Updated in according to discussion.
grimar added inline comments.Jan 24 2017, 4:53 AM
ELF/Driver.cpp
722

This should be "all our inputs are binaries, "
At this point all bitcode files are already handled in loop above:

for (InputFile *F : Files) {

I'll update this comment for next diff/commit.

ruiu added a comment.Jan 24 2017, 11:55 AM

What this does is probably okay, but this patch seems to be juggling data around unnecessarily. You probably want to restart from scratch to get cleaner code.

tpimh added a subscriber: tpimh.Jan 31 2017, 7:42 AM
ruiu added a comment.Jan 31 2017, 12:27 PM

I wouldn't submit this. Even two GNU linkers behave differently, and the new behavior this patch implements has odd semantics which is unable to describe other than "because the gold linker does that." And the original code that we are trying to handle seems to be just a typo. All in all, the best thing we should do now seems to fix the Linux kernel. If this issue resurfaces, we'll consider this patch again.

grimar abandoned this revision.Feb 16 2017, 7:13 AM

Bug was posted for linux kernel instead: https://bugzilla.kernel.org/show_bug.cgi?id=194091

test/ELF/incompatible.s