Skip to contentSkip to conversation

is casting of function descriptor assignments for ia64 ONLY a good idea?

Linux-ia64 Keith Owens 3 participants 3 messages Jan 3, 2002

lore
Share & tools
lore
#0 lore raw
Quoted 10 lines · Piet/Pete Delaney

SUMMARY:

Keith Owens just pointed out that ia64 function descriptor assignments MUST be cast:

pointer = ((unsigned long *)(&my_printf))[0])

howerver it appears that other platforms MUST NOT be cast.

I was wondering if that a good idea. It seems it might require hacking a lot of existing code.

The problem only arises if you want to print or store the location of the function code. That is very rare, most of the time you just pass function pointers around and let the compiler handle their format. Think of a function pointer as an opaque cookie.

Quoted 1 line

Why is this necessary for just ia64?

Not just ia64, powerpc 64 as well. You are assuming that all pointers are the same format when that is not guaranteed by the C standard. On most architectures they are the same, you can convert a function pointer to a void pointer and back again but it is not defined behaviour.

On IA64 and PPC64 the function pointer does not reference the function itself, instead it points to a function descriptor. The function descriptor contains a pointer to the function code plus additional data such as a pointer to the global data to be used when the function is called. This is mandated by the architecture software ABI.

I had to solve this problem for my dynamic syscall patch[1] because the syscall table points directly to the function code in the kernel, not to the function descriptor, even on ia64. I define DYNAMIC_SYSCALL_T and DYNAMIC_SYSCALL_FUNCADDR() which are asm specific. On most systems, funcaddr is a noop. For i386

#define DYNAMIC_SYSCALL_T long
#define DYNAMIC_SYSCALL_FUNCADDR(f) (DYNAMIC_SYSCALL_T)(f)

but on ia64 it does real work

#define DYNAMIC_SYSCALL_T long long
#define DYNAMIC_SYSCALL_FUNCADDR(f) ({DYNAMIC_SYSCALL_T *fp = (DYNAMIC_SYSCALL_T *)(f); fp[0];})

BTW, the lack of a true descriptor for syscall entries is one reason why trying to put syscalls in modules is a non-starter. The ia64 syscall handler assumes that all syscall code is in the kernel using the constant kernel global data pointer, so there is no need to change the environment on a syscall. But syscalls in modules require a different environment and there is nowhere to store the extra data in the syscall table.

[1] http://marc.theaimsgroup.com/?l=linux-kernel&m0902118219570&w=2

#1 lore raw

[Linux-ia64] Re: is casting of function descriptor assignments for ia64 ONLY a

Quoted 11 lines

Not just ia64, powerpc 64 as well. You are assuming that all pointers are the same format when that is not guaranteed by the C standard. On most architectures they are the same, you can convert a function pointer to a void pointer and back again but it is not defined behaviour.

On IA64 and PPC64 the function pointer does not reference the function itself, instead it points to a function descriptor. The function descriptor contains a pointer to the function code plus additional data such as a pointer to the global data to be used when the function is called. This is mandated by the architecture software ABI.

Also true for HPPA targets.
jeff

#2 lore raw
In reply to Keith Owens
Quoted 8 lines · Piet/Pete Delaney

SUMMARY:

Keith Owens just pointed out that ia64 function descriptor assignments
MUST be cast:

		 pointer = ((unsigned long *)(&my_printf))[0])

	howerver it appears that other platforms MUST NOT be cast.

I'm pretty sure parisc64 (ELF) does something similar.

We had issues with 32<->64 bit syscall wrappers where a 32-bit user space structure passed to the kernel contained a function pointer. I thought it was in either ioctl32.c or sys_wrapper32.c:
http://cvs.parisc-linux.org/linux/arch/parisc/kernel/

but couldn't find the exact code.
IIRC, a function ptr has 4 elements and the 3rd contains the addr to the actual code.

Quoted 2 lines

I've used pointers to functions a lot in the past and I don't recall ever haveing a problem like this.

IIRC, the compiler/linker deal with this transperently.
It's only done with function pointers (and not other pointer types). I only remember seeing this as an issue in 32-64 syscall wrapper conversion.

grant