mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-19 03:05:15 +00:00
92 lines
2.9 KiB
C
92 lines
2.9 KiB
C
/* descriptor-pa32-hpux.h - Given a function pointer, extract and return the
|
|
actual code address of the corresponding function.
|
|
|
|
This is done by checking if the plabel bit is set. If it's not set,
|
|
return the function pointer. If it's set, mask it off and extract
|
|
the address from the function descriptor. This address may point
|
|
to an export stub. If so, extract the branch target from the stub
|
|
and return it. Otherwise, the address from the function descriptor
|
|
is returned.
|
|
|
|
Copyright (C) 2006 Free Software Foundation
|
|
|
|
This file is part of libgcj.
|
|
|
|
This software is copyrighted work licensed under the terms of the
|
|
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
|
details. */
|
|
|
|
#define UNWRAP_FUNCTION_DESCRIPTOR pa_unwrap_function_descriptor
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* Extract bit field from word using HP's numbering (MSB = 0). */
|
|
#define GET_FIELD(X, FROM, TO) \
|
|
((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
|
|
|
|
static inline int
|
|
sign_extend (int x, int len)
|
|
{
|
|
int signbit = (1 << (len - 1));
|
|
int mask = (signbit << 1) - 1;
|
|
return ((x & mask) ^ signbit) - signbit;
|
|
}
|
|
|
|
/* Extract a 17-bit signed constant from branch instructions. */
|
|
static inline int
|
|
extract_17 (unsigned word)
|
|
{
|
|
return sign_extend (GET_FIELD (word, 19, 28)
|
|
| GET_FIELD (word, 29, 29) << 10
|
|
| GET_FIELD (word, 11, 15) << 11
|
|
| (word & 0x1) << 16, 17);
|
|
}
|
|
|
|
/* Extract a 22-bit signed constant from branch instructions. */
|
|
static inline int
|
|
extract_22 (unsigned word)
|
|
{
|
|
return sign_extend (GET_FIELD (word, 19, 28)
|
|
| GET_FIELD (word, 29, 29) << 10
|
|
| GET_FIELD (word, 11, 15) << 11
|
|
| GET_FIELD (word, 6, 10) << 16
|
|
| (word & 0x1) << 21, 22);
|
|
}
|
|
|
|
static void *
|
|
pa_unwrap_function_descriptor (void *addr)
|
|
{
|
|
unsigned int *tmp_addr;
|
|
|
|
/* Check if plabel bit is set in function pointer. */
|
|
if (!((unsigned int) addr & 2))
|
|
return addr;
|
|
|
|
tmp_addr = *(unsigned int **) ((unsigned int) addr & ~3);
|
|
|
|
/* If TMP_ADDR points to an export stub, adjust it so that it points
|
|
to the branch target of the stub. */
|
|
if ((*tmp_addr & 0xffe0e002) == 0xe8400000 /* bl x,r2 */
|
|
&& *(tmp_addr + 1) == 0x08000240 /* nop */
|
|
&& *(tmp_addr + 2) == 0x4bc23fd1 /* ldw -18(sp),rp */
|
|
&& *(tmp_addr + 3) == 0x004010a1 /* ldsid (rp),r1 */
|
|
&& *(tmp_addr + 4) == 0x00011820 /* mtsp r1,sr0 */
|
|
&& *(tmp_addr + 5) == 0xe0400002) /* be,n 0(sr0,rp) */
|
|
/* Extract target address from PA 1.x 17-bit branch. */
|
|
tmp_addr += extract_17 (*tmp_addr) + 2;
|
|
else if ((*tmp_addr & 0xfc00e002) == 0xe800a000 /* b,l x,r2 */
|
|
&& *(tmp_addr + 1) == 0x08000240 /* nop */
|
|
&& *(tmp_addr + 2) == 0x4bc23fd1 /* ldw -18(sp),rp */
|
|
&& *(tmp_addr + 3) == 0xe840d002) /* bve,n (rp) */
|
|
/* Extract target address from PA 2.0 22-bit branch. */
|
|
tmp_addr += extract_22 (*tmp_addr) + 2;
|
|
|
|
return (void *) tmp_addr;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|