天天看點

LLVM JIT finalizeObject失敗或getFunctionAddress失敗探究

環境:windows llvm5.0.1

代碼:

#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include <llvm/IRReader/IRReader.h>
#include <llvm/Support/SourceMgr.h>
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/TargetSelect.h"
#include <llvm/Support/MemoryBuffer.h>
#include "llvm/Support/raw_ostream.h"
#include <llvm/Support/DynamicLibrary.h>
#include "llvm/Support/Debug.h"


#include <cctype>
#include <cstdio>
#include <map>
#include <string>
#include <vector>
#include <stdlib.h>
#include <iostream>
using namespace llvm;
using namespace std;
static LLVMContext *context;
typedef void(*func_type)(...);

int main(int argc, char* argv[]) {

	InitializeNativeTarget();
	InitializeNativeTargetAsmPrinter();
	InitializeNativeTargetAsmParser();

	RTDyldMemoryManager* RTDyldMM = NULL;
	
	context = new LLVMContext();
	SMDiagnostic *smd = new SMDiagnostic();
	static unique_ptr<Module> Owner = llvm::parseIRFile("external.bc", *smd, *context);
	//std::unique_ptr<Module> Owner = llvm::make_unique<Module>("test", *context);
	Module *module = Owner.get();
	std::string ErrStr;
	RTDyldMM = new SectionMemoryManager();
	ExecutionEngine *executionEngine = EngineBuilder(std::move(Owner))
		.setEngineKind(EngineKind::JIT)
		.setErrorStr(&ErrStr)
		.setVerifyModules(true)
		.setMCJITMemoryManager(std::unique_ptr<RTDyldMemoryManager>(RTDyldMM))
		.setOptLevel(CodeGenOpt::Default)
		.create();

	if (!executionEngine) {
		exit(1);
	}
	executionEngine->finalizeObject();

	void *func = executionEngine->getPointerToFunction(module->getFunction("sayhello"));
//	uint64_t func = executionEngine->getFunctionAddress("islower");
	func_type f = (func_type)func;
	f();

	system("pause");
	return 0;
}
           

遇到的問題:

finalizeObject失敗,嘗試使用getFunctionAddress也失敗,調用getFunctionAddress方法時會預設調用finalizeObject方法。

當注釋掉finalizeObject方法時,出現如下錯誤:

LLVM JIT finalizeObject失敗或getFunctionAddress失敗探究

 即調用external.bc中的sayhello函數失敗,可能是函數位址擷取不正确。

注:這裡是

finalizeObject

的文檔解釋:

finalizeObject - ensure the module is fully processed and is usable.

It is the user-level function for completing the process of making the object usable for execution. It should be called after sections within an object have been relocated using mapSectionAddress. When this method is called the MCJIT execution engine will reapply relocations for a loaded object. This method has no effect for the interpeter.

解決方法: 

去掉external.cpp某些方法。

例如會導緻問題的external.cpp如下:

