Chinaunix首页 | 论坛 | 博客
  • 博客访问: 724473
  • 博文数量: 182
  • 博客积分: 2088
  • 博客等级: 大尉
  • 技术积分: 1698
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-16 15:09
个人简介

.

文章分类

全部博文(182)

文章存档

2016年(1)

2015年(18)

2014年(14)

2013年(20)

2012年(129)

分类: Android平台

2015-05-12 18:29:24

转载地址:《Android系统学习》第六章:Android4.1 HAL段错误问题—linker与prelink

1./hardware/libhardware/hardware.c

  1. static int load(const char *id,const char *path,  
  2.  const struct hw_module_t **pHmi){  
  3.   int status;  
  4.   void *handle;  
  5.   struct hw_module_t *hmi;  
  6.   handle = dlopen(path, RTLD_NOW);  
  7.   if (handle == NULL) {  
  8.     char const *err_str = dlerror();  
  9.     LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");  
  10.     status = -EINVAL;  
  11.     goto done;  
  12.   }  
  13.   const char *sym = HAL_MODULE_INFO_SYM_AS_STR;  
  14.   hmi = (struct hw_module_t *)dlsym(handle, sym);   
  15.   //sym为HMI;从handle指针所指向的库中找如下宏定义  
  16.   //hardware/libhardware/include/hardware.h  
  17.   //#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"     
  18.   //#define HAL_MODULE_INFO_SYM         HMI  
  19.   if (hmi == NULL) {   
  20.     LOGE("load: couldn't find symbol %s", sym);   
  21.     status = -EINVAL; goto done;   
  22.   }   
  23.   if (strcmp(id, hmi->id) != 0) {   
  24.     LOGE("load: id=%s != hmi->id=%s", id, hmi->id);   
  25.     status = -EINVAL; goto done;   
  26.   }   
  27.   hmi->dso = handle;   
  28.   status = 0;   
  29. done: if (status != 0) {   
  30.         hmi = NULL;   
  31.         if (handle != NULL) {   
  32.           dlclose(handle);   
  33.           handle = NULL;   
  34.         }   
  35.       }   
  36.       else {   
  37.         LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p", id, path, *pHmi, handle);   
  38.       }   
  39.       *pHmi = hmi;   
  40.       return status;  
  41.       }  
  42. }  


2./sdk/emulator/sensors/Sensors_qemu.c

  1. struct sensors_module_t HAL_MODULE_INFO_SYM = {    
  2.   //注意:Android4.0里边是这样定义的:const struct sensors_module_t  
  3.     .common = {  
  4.         .tag = HARDWARE_MODULE_TAG,  
  5.         .version_major = 1,  
  6.         .version_minor = 0,  
  7.         .id = SENSORS_HARDWARE_MODULE_ID,  
  8.         .name = "Goldfish SENSORS Module",  
  9.         .author = "The Android Open Source Project",  
  10.         .methods = &sensors_module_methods,  
  11.     },  
  12.     .get_sensors_list = sensors__get_sensors_list  
  13. };  

3.现象:


  Android4.0 上述2中HAL代码无论在4.0还是4.1环境下编译后,放置Android4.1开发板运行;结果都会在上述1中“hmi->dso = handle”处挂掉,即出现SEGV_ACCERR段错误。

4.原因:

  Android4.1修改了/bionic/linker(增加了relro支持,这部分会被编译成/system/bin/linker),而该部分即为动态链接库加载时所用dlopen、dlsym等函数代码;修改后的linker会把dlsym时对应的const变量地址映射为只读(类似mprotect函数:mprotect设置内存访问权限)。所以,当你调用hmi->dso(const型) =handle给只读地址赋值时,程序就会段错误退出。

5. 解决办法(Android4.1下)

  要么换掉linker(/system/bin/linker);或者prelink处理,这部分我还没有研究。

  要么用最简单的办法:把上述2中的const去掉。

下面通过一个简单的例子看下,说明在没有linker即动态库文件加载时、上述问题并不存在:test.c

  1. #include   
  2.   
  3. struct my_test{  
  4.   int a;  
  5.   void *b;  
  6. };  
  7.   
  8. int main(){  
  9.   char c[50];  
  10.   printf("c addr is %lx\n",c);  
  11.   const struct my_test std1 = {2,NULL};  
  12.   printf("std1.a = %d\n",std1.a);  
  13.   printf("std1.b is %lx\n",std1.b);  
  14.   struct my_test *hmi;  
  15.   hmi = &std1;  
  16.   printf("&std1 is %lx\n",&std1);  
  17.   printf("hmi is %lx\n",hmi);  
  18.   hmi->b = c;  
  19.   hmi->a = 3;  
  20.   printf("std1.a = %d\n",std1.a);  
  21.   printf("hmi->b is %lx\n",hmi->b);  
  22.   printf("std1.b is %lx\n",std1.b);  
  23.   return 0;  
  24. }  

编译:gcc -o test test.c


执行:./test

结果:


  1. c addr is bfa50aba  
  2. std1.a = 2  
  3. std1.b is 0  
  4. &std1 is bfa50aac  
  5. hmi is bfa50aac  
  6. std1.a = 3  
  7. hmi->b is bfa50aba  
  8. std1.b is bfa50aba  

====================================================================================================================================

顺便说下const,要修改const修饰变量的值、可以指针强转来实现(这在上边两处都有体现):

test1.c


  1. #include   
  2.   
  3. int main(){  
  4.   const int a = 3;  
  5.   printf("a is %d\n",a);  
  6.   //a = 2;  //这句放通则编译不过  
  7.   int *b;  
  8.   b = &a;  
  9.   *b = 2;  
  10.   printf("a is %d\n",a);  
  11.   return 0;  
  12. }  

编译:gcc -o test1 test1.c


结果:


  1. a is 3  
  2. a is 2  

说明:

  上述所有在g++编译器是编译不过的,因为C++语言强制要求指向const对象的指针也必须具有const特性!

  C++没有给const常量分配内存,意思就是它只是一个编译期间的常量(但声明一个extern const会分配内存);

  而C分配了(因此姑且叫变量),C可以通过指针“消除”(专业术语叫指针强转)const内存的“只读”属性;以上都是编译阶段的术语。原理是const只是编译阶段起作用(即编译阶段假定了这段内存是只读的),只要编译通过、程序运行过程中是可以修改的;在实际运行阶段const修饰变量在的内存区域并不是只读内存。而linker连接器却可以在运行时指定真正的只读内存。

  总结一句话:C中const修饰的是只读变量,C++中const修饰才是真正意义上的常量!

  所以,Android4.1可能也是为了防止上述修改(因为hardware.c由gcc编译器编译)对linker部分做了改动,即在linker连接器加载动态库时对其中的const类型真正给予只读内存保护、以此来提高安全性。

阅读(2215) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~