Skip to content

Instantly share code, notes, and snippets.

@koturn
Last active April 3, 2017 16:55
Show Gist options
  • Save koturn/44e72e49f04e7a1974df50cf08eacd88 to your computer and use it in GitHub Desktop.
Save koturn/44e72e49f04e7a1974df50cf08eacd88 to your computer and use it in GitHub Desktop.
x64のELF作るとこ
/*!
* @file GeneratorElfX64.hpp
* @brief x64 ELF binary generator
* @author koturn
*/
#ifndef GENERATOR_ELF_X64_HPP
#define GENERATOR_ELF_X64_HPP
#include <iostream>
#include "BinaryGenerator.hpp"
#include "util/elfsubset.h"
/*!
* @brief x64 ELF binary generator
*/
class GeneratorElfX64 : public BinaryGenerator<GeneratorElfX64>
{
private:
friend class CodeGenerator<GeneratorElfX64>;
//! Address of .text section
static const std::size_t kTextAddr;
//! Address of .bss section
static const std::size_t kBssAddr;
//! Program header size
static const std::size_t kHeaderSize;
//! Program footer size
static const std::size_t kFooterSize;
public:
GeneratorElfX64(std::ostream* oStreamPtr_=nullptr) :
BinaryGenerator<GeneratorElfX64>(oStreamPtr_)
{}
protected:
void
emitHeaderImpl() CODE_GENERATOR_NOEXCEPT
{
// skip header
Elf64_Ehdr ehdr;
write(ehdr);
Elf64_Phdr phdr;
write(phdr);
write(phdr);
// - - - - - The start of program body - - - - - //
// movabs rbx, {kBssAddr}
u8 opcode[] = {0x48, 0xbb};
write(opcode);
write<u64>(kBssAddr);
}
void
emitFooterImpl() CODE_GENERATOR_NOEXCEPT
{
// Emit newline
emitAssignImpl('\n');
emitPutcharImpl();
// mov eax, 0x3c
u8 opcode1[] = {0xb8};
write(opcode1);
write<u32>(0x3c);
// mov edi, 0x00
u8 opcode2[] = {0xbf};
write(opcode2);
write<u32>(0x00);
// syscall
u8 opcode3[] = {0x0f, 0x05};
write(opcode3);
// - - - - - The end of program body - - - - - //
std::size_t codeSize = static_cast<std::size_t>(oStreamPtr->tellp()) - kHeaderSize;
// - - - - - Program footer - - - - - //
// Section string table (22bytes)
const char kShStrTbl[] = "\0.text\0.shstrtbl\0.bss";
write(kShStrTbl);
// First section header
Elf64_Shdr shdr;
shdr.sh_name = 0;
shdr.sh_type = SHT_NULL;
shdr.sh_flags = 0x0000000000000000;
shdr.sh_addr = 0x0000000000000000;
shdr.sh_offset = 0x0000000000000000;
shdr.sh_size = 0x0000000000000000;
shdr.sh_link = 0x00000000;
shdr.sh_info = 0x00000000;
shdr.sh_addralign = 0x0000000000000000;
shdr.sh_entsize = 0x0000000000000000;
write(shdr);
// Second section header (.shstrtbl)
shdr.sh_name = 7;
shdr.sh_type = SHT_STRTAB;
shdr.sh_flags = 0x0000000000000000;
shdr.sh_addr = 0x0000000000000000;
shdr.sh_offset = kHeaderSize + codeSize;
shdr.sh_size = sizeof(kShStrTbl);
shdr.sh_link = 0x00000000;
shdr.sh_info = 0x00000000;
shdr.sh_addralign = 0x0000000000000001;
shdr.sh_entsize = 0x0000000000000000;
write(shdr);
// Third section header (.text)
shdr.sh_name = 1;
shdr.sh_type = SHT_PROGBITS;
shdr.sh_flags = SHF_EXECINSTR | SHF_ALLOC;
shdr.sh_addr = kTextAddr + kHeaderSize;
shdr.sh_offset = kHeaderSize;
shdr.sh_size = codeSize;
shdr.sh_link = 0x00000000;
shdr.sh_info = 0x00000000;
shdr.sh_addralign = 0x0000000000000004;
shdr.sh_entsize = 0x0000000000000000;
write(shdr);
// Fourth section header (.bss)
shdr.sh_name = 17;
shdr.sh_type = SHT_NOBITS;
shdr.sh_flags = SHF_ALLOC | SHF_WRITE;
shdr.sh_addr = kBssAddr;
shdr.sh_offset = 0x0000000000001000;
shdr.sh_size = 0x0000000000010000; // 65536 cells
shdr.sh_link = 0x00000000;
shdr.sh_info = 0x00000000;
shdr.sh_addralign = 0x0000000000000010;
shdr.sh_entsize = 0x0000000000000000;
write(shdr);
// - - - - - Program header - - - - - //
oStreamPtr->seekp(0, std::ios_base::beg);
// ELF header
Elf64_Ehdr ehdr;
ehdr.e_ident[EI_MAG0] = ELFMAG0;
ehdr.e_ident[EI_MAG1] = ELFMAG1;
ehdr.e_ident[EI_MAG2] = ELFMAG2;
ehdr.e_ident[EI_MAG3] = ELFMAG3;
ehdr.e_ident[EI_CLASS] = ELFCLASS64;
ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
ehdr.e_ident[EI_VERSION] = EV_CURRENT;
ehdr.e_ident[EI_OSABI] = ELFOSABI_LINUX;
ehdr.e_ident[EI_ABIVERSION] = 0x00;
ehdr.e_ident[EI_PAD] = 0x00;
ehdr.e_type = ET_EXEC;
ehdr.e_machine = EM_X86_64;
ehdr.e_version = EV_CURRENT;
ehdr.e_entry = kTextAddr + kHeaderSize;
ehdr.e_phoff = sizeof(Elf64_Ehdr);
ehdr.e_shoff = kHeaderSize + sizeof(kShStrTbl) + codeSize;
ehdr.e_flags = 0x00000000;
ehdr.e_ehsize = sizeof(Elf64_Ehdr);
ehdr.e_phentsize = sizeof(Elf64_Phdr);
ehdr.e_phnum = 2;
ehdr.e_shentsize = sizeof(Elf64_Shdr);
ehdr.e_shnum = 4;
ehdr.e_shstrndx = 1;
write(ehdr);
// Program header
Elf64_Phdr phdr;
phdr.p_type = PT_LOAD;
phdr.p_flags = PF_R | PF_X;
phdr.p_offset = 0x0000000000000000;
phdr.p_vaddr = kTextAddr;
phdr.p_paddr = kTextAddr;
phdr.p_filesz = kHeaderSize + sizeof(kShStrTbl) + kFooterSize + codeSize;
phdr.p_memsz = kHeaderSize + sizeof(kShStrTbl) + kFooterSize + codeSize;
phdr.p_align = 0x0000000000000100;
write(phdr);
// Program header for .bss (56 bytes)
phdr.p_type = PT_LOAD;
phdr.p_flags = PF_R | PF_W;
phdr.p_offset = 0x0000000000001000;
phdr.p_vaddr = kBssAddr;
phdr.p_paddr = kBssAddr;
phdr.p_filesz = 0x0000000000000000;
phdr.p_memsz = 0x0000000000010000;
phdr.p_align = 0x0000000000200000;
write(phdr);
oStreamPtr->seekp(0, std::ios_base::end);
}
void
emitMovePointerImpl(int op1) CODE_GENERATOR_NOEXCEPT
{
if (op1 > 0) {
if (op1 == 1) {
// inc rbx
u8 opcode[] = {0x48, 0xff, 0xc3};
write(opcode);
} else {
// add rbx, {op1}
u8 opcode[] = {0x48, 0x81, 0xc3};
write(opcode);
write(op1);
}
} else {
if (op1 == -1) {
// dec rbx
u8 opcode[] = {0x48, 0xff, 0xcb};
write(opcode);
} else {
// sub rbx, {op1}
u8 opcode[] = {0x48, 0x81, 0xeb};
write(opcode);
write(-op1);
}
}
}
void
emitAddImpl(int op1) CODE_GENERATOR_NOEXCEPT
{
if (op1 > 0) {
if (op1 == 1) {
// inc byte ptr [rbx]
u8 opcode[] = {0xfe, 0x03};
write(opcode);
} else {
// add byte ptr [rbx], {op1}
u8 opcode[] = {0x80, 0x03};
write(opcode);
write(static_cast<u8>(op1));
}
} else {
if (op1 == -1) {
// dec byte ptr [rbx]
u8 opcode[] = {0xfe, 0x0b};
write(opcode);
} else {
// sub byte ptr [rbx], {op1}
u8 opcode[] = {0x80, 0x2b};
write(opcode);
write(static_cast<u8>(-op1));
}
}
}
void
emitPutcharImpl() CODE_GENERATOR_NOEXCEPT
{
// mov rax, 0x01
u8 opcode1[] = {0x48, 0xc7, 0xc0};
write(opcode1);
write<u32>(0x01);
// mov rdx, 0x01
// u8 opcode2[] = {0x48, 0xc7, 0xc2};
// mov edx, 0x01
u8 opcode2[] = {0xba};
write(opcode2);
write<u32>(0x01);
// mov rsi, rbx
u8 opcode3[] = {0x48, 0x89, 0xde};
write(opcode3);
// mov edi, 0x01
u8 opcode4[] = {0xbf};
write(opcode4);
write<u32>(0x01);
// syscall
u8 opcode5[] = {0x0f, 0x05};
write(opcode5);
}
void
emitGetcharImpl() CODE_GENERATOR_NOEXCEPT
{
// mov rax, 0x00
u8 opcode1[] = {0x48, 0xc7, 0xc0};
write(opcode1);
write<u32>(0x00);
// mov rdx, 0x01
// u8 opcode2[] = {0x48, 0xc7, 0xc2};
// mov edx, 0x01
u8 opcode2[] = {0xba};
write(opcode2);
write<u32>(0x01);
// mov rsi, rbx
u8 opcode3[] = {0x48, 0x89, 0xde};
write(opcode3);
// mov edi, 0x00
u8 opcode4[] = {0xbf};
write(opcode4);
write<u32>(0x00);
// syscall
u8 opcode5[] = {0x0f, 0x05};
write(opcode5);
}
void
emitLoopStartImpl() CODE_GENERATOR_NOEXCEPT
{
loopStack.push(oStreamPtr->tellp());
// cmp byte ptr [rbx], 0
u8 opcode1[] = {0x80, 0x3b, 0x00};
write(opcode1);
// je 0x********
u8 opcode2[] = {0x0f, 0x84};
write(opcode2);
write<u32>(0x00000000);
}
void
emitLoopEndImpl() CODE_GENERATOR_NOEXCEPT
{
std::ostream::pos_type pos = loopStack.top();
// jmpq
u8 opcode = {0xe9};
write(opcode);
write(static_cast<u32>(pos - oStreamPtr->tellp() - sizeof(u32)));
// fill loop start
std::ostream::pos_type curPos = oStreamPtr->tellp();
oStreamPtr->seekp(pos + static_cast<std::ostream::pos_type>(5), std::ios_base::beg);
write(static_cast<u32>(curPos - oStreamPtr->tellp() - sizeof(u32)));
oStreamPtr->seekp(0, std::ios_base::end);
loopStack.pop();
}
void
emitAssignImpl(int op1) CODE_GENERATOR_NOEXCEPT
{
// mov byte ptr rbx, {op1}
u8 opcode[] = {0xc6, 0x03};
write(opcode);
write(static_cast<u8>(op1));
}
void
emitSearchZeroImpl(int op1) CODE_GENERATOR_NOEXCEPT
{
emitLoopStartImpl();
emitMovePointerImpl(op1);
emitLoopEndImpl();
}
void
emitAddVarImpl(int op1) CODE_GENERATOR_NOEXCEPT
{
// mov rax, rbx
u8 opcode1[] = {0x48, 0x8b, 0x03};
write(opcode1);
// add rbx, {op1}
emitMovePointerImpl(op1);
// add byte ptr [rbx], al
u8 opcode3[] = {0x00, 0x03};
write(opcode3);
// sub rbx, {op1}
emitMovePointerImpl(-op1);
}
void
emitSubVarImpl(int op1) CODE_GENERATOR_NOEXCEPT
{
// mov rax, rbx
u8 opcode1[] = {0x48, 0x8b, 0x03};
write(opcode1);
// add rbx, {op1}
emitMovePointerImpl(op1);
// sub byte ptr [rbx], al
u8 opcode3[] = {0x28, 0x03};
write(opcode3);
// sub rbx, {op1}
emitMovePointerImpl(-op1);
}
void
emitAddCMulVarImpl(int op1, int op2) CODE_GENERATOR_NOEXCEPT
{
if (op2 > 0) {
// mov al, {op2}
u8 opcode1[] = {0xb0};
write(opcode1);
write(static_cast<u8>(op2));
// mul byte ptr [rbx]
u8 opcode2[] = {0xf6, 0x23};
write(opcode2);
// add rbx, {op1}
emitMovePointerImpl(op1);
// add byte ptr [rbx], al
u8 opcode3[] = {0x00, 0x03};
write(opcode3);
// sub rbx, {op1}
emitMovePointerImpl(-op1);
} else {
// mov al, {-op2}
u8 opcode1[] = {0xb0};
write(opcode1);
write(static_cast<u8>(-op2));
// mul byte ptr [rbx]
u8 opcode2[] = {0xf6, 0x23};
write(opcode2);
// add rbx, {op1}
emitMovePointerImpl(op1);
// sub byte ptr [rbx], al
u8 opcode3[] = {0x28, 0x03};
write(opcode3);
// sub rbx, {op1}
emitMovePointerImpl(-op1);
}
}
void
emitInfLoopImpl() CODE_GENERATOR_NOEXCEPT
{
emitLoopStartImpl();
emitLoopEndImpl();
}
}; // class GeneratorElfX64
const std::size_t GeneratorElfX64::kTextAddr = 0x04048000;
const std::size_t GeneratorElfX64::kBssAddr = 0x04248000;
const std::size_t GeneratorElfX64::kHeaderSize = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * 2;
const std::size_t GeneratorElfX64::kFooterSize = sizeof(Elf64_Shdr) * 4;
#endif // GENERATOR_ELF_X64_HPP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment