2015-04-04 3 views
2

Я пытаюсь создать LLVM IR, который выводит относительные виртуальные адреса. Однако после компиляции и компоновки я вижу, что он выводит адреса на основе предпочтительного базового адреса изображения исполняемого файла, а не относительных адресов.Как получить базовый адрес изображения программы в LLVM IR

Например, если я использую такой код:

@.myconstant = private constant [12 x i8] c"My constant\00" 
@.myglobal = global {i8*} {i8* bitcast([12 x i8]* @.myconstant to i8*)} 

В согласующего исполняемом разделе, я вижу шестнадцатеричное значение как:

44 30 40 00 

или просто 0x403044, что гораздо больше, чем мой весь исполняемый размер, даже после выравнивания раздела.

Если я вручную вычитать 0x400000, как и так:

@.myconstant = private constant [12 x i8] c"My constant\00" 
@.myglobal = global {i8*} {i8* inttoptr (i32 sub(i32 ptrtoint([12 x i8]* @.myconstant to i32), i32 u0x400000) to i8*)} 

я получаю правильный адрес в исполняемый файл. Но это решение не поддерживается, потому что базовый адрес изображения не гарантируется 0x400000.

В то же время я должен использовать указатель на глобальный, потому что я не знаю, где этот глобальный окажется внутри соответствующего раздела (так как это зависит от других глобалов в том же разделе) или что адрес относительной памяти будет назначен для этого раздела (так как это зависит от выравнивания с предыдущими разделами).

Итак, мой вопрос: как я могу получить базовый адрес как константу или получить адрес относительно загрузочного адреса программы?

Update: Видимо, разработчики LLD уже сталкивались с этой проблемой, и добавил расширение, к AT & T ассемблере для учета этого:

.regular_global: 
    .long .L.myconstant # Outputs 0x403044 
.rva_global: 
    .long [email protected] # Outputs 0x3044 

Поэтому мой вопрос становится: как я заставить эту сборку производить через ИК?

ответ

0

Ну, я нашел решение. Мне нужно, чтобы определить внешний глобальный называется @__ImageBase, как это:

@__ImageBase = external global i8 

Затем я выполняю указатель вычитания относительно решения этой глобальной, как так:

@.myconstant = private constant [12 x i8] c"My constant\00" 
@.myglobal = global {i8*} {i8* inttoptr (i32 sub(i32 ptrtoint([12 x i8]* @.myconstant to i32), i32 ptrtoint(i8* @__ImageBase to i32)) to i8*)} 

Наконец, мне нужно позвонить llc с целевой тройной для Windows, так как это единственная платформа, поддерживающая относительные перемещения изображений. Например, я могу установить -mtriple=i386-pc-win32 в командной строке.

По какой-то причине, установив цель тройной внутри исходного файла примерно так:

target triple = "i386-pc-win32" 

не является достаточным. Выполнение этого без добавления командной строки выше приведет к тому, что LLVM будет жаловаться на неопределенную константу ___ImageBase.

То же самое можно достичь и для 64-битного с использованием целевой тройки x86_64-pc-win32 и замены арифметики указателя с использованием i32 на i64.