Add another example found on the interwebs
This commit is contained in:
parent
0dcdff6242
commit
fbb1bc9710
1 changed files with 80 additions and 0 deletions
80
src/another_try.cpp
Normal file
80
src/another_try.cpp
Normal 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];
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue