[Scummvm-git-logs] scummvm master -> 3f45f772699dde897bb719f9263f3e5220fdda3b

bgK bastien.bouclet at gmail.com
Thu Aug 27 19:17:31 UTC 2020


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
55db1210eb 3DS: Set a Virtual Memory Address when linking the plugins
3f45f77269 BACKENDS: Fix crash when all the plugins fail to load


Commit: 55db1210eb578bc5cbdd66edc2c054e26f2d9464
    https://github.com/scummvm/scummvm/commit/55db1210eb578bc5cbdd66edc2c054e26f2d9464
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-08-27T21:14:07+02:00

Commit Message:
3DS: Set a Virtual Memory Address when linking the plugins

Setting the base address for the plugin elf files high in memory forces
the linker to generate veneers to turn relative jumps to the main binary
into absolute jumps. This removes the need to allocate the plugins near
the the main binary in the program address space. This also removes the
need to handle the R_ARM_CALL and R_ARM_JUMP24 relocation types.

Fixes #11555.

Changed paths:
    backends/plugins/3ds/3ds-provider.cpp
    backends/plugins/3ds/plugin.ld
    backends/plugins/elf/arm-loader.cpp
    backends/plugins/elf/elf-loader.cpp


diff --git a/backends/plugins/3ds/3ds-provider.cpp b/backends/plugins/3ds/3ds-provider.cpp
index 352e981080..812f313459 100644
--- a/backends/plugins/3ds/3ds-provider.cpp
+++ b/backends/plugins/3ds/3ds-provider.cpp
@@ -39,12 +39,6 @@ static uint32 alignUp(uint32 ptr, uint32 align) {
 }
 
 class CTRDLObject : public ARMDLObject {
-public:
-	CTRDLObject():
-			ARMDLObject(),
-			_segmentHeapAddress(0) {
-	}
-
 protected:
 	static const uint32 kPageSize = 0x1000;
 
@@ -70,54 +64,6 @@ protected:
 		svcControlProcessMemory(currentHandle, (uint32)ptr, 0, len, MEMOP_PROT, ctrFlags);
 		svcCloseHandle(currentHandle);
 	}
