Skip to content

Commit a7bee7b

Browse files
committed
Add a crate for missing stubs from libcore
The core library in theory has 0 dependencies, but in practice it has some in order for it to be efficient. These dependencies are in the form of the basic memory operations provided by libc traditionally, such as memset, memcmp, etc. These functions are trivial to implement and themselves have 0 dependencies. This commit adds a new crate, librlibc, which will serve the purpose of providing these dependencies. The crate is never linked to by default, but is available to be linked to by downstream consumers. Normally these functions are provided by the system libc, but in other freestanding contexts a libc may not be available. In these cases, librlibc will suffice for enabling execution with libcore. cc #10116
1 parent e043644 commit a7bee7b

File tree

10 files changed

+141
-16
lines changed

10 files changed

+141
-16
lines changed

mk/crates.mk

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,13 @@
5151

5252
TARGET_CRATES := libc std green rustuv native flate arena glob term semver \
5353
uuid serialize sync getopts collections num test time rand \
54-
workcache url log regex graphviz core
54+
workcache url log regex graphviz core rlibc
5555
HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros fmt_macros
5656
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
5757
TOOLS := compiletest rustdoc rustc
5858

5959
DEPS_core :=
60+
DEPS_rlibc :=
6061
DEPS_std := core libc native:rustrt native:compiler-rt native:backtrace native:jemalloc
6162
DEPS_green := std rand native:context_switch
6263
DEPS_rustuv := std native:uv native:uv_support
@@ -98,6 +99,7 @@ TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs
9899
TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
99100

100101
ONLY_RLIB_core := 1
102+
ONLY_RLIB_rlibc := 1
101103

102104
################################################################################
103105
# You should not need to edit below this line

src/doc/rust.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,6 +1799,8 @@ type int8_t = i8;
17991799
- `no_start` - disable linking to the `native` crate, which specifies the
18001800
"start" language item.
18011801
- `no_std` - disable linking to the `std` crate.
1802+
- `no_builtins` - disable optimizing certain code patterns to invocations of
1803+
library functions that are assumed to exist
18021804

18031805
### Module-only attributes
18041806

src/libcore/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
//! * `memcpy`, `memcmp`, `memset` - These are core memory routines which are
1919
//! often generated by LLVM. Additionally, this library can make explicit
2020
//! calls to these funcitons. Their signatures are the same as found in C.
21+
//! These functions are often provided by the system libc, but can also be
22+
//! provided by `librlibc` which is distributed with the standard rust
23+
//! distribution.
2124
//!
2225
//! * `rust_begin_unwind` - This function takes three arguments, a
2326
//! `&fmt::Arguments`, a `&str`, and a `uint. These three arguments dictate

src/librlibc/lib.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! A bare-metal library supplying functions rustc may lower code to
12+
//!
13+
//! This library is not intended for general use, and is superseded by a system
14+
//! libc if one is available. In a freestanding context, however, common
15+
//! functions such as memset, memcpy, etc are not implemented. This library
16+
//! provides an implementation of these functions which are either required by
17+
//! libcore or called by rustc implicitly.
18+
//!
19+
//! This library is never included by default, and must be manually included if
20+
//! necessary. It is an error to include this library when also linking with
21+
//! the system libc library.
22+
23+
#![crate_id = "rlibc#0.11.0-pre"]
24+
#![license = "MIT/ASL2"]
25+
#![crate_type = "rlib"]
26+
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
27+
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
28+
html_root_url = "http://static.rust-lang.org/doc/master")]
29+
30+
#![no_std]
31+
#![experimental]
32+
33+
// This library is definining the builtin functions, so it would be a shame for
34+
// LLVM to optimize these function calls to themselves!
35+
#![no_builtins]
36+
37+
#[cfg(test)] extern crate std;
38+
#[cfg(test)] extern crate native;
39+
40+
// Require the offset intrinsics for LLVM to properly optimize the
41+
// implementations below. If pointer arithmetic is done through integers the
42+
// optimizations start to break down.
43+
extern "rust-intrinsic" {
44+
fn offset<T>(dst: *T, offset: int) -> *T;
45+
}
46+
47+
#[no_mangle]
48+
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *u8, n: uint) -> *mut u8 {
49+
let mut i = 0;
50+
while i < n {
51+
*(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int);
52+
i += 1;
53+
}
54+
return dest;
55+
}
56+
57+
#[no_mangle]
58+
pub unsafe extern "C" fn memmove(dest: *mut u8, src: *u8, n: uint) -> *mut u8 {
59+
if src < dest as *u8 { // copy from end
60+
let mut i = n;
61+
while i != 0 {
62+
i -= 1;
63+
*(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int);
64+
}
65+
} else { // copy from beginning
66+
let mut i = 0;
67+
while i < n {
68+
*(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int);
69+
i += 1;
70+
}
71+
}
72+
return dest;
73+
}
74+
75+
#[no_mangle]
76+
pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: uint) -> *mut u8 {
77+
let mut i = 0;
78+
while i < n {
79+
*(offset(s as *u8, i as int) as *mut u8) = c as u8;
80+
i += 1;
81+
}
82+
return s;
83+
}
84+
85+
#[no_mangle]
86+
pub unsafe extern "C" fn memcmp(s1: *u8, s2: *u8, n: uint) -> i32 {
87+
let mut i = 0;
88+
while i < n {
89+
let a = *offset(s1, i as int);
90+
let b = *offset(s2, i as int);
91+
if a != b {
92+
return (a - b) as i32
93+
}
94+
i += 1;
95+
}
96+
return 0;
97+
}
98+
99+
#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows

