svn commit: r293792 - head/sys/boot/uboot/lib

Bruce Evans brde at optusnet.com.au
Wed Jan 13 11:58:39 UTC 2016


On Wed, 13 Jan 2016, Konstantin Belousov wrote:

> On Wed, Jan 13, 2016 at 03:03:07PM +1100, Bruce Evans wrote:
>> Oops.  It is only declared in <machine/profile.h> outside of the kernel.
>> Only __uintfptr_t is always declared by sys/types.h.
>
> So what is the intended use of the uintfptr_t type ?  Looking at the
> implementation only, I am unable to find a difference with uintptr_t.

uintfptr_t is inded for functions.  uintptr_t is an optional type that
is only required to work for object pointers (only if it is a supported
option of course).  A similar type is needed for functions.

I added uintfptr_t at much the same time that I added uintptr_t in 1998.
Actually I added uintptr_t a little earlier under a different name, then
changed it to be more like the draft C9x name uintptr_t.

Unfortunately, standards haven't caught up with that yet.  POSIX now
uses various hacks near dlsym().  In the 2001 version it specifies
impossible things if the arch is not a vax so that function pointers
are too different from data pointers.  It gives the bad example
of casting dlsym() to a function pointer.  dlsym() returns void *.
dlopen() doesn't have this design error.  It returns a handle.

> Even on ia64 it is 64bit, which breaks my hypothesis about f standing
> for 'function'.

This might be a bug in ia64, but uintfptr_t works on it AFAIK.  It is
used for profiling.  This is hard to test since profiling support is
broken (profiling libraries not installed) on pluto.

Function pointers have size 64 bits on ia64, so they can be represented
in uint64_t's by memcpy()ing them.  Casting them might give a different
representation.  I think ia64 really has fat function pointers but they
are represented specially in 64-bit objects.  E.g., in a small
program, nm says that putchar is at 0x100000640, but when (putchar)
is cast to int (*f)(int), the bits in f are 0x1000acbb0 and casting f
to uint64_t doesn't change these bits.  f is just a pointer to data
containing the actual function address and possibly other data.  (It
points to .opd+16 which contains the same address that nm prints.
There seem to be only 64 bits of address and no extra data there too.)

binutils has to understand this of course.  Profiling too.  I think
gprof doesn't understand this.  It needs raw addresses represented in
uintfptr_t with the same encoding that ELF uses.  So uintfptr_t is not
suitable for representing function pointers after all.  It is for raw
addresses or a simple encoding of them.  Profiling hits record the
"program counter".  It is not obvious what this is when it might be
represented indirectly.  I think its raw register value is recorded,
and this can only work if its value is a raw virtual address (if not,
a table must be looked up to convert to something that gprof
understand).  Other data must use the same representation or convert
to it.  Data with C function pointers in it would need conversion.

Bruce


More information about the svn-src-all mailing list