zoc: Produce disassembly of executable

This commit is contained in:
Joëlle van Essen 2025-03-26 21:42:49 +01:00
commit 13f1a3490e
No known key found for this signature in database
GPG key ID: 28D3B5CDD4B43882
7 changed files with 101 additions and 49 deletions

View file

@ -1,7 +1,7 @@
[package] [package]
name = "comgr" name = "comgr"
version = "0.0.0" version = "0.0.0"
authors = ["Andrzej Janik <vosen@vosen.pl>"] authors = ["Andrzej Janik <vosen@vosen.pl>", "Joëlle van Essen <joelle@v-essen.nl>"]
edition = "2021" edition = "2021"
[lib] [lib]

View file

@ -110,10 +110,7 @@ impl Drop for ActionInfo {
} }
} }
pub fn link_bitcode( fn link_bitcode(main_buffer: &[u8], ptx_impl: &[u8]) -> Result<DataSet, amd_comgr_status_s> {
main_buffer: &[u8],
ptx_impl: &[u8],
) -> Result<DataSet, amd_comgr_status_s> {
use amd_comgr_sys::*; use amd_comgr_sys::*;
let bitcode_data_set = DataSet::new()?; let bitcode_data_set = DataSet::new()?;
let main_bitcode_data = Data::new( let main_bitcode_data = Data::new(
@ -136,14 +133,12 @@ pub fn link_bitcode(
) )
} }
pub fn compile_bitcode( fn compile_bitcode(
linked_data_set: &DataSet,
gcn_arch: &CStr, gcn_arch: &CStr,
main_buffer: &[u8], ) -> Result<DataSet, amd_comgr_status_s> {
ptx_impl: &[u8],
) -> Result<Vec<u8>, amd_comgr_status_s> {
use amd_comgr_sys::*; use amd_comgr_sys::*;
let linked_data_set = link_bitcode(main_buffer, ptx_impl)?;
let compile_to_exec = ActionInfo::new()?; let compile_to_exec = ActionInfo::new()?;
compile_to_exec.set_isa_name(gcn_arch)?; compile_to_exec.set_isa_name(gcn_arch)?;
compile_to_exec.set_language(amd_comgr_language_t::AMD_COMGR_LANGUAGE_LLVM_IR)?; compile_to_exec.set_language(amd_comgr_language_t::AMD_COMGR_LANGUAGE_LLVM_IR)?;
@ -176,16 +171,69 @@ pub fn compile_bitcode(
] ]
}; };
compile_to_exec.set_options(common_options.chain(opt_options))?; compile_to_exec.set_options(common_options.chain(opt_options))?;
let exec_data_set = do_action( do_action(
&linked_data_set, &linked_data_set,
&compile_to_exec, &compile_to_exec,
amd_comgr_action_kind_t::AMD_COMGR_ACTION_COMPILE_SOURCE_TO_EXECUTABLE, amd_comgr_action_kind_t::AMD_COMGR_ACTION_COMPILE_SOURCE_TO_EXECUTABLE,
)?; )
}
fn disassemble_exec(
exec_data_set: &DataSet,
gcn_arch: &CStr,
) -> Result<DataSet, amd_comgr_status_s> {
let action_info = ActionInfo::new()?;
action_info.set_isa_name(gcn_arch)?;
do_action(
&exec_data_set,
&action_info,
amd_comgr_action_kind_t::AMD_COMGR_ACTION_DISASSEMBLE_EXECUTABLE_TO_SOURCE,
)
}
pub fn get_linked_bitcode_as_bytes(
main_buffer: &[u8],
ptx_impl: &[u8],
) -> Result<Vec<u8>, amd_comgr_status_s> {
let linked_data_set = link_bitcode(main_buffer, ptx_impl)?;
let linked_bitcode =
linked_data_set.get_data(amd_comgr_data_kind_t::AMD_COMGR_DATA_KIND_BC, 0)?;
linked_bitcode.copy_content()
}
fn get_executable(
gcn_arch: &CStr,
main_buffer: &[u8],
ptx_impl: &[u8],
) -> Result<DataSet, amd_comgr_status_s> {
let linked_data_set = link_bitcode(main_buffer, ptx_impl)?;
let exec_data_set = compile_bitcode(&linked_data_set, gcn_arch)?;
Ok(exec_data_set)
}
pub fn get_executable_as_bytes(
gcn_arch: &CStr,
main_buffer: &[u8],
ptx_impl: &[u8],
) -> Result<Vec<u8>, amd_comgr_status_s> {
let exec_data_set = get_executable(gcn_arch, main_buffer, ptx_impl)?;
let executable = let executable =
exec_data_set.get_data(amd_comgr_data_kind_t::AMD_COMGR_DATA_KIND_EXECUTABLE, 0)?; exec_data_set.get_data(amd_comgr_data_kind_t::AMD_COMGR_DATA_KIND_EXECUTABLE, 0)?;
executable.copy_content() executable.copy_content()
} }
pub fn get_assembly_as_bytes(
gcn_arch: &CStr,
main_buffer: &[u8],
ptx_impl: &[u8],
) -> Result<Vec<u8>, amd_comgr_status_s> {
let exec_data_set = get_executable(gcn_arch, main_buffer, ptx_impl)?;
let disassembled_data_set = disassemble_exec(&exec_data_set, gcn_arch)?;
let assembly =
disassembled_data_set.get_data(amd_comgr_data_kind_t::AMD_COMGR_DATA_KIND_SOURCE, 0)?;
assembly.copy_content()
}
fn do_action( fn do_action(
data_set: &DataSet, data_set: &DataSet,
action: &ActionInfo, action: &ActionInfo,

View file

@ -1,3 +1,4 @@
use std::ffi::FromBytesUntilNulError;
use std::io; use std::io;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::Utf8Error; use std::str::Utf8Error;
@ -17,14 +18,14 @@ pub enum CompilerError {
CheckPathError(PathBuf), CheckPathError(PathBuf),
#[error("Invalid output type: {0}")] #[error("Invalid output type: {0}")]
ParseOutputTypeError(String), ParseOutputTypeError(String),
#[error("Error parsing PTX: {0}")]
PtxParserError(String),
#[error("Error translating PTX: {0:?}")] #[error("Error translating PTX: {0:?}")]
PtxTranslateError(TranslateError), PtxTranslateError(TranslateError),
#[error("IO error: {0:?}")] #[error("IO error: {0:?}")]
IoError(io::Error), IoError(io::Error),
#[error("Error parsing file: {0:?}")] #[error("Error parsing file: {0:?}")]
ParseFileError(Utf8Error), ParseFileError(Utf8Error),
#[error("Error: {0}")]
GenericError(String)
} }
impl From<hipErrorCode_t> for CompilerError { impl From<hipErrorCode_t> for CompilerError {
@ -43,7 +44,7 @@ impl From<Vec<PtxError<'_>>> for CompilerError {
fn from(causes: Vec<PtxError>) -> Self { fn from(causes: Vec<PtxError>) -> Self {
let errors: Vec<String> = causes.iter().map(PtxError::to_string).collect(); let errors: Vec<String> = causes.iter().map(PtxError::to_string).collect();
let msg = errors.join("\n"); let msg = errors.join("\n");
CompilerError::PtxParserError(msg) CompilerError::GenericError(msg)
} }
} }
@ -63,4 +64,10 @@ impl From<TranslateError> for CompilerError {
fn from(cause: TranslateError) -> Self { fn from(cause: TranslateError) -> Self {
CompilerError::PtxTranslateError(cause) CompilerError::PtxTranslateError(cause)
} }
}
impl From<FromBytesUntilNulError> for CompilerError {
fn from(cause: FromBytesUntilNulError) -> Self {
CompilerError::GenericError(format!("{}", cause))
}
} }

