~ubuntu-branches/ubuntu/trusty/eglibc/trusty

« back to all changes in this revision

Viewing changes to ports/sysdeps/aarch64/dl-machine.h

  • Committer: Package Import Robot
  • Author(s): Adam Conrad
  • Date: 2013-01-10 18:39:35 UTC
  • mfrom: (1.5.2) (4.4.24 experimental)
  • Revision ID: package-import@ubuntu.com-20130110183935-afsgfxkmg7wk5eaj
Tags: 2.17-0ubuntu1
* Merge with Debian, bringing in a new upstream and many small fixes:
  - patches/any/cvs-malloc-deadlock.diff: Dropped, merged upstream.
  - patches/ubuntu/lddebug-scopes.diff: Rebase for upstream changes.
  - patches/ubuntu/local-CVE-2012-3406.diff: Rebased against upstream.
  - patches/ubuntu/no-asm-mtune-i686.diff: Fixed in recent binutils.
* This upstream merge fixes a nasty hang in pulseaudio (LP: #1085342)
* Bump MIN_KERNEL_SUPPORTED to 2.6.32 on ARM, now that we no longer
  have to support shonky 2.6.31 kernels on imx51 babbage builders.
* Drop patches/ubuntu/local-disable-nscd-host-caching.diff, as these
  issues were apparently resolved upstream a while ago (LP: #613662)
* Fix the compiled-in bug URL to point to launchpad.net, not Debian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 1995-2012 Free Software Foundation, Inc.
 
2
 
 
3
   This file is part of the GNU C Library.
 
4
 
 
5
   The GNU C Library is free software; you can redistribute it and/or
 
6
   modify it under the terms of the GNU Lesser General Public License as
 
7
   published by the Free Software Foundation; either version 2.1 of the
 
8
   License, or (at your option) any later version.
 
9
 
 
10
   The GNU C Library is distributed in the hope that it will be useful,
 
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
   Lesser General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU Lesser General Public
 
16
   License along with the GNU C Library; if not, see
 
17
   <http://www.gnu.org/licenses/>.  */
 
18
 
 
19
#ifndef dl_machine_h
 
20
#define dl_machine_h
 
21
 
 
22
#define ELF_MACHINE_NAME "aarch64"
 
23
 
 
24
#include <tls.h>
 
25
#include <dl-tlsdesc.h>
 
26
 
 
27
/* Return nonzero iff ELF header is compatible with the running host.  */
 
28
static inline int __attribute__ ((unused))
 
29
elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
 
30
{
 
31
  return ehdr->e_machine == EM_AARCH64;
 
32
}
 
33
 
 
34
/* Return the link-time address of _DYNAMIC.  Conveniently, this is the
 
35
   first element of the GOT. */
 
36
static inline ElfW(Addr) __attribute__ ((unused))
 
37
elf_machine_dynamic (void)
 
38
{
 
39
  ElfW(Addr) addr = (ElfW(Addr)) &_DYNAMIC;
 
40
  return addr;
 
41
}
 
42
 
 
43
/* Return the run-time load address of the shared object.  */
 
44
 
 
45
static inline ElfW(Addr) __attribute__ ((unused))
 
46
elf_machine_load_address (void)
 
47
{
 
48
  /* To figure out the load address we use the definition that for any symbol:
 
49
     dynamic_addr(symbol) = static_addr(symbol) + load_addr
 
50
 
 
51
     The choice of symbol is arbitrary. The static address we obtain
 
52
     by constructing a non GOT reference to the symbol, the dynamic
 
53
     address of the symbol we compute using adrp/add to compute the
 
54
     symbol's address relative to the PC. */
 
55
 
 
56
  ElfW(Addr) static_addr;
 
57
  ElfW(Addr) dynamic_addr;
 
58
 
 
59
  asm ("                                        \n\
 
60
        adrp    %1, _dl_start;                  \n\
 
61
        add     %1, %1, #:lo12:_dl_start        \n\
 
62
        ldr     %w0, 1f                         \n\
 
63
        b       2f                              \n\
 
64
1:      .word   _dl_start                       \n\
 
65
2:                                              \n\
 
66
       " : "=r" (static_addr),  "=r" (dynamic_addr));
 
67
  return dynamic_addr - static_addr;
 
68
}
 
69
 
 
70
/* Set up the loaded object described by L so its unrelocated PLT
 
71
   entries will jump to the on-demand fixup code in dl-runtime.c.  */
 
72
 
 
73
static inline int __attribute__ ((unused))
 
74
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 
75
{
 
76
  if (l->l_info[DT_JMPREL] && lazy)
 
77
    {
 
78
      ElfW(Addr) *got;
 
79
      extern void _dl_runtime_resolve (ElfW(Word));
 
80
      extern void _dl_runtime_profile (ElfW(Word));
 
81
 
 
82
      got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
 
83
      if (got[1])
 
84
        {
 
85
          l->l_mach.plt = got[1] + l->l_addr;
 
86
        }
 
87
      got[1] = (ElfW(Addr)) l;
 
88
 
 
89
      /* The got[2] entry contains the address of a function which gets
 
90
         called to get the address of a so far unresolved function and
 
91
         jump to it.  The profiling extension of the dynamic linker allows
 
92
         to intercept the calls to collect information.  In this case we
 
93
         don't store the address in the GOT so that all future calls also
 
94
         end in this function.  */
 
95
      if ( profile)
 
96
        {
 
97
           got[2] = (ElfW(Addr)) &_dl_runtime_profile;
 
98
 
 
99
          if (GLRO(dl_profile) != NULL
 
100
              && _dl_name_match_p (GLRO(dl_profile), l))
 
101
            /* Say that we really want profiling and the timers are
 
102
               started.  */
 
103
            GL(dl_profile_map) = l;
 
104
        }
 
105
      else
 
106
        {
 
107
          /* This function will get called to fix up the GOT entry
 
108
             indicated by the offset on the stack, and then jump to
 
109
             the resolved address.  */
 
110
          got[2] = (ElfW(Addr)) &_dl_runtime_resolve;
 
111
        }
 
112
    }
 
113
 
 
114
  if (l->l_info[ADDRIDX (DT_TLSDESC_GOT)] && lazy)
 
115
    *(Elf64_Addr*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_GOT)]) + l->l_addr)
 
116
      = (Elf64_Addr) &_dl_tlsdesc_resolve_rela;
 
117
 
 
118
  return lazy;
 
119
}
 
