hc
2023-11-22 983d7f83616922a6439b4352d1b3af488ee27f95
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
 * Copyright (C) 2012 ARM Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef __ASM_MODULE_H
#define __ASM_MODULE_H
 
#include <asm-generic/module.h>
 
#define MODULE_ARCH_VERMAGIC    "aarch64"
 
#ifdef CONFIG_ARM64_MODULE_PLTS
struct mod_plt_sec {
   struct elf64_shdr    *plt;
   int            plt_num_entries;
   int            plt_max_entries;
};
 
struct mod_arch_specific {
   struct mod_plt_sec    core;
   struct mod_plt_sec    init;
 
   /* for CONFIG_DYNAMIC_FTRACE */
   struct plt_entry     *ftrace_trampoline;
};
#endif
 
u64 module_emit_plt_entry(struct module *mod, void *loc, const Elf64_Rela *rela,
             Elf64_Sym *sym);
 
u64 module_emit_veneer_for_adrp(struct module *mod, void *loc, u64 val);
 
#ifdef CONFIG_RANDOMIZE_BASE
extern u64 module_alloc_base;
#else
#define module_alloc_base    ((u64)_etext - MODULES_VSIZE)
#endif
 
struct plt_entry {
   /*
    * A program that conforms to the AArch64 Procedure Call Standard
    * (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or
    * IP1 (x17) may be inserted at any branch instruction that is
    * exposed to a relocation that supports long branches. Since that
    * is exactly what we are dealing with here, we are free to use x16
    * as a scratch register in the PLT veneers.
    */
   __le32    mov0;    /* movn    x16, #0x....            */
   __le32    mov1;    /* movk    x16, #0x...., lsl #16        */
   __le32    mov2;    /* movk    x16, #0x...., lsl #32        */
   __le32    br;    /* br    x16                */
};
 
static inline struct plt_entry get_plt_entry(u64 val)
{
   /*
    * MOVK/MOVN/MOVZ opcode:
    * +--------+------------+--------+-----------+-------------+---------+
    * | sf[31] | opc[30:29] | 100101 | hw[22:21] | imm16[20:5] | Rd[4:0] |
    * +--------+------------+--------+-----------+-------------+---------+
    *
    * Rd     := 0x10 (x16)
    * hw     := 0b00 (no shift), 0b01 (lsl #16), 0b10 (lsl #32)
    * opc    := 0b11 (MOVK), 0b00 (MOVN), 0b10 (MOVZ)
    * sf     := 1 (64-bit variant)
    */
   return (struct plt_entry){
       cpu_to_le32(0x92800010 | (((~val      ) & 0xffff)) << 5),
       cpu_to_le32(0xf2a00010 | ((( val >> 16) & 0xffff)) << 5),
       cpu_to_le32(0xf2c00010 | ((( val >> 32) & 0xffff)) << 5),
       cpu_to_le32(0xd61f0200)
   };
}
 
static inline bool plt_entries_equal(const struct plt_entry *a,
                    const struct plt_entry *b)
{
   return a->mov0 == b->mov0 &&
          a->mov1 == b->mov1 &&
          a->mov2 == b->mov2;
}
 
#endif /* __ASM_MODULE_H */