├── Readme.md ├── RustyKext.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata └── RustyKext ├── RustyKext-Info.plist ├── RustyKext-Prefix.pch ├── RustyKext.c ├── RustyKext.exp ├── en.lproj └── InfoPlist.strings └── rusty_kext.rs /Readme.md: -------------------------------------------------------------------------------- 1 | # RustyKext 2 | 3 | A currently very minimal OS X kernel extension written partly in the Rust programming language. 4 | 5 | * Writes "hello from rust" to the kernel log when the kext is loaded. That's it. 6 | * Xcode project assumes that rustc is installed at `/usr/local/bin/rustc`. 7 | * Uses a variety of features marked as "unstable", so you need a nightly build. Relying on unstable features means this may no longer compile with the latest nightly. I promise it did work with the x86-64 OSX build from 1st August 2015. 8 | * This currently depends on the "core" library, but it doesn't actually link against it, it only uses some inline functions. I don't know if that's a good idea in the long term. 9 | * I use the following command line arguments for `rustc`: 10 | - `--emit obj` - generate .o files, to be linked by Apple's own clang linker. 11 | - `--crate-type staticlib` - Not sure if this is actually needed. 12 | - `-C soft-float` - emulate floating-point code and don't use float registers for arguments. Kexts written in C or C++ likewise use -msoft-float with clang to avoid accidentally using floats in the kernel. (It's not disallowed, but doing so has implications.) 13 | - `-C no-redzone=y` - This is super important: don't use the [x86-64 red zone](https://en.wikipedia.org/wiki/Red_zone_%28computing%29), as interrupt handlers will trample over it. 14 | - `-C no-stack-check` - Otherwise `___morestack` is an undefined symbol, which we can't really do anything about in the kernel. 15 | * The panic etc. language features aren't properly wired up yet. 16 | * Still uses the wrapper RustyKext.c, although I could get rid of that if I knew how to call variadic C functions from Rust. 17 | 18 | I wrote [a thing on this](http://philjordan.eu/article/a-minimal-osx-kext-written-in-rust) back in the Rust 0.9 days. Things have changed quite a bit in Rust-land since then, so it's probably not much use. 19 | -------------------------------------------------------------------------------- /RustyKext.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 291302DE18E4450900F1D68D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 291302DC18E4450900F1D68D /* InfoPlist.strings */; }; 11 | 291302E018E4450900F1D68D /* RustyKext.c in Sources */ = {isa = PBXBuildFile; fileRef = 291302DF18E4450900F1D68D /* RustyKext.c */; }; 12 | 29E732EA1B6D2B47004BDE4C /* rusty_kext.rs in Resources */ = {isa = PBXBuildFile; fileRef = 29E732E91B6D2B47004BDE4C /* rusty_kext.rs */; }; 13 | 29E732EB1B6E4D2E004BDE4C /* rusty_kext.rs in Sources */ = {isa = PBXBuildFile; fileRef = 29E732E91B6D2B47004BDE4C /* rusty_kext.rs */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXBuildRule section */ 17 | 291302E918E4459100F1D68D /* PBXBuildRule */ = { 18 | isa = PBXBuildRule; 19 | compilerSpec = com.apple.compilers.proxy.script; 20 | filePatterns = "*.rs"; 21 | fileType = pattern.proxy; 22 | isEditable = 1; 23 | name = "Rust Source File"; 24 | outputFiles = ( 25 | "${DERIVED_FILE_DIR}/rust-bin/${INPUT_FILE_BASE}.o", 26 | ); 27 | script = "mkdir -p \"${DERIVED_FILE_DIR}/rust-bin\"\n\nif [ -z \"${GCC_OPTIMIZATION_LEVEL+xxx}\" ]; then\n OPT_LEVEL=1\nelse\n OPT_LEVEL=${GCC_OPTIMIZATION_LEVEL}\nfi\n\n/usr/local/bin/rustc --emit obj -C opt-level=${OPT_LEVEL} --crate-type staticlib -C soft-float -C no-redzone=y -C no-stack-check \"${INPUT_FILE_PATH}\" -o \"${DERIVED_FILE_DIR}/rust-bin/${INPUT_FILE_BASE}.o\"\n"; 28 | }; 29 | /* End PBXBuildRule section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 291302D418E4450900F1D68D /* RustyKext.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RustyKext.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 291302D818E4450900F1D68D /* Kernel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kernel.framework; path = System/Library/Frameworks/Kernel.framework; sourceTree = SDKROOT; }; 34 | 291302DB18E4450900F1D68D /* RustyKext-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RustyKext-Info.plist"; sourceTree = ""; }; 35 | 291302DD18E4450900F1D68D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 36 | 291302DF18E4450900F1D68D /* RustyKext.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = RustyKext.c; sourceTree = ""; }; 37 | 291302E118E4450900F1D68D /* RustyKext-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RustyKext-Prefix.pch"; sourceTree = ""; }; 38 | 2979000518E6E2C70080E0E0 /* Readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Readme.md; sourceTree = SOURCE_ROOT; }; 39 | 29E732E91B6D2B47004BDE4C /* rusty_kext.rs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rusty_kext.rs; sourceTree = ""; }; 40 | 29E732EC1B6E54E2004BDE4C /* RustyKext.exp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.exports; path = RustyKext.exp; sourceTree = ""; }; 41 | /* End PBXFileReference section */ 42 | 43 | /* Begin PBXFrameworksBuildPhase section */ 44 | 291302CF18E4450900F1D68D /* Frameworks */ = { 45 | isa = PBXFrameworksBuildPhase; 46 | buildActionMask = 2147483647; 47 | files = ( 48 | ); 49 | runOnlyForDeploymentPostprocessing = 0; 50 | }; 51 | /* End PBXFrameworksBuildPhase section */ 52 | 53 | /* Begin PBXGroup section */ 54 | 291302C918E4450900F1D68D = { 55 | isa = PBXGroup; 56 | children = ( 57 | 291302D918E4450900F1D68D /* RustyKext */, 58 | 291302D618E4450900F1D68D /* Frameworks */, 59 | 291302D518E4450900F1D68D /* Products */, 60 | ); 61 | sourceTree = ""; 62 | }; 63 | 291302D518E4450900F1D68D /* Products */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 291302D418E4450900F1D68D /* RustyKext.kext */, 67 | ); 68 | name = Products; 69 | sourceTree = ""; 70 | }; 71 | 291302D618E4450900F1D68D /* Frameworks */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 291302D718E4450900F1D68D /* Other Frameworks */, 75 | ); 76 | name = Frameworks; 77 | sourceTree = ""; 78 | }; 79 | 291302D718E4450900F1D68D /* Other Frameworks */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 291302D818E4450900F1D68D /* Kernel.framework */, 83 | ); 84 | name = "Other Frameworks"; 85 | sourceTree = ""; 86 | }; 87 | 291302D918E4450900F1D68D /* RustyKext */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 29E732E91B6D2B47004BDE4C /* rusty_kext.rs */, 91 | 291302DF18E4450900F1D68D /* RustyKext.c */, 92 | 291302DA18E4450900F1D68D /* Supporting Files */, 93 | 2979000518E6E2C70080E0E0 /* Readme.md */, 94 | 29E732EC1B6E54E2004BDE4C /* RustyKext.exp */, 95 | ); 96 | path = RustyKext; 97 | sourceTree = ""; 98 | }; 99 | 291302DA18E4450900F1D68D /* Supporting Files */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 291302DB18E4450900F1D68D /* RustyKext-Info.plist */, 103 | 291302DC18E4450900F1D68D /* InfoPlist.strings */, 104 | 291302E118E4450900F1D68D /* RustyKext-Prefix.pch */, 105 | ); 106 | name = "Supporting Files"; 107 | sourceTree = ""; 108 | }; 109 | /* End PBXGroup section */ 110 | 111 | /* Begin PBXHeadersBuildPhase section */ 112 | 291302D018E4450900F1D68D /* Headers */ = { 113 | isa = PBXHeadersBuildPhase; 114 | buildActionMask = 2147483647; 115 | files = ( 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | /* End PBXHeadersBuildPhase section */ 120 | 121 | /* Begin PBXNativeTarget section */ 122 | 291302D318E4450900F1D68D /* RustyKext */ = { 123 | isa = PBXNativeTarget; 124 | buildConfigurationList = 291302E418E4450900F1D68D /* Build configuration list for PBXNativeTarget "RustyKext" */; 125 | buildPhases = ( 126 | 291302CE18E4450900F1D68D /* Sources */, 127 | 291302CF18E4450900F1D68D /* Frameworks */, 128 | 291302D018E4450900F1D68D /* Headers */, 129 | 291302D118E4450900F1D68D /* Resources */, 130 | 291302D218E4450900F1D68D /* Rez */, 131 | ); 132 | buildRules = ( 133 | 291302E918E4459100F1D68D /* PBXBuildRule */, 134 | ); 135 | dependencies = ( 136 | ); 137 | name = RustyKext; 138 | productName = RustyKext; 139 | productReference = 291302D418E4450900F1D68D /* RustyKext.kext */; 140 | productType = "com.apple.product-type.kernel-extension"; 141 | }; 142 | /* End PBXNativeTarget section */ 143 | 144 | /* Begin PBXProject section */ 145 | 291302CA18E4450900F1D68D /* Project object */ = { 146 | isa = PBXProject; 147 | attributes = { 148 | LastUpgradeCheck = 0510; 149 | }; 150 | buildConfigurationList = 291302CD18E4450900F1D68D /* Build configuration list for PBXProject "RustyKext" */; 151 | compatibilityVersion = "Xcode 3.2"; 152 | developmentRegion = English; 153 | hasScannedForEncodings = 0; 154 | knownRegions = ( 155 | en, 156 | ); 157 | mainGroup = 291302C918E4450900F1D68D; 158 | productRefGroup = 291302D518E4450900F1D68D /* Products */; 159 | projectDirPath = ""; 160 | projectRoot = ""; 161 | targets = ( 162 | 291302D318E4450900F1D68D /* RustyKext */, 163 | ); 164 | }; 165 | /* End PBXProject section */ 166 | 167 | /* Begin PBXResourcesBuildPhase section */ 168 | 291302D118E4450900F1D68D /* Resources */ = { 169 | isa = PBXResourcesBuildPhase; 170 | buildActionMask = 2147483647; 171 | files = ( 172 | 29E732EA1B6D2B47004BDE4C /* rusty_kext.rs in Resources */, 173 | 291302DE18E4450900F1D68D /* InfoPlist.strings in Resources */, 174 | ); 175 | runOnlyForDeploymentPostprocessing = 0; 176 | }; 177 | /* End PBXResourcesBuildPhase section */ 178 | 179 | /* Begin PBXRezBuildPhase section */ 180 | 291302D218E4450900F1D68D /* Rez */ = { 181 | isa = PBXRezBuildPhase; 182 | buildActionMask = 2147483647; 183 | files = ( 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | }; 187 | /* End PBXRezBuildPhase section */ 188 | 189 | /* Begin PBXSourcesBuildPhase section */ 190 | 291302CE18E4450900F1D68D /* Sources */ = { 191 | isa = PBXSourcesBuildPhase; 192 | buildActionMask = 2147483647; 193 | files = ( 194 | 29E732EB1B6E4D2E004BDE4C /* rusty_kext.rs in Sources */, 195 | 291302E018E4450900F1D68D /* RustyKext.c in Sources */, 196 | ); 197 | runOnlyForDeploymentPostprocessing = 0; 198 | }; 199 | /* End PBXSourcesBuildPhase section */ 200 | 201 | /* Begin PBXVariantGroup section */ 202 | 291302DC18E4450900F1D68D /* InfoPlist.strings */ = { 203 | isa = PBXVariantGroup; 204 | children = ( 205 | 291302DD18E4450900F1D68D /* en */, 206 | ); 207 | name = InfoPlist.strings; 208 | sourceTree = ""; 209 | }; 210 | /* End PBXVariantGroup section */ 211 | 212 | /* Begin XCBuildConfiguration section */ 213 | 291302E218E4450900F1D68D /* Debug */ = { 214 | isa = XCBuildConfiguration; 215 | buildSettings = { 216 | ALWAYS_SEARCH_USER_PATHS = NO; 217 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 218 | CLANG_CXX_LIBRARY = "libc++"; 219 | CLANG_ENABLE_MODULES = YES; 220 | CLANG_ENABLE_OBJC_ARC = YES; 221 | CLANG_WARN_BOOL_CONVERSION = YES; 222 | CLANG_WARN_CONSTANT_CONVERSION = YES; 223 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 224 | CLANG_WARN_EMPTY_BODY = YES; 225 | CLANG_WARN_ENUM_CONVERSION = YES; 226 | CLANG_WARN_INT_CONVERSION = YES; 227 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 228 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 229 | COPY_PHASE_STRIP = NO; 230 | GCC_C_LANGUAGE_STANDARD = gnu99; 231 | GCC_DYNAMIC_NO_PIC = NO; 232 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 233 | GCC_OPTIMIZATION_LEVEL = 0; 234 | GCC_PREPROCESSOR_DEFINITIONS = ( 235 | "DEBUG=1", 236 | "$(inherited)", 237 | ); 238 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 241 | GCC_WARN_UNDECLARED_SELECTOR = YES; 242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 243 | GCC_WARN_UNUSED_FUNCTION = YES; 244 | GCC_WARN_UNUSED_VARIABLE = YES; 245 | MACOSX_DEPLOYMENT_TARGET = 10.8; 246 | ONLY_ACTIVE_ARCH = YES; 247 | SDKROOT = macosx; 248 | }; 249 | name = Debug; 250 | }; 251 | 291302E318E4450900F1D68D /* Release */ = { 252 | isa = XCBuildConfiguration; 253 | buildSettings = { 254 | ALWAYS_SEARCH_USER_PATHS = NO; 255 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 256 | CLANG_CXX_LIBRARY = "libc++"; 257 | CLANG_ENABLE_MODULES = YES; 258 | CLANG_ENABLE_OBJC_ARC = YES; 259 | CLANG_WARN_BOOL_CONVERSION = YES; 260 | CLANG_WARN_CONSTANT_CONVERSION = YES; 261 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 262 | CLANG_WARN_EMPTY_BODY = YES; 263 | CLANG_WARN_ENUM_CONVERSION = YES; 264 | CLANG_WARN_INT_CONVERSION = YES; 265 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 266 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 267 | COPY_PHASE_STRIP = YES; 268 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 269 | ENABLE_NS_ASSERTIONS = NO; 270 | GCC_C_LANGUAGE_STANDARD = gnu99; 271 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 272 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 273 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 274 | GCC_WARN_UNDECLARED_SELECTOR = YES; 275 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 276 | GCC_WARN_UNUSED_FUNCTION = YES; 277 | GCC_WARN_UNUSED_VARIABLE = YES; 278 | MACOSX_DEPLOYMENT_TARGET = 10.8; 279 | SDKROOT = macosx; 280 | }; 281 | name = Release; 282 | }; 283 | 291302E518E4450900F1D68D /* Debug */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | COMBINE_HIDPI_IMAGES = YES; 287 | EXPORTED_SYMBOLS_FILE = RustyKext/RustyKext.exp; 288 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 289 | GCC_PREFIX_HEADER = "RustyKext/RustyKext-Prefix.pch"; 290 | INFOPLIST_FILE = "RustyKext/RustyKext-Info.plist"; 291 | MODULE_NAME = eu.philjordan.RustyKext; 292 | MODULE_START = RustyKext_start; 293 | MODULE_STOP = RustyKext_stop; 294 | MODULE_VERSION = 1.0.0d1; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | SDKROOT = macosx10.9; 297 | WRAPPER_EXTENSION = kext; 298 | }; 299 | name = Debug; 300 | }; 301 | 291302E618E4450900F1D68D /* Release */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | COMBINE_HIDPI_IMAGES = YES; 305 | EXPORTED_SYMBOLS_FILE = RustyKext/RustyKext.exp; 306 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 307 | GCC_PREFIX_HEADER = "RustyKext/RustyKext-Prefix.pch"; 308 | INFOPLIST_FILE = "RustyKext/RustyKext-Info.plist"; 309 | MODULE_NAME = eu.philjordan.RustyKext; 310 | MODULE_START = RustyKext_start; 311 | MODULE_STOP = RustyKext_stop; 312 | MODULE_VERSION = 1.0.0d1; 313 | PRODUCT_NAME = "$(TARGET_NAME)"; 314 | SDKROOT = macosx10.9; 315 | WRAPPER_EXTENSION = kext; 316 | }; 317 | name = Release; 318 | }; 319 | /* End XCBuildConfiguration section */ 320 | 321 | /* Begin XCConfigurationList section */ 322 | 291302CD18E4450900F1D68D /* Build configuration list for PBXProject "RustyKext" */ = { 323 | isa = XCConfigurationList; 324 | buildConfigurations = ( 325 | 291302E218E4450900F1D68D /* Debug */, 326 | 291302E318E4450900F1D68D /* Release */, 327 | ); 328 | defaultConfigurationIsVisible = 0; 329 | defaultConfigurationName = Release; 330 | }; 331 | 291302E418E4450900F1D68D /* Build configuration list for PBXNativeTarget "RustyKext" */ = { 332 | isa = XCConfigurationList; 333 | buildConfigurations = ( 334 | 291302E518E4450900F1D68D /* Debug */, 335 | 291302E618E4450900F1D68D /* Release */, 336 | ); 337 | defaultConfigurationIsVisible = 0; 338 | defaultConfigurationName = Release; 339 | }; 340 | /* End XCConfigurationList section */ 341 | }; 342 | rootObject = 291302CA18E4450900F1D68D /* Project object */; 343 | } 344 | -------------------------------------------------------------------------------- /RustyKext.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RustyKext/RustyKext-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | eu.philjordan.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | KEXT 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | OSBundleLibraries 26 | 27 | com.apple.kpi.libkern 28 | 10.0.0 29 | com.apple.kpi.iokit 30 | 10.0.0 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /RustyKext/RustyKext-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | -------------------------------------------------------------------------------- /RustyKext/RustyKext.c: -------------------------------------------------------------------------------- 1 | // 2 | // RustyKext.c 3 | // RustyKext 4 | // 5 | // Created by Phil Jordan on 27/03/2014. 6 | // 7 | // 8 | 9 | #include 10 | #include 11 | 12 | void rust_main(void); 13 | 14 | kern_return_t RustyKext_start(kmod_info_t * ki, void *d); 15 | kern_return_t RustyKext_stop(kmod_info_t *ki, void *d); 16 | 17 | kern_return_t RustyKext_start(kmod_info_t * ki, void *d) 18 | { 19 | rust_main(); 20 | return KERN_SUCCESS; 21 | } 22 | 23 | kern_return_t RustyKext_stop(kmod_info_t *ki, void *d) 24 | { 25 | return KERN_SUCCESS; 26 | } 27 | 28 | /* I currently can't find a way to declare variadic C functions in rust, so I've 29 | * added this wrapper function. Note also that rust strings are not 30 | * \0-terminated, so I'm using using the %*s format string to pass the length 31 | * in explicitly. */ 32 | void IOLogString(const char* str, int len) 33 | { 34 | IOLog("%*s", len, str); 35 | } 36 | -------------------------------------------------------------------------------- /RustyKext/RustyKext.exp: -------------------------------------------------------------------------------- 1 | # RustyKext.exp 2 | # RustyKext 3 | # 4 | # Created by Phil Dennis-Jordan on 02/08/2015. 5 | # 6 | 7 | _kmod_info 8 | -------------------------------------------------------------------------------- /RustyKext/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /RustyKext/rusty_kext.rs: -------------------------------------------------------------------------------- 1 | #![crate_type="lib"] 2 | #![feature(lang_items, start, no_std, core, core_str_ext)] 3 | #![no_std] 4 | extern crate core; 5 | 6 | use core::str::*; 7 | 8 | extern "C" { 9 | pub fn IOLogString(str: *const i8, len: i32); 10 | } 11 | 12 | unsafe fn print(s: &str) { 13 | IOLogString(s.as_ptr() as *const i8, s.len() as i32); 14 | } 15 | 16 | #[no_mangle] 17 | pub unsafe fn rust_main() { 18 | print("hello from rust\n\0"); 19 | } 20 | 21 | #[lang = "stack_exhausted"] extern fn stack_exhausted() {} 22 | #[lang = "eh_personality"] extern fn eh_personality() {} 23 | #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } 24 | --------------------------------------------------------------------------------