00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <pch.h>
00033
00034 #include "Emu/Utility/System/Loader/Linux64Loader.h"
00035
00036 #include "SysDeps/posix.h"
00037 #include "Emu/Utility/System/Memory/MemorySystem.h"
00038 #include "Emu/Utility/System/Memory/MemoryUtility.h"
00039 #include "Emu/Utility/System/Loader/ElfReader.h"
00040
00041 using namespace std;
00042 using namespace boost;
00043 using namespace Onikiri;
00044 using namespace Onikiri::POSIX;
00045 using namespace Onikiri::EmulatorUtility;
00046
00047 Linux64Loader::Linux64Loader(u16 machine)
00048 : m_imageBase(0), m_entryPoint(0), m_initialSp(0), m_machine(machine)
00049 {
00050
00051 }
00052
00053 Linux64Loader::~Linux64Loader()
00054 {
00055 }
00056
00057 void Linux64Loader::LoadBinary(MemorySystem* memory, const String& command)
00058 {
00059 ElfReader elfReader;
00060
00061 try {
00062 elfReader.Open(command.c_str());
00063
00064 if (elfReader.GetMachine() != m_machine)
00065 throw runtime_error((command + " : machine type does not match").c_str());
00066
00067 m_bigEndian = elfReader.IsBigEndian();
00068
00069 u64 initialBrk = 0;
00070 for (int i = 0; i < elfReader.GetProgramHeaderCount(); i ++) {
00071 const ElfReader::Elf_Phdr &ph = elfReader.GetProgramHeader(i);
00072
00073 VIRTUAL_MEMORY_ATTR_TYPE pageAttr =
00074 VIRTUAL_MEMORY_ATTR_READ | VIRTUAL_MEMORY_ATTR_WRITE;
00075
00076
00077 if(ph.p_flags & PF_X){
00078 pageAttr = VIRTUAL_MEMORY_ATTR_READ | VIRTUAL_MEMORY_ATTR_EXEC;
00079 }
00080
00081
00082 if (ph.p_type == PT_LOAD) {
00083 if (ph.p_offset == 0)
00084 m_imageBase = ph.p_vaddr;
00085 memory->AssignPhysicalMemory(ph.p_vaddr, ph.p_memsz, pageAttr);
00086 TargetBuffer buf(memory, ph.p_vaddr, static_cast<size_t>(ph.p_filesz));
00087 elfReader.ReadRange(static_cast<size_t>(ph.p_offset), (char*)buf.Get(), static_cast<size_t>(ph.p_filesz));
00088
00089 initialBrk = max(initialBrk, ph.p_vaddr+ph.p_memsz);
00090
00091 if( memory->GetReservedAddressRange() >= ph.p_vaddr ){
00092 THROW_RUNTIME_ERROR( "Reserved address region is too large.");
00093 }
00094 }
00095
00096
00097
00098
00099 if (ph.p_flags & PF_X) {
00100 m_codeRange.first = ph.p_vaddr;
00101 m_codeRange.second = static_cast<size_t>(ph.p_memsz);
00102 }
00103 }
00104 ASSERT(m_imageBase != 0);
00105
00106 memory->SetInitialBrk(initialBrk);
00107
00108 m_elfProgramHeaderOffset = elfReader.GetProgramHeaderOffset();
00109 m_elfProgramHeaderCount = elfReader.GetProgramHeaderCount();
00110
00111
00112 m_entryPoint = CalculateEntryPoint(memory, elfReader);
00113 CalculateOthers(memory, elfReader);
00114 }
00115 catch (runtime_error& e) {
00116 THROW_RUNTIME_ERROR(e.what());
00117 }
00118 }
00119
00120 void Linux64Loader::InitArgs(MemorySystem* memory, u64 stackHead, u64 stackSize, const String& command, const String& commandArgs)
00121 {
00122 u64 sp = stackHead+stackSize;
00123
00124
00125 std::vector<String> stringArgs = commandArgs.split(" ");
00126 int argc = (int)stringArgs.size()+1;
00127 scoped_array<const char *> argv(new const char*[argc+1]);
00128
00129 argv[0] = command.c_str();
00130 for (int i = 1; i < argc; i ++) {
00131 argv[i] = stringArgs[i-1].c_str();
00132 }
00133 argv[argc] = NULL;
00134
00135
00136 scoped_array<u64> target_argv ( new u64 [argc+1] );
00137 for (int i = 0; i <= argc; i ++) {
00138 if (argv[i]) {
00139 size_t len = strlen(argv[i]);
00140 sp -= len+1;
00141 memory->MemCopyToTarget(sp, argv[i], len+1);
00142 target_argv[i] = sp;
00143 }
00144 else {
00145 target_argv[i] = 0;
00146 }
00147 }
00148 sp -= sp % sizeof(u64);
00149
00150
00151
00152
00153
00154 ELF64_AUXV auxv;
00155
00156 const int uid = posix_getuid(), gid = posix_getgid(), euid = posix_geteuid(), egid = posix_getegid();
00157
00158 sp -= sizeof(ELF64_AUXV);
00159 auxv.a_type = EndianHostToSpecified((u64)AT_NULL, m_bigEndian);
00160 auxv.a_un.a_val = 0;
00161 memory->MemCopyToTarget(sp, &auxv, sizeof(ELF64_AUXV));
00162
00163 sp -= sizeof(ELF64_AUXV);
00164 auxv.a_type = EndianHostToSpecified((u64)AT_PHDR, m_bigEndian);
00165 auxv.a_un.a_val = EndianHostToSpecified((u64)(m_imageBase + m_elfProgramHeaderOffset), m_bigEndian);
00166 memory->MemCopyToTarget(sp, &auxv, sizeof(ELF64_AUXV));
00167
00168 sp -= sizeof(ELF64_AUXV);
00169 auxv.a_type = EndianHostToSpecified((u64)AT_PHNUM, m_bigEndian);
00170 auxv.a_un.a_val = EndianHostToSpecified((u64)m_elfProgramHeaderCount, m_bigEndian);
00171 memory->MemCopyToTarget(sp, &auxv, sizeof(ELF64_AUXV));
00172
00173 sp -= sizeof(ELF64_AUXV);
00174 auxv.a_type = EndianHostToSpecified((u64)AT_PHENT, m_bigEndian);
00175 auxv.a_un.a_val = EndianHostToSpecified((u64)sizeof(ElfReader::Elf_Phdr), m_bigEndian);
00176 memory->MemCopyToTarget(sp, &auxv, sizeof(ELF64_AUXV));
00177
00178 sp -= sizeof(ELF64_AUXV);
00179 auxv.a_type = EndianHostToSpecified((u64)AT_PAGESZ, m_bigEndian);
00180 auxv.a_un.a_val = EndianHostToSpecified((u64)memory->GetPageSize(), m_bigEndian);
00181 memory->MemCopyToTarget(sp, &auxv, sizeof(ELF64_AUXV));
00182
00183 sp -= sizeof(ELF64_AUXV);
00184 auxv.a_type = EndianHostToSpecified((u64)AT_BASE, m_bigEndian);
00185 auxv.a_un.a_val = 0;
00186 memory->MemCopyToTarget(sp, &auxv, sizeof(ELF64_AUXV));
00187
00188 sp -= sizeof(ELF64_AUXV);
00189 auxv.a_type = EndianHostToSpecified((u64)AT_UID, m_bigEndian);
00190 auxv.a_un.a_val = EndianHostToSpecified((u64)uid, m_bigEndian);
00191 memory->MemCopyToTarget(sp, &auxv, sizeof(ELF64_AUXV));
00192
00193 sp -= sizeof(ELF64_AUXV);
00194 auxv.a_type = EndianHostToSpecified((u64)AT_EUID, m_bigEndian);
00195 auxv.a_un.a_val = EndianHostToSpecified((u64)euid, m_bigEndian);
00196 memory->MemCopyToTarget(sp, &auxv, sizeof(ELF64_AUXV));
00197
00198 sp -= sizeof(ELF64_AUXV);
00199 auxv.a_type = EndianHostToSpecified((u64)AT_GID, m_bigEndian);
00200 auxv.a_un.a_val = EndianHostToSpecified((u64)gid, m_bigEndian);
00201 memory->MemCopyToTarget(sp, &auxv, sizeof(ELF64_AUXV));
00202
00203 sp -= sizeof(ELF64_AUXV);
00204 auxv.a_type = EndianHostToSpecified((u64)AT_EGID, m_bigEndian);
00205 auxv.a_un.a_val = EndianHostToSpecified((u64)egid, m_bigEndian);
00206 memory->MemCopyToTarget(sp, &auxv, sizeof(ELF64_AUXV));
00207
00208 sp -= sizeof(u64);
00209
00210 sp -= sizeof(u64);
00211 WriteMemory( memory, sp, sizeof(u64), sp-8);
00212
00213 sp -= sizeof(u64);
00214
00215 for (int i = 0; i <= argc; i ++) {
00216 sp -= sizeof(u64);
00217 WriteMemory( memory, sp, sizeof(u64), target_argv[argc-i]);
00218 }
00219
00220
00221 sp -= sizeof(u64);
00222 WriteMemory( memory, sp, sizeof(u64), argc);
00223
00224 m_initialSp = sp;
00225 }
00226
00227
00228 void Linux64Loader::WriteMemory( MemorySystem* memory, u64 address, int size, u64 value )
00229 {
00230 EmuMemAccess access( address, size, value );
00231 memory->WriteMemory( &access );
00232 }
00233
00234 u64 Linux64Loader::GetImageBase() const
00235 {
00236 return m_imageBase;
00237 }
00238
00239 u64 Linux64Loader::GetEntryPoint() const
00240 {
00241 return m_entryPoint;
00242 }
00243
00244 std::pair<u64, size_t> Linux64Loader::GetCodeRange() const
00245 {
00246 return m_codeRange;
00247 }
00248
00249 u64 Linux64Loader::GetInitialSp() const
00250 {
00251 return m_initialSp;
00252 }
00253
00254 bool Linux64Loader::IsBigEndian() const
00255 {
00256 return m_bigEndian;
00257 }
00258
00259 u64 Linux64Loader::CalculateEntryPoint(EmulatorUtility::MemorySystem* memory, const ElfReader& elfReader)
00260 {
00261 return elfReader.GetEntryPoint();
00262 }
00263
00264
00265 void Linux64Loader::CalculateOthers(EmulatorUtility::MemorySystem* memory, const ElfReader& elfReader)
00266 {
00267
00268 }