3939# define MAP_ANONYMOUS MAP_ANON
4040#endif
4141#if defined(MAP_ALIGNED_SUPER )
42+ # include <sys/types.h>
43+ # include <sys/sysctl.h>
44+ # include <sys/user.h>
4245# define MAP_HUGETLB MAP_ALIGNED_SUPER
4346#endif
4447
45- #if defined(__linux__ ) && (defined(__x86_64__ ) || defined (__aarch64__ ))
48+ #if ( defined(__linux__ ) || defined( __FreeBSD__ ) ) && (defined(__x86_64__ ) || defined (__aarch64__ ))
4649static void * find_prefered_mmap_base (size_t requested_size )
4750{
48- FILE * f ;
4951 size_t huge_page_size = 2 * 1024 * 1024 ;
5052 uintptr_t last_free_addr = 0 ;
5153 uintptr_t last_candidate = (uintptr_t )MAP_FAILED ;
5254 uintptr_t start , end , text_start = 0 ;
55+ #if defined(__linux__ )
56+ FILE * f ;
5357 char buffer [MAXPATHLEN ];
5458
5559 f = fopen ("/proc/self/maps" , "r" );
@@ -89,6 +93,59 @@ static void *find_prefered_mmap_base(size_t requested_size)
8993
9094 }
9195 fclose (f );
96+ #elif defined(__FreeBSD__ )
97+ size_t s = 0 ;
98+ int mib [4 ] = {CTL_KERN , KERN_PROC , KERN_PROC_VMMAP , getpid ()};
99+ if (sysctl (mib , 4 , NULL , & s , NULL , 0 ) == 0 ) {
100+ s = s * 4 / 3 ;
101+ void * addr = mmap (NULL , s , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANON , -1 , 0 );
102+ if (addr != MAP_FAILED ) {
103+ if (sysctl (mib , 4 , addr , & s , NULL , 0 ) == 0 ) {
104+ start = (uintptr_t )addr ;
105+ end = start + s ;
106+ while (start < end ) {
107+ struct kinfo_vmentry * entry = (struct kinfo_vmentry * )start ;
108+ size_t sz = entry -> kve_structsize ;
109+ if (sz == 0 ) {
110+ break ;
111+ }
112+ uintptr_t e_start = entry -> kve_start ;
113+ uintptr_t e_end = entry -> kve_end ;
114+ if ((uintptr_t )execute_ex >= e_start ) {
115+ /* the current segment lays before PHP .text segment or PHP .text segment itself */
116+ if (last_free_addr + requested_size <= e_start ) {
117+ last_candidate = last_free_addr ;
118+ }
119+ if ((uintptr_t )execute_ex < e_end ) {
120+ /* the current segment is PHP .text segment itself */
121+ if (last_candidate != (uintptr_t )MAP_FAILED ) {
122+ if (e_end - last_candidate < UINT32_MAX ) {
123+ /* we have found a big enough hole before the text segment */
124+ break ;
125+ }
126+ last_candidate = (uintptr_t )MAP_FAILED ;
127+ }
128+ text_start = e_start ;
129+ }
130+ } else {
131+ /* the current segment lays after PHP .text segment */
132+ if (last_free_addr + requested_size - text_start > UINT32_MAX ) {
133+ /* the current segment and the following segments lay too far from PHP .text segment */
134+ break ;
135+ }
136+ if (last_free_addr + requested_size <= e_start ) {
137+ last_candidate = last_free_addr ;
138+ break ;
139+ }
140+ }
141+ last_free_addr = ZEND_MM_ALIGNED_SIZE_EX (e_end , huge_page_size );
142+ start += sz ;
143+ }
144+ }
145+ munmap (addr , s );
146+ }
147+ }
148+ #endif
92149
93150 return (void * )last_candidate ;
94151}
@@ -109,7 +166,7 @@ static int create_segments(size_t requested_size, zend_shared_segment ***shared_
109166#ifdef PROT_MAX
110167 flags |= PROT_MAX (PROT_READ | PROT_WRITE | PROT_EXEC );
111168#endif
112- #if defined(__linux__ ) && (defined(__x86_64__ ) || defined (__aarch64__ ))
169+ #if ( defined(__linux__ ) || defined( __FreeBSD__ ) ) && (defined(__x86_64__ ) || defined (__aarch64__ ))
113170 void * hint = find_prefered_mmap_base (requested_size );
114171 if (hint != MAP_FAILED ) {
115172# ifdef MAP_HUGETLB
0 commit comments