@@ -300,6 +300,48 @@ rt_err_t dlmodule_load_shared_object(struct rt_dlmodule* module, void *module_pt
300300 return RT_EOK ;
301301}
302302
303+ /**
304+ * @brief Compute the size of the common block of a symbol table, and
305+ * optionally the offset of one specific SHN_COMMON symbol inside it.
306+ *
307+ * SHN_COMMON symbols are tentative definitions of uninitialized global
308+ * variables. The loader must allocate storage for them just like a static
309+ * linker does: every common symbol is aligned to its st_value alignment
310+ * requirement and occupies st_size bytes, packed one after another.
311+ *
312+ * @param symtab pointer to the symbol table
313+ * @param nsym number of symbols in the table
314+ * @param target symbol whose offset is wanted, or RT_NULL to get the total
315+ * size of the common block
316+ * @return offset of target in the common block, or the total size of the
317+ * block when target is RT_NULL
318+ */
319+ static rt_ubase_t dlmodule_common_block (Elf_Sym * symtab , rt_ubase_t nsym ,
320+ Elf_Sym * target )
321+ {
322+ rt_ubase_t i , offset = 0 ;
323+
324+ for (i = 0 ; i < nsym ; i ++ )
325+ {
326+ if (symtab [i ].st_shndx != SHN_COMMON )
327+ {
328+ continue ;
329+ }
330+
331+ /* st_value of a SHN_COMMON symbol holds its alignment requirement */
332+ offset = RT_ALIGN (offset , symtab [i ].st_value > 1 ? symtab [i ].st_value : 1 );
333+
334+ if (target == & symtab [i ])
335+ {
336+ return offset ;
337+ }
338+
339+ offset += symtab [i ].st_size ;
340+ }
341+
342+ return offset ;
343+ }
344+
303345/**
304346 * @brief Load a relocatable file into memory.
305347 *
@@ -319,8 +361,9 @@ rt_err_t dlmodule_load_shared_object(struct rt_dlmodule* module, void *module_pt
319361 */
320362rt_err_t dlmodule_load_relocated_object (struct rt_dlmodule * module , void * module_ptr )
321363{
322- rt_ubase_t index , rodata_addr = 0 , bss_addr = 0 , data_addr = 0 ;
323- rt_ubase_t module_addr = 0 , module_size = 0 ;
364+ rt_ubase_t index , common_addr = 0 ;
365+ rt_ubase_t module_addr = 0 , module_size = 0 , common_align = 1 ;
366+ rt_ubase_t * section_load_addr = RT_NULL ;
324367 rt_uint8_t * ptr , * strtab , * shstrab ;
325368
326369 /* get the ELF image size */
@@ -349,6 +392,38 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
349392 }
350393 }
351394
395+ /* account for common symbols (uninitialized global variables) */
396+ for (index = 0 ; index < elf_module -> e_shnum ; index ++ )
397+ {
398+ Elf_Sym * symtab ;
399+ rt_ubase_t i , nsym ;
400+
401+ if (shdr [index ].sh_type != SHT_SYMTAB )
402+ {
403+ continue ;
404+ }
405+
406+ symtab = (Elf_Sym * )((rt_uint8_t * )elf_module + shdr [index ].sh_offset );
407+ nsym = (rt_ubase_t )(shdr [index ].sh_size / sizeof (Elf_Sym ));
408+ for (i = 0 ; i < nsym ; i ++ )
409+ {
410+ if ((symtab [i ].st_shndx == SHN_COMMON ) &&
411+ (symtab [i ].st_value > common_align ))
412+ {
413+ common_align = symtab [i ].st_value ;
414+ }
415+ }
416+ module_size += RT_ALIGN (dlmodule_common_block (symtab , nsym , RT_NULL ),
417+ sizeof (rt_ubase_t ));
418+ }
419+
420+ /* The actual base is known only after allocation. Reserve the worst-case
421+ * padding needed to align the common block after all sections are loaded. */
422+ if (common_align > 1 )
423+ {
424+ module_size += common_align - 1 ;
425+ }
426+
352427 /* no text, data and bss on image */
353428 if (module_size == 0 ) return RT_NULL ;
354429
@@ -363,6 +438,14 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
363438 }
364439 module -> mem_size = module_size ;
365440
441+ section_load_addr = rt_calloc (elf_module -> e_shnum ,
442+ sizeof (* section_load_addr ));
443+ if (section_load_addr == RT_NULL )
444+ {
445+ LOG_E ("Module: allocate section address table failed.\n" );
446+ return - RT_ENOMEM ;
447+ }
448+
366449 /* zero all space */
367450 ptr = module -> mem_space ;
368451 rt_memset (ptr , 0 , module_size );
@@ -373,6 +456,7 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
373456 /* load text section */
374457 if (IS_PROG (shdr [index ]) && IS_AX (shdr [index ]))
375458 {
459+ section_load_addr [index ] = (rt_ubase_t )ptr ;
376460 rt_memcpy (ptr ,
377461 (rt_uint8_t * )elf_module + shdr [index ].sh_offset ,
378462 shdr [index ].sh_size );
@@ -383,36 +467,39 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
383467 /* load rodata section */
384468 if (IS_PROG (shdr [index ]) && IS_ALLOC (shdr [index ]))
385469 {
470+ section_load_addr [index ] = (rt_ubase_t )ptr ;
386471 rt_memcpy (ptr ,
387472 (rt_uint8_t * )elf_module + shdr [index ].sh_offset ,
388473 shdr [index ].sh_size );
389- rodata_addr = (rt_ubase_t )ptr ;
390- LOG_D ("load rodata 0x%x, size %d, rodata 0x%x" , ptr ,
391- shdr [index ].sh_size , * (rt_ubase_t * )rodata_addr );
474+ LOG_D ("load rodata 0x%x, size %d" , ptr , shdr [index ].sh_size );
392475 ptr += shdr [index ].sh_size ;
393476 }
394477
395478 /* load data section */
396479 if (IS_PROG (shdr [index ]) && IS_AW (shdr [index ]))
397480 {
481+ section_load_addr [index ] = (rt_ubase_t )ptr ;
398482 rt_memcpy (ptr ,
399483 (rt_uint8_t * )elf_module + shdr [index ].sh_offset ,
400484 shdr [index ].sh_size );
401- data_addr = (rt_ubase_t )ptr ;
402- LOG_D ("load data 0x%x, size %d, data 0x%x" , ptr ,
403- shdr [index ].sh_size , * (rt_ubase_t * )data_addr );
485+ LOG_D ("load data 0x%x, size %d" , ptr , shdr [index ].sh_size );
404486 ptr += shdr [index ].sh_size ;
405487 }
406488
407489 /* load bss section */
408490 if (IS_NOPROG (shdr [index ]) && IS_AW (shdr [index ]))
409491 {
492+ section_load_addr [index ] = (rt_ubase_t )ptr ;
410493 rt_memset (ptr , 0 , shdr [index ].sh_size );
411- bss_addr = (rt_ubase_t )ptr ;
412494 LOG_D ("load bss 0x%x, size %d" , ptr , shdr [index ].sh_size );
495+ ptr += shdr [index ].sh_size ;
413496 }
414497 }
415498
499+ /* the common block (uninitialized global variables) starts right after
500+ * the loaded sections; it was zeroed together with the module space */
501+ common_addr = RT_ALIGN ((rt_ubase_t )ptr , common_align );
502+
416503 /* set module entry */
417504 module -> entry_addr = (rt_dlmodule_entry_func_t )((rt_uint8_t * )module -> mem_space + elf_module -> e_entry - module_addr );
418505
@@ -431,6 +518,12 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
431518 continue ;
432519 #endif
433520
521+ /* Only relocate sections that were loaded into module memory. */
522+ if ((shdr [index ].sh_info >= elf_module -> e_shnum ) ||
523+ (section_load_addr [shdr [index ].sh_info ] == 0 ))
524+ {
525+ continue ;
526+ }
434527
435528 /* get relocate item */
436529 rel = (Elf_Rel * )((rt_uint8_t * )module_ptr + shdr [index ].sh_offset );
@@ -452,56 +545,52 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
452545 #elif (defined(__aarch64__ ) || defined(__x86_64__ ) || (__riscv_xlen == 64 ))
453546 Elf_Sym * sym = & symtab [ELF64_R_SYM (rel -> r_info )];
454547 #endif
548+ Elf_Rel target_rel = * rel ;
549+
550+ /* r_offset is relative to the section being relocated. Convert it
551+ * to the module-relative offset expected by the arch relocator. */
552+ target_rel .r_offset += section_load_addr [shdr [index ].sh_info ] -
553+ (rt_ubase_t )module -> mem_space ;
455554
456555 LOG_D ("relocate symbol: %s" , strtab + sym -> st_name );
457556
458557 if (sym -> st_shndx != STN_UNDEF )
459558 {
460559 Elf_Addr addr = 0 ;
461560
462- if ((ELF_ST_TYPE (sym -> st_info ) == STT_SECTION ) ||
463- (ELF_ST_TYPE (sym -> st_info ) == STT_OBJECT ))
561+ if (sym -> st_shndx == SHN_COMMON )
464562 {
465- if (rt_strncmp ((const char * )(shstrab +
466- shdr [sym -> st_shndx ].sh_name ), ELF_RODATA , 8 ) == 0 )
467- {
468- /* relocate rodata section */
469- LOG_D ("rodata" );
470- addr = (Elf_Addr )(rodata_addr + sym -> st_value );
471- }
472- else if (rt_strncmp ((const char * )
473- (shstrab + shdr [sym -> st_shndx ].sh_name ), ELF_BSS , 5 ) == 0 )
474- {
475- /* relocate bss section */
476- LOG_D ("bss" );
477- addr = (Elf_Addr )bss_addr + sym -> st_value ;
478- }
479- else if (rt_strncmp ((const char * )(shstrab + shdr [sym -> st_shndx ].sh_name ),
480- ELF_DATA , 6 ) == 0 )
481- {
482- /* relocate data section */
483- LOG_D ("data" );
484- addr = (Elf_Addr )data_addr + sym -> st_value ;
485- }
486-
487- if (addr != 0 ) dlmodule_relocate (module , rel , addr );
563+ /* SHN_COMMON is not a real section index. */
564+ LOG_D ("common symbol" );
565+ addr = (Elf_Addr )(common_addr + dlmodule_common_block (
566+ symtab ,
567+ (rt_ubase_t )(shdr [shdr [index ].sh_link ].sh_size / sizeof (Elf_Sym )),
568+ sym ));
488569 }
489- else if (ELF_ST_TYPE (sym -> st_info ) == STT_FUNC )
570+ else if (((ELF_ST_TYPE (sym -> st_info ) == STT_SECTION ) ||
571+ (ELF_ST_TYPE (sym -> st_info ) == STT_OBJECT ) ||
572+ (ELF_ST_TYPE (sym -> st_info ) == STT_FUNC )) &&
573+ (sym -> st_shndx < elf_module -> e_shnum ) &&
574+ (section_load_addr [sym -> st_shndx ] != 0 ))
490575 {
491- addr = (Elf_Addr )((rt_uint8_t * ) module -> mem_space - module_addr + sym -> st_value );
576+ /* For ET_REL, st_value is already the offset within the
577+ * symbol's section; sh_addr must not be subtracted. */
578+ addr = (Elf_Addr )(section_load_addr [sym -> st_shndx ] +
579+ sym -> st_value );
580+ }
492581
493- /* relocate function */
494- dlmodule_relocate (module , rel , addr );
582+ if (addr != 0 )
583+ {
584+ dlmodule_relocate (module , & target_rel , addr );
495585 }
496586 }
497587 else if (ELF_ST_TYPE (sym -> st_info ) == STT_FUNC )
498588 {
499589 /* relocate function */
500- dlmodule_relocate (module , rel ,
501- (Elf_Addr )((rt_uint8_t * )
502- module -> mem_space
503- - module_addr
504- + sym -> st_value ));
590+ dlmodule_relocate (module , & target_rel ,
591+ (Elf_Addr )((rt_uint8_t * )
592+ module -> mem_space -
593+ module_addr + sym -> st_value ));
505594 }
506595 else
507596 {
@@ -515,7 +604,7 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
515604 addr = dlmodule_symbol_find ((const char * )(strtab + sym -> st_name ));
516605 if (addr != (Elf_Addr )RT_NULL )
517606 {
518- dlmodule_relocate (module , rel , addr );
607+ dlmodule_relocate (module , & target_rel , addr );
519608 LOG_D ("symbol addr 0x%x" , addr );
520609 }
521610 else
@@ -525,13 +614,92 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
525614 else
526615 {
527616 addr = (Elf_Addr )((rt_uint8_t * ) module -> mem_space - module_addr + sym -> st_value );
528- dlmodule_relocate (module , rel , addr );
617+ dlmodule_relocate (module , & target_rel , addr );
529618 }
530619 }
531620
532621 rel ++ ;
533622 }
534623 }
535624
625+ /* construct the module symbol table from .symtab so that lookups such as
626+ * dlsym() can resolve the module's global functions */
627+ shstrab = (rt_uint8_t * )module_ptr + shdr [elf_module -> e_shstrndx ].sh_offset ;
628+ for (index = 0 ; index < elf_module -> e_shnum ; index ++ )
629+ {
630+ if ((shdr [index ].sh_type == SHT_SYMTAB ) &&
631+ (rt_strcmp ((const char * )(shstrab + shdr [index ].sh_name ), ELF_SYMTAB ) == 0 ))
632+ {
633+ break ;
634+ }
635+ }
636+
637+ if (index != elf_module -> e_shnum )
638+ {
639+ Elf_Sym * symtab ;
640+ rt_ubase_t i , count = 0 ;
641+
642+ symtab = (Elf_Sym * )((rt_uint8_t * )module_ptr + shdr [index ].sh_offset );
643+ strtab = (rt_uint8_t * )module_ptr + shdr [shdr [index ].sh_link ].sh_offset ;
644+
645+ for (i = 0 ; i < shdr [index ].sh_size / sizeof (Elf_Sym ); i ++ )
646+ {
647+ if ((ELF_ST_BIND (symtab [i ].st_info ) == STB_GLOBAL ) &&
648+ (ELF_ST_TYPE (symtab [i ].st_info ) == STT_FUNC ) &&
649+ (symtab [i ].st_shndx != SHN_UNDEF ) &&
650+ (symtab [i ].st_shndx < elf_module -> e_shnum ) &&
651+ (section_load_addr [symtab [i ].st_shndx ] != 0 ))
652+ {
653+ count ++ ;
654+ }
655+ }
656+
657+ module -> nsym = 0 ;
658+ if (count > 0 )
659+ {
660+ module -> symtab = (struct rt_module_symtab * )rt_malloc (
661+ count * sizeof (struct rt_module_symtab ));
662+ if (module -> symtab == RT_NULL )
663+ {
664+ LOG_E ("Module: allocate symbol table failed.\n" );
665+ rt_free (section_load_addr );
666+ return - RT_ENOMEM ;
667+ }
668+
669+ for (i = 0 ; i < shdr [index ].sh_size / sizeof (Elf_Sym ); i ++ )
670+ {
671+ rt_size_t length ;
672+
673+ if ((ELF_ST_BIND (symtab [i ].st_info ) != STB_GLOBAL ) ||
674+ (ELF_ST_TYPE (symtab [i ].st_info ) != STT_FUNC ) ||
675+ (symtab [i ].st_shndx == SHN_UNDEF ) ||
676+ (symtab [i ].st_shndx >= elf_module -> e_shnum ) ||
677+ (section_load_addr [symtab [i ].st_shndx ] == 0 ))
678+ {
679+ continue ;
680+ }
681+
682+ length = rt_strlen ((const char * )(strtab + symtab [i ].st_name )) + 1 ;
683+
684+ module -> symtab [module -> nsym ].addr =
685+ (void * )(section_load_addr [symtab [i ].st_shndx ] +
686+ symtab [i ].st_value );
687+ module -> symtab [module -> nsym ].name = rt_malloc (length );
688+ if (module -> symtab [module -> nsym ].name == RT_NULL )
689+ {
690+ LOG_E ("Module: allocate symbol name failed.\n" );
691+ rt_free (section_load_addr );
692+ return - RT_ENOMEM ;
693+ }
694+ rt_memset ((void * )module -> symtab [module -> nsym ].name , 0 , length );
695+ rt_memcpy ((void * )module -> symtab [module -> nsym ].name ,
696+ strtab + symtab [i ].st_name ,
697+ length );
698+ module -> nsym ++ ;
699+ }
700+ }
701+ }
702+
703+ rt_free (section_load_addr );
536704 return RT_EOK ;
537705}
0 commit comments