#include <memory.h>
#include <libelf.h>
#include <sys/link.h>
#include <decl.h>
#include <msg.h>
#include <string.h>
#define HI32 0x80000000UL
#define LO31 0x7fffffffUL
typedef struct {
Elf32_Sword d_tag;
union {
Elf32_Word d_val;
Elf32_Addr d_ptr;
Elf32_Off d_off;
} d_un;
} Elf32_Dyn;
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
} Elf32_Rel;
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Sword r_addend;
} Elf32_Rela;
typedef struct {
Elf32_Half si_boundto;
Elf32_Half si_flags;
} Elf32_Syminfo;
enum
{
A_L0, A_L1, A_L2, A_L3
};
enum
{
A_M3, A_M2, A_M1, A_M0,
A_sizeof
};
enum
{
H_L0, H_L1
};
enum
{
H_M1, H_M0,
H_sizeof
};
enum
{
L_L0, L_L1, L_L2, L_L3, L_L4, L_L5, L_L6, L_L7
};
enum
{
L_M7, L_M6, L_M5, L_M4, L_M3, L_M2, L_M1, L_M0,
L_sizeof
};
enum
{
M1_value_L0, M1_value_L1, M1_value_L2, M1_value_L3, M1_value_L4, M1_value_L5, M1_value_L6, M1_value_L7,
M1_info_L0, M1_info_L1, M1_info_L2, M1_info_L3,
M1_poffset_L0, M1_poffset_L1, M1_poffset_L2, M1_poffset_L3,
M1_repeat_L0, M1_repeat_L1,
M1_stride_L0, M1_stride_L1
};
enum
{
M1_value_M7, M1_value_M6, M1_value_M5, M1_value_M4, M1_value_M3, M1_value_M2, M1_value_M1, M1_value_M0,
M1_info_M3, M1_info_M2, M1_info_M1, M1_info_M0,
M1_poffset_M3, M1_poffset_M2, M1_poffset_M1, M1_poffset_M0,
M1_repeat_M1, M1_repeat_M0,
M1_stride_M1, M1_stride_M0,
M1_sizeof
};
enum
{
MP1_value_L0, MP1_value_L1, MP1_value_L2, MP1_value_L3, MP1_value_L4, MP1_value_L5, MP1_value_L6, MP1_value_L7,
MP1_info_L0, MP1_info_L1, MP1_info_L2, MP1_info_L3,
MP1_poffset_L0, MP1_poffset_L1, MP1_poffset_L2, MP1_poffset_L3,
MP1_repeat_L0, MP1_repeat_L1,
MP1_stride_L0, MP1_stride_L1,
MP1_padding_L0, MP1_padding_L1, MP1_padding_L2, MP1_padding_L3
};
enum
{
MP1_value_M7, MP1_value_M6, MP1_value_M5, MP1_value_M4, MP1_value_M3, MP1_value_M2, MP1_value_M1, MP1_value_M0,
MP1_info_M3, MP1_info_M2, MP1_info_M1, MP1_info_M0,
MP1_poffset_M3, MP1_poffset_M2, MP1_poffset_M1, MP1_poffset_M0,
MP1_repeat_M1, MP1_repeat_M0,
MP1_stride_M1, MP1_stride_M0,
MP1_padding_M3, MP1_padding_M2, MP1_padding_M1, MP1_padding_M0,
MP1_sizeof
};
enum
{
O_L0, O_L1, O_L2, O_L3
};
enum
{
O_M3, O_M2, O_M1, O_M0,
O_sizeof
};
enum
{
W_L0, W_L1, W_L2, W_L3
};
enum
{
W_M3, W_M2, W_M1, W_M0,
W_sizeof
};
enum
{
D1_tag_L0, D1_tag_L1, D1_tag_L2, D1_tag_L3,
D1_val_L0, D1_val_L1, D1_val_L2, D1_val_L3
};
enum
{
D1_tag_M3, D1_tag_M2, D1_tag_M1, D1_tag_M0,
D1_val_M3, D1_val_M2, D1_val_M1, D1_val_M0,
D1_sizeof
};
#define E1_Nident 16
enum
{
E1_ident, E1_ident_L_Z = E1_Nident - 1,
E1_type_L0, E1_type_L1,
E1_machine_L0, E1_machine_L1,
E1_version_L0, E1_version_L1, E1_version_L2, E1_version_L3,
E1_entry_L0, E1_entry_L1, E1_entry_L2, E1_entry_L3,
E1_phoff_L0, E1_phoff_L1, E1_phoff_L2, E1_phoff_L3,
E1_shoff_L0, E1_shoff_L1, E1_shoff_L2, E1_shoff_L3,
E1_flags_L0, E1_flags_L1, E1_flags_L2, E1_flags_L3,
E1_ehsize_L0, E1_ehsize_L1,
E1_phentsize_L0, E1_phentsize_L1,
E1_phnum_L0, E1_phnum_L1,
E1_shentsize_L0, E1_shentsize_L1,
E1_shnum_L0, E1_shnum_L1,
E1_shstrndx_L0, E1_shstrndx_L1
};
enum
{
E1_ident_M_Z = E1_Nident - 1,
E1_type_M1, E1_type_M0,
E1_machine_M1, E1_machine_M0,
E1_version_M3, E1_version_M2, E1_version_M1, E1_version_M0,
E1_entry_M3, E1_entry_M2, E1_entry_M1, E1_entry_M0,
E1_phoff_M3, E1_phoff_M2, E1_phoff_M1, E1_phoff_M0,
E1_shoff_M3, E1_shoff_M2, E1_shoff_M1, E1_shoff_M0,
E1_flags_M3, E1_flags_M2, E1_flags_M1, E1_flags_M0,
E1_ehsize_M1, E1_ehsize_M0,
E1_phentsize_M1, E1_phentsize_M0,
E1_phnum_M1, E1_phnum_M0,
E1_shentsize_M1, E1_shentsize_M0,
E1_shnum_M1, E1_shnum_M0,
E1_shstrndx_M1, E1_shstrndx_M0,
E1_sizeof
};
enum
{
N1_namesz_L0, N1_namesz_L1, N1_namesz_L2, N1_namesz_L3,
N1_descsz_L0, N1_descsz_L1, N1_descsz_L2, N1_descsz_L3,
N1_type_L0, N1_type_L1, N1_type_L2, N1_type_L3
};
enum
{
N1_namesz_M3, N1_namesz_M2, N1_namesz_M1, N1_namesz_M0,
N1_descsz_M3, N1_descsz_M2, N1_descsz_M1, N1_descsz_M0,
N1_type_M3, N1_type_M2, N1_type_M1, N1_type_M0,
N1_sizeof
};
enum
{
P1_type_L0, P1_type_L1, P1_type_L2, P1_type_L3,
P1_offset_L0, P1_offset_L1, P1_offset_L2, P1_offset_L3,
P1_vaddr_L0, P1_vaddr_L1, P1_vaddr_L2, P1_vaddr_L3,
P1_paddr_L0, P1_paddr_L1, P1_paddr_L2, P1_paddr_L3,
P1_filesz_L0, P1_filesz_L1, P1_filesz_L2, P1_filesz_L3,
P1_memsz_L0, P1_memsz_L1, P1_memsz_L2, P1_memsz_L3,
P1_flags_L0, P1_flags_L1, P1_flags_L2, P1_flags_L3,
P1_align_L0, P1_align_L1, P1_align_L2, P1_align_L3
};
enum
{
P1_type_M3, P1_type_M2, P1_type_M1, P1_type_M0,
P1_offset_M3, P1_offset_M2, P1_offset_M1, P1_offset_M0,
P1_vaddr_M3, P1_vaddr_M2, P1_vaddr_M1, P1_vaddr_M0,
P1_paddr_M3, P1_paddr_M2, P1_paddr_M1, P1_paddr_M0,
P1_filesz_M3, P1_filesz_M2, P1_filesz_M1, P1_filesz_M0,
P1_memsz_M3, P1_memsz_M2, P1_memsz_M1, P1_memsz_M0,
P1_flags_M3, P1_flags_M2, P1_flags_M1, P1_flags_M0,
P1_align_M3, P1_align_M2, P1_align_M1, P1_align_M0,
P1_sizeof
};
enum
{
R1_offset_L0, R1_offset_L1, R1_offset_L2, R1_offset_L3,
R1_info_L0, R1_info_L1, R1_info_L2, R1_info_L3
};
enum
{
R1_offset_M3, R1_offset_M2, R1_offset_M1, R1_offset_M0,
R1_info_M3, R1_info_M2, R1_info_M1, R1_info_M0,
R1_sizeof
};
enum
{
RA1_offset_L0, RA1_offset_L1, RA1_offset_L2, RA1_offset_L3,
RA1_info_L0, RA1_info_L1, RA1_info_L2, RA1_info_L3,
RA1_addend_L0, RA1_addend_L1, RA1_addend_L2, RA1_addend_L3
};
enum
{
RA1_offset_M3, RA1_offset_M2, RA1_offset_M1, RA1_offset_M0,
RA1_info_M3, RA1_info_M2, RA1_info_M1, RA1_info_M0,
RA1_addend_M3, RA1_addend_M2, RA1_addend_M1, RA1_addend_M0,
RA1_sizeof
};
enum
{
SH1_name_L0, SH1_name_L1, SH1_name_L2, SH1_name_L3,
SH1_type_L0, SH1_type_L1, SH1_type_L2, SH1_type_L3,
SH1_flags_L0, SH1_flags_L1, SH1_flags_L2, SH1_flags_L3,
SH1_addr_L0, SH1_addr_L1, SH1_addr_L2, SH1_addr_L3,
SH1_offset_L0, SH1_offset_L1, SH1_offset_L2, SH1_offset_L3,
SH1_size_L0, SH1_size_L1, SH1_size_L2, SH1_size_L3,
SH1_link_L0, SH1_link_L1, SH1_link_L2, SH1_link_L3,
SH1_info_L0, SH1_info_L1, SH1_info_L2, SH1_info_L3,
SH1_addralign_L0, SH1_addralign_L1, SH1_addralign_L2, SH1_addralign_L3,
SH1_entsize_L0, SH1_entsize_L1, SH1_entsize_L2, SH1_entsize_L3
};
enum
{
SH1_name_M3, SH1_name_M2, SH1_name_M1, SH1_name_M0,
SH1_type_M3, SH1_type_M2, SH1_type_M1, SH1_type_M0,
SH1_flags_M3, SH1_flags_M2, SH1_flags_M1, SH1_flags_M0,
SH1_addr_M3, SH1_addr_M2, SH1_addr_M1, SH1_addr_M0,
SH1_offset_M3, SH1_offset_M2, SH1_offset_M1, SH1_offset_M0,
SH1_size_M3, SH1_size_M2, SH1_size_M1, SH1_size_M0,
SH1_link_M3, SH1_link_M2, SH1_link_M1, SH1_link_M0,
SH1_info_M3, SH1_info_M2, SH1_info_M1, SH1_info_M0,
SH1_addralign_M3, SH1_addralign_M2, SH1_addralign_M1, SH1_addralign_M0,
SH1_entsize_M3, SH1_entsize_M2, SH1_entsize_M1, SH1_entsize_M0,
SH1_sizeof
};
enum
{
ST1_name_L0, ST1_name_L1, ST1_name_L2, ST1_name_L3,
ST1_value_L0, ST1_value_L1, ST1_value_L2, ST1_value_L3,
ST1_size_L0, ST1_size_L1, ST1_size_L2, ST1_size_L3,
ST1_info_L,
ST1_other_L,
ST1_shndx_L0, ST1_shndx_L1
};
enum
{
ST1_name_M3, ST1_name_M2, ST1_name_M1, ST1_name_M0,
ST1_value_M3, ST1_value_M2, ST1_value_M1, ST1_value_M0,
ST1_size_M3, ST1_size_M2, ST1_size_M1, ST1_size_M0,
ST1_info_M,
ST1_other_M,
ST1_shndx_M1, ST1_shndx_M0,
ST1_sizeof
};
enum
{
SI1_boundto_M1, SI1_boundto_M0,
SI1_flags_M1, SI1_flags_M0,
SI1_sizeof
};
enum
{
C1_tag_M3, C1_tag_M2, C1_tag_M1, C1_tag_M0,
C1_val_M3, C1_val_M2, C1_val_M1, C1_val_M0,
C1_sizeof
};
enum
{
VD1_version_M1, VD1_version_M0,
VD1_flags_M1, VD1_flags_M0,
VD1_ndx_M1, VD1_ndx_M0,
VD1_cnt_M1, VD1_cnt_M0,
VD1_hash_M3, VD1_hash_M2, VD1_hash_M1, VD1_hash_M0,
VD1_aux_M3, VD1_aux_M2, VD1_aux_M1, VD1_aux_M0,
VD1_next_M3, VD1_next_M2, VD1_next_M1, VD1_next_M0,
VD1_sizeof
};
enum
{
VDA1_name_M3, VDA1_name_M2, VDA1_name_M1, VDA1_name_M0,
VDA1_next_M3, VDA1_next_M2, VDA1_next_M1, VDA1_next_M0,
VDA1_sizeof
};
enum
{
VN1_version_M1, VN1_version_M0,
VN1_cnt_M1, VN1_cnt_M0,
VN1_file_M3, VN1_file_M2, VN1_file_M1, VN1_file_M0,
VN1_aux_M3, VN1_aux_M2, VN1_aux_M1, VN1_aux_M0,
VN1_next_M3, VN1_next_M2, VN1_next_M1, VN1_next_M0,
VN1_sizeof
};
enum
{
VNA1_hash_M3, VNA1_hash_M2, VNA1_hash_M1, VNA1_hash_M0,
VNA1_flags_M1, VNA1_flags_M0,
VNA1_other_M1, VNA1_other_M0,
VNA1_name_M3, VNA1_name_M2, VNA1_name_M1, VNA1_name_M0,
VNA1_next_M3, VNA1_next_M2, VNA1_next_M1, VNA1_next_M0,
VNA1_sizeof
};
static const struct {
size_t s_filesz,
s_memsz;
} fmsize [EV_CURRENT] [ELF_T_NUM] =
{
{
{ 1, 1 },
{ A_sizeof, sizeof (Elf32_Addr) },
{ D1_sizeof, sizeof (Elf32_Dyn) },
{ E1_sizeof, sizeof (Elf32_Ehdr) },
{ H_sizeof, sizeof (Elf32_Half) },
{ O_sizeof, sizeof (Elf32_Off) },
{ P1_sizeof, sizeof (Elf32_Phdr) },
{ RA1_sizeof, sizeof (Elf32_Rela) },
{ R1_sizeof, sizeof (Elf32_Rel) },
{ SH1_sizeof, sizeof (Elf32_Shdr) },
{ W_sizeof, sizeof (Elf32_Sword) },
{ ST1_sizeof, sizeof (Elf32_Sym) },
{ W_sizeof, sizeof (Elf32_Word) },
{ 1, 1},
{ 1, 1},
{ 0, 0 },
{ 0, 0 },
{ SI1_sizeof, sizeof (Elf32_Syminfo) },
{ 1, 1},
},
};
static const Elf_Type mtype[EV_CURRENT][SHT_NUM] =
{
{
ELF_T_BYTE,
ELF_T_BYTE,
ELF_T_SYM,
ELF_T_BYTE,
ELF_T_RELA,
ELF_T_WORD,
ELF_T_DYN,
ELF_T_NOTE,
ELF_T_BYTE,
ELF_T_REL,
ELF_T_BYTE,
ELF_T_SYM,
ELF_T_BYTE,
ELF_T_BYTE,
ELF_T_ADDR,
ELF_T_ADDR,
ELF_T_ADDR,
ELF_T_WORD,
ELF_T_WORD
},
};
size_t
elf32_fsize(Elf_Type type, size_t count, unsigned ver)
{
if (--ver >= EV_CURRENT) {
_elf_seterr(EREQ_VER, 0);
return (0);
}
if ((unsigned)type >= ELF_T_NUM) {
_elf_seterr(EREQ_TYPE, 0);
return (0);
}
return (fmsize[ver][type].s_filesz * count);
}
size_t
_elf32_msize(Elf_Type type, unsigned ver)
{
return (fmsize[ver - 1][type].s_memsz);
}
Elf_Type
_elf32_mtype(Elf * elf, Elf32_Word shtype, unsigned ver)
{
#pragma unused(elf)
if (shtype < SHT_NUM)
return (mtype[ver - 1][shtype]);
return (ELF_T_BYTE);
}
static uint_t
_elf_sys_encoding(void)
{
union {
Elf32_Word w;
unsigned char c[W_sizeof];
} u;
u.w = 0x10203;
if (~(Elf32_Word)0 == -(Elf32_Sword)1 && (((((((Elf32_Word)(u.c)[W_L3]<<8)
+(u.c)[W_L2])<<8)
+(u.c)[W_L1])<<8)
+(u.c)[W_L0]) == 0x10203)
return (ELFDATA2LSB);
if (~(Elf32_Word)0 == -(Elf32_Sword)1 && (((((((Elf32_Word)(u.c)[W_M3]<<8)
+(u.c)[W_M2])<<8)
+(u.c)[W_M1])<<8)
+(u.c)[W_M0]) == 0x10203)
return (ELFDATA2MSB);
return (ELFDATANONE);
}
unsigned
elf_version(unsigned ver)
{
register unsigned j;
if (ver == EV_NONE)
return EV_CURRENT;
if (ver > EV_CURRENT)
{
_elf_seterr(EREQ_VER, 0);
return EV_NONE;
}
(void) mutex_lock(&_elf_globals_mutex);
if (_elf_work != EV_NONE)
{
j = _elf_work;
_elf_work = ver;
(void) mutex_unlock(&_elf_globals_mutex);
return j;
}
_elf_work = ver;
_elf_encode = _elf_sys_encoding();
(void) mutex_unlock(&_elf_globals_mutex);
return ver;
}
static Elf_Data *
xlate(Elf_Data *dst, const Elf_Data *src, unsigned encode)
{
size_t cnt, dsz, ssz;
unsigned type;
unsigned dver, sver;
unsigned _encode;
if (dst == 0 || src == 0)
return (0);
if (--encode >= (ELFDATANUM - 1)) {
_elf_seterr(EREQ_ENCODE, 0);
return (0);
}
if ((dver = dst->d_version - 1) >= EV_CURRENT ||
(sver = src->d_version - 1) >= EV_CURRENT) {
_elf_seterr(EREQ_VER, 0);
return (0);
}
if ((type = src->d_type) >= ELF_T_NUM) {
_elf_seterr(EREQ_TYPE, 0);
return (0);
}
dsz = fmsize[dver][type].s_memsz;
ssz = fmsize[sver][type].s_filesz;
cnt = src->d_size / ssz;
if (dst->d_size < dsz * cnt) {
_elf_seterr(EREQ_DSZ, 0);
return (0);
}
ELFACCESSDATA(_encode, _elf_encode)
if ((_encode == (encode + 1)) && (dsz == ssz)) {
if (src->d_buf && src->d_buf != dst->d_buf)
(void) memcpy(dst->d_buf, src->d_buf, src->d_size);
dst->d_type = src->d_type;
dst->d_size = src->d_size;
return (dst);
}
else {
_elf_seterr(EREQ_NOTSUP, 0);
return (0);
}
}
Elf_Data *
elf32_xlatetom(Elf_Data *dst, const Elf_Data *src, unsigned encode)
{
return (xlate(dst, src, encode));
}