mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-28 21:49:33 +00:00
Merge pull request #113 from autc04/r_68k_pc32
add support for R_68K_PC32 relocations (fixes #38)
This commit is contained in:
commit
f10344e316
@ -75,6 +75,10 @@ if(CMAKE_SYSTEM_NAME MATCHES Retro68)
|
||||
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)
|
||||
|
||||
|
||||
test(PCRel32.c PROPERTIES PASS_REGULAR_EXPRESSION "OK")
|
||||
target_compile_options(PCRel32 PRIVATE -march=68020)
|
||||
endif()
|
||||
|
||||
test(Exceptions.cc PROPERTIES PASS_REGULAR_EXPRESSION "OK")
|
||||
|
29
AutomatedTests/PCRel32.c
Normal file
29
AutomatedTests/PCRel32.c
Normal file
@ -0,0 +1,29 @@
|
||||
#include "Test.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
__attribute__((noinline)) static void* foo(size_t x)
|
||||
{
|
||||
return malloc(x);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if(*(short*)&foo != 0x60FF)
|
||||
{
|
||||
TEST_LOG_NO();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t offset = *(uint32_t*) ((char*)&foo + 2);
|
||||
if(((char*)&foo + 2) + offset != (char*)&malloc)
|
||||
{
|
||||
TEST_LOG_NO();
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *p = foo(42);
|
||||
strcpy(p, "OK");
|
||||
TestLog(p);
|
||||
free(p);
|
||||
return 0;
|
||||
}
|
@ -87,8 +87,8 @@ void TestLog(const char *str);
|
||||
#define TEST_LOG_NO() \
|
||||
do { \
|
||||
char no[3]; \
|
||||
no[0] = 'O'; \
|
||||
no[1] = 'K'; \
|
||||
no[0] = 'N'; \
|
||||
no[1] = 'O'; \
|
||||
no[2] = '\0'; \
|
||||
TEST_LOG_SIZED(no, 2); \
|
||||
} while(0)
|
||||
|
@ -44,26 +44,33 @@ std::string SerializeRelocsUncompressed(std::vector<RuntimeReloc> relocs)
|
||||
std::string SerializeRelocs(std::vector<RuntimeReloc> relocs)
|
||||
{
|
||||
std::ostringstream out;
|
||||
uint32_t offset = -1;
|
||||
|
||||
for(const auto& r : relocs)
|
||||
for(int relative = 0; relative <= 1; relative++)
|
||||
{
|
||||
uint32_t delta = r.offset - offset;
|
||||
offset = r.offset;
|
||||
uint32_t offset = -1;
|
||||
|
||||
uint32_t base = (uint32_t) r.base;
|
||||
|
||||
uint32_t encoded = (delta << 2) | base;
|
||||
|
||||
while(encoded >= 128)
|
||||
for(const auto& r : relocs)
|
||||
{
|
||||
byte(out, (encoded & 0x7F) | 0x80);
|
||||
encoded >>= 7;
|
||||
}
|
||||
byte(out, encoded);
|
||||
}
|
||||
if(r.relative == (bool)relative)
|
||||
{
|
||||
uint32_t delta = r.offset - offset;
|
||||
offset = r.offset;
|
||||
|
||||
byte(out, 0);
|
||||
uint32_t base = (uint32_t) r.base;
|
||||
|
||||
uint32_t encoded = (delta << 2) | base;
|
||||
|
||||
while(encoded >= 128)
|
||||
{
|
||||
byte(out, (encoded & 0x7F) | 0x80);
|
||||
encoded >>= 7;
|
||||
}
|
||||
byte(out, encoded);
|
||||
}
|
||||
}
|
||||
|
||||
byte(out, 0);
|
||||
}
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
@ -47,11 +47,11 @@ public:
|
||||
class RuntimeReloc
|
||||
{
|
||||
public:
|
||||
RelocBase base;
|
||||
uint32_t offset;
|
||||
RelocBase base = RelocBase::code;
|
||||
uint32_t offset = 0;
|
||||
bool relative = false;
|
||||
|
||||
RuntimeReloc() : base(RelocBase::code), offset(0) {}
|
||||
RuntimeReloc(RelocBase b, uint32_t o) : base(b), offset(o) {}
|
||||
RuntimeReloc(RelocBase b = RelocBase::code, uint32_t o = 0, bool r = false) : base(b), offset(o), relative(r) {}
|
||||
};
|
||||
|
||||
std::string SerializeRelocsUncompressed(std::vector<RuntimeReloc> relocs);
|
||||
|
@ -104,17 +104,20 @@ std::vector<RuntimeReloc> Section::GetRelocations(bool useOffsets)
|
||||
if(sym.sectionKind == SectionKind::undefined)
|
||||
continue;
|
||||
|
||||
uint32_t offset = rela.r_offset;
|
||||
if(useOffsets)
|
||||
offset -= shdr.sh_addr;
|
||||
|
||||
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;
|
||||
|
||||
//longword(out, offset | ((int)rela.relocBase << 24));
|
||||
outRelocs.emplace_back(rela.relocBase, offset);
|
||||
}
|
||||
|
||||
if(GELF_R_TYPE(rela.r_info) == R_68K_PC32
|
||||
&& sym.st_shndx != idx)
|
||||
{
|
||||
outRelocs.emplace_back(rela.relocBase, offset, true);
|
||||
}
|
||||
}
|
||||
|
||||
return outRelocs;
|
||||
@ -154,7 +157,7 @@ void Section::FixRelocs(bool allowDirectCodeRefs)
|
||||
{
|
||||
for(Reloc& rela : relocs)
|
||||
{
|
||||
if(GELF_R_TYPE(rela.r_info) != R_68K_32)
|
||||
if(GELF_R_TYPE(rela.r_info) != R_68K_32 && GELF_R_TYPE(rela.r_info) != R_68K_PC32)
|
||||
continue;
|
||||
|
||||
int symidx = GELF_R_SYM(rela.r_info);
|
||||
@ -165,6 +168,9 @@ void Section::FixRelocs(bool allowDirectCodeRefs)
|
||||
if(sym.sectionKind == SectionKind::undefined)
|
||||
continue;
|
||||
|
||||
if(GELF_R_TYPE(rela.r_info) == R_68K_PC32 && sym.st_shndx == idx)
|
||||
continue;
|
||||
|
||||
RelocBase relocBase;
|
||||
switch(sym.sectionKind)
|
||||
{
|
||||
|
@ -111,31 +111,39 @@ void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, ui
|
||||
void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, uint32_t displacements[])
|
||||
{
|
||||
uint8_t *reloc = (uint8_t*) relocations;
|
||||
uint8_t *addrPtr = base - 1;
|
||||
while(*reloc)
|
||||
for(int relative = 0; relative <= 1; relative++)
|
||||
{
|
||||
// read an uleb128 value
|
||||
uint32_t val = 0;
|
||||
uint8_t b;
|
||||
int i = 0;
|
||||
do
|
||||
uint8_t *addrPtr = base - 1;
|
||||
while(*reloc)
|
||||
{
|
||||
b = *reloc++;
|
||||
val |= (b & 0x7F) << i;
|
||||
i += 7;
|
||||
} while(b & 0x80);
|
||||
// read an uleb128 value
|
||||
uint32_t val = 0;
|
||||
uint8_t b;
|
||||
int i = 0;
|
||||
do
|
||||
{
|
||||
b = *reloc++;
|
||||
val |= (b & 0x7F) << i;
|
||||
i += 7;
|
||||
} while(b & 0x80);
|
||||
|
||||
// ... which consists of an offset and the displacement base index
|
||||
// the offset is relative to the previous relocation, or to base-1
|
||||
addrPtr += val >> 2;
|
||||
uint8_t kind = val & 0x3;
|
||||
// ... which consists of an offset and the displacement base index
|
||||
// the offset is relative to the previous relocation, or to base-1
|
||||
addrPtr += val >> 2;
|
||||
uint8_t kind = val & 0x3;
|
||||
|
||||
assert(addrPtr >= base);
|
||||
assert(addrPtr <= base + size - 4);
|
||||
assert(addrPtr >= base);
|
||||
assert(addrPtr <= base + size - 4);
|
||||
|
||||
uint8_t *addr = (uint8_t*) READ_UNALIGNED_LONGWORD(addrPtr);
|
||||
addr += displacements[kind];
|
||||
WRITE_UNALIGNED_LONGWORD(addrPtr, (uint32_t) addr);
|
||||
uint32_t addr = READ_UNALIGNED_LONGWORD(addrPtr);
|
||||
addr += displacements[kind];
|
||||
if(relative)
|
||||
addr -= (uint32_t) addrPtr;
|
||||
|
||||
WRITE_UNALIGNED_LONGWORD(addrPtr, addr);
|
||||
}
|
||||
|
||||
reloc++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -237,8 +245,8 @@ void Retro68Relocate()
|
||||
// this crashes with some implementations of the memory manager
|
||||
// if we guess wrong, so let's don't for now.
|
||||
// Therefore, all Retro68-compiled code resources have to be locked,
|
||||
// or they might get relocated as soon as the global variables are
|
||||
// relocated below.
|
||||
// or they might get moved as soon as the global variables are
|
||||
// allocated below.
|
||||
// TODO: figure out a way to reliably determine the offset from the
|
||||
// start of the resource (to pass it from Elf2Mac, probably).
|
||||
|
||||
@ -270,11 +278,9 @@ void Retro68Relocate()
|
||||
}
|
||||
|
||||
/*
|
||||
Relocation records consist of 4 bytes each.
|
||||
The lower three bytes are the offset of the longword being relocated.
|
||||
the first byte of each longword specifies which segment
|
||||
the relocation leads to; the corresponding displacements are taken
|
||||
from the following table:
|
||||
Relocation records logically consist of
|
||||
* the offset of the longword being relocated
|
||||
* the displacement base, specified as an index into the following table:
|
||||
*/
|
||||
long displacements[4] = {
|
||||
displacement, // code
|
||||
@ -307,22 +313,6 @@ void Retro68Relocate()
|
||||
RealApplyRelocations(base, relocatableSize, reloc, displacements);
|
||||
|
||||
// We're basically done.
|
||||
/*// Now check whether we're on 68040 or later and need to flush the cache.
|
||||
// only do this if SysEnvirons is available.
|
||||
// if SysEnvirons is not available, that means we're on an old System or ROM
|
||||
// and likely not using a 68040, so we won't do this
|
||||
if (hasSysEnvirons)
|
||||
{
|
||||
SysEnvRec env;
|
||||
|
||||
env.processor = 0;
|
||||
SysEnvirons(0, &env);
|
||||
if(env.processor >= env68040)
|
||||
{
|
||||
rState->needFlushCache = true;
|
||||
FlushCodeCache();
|
||||
}
|
||||
}*/
|
||||
if(hasFlushCodeCache)
|
||||
FlushCodeCache();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user