#include <math.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <setjmp.h>
#include <math.h>
#include <ctype.h>
#include <windows.h>
#include <process.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h> 
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <windows.h>
#include <intrin.h>
#include <io.h>
#include <intrin.h>
#include <string.h>
#pragma comment(lib,"Winmm.lib")
using namespace std;
void ex()
{
	_beginthreadex(NULL, 1, NULL, NULL, 1, NULL);
	_endthreadex(1);
	strncmp("asdf", "afd", 13);
	_ReadWriteBarrier();
	int * px = (int*)malloc(2 * sizeof(int));
	realloc(px, 1);
	memset(px, 2, 1);
	memmove(px, px, 1);
	free(px);
	char c[10] = "a";
	char b[10] = "a";
	int x = strlen(c);
	x = strcmp(b, c);
	strcpy(c, b);
	strcat(b, c);
	strncat(b, c, 1);
	sprintf(b, "a", x);
	system("IRResult.exe");

	isdigit(c[1]); isupper(c[1]); tolower(c[1]); islower(c[1]); toupper(c[1]); isspace(c[1]);
	isatty(0);
	isalpha(0);
	long *lp = NULL;
	strrchr("xxx", 38);
	strcspn("x", "x");
	strspn("x", "x");
	atoi(c); atof(c);
	floor(1.0);
	sqrt(5.0); pow(1.0, 1.0); exp(2.0);
	sin(1.0); asin(1.0); tan(1.0); atan(1.0); atan2(1.0, 1.0);
	cos(1.0); acos(1.0); abs(1); fabs(1.0); fmod(1.0, 1.0); log(1.0);
	calloc(1, 1);
	clock(); time(NULL); srand(0); rand();
	getenv(c);
	FILE * fp;
	fp = fopen("1.txt", "r");
	fread(c, 1, 1, fp);
	fprintf(fp, "%d", x);
	fprintf(stdin, "%d", x);
	fprintf(stdout, "%d", x);
	fprintf(stderr, "%d", x);
	fileno(fp);
	fscanf(fp, "%d", &x); sscanf(c, "%s", c);
	fwrite(c, 1, 1, fp);
	fseek(fp, 1, SEEK_SET);
	feof(fp);
	strtok(NULL, "sdfs");
	itoa(1, c, 10);
	rewind(fp);  fflush(fp); rename(c, c); _unlink(c);
	read(0, (void*)NULL, 0);
	tmpnam((char*)NULL);
	write(0, NULL, 0);
	memcmp(NULL, NULL, 10);

	if (c[0] != EOF)
		fputs(c, fp);
	fputc(c[1], fp); fgetc(fp); fgets(c, 10, fp); tmpfile();
	getchar(); putchar('a');
	fclose(fp);
	_close(1); perror(c); strerror(errno); remove(c); _read(1, (void*)c, 1);
	Sleep(1);
	setbuf(fp, c);
	//windows資料類型
	HANDLE  Handle;
	HANDLE OSSemaphore;
	CRITICAL_SECTION cs;
	TIMECAPS Timecaps;
	va_list OS_Printf_marker;
	//windows API函數

	//temp
	time_t timeaaa;
	localtime(&timeaaa);
	CRITICAL_SECTION  a;
	DeleteCriticalSection(&a);

	LPLONG aaa;

	unsigned char xxxx;
	_byteswap_ushort(xxxx);
	_ReadWriteBarrier();
	int x1;
	_byteswap_ulong(x1);
	_beginthreadex(NULL, 0, NULL, NULL, 0, NULL);
	_endthreadex(0);
	strncmp("", "", 1);
	AreFileApisANSI();
	CloseHandle(NULL);
	CreateFileA(NULL, 0, 0, NULL, 0, 0, NULL);
	CreateFileW(NULL, 0, 0, NULL, 0, 0, NULL);
	CreateFileMappingA(NULL, NULL, 0, 0, 0, NULL);
	CreateFileMappingW(NULL, NULL, 0, 0, 0, NULL);
	CreateMutexW(NULL, NULL, NULL);
	DeleteFileA(NULL);
	DeleteFileW(NULL);
	FlushFileBuffers(NULL);
	FormatMessageA(0, NULL, 0, 0, NULL, 0, NULL);
	FormatMessageW(0, NULL, 0, 0, NULL, 0, NULL);
	FreeLibrary(NULL);
	GetCurrentProcessId();
	GetDiskFreeSpaceA(NULL, NULL, NULL, NULL, NULL);
	GetDiskFreeSpaceW(NULL, NULL, NULL, NULL, NULL);
	GetFileAttributesA(NULL);
	GetFileAttributesW(NULL);
	GET_FILEEX_INFO_LEVELS x2;
	GetFileAttributesExW(NULL, x2, NULL);
	GetFileSize(NULL, NULL);
	GetFullPathNameA(NULL, 0, NULL, NULL);
	GetFullPathNameW(NULL, 0, NULL, NULL);
	GetLastError();
	GetProcAddress(NULL, NULL);
	GetSystemInfo(NULL);
	GetSystemTime(NULL);
	GetSystemTimeAsFileTime(NULL);
	GetTempPathA(0, NULL);
	GetTempPathW(0, NULL);
	GetTickCount();
	GetVersionExA(NULL);
	GetVersionExW(NULL);
	HeapAlloc(NULL, 0, 0);
	HeapCreate(0, 0, 0);
	HeapDestroy(0);
	HeapFree(NULL, 0, NULL);
	HeapReAlloc(NULL, 0, NULL, 0);
	HeapSize(NULL, 0, NULL);
	HeapValidate(NULL, 0, NULL);
	HeapCompact(NULL, 0);
	LoadLibraryA(NULL);
	LoadLibraryW(NULL);
	LocalFree(NULL);
	LockFile(NULL, 0, 0, 0, 0);
	LockFileEx(NULL, 0, 0, 0, 0, 0);
	MapViewOfFile(NULL, 0, 0, 0, 0);
	MultiByteToWideChar(0, 0, 0, 0, NULL, 0);
	QueryPerformanceCounter(NULL);
	ReadFile(NULL, NULL, 0, NULL, NULL);
	SetEndOfFile(NULL);
	SetFilePointer(NULL, 0, NULL, 0);
	Sleep(0);
	SystemTimeToFileTime(NULL, 0);
	UnlockFile(NULL, 0, 0, 0, 0);
	UnlockFileEx(NULL, 0, 0, 0, NULL);
	UnmapViewOfFile(NULL);
	WideCharToMultiByte(0, 0, NULL, 0, NULL, 0, NULL, NULL);
	WriteFile(NULL, NULL, 0, NULL, NULL);
	WaitForSingleObject(NULL, 0);
	WaitForSingleObjectEx(NULL, 0, 0);
	OutputDebugStringA(NULL);
	OutputDebugStringW(NULL);
	GetProcessHeap();
	FlushViewOfFile(NULL, 0);


	EnterCriticalSection(&cs);

	LeaveCriticalSection(&cs);
	InitializeCriticalSection(&cs);
	WaitForSingleObject(OSSemaphore, 1);
	ReleaseSemaphore(OSSemaphore, 1, NULL);
	SetThreadAffinityMask(Handle, 1);
	GetCurrentThreadId();

	SuspendThread(Handle);
	ResumeThread(Handle);
	SetThreadPriorityBoost(Handle, true);
	CloseHandle(Handle);

	ResetEvent(Handle);

	timeSetEvent(10, 1, 0, 1, 1);
	timeKillEvent(0);
	timeEndPeriod(0);
	timeGetDevCaps(&Timecaps, 0);
	timeBeginPeriod(0);



	GetTickCount();

	vprintf(c, OS_Printf_marker);

	exit(0);
}

