|
Packit |
5c3484 |
dnl x86 fat binary entrypoints.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
dnl Contributed to the GNU project by Kevin Ryde (original x86_32 code) and
|
|
Packit |
5c3484 |
dnl Torbjorn Granlund (port to x86_64)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
dnl Copyright 2003, 2009, 2011-2014, 2016 Free Software Foundation, Inc.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
dnl This file is part of the GNU MP Library.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl The GNU MP Library is free software; you can redistribute it and/or modify
|
|
Packit |
5c3484 |
dnl it under the terms of either:
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl * the GNU Lesser General Public License as published by the Free
|
|
Packit |
5c3484 |
dnl Software Foundation; either version 3 of the License, or (at your
|
|
Packit |
5c3484 |
dnl option) any later version.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl or
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl * the GNU General Public License as published by the Free Software
|
|
Packit |
5c3484 |
dnl Foundation; either version 2 of the License, or (at your option) any
|
|
Packit |
5c3484 |
dnl later version.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl or both in parallel, as here.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl The GNU MP Library is distributed in the hope that it will be useful, but
|
|
Packit |
5c3484 |
dnl WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
Packit |
5c3484 |
dnl or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
Packit |
5c3484 |
dnl for more details.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl You should have received copies of the GNU General Public License and the
|
|
Packit |
5c3484 |
dnl GNU Lesser General Public License along with the GNU MP Library. If not,
|
|
Packit |
5c3484 |
dnl see https://www.gnu.org/licenses/.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
include(`../config.m4')
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
dnl Forcibly disable profiling.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl The entrypoints and inits are small enough not to worry about, the real
|
|
Packit |
5c3484 |
dnl routines arrived at will have any profiling. Also, the way the code
|
|
Packit |
5c3484 |
dnl here ends with a jump means we won't work properly with the
|
|
Packit |
5c3484 |
dnl "instrument" profiling scheme anyway.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
define(`WANT_PROFILING',no)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
dnl We define PRETEND_PIC as a helper symbol, the use it for suppressing
|
|
Packit |
5c3484 |
dnl normal, fast call code, since that triggers problems on Darwin, OpenBSD
|
|
Packit |
5c3484 |
dnl and some versions of GNU/Linux. This will go away when symbol hiding is
|
|
Packit |
5c3484 |
dnl finished.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
ifdef(`DARWIN',
|
|
Packit |
5c3484 |
`define(`PRETEND_PIC')')
|
|
Packit |
5c3484 |
ifdef(`OPENBSD',
|
|
Packit |
5c3484 |
`define(`PRETEND_PIC')')
|
|
Packit |
5c3484 |
ifdef(`LINUX',
|
|
Packit |
5c3484 |
`define(`PRETEND_PIC')')
|
|
Packit |
5c3484 |
ifdef(`PIC',
|
|
Packit |
5c3484 |
`define(`PRETEND_PIC')')
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
ABI_SUPPORT(DOS64)
|
|
Packit |
5c3484 |
ABI_SUPPORT(STD64)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
TEXT
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
dnl Usage: FAT_ENTRY(name, offset)
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl Emit a fat binary entrypoint function of the given name. This is the
|
|
Packit |
5c3484 |
dnl normal entry for applications, eg. __gmpn_add_n.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl The code simply jumps through the function pointer in __gmpn_cpuvec at
|
|
Packit |
5c3484 |
dnl the given "offset" (in bytes).
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl For non-PIC, the jumps are 5 bytes each, aligning them to 8 should be
|
|
Packit |
5c3484 |
dnl fine for all x86s.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl For ELF/DARWIN PIC, the jumps are 20 bytes each, and are best aligned to
|
|
Packit |
5c3484 |
dnl 16 to ensure at least the first two instructions don't cross a cache line
|
|
Packit |
5c3484 |
dnl boundary.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl For DOS64, the jumps are 6 bytes. The same form works also for GNU/Linux
|
|
Packit |
5c3484 |
dnl (at least with certain assembler/linkers) but FreeBSD 8.2 crashes. Not
|
|
Packit |
5c3484 |
dnl tested on Darwin, Slowaris, NetBSD, etc.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl Note the extra `' ahead of PROLOGUE obscures it from the HAVE_NATIVE
|
|
Packit |
5c3484 |
dnl grepping in configure, stopping that code trying to eval something with
|
|
Packit |
5c3484 |
dnl $1 in it.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
define(FAT_ENTRY,
|
|
Packit |
5c3484 |
m4_assert_numargs(2)
|
|
Packit |
5c3484 |
`ifdef(`HOST_DOS64',
|
|
Packit |
5c3484 |
` ALIGN(8)
|
|
Packit |
5c3484 |
`'PROLOGUE($1)
|
|
Packit |
5c3484 |
jmp *$2+GSYM_PREFIX`'__gmpn_cpuvec(%rip)
|
|
Packit |
5c3484 |
EPILOGUE()
|
|
Packit |
5c3484 |
',
|
|
Packit |
5c3484 |
` ALIGN(ifdef(`PIC',16,8))
|
|
Packit |
5c3484 |
`'PROLOGUE($1)
|
|
Packit |
5c3484 |
ifdef(`PRETEND_PIC',
|
|
Packit |
5c3484 |
` LEA( GSYM_PREFIX`'__gmpn_cpuvec, %rax)
|
|
Packit |
5c3484 |
jmp *$2(%rax)
|
|
Packit |
5c3484 |
',`dnl non-PIC
|
|
Packit |
5c3484 |
jmp *GSYM_PREFIX`'__gmpn_cpuvec+$2
|
|
Packit |
5c3484 |
')
|
|
Packit |
5c3484 |
EPILOGUE()
|
|
Packit |
5c3484 |
')')
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
dnl FAT_ENTRY for each CPUVEC_FUNCS_LIST
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
define(`CPUVEC_offset',0)
|
|
Packit |
5c3484 |
foreach(i,
|
|
Packit |
5c3484 |
`FAT_ENTRY(MPN(i),CPUVEC_offset)
|
|
Packit |
5c3484 |
define(`CPUVEC_offset',eval(CPUVEC_offset + 8))',
|
|
Packit |
5c3484 |
CPUVEC_FUNCS_LIST)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
dnl Usage: FAT_INIT(name, offset)
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl Emit a fat binary initializer function of the given name. These
|
|
Packit |
5c3484 |
dnl functions are the initial values for the pointers in __gmpn_cpuvec.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl The code simply calls __gmpn_cpuvec_init, and then jumps back through
|
|
Packit |
5c3484 |
dnl the __gmpn_cpuvec pointer, at the given "offset" (in bytes).
|
|
Packit |
5c3484 |
dnl __gmpn_cpuvec_init will have stored the address of the selected
|
|
Packit |
5c3484 |
dnl implementation there.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl Only one of these routines will be executed, and only once, since after
|
|
Packit |
5c3484 |
dnl that all the __gmpn_cpuvec pointers go to real routines. So there's no
|
|
Packit |
5c3484 |
dnl need for anything special here, just something small and simple. To
|
|
Packit |
5c3484 |
dnl keep code size down, "fat_init" is a shared bit of code, arrived at
|
|
Packit |
5c3484 |
dnl with the offset in %al. %al is used since the movb instruction is 2
|
|
Packit |
5c3484 |
dnl bytes where %eax would be 4.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl Note having `PROLOGUE in FAT_INIT obscures that PROLOGUE from the
|
|
Packit |
5c3484 |
dnl HAVE_NATIVE grepping in configure, preventing that code trying to eval
|
|
Packit |
5c3484 |
dnl something with $1 in it.
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
dnl We need to preserve parameter registers over the __gmpn_cpuvec_init call
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
define(FAT_INIT,
|
|
Packit |
5c3484 |
m4_assert_numargs(2)
|
|
Packit |
5c3484 |
`PROLOGUE($1)
|
|
Packit |
5c3484 |
mov $`'$2, %al
|
|
Packit |
5c3484 |
jmp L(fat_init)
|
|
Packit |
5c3484 |
EPILOGUE()
|
|
Packit |
5c3484 |
')
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
dnl FAT_INIT for each CPUVEC_FUNCS_LIST
|
|
Packit |
5c3484 |
dnl
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
define(`CPUVEC_offset',0)
|
|
Packit |
5c3484 |
foreach(i,
|
|
Packit |
5c3484 |
`FAT_INIT(MPN(i`'_init),CPUVEC_offset)
|
|
Packit |
5c3484 |
define(`CPUVEC_offset',eval(CPUVEC_offset + 1))',
|
|
Packit |
5c3484 |
CPUVEC_FUNCS_LIST)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
L(fat_init):
|
|
Packit |
5c3484 |
C al __gmpn_cpuvec byte offset
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
movzbl %al, %eax
|
|
Packit |
5c3484 |
IFSTD(` push %rdi ')
|
|
Packit |
5c3484 |
IFSTD(` push %rsi ')
|
|
Packit |
5c3484 |
push %rdx
|
|
Packit |
5c3484 |
push %rcx
|
|
Packit |
5c3484 |
push %r8
|
|
Packit |
5c3484 |
push %r9
|
|
Packit |
5c3484 |
push %rax
|
|
Packit |
5c3484 |
CALL( __gmpn_cpuvec_init)
|
|
Packit |
5c3484 |
pop %rax
|
|
Packit |
5c3484 |
pop %r9
|
|
Packit |
5c3484 |
pop %r8
|
|
Packit |
5c3484 |
pop %rcx
|
|
Packit |
5c3484 |
pop %rdx
|
|
Packit |
5c3484 |
IFSTD(` pop %rsi ')
|
|
Packit |
5c3484 |
IFSTD(` pop %rdi ')
|
|
Packit |
5c3484 |
ifdef(`PRETEND_PIC',`
|
|
Packit |
5c3484 |
LEA( GSYM_PREFIX`'__gmpn_cpuvec, %r10)
|
|
Packit |
5c3484 |
jmp *(%r10,%rax,8)
|
|
Packit |
5c3484 |
',`dnl non-PIC
|
|
Packit |
5c3484 |
jmp *GSYM_PREFIX`'__gmpn_cpuvec(,%rax,8)
|
|
Packit |
5c3484 |
')
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
C long __gmpn_cpuid (char dst[12], int id);
|
|
Packit |
5c3484 |
C
|
|
Packit |
5c3484 |
C This is called only 3 times, so just something simple and compact is fine.
|
|
Packit |
5c3484 |
C
|
|
Packit |
5c3484 |
C The rcx/ecx zeroing here is needed for the BMI2 check.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
define(`rp', `%rdi')
|
|
Packit |
5c3484 |
define(`idx', `%rsi')
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
PROLOGUE(__gmpn_cpuid)
|
|
Packit |
5c3484 |
FUNC_ENTRY(2)
|
|
Packit |
5c3484 |
mov %rbx, %r8
|
|
Packit |
5c3484 |
mov R32(idx), R32(%rax)
|
|
Packit |
5c3484 |
xor %ecx, %ecx
|
|
Packit |
5c3484 |
cpuid
|
|
Packit |
5c3484 |
mov %ebx, (rp)
|
|
Packit |
5c3484 |
mov %edx, 4(rp)
|
|
Packit |
5c3484 |
mov %ecx, 8(rp)
|
|
Packit |
5c3484 |
mov %r8, %rbx
|
|
Packit |
5c3484 |
FUNC_EXIT()
|
|
Packit |
5c3484 |
ret
|
|
Packit |
5c3484 |
EPILOGUE()
|
|
rpm-build |
01f633 |
CF_PROT
|