Segfault при вызове llvm_sys LLVMCreateTargetMachine для создания объектного файла в Rust

extern crate llvm_sys;

use llvm_sys::*;
use llvm_sys::prelude::*;
use llvm_sys::core::*;

pub fn emit(module: LLVMModuleRef) {
    unsafe {
        use llvm_sys::target_machine::*;
        let triple = LLVMGetDefaultTargetTriple();
        let mut target: LLVMTargetRef = std::mem::uninitialized();
        LLVMGetTargetFromTriple(triple, &mut target, ["Cannot get target.\0".as_ptr() as *mut i8].as_mut_ptr());
        let cpu = "x86\0".as_ptr() as *const i8;
        let feature = "\0".as_ptr() as *const i8;
        let opt_level = LLVMCodeGenOptLevel::LLVMCodeGenLevelNone;
        let reloc_mode = LLVMRelocMode::LLVMRelocDefault;
        let code_model = LLVMCodeModel::LLVMCodeModelDefault;
        let target_machine = LLVMCreateTargetMachine(target, triple, cpu, feature, opt_level, reloc_mode, code_model);

        let file_type = LLVMCodeGenFileType::LLVMObjectFile;

        // LLVMTargetMachineEmitToFile(target_machine, module, "/Users/andyshiue/Desktop/main.o\0".as_ptr() as *mut i8, file_type, "Cannot generate file.\0".as_ptr() as *mut *mut i8);
    }
}

pub fn main() {
    use Term::*;

    unsafe {
        let module = LLVMModuleCreateWithName("Main\0".as_ptr() as *const i8);
        emit(module);
    }
}

ошибка:

Process didn't exit successfully: `target/debug/ende` (signal: 11, SIGSEGV: invalid memory reference)

Я пишу свой игрушечный компилятор, и теперь я хочу генерировать объектные файлы. Почему код выше производит segfault? Откуда я знаю, что я делаю не так? Можно ли получить трассировку стека? У меня нет опыта работы с C/C++, поэтому я не знаю, как отлаживать. Проблема как-то связана с target?

1 ответ

Решение

Вы неправильно понимаете, как позвонить LLVMGetTargetFromTriple:

pub unsafe extern "C" fn LLVMGetTargetFromTriple(Triple: *const c_char,
                                                 T: *mut LLVMTargetRef,
                                                 ErrorMessage: *mut *mut c_char)
                                                 -> LLVMBool

Эта функция принимает указатель на строку в стиле C, которая будет заполнена в случае ошибки. Фактический успех метода сообщается в результате.

Согласно документам LLVM:

Находит цель, соответствующую данной тройке, и сохраняет ее в T.

Возвращает 0 в случае успеха. Опционально возвращает любую ошибку в ErrorMessage. Используйте LLVMDisposeMessage для удаления сообщения.

(акцент мой)

Прямо сейчас этот вызов не выполняется, поэтому целевой ref никогда не инициализируется, поэтому вы пытаетесь вызвать методы для неопределенного кода.

Другие вопросы по тегам