void *memcpy(void *dest, const void *src, size_t count)

{
	//assert(dest != NULL && src != NULL && count>0);
	char *tmp_dest = (char*)dest;
	char *tmp_src = (char*)src;
	while (count--)//不對是否存在重疊區域進行判斷
		*tmp_dest++ = *tmp_src++;
	return dest;
}

void * memmove(void *dest, const void *src, int num)
{
	//assert(dest != NULL && src != NULL && num>0);
	char *tmp_dest = (char*)dest;
	char *tmp_src = (char*)src;
	//判斷des和src是否存在重疊
	if (tmp_dest + num < tmp_src || tmp_src + num < tmp_dest)
	{
		while (num--)
			*tmp_dest++ = *tmp_src++;
	}
	else//存在重疊,防止資訊丢失,從後向前指派
	{
		tmp_dest = tmp_dest + num - 1;
		tmp_src = tmp_src + num - 1;
		while (num--)
			*tmp_dest-- = *tmp_src--;
	}
	return dest;
}
void* memset(void* s, int c, size_t n)
{
	printf("hello");
	unsigned char* p = (unsigned char*)s;

	while (n > 0) {
		*p++ = (unsigned char)c;
		--n;
		printf("%d ", &n);
	}

	return s;
}

extern "C" {
	void sayhello()
	{
		printf("hello\n");
	}
}
           

