Skip to content

Commit 17aa81a

Browse files
authoredJun 30, 2022
Allocate JIT bufer close to PHP .text segment to allow using direct IP-relative calls and jumps (#8890)
This implementation is based on #8618 developed by Su Tao, Wang Xue, Chen Hu and Lizhen Lizhen.
1 parent 7ceae66 commit 17aa81a

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed
 

‎ext/opcache/shared_alloc_mmap.c

+72
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,67 @@
3333
#include <mach/vm_statistics.h>
3434
#endif
3535

36+
#include "zend_execute.h"
37+
3638
#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
3739
# define MAP_ANONYMOUS MAP_ANON
3840
#endif
3941
#if defined(MAP_ALIGNED_SUPER)
4042
# define MAP_HUGETLB MAP_ALIGNED_SUPER
4143
#endif
4244

45+
#if defined(__linux__) && (defined(__x86_64__) || defined (__aarch64__))
46+
static void *find_prefered_mmap_base(size_t requested_size)
47+
{
48+
FILE *f;
49+
size_t huge_page_size = 2 * 1024 * 1024;
50+
uintptr_t last_free_addr = 0;
51+
uintptr_t last_candidate = (uintptr_t)MAP_FAILED;
52+
uintptr_t start, end, text_start = 0;
53+
char buffer[MAXPATHLEN];
54+
55+
f = fopen("/proc/self/maps", "r");
56+
if (!f) {
57+
return MAP_FAILED;
58+
}
59+
60+
while (fgets(buffer, MAXPATHLEN, f) && sscanf(buffer, "%lx-%lx", &start, &end) == 2) {
61+
if ((uintptr_t)execute_ex >= start) {
62+
/* the current segment lays before PHP .text segment or PHP .text segment itself */
63+
if (last_free_addr + requested_size <= start) {
64+
last_candidate = last_free_addr;
65+
}
66+
if ((uintptr_t)execute_ex < end) {
67+
/* the current segment is PHP .text segment itself */
68+
if (last_candidate != (uintptr_t)MAP_FAILED) {
69+
if (end - last_candidate < UINT32_MAX) {
70+
/* we have found a big anough hole before the text segment */
71+
break;
72+
}
73+
last_candidate = (uintptr_t)MAP_FAILED;
74+
}
75+
text_start = start;
76+
}
77+
} else {
78+
/* the current segment lays after PHP .text segment */
79+
if (last_free_addr + requested_size - text_start > UINT32_MAX) {
80+
/* the current segment and the following segments lay too far from PHP .text segment */
81+
break;
82+
}
83+
if (last_free_addr + requested_size <= start) {
84+
last_candidate = last_free_addr;
85+
break;
86+
}
87+
}
88+
last_free_addr = ZEND_MM_ALIGNED_SIZE_EX(end, huge_page_size);
89+
90+
}
91+
fclose(f);
92+
93+
return (void*)last_candidate;
94+
}
95+
#endif
96+
4397
static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in)
4498
{
4599
zend_shared_segment *shared_segment;
@@ -55,6 +109,24 @@ static int create_segments(size_t requested_size, zend_shared_segment ***shared_
55109
#ifdef PROT_MAX
56110
flags |= PROT_MAX(PROT_READ | PROT_WRITE | PROT_EXEC);
57111
#endif
112+
#if defined(__linux__) && (defined(__x86_64__) || defined (__aarch64__))
113+
void *hint = find_prefered_mmap_base(requested_size);
114+
if (hint != MAP_FAILED) {
115+
# ifdef MAP_HUGETLB
116+
size_t huge_page_size = 2 * 1024 * 1024;
117+
if (requested_size >= huge_page_size && requested_size % huge_page_size == 0) {
118+
p = mmap(hint, requested_size, flags, MAP_SHARED|MAP_ANONYMOUS|MAP_HUGETLB|MAP_FIXED, -1, 0);
119+
if (p != MAP_FAILED) {
120+
goto success;
121+
}
122+
}
123+
#endif
124+
p = mmap(hint, requested_size, flags, MAP_SHARED|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
125+
if (p != MAP_FAILED) {
126+
goto success;
127+
}
128+
}
129+
#endif
58130
#ifdef MAP_HUGETLB
59131
size_t huge_page_size = 2 * 1024 * 1024;
60132

0 commit comments

Comments
 (0)