Add another example found on the interwebs

This commit is contained in:
Attila Body 2024-04-08 17:04:35 +02:00
parent 0dcdff6242
commit fbb1bc9710
No known key found for this signature in database
GPG key ID: 3D2FC6085E166F70

80
src/another_try.cpp Normal file
View file

@ -0,0 +1,80 @@
#include <memory.h>
#include <stddef.h>
#include <stdint.h>
/* AbstractClass may have several different concrete implementations. */
class AbstractClass
{
public:
virtual int f() = 0;
virtual int g() = 0;
};
/* Return the address of the `f' function of `aClass' that would be
called for the expression:
aClass->f();
regardless of the concrete type of `aClass'.
It is left as an exercise for the reader to templatize this function for
arbitrary `f'. */
void *find_f_address(AbstractClass *aClass)
{
/* The virtual function table is stored at the beginning of the object. */
void **vtable = *(void ***)aClass;
/* This structure is described in the cross-platform "Itanium" C++ ABI:
http://mentorembedded.github.io/cxx-abi/abi.html
The particular layout replicated here is described in:
http://mentorembedded.github.io/cxx-abi/abi.html#member-pointers */
struct pointerToMember
{
/* This field has separate representations for non-virtual and virtual
functions. For non-virtual functions, this field is simply the
address of the function. For our case, virtual functions, this
field is 1 plus the virtual table offset (in bytes) of the function
in question. The least-significant bit therefore discriminates
between virtual and non-virtual functions.
"Ah," you say, "what about architectures where function pointers do
not necessarily have even addresses?" (ARM, MIPS, and AArch64 are
the major ones.) Excellent point. Please see below. */
size_t pointerOrOffset;
/* This field is only interesting for calling the function; it
describes the amount that the `this' pointer must be adjusted
prior to the call. However, on architectures where function
pointers do not necessarily have even addresses, this field has the
representation:
2 * adjustment + (virtual_function_p ? 1 : 0) */
ptrdiff_t thisAdjustment;
};
/* Translate from the opaque pointer-to-member type representation to
the representation given above. */
pointerToMember p;
int((AbstractClass::*m)()) = &AbstractClass::f;
memcpy(&p, &m, sizeof(p));
/* Compute the actual offset into the vtable. Given the differing meaing
of the fields between architectures, as described above, and that
there's no convenient preprocessor macro, we have to do this
ourselves. */
#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
/* No adjustment required to `pointerOrOffset'. */
static const size_t pfnAdjustment = 0;
#else
/* Strip off the lowest bit of `pointerOrOffset'. */
static const size_t pfnAdjustment = 1;
#endif
size_t offset = (p.pointerOrOffset - pfnAdjustment) / sizeof(void *);
/* Now grab the address out of the vtable and return it. */
return vtable[offset];
}