/
/
初始化函数
typedef void
*
(
*
PFN_INIT)();
Elf64_Hash g_hash
=
{
0
};
char
*
pStrTable
=
NULL;
Elf64_Sym
*
pSymTable
=
NULL;
char
*
bufNedded[
256
]
=
{
0
};
size_t nNumOfNeede
=
0
;
Elf64_Rela
*
pRelaDyn
=
NULL;
size_t nNumOfRela
=
0
;
Elf64_Rela
*
pRelaPlt
=
NULL;
size_t nNumOfRelaPlt
=
0
;
PFN_INIT
*
bufInis
=
NULL;
size_t nNumOfInis
=
0
;
/
/
重定位函数
__attribute__((noinline))
void Relocate(uint8_t
*
pBase, Elf64_Rela
*
pRel,
size_t nNumOfRels,Elf64_Sym
*
pSym,void
*
hSos[],
size_t nNumOfSos,
const char
*
pStr)
{
/
/
解析重定位表
for
(size_t i
=
0
; i < nNumOfRels; i
+
+
)
{
uint32_t nSym
=
ELF64_R_SYM(pRel[i].r_info);
/
/
索引
uint32_t nType
=
ELF64_R_TYPE(pRel[i].r_info);
/
/
类型
/
/
根据符号获取地址
void
*
nAddr
=
NULL;
if
(pSym[nSym].st_value !
=
0
)
{
/
/
导出符号,自己模块内部的符号
nAddr
=
pBase
+
pSym[nSym].st_value;
}
else
{
/
/
导入符号,其他模块符号
for
(size_t i
=
0
; i<nNumOfSos;i
+
+
)
{
nAddr
=
dlsym(hSos[i],pStr
+
pSym[nSym].st_name);
if
(nAddr!
=
NULL)
{
break
;
/
/
找到了
}
}
}
switch (nType)
{
case R_AARCH64_RELATIVE:
/
/
相对
*
(uint64_t
*
)(pBase
+
pRel[i].r_offset)
=
(uint64_t)(pBase
+
pRel[i].r_addend);
break
;
case R_AARCH64_GLOB_DAT:
/
/
全局偏移量
*
(uint64_t
*
)(pBase
+
pRel[i].r_offset)
=
(uint64_t)nAddr;
break
;
case R_AARCH64_JUMP_SLOT:
/
/
跳转槽
*
(uint64_t
*
)(pBase
+
pRel[i].r_offset)
=
(uint64_t)nAddr;
break
;
default:
break
;
}
}
}
__attribute__((noinline))
void
*
MyDlSym(uint8_t
*
pBase, const char
*
szName)
{
/
/
判断要查找的字符是否存在于此so内
uint32_t
hash
=
gnu_hash(szName);
/
/
计算
hash
uint32_t h2
=
hash
>>g_hash.shift2;
uint32_t bloom_mask_bits
=
64
;
uint32_t word_num
=
(
hash
/
bloom_mask_bits)& g_hash.maskswords;
uint64_t bloom_word
=
g_hash.gnu_bloom_filter_[word_num];
if
( (
1
&(bloom_word>>(
hash
%
bloom_mask_bits)) & (bloom_word>>(h2
%
bloom_mask_bits)))
=
=
0
)
{
/
/
不在模块内
return
NULL;
}
uint32_t n
=
g_hash.gnu_bucket_[
hash
%
g_hash.nbucket];
do
{
Elf64_Sym
*
s
=
pSymTable
+
n;
if
( ((g_hash.gnu_chain_[n] ^
hash
) >>
1
)
=
=
0
&&
strcmp(pStrTable
+
s
-
>st_name, szName)
=
=
0
)
{
/
/
找到了,返回地址
return
pBase
+
s
-
>st_value;
}
}
while
((g_hash.gnu_chain_[n
+
+
]&
1
)
=
=
0
);
}
void
*
MyDlopen(const char
*
szName)
{
/
/
读取文件、文件头和段表
FILE
*
file
=
fopen(szName,
"rb"
);
if
(
file
=
=
NULL)
{
printf(
"open file error!\n"
);
return
0
;
}
Elf64_Ehdr hdr
=
{
0
};
/
/
elf hander
if
(fread(&hdr,
1
, sizeof(hdr),
file
) !
=
sizeof(hdr))
{
printf(
"read Ehdr error!\n"
);
return
0
;
}
size_t nSizeOfPhdrs
=
hdr.e_phentsize
*
hdr.e_phnum;
/
/
段表大小
Elf64_Phdr
*
phdrs
=
(Elf64_Phdr
*
)malloc(nSizeOfPhdrs);
if
( fread(phdrs,
1
, nSizeOfPhdrs,
file
) !
=
nSizeOfPhdrs)
{
printf(
"read phdr error!\n"
);
return
0
;
}
/
/
fclose(
file
);
/
/
申请内存、映射
size_t nLoadSize
=
0
;
for
(
int
i
=
hdr.e_phnum
-
1
;i>
=
0
;i
-
-
)
{
if
(phdrs[i].p_type
=
=
PT_LOAD)
{
nLoadSize
=
((phdrs[i].p_vaddr
+
phdrs[i].p_memsz
+
PAGE_SIZE
-
1
)
/
PAGE_SIZE)
*
PAGE_SIZE;
/
/
需要申请的内存大小
break
;
}
}
uint8_t
*
pBase
=
mmap64(NULL, nLoadSize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,
-
1
,
0
);
/
/
申请空间
if
(pBase
=
=
MAP_FAILED)
{
printf(
"mmap64 error: %s\n"
,strerror(errno));
return
0
;
}
for
(size_t i
=
0
;i<hdr.e_phnum;i
+
+
)
{
if
(phdrs[i].p_type
=
=
PT_LOAD)
{
fseek(
file
, phdrs[i].p_offset,SEEK_SET);
fread(pBase
+
phdrs[i].p_vaddr,
1
, phdrs[i].p_filesz,
file
);
/
/
读取文件到内存
}
}
free(phdrs);
/
/
定位动态段
phdrs
=
(Elf64_Phdr
*
)(pBase
+
hdr.e_phoff);
int
nDyncIdx
=
0
;
/
/
动态段索引
Elf64_Dyn
*
pDyns
=
NULL;
size_t nNumofDyns
=
0
;
/
/
动态段元素个数
for
(size_t i
=
0
;i<hdr.e_phnum;i
+
+
)
{
if
(phdrs[i].p_type
=
=
PT_DYNAMIC)
{
nDyncIdx
=
i;
pDyns
=
(Elf64_Dyn
*
)(pBase
+
phdrs[i].p_vaddr);
nNumofDyns
=
phdrs[i].p_filesz
/
sizeof(Elf64_Dyn);
break
;
}
}
/
/
解析动态段
while
(pDyns
-
>d_tag!
=
DT_NULL)
{
switch(pDyns
-
>d_tag)
{
case DT_STRTAB:
/
/
字符串段
pStrTable
=
(char
*
)(pBase
+
pDyns
-
>d_un.d_ptr);
/
/
模块基址
+
字符串表偏移
break
;
case DT_SYMTAB:
/
/
符号表
pSymTable
=
(Elf64_Sym
*
)(pBase
+
pDyns
-
>d_un.d_ptr);
break
;
case DT_NEEDED:
/
/
elf文件依赖项
bufNedded[nNumOfNeede
+
+
]
=
pDyns
-
>d_un.d_ptr;
/
/
str
表还没解析,先拿偏移
break
;
case DT_RELA:
/
/
重定位表
pRelaDyn
=
(Elf64_Rela
*
)(pBase
+
pDyns
-
>d_un.d_ptr);
break
;
case DT_RELASZ:
nNumOfRela
=
pDyns
-
>d_un.d_val
/
sizeof(Elf64_Rela);
break
;
case DT_JMPREL:
/
/
plt表
pRelaPlt
=
(Elf64_Rela
*
)(pBase
+
pDyns
-
>d_un.d_ptr);
break
;
case DT_PLTRELSZ:
nNumOfRelaPlt
=
pDyns
-
>d_un.d_val
/
sizeof(Elf64_Rela);
break
;
case DT_GNU_HASH:
/
/
hash
表
{
uint8_t
*
pHashTable
=
pBase
+
pDyns
-
>d_un.d_ptr;
g_hash.nbucket
=
((uint32_t
*
)pHashTable)[
0
];
g_hash.symindex
=
((uint32_t
*
)pHashTable)[
1
];
g_hash.maskswords
=
((uint32_t
*
)pHashTable)[
2
];
g_hash.shift2
=
((uint32_t
*
)pHashTable)[
3
];
g_hash.gnu_bloom_filter_
=
(uint64_t
*
)(pHashTable
+
16
);
g_hash.gnu_bucket_
=
(uint32_t
*
)(g_hash.gnu_bloom_filter_
+
g_hash.maskswords);
g_hash.gnu_chain_
=
g_hash.gnu_bucket_
+
g_hash.nbucket
-
g_hash .symindex;
-
-
g_hash.maskswords;
break
;
}
case DT_INIT_ARRAY:
/
/
初始化
bufInis
=
(PFN_INIT
*
)(pBase
+
pDyns
-
>d_un.d_ptr);
break
;
case DT_INIT_ARRAYSZ:
nNumOfInis
=
pDyns
-
>d_un.d_val
/
sizeof(void
*
);
break
;
default:
break
;
}
pDyns
+
+
;
}
/
/
加载模块,此so需要依赖的elf,方便查找导入符号
void
*
*
hSos
=
malloc(sizeof(void
*
)
*
nNumOfNeede);
for
(size_t i
=
0
;i<nNumOfNeede;i
+
+
)
{
bufNedded[i]
=
(uint64_t)bufNedded[i]
+
pStrTable;
/
/
字符串表已加载,偏移加字符串表基址为目标字符串地址
hSos[i]
=
dlopen(bufNedded[i], RTLD_NOW);
}
/
/
重定位
Relocate(pBase, pRelaDyn, nNumOfRela,pSymTable,hSos,nNumOfNeede,pStrTable);
Relocate(pBase, pRelaPlt,nNumOfRelaPlt,pSymTable,hSos,nNumOfNeede,pStrTable);
/
/
调用初始化函数
for
(size_t i
=
0
;i<nNumOfInis;i
+
+
)
{
bufInis[i]();
}
return
pBase;
}