This is an archive of the discontinued LLVM Phabricator instance.

[ELF] Set EF_ARM_EABI_VER5 for ARM
ClosedPublic

Authored by mstorsjo on Sep 12 2016, 1:55 PM.

Details

Summary

Without this flag set, an aarch64 linux kernel won't try to load the executable (even if a 32 bit arm kernel will run the binary just fine).

Diff Detail

Repository
rL LLVM

Event Timeline

mstorsjo updated this revision to Diff 71051.Sep 12 2016, 1:55 PM
mstorsjo retitled this revision from to [ELF] Set EF_ARM_EABI_VER5 for ARM.
mstorsjo updated this object.
mstorsjo added a reviewer: rui314.
mstorsjo added a subscriber: llvm-commits.
ruiu edited reviewers, added: ruiu; removed: rui314.Sep 12 2016, 1:58 PM
ruiu edited edge metadata.Sep 12 2016, 2:02 PM

I don't know if this is the right thing to do, so I'd defer this to ARM developers.

emaste added a subscriber: emaste.Sep 12 2016, 5:35 PM

Can you add a test case?

Without this flag set, an aarch64 kernel won't try to load the executable

Do you mean this is part of some ABI spec and so any aarch64 kernel should not load the executable, or that this is due to an implementation detail of (presumably) the Linux kernel?

