[PATCH] D131982: [llvm-objdump] Complete -chained_fixups support
Nico Weber via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 19 10:02:57 PDT 2022
thakis added a comment.
We chatted a bit offline. Rough summary
- https://github.com/freebsd/freebsd-src/blob/master/sys/netinet/ip.h#L51-L59 works if the on-disk format is the same for BE and LE, but since `$(xcrun -show-sdk-path)/usr/include/mach-o/fixup-chains.h` doesn't have any ifdefs, that's likely not the case here
- …but all chained fixup apple platforms are little endian, so it's really unknowable
- the current code does work on all hosts for when the on-disk data is little-endian
- it'd be nice to do the swapping anyways, since that puts all the endianness handling in a single place
- Bitfield swapping is different for little-endian-file-on-big-endian-host and the other way round, and the swapStruct() wrappers in BinaryFormat/MachO.h don't know which direction they're swapping in, so there's have to be a dedicated wrapper for each struct. Example for dyld_chained_import:
// Little-endian file running on big-endian host:
Raw = ((Raw & 0xff) << 24) | ((Raw & 0x100) << 15) || (Raw >> 9);
// Big-endian file running on little-endian host:
Raw = (Raw >> 24) | ((Raw & 0x800000) >> 15) || ((Raw & 0x7fffff << 9);
- Since there's a bunch of those structs, it'd be nice to make a general helper for this. This seems to roughly work:
#include <stdio.h>
template<typename T, unsigned W>
T bitfield_swap_le(T t) {
static_assert(W == 0, "");
return 0;
}
template<typename T, unsigned W, unsigned First, int... Sizes>
T bitfield_swap_le(T t) {
// Peel off rightmost field, add it on left, recurse.
return ((t & ((1u << First) - 1)) << (W - First)) |
bitfield_swap_le<T, W - First, Sizes...>(t >> First);
}
template<typename T, unsigned W>
T bitfield_swap_be(T t) {
static_assert(W == 0, "");
return 0;
}
template<typename T, unsigned W, unsigned First, int... Sizes>
T bitfield_swap_be(T t) {
// Peel off leftmost field, add it on right, recurse.
return ((t >> (W - First)) |
(bitfield_swap_be<T, W - First, Sizes...>(t & ((1u << (W - First)) - 1))) << First);
}
int main() {
{
unsigned i = bitfield_swap_le<unsigned, 32, 8, 1, 23>(0xff);
unsigned j = bitfield_swap_le<unsigned, 32, 8, 1, 23>(0x100);
unsigned k = bitfield_swap_le<unsigned, 32, 8, 1, 23>(0xffff'fe00);
printf("%08x %08x %08x\n", i, j, k);
}
{
unsigned i = bitfield_swap_be<unsigned, 32, 8, 1, 23>(0xff00'0000);
unsigned j = bitfield_swap_be<unsigned, 32, 8, 1, 23>(0x0080'0000);
unsigned k = bitfield_swap_be<unsigned, 32, 8, 1, 23>(0x007f'ffff);
printf("%08x %08x %08x\n", i, j, k);
}
}
% clang bitfield_swap.cc -std=c++17
% ./a.out
ff000000 00800000 007fffff
000000ff 00000100 fffffe00
- Then there could be a `bitfield_swap<>` member template that calls either of those based on file and host bitness, and that'd make it convenient to write a swapStruct() wrapper for each type with a bitfield
- However, all likely host systems are little-endian too, so it also seems fine to just go back to the original code, add a comment, mark the test `REQUIRES: host-byteorder-little-endian` and do the rest later (or have someone who actually needs it do it)
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D131982/new/
https://reviews.llvm.org/D131982
More information about the llvm-commits
mailing list