Fixed version of hw2
Signed-off-by: jmug <u.g.a.mariano@gmail.com>
This commit is contained in:
parent
3308388106
commit
b8fc429f4d
25 changed files with 1983 additions and 1963 deletions
|
|
@ -4,32 +4,35 @@ FROM ubuntu:20.04
|
||||||
|
|
||||||
# Create a user
|
# Create a user
|
||||||
|
|
||||||
ARG USERNAME=cis3410
|
ARG USERNAME=cs131
|
||||||
ARG USER_UID=1000
|
ARG USER_UID=1000
|
||||||
ARG USER_GID=$USER_UID
|
ARG USER_GID=$USER_UID
|
||||||
|
|
||||||
ENV TZ='Asia/Shanghai'
|
ENV TZ='Asia/Shanghai'
|
||||||
# !!![zjy] apt change ustc source
|
# !!![zjy] apt change ustc source
|
||||||
RUN apt-get update -y\
|
RUN apt-get update -y \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
apt-transport-https \
|
apt-transport-https \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
|
dos2unix \
|
||||||
tzdata \
|
tzdata \
|
||||||
&& sed -i "s@http://.*.ubuntu.com@https://mirrors.ustc.edu.cn@g" /etc/apt/sources.list \
|
&& sed -i "s@http://.*.ubuntu.com@https://mirrors.ustc.edu.cn@g" /etc/apt/sources.list \
|
||||||
&& rm -rf /var/apt/cache/*
|
&& rm -rf /var/apt/cache/*
|
||||||
|
|
||||||
RUN groupadd --gid $USER_GID $USERNAME \
|
RUN groupadd --gid $USER_GID $USERNAME \
|
||||||
#
|
|
||||||
# [Optional] Add sudo support. Omit if you don't need to install software after connecting.
|
# [Optional] Add sudo support. Omit if you don't need to install software after connecting.
|
||||||
&& apt-get update -y \
|
&& apt-get update \
|
||||||
&& apt-get install -y sudo \
|
&& apt-get install -y sudo \
|
||||||
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
|
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
|
||||||
&& chmod 0440 /etc/sudoers.d/$USERNAME
|
&& chmod 0440 /etc/sudoers.d/$USERNAME
|
||||||
|
|
||||||
|
|
||||||
## Hack needs root permissions
|
## Hack needs root permissions
|
||||||
|
|
||||||
# See hack.sh
|
# See hack.sh
|
||||||
COPY hack.sh /tmp/hack.sh
|
COPY hack.sh /tmp/hack.sh
|
||||||
|
# windows compatibility
|
||||||
|
RUN dos2unix /tmp/hack.sh
|
||||||
RUN chmod +x /tmp/hack.sh
|
RUN chmod +x /tmp/hack.sh
|
||||||
RUN /tmp/hack.sh
|
RUN /tmp/hack.sh
|
||||||
|
|
||||||
|
|
@ -46,8 +49,10 @@ RUN apt-get install -y zsh
|
||||||
# !!![zjy] install zsh first then set user
|
# !!![zjy] install zsh first then set user
|
||||||
RUN useradd --uid $USER_UID --gid $USER_GID -m $USERNAME --shell /bin/zsh
|
RUN useradd --uid $USER_UID --gid $USER_GID -m $USERNAME --shell /bin/zsh
|
||||||
|
|
||||||
|
|
||||||
## Set up user environmnent
|
## Set up user environmnent
|
||||||
COPY .zshrc /home/$USERNAME/
|
COPY .zshrc /home/$USERNAME/
|
||||||
|
RUN dos2unix /home/$USERNAME/.zshrc
|
||||||
RUN chown $USERNAME /home/$USERNAME/.zshrc
|
RUN chown $USERNAME /home/$USERNAME/.zshrc
|
||||||
|
|
||||||
## Run in usermode
|
## Run in usermode
|
||||||
|
|
@ -60,12 +65,13 @@ RUN touch /home/$USERNAME/.local/state/utop-history
|
||||||
|
|
||||||
# Configure opam/ocaml
|
# Configure opam/ocaml
|
||||||
# !!![zjy] change default repo to github (SJTU repo is failed)
|
# !!![zjy] change default repo to github (SJTU repo is failed)
|
||||||
RUN opam init --yes --disable-sandboxing default https://github.com/ocaml/opam-repository.git
|
# RUN opam init --yes --disable-sandboxing default https://github.com/ocaml/opam-repository.git
|
||||||
RUN opam switch create 4.14.1 ocaml-base-compiler.4.14.1
|
RUN opam init -y --disable-sandboxing --compiler=4.14.1
|
||||||
|
# RUN opam switch create 4.14.1 ocaml-base-compiler.4.14.1
|
||||||
RUN opam switch 4.14.1
|
RUN opam switch 4.14.1
|
||||||
RUN opam install -y dune
|
RUN opam install --yes dune
|
||||||
RUN opam install -y num
|
RUN opam install --yes num
|
||||||
RUN opam install -y menhir
|
RUN opam install --yes menhir
|
||||||
RUN opam install -y utop
|
RUN opam install -y utop
|
||||||
RUN opam install -y ocamlformat
|
RUN opam install -y ocamlformat
|
||||||
RUN opam install -y ocaml-lsp-server
|
RUN opam install -y ocaml-lsp-server
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"ocamllabs.ocaml-platform",
|
"ocamllabs.ocaml-platform"
|
||||||
"allanblanchard.ocp-indent"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
profile = janestreet
|
profile = janestreet
|
||||||
version = 0.26.1
|
version = 0.26.2
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ open X86
|
||||||
|
|
||||||
(* simulator machine state -------------------------------------------------- *)
|
(* simulator machine state -------------------------------------------------- *)
|
||||||
|
|
||||||
let mem_bot = 0x400000L (* lowest valid address *)
|
let mem_bot = 0x400000L (* lowest valid address *)
|
||||||
let mem_top = 0x410000L (* one past the last byte in memory *)
|
let mem_top = 0x410000L (* one past the last byte in memory *)
|
||||||
let mem_size = Int64.to_int (Int64.sub mem_top mem_bot)
|
let mem_size = Int64.to_int (Int64.sub mem_top mem_bot)
|
||||||
let nregs = 17 (* including Rip *)
|
let nregs = 17 (* including Rip *)
|
||||||
let ins_size = 8L (* assume we have a 8-byte encoding *)
|
let ins_size = 8L (* assume we have a 8-byte encoding *)
|
||||||
let exit_addr = 0xfdeadL (* halt when m.regs(%rip) = exit_addr *)
|
let exit_addr = 0xfdeadL (* halt when m.regs(%rip) = exit_addr *)
|
||||||
|
|
||||||
(* The simulator memory maps addresses to symbolic bytes. Symbolic
|
(* The simulator memory maps addresses to symbolic bytes. Symbolic
|
||||||
bytes are either actual data indicated by the Byte constructor or
|
bytes are either actual data indicated by the Byte constructor or
|
||||||
|
|
@ -28,234 +28,253 @@ let exit_addr = 0xfdeadL (* halt when m.regs(%rip) = exit_addr *)
|
||||||
elements, which aren't valid data.
|
elements, which aren't valid data.
|
||||||
|
|
||||||
For example, the two-instruction sequence:
|
For example, the two-instruction sequence:
|
||||||
at&t syntax ocaml syntax
|
at&t syntax ocaml syntax
|
||||||
movq %rdi, (%rsp) Movq, [~%Rdi; Ind2 Rsp]
|
movq %rdi, (%rsp) Movq, [~%Rdi; Ind2 Rsp]
|
||||||
decq %rdi Decq, [~%Rdi]
|
decq %rdi Decq, [~%Rdi]
|
||||||
|
|
||||||
is represented by the following elements of the mem array (starting
|
is represented by the following elements of the mem array (starting
|
||||||
at address 0x400000):
|
at address 0x400000):
|
||||||
|
|
||||||
0x400000 : InsB0 (Movq, [~%Rdi; Ind2 Rsp])
|
0x400000 : InsB0 (Movq, [~%Rdi; Ind2 Rsp])
|
||||||
0x400001 : InsFrag
|
0x400001 : InsFrag
|
||||||
0x400002 : InsFrag
|
0x400002 : InsFrag
|
||||||
0x400003 : InsFrag
|
0x400003 : InsFrag
|
||||||
0x400004 : InsFrag
|
0x400004 : InsFrag
|
||||||
0x400005 : InsFrag
|
0x400005 : InsFrag
|
||||||
0x400006 : InsFrag
|
0x400006 : InsFrag
|
||||||
0x400007 : InsFrag
|
0x400007 : InsFrag
|
||||||
0x400008 : InsB0 (Decq, [~%Rdi])
|
0x400008 : InsB0 (Decq, [~%Rdi])
|
||||||
0x40000A : InsFrag
|
0x40000A : InsFrag
|
||||||
0x40000B : InsFrag
|
0x40000B : InsFrag
|
||||||
0x40000C : InsFrag
|
0x40000C : InsFrag
|
||||||
0x40000D : InsFrag
|
0x40000D : InsFrag
|
||||||
0x40000E : InsFrag
|
0x40000E : InsFrag
|
||||||
0x40000F : InsFrag
|
0x40000F : InsFrag
|
||||||
0x400010 : InsFrag
|
0x400010 : InsFrag
|
||||||
*)
|
*)
|
||||||
type sbyte = InsB0 of ins (* 1st byte of an instruction *)
|
type sbyte =
|
||||||
| InsFrag (* 2nd - 8th bytes of an instruction *)
|
| InsB0 of ins (* 1st byte of an instruction *)
|
||||||
| Byte of char (* non-instruction byte *)
|
| InsFrag (* 2nd - 8th bytes of an instruction *)
|
||||||
|
| Byte of char (* non-instruction byte *)
|
||||||
|
|
||||||
(* memory maps addresses to symbolic bytes *)
|
(* memory maps addresses to symbolic bytes *)
|
||||||
type mem = sbyte array
|
type mem = sbyte array
|
||||||
|
|
||||||
(* Flags for condition codes *)
|
(* Flags for condition codes *)
|
||||||
type flags = { mutable fo : bool
|
type flags =
|
||||||
; mutable fs : bool
|
{ mutable fo : bool
|
||||||
; mutable fz : bool
|
; mutable fs : bool
|
||||||
}
|
; mutable fz : bool
|
||||||
|
}
|
||||||
|
|
||||||
(* Register files *)
|
(* Register files *)
|
||||||
type regs = int64 array
|
type regs = int64 array
|
||||||
|
|
||||||
(* Complete machine state *)
|
(* Complete machine state *)
|
||||||
type mach = { flags : flags
|
type mach =
|
||||||
; regs : regs
|
{ flags : flags
|
||||||
; mem : mem
|
; regs : regs
|
||||||
}
|
; mem : mem
|
||||||
|
}
|
||||||
|
|
||||||
(* simulator helper functions ----------------------------------------------- *)
|
(* simulator helper functions ----------------------------------------------- *)
|
||||||
|
|
||||||
(* The index of a register in the regs array *)
|
(* The index of a register in the regs array *)
|
||||||
let rind : reg -> int = function
|
let rind : reg -> int = function
|
||||||
| Rip -> 16
|
| Rip -> 16
|
||||||
| Rax -> 0 | Rbx -> 1 | Rcx -> 2 | Rdx -> 3
|
| Rax -> 0
|
||||||
| Rsi -> 4 | Rdi -> 5 | Rbp -> 6 | Rsp -> 7
|
| Rbx -> 1
|
||||||
| R08 -> 8 | R09 -> 9 | R10 -> 10 | R11 -> 11
|
| Rcx -> 2
|
||||||
| R12 -> 12 | R13 -> 13 | R14 -> 14 | R15 -> 15
|
| Rdx -> 3
|
||||||
|
| Rsi -> 4
|
||||||
|
| Rdi -> 5
|
||||||
|
| Rbp -> 6
|
||||||
|
| Rsp -> 7
|
||||||
|
| R08 -> 8
|
||||||
|
| R09 -> 9
|
||||||
|
| R10 -> 10
|
||||||
|
| R11 -> 11
|
||||||
|
| R12 -> 12
|
||||||
|
| R13 -> 13
|
||||||
|
| R14 -> 14
|
||||||
|
| R15 -> 15
|
||||||
|
;;
|
||||||
|
|
||||||
(* Helper functions for reading/writing sbytes *)
|
(* Helper functions for reading/writing sbytes *)
|
||||||
|
|
||||||
(* Convert an int64 to its sbyte representation *)
|
(* Convert an int64 to its sbyte representation *)
|
||||||
let sbytes_of_int64 (i:int64) : sbyte list =
|
let sbytes_of_int64 (i : int64) : sbyte list =
|
||||||
let open Char in
|
let open Char in
|
||||||
let open Int64 in
|
let open Int64 in
|
||||||
List.map (fun n -> Byte (shift_right i n |> logand 0xffL |> to_int |> chr))
|
List.map
|
||||||
[0; 8; 16; 24; 32; 40; 48; 56]
|
(fun n -> Byte (shift_right i n |> logand 0xffL |> to_int |> chr))
|
||||||
|
[ 0; 8; 16; 24; 32; 40; 48; 56 ]
|
||||||
|
;;
|
||||||
|
|
||||||
(* Convert an sbyte representation to an int64 *)
|
(* Convert an sbyte representation to an int64 *)
|
||||||
let int64_of_sbytes (bs:sbyte list) : int64 =
|
let int64_of_sbytes (bs : sbyte list) : int64 =
|
||||||
let open Char in
|
let open Char in
|
||||||
let open Int64 in
|
let open Int64 in
|
||||||
let f b i = match b with
|
let f b i =
|
||||||
|
match b with
|
||||||
| Byte c -> logor (shift_left i 8) (c |> code |> of_int)
|
| Byte c -> logor (shift_left i 8) (c |> code |> of_int)
|
||||||
| _ -> 0L
|
| _ -> 0L
|
||||||
in
|
in
|
||||||
List.fold_right f bs 0L
|
List.fold_right f bs 0L
|
||||||
|
;;
|
||||||
|
|
||||||
(* Convert a string to its sbyte representation *)
|
(* Convert a string to its sbyte representation *)
|
||||||
let sbytes_of_string (s:string) : sbyte list =
|
let sbytes_of_string (s : string) : sbyte list =
|
||||||
let rec loop acc = function
|
let rec loop acc = function
|
||||||
| i when i < 0 -> acc
|
| i when i < 0 -> acc
|
||||||
| i -> loop (Byte s.[i]::acc) (pred i)
|
| i -> loop (Byte s.[i] :: acc) (pred i)
|
||||||
in
|
in
|
||||||
loop [Byte '\x00'] @@ String.length s - 1
|
loop [ Byte '\x00' ] @@ (String.length s - 1)
|
||||||
|
;;
|
||||||
|
|
||||||
(* Serialize an instruction to sbytes *)
|
(* Serialize an instruction to sbytes *)
|
||||||
let sbytes_of_ins (op, args:ins) : sbyte list =
|
let sbytes_of_ins ((op, args) : ins) : sbyte list =
|
||||||
let check = function
|
let check = function
|
||||||
| Imm (Lbl _) | Ind1 (Lbl _) | Ind3 (Lbl _, _) ->
|
| Imm (Lbl _) | Ind1 (Lbl _) | Ind3 (Lbl _, _) ->
|
||||||
invalid_arg "sbytes_of_ins: tried to serialize a label!"
|
invalid_arg "sbytes_of_ins: tried to serialize a label!"
|
||||||
| _ -> ()
|
| _ -> ()
|
||||||
in
|
in
|
||||||
List.iter check args;
|
List.iter check args;
|
||||||
[InsB0 (op, args); InsFrag; InsFrag; InsFrag;
|
[ InsB0 (op, args); InsFrag; InsFrag; InsFrag; InsFrag; InsFrag; InsFrag; InsFrag ]
|
||||||
InsFrag; InsFrag; InsFrag; InsFrag]
|
;;
|
||||||
|
|
||||||
(* Serialize a data element to sbytes *)
|
(* Serialize a data element to sbytes *)
|
||||||
let sbytes_of_data : data -> sbyte list = function
|
let sbytes_of_data : data -> sbyte list = function
|
||||||
| Quad (Lit i) -> sbytes_of_int64 i
|
| Quad (Lit i) -> sbytes_of_int64 i
|
||||||
| Asciz s -> sbytes_of_string s
|
| Asciz s -> sbytes_of_string s
|
||||||
| Quad (Lbl _) -> invalid_arg "sbytes_of_data: tried to serialize a label!"
|
| Quad (Lbl _) -> invalid_arg "sbytes_of_data: tried to serialize a label!"
|
||||||
|
;;
|
||||||
|
|
||||||
(* It might be useful to toggle printing of intermediate states of your
|
(* It might be useful to toggle printing of intermediate states of your
|
||||||
simulator. Our implementation uses this mutable flag to turn on/off
|
simulator. Our implementation uses this mutable flag to turn on/off
|
||||||
printing. For instance, you might write something like:
|
printing. For instance, you might write something like:
|
||||||
|
|
||||||
[if !debug_simulator then print_endline @@ string_of_ins u; ...]
|
[if !debug_simulator then print_endline @@ string_of_ins u; ...]
|
||||||
|
|
||||||
*)
|
*)
|
||||||
let debug_simulator = ref false
|
let debug_simulator = ref false
|
||||||
|
|
||||||
|
(* override some useful operators *)
|
||||||
(* override some useful operators *)
|
|
||||||
let ( +. ) = Int64.add
|
let ( +. ) = Int64.add
|
||||||
let ( -. ) = Int64.sub
|
let ( -. ) = Int64.sub
|
||||||
let ( *. ) = Int64.mul
|
let ( *. ) = Int64.mul
|
||||||
let ( <. ) a b = (Int64.compare a b) < 0
|
let ( <. ) a b = Int64.compare a b < 0
|
||||||
let ( >. ) a b = (Int64.compare a b) > 0
|
let ( >. ) a b = Int64.compare a b > 0
|
||||||
let ( <=. ) a b = (Int64.compare a b) <= 0
|
let ( <=. ) a b = Int64.compare a b <= 0
|
||||||
let ( >=. ) a b = (Int64.compare a b) >= 0
|
let ( >=. ) a b = Int64.compare a b >= 0
|
||||||
|
|
||||||
(* Interpret a condition code with respect to the given flags. *)
|
(* Interpret a condition code with respect to the given flags. *)
|
||||||
(* !!! Check the Specification for Help *)
|
(* !!! Check the Specification for Help *)
|
||||||
let interp_cnd {fo; fs; fz} : cnd -> bool = fun x -> failwith "interp_cnd unimplemented"
|
let interp_cnd { fo; fs; fz } : cnd -> bool = fun x -> failwith "interp_cnd unimplemented"
|
||||||
|
|
||||||
|
|
||||||
(* Maps an X86lite address into Some OCaml array index,
|
(* Maps an X86lite address into Some OCaml array index,
|
||||||
or None if the address is not within the legal address space. *)
|
or None if the address is not within the legal address space. *)
|
||||||
let map_addr (addr:quad) : int option =
|
let map_addr (addr : quad) : int option = failwith "map_addr not implemented"
|
||||||
failwith "map_addr not implemented"
|
|
||||||
|
|
||||||
(* Your simulator should raise this exception if it tries to read from or
|
(* Your simulator should raise this exception if it tries to read from or
|
||||||
store to an address not within the valid address space. *)
|
store to an address not within the valid address space. *)
|
||||||
exception X86lite_segfault
|
exception X86lite_segfault
|
||||||
|
|
||||||
(* Raise X86lite_segfault when addr is invalid. *)
|
(* Raise X86lite_segfault when addr is invalid. *)
|
||||||
let map_addr_segfault (addr:quad) : int =
|
let map_addr_segfault (addr : quad) : int = failwith "map_addr_segfault not implemented"
|
||||||
failwith "map_addr_segfault not implemented"
|
|
||||||
|
|
||||||
(* Simulates one step of the machine:
|
(* Simulates one step of the machine:
|
||||||
- fetch the instruction at %rip
|
- fetch the instruction at %rip
|
||||||
- compute the source and/or destination information from the operands
|
- compute the source and/or destination information from the operands
|
||||||
- simulate the instruction semantics
|
- simulate the instruction semantics
|
||||||
- update the registers and/or memory appropriately
|
- update the registers and/or memory appropriately
|
||||||
- set the condition flags
|
- set the condition flags
|
||||||
|
|
||||||
We provide the basic structure of step function and helper functions.
|
We provide the basic structure of step function and helper functions.
|
||||||
Implement the subroutine below to complete the step function.
|
Implement the subroutine below to complete the step function.
|
||||||
See step function to understand each subroutine and how they
|
See step function to understand each subroutine and how they
|
||||||
are glued together.
|
are glued together.
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let readquad (m:mach) (addr:quad) : quad =
|
let readquad (m : mach) (addr : quad) : quad = failwith "readquad not implemented"
|
||||||
failwith "readquad not implemented"
|
|
||||||
|
|
||||||
|
let writequad (m : mach) (addr : quad) (w : quad) : unit =
|
||||||
let writequad (m:mach) (addr:quad) (w:quad) : unit =
|
|
||||||
failwith "writequad not implemented"
|
failwith "writequad not implemented"
|
||||||
|
;;
|
||||||
|
|
||||||
let fetchins (m:mach) (addr:quad) : ins =
|
let fetchins (m : mach) (addr : quad) : ins = failwith "fetchins not implemented"
|
||||||
failwith "fetchins not implemented"
|
|
||||||
|
|
||||||
(* Compute the instruction result.
|
(* Compute the instruction result.
|
||||||
* NOTE: See int64_overflow.ml for the definition of the return type
|
* NOTE: See int64_overflow.ml for the definition of the return type
|
||||||
* Int64_overflow.t. *)
|
* Int64_overflow.t. *)
|
||||||
let interp_opcode (m: mach) (o:opcode) (args:int64 list) : Int64_overflow.t =
|
let interp_opcode (m : mach) (o : opcode) (args : int64 list) : Int64_overflow.t =
|
||||||
let open Int64 in
|
let open Int64 in
|
||||||
let open Int64_overflow in
|
let open Int64_overflow in
|
||||||
match o, args with
|
match o, args with
|
||||||
| _ -> failwith "interp_opcode not implemented"
|
| _ -> failwith "interp_opcode not implemented"
|
||||||
|
;;
|
||||||
|
|
||||||
(** Update machine state with instruction results. *)
|
(** Update machine state with instruction results. *)
|
||||||
let ins_writeback (m: mach) : ins -> int64 -> unit =
|
let ins_writeback (m : mach) : ins -> int64 -> unit =
|
||||||
failwith "ins_writeback not implemented"
|
failwith "ins_writeback not implemented"
|
||||||
|
;;
|
||||||
|
|
||||||
(* mem addr ---> mem array index *)
|
(* mem addr ---> mem array index *)
|
||||||
let interp_operands (m:mach) : ins -> int64 list =
|
let interp_operands (m : mach) : ins -> int64 list =
|
||||||
failwith "interp_operands not implemented"
|
failwith "interp_operands not implemented"
|
||||||
|
;;
|
||||||
|
|
||||||
let validate_operands : ins -> unit = function
|
let validate_operands : ins -> unit = function
|
||||||
| _ -> failwith "validate_operands not implemented"
|
| _ -> failwith "validate_operands not implemented"
|
||||||
|
;;
|
||||||
|
|
||||||
let crack : ins -> ins list = function
|
let crack : ins -> ins list = function
|
||||||
| _ -> failwith "crack not implemented"
|
| _ -> failwith "crack not implemented"
|
||||||
|
;;
|
||||||
|
|
||||||
(* TODO: double check against spec *)
|
(* TODO: double check against spec *)
|
||||||
let set_flags (m:mach) (op:opcode) (ws: quad list) (w : Int64_overflow.t) : unit =
|
let set_flags (m : mach) (op : opcode) (ws : quad list) (w : Int64_overflow.t) : unit =
|
||||||
failwith "set_flags not implemented"
|
failwith "set_flags not implemented"
|
||||||
|
;;
|
||||||
|
|
||||||
let step (m:mach) : unit =
|
let step (m : mach) : unit =
|
||||||
(* execute an instruction *)
|
(* execute an instruction *)
|
||||||
let (op, args) as ins = fetchins m m.regs.(rind Rip) in
|
let ((op, args) as ins) = fetchins m m.regs.(rind Rip) in
|
||||||
validate_operands ins;
|
validate_operands ins;
|
||||||
|
|
||||||
(* Some instructions involve running two or more basic instructions.
|
(* Some instructions involve running two or more basic instructions.
|
||||||
* For other instructions, just return a list of one instruction.
|
* For other instructions, just return a list of one instruction.
|
||||||
* See the X86lite specification for details. *)
|
* See the X86lite specification for details. *)
|
||||||
let uops: ins list = crack (op,args) in
|
let uops : ins list = crack (op, args) in
|
||||||
|
|
||||||
m.regs.(rind Rip) <- m.regs.(rind Rip) +. ins_size;
|
m.regs.(rind Rip) <- m.regs.(rind Rip) +. ins_size;
|
||||||
|
|
||||||
List.iter
|
List.iter
|
||||||
(fun (uop,_ as u) ->
|
(fun ((uop, _) as u) ->
|
||||||
if !debug_simulator then print_endline @@ string_of_ins u;
|
if !debug_simulator then print_endline @@ string_of_ins u;
|
||||||
let ws = interp_operands m u in
|
let ws = interp_operands m u in
|
||||||
let res = interp_opcode m uop ws in
|
let res = interp_opcode m uop ws in
|
||||||
ins_writeback m u @@ res.Int64_overflow.value;
|
ins_writeback m u @@ res.Int64_overflow.value;
|
||||||
set_flags m op ws res
|
set_flags m op ws res)
|
||||||
) uops
|
uops
|
||||||
|
;;
|
||||||
|
|
||||||
(* Runs the machine until the rip register reaches a designated
|
(* Runs the machine until the rip register reaches a designated
|
||||||
memory address. Returns the contents of %rax when the
|
memory address. Returns the contents of %rax when the
|
||||||
machine halts. *)
|
machine halts. *)
|
||||||
let run (m:mach) : int64 =
|
let run (m : mach) : int64 =
|
||||||
while m.regs.(rind Rip) <> exit_addr do step m done;
|
while m.regs.(rind Rip) <> exit_addr do
|
||||||
|
step m
|
||||||
|
done;
|
||||||
m.regs.(rind Rax)
|
m.regs.(rind Rax)
|
||||||
|
;;
|
||||||
|
|
||||||
(* assembling and linking --------------------------------------------------- *)
|
(* assembling and linking --------------------------------------------------- *)
|
||||||
|
|
||||||
(* A representation of the executable *)
|
(* A representation of the executable *)
|
||||||
type exec = { entry : quad (* address of the entry point *)
|
type exec =
|
||||||
; text_pos : quad (* starting address of the code *)
|
{ entry : quad (* address of the entry point *)
|
||||||
; data_pos : quad (* starting address of the data *)
|
; text_pos : quad (* starting address of the code *)
|
||||||
; text_seg : sbyte list (* contents of the text segment *)
|
; data_pos : quad (* starting address of the data *)
|
||||||
; data_seg : sbyte list (* contents of the data segment *)
|
; text_seg : sbyte list (* contents of the text segment *)
|
||||||
}
|
; data_seg : sbyte list (* contents of the data segment *)
|
||||||
|
}
|
||||||
|
|
||||||
(* Assemble should raise this when a label is used but not defined *)
|
(* Assemble should raise this when a label is used but not defined *)
|
||||||
exception Undefined_sym of lbl
|
exception Undefined_sym of lbl
|
||||||
|
|
@ -266,8 +285,8 @@ exception Redefined_sym of lbl
|
||||||
(* Convert an X86 program into an object file:
|
(* Convert an X86 program into an object file:
|
||||||
- separate the text and data segments
|
- separate the text and data segments
|
||||||
- compute the size of each segment
|
- compute the size of each segment
|
||||||
Note: the size of an Asciz string section is (1 + the string length)
|
Note: the size of an Asciz string section is (1 + the string length)
|
||||||
due to the null terminator
|
due to the null terminator
|
||||||
|
|
||||||
- resolve the labels to concrete addresses and 'patch' the instructions to
|
- resolve the labels to concrete addresses and 'patch' the instructions to
|
||||||
replace Lbl values with the corresponding Imm values.
|
replace Lbl values with the corresponding Imm values.
|
||||||
|
|
@ -276,29 +295,25 @@ exception Redefined_sym of lbl
|
||||||
- the text segment starts at the lowest address
|
- the text segment starts at the lowest address
|
||||||
- the data segment starts after the text segment
|
- the data segment starts after the text segment
|
||||||
|
|
||||||
HINT: List.fold_left and List.fold_right are your friends.
|
HINT: List.fold_left and List.fold_right are your friends.
|
||||||
*)
|
*)
|
||||||
let is_size (is: ins list): quad =
|
let is_size (is : ins list) : quad = failwith "is_size not implemented"
|
||||||
failwith "is_size not implemented"
|
let ds_size (ds : data list) : quad = failwith "ds_size not implemented"
|
||||||
|
let assemble (p : prog) : exec = failwith "assemble unimplemented"
|
||||||
let ds_size (ds: data list): quad =
|
|
||||||
failwith "ds_size not implemented"
|
|
||||||
|
|
||||||
let assemble (p:prog) : exec =
|
|
||||||
failwith "assemble unimplemented"
|
|
||||||
|
|
||||||
(* Convert an object file into an executable machine state.
|
(* Convert an object file into an executable machine state.
|
||||||
- allocate the mem array
|
- allocate the mem array
|
||||||
- set up the memory state by writing the symbolic bytes to the
|
- set up the memory state by writing the symbolic bytes to the
|
||||||
appropriate locations
|
appropriate locations
|
||||||
- create the inital register state
|
- create the inital register state
|
||||||
- initialize rip to the entry point address
|
- initialize rip to the entry point address
|
||||||
- initializes rsp to the last word in memory
|
- initializes rsp to the last word in memory
|
||||||
- the other registers are initialized to 0
|
- the other registers are initialized to 0
|
||||||
- the condition code flags start as 'false'
|
- the condition code flags start as 'false'
|
||||||
|
|
||||||
Hint: The Array.make, Array.blit, and Array.of_list library functions
|
Hint: The Array.make, Array.blit, and Array.of_list library functions
|
||||||
may be of use.
|
may be of use.
|
||||||
*)
|
*)
|
||||||
let load {entry; text_pos; data_pos; text_seg; data_seg} : mach =
|
let load { entry; text_pos; data_pos; text_seg; data_seg } : mach =
|
||||||
failwith "load not implemented"
|
failwith "load not implemented"
|
||||||
|
;;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue