手机站
网通分站
电信主站
密 码:
用户名:
当前位置 : 主页>网站运营>建站经验>列表

Intel平台下linux中 ELF文档动态链接的加载、解析及实例分析(二): 函数解析和卸载

来源:互联网 作者:west263.com 时间:2008-04-16
西部数码-全国虚拟主机10强!40余项虚拟主机管理功能,全国领先!双线多线虚拟主机南北访问畅通无阻!免费赠送企业邮局,.CN域名,自助建站480元起,免费试用7天,满意再付款! P4主机租用799元/月.月付免压金!


100行for_each_search_lmap_in_search_list就是从前面在 _dl_map_object_deps中得到的l_searchlist中取下的他本身的依赖动态链接库,中间查找的方法就如下面那张图中所显示的。

上面所表示的就是个在hash表中symidx偏移处所存的就是下一个偏移所在。最后假如strcmp==0就能够得到了,否则就会返回一个0表示失败了。

现在我们已把函数的解析过程分析完毕,有必要作一个小结工作:

  1. 在调用函数的动态链接库中,他所用的方法是从plt节的代码执行绝对转移,而转移的地址存放在got节中。
  2. 在被调用函数的动态链接库中(就是函数实现的动态链接库),他的函数在以DT_HASH和DT_SYMTAB, DT_STRTAB组织起来。组织的方式如下面的一张图,以symtab中的Elf32_Sym中的st_value表示这个可导出的标记在动态链接库中的偏移量,st_name则是在动态链接库strtab中的偏移量。
  3. 在调用动态链接库和被调用动态链接库的联系能过的是Elf32_Rel(对MIPS等的体系结构中是Elf32_Rela),他的r_info体现了这个要导入标记(就是调用方中)的性质,而r_offset则是这个标记在动态链接库中的偏移量。(这个能够看 elf_machine_lazy_rel中的实现)

五、动态链接库的卸载

实际上卸载和加载只是反过程而已,但原来的代码为了提高效率实现在栈内分配内存,但是这样倒使原来简单易懂的变的过于复杂,所以,我这里作了很大的修改,这里是伪代码的实现。


245 void dl_close(struct link_map* lmap)
246 {
247 struct link_map** dep_lmaplist=NULL;
248 int i;
249 Elf32_Addr* fini_call_array;
250 void* fini_call;
251 struct link_map* curlmap;
252 struct list * has_removed_list=malloc(sizeof(struct list));
253
254 has_removed_list->lmap=lmap;
255 has_removed_list->next=NULL;
256
257 if (lmap->l_opencount>1)
258 {
259 lmap->l_opencount--;
260 return;
261 }
262
263 lmap->l_opencount--;
264
265
266 dep_lmaplist=lmap->l_initfini;
267
268
269
270 for (i=0;dep_lmaplist[i]!=NULL;i )
271 {
272
273 try_dl_close(dep_lmaplist[i],has_removed_list);
274 }
275
276
277 if (lmap->l_info[DT_FINI_ARRAY].d_un.d_ptr!=NULL && lmap->l_opencount ==0)
278 {
279
280 fini_call_array=lmap->l_info[DT_FINI_ARRAY].d_un.d_ptr
281 lmap->l_addr;
282 unsigned int sz=lmap->l_info[DT_FINI_ARRAYSZ].d_un.d_ptr
283 lmap->l_addr;
284
285 while(sz-->0)
286 {
287 /*call the fini function*/
288 ((void*)fini_call_array[sz])();
289
290 }
291 }
292
293 if (lmap->l_info[DT_FINI].d_un.d_ptr!=NULL && lmap->l_opencount ==0)
294 {
295 fini_call=lmap->l_info[DT_FINI].d_un.d_ptr
296 lmap->l_addr;
297
298 ((void*)fini_call)();
299 }
300
301
302 munmap(lmap->l_map_start,lmap->l_map_end-lmap->l_map_start);
303
304
305 free (lmap->l_initfini);
306
307 free (lmap->l_scope);
308
309 if (lmap->l_phdr_allocated)
310 free ((void *) lmap->l_phdr);
311
312 free_list(has_removed_list);
313
314 free (lmap);
315
316
317 return;
318 }

这里的has_removed_list就是记录整个在这一次dl_close操作中已被卸载了的动态链接库,主要是为了防止再次卸载已卸载的动态链接库。其实先开始判断这是否是已没有再依赖他本向的动态链接库了。假如没有了(减去1,等于0就是了),那才能够继续去了,接下来不要先把他自己加入这个动态链接库,试着去卸载他所依赖的动态链接库,这些全做完之后就是他本身的各要点,一是他的DT_FINI_ARRAY中的卸载函数,更有就是DT_FINI中的函数,这之完了,便是加载到内存内容的去映射化,213行。再就是对struct link_map申请的内存就是了。

您能够看try_dl_close之后的代码就能明白这种可能有的深度的递归过程。


233 void try_dl_close(struct link_map* lmap,struct list*
234 has_removed_lmap_list)
234 {
235 if(in_the_list(has_removed_lmap_list,lmap))
236 return ;
237 dl_close_with_list(lmap,has_removed_lmap_list);
238 return ;
239
240 }


156 void dl_close_with_list(struct link_map* lmap,struct list* has_removed_lmap_list)
157 {
158 struct link_map** dep_lmaplist=NULL;
159 int i;
160 Elf32_Addr* fini_call_array;
161 void* fini_call;
162
163
164
165
166
167 if (lmap->l_opencount>1)
168 {
169 lmap->l_opencount--;
170 return;
171 }
172 add_to_list_tail_uniq(has_removed_lmap_list,lmap);
173
174 lmap->l_opencount--;
175
176
177 dep_lmaplist=lmap->l_initfini;
178
179
180
181 for (i=0;dep_lmaplist[i]!=NULL;i )
182 {
183
184 try_dl_close(dep_lmaplist[i],has_removed_lmap_list);
185 }
186
187
188 if (lmap->l_info[DT_FINI_ARRAY].d_un.d_ptr!=NULL && lmap->l_opencount ==0)
189 {
190
191 fini_call_array=lmap->l_info[DT_FINI_ARRAY].d_un.d_ptr
192 lmap->l_addr;
193 unsigned int sz=lmap->l_info[DT_FINI_ARRAYSZ].d_un.d_ptr
194 lmap->l_addr;
195
196 while(sz-->0)
197 {
198 /*call the fini function*/
199 ((void*)fini_call_array[sz])();
200
201 }
202 }
203
204 if (lmap->l_info[DT_FINI].d_un.d_ptr!=NULL && lmap->l_opencount ==0)
205 {
206 fini_call=lmap->l_info[DT_FINI].d_un.d_ptr
207 lmap->l_addr;
208
209 ((void*)fini_call)();
210 }
211
212
213 munmap(lmap->l_map_start,lmap->l_map_end-lmap->l_map_start);
214
215
216 free (lmap->l_initfini);
217
218 free (lmap->l_scope);
219
220 if (lmap->l_phdr_allocated)
221 free ((void *) lmap->l_phdr);
222
223 free (lmap);
224
225
226 return;
227
228 }

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!