Add nitool option to compile system libs with unique default base address
authorGleb Balykov <g.balykov@samsung.com>
Fri, 28 Jun 2019 12:55:38 +0000 (15:55 +0300)
committer조웅석/Common Platform Lab(SR)/Principal Engineer/삼성전자 <ws77.cho@samsung.com>
Tue, 16 Jul 2019 05:05:17 +0000 (14:05 +0900)
NativeLauncher/CMakeLists.txt
NativeLauncher/inc/ni_common.h
NativeLauncher/inc/utils.h
NativeLauncher/tool/ni_common.cc
NativeLauncher/tool/nitool.cc
NativeLauncher/util/utils.cc
packaging/dotnet-launcher.spec

index cc70ba6..9773988 100644 (file)
@@ -42,6 +42,10 @@ IF(DEFINED USE_DEFAULT_BASE_ADDR)
     SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DUSE_DEFAULT_BASE_ADDR")
 ENDIF(DEFINED USE_DEFAULT_BASE_ADDR)
 
+IF(DEFINED UNIQUE_DEFAULT_BASE_ADDR_SUPPORT)
+    SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DUNIQUE_DEFAULT_BASE_ADDR_SUPPORT")
+ENDIF(DEFINED UNIQUE_DEFAULT_BASE_ADDR_SUPPORT)
+
 OPTION(NOT_USE_FUNCTION "Remove build warning" OFF)
 IF(NOT_USE_FUNCTION)
     ADD_DEFINITIONS("-DNOT_USE_FUNCTION")
index 3f3de82..3c43a57 100644 (file)
@@ -56,7 +56,7 @@ void finalizeNICommon();
 /**
  * @brief create native images (NI file) for Platform DLLs (.NETCore + TizenFX)
  */
-void createNiPlatform(bool enableR2R);
+void createNiPlatform(bool enableR2R, bool doGenUniqueBaseSystem);
 
 /**
  * @brief create native image for specific dll with file path.
@@ -64,7 +64,7 @@ void createNiPlatform(bool enableR2R);
  * @param[i] enableR2R enable ready-to-run mode
  * @return ni_error_e
  */
-ni_error_e createNiDll(const std::string& dllPath, bool enableR2R);
+ni_error_e createNiDll(const std::string& dllPath, bool enableR2R, bool doGenUniqueBaseSystem);
 
 /**
  * @brief create native images with files under specific directory.
@@ -73,7 +73,7 @@ ni_error_e createNiDll(const std::string& dllPath, bool enableR2R);
  * @param[i] enableR2R enable ready-to-run mode
  * @param[i] isAppNI if you want to create ni files under nativeImage directory, set it true
  */