ELF/Writer.cpp
1265–1268 ↗(On Diff #71051)

All else being equal I'd keep these in alphabetical order.

Can you add a test case?

Ok, I'll have a look at it

Without this flag set, an aarch64 kernel won't try to load the executable

Do you mean this is part of some ABI spec and so any aarch64 kernel should not load the executable, or that this is due to an implementation detail of (presumably) the Linux kernel?

I think it's just an implementation detail. Since GNU ld has been setting it since forever (I assume), I guess the aarch64 kernel just hasn't bothered to add support for "legacy" binaries, only the ones commonly available.

Without this flag set, an aarch64 kernel won't try to load the executable

Do you mean this is part of some ABI spec and so any aarch64 kernel should not load the executable, or that this is due to an implementation detail of (presumably) the Linux kernel?

I think it's just an implementation detail. Since GNU ld has been setting it since forever (I assume), I guess the aarch64 kernel just hasn't bothered to add support for "legacy" binaries, only the ones commonly available.

http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/arch/arm64/include/asm/elf.h?h=v4.4.9&id=1a1a512b983108015ced1e7a7c7775cfeec42d8c#n176

So it seems like it doesn't matter much which EABI version is set, as long as any flag within EF_ARM_EABI_MASK is set.

peter.smith edited edge metadata.Sep 13 2016, 3:35 AM

Strictly speaking EF_ARM_EABI version It is a bit more than an implementation detail. The current value of 0 is more honest, however it may be less useful in practice.

The EF_ARM_EABI version is defined in http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf

EF_ARM_ABIMASK (0xFF000000) (current version is 0x05000000)

This masks an 8-bit version number, the version of the ABI to which this
ELF file conforms. This ABI is version 5. A value of 0 denotes unknown
conformance. |

I think the AArch64 kernel isn't being very helpful here as 0 does not necessarily mean < 1, it just means not known. However that isn't lld's problem.

To the question of what should the ABI version be set to:
The ABI version that is put in the executable is a combination of the ABI version of the input files and the changes made by the linker for the output file. For example some aspects of the ABI version are determined by the compiler/assembler, the linker can also use and will set certain flags such as EF_ARM_ABI_FLOAT_HARD that are only defined in a certain ABI version.

In an ideal world we would read the ABI version from the input objects, fault any incompatibilities that we can't handle, use no ARM ELF specific features from the highest ABI version read, and write this version out into the executable. We are quite a long way from doing this in the ARM port so far.

I think the current value of EF_ARM_ABI_VERSION = 0 is honest, as the ARM port is incomplete and we can't make any firm statements of conformance right now. In practice all input objects given to lld will be EF_ARM_ABI_VERSION 5 and we don't make use of any features that are incompatible with EF_ARM_ABI_VERSION 5 so I think it is acceptable to set the default to 5 as long as we leave an appropriate comment.

We aren't in a position to report hard or soft float. We don't support BuildAttributes to get this information from object files and we don't hard-code at build time like GNU ld (arm-linux-gnueabi-hf distribution). In any case EF_ARM_VFP_FLOAT and EF_ARM_SOFT_FLOAT are one of the few changes from ABI version 4 to version 5. The correct terms are EF_ARM_ABI_FLOAT_HARD and EF_ARM_ABI_FLOAT_SOFT in version 5.

Strictly speaking EF_ARM_EABI version It is a bit more than an implementation detail. The current value of 0 is more honest, however it may be less useful in practice.

What I meant was that the fact that the aarch64 kernel refuses to run binaries with a zero version is an implementation detail.

I think the current value of EF_ARM_ABI_VERSION = 0 is honest, as the ARM port is incomplete and we can't make any firm statements of conformance right now. In practice all input objects given to lld will be EF_ARM_ABI_VERSION 5 and we don't make use of any features that are incompatible with EF_ARM_ABI_VERSION 5 so I think it is acceptable to set the default to 5 as long as we leave an appropriate comment.

Thanks for the good writeup!

What would be a useful but concise enough comment here? "// We don't currently use any features incompatible with EF_ARM_EABI_VER5, but we don't have any firm guarantees of conformance"

Yes I think your suggested comment sums up the situation well.

Can you add a test case?

It seems to me that llvm-objdump doesn't print e_flags at all anywhere. Any suggestions on how to test it without that?

Also, is something similar to "Subtarget->isTargetAEABI() || Subtarget->isTargetGNUAEABI() || Subtarget->isTargetMuslAEABI()" available in ELF/Writer.cpp? In that case, we could selectively set the flag in those cases.

I think the current value of EF_ARM_ABI_VERSION = 0 is honest, as the ARM port is incomplete and we can't make any firm statements of conformance right now. In practice all input objects given to lld will be EF_ARM_ABI_VERSION 5 and we don't make use of any features that are incompatible with EF_ARM_ABI_VERSION 5 so I think it is acceptable to set the default to 5 as long as we leave an appropriate comment.

Well, I take it the kernel interprets this flag as being "what I intend to implement", not "what I honestly can implement".

In that case, 5 is the *correct* value, given the users' interpretation, not the ABI. We've been into that situation before with regards to architecture support and the approach was similar: state what we intend to do and fix the bugs as we find them.

Since we don't have a full conformance test-suite, exaggerating the statement and complete later is the only thing we can reliably do.

I agree the comment expresses it well and is necessary.

cheers,
--renato

I think llvm-readobj -file-headers is a good starting point. This should dump the ELF header, and if the flag isn't shown textually you should be able to find the binary value.

ELF/Writer.cpp doesn't have any similar for subtargets at the moment unfortunately.

mstorsjo updated this revision to Diff 71138.Sep 13 2016, 4:20 AM
mstorsjo updated this object.
mstorsjo edited edge metadata.

Updated the order of the if statements as requested (alphabetically) and added the requested comment. No tests added yet.

mstorsjo updated this revision to Diff 71142.Sep 13 2016, 4:28 AM

Added a test using llvm-readobj.

peter.smith accepted this revision.Sep 13 2016, 6:05 AM
peter.smith edited edge metadata.

The test looks ok despite llvm-readobj generic header output separating 0x5000000 into 0x1000000 and 0x4000000 which is confusing. The actual binary field is correct.

This looks good to me. I've accepted the revision although you might want to wait to see if Rui has any further comments.

This revision is now accepted and ready to land.Sep 13 2016, 6:05 AM

This seems fine to me also.

One request if you're using the summary above as the commit message, please be explicit that you mean "an AArch64 Linux kernel." FreeBSD's kernel is "an AArch64 kernel" and does not have this issue (we don't currently run 32-bit arm binaries at all).

mstorsjo updated this object.Sep 13 2016, 12:52 PM
mstorsjo edited edge metadata.
ruiu added a comment.Sep 13 2016, 1:21 PM

LGTM.

Thanks a lot Peter, your explanation was extremely useful to understand the situation.

ELF/Writer.cpp
1267 ↗(On Diff #71142)

Please also add a comment to describe why we need to set this value and can't leave as zero. Linux/AArch64 as of 2016 doesn't accept e_flags with zero.

mstorsjo updated this revision to Diff 71231.Sep 13 2016, 1:41 PM

Amended the comment as requested.

In D24471#541688, @ruiu wrote:

LGTM

Thanks - can you commit it?

This revision was automatically updated to reflect the committed changes.
ruiu added a comment.Sep 13 2016, 2:00 PM

Submitted as r281394.