|
Packit |
5c3484 |
dnl x86 fat binary entrypoints.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
dnl Copyright 2003, 2012, 2014 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 |
TEXT
|
|
Packit |
5c3484 |
|
|
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 PIC, the jumps are 20 bytes each, and are best aligned to 16 to
|
|
Packit |
5c3484 |
dnl ensure at least the first two instructions don't cross a cache line
|
|
Packit |
5c3484 |
dnl boundary.
|
|
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 |
` ALIGN(ifdef(`PIC',16,8))
|
|
Packit |
5c3484 |
`'PROLOGUE($1)dnl
|
|
Packit |
5c3484 |
ifdef(`PIC',`dnl
|
|
Packit |
5c3484 |
ifdef(`DARWIN',`
|
|
Packit |
5c3484 |
call L(movl_eip_edx)
|
|
Packit |
5c3484 |
movl L(___gmpn_cpuvec)$non_lazy_ptr-.(%edx), %edx
|
|
Packit |
5c3484 |
jmp *m4_empty_if_zero($2)(%edx)
|
|
Packit |
5c3484 |
',`dnl
|
|
Packit |
5c3484 |
call L(movl_eip_edx)
|
|
Packit |
5c3484 |
L(entry_here$2):
|
|
Packit |
5c3484 |
addl $_GLOBAL_OFFSET_TABLE_+[.-L(entry_here$2)], %edx
|
|
Packit |
5c3484 |
movl GSYM_PREFIX`'__gmpn_cpuvec@GOT(%edx), %edx
|
|
Packit |
5c3484 |
jmp *m4_empty_if_zero($2)(%edx)
|
|
Packit |
5c3484 |
')
|
|
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 + 4))',
|
|
Packit |
5c3484 |
CPUVEC_FUNCS_LIST)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
ifdef(`PIC',`
|
|
Packit |
5c3484 |
ALIGN(8)
|
|
Packit |
5c3484 |
L(movl_eip_edx):
|
|
Packit |
5c3484 |
movl (%esp), %edx
|
|
Packit |
5c3484 |
ret_internal
|
|
Packit |
5c3484 |
ifdef(`DARWIN',`
|
|
Packit |
5c3484 |
.section __IMPORT,__pointers,non_lazy_symbol_pointers
|
|
Packit |
5c3484 |
L(___gmpn_cpuvec)$non_lazy_ptr:
|
|
Packit |
5c3484 |
.indirect_symbol ___gmpn_cpuvec
|
|
Packit |
5c3484 |
.long 0
|
|
Packit |
5c3484 |
TEXT
|
|
Packit |
5c3484 |
')
|
|
Packit |
5c3484 |
')
|
|
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 |
|
|
Packit |
5c3484 |
define(FAT_INIT,
|
|
Packit |
5c3484 |
m4_assert_numargs(2)
|
|
Packit |
5c3484 |
`PROLOGUE($1)dnl
|
|
Packit |
5c3484 |
movb $`'$2, %al
|
|
Packit |
5c3484 |
jmp L(fat_init)
|
|
Packit |
5c3484 |
EPILOGUE()
|
|
Packit |
5c3484 |
')
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
L(fat_init):
|
|
Packit |
5c3484 |
C al __gmpn_cpuvec byte offset
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
movzbl %al, %eax
|
|
Packit |
5c3484 |
pushl %eax
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
ifdef(`PIC',`dnl
|
|
Packit |
5c3484 |
ifdef(`DARWIN',`
|
|
Packit |
5c3484 |
sub $8, %esp
|
|
Packit |
5c3484 |
CALL( __gmpn_cpuvec_init)
|
|
Packit |
5c3484 |
add $8, %esp
|
|
Packit |
5c3484 |
call L(movl_eip_edx)
|
|
Packit |
5c3484 |
movl L(___gmpn_cpuvec)$non_lazy_ptr-.(%edx), %edx
|
|
Packit |
5c3484 |
',`dnl
|
|
Packit |
5c3484 |
pushl %ebx
|
|
Packit |
5c3484 |
call L(movl_eip_ebx)
|
|
Packit |
5c3484 |
L(init_here):
|
|
Packit |
5c3484 |
addl $_GLOBAL_OFFSET_TABLE_+[.-L(init_here)], %ebx
|
|
Packit |
5c3484 |
CALL( __gmpn_cpuvec_init)
|
|
Packit |
5c3484 |
movl GSYM_PREFIX`'__gmpn_cpuvec@GOT(%ebx), %edx
|
|
Packit |
5c3484 |
popl %ebx
|
|
Packit |
5c3484 |
')
|
|
Packit |
5c3484 |
popl %eax
|
|
Packit |
5c3484 |
jmp *(%edx,%eax)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
L(movl_eip_ebx):
|
|
Packit |
5c3484 |
movl (%esp), %ebx
|
|
Packit |
5c3484 |
ret_internal
|
|
Packit |
5c3484 |
',`dnl non-PIC
|
|
Packit |
5c3484 |
sub $8, %esp C needed on Darwin, harmless elsewhere
|
|
Packit |
5c3484 |
CALL( __gmpn_cpuvec_init)
|
|
Packit |
5c3484 |
add $8, %esp C needed on Darwin, harmless elsewhere
|
|
Packit |
5c3484 |
popl %eax
|
|
Packit |
5c3484 |
jmp *GSYM_PREFIX`'__gmpn_cpuvec(%eax)
|
|
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 + 4))',
|
|
Packit |
5c3484 |
CPUVEC_FUNCS_LIST)
|
|
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 once, so just something simple and compact is fine.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
defframe(PARAM_ID, 8)
|
|
Packit |
5c3484 |
defframe(PARAM_DST, 4)
|
|
Packit |
5c3484 |
deflit(`FRAME',0)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
PROLOGUE(__gmpn_cpuid)
|
|
Packit |
5c3484 |
pushl %esi FRAME_pushl()
|
|
Packit |
5c3484 |
pushl %ebx FRAME_pushl()
|
|
Packit |
5c3484 |
movl PARAM_ID, %eax
|
|
Packit |
5c3484 |
cpuid
|
|
Packit |
5c3484 |
movl PARAM_DST, %esi
|
|
Packit |
5c3484 |
movl %ebx, (%esi)
|
|
Packit |
5c3484 |
movl %edx, 4(%esi)
|
|
Packit |
5c3484 |
movl %ecx, 8(%esi)
|
|
Packit |
5c3484 |
popl %ebx
|
|
Packit |
5c3484 |
popl %esi
|
|
Packit |
5c3484 |
ret
|
|
Packit |
5c3484 |
EPILOGUE()
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
C int __gmpn_cpuid_available (void);
|
|
Packit |
5c3484 |
C
|
|
Packit |
5c3484 |
C Return non-zero if the cpuid instruction is available, which means late
|
|
Packit |
5c3484 |
C model 80486 and higher. 80386 and early 80486 don't have cpuid.
|
|
Packit |
5c3484 |
C
|
|
Packit |
5c3484 |
C The test follows Intel AP-485 application note, namely that if bit 21 is
|
|
Packit |
5c3484 |
C modifiable then cpuid is supported. This test is reentrant and thread
|
|
Packit |
5c3484 |
C safe, since of course any interrupt or context switch will preserve the
|
|
Packit |
5c3484 |
C flags while we're tinkering with them.
|
|
Packit |
5c3484 |
C
|
|
Packit |
5c3484 |
C This is called only once, so just something simple and compact is fine.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
PROLOGUE(__gmpn_cpuid_available)
|
|
Packit |
5c3484 |
pushf
|
|
Packit |
5c3484 |
popl %ecx C old flags
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
movl %ecx, %edx
|
|
Packit |
5c3484 |
xorl $0x200000, %edx
|
|
Packit |
5c3484 |
pushl %edx
|
|
Packit |
5c3484 |
popf
|
|
Packit |
5c3484 |
pushf
|
|
Packit |
5c3484 |
popl %edx C tweaked flags
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
movl $1, %eax
|
|
Packit |
5c3484 |
cmpl %ecx, %edx
|
|
Packit |
5c3484 |
jne L(available)
|
|
Packit |
5c3484 |
xorl %eax, %eax C not changed, so cpuid not available
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
L(available):
|
|
Packit |
5c3484 |
ret
|
|
Packit |
5c3484 |
EPILOGUE()
|
|
Packit |
5c3484 |
ASM_END()
|