1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22/* 23 * Copyright (c) 1988 AT&T 24 * All Rights Reserved 25 * 26 * 27 * Copyright 2000-2002 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30#pragma ident "%Z%%M% %I% %E% SMI" 31 32#if defined(lint) 33 34#include <sys/types.h> 35#include "_rtld.h" 36#include "_audit.h" 37#include "_elf.h" 38 39/* ARGSUSED0 */ 40int 41elf_plt_trace() 42{ 43 return (0); 44} 45#else 46 47#include <link.h> 48#include "_audit.h" 49 50 .file "boot_elf.s" 51 .text 52 53/* 54 * On entry the 'glue code' has already done the following: 55 * 56 * pushl %ebp 57 * movl %esp, %ebp 58 * pushl dyndata_ptr 59 * jmp elf_plt_trace 60 * 61 * so - -4(%ebp) contains the dyndata ptr 62 * 63 * 0x0 uintptr_t reflmp 64 * 0x4 uintptr_t deflmp 65 * 0x8 ulong_t symndx 66 * 0xc ulont_t sb_flags 67 * 0x10 Elf32_Sym symdef.st_name 68 * 0x14 symdef.st_value 69 * 0x18 symdef.st_size 70 * 0x1c symdef.st_info 71 * 0x1d symdef.st_other 72 * 0x1e symdef.st_shndx 73 */ 74#define REFLMP_OFF 0x0 75#define DEFLMP_OFF 0x4 76#define SYMNDX_OFF 0x8 77#define SBFLAGS_OFF 0xc 78#define SYMDEF_OFF 0x10 79#define SYMDEF_VALUE_OFF 0x14 80 81 .globl elf_plt_trace 82 .type elf_plt_trace,@function 83 .align 16 84elf_plt_trace: 85 subl $84,%esp / create some local storage 86 pushl %eax 87 pushl %ebx 88 pushl %edi 89 pushl %esi 90 call .L1 / initialize %ebx to GOT 91.L1: 92 popl %ebx 93 addl $_GLOBAL_OFFSET_TABLE_+[.-.L1], %ebx 94 /* 95 * Local stack space storage is allocated as follows: 96 * 97 * -4(%ebp) store dyndata ptr 98 * -8(%ebp) store call destination 99 * -84(%ebp) space for gregset 100 * -88(%ebp) prev stack size 101 * -92(%ebp) entering %eax 102 * -96(%ebp) entering %ebx 103 * -100(%ebp) entering %edi 104 * -104(%ebp) entering %esi 105 */ 106 movl -4(%ebp), %eax / %eax = dyndata 107 testb $LA_SYMB_NOPLTENTER, 0xc(%eax) / <link.h> 108 je .start_pltenter 109 movl SYMDEF_VALUE_OFF(%eax), %edi 110 movl %edi, -8(%ebp) / save destination address 111 jmp .end_pltenter 112 113.start_pltenter: 114 /* 115 * save all registers into gregset_t 116 */ 117 lea 4(%ebp), %edi 118 movl %edi, -84(%ebp) / %esp 119 movl 0(%ebp), %edi 120 movl %edi, -80(%ebp) / %ebp 121 /* 122 * trapno, err, eip, cs, efl, uesp, ss 123 */ 124 movl -4(%ebp), %edi 125 lea SBFLAGS_OFF(%edi), %eax 126 pushl %eax / arg5 (&sb_flags) 127 lea -84(%ebp), %eax 128 pushl %eax / arg4 (regset) 129 pushl SYMNDX_OFF(%edi) / arg3 (symndx) 130 lea SYMDEF_OFF(%edi), %eax 131 pushl %eax / arg2 (&sym) 132 pushl DEFLMP_OFF(%edi) / arg1 (dlmp) 133 pushl REFLMP_OFF(%edi) / arg0 (rlmp) 134 call audit_pltenter@PLT 135 addl $24, %esp / cleanup stack 136 movl %eax, -8(%ebp) / save calling address 137.end_pltenter: 138 139 /* 140 * If *no* la_pltexit() routines exist 141 * we do not need to keep the stack frame 142 * before we call the actual routine. Instead we 143 * jump to it and remove our stack from the stack 144 * at the same time. 145 */ 146 movl audit_flags@GOT(%ebx), %eax 147 movl (%eax), %eax 148 andl $AF_PLTEXIT, %eax / value of audit.h:AF_PLTEXIT 149 cmpl $0, %eax 150 je .bypass_pltexit 151 /* 152 * Has the *nopltexit* flag been set for this entry point 153 */ 154 testb $LA_SYMB_NOPLTEXIT, 12(%edi) 155 je .start_pltexit 156 157.bypass_pltexit: 158 /* 159 * No PLTEXIT processing required. 160 */ 161 movl 0(%ebp), %eax 162 movl %eax, -4(%ebp) 163 movl -8(%ebp), %eax / eax == calling destination 164 movl %eax, 0(%ebp) / store destination at top 165 166 popl %esi / 167 popl %edi / clean up stack 168 popl %ebx / 169 popl %eax / 170 subl $4, %ebp / adjust %ebp for 'ret' 171 /* 172 * At this point, after a little doctoring, we should 173 * have the following on the stack: 174 * 175 * 8(%esp): ret addr 176 * 4(%esp): dest_addr 177 * 0(%esp): Previous %ebp 178 * 179 * So - we pop the previous %ebp, and then 180 * ret to our final destination. 181 */ 182 movl %ebp, %esp / 183 popl %ebp / 184 ret / jmp to final destination 185 / and clean up stack :) 186 187.start_pltexit: 188 189 /* 190 * In order to call the destination procedure and then return 191 * to audit_pltexit() for post analysis we must first grow 192 * our stack frame and then duplicate the original callers 193 * stack state. This duplicates all of the arguements 194 * that were to be passed to the destination procedure. 195 */ 196 movl %ebp, %edi / 197 addl $8, %edi / %edi = src 198 movl (%ebp), %edx / 199 subl %edi, %edx / %edx == prev frame sz 200 /* 201 * If audit_argcnt > 0 then we limit the number of 202 * arguements that will be duplicated to audit_argcnt. 203 * 204 * If (prev_stack_size > (audit_argcnt * 4)) 205 * prev_stack_size = audit_argcnt * 4; 206 */ 207 movl audit_argcnt@GOT(%ebx),%eax 208 movl (%eax), %eax / %eax = audit_argcnt 209 cmpl $0, %eax 210 jle .grow_stack 211 lea (,%eax,4), %eax / %eax = %eax * 4 212 cmpl %eax,%edx 213 jle .grow_stack 214 movl %eax, %edx 215 /* 216 * Grow the stack and duplicate the arguements of the 217 * original caller. 218 */ 219.grow_stack: 220 subl %edx, %esp / grow the stack 221 movl %edx, -88(%ebp) / -88(%ebp) == prev frame sz 222 movl %esp, %ecx / %ecx = dest 223 addl %ecx, %edx / %edx == tail of dest 224.while_base: 225 cmpl %edx, %ecx / while (base+size >= src++) { 226 jge .end_while / 227 movl (%edi), %esi 228 movl %esi,(%ecx) / *dest = *src 229 addl $4, %edi / src++ 230 addl $4, %ecx / dest++ 231 jmp .while_base / } 232 233 /* 234 * The above stack is now an exact duplicate of 235 * the stack of the original calling procedure. 236 */ 237.end_while: 238 movl -92(%ebp), %eax / restore %eax 239 movl -96(%ebp), %ebx / restore %ebx 240 movl -104(%ebp), %esi / restore %esi 241 242 movl -8(%ebp), %edi 243 call *%edi / call dest_proc() 244 245 addl -88(%ebp), %esp / cleanup dupped stack 246 247 movl -4(%ebp), %edi 248 pushl SYMNDX_OFF(%edi) / arg4 (symndx) 249 lea SYMDEF_OFF(%edi), %ecx 250 pushl %ecx / arg3 (symp) 251 pushl DEFLMP_OFF(%edi) / arg2 (dlmp) 252 pushl REFLMP_OFF(%edi) / arg1 (rlmp) 253 pushl %eax / arg0 (retval) 254 call audit_pltexit@PLT 255 addl $20, %esp / cleanup stack 256 257 /* 258 * Clean up after ourselves and return to the 259 * original calling procedure. 260 */ 261 popl %esi / 262 popl %edi / clean up stack 263 popl %ebx / 264 movl %ebp, %esp / 265 popl %ebp / 266 ret / return to caller 267 .size elf_plt_trace, .-elf_plt_trace 268#endif 269 270/* 271 * We got here because a call to a function resolved to a procedure 272 * linkage table entry. That entry did a JMPL to the first PLT entry, which 273 * in turn did a call to elf_rtbndr. 274 * 275 * the code sequence that got us here was: 276 * 277 * PLT entry for foo: 278 * jmp *name1@GOT(%ebx) 279 * pushl $rel.plt.foo 280 * jmp PLT0 281 * 282 * 1st PLT entry (PLT0): 283 * pushl 4(%ebx) 284 * jmp *8(%ebx) 285 * nop; nop; nop;nop; 286 * 287 */ 288#if defined(lint) 289 290extern unsigned long elf_bndr(Rt_map *, unsigned long, caddr_t); 291 292void 293elf_rtbndr(Rt_map * lmp, unsigned long reloc, caddr_t pc) 294{ 295 (void) elf_bndr(lmp, reloc, pc); 296} 297 298#else 299 .globl elf_bndr 300 .globl elf_rtbndr 301 .weak _elf_rtbndr 302 _elf_rtbndr = elf_rtbndr / Make dbx happy 303 .type elf_rtbndr,@function 304 .align 4 305 306elf_rtbndr: 307 pushl %ebp 308 movl %esp, %ebp 309 pushl %eax 310 pushl %ecx 311 pushl %edx 312 pushl 12(%ebp) / push pc 313 pushl 8(%ebp) / push reloc 314 pushl 4(%ebp) / push *lmp 315 call elf_bndr@PLT / call the C binder code 316 addl $12, %esp / pop args 317 movl %eax, 8(%ebp) / store final destination 318 popl %edx 319 popl %ecx 320 popl %eax 321 movl %ebp, %esp 322 popl %ebp 323 addl $4,%esp / pop args 324 ret / invoke resolved function 325 .size elf_rtbndr, .-elf_rtbndr 326#endif 327