View file

@ -1,12 +1,11 @@
use std::env; use std::env;
use std::ffi::{CStr, OsStr}; use std::ffi::{CStr, CString, OsStr};
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::{self, Write}; use std::io::{self, Write};
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::{self, FromStr}; use std::str::{self, FromStr};
use amd_comgr_sys::amd_comgr_data_kind_s;
use bpaf::Bpaf; use bpaf::Bpaf;
mod error; mod error;
@ -28,11 +27,6 @@ fn main() -> Result<(), CompilerError> {
let output_type = opts.output_type.unwrap_or_default(); let output_type = opts.output_type.unwrap_or_default();
match output_type {
OutputType::Assembly => todo!(),
_ => {}
}
let ptx_path = Path::new(&opts.ptx_path).to_path_buf(); let ptx_path = Path::new(&opts.ptx_path).to_path_buf();
check_path(&ptx_path)?; check_path(&ptx_path)?;
@ -43,20 +37,14 @@ fn main() -> Result<(), CompilerError> {
let ptx = str::from_utf8(&ptx).map_err(CompilerError::from)?; let ptx = str::from_utf8(&ptx).map_err(CompilerError::from)?;
let llvm = ptx_to_llvm(ptx).map_err(CompilerError::from)?; let llvm = ptx_to_llvm(ptx).map_err(CompilerError::from)?;
if output_type == OutputType::LlvmIrPreLinked { let output = match output_type {
write_to_file(&llvm.llvm_ir, &output_path).map_err(CompilerError::from)?; OutputType::LlvmIrPreLinked => llvm.llvm_ir,
return Ok(()); OutputType::LlvmIrLinked => get_linked_bitcode(&llvm)?,
} OutputType::Elf => get_elf(&llvm)?,
OutputType::Assembly => get_assembly(&llvm)?
if output_type == OutputType::LlvmIrLinked { };
let linked_llvm = link_llvm(&llvm)?;
write_to_file(&linked_llvm, &output_path).map_err(CompilerError::from)?;
return Ok(());
}
let elf = llvm_to_elf(&llvm)?;
write_to_file(&elf, &output_path).map_err(CompilerError::from)?;
write_to_file(&output, &output_path).map_err(CompilerError::from)?;
Ok(()) Ok(())
} }
@ -80,22 +68,31 @@ struct LLVMArtifacts {
llvm_ir: Vec<u8>, llvm_ir: Vec<u8>,
} }
fn link_llvm(llvm: &LLVMArtifacts) -> Result<Vec<u8>, CompilerError> { fn get_arch() -> Result<CString, CompilerError> {
let linked_bitcode = comgr::link_bitcode(&llvm.bitcode, &llvm.linked_bitcode)?;
let data = linked_bitcode.get_data(amd_comgr_data_kind_s::AMD_COMGR_DATA_KIND_BC, 0)?;
let linked_llvm = data.copy_content().map_err(CompilerError::from)?;
Ok(ptx::bitcode_to_ir(linked_llvm))
}
fn llvm_to_elf(llvm: &LLVMArtifacts) -> Result<Vec<u8>, CompilerError> {
use hip_runtime_sys::*; use hip_runtime_sys::*;
unsafe { hipInit(0) }?; unsafe { hipInit(0) }?;
let mut dev_props: MaybeUninit<hipDeviceProp_tR0600> = MaybeUninit::uninit(); let mut dev_props: MaybeUninit<hipDeviceProp_tR0600> = MaybeUninit::uninit();
unsafe { hipGetDevicePropertiesR0600(dev_props.as_mut_ptr(), 0) }?; unsafe { hipGetDevicePropertiesR0600(dev_props.as_mut_ptr(), 0) }?;
let dev_props = unsafe { dev_props.assume_init() }; let dev_props = unsafe { dev_props.assume_init() };
let gcn_arch = unsafe { CStr::from_ptr(dev_props.gcnArchName.as_ptr()) }; let arch = dev_props.gcnArchName;
let arch: Vec<u8> = arch.to_vec().iter().map(|&v| i8::to_ne_bytes(v)[0]).collect();
let arch = CStr::from_bytes_until_nul(arch.as_slice())?;
Ok(CString::from(arch))
}
comgr::compile_bitcode(gcn_arch, &llvm.bitcode, &llvm.linked_bitcode).map_err(CompilerError::from) fn get_linked_bitcode(llvm: &LLVMArtifacts) -> Result<Vec<u8>, CompilerError> {
let linked_bitcode = comgr::get_linked_bitcode_as_bytes(&llvm.bitcode, &llvm.linked_bitcode)?;
Ok(ptx::bitcode_to_ir(linked_bitcode))
}
fn get_elf(llvm: &LLVMArtifacts) -> Result<Vec<u8>, CompilerError> {
let arch = get_arch()?;
comgr::get_executable_as_bytes(&arch, &llvm.bitcode, &llvm.linked_bitcode).map_err(CompilerError::from)
}
fn get_assembly(llvm: &LLVMArtifacts) -> Result<Vec<u8>, CompilerError> {
let arch = get_arch()?;
comgr::get_assembly_as_bytes(&arch, &llvm.bitcode, &llvm.linked_bitcode).map_err(CompilerError::from)
} }
fn check_path(path: &Path) -> Result<(), CompilerError> { fn check_path(path: &Path) -> Result<(), CompilerError> {

View file

@ -1,7 +1,7 @@
[package] [package]
name = "ptx" name = "ptx"
version = "0.0.0" version = "0.0.0"
authors = ["Andrzej Janik <vosen@vosen.pl>"] authors = ["Andrzej Janik <vosen@vosen.pl>", "Joëlle van Essen <joelle@v-essen.nl>"]
edition = "2021" edition = "2021"
[lib] [lib]

View file

@ -361,7 +361,7 @@ fn run_hip<Input: From<u8> + Copy + Debug, Output: From<u8> + Copy + Debug + Def
unsafe { hipStreamCreate(&mut stream) }.unwrap(); unsafe { hipStreamCreate(&mut stream) }.unwrap();
let mut dev_props = unsafe { mem::zeroed() }; let mut dev_props = unsafe { mem::zeroed() };
unsafe { hipGetDevicePropertiesR0600(&mut dev_props, dev) }.unwrap(); unsafe { hipGetDevicePropertiesR0600(&mut dev_props, dev) }.unwrap();
let elf_module = comgr::compile_bitcode( let elf_module = comgr::get_executable_as_bytes(
unsafe { CStr::from_ptr(dev_props.gcnArchName.as_ptr()) }, unsafe { CStr::from_ptr(dev_props.gcnArchName.as_ptr()) },
&*module.llvm_ir.write_bitcode_to_memory(), &*module.llvm_ir.write_bitcode_to_memory(),
module.linked_bitcode(), module.linked_bitcode(),

View file

@ -28,7 +28,7 @@ pub(crate) fn load_data(module: &mut CUmodule, image: *const std::ffi::c_void) -
unsafe { hipCtxGetDevice(&mut dev) }?; unsafe { hipCtxGetDevice(&mut dev) }?;
let mut props = unsafe { mem::zeroed() }; let mut props = unsafe { mem::zeroed() };
unsafe { hipGetDevicePropertiesR0600(&mut props, dev) }?; unsafe { hipGetDevicePropertiesR0600(&mut props, dev) }?;
let elf_module = comgr::compile_bitcode( let elf_module = comgr::get_executable_as_bytes(
unsafe { CStr::from_ptr(props.gcnArchName.as_ptr()) }, unsafe { CStr::from_ptr(props.gcnArchName.as_ptr()) },
&*llvm_module.llvm_ir.write_bitcode_to_memory(), &*llvm_module.llvm_ir.write_bitcode_to_memory(),
llvm_module.linked_bitcode(), llvm_module.linked_bitcode(),