xref: /aosp_15_r20/external/mesa3d/src/amd/common/ac_rtld.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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, &section_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