-void createNiUnderDirs(const std::string rootPaths[], int count, bool enableR2R, bool isAppNI = false);
+void createNiUnderDirs(const std::string rootPaths[], int count, bool enableR2R, bool doGenUniqueBaseSystem, bool isAppNI = false);
 
 /**
  * @brief create native images for specific package. (All DLLs)
index f1d4306..c8843b5 100644 (file)
@@ -91,6 +91,13 @@ void splitPath(const std::string& path, std::vector<std::string>& out);
 bool isFileExist(const std::string& path);
 
 /**
+ * @brief get file size
+ * @param[in] source path
+ * @return size of file
+ */
+uintptr_t getFileSize(const std::string& path);
+
+/**
  * @brief check the file is managed assembly or not.
  * @param[in] file path
  * @return return true when the file is managed assembly.
index 182720d..fd366f0 100644 (file)
 #error "CROSSGEN_PATH is missed"
 #endif
 
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+#define SYSTEM_BASE_FILE "/usr/share/dotnet.tizen/system.base.addr.txt"
+#define DEFAULT_BASE_ADDR_START 0x1000000
+#endif
+
 #define __XSTR(x) #x
 #define __STR(x) __XSTR(x)
 static const char* __CROSSGEN_PATH = __STR(CROSSGEN_PATH);
@@ -134,7 +139,88 @@ static bool niExist(const std::string& path)
        return false;
 }
 
-static ni_error_e crossgen(const std::string& dllPath, const std::string& appPath, bool enableR2R, bool isAppNI = false)
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+// Get next base address to be used for system ni image from file
+// SYSTEM_BASE_FILE should be checked for existance before calling this function
+static uintptr_t getNextBaseAddrFromFile()
+{
+       FILE *pFile = fopen(SYSTEM_BASE_FILE, "r");
+       if (pFile == NULL) {
+               fprintf(stderr, "Failed to open " SYSTEM_BASE_FILE "\n");
+               return 0;
+       }
+
+       uintptr_t addr = 0;
+       uintptr_t size = 0;
+
+       while (fscanf(pFile, "%u %u", &addr, &size) != EOF) {
+       }
+
+       fclose(pFile);
+
+       return addr + size;
+}
+
+// Get next base address to be used for system ni image
+static uintptr_t getNextBaseAddr()
+{
+       uintptr_t baseAddr = 0;
+
+       if (!isFileExist(SYSTEM_BASE_FILE)) {
+               // This is the starting address for all default base addresses
+               baseAddr = DEFAULT_BASE_ADDR_START;
+       } else {
+               baseAddr = getNextBaseAddrFromFile();
+
+               // Round to a multple of 64K (see ZapImage::CalculateZapBaseAddress in CoreCLR)
+               uintptr_t BASE_ADDRESS_ALIGNMENT = 0xffff;
+               baseAddr = (baseAddr + BASE_ADDRESS_ALIGNMENT) & ~BASE_ADDRESS_ALIGNMENT;
+       }
+
+       return baseAddr;
+}
+
+// Save base address of system ni image to file
+static void updateBaseAddrFile(const std::string &dllPath, uintptr_t baseAddr)
+{
+       std::string absNiPath = getNiFilePath(dllPath);
+       if (absNiPath.empty()) {
+               fprintf(stderr, "Failed to get ni file path for %s\n", dllPath.c_str());
+               return;
+       }
+
+       uintptr_t niSize = getFileSize(absNiPath);
+       if (niSize == 0) {
+               fprintf(stderr, "File %s doesn't exist\n", absNiPath.c_str());
+               return;
+       }
+
+       // Write new entry to the file
+       FILE *pFile = fopen(SYSTEM_BASE_FILE, "a");
+       if (pFile == NULL) {
+               fprintf(stderr, "Failed to open " SYSTEM_BASE_FILE "\n");
+               return;
+       }
+
+       fprintf(pFile, "%u %u\n", baseAddr, niSize);
+       fclose(pFile);
+}
+
+// check if dll is listed in TPA
+static bool isTPADll(const std::string &dllPath)
+{
+       std::string absDllPath = absolutePath(dllPath);
+
+       if (__tpa.find(absDllPath) != std::string::npos) {
+               return true;
+       }
+
+       return false;
+}
+#endif
+
+// baseAddr should be checked in file before getting here
+static ni_error_e crossgen(const std::string& dllPath, const std::string& appPath, bool enableR2R, uintptr_t baseAddr = 0, bool isAppNI = false)
 {
        if (!isFileExist(dllPath)) {
                fprintf(stderr, "dll file is not exist : %s\n", dllPath.c_str());
@@ -193,6 +279,13 @@ static ni_error_e crossgen(const std::string& dllPath, const std::string& appPat
                        argv.push_back("/FragileNonVersionable");
                }
 
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+               if (baseAddr != 0) {
+                       argv.push_back("/BaseAddress");
+                       argv.push_back(std::to_string(baseAddr).c_str());
+               }
+#endif
+
                argv.push_back("/App_Paths");
                std::string absAppPath;
                if (!appPath.empty()) {
@@ -246,14 +339,28 @@ static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
        return 0;
 }
 
-static void createCoreLibNI(bool enableR2R)
+static void createCoreLibNI(bool enableR2R, bool doGenUniqueBaseSystem)
 {
        std::string coreLib = concatPath(getRuntimeDir(), "System.Private.CoreLib.dll");
        std::string niCoreLib = concatPath(getRuntimeDir(), "System.Private.CoreLib.ni.dll");
        std::string coreLibBackup = concatPath(getRuntimeDir(), "System.Private.CoreLib.dll.Backup");
 
        if (!isFileExist(coreLibBackup)) {
-               if (!crossgen(coreLib, std::string(), enableR2R)) {
+               uintptr_t baseAddr = 0;
+
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+               if (doGenUniqueBaseSystem) {
+                       baseAddr = getNextBaseAddr();
+               }
+#endif
+
+               if (!crossgen(coreLib, std::string(), enableR2R, baseAddr)) {
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+                       if (doGenUniqueBaseSystem && baseAddr != 0) {
+                               updateBaseAddrFile(coreLib, baseAddr);
+                       }
+#endif
+
                        if (rename(coreLib.c_str(), coreLibBackup.c_str())) {
                                fprintf(stderr, "Failed to rename System.Private.CoreLib.dll\n");
                        }
@@ -306,27 +413,43 @@ void finalizeNICommon()
 }
 
 
-void createNiPlatform(bool enableR2R)
+void createNiPlatform(bool enableR2R, bool doGenUniqueBaseSystem)
 {
        const std::string platformDirs[] = {getRuntimeDir(), getTizenFXDir()};
-       createNiUnderDirs(platformDirs, 2, enableR2R);
+       createNiUnderDirs(platformDirs, 2, enableR2R, doGenUniqueBaseSystem);
 }
 
-ni_error_e createNiDll(const std::string& dllPath, bool enableR2R)
+ni_error_e createNiDll(const std::string& dllPath, bool enableR2R, bool doGenUniqueBaseSystem)
 {
-       createCoreLibNI(enableR2R);
+       createCoreLibNI(enableR2R, doGenUniqueBaseSystem);
        // System.Private.CoreLib.dll is generated in the createCoreLibNI function.
        // Skip if input dll is System.Private.CoreLib.dll
        if (dllPath.find("System.Private.CoreLib.dll") != std::string::npos) {
                return NI_ERROR_NONE;
        }
 
-       return crossgen(dllPath, std::string(), enableR2R);
+       uintptr_t baseAddr = 0;
+
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+       if (doGenUniqueBaseSystem && isTPADll(dllPath)) {
+               baseAddr = getNextBaseAddr();
+       }
+#endif
+
+       ni_error_e status = crossgen(dllPath, std::string(), enableR2R, baseAddr);
+
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+       if (doGenUniqueBaseSystem && baseAddr != 0) {
+               updateBaseAddrFile(dllPath, baseAddr);
+       }
+#endif
+
+       return status;
 }
 
-void createNiUnderDirs(const std::string rootPaths[], int count, bool enableR2R, bool isAppNI)
+void createNiUnderDirs(const std::string rootPaths[], int count, bool enableR2R, bool doGenUniqueBaseSystem, bool isAppNI)
 {
-       createCoreLibNI(enableR2R);
+       createCoreLibNI(enableR2R, doGenUniqueBaseSystem);
 
        std::string appPaths;
        for (int i = 0; i < count; i++) {
@@ -337,8 +460,22 @@ void createNiUnderDirs(const std::string rootPaths[], int count, bool enableR2R,
        if (appPaths.back() == ':')
                appPaths.pop_back();
 
-       auto convert = [&appPaths, enableR2R, isAppNI](const std::string& path, const char* name) {
-               if (!crossgen(path, appPaths.c_str(), enableR2R, isAppNI)) {
+       auto convert = [&appPaths, enableR2R, doGenUniqueBaseSystem, isAppNI](const std::string& path, const char* name) {
+               uintptr_t baseAddr = 0;
+
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+               if (doGenUniqueBaseSystem && !isAppNI && isTPADll(path)) {
+                       baseAddr = getNextBaseAddr();
+               }
+#endif
+
+               if (!crossgen(path, appPaths.c_str(), enableR2R, baseAddr, isAppNI)) {
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+                       if (doGenUniqueBaseSystem && !isAppNI && baseAddr != 0) {
+                               updateBaseAddrFile(path, baseAddr);
+                       }
+#endif
+
                        waitInterval();
                }
        };
@@ -361,7 +498,7 @@ ni_error_e createNiUnderPkgRoot(const std::string& pkgId, bool enableR2R)
        std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR);
        std::string paths[] = {binDir, libDir, tacDir};
 
-       createNiUnderDirs(paths, 3, enableR2R, true);
+       createNiUnderDirs(paths, 3, enableR2R, false, true);
 
        return NI_ERROR_NONE;
 }
@@ -379,7 +516,7 @@ ni_error_e createNiDllUnderPkgRoot(const std::string& pkgId, const std::string&
        std::string appTAC = concatPath(binDir, ".TAC.Release");
        std::string paths = binDir + ":" + libDir + ":" + appTAC;
 
-       return crossgen(dllPath, paths, enableR2R, true);
+       return crossgen(dllPath, paths, enableR2R, 0, true);
 }
 
 void removeNiPlatform()
@@ -391,6 +528,14 @@ void removeNiPlatform()
                return;
        }
 
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+       if (isFileExist(SYSTEM_BASE_FILE)) {
+               if (remove(SYSTEM_BASE_FILE)) {
+                       fprintf(stderr, "Failed to remove " SYSTEM_BASE_FILE " file\n");
+               }
+       }
+#endif
+
        if (remove(coreLib.c_str())) {
                fprintf(stderr, "Failed to remove System.Private.CoreLib native image file\n");
        }
index 9647369..39aedda 100644 (file)
@@ -47,6 +47,9 @@ static void help(const char *argv0)
                "       --reset-system      - Remove System NI files\n"
                "       --reset-pkg         - Remove App NI files\n"
                "       --regen-all-app     - Re-generate All App NI files\n"
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+               "       --gen-unique-baddr-system - Generate unique base addr for dll\n"
+#endif
                "\n"
                "Example:\n"
                "1. Create native image for dlls and exes under platform directories\n"
@@ -56,8 +59,13 @@ static void help(const char *argv0)
                "3. Create native image under the package's bin and lib directory\n"
                "   # %s --pkg org.tizen.FormsGallery\n"
                "4. Regenerate native images for all installed .net packages with ready-to-run option\n"
-               "   # %s --r2r --regen-all-app\n\n";
-       printf(helpDesc, argv0, argv0, argv0, argv0, argv0);
+               "   # %s --r2r --regen-all-app\n\n"
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+               "5. Generate unique base addr for system dll\n"
+               "   # %s --gen-unique-baddr-system --dll /usr/bin/Tizen.Runtime.dll\n\n"
+#endif
+               ;
+       printf(helpDesc, argv0, argv0, argv0, argv0, argv0, argv0);
 }
 
 int main(int argc, char* argv[])
@@ -69,6 +77,8 @@ int main(int argc, char* argv[])
        bool enableR2R = false;
        bool pkgDllMode = false;
 
+       bool doGenUniqueBaseSystem = false;
+
        NiCommonOption option = {std::string(), std::string(), std::string()};
        if (initNICommon(&option) != NI_ERROR_NONE) {
                fprintf(stderr, "Fail to initialize NI Common\n");
@@ -79,11 +89,19 @@ int main(int argc, char* argv[])
                enableR2R = true;
        }
 
+       if (cmdOptionExists(argv, argv+argc, "--gen-unique-baddr-system")) {
+#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
+               doGenUniqueBaseSystem = true;
+#else
+               fprintf(stderr, "--gen-unique-baddr-system is not supported\n");
+#endif
+       }
+
        if (cmdOptionExists(argv, argv+argc, "--help")) {
                help(argv[0]);
                return 0;
        } else if (cmdOptionExists(argv, argv+argc, "--system")) {
-               createNiPlatform(enableR2R);
+               createNiPlatform(enableR2R, doGenUniqueBaseSystem);
                return 0;
        } else if (cmdOptionExists(argv, argv+argc, "--dll")) {
                dllMode = true;
@@ -156,7 +174,7 @@ int main(int argc, char* argv[])
                // donot return error code for generation failure.
                // we have to run crossgen for all input dlls.
                for (const std::string dll : args) {
-                       int ret = createNiDll(dll, enableR2R);
+                       int ret = createNiDll(dll, enableR2R, doGenUniqueBaseSystem);
                        if (ret == NI_ERROR_ALREADY_EXIST) {
                                // skip for already exist case
                        } else if (ret != NI_ERROR_NONE) {
@@ -164,7 +182,7 @@ int main(int argc, char* argv[])
                        }
                }
        } else if (dirMode) {
-               createNiUnderDirs(args.data(), args.size(), enableR2R);
+               createNiUnderDirs(args.data(), args.size(), enableR2R, doGenUniqueBaseSystem);
        }
 
        return 0;
index a33eec2..ee22d0a 100644 (file)
@@ -158,6 +158,17 @@ bool isFileExist(const std::string& path)
        return stat(path.c_str(), &sb) == 0;
 }
 
+uintptr_t getFileSize(const std::string& path)
+{
+       struct stat sb;
+
+       if (stat(path.c_str(), &sb) == 0) {
+               return sb.st_size;
+       }
+
+       return 0;
+}
+
 std::string stripNiDLL(const std::string& path)
 {
        std::string niPath(path);
@@ -477,4 +488,4 @@ bool removeAll(const bf::path& path) {
                return false;
        }
        return true;
-}
\ No newline at end of file
+}
index cb67185..3277e7f 100644 (file)
@@ -113,6 +113,9 @@ cmake \
 %if 0%{?use_default_base_addr}
        -DUSE_DEFAULT_BASE_ADDR="" \
 %endif
+%if 0%{?default_base_nitool}
+       -DUNIQUE_DEFAULT_BASE_ADDR_SUPPORT="" \
+%endif
        NativeLauncher
 
 make %{?jobs:-j%jobs} VERBOSE=1
@@ -134,7 +137,11 @@ install -m 0644 %{name}.conf %{buildroot}/etc/tmpfiles.d/%{name}.conf
 %post
 mkdir -p /opt/etc/skel/.dotnet
 chsmack -t -a User::App::Shared /opt/etc/skel/.dotnet
+%if 0%{?default_base_nitool}
+%{_bindir}/nitool --gen-unique-baddr-system --dll %{_runtime_dir}/System.Private.CoreLib.dll
+%else
 %{_bindir}/nitool --dll %{_runtime_dir}/System.Private.CoreLib.dll
+%endif
 
 %files
 %manifest dotnet-launcher.manifest