Support 32 bit and 64 bit decoding with one binary
It is possible to configure the build process such that decoding of 32 bit and 64 bit instructions can be chosen at runtime using an additional parameter of the decode function. The header file is now entirely architecture-independent and no longer required any previous defines. Decoding x86-64 still requires a 64-bit pointer size.
This commit is contained in:
@@ -24,24 +24,40 @@ parse_nibble(const char nibble)
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2 && argc != 3)
|
||||
if (argc != 3 && argc != 4)
|
||||
{
|
||||
printf("usage: %s [instruction bytes] ([repetitions])\n", argv[0]);
|
||||
printf("usage: %s [mode] [instruction bytes] ([repetitions])\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DecodeMode mode;
|
||||
size_t mode_input = strtoul(argv[1], NULL, 0);
|
||||
if (mode_input == 32)
|
||||
{
|
||||
mode = DECODE_32;
|
||||
}
|
||||
else if (mode_input == 64)
|
||||
{
|
||||
mode = DECODE_64;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unknown decode mode\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Avoid allocation by transforming hex to binary in-place.
|
||||
uint8_t* code = (uint8_t*) argv[1];
|
||||
uint8_t* code = (uint8_t*) argv[2];
|
||||
uint8_t* code_end = code;
|
||||
char* hex = argv[1];
|
||||
char* hex = argv[2];
|
||||
for (; *hex; hex += 2, code_end++)
|
||||
*code_end = (parse_nibble(hex[0]) << 4) | parse_nibble(hex[1]);
|
||||
|
||||
size_t length = (size_t) (code_end - code);
|
||||
|
||||
size_t repetitions = 1;
|
||||
if (argc >= 3)
|
||||
repetitions = strtoul(argv[2], NULL, 0);
|
||||
if (argc >= 4)
|
||||
repetitions = strtoul(argv[3], NULL, 0);
|
||||
|
||||
struct timespec time_start;
|
||||
struct timespec time_end;
|
||||
@@ -56,7 +72,7 @@ main(int argc, char** argv)
|
||||
while (current_off != length)
|
||||
{
|
||||
size_t remaining = length - current_off;
|
||||
int retval = decode(code + current_off, remaining, &instr);
|
||||
int retval = decode(code + current_off, remaining, mode, &instr);
|
||||
if (retval < 0)
|
||||
goto fail;
|
||||
current_off += retval;
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
test_driver = executable('test_driver', 'driver.c',
|
||||
dependencies: libx86decode,
|
||||
c_args: ['-D_GNU_SOURCE'])
|
||||
test_args = [files('test.py'), test_driver, archmode]
|
||||
test_args = [files('test.py'), test_driver]
|
||||
if decode_32
|
||||
test_args += ['--32']
|
||||
endif
|
||||
if decode_64
|
||||
test_args += ['--64']
|
||||
endif
|
||||
|
||||
|
||||
## Test cases
|
||||
|
||||
@@ -5,12 +5,12 @@ import statistics
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def run(args, code, expected):
|
||||
def run(args, mode, code, expected):
|
||||
inner_reps = 10000000 if args.benchmark else 1
|
||||
outer_reps = 3 if args.benchmark else 1
|
||||
times = []
|
||||
for _ in range(outer_reps):
|
||||
output = subprocess.check_output([args.driver, code, str(inner_reps)],
|
||||
output = subprocess.check_output([args.driver, str(mode), code, str(inner_reps)],
|
||||
universal_newlines=True)
|
||||
instr, time = tuple(output.split("\n", 1))
|
||||
if instr != expected:
|
||||
@@ -22,26 +22,29 @@ def run(args, code, expected):
|
||||
if args.benchmark:
|
||||
mean = statistics.mean(times)
|
||||
stdev = statistics.stdev(times)
|
||||
print("{:53} {:6.3f} ns (std: {:6.3f} ns)".format(expected, mean, stdev))
|
||||
print("{:2} {:50} {:6.3f} ns (std: {:6.3f} ns)".format(mode, expected, mean, stdev))
|
||||
|
||||
return times
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--benchmark", action="store_true")
|
||||
parser.add_argument("--32", dest="test_modes", action="append_const", const=32)
|
||||
parser.add_argument("--64", dest="test_modes", action="append_const", const=64)
|
||||
parser.add_argument("driver")
|
||||
parser.add_argument("archmode", choices=[32, 64], type=int)
|
||||
parser.add_argument("cases", nargs="+", type=argparse.FileType('r'))
|
||||
args = parser.parse_args()
|
||||
|
||||
failed, total = 0, 0
|
||||
total_times = []
|
||||
|
||||
test_modes = frozenset(args.test_modes if args.test_modes else [32, 64])
|
||||
|
||||
for file in args.cases:
|
||||
cases = [tuple(ln.strip().split(maxsplit=2)) for ln in file.readlines()]
|
||||
for op, code, expected in cases:
|
||||
if op == "decode32" and args.archmode != 32: continue
|
||||
if op == "decode64" and args.archmode != 64: continue
|
||||
case_modes = {"decode":{32,64},"decode32":{32},"decode64":{64}}[op]
|
||||
if not case_modes & test_modes: continue
|
||||
|
||||
# Compatibility with old test system
|
||||
if expected[0] == '"' and expected[-1] == '"':
|
||||
@@ -49,7 +52,8 @@ if __name__ == "__main__":
|
||||
|
||||
try:
|
||||
total += 1
|
||||
total_times += run(args, code, expected)
|
||||
for mode in case_modes & test_modes:
|
||||
total_times += run(args, mode, code, expected)
|
||||
except Exception as e:
|
||||
failed += 1
|
||||
print("FAILED: %s" % e)
|
||||
|
||||
Reference in New Issue
Block a user