dl-vdso.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. #include <elf.h>
  2. //#include <stdio.h>
  3. #include <string.h>
  4. #include "sys/auxv.h"
  5. //#include <linux/time.h>
  6. //#include <time.h>
  7. #include "ldso.h"
  8. #include "generated/autoconf.h"
  9. #ifndef ELF_BITS
  10. # if ULONG_MAX > 0xffffffffUL
  11. # define ELF_BITS 64
  12. # else
  13. # define ELF_BITS 32
  14. # endif
  15. #endif
  16. #define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x
  17. #define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x)
  18. #define ELF(x) ELF_BITS_XFORM(ELF_BITS, x)
  19. #ifndef __VDSO_SUPPORT__
  20. void load_vdso( uint32_t sys_info_ehdr, char **envp ){
  21. #ifdef __SUPPORT_LD_DEBUG__
  22. if ( _dl_debug_vdso != 0 ){
  23. _dl_dprintf(2,"_dl_vdso support not enabled\n" );
  24. }
  25. #endif
  26. }
  27. #else
  28. //typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz);
  29. void* _dl__vdso_gettimeofday = 0;
  30. //typedef long (*clock_gettime_t)(int clk_id, struct timespec *tp);
  31. void* _dl__vdso_clock_gettime = 0;
  32. typedef struct{
  33. void* base_addr;
  34. ELF(Ehdr) *hdr;
  35. char* section_header_strtab;
  36. ELF(Sym) *dynsym_table;
  37. uint32_t dynsym_table_num;
  38. char* dynstr_table;
  39. uint16_t *versym_table;
  40. ELF(Verdef) *verdef_table;
  41. uint32_t verdef_num;
  42. ELF(Dyn) *dynamic_section;
  43. uint32_t dynamic_section_num;
  44. char* text_section;
  45. char* vers_strings[10];
  46. }elf_infos;
  47. /*
  48. * the raise() dummy function is needed because of divisons in this code
  49. * but keep it hidden in this object
  50. *
  51. * fixes link error with gcc 12 for arm
  52. */
  53. #pragma GCC visibility push(hidden)
  54. int raise(int sig){
  55. sig = sig;
  56. return 0;
  57. }
  58. #pragma GCC visibility pop
  59. static int vdso_check_elf_header( elf_infos* elf ){
  60. if ( 0 != _dl_memcmp( ELFMAG, elf->base_addr, 4 ) ){
  61. return 1;
  62. }
  63. if (elf->hdr->e_ident[EI_CLASS] != (ELF_BITS == 32 ? ELFCLASS32 : ELFCLASS64)) {
  64. _dl_dprintf(2,"vdso ELF Bits check error\n");
  65. return 1; /* Wrong ELF class -- check ELF_BITS */
  66. }
  67. return 0;
  68. }
  69. static ELF(Shdr) *vdso_get_sec_header( elf_infos* elf, int index ){
  70. return (ELF(Shdr) *) ( elf->base_addr + elf->hdr->e_shoff + ( index * sizeof( ELF(Shdr) )) );
  71. }
  72. void load_vdso( uint32_t sys_info_ehdr, char **envp ){
  73. elf_infos vdso_infos;
  74. if ( sys_info_ehdr == 0 ){
  75. #ifdef __SUPPORT_LD_DEBUG__
  76. if ( _dl_debug_vdso != 0 ){
  77. _dl_dprintf(2,"_dl_vdso no vdso provied by kernel\n" );
  78. }
  79. #endif
  80. return;
  81. }
  82. char* _dl_vdso_disable = _dl_getenv("VDSO_DISABLE", envp);
  83. if ( _dl_vdso_disable != 0 ){
  84. #ifdef __SUPPORT_LD_DEBUG__
  85. if ( _dl_debug_vdso != 0 ){
  86. _dl_dprintf(2,"_dl_vdso vdso support disabled\n" );
  87. }
  88. #endif
  89. return;
  90. }
  91. _dl_memset( &vdso_infos, 0 , sizeof( elf_infos ) );
  92. vdso_infos.base_addr = (void*)sys_info_ehdr;
  93. vdso_infos.hdr = (ELF(Ehdr)*)vdso_infos.base_addr;
  94. //printf("base : %p\n",vdso_infos.base_addr);
  95. if ( 0 != vdso_check_elf_header( &vdso_infos ) ){
  96. return;
  97. }
  98. ELF(Shdr) *sec_header = vdso_get_sec_header( &vdso_infos, vdso_infos.hdr->e_shstrndx);
  99. vdso_infos.section_header_strtab = ( vdso_infos.base_addr + sec_header->sh_offset );
  100. /*
  101. *
  102. * load ELF section headers
  103. *
  104. */
  105. for ( int i = 0 ; i < vdso_infos.hdr->e_shnum; i++ ){
  106. sec_header = vdso_get_sec_header( &vdso_infos, i );
  107. char* name = vdso_infos.section_header_strtab + sec_header->sh_name;
  108. if( ( SHT_DYNSYM == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".dynsym",name ) ) ){
  109. vdso_infos.dynsym_table = ( vdso_infos.base_addr + sec_header->sh_offset );
  110. vdso_infos.dynsym_table_num = sec_header->sh_size / sec_header->sh_entsize ;
  111. continue;
  112. }
  113. if( ( SHT_STRTAB == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".dynstr",name ) ) ){
  114. vdso_infos.dynstr_table = ( vdso_infos.base_addr + sec_header->sh_offset );
  115. continue;
  116. }
  117. if( ( SHT_GNU_versym == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".gnu.version",name ) ) ){
  118. vdso_infos.versym_table = ( vdso_infos.base_addr + sec_header->sh_offset );
  119. continue;
  120. }
  121. if( ( SHT_GNU_verdef == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".gnu.version_d",name ) ) ){
  122. vdso_infos.verdef_table = ( vdso_infos.base_addr + sec_header->sh_offset );
  123. continue;
  124. }
  125. if( ( SHT_DYNAMIC == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".dynamic",name ) ) ){
  126. vdso_infos.dynamic_section = ( vdso_infos.base_addr + sec_header->sh_offset );
  127. vdso_infos.dynamic_section_num = sec_header->sh_size / sec_header->sh_entsize ;
  128. continue;
  129. }
  130. if( ( SHT_PROGBITS == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".text",name ) ) ){
  131. vdso_infos.text_section = ( vdso_infos.base_addr + sec_header->sh_offset );
  132. continue;
  133. }
  134. }
  135. /*
  136. *
  137. * check section header -> dynamic table consistence
  138. *
  139. */
  140. for( int i = 0 ; i < vdso_infos.dynamic_section_num ; i++ ){
  141. ELF(Dyn) *dyn_sec = &vdso_infos.dynamic_section[i];
  142. if ( dyn_sec->d_tag == 0 ) continue;
  143. if ( dyn_sec->d_tag == DT_STRTAB ){
  144. char* strtab = ( vdso_infos.base_addr + dyn_sec->d_un.d_ptr );
  145. if ( strtab != (char*) vdso_infos.dynstr_table ){
  146. _dl_dprintf(2,"vdso elf DT_STRTAB check error\n");
  147. return;
  148. }
  149. continue;
  150. }
  151. if ( dyn_sec->d_tag == DT_SYMTAB ){
  152. char* symtab = ( vdso_infos.base_addr + dyn_sec->d_un.d_ptr );
  153. if ( symtab != (char*) vdso_infos.dynsym_table ){
  154. _dl_dprintf(2,"vdso elf DT_SYMTAB check error\n");
  155. return;
  156. }
  157. continue;
  158. }
  159. if ( dyn_sec->d_tag == DT_VERDEF ){
  160. Elf32_Verdef* verdef = ( vdso_infos.base_addr + dyn_sec->d_un.d_ptr );
  161. if ( verdef != (Elf32_Verdef*) vdso_infos.verdef_table ){
  162. _dl_dprintf(2,"vdso elf DT_VERDEF check error\n");
  163. return;
  164. }
  165. continue;
  166. }
  167. if ( dyn_sec->d_tag == DT_VERDEFNUM ){
  168. vdso_infos.verdef_num = dyn_sec->d_un.d_val;
  169. continue;
  170. }
  171. if ( dyn_sec->d_tag == DT_VERSYM ){
  172. uint16_t* versym = ( vdso_infos.base_addr + dyn_sec->d_un.d_ptr );
  173. if ( versym != vdso_infos.versym_table ){
  174. _dl_dprintf(2,"vdso elf DT_VERSYM check error\n");
  175. return;
  176. }
  177. continue;
  178. }
  179. }
  180. /*
  181. *
  182. * load vdso version definition strings
  183. *
  184. */
  185. ELF(Verdef) *vd = vdso_infos.verdef_table;
  186. for( int i = 0 ; i < vdso_infos.verdef_num ; i++ ){
  187. ELF(Verdaux) *vd_aux = (ELF(Verdaux) *)(( ( char*)vd ) + vd->vd_aux);
  188. vdso_infos.vers_strings[ vd->vd_ndx ] = vdso_infos.dynstr_table + vd_aux->vda_name;
  189. vd = ( ELF(Verdef) *)(( ( char*)vd ) + vd->vd_next);
  190. }
  191. /*
  192. *
  193. * load function from the vdso
  194. *
  195. */
  196. #ifdef __SUPPORT_LD_DEBUG__
  197. if ( _dl_debug_vdso != 0 ){
  198. int vdso_functions = 0;
  199. for( int i = 0 ; i < vdso_infos.dynsym_table_num ; i++ ){
  200. ELF(Sym)* sym = &vdso_infos.dynsym_table[i];
  201. if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
  202. continue;
  203. char* name = vdso_infos.dynstr_table + sym->st_name;
  204. if ( name[0] == 0 ){
  205. continue;
  206. }
  207. vdso_functions++;
  208. }
  209. _dl_dprintf(2,"_dl_vdso_load functions found : %d\n", vdso_functions );
  210. }
  211. #endif
  212. for( int i = 0 ; i < vdso_infos.dynsym_table_num ; i++ ){
  213. ELF(Sym)* sym = &vdso_infos.dynsym_table[i];
  214. if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
  215. continue;
  216. char* name = vdso_infos.dynstr_table + sym->st_name;
  217. char* vers = vdso_infos.vers_strings[ vdso_infos.versym_table[i] ];
  218. void* func_addr = (void*)( vdso_infos.base_addr + sym->st_value );
  219. // the function name is patched to zero if the kernel has no timer which is
  220. // usable for the function
  221. if ( name[0] == 0 ){
  222. #ifdef __SUPPORT_LD_DEBUG__
  223. if ( _dl_debug_vdso != 0 ){
  224. _dl_dprintf(2," function at address %p disabled by the kernel\n", sym->st_value );
  225. }
  226. #endif
  227. continue;
  228. }
  229. //printf(" %s@@%s\n", name , vers );
  230. //print_sym( sym );
  231. if ( 0 == _dl_strcmp( name, "__vdso_gettimeofday" ) ){
  232. _dl__vdso_gettimeofday = func_addr;
  233. #ifdef __SUPPORT_LD_DEBUG__
  234. if ( _dl_debug_vdso != 0 ){
  235. _dl_dprintf(2," %s at address %p\n", name, func_addr );
  236. }
  237. #endif
  238. continue;
  239. }
  240. if ( 0 == _dl_strcmp( name, "__vdso_clock_gettime" ) ){
  241. _dl__vdso_clock_gettime = func_addr;
  242. #ifdef __SUPPORT_LD_DEBUG__
  243. if ( _dl_debug_vdso != 0 ){
  244. _dl_dprintf(2," %s at address %p\n", name, func_addr );
  245. }
  246. #endif
  247. continue;
  248. }
  249. #ifdef __SUPPORT_LD_DEBUG__
  250. if ( _dl_debug_vdso != 0 ){
  251. _dl_dprintf(2," <%s> not handled\n", name );
  252. }
  253. #endif
  254. }
  255. }
  256. #endif // __VDSO_SUPPORT__