-
-	void *allocateMemory(uint32 align, uint32 size) override {
-		assert(!_segmentHeapAddress); // At the moment we can only load a single segment
-
-		_segmentHeapAddress = (uint32)ARMDLObject::allocateMemory(align, size);
-		if (!_segmentHeapAddress) {
-			return nullptr;
-		}
-
-		size = alignUp(size, kPageSize);
-
-		// The plugin needs to be loaded near the main executable for PC-relative calls
-		// to resolve. The segment is allocated on the heap which not in the +/-32 MB
-		// range of the main executable. So here we map the segment address in the heap
-		// to a virtual address just after the main executable.
-		uint32 segmentNearAddress = alignUp((uint32)&__end__, kPageSize) + kPageSize;
-
-		Handle currentHandle;
-		svcDuplicateHandle(&currentHandle, CUR_PROCESS_HANDLE);
-		Result mapResult = svcControlProcessMemory(currentHandle, segmentNearAddress, _segmentHeapAddress, size, MEMOP_MAP, MemPerm(MEMPERM_READ | MEMPERM_WRITE));
-		svcCloseHandle(currentHandle);
-
-		if (mapResult != 0) {
-			warning("elfloader: unable to map segment memory (%x) near the excutable (%x)", _segmentHeapAddress, segmentNearAddress);
-
-			ARMDLObject::deallocateMemory((void *)_segmentHeapAddress, size);
-			_segmentHeapAddress = 0;
-			return nullptr;
-		}
-
-		return (void *)segmentNearAddress;
-	}
-
-	void deallocateMemory(void *ptr, uint32 size) override {
-		assert(_segmentHeapAddress);
-
-		uint32 alignedSize = alignUp(size, kPageSize);
-
-		Handle currentHandle;
-		svcDuplicateHandle(&currentHandle, CUR_PROCESS_HANDLE);
-		svcControlProcessMemory(currentHandle, (uint32)ptr, _segmentHeapAddress, alignedSize, MEMOP_UNMAP, MemPerm(MEMPERM_READ | MEMPERM_WRITE));
-		svcCloseHandle(currentHandle);
-
-		ARMDLObject::deallocateMemory((void *)_segmentHeapAddress, size);
-
-		_segmentHeapAddress = 0;
-	}
-
 };
 
 Plugin *CTRPluginProvider::createPlugin(const Common::FSNode &node) const {
diff --git a/backends/plugins/3ds/plugin.ld b/backends/plugins/3ds/plugin.ld
index ae83a7ac2e..0e8ef57d9d 100644
--- a/backends/plugins/3ds/plugin.ld
+++ b/backends/plugins/3ds/plugin.ld
@@ -12,7 +12,10 @@ SECTIONS
 {
 	/* =========== CODE section =========== */
 
-	. = 0;
+	/* Start the output high in memory so PC-relative jumps from the plugin
+	    to the main binary cannot reach, to force the linker to generate
+	    veneers converting the relative jumps to absolute jumps */
+	. = 0x8000000;
 
 	.text ALIGN(0x1000) :
 	{
diff --git a/backends/plugins/elf/arm-loader.cpp b/backends/plugins/elf/arm-loader.cpp
index 3bbb5b2ee5..144d19d2ad 100644
--- a/backends/plugins/elf/arm-loader.cpp
+++ b/backends/plugins/elf/arm-loader.cpp
@@ -57,10 +57,10 @@ bool ARMDLObject::relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment)
 		// Get the symbol this relocation entry is referring to
 		Elf32_Sym *sym = _symtab + (REL_INDEX(rel[i].r_info));
 
-		// Get the target instruction in the code. TODO: repect _segmentVMA
-		uint32 *target = (uint32 *)((byte *)relSegment + rel[i].r_offset);
+		// Get the target instruction in the code.
+		uint32 *target = (uint32 *)((byte *)relSegment + rel[i].r_offset - _segmentVMA);
 
-		uint32 origTarget = *target;	//Save for debugging
+//		uint32 origTarget = *target;	//Save for debugging
 
 		// Act differently based on the type of relocation
 		switch (REL_TYPE(rel[i].r_info)) {
@@ -68,51 +68,24 @@ bool ARMDLObject::relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment)
 		case R_ARM_TARGET1:
 			if (sym->st_shndx < SHN_LOPROC) {			// Only shift for plugin section.
 				a = *target;							// Get full 32 bits of addend
-				relocation = a + Elf32_Addr(_segment);	// Shift by main offset
+				relocation = a - _segmentVMA + Elf32_Addr(_segment);	// Shift by main offset
 
 				*target = relocation;
 
-				debug(8, "elfloader: R_ARM_ABS32: i=%d, a=%x, origTarget=%x, target=%x", i, a, origTarget, *target);
+//				debug(8, "elfloader: R_ARM_ABS32: i=%d, a=%x, origTarget=%x, target=%x", i, a, origTarget, *target);
 			}
 			break;
 
 		case R_ARM_THM_CALL:
-			debug(8, "elfloader: R_ARM_THM_CALL: PC-relative jump, ld takes care of necessary relocation work for us.");
+//			debug(8, "elfloader: R_ARM_THM_CALL: PC-relative jump, ld takes care of necessary relocation work for us.");
 			break;
 
 		case R_ARM_CALL:
 		case R_ARM_JUMP24:
-			if (sym->st_shndx == SHN_ABS) { // Absolute symbols used in PC-relative instructions need to be relocated
-				// Extract the PC offset from the instruction
-				int32 pcOffset = *target;
-				pcOffset = (pcOffset & 0x00ffffff) << 2;
-
-				if (pcOffset & 0x02000000)
-					pcOffset -= 0x04000000;
-
-				// Shift by the segment offset
-				pcOffset -= Elf32_Addr(_segment);
-
-				// Check the relocated offset is valid for the instruction
-				if (pcOffset <= (int32)0xfe000000 ||
-					pcOffset >= (int32)0x02000000) {
-					warning("elfloader: R_ARM_CALL/R_ARM_JUMP24: Out of range relocation i=%d, target=%p, pcOffset=%d", i, target, pcOffset);
-					free(rel);
-					return false;
-				}
-
-				// Put the relocated offset back in the instruction
-				pcOffset >>= 2;
-				pcOffset &= 0x00ffffff;
-
-				*target &= (uint32)0xff000000;
-				*target |= (uint32)pcOffset;
-
-				debug(8, "elfloader: R_ARM_CALL/R_ARM_JUMP24: i=%d, origTarget=%x, target=%x", i, origTarget, *target);
-			}
+//			debug(8, "elfloader: R_ARM_CALL/R_ARM_JUMP24: PC-relative jump, ld takes care of necessary relocation work for us.");
 			break;
 		case R_ARM_V4BX:
-			debug(8, "elfloader: R_ARM_V4BX: No relocation calculation necessary.");
+//			debug(8, "elfloader: R_ARM_V4BX: No relocation calculation necessary.");
 			break;
 
 		default:
diff --git a/backends/plugins/elf/elf-loader.cpp b/backends/plugins/elf/elf-loader.cpp
index 39f1f7dfa5..d2e418a25f 100644
--- a/backends/plugins/elf/elf-loader.cpp
+++ b/backends/plugins/elf/elf-loader.cpp
@@ -311,6 +311,9 @@ void DLObject::relocateSymbols(ptrdiff_t offset) {
 	for (uint32 c = _symbol_cnt; c--; s++) {
 		// Make sure we don't relocate special valued symbols
 		if (s->st_shndx < SHN_LOPROC) {
+			if (s->st_value < _segmentVMA)
+				s->st_value = _segmentVMA;	// deal with symbols referring to sections, which start before the VMA
+
 			s->st_value += offset;
 
 			if (s->st_value < Elf32_Addr(_segment) ||


Commit: 3f45f772699dde897bb719f9263f3e5220fdda3b
    https://github.com/scummvm/scummvm/commit/3f45f772699dde897bb719f9263f3e5220fdda3b
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-08-27T21:14:07+02:00

Commit Message:
BACKENDS: Fix crash when all the plugins fail to load

Changed paths:
    base/plugins.cpp


diff --git a/base/plugins.cpp b/base/plugins.cpp
index 9e1445b059..1429fc2a92 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -361,7 +361,7 @@ void PluginManagerUncached::loadFirstPlugin() {
 bool PluginManagerUncached::loadNextPlugin() {
 	unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
 
-	if (!_currentPlugin)
+	if (!_currentPlugin || _currentPlugin == _allEnginePlugins.end())
 		return false;
 
 	for (++_currentPlugin; _currentPlugin != _allEnginePlugins.end(); ++_currentPlugin) {




More information about the Scummvm-git-logs mailing list