120
 
 
121
/* Initial entry point for the dynamic linker. The C function
 
122
   _dl_start is the real entry point, its return value is the user
 
123
   program's entry point */
 
124
 
 
125
#define RTLD_START asm ("\
 
126
.text                                                           \n\
 
127
.globl _start                                                   \n\
 
128
.type _start, %function                                         \n\
 
129
.globl _dl_start_user                                           \n\
 
130
.type _dl_start_user, %function                                 \n\
 
131
_start:                                                         \n\
 
132
        mov     x0,     sp                                      \n\
 
133
        bl      _dl_start                                       \n\
 
134
        // returns user entry point in x0                       \n\
 
135
        mov     x21, x0                                         \n\
 
136
_dl_start_user:                                                 \n\
 
137
        // get the original arg count                           \n\
 
138
        ldr     x1, [sp]                                        \n\
 
139
        // get the argv address                                 \n\
 
140
        add     x2, sp, #8                                      \n\
 
141
        // get _dl_skip_args to see if we were                  \n\
 
142
        // invoked as an executable                             \n\
 
143
        adrp    x4, _dl_skip_args                               \n\
 
144
        ldr     w4, [x4, #:lo12:_dl_skip_args]                  \n\
 
145
        // do we need to adjust argc/argv                       \n\
 
146
        cmp     w4, 0                                           \n\
 
147
        beq     .L_done_stack_adjust                            \n\
 
148
        // subtract _dl_skip_args from original arg count       \n\
 
149
        sub     x1, x1, x4                                      \n\
 
150
        // store adjusted argc back to stack                    \n\
 
151
        str     x1, [sp]                                        \n\
 
152
        // find the first unskipped argument                    \n\
 
153
        mov     x3, x2                                          \n\
 
154
        add     x4, x2, x4, lsl #3                              \n\
 
155
        // shuffle argv down                                    \n\
 
156
1:      ldr     x5, [x4], #8                                    \n\
 
157
        str     x5, [x3], #8                                    \n\
 
158
        cmp     x5, #0                                          \n\
 
159
        bne     1b                                              \n\
 
160
        // shuffle envp down                                    \n\
 
161
1:      ldr     x5, [x4], #8                                    \n\
 
162
        str     x5, [x3], #8                                    \n\
 
163
        cmp     x5, #0                                          \n\
 
164
        bne     1b                                              \n\
 
165
        // shuffle auxv down                                    \n\
 
166
1:      ldp     x0, x5, [x4, #16]!                              \n\
 
167
        stp     x0, x5, [x3], #16                               \n\
 
168
        cmp     x0, #0                                          \n\
 
169
        bne     1b                                              \n\
 
170
        // Update _dl_argv                                      \n\
 
171
        adrp    x3, _dl_argv                                    \n\
 
172
        str     x2, [x3, #:lo12:_dl_argv]                       \n\
 
173
.L_done_stack_adjust:                                           \n\
 
174
        // compute envp                                         \n\
 
175
        add     x3, x2, x1, lsl #3                              \n\
 
176
        add     x3, x3, #8                                      \n\
 
177
        adrp    x16, _rtld_local                                \n\
 
178
        add     x16, x16, #:lo12:_rtld_local                    \n\
 
179
        ldr     x0, [x16]                                       \n\
 
180
        bl      _dl_init_internal                               \n\
 
181
        // load the finalizer function                          \n\
 
182
        adrp    x0, _dl_fini                                    \n\
 
183
        add     x0, x0, #:lo12:_dl_fini                         \n\
 
184
        // jump to the user_s entry point                       \n\
 
185
        br      x21                                             \n\
 
186
");
 
187
 
 
188
#define elf_machine_type_class(type)                                    \
 
189
  ((((type) == R_AARCH64_JUMP_SLOT ||                                   \
 
190
     (type) == R_AARCH64_TLS_DTPMOD64 ||                                \
 
191
     (type) == R_AARCH64_TLS_DTPREL64 ||                                \
 
192
     (type) == R_AARCH64_TLS_TPREL64 ||                                 \
 
193
     (type) == R_AARCH64_TLSDESC) * ELF_RTYPE_CLASS_PLT)                \
 
194
   | (((type) == R_AARCH64_COPY) * ELF_RTYPE_CLASS_COPY))
 
195
 
 
196
#define ELF_MACHINE_JMP_SLOT    R_AARCH64_JUMP_SLOT
 
197
 
 
198
/* AArch64 uses RELA not REL */
 
199
#define ELF_MACHINE_NO_REL 1
 
200
 
 
201
static inline ElfW(Addr)
 
202
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
 
203
                       const ElfW(Rela) *reloc,
 
204
                       ElfW(Addr) *reloc_addr,
 
205
                       ElfW(Addr) value)
 
206
{
 
207
  return *reloc_addr = value;
 
208
}
 
209
 
 
210
/* Return the final value of a plt relocation.  */
 
211
static inline ElfW(Addr)
 
212
elf_machine_plt_value (struct link_map *map,
 
213
                       const ElfW(Rela) *reloc,
 
214
                       ElfW(Addr) value)
 
215
{
 
216
  return value;
 
217
}
 
218
 
 
219
#endif
 
220
 
 
221
/* Names of the architecture-specific auditing callback functions.  */
 
222
#define ARCH_LA_PLTENTER aarch64_gnu_pltenter
 
223
#define ARCH_LA_PLTEXIT  aarch64_gnu_pltexit
 
224
 
 
225
#ifdef RESOLVE_MAP
 
226
 
 
227
auto inline void
 
228
__attribute__ ((always_inline))
 
229
elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
 
230
                  const ElfW(Sym) *sym, const struct r_found_version *version,
 
231
                  void *const reloc_addr_arg, int skip_ifunc)
 
232
{
 
233
  ElfW(Addr) *const reloc_addr = reloc_addr_arg;
 
234
  const unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
 
235
 
 
236
  if (__builtin_expect (r_type == R_AARCH64_RELATIVE, 0))
 
237
      *reloc_addr = map->l_addr + reloc->r_addend;
 
238
  else if (__builtin_expect (r_type == R_AARCH64_NONE, 0))
 
239
      return;
 
240
  else
 
241
    {
 
242
      const ElfW(Sym) *const refsym = sym;
 
243
      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
 
244
      ElfW(Addr) value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
 
245
 
 
246
      switch (r_type)
 
247
        {
 
248
        case R_AARCH64_COPY:
 
249
          if (sym == NULL)
 
250
              break;
 
251
 
 
252
          if (sym->st_size > refsym->st_size
 
253
              || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
 
254
            {
 
255
              const char *strtab;
 
256
 
 
257
              strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
 
258
              _dl_error_printf ("\
 
259
%s: Symbol `%s' has different size in shared object, consider re-linking\n",
 
260
                                rtld_progname ?: "<program name unknown>",
 
261
                                strtab + refsym->st_name);
 
262
            }
 
263
          memcpy (reloc_addr_arg, (void *) value,
 
264
                  MIN (sym->st_size, refsym->st_size));
 
265
          break;
 
266
 
 
267
        case R_AARCH64_RELATIVE:
 
268
        case R_AARCH64_GLOB_DAT:
 
269
        case R_AARCH64_JUMP_SLOT:
 
270
        case R_AARCH64_ABS32:
 
271
        case R_AARCH64_ABS64:
 
272
          *reloc_addr = value + reloc->r_addend;
 
273
          break;
 
274
 
 
275
        case R_AARCH64_TLSDESC:
 
276
          {
 
277
            struct tlsdesc volatile *td =
 
278
              (struct tlsdesc volatile *)reloc_addr;
 
279
#ifndef RTLD_BOOTSTRAP
 
280
            if (! sym)
 
281
              {
 
282
                td->arg = (void*)reloc->r_addend;
 
283
                td->entry = _dl_tlsdesc_undefweak;
 
284
              }
 
285
            else
 
286
#endif
 
287
              {
 
288
#ifndef RTLD_BOOTSTRAP
 
289
# ifndef SHARED
 
290
                CHECK_STATIC_TLS (map, sym_map);
 
291
# else
 
292
                if (!TRY_STATIC_TLS (map, sym_map))
 
293
                  {
 
294
                    td->arg = _dl_make_tlsdesc_dynamic
 
295
                      (sym_map, sym->st_value + reloc->r_addend);
 
296
                    td->entry = _dl_tlsdesc_dynamic;
 
297
                  }
 
298
                else
 
299
# endif
 
300
#endif
 
301
                  {
 
302
                    td->arg = (void*)(sym->st_value + sym_map->l_tls_offset
 
303
                                      + reloc->r_addend);
 
304
                    td->entry = _dl_tlsdesc_return;
 
305
                  }
 
306
              }
 
307
            break;
 
308
          }
 
309
 
 
310
        case R_AARCH64_TLS_DTPMOD64:
 
311
#ifdef RTLD_BOOTSTRAP
 
312
          *reloc_addr = 1;
 
313
#else
 
314
          if (sym_map != NULL)
 
315
            {
 
316
              *reloc_addr = sym_map->l_tls_modid;
 
317
            }
 
318
#endif
 
319
          break;
 
320
 
 
321
        case R_AARCH64_TLS_DTPREL64:
 
322
          if (sym)
 
323
            *reloc_addr = sym->st_value + reloc->r_addend;
 
324
          break;
 
325
 
 
326
        case R_AARCH64_TLS_TPREL64:
 
327
          if (sym)
 
328
            {
 
329
              CHECK_STATIC_TLS (map, sym_map);
 
330
              *reloc_addr =
 
331
                sym->st_value + reloc->r_addend + sym_map->l_tls_offset;
 
332
            }
 
333
          break;
 
334
 
 
335
        default:
 
336
          _dl_reloc_bad_type (map, r_type, 0);
 
337
          break;
 
338
        }
 
339
    }
 
340
}
 
341
 
 
342
inline void
 
343
__attribute__ ((always_inline))
 
344
elf_machine_rela_relative (ElfW(Addr) l_addr,
 
345
                           const ElfW(Rela) *reloc,
 
346
                           void *const reloc_addr_arg)
 
347
{
 
348
  ElfW(Addr) *const reloc_addr = reloc_addr_arg;
 
349
  *reloc_addr = l_addr + reloc->r_addend;
 
350
}
 
351
 
 
352
inline void
 
353
__attribute__ ((always_inline))
 
354
elf_machine_lazy_rel (struct link_map *map,
 
355
                      ElfW(Addr) l_addr,
 
356
                      const ElfW(Rela) *reloc,
 
357
                      int skip_ifunc)
 
358
{
 
359
  ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
 
360
  const unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
 
361
  /* Check for unexpected PLT reloc type.  */
 
362
  if (__builtin_expect (r_type == R_AARCH64_JUMP_SLOT, 1))
 
363
    {
 
364
      if (__builtin_expect (map->l_mach.plt, 0) == 0)
 
365
        *reloc_addr += l_addr;
 
366
      else
 
367
        *reloc_addr = map->l_mach.plt;
 
368
    }
 
369
  else if (__builtin_expect (r_type == R_AARCH64_TLSDESC, 1))
 
370
    {
 
371
      struct tlsdesc volatile *td =
 
372
        (struct tlsdesc volatile *)reloc_addr;
 
373
 
 
374
      td->arg = (void*)reloc;
 
375
      td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
 
376
                          + map->l_addr);
 
377
    }
 
378
  else
 
379
    _dl_reloc_bad_type (map, r_type, 1);
 
380
}
 
381
 
 
382
#endif