summaryrefslogtreecommitdiffstats
path: root/meta-vitis-tc/scripts/relocate-wrapper.py
diff options
context:
space:
mode:
Diffstat (limited to 'meta-vitis-tc/scripts/relocate-wrapper.py')
-rwxr-xr-xmeta-vitis-tc/scripts/relocate-wrapper.py247
1 files changed, 247 insertions, 0 deletions
diff --git a/meta-vitis-tc/scripts/relocate-wrapper.py b/meta-vitis-tc/scripts/relocate-wrapper.py
new file mode 100755
index 00000000..d6c63edf
--- /dev/null
+++ b/meta-vitis-tc/scripts/relocate-wrapper.py
@@ -0,0 +1,247 @@
1#!/usr/bin/env python3
2#
3# Copyright (c) 2012 Intel Corporation
4#
5# SPDX-License-Identifier: GPL-2.0-only
6#
7# AUTHORS
8# Laurentiu Palcu <laurentiu.palcu@intel.com>
9#
10
11# Copyright (C) 2019-2020, Xilinx, Inc. All rights reserved.
12# Copyright (C) 2023, Advanced Micro Devices, Inc. All rights reserved.
13#
14# DESCRIPTION
15# Runtime-relocation wrapper scripting based on YP relocation scripting
16#
17# AUTHORS
18# Mark Hatle <mark.hatle@amd.com>
19
20import struct
21import sys
22import stat
23import os
24import re
25import errno
26
27if sys.version < '3':
28 def b(x):
29 return x
30else:
31 def b(x):
32 return x.encode(sys.getfilesystemencoding())
33
34old_prefix = re.compile(b("##DEFAULT_INSTALL_DIR##"))
35
36def get_arch():
37 global endian_prefix
38 f.seek(0)
39 e_ident =f.read(16)
40 ei_mag0,ei_mag1_3,ei_class,ei_data,ei_version = struct.unpack("<B3sBBB9x", e_ident)
41
42 # ei_data = 1 for little-endian & 0 for big-endian
43 if ei_data == 1:
44 endian_prefix = '<'
45 else:
46 endian_prefix = '>'
47
48 if (ei_mag0 != 0x7f and ei_mag1_3 != "ELF") or ei_class == 0:
49 return 0
50
51 if ei_class == 1:
52 return 32
53 elif ei_class == 2:
54 return 64
55
56def parse_elf_header(f):
57 global e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags,\
58 e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx
59
60 f.seek(0)
61 elf_header = f.read(64)
62
63 if arch == 32:
64 # 32bit
65 hdr_fmt = endian_prefix + "HHILLLIHHHHHH"
66 hdr_size = 52
67 else:
68 # 64bit
69 hdr_fmt = endian_prefix + "HHIQQQIHHHHHH"
70 hdr_size = 64
71
72 e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags,\
73 e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx =\
74 struct.unpack(hdr_fmt, elf_header[16:hdr_size])
75
76def is_elf_executable(f):
77 global interp
78
79 rc = False
80
81 if arch == 32:
82 ph_fmt = endian_prefix + "IIIIIIII"
83 else:
84 ph_fmt = endian_prefix + "IIQQQQQQ"
85
86 """ look for PT_INTERP section """
87 for i in range(0,e_phnum):
88 f.seek(e_phoff + i * e_phentsize)
89 ph_hdr = f.read(e_phentsize)
90 if arch == 32:
91 # 32bit
92 p_type, p_offset, p_vaddr, p_paddr, p_filesz,\
93 p_memsz, p_flags, p_align = struct.unpack(ph_fmt, ph_hdr)
94 else:
95 # 64bit
96 p_type, p_flags, p_offset, p_vaddr, p_paddr, \
97 p_filesz, p_memsz, p_align = struct.unpack(ph_fmt, ph_hdr)
98
99 """ change interpreter """
100 if p_type == 3:
101 # PT_INTERP section
102 f.seek(p_offset)
103 # External SDKs with mixed pre-compiled binaries should not get
104 # relocated so look for some variant of /lib
105 fname = f.read(11)
106 if fname.startswith(b("/lib/")) or fname.startswith(b("/lib64/")) or \
107 fname.startswith(b("/lib32/")) or fname.startswith(b("/usr/lib32/")) or \
108 fname.startswith(b("/usr/lib32/")) or fname.startswith(b("/usr/lib64/")):
109 break
110 if p_filesz == 0:
111 break
112 rc = True
113 # Store the interpretor name to global interp
114 f.seek(p_offset)
115 chars = []
116 while True:
117 c = f.read(1)
118 if c == b'\x00':
119 interp = (b''.join(chars)).decode('utf-8')
120 break
121 chars.append(c)
122 break
123
124 return rc
125
126# MAIN
127if len(sys.argv) < 2:
128 print('%s: <path>' % sys.argv[0])
129 sys.exit(-1)
130
131# In python > 3, strings may also contain Unicode characters. So, convert
132# them to bytes
133if sys.version_info < (3,):
134 process_path = sys.argv[1]
135else:
136 process_path = sys.argv[1]
137
138process_path = os.path.realpath(process_path)
139
140for root, _, files in os.walk(process_path):
141 for file in files:
142 if file.endswith('.real'):
143 continue
144
145 e = os.path.join(root, file)
146
147 if not os.path.isfile(e) or not os.access(e, os.X_OK) or os.path.islink(e):
148 continue
149
150 if os.path.dirname(e).endswith('/lib') and (os.path.basename(e).startswith('libc-') or os.path.basename(e).startswith('libc.so')):
151 # Special case, don't wrap this...
152 continue
153
154 if os.path.dirname(e).endswith('/lib') and os.path.basename(e).startswith('libpthread-'):
155 # Special case, don't wrap this...
156 continue
157
158 perms = os.stat(e)[stat.ST_MODE]
159 if os.access(e, os.R_OK):
160 perms = None
161 else:
162 os.chmod(e, perms|stat.S_IRWXU)
163
164 try:
165 f = open(e, "r+b")
166 except IOError:
167 exctype, ioex = sys.exc_info()[:2]
168 if ioex.errno == errno.ETXTBSY:
169 print("Could not open %s. File used by another process.\nPlease "\
170 "make sure you exit all processes that might use any SDK "\
171 "binaries." % e)
172 else:
173 print("Could not open %s: %s(%d)" % (e, ioex.strerror, ioex.errno))
174 sys.exit(-1)
175
176 # Save old size and do a size check at the end. Just a safety measure.
177 old_size = os.path.getsize(e)
178 if old_size >= 64:
179 arch = get_arch()
180 if arch:
181 parse_elf_header(f)
182
183 if is_elf_executable(f):
184 dirpath = os.path.dirname(e)
185 destfile = os.path.join(dirpath, file + '.real')
186
187 wrapper = os.path.join(dirpath, 'execwrapper.sh')
188
189 if not os.path.exists(wrapper):
190 #print('write %s' % wrapper)
191 with open(wrapper, "w+") as wrapperf:
192 ldso = os.path.basename(interp)
193 libbasepath = os.path.dirname(interp) # should be /lib
194 libdirname = os.path.basename(libbasepath) # lib or lib32 or lib64 or ....
195 basepath = os.path.dirname(libbasepath) # should be /
196
197 libpath = os.path.join(basepath, 'usr', libdirname)
198
199 # Generate relative names to the path of the execwrapper
200 libbasepath = os.path.relpath(libbasepath, dirpath)
201 libpath = os.path.relpath(libpath, dirpath)
202
203 print('')
204 print('wrapper: %s' % wrapper)
205 print('ldso = %s' % ldso)
206 print('lib = %s' % libdirname)
207 print('libpath = %s' % libbasepath)
208 print('usrlibpath = %s' % libpath)
209 print('')
210
211 wrapperf.write('#!/bin/bash\n')
212 wrapperf.write('# Written by Mark Hatle <mark.hatle@amd.com>\n')
213 wrapperf.write('# Copyright (C) 2019-2020, Xilinx, Inc. All rights reserved\n')
214 wrapperf.write('# Copyright (C) 2023-2024, Advanced Micro Devices, Inc. All rights reserved\n')
215 wrapperf.write('#\n')
216 wrapperf.write('# SPDX-License-Identifier: GPL-2.0-only\n')
217 wrapperf.write('LDSO=%s\n' % ldso)
218 wrapperf.write('LIBBASEPATH=%s\n' % libbasepath)
219 wrapperf.write('LIBPATH=%s\n' % libpath)
220 wrapperf.write('executable=$(basename $0)\n')
221 wrapperf.write('wrapper=$0\n')
222 wrapperf.write('BASEPATH=$(dirname ${wrapper})\n')
223 wrapperf.write('if [ ! -x $0 ]; then\n')
224 wrapperf.write(' wrapper=$(which $0)\n')
225 wrapperf.write('fi\n')
226 wrapperf.write('if [ -h $0 ]; then\n')
227 wrapperf.write(' executable=$(basename "$(readlink $0)" )\n')
228 wrapperf.write(' BASEPATH=$(dirname "$(realpath $0)")\n')
229 wrapperf.write('fi\n')
230 wrapperf.write('LIBBASEPATH=$(realpath ${BASEPATH}/${LIBBASEPATH})\n')
231 wrapperf.write('LIBPATH=$(realpath ${BASEPATH}/${LIBPATH})\n')
232 wrapperf.write('export COLLECT_GCC=${COLLECT_GCC%%.real}\n')
233 wrapperf.write('exec ${LIBBASEPATH}/${LDSO} --library-path ${LIBPATH}:${LIBBASEPATH} ${BASEPATH}/${executable}.real $@\n')
234 #print('chmod %s 0775' % wrapper)
235 os.chmod(wrapper, 0o775)
236
237 print('%s -> %s' % (e, destfile))
238 #print('mv %s %s' % (e, destfile))
239 os.rename(e, destfile)
240 #print('ln %s %s' % (wrapper, e))
241 os.link(wrapper, e)
242
243 """ change permissions back """
244 if perms:
245 os.chmod(e, perms)
246
247 f.close()