Skip to content

Commit

Permalink
Update docs with the new features and be a bit more explicit on mmap …
Browse files Browse the repository at this point in the history
…failures in the runtime library
  • Loading branch information
CensoredUsername committed Sep 25, 2016
1 parent 7241c57 commit 816ca69
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 40 deletions.
2 changes: 1 addition & 1 deletion build_docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mkdir ./build_docs/plugin
mkdir ./build_docs/runtime

# create instruction reference markdown file
(cd doc/insref && cargo run > ../instructionref.md)
(cd doc/insref && cargo update && cargo run > ../instructionref.md)

# build plugin docs
for f in ./doc/*.md; do
Expand Down
14 changes: 5 additions & 9 deletions doc/examples/bf-jit/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,15 @@ impl Program {
);
},
b',' => {
call_extern!(ops, State::getchar);
dynasm!(ops
;; call_extern!(ops, State::getchar)
; cmp al, 0
; jnz ->io_failure
);
},
b'.' => {
call_extern!(ops, State::putchar);
dynasm!(ops
;; call_extern!(ops, State::putchar)
; cmp al, 0
; jnz ->io_failure
);
Expand Down Expand Up @@ -172,17 +172,13 @@ impl Program {
return Err("[ without matching ]");
}

epilogue!(ops, 0);

dynasm!(ops
;; epilogue!(ops, 0)
;->overflow:
);
epilogue!(ops, 1);

dynasm!(ops
;; epilogue!(ops, 1)
;->io_failure:
;; epilogue!(ops, 2)
);
epilogue!(ops, 2);

let code = ops.finalize().unwrap();
Ok(Program {
Expand Down
30 changes: 26 additions & 4 deletions doc/langref.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ The following syntax units used in dynasm syntax are defined by the [rust gramma
- `ident`
- `expr_path`
- `expr`
- `stmt`


Dynasm-rs defines the following base syntax units:

Expand All @@ -26,7 +28,7 @@ The entry point of dynasm-rs is the dynasm! macro. It is structured as following

Where line can be one of the following:

`line : directive | label | instruction ;`
`line : (";" stmt) | directive | label | instruction ;`

## Directives

Expand Down Expand Up @@ -98,13 +100,13 @@ macro_rules! fma {
}
```

An important thing to notice here is which matchers are used for which parts of dynasm! syntax. The following table lists the correct matchers to be used for expanding to dynasm syntax elements. Note that `$a:expr` means that anything that parses to an expression like `$a:ident` and just raw token trees are allowed.
An important thing to notice here is which matchers are used for which parts of `dynasm!` syntax. The following table lists the correct matchers to be used for expanding to dynasm syntax elements. Note that `$a:expr` means that anything that parses to an expression like `$a:ident` and just raw token trees are allowed.

Table 2: dynasm-rs macro expansion rules

Syntax element | Matchers
:----------------------|:------------------------
Assembling buffer | `$ops:ident`
Assembling buffer | `$ops:expr`
Register reference | `$reg:expr`
Memory reference | `$mem:expr`
Any element inside a memory reference | `$elem:expr, $reg:ident`
Expand All @@ -113,6 +115,26 @@ Local or global label name | `$label:ident`
Dynamic label | `$label:expr`
Type map | `$reg:expr => $type:path[$reg:expr].$attr:ident`

## statements

To make code that uses a lot of macros less verbose, dynasm-rs allows bare rust statements to be inserted inside `dynasm!` invocations. This can be done by using a double semicolon instead of a single semicolon at the start of the line as displayed in the following equivalent examples:

```
dynasm!(ops
; mov rcx, rax
);
call_extern!(ops, extern_func);
dynasm!(ops
; mov rcx, rax
);
dynasm!(ops
; mov rcx, rax
;; call_extern!(ops, extern_func)
; mov rcx, rax
);
```

## Labels

In order to describe flow control effectively, dynasm-rs supports labels. However, since the assembly templates can be combined in a variety of ways at the mercy of the program using dynasm-rs, the semantics of these labels are somewhat different from how labels work in a static assembler.
Expand Down Expand Up @@ -209,7 +231,7 @@ Syntax | Equivalent expression
:------|:-----------
`rax => Type.attr` | `(rax as *mut Type).attr`
`rax => Type[expr]` | `(rax as *mut [Type])[expr]`
`rax => Type[rbx + expr]` | `(rax as *mut [Type])[rbx + expr]`
`rax => Type[rbx]` | `(rax as *mut [Type])[rbx]`
`rax => Type[rbx + expr].attr` | `(rax as *mut [Type])[rbx + expr].attr `

#### Immediates
Expand Down
28 changes: 10 additions & 18 deletions doc/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -593,8 +593,8 @@ We can then simply call these methods directly from the compiled code. If the I/
- }
```
```diffnew
+ call_extern!(ops, State::getchar);
+ dynasm!(ops
+ ;; call_extern!(ops, State::getchar)
+ ; cmp al, 0
+ ; jnz ->io_failure
+ );
Expand All @@ -606,8 +606,8 @@ We can then simply call these methods directly from the compiled code. If the I/
- }
```
```diffnew
+ call_extern!(ops, State::putchar);
+ dynasm!(ops
+ ;; call_extern!(ops, State::putchar)
+ ; cmp al, 0
+ ; jnz ->io_failure
+ );
Expand Down Expand Up @@ -679,17 +679,13 @@ The `[` and `]` commands have the most complex implementation. When a `[` is enc
With the end of the parsing reached, we must now handle the return and possible error conditions. This is done by returning 0 if the executionw as successful, or an error code when an error happened at runtime.

```diffnew
+ epilogue!(ops, 0);
+
+ dynasm!(ops
+ ;; epilogue!(ops, 0)
+ ;->overflow:
+ );
+ epilogue!(ops, 1);
+
+ dynasm!(ops
+ ;; epilogue!(ops, 1)
+ ;->io_failure:
+ ;; epilogue!(ops, 2)
+ );
+ epilogue!(ops, 2);
```

Now we can finalize the assembler and construct a Program from the resulting buffer:
Expand Down Expand Up @@ -904,15 +900,15 @@ impl Program {
);
},
b',' => {
call_extern!(ops, State::getchar);
dynasm!(ops
;; call_extern!(ops, State::getchar)
; cmp al, 0
; jnz ->io_failure
);
},
b'.' => {
call_extern!(ops, State::putchar);
dynasm!(ops
;; call_extern!(ops, State::putchar)
; cmp al, 0
; jnz ->io_failure
);
Expand Down Expand Up @@ -954,17 +950,13 @@ impl Program {
return Err("[ without matching ]");
}
epilogue!(ops, 0);
dynasm!(ops
;; epilogue!(ops, 0)
;->overflow:
);
epilogue!(ops, 1);
dynasm!(ops
;; epilogue!(ops, 1)
;->io_failure:
;; epilogue!(ops, 2)
);
epilogue!(ops, 2);
let code = ops.finalize().unwrap();
Ok(Program {
Expand Down
20 changes: 12 additions & 8 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ macro_rules! Pointer {
($e:expr) => {$e as *const _ as _};
}

/// Preforms the same action as the Pointer! macro, but casts to a *mut pointer.
/// Preforms the same action as the `Pointer!` macro, but casts to a *mut pointer.
#[macro_export]
macro_rules! MutPointer {
($e:expr) => {$e as *mut _ as _};
Expand Down Expand Up @@ -191,7 +191,7 @@ impl Assembler {
Assembler {
execbuffer: Arc::new(RwLock::new(ExecutableBuffer {
length: 0,
buffer: Mmap::anonymous(MMAP_INIT_SIZE, Protection::ReadExecute).unwrap()
buffer: Mmap::anonymous(MMAP_INIT_SIZE, Protection::ReadExecute).expect("Failed to allocate executable memory")
})),
asmoffset: 0,
map_len: MMAP_INIT_SIZE,
Expand Down Expand Up @@ -227,7 +227,7 @@ impl Assembler {
let lock = self.execbuffer.clone();
let mut lock = lock.write().unwrap();
let buf = lock.deref_mut();
buf.buffer.set_protection(Protection::ReadWrite).unwrap();
buf.buffer.set_protection(Protection::ReadWrite).expect("Failed to change memory protection mode");

{
let mut m = AssemblyModifier {
Expand All @@ -238,11 +238,15 @@ impl Assembler {
m.encode_relocs();
}

buf.buffer.set_protection(Protection::ReadExecute).unwrap();
buf.buffer.set_protection(Protection::ReadExecute).expect("Failed to change memory protection mode");
self.asmoffset = asmoffset;
// no commit is required as we directly modified the buffer.
}

/// Similar to `Assembler::alter`, this method allows modification of the yet to be
/// committed assembing buffer. Note that it is not possible to use labels in this
/// context, and overriding labels will cause corruption when the assembler tries to
/// resolve the labels at commit time.
pub fn alter_uncommitted<F>(&mut self, f: F) where F: FnOnce(&mut UncommittedModifier) -> () {
f(&mut UncommittedModifier {
offset: self.asmoffset,
Expand Down Expand Up @@ -317,15 +321,15 @@ impl Assembler {
if buf_end > self.map_len {
// create a new buffer of the necessary size max(current_buf_len * 2, wanted_len)
let map_len = cmp::max(buf_end, self.map_len * 2);
let mut new_buf = Mmap::anonymous(map_len, Protection::ReadWrite).unwrap();
let mut new_buf = Mmap::anonymous(map_len, Protection::ReadWrite).expect("Failed to change memory protection mode");
self.map_len = new_buf.len();

// copy over from the old buffer and the asm buffer (unsafe is completely safe due to use of anonymous mappings)
unsafe {
new_buf.as_mut_slice()[same].copy_from_slice(&self.execbuffer.read().unwrap().buffer.as_slice()[same]);
new_buf.as_mut_slice()[changed].copy_from_slice(&self.ops);
}
new_buf.set_protection(Protection::ReadExecute).unwrap();
new_buf.set_protection(Protection::ReadExecute).expect("Failed to change memory protection mode");

// swap the buffers and the initialized length
let mut data = ExecutableBuffer {
Expand All @@ -337,11 +341,11 @@ impl Assembler {
} else {
// make the buffer writeable and copy things over.
let mut data = self.execbuffer.write().unwrap();
data.buffer.set_protection(Protection::ReadWrite).unwrap();
data.buffer.set_protection(Protection::ReadWrite).expect("Failed to change memory protection mode");
unsafe {
data.buffer.as_mut_slice()[changed].copy_from_slice(&self.ops);
}
data.buffer.set_protection(Protection::ReadExecute).unwrap();
data.buffer.set_protection(Protection::ReadExecute).expect("Failed to change memory protection mode");
// update the length of the initialized part of the buffer, if this commit adds length
if buf_end > data.length {
data.length = buf_end;
Expand Down

0 comments on commit 816ca69

Please sign in to comment.