Document new tristate __libc_missing_32bit_uids.
[kopensolaris-gnu/glibc.git] / sysdeps / arm / dl-machine.h
index e6a686e..78341fc 100644 (file)
@@ -1,5 +1,5 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  ARM version.
-   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
 
 #include <sys/param.h>
 
-#include <assert.h>
+#define VALID_ELF_ABIVERSION(ver)      (ver == 0)
+#define VALID_ELF_OSABI(osabi) \
+  (osabi == ELFOSABI_SYSV || osabi == ELFOSABI_ARM)
+#define VALID_ELF_HEADER(hdr,exp,size) \
+  memcmp (hdr,exp,size-2) == 0 \
+  && VALID_ELF_OSABI (hdr[EI_OSABI]) \
+  && VALID_ELF_ABIVERSION (hdr[EI_ABIVERSION])
+
+#define CLEAR_CACHE(BEG,END)                                           \
+{                                                                      \
+  register unsigned long _beg __asm ("a1") = (unsigned long)(BEG);     \
+  register unsigned long _end __asm ("a2") = (unsigned long)(END);     \
+  register unsigned long _flg __asm ("a3") = 0;                                \
+  __asm __volatile ("swi 0x9f0002              @ sys_cacheflush"       \
+                   : /* no outputs */                                  \
+                   : /* no inputs */                                   \
+                   : "a1");                                            \
+}
 
 /* Return nonzero iff E_MACHINE is compatible with the running host.  */
 static inline int __attribute__ ((unused))
@@ -52,22 +69,14 @@ elf_machine_dynamic (void)
 
 
 /* Return the run-time load address of the shared object.  */
-// patb
 static inline Elf32_Addr __attribute__ ((unused))
 elf_machine_load_address (void)
 {
-  Elf32_Addr addr;
-  asm (" ldr ip,.L1
-       ldr r3,.L3
-       add r3, r3, sl
-       ldr ip,[sl, ip]
-       sub ip, r3, ip
-       b .L2
-       .L1: .word _dl_start(GOT)
-       .L3: .word _dl_start(GOTOFF)
-       .L2: mov %0, ip"
-       : "=r" (addr) : : "ip", "r3");
-  return addr;
+  extern void __dl_start asm ("_dl_start");
+  Elf32_Addr got_addr = (Elf32_Addr) &__dl_start;
+  Elf32_Addr pcrel_addr;
+  asm ("adr %0, _dl_start" : "=r" (pcrel_addr));
+  return pcrel_addr - got_addr;
 }
 
 
@@ -88,7 +97,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
         in.  Their initial contents will arrange when called to push an
         index into the .got section, load ip with &_GLOBAL_OFFSET_TABLE_[3],
         and then jump to _GLOBAL_OFFSET_TABLE[2].  */
