mirror of
https://github.com/autc04/Retro68.git
synced 2026-04-19 10:31:24 +00:00
Switch tab-indented files to 4-space indent
This commit is contained in:
@@ -6,6 +6,9 @@ indent_style = space
|
||||
tab_width = 4
|
||||
charset = utf-8
|
||||
|
||||
[InterfacesAndLibraries/**/*]
|
||||
indent_style = tab
|
||||
|
||||
[gcc/**/*]
|
||||
indent_style = tab
|
||||
tab_width = 8
|
||||
@@ -16,5 +19,15 @@ indent_style = tab
|
||||
tab_width = 8
|
||||
indent_width = 2
|
||||
|
||||
[libelf/**/*]
|
||||
indent_style = tab
|
||||
tab_width = 8
|
||||
indent_width = 2
|
||||
|
||||
[hfsutils/**/*]
|
||||
indent_style = tab
|
||||
tab_width = 8
|
||||
indent_width = 2
|
||||
|
||||
[**/Makefile]
|
||||
indent_style=tab
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
find_program(LAUNCH_APPL LaunchAPPL PATH "${CMAKE_INSTALL_PREFIX}/../bin/")
|
||||
execute_process(COMMAND ${LAUNCH_APPL} --list-emulators
|
||||
OUTPUT_VARIABLE EMULATOR_LIST)
|
||||
OUTPUT_VARIABLE EMULATOR_LIST)
|
||||
string(REPLACE "\n" ";" EMULATOR_LIST "${EMULATOR_LIST}")
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "RetroCarbon")
|
||||
if("carbon" IN_LIST EMULATOR_LIST)
|
||||
set(RETRO68_LAUNCH_METHOD carbon CACHE STRING "How to launch Mac applications (for automated testing)")
|
||||
else()
|
||||
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
|
||||
endif()
|
||||
if("carbon" IN_LIST EMULATOR_LIST)
|
||||
set(RETRO68_LAUNCH_METHOD carbon CACHE STRING "How to launch Mac applications (for automated testing)")
|
||||
else()
|
||||
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
|
||||
endif()
|
||||
else()
|
||||
if("classic" IN_LIST EMULATOR_LIST)
|
||||
set(RETRO68_LAUNCH_METHOD classic CACHE STRING "How to launch Mac applications (for automated testing)")
|
||||
else()
|
||||
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
|
||||
endif()
|
||||
if("classic" IN_LIST EMULATOR_LIST)
|
||||
set(RETRO68_LAUNCH_METHOD classic CACHE STRING "How to launch Mac applications (for automated testing)")
|
||||
else()
|
||||
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "RetroCarbon")
|
||||
@@ -33,17 +33,17 @@ set(LAUNCH_METHOD_FLAG)
|
||||
if(RETRO68_LAUNCH_METHOD MATCHES "NONE")
|
||||
else()
|
||||
set(LAUNCH_METHOD_FLAG "-e${RETRO68_LAUNCH_METHOD}")
|
||||
endif() # RETRO68_LAUNCH_METHOD
|
||||
endif() # RETRO68_LAUNCH_METHOD
|
||||
|
||||
enable_testing()
|
||||
|
||||
|
||||
|
||||
function(test FILE)
|
||||
get_filename_component(NAME ${FILE} NAME_WE)
|
||||
get_filename_component(NAME ${FILE} NAME_WE)
|
||||
add_application(${NAME} ${FILE} Test.h Test.c)
|
||||
target_include_directories(${NAME} PRIVATE .)
|
||||
add_test(NAME ${TESTCASE_PREFIX}${NAME} COMMAND ${LAUNCH_APPL}
|
||||
add_test(NAME ${TESTCASE_PREFIX}${NAME} COMMAND ${LAUNCH_APPL}
|
||||
${LAUNCH_METHOD_FLAG} ${RETRO68_TEST_CONFIG} ${NAME}.bin)
|
||||
if(ARGN)
|
||||
set_tests_properties(${TESTCASE_PREFIX}${NAME} ${ARGN})
|
||||
@@ -51,8 +51,8 @@ function(test FILE)
|
||||
endfunction()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Retro68")
|
||||
test(ReallyEmpty.c)
|
||||
set_target_properties(ReallyEmpty PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-single")
|
||||
test(ReallyEmpty.c)
|
||||
set_target_properties(ReallyEmpty PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-single")
|
||||
endif()
|
||||
|
||||
test(Empty.c)
|
||||
@@ -70,10 +70,10 @@ test(Init.cc PROPERTIES PASS_REGULAR_EXPRESSION "constructor\nmain\ndestructor")
|
||||
test(StdIO.c PROPERTIES PASS_REGULAR_EXPRESSION "OK")
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES Retro68)
|
||||
add_application(Segments Segment1.c Segment2.c Segments.segmap Test.h Test.c)
|
||||
set_target_properties(Segments PROPERTIES
|
||||
LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-segments -Wl,${CMAKE_CURRENT_SOURCE_DIR}/Segments.segmap")
|
||||
add_test(NAME ${TESTCASE_PREFIX}Segments COMMAND ${LAUNCH_APPL}
|
||||
add_application(Segments Segment1.c Segment2.c Segments.segmap Test.h Test.c)
|
||||
set_target_properties(Segments PROPERTIES
|
||||
LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-segments -Wl,${CMAKE_CURRENT_SOURCE_DIR}/Segments.segmap")
|
||||
add_test(NAME ${TESTCASE_PREFIX}Segments COMMAND ${LAUNCH_APPL}
|
||||
${LAUNCH_METHOD_FLAG} ${RETRO68_TEST_CONFIG} Segments.bin)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
int main()
|
||||
{
|
||||
// Test: do things work well enough for us to get to main()?
|
||||
return 0;
|
||||
// Test: do things work well enough for us to get to main()?
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
TEST_LOG_OK();
|
||||
TEST_LOG_OK();
|
||||
}
|
||||
|
||||
+10
-10
@@ -3,20 +3,20 @@
|
||||
class Constructed
|
||||
{
|
||||
public:
|
||||
Constructed()
|
||||
{
|
||||
TestLog("constructor");
|
||||
}
|
||||
~Constructed()
|
||||
{
|
||||
TestLog("destructor");
|
||||
}
|
||||
Constructed()
|
||||
{
|
||||
TestLog("constructor");
|
||||
}
|
||||
~Constructed()
|
||||
{
|
||||
TestLog("destructor");
|
||||
}
|
||||
};
|
||||
|
||||
Constructed thing;
|
||||
|
||||
int main()
|
||||
{
|
||||
TestLog("main");
|
||||
return 0;
|
||||
TestLog("main");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ char readWriteData[6] = "Three";
|
||||
|
||||
int main()
|
||||
{
|
||||
// constant initialized data
|
||||
TEST_LOG_SIZED("One",3);
|
||||
TEST_LOG_SIZED("Two",3);
|
||||
// read-write initialized data
|
||||
TEST_LOG_SIZED(readWriteData,5);
|
||||
return 0;
|
||||
// constant initialized data
|
||||
TEST_LOG_SIZED("One",3);
|
||||
TEST_LOG_SIZED("Two",3);
|
||||
// read-write initialized data
|
||||
TEST_LOG_SIZED(readWriteData,5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
void _start()
|
||||
{
|
||||
// Test: do things work well enough for us to get to a startup function?
|
||||
// Note: this won't work for multisegment 68K apps, as the startup function will be in the wrong segment.
|
||||
// Test: do things work well enough for us to get to a startup function?
|
||||
// Note: this won't work for multisegment 68K apps, as the startup function will be in the wrong segment.
|
||||
}
|
||||
|
||||
|
||||
+64
-64
@@ -10,87 +10,87 @@ void Bar();
|
||||
|
||||
Boolean Test(Boolean unloadFoo, Boolean unloadBar, Boolean compact)
|
||||
{
|
||||
variable = 6;
|
||||
Foo();
|
||||
if(variable != 54)
|
||||
{
|
||||
TestLog("Expected 54 after Foo().");
|
||||
return false;
|
||||
}
|
||||
variable = 6;
|
||||
Foo();
|
||||
if(variable != 54)
|
||||
{
|
||||
TestLog("Expected 54 after Foo().");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(unloadFoo)
|
||||
UnloadSeg(&Foo);
|
||||
if(unloadBar)
|
||||
UnloadSeg(&Bar);
|
||||
if(unloadFoo)
|
||||
UnloadSeg(&Foo);
|
||||
if(unloadBar)
|
||||
UnloadSeg(&Bar);
|
||||
|
||||
Size grow;
|
||||
if(compact)
|
||||
MaxMem(&grow);
|
||||
Size grow;
|
||||
if(compact)
|
||||
MaxMem(&grow);
|
||||
|
||||
Bar();
|
||||
if(variable != 42)
|
||||
{
|
||||
TestLog("Expected 42 after Bar().");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
Bar();
|
||||
if(variable != 42)
|
||||
{
|
||||
TestLog("Expected 42 after Bar().");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Size grow, maxblock, maxblock2, freemem, freemem2;
|
||||
Size grow, maxblock, maxblock2, freemem, freemem2;
|
||||
|
||||
MaxApplZone(); // just to keep things simple and predictable
|
||||
MoreMasters();
|
||||
MaxApplZone(); // just to keep things simple and predictable
|
||||
MoreMasters();
|
||||
|
||||
maxblock = MaxMem(&grow);
|
||||
freemem = FreeMem();
|
||||
maxblock = MaxMem(&grow);
|
||||
freemem = FreeMem();
|
||||
|
||||
TestLog("1. No unloading");
|
||||
if(!Test(false, false, false))
|
||||
return 1;
|
||||
TestLog("1. No unloading");
|
||||
if(!Test(false, false, false))
|
||||
return 1;
|
||||
|
||||
maxblock2 = MaxMem(&grow);
|
||||
maxblock2 = MaxMem(&grow);
|
||||
|
||||
|
||||
TestLog("2. UnloadSeg(&Foo)");
|
||||
if(!Test(true, false, false))
|
||||
return 1;
|
||||
TestLog("3. UnloadSeg(&Bar)");
|
||||
if(!Test(false, true, false))
|
||||
return 1;
|
||||
TestLog("4. UnloadSeg(&Foo); UnloadSeg(&Bar)");
|
||||
if(!Test(true, true, false))
|
||||
return 1;
|
||||
TestLog("2. UnloadSeg(&Foo)");
|
||||
if(!Test(true, false, false))
|
||||
return 1;
|
||||
TestLog("3. UnloadSeg(&Bar)");
|
||||
if(!Test(false, true, false))
|
||||
return 1;
|
||||
TestLog("4. UnloadSeg(&Foo); UnloadSeg(&Bar)");
|
||||
if(!Test(true, true, false))
|
||||
return 1;
|
||||
|
||||
TestLog("5. UnloadSeg(&Foo); MaxMem()");
|
||||
if(!Test(true, false, true))
|
||||
return 1;
|
||||
TestLog("6. UnloadSeg(&Bar); MaxMem()");
|
||||
if(!Test(false, true, true))
|
||||
return 1;
|
||||
TestLog("7. UnloadSeg(&Foo); UnloadSeg(&Bar); MaxMem()");
|
||||
if(!Test(true, true, true))
|
||||
return 1;
|
||||
TestLog("5. UnloadSeg(&Foo); MaxMem()");
|
||||
if(!Test(true, false, true))
|
||||
return 1;
|
||||
TestLog("6. UnloadSeg(&Bar); MaxMem()");
|
||||
if(!Test(false, true, true))
|
||||
return 1;
|
||||
TestLog("7. UnloadSeg(&Foo); UnloadSeg(&Bar); MaxMem()");
|
||||
if(!Test(true, true, true))
|
||||
return 1;
|
||||
|
||||
UnloadSeg(&Foo);
|
||||
UnloadSeg(&Foo);
|
||||
|
||||
maxblock2 = MaxMem(&grow);
|
||||
freemem2 = FreeMem();
|
||||
maxblock2 = MaxMem(&grow);
|
||||
freemem2 = FreeMem();
|
||||
|
||||
if(maxblock2 < maxblock || freemem2 < freemem)
|
||||
{
|
||||
TestLog("Leak");
|
||||
char s[256];
|
||||
sprintf(s, "maxblock: %d (delta %d), freemem: %d (delta %d)",
|
||||
maxblock2, maxblock2-maxblock, freemem2, freemem2-freemem);
|
||||
TestLog(s);
|
||||
return 1;
|
||||
}
|
||||
else if(maxblock2 > maxblock || freemem2 > freemem)
|
||||
TestLog("Magic Memory");
|
||||
if(maxblock2 < maxblock || freemem2 < freemem)
|
||||
{
|
||||
TestLog("Leak");
|
||||
char s[256];
|
||||
sprintf(s, "maxblock: %d (delta %d), freemem: %d (delta %d)",
|
||||
maxblock2, maxblock2-maxblock, freemem2, freemem2-freemem);
|
||||
TestLog(s);
|
||||
return 1;
|
||||
}
|
||||
else if(maxblock2 > maxblock || freemem2 > freemem)
|
||||
TestLog("Magic Memory");
|
||||
|
||||
TestLog("OK");
|
||||
TestLog("OK");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ extern int variable;
|
||||
#include <SegLoad.h>
|
||||
void Foo()
|
||||
{
|
||||
variable *= 9;
|
||||
variable *= 9;
|
||||
}
|
||||
|
||||
void Bar()
|
||||
{
|
||||
variable /= 9;
|
||||
variable *= 7;
|
||||
variable /= 9;
|
||||
variable *= 7;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
FILE *f = fopen("out", "w");
|
||||
fprintf(f, "OK\n");
|
||||
fclose(f);
|
||||
FILE *f = fopen("out", "w");
|
||||
fprintf(f, "OK\n");
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
void TestLog(const char *str)
|
||||
{
|
||||
TEST_LOG_SIZED(str, strlen(str));
|
||||
TEST_LOG_SIZED(str, strlen(str));
|
||||
}
|
||||
|
||||
+62
-62
@@ -22,52 +22,52 @@ void TestLog(const char *str);
|
||||
/* The same thing as a macro. String length has to be given explicitly,
|
||||
* to avoid a call to strlen(). */
|
||||
#define TEST_LOG_SIZED(str, size) \
|
||||
do { \
|
||||
HParamBlockRec _hpb; \
|
||||
\
|
||||
unsigned char _fileName[4]; \
|
||||
short _ref;\
|
||||
_fileName[0] = 3; \
|
||||
_fileName[1] = 'o'; \
|
||||
_fileName[2] = 'u'; \
|
||||
_fileName[3] = 't'; \
|
||||
\
|
||||
_hpb.ioParam.ioCompletion = NULL; \
|
||||
_hpb.ioParam.ioNamePtr = (StringPtr)_fileName; \
|
||||
_hpb.ioParam.ioVRefNum = 0; \
|
||||
_hpb.fileParam.ioDirID = 0; \
|
||||
_hpb.ioParam.ioPermssn = fsRdWrPerm; \
|
||||
_hpb.ioParam.ioMisc = NULL; \
|
||||
PBHOpenSync(&_hpb); \
|
||||
_ref = _hpb.ioParam.ioRefNum; \
|
||||
\
|
||||
_hpb.ioParam.ioCompletion = NULL; \
|
||||
_hpb.ioParam.ioBuffer = (Ptr)str; \
|
||||
_hpb.ioParam.ioReqCount = size; \
|
||||
_hpb.ioParam.ioPosMode = fsFromLEOF; \
|
||||
_hpb.ioParam.ioPosOffset = 0; \
|
||||
_hpb.ioParam.ioRefNum = _ref; \
|
||||
_hpb.ioParam.ioMisc = NULL; \
|
||||
PBWriteSync((ParmBlkPtr)&_hpb); \
|
||||
char _newline = '\n'; \
|
||||
_hpb.ioParam.ioCompletion = NULL; \
|
||||
_hpb.ioParam.ioBuffer = &_newline; \
|
||||
_hpb.ioParam.ioReqCount = 1; \
|
||||
_hpb.ioParam.ioPosMode = fsFromLEOF; \
|
||||
_hpb.ioParam.ioPosOffset = 0; \
|
||||
_hpb.ioParam.ioRefNum = _ref; \
|
||||
_hpb.ioParam.ioMisc = NULL; \
|
||||
PBWriteSync((ParmBlkPtr)&_hpb); \
|
||||
_hpb.ioParam.ioCompletion = NULL; \
|
||||
_hpb.ioParam.ioRefNum = _ref; \
|
||||
_hpb.ioParam.ioMisc = NULL; \
|
||||
PBCloseSync((ParmBlkPtr)&_hpb); \
|
||||
_hpb.ioParam.ioCompletion = NULL; \
|
||||
_hpb.ioParam.ioNamePtr = NULL; \
|
||||
_hpb.ioParam.ioVRefNum = 0; \
|
||||
_hpb.ioParam.ioMisc = NULL; \
|
||||
PBFlushVolSync((ParmBlkPtr)&_hpb); \
|
||||
} while(0);
|
||||
do { \
|
||||
HParamBlockRec _hpb; \
|
||||
\
|
||||
unsigned char _fileName[4]; \
|
||||
short _ref;\
|
||||
_fileName[0] = 3; \
|
||||
_fileName[1] = 'o'; \
|
||||
_fileName[2] = 'u'; \
|
||||
_fileName[3] = 't'; \
|
||||
\
|
||||
_hpb.ioParam.ioCompletion = NULL; \
|
||||
_hpb.ioParam.ioNamePtr = (StringPtr)_fileName; \
|
||||
_hpb.ioParam.ioVRefNum = 0; \
|
||||
_hpb.fileParam.ioDirID = 0; \
|
||||
_hpb.ioParam.ioPermssn = fsRdWrPerm; \
|
||||
_hpb.ioParam.ioMisc = NULL; \
|
||||
PBHOpenSync(&_hpb); \
|
||||
_ref = _hpb.ioParam.ioRefNum; \
|
||||
\
|
||||
_hpb.ioParam.ioCompletion = NULL; \
|
||||
_hpb.ioParam.ioBuffer = (Ptr)str; \
|
||||
_hpb.ioParam.ioReqCount = size; \
|
||||
_hpb.ioParam.ioPosMode = fsFromLEOF; \
|
||||
_hpb.ioParam.ioPosOffset = 0; \
|
||||
_hpb.ioParam.ioRefNum = _ref; \
|
||||
_hpb.ioParam.ioMisc = NULL; \
|
||||
PBWriteSync((ParmBlkPtr)&_hpb); \
|
||||
char _newline = '\n'; \
|
||||
_hpb.ioParam.ioCompletion = NULL; \
|
||||
_hpb.ioParam.ioBuffer = &_newline; \
|
||||
_hpb.ioParam.ioReqCount = 1; \
|
||||
_hpb.ioParam.ioPosMode = fsFromLEOF; \
|
||||
_hpb.ioParam.ioPosOffset = 0; \
|
||||
_hpb.ioParam.ioRefNum = _ref; \
|
||||
_hpb.ioParam.ioMisc = NULL; \
|
||||
PBWriteSync((ParmBlkPtr)&_hpb); \
|
||||
_hpb.ioParam.ioCompletion = NULL; \
|
||||
_hpb.ioParam.ioRefNum = _ref; \
|
||||
_hpb.ioParam.ioMisc = NULL; \
|
||||
PBCloseSync((ParmBlkPtr)&_hpb); \
|
||||
_hpb.ioParam.ioCompletion = NULL; \
|
||||
_hpb.ioParam.ioNamePtr = NULL; \
|
||||
_hpb.ioParam.ioVRefNum = 0; \
|
||||
_hpb.ioParam.ioMisc = NULL; \
|
||||
PBFlushVolSync((ParmBlkPtr)&_hpb); \
|
||||
} while(0);
|
||||
|
||||
/*
|
||||
* Output either "OK" or "NO".
|
||||
@@ -75,23 +75,23 @@ void TestLog(const char *str);
|
||||
* we might not want to test them yet.
|
||||
*/
|
||||
|
||||
#define TEST_LOG_OK() \
|
||||
do { \
|
||||
char ok[3]; \
|
||||
ok[0] = 'O'; \
|
||||
ok[1] = 'K'; \
|
||||
ok[2] = '\0'; \
|
||||
TEST_LOG_SIZED(ok, 2); \
|
||||
} while(0)
|
||||
#define TEST_LOG_OK() \
|
||||
do { \
|
||||
char ok[3]; \
|
||||
ok[0] = 'O'; \
|
||||
ok[1] = 'K'; \
|
||||
ok[2] = '\0'; \
|
||||
TEST_LOG_SIZED(ok, 2); \
|
||||
} while(0)
|
||||
|
||||
#define TEST_LOG_NO() \
|
||||
do { \
|
||||
char no[3]; \
|
||||
no[0] = 'O'; \
|
||||
no[1] = 'K'; \
|
||||
no[2] = '\0'; \
|
||||
TEST_LOG_SIZED(no, 2); \
|
||||
} while(0)
|
||||
#define TEST_LOG_NO() \
|
||||
do { \
|
||||
char no[3]; \
|
||||
no[0] = 'O'; \
|
||||
no[1] = 'K'; \
|
||||
no[2] = '\0'; \
|
||||
TEST_LOG_SIZED(no, 2); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#endif // TEST_H
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
TEST_LOG_SIZED("One",3);
|
||||
TEST_LOG_SIZED("Two",3);
|
||||
for(;;)
|
||||
;
|
||||
TEST_LOG_SIZED("Three",5);
|
||||
return 0;
|
||||
TEST_LOG_SIZED("One",3);
|
||||
TEST_LOG_SIZED("Two",3);
|
||||
for(;;)
|
||||
;
|
||||
TEST_LOG_SIZED("Three",5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,45 +10,45 @@ EventRecord e;
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
if(commonSymbol)
|
||||
{
|
||||
TEST_LOG_NO();
|
||||
return 1;
|
||||
}
|
||||
if(zeroInited)
|
||||
{
|
||||
TEST_LOG_NO();
|
||||
return 1;
|
||||
}
|
||||
for(i = 0; i < 32768; i++)
|
||||
{
|
||||
if(zeroInitedArray[i])
|
||||
{
|
||||
TEST_LOG_NO();
|
||||
return 1;
|
||||
}
|
||||
zeroInitedArray[i] = 42;
|
||||
}
|
||||
|
||||
int i;
|
||||
if(commonSymbol)
|
||||
{
|
||||
TEST_LOG_NO();
|
||||
return 1;
|
||||
}
|
||||
if(zeroInited)
|
||||
{
|
||||
TEST_LOG_NO();
|
||||
return 1;
|
||||
}
|
||||
for(i = 0; i < 32768; i++)
|
||||
{
|
||||
if(zeroInitedArray[i])
|
||||
{
|
||||
TEST_LOG_NO();
|
||||
return 1;
|
||||
}
|
||||
zeroInitedArray[i] = 42;
|
||||
}
|
||||
|
||||
// Initialize some of the Macintosh Toolbox
|
||||
// and maybe trigger a context switch, so we can be sure
|
||||
// our global variables were put in the right placce.
|
||||
#if !TARGET_API_MAC_CARBON
|
||||
InitGraf(&qd.thePort);
|
||||
InitFonts();
|
||||
InitWindows();
|
||||
InitGraf(&qd.thePort);
|
||||
InitFonts();
|
||||
InitWindows();
|
||||
#endif
|
||||
GetNextEvent(everyEvent, &e);
|
||||
GetNextEvent(everyEvent, &e);
|
||||
|
||||
for(i = 0; i < 32768; i++)
|
||||
{
|
||||
if(zeroInitedArray[i] != 42)
|
||||
{
|
||||
TEST_LOG_NO();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
TEST_LOG_OK();
|
||||
return 0;
|
||||
for(i = 0; i < 32768; i++)
|
||||
{
|
||||
if(zeroInitedArray[i] != 42)
|
||||
{
|
||||
TEST_LOG_NO();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
TEST_LOG_OK();
|
||||
return 0;
|
||||
}
|
||||
|
||||
+10
-10
@@ -16,15 +16,15 @@
|
||||
# along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
add_library(RetroConsole
|
||||
retro/Console.cc
|
||||
retro/Console.h
|
||||
retro/ConsoleWindow.cc
|
||||
retro/ConsoleWindow.h
|
||||
retro/MacUtils.h
|
||||
retro/InitConsole.cc
|
||||
)
|
||||
retro/Console.cc
|
||||
retro/Console.h
|
||||
retro/ConsoleWindow.cc
|
||||
retro/ConsoleWindow.h
|
||||
retro/MacUtils.h
|
||||
retro/InitConsole.cc
|
||||
)
|
||||
set_target_properties(retrocrt
|
||||
PROPERTIES
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS -ffunction-sections)
|
||||
|
||||
# different library name for Carbon
|
||||
@@ -37,6 +37,6 @@ target_include_directories(RetroConsole PUBLIC .)
|
||||
install(TARGETS RetroConsole DESTINATION lib)
|
||||
|
||||
add_application(ConsoleTest
|
||||
ConsoleTest.cc
|
||||
)
|
||||
ConsoleTest.cc
|
||||
)
|
||||
target_link_libraries(ConsoleTest RetroConsole)
|
||||
|
||||
+13
-13
@@ -3,21 +3,21 @@
|
||||
|
||||
namespace retro
|
||||
{
|
||||
void InitConsole();
|
||||
void InitConsole();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
retro::InitConsole();
|
||||
std::string out = "Hello, world.\nEnter \"exit\" to quit.\n";
|
||||
retro::Console::currentInstance->write(out.data(), out.size());
|
||||
|
||||
std::string in;
|
||||
do
|
||||
{
|
||||
in = retro::Console::currentInstance->ReadLine();
|
||||
out = "You Entered: " + in;
|
||||
retro::Console::currentInstance->write(out.data(), out.size());
|
||||
} while(in != "exit\n");
|
||||
return 0;
|
||||
retro::InitConsole();
|
||||
std::string out = "Hello, world.\nEnter \"exit\" to quit.\n";
|
||||
retro::Console::currentInstance->write(out.data(), out.size());
|
||||
|
||||
std::string in;
|
||||
do
|
||||
{
|
||||
in = retro::Console::currentInstance->ReadLine();
|
||||
out = "You Entered: " + in;
|
||||
retro::Console::currentInstance->write(out.data(), out.size());
|
||||
} while(in != "exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ std::string Console::ReadLine()
|
||||
char c;
|
||||
|
||||
do
|
||||
{
|
||||
{
|
||||
c = WaitNextChar();
|
||||
if(!c)
|
||||
{
|
||||
|
||||
+44
-44
@@ -25,66 +25,66 @@
|
||||
|
||||
namespace retro
|
||||
{
|
||||
class Console
|
||||
{
|
||||
public:
|
||||
Console();
|
||||
Console(GrafPtr port, Rect r);
|
||||
~Console();
|
||||
class Console
|
||||
{
|
||||
public:
|
||||
Console();
|
||||
Console(GrafPtr port, Rect r);
|
||||
~Console();
|
||||
|
||||
void Reshape(Rect newBounds);
|
||||
void Reshape(Rect newBounds);
|
||||
|
||||
void Draw(Rect r);
|
||||
void Draw() { Draw(bounds); }
|
||||
void putch(char c);
|
||||
void Draw(Rect r);
|
||||
void Draw() { Draw(bounds); }
|
||||
void putch(char c);
|
||||
|
||||
void write(const char *s, int n);
|
||||
std::string ReadLine();
|
||||
void write(const char *s, int n);
|
||||
std::string ReadLine();
|
||||
|
||||
static Console *currentInstance;
|
||||
static Console *currentInstance;
|
||||
|
||||
short GetRows() const { return rows; }
|
||||
short GetCols() const { return cols; }
|
||||
|
||||
void Idle();
|
||||
short GetRows() const { return rows; }
|
||||
short GetCols() const { return cols; }
|
||||
|
||||
void Idle();
|
||||
|
||||
bool IsEOF() const { return eof; }
|
||||
private:
|
||||
GrafPtr consolePort = nullptr;
|
||||
Rect bounds;
|
||||
private:
|
||||
GrafPtr consolePort = nullptr;
|
||||
Rect bounds;
|
||||
|
||||
std::vector<char> chars, onscreen;
|
||||
std::vector<char> chars, onscreen;
|
||||
|
||||
short cellSizeX;
|
||||
short cellSizeY;
|
||||
short cellSizeX;
|
||||
short cellSizeY;
|
||||
|
||||
short rows = 0, cols = 0;
|
||||
short rows = 0, cols = 0;
|
||||
|
||||
short cursorX, cursorY;
|
||||
short cursorX, cursorY;
|
||||
|
||||
Rect dirtyRect = {};
|
||||
|
||||
long blinkTicks = 0;
|
||||
bool cursorDrawn = false;
|
||||
bool cursorVisible = true;
|
||||
Rect dirtyRect = {};
|
||||
|
||||
long blinkTicks = 0;
|
||||
bool cursorDrawn = false;
|
||||
bool cursorVisible = true;
|
||||
bool eof = false;
|
||||
|
||||
void PutCharNoUpdate(char c);
|
||||
void Update();
|
||||
void PutCharNoUpdate(char c);
|
||||
void Update();
|
||||
|
||||
Rect CellRect(short x, short y);
|
||||
void DrawCell(short x, short y, bool erase = true);
|
||||
void DrawCells(short x1, short x2, short y, bool erase = true);
|
||||
void ScrollUp(short n = 1);
|
||||
|
||||
void InvalidateCursor();
|
||||
Rect CellRect(short x, short y);
|
||||
void DrawCell(short x, short y, bool erase = true);
|
||||
void DrawCells(short x1, short x2, short y, bool erase = true);
|
||||
void ScrollUp(short n = 1);
|
||||
|
||||
void InvalidateCursor();
|
||||
|
||||
virtual char WaitNextChar();
|
||||
|
||||
protected:
|
||||
void Init(GrafPtr port, Rect r);
|
||||
|
||||
};
|
||||
virtual char WaitNextChar();
|
||||
|
||||
protected:
|
||||
void Init(GrafPtr port, Rect r);
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -25,103 +25,103 @@ using namespace retro;
|
||||
|
||||
namespace
|
||||
{
|
||||
std::unordered_map<WindowPtr, ConsoleWindow*> *windows = NULL;
|
||||
std::unordered_map<WindowPtr, ConsoleWindow*> *windows = NULL;
|
||||
}
|
||||
|
||||
ConsoleWindow::ConsoleWindow(Rect r, ConstStr255Param title)
|
||||
{
|
||||
GrafPtr port;
|
||||
GrafPtr port;
|
||||
|
||||
win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, false, 0);
|
||||
win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, false, 0);
|
||||
|
||||
#if !TARGET_API_MAC_CARBON
|
||||
port = win;
|
||||
Rect portRect = port->portRect;
|
||||
port = win;
|
||||
Rect portRect = port->portRect;
|
||||
#else
|
||||
port = GetWindowPort(win);
|
||||
Rect portRect;
|
||||
GetPortBounds(port, &portRect);
|
||||
port = GetWindowPort(win);
|
||||
Rect portRect;
|
||||
GetPortBounds(port, &portRect);
|
||||
#endif
|
||||
|
||||
SetPort(port);
|
||||
EraseRect(&portRect);
|
||||
SetPort(port);
|
||||
EraseRect(&portRect);
|
||||
|
||||
if(!windows)
|
||||
windows = new std::unordered_map<WindowPtr, ConsoleWindow*>();
|
||||
(*windows)[win] = this;
|
||||
if(!windows)
|
||||
windows = new std::unordered_map<WindowPtr, ConsoleWindow*>();
|
||||
(*windows)[win] = this;
|
||||
|
||||
Init(port, portRect);
|
||||
Init(port, portRect);
|
||||
}
|
||||
|
||||
ConsoleWindow::~ConsoleWindow()
|
||||
{
|
||||
windows->erase(win);
|
||||
DisposeWindow(win);
|
||||
windows->erase(win);
|
||||
DisposeWindow(win);
|
||||
}
|
||||
|
||||
char ConsoleWindow::WaitNextChar()
|
||||
{
|
||||
EventRecord event;
|
||||
WindowPtr eventWin;
|
||||
ConsoleWindow *realConsole;
|
||||
EventRecord event;
|
||||
WindowPtr eventWin;
|
||||
ConsoleWindow *realConsole;
|
||||
#if TARGET_API_MAC_CARBON
|
||||
Rect *boundsPtr = NULL;
|
||||
Rect *boundsPtr = NULL;
|
||||
#else
|
||||
Rect *boundsPtr = &qd.screenBits.bounds;
|
||||
Rect *boundsPtr = &qd.screenBits.bounds;
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
#if TARGET_API_MAC_CARBON
|
||||
#define SystemTask()
|
||||
#endif
|
||||
SystemTask();
|
||||
Idle();
|
||||
while(!GetNextEvent(everyEvent, &event))
|
||||
{
|
||||
SystemTask();
|
||||
Idle();
|
||||
}
|
||||
|
||||
switch(event.what)
|
||||
{
|
||||
case updateEvt:
|
||||
eventWin = (WindowPtr)event.message;
|
||||
realConsole = (*windows)[(WindowPtr)event.message];
|
||||
if(realConsole)
|
||||
{
|
||||
Rect updateRect;
|
||||
BeginUpdate(eventWin);
|
||||
|
||||
do
|
||||
{
|
||||
#if TARGET_API_MAC_CARBON
|
||||
#define SystemTask()
|
||||
#endif
|
||||
SystemTask();
|
||||
Idle();
|
||||
while(!GetNextEvent(everyEvent, &event))
|
||||
{
|
||||
SystemTask();
|
||||
Idle();
|
||||
}
|
||||
|
||||
switch(event.what)
|
||||
{
|
||||
case updateEvt:
|
||||
eventWin = (WindowPtr)event.message;
|
||||
realConsole = (*windows)[(WindowPtr)event.message];
|
||||
if(realConsole)
|
||||
{
|
||||
Rect updateRect;
|
||||
BeginUpdate(eventWin);
|
||||
#if TARGET_API_MAC_CARBON
|
||||
RgnHandle rgn = NewRgn();
|
||||
GetPortVisibleRegion(GetWindowPort(eventWin), rgn);
|
||||
GetRegionBounds(rgn, &updateRect);
|
||||
DisposeRgn(rgn);
|
||||
RgnHandle rgn = NewRgn();
|
||||
GetPortVisibleRegion(GetWindowPort(eventWin), rgn);
|
||||
GetRegionBounds(rgn, &updateRect);
|
||||
DisposeRgn(rgn);
|
||||
#else
|
||||
updateRect = (*qd.thePort->visRgn)->rgnBBox; // Life was simple back then.
|
||||
updateRect = (*qd.thePort->visRgn)->rgnBBox; // Life was simple back then.
|
||||
#endif
|
||||
realConsole->Draw(updateRect);
|
||||
EndUpdate(eventWin);
|
||||
}
|
||||
break;
|
||||
case mouseDown:
|
||||
|
||||
switch(FindWindow(event.where, &eventWin))
|
||||
{
|
||||
case inDrag:
|
||||
DragWindow(eventWin, event.where, boundsPtr);
|
||||
break;
|
||||
case inGrow:
|
||||
{
|
||||
long growResult = GrowWindow(eventWin, event.where, boundsPtr);
|
||||
SizeWindow(eventWin, growResult & 0xFFFF, growResult >> 16, false);
|
||||
Reshape(Rect {0, 0, (short) (growResult >> 16), (short) (growResult & 0xFFFF) });
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while(event.what != keyDown && event.what != autoKey);
|
||||
|
||||
return event.message & charCodeMask;
|
||||
realConsole->Draw(updateRect);
|
||||
EndUpdate(eventWin);
|
||||
}
|
||||
break;
|
||||
case mouseDown:
|
||||
|
||||
switch(FindWindow(event.where, &eventWin))
|
||||
{
|
||||
case inDrag:
|
||||
DragWindow(eventWin, event.where, boundsPtr);
|
||||
break;
|
||||
case inGrow:
|
||||
{
|
||||
long growResult = GrowWindow(eventWin, event.where, boundsPtr);
|
||||
SizeWindow(eventWin, growResult & 0xFFFF, growResult >> 16, false);
|
||||
Reshape(Rect {0, 0, (short) (growResult >> 16), (short) (growResult & 0xFFFF) });
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while(event.what != keyDown && event.what != autoKey);
|
||||
|
||||
return event.message & charCodeMask;
|
||||
}
|
||||
|
||||
@@ -25,14 +25,14 @@
|
||||
|
||||
namespace retro
|
||||
{
|
||||
class ConsoleWindow : public Console
|
||||
{
|
||||
public:
|
||||
ConsoleWindow(Rect r, ConstStr255Param title);
|
||||
~ConsoleWindow();
|
||||
private:
|
||||
WindowPtr win;
|
||||
class ConsoleWindow : public Console
|
||||
{
|
||||
public:
|
||||
ConsoleWindow(Rect r, ConstStr255Param title);
|
||||
~ConsoleWindow();
|
||||
private:
|
||||
WindowPtr win;
|
||||
|
||||
virtual char WaitNextChar();
|
||||
};
|
||||
virtual char WaitNextChar();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2014 Wolfgang Thaller.
|
||||
Copyright 2014 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
@@ -34,26 +34,26 @@
|
||||
|
||||
namespace retro
|
||||
{
|
||||
void InitConsole();
|
||||
void InitConsole();
|
||||
}
|
||||
|
||||
using namespace retro;
|
||||
|
||||
void retro::InitConsole()
|
||||
{
|
||||
if(Console::currentInstance)
|
||||
return;
|
||||
if(Console::currentInstance)
|
||||
return;
|
||||
Console::currentInstance = (Console*) -1;
|
||||
|
||||
#if !TARGET_API_MAC_CARBON
|
||||
InitGraf(&qd.thePort);
|
||||
InitFonts();
|
||||
InitWindows();
|
||||
InitMenus();
|
||||
InitGraf(&qd.thePort);
|
||||
InitFonts();
|
||||
InitWindows();
|
||||
InitMenus();
|
||||
|
||||
Rect r = qd.screenBits.bounds;
|
||||
Rect r = qd.screenBits.bounds;
|
||||
#else
|
||||
Rect r = (*GetMainDevice())->gdRect;
|
||||
Rect r = (*GetMainDevice())->gdRect;
|
||||
#endif
|
||||
{
|
||||
// give MultiFinder a chance to bring the App to front
|
||||
@@ -71,41 +71,41 @@ void retro::InitConsole()
|
||||
EventAvail(everyEvent, &event);
|
||||
}
|
||||
|
||||
r.top += 40;
|
||||
InsetRect(&r, 5,5);
|
||||
|
||||
Console::currentInstance = new ConsoleWindow(r, "\pRetro68 Console");
|
||||
InitCursor();
|
||||
r.top += 40;
|
||||
InsetRect(&r, 5,5);
|
||||
|
||||
Console::currentInstance = new ConsoleWindow(r, "\pRetro68 Console");
|
||||
InitCursor();
|
||||
}
|
||||
|
||||
extern "C" ssize_t _consolewrite(int fd, const void *buf, size_t count)
|
||||
{
|
||||
if(!Console::currentInstance)
|
||||
InitConsole();
|
||||
if(Console::currentInstance == (Console*)-1)
|
||||
return 0;
|
||||
if(!Console::currentInstance)
|
||||
InitConsole();
|
||||
if(Console::currentInstance == (Console*)-1)
|
||||
return 0;
|
||||
|
||||
Console::currentInstance->write((const char*)buf, count);
|
||||
return count;
|
||||
Console::currentInstance->write((const char*)buf, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
extern "C" ssize_t _consoleread(int fd, void *buf, size_t count)
|
||||
{
|
||||
if(!Console::currentInstance)
|
||||
InitConsole();
|
||||
if(Console::currentInstance == (Console*)-1)
|
||||
return 0;
|
||||
if(!Console::currentInstance)
|
||||
InitConsole();
|
||||
if(Console::currentInstance == (Console*)-1)
|
||||
return 0;
|
||||
|
||||
static std::string consoleBuf;
|
||||
if(consoleBuf.size() == 0)
|
||||
{
|
||||
consoleBuf = Console::currentInstance->ReadLine();
|
||||
static std::string consoleBuf;
|
||||
if(consoleBuf.size() == 0)
|
||||
{
|
||||
consoleBuf = Console::currentInstance->ReadLine();
|
||||
if(!Console::currentInstance->IsEOF())
|
||||
consoleBuf += "\n";
|
||||
}
|
||||
if(count > consoleBuf.size())
|
||||
count = consoleBuf.size();
|
||||
memcpy(buf, consoleBuf.data(), count);
|
||||
consoleBuf = consoleBuf.substr(count);
|
||||
return count;
|
||||
}
|
||||
if(count > consoleBuf.size())
|
||||
count = consoleBuf.size();
|
||||
memcpy(buf, consoleBuf.data(), count);
|
||||
consoleBuf = consoleBuf.substr(count);
|
||||
return count;
|
||||
}
|
||||
|
||||
+340
-340
@@ -25,22 +25,22 @@ bool dataSections = true;
|
||||
bool dataInText = false;
|
||||
|
||||
using stringid = int;
|
||||
unordered_map<stringid,stringid> sectionMap;
|
||||
unordered_map<stringid,string> stringDictionary;
|
||||
unordered_map<stringid,stringid> sectionMap;
|
||||
unordered_map<stringid,string> stringDictionary;
|
||||
unordered_set<stringid> localLabels;
|
||||
|
||||
enum RecordType {
|
||||
kPad = 0,
|
||||
kFirst = 1,
|
||||
kLast = 2,
|
||||
kPad = 0,
|
||||
kFirst = 1,
|
||||
kLast = 2,
|
||||
kComment = 3,
|
||||
kDictionary = 4,
|
||||
kModule = 5,
|
||||
kEntryPoint = 6,
|
||||
kSize = 7,
|
||||
kContent = 8,
|
||||
kReference = 9,
|
||||
kComputedRef = 10,
|
||||
kDictionary = 4,
|
||||
kModule = 5,
|
||||
kEntryPoint = 6,
|
||||
kSize = 7,
|
||||
kContent = 8,
|
||||
kReference = 9,
|
||||
kComputedRef = 10,
|
||||
kFilename = 11
|
||||
};
|
||||
|
||||
@@ -49,19 +49,19 @@ enum ModuleFlags {
|
||||
kExtern = 0x08 // default local
|
||||
};
|
||||
|
||||
enum ReferenceFlags { // flags field of kReference
|
||||
k16BitPatch = 0x10, // default 32Bit
|
||||
kFromData = 0x01, // default fromCode
|
||||
kA5Relative = 0x80, // default absolute
|
||||
enum ReferenceFlags { // flags field of kReference
|
||||
k16BitPatch = 0x10, // default 32Bit
|
||||
kFromData = 0x01, // default fromCode
|
||||
kA5Relative = 0x80, // default absolute
|
||||
|
||||
kUnknownReferenceFlags = 0x6E // rather a lot, isn't it?
|
||||
// The following flags are known to exist from DumpOBJ,
|
||||
// but their value is unkown as I haven't actually seen them yet:
|
||||
// k32BitOffsets (default k16BitOffsets)
|
||||
kUnknownReferenceFlags = 0x6E // rather a lot, isn't it?
|
||||
// The following flags are known to exist from DumpOBJ,
|
||||
// but their value is unkown as I haven't actually seen them yet:
|
||||
// k32BitOffsets (default k16BitOffsets)
|
||||
};
|
||||
|
||||
enum ComputedReferenceFlags {
|
||||
kDifference = 0x80
|
||||
kDifference = 0x80
|
||||
};
|
||||
|
||||
enum ContentFlags {
|
||||
@@ -73,97 +73,97 @@ enum ContentFlags {
|
||||
string encodeIdentifier(stringid id)
|
||||
{
|
||||
const string& s = stringDictionary[id];
|
||||
std::ostringstream ss;
|
||||
std::ostringstream ss;
|
||||
|
||||
if(localLabels.find(id) != localLabels.end())
|
||||
ss << "L" << id << ".";
|
||||
|
||||
if(s.empty() || isdigit(s[0]))
|
||||
ss << "__z";
|
||||
ss << "__z";
|
||||
|
||||
for(char c : s)
|
||||
{
|
||||
if(c == '_' || isalnum(c))
|
||||
ss << c;
|
||||
else
|
||||
{
|
||||
ss << "__z" << (int) c << "_";
|
||||
}
|
||||
}
|
||||
for(char c : s)
|
||||
{
|
||||
if(c == '_' || isalnum(c))
|
||||
ss << c;
|
||||
else
|
||||
{
|
||||
ss << "__z" << (int) c << "_";
|
||||
}
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
struct Reloc
|
||||
{
|
||||
int size;
|
||||
stringid name1 = -1;
|
||||
stringid name2 = -1;
|
||||
int size;
|
||||
stringid name1 = -1;
|
||||
stringid name2 = -1;
|
||||
|
||||
int write(std::ostream& out, uint8_t *p);
|
||||
int write(std::ostream& out, uint8_t *p);
|
||||
};
|
||||
|
||||
int Reloc::write(std::ostream& out, uint8_t *p)
|
||||
{
|
||||
if(size == 2)
|
||||
{
|
||||
out << "\t.short ";
|
||||
int val = (int)p[0] * 256 + p[1];
|
||||
if(size == 2)
|
||||
{
|
||||
out << "\t.short ";
|
||||
int val = (int)p[0] * 256 + p[1];
|
||||
|
||||
out << encodeIdentifier(name1);
|
||||
if(name2 != -1)
|
||||
out << " - " << encodeIdentifier(name2);
|
||||
if(val > 0)
|
||||
out << " + " << val;
|
||||
else if(val < 0)
|
||||
out << " - " << -val;
|
||||
if(name2 == -1)
|
||||
out << "-.";
|
||||
out << std::endl;
|
||||
return 2;
|
||||
}
|
||||
else if(size == 4)
|
||||
{
|
||||
out << "\t.long ";
|
||||
int val = ((int)p[0] << 24) | ((int)p[1] << 16) | ((int)p[2] << 8) | p[3];
|
||||
out << encodeIdentifier(name1);
|
||||
if(name2 != -1)
|
||||
out << " - " << encodeIdentifier(name2);
|
||||
if(val > 0)
|
||||
out << " + " << val;
|
||||
else if(val < 0)
|
||||
out << " - " << -val;
|
||||
if(name2 == -1)
|
||||
out << "-.";
|
||||
out << std::endl;
|
||||
return 2;
|
||||
}
|
||||
else if(size == 4)
|
||||
{
|
||||
out << "\t.long ";
|
||||
int val = ((int)p[0] << 24) | ((int)p[1] << 16) | ((int)p[2] << 8) | p[3];
|
||||
|
||||
out << encodeIdentifier(name1);
|
||||
if(name2 != -1)
|
||||
out << " - " << encodeIdentifier(name2);
|
||||
if(val > 0)
|
||||
out << " + " << val;
|
||||
else if(val < 0)
|
||||
out << " - " << -val;
|
||||
out << std::endl;
|
||||
return 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
return 1;
|
||||
}
|
||||
out << encodeIdentifier(name1);
|
||||
if(name2 != -1)
|
||||
out << " - " << encodeIdentifier(name2);
|
||||
if(val > 0)
|
||||
out << " + " << val;
|
||||
else if(val < 0)
|
||||
out << " - " << -val;
|
||||
out << std::endl;
|
||||
return 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct Module
|
||||
{
|
||||
stringid name;
|
||||
stringid segment;
|
||||
stringid name;
|
||||
stringid segment;
|
||||
bool isData;
|
||||
vector<uint8_t> bytes;
|
||||
unordered_map<uint32_t, vector<stringid>> labels;
|
||||
unordered_map<uint32_t, Reloc> relocs;
|
||||
vector<uint8_t> bytes;
|
||||
unordered_map<uint32_t, vector<stringid>> labels;
|
||||
unordered_map<uint32_t, Reloc> relocs;
|
||||
|
||||
std::vector<std::weak_ptr<Module>> nearrefs;
|
||||
std::vector<std::weak_ptr<Module>> nearrefs;
|
||||
|
||||
void write(std::ostream& out);
|
||||
void write(std::ostream& out);
|
||||
};
|
||||
|
||||
void Module::write(std::ostream& out)
|
||||
{
|
||||
|
||||
string encodedName = encodeIdentifier(sectionMap[name]);
|
||||
|
||||
string encodedName = encodeIdentifier(sectionMap[name]);
|
||||
|
||||
if(isData && !dataInText)
|
||||
if(isData && !dataInText)
|
||||
{
|
||||
if(dataSections)
|
||||
out << "\t.section .data." << encodedName << ",\"aw\"\n";
|
||||
@@ -175,41 +175,41 @@ void Module::write(std::ostream& out)
|
||||
else
|
||||
{
|
||||
if(functionSections)
|
||||
out << "\t.section .text." << encodedName << ",\"ax\",@progbits\n";
|
||||
out << "\t.section .text." << encodedName << ",\"ax\",@progbits\n";
|
||||
else
|
||||
out << "\t.section .text,\"ax\",@progbits\n";
|
||||
out << "\t.section .text,\"ax\",@progbits\n";
|
||||
out << "\t.align 2,0\n";
|
||||
}
|
||||
|
||||
for(uint32_t offset = 0; offset < bytes.size();)
|
||||
{
|
||||
auto labelP = labels.find(offset);
|
||||
if(labelP != labels.end())
|
||||
{
|
||||
for(stringid rawLabel : labelP->second)
|
||||
{
|
||||
string label = encodeIdentifier(rawLabel);
|
||||
if(localLabels.find(rawLabel) == localLabels.end())
|
||||
for(uint32_t offset = 0; offset < bytes.size();)
|
||||
{
|
||||
auto labelP = labels.find(offset);
|
||||
if(labelP != labels.end())
|
||||
{
|
||||
for(stringid rawLabel : labelP->second)
|
||||
{
|
||||
string label = encodeIdentifier(rawLabel);
|
||||
if(localLabels.find(rawLabel) == localLabels.end())
|
||||
out << "\t.globl " << label << "\n";
|
||||
out << label << ":\n";
|
||||
}
|
||||
}
|
||||
out << label << ":\n";
|
||||
}
|
||||
}
|
||||
|
||||
auto relocP = relocs.find(offset);
|
||||
if(relocP != relocs.end())
|
||||
{
|
||||
offset += relocP->second.write(out, &bytes[offset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "\t.byte " << (int)bytes[offset] << "\n";
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
auto relocP = relocs.find(offset);
|
||||
if(relocP != relocs.end())
|
||||
{
|
||||
offset += relocP->second.write(out, &bytes[offset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "\t.byte " << (int)bytes[offset] << "\n";
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
if(addMacsbugNames && !isData)
|
||||
{
|
||||
if(functionSections)
|
||||
out << "\t.section .text." << encodedName << ".macsbug,\"ax\",@progbits\n";
|
||||
out << "\t.section .text." << encodedName << ".macsbug,\"ax\",@progbits\n";
|
||||
if(encodedName.size() < 32)
|
||||
out << "\t.byte " << (encodedName.size() | 0x80) << "\n";
|
||||
else
|
||||
@@ -218,38 +218,38 @@ void Module::write(std::ostream& out)
|
||||
out << "\t.ascii \"" << encodedName << "\"\n";
|
||||
out << "\t.align 2,0\n\t.short 0\n";
|
||||
}
|
||||
out << "# ######\n\n";
|
||||
out << "# ######\n\n";
|
||||
}
|
||||
|
||||
void sortModules(std::vector<std::shared_ptr<Module>>& modules)
|
||||
{
|
||||
std::set<stringid> unemitted;
|
||||
for(auto& m : modules)
|
||||
unemitted.insert(m->name);
|
||||
|
||||
std::unordered_map<stringid, std::shared_ptr<Module>> nameMap;
|
||||
for(auto& m : modules)
|
||||
for(auto& l : m->labels)
|
||||
for(auto& str : l.second)
|
||||
nameMap[str] = m;
|
||||
|
||||
|
||||
for(auto& m : modules)
|
||||
for(auto& r : m->relocs)
|
||||
{
|
||||
if(r.second.size != 2)
|
||||
continue;
|
||||
if(r.second.name2 == -1)
|
||||
{
|
||||
if(auto p = nameMap.find(r.second.name1); p != nameMap.end())
|
||||
std::set<stringid> unemitted;
|
||||
for(auto& m : modules)
|
||||
unemitted.insert(m->name);
|
||||
|
||||
std::unordered_map<stringid, std::shared_ptr<Module>> nameMap;
|
||||
for(auto& m : modules)
|
||||
for(auto& l : m->labels)
|
||||
for(auto& str : l.second)
|
||||
nameMap[str] = m;
|
||||
|
||||
|
||||
for(auto& m : modules)
|
||||
for(auto& r : m->relocs)
|
||||
{
|
||||
if(r.second.size != 2)
|
||||
continue;
|
||||
if(r.second.name2 == -1)
|
||||
{
|
||||
if(auto p = nameMap.find(r.second.name1); p != nameMap.end())
|
||||
{
|
||||
std::shared_ptr<Module> m1 = p->second;
|
||||
m1->nearrefs.push_back(m);
|
||||
m->nearrefs.push_back(m1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
auto p1 = nameMap.find(r.second.name1);
|
||||
auto p2 = nameMap.find(r.second.name2);
|
||||
|
||||
@@ -260,60 +260,60 @@ void sortModules(std::vector<std::shared_ptr<Module>>& modules)
|
||||
m1->nearrefs.push_back(m2);
|
||||
m2->nearrefs.push_back(m1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::shared_ptr<Module>> sorted;
|
||||
sorted.reserve(modules.size());
|
||||
|
||||
auto p = sorted.begin();
|
||||
|
||||
while(!unemitted.empty())
|
||||
{
|
||||
while(p != sorted.end())
|
||||
{
|
||||
for(auto& m2weak : (*p)->nearrefs)
|
||||
{
|
||||
if(std::shared_ptr<Module> m2 = m2weak.lock())
|
||||
{
|
||||
auto unemittedP = unemitted.find(m2->name);
|
||||
if(unemittedP != unemitted.end())
|
||||
{
|
||||
sorted.push_back(m2);
|
||||
unemitted.erase(unemittedP);
|
||||
}
|
||||
}
|
||||
}
|
||||
++p;
|
||||
}
|
||||
std::vector<std::shared_ptr<Module>> sorted;
|
||||
sorted.reserve(modules.size());
|
||||
|
||||
auto p = sorted.begin();
|
||||
|
||||
while(!unemitted.empty())
|
||||
{
|
||||
while(p != sorted.end())
|
||||
{
|
||||
for(auto& m2weak : (*p)->nearrefs)
|
||||
{
|
||||
if(std::shared_ptr<Module> m2 = m2weak.lock())
|
||||
{
|
||||
auto unemittedP = unemitted.find(m2->name);
|
||||
if(unemittedP != unemitted.end())
|
||||
{
|
||||
sorted.push_back(m2);
|
||||
unemitted.erase(unemittedP);
|
||||
}
|
||||
}
|
||||
}
|
||||
++p;
|
||||
}
|
||||
if(!unemitted.empty())
|
||||
{
|
||||
sorted.push_back(nameMap[*unemitted.begin()]);
|
||||
unemitted.erase(unemitted.begin());
|
||||
}
|
||||
}
|
||||
|
||||
sorted.swap(modules);
|
||||
}
|
||||
|
||||
sorted.swap(modules);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if(argc != 2)
|
||||
{
|
||||
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
|
||||
return 1;
|
||||
}
|
||||
std::ifstream in(argv[1]);
|
||||
if(!in)
|
||||
{
|
||||
std::cerr << "Could not read imput file \"" << argv[1] << "\"\n";
|
||||
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::shared_ptr<Module> module;
|
||||
std::vector<std::shared_ptr<Module>> modules;
|
||||
if(argc != 2)
|
||||
{
|
||||
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
|
||||
return 1;
|
||||
}
|
||||
std::ifstream in(argv[1]);
|
||||
if(!in)
|
||||
{
|
||||
std::cerr << "Could not read imput file \"" << argv[1] << "\"\n";
|
||||
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::shared_ptr<Module> module;
|
||||
std::vector<std::shared_ptr<Module>> modules;
|
||||
|
||||
|
||||
{
|
||||
@@ -343,30 +343,30 @@ int main(int argc, char* argv[])
|
||||
|
||||
std::cout << "\t.text\n\t.align 2\n";
|
||||
|
||||
for(bool endOfObject = false; !endOfObject;) {
|
||||
if(verbose)
|
||||
std::cerr << std::hex << in.tellg() << ": ";
|
||||
int recordType = byte(in);
|
||||
if(!in)
|
||||
{
|
||||
std::cerr << "Unexpected End of File\n";
|
||||
return 1;
|
||||
}
|
||||
for(bool endOfObject = false; !endOfObject;) {
|
||||
if(verbose)
|
||||
std::cerr << std::hex << in.tellg() << ": ";
|
||||
int recordType = byte(in);
|
||||
if(!in)
|
||||
{
|
||||
std::cerr << "Unexpected End of File\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(verbose)
|
||||
std::cerr << "Record: " << recordType << std::endl;
|
||||
if(verbose)
|
||||
std::cerr << "Record: " << recordType << std::endl;
|
||||
|
||||
|
||||
switch(recordType)
|
||||
{
|
||||
case kPad:
|
||||
if(verbose)
|
||||
std::cerr << "Pad\n";
|
||||
break;
|
||||
switch(recordType)
|
||||
{
|
||||
case kPad:
|
||||
if(verbose)
|
||||
std::cerr << "Pad\n";
|
||||
break;
|
||||
case kComment:
|
||||
{
|
||||
/*int flags =*/ byte(in);
|
||||
int size = word(in);
|
||||
/*int flags =*/ byte(in);
|
||||
int size = word(in);
|
||||
size -= 4;
|
||||
if(verbose)
|
||||
std::cerr << "Comment: ";
|
||||
@@ -380,189 +380,189 @@ int main(int argc, char* argv[])
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
break;
|
||||
case kDictionary:
|
||||
{
|
||||
/*int flags =*/ byte(in);
|
||||
if(verbose)
|
||||
std::cerr << "Dictionary\n";
|
||||
int sz = word(in);
|
||||
int stringId = word(in);
|
||||
int end = (int)(in.tellg()) - 6 + sz;
|
||||
while(in.tellg() < end)
|
||||
{
|
||||
int n = byte(in);
|
||||
string s;
|
||||
for(int i = 0; i < n; i++)
|
||||
s += (char) byte(in);
|
||||
if(verbose)
|
||||
std::cerr << s << std::endl;
|
||||
stringDictionary[stringId++] = s;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kModule:
|
||||
{
|
||||
int flags = byte(in);
|
||||
stringid name = word(in);
|
||||
sectionMap[name] = name;
|
||||
stringid segment = word(in);
|
||||
case kDictionary:
|
||||
{
|
||||
/*int flags =*/ byte(in);
|
||||
if(verbose)
|
||||
std::cerr << "Dictionary\n";
|
||||
int sz = word(in);
|
||||
int stringId = word(in);
|
||||
int end = (int)(in.tellg()) - 6 + sz;
|
||||
while(in.tellg() < end)
|
||||
{
|
||||
int n = byte(in);
|
||||
string s;
|
||||
for(int i = 0; i < n; i++)
|
||||
s += (char) byte(in);
|
||||
if(verbose)
|
||||
std::cerr << s << std::endl;
|
||||
stringDictionary[stringId++] = s;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kModule:
|
||||
{
|
||||
int flags = byte(in);
|
||||
stringid name = word(in);
|
||||
sectionMap[name] = name;
|
||||
stringid segment = word(in);
|
||||
|
||||
if(verbose)
|
||||
std::cerr << "Module " << stringDictionary[name] << "(" << stringDictionary[segment] << "), flags = " << flags << "\n";
|
||||
if(verbose)
|
||||
std::cerr << "Module " << stringDictionary[name] << "(" << stringDictionary[segment] << "), flags = " << flags << "\n";
|
||||
|
||||
if((flags & kExtern) == 0)
|
||||
localLabels.insert(name);
|
||||
|
||||
module.reset(new Module());
|
||||
module->name = name;
|
||||
module.reset(new Module());
|
||||
module->name = name;
|
||||
module->segment = segment;
|
||||
module->isData = (flags & kData) != 0;
|
||||
module->labels[0].push_back(name);
|
||||
modules.push_back(module);
|
||||
}
|
||||
break;
|
||||
case kContent:
|
||||
{
|
||||
int flags = byte(in);
|
||||
int sz = word(in) - 4;
|
||||
uint32_t offset = 0;
|
||||
if(flags & kContentOffset)
|
||||
{
|
||||
offset = longword(in);
|
||||
sz -= 4;
|
||||
}
|
||||
module->labels[0].push_back(name);
|
||||
modules.push_back(module);
|
||||
}
|
||||
break;
|
||||
case kContent:
|
||||
{
|
||||
int flags = byte(in);
|
||||
int sz = word(in) - 4;
|
||||
uint32_t offset = 0;
|
||||
if(flags & kContentOffset)
|
||||
{
|
||||
offset = longword(in);
|
||||
sz -= 4;
|
||||
}
|
||||
int repeat = 1;
|
||||
if(flags & kContentRepeat)
|
||||
{
|
||||
repeat = word(in);
|
||||
sz -= 2;
|
||||
}
|
||||
if(verbose)
|
||||
std::cerr << "Content (offset = " << offset << ", size = " << sz << ", repeat = " << repeat << ")\n";
|
||||
if(verbose)
|
||||
std::cerr << "Content (offset = " << offset << ", size = " << sz << ", repeat = " << repeat << ")\n";
|
||||
|
||||
assert(module.get());
|
||||
if(module->bytes.size() < offset + sz * repeat)
|
||||
module->bytes.resize(offset + sz * repeat);
|
||||
in.read((char*) &module->bytes[offset], sz);
|
||||
assert(module.get());
|
||||
if(module->bytes.size() < offset + sz * repeat)
|
||||
module->bytes.resize(offset + sz * repeat);
|
||||
in.read((char*) &module->bytes[offset], sz);
|
||||
while(--repeat > 0)
|
||||
{
|
||||
std::copy(module->bytes.begin() + offset, module->bytes.begin() + offset + sz,
|
||||
module->bytes.begin() + offset + sz);
|
||||
offset += sz;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kSize:
|
||||
{
|
||||
/*int flags =*/ byte(in);
|
||||
long size = longword(in);
|
||||
if(verbose)
|
||||
std::cerr << "Size " << size << "\n";
|
||||
assert(module.get());
|
||||
module->bytes.resize(size);
|
||||
}
|
||||
break;
|
||||
case kReference:
|
||||
{
|
||||
int flags = byte(in);
|
||||
int sz = word(in);
|
||||
int end = (int)(in.tellg()) - 4 + sz;
|
||||
stringid name = word(in);
|
||||
}
|
||||
break;
|
||||
case kSize:
|
||||
{
|
||||
/*int flags =*/ byte(in);
|
||||
long size = longword(in);
|
||||
if(verbose)
|
||||
std::cerr << "Size " << size << "\n";
|
||||
assert(module.get());
|
||||
module->bytes.resize(size);
|
||||
}
|
||||
break;
|
||||
case kReference:
|
||||
{
|
||||
int flags = byte(in);
|
||||
int sz = word(in);
|
||||
int end = (int)(in.tellg()) - 4 + sz;
|
||||
stringid name = word(in);
|
||||
|
||||
if(verbose)
|
||||
std::cerr << "Reference to " << stringDictionary[name] << " at\n";
|
||||
Reloc reloc;
|
||||
reloc.name1 = name;
|
||||
if(verbose)
|
||||
std::cerr << "Reference to " << stringDictionary[name] << " at\n";
|
||||
Reloc reloc;
|
||||
reloc.name1 = name;
|
||||
|
||||
if(flags & kUnknownReferenceFlags)
|
||||
{
|
||||
std::cerr << "Unknown relocation flags: 0x" << std::hex << flags << std::endl;
|
||||
std::cerr << "Cannot convert this file.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
if(flags & kA5Relative)
|
||||
{
|
||||
std::cerr << "Unsupported relocation flags: 0x" << std::hex << flags << std::endl;
|
||||
std::cerr << "MPW .o files with near-model global variables or calls to imported functions will not work.\n";
|
||||
std::cerr << "Cannot convert this file.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
flags &= ~kFromData; // FIXME: sticking data bits in the text section, not nice, but might sometimes work
|
||||
if(flags & kUnknownReferenceFlags)
|
||||
{
|
||||
std::cerr << "Unknown relocation flags: 0x" << std::hex << flags << std::endl;
|
||||
std::cerr << "Cannot convert this file.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
if(flags & kA5Relative)
|
||||
{
|
||||
std::cerr << "Unsupported relocation flags: 0x" << std::hex << flags << std::endl;
|
||||
std::cerr << "MPW .o files with near-model global variables or calls to imported functions will not work.\n";
|
||||
std::cerr << "Cannot convert this file.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
flags &= ~kFromData; // FIXME: sticking data bits in the text section, not nice, but might sometimes work
|
||||
|
||||
reloc.size = (flags & k16BitPatch ? 2 : 4);
|
||||
reloc.size = (flags & k16BitPatch ? 2 : 4);
|
||||
|
||||
assert(module);
|
||||
assert(module);
|
||||
|
||||
while(in.tellg() < end)
|
||||
{
|
||||
int offset = word(in);
|
||||
if(verbose)
|
||||
std::cerr << " " << offset << std::endl;
|
||||
module->relocs[offset] = reloc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kEntryPoint:
|
||||
{
|
||||
int flags = byte(in);
|
||||
stringid name = word(in);
|
||||
long offset = longword(in);
|
||||
if(verbose)
|
||||
std::cerr << "EntryPoint " << stringDictionary[name] << " at offset " << offset << "\n";
|
||||
while(in.tellg() < end)
|
||||
{
|
||||
int offset = word(in);
|
||||
if(verbose)
|
||||
std::cerr << " " << offset << std::endl;
|
||||
module->relocs[offset] = reloc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kEntryPoint:
|
||||
{
|
||||
int flags = byte(in);
|
||||
stringid name = word(in);
|
||||
long offset = longword(in);
|
||||
if(verbose)
|
||||
std::cerr << "EntryPoint " << stringDictionary[name] << " at offset " << offset << "\n";
|
||||
if((flags & kExtern) == 0)
|
||||
localLabels.insert(name);
|
||||
|
||||
assert(module);
|
||||
module->labels[offset].push_back(name);
|
||||
}
|
||||
break;
|
||||
case kComputedRef:
|
||||
{
|
||||
int flags = byte(in);
|
||||
int sz = word(in);
|
||||
int end = (int)(in.tellg()) - 4 + sz;
|
||||
stringid name1 = word(in);
|
||||
stringid name2 = word(in);
|
||||
assert(module);
|
||||
module->labels[offset].push_back(name);
|
||||
}
|
||||
break;
|
||||
case kComputedRef:
|
||||
{
|
||||
int flags = byte(in);
|
||||
int sz = word(in);
|
||||
int end = (int)(in.tellg()) - 4 + sz;
|
||||
stringid name1 = word(in);
|
||||
stringid name2 = word(in);
|
||||
|
||||
Reloc reloc;
|
||||
reloc.name1 = name1;
|
||||
reloc.name2 = name2;
|
||||
reloc.size = 2;
|
||||
Reloc reloc;
|
||||
reloc.name1 = name1;
|
||||
reloc.name2 = name2;
|
||||
reloc.size = 2;
|
||||
|
||||
assert(flags == 0x90);
|
||||
assert(module);
|
||||
assert(flags == 0x90);
|
||||
assert(module);
|
||||
|
||||
if(auto p = sectionMap.find(name1); p != sectionMap.end())
|
||||
sectionMap[module->name] = p->second;
|
||||
if(verbose)
|
||||
std::cerr << "ComputedReference to "
|
||||
if(verbose)
|
||||
std::cerr << "ComputedReference to "
|
||||
<< stringDictionary[name1] << " - " << stringDictionary[name2] << " at\n";
|
||||
while(in.tellg() < end)
|
||||
{
|
||||
int offset = word(in);
|
||||
if(verbose)
|
||||
std::cerr << " " << offset << std::endl;
|
||||
module->relocs[offset] = reloc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
while(in.tellg() < end)
|
||||
{
|
||||
int offset = word(in);
|
||||
if(verbose)
|
||||
std::cerr << " " << offset << std::endl;
|
||||
module->relocs[offset] = reloc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kFilename:
|
||||
/* int flags = */ byte(in);
|
||||
/* short nameref = */ word(in);
|
||||
/* long date = */ longword(in);
|
||||
break;
|
||||
case kLast:
|
||||
byte(in);
|
||||
endOfObject = true;
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Unknown record (type " << recordType << ") at " << std::hex << in.tellg() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(shouldSortModules)
|
||||
sortModules(modules);
|
||||
for(auto& m : modules)
|
||||
m->write(std::cout);
|
||||
return 0;
|
||||
case kLast:
|
||||
byte(in);
|
||||
endOfObject = true;
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Unknown record (type " << recordType << ") at " << std::hex << in.tellg() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(shouldSortModules)
|
||||
sortModules(modules);
|
||||
for(auto& m : modules)
|
||||
m->write(std::cout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
find_package(Boost COMPONENTS REQUIRED)
|
||||
|
||||
add_executable(Elf2Mac
|
||||
Elf2Mac.h Elf2Mac.cc SegmentMap.cc LdScript.cc
|
||||
Reloc.h Reloc.cc
|
||||
Symbol.h Symbol.cc
|
||||
Symtab.h Symtab.cc
|
||||
Section.h Section.cc
|
||||
Object.h Object.cc)
|
||||
Elf2Mac.h Elf2Mac.cc SegmentMap.cc LdScript.cc
|
||||
Reloc.h Reloc.cc
|
||||
Symbol.h Symbol.cc
|
||||
Symtab.h Symtab.cc
|
||||
Section.h Section.cc
|
||||
Object.h Object.cc)
|
||||
target_link_libraries(Elf2Mac ResourceFiles ELF)
|
||||
|
||||
target_include_directories(Elf2Mac PRIVATE ${CMAKE_INSTALL_PREFIX}/include)
|
||||
|
||||
+161
-161
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Elf2Mac.h"
|
||||
@@ -45,179 +45,179 @@ string argvZero;
|
||||
|
||||
void RealLD(vector<string> args)
|
||||
{
|
||||
vector<const char*> argv;
|
||||
string realLD = argvZero + ".real";
|
||||
argv.push_back(realLD.c_str());
|
||||
for(string& s : args)
|
||||
argv.push_back(s.c_str());
|
||||
argv.push_back(NULL);
|
||||
vector<const char*> argv;
|
||||
string realLD = argvZero + ".real";
|
||||
argv.push_back(realLD.c_str());
|
||||
for(string& s : args)
|
||||
argv.push_back(s.c_str());
|
||||
argv.push_back(NULL);
|
||||
|
||||
pid_t pid = fork();
|
||||
if(pid < 0)
|
||||
{
|
||||
perror("unable to fork");
|
||||
exit(-1);
|
||||
}
|
||||
else if(pid == 0)
|
||||
{
|
||||
execvp(argv[0], const_cast<char* const *> (argv.data()));
|
||||
perror("exec failed");
|
||||
exit(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int wstatus;
|
||||
int result = 0;
|
||||
do
|
||||
{
|
||||
result = waitpid(pid, &wstatus, 0);
|
||||
} while(result == -1 && errno == EINTR);
|
||||
if(!WIFEXITED(wstatus))
|
||||
{
|
||||
errx(EXIT_FAILURE, "ld process did not exit properly");
|
||||
}
|
||||
else
|
||||
{
|
||||
int exitcode = WEXITSTATUS(wstatus);
|
||||
if(exitcode)
|
||||
exit(exitcode);
|
||||
}
|
||||
}
|
||||
pid_t pid = fork();
|
||||
if(pid < 0)
|
||||
{
|
||||
perror("unable to fork");
|
||||
exit(-1);
|
||||
}
|
||||
else if(pid == 0)
|
||||
{
|
||||
execvp(argv[0], const_cast<char* const *> (argv.data()));
|
||||
perror("exec failed");
|
||||
exit(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int wstatus;
|
||||
int result = 0;
|
||||
do
|
||||
{
|
||||
result = waitpid(pid, &wstatus, 0);
|
||||
} while(result == -1 && errno == EINTR);
|
||||
if(!WIFEXITED(wstatus))
|
||||
{
|
||||
errx(EXIT_FAILURE, "ld process did not exit properly");
|
||||
}
|
||||
else
|
||||
{
|
||||
int exitcode = WEXITSTATUS(wstatus);
|
||||
if(exitcode)
|
||||
exit(exitcode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
vector<string> args;
|
||||
std::copy(argv + 1, argv+argc, std::back_inserter(args));
|
||||
argvZero = argv[0];
|
||||
vector<string> args;
|
||||
std::copy(argv + 1, argv+argc, std::back_inserter(args));
|
||||
argvZero = argv[0];
|
||||
|
||||
if(boost::algorithm::ends_with(argv[0], "ld"))
|
||||
{
|
||||
string outputFile = "a.out";
|
||||
if(boost::algorithm::ends_with(argv[0], "ld"))
|
||||
{
|
||||
string outputFile = "a.out";
|
||||
string entryPoint = "_start";
|
||||
bool elf2mac = false;
|
||||
bool flatoutput = false;
|
||||
bool segments = true;
|
||||
bool stripMacsbug = false;
|
||||
bool elf2mac = false;
|
||||
bool flatoutput = false;
|
||||
bool segments = true;
|
||||
bool stripMacsbug = false;
|
||||
bool saveLdScript = false;
|
||||
|
||||
SegmentMap segmentMap;
|
||||
SegmentMap segmentMap;
|
||||
|
||||
vector<string> args2;
|
||||
for(auto p = args.begin(), e = args.end(); p != e; ++p)
|
||||
{
|
||||
if(*p == "-o")
|
||||
{
|
||||
++p;
|
||||
if(p == e)
|
||||
errx(EXIT_FAILURE, "-o missing argument");
|
||||
outputFile = *p;
|
||||
}
|
||||
else if(boost::algorithm::starts_with(*p, "-o"))
|
||||
{
|
||||
outputFile = (*p).substr(2);
|
||||
}
|
||||
else if(*p == "-elf2mac" || *p == "--elf2mac")
|
||||
{
|
||||
elf2mac = true;
|
||||
}
|
||||
vector<string> args2;
|
||||
for(auto p = args.begin(), e = args.end(); p != e; ++p)
|
||||
{
|
||||
if(*p == "-o")
|
||||
{
|
||||
++p;
|
||||
if(p == e)
|
||||
errx(EXIT_FAILURE, "-o missing argument");
|
||||
outputFile = *p;
|
||||
}
|
||||
else if(boost::algorithm::starts_with(*p, "-o"))
|
||||
{
|
||||
outputFile = (*p).substr(2);
|
||||
}
|
||||
else if(*p == "-elf2mac" || *p == "--elf2mac")
|
||||
{
|
||||
elf2mac = true;
|
||||
}
|
||||
else if(*p == "-e")
|
||||
{
|
||||
++p;
|
||||
if(p == e)
|
||||
errx(EXIT_FAILURE, "-e missing argument");
|
||||
entryPoint = *p;
|
||||
}
|
||||
{
|
||||
++p;
|
||||
if(p == e)
|
||||
errx(EXIT_FAILURE, "-e missing argument");
|
||||
entryPoint = *p;
|
||||
}
|
||||
else if(boost::algorithm::starts_with(*p, "-e"))
|
||||
{
|
||||
entryPoint = (*p).substr(2);
|
||||
}
|
||||
else if(*p == "--mac-flat")
|
||||
{
|
||||
elf2mac = true;
|
||||
flatoutput = true;
|
||||
segments = false;
|
||||
}
|
||||
else if(*p == "--mac-single")
|
||||
{
|
||||
elf2mac = true;
|
||||
flatoutput = false;
|
||||
segments = false;
|
||||
}
|
||||
else if(*p == "--mac-segments")
|
||||
{
|
||||
elf2mac = true;
|
||||
if(flatoutput)
|
||||
errx(EXIT_FAILURE, "--mac-segments can't be used with --mac-flat");
|
||||
++p;
|
||||
if(p == e)
|
||||
errx(EXIT_FAILURE, "--mac-segments missing argument");
|
||||
segmentMap = SegmentMap(*p);
|
||||
}
|
||||
else if(*p == "--mac-strip-macsbug")
|
||||
{
|
||||
stripMacsbug = true;
|
||||
}
|
||||
else if(*p == "--mac-flat")
|
||||
{
|
||||
elf2mac = true;
|
||||
flatoutput = true;
|
||||
segments = false;
|
||||
}
|
||||
else if(*p == "--mac-single")
|
||||
{
|
||||
elf2mac = true;
|
||||
flatoutput = false;
|
||||
segments = false;
|
||||
}
|
||||
else if(*p == "--mac-segments")
|
||||
{
|
||||
elf2mac = true;
|
||||
if(flatoutput)
|
||||
errx(EXIT_FAILURE, "--mac-segments can't be used with --mac-flat");
|
||||
++p;
|
||||
if(p == e)
|
||||
errx(EXIT_FAILURE, "--mac-segments missing argument");
|
||||
segmentMap = SegmentMap(*p);
|
||||
}
|
||||
else if(*p == "--mac-strip-macsbug")
|
||||
{
|
||||
stripMacsbug = true;
|
||||
}
|
||||
else if(*p == "--mac-keep-ldscript")
|
||||
{
|
||||
saveLdScript = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
args2.push_back(*p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
args2.push_back(*p);
|
||||
}
|
||||
}
|
||||
|
||||
if(elf2mac)
|
||||
{
|
||||
char tmpfile[] = "/tmp/ldscriptXXXXXX";
|
||||
int fd = mkstemp(tmpfile);
|
||||
if(fd < 0)
|
||||
errx(EXIT_FAILURE, "can't create temp file");
|
||||
if(elf2mac)
|
||||
{
|
||||
char tmpfile[] = "/tmp/ldscriptXXXXXX";
|
||||
int fd = mkstemp(tmpfile);
|
||||
if(fd < 0)
|
||||
errx(EXIT_FAILURE, "can't create temp file");
|
||||
|
||||
{
|
||||
ofstream out(tmpfile);
|
||||
if(segments)
|
||||
{
|
||||
segmentMap.CreateLdScript(out, entryPoint, stripMacsbug);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateFlatLdScript(out, entryPoint, stripMacsbug);
|
||||
}
|
||||
}
|
||||
{
|
||||
ofstream out(tmpfile);
|
||||
if(segments)
|
||||
{
|
||||
segmentMap.CreateLdScript(out, entryPoint, stripMacsbug);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateFlatLdScript(out, entryPoint, stripMacsbug);
|
||||
}
|
||||
}
|
||||
|
||||
args2.push_back("-o");
|
||||
args2.push_back(outputFile + ".gdb");
|
||||
args2.push_back("-T");
|
||||
args2.push_back(tmpfile);
|
||||
RealLD(args2);
|
||||
if(saveLdScript)
|
||||
args2.push_back("-o");
|
||||
args2.push_back(outputFile + ".gdb");
|
||||
args2.push_back("-T");
|
||||
args2.push_back(tmpfile);
|
||||
RealLD(args2);
|
||||
if(saveLdScript)
|
||||
std::cerr << "Ld Script at: " << tmpfile << std::endl;
|
||||
else
|
||||
unlink(tmpfile);
|
||||
Object theObject(outputFile + ".gdb");
|
||||
if(flatoutput)
|
||||
theObject.FlatCode(outputFile);
|
||||
else if(segments)
|
||||
theObject.MultiSegmentApp(outputFile, segmentMap);
|
||||
else
|
||||
theObject.SingleSegmentApp(outputFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
RealLD(args);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(argc != 2)
|
||||
errx(EXIT_FAILURE, "usage : %s file-name ", argv[0]);
|
||||
Object theObject(argv[1]);
|
||||
SegmentMap segmentMap;
|
||||
theObject.MultiSegmentApp("out.bin", segmentMap);
|
||||
}
|
||||
return 0;
|
||||
Object theObject(outputFile + ".gdb");
|
||||
if(flatoutput)
|
||||
theObject.FlatCode(outputFile);
|
||||
else if(segments)
|
||||
theObject.MultiSegmentApp(outputFile, segmentMap);
|
||||
else
|
||||
theObject.SingleSegmentApp(outputFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
RealLD(args);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(argc != 2)
|
||||
errx(EXIT_FAILURE, "usage : %s file-name ", argv[0]);
|
||||
Object theObject(argv[1]);
|
||||
SegmentMap segmentMap;
|
||||
theObject.MultiSegmentApp("out.bin", segmentMap);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+12
-12
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ELF2MAC_H
|
||||
|
||||
+103
-103
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Elf2Mac.h"
|
||||
@@ -34,7 +34,7 @@ SECTIONS
|
||||
)ld";
|
||||
|
||||
const char * textSection = R"ld(/* ld script for Elf2Mac */
|
||||
.text : {
|
||||
.text : {
|
||||
_stext = . ;
|
||||
PROVIDE(_rsrc_start = .);
|
||||
*(.rsrcheader)
|
||||
@@ -142,7 +142,7 @@ const char * scriptEnd = R"ld(
|
||||
* Keep them for now, they are discarded by Elf2Mac. */
|
||||
|
||||
/DISCARD/ : { *(.note.GNU-stack) }
|
||||
/* Stabs debugging sections. */
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
@@ -184,120 +184,120 @@ const char * scriptEnd = R"ld(
|
||||
|
||||
void CreateFlatLdScript(std::ostream& out, string entryPoint, bool stripMacsbug)
|
||||
{
|
||||
out << "_MULTISEG_APP = 0;\n";
|
||||
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
|
||||
if(stripMacsbug)
|
||||
{
|
||||
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
|
||||
out << "\t. = 0;\n";
|
||||
}
|
||||
out << boost::replace_all_copy<string>(textSection, "@entryPoint@", entryPoint) << scriptEnd;
|
||||
out << "_MULTISEG_APP = 0;\n";
|
||||
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
|
||||
if(stripMacsbug)
|
||||
{
|
||||
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
|
||||
out << "\t. = 0;\n";
|
||||
}
|
||||
out << boost::replace_all_copy<string>(textSection, "@entryPoint@", entryPoint) << scriptEnd;
|
||||
}
|
||||
|
||||
|
||||
void SegmentInfo::WriteFilters(std::ostream &out, string section)
|
||||
{
|
||||
for(string filter : filters)
|
||||
{
|
||||
out << " " << filter << "(" << section << ")\n";
|
||||
out << " " << filter << "(" << section << ".*)\n";
|
||||
}
|
||||
for(string filter : filters)
|
||||
{
|
||||
out << " " << filter << "(" << section << ")\n";
|
||||
out << " " << filter << "(" << section << ".*)\n";
|
||||
}
|
||||
}
|
||||
void SegmentInfo::WriteFiltersKeep(std::ostream &out, string section)
|
||||
{
|
||||
for(string filter : filters)
|
||||
{
|
||||
out << "\t\tKEEP(" << filter << "(" << section << "))\n";
|
||||
out << "\t\tKEEP(" << filter << "(" << section << ".*))\n";
|
||||
}
|
||||
for(string filter : filters)
|
||||
{
|
||||
out << "\t\tKEEP(" << filter << "(" << section << "))\n";
|
||||
out << "\t\tKEEP(" << filter << "(" << section << ".*))\n";
|
||||
}
|
||||
}
|
||||
|
||||
void SegmentInfo::CreateLdScript(std::ostream &out, string entryPoint)
|
||||
{
|
||||
out << "\t.code" << id << " : {\n";
|
||||
out << "\t\tFILL(0x4E71);\n";
|
||||
if(id == 1)
|
||||
{
|
||||
out << boost::replace_all_copy<string>(R"ld(
|
||||
_stext = .;
|
||||
FILL(0x4E71);
|
||||
PROVIDE(_rsrc_start = .);
|
||||
. = ALIGN (2);
|
||||
_entry_trampoline = .;
|
||||
SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71);
|
||||
LONG(0x61000002); /* bsr *+2 */
|
||||
SHORT(0x0697); /* addi.l #_, (a7) */
|
||||
LONG(@entryPoint@ - _entry_trampoline - 6);
|
||||
PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */
|
||||
SHORT(0x4e75); /* rts */
|
||||
out << "\t.code" << id << " : {\n";
|
||||
out << "\t\tFILL(0x4E71);\n";
|
||||
if(id == 1)
|
||||
{
|
||||
out << boost::replace_all_copy<string>(R"ld(
|
||||
_stext = .;
|
||||
FILL(0x4E71);
|
||||
PROVIDE(_rsrc_start = .);
|
||||
. = ALIGN (2);
|
||||
_entry_trampoline = .;
|
||||
SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71);
|
||||
LONG(0x61000002); /* bsr *+2 */
|
||||
SHORT(0x0697); /* addi.l #_, (a7) */
|
||||
LONG(@entryPoint@ - _entry_trampoline - 6);
|
||||
PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */
|
||||
SHORT(0x4e75); /* rts */
|
||||
|
||||
FILL(0);
|
||||
*(.relocvars)
|
||||
FILL(0x4E71);
|
||||
FILL(0);
|
||||
*(.relocvars)
|
||||
FILL(0x4E71);
|
||||
)ld", "@entryPoint@", entryPoint);
|
||||
}
|
||||
WriteFilters(out, ".text");
|
||||
}
|
||||
WriteFilters(out, ".text");
|
||||
|
||||
if(id == 2)
|
||||
{
|
||||
out << "\t\t*(.gnu.linkonce.t*)\n";
|
||||
}
|
||||
if(id == 1)
|
||||
{
|
||||
out << R"ld(
|
||||
. = ALIGN (4) ;
|
||||
__init_section = .;
|
||||
KEEP (*(.init))
|
||||
__init_section_end = .;
|
||||
__fini_section = .;
|
||||
KEEP (*(.fini))
|
||||
__fini_section_end = .;
|
||||
if(id == 2)
|
||||
{
|
||||
out << "\t\t*(.gnu.linkonce.t*)\n";
|
||||
}
|
||||
if(id == 1)
|
||||
{
|
||||
out << R"ld(
|
||||
. = ALIGN (4) ;
|
||||
__init_section = .;
|
||||
KEEP (*(.init))
|
||||
__init_section_end = .;
|
||||
__fini_section = .;
|
||||
KEEP (*(.fini))
|
||||
__fini_section_end = .;
|
||||
)ld";
|
||||
}
|
||||
}
|
||||
|
||||
out << "\t\t. = ALIGN (4);\n"; // this is important, for some reason.
|
||||
if(id == 1)
|
||||
out << "\t\t__EH_FRAME_BEGIN__" << " = .;\n";
|
||||
else
|
||||
out << "\t\t__EH_FRAME_BEGIN__" << id << " = .;\n";
|
||||
WriteFiltersKeep(out, ".eh_frame");
|
||||
out << "\t\tLONG(0);\n";
|
||||
WriteFiltersKeep(out, ".gcc_except_table");
|
||||
out << "\t\t. = ALIGN (4);\n"; // this is important, for some reason.
|
||||
if(id == 1)
|
||||
out << "\t\t__EH_FRAME_BEGIN__" << " = .;\n";
|
||||
else
|
||||
out << "\t\t__EH_FRAME_BEGIN__" << id << " = .;\n";
|
||||
WriteFiltersKeep(out, ".eh_frame");
|
||||
out << "\t\tLONG(0);\n";
|
||||
WriteFiltersKeep(out, ".gcc_except_table");
|
||||
|
||||
if(id == 1)
|
||||
{
|
||||
out << R"ld(
|
||||
. = ALIGN(0x4) ;
|
||||
_etext = . ;
|
||||
if(id == 1)
|
||||
{
|
||||
out << R"ld(
|
||||
. = ALIGN(0x4) ;
|
||||
_etext = . ;
|
||||
)ld";
|
||||
}
|
||||
else
|
||||
{
|
||||
out << boost::replace_all_copy<string>(R"ld(
|
||||
. = ALIGN(0x4);
|
||||
FILL(0);
|
||||
. += 32;
|
||||
LONG(__EH_FRAME_BEGIN__@N@ - .);
|
||||
}
|
||||
else
|
||||
{
|
||||
out << boost::replace_all_copy<string>(R"ld(
|
||||
. = ALIGN(0x4);
|
||||
FILL(0);
|
||||
. += 32;
|
||||
LONG(__EH_FRAME_BEGIN__@N@ - .);
|
||||
)ld", "@N@", boost::lexical_cast<string>(id));
|
||||
}
|
||||
}
|
||||
|
||||
out << "\t}\n";
|
||||
out << "\t}\n";
|
||||
|
||||
}
|
||||
|
||||
void SegmentMap::CreateLdScript(std::ostream &out, string entryPoint, bool stripMacsbug)
|
||||
{
|
||||
out << "_MULTISEG_APP = 1;\n";
|
||||
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
|
||||
if(stripMacsbug)
|
||||
{
|
||||
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
|
||||
out << "\t. = 0;\n";
|
||||
}
|
||||
for(SegmentInfo& seg: segments)
|
||||
{
|
||||
seg.CreateLdScript(out, entryPoint);
|
||||
}
|
||||
out << "_MULTISEG_APP = 1;\n";
|
||||
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
|
||||
if(stripMacsbug)
|
||||
{
|
||||
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
|
||||
out << "\t. = 0;\n";
|
||||
}
|
||||
for(SegmentInfo& seg: segments)
|
||||
{
|
||||
seg.CreateLdScript(out, entryPoint);
|
||||
}
|
||||
|
||||
out << scriptEnd;
|
||||
out << scriptEnd;
|
||||
}
|
||||
|
||||
+260
-260
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
@@ -52,173 +52,173 @@ Object::~Object()
|
||||
|
||||
Object::Object(string input)
|
||||
{
|
||||
if(elf_version ( EV_CURRENT ) == EV_NONE)
|
||||
errx(EXIT_FAILURE , "ELF library initialization failed: %s", elf_errmsg( -1));
|
||||
if(elf_version ( EV_CURRENT ) == EV_NONE)
|
||||
errx(EXIT_FAILURE , "ELF library initialization failed: %s", elf_errmsg( -1));
|
||||
|
||||
int fd = open(input.c_str(), O_RDONLY, 0);
|
||||
elf = elf_begin(fd, ELF_C_READ, NULL);
|
||||
int fd = open(input.c_str(), O_RDONLY, 0);
|
||||
elf = elf_begin(fd, ELF_C_READ, NULL);
|
||||
|
||||
elf_getshdrstrndx(elf, §ionHeaderStringTableIdx);
|
||||
elf_getshdrstrndx(elf, §ionHeaderStringTableIdx);
|
||||
|
||||
GElf_Ehdr ehdr;
|
||||
gelf_getehdr(elf, &ehdr);
|
||||
GElf_Ehdr ehdr;
|
||||
gelf_getehdr(elf, &ehdr);
|
||||
|
||||
int idx;
|
||||
int idx;
|
||||
|
||||
idx = 1;
|
||||
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
|
||||
{
|
||||
GElf_Shdr shdr;
|
||||
gelf_getshdr(scn, &shdr);
|
||||
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
|
||||
if(shdr.sh_type == SHT_STRTAB)
|
||||
{
|
||||
if(name == ".strtab")
|
||||
mainStringTableIdx = idx;
|
||||
}
|
||||
}
|
||||
idx = 1;
|
||||
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
|
||||
{
|
||||
GElf_Shdr shdr;
|
||||
gelf_getshdr(scn, &shdr);
|
||||
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
|
||||
if(shdr.sh_type == SHT_STRTAB)
|
||||
{
|
||||
if(name == ".strtab")
|
||||
mainStringTableIdx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
idx = 1;
|
||||
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
|
||||
{
|
||||
GElf_Shdr shdr;
|
||||
gelf_getshdr(scn, &shdr);
|
||||
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
|
||||
//std::cout << "section #" << idx << ": " << name << std::endl;
|
||||
//std::cout << " =" << shdr.sh_addr << " + " << shdr.sh_size << std::endl;
|
||||
idx = 1;
|
||||
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
|
||||
{
|
||||
GElf_Shdr shdr;
|
||||
gelf_getshdr(scn, &shdr);
|
||||
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
|
||||
//std::cout << "section #" << idx << ": " << name << std::endl;
|
||||
//std::cout << " =" << shdr.sh_addr << " + " << shdr.sh_size << std::endl;
|
||||
|
||||
if(shdr.sh_type == SHT_SYMTAB
|
||||
&& !symtab)
|
||||
{
|
||||
symtab.reset(new Symtab(*this, scn));
|
||||
}
|
||||
if(shdr.sh_type == SHT_RELA)
|
||||
{
|
||||
if(boost::algorithm::starts_with(name,".rela."))
|
||||
{
|
||||
string progbitsName = name.substr(5);
|
||||
assert(sections.find(progbitsName) != sections.end());
|
||||
sections[progbitsName]->SetRela(scn);
|
||||
}
|
||||
}
|
||||
if(shdr.sh_type == SHT_PROGBITS && (shdr.sh_flags & SHF_ALLOC))
|
||||
{
|
||||
SectionKind kind = SectionKind::code;
|
||||
if(shdr.sh_type == SHT_SYMTAB
|
||||
&& !symtab)
|
||||
{
|
||||
symtab.reset(new Symtab(*this, scn));
|
||||
}
|
||||
if(shdr.sh_type == SHT_RELA)
|
||||
{
|
||||
if(boost::algorithm::starts_with(name,".rela."))
|
||||
{
|
||||
string progbitsName = name.substr(5);
|
||||
assert(sections.find(progbitsName) != sections.end());
|
||||
sections[progbitsName]->SetRela(scn);
|
||||
}
|
||||
}
|
||||
if(shdr.sh_type == SHT_PROGBITS && (shdr.sh_flags & SHF_ALLOC))
|
||||
{
|
||||
SectionKind kind = SectionKind::code;
|
||||
|
||||
if(name == ".data")
|
||||
kind = SectionKind::data;
|
||||
if(name == ".strippedmacsbugnames")
|
||||
kind = SectionKind::undefined;
|
||||
if(name == ".data")
|
||||
kind = SectionKind::data;
|
||||
if(name == ".strippedmacsbugnames")
|
||||
kind = SectionKind::undefined;
|
||||
|
||||
auto section = make_shared<Section>(*this, name, idx, kind, scn);
|
||||
auto section = make_shared<Section>(*this, name, idx, kind, scn);
|
||||
|
||||
sections[name] = sectionsByElfIndex[idx] = section;
|
||||
if(kind == SectionKind::data)
|
||||
dataSection = section;
|
||||
else if(kind == SectionKind::code)
|
||||
codeSections.push_back(section);
|
||||
}
|
||||
if(shdr.sh_type == SHT_NOBITS)
|
||||
{
|
||||
bssSection = sections[name] = sectionsByElfIndex[idx] =
|
||||
make_shared<Section>(*this, name, idx, SectionKind::bss, scn);
|
||||
}
|
||||
}
|
||||
sections[name] = sectionsByElfIndex[idx] = section;
|
||||
if(kind == SectionKind::data)
|
||||
dataSection = section;
|
||||
else if(kind == SectionKind::code)
|
||||
codeSections.push_back(section);
|
||||
}
|
||||
if(shdr.sh_type == SHT_NOBITS)
|
||||
{
|
||||
bssSection = sections[name] = sectionsByElfIndex[idx] =
|
||||
make_shared<Section>(*this, name, idx, SectionKind::bss, scn);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(codeSections.begin(), codeSections.end(),
|
||||
[](shared_ptr<Section> a, shared_ptr<Section> b) { return a->name < b->name; });
|
||||
std::sort(codeSections.begin(), codeSections.end(),
|
||||
[](shared_ptr<Section> a, shared_ptr<Section> b) { return a->name < b->name; });
|
||||
}
|
||||
|
||||
void Object::FlatCode(std::ostream& out)
|
||||
{
|
||||
for(auto sec : codeSections)
|
||||
{
|
||||
sec->FixRelocs(true);
|
||||
out << sec->GetData();
|
||||
}
|
||||
|
||||
dataSection->FixRelocs(true);
|
||||
out << dataSection->GetData();
|
||||
for(auto sec : codeSections)
|
||||
{
|
||||
sec->FixRelocs(true);
|
||||
out << sec->GetData();
|
||||
}
|
||||
|
||||
dataSection->FixRelocs(true);
|
||||
out << dataSection->GetData();
|
||||
|
||||
std::vector<RuntimeReloc> relocs;
|
||||
for(auto sec : codeSections)
|
||||
{
|
||||
auto tmp = sec->GetRelocations(false);
|
||||
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
{
|
||||
auto tmp = dataSection->GetRelocations(false);
|
||||
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
out << SerializeRelocs(relocs);
|
||||
std::vector<RuntimeReloc> relocs;
|
||||
for(auto sec : codeSections)
|
||||
{
|
||||
auto tmp = sec->GetRelocations(false);
|
||||
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
{
|
||||
auto tmp = dataSection->GetRelocations(false);
|
||||
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
out << SerializeRelocs(relocs);
|
||||
}
|
||||
|
||||
void Object::FlatCode(string fn)
|
||||
{
|
||||
ofstream out(fn);
|
||||
FlatCode(out);
|
||||
ofstream out(fn);
|
||||
FlatCode(out);
|
||||
}
|
||||
|
||||
|
||||
std::string fromhex(std::string hex)
|
||||
{
|
||||
std::string bin;
|
||||
int nibble;
|
||||
bool haveNibble = false;
|
||||
for(std::string::iterator p = hex.begin(); p != hex.end(); ++p)
|
||||
{
|
||||
if(std::isspace(*p))
|
||||
continue;
|
||||
assert(isdigit(*p) || (tolower(*p) >= 'a' && tolower(*p) <= 'f'));
|
||||
int digit;
|
||||
if(isdigit(*p))
|
||||
digit = *p - '0';
|
||||
else
|
||||
digit = tolower(*p) - 'a' + 0xA;
|
||||
std::string bin;
|
||||
int nibble;
|
||||
bool haveNibble = false;
|
||||
for(std::string::iterator p = hex.begin(); p != hex.end(); ++p)
|
||||
{
|
||||
if(std::isspace(*p))
|
||||
continue;
|
||||
assert(isdigit(*p) || (tolower(*p) >= 'a' && tolower(*p) <= 'f'));
|
||||
int digit;
|
||||
if(isdigit(*p))
|
||||
digit = *p - '0';
|
||||
else
|
||||
digit = tolower(*p) - 'a' + 0xA;
|
||||
|
||||
if(haveNibble)
|
||||
{
|
||||
bin += (char) ((nibble << 4) | digit);
|
||||
haveNibble = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
nibble = digit;
|
||||
haveNibble = true;
|
||||
}
|
||||
}
|
||||
return bin;
|
||||
if(haveNibble)
|
||||
{
|
||||
bin += (char) ((nibble << 4) | digit);
|
||||
haveNibble = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
nibble = digit;
|
||||
haveNibble = true;
|
||||
}
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Object::SingleSegmentApp(string output)
|
||||
{
|
||||
ResourceFile file(output);
|
||||
Resources& rsrc = file.resources;
|
||||
ResourceFile file(output);
|
||||
Resources& rsrc = file.resources;
|
||||
|
||||
rsrc.addResource(Resource(ResType("CODE"), 0,
|
||||
fromhex(
|
||||
"00000028 00000000 00000008 00000020"
|
||||
"0000 3F3C 0001 A9F0"
|
||||
)
|
||||
));
|
||||
rsrc.addResource(Resource(ResType("CODE"), 0,
|
||||
fromhex(
|
||||
"00000028 00000000 00000008 00000020"
|
||||
"0000 3F3C 0001 A9F0"
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
{
|
||||
std::ostringstream code1;
|
||||
word(code1, 0);
|
||||
word(code1, 1);
|
||||
FlatCode(code1);
|
||||
{
|
||||
std::ostringstream code1;
|
||||
word(code1, 0);
|
||||
word(code1, 1);
|
||||
FlatCode(code1);
|
||||
|
||||
rsrc.addResource(Resource(ResType("CODE"), 1,
|
||||
code1.str()));
|
||||
}
|
||||
rsrc.addResource(Resource(ResType("CODE"), 1,
|
||||
code1.str()));
|
||||
}
|
||||
|
||||
file.creator = ResType("????");
|
||||
file.type = ResType("APPL");
|
||||
file.creator = ResType("????");
|
||||
file.type = ResType("APPL");
|
||||
|
||||
file.write();
|
||||
file.write();
|
||||
}
|
||||
|
||||
|
||||
@@ -227,70 +227,70 @@ void Object::MultiSegmentApp(string output, SegmentMap& segmentMap)
|
||||
{
|
||||
bool noisy = false;
|
||||
|
||||
ResourceFile file(output);
|
||||
Resources& rsrc = file.resources;
|
||||
ResourceFile file(output);
|
||||
Resources& rsrc = file.resources;
|
||||
|
||||
for(auto namedSec : sections)
|
||||
{
|
||||
namedSec.second->ScanRelocs();
|
||||
}
|
||||
for(auto namedSec : sections)
|
||||
{
|
||||
namedSec.second->ScanRelocs();
|
||||
}
|
||||
|
||||
int jtEntryCount = 0;
|
||||
unordered_map<int, vector<Symbol*>> jtEntries;
|
||||
for(Symbol& sym : symtab->symbols)
|
||||
{
|
||||
if(sym.valid)
|
||||
{
|
||||
if(sym.referencedExternally && sym.sectionKind == SectionKind::code)
|
||||
{
|
||||
sym.needsJT = true;
|
||||
sym.jtIndex = -1;
|
||||
sym.section->jtEntries.push_back(&sym);
|
||||
++jtEntryCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
int jtEntryCount = 0;
|
||||
unordered_map<int, vector<Symbol*>> jtEntries;
|
||||
for(Symbol& sym : symtab->symbols)
|
||||
{
|
||||
if(sym.valid)
|
||||
{
|
||||
if(sym.referencedExternally && sym.sectionKind == SectionKind::code)
|
||||
{
|
||||
sym.needsJT = true;
|
||||
sym.jtIndex = -1;
|
||||
sym.section->jtEntries.push_back(&sym);
|
||||
++jtEntryCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t data_and_bss_size = dataSection->shdr.sh_size + bssSection->shdr.sh_size;
|
||||
uint32_t data_and_bss_size = dataSection->shdr.sh_size + bssSection->shdr.sh_size;
|
||||
|
||||
{
|
||||
std::ostringstream code0;
|
||||
longword(code0, 0x20 + 8 * (jtEntryCount+2));
|
||||
longword(code0, data_and_bss_size);
|
||||
longword(code0, 8 * (jtEntryCount+2));
|
||||
longword(code0, 0x20);
|
||||
{
|
||||
std::ostringstream code0;
|
||||
longword(code0, 0x20 + 8 * (jtEntryCount+2));
|
||||
longword(code0, data_and_bss_size);
|
||||
longword(code0, 8 * (jtEntryCount+2));
|
||||
longword(code0, 0x20);
|
||||
|
||||
code0 << fromhex("0000 3F3C 0001 A9F0"); // jt entry for entrypoint
|
||||
code0 << fromhex("0000 FFFF 0000 0000"); // 32-bit entries start from here
|
||||
code0 << fromhex("0000 3F3C 0001 A9F0"); // jt entry for entrypoint
|
||||
code0 << fromhex("0000 FFFF 0000 0000"); // 32-bit entries start from here
|
||||
|
||||
int jtIndex = 2;
|
||||
int id = 1;
|
||||
for(auto sec : codeSections)
|
||||
{
|
||||
sec->codeID = id;
|
||||
int jtIndex = 2;
|
||||
int id = 1;
|
||||
for(auto sec : codeSections)
|
||||
{
|
||||
sec->codeID = id;
|
||||
|
||||
sec->firstJTEntryIndex = jtIndex;
|
||||
sec->firstJTEntryIndex = jtIndex;
|
||||
|
||||
GElf_Shdr &shdr = sec->shdr;
|
||||
GElf_Shdr &shdr = sec->shdr;
|
||||
|
||||
for(Symbol* jtEntry : sec->jtEntries)
|
||||
{
|
||||
word(code0, id);
|
||||
word(code0, 0xA9F0);
|
||||
uint32_t offset = jtEntry->st_value - shdr.sh_addr;
|
||||
if(id == 1)
|
||||
offset += 4;
|
||||
else
|
||||
offset += 40;
|
||||
longword(code0, offset);
|
||||
for(Symbol* jtEntry : sec->jtEntries)
|
||||
{
|
||||
word(code0, id);
|
||||
word(code0, 0xA9F0);
|
||||
uint32_t offset = jtEntry->st_value - shdr.sh_addr;
|
||||
if(id == 1)
|
||||
offset += 4;
|
||||
else
|
||||
offset += 40;
|
||||
longword(code0, offset);
|
||||
|
||||
jtEntry->jtIndex = jtIndex++;
|
||||
jtEntry->jtIndex = jtIndex++;
|
||||
|
||||
//std::cout << "JT Entry " << jtEntry->jtIndex << ": " << jtEntry->name << std::endl;
|
||||
}
|
||||
//std::cout << "JT Entry " << jtEntry->jtIndex << ": " << jtEntry->name << std::endl;
|
||||
}
|
||||
|
||||
id++;
|
||||
}
|
||||
id++;
|
||||
}
|
||||
|
||||
if(noisy)
|
||||
{
|
||||
@@ -302,69 +302,69 @@ void Object::MultiSegmentApp(string output, SegmentMap& segmentMap)
|
||||
std::cout << ".bss: " << bssSection->shdr.sh_size << " bytes at A5-"
|
||||
<< std::hex << bssSection->shdr.sh_size << std::dec << "\n";
|
||||
}
|
||||
rsrc.addResource(Resource(ResType("CODE"), 0, code0.str()));
|
||||
}
|
||||
rsrc.addResource(Resource(ResType("CODE"), 0, code0.str()));
|
||||
}
|
||||
|
||||
for(auto sec : codeSections)
|
||||
{
|
||||
int id = sec->codeID;
|
||||
if(id == 1)
|
||||
sec->outputBase = 4; // standard 'CODE' header
|
||||
else
|
||||
sec->outputBase = 40; // far-model 'CODE' header
|
||||
for(auto sec : codeSections)
|
||||
{
|
||||
int id = sec->codeID;
|
||||
if(id == 1)
|
||||
sec->outputBase = 4; // standard 'CODE' header
|
||||
else
|
||||
sec->outputBase = 40; // far-model 'CODE' header
|
||||
|
||||
string exceptionInfoMarker = "__EH_FRAME_BEGIN__";
|
||||
if(id != 1)
|
||||
exceptionInfoMarker += boost::lexical_cast<string>(id);
|
||||
int exceptionInfoSym = symtab->FindSym(exceptionInfoMarker);
|
||||
if(exceptionInfoSym != -1)
|
||||
{
|
||||
Symbol& s = symtab->GetSym(exceptionInfoSym);
|
||||
sec->exceptionInfoStart = s.st_value;
|
||||
string exceptionInfoMarker = "__EH_FRAME_BEGIN__";
|
||||
if(id != 1)
|
||||
exceptionInfoMarker += boost::lexical_cast<string>(id);
|
||||
int exceptionInfoSym = symtab->FindSym(exceptionInfoMarker);
|
||||
if(exceptionInfoSym != -1)
|
||||
{
|
||||
Symbol& s = symtab->GetSym(exceptionInfoSym);
|
||||
sec->exceptionInfoStart = s.st_value;
|
||||
|
||||
int codeSize = sec->shdr.sh_size;
|
||||
int exceptionSize = sec->shdr.sh_addr + codeSize - sec->exceptionInfoStart;
|
||||
double percent = 100.0 * exceptionSize / codeSize;
|
||||
int codeSize = sec->shdr.sh_size;
|
||||
int exceptionSize = sec->shdr.sh_addr + codeSize - sec->exceptionInfoStart;
|
||||
double percent = 100.0 * exceptionSize / codeSize;
|
||||
|
||||
if(noisy)
|
||||
if(noisy)
|
||||
std::cout << "CODE " << id << " has " << exceptionSize << " bytes of exception info (" << percent << "%)\n";
|
||||
}
|
||||
else if(noisy)
|
||||
std::cout << "exception info marker not found: " << exceptionInfoMarker << std::endl;
|
||||
}
|
||||
dataSection->outputBase = -data_and_bss_size;
|
||||
bssSection->outputBase = -bssSection->shdr.sh_size;
|
||||
}
|
||||
else if(noisy)
|
||||
std::cout << "exception info marker not found: " << exceptionInfoMarker << std::endl;
|
||||
}
|
||||
dataSection->outputBase = -data_and_bss_size;
|
||||
bssSection->outputBase = -bssSection->shdr.sh_size;
|
||||
|
||||
|
||||
for(auto namedSec : sections)
|
||||
{
|
||||
namedSec.second->FixRelocs(false);
|
||||
}
|
||||
for(auto namedSec : sections)
|
||||
{
|
||||
namedSec.second->FixRelocs(false);
|
||||
}
|
||||
|
||||
for(auto sec : codeSections)
|
||||
{
|
||||
int id = sec->codeID;
|
||||
std::ostringstream code;
|
||||
if(id == 1)
|
||||
{
|
||||
word(code, 0);
|
||||
word(code, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
word(code, 0xFFFF);
|
||||
word(code, 0);
|
||||
longword(code, 0);
|
||||
longword(code, 0);
|
||||
longword(code, 8 * sec->firstJTEntryIndex );
|
||||
longword(code, sec->jtEntries.size());
|
||||
longword(code, 0); // reloc info for A5
|
||||
longword(code, 0); // assumed address for A5
|
||||
longword(code, 0); // reloc info for code
|
||||
longword(code, 0); // assumed address for start of code resource
|
||||
longword(code, 0);
|
||||
}
|
||||
code << sec->GetData();
|
||||
for(auto sec : codeSections)
|
||||
{
|
||||
int id = sec->codeID;
|
||||
std::ostringstream code;
|
||||
if(id == 1)
|
||||
{
|
||||
word(code, 0);
|
||||
word(code, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
word(code, 0xFFFF);
|
||||
word(code, 0);
|
||||
longword(code, 0);
|
||||
longword(code, 0);
|
||||
longword(code, 8 * sec->firstJTEntryIndex );
|
||||
longword(code, sec->jtEntries.size());
|
||||
longword(code, 0); // reloc info for A5
|
||||
longword(code, 0); // assumed address for A5
|
||||
longword(code, 0); // reloc info for code
|
||||
longword(code, 0); // assumed address for start of code resource
|
||||
longword(code, 0);
|
||||
}
|
||||
code << sec->GetData();
|
||||
|
||||
if(noisy)
|
||||
{
|
||||
@@ -377,24 +377,24 @@ void Object::MultiSegmentApp(string output, SegmentMap& segmentMap)
|
||||
}
|
||||
}
|
||||
|
||||
string segmentName = segmentMap.GetSegmentName(id);
|
||||
string segmentName = segmentMap.GetSegmentName(id);
|
||||
|
||||
rsrc.addResource(Resource(ResType("CODE"), id,
|
||||
code.str(),
|
||||
segmentName));
|
||||
rsrc.addResource(Resource(ResType("CODE"), id,
|
||||
code.str(),
|
||||
segmentName));
|
||||
|
||||
|
||||
rsrc.addResource(Resource(ResType("RELA"),id, SerializeRelocs(sec->GetRelocations(true))));
|
||||
}
|
||||
rsrc.addResource(Resource(ResType("RELA"),id, SerializeRelocs(sec->GetRelocations(true))));
|
||||
}
|
||||
|
||||
rsrc.addResource(Resource(ResType("DATA"),0, dataSection->GetData()));
|
||||
rsrc.addResource(Resource(ResType("RELA"),0, SerializeRelocs(dataSection->GetRelocations(true))));
|
||||
rsrc.addResource(Resource(ResType("DATA"),0, dataSection->GetData()));
|
||||
rsrc.addResource(Resource(ResType("RELA"),0, SerializeRelocs(dataSection->GetRelocations(true))));
|
||||
|
||||
if(noisy)
|
||||
std::cout << "DATA 0: " << dataSection->shdr.sh_size << " bytes\n";
|
||||
std::cout << "DATA 0: " << dataSection->shdr.sh_size << " bytes\n";
|
||||
|
||||
file.creator = ResType("????");
|
||||
file.type = ResType("APPL");
|
||||
file.creator = ResType("????");
|
||||
file.type = ResType("APPL");
|
||||
|
||||
file.write();
|
||||
file.write();
|
||||
}
|
||||
|
||||
+26
-26
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OBJECT_H
|
||||
@@ -36,25 +36,25 @@ class SegmentMap;
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
Elf *elf;
|
||||
std::unique_ptr<Symtab> symtab;
|
||||
std::unordered_map<std::string, std::shared_ptr<Section>> sections;
|
||||
std::unordered_map<int, std::shared_ptr<Section>> sectionsByElfIndex;
|
||||
Elf *elf;
|
||||
std::unique_ptr<Symtab> symtab;
|
||||
std::unordered_map<std::string, std::shared_ptr<Section>> sections;
|
||||
std::unordered_map<int, std::shared_ptr<Section>> sectionsByElfIndex;
|
||||
|
||||
std::vector<std::shared_ptr<Section>> codeSections;
|
||||
std::shared_ptr<Section> dataSection, bssSection;
|
||||
size_t sectionHeaderStringTableIdx;
|
||||
size_t mainStringTableIdx;
|
||||
std::vector<std::shared_ptr<Section>> codeSections;
|
||||
std::shared_ptr<Section> dataSection, bssSection;
|
||||
size_t sectionHeaderStringTableIdx;
|
||||
size_t mainStringTableIdx;
|
||||
|
||||
|
||||
Object(std::string input);
|
||||
~Object();
|
||||
Object(std::string input);
|
||||
~Object();
|
||||
|
||||
void FlatCode(std::ostream& out);
|
||||
void FlatCode(std::string fn);
|
||||
void FlatCode(std::ostream& out);
|
||||
void FlatCode(std::string fn);
|
||||
|
||||
void SingleSegmentApp(std::string output);
|
||||
void MultiSegmentApp(std::string output, SegmentMap &segmentMap);
|
||||
void SingleSegmentApp(std::string output);
|
||||
void MultiSegmentApp(std::string output, SegmentMap &segmentMap);
|
||||
};
|
||||
|
||||
|
||||
|
||||
+36
-36
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Reloc.h"
|
||||
@@ -32,38 +32,38 @@ Reloc::Reloc(const GElf_Rela &rela)
|
||||
|
||||
std::string SerializeRelocsUncompressed(std::vector<RuntimeReloc> relocs)
|
||||
{
|
||||
std::ostringstream out;
|
||||
for(const auto& r : relocs)
|
||||
{
|
||||
longword(out, r.offset | ((int)r.base << 24));
|
||||
}
|
||||
longword(out, -1);
|
||||
return out.str();
|
||||
std::ostringstream out;
|
||||
for(const auto& r : relocs)
|
||||
{
|
||||
longword(out, r.offset | ((int)r.base << 24));
|
||||
}
|
||||
longword(out, -1);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string SerializeRelocs(std::vector<RuntimeReloc> relocs)
|
||||
{
|
||||
std::ostringstream out;
|
||||
uint32_t offset = -1;
|
||||
std::ostringstream out;
|
||||
uint32_t offset = -1;
|
||||
|
||||
for(const auto& r : relocs)
|
||||
{
|
||||
uint32_t delta = r.offset - offset;
|
||||
offset = r.offset;
|
||||
for(const auto& r : relocs)
|
||||
{
|
||||
uint32_t delta = r.offset - offset;
|
||||
offset = r.offset;
|
||||
|
||||
uint32_t base = (uint32_t) r.base;
|
||||
uint32_t base = (uint32_t) r.base;
|
||||
|
||||
uint32_t encoded = (delta << 2) | base;
|
||||
uint32_t encoded = (delta << 2) | base;
|
||||
|
||||
while(encoded >= 128)
|
||||
{
|
||||
byte(out, (encoded & 0x7F) | 0x80);
|
||||
encoded >>= 7;
|
||||
}
|
||||
byte(out, encoded);
|
||||
}
|
||||
while(encoded >= 128)
|
||||
{
|
||||
byte(out, (encoded & 0x7F) | 0x80);
|
||||
encoded >>= 7;
|
||||
}
|
||||
byte(out, encoded);
|
||||
}
|
||||
|
||||
byte(out, 0);
|
||||
byte(out, 0);
|
||||
|
||||
return out.str();
|
||||
return out.str();
|
||||
}
|
||||
|
||||
+24
-24
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RELOC_H
|
||||
@@ -28,30 +28,30 @@
|
||||
|
||||
enum class RelocBase
|
||||
{
|
||||
code = 0,
|
||||
data,
|
||||
bss,
|
||||
jumptable,
|
||||
code1
|
||||
code = 0,
|
||||
data,
|
||||
bss,
|
||||
jumptable,
|
||||
code1
|
||||
};
|
||||
|
||||
class Reloc : public GElf_Rela
|
||||
{
|
||||
public:
|
||||
RelocBase relocBase;
|
||||
RelocBase relocBase;
|
||||
|
||||
Reloc();
|
||||
Reloc(const GElf_Rela& rela);
|
||||
Reloc();
|
||||
Reloc(const GElf_Rela& rela);
|
||||
};
|
||||
|
||||
class RuntimeReloc
|
||||
{
|
||||
public:
|
||||
RelocBase base;
|
||||
uint32_t offset;
|
||||
RelocBase base;
|
||||
uint32_t offset;
|
||||
|
||||
RuntimeReloc() : base(RelocBase::code), offset(0) {}
|
||||
RuntimeReloc(RelocBase b, uint32_t o) : base(b), offset(o) {}
|
||||
RuntimeReloc() : base(RelocBase::code), offset(0) {}
|
||||
RuntimeReloc(RelocBase b, uint32_t o) : base(b), offset(o) {}
|
||||
};
|
||||
|
||||
std::string SerializeRelocsUncompressed(std::vector<RuntimeReloc> relocs);
|
||||
|
||||
+159
-159
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Section.h"
|
||||
@@ -43,198 +43,198 @@ Section::Section(Object& theObject, string name, int idx, SectionKind kind, Elf_
|
||||
exceptionInfoStart(0),
|
||||
codeID(-1), firstJTEntryIndex(0)
|
||||
{
|
||||
data = elf_getdata(elfsec, NULL);
|
||||
gelf_getshdr(elfsec, &shdr);
|
||||
outputBase = shdr.sh_addr;
|
||||
data = elf_getdata(elfsec, NULL);
|
||||
gelf_getshdr(elfsec, &shdr);
|
||||
outputBase = shdr.sh_addr;
|
||||
}
|
||||
|
||||
|
||||
void Section::SetRela(Elf_Scn *scn)
|
||||
{
|
||||
relasec = scn;
|
||||
GElf_Shdr rshdr;
|
||||
gelf_getshdr(relasec, &rshdr);
|
||||
relasec = scn;
|
||||
GElf_Shdr rshdr;
|
||||
gelf_getshdr(relasec, &rshdr);
|
||||
|
||||
int nRela = rshdr.sh_size / rshdr.sh_entsize;
|
||||
Elf_Data *data = elf_getdata(relasec, NULL);
|
||||
for(int i = 0; i < nRela; i++)
|
||||
{
|
||||
GElf_Rela rela;
|
||||
gelf_getrela(data, i, &rela);
|
||||
int nRela = rshdr.sh_size / rshdr.sh_entsize;
|
||||
Elf_Data *data = elf_getdata(relasec, NULL);
|
||||
for(int i = 0; i < nRela; i++)
|
||||
{
|
||||
GElf_Rela rela;
|
||||
gelf_getrela(data, i, &rela);
|
||||
|
||||
if(rela.r_offset < shdr.sh_addr || rela.r_offset > shdr.sh_addr + shdr.sh_size - 4)
|
||||
{
|
||||
// FIXME: There are sometimes relocations beyond the end of the sections
|
||||
// in LD output for some reason. That's bad. Let's ignore it.
|
||||
continue;
|
||||
}
|
||||
relocs.push_back(rela);
|
||||
}
|
||||
if(rela.r_offset < shdr.sh_addr || rela.r_offset > shdr.sh_addr + shdr.sh_size - 4)
|
||||
{
|
||||
// FIXME: There are sometimes relocations beyond the end of the sections
|
||||
// in LD output for some reason. That's bad. Let's ignore it.
|
||||
continue;
|
||||
}
|
||||
relocs.push_back(rela);
|
||||
}
|
||||
|
||||
std::sort(relocs.begin(), relocs.end(),
|
||||
[](GElf_Rela& a, GElf_Rela& b) { return a.r_offset < b.r_offset; });
|
||||
std::sort(relocs.begin(), relocs.end(),
|
||||
[](GElf_Rela& a, GElf_Rela& b) { return a.r_offset < b.r_offset; });
|
||||
}
|
||||
|
||||
uint32_t Section::GetSize()
|
||||
{
|
||||
return data->d_size;
|
||||
return data->d_size;
|
||||
}
|
||||
|
||||
string Section::GetData()
|
||||
{
|
||||
return string((char*)data->d_buf, (char*)data->d_buf + data->d_size);
|
||||
return string((char*)data->d_buf, (char*)data->d_buf + data->d_size);
|
||||
}
|
||||
|
||||
std::vector<RuntimeReloc> Section::GetRelocations(bool useOffsets)
|
||||
{
|
||||
std::vector<RuntimeReloc> outRelocs;
|
||||
std::vector<RuntimeReloc> outRelocs;
|
||||
|
||||
for(auto& rela : relocs)
|
||||
{
|
||||
//printf("rel: %d %d %x %x\n", (int)GELF_R_TYPE(rela.r_info), (int)GELF_R_SYM(rela.r_info), (unsigned)rela.r_addend, (unsigned)rela.r_offset);
|
||||
for(auto& rela : relocs)
|
||||
{
|
||||
//printf("rel: %d %d %x %x\n", (int)GELF_R_TYPE(rela.r_info), (int)GELF_R_SYM(rela.r_info), (unsigned)rela.r_addend, (unsigned)rela.r_offset);
|
||||
|
||||
int symidx = GELF_R_SYM(rela.r_info);
|
||||
if(symidx == 0)
|
||||
continue;
|
||||
int symidx = GELF_R_SYM(rela.r_info);
|
||||
if(symidx == 0)
|
||||
continue;
|
||||
|
||||
Symbol& sym = theObject.symtab->GetSym(symidx);
|
||||
Symbol& sym = theObject.symtab->GetSym(symidx);
|
||||
|
||||
if(sym.st_shndx == SHN_UNDEF || sym.st_shndx >= SHN_LORESERVE)
|
||||
continue;
|
||||
if(sym.sectionKind == SectionKind::undefined)
|
||||
continue;
|
||||
if(sym.st_shndx == SHN_UNDEF || sym.st_shndx >= SHN_LORESERVE)
|
||||
continue;
|
||||
if(sym.sectionKind == SectionKind::undefined)
|
||||
continue;
|
||||
|
||||
if(GELF_R_TYPE(rela.r_info) == R_68K_32)
|
||||
{
|
||||
assert(sym.sectionKind != SectionKind::undefined);
|
||||
if(GELF_R_TYPE(rela.r_info) == R_68K_32)
|
||||
{
|
||||
assert(sym.sectionKind != SectionKind::undefined);
|
||||
|
||||
uint32_t offset = rela.r_offset;
|
||||
if(useOffsets)
|
||||
offset -= shdr.sh_addr;
|
||||
uint32_t offset = rela.r_offset;
|
||||
if(useOffsets)
|
||||
offset -= shdr.sh_addr;
|
||||
|
||||
//longword(out, offset | ((int)rela.relocBase << 24));
|
||||
outRelocs.emplace_back(rela.relocBase, offset);
|
||||
}
|
||||
}
|
||||
//longword(out, offset | ((int)rela.relocBase << 24));
|
||||
outRelocs.emplace_back(rela.relocBase, offset);
|
||||
}
|
||||
}
|
||||
|
||||
return outRelocs;
|
||||
return outRelocs;
|
||||
}
|
||||
|
||||
void Section::ScanRelocs()
|
||||
{
|
||||
for(Reloc& rela : relocs)
|
||||
{
|
||||
int symidx = GELF_R_SYM(rela.r_info);
|
||||
if(symidx == 0)
|
||||
continue;
|
||||
for(Reloc& rela : relocs)
|
||||
{
|
||||
int symidx = GELF_R_SYM(rela.r_info);
|
||||
if(symidx == 0)
|
||||
continue;
|
||||
|
||||
Symbol *sym = &theObject.symtab->GetSym(symidx);
|
||||
Symbol *sym = &theObject.symtab->GetSym(symidx);
|
||||
|
||||
if(sym->st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
if(sym->st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
|
||||
if(rela.r_addend != 0)
|
||||
{
|
||||
int symidx2 = theObject.symtab->FindSym(sym->st_shndx, sym->st_value + rela.r_addend);
|
||||
if(symidx2 != -1)
|
||||
{
|
||||
sym = &theObject.symtab->GetSym(symidx2);
|
||||
rela.r_addend = 0;
|
||||
rela.r_info = GELF_R_INFO(symidx2, GELF_R_TYPE(rela.r_info));
|
||||
if(rela.r_addend != 0)
|
||||
{
|
||||
int symidx2 = theObject.symtab->FindSym(sym->st_shndx, sym->st_value + rela.r_addend);
|
||||
if(symidx2 != -1)
|
||||
{
|
||||
sym = &theObject.symtab->GetSym(symidx2);
|
||||
rela.r_addend = 0;
|
||||
rela.r_info = GELF_R_INFO(symidx2, GELF_R_TYPE(rela.r_info));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sym->st_shndx != idx)
|
||||
sym->referencedExternally = true;
|
||||
}
|
||||
if(sym->st_shndx != idx)
|
||||
sym->referencedExternally = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Section::FixRelocs(bool allowDirectCodeRefs)
|
||||
{
|
||||
for(Reloc& rela : relocs)
|
||||
{
|
||||
if(GELF_R_TYPE(rela.r_info) != R_68K_32)
|
||||
continue;
|
||||
for(Reloc& rela : relocs)
|
||||
{
|
||||
if(GELF_R_TYPE(rela.r_info) != R_68K_32)
|
||||
continue;
|
||||
|
||||
int symidx = GELF_R_SYM(rela.r_info);
|
||||
if(symidx == 0)
|
||||
continue;
|
||||
Symbol& sym = theObject.symtab->GetSym(symidx);
|
||||
int symidx = GELF_R_SYM(rela.r_info);
|
||||
if(symidx == 0)
|
||||
continue;
|
||||
Symbol& sym = theObject.symtab->GetSym(symidx);
|
||||
|
||||
if(sym.sectionKind == SectionKind::undefined)
|
||||
continue;
|
||||
if(sym.sectionKind == SectionKind::undefined)
|
||||
continue;
|
||||
|
||||
RelocBase relocBase;
|
||||
switch(sym.sectionKind)
|
||||
{
|
||||
case SectionKind::code:
|
||||
relocBase = RelocBase::code;
|
||||
if(sym.needsJT && (exceptionInfoStart == 0 || rela.r_offset < exceptionInfoStart || sym.name == "__gxx_personality_v0"))
|
||||
{
|
||||
if(rela.r_addend == 0)
|
||||
{
|
||||
relocBase = RelocBase::jumptable;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sym.section.get() != this)
|
||||
{
|
||||
std::cerr << "Invalid ref from "
|
||||
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
|
||||
<< " to " << sym.section->name
|
||||
<< "(" << sym.name << ")"
|
||||
<< "+" << rela.r_offset << std::endl;
|
||||
}
|
||||
assert(sym.section.get() == this);
|
||||
}
|
||||
}
|
||||
else if(!allowDirectCodeRefs)
|
||||
{
|
||||
if(sym.section.get() != this)
|
||||
{
|
||||
std::cerr << "Invalid ref from "
|
||||
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
|
||||
<< " to " << sym.section->name
|
||||
<< "(" << sym.name << ")"
|
||||
<< "+" << rela.r_offset << std::endl;
|
||||
std::cerr << "needsJT: " << (sym.needsJT ? "true" : "false") << std::endl;
|
||||
std::cerr << "from addr: " << rela.r_offset << ", exceptionInfoStart: " << exceptionInfoStart << std::endl;
|
||||
RelocBase relocBase;
|
||||
switch(sym.sectionKind)
|
||||
{
|
||||
case SectionKind::code:
|
||||
relocBase = RelocBase::code;
|
||||
if(sym.needsJT && (exceptionInfoStart == 0 || rela.r_offset < exceptionInfoStart || sym.name == "__gxx_personality_v0"))
|
||||
{
|
||||
if(rela.r_addend == 0)
|
||||
{
|
||||
relocBase = RelocBase::jumptable;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sym.section.get() != this)
|
||||
{
|
||||
std::cerr << "Invalid ref from "
|
||||
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
|
||||
<< " to " << sym.section->name
|
||||
<< "(" << sym.name << ")"
|
||||
<< "+" << rela.r_offset << std::endl;
|
||||
}
|
||||
assert(sym.section.get() == this);
|
||||
}
|
||||
}
|
||||
else if(!allowDirectCodeRefs)
|
||||
{
|
||||
if(sym.section.get() != this)
|
||||
{
|
||||
std::cerr << "Invalid ref from "
|
||||
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
|
||||
<< " to " << sym.section->name
|
||||
<< "(" << sym.name << ")"
|
||||
<< "+" << rela.r_offset << std::endl;
|
||||
std::cerr << "needsJT: " << (sym.needsJT ? "true" : "false") << std::endl;
|
||||
std::cerr << "from addr: " << rela.r_offset << ", exceptionInfoStart: " << exceptionInfoStart << std::endl;
|
||||
|
||||
}
|
||||
assert(sym.section.get() == this);
|
||||
}
|
||||
break;
|
||||
case SectionKind::data:
|
||||
relocBase = RelocBase::data;
|
||||
break;
|
||||
case SectionKind::bss:
|
||||
relocBase = RelocBase::bss;
|
||||
break;
|
||||
case SectionKind::undefined:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
rela.relocBase = relocBase;
|
||||
}
|
||||
assert(sym.section.get() == this);
|
||||
}
|
||||
break;
|
||||
case SectionKind::data:
|
||||
relocBase = RelocBase::data;
|
||||
break;
|
||||
case SectionKind::bss:
|
||||
relocBase = RelocBase::bss;
|
||||
break;
|
||||
case SectionKind::undefined:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
rela.relocBase = relocBase;
|
||||
|
||||
uint8_t *relocand = ((uint8_t*) data->d_buf + rela.r_offset - shdr.sh_addr);
|
||||
uint8_t *relocand = ((uint8_t*) data->d_buf + rela.r_offset - shdr.sh_addr);
|
||||
|
||||
if(relocBase == RelocBase::jumptable)
|
||||
{
|
||||
uint32_t dst = 0x20 + sym.jtIndex * 8 + 2;
|
||||
relocand[0] = dst >> 24;
|
||||
relocand[1] = dst >> 16;
|
||||
relocand[2] = dst >> 8;
|
||||
relocand[3] = dst;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t orig = (relocand[0] << 24) | (relocand[1] << 16) | (relocand[2] << 8) | relocand[3];
|
||||
uint32_t dst = orig + sym.section->outputBase - sym.section->shdr.sh_addr;
|
||||
relocand[0] = dst >> 24;
|
||||
relocand[1] = dst >> 16;
|
||||
relocand[2] = dst >> 8;
|
||||
relocand[3] = dst;
|
||||
}
|
||||
}
|
||||
if(relocBase == RelocBase::jumptable)
|
||||
{
|
||||
uint32_t dst = 0x20 + sym.jtIndex * 8 + 2;
|
||||
relocand[0] = dst >> 24;
|
||||
relocand[1] = dst >> 16;
|
||||
relocand[2] = dst >> 8;
|
||||
relocand[3] = dst;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t orig = (relocand[0] << 24) | (relocand[1] << 16) | (relocand[2] << 8) | relocand[3];
|
||||
uint32_t dst = orig + sym.section->outputBase - sym.section->shdr.sh_addr;
|
||||
relocand[0] = dst >> 24;
|
||||
relocand[1] = dst >> 16;
|
||||
relocand[2] = dst >> 8;
|
||||
relocand[3] = dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+37
-37
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SECTION_H
|
||||
@@ -33,41 +33,41 @@ class RuntimeReloc;
|
||||
|
||||
enum class SectionKind
|
||||
{
|
||||
undefined = -1,
|
||||
code = 0,
|
||||
data,
|
||||
bss
|
||||
undefined = -1,
|
||||
code = 0,
|
||||
data,
|
||||
bss
|
||||
};
|
||||
|
||||
class Section
|
||||
{
|
||||
public:
|
||||
Object& theObject;
|
||||
std::string name;
|
||||
int idx;
|
||||
SectionKind kind;
|
||||
Elf_Scn *elfsec, *relasec;
|
||||
Elf_Data *data;
|
||||
GElf_Shdr shdr;
|
||||
uint32_t outputBase;
|
||||
uint32_t exceptionInfoStart;
|
||||
Object& theObject;
|
||||
std::string name;
|
||||
int idx;
|
||||
SectionKind kind;
|
||||
Elf_Scn *elfsec, *relasec;
|
||||
Elf_Data *data;
|
||||
GElf_Shdr shdr;
|
||||
uint32_t outputBase;
|
||||
uint32_t exceptionInfoStart;
|
||||
|
||||
int codeID;
|
||||
int codeID;
|
||||
|
||||
std::vector<Reloc> relocs;
|
||||
std::vector<Symbol*> jtEntries;
|
||||
int firstJTEntryIndex;
|
||||
std::vector<Reloc> relocs;
|
||||
std::vector<Symbol*> jtEntries;
|
||||
int firstJTEntryIndex;
|
||||
|
||||
Section(Object& object, std::string name, int idx, SectionKind kind, Elf_Scn *elfsec);
|
||||
~Section();
|
||||
void SetRela(Elf_Scn *scn);
|
||||
Section(Object& object, std::string name, int idx, SectionKind kind, Elf_Scn *elfsec);
|
||||
~Section();
|
||||
void SetRela(Elf_Scn *scn);
|
||||
|
||||
uint32_t GetSize();
|
||||
std::string GetData();
|
||||
std::vector<RuntimeReloc> GetRelocations(bool useOffsets);
|
||||
uint32_t GetSize();
|
||||
std::string GetData();
|
||||
std::vector<RuntimeReloc> GetRelocations(bool useOffsets);
|
||||
|
||||
void ScanRelocs();
|
||||
void FixRelocs(bool allowDirectCodeRefs);
|
||||
void ScanRelocs();
|
||||
void FixRelocs(bool allowDirectCodeRefs);
|
||||
|
||||
};
|
||||
|
||||
|
||||
+88
-88
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SegmentMap.h"
|
||||
@@ -29,98 +29,98 @@ SegmentInfo::SegmentInfo()
|
||||
|
||||
SegmentMap::SegmentMap()
|
||||
{
|
||||
segments.emplace_back(1, "Runtime",
|
||||
"*/libretrocrt.a:start.c.obj",
|
||||
"*/libretrocrt.a:relocate.c.obj",
|
||||
"*/libretrocrt.a:MultiSegApp.c.obj",
|
||||
"*/libretrocrt.a:LoadSeg.s.obj",
|
||||
"*/libretrocrt.a:*",
|
||||
segments.emplace_back(1, "Runtime",
|
||||
"*/libretrocrt.a:start.c.obj",
|
||||
"*/libretrocrt.a:relocate.c.obj",
|
||||
"*/libretrocrt.a:MultiSegApp.c.obj",
|
||||
"*/libretrocrt.a:LoadSeg.s.obj",
|
||||
"*/libretrocrt.a:*",
|
||||
"*/libInterface.a:*",
|
||||
"*/libgcc.a:*",
|
||||
"*/libc.a:*"
|
||||
);
|
||||
segments.emplace_back(5, "libstdc++ locale",
|
||||
"*/libstdc++.a:locale.o",
|
||||
"*/libstdc++.a:locale_faces.o",
|
||||
"*/libstdc++.a:locale_init.o");
|
||||
segments.emplace_back(7, "libstdc++ locale-inst",
|
||||
"*/libstdc++.a:locale-inst.o");
|
||||
segments.emplace_back(8, "libstdc++ wlocale-inst",
|
||||
"*/libstdc++.a:wlocale-inst.o");
|
||||
segments.emplace_back(6, "libstdc++ cp-demangle",
|
||||
"*/libstdc++.a:cp-demangle.o");
|
||||
segments.emplace_back(3, "libstdc++",
|
||||
"*/libstdc++.a:*");
|
||||
segments.emplace_back(4, "RetroConsole",
|
||||
"*/libRetroConsole.a:*");
|
||||
"*/libgcc.a:*",
|
||||
"*/libc.a:*"
|
||||
);
|
||||
segments.emplace_back(5, "libstdc++ locale",
|
||||
"*/libstdc++.a:locale.o",
|
||||
"*/libstdc++.a:locale_faces.o",
|
||||
"*/libstdc++.a:locale_init.o");
|
||||
segments.emplace_back(7, "libstdc++ locale-inst",
|
||||
"*/libstdc++.a:locale-inst.o");
|
||||
segments.emplace_back(8, "libstdc++ wlocale-inst",
|
||||
"*/libstdc++.a:wlocale-inst.o");
|
||||
segments.emplace_back(6, "libstdc++ cp-demangle",
|
||||
"*/libstdc++.a:cp-demangle.o");
|
||||
segments.emplace_back(3, "libstdc++",
|
||||
"*/libstdc++.a:*");
|
||||
segments.emplace_back(4, "RetroConsole",
|
||||
"*/libRetroConsole.a:*");
|
||||
|
||||
segments.emplace_back(2, "Main",
|
||||
"*");
|
||||
segments.emplace_back(2, "Main",
|
||||
"*");
|
||||
}
|
||||
|
||||
SegmentMap::SegmentMap(std::string filename)
|
||||
{
|
||||
segments.emplace_back(1, "Runtime",
|
||||
"*/libretrocrt.a:start.c.obj",
|
||||
"*/libretrocrt.a:relocate.c.obj",
|
||||
"*/libretrocrt.a:MultiSegApp.c.obj",
|
||||
"*/libretrocrt.a:LoadSeg.s.obj",
|
||||
"*/libretrocrt.a:*",
|
||||
segments.emplace_back(1, "Runtime",
|
||||
"*/libretrocrt.a:start.c.obj",
|
||||
"*/libretrocrt.a:relocate.c.obj",
|
||||
"*/libretrocrt.a:MultiSegApp.c.obj",
|
||||
"*/libretrocrt.a:LoadSeg.s.obj",
|
||||
"*/libretrocrt.a:*",
|
||||
"*/libInterface.a:*",
|
||||
"*/libgcc.a:*",
|
||||
"*/libc.a:*"
|
||||
);
|
||||
"*/libgcc.a:*",
|
||||
"*/libc.a:*"
|
||||
);
|
||||
|
||||
std::ifstream in(filename);
|
||||
int id = -1;
|
||||
int nextID = 3;
|
||||
while(in)
|
||||
{
|
||||
std::string s;
|
||||
in >> std::ws;
|
||||
std::getline(in, s);
|
||||
//std::cout << "segs: " << s << std::endl;
|
||||
if(!in)
|
||||
break;
|
||||
std::ifstream in(filename);
|
||||
int id = -1;
|
||||
int nextID = 3;
|
||||
while(in)
|
||||
{
|
||||
std::string s;
|
||||
in >> std::ws;
|
||||
std::getline(in, s);
|
||||
//std::cout << "segs: " << s << std::endl;
|
||||
if(!in)
|
||||
break;
|
||||
|
||||
std::string upper;
|
||||
std::transform(s.begin(), s.end(), std::back_inserter(upper), [](char c) { return std::toupper(c); });
|
||||
std::string upper;
|
||||
std::transform(s.begin(), s.end(), std::back_inserter(upper), [](char c) { return std::toupper(c); });
|
||||
|
||||
if(s[0] == '#')
|
||||
continue;
|
||||
else if(upper == "SEGMENT" || (upper.substr(0,7) == "SEGMENT" && std::isspace(upper[7])))
|
||||
{
|
||||
std::string name;
|
||||
if(s[0] == '#')
|
||||
continue;
|
||||
else if(upper == "SEGMENT" || (upper.substr(0,7) == "SEGMENT" && std::isspace(upper[7])))
|
||||
{
|
||||
std::string name;
|
||||
|
||||
auto p = s.begin() + 7;
|
||||
while(p != s.end() && std::isspace(*p))
|
||||
++p;
|
||||
name = std::string(p, s.end());
|
||||
id = nextID++;
|
||||
auto p = s.begin() + 7;
|
||||
while(p != s.end() && std::isspace(*p))
|
||||
++p;
|
||||
name = std::string(p, s.end());
|
||||
id = nextID++;
|
||||
|
||||
segments.emplace_back(id, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(id < 0)
|
||||
{
|
||||
throw std::runtime_error("missing SEGMENT directive.\n");
|
||||
}
|
||||
segments.emplace_back(id, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(id < 0)
|
||||
{
|
||||
throw std::runtime_error("missing SEGMENT directive.\n");
|
||||
}
|
||||
|
||||
segments.back().filters.push_back(s);
|
||||
}
|
||||
}
|
||||
segments.back().filters.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
segments.emplace_back(2, "Main",
|
||||
"*");
|
||||
segments.emplace_back(2, "Main",
|
||||
"*");
|
||||
}
|
||||
|
||||
std::string SegmentMap::GetSegmentName(int id)
|
||||
{
|
||||
for(auto& seg : segments)
|
||||
{
|
||||
if(seg.id == id)
|
||||
return seg.name;
|
||||
}
|
||||
return "";
|
||||
for(auto& seg : segments)
|
||||
{
|
||||
if(seg.id == id)
|
||||
return seg.name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
+29
-29
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SEGMENTMAP_H
|
||||
@@ -26,31 +26,31 @@
|
||||
class SegmentInfo
|
||||
{
|
||||
public:
|
||||
int id;
|
||||
std::string name;
|
||||
std::vector<std::string> filters;
|
||||
SegmentInfo();
|
||||
int id;
|
||||
std::string name;
|
||||
std::vector<std::string> filters;
|
||||
SegmentInfo();
|
||||
|
||||
template<typename... Args>
|
||||
SegmentInfo(int id, std::string name, Args... args)
|
||||
: id(id), name(name), filters { args... }
|
||||
{
|
||||
}
|
||||
template<typename... Args>
|
||||
SegmentInfo(int id, std::string name, Args... args)
|
||||
: id(id), name(name), filters { args... }
|
||||
{
|
||||
}
|
||||
|
||||
void WriteFilters(std::ostream& out, std::string section);
|
||||
void WriteFiltersKeep(std::ostream& out, std::string section);
|
||||
void CreateLdScript(std::ostream& out, std::string entryPoint);
|
||||
void WriteFilters(std::ostream& out, std::string section);
|
||||
void WriteFiltersKeep(std::ostream& out, std::string section);
|
||||
void CreateLdScript(std::ostream& out, std::string entryPoint);
|
||||
};
|
||||
|
||||
class SegmentMap
|
||||
{
|
||||
std::vector<SegmentInfo> segments;
|
||||
std::vector<SegmentInfo> segments;
|
||||
public:
|
||||
SegmentMap();
|
||||
SegmentMap(std::string filename);
|
||||
SegmentMap();
|
||||
SegmentMap(std::string filename);
|
||||
|
||||
void CreateLdScript(std::ostream& out, std::string entryPoint, bool stripMacsbug);
|
||||
std::string GetSegmentName(int id);
|
||||
void CreateLdScript(std::ostream& out, std::string entryPoint, bool stripMacsbug);
|
||||
std::string GetSegmentName(int id);
|
||||
};
|
||||
|
||||
#endif // SEGMENTMAP_H
|
||||
|
||||
+21
-21
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Symbol.h"
|
||||
@@ -33,13 +33,13 @@ Symbol::Symbol(Object& theObject, const GElf_Sym &sym)
|
||||
sectionKind(SectionKind::undefined),
|
||||
needsJT(false)
|
||||
{
|
||||
if(st_shndx != SHN_UNDEF && st_shndx < SHN_LORESERVE)
|
||||
{
|
||||
section = theObject.sectionsByElfIndex[st_shndx];
|
||||
sectionKind = section->kind;
|
||||
}
|
||||
if(st_name)
|
||||
{
|
||||
name = elf_strptr(theObject.elf, theObject.mainStringTableIdx, st_name);
|
||||
}
|
||||
if(st_shndx != SHN_UNDEF && st_shndx < SHN_LORESERVE)
|
||||
{
|
||||
section = theObject.sectionsByElfIndex[st_shndx];
|
||||
sectionKind = section->kind;
|
||||
}
|
||||
if(st_name)
|
||||
{
|
||||
name = elf_strptr(theObject.elf, theObject.mainStringTableIdx, st_name);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-21
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SYMBOL_H
|
||||
@@ -32,16 +32,16 @@ class Object;
|
||||
class Symbol : public GElf_Sym
|
||||
{
|
||||
public:
|
||||
bool valid;
|
||||
bool referencedExternally;
|
||||
SectionKind sectionKind;
|
||||
bool needsJT;
|
||||
int jtIndex;
|
||||
std::shared_ptr<Section> section;
|
||||
std::string name;
|
||||
bool valid;
|
||||
bool referencedExternally;
|
||||
SectionKind sectionKind;
|
||||
bool needsJT;
|
||||
int jtIndex;
|
||||
std::shared_ptr<Section> section;
|
||||
std::string name;
|
||||
|
||||
Symbol();
|
||||
Symbol(Object &theObject, const GElf_Sym& sym);
|
||||
Symbol();
|
||||
Symbol(Object &theObject, const GElf_Sym& sym);
|
||||
};
|
||||
|
||||
|
||||
|
||||
+39
-39
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Symtab.h"
|
||||
@@ -30,26 +30,26 @@ using std::string;
|
||||
Symtab::Symtab(Object& theObject, Elf_Scn *elfsec)
|
||||
: elfsec(elfsec)
|
||||
{
|
||||
data = elf_getdata(elfsec, NULL);
|
||||
data = elf_getdata(elfsec, NULL);
|
||||
|
||||
GElf_Shdr shdr;
|
||||
gelf_getshdr(elfsec, &shdr);
|
||||
GElf_Shdr shdr;
|
||||
gelf_getshdr(elfsec, &shdr);
|
||||
|
||||
int count = shdr.sh_size / shdr.sh_entsize;
|
||||
symbols.reserve(count);
|
||||
int count = shdr.sh_size / shdr.sh_entsize;
|
||||
symbols.reserve(count);
|
||||
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
GElf_Sym sym;
|
||||
auto res = gelf_getsym(data, i, &sym);
|
||||
assert(res != 0);
|
||||
symbols.emplace_back(theObject, sym);
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
GElf_Sym sym;
|
||||
auto res = gelf_getsym(data, i, &sym);
|
||||
assert(res != 0);
|
||||
symbols.emplace_back(theObject, sym);
|
||||
|
||||
if(sym.st_shndx != SHN_UNDEF && sym.st_shndx < SHN_LORESERVE)
|
||||
symbolsByAddress[make_pair((int)sym.st_shndx,sym.st_value)] = i;
|
||||
if(sym.st_name)
|
||||
symbolsByName[symbols.back().name] = i;
|
||||
}
|
||||
if(sym.st_shndx != SHN_UNDEF && sym.st_shndx < SHN_LORESERVE)
|
||||
symbolsByAddress[make_pair((int)sym.st_shndx,sym.st_value)] = i;
|
||||
if(sym.st_name)
|
||||
symbolsByName[symbols.back().name] = i;
|
||||
}
|
||||
}
|
||||
|
||||
Symtab::~Symtab()
|
||||
@@ -59,23 +59,23 @@ Symtab::~Symtab()
|
||||
|
||||
Symbol &Symtab::GetSym(int idx)
|
||||
{
|
||||
return symbols[idx];
|
||||
return symbols[idx];
|
||||
}
|
||||
|
||||
int Symtab::FindSym(int secidx, uint32_t addr)
|
||||
{
|
||||
auto p = symbolsByAddress.find(make_pair(secidx, addr));
|
||||
if(p != symbolsByAddress.end())
|
||||
return p->second;
|
||||
else
|
||||
return -1;
|
||||
auto p = symbolsByAddress.find(make_pair(secidx, addr));
|
||||
if(p != symbolsByAddress.end())
|
||||
return p->second;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Symtab::FindSym(string name)
|
||||
{
|
||||
auto p = symbolsByName.find(name);
|
||||
if(p != symbolsByName.end())
|
||||
return p->second;
|
||||
else
|
||||
return -1;
|
||||
auto p = symbolsByName.find(name);
|
||||
if(p != symbolsByName.end())
|
||||
return p->second;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
+22
-22
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
Copyright 2017 Wolfgang Thaller.
|
||||
|
||||
This file is part of Retro68.
|
||||
This file is part of Retro68.
|
||||
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Retro68 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Retro68 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SYMTAB_H
|
||||
@@ -33,18 +33,18 @@ class Symbol;
|
||||
class Symtab
|
||||
{
|
||||
public:
|
||||
Elf_Scn *elfsec;
|
||||
Elf_Data *data;
|
||||
std::vector<Symbol> symbols;
|
||||
std::map<std::pair<int,uint32_t>, int> symbolsByAddress;
|
||||
std::unordered_map<std::string, int> symbolsByName;
|
||||
Elf_Scn *elfsec;
|
||||
Elf_Data *data;
|
||||
std::vector<Symbol> symbols;
|
||||
std::map<std::pair<int,uint32_t>, int> symbolsByAddress;
|
||||
std::unordered_map<std::string, int> symbolsByName;
|
||||
|
||||
Symtab(Object &theObject, Elf_Scn *elfsec);
|
||||
~Symtab();
|
||||
Symtab(Object &theObject, Elf_Scn *elfsec);
|
||||
~Symtab();
|
||||
|
||||
Symbol& GetSym(int idx);
|
||||
int FindSym(int secidx, uint32_t addr);
|
||||
int FindSym(std::string name);
|
||||
Symbol& GetSym(int idx);
|
||||
int FindSym(int secidx, uint32_t addr);
|
||||
int FindSym(std::string name);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
find_package(Boost COMPONENTS filesystem program_options)
|
||||
|
||||
set(LAUNCHMETHODS
|
||||
Executor.h Executor.cc
|
||||
MiniVMac.h MiniVMac.cc
|
||||
Executor.h Executor.cc
|
||||
MiniVMac.h MiniVMac.cc
|
||||
SSH.h SSH.cc
|
||||
StreamBasedLauncher.h StreamBasedLauncher.cc
|
||||
Serial.h Serial.cc
|
||||
@@ -11,32 +11,32 @@ set(LAUNCHMETHODS
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
LIST(APPEND LAUNCHMETHODS
|
||||
Classic.h Classic.cc
|
||||
)
|
||||
LIST(APPEND LAUNCHMETHODS
|
||||
Carbon.h Carbon.cc)
|
||||
LIST(APPEND LAUNCHMETHODS
|
||||
Classic.h Classic.cc
|
||||
)
|
||||
LIST(APPEND LAUNCHMETHODS
|
||||
Carbon.h Carbon.cc)
|
||||
endif()
|
||||
add_definitions(-DRETRO68_PREFIX="${CMAKE_INSTALL_PREFIX}")
|
||||
|
||||
add_executable(LaunchAPPL
|
||||
LaunchAPPL.cc
|
||||
MakeExecutable.cc
|
||||
LaunchAPPL.cc
|
||||
MakeExecutable.cc
|
||||
|
||||
LaunchMethod.h LaunchMethod.cc
|
||||
Launcher.h Launcher.cc
|
||||
LaunchMethod.h LaunchMethod.cc
|
||||
Launcher.h Launcher.cc
|
||||
|
||||
Utilities.h Utilities.cc
|
||||
Utilities.h Utilities.cc
|
||||
|
||||
${LAUNCHMETHODS})
|
||||
|
||||
${LAUNCHMETHODS})
|
||||
|
||||
|
||||
target_include_directories(LaunchAPPL PRIVATE ${CMAKE_INSTALL_PREFIX}/include ${Boost_INCLUDE_DIR})
|
||||
target_link_libraries(LaunchAPPL ResourceFiles LaunchAPPLCommon ${Boost_LIBRARIES})
|
||||
|
||||
if(APPLE)
|
||||
find_library(APPLICATIONSERVICES_FW ApplicationServices)
|
||||
target_link_libraries(LaunchAPPL ${APPLICATIONSERVICES_FW})
|
||||
find_library(APPLICATIONSERVICES_FW ApplicationServices)
|
||||
target_link_libraries(LaunchAPPL ${APPLICATIONSERVICES_FW})
|
||||
endif()
|
||||
|
||||
install(TARGETS LaunchAPPL RUNTIME DESTINATION bin)
|
||||
|
||||
+10
-10
@@ -3,17 +3,17 @@
|
||||
#include "Utilities.h"
|
||||
|
||||
const std::string launchCFM =
|
||||
"/System/Library/Frameworks/Carbon.framework/Versions/A/Support/LaunchCFMApp";
|
||||
"/System/Library/Frameworks/Carbon.framework/Versions/A/Support/LaunchCFMApp";
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
class CarbonLauncher : public Launcher
|
||||
{
|
||||
public:
|
||||
CarbonLauncher(po::variables_map& options);
|
||||
virtual ~CarbonLauncher();
|
||||
CarbonLauncher(po::variables_map& options);
|
||||
virtual ~CarbonLauncher();
|
||||
|
||||
virtual bool Go(int timeout = 0);
|
||||
virtual bool Go(int timeout = 0);
|
||||
|
||||
};
|
||||
|
||||
@@ -30,18 +30,18 @@ CarbonLauncher::~CarbonLauncher()
|
||||
|
||||
bool CarbonLauncher::Go(int timeout)
|
||||
{
|
||||
return ChildProcess(launchCFM, { appPath.string() }, timeout) == 0;
|
||||
return ChildProcess(launchCFM, { appPath.string() }, timeout) == 0;
|
||||
}
|
||||
|
||||
bool Carbon::CheckPlatform()
|
||||
{
|
||||
/* If LaunchCFMApp doesn't exist, we're likely on a Mac OS X version
|
||||
where it doesn't exist anymore (10.7 Lion or later),
|
||||
or on an entirely different platform. */
|
||||
return CheckExecutable(launchCFM);
|
||||
/* If LaunchCFMApp doesn't exist, we're likely on a Mac OS X version
|
||||
where it doesn't exist anymore (10.7 Lion or later),
|
||||
or on an entirely different platform. */
|
||||
return CheckExecutable(launchCFM);
|
||||
}
|
||||
|
||||
std::unique_ptr<Launcher> Carbon::MakeLauncher(variables_map &options)
|
||||
{
|
||||
return std::unique_ptr<Launcher>(new CarbonLauncher(options));
|
||||
return std::unique_ptr<Launcher>(new CarbonLauncher(options));
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
class Carbon : public LaunchMethod
|
||||
{
|
||||
public:
|
||||
virtual std::string GetName() { return "carbon"; }
|
||||
virtual std::string GetName() { return "carbon"; }
|
||||
|
||||
virtual bool CheckPlatform();
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
virtual bool CheckPlatform();
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
};
|
||||
|
||||
#endif // CARBON_METHOD_H
|
||||
|
||||
@@ -12,10 +12,10 @@ namespace po = boost::program_options;
|
||||
class ClassicLauncher : public Launcher
|
||||
{
|
||||
public:
|
||||
ClassicLauncher(po::variables_map& options);
|
||||
virtual ~ClassicLauncher();
|
||||
ClassicLauncher(po::variables_map& options);
|
||||
virtual ~ClassicLauncher();
|
||||
|
||||
virtual bool Go(int timeout = 0);
|
||||
virtual bool Go(int timeout = 0);
|
||||
|
||||
};
|
||||
|
||||
@@ -31,52 +31,52 @@ ClassicLauncher::~ClassicLauncher()
|
||||
}
|
||||
|
||||
bool ClassicLauncher::Go(int timeout)
|
||||
{
|
||||
FSRef ref;
|
||||
FSPathMakeRef((const UInt8*) appPath.string().c_str(), &ref, NULL);
|
||||
LSApplicationParameters params;
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.flags = kLSLaunchStartClassic
|
||||
| kLSLaunchInClassic
|
||||
| kLSLaunchDontAddToRecents
|
||||
| kLSLaunchNewInstance;
|
||||
params.application = &ref;
|
||||
|
||||
ProcessSerialNumber psn;
|
||||
LSOpenApplication(¶ms, &psn);
|
||||
|
||||
// Classic startup takes place before LSOpenApplication returns,
|
||||
// so no extra timeout is needed
|
||||
|
||||
for(int i = 0; i < timeout || timeout == 0; i++)
|
||||
{
|
||||
sleep(1);
|
||||
|
||||
ProcessInfoRec pi;
|
||||
pi.processInfoLength = sizeof(pi);
|
||||
pi.processName = NULL;
|
||||
pi.processAppSpec = 0;
|
||||
if(GetProcessInformation(&psn, &pi) == procNotFound)
|
||||
return true;
|
||||
}
|
||||
{
|
||||
FSRef ref;
|
||||
FSPathMakeRef((const UInt8*) appPath.string().c_str(), &ref, NULL);
|
||||
LSApplicationParameters params;
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.flags = kLSLaunchStartClassic
|
||||
| kLSLaunchInClassic
|
||||
| kLSLaunchDontAddToRecents
|
||||
| kLSLaunchNewInstance;
|
||||
params.application = &ref;
|
||||
|
||||
ProcessSerialNumber psn;
|
||||
LSOpenApplication(¶ms, &psn);
|
||||
|
||||
// Classic startup takes place before LSOpenApplication returns,
|
||||
// so no extra timeout is needed
|
||||
|
||||
for(int i = 0; i < timeout || timeout == 0; i++)
|
||||
{
|
||||
sleep(1);
|
||||
|
||||
ProcessInfoRec pi;
|
||||
pi.processInfoLength = sizeof(pi);
|
||||
pi.processName = NULL;
|
||||
pi.processAppSpec = 0;
|
||||
if(GetProcessInformation(&psn, &pi) == procNotFound)
|
||||
return true;
|
||||
}
|
||||
|
||||
KillProcess(&psn);
|
||||
KillProcess(&psn);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Classic::CheckPlatform()
|
||||
{
|
||||
long sysver = 0;
|
||||
Gestalt(gestaltSystemVersion, &sysver);
|
||||
if(sysver >= 0x1050)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
long sysver = 0;
|
||||
Gestalt(gestaltSystemVersion, &sysver);
|
||||
if(sysver >= 0x1050)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Launcher> Classic::MakeLauncher(variables_map &options)
|
||||
{
|
||||
return std::unique_ptr<Launcher>(new ClassicLauncher(options));
|
||||
return std::unique_ptr<Launcher>(new ClassicLauncher(options));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
class Classic : public LaunchMethod
|
||||
{
|
||||
public:
|
||||
virtual std::string GetName() { return "classic"; }
|
||||
virtual std::string GetName() { return "classic"; }
|
||||
|
||||
virtual bool CheckPlatform();
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
virtual bool CheckPlatform();
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
};
|
||||
|
||||
#endif // CLASSIC_H
|
||||
|
||||
@@ -7,10 +7,10 @@ namespace po = boost::program_options;
|
||||
class ExecutorLauncher : public Launcher
|
||||
{
|
||||
public:
|
||||
ExecutorLauncher(po::variables_map& options);
|
||||
virtual ~ExecutorLauncher();
|
||||
ExecutorLauncher(po::variables_map& options);
|
||||
virtual ~ExecutorLauncher();
|
||||
|
||||
virtual bool Go(int timeout = 0);
|
||||
virtual bool Go(int timeout = 0);
|
||||
|
||||
};
|
||||
|
||||
@@ -27,37 +27,37 @@ ExecutorLauncher::~ExecutorLauncher()
|
||||
|
||||
bool ExecutorLauncher::Go(int timeout)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
if(options.count("executor-option"))
|
||||
args = options["executor-option"].as<std::vector<std::string>>();
|
||||
args.push_back(appPath.string());
|
||||
std::vector<std::string> args;
|
||||
if(options.count("executor-option"))
|
||||
args = options["executor-option"].as<std::vector<std::string>>();
|
||||
args.push_back(appPath.string());
|
||||
|
||||
if(options.count("executor-system-folder"))
|
||||
setenv("SystemFolder", options["executor-system-folder"].as<std::string>().c_str(), true);
|
||||
if(options.count("executor-system-folder"))
|
||||
setenv("SystemFolder", options["executor-system-folder"].as<std::string>().c_str(), true);
|
||||
|
||||
return ChildProcess(options["executor-path"].as<std::string>(), args, timeout) == 0;
|
||||
return ChildProcess(options["executor-path"].as<std::string>(), args, timeout) == 0;
|
||||
}
|
||||
|
||||
|
||||
void Executor::GetOptions(options_description &desc)
|
||||
{
|
||||
desc.add_options()
|
||||
("executor-path", po::value<std::string>()->default_value("executor"),"path to executor")
|
||||
("executor-system-folder", po::value<std::string>(),
|
||||
"system folder for executor (overrides SystemFolder environment variable)")
|
||||
("executor-option", po::value<std::vector<std::string>>(),
|
||||
"pass an option to executor")
|
||||
;
|
||||
desc.add_options()
|
||||
("executor-path", po::value<std::string>()->default_value("executor"),"path to executor")
|
||||
("executor-system-folder", po::value<std::string>(),
|
||||
"system folder for executor (overrides SystemFolder environment variable)")
|
||||
("executor-option", po::value<std::vector<std::string>>(),
|
||||
"pass an option to executor")
|
||||
;
|
||||
}
|
||||
|
||||
bool Executor::CheckOptions(variables_map &options)
|
||||
{
|
||||
if(options.count("executor-path") == 0)
|
||||
return false;
|
||||
return CheckExecutable(options["executor-path"].as<std::string>());
|
||||
if(options.count("executor-path") == 0)
|
||||
return false;
|
||||
return CheckExecutable(options["executor-path"].as<std::string>());
|
||||
}
|
||||
|
||||
std::unique_ptr<Launcher> Executor::MakeLauncher(variables_map &options)
|
||||
{
|
||||
return std::unique_ptr<Launcher>(new ExecutorLauncher(options));
|
||||
return std::unique_ptr<Launcher>(new ExecutorLauncher(options));
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
class Executor : public LaunchMethod
|
||||
{
|
||||
public:
|
||||
virtual std::string GetName() { return "executor"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
virtual std::string GetName() { return "executor"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
};
|
||||
|
||||
#endif // EXECUTOR_H
|
||||
|
||||
+191
-191
@@ -9,13 +9,13 @@
|
||||
#include "Launcher.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# define ResType MacResType
|
||||
# include <ApplicationServices/ApplicationServices.h>
|
||||
# undef ResType
|
||||
# if TARGET_CPU_PPC
|
||||
# include "Classic.h"
|
||||
# endif
|
||||
# include "Carbon.h"
|
||||
# define ResType MacResType
|
||||
# include <ApplicationServices/ApplicationServices.h>
|
||||
# undef ResType
|
||||
# if TARGET_CPU_PPC
|
||||
# include "Classic.h"
|
||||
# endif
|
||||
# include "Carbon.h"
|
||||
#endif
|
||||
#include "Executor.h"
|
||||
#include "MiniVMac.h"
|
||||
@@ -37,224 +37,224 @@ static vector<LaunchMethod*> launchMethods;
|
||||
|
||||
static void RegisterLaunchMethods()
|
||||
{
|
||||
vector<LaunchMethod*> methods = {
|
||||
vector<LaunchMethod*> methods = {
|
||||
#if defined(__APPLE__)
|
||||
# if TARGET_CPU_PPC
|
||||
new Classic(),
|
||||
# endif
|
||||
new Carbon(),
|
||||
# if TARGET_CPU_PPC
|
||||
new Classic(),
|
||||
# endif
|
||||
new Carbon(),
|
||||
#endif
|
||||
new Executor(), new MiniVMac(),
|
||||
new SSH(),
|
||||
new Executor(), new MiniVMac(),
|
||||
new SSH(),
|
||||
new Serial(),
|
||||
new TCP(),
|
||||
new SharedFile()
|
||||
// #### Add new `LaunchMethod`s here.
|
||||
};
|
||||
|
||||
for(LaunchMethod *m : methods)
|
||||
{
|
||||
if(m->CheckPlatform())
|
||||
launchMethods.push_back(m);
|
||||
}
|
||||
// #### Add new `LaunchMethod`s here.
|
||||
};
|
||||
|
||||
for(LaunchMethod *m : methods)
|
||||
{
|
||||
if(m->CheckPlatform())
|
||||
launchMethods.push_back(m);
|
||||
}
|
||||
}
|
||||
|
||||
static void usage()
|
||||
{
|
||||
std::cerr << "Usage: " << "LaunchAPPL [options] appl-file\n";
|
||||
std::cerr << desc << std::endl;
|
||||
std::cerr << "Defaults are read from:\n";
|
||||
for(string str : configFiles)
|
||||
{
|
||||
std::cerr << "\t" << str;
|
||||
if(!std::ifstream(str))
|
||||
std::cerr << " (not found)";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "Usage: " << "LaunchAPPL [options] appl-file\n";
|
||||
std::cerr << desc << std::endl;
|
||||
std::cerr << "Defaults are read from:\n";
|
||||
for(string str : configFiles)
|
||||
{
|
||||
std::cerr << "\t" << str;
|
||||
if(!std::ifstream(str))
|
||||
std::cerr << " (not found)";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
||||
vector<string> configuredMethods, unconfiguredMethods;
|
||||
for(LaunchMethod *method : launchMethods)
|
||||
(method->CheckOptions(options) ? configuredMethods : unconfiguredMethods)
|
||||
.push_back(method->GetName());
|
||||
vector<string> configuredMethods, unconfiguredMethods;
|
||||
for(LaunchMethod *method : launchMethods)
|
||||
(method->CheckOptions(options) ? configuredMethods : unconfiguredMethods)
|
||||
.push_back(method->GetName());
|
||||
|
||||
if(!configuredMethods.empty())
|
||||
{
|
||||
std::cerr << "Available emulators/environments:\n";
|
||||
for(string m : configuredMethods)
|
||||
std::cerr << "\t" << m << std::endl;
|
||||
}
|
||||
if(!unconfiguredMethods.empty())
|
||||
{
|
||||
std::cerr << "Emulators/environments needing more configuration:\n";
|
||||
for(string m : unconfiguredMethods)
|
||||
std::cerr << "\t" << m << std::endl;
|
||||
}
|
||||
if(!configuredMethods.empty())
|
||||
{
|
||||
std::cerr << "Available emulators/environments:\n";
|
||||
for(string m : configuredMethods)
|
||||
std::cerr << "\t" << m << std::endl;
|
||||
}
|
||||
if(!unconfiguredMethods.empty())
|
||||
{
|
||||
std::cerr << "Emulators/environments needing more configuration:\n";
|
||||
for(string m : unconfiguredMethods)
|
||||
std::cerr << "\t" << m << std::endl;
|
||||
}
|
||||
|
||||
if(options.count("emulator"))
|
||||
{
|
||||
string e = options["emulator"].as<string>();
|
||||
std::cerr << "\nChosen emulator/environment: " << e;
|
||||
if(std::find(configuredMethods.begin(), configuredMethods.end(), e)
|
||||
!= configuredMethods.end())
|
||||
std::cerr << "\n";
|
||||
else if(std::find(unconfiguredMethods.begin(), unconfiguredMethods.end(), e)
|
||||
!= unconfiguredMethods.end())
|
||||
std::cerr << " (needs more configuration)\n";
|
||||
else
|
||||
std::cerr << " (UNKNOWN)\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "\nNo emulator/environment chosen (-e)\n";
|
||||
}
|
||||
if(options.count("emulator"))
|
||||
{
|
||||
string e = options["emulator"].as<string>();
|
||||
std::cerr << "\nChosen emulator/environment: " << e;
|
||||
if(std::find(configuredMethods.begin(), configuredMethods.end(), e)
|
||||
!= configuredMethods.end())
|
||||
std::cerr << "\n";
|
||||
else if(std::find(unconfiguredMethods.begin(), unconfiguredMethods.end(), e)
|
||||
!= unconfiguredMethods.end())
|
||||
std::cerr << " (needs more configuration)\n";
|
||||
else
|
||||
std::cerr << " (UNKNOWN)\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "\nNo emulator/environment chosen (-e)\n";
|
||||
}
|
||||
}
|
||||
|
||||
void MakeExecutable(string filepath);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
RegisterLaunchMethods();
|
||||
configFiles = { string(getenv("HOME")) + "/.LaunchAPPL.cfg", RETRO68_PREFIX "/LaunchAPPL.cfg"};
|
||||
RegisterLaunchMethods();
|
||||
configFiles = { string(getenv("HOME")) + "/.LaunchAPPL.cfg", RETRO68_PREFIX "/LaunchAPPL.cfg"};
|
||||
|
||||
desc.add_options()
|
||||
("help,h", "show this help message")
|
||||
("list-emulators,l", "get the list of available, fully configured emulators/environments")
|
||||
("make-executable,x", po::value<std::string>(), "make a MacBinary file executable")
|
||||
;
|
||||
po::options_description configdesc;
|
||||
configdesc.add_options()
|
||||
("emulator,e", po::value<std::string>(), "what emulator/environment to use")
|
||||
;
|
||||
for(LaunchMethod *lm : launchMethods)
|
||||
lm->GetOptions(configdesc);
|
||||
desc.add(configdesc);
|
||||
desc.add_options()
|
||||
("help,h", "show this help message")
|
||||
("list-emulators,l", "get the list of available, fully configured emulators/environments")
|
||||
("make-executable,x", po::value<std::string>(), "make a MacBinary file executable")
|
||||
;
|
||||
po::options_description configdesc;
|
||||
configdesc.add_options()
|
||||
("emulator,e", po::value<std::string>(), "what emulator/environment to use")
|
||||
;
|
||||
for(LaunchMethod *lm : launchMethods)
|
||||
lm->GetOptions(configdesc);
|
||||
desc.add(configdesc);
|
||||
|
||||
desc.add_options()
|
||||
("timeout,t", po::value<int>(),"abort after timeout")
|
||||
desc.add_options()
|
||||
("timeout,t", po::value<int>(),"abort after timeout")
|
||||
("upgrade-server", "upgrade the server application")
|
||||
;
|
||||
po::options_description hidden, alldesc;
|
||||
hidden.add_options()
|
||||
("application,a", po::value<std::string>(), "application" )
|
||||
;
|
||||
alldesc.add(desc).add(hidden);
|
||||
try
|
||||
{
|
||||
auto parsed = po::command_line_parser(argc, argv)
|
||||
.options(alldesc)
|
||||
.positional(po::positional_options_description().add("application", -1))
|
||||
.style(po::command_line_style::default_style)
|
||||
.run();
|
||||
;
|
||||
po::options_description hidden, alldesc;
|
||||
hidden.add_options()
|
||||
("application,a", po::value<std::string>(), "application" )
|
||||
;
|
||||
alldesc.add(desc).add(hidden);
|
||||
try
|
||||
{
|
||||
auto parsed = po::command_line_parser(argc, argv)
|
||||
.options(alldesc)
|
||||
.positional(po::positional_options_description().add("application", -1))
|
||||
.style(po::command_line_style::default_style)
|
||||
.run();
|
||||
|
||||
po::store(parsed, options);
|
||||
}
|
||||
catch(po::error& e)
|
||||
{
|
||||
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
po::store(parsed, options);
|
||||
}
|
||||
catch(po::error& e)
|
||||
{
|
||||
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
for(string configFileName : configFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ifstream cfg(configFileName);
|
||||
if(cfg)
|
||||
{
|
||||
auto parsed = po::parse_config_file<char>(cfg,configdesc,false);
|
||||
for(string configFileName : configFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ifstream cfg(configFileName);
|
||||
if(cfg)
|
||||
{
|
||||
auto parsed = po::parse_config_file<char>(cfg,configdesc,false);
|
||||
|
||||
po::store(parsed, options);
|
||||
}
|
||||
}
|
||||
catch(po::error& e)
|
||||
{
|
||||
std::cerr << "CONFIG FILE ERROR: " << e.what() << std::endl << std::endl;
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
po::store(parsed, options);
|
||||
}
|
||||
}
|
||||
catch(po::error& e)
|
||||
{
|
||||
std::cerr << "CONFIG FILE ERROR: " << e.what() << std::endl << std::endl;
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
po::notify(options);
|
||||
po::notify(options);
|
||||
|
||||
vector<string> commandModes = {"application", "help", "make-executable", "list-emulators"};
|
||||
int nModes = 0;
|
||||
string mode;
|
||||
vector<string> commandModes = {"application", "help", "make-executable", "list-emulators"};
|
||||
int nModes = 0;
|
||||
string mode;
|
||||
|
||||
for(string aMode : commandModes)
|
||||
{
|
||||
if(options.count(aMode))
|
||||
{
|
||||
nModes++;
|
||||
mode = aMode;
|
||||
}
|
||||
}
|
||||
if(nModes > 1)
|
||||
{
|
||||
std::cerr << "Need to specify either an application file or exactly one of ";
|
||||
for(int i = 1, n = commandModes.size(); i < n-1; i++)
|
||||
std::cerr << "--" << commandModes[i] << ", ";
|
||||
std::cerr << "or " << commandModes.back() << "." << std::endl << std::endl;
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
if(mode == "" || mode == "help")
|
||||
{
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
else if(mode == "make-executable")
|
||||
{
|
||||
string fn = options["make-executable"].as<std::string>();
|
||||
MakeExecutable(fn);
|
||||
return 0;
|
||||
}
|
||||
else if(mode == "list-emulators")
|
||||
{
|
||||
for(LaunchMethod *method : launchMethods)
|
||||
if(method->CheckOptions(options))
|
||||
std::cout << method->GetName() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
for(string aMode : commandModes)
|
||||
{
|
||||
if(options.count(aMode))
|
||||
{
|
||||
nModes++;
|
||||
mode = aMode;
|
||||
}
|
||||
}
|
||||
if(nModes > 1)
|
||||
{
|
||||
std::cerr << "Need to specify either an application file or exactly one of ";
|
||||
for(int i = 1, n = commandModes.size(); i < n-1; i++)
|
||||
std::cerr << "--" << commandModes[i] << ", ";
|
||||
std::cerr << "or " << commandModes.back() << "." << std::endl << std::endl;
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
if(mode == "" || mode == "help")
|
||||
{
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
else if(mode == "make-executable")
|
||||
{
|
||||
string fn = options["make-executable"].as<std::string>();
|
||||
MakeExecutable(fn);
|
||||
return 0;
|
||||
}
|
||||
else if(mode == "list-emulators")
|
||||
{
|
||||
for(LaunchMethod *method : launchMethods)
|
||||
if(method->CheckOptions(options))
|
||||
std::cout << method->GetName() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!options.count("emulator"))
|
||||
{
|
||||
std::cerr << "ERROR: emulator/environment not specified.\n";
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
if(!options.count("emulator"))
|
||||
{
|
||||
std::cerr << "ERROR: emulator/environment not specified.\n";
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
LaunchMethod *method = NULL;
|
||||
for(LaunchMethod *lm : launchMethods)
|
||||
{
|
||||
if(lm->GetName() == options["emulator"].as<string>())
|
||||
{
|
||||
method = lm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!method)
|
||||
{
|
||||
std::cerr << "ERROR: unknown emulator/environment: " << options["emulator"].as<string>() << "\n";
|
||||
return 1;
|
||||
}
|
||||
LaunchMethod *method = NULL;
|
||||
for(LaunchMethod *lm : launchMethods)
|
||||
{
|
||||
if(lm->GetName() == options["emulator"].as<string>())
|
||||
{
|
||||
method = lm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!method)
|
||||
{
|
||||
std::cerr << "ERROR: unknown emulator/environment: " << options["emulator"].as<string>() << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!method->CheckOptions(options))
|
||||
{
|
||||
std::cerr << "Need more configuration.\n";
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
if(!method->CheckOptions(options))
|
||||
{
|
||||
std::cerr << "Need more configuration.\n";
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Launcher> launcher = method->MakeLauncher(options);
|
||||
std::unique_ptr<Launcher> launcher = method->MakeLauncher(options);
|
||||
|
||||
int timeout = options.count("timeout") ? options["timeout"].as<int>() : 0;
|
||||
int timeout = options.count("timeout") ? options["timeout"].as<int>() : 0;
|
||||
|
||||
bool result = launcher->Go(timeout);
|
||||
bool result = launcher->Go(timeout);
|
||||
|
||||
launcher->DumpOutput();
|
||||
launcher->DumpOutput();
|
||||
|
||||
|
||||
return result ? 0 : 1;
|
||||
return result ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@ void LaunchMethod::GetOptions(boost::program_options::options_description &desc)
|
||||
|
||||
bool LaunchMethod::CheckPlatform()
|
||||
{
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LaunchMethod::CheckOptions(boost::program_options::variables_map &options)
|
||||
{
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -18,52 +18,52 @@ class Launcher;
|
||||
class LaunchMethod
|
||||
{
|
||||
public:
|
||||
typedef boost::program_options::options_description options_description;
|
||||
typedef boost::program_options::variables_map variables_map;
|
||||
typedef boost::program_options::options_description options_description;
|
||||
typedef boost::program_options::variables_map variables_map;
|
||||
|
||||
LaunchMethod();
|
||||
virtual ~LaunchMethod();
|
||||
LaunchMethod();
|
||||
virtual ~LaunchMethod();
|
||||
|
||||
/**
|
||||
* @brief GetName
|
||||
* @return the name of the launch method, as it will be specified on the command line
|
||||
*/
|
||||
virtual std::string GetName() = 0;
|
||||
/**
|
||||
* @brief GetName
|
||||
* @return the name of the launch method, as it will be specified on the command line
|
||||
*/
|
||||
virtual std::string GetName() = 0;
|
||||
|
||||
/**
|
||||
* @brief GetOptions
|
||||
* @param desc
|
||||
*
|
||||
* Add any command line options for this LaunchMethod
|
||||
* to the options_description structure.
|
||||
*/
|
||||
virtual void GetOptions(options_description& desc);
|
||||
/**
|
||||
* @brief GetOptions
|
||||
* @param desc
|
||||
*
|
||||
* Add any command line options for this LaunchMethod
|
||||
* to the options_description structure.
|
||||
*/
|
||||
virtual void GetOptions(options_description& desc);
|
||||
|
||||
/**
|
||||
* @brief CheckPlatform
|
||||
*
|
||||
* Check whether this is the right kind of machine to use this method.
|
||||
* For things like Apple's Classic Environment, which is only available on some system versions.
|
||||
* The default implementation returns true.
|
||||
*/
|
||||
virtual bool CheckPlatform();
|
||||
/**
|
||||
* @brief CheckPlatform
|
||||
*
|
||||
* Check whether this is the right kind of machine to use this method.
|
||||
* For things like Apple's Classic Environment, which is only available on some system versions.
|
||||
* The default implementation returns true.
|
||||
*/
|
||||
virtual bool CheckPlatform();
|
||||
|
||||
/**
|
||||
* @brief CheckOptions
|
||||
* @param options
|
||||
* @return are we ready to run?
|
||||
*
|
||||
* Check whether all necessary options have been specified.
|
||||
* Don't output error messages here, this is also called when outputting usage information
|
||||
*/
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
/**
|
||||
* @brief CheckOptions
|
||||
* @param options
|
||||
* @return are we ready to run?
|
||||
*
|
||||
* Check whether all necessary options have been specified.
|
||||
* Don't output error messages here, this is also called when outputting usage information
|
||||
*/
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
|
||||
/**
|
||||
* @brief MakeLauncher
|
||||
* @param options
|
||||
* @return a new instance of a subclass of Launcher which will do the actual work
|
||||
*/
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options) = 0;
|
||||
/**
|
||||
* @brief MakeLauncher
|
||||
* @param options
|
||||
* @return a new instance of a subclass of Launcher which will do the actual work
|
||||
*/
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options) = 0;
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
@@ -11,47 +11,47 @@ using std::vector;
|
||||
Launcher::Launcher(boost::program_options::variables_map &options)
|
||||
: options(options)
|
||||
{
|
||||
string fn = options["application"].as<std::string>();
|
||||
|
||||
if(fn == "-")
|
||||
{
|
||||
std::stringstream tmp;
|
||||
tmp << std::cin.rdbuf();
|
||||
if(!app.read(tmp, ResourceFile::Format::macbin))
|
||||
throw std::runtime_error("Could not load application from stdin.");
|
||||
}
|
||||
else
|
||||
{
|
||||
app.assign(fn);
|
||||
if(!app.read())
|
||||
throw std::runtime_error("Could not load application file.");
|
||||
}
|
||||
|
||||
tempDir = fs::absolute(fs::unique_path());
|
||||
fs::create_directories(tempDir);
|
||||
string fn = options["application"].as<std::string>();
|
||||
|
||||
if(fn == "-")
|
||||
{
|
||||
std::stringstream tmp;
|
||||
tmp << std::cin.rdbuf();
|
||||
if(!app.read(tmp, ResourceFile::Format::macbin))
|
||||
throw std::runtime_error("Could not load application from stdin.");
|
||||
}
|
||||
else
|
||||
{
|
||||
app.assign(fn);
|
||||
if(!app.read())
|
||||
throw std::runtime_error("Could not load application file.");
|
||||
}
|
||||
|
||||
tempDir = fs::absolute(fs::unique_path());
|
||||
fs::create_directories(tempDir);
|
||||
|
||||
appPath = tempDir / "Application";
|
||||
outPath = tempDir / "out";
|
||||
appPath = tempDir / "Application";
|
||||
outPath = tempDir / "out";
|
||||
|
||||
fs::ofstream out(outPath);
|
||||
fs::ofstream out(outPath);
|
||||
}
|
||||
|
||||
Launcher::Launcher(boost::program_options::variables_map &options, ResourceFile::Format f)
|
||||
: Launcher(options)
|
||||
{
|
||||
app.assign(appPath.string(), f);
|
||||
app.write();
|
||||
app.assign(appPath.string(), f);
|
||||
app.write();
|
||||
}
|
||||
|
||||
void Launcher::DumpOutput()
|
||||
{
|
||||
fs::ifstream in(outPath);
|
||||
std::cout << in.rdbuf();
|
||||
fs::ifstream in(outPath);
|
||||
std::cout << in.rdbuf();
|
||||
}
|
||||
|
||||
Launcher::~Launcher()
|
||||
{
|
||||
fs::remove_all(tempDir);
|
||||
fs::remove_all(tempDir);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,61 +14,61 @@
|
||||
class Launcher
|
||||
{
|
||||
protected:
|
||||
boost::program_options::variables_map& options;
|
||||
boost::program_options::variables_map& options;
|
||||
|
||||
ResourceFile app;
|
||||
boost::filesystem::path tempDir, appPath, outPath;
|
||||
bool keepTempFiles;
|
||||
ResourceFile app;
|
||||
boost::filesystem::path tempDir, appPath, outPath;
|
||||
bool keepTempFiles;
|
||||
public:
|
||||
/**
|
||||
* @brief Launcher
|
||||
* @param options
|
||||
*
|
||||
* Create a Launcher object and set up a temporary directory to play in.
|
||||
* Reads the Applicatio specified on the command line into the `app` member variable.
|
||||
* Also create an empty file named 'out' in the temporary directory, for test suite programs.
|
||||
*/
|
||||
Launcher(boost::program_options::variables_map& options);
|
||||
/**
|
||||
* @brief Launcher
|
||||
* @param options
|
||||
*
|
||||
* Create a Launcher object and set up a temporary directory to play in.
|
||||
* Reads the Applicatio specified on the command line into the `app` member variable.
|
||||
* Also create an empty file named 'out' in the temporary directory, for test suite programs.
|
||||
*/
|
||||
Launcher(boost::program_options::variables_map& options);
|
||||
|
||||
/**
|
||||
* @brief Launcher
|
||||
* @param options
|
||||
* @param f
|
||||
*
|
||||
* Create a Launcher object, set up a temporary directory
|
||||
* and store the application to be executed at `appPath` in the temporary directory,
|
||||
* using format `f`.
|
||||
*/
|
||||
Launcher(boost::program_options::variables_map& options, ResourceFile::Format f);
|
||||
/**
|
||||
* @brief Launcher
|
||||
* @param options
|
||||
* @param f
|
||||
*
|
||||
* Create a Launcher object, set up a temporary directory
|
||||
* and store the application to be executed at `appPath` in the temporary directory,
|
||||
* using format `f`.
|
||||
*/
|
||||
Launcher(boost::program_options::variables_map& options, ResourceFile::Format f);
|
||||
|
||||
|
||||
/**
|
||||
* @brief ~Launcher
|
||||
* Delete our temporary directory.
|
||||
*/
|
||||
virtual ~Launcher();
|
||||
/**
|
||||
* @brief ~Launcher
|
||||
* Delete our temporary directory.
|
||||
*/
|
||||
virtual ~Launcher();
|
||||
|
||||
/**
|
||||
* @brief Go
|
||||
* @param timeout
|
||||
* @return true for success
|
||||
*
|
||||
* Launch the application, return true on success and false on error or timeout.
|
||||
*/
|
||||
virtual bool Go(int timeout = 0) = 0;
|
||||
/**
|
||||
* @brief Go
|
||||
* @param timeout
|
||||
* @return true for success
|
||||
*
|
||||
* Launch the application, return true on success and false on error or timeout.
|
||||
*/
|
||||
virtual bool Go(int timeout = 0) = 0;
|
||||
|
||||
/**
|
||||
* @brief DumpOutput
|
||||
*
|
||||
* After the application has been run, copy the contents of the 'out' file to stdout.
|
||||
*/
|
||||
virtual void DumpOutput();
|
||||
/**
|
||||
* @brief DumpOutput
|
||||
*
|
||||
* After the application has been run, copy the contents of the 'out' file to stdout.
|
||||
*/
|
||||
virtual void DumpOutput();
|
||||
|
||||
/**
|
||||
* @brief KeepTempFiles
|
||||
* Inhibit deletion of the temporary directory.
|
||||
*/
|
||||
void KeepTempFiles() { keepTempFiles = true; }
|
||||
/**
|
||||
* @brief KeepTempFiles
|
||||
* Inhibit deletion of the temporary directory.
|
||||
*/
|
||||
void KeepTempFiles() { keepTempFiles = true; }
|
||||
};
|
||||
|
||||
#endif // LAUNCHER_H
|
||||
|
||||
@@ -11,43 +11,43 @@ namespace fs = boost::filesystem;
|
||||
|
||||
void MakeExecutable(string fn)
|
||||
{
|
||||
ResourceFile rsrcFile(fn);
|
||||
if(!rsrcFile.read())
|
||||
{
|
||||
std::cerr << "Cannot read application file: " << fn << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
if(!rsrcFile.hasPlainDataFork())
|
||||
{
|
||||
std::cerr << "--make-executable can not be used with this data format.\n";
|
||||
exit(1);
|
||||
}
|
||||
ResourceFile rsrcFile(fn);
|
||||
if(!rsrcFile.read())
|
||||
{
|
||||
std::cerr << "Cannot read application file: " << fn << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
if(!rsrcFile.hasPlainDataFork())
|
||||
{
|
||||
std::cerr << "--make-executable can not be used with this data format.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
string headerString = "#!" RETRO68_PREFIX "/bin/LaunchAPPL\n";
|
||||
string headerString = "#!" RETRO68_PREFIX "/bin/LaunchAPPL\n";
|
||||
|
||||
bool hadShebang = false;
|
||||
if(rsrcFile.data.size())
|
||||
{
|
||||
if(headerString.substr(2) == "#!")
|
||||
{
|
||||
string::size_type eol = headerString.find('\n');
|
||||
if(eol != string::npos && eol >= 13 && eol < 4096)
|
||||
{
|
||||
if(headerString.substr(eol-11,11) == "/LaunchAPPL")
|
||||
hadShebang = true;
|
||||
}
|
||||
}
|
||||
bool hadShebang = false;
|
||||
if(rsrcFile.data.size())
|
||||
{
|
||||
if(headerString.substr(2) == "#!")
|
||||
{
|
||||
string::size_type eol = headerString.find('\n');
|
||||
if(eol != string::npos && eol >= 13 && eol < 4096)
|
||||
{
|
||||
if(headerString.substr(eol-11,11) == "/LaunchAPPL")
|
||||
hadShebang = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!hadShebang)
|
||||
{
|
||||
std::cerr << "Unfortunately, the application already has a data fork.\n";
|
||||
std::cerr << "LaunchAPPL --make-executable does not currently work for PowerPC apps.\n";
|
||||
// TODO: if it's a PEF container, move it back a little and update cfrg
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if(!hadShebang)
|
||||
{
|
||||
std::cerr << "Unfortunately, the application already has a data fork.\n";
|
||||
std::cerr << "LaunchAPPL --make-executable does not currently work for PowerPC apps.\n";
|
||||
// TODO: if it's a PEF container, move it back a little and update cfrg
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
std::fstream(fn, std::ios::in | std::ios::out | std::ios::binary) << headerString;
|
||||
std::fstream(fn, std::ios::in | std::ios::out | std::ios::binary) << headerString;
|
||||
|
||||
fs::permissions(fs::path(fn), fs::owner_exe | fs::group_exe | fs::others_exe | fs::add_perms);
|
||||
fs::permissions(fs::path(fn), fs::owner_exe | fs::group_exe | fs::others_exe | fs::add_perms);
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
class MiniVMac : public LaunchMethod
|
||||
{
|
||||
public:
|
||||
virtual std::string GetName() { return "minivmac"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
virtual std::string GetName() { return "minivmac"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
};
|
||||
|
||||
#endif // MINIVMAC_H
|
||||
|
||||
+86
-86
@@ -16,10 +16,10 @@ using std::vector;
|
||||
class SSHLauncher : public Launcher
|
||||
{
|
||||
public:
|
||||
SSHLauncher(po::variables_map& options);
|
||||
virtual ~SSHLauncher();
|
||||
SSHLauncher(po::variables_map& options);
|
||||
virtual ~SSHLauncher();
|
||||
|
||||
virtual bool Go(int timeout = 0);
|
||||
virtual bool Go(int timeout = 0);
|
||||
|
||||
};
|
||||
|
||||
@@ -36,115 +36,115 @@ SSHLauncher::~SSHLauncher()
|
||||
|
||||
static void insertArgs(vector<string>& args, po::variables_map& options, string name)
|
||||
{
|
||||
if(options.count(name))
|
||||
{
|
||||
auto extraArgs = SplitArguments(options[name].as<vector<string>>());
|
||||
args.insert(args.end(), extraArgs.begin(), extraArgs.end());
|
||||
}
|
||||
if(options.count(name))
|
||||
{
|
||||
auto extraArgs = SplitArguments(options[name].as<vector<string>>());
|
||||
args.insert(args.end(), extraArgs.begin(), extraArgs.end());
|
||||
}
|
||||
}
|
||||
|
||||
bool SSHLauncher::Go(int timeout)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
args.push_back(options["ssh-host"].as<string>());
|
||||
insertArgs(args, options, "ssh-args");
|
||||
args.push_back("--");
|
||||
args.push_back(options["ssh-remote-path"].as<string>());
|
||||
insertArgs(args, options, "ssh-remote-args");
|
||||
if(timeout)
|
||||
{
|
||||
args.push_back("--timeout");
|
||||
args.push_back(boost::lexical_cast<std::string>(timeout));
|
||||
}
|
||||
args.push_back("-");
|
||||
std::vector<std::string> args;
|
||||
args.push_back(options["ssh-host"].as<string>());
|
||||
insertArgs(args, options, "ssh-args");
|
||||
args.push_back("--");
|
||||
args.push_back(options["ssh-remote-path"].as<string>());
|
||||
insertArgs(args, options, "ssh-remote-args");
|
||||
if(timeout)
|
||||
{
|
||||
args.push_back("--timeout");
|
||||
args.push_back(boost::lexical_cast<std::string>(timeout));
|
||||
}
|
||||
args.push_back("-");
|
||||
|
||||
std::string program = options["ssh-path"].as<std::string>();
|
||||
std::string program = options["ssh-path"].as<std::string>();
|
||||
|
||||
std::vector<const char*> argv;
|
||||
argv.push_back(program.c_str());
|
||||
for(std::string& s : args)
|
||||
argv.push_back(s.c_str());
|
||||
argv.push_back(NULL);
|
||||
std::vector<const char*> argv;
|
||||
argv.push_back(program.c_str());
|
||||
for(std::string& s : args)
|
||||
argv.push_back(s.c_str());
|
||||
argv.push_back(NULL);
|
||||
|
||||
int fd[2];
|
||||
pipe(fd);
|
||||
const int READ_END = 0;
|
||||
const int WRITE_END = 1;
|
||||
int fd[2];
|
||||
pipe(fd);
|
||||
const int READ_END = 0;
|
||||
const int WRITE_END = 1;
|
||||
|
||||
pid_t pid = fork();
|
||||
if(pid < 0)
|
||||
{
|
||||
perror("unable to fork");
|
||||
return 1;
|
||||
}
|
||||
else if(pid == 0)
|
||||
{
|
||||
dup2(fd[READ_END], STDIN_FILENO);
|
||||
close(fd[WRITE_END]);
|
||||
close(fd[READ_END]);
|
||||
pid_t pid = fork();
|
||||
if(pid < 0)
|
||||
{
|
||||
perror("unable to fork");
|
||||
return 1;
|
||||
}
|
||||
else if(pid == 0)
|
||||
{
|
||||
dup2(fd[READ_END], STDIN_FILENO);
|
||||
close(fd[WRITE_END]);
|
||||
close(fd[READ_END]);
|
||||
|
||||
execvp(argv[0], const_cast<char* const *> (argv.data()));
|
||||
perror("exec failed");
|
||||
std::cerr << "Tried to execute: " << program;
|
||||
for(auto a : args)
|
||||
std::cerr << " " << a;
|
||||
std::cerr << std::endl;
|
||||
_exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
close(fd[READ_END]);
|
||||
execvp(argv[0], const_cast<char* const *> (argv.data()));
|
||||
perror("exec failed");
|
||||
std::cerr << "Tried to execute: " << program;
|
||||
for(auto a : args)
|
||||
std::cerr << " " << a;
|
||||
std::cerr << std::endl;
|
||||
_exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
close(fd[READ_END]);
|
||||
|
||||
std::ostringstream tmp;
|
||||
app.write(tmp, ResourceFile::Format::macbin);
|
||||
const std::string data = tmp.str();
|
||||
std::ostringstream tmp;
|
||||
app.write(tmp, ResourceFile::Format::macbin);
|
||||
const std::string data = tmp.str();
|
||||
|
||||
write(fd[WRITE_END], data.data(), data.size());
|
||||
close(fd[WRITE_END]);
|
||||
write(fd[WRITE_END], data.data(), data.size());
|
||||
close(fd[WRITE_END]);
|
||||
|
||||
int wstatus;
|
||||
int result = 0;
|
||||
do
|
||||
{
|
||||
result = waitpid(pid, &wstatus, 0);
|
||||
} while(result == -1 && errno == EINTR);
|
||||
int wstatus;
|
||||
int result = 0;
|
||||
do
|
||||
{
|
||||
result = waitpid(pid, &wstatus, 0);
|
||||
} while(result == -1 && errno == EINTR);
|
||||
|
||||
if(!WIFEXITED(wstatus))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//int exitcode = WEXITSTATUS(wstatus);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(!WIFEXITED(wstatus))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//int exitcode = WEXITSTATUS(wstatus);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SSH::GetOptions(options_description &desc)
|
||||
{
|
||||
desc.add_options()
|
||||
("ssh-path", po::value<string>()->default_value("ssh"),"ssh command to use")
|
||||
("ssh-host", po::value<string>(),
|
||||
"[username@]address of remote host")
|
||||
("ssh-args", po::value<vector<string>>(),
|
||||
"additional arguments for ssh")
|
||||
("ssh-remote-path", po::value<string>()->default_value("LaunchAPPL"),
|
||||
"path to LaunchAPPL on remote host")
|
||||
("ssh-remote-args", po::value<vector<string>>(),
|
||||
"additional arguments for LaunchAPPL on remote host")
|
||||
;
|
||||
desc.add_options()
|
||||
("ssh-path", po::value<string>()->default_value("ssh"),"ssh command to use")
|
||||
("ssh-host", po::value<string>(),
|
||||
"[username@]address of remote host")
|
||||
("ssh-args", po::value<vector<string>>(),
|
||||
"additional arguments for ssh")
|
||||
("ssh-remote-path", po::value<string>()->default_value("LaunchAPPL"),
|
||||
"path to LaunchAPPL on remote host")
|
||||
("ssh-remote-args", po::value<vector<string>>(),
|
||||
"additional arguments for LaunchAPPL on remote host")
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
bool SSH::CheckOptions(variables_map &options)
|
||||
{
|
||||
return options.count("ssh-host") != 0;
|
||||
return options.count("ssh-host") != 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<Launcher> SSH::MakeLauncher(variables_map &options)
|
||||
{
|
||||
return std::unique_ptr<Launcher>(new SSHLauncher(options));
|
||||
return std::unique_ptr<Launcher>(new SSHLauncher(options));
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
class SSH : public LaunchMethod
|
||||
{
|
||||
public:
|
||||
virtual std::string GetName() { return "ssh"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
virtual std::string GetName() { return "ssh"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
};
|
||||
|
||||
#endif // SSH_H
|
||||
|
||||
@@ -36,7 +36,7 @@ class SerialLauncher : public StreamBasedLauncher
|
||||
SerialStream stream;
|
||||
ReliableStream rStream;
|
||||
public:
|
||||
SerialLauncher(po::variables_map& options);
|
||||
SerialLauncher(po::variables_map& options);
|
||||
};
|
||||
|
||||
|
||||
@@ -146,10 +146,10 @@ void Serial::GetOptions(options_description &desc)
|
||||
|
||||
bool Serial::CheckOptions(variables_map &options)
|
||||
{
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Launcher> Serial::MakeLauncher(variables_map &options)
|
||||
{
|
||||
return std::unique_ptr<Launcher>(new SerialLauncher(options));
|
||||
return std::unique_ptr<Launcher>(new SerialLauncher(options));
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
class Serial : public LaunchMethod
|
||||
{
|
||||
public:
|
||||
virtual std::string GetName() { return "serial"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
virtual std::string GetName() { return "serial"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
};
|
||||
|
||||
#endif // EXECUTOR_H
|
||||
|
||||
@@ -30,7 +30,7 @@ class SharedFileLauncher : public StreamBasedLauncher
|
||||
{
|
||||
SharedFileStream stream;
|
||||
public:
|
||||
SharedFileLauncher(po::variables_map& options);
|
||||
SharedFileLauncher(po::variables_map& options);
|
||||
};
|
||||
|
||||
SharedFileStream::SharedFileStream(po::variables_map &options)
|
||||
@@ -90,10 +90,10 @@ void SharedFile::GetOptions(options_description &desc)
|
||||
|
||||
bool SharedFile::CheckOptions(variables_map &options)
|
||||
{
|
||||
return options.count("shared-directory") != 0;
|
||||
return options.count("shared-directory") != 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<Launcher> SharedFile::MakeLauncher(variables_map &options)
|
||||
{
|
||||
return std::unique_ptr<Launcher>(new SharedFileLauncher(options));
|
||||
return std::unique_ptr<Launcher>(new SharedFileLauncher(options));
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
class SharedFile : public LaunchMethod
|
||||
{
|
||||
public:
|
||||
virtual std::string GetName() { return "shared"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
virtual std::string GetName() { return "shared"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
};
|
||||
|
||||
@@ -12,11 +12,11 @@ class StreamBasedLauncher : public Launcher
|
||||
std::vector<char> outputBytes;
|
||||
bool upgradeMode = false;
|
||||
public:
|
||||
StreamBasedLauncher(boost::program_options::variables_map& options);
|
||||
virtual ~StreamBasedLauncher();
|
||||
StreamBasedLauncher(boost::program_options::variables_map& options);
|
||||
virtual ~StreamBasedLauncher();
|
||||
|
||||
virtual bool Go(int timeout = 0);
|
||||
virtual void DumpOutput();
|
||||
virtual bool Go(int timeout = 0);
|
||||
virtual void DumpOutput();
|
||||
|
||||
protected:
|
||||
void SetupStream(WaitableStream* aStream, Stream* wrapped = nullptr);
|
||||
|
||||
@@ -34,7 +34,7 @@ class TCPLauncher : public StreamBasedLauncher
|
||||
{
|
||||
TCPStream stream;
|
||||
public:
|
||||
TCPLauncher(po::variables_map& options);
|
||||
TCPLauncher(po::variables_map& options);
|
||||
};
|
||||
|
||||
|
||||
@@ -85,10 +85,10 @@ void TCP::GetOptions(options_description &desc)
|
||||
|
||||
bool TCP::CheckOptions(variables_map &options)
|
||||
{
|
||||
return options.count("tcp-address") != 0;
|
||||
return options.count("tcp-address") != 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<Launcher> TCP::MakeLauncher(variables_map &options)
|
||||
{
|
||||
return std::unique_ptr<Launcher>(new TCPLauncher(options));
|
||||
return std::unique_ptr<Launcher>(new TCPLauncher(options));
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
class TCP : public LaunchMethod
|
||||
{
|
||||
public:
|
||||
virtual std::string GetName() { return "tcp"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
virtual std::string GetName() { return "tcp"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
};
|
||||
|
||||
#endif // EXECUTOR_H
|
||||
|
||||
+149
-149
@@ -13,90 +13,90 @@ using std::vector;
|
||||
|
||||
int ChildProcess(string program, vector<string> args, int timeout)
|
||||
{
|
||||
std::vector<const char*> argv;
|
||||
argv.push_back(program.c_str());
|
||||
for(string& s : args)
|
||||
argv.push_back(s.c_str());
|
||||
argv.push_back(NULL);
|
||||
std::vector<const char*> argv;
|
||||
argv.push_back(program.c_str());
|
||||
for(string& s : args)
|
||||
argv.push_back(s.c_str());
|
||||
argv.push_back(NULL);
|
||||
|
||||
pid_t pid = fork();
|
||||
if(pid < 0)
|
||||
{
|
||||
perror("unable to fork");
|
||||
return 1;
|
||||
}
|
||||
else if(pid == 0)
|
||||
{
|
||||
pid_t worker_pid = timeout ? fork() : 0;
|
||||
if(worker_pid < 0)
|
||||
{
|
||||
perror("unable to fork");
|
||||
_exit(1);
|
||||
}
|
||||
if(worker_pid == 0)
|
||||
{
|
||||
execvp(argv[0], const_cast<char* const *> (argv.data()));
|
||||
perror("exec failed");
|
||||
std::cerr << "Tried to execute: " << program;
|
||||
for(auto a : args)
|
||||
std::cerr << " " << a;
|
||||
std::cerr << std::endl;
|
||||
_exit(1);
|
||||
}
|
||||
pid_t pid = fork();
|
||||
if(pid < 0)
|
||||
{
|
||||
perror("unable to fork");
|
||||
return 1;
|
||||
}
|
||||
else if(pid == 0)
|
||||
{
|
||||
pid_t worker_pid = timeout ? fork() : 0;
|
||||
if(worker_pid < 0)
|
||||
{
|
||||
perror("unable to fork");
|
||||
_exit(1);
|
||||
}
|
||||
if(worker_pid == 0)
|
||||
{
|
||||
execvp(argv[0], const_cast<char* const *> (argv.data()));
|
||||
perror("exec failed");
|
||||
std::cerr << "Tried to execute: " << program;
|
||||
for(auto a : args)
|
||||
std::cerr << " " << a;
|
||||
std::cerr << std::endl;
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
pid_t timeout_pid = fork();
|
||||
if(timeout_pid < 0)
|
||||
{
|
||||
perror("unable to fork");
|
||||
_exit(1);
|
||||
}
|
||||
if(timeout_pid == 0)
|
||||
{
|
||||
sleep(timeout);
|
||||
_exit(0);
|
||||
}
|
||||
int wstatus;
|
||||
pid_t exited_pid = wait(&wstatus);
|
||||
if(exited_pid == worker_pid)
|
||||
{
|
||||
kill(timeout_pid, SIGKILL);
|
||||
wait(NULL);
|
||||
if(!WIFEXITED(wstatus))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int exitcode = WEXITSTATUS(wstatus);
|
||||
_exit(exitcode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kill(worker_pid, SIGKILL);
|
||||
wait(NULL);
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int wstatus;
|
||||
int result = 0;
|
||||
do
|
||||
{
|
||||
result = waitpid(pid, &wstatus, 0);
|
||||
} while(result == -1 && errno == EINTR);
|
||||
pid_t timeout_pid = fork();
|
||||
if(timeout_pid < 0)
|
||||
{
|
||||
perror("unable to fork");
|
||||
_exit(1);
|
||||
}
|
||||
if(timeout_pid == 0)
|
||||
{
|
||||
sleep(timeout);
|
||||
_exit(0);
|
||||
}
|
||||
int wstatus;
|
||||
pid_t exited_pid = wait(&wstatus);
|
||||
if(exited_pid == worker_pid)
|
||||
{
|
||||
kill(timeout_pid, SIGKILL);
|
||||
wait(NULL);
|
||||
if(!WIFEXITED(wstatus))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int exitcode = WEXITSTATUS(wstatus);
|
||||
_exit(exitcode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kill(worker_pid, SIGKILL);
|
||||
wait(NULL);
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int wstatus;
|
||||
int result = 0;
|
||||
do
|
||||
{
|
||||
result = waitpid(pid, &wstatus, 0);
|
||||
} while(result == -1 && errno == EINTR);
|
||||
|
||||
if(!WIFEXITED(wstatus))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int exitcode = WEXITSTATUS(wstatus);
|
||||
return exitcode;
|
||||
}
|
||||
}
|
||||
if(!WIFEXITED(wstatus))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int exitcode = WEXITSTATUS(wstatus);
|
||||
return exitcode;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -104,89 +104,89 @@ int ChildProcess(string program, vector<string> args, int timeout)
|
||||
|
||||
bool CheckExecutable(std::string program)
|
||||
{
|
||||
if(access(program.c_str(), X_OK) == 0)
|
||||
return true;
|
||||
if(program.find("/") != std::string::npos)
|
||||
return false;
|
||||
const char *PATH = getenv("PATH");
|
||||
if(access(program.c_str(), X_OK) == 0)
|
||||
return true;
|
||||
if(program.find("/") != std::string::npos)
|
||||
return false;
|
||||
const char *PATH = getenv("PATH");
|
||||
|
||||
if(PATH)
|
||||
{
|
||||
bool endFound = false;
|
||||
do
|
||||
{
|
||||
const char *end = strchr(PATH, ':');
|
||||
if(!end)
|
||||
{
|
||||
end = strchr(PATH, '\0');
|
||||
endFound = true;
|
||||
}
|
||||
std::string pathElement(PATH, end);
|
||||
if(PATH)
|
||||
{
|
||||
bool endFound = false;
|
||||
do
|
||||
{
|
||||
const char *end = strchr(PATH, ':');
|
||||
if(!end)
|
||||
{
|
||||
end = strchr(PATH, '\0');
|
||||
endFound = true;
|
||||
}
|
||||
std::string pathElement(PATH, end);
|
||||
|
||||
if(pathElement == "")
|
||||
pathElement = ".";
|
||||
if(pathElement == "")
|
||||
pathElement = ".";
|
||||
|
||||
fs::path f = fs::path(pathElement) / program;
|
||||
fs::path f = fs::path(pathElement) / program;
|
||||
|
||||
if(access(f.string().c_str(), X_OK) == 0)
|
||||
return true;
|
||||
if(access(f.string().c_str(), X_OK) == 0)
|
||||
return true;
|
||||
|
||||
PATH = end + 1;
|
||||
} while(!endFound);
|
||||
}
|
||||
PATH = end + 1;
|
||||
} while(!endFound);
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<string> SplitArguments(std::string str)
|
||||
{
|
||||
bool backslash = false;
|
||||
bool quote = false;
|
||||
bool begun = false;
|
||||
vector<string> args;
|
||||
bool backslash = false;
|
||||
bool quote = false;
|
||||
bool begun = false;
|
||||
vector<string> args;
|
||||
|
||||
for(char c : str)
|
||||
{
|
||||
if(!backslash && !quote && isspace(c))
|
||||
{
|
||||
begun = false;
|
||||
}
|
||||
else if(!backslash && c == '"')
|
||||
{
|
||||
quote = !quote;
|
||||
if(quote && !begun)
|
||||
{
|
||||
args.emplace_back();
|
||||
begun = true;
|
||||
}
|
||||
}
|
||||
else if(!backslash && c == '\\')
|
||||
{
|
||||
backslash = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
backslash = false;
|
||||
for(char c : str)
|
||||
{
|
||||
if(!backslash && !quote && isspace(c))
|
||||
{
|
||||
begun = false;
|
||||
}
|
||||
else if(!backslash && c == '"')
|
||||
{
|
||||
quote = !quote;
|
||||
if(quote && !begun)
|
||||
{
|
||||
args.emplace_back();
|
||||
begun = true;
|
||||
}
|
||||
}
|
||||
else if(!backslash && c == '\\')
|
||||
{
|
||||
backslash = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
backslash = false;
|
||||
|
||||
if(!begun)
|
||||
{
|
||||
args.emplace_back();
|
||||
begun = true;
|
||||
}
|
||||
args.back() += c;
|
||||
}
|
||||
}
|
||||
if(!begun)
|
||||
{
|
||||
args.emplace_back();
|
||||
begun = true;
|
||||
}
|
||||
args.back() += c;
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
return args;
|
||||
}
|
||||
|
||||
vector<string> SplitArguments(vector<string> strs)
|
||||
{
|
||||
vector<string> args;
|
||||
for(string str : strs)
|
||||
{
|
||||
vector<string> args1 = SplitArguments(str);
|
||||
args.insert(args.end(), args1.begin(), args1.end());
|
||||
}
|
||||
return args;
|
||||
vector<string> args;
|
||||
for(string str : strs)
|
||||
{
|
||||
vector<string> args1 = SplitArguments(str);
|
||||
args.insert(args.end(), args1.begin(), args1.end());
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -645,20 +645,20 @@ int main()
|
||||
|
||||
#if TARGET_CPU_68K && !TARGET_RT_MAC_CFM
|
||||
short& ROM85 = *(short*) 0x028E;
|
||||
Boolean is128KROM = (ROM85 > 0);
|
||||
Boolean hasWaitNextEvent = false;
|
||||
Boolean is128KROM = (ROM85 > 0);
|
||||
Boolean hasWaitNextEvent = false;
|
||||
Boolean hasGestalt = false;
|
||||
Boolean hasAppleEvents = false;
|
||||
hasIconUtils = false;
|
||||
hasColorQD = false;
|
||||
|
||||
if (is128KROM)
|
||||
{
|
||||
UniversalProcPtr trapUnimpl = GetToolTrapAddress(_Unimplemented);
|
||||
if (is128KROM)
|
||||
{
|
||||
UniversalProcPtr trapUnimpl = GetToolTrapAddress(_Unimplemented);
|
||||
UniversalProcPtr trapWaitNextEvent = GetToolTrapAddress(_WaitNextEvent);
|
||||
UniversalProcPtr trapGestalt = GetOSTrapAddress(_Gestalt);
|
||||
|
||||
hasWaitNextEvent = (trapWaitNextEvent != trapUnimpl);
|
||||
hasWaitNextEvent = (trapWaitNextEvent != trapUnimpl);
|
||||
hasGestalt = (trapGestalt != trapUnimpl);
|
||||
|
||||
if(hasGestalt)
|
||||
@@ -676,10 +676,10 @@ int main()
|
||||
err = Gestalt(gestaltStandardFileAttr, &response);
|
||||
hasSys7StdFile = err == noErr && (response & (1 << gestaltStandardFile58)) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#if !TARGET_API_MAC_CARBON
|
||||
const Boolean hasWaitNextEvent = true;
|
||||
const Boolean hasWaitNextEvent = true;
|
||||
#endif
|
||||
const Boolean hasGestalt = true;
|
||||
const Boolean hasAppleEvents = true;
|
||||
@@ -816,5 +816,5 @@ int main()
|
||||
}
|
||||
|
||||
WritePrefs();
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ void MacSerialStream::write(const void* p, size_t n)
|
||||
pb.ioParam.ioRefNum = outRefNum;
|
||||
pb.ioParam.ioBuffer = (Ptr)p;
|
||||
pb.ioParam.ioReqCount = n;
|
||||
/*OSErr err =*/ PBWriteSync(&pb);
|
||||
/*OSErr err =*/ PBWriteSync(&pb);
|
||||
}
|
||||
|
||||
void MacSerialStream::idle()
|
||||
|
||||
@@ -48,13 +48,13 @@ void MacTCPStream::startListening()
|
||||
readPB.ioCRefNum = refNum;
|
||||
readPB.tcpStream = tcpStream;
|
||||
|
||||
readPB.csCode = TCPPassiveOpen;
|
||||
readPB.ioResult = 1;
|
||||
readPB.csParam.open.ulpTimeoutValue = 5;// ###
|
||||
readPB.csParam.open.ulpTimeoutAction = 1;
|
||||
readPB.csParam.open.validityFlags = 0xC0;
|
||||
readPB.csParam.open.commandTimeoutValue = 0;
|
||||
readPB.csParam.open.localPort = 1984;
|
||||
readPB.csCode = TCPPassiveOpen;
|
||||
readPB.ioResult = 1;
|
||||
readPB.csParam.open.ulpTimeoutValue = 5;// ###
|
||||
readPB.csParam.open.ulpTimeoutAction = 1;
|
||||
readPB.csParam.open.validityFlags = 0xC0;
|
||||
readPB.csParam.open.commandTimeoutValue = 0;
|
||||
readPB.csParam.open.localPort = 1984;
|
||||
PBControlAsync((ParmBlkPtr)&readPB);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ MacTCPStream::~MacTCPStream()
|
||||
memset(&pb, 0, sizeof(pb));
|
||||
pb.ioCRefNum = refNum;
|
||||
pb.tcpStream = tcpStream;
|
||||
pb.csCode = TCPRelease;
|
||||
pb.csCode = TCPRelease;
|
||||
PBControlSync((ParmBlkPtr)&pb);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ OpenTptStream::~OpenTptStream()
|
||||
{
|
||||
endpoint->SetNonBlocking();
|
||||
if(connected)
|
||||
endpoint->SndDisconnect(&call);
|
||||
endpoint->SndDisconnect(&call);
|
||||
endpoint->Unbind();
|
||||
OTCloseProvider(endpoint);
|
||||
}
|
||||
|
||||
+283
-283
@@ -40,328 +40,328 @@ bool verboseFlag = false;
|
||||
|
||||
struct CFragMember
|
||||
{
|
||||
string name;
|
||||
uint32_t architecture;
|
||||
uint8_t usage;
|
||||
char *data;
|
||||
uint32_t length;
|
||||
|
||||
CFragMember() : architecture(0), usage(0), data(0), length(0) {}
|
||||
CFragMember(string n, uint32_t a, uint8_t u, char *d, uint32_t l)
|
||||
: name(n), architecture(a), usage(u), data(d), length(l)
|
||||
{
|
||||
}
|
||||
string name;
|
||||
uint32_t architecture;
|
||||
uint8_t usage;
|
||||
char *data;
|
||||
uint32_t length;
|
||||
|
||||
CFragMember() : architecture(0), usage(0), data(0), length(0) {}
|
||||
CFragMember(string n, uint32_t a, uint8_t u, char *d, uint32_t l)
|
||||
: name(n), architecture(a), usage(u), data(d), length(l)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void RunCommand(const char *command, std::vector<std::string> args)
|
||||
{
|
||||
std::vector<const char*> ptrs;
|
||||
ptrs.push_back(command);
|
||||
for(auto& s : args)
|
||||
ptrs.push_back(s.c_str());
|
||||
ptrs.push_back(NULL);
|
||||
std::vector<const char*> ptrs;
|
||||
ptrs.push_back(command);
|
||||
for(auto& s : args)
|
||||
ptrs.push_back(s.c_str());
|
||||
ptrs.push_back(NULL);
|
||||
|
||||
pid_t pid = fork();
|
||||
if(pid == -1)
|
||||
{
|
||||
perror(command);
|
||||
exit(1);
|
||||
}
|
||||
pid_t pid = fork();
|
||||
if(pid == -1)
|
||||
{
|
||||
perror(command);
|
||||
exit(1);
|
||||