Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

elf: use per-instruction metadata for .kconfig references #994

Merged
merged 1 commit into from
Apr 6, 2023

Conversation

lmb
Copy link
Collaborator

@lmb lmb commented Mar 30, 2023

.kconfig support is currently implemented in the ELF loader, which does
a fix up of the relevant instructions to point at a ".kconfig" map. This
map is available in CollectionSpec.Maps. This is basically how constants
(aka references to .rodata) work today. Now that we have per-instruction
metadata this isn't necessary anymore.

Instead of using the generic WithReference, introduce a new kconfig
metadata and tag instructions with that. Right now the metadata just
contains the MapSpec for .kconfig as generated by the compiler. In
the future we can create the MapSpec on the fly, which would allow
referencing kconfig via ins.WithKconfig or similar.

Prevent ".kconfig" from being accessible via CollectionSpec.Maps.
This preserves our ability to change how kconfig references work
without having to retain the original MapSpec.

@lmb lmb force-pushed the kconfig-metadata branch 2 times, most recently from b97c239 to ed6b67b Compare April 4, 2023 13:59
@lmb lmb changed the title elf: hide .kconfig map from users elf: use per-instruction metadata for .kconfig references Apr 4, 2023
@lmb lmb requested a review from rgo3 April 4, 2023 14:03
return nil, fmt.Errorf("instruction %d: reference to multiple .kconfig maps is not allowed", iter.Index)
}

if err := iter.Ins.AssociateMap(kconfig); err != nil {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only half joking: we could implement this without going via a map in the first place and just patch instructions directly. Something for the future maybe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure to understand what you mean here.
Do you mean we can compute a "whole offset" instead of using the offset inside the map?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of putting LINUX_VERSION_CODE into the map at an offset, and referencing the map from this instruction, we could rewrite the instruction to be a LdImm64 of LINUX_VERSION_CODE. This avoids the indirection via the map and works on older kernels. It has subtleties though when a single value is accessed multiple times, etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh definitely! This seems a good idea!
Nonetheless, maybe we should not do it in case we add more generic __kconfig value?
Indeed, it will add an exception for LINUX_KERNEL_VERSION as others will need to be map load?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not going to do it now, since I don't have a use case yet. It might happen that we need something like it in cilium though. Then we can probably extend this to anything that fits in 64 bit.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has subtleties though when a single value is accessed multiple times, etc.

Indeed, but it's also a subtlety that cannot realistically be worked around by the library. It would require userspace to track all accesses to the register the map pointer was loaded into, accounting for branches and jumps, as well as the possibility of aliasing/moving, etc. This is best left to the verifier. 🙂

@lmb lmb marked this pull request as ready for review April 4, 2023 14:06
@lmb
Copy link
Collaborator Author

lmb commented Apr 4, 2023

cc @eiffel-fl

@lmb lmb force-pushed the kconfig-metadata branch 2 times, most recently from 84db3ff to 615381b Compare April 4, 2023 16:47
Copy link
Contributor

@eiffel-fl eiffel-fl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code is clearer now, thanks!

I have nonetheless some comments.
Also, can you please indicate me since when each instruction has metadata?

linker.go Outdated Show resolved Hide resolved
@@ -1134,7 +1132,7 @@ func (ec *elfCode) loadKconfigSection() error {
}

var ds *btf.Datasec
err := ec.btf.TypeByName(kconfigMap, &ds)
err := ec.btf.TypeByName(".kconfig", &ds)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should you keep this const and use it here:
const kconfigMap = ".kconfig"
?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's only used in three places now: here in the elf reader and when fixing up datasec in btf. The one use for MapSpec.Name is purely informational, so if we get it wrong it doesn't matter much.

In general I'm not a big fan of turning string literals into a constant, since it adds a layer of indirection. When reading code it's not clear that it's a constant (could be a var) and also what it's value is. If a string literal is repeated over an over as a key I try to reduce the number of lookups instead of introducing a constant.

linker.go Show resolved Hide resolved
return nil, fmt.Errorf("instruction %d: reference to multiple .kconfig maps is not allowed", iter.Index)
}

if err := iter.Ins.AssociateMap(kconfig); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure to understand what you mean here.
Do you mean we can compute a "whole offset" instead of using the offset inside the map?

@lmb
Copy link
Collaborator Author

lmb commented Apr 6, 2023

Also, can you please indicate me since when each instruction has metadata?

Here you go: e3e0e9e

.kconfig support is currently implemented in the ELF loader, which does
a fix up of the relevant instructions to point at a ".kconfig" map. This
map is available in CollectionSpec.Maps. This is basically how constants
(aka references to .rodata) work today. Now that we have per-instruction
metadata this isn't necessary anymore.

Instead of using the generic WithReference, introduce a new kconfig
metadata and tag instructions with that. Right now the metadata just
contains the MapSpec for .kconfig as generated by the compiler. In
the future we can create the MapSpec on the fly, which would allow
referencing kconfig via ins.WithKconfig or similar.

Prevent ".kconfig" from being accessible via CollectionSpec.Maps.
This preserves our ability to change how kconfig references work
without having to retain the original MapSpec.

Signed-off-by: Lorenz Bauer <lmb@isovalent.com>
@lmb lmb merged commit 73acad5 into cilium:master Apr 6, 2023
@lmb lmb deleted the kconfig-metadata branch April 6, 2023 09:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants