@@ -393,32 +393,64 @@ typedef struct
393393
394394// //////////////////////////////////////////////////////////////////////////////
395395
396+ struct MCLinuxELF32Traits
397+ {
398+ typedef Elf32_Ehdr Ehdr;
399+ typedef Elf32_Shdr Shdr;
400+ typedef Elf32_Phdr Phdr;
401+ };
402+
403+ struct MCLinuxELF64Traits
404+ {
405+ typedef Elf64_Ehdr Ehdr;
406+ typedef Elf64_Shdr Shdr;
407+ typedef Elf64_Phdr Phdr;
408+ };
409+
410+ // //////////////////////////////////////////////////////////////////////////////
411+
396412static void swap_uint32 (uint32_t & x)
397413{
398414 MCDeployByteSwap32 (false , x);
399415}
400416
401- static void swap_Elf32_Ehdr (Elf32_Ehdr& x)
417+ static void swap_ElfX_Ehdr (Elf32_Ehdr& x)
402418{
403419 MCDeployByteSwapRecord (false , " bbbbbbbbbbbbbbbbsslllllssssss" , &x, sizeof (Elf32_Ehdr));
404420}
405421
406- static void swap_Elf32_Shdr (Elf32_Shdr& x)
422+ static void swap_ElfX_Shdr (Elf32_Shdr& x)
407423{
408424 MCDeployByteSwapRecord (false , " llllllllll" , &x, sizeof (Elf32_Shdr));
409425}
410426
411- static void swap_Elf32_Phdr (Elf32_Phdr& x)
427+ static void swap_ElfX_Phdr (Elf32_Phdr& x)
412428{
413429 MCDeployByteSwapRecord (false , " llllllll" , &x, sizeof (Elf32_Phdr));
414430}
415431
432+ static void swap_ElfX_Ehdr (Elf64_Ehdr& x)
433+ {
434+ MCDeployByteSwapRecord (false , " bbbbbbbbbbbbbbbbsslqqqlssssss" , &x, sizeof (Elf64_Ehdr));
435+ }
436+
437+ static void swap_ElfX_Shdr (Elf64_Shdr& x)
438+ {
439+ MCDeployByteSwapRecord (false , " llqqqqllqq" , &x, sizeof (Elf64_Shdr));
440+ }
441+
442+ static void swap_ElfX_Phdr (Elf64_Phdr& x)
443+ {
444+ MCDeployByteSwapRecord (false , " llqqqqqq" , &x, sizeof (Elf64_Phdr));
445+ }
446+
416447// //////////////////////////////////////////////////////////////////////////////
417448
418- static bool MCDeployToLinuxReadHeader (MCDeployFileRef p_file, bool p_is_android, Elf32_Ehdr& r_header)
449+ template <typename T>
450+ static bool MCDeployToLinuxReadHeader (MCDeployFileRef p_file, bool p_is_android, typename T::Ehdr& r_header)
419451{
420452 // Read the header
421- if (!MCDeployFileRead (p_file, &r_header, sizeof (Elf32_Ehdr )))
453+ if (!MCDeployFileRead (p_file, &r_header, sizeof (typename T::Ehdr )))
422454 return MCDeployThrow (kMCDeployErrorLinuxNoHeader );
423455
424456 // Validate the ident field to make sure the exe is what we expect.
@@ -428,19 +460,21 @@ static bool MCDeployToLinuxReadHeader(MCDeployFileRef p_file, bool p_is_android,
428460 r_header . e_ident[EI_MAG3] != ELFMAG3)
429461 return MCDeployThrow (kMCDeployErrorLinuxBadHeaderMagic );
430462
431- if (r_header . e_ident[EI_CLASS] != ELFCLASS32 ||
463+ // MW-2013-05-03: [[ Linux64 ]] Class could be 32 or 64-bit.
464+ if ((r_header . e_ident[EI_CLASS] != ELFCLASS32 && r_header . e_ident[EI_CLASS] != ELFCLASS64) ||
432465 r_header . e_ident[EI_DATA] != ELFDATA2LSB ||
433466 r_header . e_ident[EI_VERSION] != EV_CURRENT)
434467 return MCDeployThrow (kMCDeployErrorLinuxBadHeaderType );
435468
436469 // Swap the fields as appropriate
437- swap_Elf32_Ehdr (r_header);
470+ swap_ElfX_Ehdr (r_header);
438471
439472 // Now check the header fields that aren't part of the ident
440473 if (!p_is_android)
441474 {
475+ // MW-2013-04-29: [[ Linux64 ]] Allow any type of machine architecture.
476+ // (in particular, ARM and x64 in addition to x386).
442477 if (r_header . e_type != ET_EXEC ||
443- r_header . e_machine != EM_386 ||
444478 r_header . e_version != EV_CURRENT)
445479 return MCDeployThrow (kMCDeployErrorLinuxBadImage );
446480 }
@@ -455,55 +489,58 @@ static bool MCDeployToLinuxReadHeader(MCDeployFileRef p_file, bool p_is_android,
455489 return true ;
456490}
457491
458- static bool MCDeployToLinuxReadSectionHeaders (MCDeployFileRef p_file, Elf32_Ehdr& p_header, Elf32_Shdr*& r_table)
492+ template <typename T>
493+ static bool MCDeployToLinuxReadSectionHeaders (MCDeployFileRef p_file, typename T::Ehdr& p_header, typename T::Shdr*& r_table)
459494{
460495 // First check that we can read the section headers - they must be the size
461496 // we think they should be.
462- if (p_header . e_shentsize != sizeof (Elf32_Shdr ))
497+ if (p_header . e_shentsize != sizeof (typename T::Shdr ))
463498 return MCDeployThrow (kMCDeployErrorLinuxBadSectionSize );
464499
465500 // Allocate the array of the entries
466- r_table = new Elf32_Shdr [p_header . e_shnum];
501+ r_table = new typename T::Shdr [p_header . e_shnum];
467502 if (r_table == NULL )
468503 return MCDeployThrow (kMCDeployErrorNoMemory );
469504
470505 // Next read each entry in from the file
471506 for (uint32_t i = 0 ; i < p_header . e_shnum; i++)
472507 {
473- if (!MCDeployFileReadAt (p_file, &r_table[i], sizeof (Elf32_Shdr ), p_header . e_shoff + i * p_header . e_shentsize))
508+ if (!MCDeployFileReadAt (p_file, &r_table[i], sizeof (typename T::Shdr ), p_header . e_shoff + i * p_header . e_shentsize))
474509 return MCDeployThrow (kMCDeployErrorLinuxBadSectionTable );
475510
476- swap_Elf32_Shdr (r_table[i]);
511+ swap_ElfX_Shdr (r_table[i]);
477512 }
478513
479514 return true ;
480515}
481516
482- static bool MCDeployToLinuxReadProgramHeaders (MCDeployFileRef p_file, Elf32_Ehdr& p_header, Elf32_Phdr*& r_table)
517+ template <typename T>
518+ static bool MCDeployToLinuxReadProgramHeaders (MCDeployFileRef p_file, typename T::Ehdr& p_header, typename T::Phdr*& r_table)
483519{
484520 // First check that we can read the program headers - they must be the size
485521 // we think they should be.
486- if (p_header . e_phentsize != sizeof (Elf32_Phdr ))
522+ if (p_header . e_phentsize != sizeof (typename T::Phdr ))
487523 return MCDeployThrow (kMCDeployErrorLinuxBadSegmentSize );
488524
489525 // Allocate the array of the entries
490- r_table = new Elf32_Phdr [p_header . e_phnum];
526+ r_table = new typename T::Phdr [p_header . e_phnum];
491527 if (r_table == NULL )
492528 return MCDeployThrow (kMCDeployErrorNoMemory );
493529
494530 // Next read each entry in from the file
495531 for (uint32_t i = 0 ; i < p_header . e_phnum; i++)
496532 {
497- if (!MCDeployFileReadAt (p_file, &r_table[i], sizeof (Elf32_Phdr ), p_header . e_phoff + i * p_header . e_phentsize))
533+ if (!MCDeployFileReadAt (p_file, &r_table[i], sizeof (typename T::Phdr ), p_header . e_phoff + i * p_header . e_phentsize))
498534 return MCDeployThrow (kMCDeployErrorLinuxBadProgramTable );
499535
500- swap_Elf32_Phdr (r_table[i]);
536+ swap_ElfX_Phdr (r_table[i]);
501537 }
502538
503539 return true ;
504540}
505541
506- static bool MCDeployToLinuxReadString (MCDeployFileRef p_file, Elf32_Shdr& p_string_header, uint32_t p_index, char *& r_string)
542+ template <typename T>
543+ static bool MCDeployToLinuxReadString (MCDeployFileRef p_file, typename T::Shdr& p_string_header, uint32_t p_index, char *& r_string)
507544{
508545 bool t_success;
509546 t_success = true ;
@@ -607,6 +644,7 @@ static bool MCDeployToLinuxReadString(MCDeployFileRef p_file, Elf32_Shdr& p_stri
607644// Note that this method validates the structure to a good extent so build
608645// errors should be caught relatively easily.
609646//
647+ template <typename T>
610648Exec_stat MCDeployToELF (const MCDeployParameters& p_params, bool p_is_android)
611649{
612650 bool t_success;
@@ -621,31 +659,31 @@ Exec_stat MCDeployToELF(const MCDeployParameters& p_params, bool p_is_android)
621659 t_success = MCDeployThrow (kMCDeployErrorNoOutput );
622660
623661 // Now read in the main ELF header
624- Elf32_Ehdr t_header;
662+ typename T::Ehdr t_header;
625663 if (t_success)
626- t_success = MCDeployToLinuxReadHeader (t_engine, p_is_android, t_header);
664+ t_success = MCDeployToLinuxReadHeader<T> (t_engine, p_is_android, t_header);
627665
628666 // Next read in the section header table
629- Elf32_Shdr *t_section_headers;
667+ typename T::Shdr *t_section_headers;
630668 t_section_headers = NULL ;
631669 if (t_success)
632- t_success = MCDeployToLinuxReadSectionHeaders (t_engine, t_header, t_section_headers);
670+ t_success = MCDeployToLinuxReadSectionHeaders<T> (t_engine, t_header, t_section_headers);
633671
634672 // Next read in the program header table
635- Elf32_Phdr *t_program_headers;
673+ typename T::Phdr *t_program_headers;
636674 t_program_headers = NULL ;
637675 if (t_success)
638- t_success = MCDeployToLinuxReadProgramHeaders (t_engine, t_header, t_program_headers);
676+ t_success = MCDeployToLinuxReadProgramHeaders<T> (t_engine, t_header, t_program_headers);
639677
640678 // Now we have the section header, we search for the 'project' and
641679 // 'payload' sections.
642- Elf32_Shdr *t_project_section, *t_payload_section;
680+ typename T::Shdr *t_project_section, *t_payload_section;
643681 t_project_section = NULL ;
644682 t_payload_section = NULL ;
645683 for (uint32_t i = 0 ; i < t_header . e_shnum && t_project_section == NULL && t_success; i++)
646684 {
647685 char *t_section_name;
648- t_success = MCDeployToLinuxReadString (t_engine, t_section_headers[t_header . e_shstrndx], t_section_headers[i] . sh_name, t_section_name);
686+ t_success = MCDeployToLinuxReadString<T> (t_engine, t_section_headers[t_header . e_shstrndx], t_section_headers[i] . sh_name, t_section_name);
649687
650688 // Notice that we compare 9 bytes, this is to ensure we match .project
651689 // only and not .project<otherchar> (i.e. we match the NUL char).
@@ -668,7 +706,7 @@ Exec_stat MCDeployToELF(const MCDeployParameters& p_params, bool p_is_android)
668706 // since the section table is ordered by vaddr and segments can only
669707 // contain stuff in sections).
670708 if (t_success)
671- for (Elf32_Shdr *t_section = t_project_section + 1 ; t_section < t_section_headers + t_header . e_shnum; t_section += 1 )
709+ for (typename T::Shdr *t_section = t_project_section + 1 ; t_section < t_section_headers + t_header . e_shnum; t_section += 1 )
672710 if (t_section -> sh_addr > t_project_section -> sh_addr)
673711 {
674712 t_success = MCDeployThrow (kMCDeployErrorLinuxBadSectionOrder );
@@ -678,7 +716,7 @@ Exec_stat MCDeployToELF(const MCDeployParameters& p_params, bool p_is_android)
678716 // Now we must search for the segment containing the payload/project sections.
679717 // At present, we required that these sections sit in their own segment and
680718 // that segment must be the last.
681- Elf32_Phdr *t_project_segment;
719+ typename T::Phdr *t_project_segment;
682720 t_project_segment = NULL ;
683721 for (uint32_t i = 0 ; i < t_header . e_phnum && t_success; i++)
684722 if (t_project_section -> sh_addr >= t_program_headers[i] . p_vaddr &&
@@ -774,7 +812,7 @@ Exec_stat MCDeployToELF(const MCDeployParameters& p_params, bool p_is_android)
774812 t_project_segment -> p_filesz = t_payload_size + t_project_size;
775813 t_project_segment -> p_memsz = t_payload_size + t_project_size;
776814
777- for (Elf32_Shdr *t_section = t_project_section + 1 ; t_section < t_section_headers + t_header . e_shnum; t_section += 1 )
815+ for (typename T::Shdr *t_section = t_project_section + 1 ; t_section < t_section_headers + t_header . e_shnum; t_section += 1 )
778816 if (t_section -> sh_offset >= t_end_offset)
779817 t_section -> sh_offset += t_project_delta + t_payload_delta;
780818
@@ -791,17 +829,17 @@ Exec_stat MCDeployToELF(const MCDeployParameters& p_params, bool p_is_android)
791829 //
792830
793831 for (uint32_t i = 0 ; i < t_header . e_shnum; i++)
794- swap_Elf32_Shdr (t_section_headers[i]);
832+ swap_ElfX_Shdr (t_section_headers[i]);
795833
796834 for (uint32_t i = 0 ; i < t_header . e_phnum; i++)
797- swap_Elf32_Phdr (t_program_headers[i]);
835+ swap_ElfX_Phdr (t_program_headers[i]);
798836
799- swap_Elf32_Ehdr (t_header);
837+ swap_ElfX_Ehdr (t_header);
800838 }
801839
802840 // Overwrite the updated header and program headers
803841 if (t_success)
804- t_success = MCDeployFileWriteAt (t_output, &t_header, sizeof (Elf32_Ehdr ), 0 );
842+ t_success = MCDeployFileWriteAt (t_output, &t_header, sizeof (typename T::Ehdr ), 0 );
805843 if (t_success)
806844 t_success = MCDeployFileWriteAt (t_output, t_program_headers, t_segment_table_size, t_segment_table_offset);
807845
@@ -844,20 +882,44 @@ Exec_stat MCDeployToELF(const MCDeployParameters& p_params, bool p_is_android)
844882
845883// //////////////////////////////////////////////////////////////////////////////
846884
847- // This method attempts to build an Linux standalone using the given deployment
885+ // This method attempts to build a Linux standalone using the given deployment
848886// parameters.
849887//
850888Exec_stat MCDeployToLinux (const MCDeployParameters& p_params)
851889{
852- return MCDeployToELF (p_params, false );
890+ bool t_success;
891+ t_success = true ;
892+
893+ // MW-2013-05-03: [[ Linux64 ]] Snoop the engine type from the ident field.
894+
895+ MCDeployFileRef t_engine;
896+ t_engine = NULL ;
897+ if (t_success && !MCDeployFileOpen (p_params . engine, " rb" , t_engine))
898+ t_success = MCDeployThrow (kMCDeployErrorNoEngine );
899+
900+ char t_ident[EI_NIDENT];
901+ if (t_success && !MCDeployFileRead (t_engine, t_ident, EI_NIDENT))
902+ t_success = MCDeployThrow (kMCDeployErrorLinuxNoHeader );
903+
904+ if (t_success)
905+ {
906+ if (t_ident[EI_CLASS] == ELFCLASS32)
907+ return MCDeployToELF<MCLinuxELF32Traits>(p_params, false );
908+ else if (t_ident[EI_CLASS] == ELFCLASS64)
909+ return MCDeployToELF<MCLinuxELF64Traits>(p_params, false );
910+
911+ t_success = MCDeployThrow (kMCDeployErrorLinuxBadHeaderType );
912+ }
913+
914+ return t_success ? ES_NORMAL : ES_ERROR;
853915}
854916
855917// This method attempts to build an Android standalone using the given deployment
856918// parameters.
857919//
858920Exec_stat MCDeployToAndroid (const MCDeployParameters& p_params)
859921{
860- return MCDeployToELF (p_params, true );
922+ return MCDeployToELF<MCLinuxELF32Traits> (p_params, true );
861923}
862924
863925// //////////////////////////////////////////////////////////////////////////////
0 commit comments