1 |
commit: 949b7a9801e59a2317cd68da53bdae344cd3e417 |
2 |
Author: Michael Haubenwallner <haubi <AT> gentoo <DOT> org> |
3 |
AuthorDate: Mon May 6 09:43:11 2019 +0000 |
4 |
Commit: Michael Haubenwallner <haubi <AT> gentoo <DOT> org> |
5 |
CommitDate: Tue May 7 08:05:53 2019 +0000 |
6 |
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=949b7a98 |
7 |
|
8 |
prefix/cygwin/profile.bashrc: add the Cygwin rebase hook |
9 |
|
10 |
The Cygwin fork can work more reliable when each DLL is loaded at it's |
11 |
preferred base address. The Cygwin rebase hook does maintain these |
12 |
preferred base addresses to be unique across all installed DLLs, using |
13 |
the app-admin/cygwin-rebase utility. |
14 |
|
15 |
Signed-off-by: Michael Haubenwallner <haubi <AT> gentoo.org> |
16 |
|
17 |
profiles/prefix/windows/cygwin/profile.bashrc | 187 +++++++++++++++++++++++++- |
18 |
1 file changed, 184 insertions(+), 3 deletions(-) |
19 |
|
20 |
diff --git a/profiles/prefix/windows/cygwin/profile.bashrc b/profiles/prefix/windows/cygwin/profile.bashrc |
21 |
index dd7e59f331a..aecfd9adb7c 100644 |
22 |
--- a/profiles/prefix/windows/cygwin/profile.bashrc |
23 |
+++ b/profiles/prefix/windows/cygwin/profile.bashrc |
24 |
@@ -25,13 +25,194 @@ post_pkg_prerm() { |
25 |
} |
26 |
|
27 |
cygwin-post_pkg_preinst() { |
28 |
- : |
29 |
+ cygwin-rebase-post_pkg_preinst |
30 |
} |
31 |
|
32 |
cygwin-pre_pkg_postinst() { |
33 |
- : |
34 |
+ cygwin-rebase-pre_pkg_postinst |
35 |
} |
36 |
|
37 |
cygwin-post_pkg_prerm() { |
38 |
- : |
39 |
+ cygwin-rebase-post_pkg_prerm |
40 |
+} |
41 |
+ |
42 |
+############################################################################### |
43 |
+# To allow a Windows DLL to reside in memory just once for multiple processes, |
44 |
+# each process needs to be able to map that DLL at the same base address, |
45 |
+# without the need for a dynamic rebase. However, this requires the DLL's |
46 |
+# base address to be unique across all DLLs potentially loaded into a single |
47 |
+# process. Hence the PE/COFF binary format allows to define a preferred base |
48 |
+# address for DLLs, but leaves it up to the package manager to maintain that |
49 |
+# base address to be unique across all DLLs related together. |
50 |
+# (Not sure how exactly ASLR plays in here, though.) |
51 |
+# |
52 |
+# Furthermore, for the Cygwin fork, it is crucial that the child process is |
53 |
+# able to reload a DLL at the very same address as in the parent process. |
54 |
+# Having unique preferred base addresses across all related DLLs does help |
55 |
+# here as well. |
56 |
+# |
57 |
+# The Cygwin rebase utility does maintain some database holding the size and |
58 |
+# preferred base address for each DLL, and allows to update a DLL's preferred |
59 |
+# base address to not conflict with already installed DLLs. |
60 |
+# |
61 |
+# As updating the preferred base address for a DLL in use is a bad idea, we |
62 |
+# need to update the base address while the DLL is in staging directory, and |
63 |
+# update the rebase database after merging the DLL to the live file system. |
64 |
+# |
65 |
+# This allows to define a new preferred base address for a DLL that would |
66 |
+# replace an existing one, because during fork we really want to use the |
67 |
+# old version in the child process, which is verified using the preferred |
68 |
+# base address value to be identical in parent and child process. |
69 |
+# |
70 |
+# Otherwise, the new DLL may have identical size and preferred base address |
71 |
+# as the old DLL, and we may not detect a different DLL in the fork child. |
72 |
+# |
73 |
+# For unmerging a DLL: The Cygwin rebase utility does check if a DLL found |
74 |
+# in the database does still exist, removing that database entry otherwise. |
75 |
+############################################################################### |
76 |
+ |
77 |
+cygwin-rebase-get_pendingdir() { |
78 |
+ echo "var/db/rebase/pending" |
79 |
+} |
80 |
+ |
81 |
+cygwin-rebase-get_mergeddir() { |
82 |
+ echo "var/db/rebase/merged" |
83 |
+} |
84 |
+ |
85 |
+cygwin-rebase-get_listname() { |
86 |
+ echo "dlls_${CATEGORY}_${P}${PR:+-}${PR}" |
87 |
+} |
88 |
+ |
89 |
+cygwin-rebase-get_rebase_program() { |
90 |
+ [[ ${CHOST} == "${CBUILD}" ]] || return 1 |
91 |
+ local pfx |
92 |
+ for pfx in "${EPREFIX}" "${BROOT:-${PORTAGE_OVERRIDE_EPREFIX}}" |
93 |
+ do |
94 |
+ [[ -x ${pfx}/usr/bin/rebase ]] || continue |
95 |
+ echo "${pfx}/usr/bin/rebase" |
96 |
+ return 0 |
97 |
+ done |
98 |
+ return 1 |
99 |
+} |
100 |
+ |
101 |
+cygwin-rebase-post_pkg_preinst() { |
102 |
+ # Ensure database is up to date for when dlls were merged but |
103 |
+ # subsequent cygwin-rebase-merge-pending was not executed. |
104 |
+ einfo "Cygwin: Merging pending files into rebase database..." |
105 |
+ cygwin-rebase-merge pending |
106 |
+ eend $? |
107 |
+ |
108 |
+ local listname=$(cygwin-rebase-get_listname) |
109 |
+ local pendingdir=$(cygwin-rebase-get_pendingdir) |
110 |
+ local rebase_program=$(cygwin-rebase-get_rebase_program) |
111 |
+ |
112 |
+ if [[ ${CATEGORY}/${PN} == 'app-admin/cygwin-rebase' ]] |
113 |
+ then |
114 |
+ local mergeddir=$(cygwin-rebase-get_mergeddir) |
115 |
+ keepdir "/${pendingdir}" |
116 |
+ keepdir "/${mergeddir}" |
117 |
+ fi |
118 |
+ |
119 |
+ einfo "Cygwin: Rebasing new files..." |
120 |
+ ( |
121 |
+ set -e |
122 |
+ cd "${ED}" |
123 |
+ |
124 |
+ # The list of suffixes is found in the rebaseall script. |
125 |
+ find . -type f \ |
126 |
+ '(' -name '*.dll' \ |
127 |
+ -o -name '*.so' \ |
128 |
+ -o -name '*.oct' \ |
129 |
+ ')' \ |
130 |
+ | sed -e "s|^\.|${EPREFIX}|" > "${T}/rebase-filelist" |
131 |
+ [[ "${PIPESTATUS[*]}" == '0 0' ]] |
132 |
+ |
133 |
+ # Nothing found to rebase in this package. |
134 |
+ [[ -s ${T}/rebase-filelist ]] || exit 0 |
135 |
+ |
136 |
+ mkdir -p "./${pendingdir}" |
137 |
+ cp -f "${T}/rebase-filelist" "./${pendingdir}/${listname}" |
138 |
+ |
139 |
+ # Without the rebase program, do not perform a rebase. |
140 |
+ [[ ${rebase_program} ]] || exit 0 |
141 |
+ |
142 |
+ sed -ne "/^${EPREFIX//\//\\/}\\//{s|^${EPREFIX}/||;p}" "./${pendingdir}/${listname}" \ |
143 |
+ | "${rebase_program}" --verbose --oblivious --database --filelist=- |
144 |
+ [[ "${PIPESTATUS[*]}" == '0 0' ]] |
145 |
+ ) |
146 |
+ eend $? |
147 |
+} |
148 |
+ |
149 |
+cygwin-rebase-pre_pkg_postinst() { |
150 |
+ if [[ ${CATEGORY}/${PN} == 'app-admin/cygwin-rebase' ]] |
151 |
+ then |
152 |
+ einfo "Cygwin: Updating rebase database with installed files..." |
153 |
+ cygwin-rebase-merge merged |
154 |
+ eend $? |
155 |
+ fi |
156 |
+ einfo "Cygwin: Merging updated files into rebase database..." |
157 |
+ cygwin-rebase-merge pending |
158 |
+ eend $? |
159 |
+} |
160 |
+ |
161 |
+cygwin-rebase-merge() { |
162 |
+ local mode=${1} |
163 |
+ |
164 |
+ local rebase_program=$(cygwin-rebase-get_rebase_program) |
165 |
+ [[ ${rebase_program} ]] || return 0 |
166 |
+ |
167 |
+ local pendingdir='' |
168 |
+ local mergeddir='' |
169 |
+ case ${mode} in |
170 |
+ pending) |
171 |
+ pendingdir=$(cygwin-rebase-get_pendingdir) |
172 |
+ mergeddir=$(cygwin-rebase-get_mergeddir) |
173 |
+ ;; |
174 |
+ merged) |
175 |
+ pendingdir=$(cygwin-rebase-get_mergeddir) |
176 |
+ mergeddir='' |
177 |
+ ;; |
178 |
+ *) |
179 |
+ die "Invalid mode '${mode}'." |
180 |
+ ;; |
181 |
+ esac |
182 |
+ |
183 |
+ ( |
184 |
+ set -e |
185 |
+ cd "${EROOT}" |
186 |
+ |
187 |
+ [[ -r ./${pendingdir}/. ]] |
188 |
+ [[ -r ./${mergeddir}/. ]] |
189 |
+ |
190 |
+ find ./"${pendingdir}" -mindepth 1 -maxdepth 1 -type f -name 'dlls_*' \ |
191 |
+ -exec sed -ne "/^${EPREFIX//\//\\/}\\//{s|^${EPREFIX}/||;p}" {} + \ |
192 |
+ | "${rebase_program}" --verbose --merge-files --database --filelist=- |
193 |
+ [[ "${PIPESTATUS[*]}" == '0 0' ]] |
194 |
+ |
195 |
+ [[ ${mode} == 'pending' ]] || exit 0 |
196 |
+ |
197 |
+ find "./${pendingdir}" -maxdepth 1 -type f \ |
198 |
+ -exec mv -f -t "./${mergeddir}/" {} + |
199 |
+ ) |
200 |
+ [[ $? == 0 ]] || die "Merging ${mode} files into rebase database failed." |
201 |
+} |
202 |
+ |
203 |
+cygwin-rebase-post_pkg_prerm() { |
204 |
+ # The pending list is installed as part of the package, but |
205 |
+ # the merged list is not. Move from merged back to pending, |
206 |
+ # in case the unmerge fails... |
207 |
+ local pendingdir=$(cygwin-rebase-get_pendingdir) |
208 |
+ local mergeddir=$(cygwin-rebase-get_mergeddir) |
209 |
+ local listname=$(cygwin-rebase-get_listname) |
210 |
+ ( |
211 |
+ set -e |
212 |
+ cd "${EROOT}" |
213 |
+ [[ -w ./${mergeddir}/. ]] |
214 |
+ [[ -w ./${pendingdir}/. ]] |
215 |
+ if [[ -s ./${mergeddir}/${listname} ]] |
216 |
+ then |
217 |
+ mv -f "./${mergeddir}/${listname}" "./${pendingdir}/${listname}" || : |
218 |
+ fi |
219 |
+ rm -f "./${mergeddir}/${listname}" |
220 |
+ ) |
221 |
} |