@@ -594,31 +594,19 @@ struct elf_mcount_loc {
594
594
uint64_t stop_mcount_loc ;
595
595
};
596
596
597
- /* Sort the relocations not the address itself */
598
- static void * sort_relocs ( Elf_Ehdr * ehdr , uint64_t start_loc , uint64_t size )
597
+ /* Fill the array with the content of the relocs */
598
+ static int fill_relocs ( void * ptr , uint64_t size , Elf_Ehdr * ehdr , uint64_t start_loc )
599
599
{
600
600
Elf_Shdr * shdr_start ;
601
601
Elf_Rela * rel ;
602
602
unsigned int shnum ;
603
- unsigned int count ;
603
+ unsigned int count = 0 ;
604
604
int shentsize ;
605
- void * vals ;
606
- void * ptr ;
607
-
608
- compare_values = long_size == 4 ? compare_values_32 : compare_values_64 ;
605
+ void * array_end = ptr + size ;
609
606
610
607
shdr_start = (Elf_Shdr * )((char * )ehdr + ehdr_shoff (ehdr ));
611
608
shentsize = ehdr_shentsize (ehdr );
612
609
613
- vals = malloc (long_size * size );
614
- if (!vals ) {
615
- snprintf (m_err , ERRSTR_MAXSZ , "Failed to allocate sort array" );
616
- pthread_exit (m_err );
617
- return NULL ;
618
- }
619
-
620
- ptr = vals ;
621
-
622
610
shnum = ehdr_shnum (ehdr );
623
611
if (shnum == SHN_UNDEF )
624
612
shnum = shdr_size (shdr_start );
@@ -637,36 +625,47 @@ static void *sort_relocs(Elf_Ehdr *ehdr, uint64_t start_loc, uint64_t size)
637
625
uint64_t offset = rela_offset (rel );
638
626
639
627
if (offset >= start_loc && offset < start_loc + size ) {
640
- if (ptr + long_size > vals + size ) {
641
- free (vals );
628
+ if (ptr + long_size > array_end ) {
642
629
snprintf (m_err , ERRSTR_MAXSZ ,
643
630
"Too many relocations" );
644
- pthread_exit (m_err );
645
- return NULL ;
631
+ return -1 ;
646
632
}
647
633
648
634
/* Make sure this has the correct type */
649
635
if (rela_info (rel ) != rela_type ) {
650
- free (vals );
651
636
snprintf (m_err , ERRSTR_MAXSZ ,
652
637
"rela has type %lx but expected %lx\n" ,
653
638
(long )rela_info (rel ), rela_type );
654
- pthread_exit (m_err );
655
- return NULL ;
639
+ return -1 ;
656
640
}
657
641
658
642
if (long_size == 4 )
659
643
* (uint32_t * )ptr = rela_addend (rel );
660
644
else
661
645
* (uint64_t * )ptr = rela_addend (rel );
662
646
ptr += long_size ;
647
+ count ++ ;
663
648
}
664
649
}
665
650
}
666
- count = ptr - vals ;
667
- qsort (vals , count / long_size , long_size , compare_values );
651
+ return count ;
652
+ }
653
+
654
+ /* Put the sorted vals back into the relocation elements */
655
+ static void replace_relocs (void * ptr , uint64_t size , Elf_Ehdr * ehdr , uint64_t start_loc )
656
+ {
657
+ Elf_Shdr * shdr_start ;
658
+ Elf_Rela * rel ;
659
+ unsigned int shnum ;
660
+ int shentsize ;
661
+
662
+ shdr_start = (Elf_Shdr * )((char * )ehdr + ehdr_shoff (ehdr ));
663
+ shentsize = ehdr_shentsize (ehdr );
664
+
665
+ shnum = ehdr_shnum (ehdr );
666
+ if (shnum == SHN_UNDEF )
667
+ shnum = shdr_size (shdr_start );
668
668
669
- ptr = vals ;
670
669
for (int i = 0 ; i < shnum ; i ++ ) {
671
670
Elf_Shdr * shdr = get_index (shdr_start , shentsize , i );
672
671
void * end ;
@@ -689,8 +688,32 @@ static void *sort_relocs(Elf_Ehdr *ehdr, uint64_t start_loc, uint64_t size)
689
688
}
690
689
}
691
690
}
692
- free (vals );
693
- return NULL ;
691
+ }
692
+
693
+ static int fill_addrs (void * ptr , uint64_t size , void * addrs )
694
+ {
695
+ void * end = ptr + size ;
696
+ int count = 0 ;
697
+
698
+ for (; ptr < end ; ptr += long_size , addrs += long_size , count ++ ) {
699
+ if (long_size == 4 )
700
+ * (uint32_t * )ptr = r (addrs );
701
+ else
702
+ * (uint64_t * )ptr = r8 (addrs );
703
+ }
704
+ return count ;
705
+ }
706
+
707
+ static void replace_addrs (void * ptr , uint64_t size , void * addrs )
708
+ {
709
+ void * end = ptr + size ;
710
+
711
+ for (; ptr < end ; ptr += long_size , addrs += long_size ) {
712
+ if (long_size == 4 )
713
+ w (* (uint32_t * )ptr , addrs );
714
+ else
715
+ w8 (* (uint64_t * )ptr , addrs );
716
+ }
694
717
}
695
718
696
719
/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
@@ -699,14 +722,49 @@ static void *sort_mcount_loc(void *arg)
699
722
struct elf_mcount_loc * emloc = (struct elf_mcount_loc * )arg ;
700
723
uint64_t offset = emloc -> start_mcount_loc - shdr_addr (emloc -> init_data_sec )
701
724
+ shdr_offset (emloc -> init_data_sec );
702
- uint64_t count = emloc -> stop_mcount_loc - emloc -> start_mcount_loc ;
725
+ uint64_t size = emloc -> stop_mcount_loc - emloc -> start_mcount_loc ;
703
726
unsigned char * start_loc = (void * )emloc -> ehdr + offset ;
727
+ Elf_Ehdr * ehdr = emloc -> ehdr ;
728
+ void * e_msg = NULL ;
729
+ void * vals ;
730
+ int count ;
731
+
732
+ vals = malloc (long_size * size );
733
+ if (!vals ) {
734
+ snprintf (m_err , ERRSTR_MAXSZ , "Failed to allocate sort array" );
735
+ pthread_exit (m_err );
736
+ }
704
737
705
738
if (sort_reloc )
706
- return sort_relocs (emloc -> ehdr , emloc -> start_mcount_loc , count );
739
+ count = fill_relocs (vals , size , ehdr , emloc -> start_mcount_loc );
740
+ else
741
+ count = fill_addrs (vals , size , start_loc );
742
+
743
+ if (count < 0 ) {
744
+ e_msg = m_err ;
745
+ goto out ;
746
+ }
747
+
748
+ if (count != size / long_size ) {
749
+ snprintf (m_err , ERRSTR_MAXSZ , "Expected %u mcount elements but found %u\n" ,
750
+ (int )(size / long_size ), count );
751
+ e_msg = m_err ;
752
+ goto out ;
753
+ }
754
+
755
+ compare_values = long_size == 4 ? compare_values_32 : compare_values_64 ;
756
+
757
+ qsort (vals , count , long_size , compare_values );
758
+
759
+ if (sort_reloc )
760
+ replace_relocs (vals , size , ehdr , emloc -> start_mcount_loc );
761
+ else
762
+ replace_addrs (vals , size , start_loc );
763
+
764
+ out :
765
+ free (vals );
707
766
708
- qsort (start_loc , count /long_size , long_size , compare_extable );
709
- return NULL ;
767
+ pthread_exit (e_msg );
710
768
}
711
769
712
770
/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
0 commit comments