Skip to content

Commit fcf31eb

Browse files
committed
Added support for ELF64 binaries to the (internal) deploy command.
1 parent c9abe26 commit fcf31eb

File tree

1 file changed

+99
-37
lines changed

1 file changed

+99
-37
lines changed

engine/src/deploy_linux.cpp

Lines changed: 99 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
396412
static 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>
610648
Exec_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
//
850888
Exec_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
//
858920
Exec_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

Comments
 (0)