其中isatty 以及 itoa 等會引發上訴問題。

修改後的external.cpp 如下:

#include <math.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <setjmp.h>
#include <math.h>
#include <ctype.h>
#include <windows.h>
#include <process.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h> 
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <windows.h>
#include <intrin.h>
#include <io.h>
#include <intrin.h>
#include <string.h>
#pragma comment(lib,"Winmm.lib")
using namespace std;
void ex()
{
	strncmp("asdf", "afd", 13);
	int * px = (int*)malloc(2 * sizeof(int));
	realloc(px, 1);
	memset(px, 2, 1);
	memmove(px, px, 1);
	memcmp(NULL, NULL, 10);
	memcpy(NULL, NULL, 10);
	free(px);
	char c[10] = "a";
	char b[10] = "a";
	int x = strlen(c);
	x = strcmp(b, c);
	strcpy(c, b);
	strcat(b, c);
	strncat(b, c, 1);
	sprintf(b, "a", x);
	isdigit(c[1]); isupper(c[1]); tolower(c[1]); islower(c[1]); toupper(c[1]); isspace(c[1]);
	isalpha(0);
	long *lp = NULL;
	strrchr("xxx", 38);
	strcspn("x", "x");
	strspn("x", "x");
	atoi(c); atof(c);
	floor(1.0);
	sqrt(5.0); pow(1.0, 1.0); exp(2.0);
	sin(1.0); asin(1.0); tan(1.0); atan(1.0); atan2(1.0, 1.0);
	cos(1.0); acos(1.0); abs(1); fabs(1.0); fmod(1.0, 1.0); log(1.0);
	FILE * fp;
	fp = fopen("1.txt", "r");
	fread(c, 1, 1, fp);
	fprintf(fp, "%d", x);
	fprintf(stdin, "%d", x);
	fprintf(stdout, "%d", x);
	fprintf(stderr, "%d", x);

	fscanf(fp, "%d", &x); sscanf(c, "%s", c);
	fwrite(c, 1, 1, fp);

	strtok(NULL, "sdfs");


	if (c[0] != EOF)
		fputs(c, fp);
	fputc(c[1], fp); fgetc(fp); fgets(c, 10, fp);
	getchar(); putchar('a');
	fclose(fp);
}

void *memcpy(void *dest, const void *src, size_t count)

{
	//assert(dest != NULL && src != NULL && count>0);
	char *tmp_dest = (char*)dest;
	char *tmp_src = (char*)src;
	while( count--)//不對是否存在重疊區域進行判斷
		*tmp_dest++ = *tmp_src++;
	return dest;
}

void* memmove(void *dest, const void *src, size_t num)
{
	//assert(dest != NULL && src != NULL && num>0);
	char *tmp_dest = (char*)dest;
	char *tmp_src = (char*)src;
	//判斷des和src是否存在重疊
	if (tmp_dest + num < tmp_src || tmp_src + num < tmp_dest)
	{
		while (num--)
			*tmp_dest++ = *tmp_src++;
	}
	else//存在重疊,防止資訊丢失,從後向前指派
	{
		tmp_dest = tmp_dest + num - 1;
		tmp_src = tmp_src + num - 1;
		while (num--)
			*tmp_dest-- = *tmp_src--;
	}
	return dest;
}
void* memset(void* s, int c, size_t n)
{
    unsigned char* p = (unsigned char*) s;

    while (n > 0) {
    	*p++ = (unsigned char) c;
   		--n;
    }

    return s;
}

extern "C" {
	void sayhello()
	{
		printf("hello\n");
	}
}
           

補充:

如果需要保證c++ 與 IR 的自定義函數名不發生變化,需要使用

extern "C"{ 方法... }

繼續閱讀