diff options
author | Kartik Agaram <vc@akkartik.com> | 2018-08-12 22:38:54 -0700 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2018-08-12 22:45:29 -0700 |
commit | d33fa1c5edd9240b91b83a3eb0807b7751d01a28 (patch) | |
tree | e9499b2a4ea9a58636a4c1a19fc96c4cf11cef0a | |
parent | f3901d906901e80588f2e3e56bbe3052e47e4d64 (diff) | |
download | mu-d33fa1c5edd9240b91b83a3eb0807b7751d01a28.tar.gz |
4513 - disallow jumps across functions
-rw-r--r-- | subx/035labels.cc | 4 | ||||
-rw-r--r-- | subx/038check_local_jumps.cc | 60 |
2 files changed, 62 insertions, 2 deletions
diff --git a/subx/035labels.cc b/subx/035labels.cc index c7274613..efab173d 100644 --- a/subx/035labels.cc +++ b/subx/035labels.cc @@ -189,7 +189,7 @@ string drop_last(const string& s) { # op subop mod rm32 base index scale r32 # 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes # address 1 - $loop: +loop: $loop2: # address 1 (labels take up no space) 05 0x0d0c0b0a/imm32 # add to EAX @@ -199,7 +199,7 @@ string drop_last(const string& s) { eb $loop3/disp8 # address 10 $loop3: -+transform: label '$loop' is at address 1 ++transform: label 'loop' is at address 1 +transform: label '$loop2' is at address 1 +transform: label '$loop3' is at address 10 # first jump is to -7 diff --git a/subx/038check_local_jumps.cc b/subx/038check_local_jumps.cc new file mode 100644 index 00000000..41f8e471 --- /dev/null +++ b/subx/038check_local_jumps.cc @@ -0,0 +1,60 @@ +//: Make sure that we never jump from one function to within another. +//: +//: (The check for label types already ensures we can't jump to the start of +//: another function.) + +:(scenario jump_to_different_function) +% Hide_errors = true; +== 0x1 +fn1: + 7e/jump-if $target/disp8 +fn2: + $target: ++error: '7e/jump-if $target/disp8' in function 'fn1': jump to within another function 'fn2' is a *really* bad idea + +:(before "Rewrite Labels(segment code)") +check_local_jumps(code); +if (trace_contains_errors()) return; +:(code) +void check_local_jumps(const segment& code) { + map</*jump target*/string, /*containing call target*/string> function; + compute_function_target(code, function); + if (trace_contains_errors()) return; + string current_function; + for (int i = 0; i < SIZE(code.lines); ++i) { + const line& inst = code.lines.at(i); + if (SIZE(inst.words) == 1 && is_label(inst.words.at(0))) { + // label definition + if (inst.words.at(0).data.at(0) != '$') + current_function = drop_last(inst.words.at(0).data); + } + else if (is_jump(inst)) { + const word& target = inst.words.at(first_operand(inst)); + if (!contains_key(function, target.data)) continue; // error/warning handled elsewhere + if (get(function, target.data) == current_function) continue; + raise << "'" << to_string(inst) << "' in function '" << current_function << "': jump to within another function '" << get(function, target.data) << "' is a *really* bad idea\n" << end(); + return; + } + } +} + +void compute_function_target(const segment& code, map<string, string>& out) { + string current_function; + for (int i = 0; i < SIZE(code.lines); ++i) { + const line& inst = code.lines.at(i); + if (SIZE(inst.words) != 1) continue; + const word& curr = inst.words.at(0); + if (!is_label(curr)) continue; + const string& label = drop_last(curr.data); + if (label.at(0) != '$') { + current_function = label; + continue; + } + if (contains_key(out, label)) { + raise << "duplicate label '" << label << "'\n" << end(); + return; + } + // current_function can be empty! if so that would be 'main'. + put(out, label, current_function); + } +} |