diff --git a/libtest.sh b/libtest.sh index efd20a8..a820069 100755 --- a/libtest.sh +++ b/libtest.sh @@ -7,5 +7,40 @@ export .env cargo run --example libtest && \ -clang++ main.cpp hello.o -o main && \ -./main +# clang++ main.cpp hello.o -o main && \ +ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \ + -o main /usr/lib/crt1.o hello.o -lc && \ +./main ; echo $? + + +## Command from: clang -v hello.o -o test +## Original command: +# ld --hash-style=gnu \ +# --build-id \ +# --eh-frame-hdr \ +# -m elf_x86_64 \ +# -pie \ +# -dynamic-linker /lib64/ld-linux-x86-64.so.2 \ +# -o test \ +# /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/15.1.1/../../../../lib64/Scrt1.o \ +# /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/15.1.1/../../../../lib64/crti.o \ +# /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/15.1.1/crtbeginS.o \ +# -L/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/15.1.1 \ +# -L/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/15.1.1/../../../../lib64 \ +# -L/lib/../lib64 \ +# -L/usr/lib/../lib64 \ +# -L/lib \ +# -L/usr/lib \ +# hello.o \ +# -lgcc \ +# --as-needed \ +# -lgcc_s \ +# --no-as-needed \ +# -lc \ +# -lgcc \ +# --as-needed \ +# -lgcc_s \ +# --no-as-needed \ +# /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/15.1.1/crtendS.o \ +# /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/15.1.1/../../../../lib64/crtn.o \ +# && \ \ No newline at end of file diff --git a/reid-llvm-lib/examples/libtest.rs b/reid-llvm-lib/examples/libtest.rs index 67da38c..6e2b5ae 100644 --- a/reid-llvm-lib/examples/libtest.rs +++ b/reid-llvm-lib/examples/libtest.rs @@ -1,10 +1,16 @@ use reid_lib::*; pub fn main() { + // Notes from inkwell: + // - Creating new values should probably just be functions in the context + // - Creating functions should probably be functions from module + // - Builder could well be it's own struct + // - Although, I do like the fact where blocks move the builder by itself.. + let context = IRContext::new(); let module = IRModule::new(&context, &"hello".to_owned()); - let mainfunc = IRFunction::new(&module, &"mainfunc".to_owned()); + let mainfunc = IRFunction::new(&module, &"main".to_owned()); let secondary_func = IRFunction::new(&module, &"secondary".to_owned()); diff --git a/reid-llvm-lib/src/lib.rs b/reid-llvm-lib/src/lib.rs index 24357fd..c2c85e7 100644 --- a/reid-llvm-lib/src/lib.rs +++ b/reid-llvm-lib/src/lib.rs @@ -1,46 +1,22 @@ -use std::ffi::{CStr, CString, c_char}; +use std::ffi::{CStr, CString}; use std::marker::PhantomData; -use std::mem; -use std::ptr::{null, null_mut}; +use std::ptr::null_mut; use llvm_sys::analysis::LLVMVerifyModule; use llvm_sys::target::{ LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos, - LLVM_InitializeAllTargetMCs, LLVM_InitializeAllTargets, LLVM_InitializeNativeAsmParser, - LLVM_InitializeNativeTarget, LLVMInitializeAMDGPUAsmPrinter, LLVMInitializeX86Target, - LLVMInitializeX86TargetInfo, LLVMInitializeX86TargetMC, LLVMSetModuleDataLayout, + LLVM_InitializeAllTargetMCs, LLVM_InitializeAllTargets, LLVMSetModuleDataLayout, }; use llvm_sys::target_machine::{ LLVMCodeGenFileType, LLVMCreateTargetDataLayout, LLVMCreateTargetMachine, - LLVMGetDefaultTargetTriple, LLVMGetFirstTarget, LLVMGetHostCPUFeatures, LLVMGetHostCPUName, - LLVMGetTargetFromTriple, LLVMTargetMachineEmitToFile, LLVMTargetMachineEmitToMemoryBuffer, -}; -use llvm_sys::transforms::pass_manager_builder::{ - LLVMPassManagerBuilderCreate, LLVMPassManagerBuilderPopulateModulePassManager, - LLVMPassManagerBuilderSetOptLevel, + LLVMGetDefaultTargetTriple, LLVMGetTargetFromTriple, LLVMTargetMachineEmitToFile, }; use llvm_sys::{ LLVMBasicBlock, LLVMBuilder, LLVMContext, LLVMModule, LLVMType, LLVMValue, core::*, prelude::*, }; +use util::{ErrorMessageHolder, from_cstring, into_cstring}; -fn into_cstring>(value: T) -> CString { - let string = value.into(); - unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } -} - -fn from_cstring(value: *mut c_char) -> Option { - if value.is_null() { - None - } else { - unsafe { CString::from_raw(value).into_string().ok() } - } -} - -fn cstring_to_err(value: *mut c_char) -> Result<(), String> { - from_cstring(value) - .filter(|s| !s.is_empty()) - .map_or(Ok(()), |s| Err(s)) -} +mod util; pub trait IRType { const SIGNED: LLVMBool; @@ -131,12 +107,6 @@ impl<'a> IRModule<'a> { pub fn print_to_string(&self) -> Result<&str, String> { unsafe { - // let pmb = LLVMPassManagerBuilderCreate(); - // LLVMPassManagerBuilderSetOptLevel(pmb, 0); - // let pm = LLVMCreatePassManager(); - // LLVMPassManagerBuilderPopulateModulePassManager(pmb, pm); - // println!("{}", LLVMRunPassManager(pm, self.module)); - LLVM_InitializeAllTargets(); LLVM_InitializeAllTargetInfos(); LLVM_InitializeAllTargetMCs(); @@ -146,10 +116,14 @@ impl<'a> IRModule<'a> { let triple = LLVMGetDefaultTargetTriple(); let mut target: _ = null_mut(); - let mut err: _ = null_mut(); - LLVMGetTargetFromTriple(c"x86_64-unknown-linux-gnu".as_ptr(), &mut target, &mut err); + let mut err = ErrorMessageHolder::null(); + LLVMGetTargetFromTriple( + c"x86_64-unknown-linux-gnu".as_ptr(), + &mut target, + err.borrow_mut(), + ); println!("{:?}, {:?}", from_cstring(triple), target); - cstring_to_err(err).unwrap(); + err.into_result().unwrap(); let target_machine = LLVMCreateTargetMachine( target, @@ -164,33 +138,33 @@ impl<'a> IRModule<'a> { let data_layout = LLVMCreateTargetDataLayout(target_machine); LLVMSetModuleDataLayout(self.module, data_layout); - let mut err = null_mut(); + let mut err = ErrorMessageHolder::null(); LLVMVerifyModule( self.module, llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction, - &mut err, + err.borrow_mut(), ); - cstring_to_err(err).unwrap(); + err.into_result().unwrap(); - let mut err = null_mut(); + let mut err = ErrorMessageHolder::null(); LLVMTargetMachineEmitToFile( target_machine, self.module, CString::new("hello.asm").unwrap().into_raw(), LLVMCodeGenFileType::LLVMAssemblyFile, - &mut err, + err.borrow_mut(), ); - cstring_to_err(err).unwrap(); + err.into_result().unwrap(); - let mut err = null_mut(); + let mut err = ErrorMessageHolder::null(); LLVMTargetMachineEmitToFile( target_machine, self.module, CString::new("hello.o").unwrap().into_raw(), LLVMCodeGenFileType::LLVMObjectFile, - &mut err, + err.borrow_mut(), ); - cstring_to_err(err).unwrap(); + err.into_result().unwrap(); Ok(CStr::from_ptr(LLVMPrintModuleToString(self.module)) .to_str() diff --git a/reid-llvm-lib/src/util.rs b/reid-llvm-lib/src/util.rs new file mode 100644 index 0000000..efe5e9f --- /dev/null +++ b/reid-llvm-lib/src/util.rs @@ -0,0 +1,51 @@ +use std::{ + ffi::{CString, c_char}, + ptr::null_mut, +}; + +use llvm_sys::error::LLVMDisposeErrorMessage; + +pub fn into_cstring>(value: T) -> CString { + let string = value.into(); + unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } +} + +pub fn from_cstring(value: *mut c_char) -> Option { + if value.is_null() { + None + } else { + unsafe { CString::from_raw(value).into_string().ok() } + } +} + +fn cstring_to_err(value: *mut c_char) -> Result<(), String> { + from_cstring(value) + .filter(|s| !s.is_empty()) + .map_or(Ok(()), |s| Err(s)) +} + +pub struct ErrorMessageHolder(*mut c_char); + +impl ErrorMessageHolder { + pub fn null() -> Self { + ErrorMessageHolder(null_mut()) + } + + pub fn borrow_mut(&mut self) -> *mut *mut c_char { + &mut self.0 + } + + pub fn into_result(&self) -> Result<(), String> { + cstring_to_err(self.0) + } +} + +impl Drop for ErrorMessageHolder { + fn drop(&mut self) { + unsafe { + if !self.0.is_null() { + LLVMDisposeErrorMessage(self.0); + } + } + } +}