src/librustc/back/link.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ pub mod write {
212212
if !sess.opts.cg.no_prepopulate_passes {
213213
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
214214
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
215-
populate_llvm_passes(fpm, mpm, llmod, opt_level);
215+
populate_llvm_passes(fpm, mpm, llmod, opt_level,
216+
trans.no_builtins);
216217
}
217218

218219
for pass in sess.opts.cg.passes.iter() {
@@ -264,11 +265,11 @@ pub mod write {
264265
// escape the closure itself, and the manager should only be
265266
// used once.
266267
fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
267-
f: |PassManagerRef|) {
268+
no_builtins: bool, f: |PassManagerRef|) {
268269
unsafe {
269270
let cpm = llvm::LLVMCreatePassManager();
270271
llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
271-
llvm::LLVMRustAddLibraryInfo(cpm, llmod);
272+
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
272273
f(cpm);
273274
llvm::LLVMDisposePassManager(cpm);
274275
}
@@ -286,7 +287,7 @@ pub mod write {
286287
}
287288
OutputTypeLlvmAssembly => {
288289
path.with_c_str(|output| {
289-
with_codegen(tm, llmod, |cpm| {
290+
with_codegen(tm, llmod, trans.no_builtins, |cpm| {
290291
llvm::LLVMRustPrintModule(cpm, llmod, output);
291292
})
292293
})
@@ -303,7 +304,7 @@ pub mod write {
303304
needs_metadata = true;
304305
output.temp_path(OutputTypeAssembly)
305306
};
306-
with_codegen(tm, llmod, |cpm| {
307+
with_codegen(tm, llmod, trans.no_builtins, |cpm| {
307308
WriteOutputFile(sess, tm, cpm, llmod, &path,
308309
lib::llvm::AssemblyFile);
309310
});
@@ -321,15 +322,16 @@ pub mod write {
321322
time(sess.time_passes(), "codegen passes", (), |()| {
322323
match object_file {
323324
Some(ref path) => {
324-
with_codegen(tm, llmod, |cpm| {
325+
with_codegen(tm, llmod, trans.no_builtins, |cpm| {
325326
WriteOutputFile(sess, tm, cpm, llmod, path,
326327
lib::llvm::ObjectFile);
327328
});
328329
}
329330
None => {}
330331
}
331332
if needs_metadata {
332-
with_codegen(tm, trans.metadata_module, |cpm| {
333+
with_codegen(tm, trans.metadata_module,
334+
trans.no_builtins, |cpm| {
333335
let out = output.temp_path(OutputTypeObject)
334336
.with_extension("metadata.o");
335337
WriteOutputFile(sess, tm, cpm,
@@ -437,7 +439,8 @@ pub mod write {
437439
unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef,
438440
mpm: lib::llvm::PassManagerRef,
439441
llmod: ModuleRef,
440-
opt: lib::llvm::CodeGenOptLevel) {
442+
opt: lib::llvm::CodeGenOptLevel,
443+
no_builtins: bool) {
441444
// Create the PassManagerBuilder for LLVM. We configure it with
442445
// reasonable defaults and prepare it to actually populate the pass
443446
// manager.
@@ -461,7 +464,7 @@ pub mod write {
461464
}
462465
}
463466
llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint);
464-
llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
467+
llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, no_builtins);
465468

466469
// Use the builder to populate the function/module pass managers.
467470
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);

src/librustc/driver/driver.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ pub struct CrateTranslation {
356356
pub metadata: Vec<u8>,
357357
pub reachable: Vec<StrBuf>,
358358
pub crate_formats: dependency_format::Dependencies,
359+
pub no_builtins: bool,
359360
}
360361

361362
/// Run the translation phase to LLVM, after which the AST and analysis can

src/librustc/lib/llvm.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,8 +1755,10 @@ pub mod llvm {
17551755
PM: PassManagerRef,
17561756
M: ModuleRef);
17571757
pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef,
1758-
M: ModuleRef);
1759-
pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef);
1758+
M: ModuleRef,
1759+
DisableSimplifyLibCalls: bool);
1760+
pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef,
1761+
DisableSimplifyLibCalls: bool);
17601762
pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef);
17611763
pub fn LLVMRustWriteOutputFile(T: TargetMachineRef,
17621764
PM: PassManagerRef,

src/librustc/middle/lint.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,7 @@ fn check_raw_ptr_deriving(cx: &mut Context, item: &ast::Item) {
10501050
static crate_attrs: &'static [&'static str] = &[
10511051
"crate_type", "feature", "no_start", "no_main", "no_std", "crate_id",
10521052
"desc", "comment", "license", "copyright", // not used in rustc now
1053+
"no_builtins",
10531054
];
10541055

10551056

src/librustc/middle/trans/base.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2226,6 +2226,7 @@ pub fn trans_crate(krate: ast::Crate,
22262226

22272227
let metadata_module = ccx.metadata_llmod;
22282228
let formats = ccx.tcx.dependency_formats.borrow().clone();
2229+
let no_builtins = attr::contains_name(krate.attrs.as_slice(), "no_builtins");
22292230

22302231
(ccx.tcx, CrateTranslation {
22312232
context: llcx,
@@ -2235,5 +2236,6 @@ pub fn trans_crate(krate: ast::Crate,
22352236
metadata: metadata,
22362237
reachable: reachable,
22372238
crate_formats: formats,
2239+
no_builtins: no_builtins,
22382240
})
22392241
}

src/rustllvm/PassWrapper.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,17 +128,27 @@ LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM,
128128
// Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`
129129
// field of a PassManagerBuilder, we expose our own method of doing so.
130130
extern "C" void
131-
LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB, LLVMModuleRef M) {
131+
LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB,
132+
LLVMModuleRef M,
133+
bool DisableSimplifyLibCalls) {
132134
Triple TargetTriple(unwrap(M)->getTargetTriple());
133-
unwrap(PMB)->LibraryInfo = new TargetLibraryInfo(TargetTriple);
135+
TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
136+
if (DisableSimplifyLibCalls)
137+
TLI->disableAllFunctions();
138+
unwrap(PMB)->LibraryInfo = TLI;
134139
}
135140

136141
// Unfortunately, the LLVM C API doesn't provide a way to create the
137142
// TargetLibraryInfo pass, so we use this method to do so.
138143
extern "C" void
139-
LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, LLVMModuleRef M) {
144+
LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB,
145+
LLVMModuleRef M,
146+
bool DisableSimplifyLibCalls) {
140147
Triple TargetTriple(unwrap(M)->getTargetTriple());
141-
unwrap(PMB)->add(new TargetLibraryInfo(TargetTriple));
148+
TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
149+
if (DisableSimplifyLibCalls)
150+
TLI->disableAllFunctions();
151+
unwrap(PMB)->add(TLI);
142152
}
143153

144154
// Unfortunately, the LLVM C API doesn't provide an easy way of iterating over

0 commit comments

Comments
 (0)