-      got = (Elf32_Addr *) (l->l_addr + l->l_info[DT_PLTGOT]->d_un.d_ptr);
+      got = (Elf32_Addr *) l->l_info[DT_PLTGOT]->d_un.d_ptr;
       got[1] = (Elf32_Addr) l; /* Identify this shared object.  */
 
       /* The got[2] entry contains the address of a function which gets
@@ -144,7 +153,6 @@ _dl_runtime_resolve:
        stmdb   sp!,{r0-r3,sl,fp}
 
        @ prepare to call fixup()
-
        @ change &GOT[n+3] into 8*n        NOTE: reloc are 8 bytes each
        sub     r1, ip, lr
        sub     r1, r1, #4
@@ -153,6 +161,7 @@ _dl_runtime_resolve:
        @ get pointer to linker struct
        ldr     r0, [lr, #-4]
 
+       @ call fixup routine
        " CALL_ROUTINE(fixup) "
 
        @ save the return
@@ -170,16 +179,10 @@ _dl_runtime_resolve:
        .type _dl_runtime_profile, #function
        .align 2
 _dl_runtime_profile:
-       @ we get caled with
-       @       stack[0] contains the return address from this call
-       @       ip contains &GOT[n+3] (pointer to function)
-       @       lr points to &GOT[2]
-
-       @ save almost everything; return add is already on the stack
-       stmdb   sp!,{r0-r3,fp}
+       @ save almost everything; lr is already on the stack
+       stmdb   sp!,{r0-r3,sl,fp}
 
        @ prepare to call fixup()
-
        @ change &GOT[n+3] into 8*n        NOTE: reloc are 8 bytes each
        sub     r1, ip, lr
        sub     r1, r1, #4
@@ -188,18 +191,19 @@ _dl_runtime_profile:
        @ get pointer to linker struct
        ldr     r0, [lr, #-4]
 
+       @ call profiling fixup routine
        " CALL_ROUTINE(profile_fixup) "
 
        @ save the return
        mov     ip, r0
 
        @ restore the stack
-       ldmia   sp!,{r0-r3,fp,lr}
+       ldmia   sp!,{r0-r3,sl,fp,lr}
 
        @ jump to the newly found address
        mov     pc, ip
 
-       .size _dl_runtime_profile, .-_dl_runtime_profile
+       .size _dl_runtime_resolve, .-_dl_runtime_resolve
        .previous
 ");
 #else // PROF
@@ -212,15 +216,33 @@ _dl_runtime_profile:
        .align 2
 _dl_runtime_resolve:
 _dl_runtime_profile:
-       stmdb   sp!,{r0-r3,fp}
-       ldr     r1,[sp,#0x34]
+       @ we get called with
+       @       stack[0] contains the return address from this call
+       @       ip contains &GOT[n+3] (pointer to function)
+       @       lr points to &GOT[2]
+
+       @ save almost everything; return add is already on the stack
+       stmdb   sp!,{r0-r3,sl,fp}
+
+       @ prepare to call fixup()
+       @ change &GOT[n+3] into 8*n        NOTE: reloc are 8 bytes each
        sub     r1, ip, lr
        sub     r1, r1, #4
        add     r1, r1, r1
+
+       @ get pointer to linker struct
        ldr     r0, [lr, #-4]
+
+       @ call profiling fixup routine
        " CALL_ROUTINE(fixup) "
+
+       @ save the return
        mov     ip, r0
-       ldmia   sp!,{r0-r3,fp,lr}
+
+       @ restore the stack
+       ldmia   sp!,{r0-r3,sl,fp,lr}
+
+       @ jump to the newly found address
        mov     pc, ip
 
        .size _dl_runtime_profile, .-_dl_runtime_profile
@@ -251,6 +273,10 @@ _dl_start_user:
        ldr     sl, .L_GET_GOT
        add     sl, pc, sl
 .L_GOT_GOT:
+       @ Store the highest stack address
+       ldr     r1, .L_STACK_END
+       ldr     r1, [sl, r1]
+       str     sp, [r1]
        @ See if we were run as a command with the executable file
        @ name as an extra leading argument.
        ldr     r1, .L_SKIP_ARGS
@@ -265,9 +291,9 @@ _dl_start_user:
        str     r0, [sp]
 
        @ now we enter a _dl_init_next loop
-       ldr     r2, .L_DEF_SCOPE
-       ldr     r2, [sl, r2]
-       ldr     r4, [r2, #8]
+       ldr     r4, .L_MAIN_SEARCHLIST
+       ldr     r4, [sl, r4]
+       ldr     r4, [r4]
        @ call _dl_init_next to get the address of an initalizer
 0:     mov     r0, r4
        bl      _dl_init_next(PLT)
@@ -293,12 +319,14 @@ _dl_start_user:
        .word   _GLOBAL_OFFSET_TABLE_ - .L_GOT_GOT - 4  \n\
 .L_SKIP_ARGS:                                  \n\
        .word   _dl_skip_args(GOTOFF)           \n\
-.L_DEF_SCOPE:                                  \n\
-       .word   _dl_default_scope(GOT)          \n\
 .L_STARTUP_FLAG:
        .word   _dl_starting_up(GOT)
 .L_FINI_PROC:
        .word   _dl_fini(GOT)
+.L_STACK_END:
+       .word   __libc_stack_end(GOT)
+.L_MAIN_SEARCHLIST:
+       .word   _dl_main_searchlist(GOT)
 .previous\n\
 ");
 
@@ -313,7 +341,7 @@ _dl_start_user:
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
 #define ELF_MACHINE_JMP_SLOT   R_ARM_JUMP_SLOT
 
-/* The i386 never uses Elf32_Rela relocations.  */
+/* The ARM never uses Elf32_Rela relocations.  */
 #define ELF_MACHINE_NO_RELA 1
 
 /* We define an initialization functions.  This is called very early in
@@ -325,10 +353,9 @@ extern const char *_dl_platform;
 static inline void __attribute__ ((unused))
 dl_platform_init (void)
 {
-  if (_dl_platform == NULL)
-    /* We default to ARM
-    This is where processors could be distinguished arm2, arm6, sa110, etc */
-    _dl_platform = "ARM";
+  if (_dl_platform != NULL && *_dl_platform == '\0')
+    /* Avoid an empty string which would disturb us.  */
+    _dl_platform = NULL;
 }
 
 static inline void
