[arch][arm64] add some helpful assembly macros for arm64
Pulled from Fuchsia Zircon kernel code.
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Travis Geiselbrecht
|
||||
*
|
||||
* Copyright 2020 The Fuchsia Authors
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __ASSEMBLER__ // clang-format off
|
||||
|
||||
#ifndef __has_feature
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
.macro push ra, rb
|
||||
stp \ra, \rb, [sp,#-16]!
|
||||
.endm
|
||||
@@ -16,6 +21,84 @@ stp \ra, \rb, [sp,#-16]!
|
||||
ldp \ra, \rb, [sp], #16
|
||||
.endm
|
||||
|
||||
/// Fill a register with a wide integer literal.
|
||||
///
|
||||
/// This emits the one to four instructions required to fill a 64-bit
|
||||
/// register with a given bit pattern. It uses as few instructions as
|
||||
/// suffice for the particular value.
|
||||
///
|
||||
/// Parameters
|
||||
///
|
||||
/// * reg
|
||||
/// - Required: Output 64-bit register.
|
||||
///
|
||||
/// * literal
|
||||
/// - Required: An integer expression that can be evaluated immediately
|
||||
/// without relocation.
|
||||
///
|
||||
.macro movlit reg, literal
|
||||
mov \reg, #((\literal) & 0xffff)
|
||||
.ifne (((\literal) >> 16) & 0xffff)
|
||||
movk \reg, #(((\literal) >> 16) & 0xffff), lsl #16
|
||||
.endif
|
||||
.ifne (((\literal) >> 32) & 0xffff)
|
||||
movk \reg, #(((\literal) >> 32) & 0xffff), lsl #32
|
||||
.endif
|
||||
.ifne (((\literal) >> 48) & 0xffff)
|
||||
movk \reg, #(((\literal) >> 48) & 0xffff), lsl #48
|
||||
.endif
|
||||
.endm // movlit
|
||||
|
||||
/// Materialize a symbol (with optional addend) into a register.
|
||||
///
|
||||
/// This emits the `adr` instruction or two-instruction sequence required
|
||||
/// to materialize the address of a global variable or function symbol.
|
||||
///
|
||||
/// Parameters
|
||||
///
|
||||
/// * reg
|
||||
/// - Required: Output 64-bit register.
|
||||
///
|
||||
/// * symbol
|
||||
/// - Required: A symbolic expression requiring at most PC-relative reloc.
|
||||
///
|
||||
.macro adr_global reg, symbol
|
||||
#if __has_feature(hwaddress_sanitizer)
|
||||
adrp \reg, :pg_hi21_nc:\symbol
|
||||
movk \reg, #:prel_g3:\symbol+0x100000000
|
||||
add \reg, \reg, #:lo12:\symbol
|
||||
#elif defined(__AARCH64_CMODEL_TINY__)
|
||||
adr \reg, \symbol
|
||||
#else
|
||||
adrp \reg, \symbol
|
||||
add \reg, \reg, #:lo12:\symbol
|
||||
#endif
|
||||
.endm // adr_global
|
||||
|
||||
/// Load a 64-bit fixed global symbol (with optional addend) into a register.
|
||||
///
|
||||
/// This emits the `ldr` instruction or two-instruction sequence required to
|
||||
/// load a global variable. If multiple words are required, it's more
|
||||
/// efficient to use `adr_global` and then `ldp` than to repeat `ldr_global`
|
||||
/// with related locations.
|
||||
///
|
||||
/// Parameters
|
||||
///
|
||||
/// * reg
|
||||
/// - Required: Output 64-bit register.
|
||||
///
|
||||
/// * symbol
|
||||
/// - Required: A symbolic expression requiring at most PC-relative reloc.
|
||||
///
|
||||
.macro ldr_global reg, symbol
|
||||
#ifdef __AARCH64_CMODEL_TINY__
|
||||
ldr \reg, \symbol
|
||||
#else
|
||||
adrp \reg, \symbol
|
||||
ldr \reg, [\reg, #:lo12:\symbol]
|
||||
#endif
|
||||
.endm // adr_global
|
||||
|
||||
.macro tbzmask, reg, mask, label, shift=0
|
||||
.if \shift >= 64
|
||||
.error "tbzmask: unsupported mask, \mask"
|
||||
@@ -88,3 +171,5 @@ ldp \ra, \rb, [sp], #16
|
||||
.quad \handler
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
#endif // __ASSEMBLER__
|
||||
|
||||
Reference in New Issue
Block a user