From cbf8feb988e8cfacd9614bcdb8b7957aa09820cf Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 16 Nov 2022 10:11:05 +1030 Subject: [PATCH] merge dev for version v1.3.2 --- Changelog | 10 ++ Makefile.am | 13 ++- configure.ac | 39 +++++++- data/completion/_asmline | 31 +++++++ data/completion/asmline | 40 ++++++++ test/tools/asmline.sh | 9 ++ tools/asmline.c | 192 ++++++++++++++++++--------------------- 7 files changed, 228 insertions(+), 106 deletions(-) create mode 100644 data/completion/_asmline create mode 100755 data/completion/asmline diff --git a/Changelog b/Changelog index c1e50c4..e583294 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,13 @@ +version 1.3.2-release (2022-11-16) + + - fixed bug which caused `asmline -{c,b} ` to not display the + correct chuks + + - asmline {-h,--help} now emits to stdout to be conform with GNU standards + and with a slightly different indentation. + + - provide bash and zsh auto completion helper for asmline cli-tool + version 1.3.1-release (2022-11-10) - added support for all shift instructions shr/shl/sar/sal as well as all diff --git a/Makefile.am b/Makefile.am index 5b9d012..3f6c52b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -70,7 +70,7 @@ include_HEADERS = src/assemblyline.h # 3. Programs may need to be changed, recompiled, and relinked in order to use the new version. Bump current, set revision and age to 0. # in short, if only patch from configure.ac is bumped, bump the middle number below. If more is changed, read the above -libassemblyline_la_LDFLAGS = -version-info 3:4:2 +libassemblyline_la_LDFLAGS = -version-info 3:5:2 ############################################################################################## ############################################################################################## ############################### BINS ############################################## @@ -80,6 +80,17 @@ libassemblyline_la_LDFLAGS = -version-info 3:4:2 bin_PROGRAMS = tools/asmline LDADD = libassemblyline.la +# completion --start-- +if ENABLE_BASH_COMPLETION +bashcompletiondir = $(BASH_COMPLETION_DIR) +dist_bashcompletion_DATA = data/completion/asmline +endif +if ENABLE_ZSH_COMPLETION +zshcompletiondir = $(ZSH_COMPLETION_DIR) +dist_zshcompletion_DATA = data/completion/_asmline +endif +# completion --end-- + ############################################################################################## ############################################################################################## ############################### MANS ############################################## diff --git a/configure.ac b/configure.ac index 22e5b0a..b5fe40c 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT([assemblyline],[1.3.1],[yval@cs.adelaide.edu.au]) +AC_INIT([assemblyline],[1.3.2],[yval@cs.adelaide.edu.au]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR([src/assemblyline.c]) AC_CONFIG_AUX_DIR([build-aux]) @@ -34,6 +34,43 @@ AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T + + +# completion --start-- +# bash +AC_ARG_WITH([bash-completion-dir], + AS_HELP_STRING([--with-bash-completion-dir[=PATH]], + [Install the bash auto-completion script in this directory. @<:@default=yes@:>@]), + [], + [with_bash_completion_dir=yes]) + +if test "x$with_bash_completion_dir" = "xyes"; then + PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0], + [BASH_COMPLETION_DIR="`pkg-config --variable=completionsdir bash-completion`"], + [BASH_COMPLETION_DIR="$datadir/bash-completion/completions"]) +else + BASH_COMPLETION_DIR="$with_bash_completion_dir" +fi +AC_SUBST([BASH_COMPLETION_DIR]) +AM_CONDITIONAL([ENABLE_BASH_COMPLETION],[test "x$with_bash_completion_dir" != "xno"]) +# end bash +# start zsh +AC_ARG_WITH([zsh-completion-dir], + AS_HELP_STRING([--with-zsh-completion-dir[=PATH]], + [Install the zsh auto-completion script in this directory. @<:@default=yes@:>@]), + [], + [with_zsh_completion_dir=yes]) + +if test "x$with_zsh_completion_dir" = "xyes"; then + ZSH_COMPLETION_DIR="$datadir/zsh/site-functions" +else + ZSH_COMPLETION_DIR="$with_zsh_completion_dir" +fi +AC_SUBST([ZSH_COMPLETION_DIR]) +AM_CONDITIONAL([ENABLE_ZSH_COMPLETION],[test "x$with_zsh_completion_dir" != "xno"]) +# end zsh +# completion --end-- + # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_MMAP diff --git a/data/completion/_asmline b/data/completion/_asmline new file mode 100644 index 0000000..c68c0e7 --- /dev/null +++ b/data/completion/_asmline @@ -0,0 +1,31 @@ +#compdef asmline + +_arguments -S -s \ + '(H --rand)--rand[runs the code and initializes memory with random data _rdi--r9 can be dereferenced_.]:random heap:' \ + '(H -r --return)'{-r=-,--return=-}'[runs assembled code]:number of elements::resolution:(300 500)' \ + '(H -p --print)'{-p,--print}'[print to stdout in ASCII-hex.]' \ + '(H -P --printfile -o --object)'{-P+,--printfile+}'[write raw binary into FILE]' \ + '(H -P --printfile -o --object)'{-o+,--object+}'[write raw binary machinecode to FILE.bin]' \ + '(H -c --chunk)'{-c+,--chunk+}'[set (write) chunk size. Will NOP-pad every chunk]' \ + '(H -b --breaks)'{-b+,--breaks+}'[set (read) chunk size. Counts how many chunks break a boundary.]' \ + + '(mov)' \ + "(H)--nasm-mov-imm[nasm mov imm: mov to 32-bit reg if possible.]" \ + "(H)--smart-mov-imm[smart mov imm: if 64-bit padded, mov to 64-bit reg, to 32-bit otherwise.]" \ + "(H)--strict-mov-imm[strict mov imm: always mov to 64-bit reg.]" \ + + '(sib_index)' \ + "(H)--nasm-sib-index-base-swap[nasm swap sib; 'lea r15, \[rax+rsp\]' -> 'lea r15, \[rsp+rax\]']" \ + "(H)--strict-sib-index-base-swap[no swap sib; 'lea r15, \[rax+rsp\]' as is.]" \ + + '(sib_nobase)' \ + "(H)--nasm-sib-no-base[nasm scale sib; 'lea r15, \[2*rax\]' -> 'lea r15, \[rax+1*rax\]']" \ + "(H)--strict-sib-no-base[no scale sib; 'lea r15, \[2*rax\]' as is.]" \ + + '(sib_total)' \ + "(H sib_index sib_nobase)--nasm-sib[implies --nasm-sib-{no-base,index-base-swap}]" \ + "(H sib_index sib_nobase)--strict-sib[implies --strict-sib-{no-base,index-base-swap}]" \ + + '(mode_total)' \ + "(H sib_total mov)"{--nasm,-n}'[implies --nasm-{mov-imm,sib-{no-base,index-base-swap}}]' \ + "(H sib_total mov)"{--strict,-t}'[implies --strict-{mov-imm,-{no-base,index-base-swap}}]' \ + + '(H)' \ + '(* - input)'{-v,--version}'[Prints version information to stdout and exits.]' \ + '(* - input)'{-h,--help}'[Prints usage information to stdout and exits.]' \ + + '(input)' \ + ':assembly file:_files -g \*.\(asm\|s\|S\)' && ret=0 diff --git a/data/completion/asmline b/data/completion/asmline new file mode 100755 index 0000000..e0dc135 --- /dev/null +++ b/data/completion/asmline @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +_asmline() { + + local current="${COMP_WORDS[COMP_CWORD]}" + local options=" +--breaks +--chunk +--help +--nasm +--nasm-mov-imm +--nasm-sib +--nasm-sib-index-base-swap +--nasm-sib-no-base +--object +--print +--printfile +--rand +--return +--smart-mov-imm +--strict +--strict-mov-imm +--strict-sib +--strict-sib-index-base-swap +--strict-sib-no-base +--version +-P +-b +-c +-h +-n +-o +-p +-r +-t +-v +" + mapfile -t COMPREPLY < <(compgen -W "${options}" -- "${current}") +} + +complete -F _asmline asmline diff --git a/test/tools/asmline.sh b/test/tools/asmline.sh index d2eea56..71c0450 100755 --- a/test/tools/asmline.sh +++ b/test/tools/asmline.sh @@ -135,3 +135,12 @@ mov [rdi + 0x00], rax mov [rdi + 0x50], rax ret EOF + +ret=$( + ${tool} -b 3 <1 boundary in bytes. Nop \n\ + padding will be used to ensure no instruction \n\ + opcode will cross the specified CHUNK_SIZE \n\ + boundary.\n\ + -b, --breaks CHUNK_BOUNDARY Given a CHUNK_BOUNDARY>1, counts the number of \n\ + instructions where their opcode crosses the \n\ + specified CHUNK_BOUNDARY size in bytes.\n\ + --nasm-mov-imm Enables nasm-style mov-immediate register-size\n\ + handling. ex: if immediate size for mov is les\n\ + than or equal to max signed 32 bit assemblyline\n\ + will emit code to mov to the 32-bit register \n\ + rather than 64-bit. That is: \n\ + \"mov rax,0x7fffffff\" as \"mov eax,0x7fffffff\"\n\ + -> b8 ff ff ff 7f note: rax got optimized to \n\ + eax for faster immediate to register transfer\n\ + and produces a shorter instruction\n\ + --strict-mov-imm Disables nasm-style mov-immediate register-size\n\ + handling. ex: even if immediate size for mov \n\ + is less than or equal to max signed 32 bit \n\ + assemblyline. Will pad the immediate to fit \n\ + 64-bit. That is: \"mov rax,0x7fffffff\" as\n\ + \"mov rax,0x000000007fffffff\" ->\n\ + 48 b8 ff ff ff 7f 00 00 00 00\n\ + --smart-mov-imm The immediate value will be checked for leading \n\ + 0's. Immediate must be zero padded to 64-bits\n\ + exactly to ensure it will not optimize. This is\n\ + currently set as default. ex: \n\ + \"mov rax, 0x000000007fffffff\" -> \n\ + 48 b8 ff ff ff 7f 00 00 00 00\n\ + --nasm-sib-index-base-swap In SIB addressing if the index register is esp or\n\ + rsp then the base and index registers will be \n\ + swapped. That is: \"lea r15, [rax+rsp]\" ->\n\ + \"lea r15, [rsp+rax]\"\n\ + --strict-sib-index-base-swap In SIB addressing the base and index registers \n\ + will not be swapped even if the index register\n\ + is esp or rsp.\n\ + --nasm-sib-no-base In SIB addressing if there is no base register \n\ + present and scale is equal to 2; the base \n\ + register will be set to the index register and\n\ + the scale will be reduced to 1. That is: \n\ + \"lea r15, [2*rax]\" -> \"lea r15, [rax+1*rax]\"\n\ + --strict-sib-no-base In SIB addressing when there is no base register\n\ + present the index and scale would not change \n\ + regardless of scale value. That is: \n\ + \"lea r15, [2*rax]\" -> \"lea r15, [2*rax]\" \n\ + --nasm-sib Is equivalent to --nasm-sib-index-base-swap \n\ + --nasm-sib-no-base \n\ + --strict-sib Is equivalent to --strict-sib-index-base-swap \n\ + --strict-sib-no-base \n\ + -n, --nasm Is equivalent to --nasm-mov-imm --nasm-sib \n\ + -t, --strict Is equivalent to --strict-mov-imm --strict-sib \n\ + -h, --help Prints usage information to stdout and exits. \n\ + -v, --version Prints version information to stdout and exits.\n"); +} static void err_print_usage(char *error_msg) { - fprintf( - stderr, - "%s\nUsage: asmline " - "[OPTIONS]... path/to/file.asm\n\n" - - " -r[=LEN], --return[=LEN]\n" - "\tAssembles given code. Then executes it with six parameters to " - "heap-allocated memory.\n\tEach pointer points to an array of LEN 64-bit " - "elements which can be dereferenced \n\tin the asm-code, where LEN " - "defaults " - "to 10.\n\tAfter execution, it prints out the contents of the return " - "(rax) register and frees \n\tthe heap-memory.\n\n" - - " --rand \n" - "\tImplies -r and will additionally initialize the memory from with " - "random data. \n\t-r=11 can be used to alter LEN.\n\n" - - " -p, --print\n" - "\tThe corresponding machine code will be printed to stdout in hex " - "form.\n" - "\tOutput is similar to `objdump`: Byte-wise delimited by space and " - "linebreaks after 7 bytes.\n\tIf -c is given, the chunks are " - "delimited by '|' and each chunk is on one line.\n\n" - - " -P, --printfile FILENAME\n" - "\tThe corresponding machine code will be printed to FILENAME in binary " - "form.\n\tCan be set to '/dev/stdout' to write to stdout.\n\n" - - " -o, --object FILENAME\n" - "\tThe corresponding machine code will be printed to FILENAME.bin in " - "binary.\n\n" - - " -c, --chunk CHUNK_SIZE>1\n" - "\tSets a given CHUNK_SIZE boundary in bytes. Nop padding will be used " - "to ensure no instruction\n" - "\topcode will cross the specified CHUNK_SIZE boundary.\n\n" - - " -b, --breaks CHUNK_BOUNDARY>1\n" - "\tGiven a CHUNK_BOUNDARY, counts the number of instructions where\n" - "\ttheir opcode crosses the specified CHUNK_BOUNDARY size in bytes.\n\n" - - " --nasm-mov-imm\n" - "\tEnables nasm-style mov-immediate register-size handling.\n" - "\tex: if immediate size for mov is less than or equal to max " - "signed 32 bit assemblyline\n" - "\t will emit code to mov to the 32-bit register rather than 64-bit.\n" - "\tThat is: \"mov rax,0x7fffffff\" as \"mov eax,0x7fffffff\" " - "-> b8 ff ff ff 7f\n" - "\tnote: rax got optimized to eax for faster immediate to register " - "transfer\n" - "\t and produces a shorter instruction\n\n" - - " --strict-mov-imm\n" - "\tDisables nasm-style mov-immediate register-size handling.\n" - "\tex: even if immediate size for mov is less than or equal to max " - "signed 32 bit assemblyline.\n" - "\t will pad the immediate to fit 64-bit\n" - "\tThat is: \"mov rax,0x7fffffff\" as \"mov rax,0x000000007fffffff\"\n" - "\t -> 48 b8 ff ff ff 7f 00 00 00 00\n\n" - - " --smart-mov-imm\n" - "\tThe immediate value will be checked for leading 0's.\n" - "\tImmediate must be zero padded to 64-bits exactly to ensure\n" - "\tit will not optimize. This is currently set as default.\n" - "\tex: \"mov rax, 0x000000007fffffff\" -> 48 b8 ff ff ff 7f 00 00 00 " - "00\n\n" - - " --nasm-sib-index-base-swap\n" - "\tIn SIB addressing if the index register is esp or rsp then\n" - "\tthe base and index registers will be swapped.\n" - "\tThat is: \"lea r15, [rax+rsp]\" -> \"lea r15, [rsp+rax]\"\n\n" - " --strict-sib-index-base-swap\n" - "\tIn SIB addressing the base and index registers will not be swapped\n" - "\teven if the index register is esp or rsp.\n\n" - - " --nasm-sib-no-base\n" - "\tIn SIB addressing if there is no base register present and scale\n" - "\tis equal to 2; the base register will be set to the index register\n" - "\tand the scale will be reduced to 1.\n" - "\tThat is: \"lea r15, [2*rax]\" -> \"lea r15, [rax+1*rax]\"\n\n" - " --strict-sib-no-base\n" - "\tIn SIB addressing when there is no base register present the index\n" - "\tand scale would not change regardless of scale value.\n" - "\tThat is: \"lea r15, [2*rax]\" -> \"lea r15, [2*rax]\"\n\n" - - " --nasm-sib\n" - "\tequivalent to --nasm-sib-index-base-swap --nasm-sib-no-base\n\n" - " --strict-sib\n" - "\tequivalent to --strict-sib-index-base-swap --strict-sib-no-base\n\n" - - " -n, --nasm\n" - "\tequivalent to --nasm-mov-imm --nasm-sib\n\n" - - " -t, --strict\n" - "\tequivalent to --strict-mov-imm --strict-sib\n\n" - - " -h, --help\n" - "\tPrints usage information to stdout and exits.\n\n" - - " -v, --version\n" - "\tPrints version information to stdout and exits.\n\n", - error_msg); + fprintf(stderr, "%s", error_msg); + print_usage(); exit(EXIT_FAILURE); } @@ -405,6 +385,10 @@ int main(int argc, char *argv[]) { char *line = NULL; int chunk_brks = 0; size_t size = BUFFER_SIZE; + // init total count + if (m.count) + total_chunk_brks = 0; + while (getline(&line, &size, stdin) != -1) { int ret = m.count ? asm_assemble_string_counting_chunks( @@ -513,13 +497,13 @@ static void parse_opt(assemblyline_t al, int argc, char **argv, asm_set_all(al, SMART); break; case 'c': - if (optarg == NULL || (temp = atoi(optarg) <= 1)) + if (optarg == NULL || (temp = atoi(optarg)) <= 1) err_print_usage("Error: [-c CHUNK_SIZE>1] expects an integer\n"); asm_set_chunk_size(al, temp); break; case 'b': - if (optarg == NULL || (temp = atoi(optarg) <= 1)) + if (optarg == NULL || (temp = atoi(optarg)) <= 1) err_print_usage("Error: [-b CHUNK_BOUNDARY>1] expects an integer\n"); r->chunk_boundary = temp; break;