1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright 2014-2019 Advanced Micro Devices, Inc.
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker */
6*61046927SAndroid Build Coastguard Worker
7*61046927SAndroid Build Coastguard Worker #include "ac_rtld.h"
8*61046927SAndroid Build Coastguard Worker
9*61046927SAndroid Build Coastguard Worker #include "ac_binary.h"
10*61046927SAndroid Build Coastguard Worker #include "ac_gpu_info.h"
11*61046927SAndroid Build Coastguard Worker #include "util/compiler.h"
12*61046927SAndroid Build Coastguard Worker #include "util/u_dynarray.h"
13*61046927SAndroid Build Coastguard Worker #include "util/u_math.h"
14*61046927SAndroid Build Coastguard Worker
15*61046927SAndroid Build Coastguard Worker #include <gelf.h>
16*61046927SAndroid Build Coastguard Worker #include <libelf.h>
17*61046927SAndroid Build Coastguard Worker #include <stdarg.h>
18*61046927SAndroid Build Coastguard Worker #include <stdio.h>
19*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
20*61046927SAndroid Build Coastguard Worker #include <string.h>
21*61046927SAndroid Build Coastguard Worker
22*61046927SAndroid Build Coastguard Worker #ifndef EM_AMDGPU
23*61046927SAndroid Build Coastguard Worker // Old distributions may not have this enum constant
24*61046927SAndroid Build Coastguard Worker #define EM_AMDGPU 224
25*61046927SAndroid Build Coastguard Worker #endif
26*61046927SAndroid Build Coastguard Worker
27*61046927SAndroid Build Coastguard Worker #ifndef STT_AMDGPU_LDS
28*61046927SAndroid Build Coastguard Worker #define STT_AMDGPU_LDS 13 // this is deprecated -- remove
29*61046927SAndroid Build Coastguard Worker #endif
30*61046927SAndroid Build Coastguard Worker
31*61046927SAndroid Build Coastguard Worker #ifndef SHN_AMDGPU_LDS
32*61046927SAndroid Build Coastguard Worker #define SHN_AMDGPU_LDS 0xff00
33*61046927SAndroid Build Coastguard Worker #endif
34*61046927SAndroid Build Coastguard Worker
35*61046927SAndroid Build Coastguard Worker #ifndef R_AMDGPU_NONE
36*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_NONE 0
37*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_ABS32_LO 1
38*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_ABS32_HI 2
39*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_ABS64 3
40*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_REL32 4
41*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_REL64 5
42*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_ABS32 6
43*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_GOTPCREL 7
44*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_GOTPCREL32_LO 8
45*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_GOTPCREL32_HI 9
46*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_REL32_LO 10
47*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_REL32_HI 11
48*61046927SAndroid Build Coastguard Worker #define R_AMDGPU_RELATIVE64 13
49*61046927SAndroid Build Coastguard Worker #endif
50*61046927SAndroid Build Coastguard Worker
51*61046927SAndroid Build Coastguard Worker /* For the UMR disassembler. */
52*61046927SAndroid Build Coastguard Worker #define DEBUGGER_END_OF_CODE_MARKER 0xbf9f0000 /* invalid instruction */
53*61046927SAndroid Build Coastguard Worker #define DEBUGGER_NUM_MARKERS 5
54*61046927SAndroid Build Coastguard Worker
55*61046927SAndroid Build Coastguard Worker struct ac_rtld_section {
56*61046927SAndroid Build Coastguard Worker bool is_rx : 1;
57*61046927SAndroid Build Coastguard Worker bool is_pasted_text : 1;
58*61046927SAndroid Build Coastguard Worker uint64_t offset;
59*61046927SAndroid Build Coastguard Worker const char *name;
60*61046927SAndroid Build Coastguard Worker };
61*61046927SAndroid Build Coastguard Worker
62*61046927SAndroid Build Coastguard Worker struct ac_rtld_part {
63*61046927SAndroid Build Coastguard Worker Elf *elf;
64*61046927SAndroid Build Coastguard Worker struct ac_rtld_section *sections;
65*61046927SAndroid Build Coastguard Worker unsigned num_sections;
66*61046927SAndroid Build Coastguard Worker };
67*61046927SAndroid Build Coastguard Worker
report_errorvf(const char * fmt,va_list va)68*61046927SAndroid Build Coastguard Worker static void report_errorvf(const char *fmt, va_list va)
69*61046927SAndroid Build Coastguard Worker {
70*61046927SAndroid Build Coastguard Worker fprintf(stderr, "ac_rtld error: ");
71*61046927SAndroid Build Coastguard Worker
72*61046927SAndroid Build Coastguard Worker vfprintf(stderr, fmt, va);
73*61046927SAndroid Build Coastguard Worker
74*61046927SAndroid Build Coastguard Worker fprintf(stderr, "\n");
75*61046927SAndroid Build Coastguard Worker }
76*61046927SAndroid Build Coastguard Worker
77*61046927SAndroid Build Coastguard Worker static void report_errorf(const char *fmt, ...) PRINTFLIKE(1, 2);
78*61046927SAndroid Build Coastguard Worker
report_errorf(const char * fmt,...)79*61046927SAndroid Build Coastguard Worker static void report_errorf(const char *fmt, ...)
80*61046927SAndroid Build Coastguard Worker {
81*61046927SAndroid Build Coastguard Worker va_list va;
82*61046927SAndroid Build Coastguard Worker va_start(va, fmt);
83*61046927SAndroid Build Coastguard Worker report_errorvf(fmt, va);
84*61046927SAndroid Build Coastguard Worker va_end(va);
85*61046927SAndroid Build Coastguard Worker }
86*61046927SAndroid Build Coastguard Worker
87*61046927SAndroid Build Coastguard Worker static void report_elf_errorf(const char *fmt, ...) PRINTFLIKE(1, 2);
88*61046927SAndroid Build Coastguard Worker
report_elf_errorf(const char * fmt,...)89*61046927SAndroid Build Coastguard Worker static void report_elf_errorf(const char *fmt, ...)
90*61046927SAndroid Build Coastguard Worker {
91*61046927SAndroid Build Coastguard Worker va_list va;
92*61046927SAndroid Build Coastguard Worker va_start(va, fmt);
93*61046927SAndroid Build Coastguard Worker report_errorvf(fmt, va);
94*61046927SAndroid Build Coastguard Worker va_end(va);
95*61046927SAndroid Build Coastguard Worker
96*61046927SAndroid Build Coastguard Worker fprintf(stderr, "ELF error: %s\n", elf_errmsg(elf_errno()));
97*61046927SAndroid Build Coastguard Worker }
98*61046927SAndroid Build Coastguard Worker
99*61046927SAndroid Build Coastguard Worker /**
100*61046927SAndroid Build Coastguard Worker * Find a symbol in a dynarray of struct ac_rtld_symbol by \p name and shader
101*61046927SAndroid Build Coastguard Worker * \p part_idx.
102*61046927SAndroid Build Coastguard Worker */
find_symbol(const struct util_dynarray * symbols,const char * name,unsigned part_idx)103*61046927SAndroid Build Coastguard Worker static const struct ac_rtld_symbol *find_symbol(const struct util_dynarray *symbols,
104*61046927SAndroid Build Coastguard Worker const char *name, unsigned part_idx)
105*61046927SAndroid Build Coastguard Worker {
106*61046927SAndroid Build Coastguard Worker util_dynarray_foreach (symbols, struct ac_rtld_symbol, symbol) {
107*61046927SAndroid Build Coastguard Worker if ((symbol->part_idx == ~0u || symbol->part_idx == part_idx) && !strcmp(name, symbol->name))
108*61046927SAndroid Build Coastguard Worker return symbol;
109*61046927SAndroid Build Coastguard Worker }
110*61046927SAndroid Build Coastguard Worker return NULL;
111*61046927SAndroid Build Coastguard Worker }
112*61046927SAndroid Build Coastguard Worker
compare_symbol_by_align(const void * lhsp,const void * rhsp)113*61046927SAndroid Build Coastguard Worker static int compare_symbol_by_align(const void *lhsp, const void *rhsp)
114*61046927SAndroid Build Coastguard Worker {
115*61046927SAndroid Build Coastguard Worker const struct ac_rtld_symbol *lhs = lhsp;
116*61046927SAndroid Build Coastguard Worker const struct ac_rtld_symbol *rhs = rhsp;
117*61046927SAndroid Build Coastguard Worker if (rhs->align > lhs->align)
118*61046927SAndroid Build Coastguard Worker return 1;
119*61046927SAndroid Build Coastguard Worker if (rhs->align < lhs->align)
120*61046927SAndroid Build Coastguard Worker return -1;
121*61046927SAndroid Build Coastguard Worker return 0;
122*61046927SAndroid Build Coastguard Worker }
123*61046927SAndroid Build Coastguard Worker
124*61046927SAndroid Build Coastguard Worker /**
125*61046927SAndroid Build Coastguard Worker * Sort the given symbol list by decreasing alignment and assign offsets.
126*61046927SAndroid Build Coastguard Worker */
layout_symbols(struct ac_rtld_symbol * symbols,unsigned num_symbols,uint64_t * ptotal_size)127*61046927SAndroid Build Coastguard Worker static bool layout_symbols(struct ac_rtld_symbol *symbols, unsigned num_symbols,
128*61046927SAndroid Build Coastguard Worker uint64_t *ptotal_size)
129*61046927SAndroid Build Coastguard Worker {
130*61046927SAndroid Build Coastguard Worker qsort(symbols, num_symbols, sizeof(*symbols), compare_symbol_by_align);
131*61046927SAndroid Build Coastguard Worker
132*61046927SAndroid Build Coastguard Worker uint64_t total_size = *ptotal_size;
133*61046927SAndroid Build Coastguard Worker
134*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_symbols; ++i) {
135*61046927SAndroid Build Coastguard Worker struct ac_rtld_symbol *s = &symbols[i];
136*61046927SAndroid Build Coastguard Worker assert(util_is_power_of_two_nonzero(s->align));
137*61046927SAndroid Build Coastguard Worker
138*61046927SAndroid Build Coastguard Worker total_size = align64(total_size, s->align);
139*61046927SAndroid Build Coastguard Worker s->offset = total_size;
140*61046927SAndroid Build Coastguard Worker
141*61046927SAndroid Build Coastguard Worker if (total_size + s->size < total_size) {
142*61046927SAndroid Build Coastguard Worker report_errorf("%s: size overflow", __func__);
143*61046927SAndroid Build Coastguard Worker return false;
144*61046927SAndroid Build Coastguard Worker }
145*61046927SAndroid Build Coastguard Worker
146*61046927SAndroid Build Coastguard Worker total_size += s->size;
147*61046927SAndroid Build Coastguard Worker }
148*61046927SAndroid Build Coastguard Worker
149*61046927SAndroid Build Coastguard Worker *ptotal_size = total_size;
150*61046927SAndroid Build Coastguard Worker return true;
151*61046927SAndroid Build Coastguard Worker }
152*61046927SAndroid Build Coastguard Worker
153*61046927SAndroid Build Coastguard Worker /**
154*61046927SAndroid Build Coastguard Worker * Read LDS symbols from the given \p section of the ELF of \p part and append
155*61046927SAndroid Build Coastguard Worker * them to the LDS symbols list.
156*61046927SAndroid Build Coastguard Worker *
157*61046927SAndroid Build Coastguard Worker * Shared LDS symbols are filtered out.
158*61046927SAndroid Build Coastguard Worker */
read_private_lds_symbols(struct ac_rtld_binary * binary,unsigned part_idx,Elf_Scn * section,uint32_t * lds_end_align)159*61046927SAndroid Build Coastguard Worker static bool read_private_lds_symbols(struct ac_rtld_binary *binary, unsigned part_idx,
160*61046927SAndroid Build Coastguard Worker Elf_Scn *section, uint32_t *lds_end_align)
161*61046927SAndroid Build Coastguard Worker {
162*61046927SAndroid Build Coastguard Worker #define report_if(cond) \
163*61046927SAndroid Build Coastguard Worker do { \
164*61046927SAndroid Build Coastguard Worker if ((cond)) { \
165*61046927SAndroid Build Coastguard Worker report_errorf(#cond); \
166*61046927SAndroid Build Coastguard Worker return false; \
167*61046927SAndroid Build Coastguard Worker } \
168*61046927SAndroid Build Coastguard Worker } while (false)
169*61046927SAndroid Build Coastguard Worker #define report_elf_if(cond) \
170*61046927SAndroid Build Coastguard Worker do { \
171*61046927SAndroid Build Coastguard Worker if ((cond)) { \
172*61046927SAndroid Build Coastguard Worker report_elf_errorf(#cond); \
173*61046927SAndroid Build Coastguard Worker return false; \
174*61046927SAndroid Build Coastguard Worker } \
175*61046927SAndroid Build Coastguard Worker } while (false)
176*61046927SAndroid Build Coastguard Worker
177*61046927SAndroid Build Coastguard Worker struct ac_rtld_part *part = &binary->parts[part_idx];
178*61046927SAndroid Build Coastguard Worker Elf64_Shdr *shdr = elf64_getshdr(section);
179*61046927SAndroid Build Coastguard Worker uint32_t strtabidx = shdr->sh_link;
180*61046927SAndroid Build Coastguard Worker Elf_Data *symbols_data = elf_getdata(section, NULL);
181*61046927SAndroid Build Coastguard Worker report_elf_if(!symbols_data);
182*61046927SAndroid Build Coastguard Worker
183*61046927SAndroid Build Coastguard Worker const Elf64_Sym *symbol = symbols_data->d_buf;
184*61046927SAndroid Build Coastguard Worker size_t num_symbols = symbols_data->d_size / sizeof(Elf64_Sym);
185*61046927SAndroid Build Coastguard Worker
186*61046927SAndroid Build Coastguard Worker for (size_t j = 0; j < num_symbols; ++j, ++symbol) {
187*61046927SAndroid Build Coastguard Worker struct ac_rtld_symbol s = {0};
188*61046927SAndroid Build Coastguard Worker
189*61046927SAndroid Build Coastguard Worker if (ELF64_ST_TYPE(symbol->st_info) == STT_AMDGPU_LDS) {
190*61046927SAndroid Build Coastguard Worker /* old-style LDS symbols from initial prototype -- remove eventually */
191*61046927SAndroid Build Coastguard Worker s.align = MIN2(1u << (symbol->st_other >> 3), 1u << 16);
192*61046927SAndroid Build Coastguard Worker } else if (symbol->st_shndx == SHN_AMDGPU_LDS) {
193*61046927SAndroid Build Coastguard Worker s.align = MIN2(symbol->st_value, 1u << 16);
194*61046927SAndroid Build Coastguard Worker report_if(!util_is_power_of_two_nonzero(s.align));
195*61046927SAndroid Build Coastguard Worker } else
196*61046927SAndroid Build Coastguard Worker continue;
197*61046927SAndroid Build Coastguard Worker
198*61046927SAndroid Build Coastguard Worker report_if(symbol->st_size > 1u << 29);
199*61046927SAndroid Build Coastguard Worker
200*61046927SAndroid Build Coastguard Worker s.name = elf_strptr(part->elf, strtabidx, symbol->st_name);
201*61046927SAndroid Build Coastguard Worker s.size = symbol->st_size;
202*61046927SAndroid Build Coastguard Worker s.part_idx = part_idx;
203*61046927SAndroid Build Coastguard Worker
204*61046927SAndroid Build Coastguard Worker if (!strcmp(s.name, "__lds_end")) {
205*61046927SAndroid Build Coastguard Worker report_elf_if(s.size != 0);
206*61046927SAndroid Build Coastguard Worker *lds_end_align = MAX2(*lds_end_align, s.align);
207*61046927SAndroid Build Coastguard Worker continue;
208*61046927SAndroid Build Coastguard Worker }
209*61046927SAndroid Build Coastguard Worker
210*61046927SAndroid Build Coastguard Worker const struct ac_rtld_symbol *shared = find_symbol(&binary->lds_symbols, s.name, part_idx);
211*61046927SAndroid Build Coastguard Worker if (shared) {
212*61046927SAndroid Build Coastguard Worker report_elf_if(s.align > shared->align);
213*61046927SAndroid Build Coastguard Worker report_elf_if(s.size > shared->size);
214*61046927SAndroid Build Coastguard Worker continue;
215*61046927SAndroid Build Coastguard Worker }
216*61046927SAndroid Build Coastguard Worker
217*61046927SAndroid Build Coastguard Worker util_dynarray_append(&binary->lds_symbols, struct ac_rtld_symbol, s);
218*61046927SAndroid Build Coastguard Worker }
219*61046927SAndroid Build Coastguard Worker
220*61046927SAndroid Build Coastguard Worker return true;
221*61046927SAndroid Build Coastguard Worker
222*61046927SAndroid Build Coastguard Worker #undef report_if
223*61046927SAndroid Build Coastguard Worker #undef report_elf_if
224*61046927SAndroid Build Coastguard Worker }
225*61046927SAndroid Build Coastguard Worker
226*61046927SAndroid Build Coastguard Worker /**
227*61046927SAndroid Build Coastguard Worker * Open a binary consisting of one or more shader parts.
228*61046927SAndroid Build Coastguard Worker *
229*61046927SAndroid Build Coastguard Worker * \param binary the uninitialized struct
230*61046927SAndroid Build Coastguard Worker * \param i binary opening parameters
231*61046927SAndroid Build Coastguard Worker */
ac_rtld_open(struct ac_rtld_binary * binary,struct ac_rtld_open_info i)232*61046927SAndroid Build Coastguard Worker bool ac_rtld_open(struct ac_rtld_binary *binary, struct ac_rtld_open_info i)
233*61046927SAndroid Build Coastguard Worker {
234*61046927SAndroid Build Coastguard Worker /* One of the libelf implementations
235*61046927SAndroid Build Coastguard Worker * (http://www.mr511.de/software/english.htm) requires calling
236*61046927SAndroid Build Coastguard Worker * elf_version() before elf_memory().
237*61046927SAndroid Build Coastguard Worker */
238*61046927SAndroid Build Coastguard Worker elf_version(EV_CURRENT);
239*61046927SAndroid Build Coastguard Worker
240*61046927SAndroid Build Coastguard Worker memset(binary, 0, sizeof(*binary));
241*61046927SAndroid Build Coastguard Worker memcpy(&binary->options, &i.options, sizeof(binary->options));
242*61046927SAndroid Build Coastguard Worker binary->wave_size = i.wave_size;
243*61046927SAndroid Build Coastguard Worker binary->gfx_level = i.info->gfx_level;
244*61046927SAndroid Build Coastguard Worker binary->num_parts = i.num_parts;
245*61046927SAndroid Build Coastguard Worker binary->parts = calloc(sizeof(*binary->parts), i.num_parts);
246*61046927SAndroid Build Coastguard Worker if (!binary->parts)
247*61046927SAndroid Build Coastguard Worker return false;
248*61046927SAndroid Build Coastguard Worker
249*61046927SAndroid Build Coastguard Worker uint64_t pasted_text_size = 0;
250*61046927SAndroid Build Coastguard Worker uint64_t rx_align = 1;
251*61046927SAndroid Build Coastguard Worker uint64_t rx_size = 0;
252*61046927SAndroid Build Coastguard Worker uint64_t exec_size = 0;
253*61046927SAndroid Build Coastguard Worker
254*61046927SAndroid Build Coastguard Worker #define report_if(cond) \
255*61046927SAndroid Build Coastguard Worker do { \
256*61046927SAndroid Build Coastguard Worker if ((cond)) { \
257*61046927SAndroid Build Coastguard Worker report_errorf(#cond); \
258*61046927SAndroid Build Coastguard Worker goto fail; \
259*61046927SAndroid Build Coastguard Worker } \
260*61046927SAndroid Build Coastguard Worker } while (false)
261*61046927SAndroid Build Coastguard Worker #define report_elf_if(cond) \
262*61046927SAndroid Build Coastguard Worker do { \
263*61046927SAndroid Build Coastguard Worker if ((cond)) { \
264*61046927SAndroid Build Coastguard Worker report_elf_errorf(#cond); \
265*61046927SAndroid Build Coastguard Worker goto fail; \
266*61046927SAndroid Build Coastguard Worker } \
267*61046927SAndroid Build Coastguard Worker } while (false)
268*61046927SAndroid Build Coastguard Worker
269*61046927SAndroid Build Coastguard Worker /* Copy and layout shared LDS symbols. */
270*61046927SAndroid Build Coastguard Worker if (i.num_shared_lds_symbols) {
271*61046927SAndroid Build Coastguard Worker if (!util_dynarray_resize(&binary->lds_symbols, struct ac_rtld_symbol,
272*61046927SAndroid Build Coastguard Worker i.num_shared_lds_symbols))
273*61046927SAndroid Build Coastguard Worker goto fail;
274*61046927SAndroid Build Coastguard Worker
275*61046927SAndroid Build Coastguard Worker memcpy(binary->lds_symbols.data, i.shared_lds_symbols, binary->lds_symbols.size);
276*61046927SAndroid Build Coastguard Worker }
277*61046927SAndroid Build Coastguard Worker
278*61046927SAndroid Build Coastguard Worker util_dynarray_foreach (&binary->lds_symbols, struct ac_rtld_symbol, symbol)
279*61046927SAndroid Build Coastguard Worker symbol->part_idx = ~0u;
280*61046927SAndroid Build Coastguard Worker
281*61046927SAndroid Build Coastguard Worker unsigned max_lds_size = i.info->gfx_level == GFX6 ? 32 * 1024 : 64 * 1024;
282*61046927SAndroid Build Coastguard Worker
283*61046927SAndroid Build Coastguard Worker uint64_t shared_lds_size = 0;
284*61046927SAndroid Build Coastguard Worker if (!layout_symbols(binary->lds_symbols.data, i.num_shared_lds_symbols, &shared_lds_size))
285*61046927SAndroid Build Coastguard Worker goto fail;
286*61046927SAndroid Build Coastguard Worker
287*61046927SAndroid Build Coastguard Worker if (shared_lds_size > max_lds_size) {
288*61046927SAndroid Build Coastguard Worker fprintf(stderr, "ac_rtld error(1): too much LDS (used = %u, max = %u)\n",
289*61046927SAndroid Build Coastguard Worker (unsigned)shared_lds_size, max_lds_size);
290*61046927SAndroid Build Coastguard Worker goto fail;
291*61046927SAndroid Build Coastguard Worker }
292*61046927SAndroid Build Coastguard Worker binary->lds_size = shared_lds_size;
293*61046927SAndroid Build Coastguard Worker
294*61046927SAndroid Build Coastguard Worker /* First pass over all parts: open ELFs, pre-determine the placement of
295*61046927SAndroid Build Coastguard Worker * sections in the memory image, and collect and layout private LDS symbols. */
296*61046927SAndroid Build Coastguard Worker uint32_t lds_end_align = 0;
297*61046927SAndroid Build Coastguard Worker
298*61046927SAndroid Build Coastguard Worker if (binary->options.halt_at_entry)
299*61046927SAndroid Build Coastguard Worker pasted_text_size += 4;
300*61046927SAndroid Build Coastguard Worker
301*61046927SAndroid Build Coastguard Worker for (unsigned part_idx = 0; part_idx < i.num_parts; ++part_idx) {
302*61046927SAndroid Build Coastguard Worker struct ac_rtld_part *part = &binary->parts[part_idx];
303*61046927SAndroid Build Coastguard Worker unsigned part_lds_symbols_begin =
304*61046927SAndroid Build Coastguard Worker util_dynarray_num_elements(&binary->lds_symbols, struct ac_rtld_symbol);
305*61046927SAndroid Build Coastguard Worker
306*61046927SAndroid Build Coastguard Worker part->elf = elf_memory((char *)i.elf_ptrs[part_idx], i.elf_sizes[part_idx]);
307*61046927SAndroid Build Coastguard Worker report_elf_if(!part->elf);
308*61046927SAndroid Build Coastguard Worker
309*61046927SAndroid Build Coastguard Worker const Elf64_Ehdr *ehdr = elf64_getehdr(part->elf);
310*61046927SAndroid Build Coastguard Worker report_elf_if(!ehdr);
311*61046927SAndroid Build Coastguard Worker report_if(ehdr->e_machine != EM_AMDGPU);
312*61046927SAndroid Build Coastguard Worker
313*61046927SAndroid Build Coastguard Worker size_t section_str_index;
314*61046927SAndroid Build Coastguard Worker size_t num_shdrs;
315*61046927SAndroid Build Coastguard Worker report_elf_if(elf_getshdrstrndx(part->elf, §ion_str_index) < 0);
316*61046927SAndroid Build Coastguard Worker report_elf_if(elf_getshdrnum(part->elf, &num_shdrs) < 0);
317*61046927SAndroid Build Coastguard Worker
318*61046927SAndroid Build Coastguard Worker part->num_sections = num_shdrs;
319*61046927SAndroid Build Coastguard Worker part->sections = calloc(sizeof(*part->sections), num_shdrs);
320*61046927SAndroid Build Coastguard Worker report_if(!part->sections);
321*61046927SAndroid Build Coastguard Worker
322*61046927SAndroid Build Coastguard Worker Elf_Scn *section = NULL;
323*61046927SAndroid Build Coastguard Worker bool first_section = true;
324*61046927SAndroid Build Coastguard Worker while ((section = elf_nextscn(part->elf, section))) {
325*61046927SAndroid Build Coastguard Worker Elf64_Shdr *shdr = elf64_getshdr(section);
326*61046927SAndroid Build Coastguard Worker struct ac_rtld_section *s = &part->sections[elf_ndxscn(section)];
327*61046927SAndroid Build Coastguard Worker s->name = elf_strptr(part->elf, section_str_index, shdr->sh_name);
328*61046927SAndroid Build Coastguard Worker report_elf_if(!s->name);
329*61046927SAndroid Build Coastguard Worker
330*61046927SAndroid Build Coastguard Worker /* Cannot actually handle linked objects yet */
331*61046927SAndroid Build Coastguard Worker report_elf_if(shdr->sh_addr != 0);
332*61046927SAndroid Build Coastguard Worker
333*61046927SAndroid Build Coastguard Worker /* Alignment must be 0 or a power of two */
334*61046927SAndroid Build Coastguard Worker report_elf_if(shdr->sh_addralign & (shdr->sh_addralign - 1));
335*61046927SAndroid Build Coastguard Worker uint64_t sh_align = MAX2(shdr->sh_addralign, 1);
336*61046927SAndroid Build Coastguard Worker
337*61046927SAndroid Build Coastguard Worker if (shdr->sh_flags & SHF_ALLOC && shdr->sh_type != SHT_NOTE) {
338*61046927SAndroid Build Coastguard Worker report_if(shdr->sh_flags & SHF_WRITE);
339*61046927SAndroid Build Coastguard Worker
340*61046927SAndroid Build Coastguard Worker s->is_rx = true;
341*61046927SAndroid Build Coastguard Worker
342*61046927SAndroid Build Coastguard Worker if (shdr->sh_flags & SHF_EXECINSTR) {
343*61046927SAndroid Build Coastguard Worker report_elf_if(shdr->sh_size & 3);
344*61046927SAndroid Build Coastguard Worker
345*61046927SAndroid Build Coastguard Worker if (!strcmp(s->name, ".text"))
346*61046927SAndroid Build Coastguard Worker s->is_pasted_text = true;
347*61046927SAndroid Build Coastguard Worker
348*61046927SAndroid Build Coastguard Worker exec_size += shdr->sh_size;
349*61046927SAndroid Build Coastguard Worker }
350*61046927SAndroid Build Coastguard Worker
351*61046927SAndroid Build Coastguard Worker if (s->is_pasted_text) {
352*61046927SAndroid Build Coastguard Worker if (part_idx > 0 && first_section && binary->options.waitcnt_wa) {
353*61046927SAndroid Build Coastguard Worker /* Reserve a dword at the beginning of this part. */
354*61046927SAndroid Build Coastguard Worker exec_size += 4;
355*61046927SAndroid Build Coastguard Worker pasted_text_size += 4;
356*61046927SAndroid Build Coastguard Worker first_section = false;
357*61046927SAndroid Build Coastguard Worker }
358*61046927SAndroid Build Coastguard Worker
359*61046927SAndroid Build Coastguard Worker s->offset = pasted_text_size;
360*61046927SAndroid Build Coastguard Worker pasted_text_size += shdr->sh_size;
361*61046927SAndroid Build Coastguard Worker } else {
362*61046927SAndroid Build Coastguard Worker rx_align = align(rx_align, sh_align);
363*61046927SAndroid Build Coastguard Worker rx_size = align(rx_size, sh_align);
364*61046927SAndroid Build Coastguard Worker s->offset = rx_size;
365*61046927SAndroid Build Coastguard Worker rx_size += shdr->sh_size;
366*61046927SAndroid Build Coastguard Worker }
367*61046927SAndroid Build Coastguard Worker } else if (shdr->sh_type == SHT_SYMTAB) {
368*61046927SAndroid Build Coastguard Worker if (!read_private_lds_symbols(binary, part_idx, section, &lds_end_align))
369*61046927SAndroid Build Coastguard Worker goto fail;
370*61046927SAndroid Build Coastguard Worker }
371*61046927SAndroid Build Coastguard Worker }
372*61046927SAndroid Build Coastguard Worker
373*61046927SAndroid Build Coastguard Worker uint64_t part_lds_size = shared_lds_size;
374*61046927SAndroid Build Coastguard Worker if (!layout_symbols(util_dynarray_element(&binary->lds_symbols, struct ac_rtld_symbol,
375*61046927SAndroid Build Coastguard Worker part_lds_symbols_begin),
376*61046927SAndroid Build Coastguard Worker util_dynarray_num_elements(&binary->lds_symbols, struct ac_rtld_symbol) -
377*61046927SAndroid Build Coastguard Worker part_lds_symbols_begin,
378*61046927SAndroid Build Coastguard Worker &part_lds_size))
379*61046927SAndroid Build Coastguard Worker goto fail;
380*61046927SAndroid Build Coastguard Worker binary->lds_size = MAX2(binary->lds_size, part_lds_size);
381*61046927SAndroid Build Coastguard Worker }
382*61046927SAndroid Build Coastguard Worker
383*61046927SAndroid Build Coastguard Worker binary->rx_end_markers = pasted_text_size;
384*61046927SAndroid Build Coastguard Worker pasted_text_size += 4 * DEBUGGER_NUM_MARKERS;
385*61046927SAndroid Build Coastguard Worker
386*61046927SAndroid Build Coastguard Worker /* __lds_end is a special symbol that points at the end of the memory
387*61046927SAndroid Build Coastguard Worker * occupied by other LDS symbols. Its alignment is taken as the
388*61046927SAndroid Build Coastguard Worker * maximum of its alignment over all shader parts where it occurs.
389*61046927SAndroid Build Coastguard Worker */
390*61046927SAndroid Build Coastguard Worker if (lds_end_align) {
391*61046927SAndroid Build Coastguard Worker binary->lds_size = align(binary->lds_size, lds_end_align);
392*61046927SAndroid Build Coastguard Worker
393*61046927SAndroid Build Coastguard Worker struct ac_rtld_symbol *lds_end =
394*61046927SAndroid Build Coastguard Worker util_dynarray_grow(&binary->lds_symbols, struct ac_rtld_symbol, 1);
395*61046927SAndroid Build Coastguard Worker lds_end->name = "__lds_end";
396*61046927SAndroid Build Coastguard Worker lds_end->size = 0;
397*61046927SAndroid Build Coastguard Worker lds_end->align = lds_end_align;
398*61046927SAndroid Build Coastguard Worker lds_end->offset = binary->lds_size;
399*61046927SAndroid Build Coastguard Worker lds_end->part_idx = ~0u;
400*61046927SAndroid Build Coastguard Worker }
401*61046927SAndroid Build Coastguard Worker
402*61046927SAndroid Build Coastguard Worker if (binary->lds_size > max_lds_size) {
403*61046927SAndroid Build Coastguard Worker fprintf(stderr, "ac_rtld error(2): too much LDS (used = %u, max = %u)\n",
404*61046927SAndroid Build Coastguard Worker (unsigned)binary->lds_size, max_lds_size);
405*61046927SAndroid Build Coastguard Worker goto fail;
406*61046927SAndroid Build Coastguard Worker }
407*61046927SAndroid Build Coastguard Worker
408*61046927SAndroid Build Coastguard Worker /* Second pass: Adjust offsets of non-pasted text sections. */
409*61046927SAndroid Build Coastguard Worker binary->rx_size = pasted_text_size;
410*61046927SAndroid Build Coastguard Worker binary->rx_size = align(binary->rx_size, rx_align);
411*61046927SAndroid Build Coastguard Worker
412*61046927SAndroid Build Coastguard Worker for (unsigned part_idx = 0; part_idx < i.num_parts; ++part_idx) {
413*61046927SAndroid Build Coastguard Worker struct ac_rtld_part *part = &binary->parts[part_idx];
414*61046927SAndroid Build Coastguard Worker size_t num_shdrs;
415*61046927SAndroid Build Coastguard Worker elf_getshdrnum(part->elf, &num_shdrs);
416*61046927SAndroid Build Coastguard Worker
417*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < num_shdrs; ++j) {
418*61046927SAndroid Build Coastguard Worker struct ac_rtld_section *s = &part->sections[j];
419*61046927SAndroid Build Coastguard Worker if (s->is_rx && !s->is_pasted_text)
420*61046927SAndroid Build Coastguard Worker s->offset += binary->rx_size;
421*61046927SAndroid Build Coastguard Worker }
422*61046927SAndroid Build Coastguard Worker }
423*61046927SAndroid Build Coastguard Worker
424*61046927SAndroid Build Coastguard Worker binary->rx_size += rx_size;
425*61046927SAndroid Build Coastguard Worker binary->exec_size = exec_size;
426*61046927SAndroid Build Coastguard Worker
427*61046927SAndroid Build Coastguard Worker return true;
428*61046927SAndroid Build Coastguard Worker
429*61046927SAndroid Build Coastguard Worker #undef report_if
430*61046927SAndroid Build Coastguard Worker #undef report_elf_if
431*61046927SAndroid Build Coastguard Worker
432*61046927SAndroid Build Coastguard Worker fail:
433*61046927SAndroid Build Coastguard Worker ac_rtld_close(binary);
434*61046927SAndroid Build Coastguard Worker return false;
435*61046927SAndroid Build Coastguard Worker }
436*61046927SAndroid Build Coastguard Worker
ac_rtld_close(struct ac_rtld_binary * binary)437*61046927SAndroid Build Coastguard Worker void ac_rtld_close(struct ac_rtld_binary *binary)
438*61046927SAndroid Build Coastguard Worker {
439*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < binary->num_parts; ++i) {
440*61046927SAndroid Build Coastguard Worker struct ac_rtld_part *part = &binary->parts[i];
441*61046927SAndroid Build Coastguard Worker free(part->sections);
442*61046927SAndroid Build Coastguard Worker elf_end(part->elf);
443*61046927SAndroid Build Coastguard Worker }
444*61046927SAndroid Build Coastguard Worker
445*61046927SAndroid Build Coastguard Worker util_dynarray_fini(&binary->lds_symbols);
446*61046927SAndroid Build Coastguard Worker free(binary->parts);
447*61046927SAndroid Build Coastguard Worker binary->parts = NULL;
448*61046927SAndroid Build Coastguard Worker binary->num_parts = 0;
449*61046927SAndroid Build Coastguard Worker }
450*61046927SAndroid Build Coastguard Worker
get_section_by_name(struct ac_rtld_part * part,const char * name,const char ** data,size_t * nbytes)451*61046927SAndroid Build Coastguard Worker static bool get_section_by_name(struct ac_rtld_part *part, const char *name, const char **data,
452*61046927SAndroid Build Coastguard Worker size_t *nbytes)
453*61046927SAndroid Build Coastguard Worker {
454*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < part->num_sections; ++i) {
455*61046927SAndroid Build Coastguard Worker struct ac_rtld_section *s = &part->sections[i];
456*61046927SAndroid Build Coastguard Worker if (s->name && !strcmp(name, s->name)) {
457*61046927SAndroid Build Coastguard Worker Elf_Scn *target_scn = elf_getscn(part->elf, i);
458*61046927SAndroid Build Coastguard Worker Elf_Data *target_data = elf_getdata(target_scn, NULL);
459*61046927SAndroid Build Coastguard Worker if (!target_data) {
460*61046927SAndroid Build Coastguard Worker report_elf_errorf("ac_rtld: get_section_by_name: elf_getdata");
461*61046927SAndroid Build Coastguard Worker return false;
462*61046927SAndroid Build Coastguard Worker }
463*61046927SAndroid Build Coastguard Worker
464*61046927SAndroid Build Coastguard Worker *data = target_data->d_buf;
465*61046927SAndroid Build Coastguard Worker *nbytes = target_data->d_size;
466*61046927SAndroid Build Coastguard Worker return true;
467*61046927SAndroid Build Coastguard Worker }
468*61046927SAndroid Build Coastguard Worker }
469*61046927SAndroid Build Coastguard Worker return false;
470*61046927SAndroid Build Coastguard Worker }
471*61046927SAndroid Build Coastguard Worker
ac_rtld_get_section_by_name(struct ac_rtld_binary * binary,const char * name,const char ** data,size_t * nbytes)472*61046927SAndroid Build Coastguard Worker bool ac_rtld_get_section_by_name(struct ac_rtld_binary *binary, const char *name, const char **data,
473*61046927SAndroid Build Coastguard Worker size_t *nbytes)
474*61046927SAndroid Build Coastguard Worker {
475*61046927SAndroid Build Coastguard Worker assert(binary->num_parts == 1);
476*61046927SAndroid Build Coastguard Worker return get_section_by_name(&binary->parts[0], name, data, nbytes);
477*61046927SAndroid Build Coastguard Worker }
478*61046927SAndroid Build Coastguard Worker
ac_rtld_read_config(const struct radeon_info * info,struct ac_rtld_binary * binary,struct ac_shader_config * config)479*61046927SAndroid Build Coastguard Worker bool ac_rtld_read_config(const struct radeon_info *info, struct ac_rtld_binary *binary,
480*61046927SAndroid Build Coastguard Worker struct ac_shader_config *config)
481*61046927SAndroid Build Coastguard Worker {
482*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < binary->num_parts; ++i) {
483*61046927SAndroid Build Coastguard Worker struct ac_rtld_part *part = &binary->parts[i];
484*61046927SAndroid Build Coastguard Worker const char *config_data;
485*61046927SAndroid Build Coastguard Worker size_t config_nbytes;
486*61046927SAndroid Build Coastguard Worker
487*61046927SAndroid Build Coastguard Worker if (!get_section_by_name(part, ".AMDGPU.config", &config_data, &config_nbytes))
488*61046927SAndroid Build Coastguard Worker return false;
489*61046927SAndroid Build Coastguard Worker
490*61046927SAndroid Build Coastguard Worker /* TODO: be precise about scratch use? */
491*61046927SAndroid Build Coastguard Worker struct ac_shader_config c = {0};
492*61046927SAndroid Build Coastguard Worker ac_parse_shader_binary_config(config_data, config_nbytes, binary->wave_size, info, &c);
493*61046927SAndroid Build Coastguard Worker
494*61046927SAndroid Build Coastguard Worker config->num_sgprs = MAX2(config->num_sgprs, c.num_sgprs);
495*61046927SAndroid Build Coastguard Worker config->num_vgprs = MAX2(config->num_vgprs, c.num_vgprs);
496*61046927SAndroid Build Coastguard Worker config->spilled_sgprs = MAX2(config->spilled_sgprs, c.spilled_sgprs);
497*61046927SAndroid Build Coastguard Worker config->spilled_vgprs = MAX2(config->spilled_vgprs, c.spilled_vgprs);
498*61046927SAndroid Build Coastguard Worker config->scratch_bytes_per_wave =
499*61046927SAndroid Build Coastguard Worker MAX2(config->scratch_bytes_per_wave, c.scratch_bytes_per_wave);
500*61046927SAndroid Build Coastguard Worker
501*61046927SAndroid Build Coastguard Worker assert(i == 0 || config->float_mode == c.float_mode);
502*61046927SAndroid Build Coastguard Worker config->float_mode = c.float_mode;
503*61046927SAndroid Build Coastguard Worker
504*61046927SAndroid Build Coastguard Worker /* SPI_PS_INPUT_ENA/ADDR can't be combined. Only the value from
505*61046927SAndroid Build Coastguard Worker * the main shader part is used. */
506*61046927SAndroid Build Coastguard Worker assert(config->spi_ps_input_ena == 0 && config->spi_ps_input_addr == 0);
507*61046927SAndroid Build Coastguard Worker config->spi_ps_input_ena = c.spi_ps_input_ena;
508*61046927SAndroid Build Coastguard Worker config->spi_ps_input_addr = c.spi_ps_input_addr;
509*61046927SAndroid Build Coastguard Worker
510*61046927SAndroid Build Coastguard Worker /* TODO: consistently use LDS symbols for this */
511*61046927SAndroid Build Coastguard Worker config->lds_size = MAX2(config->lds_size, c.lds_size);
512*61046927SAndroid Build Coastguard Worker
513*61046927SAndroid Build Coastguard Worker /* TODO: Should we combine these somehow? It's currently only
514*61046927SAndroid Build Coastguard Worker * used for radeonsi's compute, where multiple parts aren't used. */
515*61046927SAndroid Build Coastguard Worker assert(config->rsrc1 == 0 && config->rsrc2 == 0);
516*61046927SAndroid Build Coastguard Worker config->rsrc1 = c.rsrc1;
517*61046927SAndroid Build Coastguard Worker config->rsrc2 = c.rsrc2;
518*61046927SAndroid Build Coastguard Worker }
519*61046927SAndroid Build Coastguard Worker
520*61046927SAndroid Build Coastguard Worker return true;
521*61046927SAndroid Build Coastguard Worker }
522*61046927SAndroid Build Coastguard Worker
resolve_symbol(const struct ac_rtld_upload_info * u,unsigned part_idx,const Elf64_Sym * sym,const char * name,uint64_t * value)523*61046927SAndroid Build Coastguard Worker static bool resolve_symbol(const struct ac_rtld_upload_info *u, unsigned part_idx,
524*61046927SAndroid Build Coastguard Worker const Elf64_Sym *sym, const char *name, uint64_t *value)
525*61046927SAndroid Build Coastguard Worker {
526*61046927SAndroid Build Coastguard Worker /* TODO: properly disentangle the undef and the LDS cases once
527*61046927SAndroid Build Coastguard Worker * STT_AMDGPU_LDS is retired. */
528*61046927SAndroid Build Coastguard Worker if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_AMDGPU_LDS) {
529*61046927SAndroid Build Coastguard Worker const struct ac_rtld_symbol *lds_sym = find_symbol(&u->binary->lds_symbols, name, part_idx);
530*61046927SAndroid Build Coastguard Worker
531*61046927SAndroid Build Coastguard Worker if (lds_sym) {
532*61046927SAndroid Build Coastguard Worker *value = lds_sym->offset;
533*61046927SAndroid Build Coastguard Worker return true;
534*61046927SAndroid Build Coastguard Worker }
535*61046927SAndroid Build Coastguard Worker
536*61046927SAndroid Build Coastguard Worker /* TODO: resolve from other parts */
537*61046927SAndroid Build Coastguard Worker
538*61046927SAndroid Build Coastguard Worker if (u->get_external_symbol(u->binary->gfx_level, u->cb_data, name, value))
539*61046927SAndroid Build Coastguard Worker return true;
540*61046927SAndroid Build Coastguard Worker
541*61046927SAndroid Build Coastguard Worker report_errorf("symbol %s: unknown", name);
542*61046927SAndroid Build Coastguard Worker return false;
543*61046927SAndroid Build Coastguard Worker }
544*61046927SAndroid Build Coastguard Worker
545*61046927SAndroid Build Coastguard Worker struct ac_rtld_part *part = &u->binary->parts[part_idx];
546*61046927SAndroid Build Coastguard Worker if (sym->st_shndx >= part->num_sections) {
547*61046927SAndroid Build Coastguard Worker report_errorf("symbol %s: section out of bounds", name);
548*61046927SAndroid Build Coastguard Worker return false;
549*61046927SAndroid Build Coastguard Worker }
550*61046927SAndroid Build Coastguard Worker
551*61046927SAndroid Build Coastguard Worker struct ac_rtld_section *s = &part->sections[sym->st_shndx];
552*61046927SAndroid Build Coastguard Worker if (!s->is_rx) {
553*61046927SAndroid Build Coastguard Worker report_errorf("symbol %s: bad section", name);
554*61046927SAndroid Build Coastguard Worker return false;
555*61046927SAndroid Build Coastguard Worker }
556*61046927SAndroid Build Coastguard Worker
557*61046927SAndroid Build Coastguard Worker uint64_t section_base = u->rx_va + s->offset;
558*61046927SAndroid Build Coastguard Worker
559*61046927SAndroid Build Coastguard Worker *value = section_base + sym->st_value;
560*61046927SAndroid Build Coastguard Worker return true;
561*61046927SAndroid Build Coastguard Worker }
562*61046927SAndroid Build Coastguard Worker
apply_relocs(const struct ac_rtld_upload_info * u,unsigned part_idx,const Elf64_Shdr * reloc_shdr,const Elf_Data * reloc_data)563*61046927SAndroid Build Coastguard Worker static bool apply_relocs(const struct ac_rtld_upload_info *u, unsigned part_idx,
564*61046927SAndroid Build Coastguard Worker const Elf64_Shdr *reloc_shdr, const Elf_Data *reloc_data)
565*61046927SAndroid Build Coastguard Worker {
566*61046927SAndroid Build Coastguard Worker #define report_if(cond) \
567*61046927SAndroid Build Coastguard Worker do { \
568*61046927SAndroid Build Coastguard Worker if ((cond)) { \
569*61046927SAndroid Build Coastguard Worker report_errorf(#cond); \
570*61046927SAndroid Build Coastguard Worker return false; \
571*61046927SAndroid Build Coastguard Worker } \
572*61046927SAndroid Build Coastguard Worker } while (false)
573*61046927SAndroid Build Coastguard Worker #define report_elf_if(cond) \
574*61046927SAndroid Build Coastguard Worker do { \
575*61046927SAndroid Build Coastguard Worker if ((cond)) { \
576*61046927SAndroid Build Coastguard Worker report_elf_errorf(#cond); \
577*61046927SAndroid Build Coastguard Worker return false; \
578*61046927SAndroid Build Coastguard Worker } \
579*61046927SAndroid Build Coastguard Worker } while (false)
580*61046927SAndroid Build Coastguard Worker
581*61046927SAndroid Build Coastguard Worker struct ac_rtld_part *part = &u->binary->parts[part_idx];
582*61046927SAndroid Build Coastguard Worker Elf_Scn *target_scn = elf_getscn(part->elf, reloc_shdr->sh_info);
583*61046927SAndroid Build Coastguard Worker report_elf_if(!target_scn);
584*61046927SAndroid Build Coastguard Worker
585*61046927SAndroid Build Coastguard Worker Elf_Data *target_data = elf_getdata(target_scn, NULL);
586*61046927SAndroid Build Coastguard Worker report_elf_if(!target_data);
587*61046927SAndroid Build Coastguard Worker
588*61046927SAndroid Build Coastguard Worker Elf_Scn *symbols_scn = elf_getscn(part->elf, reloc_shdr->sh_link);
589*61046927SAndroid Build Coastguard Worker report_elf_if(!symbols_scn);
590*61046927SAndroid Build Coastguard Worker
591*61046927SAndroid Build Coastguard Worker Elf64_Shdr *symbols_shdr = elf64_getshdr(symbols_scn);
592*61046927SAndroid Build Coastguard Worker report_elf_if(!symbols_shdr);
593*61046927SAndroid Build Coastguard Worker uint32_t strtabidx = symbols_shdr->sh_link;
594*61046927SAndroid Build Coastguard Worker
595*61046927SAndroid Build Coastguard Worker Elf_Data *symbols_data = elf_getdata(symbols_scn, NULL);
596*61046927SAndroid Build Coastguard Worker report_elf_if(!symbols_data);
597*61046927SAndroid Build Coastguard Worker
598*61046927SAndroid Build Coastguard Worker const Elf64_Sym *symbols = symbols_data->d_buf;
599*61046927SAndroid Build Coastguard Worker size_t num_symbols = symbols_data->d_size / sizeof(Elf64_Sym);
600*61046927SAndroid Build Coastguard Worker
601*61046927SAndroid Build Coastguard Worker struct ac_rtld_section *s = &part->sections[reloc_shdr->sh_info];
602*61046927SAndroid Build Coastguard Worker report_if(!s->is_rx);
603*61046927SAndroid Build Coastguard Worker
604*61046927SAndroid Build Coastguard Worker const char *orig_base = target_data->d_buf;
605*61046927SAndroid Build Coastguard Worker char *dst_base = u->rx_ptr + s->offset;
606*61046927SAndroid Build Coastguard Worker uint64_t va_base = u->rx_va + s->offset;
607*61046927SAndroid Build Coastguard Worker
608*61046927SAndroid Build Coastguard Worker Elf64_Rel *rel = reloc_data->d_buf;
609*61046927SAndroid Build Coastguard Worker size_t num_relocs = reloc_data->d_size / sizeof(*rel);
610*61046927SAndroid Build Coastguard Worker for (size_t i = 0; i < num_relocs; ++i, ++rel) {
611*61046927SAndroid Build Coastguard Worker size_t r_sym = ELF64_R_SYM(rel->r_info);
612*61046927SAndroid Build Coastguard Worker unsigned r_type = ELF64_R_TYPE(rel->r_info);
613*61046927SAndroid Build Coastguard Worker
614*61046927SAndroid Build Coastguard Worker const char *orig_ptr = orig_base + rel->r_offset;
615*61046927SAndroid Build Coastguard Worker char *dst_ptr = dst_base + rel->r_offset;
616*61046927SAndroid Build Coastguard Worker uint64_t va = va_base + rel->r_offset;
617*61046927SAndroid Build Coastguard Worker
618*61046927SAndroid Build Coastguard Worker uint64_t symbol;
619*61046927SAndroid Build Coastguard Worker uint64_t addend;
620*61046927SAndroid Build Coastguard Worker
621*61046927SAndroid Build Coastguard Worker if (r_sym == STN_UNDEF) {
622*61046927SAndroid Build Coastguard Worker symbol = 0;
623*61046927SAndroid Build Coastguard Worker } else {
624*61046927SAndroid Build Coastguard Worker report_elf_if(r_sym >= num_symbols);
625*61046927SAndroid Build Coastguard Worker
626*61046927SAndroid Build Coastguard Worker const Elf64_Sym *sym = &symbols[r_sym];
627*61046927SAndroid Build Coastguard Worker const char *symbol_name = elf_strptr(part->elf, strtabidx, sym->st_name);
628*61046927SAndroid Build Coastguard Worker report_elf_if(!symbol_name);
629*61046927SAndroid Build Coastguard Worker
630*61046927SAndroid Build Coastguard Worker if (!resolve_symbol(u, part_idx, sym, symbol_name, &symbol))
631*61046927SAndroid Build Coastguard Worker return false;
632*61046927SAndroid Build Coastguard Worker }
633*61046927SAndroid Build Coastguard Worker
634*61046927SAndroid Build Coastguard Worker /* TODO: Should we also support .rela sections, where the
635*61046927SAndroid Build Coastguard Worker * addend is part of the relocation record? */
636*61046927SAndroid Build Coastguard Worker
637*61046927SAndroid Build Coastguard Worker /* Load the addend from the ELF instead of the destination,
638*61046927SAndroid Build Coastguard Worker * because the destination may be in VRAM. */
639*61046927SAndroid Build Coastguard Worker switch (r_type) {
640*61046927SAndroid Build Coastguard Worker case R_AMDGPU_ABS32:
641*61046927SAndroid Build Coastguard Worker case R_AMDGPU_ABS32_LO:
642*61046927SAndroid Build Coastguard Worker case R_AMDGPU_ABS32_HI:
643*61046927SAndroid Build Coastguard Worker case R_AMDGPU_REL32:
644*61046927SAndroid Build Coastguard Worker case R_AMDGPU_REL32_LO:
645*61046927SAndroid Build Coastguard Worker case R_AMDGPU_REL32_HI:
646*61046927SAndroid Build Coastguard Worker addend = *(const uint32_t *)orig_ptr;
647*61046927SAndroid Build Coastguard Worker break;
648*61046927SAndroid Build Coastguard Worker case R_AMDGPU_ABS64:
649*61046927SAndroid Build Coastguard Worker case R_AMDGPU_REL64:
650*61046927SAndroid Build Coastguard Worker addend = *(const uint64_t *)orig_ptr;
651*61046927SAndroid Build Coastguard Worker break;
652*61046927SAndroid Build Coastguard Worker default:
653*61046927SAndroid Build Coastguard Worker report_errorf("unsupported r_type == %u", r_type);
654*61046927SAndroid Build Coastguard Worker return false;
655*61046927SAndroid Build Coastguard Worker }
656*61046927SAndroid Build Coastguard Worker
657*61046927SAndroid Build Coastguard Worker uint64_t abs = symbol + addend;
658*61046927SAndroid Build Coastguard Worker
659*61046927SAndroid Build Coastguard Worker switch (r_type) {
660*61046927SAndroid Build Coastguard Worker case R_AMDGPU_ABS32:
661*61046927SAndroid Build Coastguard Worker assert((uint32_t)abs == abs);
662*61046927SAndroid Build Coastguard Worker FALLTHROUGH;
663*61046927SAndroid Build Coastguard Worker case R_AMDGPU_ABS32_LO:
664*61046927SAndroid Build Coastguard Worker *(uint32_t *)dst_ptr = util_cpu_to_le32(abs);
665*61046927SAndroid Build Coastguard Worker break;
666*61046927SAndroid Build Coastguard Worker case R_AMDGPU_ABS32_HI:
667*61046927SAndroid Build Coastguard Worker *(uint32_t *)dst_ptr = util_cpu_to_le32(abs >> 32);
668*61046927SAndroid Build Coastguard Worker break;
669*61046927SAndroid Build Coastguard Worker case R_AMDGPU_ABS64:
670*61046927SAndroid Build Coastguard Worker *(uint64_t *)dst_ptr = util_cpu_to_le64(abs);
671*61046927SAndroid Build Coastguard Worker break;
672*61046927SAndroid Build Coastguard Worker case R_AMDGPU_REL32:
673*61046927SAndroid Build Coastguard Worker assert((int64_t)(int32_t)(abs - va) == (int64_t)(abs - va));
674*61046927SAndroid Build Coastguard Worker FALLTHROUGH;
675*61046927SAndroid Build Coastguard Worker case R_AMDGPU_REL32_LO:
676*61046927SAndroid Build Coastguard Worker *(uint32_t *)dst_ptr = util_cpu_to_le32(abs - va);
677*61046927SAndroid Build Coastguard Worker break;
678*61046927SAndroid Build Coastguard Worker case R_AMDGPU_REL32_HI:
679*61046927SAndroid Build Coastguard Worker *(uint32_t *)dst_ptr = util_cpu_to_le32((abs - va) >> 32);
680*61046927SAndroid Build Coastguard Worker break;
681*61046927SAndroid Build Coastguard Worker case R_AMDGPU_REL64:
682*61046927SAndroid Build Coastguard Worker *(uint64_t *)dst_ptr = util_cpu_to_le64(abs - va);
683*61046927SAndroid Build Coastguard Worker break;
684*61046927SAndroid Build Coastguard Worker default:
685*61046927SAndroid Build Coastguard Worker unreachable("bad r_type");
686*61046927SAndroid Build Coastguard Worker }
687*61046927SAndroid Build Coastguard Worker }
688*61046927SAndroid Build Coastguard Worker
689*61046927SAndroid Build Coastguard Worker return true;
690*61046927SAndroid Build Coastguard Worker
691*61046927SAndroid Build Coastguard Worker #undef report_if
692*61046927SAndroid Build Coastguard Worker #undef report_elf_if
693*61046927SAndroid Build Coastguard Worker }
694*61046927SAndroid Build Coastguard Worker
695*61046927SAndroid Build Coastguard Worker /**
696*61046927SAndroid Build Coastguard Worker * Upload the binary or binaries to the provided GPU buffers, including
697*61046927SAndroid Build Coastguard Worker * relocations.
698*61046927SAndroid Build Coastguard Worker */
ac_rtld_upload(struct ac_rtld_upload_info * u)699*61046927SAndroid Build Coastguard Worker int ac_rtld_upload(struct ac_rtld_upload_info *u)
700*61046927SAndroid Build Coastguard Worker {
701*61046927SAndroid Build Coastguard Worker #define report_if(cond) \
702*61046927SAndroid Build Coastguard Worker do { \
703*61046927SAndroid Build Coastguard Worker if ((cond)) { \
704*61046927SAndroid Build Coastguard Worker report_errorf(#cond); \
705*61046927SAndroid Build Coastguard Worker return -1; \
706*61046927SAndroid Build Coastguard Worker } \
707*61046927SAndroid Build Coastguard Worker } while (false)
708*61046927SAndroid Build Coastguard Worker #define report_elf_if(cond) \
709*61046927SAndroid Build Coastguard Worker do { \
710*61046927SAndroid Build Coastguard Worker if ((cond)) { \
711*61046927SAndroid Build Coastguard Worker report_errorf(#cond); \
712*61046927SAndroid Build Coastguard Worker return -1; \
713*61046927SAndroid Build Coastguard Worker } \
714*61046927SAndroid Build Coastguard Worker } while (false)
715*61046927SAndroid Build Coastguard Worker
716*61046927SAndroid Build Coastguard Worker int size = 0;
717*61046927SAndroid Build Coastguard Worker if (u->binary->options.halt_at_entry) {
718*61046927SAndroid Build Coastguard Worker /* s_sethalt 1 */
719*61046927SAndroid Build Coastguard Worker *(uint32_t *)u->rx_ptr = util_cpu_to_le32(0xbf8d0001);
720*61046927SAndroid Build Coastguard Worker }
721*61046927SAndroid Build Coastguard Worker
722*61046927SAndroid Build Coastguard Worker /* First pass: upload raw section data and lay out private LDS symbols. */
723*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < u->binary->num_parts; ++i) {
724*61046927SAndroid Build Coastguard Worker struct ac_rtld_part *part = &u->binary->parts[i];
725*61046927SAndroid Build Coastguard Worker
726*61046927SAndroid Build Coastguard Worker bool first_section = true;
727*61046927SAndroid Build Coastguard Worker Elf_Scn *section = NULL;
728*61046927SAndroid Build Coastguard Worker while ((section = elf_nextscn(part->elf, section))) {
729*61046927SAndroid Build Coastguard Worker Elf64_Shdr *shdr = elf64_getshdr(section);
730*61046927SAndroid Build Coastguard Worker struct ac_rtld_section *s = &part->sections[elf_ndxscn(section)];
731*61046927SAndroid Build Coastguard Worker
732*61046927SAndroid Build Coastguard Worker if (!s->is_rx)
733*61046927SAndroid Build Coastguard Worker continue;
734*61046927SAndroid Build Coastguard Worker
735*61046927SAndroid Build Coastguard Worker report_if(shdr->sh_type != SHT_PROGBITS);
736*61046927SAndroid Build Coastguard Worker
737*61046927SAndroid Build Coastguard Worker Elf_Data *data = elf_getdata(section, NULL);
738*61046927SAndroid Build Coastguard Worker report_elf_if(!data || data->d_size != shdr->sh_size);
739*61046927SAndroid Build Coastguard Worker
740*61046927SAndroid Build Coastguard Worker if (i > 0 && first_section && u->binary->options.waitcnt_wa) {
741*61046927SAndroid Build Coastguard Worker assert(s->offset >= 4);
742*61046927SAndroid Build Coastguard Worker *(uint32_t *)(u->rx_ptr + s->offset - 4) = util_cpu_to_le32(0xbf880fff);
743*61046927SAndroid Build Coastguard Worker first_section = false;
744*61046927SAndroid Build Coastguard Worker }
745*61046927SAndroid Build Coastguard Worker
746*61046927SAndroid Build Coastguard Worker memcpy(u->rx_ptr + s->offset, data->d_buf, shdr->sh_size);
747*61046927SAndroid Build Coastguard Worker
748*61046927SAndroid Build Coastguard Worker size = MAX2(size, s->offset + shdr->sh_size);
749*61046927SAndroid Build Coastguard Worker }
750*61046927SAndroid Build Coastguard Worker }
751*61046927SAndroid Build Coastguard Worker
752*61046927SAndroid Build Coastguard Worker if (u->binary->rx_end_markers) {
753*61046927SAndroid Build Coastguard Worker uint32_t *dst = (uint32_t *)(u->rx_ptr + u->binary->rx_end_markers);
754*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < DEBUGGER_NUM_MARKERS; ++i)
755*61046927SAndroid Build Coastguard Worker *dst++ = util_cpu_to_le32(DEBUGGER_END_OF_CODE_MARKER);
756*61046927SAndroid Build Coastguard Worker size += 4 * DEBUGGER_NUM_MARKERS;
757*61046927SAndroid Build Coastguard Worker }
758*61046927SAndroid Build Coastguard Worker
759*61046927SAndroid Build Coastguard Worker /* Second pass: handle relocations, overwriting uploaded data where
760*61046927SAndroid Build Coastguard Worker * appropriate. */
761*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < u->binary->num_parts; ++i) {
762*61046927SAndroid Build Coastguard Worker struct ac_rtld_part *part = &u->binary->parts[i];
763*61046927SAndroid Build Coastguard Worker Elf_Scn *section = NULL;
764*61046927SAndroid Build Coastguard Worker while ((section = elf_nextscn(part->elf, section))) {
765*61046927SAndroid Build Coastguard Worker Elf64_Shdr *shdr = elf64_getshdr(section);
766*61046927SAndroid Build Coastguard Worker if (shdr->sh_type == SHT_REL) {
767*61046927SAndroid Build Coastguard Worker Elf_Data *relocs = elf_getdata(section, NULL);
768*61046927SAndroid Build Coastguard Worker report_elf_if(!relocs || relocs->d_size != shdr->sh_size);
769*61046927SAndroid Build Coastguard Worker if (!apply_relocs(u, i, shdr, relocs))
770*61046927SAndroid Build Coastguard Worker return -1;
771*61046927SAndroid Build Coastguard Worker } else if (shdr->sh_type == SHT_RELA) {
772*61046927SAndroid Build Coastguard Worker report_errorf("SHT_RELA not supported");
773*61046927SAndroid Build Coastguard Worker return -1;
774*61046927SAndroid Build Coastguard Worker }
775*61046927SAndroid Build Coastguard Worker }
776*61046927SAndroid Build Coastguard Worker }
777*61046927SAndroid Build Coastguard Worker
778*61046927SAndroid Build Coastguard Worker return size;
779*61046927SAndroid Build Coastguard Worker
780*61046927SAndroid Build Coastguard Worker #undef report_if
781*61046927SAndroid Build Coastguard Worker #undef report_elf_if
782*61046927SAndroid Build Coastguard Worker }
783