2015-03-25 19:14:22 +01:00
/*
* Copyright 2015 Mentor Graphics Corporation .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; version 2 of the
* License .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
*
* vdsomunge - Host program which produces a shared object
* architecturally specified to be usable by both soft - and hard - float
* programs .
*
* The Procedure Call Standard for the ARM Architecture ( ARM IHI
* 0042 E ) says :
*
* 6.4 .1 VFP and Base Standard Compatibility
*
* Code compiled for the VFP calling standard is compatible with
* the base standard ( and vice - versa ) if no floating - point or
* containerized vector arguments or results are used .
*
* And ELF for the ARM Architecture ( ARM IHI 0044 E ) ( Table 4 - 2 ) says :
*
* If both EF_ARM_ABI_FLOAT_XXXX bits are clear , conformance to the
* base procedure - call standard is implied .
*
* The VDSO is built with - msoft - float , as with the rest of the ARM
* kernel , and uses no floating point arguments or results . The build
* process will produce a shared object that may or may not have the
* EF_ARM_ABI_FLOAT_SOFT flag set ( it seems to depend on the binutils
* version ; binutils starting with 2.24 appears to set it ) . The
* EF_ARM_ABI_FLOAT_HARD flag should definitely not be set , and this
* program will error out if it is .
*
* If the soft - float flag is set , this program clears it . That ' s all
* it does .
*/
# include <byteswap.h>
# include <elf.h>
# include <errno.h>
# include <fcntl.h>
2015-07-01 23:08:10 +01:00
# include <stdarg.h>
2015-03-25 19:14:22 +01:00
# include <stdbool.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/mman.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <unistd.h>
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define HOST_ORDER ELFDATA2LSB
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define HOST_ORDER ELFDATA2MSB
# endif
/* Some of the ELF constants we'd like to use were added to <elf.h>
* relatively recently .
*/
# ifndef EF_ARM_EABI_VER5
# define EF_ARM_EABI_VER5 0x05000000
# endif
# ifndef EF_ARM_ABI_FLOAT_SOFT
# define EF_ARM_ABI_FLOAT_SOFT 0x200
# endif
# ifndef EF_ARM_ABI_FLOAT_HARD
# define EF_ARM_ABI_FLOAT_HARD 0x400
# endif
2015-07-01 23:08:10 +01:00
static int failed ;
static const char * argv0 ;
2015-03-25 19:14:22 +01:00
static const char * outfile ;
2015-07-01 23:08:10 +01:00
static void fail ( const char * fmt , . . . )
{
va_list ap ;
failed = 1 ;
fprintf ( stderr , " %s: " , argv0 ) ;
va_start ( ap , fmt ) ;
vfprintf ( stderr , fmt , ap ) ;
va_end ( ap ) ;
exit ( EXIT_FAILURE ) ;
}
2015-03-25 19:14:22 +01:00
static void cleanup ( void )
{
2015-07-01 23:08:10 +01:00
if ( failed & & outfile ! = NULL )
2015-03-25 19:14:22 +01:00
unlink ( outfile ) ;
}
static Elf32_Word read_elf_word ( Elf32_Word word , bool swap )
{
return swap ? bswap_32 ( word ) : word ;
}
static Elf32_Half read_elf_half ( Elf32_Half half , bool swap )
{
return swap ? bswap_16 ( half ) : half ;
}
static void write_elf_word ( Elf32_Word val , Elf32_Word * dst , bool swap )
{
* dst = swap ? bswap_32 ( val ) : val ;
}
int main ( int argc , char * * argv )
{
const Elf32_Ehdr * inhdr ;
bool clear_soft_float ;
const char * infile ;
Elf32_Word e_flags ;
const void * inbuf ;
struct stat stat ;
void * outbuf ;
bool swap ;
int outfd ;
int infd ;
atexit ( cleanup ) ;
2015-07-01 23:08:10 +01:00
argv0 = argv [ 0 ] ;
2015-03-25 19:14:22 +01:00
if ( argc ! = 3 )
2015-07-01 23:08:10 +01:00
fail ( " Usage: %s [infile] [outfile] \n " , argv [ 0 ] ) ;
2015-03-25 19:14:22 +01:00
infile = argv [ 1 ] ;
outfile = argv [ 2 ] ;
infd = open ( infile , O_RDONLY ) ;
if ( infd < 0 )
2015-07-01 23:08:10 +01:00
fail ( " Cannot open %s: %s \n " , infile , strerror ( errno ) ) ;
2015-03-25 19:14:22 +01:00
if ( fstat ( infd , & stat ) ! = 0 )
2015-07-01 23:08:10 +01:00
fail ( " Failed stat for %s: %s \n " , infile , strerror ( errno ) ) ;
2015-03-25 19:14:22 +01:00
inbuf = mmap ( NULL , stat . st_size , PROT_READ , MAP_PRIVATE , infd , 0 ) ;
if ( inbuf = = MAP_FAILED )
2015-07-01 23:08:10 +01:00
fail ( " Failed to map %s: %s \n " , infile , strerror ( errno ) ) ;
2015-03-25 19:14:22 +01:00
close ( infd ) ;
inhdr = inbuf ;
if ( memcmp ( & inhdr - > e_ident , ELFMAG , SELFMAG ) ! = 0 )
2015-07-01 23:08:10 +01:00
fail ( " Not an ELF file \n " ) ;
2015-03-25 19:14:22 +01:00
if ( inhdr - > e_ident [ EI_CLASS ] ! = ELFCLASS32 )
2015-07-01 23:08:10 +01:00
fail ( " Unsupported ELF class \n " ) ;
2015-03-25 19:14:22 +01:00
swap = inhdr - > e_ident [ EI_DATA ] ! = HOST_ORDER ;
if ( read_elf_half ( inhdr - > e_type , swap ) ! = ET_DYN )
2015-07-01 23:08:10 +01:00
fail ( " Not a shared object \n " ) ;
2015-03-25 19:14:22 +01:00
2015-07-01 23:08:10 +01:00
if ( read_elf_half ( inhdr - > e_machine , swap ) ! = EM_ARM )
fail ( " Unsupported architecture %#x \n " , inhdr - > e_machine ) ;
2015-03-25 19:14:22 +01:00
e_flags = read_elf_word ( inhdr - > e_flags , swap ) ;
if ( EF_ARM_EABI_VERSION ( e_flags ) ! = EF_ARM_EABI_VER5 ) {
2015-07-01 23:08:10 +01:00
fail ( " Unsupported EABI version %#x \n " ,
EF_ARM_EABI_VERSION ( e_flags ) ) ;
2015-03-25 19:14:22 +01:00
}
if ( e_flags & EF_ARM_ABI_FLOAT_HARD )
2015-07-01 23:08:10 +01:00
fail ( " Unexpected hard-float flag set in e_flags \n " ) ;
2015-03-25 19:14:22 +01:00
clear_soft_float = ! ! ( e_flags & EF_ARM_ABI_FLOAT_SOFT ) ;
outfd = open ( outfile , O_RDWR | O_CREAT | O_TRUNC , S_IRUSR | S_IWUSR ) ;
if ( outfd < 0 )
2015-07-01 23:08:10 +01:00
fail ( " Cannot open %s: %s \n " , outfile , strerror ( errno ) ) ;
2015-03-25 19:14:22 +01:00
if ( ftruncate ( outfd , stat . st_size ) ! = 0 )
2015-07-01 23:08:10 +01:00
fail ( " Cannot truncate %s: %s \n " , outfile , strerror ( errno ) ) ;
2015-03-25 19:14:22 +01:00
outbuf = mmap ( NULL , stat . st_size , PROT_READ | PROT_WRITE , MAP_SHARED ,
outfd , 0 ) ;
if ( outbuf = = MAP_FAILED )
2015-07-01 23:08:10 +01:00
fail ( " Failed to map %s: %s \n " , outfile , strerror ( errno ) ) ;
2015-03-25 19:14:22 +01:00
close ( outfd ) ;
memcpy ( outbuf , inbuf , stat . st_size ) ;
if ( clear_soft_float ) {
Elf32_Ehdr * outhdr ;
outhdr = outbuf ;
e_flags & = ~ EF_ARM_ABI_FLOAT_SOFT ;
write_elf_word ( e_flags , & outhdr - > e_flags , swap ) ;
}
if ( msync ( outbuf , stat . st_size , MS_SYNC ) ! = 0 )
2015-07-01 23:08:10 +01:00
fail ( " Failed to sync %s: %s \n " , outfile , strerror ( errno ) ) ;
2015-03-25 19:14:22 +01:00
return EXIT_SUCCESS ;
}