Last active
August 16, 2022 14:47
-
-
Save xobs/9cb7156147de68b0767c43dabafcbab9 to your computer and use it in GitHub Desktop.
Sample program to convert C to Rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# 1. Install c2rust dependencies: | |
# sudo apt install build-essential llvm clang libclang-dev cmake libssl-dev pkg-config python3 | |
# 2. Install c2rust: | |
# cargo install c2rust: | |
# 3. Run this program inside the target directory: | |
# python ring-transpile-c2rust.py | |
# | |
# This creates a bunch of `.rs` files with `#[no_mangle] extern "C"` declarations, | |
# which allow other Rust code to link against it. This program also tries hard to | |
# fixup the types so that they work without libc. | |
# | |
# The resulting code may even compile! But you may need to add more fixes under the | |
# `massage_line()` function in order to get things working. | |
# | |
# The idea behind this program is that you run it once on a project and then begin | |
# gradually rewriting parts of it. | |
import subprocess | |
import os | |
RING_C_FILES = [ | |
"crypto/fipsmodule/aes/aes_nohw.c", | |
"crypto/fipsmodule/bn/montgomery.c", | |
"crypto/fipsmodule/bn/montgomery_inv.c", | |
"crypto/limbs/limbs.c", | |
"crypto/mem.c", | |
"crypto/poly1305/poly1305.c", | |
# Other libraries | |
"crypto/crypto.c", | |
"crypto/curve25519/curve25519.c", | |
"crypto/fipsmodule/ec/ecp_nistz.c", | |
"crypto/fipsmodule/ec/ecp_nistz256.c", | |
"crypto/fipsmodule/ec/gfp_p256.c", | |
"crypto/fipsmodule/ec/gfp_p384.c", | |
] | |
COMMANDS_FILE = "compile_commands.json" | |
def massage_line(line): | |
line = line.strip() | |
# Remove various compile-time directives | |
if line == "#![register_tool(c2rust)]": | |
return "" | |
if line == "use core::arch::asm;": | |
return "" | |
if line.startswith("#![feature("): | |
return "" | |
if line.startswith("#![allow("): | |
return "" | |
# Convert types | |
line = line.replace("libc::c_int", "i32") | |
line = line.replace("libc::c_ulong", "u64") | |
line = line.replace("libc::c_long", "i64") | |
line = line.replace("libc::c_uint", "u32") | |
line = line.replace("libc::c_char", "u8") | |
line = line.replace("libc::c_uchar", "u8") | |
line = line.replace("libc::c_schar", "i8") | |
line = line.replace("libc::c_void", "u8") | |
# Fix program-specific oddities | |
line = line.replace("::std::vec::", "std::vec::") | |
line = line.replace(": Vec::", ": std::vec::Vec::") | |
line = line.replace(") = limbs_mul_add_limb(", ") = GFp_limbs_mul_add_limb(") | |
# Replace this ASM weirdness with a barrier | |
compiler_fence = ( | |
"core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);" | |
) | |
line = line.replace( | |
'asm!("", inlateout(reg) a, options(preserves_flags, pure, readonly, att_syntax));', | |
compiler_fence, | |
) | |
return line | |
def run(): | |
# Generate the `compile_commands.json` file that c2rust uses | |
cwd = os.getcwd() | |
with open(COMMANDS_FILE, "w") as cmd_file: | |
print("[", file=cmd_file) | |
first_line = False | |
for file in RING_C_FILES: | |
rs_file = file.replace(".c", ".rs") | |
if os.path.exists(rs_file): | |
os.unlink(rs_file) | |
if first_line is not False: | |
print(",", file=cmd_file) | |
first_line = True | |
print(" {", file=cmd_file) | |
print( | |
f""" "arguments": [ | |
"cc", | |
"-c", | |
"-m32", | |
"-o", | |
"build/tmp.o", | |
"-Iinclude", | |
"-DOPENSSL_32_BIT=1", | |
"{file}" | |
], | |
"directory": "{cwd}", | |
"file": "{file}" | |
}}""", | |
file=cmd_file, | |
end="", | |
) | |
print("", file=cmd_file) | |
print("]", file=cmd_file) | |
subprocess.run(["c2rust", "transpile", COMMANDS_FILE]) | |
if not os.path.exists("src/c2rust"): | |
os.mkdir("src/c2rust") | |
print("Add this to the end of `src/lib.rs`:") | |
print("mod c2rust {") | |
for file in RING_C_FILES: | |
mod_name = file.split("/")[-1].split(".")[0] | |
rs_file = file.replace(".c", ".rs") | |
# print(f" #[path = \"../{rs_file}\"]") | |
print(f" mod {mod_name};") | |
with open(rs_file, "r") as src_file: | |
with open(f"src/c2rust/{mod_name}.rs", "w") as dest_file: | |
print("extern crate std;", file=dest_file) | |
for line in src_file: | |
print(massage_line(line), file=dest_file) | |
print("}") | |
if __name__ == "__main__": | |
run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment