@@ -2974,10 +2974,22 @@ static void accel_globals_dtor(zend_accel_globals *accel_globals)
2974
2974
# include <sys/user.h>
2975
2975
# define MAP_HUGETLB MAP_ALIGNED_SUPER
2976
2976
# endif
2977
+ # if __has_include (< link .h > )
2978
+ # include <link.h>
2979
+ # endif
2980
+ # if __has_include (< elf .h > )
2981
+ # include <elf.h>
2982
+ # endif
2977
2983
# endif
2978
2984
2979
- # if defined(MAP_HUGETLB ) || defined(MADV_HUGEPAGE )
2980
- static zend_result accel_remap_huge_pages (void * start , size_t size , size_t real_size , const char * name , size_t offset )
2985
+ # define ZEND_HUGE_PAGE_SIZE (2UL * 1024 * 1024)
2986
+
2987
+ # if (defined(__linux__ ) || defined(__FreeBSD__ )) && (defined(MAP_HUGETLB ) || defined(MADV_HUGEPAGE )) && defined(HAVE_ATTRIBUTE_ALIGNED ) && defined(HAVE_ATTRIBUTE_SECTION ) && __has_include (< link .h > ) && __has_include (< elf .h > )
2988
+ static zend_result
2989
+ __attribute__((section (".remap_stub" )))
2990
+ __attribute__((aligned (ZEND_HUGE_PAGE_SIZE )))
2991
+ zend_never_inline
2992
+ accel_remap_huge_pages (void * start , size_t size , size_t real_size )
2981
2993
{
2982
2994
void * ret = MAP_FAILED ;
2983
2995
void * mem ;
@@ -3030,94 +3042,113 @@ static zend_result accel_remap_huge_pages(void *start, size_t size, size_t real_
3030
3042
3031
3043
// Given the MAP_FIXED flag the address can never diverge
3032
3044
ZEND_ASSERT (ret == start );
3033
- zend_mmap_set_name ( start , size , "zend_huge_code_pages" );
3045
+
3034
3046
memcpy (start , mem , real_size );
3035
3047
mprotect (start , size , PROT_READ | PROT_EXEC );
3048
+ zend_mmap_set_name (start , size , "zend_huge_code_pages" );
3036
3049
3037
3050
munmap (mem , size );
3038
3051
3039
3052
return SUCCESS ;
3040
3053
}
3041
3054
3042
- static void accel_move_code_to_huge_pages (void )
3043
- {
3055
+ static int accel_dl_iterate_phdr_callback (struct dl_phdr_info * info , size_t size , void * data ) {
3056
+ if (info -> dlpi_name == NULL || strcmp (info -> dlpi_name , "" ) == 0 ) {
3057
+ * ((uintptr_t * )data ) = info -> dlpi_addr ;
3058
+ return 1 ;
3059
+ }
3060
+ return 0 ;
3061
+ }
3062
+
3063
+ static zend_result accel_find_program_section (ElfW (Shdr ) * section ) {
3064
+
3065
+ uintptr_t base_addr ;
3066
+ if (dl_iterate_phdr (accel_dl_iterate_phdr_callback , & base_addr ) != 1 ) {
3067
+ zend_error (E_WARNING , ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages: executable base address not found" );
3068
+ return FAILURE ;
3069
+ }
3070
+
3044
3071
#if defined(__linux__ )
3045
- FILE * f ;
3046
- long unsigned int huge_page_size = 2 * 1024 * 1024 ;
3047
-
3048
- f = fopen ("/proc/self/maps" , "r" );
3049
- if (f ) {
3050
- long unsigned int start , end , offset , inode ;
3051
- char perm [5 ], dev [10 ], name [MAXPATHLEN ];
3052
- int ret ;
3053
- extern char * __progname ;
3054
- char buffer [MAXPATHLEN ];
3055
-
3056
- while (fgets (buffer , MAXPATHLEN , f )) {
3057
- ret = sscanf (buffer , "%lx-%lx %4s %lx %9s %lu %s\n" , & start , & end , perm , & offset , dev , & inode , name );
3058
- if (ret >= 6 ) {
3059
- /* try to find the php text segment and map it into huge pages
3060
- Lines without 'name' are going to be skipped */
3061
- if (ret > 6 && perm [0 ] == 'r' && perm [1 ] == '-' && perm [2 ] == 'x' && name [0 ] == '/' \
3062
- && strstr (name , __progname )) {
3063
- long unsigned int seg_start = ZEND_MM_ALIGNED_SIZE_EX (start , huge_page_size );
3064
- long unsigned int seg_end = (end & ~(huge_page_size - 1L ));
3065
- long unsigned int real_end ;
3066
-
3067
- ret = fscanf (f , "%lx-" , & start );
3068
- if (ret == 1 && start == seg_end + huge_page_size ) {
3069
- real_end = end ;
3070
- seg_end = start ;
3071
- } else {
3072
- real_end = seg_end ;
3073
- }
3072
+ FILE * f = fopen ("/proc/self/exe" , "r" );
3073
+ #elif defined(__FreeBSD__ )
3074
+ char path [4096 ];
3075
+ int mib [4 ];
3076
+ size_t len = sizeof (path );
3074
3077
3075
- if (seg_end > seg_start ) {
3076
- zend_accel_error (ACCEL_LOG_DEBUG , "remap to huge page %lx-%lx %s \n" , seg_start , seg_end , name );
3077
- accel_remap_huge_pages ((void * )seg_start , seg_end - seg_start , real_end - seg_start , name , offset + seg_start - start );
3078
- }
3079
- break ;
3080
- }
3081
- }
3082
- }
3078
+ mib [0 ] = CTL_KERN ;
3079
+ mib [1 ] = KERN_PROC ;
3080
+ mib [2 ] = KERN_PROC_PATHNAME ;
3081
+ mib [3 ] = -1 ; /* Current process */
3082
+
3083
+ if (sysctl (mib , 4 , path , & len , NULL , 0 ) == -1 ) {
3084
+ zend_error (E_WARNING , ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages: sysctl(KERN_PROC_PATHNAME) failed: %s (%d)" ,
3085
+ strerror (errno ), errno );
3086
+ return FAILURE ;
3087
+ }
3088
+
3089
+ FILE * f = fopen (path , "r" );
3090
+ #endif
3091
+ if (!f ) {
3092
+ zend_error (E_WARNING , ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages: fopen(/proc/self/exe) failed: %s (%d)" ,
3093
+ strerror (errno ), errno );
3094
+ return FAILURE ;
3095
+ }
3096
+
3097
+ /* Read ELF header */
3098
+ ElfW (Ehdr ) ehdr ;
3099
+ if (!fread (& ehdr , sizeof (ehdr ), 1 , f )) {
3100
+ zend_error (E_WARNING , ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages: fread() failed: %s (%d)" ,
3101
+ strerror (errno ), errno );
3083
3102
fclose (f );
3103
+ return FAILURE ;
3084
3104
}
3085
- #elif defined(__FreeBSD__ )
3086
- size_t s = 0 ;
3087
- int mib [4 ] = {CTL_KERN , KERN_PROC , KERN_PROC_VMMAP , getpid ()};
3088
- long unsigned int huge_page_size = 2 * 1024 * 1024 ;
3089
- if (sysctl (mib , 4 , NULL , & s , NULL , 0 ) == 0 ) {
3090
- s = s * 4 / 3 ;
3091
- void * addr = mmap (NULL , s , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANON , -1 , 0 );
3092
- if (addr != MAP_FAILED ) {
3093
- if (sysctl (mib , 4 , addr , & s , NULL , 0 ) == 0 ) {
3094
- uintptr_t start = (uintptr_t )addr ;
3095
- uintptr_t end = start + s ;
3096
- while (start < end ) {
3097
- struct kinfo_vmentry * entry = (struct kinfo_vmentry * )start ;
3098
- size_t sz = entry -> kve_structsize ;
3099
- if (sz == 0 ) {
3100
- break ;
3101
- }
3102
- int permflags = entry -> kve_protection ;
3103
- if ((permflags & KVME_PROT_READ ) && !(permflags & KVME_PROT_WRITE ) &&
3104
- (permflags & KVME_PROT_EXEC ) && entry -> kve_path [0 ] != '\0' ) {
3105
- long unsigned int seg_start = ZEND_MM_ALIGNED_SIZE_EX (start , huge_page_size );
3106
- long unsigned int seg_end = (end & ~(huge_page_size - 1L ));
3107
- if (seg_end > seg_start ) {
3108
- zend_accel_error (ACCEL_LOG_DEBUG , "remap to huge page %lx-%lx %s \n" , seg_start , seg_end , entry -> kve_path );
3109
- accel_remap_huge_pages ((void * )seg_start , seg_end - seg_start , seg_end - seg_start , entry -> kve_path , entry -> kve_offset + seg_start - start );
3110
- // First relevant segment found is our binary
3111
- break ;
3112
- }
3113
- }
3114
- start += sz ;
3115
- }
3116
- }
3117
- munmap (addr , s );
3105
+
3106
+ /* Read section headers */
3107
+ ElfW (Shdr ) shdrs [ehdr .e_shnum ];
3108
+ if (fseek (f , ehdr .e_shoff , SEEK_SET ) != 0 ) {
3109
+ zend_error (E_WARNING , ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages: fseek() failed: %s (%d)" ,
3110
+ strerror (errno ), errno );
3111
+ fclose (f );
3112
+ return FAILURE ;
3113
+ }
3114
+ if (fread (shdrs , sizeof (shdrs [0 ]), ehdr .e_shnum , f ) != ehdr .e_shnum ) {
3115
+ zend_error (E_WARNING , ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages: fread() failed: %s (%d)" ,
3116
+ strerror (errno ), errno );
3117
+ fclose (f );
3118
+ return FAILURE ;
3119
+ }
3120
+
3121
+ fclose (f );
3122
+
3123
+ /* Find the program section */
3124
+ for (ElfW (Half ) idx = 0 ; idx < ehdr .e_shnum ; idx ++ ) {
3125
+ ElfW (Shdr ) * sh = & shdrs [idx ];
3126
+ uintptr_t start = (uintptr_t )sh -> sh_addr + base_addr ;
3127
+ zend_accel_error (ACCEL_LOG_DEBUG , "considering section %016" PRIxPTR "-%016" PRIxPTR " vs %016" PRIxPTR "\n" , start , start + sh -> sh_size , (uintptr_t )accel_find_program_section );
3128
+ if ((uintptr_t )accel_find_program_section >= start && (uintptr_t )accel_find_program_section < start + sh -> sh_size ) {
3129
+ * section = * sh ;
3130
+ section -> sh_addr = (ElfW (Addr ))start ;
3131
+ return SUCCESS ;
3118
3132
}
3119
3133
}
3120
- #endif
3134
+
3135
+ return FAILURE ;
3136
+ }
3137
+
3138
+ static void accel_move_code_to_huge_pages (void )
3139
+ {
3140
+ ElfW (Shdr ) section ;
3141
+ if (accel_find_program_section (& section ) == FAILURE ) {
3142
+ zend_error (E_WARNING , ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages: program section not found" );
3143
+ return ;
3144
+ }
3145
+
3146
+ uintptr_t start = ZEND_MM_ALIGNED_SIZE_EX (section .sh_addr , ZEND_HUGE_PAGE_SIZE );
3147
+ uintptr_t end = (section .sh_addr + section .sh_size ) & ~(ZEND_HUGE_PAGE_SIZE - 1UL );
3148
+ if (end > start ) {
3149
+ zend_accel_error (ACCEL_LOG_DEBUG , "remap to huge page %" PRIxPTR "-%" PRIxPTR "\n" , start , end );
3150
+ accel_remap_huge_pages ((void * )start , end - start , end - start );
3151
+ }
3121
3152
}
3122
3153
# else
3123
3154
static void accel_move_code_to_huge_pages (void )
0 commit comments