diff --git a/arch/arm64/include/arch/asm_macros.h b/arch/arm64/include/arch/asm_macros.h index 9fe6c120..86ef6194 100644 --- a/arch/arm64/include/arch/asm_macros.h +++ b/arch/arm64/include/arch/asm_macros.h @@ -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__