-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added various features #655
base: master
Are you sure you want to change the base?
Changes from all commits
bd30f4b
2f0deb5
c0a40d6
b62a0ae
fc892e7
25c32e4
e13a346
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -100,6 +100,7 @@ Exe::Exe(const char *x_szFilename) | |
// read section headers | ||
{ | ||
m_SectionHeader = new SectionHeader[m_Header.m_sections]; | ||
m_SectionHeader_longname = new SectionHeader_longname[m_Header.m_sections]; | ||
|
||
printf("Exe::Exe: Reading Section Headers...\n"); | ||
|
||
|
@@ -115,7 +116,46 @@ Exe::Exe(const char *x_szFilename) | |
goto cleanup; | ||
} | ||
|
||
printf("OK %d\n", v); | ||
// interpret long section names | ||
if(m_SectionHeader[v].m_name[0] == '/') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How was this commit tested? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used objcopy to rename a section I made in some inline asm There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have to say I'm not a fan, I'd rather stay a mile away from intentionally breaking the PE spec (or giving the impression that we support doing so). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The thing with Oh also debug sections use long section names There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it is documented as not being valid for executable images. While it may be possible to hack around the linker for that, it is breaking the spec. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also I added this because I actually need this to have a title image. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
{ | ||
m_SectionHeader_longname[v].m_offset = 0; | ||
for(uint32 i = 1; i < 8; ++i) | ||
{ | ||
char c = m_SectionHeader[v].m_name[i]; | ||
if(!c) | ||
break; | ||
if(c < '0' || c > '9') // not a long section after all? | ||
goto notlong; | ||
m_SectionHeader_longname[v].m_offset *= 10; | ||
m_SectionHeader_longname[v].m_offset += c - '0'; | ||
} | ||
m_SectionHeader_longname[v].m_longname = new char[256](); | ||
|
||
long tmppos = ftell(ExeFile); | ||
fseek(ExeFile, m_Header.m_symbol_table_addr + m_SectionHeader_longname[v].m_offset, | ||
SEEK_SET); | ||
|
||
uint32 i; | ||
for(i = 0; i < 255; ++i) | ||
{ | ||
int c = fgetc(ExeFile); | ||
if(!c || c == EOF) | ||
break; | ||
m_SectionHeader_longname[v].m_longname[i] = c; | ||
} | ||
m_SectionHeader_longname[v].m_longname[i] = 0; | ||
|
||
fseek(ExeFile, tmppos, SEEK_SET); | ||
printf("OK %d (long)\n", v, m_SectionHeader_longname[v].m_offset, | ||
m_SectionHeader_longname[v].m_longname); | ||
} | ||
else | ||
{ | ||
notlong:; | ||
m_SectionHeader_longname[v].m_longname = NULL; | ||
printf("OK %d\n", v); | ||
} | ||
} | ||
} | ||
|
||
|
@@ -184,6 +224,7 @@ Exe::Exe(const char *x_szFilename) | |
void Exe::ConstructorInit() | ||
{ | ||
m_SectionHeader = NULL; | ||
m_SectionHeader_longname = NULL; | ||
m_bzSection = NULL; | ||
} | ||
|
||
|
@@ -193,12 +234,16 @@ Exe::~Exe() | |
if(m_bzSection != 0) | ||
{ | ||
for(uint32 v = 0; v < m_Header.m_sections; v++) | ||
{ | ||
delete[] m_SectionHeader_longname[v].m_longname; | ||
delete[] m_bzSection[v]; | ||
} | ||
|
||
delete[] m_bzSection; | ||
} | ||
|
||
delete[] m_SectionHeader; | ||
delete[] m_SectionHeader_longname; | ||
} | ||
|
||
// export to Exe file | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
#include "Exe.h" | ||
#include "Xbe.h" | ||
|
||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
// program entry point | ||
|
@@ -19,18 +20,35 @@ int main(int argc, char *argv[]) | |
char szXbeFilename[OPTION_LEN + 1] = { 0 }; | ||
char szDumpFilename[OPTION_LEN + 1] = { 0 }; | ||
char szXbeTitle[OPTION_LEN + 1] = "Untitled"; | ||
char szXbeTitleID[OPTION_LEN + 1] = ""; | ||
char szXbeRegions[OPTION_LEN + 1] = ""; | ||
char szXbeVersion[OPTION_LEN + 1] = ""; | ||
char szMode[OPTION_LEN + 1] = "retail"; | ||
char szLogo[OPTION_LEN + 1] = ""; | ||
char szDebugPath[OPTION_LEN + 1] = ""; | ||
|
||
bool bRetail; | ||
uint32 dwTitleId = 0xFFFF0002; | ||
uint32 dwRegions = XBEIMAGE_GAME_REGION_NA | XBEIMAGE_GAME_REGION_JAPAN | | ||
XBEIMAGE_GAME_REGION_RESTOFWORLD | XBEIMAGE_GAME_REGION_MANUFACTURING; | ||
uint32 dwVersion; | ||
|
||
const char *program = argv[0]; | ||
const char *program_desc = "CXBE EXE to XBE (win32 to Xbox) Relinker (Version: " VERSION ")"; | ||
Option options[] = { | ||
{ szExeFilename, NULL, "exefile" }, { szXbeFilename, "OUT", "filename" }, | ||
{ szDumpFilename, "DUMPINFO", "filename" }, { szXbeTitle, "TITLE", "title" }, | ||
{ szMode, "MODE", "{debug|retail}" }, { szLogo, "LOGO", "filename" }, | ||
{ szDebugPath, "DEBUGPATH", "path" }, { NULL } | ||
{ szExeFilename, NULL, "exefile" }, | ||
{ szXbeFilename, "OUT", "filename" }, | ||
{ szDumpFilename, "DUMPINFO", "filename" }, | ||
{ szXbeTitle, "TITLE", "title" }, | ||
{ szXbeTitleID, "TITLEID", "{%c%c-%u|%x}" }, | ||
{ szXbeRegions, "REGION", | ||
"{-|[n][j][w][m]}\n" | ||
" -=none, n=North America, j=Japan, w=world, m=manufacturing" }, | ||
{ szXbeVersion, "VERSION", "version" }, | ||
{ szMode, "MODE", "{debug|retail}" }, | ||
{ szLogo, "LOGO", "filename" }, | ||
{ szDebugPath, "DEBUGPATH", "path" }, | ||
{ NULL } | ||
}; | ||
|
||
if(ParseOptions(argv, argc, options, szErrorMessage)) | ||
|
@@ -54,6 +72,91 @@ int main(int argc, char *argv[]) | |
szXbeTitle[40] = '\0'; | ||
} | ||
|
||
// interpret title id | ||
if(szXbeTitleID[0]) | ||
{ | ||
bool hex = true; | ||
for(int i = 0; szXbeTitleID[i]; ++i) | ||
{ | ||
if(szXbeTitleID[i] == '-') | ||
{ | ||
hex = false; | ||
break; | ||
} | ||
} | ||
if(hex) | ||
{ | ||
sscanf(szXbeTitleID, "%x", &dwTitleId); | ||
} | ||
else | ||
{ | ||
char titlechar[2]; | ||
unsigned titleno; | ||
Comment on lines
+93
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using a not explicitly unsigned char can lead to incorrect results when shifting, better use the types defined in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will adding |
||
if(sscanf(szXbeTitleID, "%c%c-%u", &titlechar[0], &titlechar[1], &titleno) != 3) | ||
{ | ||
strncpy(szErrorMessage, "invalid TITLEID", ERROR_LEN); | ||
goto cleanup; | ||
} | ||
if(titleno > 0xFFFF) | ||
{ | ||
printf("WARNING: Title ID number too high (max is 65535)\n"); | ||
titleno = 0xFFFF; | ||
} | ||
dwTitleId = (titlechar[0] << 24) | (titlechar[1] << 16) | titleno; | ||
} | ||
} | ||
|
||
// interpret region flags | ||
if(szXbeRegions[0]) | ||
{ | ||
char c; | ||
for(int i = 0; (c = szXbeRegions[i]); ++i) | ||
{ | ||
switch(c) | ||
{ | ||
case '-':; | ||
dwRegions = 0; | ||
goto breakfor; | ||
case 'a':; | ||
dwRegions = XBEIMAGE_GAME_REGION_NA | XBEIMAGE_GAME_REGION_JAPAN | | ||
XBEIMAGE_GAME_REGION_RESTOFWORLD | | ||
XBEIMAGE_GAME_REGION_MANUFACTURING; | ||
goto breakfor; | ||
case 'n':; | ||
dwRegions |= XBEIMAGE_GAME_REGION_NA; | ||
break; | ||
case 'j':; | ||
dwRegions |= XBEIMAGE_GAME_REGION_JAPAN; | ||
break; | ||
case 'w':; | ||
dwRegions |= XBEIMAGE_GAME_REGION_RESTOFWORLD; | ||
break; | ||
case 'm':; | ||
dwRegions |= XBEIMAGE_GAME_REGION_MANUFACTURING; | ||
break; | ||
default:; | ||
printf("WARNING: Invalid region char: %c\n", c); | ||
break; | ||
} | ||
} | ||
breakfor:; | ||
} | ||
else | ||
{ | ||
dwRegions = XBEIMAGE_GAME_REGION_NA | XBEIMAGE_GAME_REGION_JAPAN | | ||
XBEIMAGE_GAME_REGION_RESTOFWORLD | XBEIMAGE_GAME_REGION_MANUFACTURING; | ||
} | ||
|
||
// interpret version | ||
if(szXbeVersion[0]) | ||
{ | ||
dwVersion = strtoul(szXbeVersion, NULL, 0); | ||
} | ||
else | ||
{ | ||
dwVersion = 0; | ||
} | ||
|
||
// verify we received the required parameters | ||
if(szExeFilename[0] == '\0') | ||
{ | ||
|
@@ -90,7 +193,8 @@ int main(int argc, char *argv[]) | |
LogoPtr = &logo; | ||
} | ||
|
||
Xbe *XbeFile = new Xbe(ExeFile, szXbeTitle, bRetail, LogoPtr, szDebugPath); | ||
Xbe *XbeFile = new Xbe( | ||
ExeFile, szXbeTitle, dwTitleId, dwRegions, dwVersion, bRetail, LogoPtr, szDebugPath); | ||
Comment on lines
+196
to
+197
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This formatting change does not belong here. |
||
|
||
if(XbeFile->GetError() != 0) | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,7 +32,8 @@ static size_t BasenameOffset(const std::string &path) | |
} | ||
|
||
// construct via Exe file object | ||
Xbe::Xbe(class Exe *x_Exe, const char *x_szTitle, bool x_bRetail, const std::vector<uint08> *logo, | ||
Xbe::Xbe(class Exe *x_Exe, const char *x_szTitle, uint32 x_dwTitleID, uint32 x_dwRegions, | ||
uint32 x_dwVersion, bool x_bRetail, const std::vector<uint08> *logo, | ||
const char *x_szDebugPath) | ||
{ | ||
ConstructorInit(); | ||
|
@@ -125,8 +126,16 @@ Xbe::Xbe(class Exe *x_Exe, const char *x_szTitle, bool x_bRetail, const std::vec | |
{ | ||
uint32 s = 0; | ||
|
||
while(s < 8 && x_Exe->m_SectionHeader[v].m_name[s] != '\0') | ||
s++; | ||
if(x_Exe->m_SectionHeader_longname[v].m_longname) | ||
{ | ||
while(s < 255 && x_Exe->m_SectionHeader_longname[v].m_longname[s] != '\0') | ||
s++; | ||
} | ||
else | ||
{ | ||
while(s < 8 && x_Exe->m_SectionHeader[v].m_name[s] != '\0') | ||
s++; | ||
} | ||
|
||
mrc += s + 1; | ||
} | ||
|
@@ -271,8 +280,7 @@ Xbe::Xbe(class Exe *x_Exe, const char *x_szTitle, bool x_bRetail, const std::vec | |
|
||
m_Certificate.dwTimeDate = CurrentTime; | ||
|
||
// TODO: generate in the form CX-9999 | ||
m_Certificate.dwTitleId = 0xFFFF0002; | ||
m_Certificate.dwTitleId = x_dwTitleID; | ||
|
||
// title name | ||
memset(m_Certificate.wszTitleName, 0, sizeof(m_Certificate.wszTitleName)); | ||
|
@@ -297,19 +305,15 @@ Xbe::Xbe(class Exe *x_Exe, const char *x_szTitle, bool x_bRetail, const std::vec | |
XBEIMAGE_MEDIA_TYPE_MEDIA_BOARD | XBEIMAGE_MEDIA_TYPE_NONSECURE_HARD_DISK | | ||
XBEIMAGE_MEDIA_TYPE_NONSECURE_MODE; | ||
|
||
// TODO: allow configuration | ||
m_Certificate.dwGameRegion = XBEIMAGE_GAME_REGION_MANUFACTURING | | ||
XBEIMAGE_GAME_REGION_NA | XBEIMAGE_GAME_REGION_JAPAN | | ||
XBEIMAGE_GAME_REGION_RESTOFWORLD; | ||
m_Certificate.dwGameRegion = x_dwRegions; | ||
Comment on lines
-300
to
+308
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change probably belongs to a different commit and breaks building this one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably |
||
|
||
// TODO: allow configuration | ||
m_Certificate.dwGameRatings = 0xFFFFFFFF; | ||
|
||
// always disk 0, AFAIK | ||
m_Certificate.dwDiskNumber = 0; | ||
|
||
// TODO: allow configuration | ||
m_Certificate.dwVersion = 0; | ||
m_Certificate.dwVersion = x_dwVersion; | ||
|
||
// generate blank LAN, signature, and alternate signature keys | ||
{ | ||
|
@@ -345,7 +349,7 @@ Xbe::Xbe(class Exe *x_Exe, const char *x_szTitle, bool x_bRetail, const std::vec | |
|
||
// write section headers / section names | ||
{ | ||
m_szSectionName = new char[m_Header.dwSections][9]; | ||
m_szSectionName = new char[m_Header.dwSections][256]; | ||
|
||
m_SectionHeader = new SectionHeader[m_Header.dwSections]; | ||
|
||
|
@@ -373,14 +377,31 @@ Xbe::Xbe(class Exe *x_Exe, const char *x_szTitle, bool x_bRetail, const std::vec | |
|
||
memset(&m_SectionHeader[v].dwFlags, 0, sizeof(m_SectionHeader->dwFlags)); | ||
|
||
if(characteristics & IMAGE_SCN_MEM_WRITE) | ||
m_SectionHeader[v].dwFlags.bWritable = true; | ||
|
||
if((characteristics & IMAGE_SCN_MEM_EXECUTE) || | ||
(characteristics & IMAGE_SCN_CNT_CODE)) | ||
m_SectionHeader[v].dwFlags.bExecutable = true; | ||
// check for $$XTIMAGE or $$XSIMAGE and set the correct flags | ||
if(x_Exe->m_SectionHeader_longname[v].m_longname && | ||
(!strcmp(x_Exe->m_SectionHeader_longname[v].m_longname, "$$XTIMAGE") || | ||
!strcmp(x_Exe->m_SectionHeader_longname[v].m_longname, "$$XSIMAGE"))) | ||
Comment on lines
+382
to
+383
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a fan of this hack. I'd rather like to see proper file insertion support in cxbe and something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is currently no code to do section insertion as far as i'm aware, and that could probably be removed later once there is code made to add sections. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There isn't, as I said I'd rather see it implemented than a name-based hack on top of violating the PE spec. nxdk does not require the usage of these sections nor does it implement the APIs relying on them yet, so we might as well take the time to do things properly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't have the time to write something like that and I need the feature now. Loading the image sections takes up ram to do nothing. This code can be removed later when the better code is added. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm not really interested in nxdk acquiring even more technical debt. We haven't even gotten rid of the one inherited from OpenXDK yet. |
||
{ | ||
m_SectionHeader[v].dwFlags.bInsertedFile = true; | ||
m_SectionHeader[v].dwFlags.bHeadPageRO = true; | ||
m_SectionHeader[v].dwFlags.bTailPageRO = true; | ||
Comment on lines
+385
to
+387
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How were these flag settings determined? They don't match Halo 2. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used an XBE header dumper on a few XBEs. I think it was Doom 3 and a Quake homebrew XBE I had laying around |
||
} | ||
else | ||
{ | ||
if(characteristics & IMAGE_SCN_MEM_WRITE) | ||
m_SectionHeader[v].dwFlags.bWritable = true; | ||
|
||
if((characteristics & IMAGE_SCN_MEM_EXECUTE) || | ||
(characteristics & IMAGE_SCN_CNT_CODE)) | ||
m_SectionHeader[v].dwFlags.bExecutable = true; | ||
|
||
char *name = (x_Exe->m_SectionHeader_longname[v].m_longname) | ||
? x_Exe->m_SectionHeader_longname[v].m_longname | ||
: (char *)x_Exe->m_SectionHeader[v].m_name; | ||
m_SectionHeader[v].dwFlags.bPreload = | ||
(strcmp(name, ".debug") && strncmp(name, ".debug_", 7)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It could be user generated. I only did it for completeness and it's not like it would hurt performance terribly. The more performance-oriented option would be to check if the first 6 matched There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The dot prefix is reserved. I don't care about performance here as much as clean code. |
||
} | ||
|
||
m_SectionHeader[v].dwFlags.bPreload = true; | ||
m_SectionHeader[v].dwVirtualAddr = | ||
x_Exe->m_SectionHeader[v].m_virtual_addr + m_Header.dwPeBaseAddr; | ||
|
||
|
@@ -431,10 +452,21 @@ Xbe::Xbe(class Exe *x_Exe, const char *x_szTitle, bool x_bRetail, const std::vec | |
memset(secn, 0, 8); | ||
|
||
m_SectionHeader[v].dwSectionNameAddr = hwc_secn; | ||
while(s < 8 && x_Exe->m_SectionHeader[v].m_name[s] != '\0') | ||
if(x_Exe->m_SectionHeader_longname[v].m_longname) | ||
{ | ||
m_szSectionName[v][s] = secn[s] = x_Exe->m_SectionHeader[v].m_name[s]; | ||
s++; | ||
while(s < 255 && x_Exe->m_SectionHeader_longname[v].m_longname[s] != '\0') | ||
{ | ||
m_szSectionName[v][s] = secn[s] = x_Exe->m_SectionHeader_longname[v].m_longname[s]; | ||
s++; | ||
} | ||
} | ||
else | ||
{ | ||
while(s < 8 && x_Exe->m_SectionHeader[v].m_name[s] != '\0') | ||
{ | ||
m_szSectionName[v][s] = secn[s] = x_Exe->m_SectionHeader[v].m_name[s]; | ||
s++; | ||
} | ||
} | ||
|
||
m_szSectionName[v][s] = '\0'; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I said before, using this Makefile to build third-party applications should be considered deprecated. It will get removed and we won't add any features to it.
Using your own Makefile not relying on this one is the way to go. If you absolutely have to rely on this Makefile for now and want to use custom cxbe parameters, override this rule in your Makefile which includes this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really can't include your Makefile in mine. It has too many conflicts. It ended up causing a lot of issues with my Makefile especially with flags. Making another Makefile specifically for the NXDK would require maintaining 2 Makefiles and that would be an absolute pain thanks to the complexity of my Makefile. It turned out to be easier to just call
$(MAKE) -C $(NXDK_DIR)
and pass in stuff.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not suggesting you include the nxdk Makefile, I'm recommending the exact opposite. Don't rely on it, it's going to get removed.
I don't get why you would need two Makefiles either, you already seem to call cxbe yourself in your Makefile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I currently use it to fetch all the includes from NXDK's lib dir and use it to build the tools.
I'll remove it since I'm assuming no one will use the new vars.