@@ -386,8 +413,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
            {
              const char *strtab;
 
-             strtab = ((const char *) map->l_addr
-                       + map->l_info[DT_STRTAB]->d_un.d_ptr);
+             strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
              _dl_sysdep_error (_dl_argv[0] ?: "<program name unknown>",
                                ": Symbol `", strtab + refsym->st_name,
                                "' has different size in shared object, "
@@ -398,36 +424,13 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
          break;
        case R_ARM_GLOB_DAT:
        case R_ARM_JUMP_SLOT:
-
-#if 0
-#define _HEX(i) for (j=28; j>=0; j-=4) b[7-j/4]="0123456789abcdef"[((int)i>>j)&15];
-{
-char b[10];
-int j;
-_HEX(map->l_addr);
-__asm__ (" mov r0, #2; mov r1, %0; mov r2, #9; swi 0x00900004; "
-       : : "r"(b) : "r0", "r1", "r2" );
-_HEX(sym->st_size);
-__asm__ (" mov r0, #2; mov r1, %0; mov r2, #9; swi 0x00900004; "
-       : : "r"(b) : "r0", "r1", "r2" );
-_HEX(&sym->st_value);
-__asm__ (" mov r0, #2; mov r1, %0; mov r2, #9; swi 0x00900004; "
-       : : "r"(b) : "r0", "r1", "r2" );
-_HEX(sym->st_value);
-__asm__ (" mov r0, #2; mov r1, %0; mov r2, #9; swi 0x00900004; "
-       : : "r"(b) : "r0", "r1", "r2" );
-_HEX(sym);
-__asm__ (" mov r0, #2; mov r1, %0; mov r2, #9; swi 0x00900004; "
-       : : "r"(b) : "r0", "r1", "r2" );
-_HEX(reloc_addr);
-__asm__ (" mov r0, #2; mov r1, %0; mov r2, #9; swi 0x00900004; "
-       : : "r"(b) : "r0", "r1", "r2" );
-b[0]=' '; b[1]='\n';
-__asm__ (" mov r0, #2; mov r1, %0; mov r2, #2; swi 0x00900004; "
-       : : "r"(b) : "r0", "r1", "r2" );
-}
+#ifdef RTLD_BOOTSTRAP
+         /* Fix weak undefined references.  */
+         if (sym != NULL && sym->st_value == 0)
+           *reloc_addr = 0;
+         else
 #endif
-         *reloc_addr = value;
+           *reloc_addr = value;
          break;
        case R_ARM_ABS32:
          {
@@ -451,28 +454,39 @@ __asm__ (" mov r0, #2; mov r1, %0; mov r2, #2; swi 0x00900004; "
            break;
          }
        case R_ARM_PC24:
-         *reloc_addr += (value - (Elf32_Addr) reloc_addr);
-         break;
+         {
+            signed int addend;
+
+            addend = *reloc_addr & 0x00ffffff;
+            if (addend & 0x00800000) addend |= 0xff000000;
+
+            value = value - (unsigned int)reloc_addr + (addend << 2);
+            if (value & 0xfc000003)
+              _dl_signal_error (0, map->l_name,
+                         "R_ARM_PC24 relocation out of range");
+              
+            value = value >> 2;
+            value = (*reloc_addr & 0xff000000) | (value & 0x00ffffff);
+            *reloc_addr = value;
+         }
+       break;
        default:
-         assert (! "unexpected dynamic reloc type");
+         _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 0);
          break;
        }
     }
 }
 
 static inline void
-elf_machine_lazy_rel (struct link_map *map, const Elf32_Rel *reloc)
+elf_machine_lazy_rel (struct link_map *map,
+                     Elf32_Addr l_addr, const Elf32_Rel *reloc)
 {
-  Elf32_Addr *const reloc_addr = (void *) (map->l_addr + reloc->r_offset);
-  switch (ELF32_R_TYPE (reloc->r_info))
-    {
-    case R_ARM_JUMP_SLOT:
-      *reloc_addr += map->l_addr;
-      break;
-    default:
-      assert (! "unexpected PLT reloc type");
-      break;
-    }
+  Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
+  /* Check for unexpected PLT reloc type.  */
+  if (ELF32_R_TYPE (reloc->r_info) == R_ARM_JUMP_SLOT)
+    *reloc_addr += l_addr;
+  else
+    _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
 }
 
 #endif /* RESOLVE */