/* Copyright 2017 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __ELF_ABI_H #define __ELF_ABI_H #ifndef __ASSEMBLY__ #if defined (_CALL_ELF) && _CALL_ELF == 2 #define ELF_ABI_v2 #else #define ELF_ABI_v1 #endif /* From linux/arch/powerpc/include/asm/code-patching.h */ #define OP_RT_RA_MASK 0xffff0000UL #define LIS_R2 0x3c020000UL #define ADDIS_R2_R12 0x3c4c0000UL #define ADDI_R2_R2 0x38420000UL static inline uint64_t function_entry_address(void *func) { #ifdef ELF_ABI_v2 u32 *insn = func; /* * A PPC64 ABIv2 function may have a local and a global entry * point. We use the local entry point for branch tables called * from asm, only a single TOC is used, so identify and step over * the global entry point sequence. * * The global entry point sequence is always of the form: * * addis r2,r12,XXXX * addi r2,r2,XXXX * * A linker optimisation may convert the addis to lis: * * lis r2,XXXX * addi r2,r2,XXXX */ if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) || ((*insn & OP_RT_RA_MASK) == LIS_R2)) && ((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2)) return (uint64_t)(insn + 2); else return (uint64_t)func; #else return *(uint64_t *)func; #endif } #endif /* __ASSEMBLY__ */ #endif /* __COMPILER_H */