Skip to content

Commit

Permalink
version 1.2.2
Browse files Browse the repository at this point in the history
  • Loading branch information
dderjoel committed Mar 29, 2022
1 parent be2fab3 commit 459ee0f
Show file tree
Hide file tree
Showing 34 changed files with 548 additions and 184 deletions.
19 changes: 19 additions & 0 deletions Changelog
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
version 1.2.2-release

- added support for neg: Two's Complement Negation

- fixed a bug where shift and rotate instruction produce the wrong opcode
when immediate is zero

- fixed a bug when using sib addressing with no base and a single operand

- asmline can now count the number of instructions that breaks a chunk boundary

- the number of instructions that break a chunk boundary can be counted when
assembling a file.

- adding `cpuid`-instruction



version 1.2.1-release (2022-02-23)

- Fixed bugs regarding -imm/8


version 1.2.0-release (2022-02-19)

- binary file can now be generated from libassemblyline
Expand Down
12 changes: 8 additions & 4 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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:1:2
libassemblyline_la_LDFLAGS = -version-info 3:2:2
##############################################################################################
##############################################################################################
############################### BINS ##############################################
Expand Down Expand Up @@ -127,10 +127,12 @@ TAP_LOG_COMPILER = ./test/tap/compiler.sh

# add TAP tests here
TEST_TAP = \
test/tap/misc.tap \
test/tap/lea.tap \
test/tap/cmp.tap \
test/tap/imul.tap \
test/tap/nasm_incompatible.tap
test/tap/lea.tap \
test/tap/misc.tap \
test/tap/nasm_incompatible.tap \
test/tap/xor.tap

# those are the tests, where asmline is expected to fail, for the suite to be ok.
# eaf stands for 'expected asmline to fail'
Expand Down Expand Up @@ -174,6 +176,7 @@ TEST_ASM = \
test/bzhi.asm \
test/clc.asm \
test/cmp.asm \
test/cpuid.asm \
test/high_low_xmm.asm \
test/imul.asm \
test/lea.asm \
Expand All @@ -187,6 +190,7 @@ TEST_ASM = \
test/movq.asm \
test/movzx.asm \
test/mulx.asm \
test/neg.asm \
test/negative_mem_disp.asm \
test/new_instruction.asm \
test/no_ptr.asm \
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([assemblyline],[1.2.1],[[email protected]])
AC_INIT([assemblyline],[1.2.2],[[email protected]])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/assemblyline.c])
AC_CONFIG_AUX_DIR([build-aux])
Expand Down
5 changes: 5 additions & 0 deletions man/asmline.1
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ The corresponding machine code will be printed to \fIFILENAME\fR in binary form.
.BR \-c ", " \-\-chunk " " \fICHUNK_SIZE>1
Sets a given \fICHUNK_SIZE\fR boundary in bytes. Nop padding will be used to ensure no instruction opcode will cross the specified \fICHUNK_SIZE\fR boundary.

.TP
.BR \-b ", " \-\-breaks " " \fICHUNK_BOUNDARY>1

Given a \fICHUNK_BOUNDARY\fR asmline will count the number of instructions where their opcode crosses the specified \fICHUNK_BOUNDARY\fR size in bytes.

.TP
.BR \-o ", " \-\-object " " \fIFILENAME
Generates a binary file from path/to/file.asm called \fIFILENAME\fR.bin in the current directory.
Expand Down
17 changes: 11 additions & 6 deletions man/libassemblyline.3
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,30 @@ Allocates an instance of assemblyline_t and attaches a pointer to a memory \fIbu

.TP
.BI "int asm_destroy_instance(assemblyline_t " instance );
Frees all memory associated with \fIinstance\fR.
Frees all memory associated with \fIinstance\fR. Returns EXIT_SUCCESS or EXIT_FAILURE.

.TP
.BI "int asm_assemble_str(assemblyline_t " al ", const char *" assembly_str );
Assembles the given string \fIassembly_str\fR containing valid x64 assembly code with instance \fIal\fR. It writes the corresponding machine code to the memory location specified by al->buffer.
Assembles the given string \fIassembly_str\fR containing valid x64 assembly code with instance \fIal\fR. It writes the corresponding machine code to the memory location specified by the buffer associated with \fIal\fR. Returns EXIT_SUCCESS or EXIT_FAILURE.

.TP
.BI "int asm_assemble_file(assemblyline_t " al ", char *" asm_file );
Assembles the given file path \fIasm_file\fR containing valid x64 assembly code with instance \fIal\fR. It writes the corresponding machine code to the memory location specified by al->buffer.
Assembles the given file path \fIasm_file\fR containing valid x64 assembly code with instance \fIal\fR. It writes the corresponding machine code to the memory location specified by the buffer associated with \fIal\fR. Returns EXIT_SUCCESS or EXIT_FAILURE.

.TP
.BI "int asm_assemble_string_counting_chunks(assemblyline_t " al ", char *" str ", int " chunk_size ", int *" dest );
Assembles the given null-terminated @param string with instance \fIal\fR. It counts the number of instructions that break the chunk boundary of size \fIchunk_size\fR and saves it to \fIdest\fR. It does not nop-pad by default, depends on instance \fIal\fR (you can nop-pad and count different chunk breaks).
Assembles the given null-terminated string \fIstr\fR with instance \fIal\fR. It counts the number of instructions that break the chunk boundary of size \fIchunk_size\fR and saves it to \fIdest\fR. It does not nop-pad by default, depends on instance \fIal\fR (you can nop-pad and count different chunk breaks). Returns EXIT_SUCCESS or EXIT_FAILURE.

.br
\fBNOTE:\fR you cannot pass const char* as \fIstr\fR, it will segfault, because string will be altered.

.TP
.BI "int asm_assemble_file_counting_chunks(assemblyline_t " al ", char *" asm_file ", int " chunk_size ", int *" dest );
Assembles the given file \fIasm_file\fR with instance \fIal\fR. It counts the number of instructions that break the chunk boundary of size \fIchunk_size\fR and saves it to \fIdest\fR. It does not nop-pad by default, depends on instance \fIal\fR (you can nop-pad and count different chunk breaks).

.TP
.BI "void asm_set_chunk_size(assemblyline_t " al ", size_t " chunk_size );
Sets a given chunk size boundary \fIchunk_size\fR in bytes with instance \fIal\fR. When called before assemble_str() or assemble_file() assemblyline will ensure no instruction opcode will cross the specified \fIchunk_size\fR boundary via nop padding.
Sets a given chunk size boundary \fIchunk_size\fR in bytes with instance \fIal\fR. When called before assemble_str() or assemble_file() assemblyline will ensure no instruction opcode will cross the specified \fIchunk_size\fR boundary via nop padding.
.br
\fBNOTE:\fR \fIchunk_size\fR must be greater than 2 in order to be classified as a valid memory chunk boundary size.

Expand Down Expand Up @@ -67,7 +72,7 @@ Returns the buffer associated with \fIal\fR (DEPRECATED: use \fBasm_get_code(3)\

.TP
.BI "int asm_create_bin_file(assemblyline_t " al ", char *" file_name );
Generates a binary file \fIfile_name\fR from assembled machine code up to the memory offset of the current instance \fIal\fR.
Generates a binary file \fIfile_name\fR from assembled machine code up to the memory offset of the current instance \fIal\fR. Returns EXIT_SUCCESS or EXIT_FAILURE.

.TP
.BI "void asm_mov_imm(assemblyline_t " al ", enum asm_opt "option );
Expand Down
53 changes: 35 additions & 18 deletions src/assemblyline.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
* INSTR_TABLE[] where the first occurrence of each letter of the alphabet to
* instr_index_table for more efficient instruction lookup
*/
static void asm_build_index_tables(assemblyline_t al) {
static void asm_build_index_tables() {
// INSTR_TABLE index starts at the SKIP entry
size_t i = 2;
char previous_char = 'a' - 1;
Expand All @@ -53,7 +53,6 @@ static void asm_build_index_tables(assemblyline_t al) {
previous_char = OPD_FORMAT_TABLE[i].str[0];
}
}
al->table_built = true;
}

assemblyline_t asm_create_instance(uint8_t *buffer, int len) {
Expand Down Expand Up @@ -84,7 +83,7 @@ assemblyline_t asm_create_instance(uint8_t *buffer, int len) {
al->chunk_size++;
al->debug = false;
al->finalized = false;
asm_build_index_tables(al);
asm_build_index_tables();
return al;
}

Expand Down Expand Up @@ -141,27 +140,44 @@ int asm_assemble_string_counting_chunks(assemblyline_t al, char *str,
return EXIT_SUCCESS;
}

int assemble_file(assemblyline_t al, char *asm_file) {
return asm_assemble_file(al, asm_file);
}

int asm_assemble_file(assemblyline_t al, char *asm_file) {
static void *asm_mmap_file(char *asm_file, size_t *str_len) {
// open file for reading
int fd = open(asm_file, O_RDONLY, S_IRUSR | S_IRUSR);
FAIL_SYS(fd == -1, "failed to open file\n");
FAIL_SYS(fd == -1, "failed to open file\n", MAP_FAILED);
struct stat file_stat;
FAIL_SYS(fstat(fd, &file_stat), "failed to get file stats\n");
FAIL_SYS(fstat(fd, &file_stat), "failed to get file stats\n", MAP_FAILED);
// map file contents to a string
size_t str_len = file_stat.st_size;
const char *assembly_str =
mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
*str_len = file_stat.st_size;
void *str = mmap(NULL, *str_len, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
FAIL_SYS(assembly_str == MAP_FAILED, "failed to allocate memory via mmap\n");
int exit_status = asm_assemble_str(al, assembly_str);
return str;
}

int asm_assemble_file_counting_chunks(assemblyline_t al, char *asm_file,
int chunk_size, int *dest) {

size_t str_len = 0;
char *str = asm_mmap_file(asm_file, &str_len);
FAIL_SYS(str == MAP_FAILED, "mmap failed to read file\n", EXIT_FAILURE);
int exit = asm_assemble_string_counting_chunks(al, str, chunk_size, dest);
// free mmap memory used for reading file
FAIL_SYS(munmap((void *)str, str_len) == -1, "munmap failed\n", EXIT_FAILURE);
return exit;
}

int assemble_file(assemblyline_t al, char *asm_file) {
return asm_assemble_file(al, asm_file);
}

int asm_assemble_file(assemblyline_t al, char *asm_file) {

size_t str_len = 0;
const char *str = asm_mmap_file(asm_file, &str_len);
FAIL_SYS(str == MAP_FAILED, "mmap failed to read file\n", EXIT_FAILURE);
int exit = asm_assemble_str(al, str);
// free mmap memory used for reading file
FAIL_SYS(munmap((void *)assembly_str, str_len) == -1,
"Error: failed to free memory\n");
return exit_status;
FAIL_SYS(munmap((void *)str, str_len) == -1, "munmap failed\n", EXIT_FAILURE);
return exit;
}

void asm_set_chunk_size(assemblyline_t al, size_t chunk_size) {
Expand All @@ -188,6 +204,7 @@ uint8_t __attribute__((deprecated("use asm_get_code instead"))) *
void *asm_get_code(assemblyline_t al) { return (void *)al->buffer; }

int asm_create_bin_file(assemblyline_t al, const char *file_name) {

void *buffer = asm_get_code(al);
int len = asm_get_offset(al);
FILE *write_ptr = fopen(file_name, "wb");
Expand Down
34 changes: 25 additions & 9 deletions src/assemblyline.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,16 @@ typedef struct assemblyline *assemblyline_t;
assemblyline_t asm_create_instance(uint8_t *buffer, int len);

/**
* frees all memory associated with @param instance
* frees all memory associated with @param instance. Returns EXIT_SUCCESS or
* EXIT_FAILURE.
*/
int asm_destroy_instance(assemblyline_t instance);

/**
* assembles the given string @param assembly_str containing valid x64 assembly
* code with instance @param al It writes the corresponding machine code to the
* memory location specified by al->buffer.
* memory location specified by the buffer attached to @param al. Returns
* EXIT_SUCCESS or EXIT_FAILURE.
* (DEPRECATED: use asm_assemble_str() instead)
*/
int __attribute__((deprecated("use asm_assemble_str instead")))
Expand All @@ -56,14 +58,16 @@ assemble_str(assemblyline_t al, const char *assembly_str);
/**
* assembles the given string @param assembly_str containing valid x64 assembly
* code with instance @param al It writes the corresponding machine code to the
* memory location specified by al->buffer.
* memory location specified by buffer attached to @param al. Returns
* EXIT_SUCCESS or EXIT_FAILURE.
*/
int asm_assemble_str(assemblyline_t al, const char *assembly_str);

/**
* assembles the given file path @param asm_file containing valid x64 assembly
* code with instance @param al It writes the corresponding machine code to the
* memory location specified by al->buffer.
* memory location specified by buffer attached to @param al. Returns
* EXIT_SUCCESS or EXIT_FAILURE.
* (DEPRECATED: use asm_assemble_file() instead)
*/
int __attribute__((deprecated("use asm_assemble_file instead")))
Expand All @@ -72,7 +76,8 @@ assemble_file(assemblyline_t al, char *asm_file);
/**
* assembles the given file path @param asm_file containing valid x64 assembly
* code with instance @param al It writes the corresponding machine code to the
* memory location specified by al->buffer.
* memory location specified by buffer attached to @param al. Returns
* EXIT_SUCCESS or EXIT_FAILURE.
*/
int asm_assemble_file(assemblyline_t al, char *asm_file);

Expand All @@ -81,7 +86,7 @@ int asm_assemble_file(assemblyline_t al, char *asm_file);
* It counts the number of instructions that break the chunk boundary of size
* @param chunk_size and saves it to @param dest It does not nop-pad
* necessarily, depends on the @param al instance (you can nop-pad and count
* different chunk breaks).
* different chunk breaks). Returns EXIT_SUCCESS or EXIT_FAILURE.
* NOTE: you cannot pass const char* as @param string, it will segfault, because
* string will be altered.
* (DEPRECATED: use asm_assemble_string_counting_chunks() instead)
Expand All @@ -96,17 +101,27 @@ assemble_string_counting_chunks(assemblyline_t al, char *string, int chunk_size,
* It counts the number of instructions that break the chunk boundary of size
* @param chunk_size and saves it to @param dest It does not nop-pad
* necessarily, depends on the @param al instance (you can nop-pad and count
* different chunk breaks).
* different chunk breaks). Returns EXIT_SUCCESS or EXIT_FAILURE.
* NOTE: you cannot pass const char* as @param string, it will segfault, because
* string will be altered.
*/
int asm_assemble_string_counting_chunks(assemblyline_t al, char *string,
int chunk_size, int *dest);

/**
* assembles the given @param asm_file with instance @param al.
* It counts the number of instructions that break the chunk boundary of size
* @param chunk_size and saves it to @param dest It does not nop-pad
* necessarily, depends on the @param al instance (you can nop-pad and count
* different chunk breaks). Returns EXIT_SUCCESS or EXIT_FAILURE.
*/
int asm_assemble_file_counting_chunks(assemblyline_t al, char *asm_file,
int chunk_size, int *dest);

/**
* sets a given chunk size boundary @param chunk_size in bytes with instance
* @param al. When called before assemble_str() or assemble_file() assemblyline
* will ensure no instruction opcode will cross the specified @param chunk_size
* will ensure no instruction opcode will cross the specified @param chunk_size
* boundary via nop padding.
* NOTE: @param chunk_size must be greater than 2 in order to
* be classified as a valid memory chunk boundary
Expand Down Expand Up @@ -147,7 +162,8 @@ void *asm_get_code(assemblyline_t al);

/**
* Generates a binary file @param file_name from assembled machine code up to
* the memory offset of the current instance @param al
* the memory offset of the current instance @param al. Returns EXIT_SUCCESS or
* EXIT_FAILURE.
*/
int asm_create_bin_file(assemblyline_t al, const char *file_name);

Expand Down
13 changes: 8 additions & 5 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,15 @@
#define NEG32BIT 0xffffffff00000000
#define NEG8BIT 0xffffffffffffff00
#define NEG80BIT 0xffffffffffffff80
#define NEG80_32BIT 0xffffff80
#define MAX_SIGNED_8BIT 0x7f
#define MAX_UNSIGNED_8BIT 0xff
#define MAX_UNSIGNED_16BIT 0xffff
#define MAX_SIGNED_32BIT 0x7fffffff
#define MAX_UNSIGNED_32BIT 0xffffffff
#define NEG32BIT_CHECK 0x80000000
// check if a number is at least 32 bits
#define X32BIT_CHECK 0x10000000
#define NEG8BIT_CHECK 0x80

// set register length to 1 byte
Expand Down Expand Up @@ -134,8 +137,8 @@

// used only in tokenizer
#define IN_RANGE(var, lower, upper) ((var >= lower) && (var <= upper))
#define DO_NOT_PAD(reduce, set) \
reduce &= MAX_UNSIGNED_32BIT; \
#define DO_NOT_PAD(reduce, set, mask) \
reduce &= mask; \
set = true;

// keyword length
Expand Down Expand Up @@ -178,11 +181,11 @@
return EXIT_FAILURE; \
}

#define FAIL_SYS(EXP, MSG) \
#define FAIL_SYS(EXP, MSG, RET) \
if (EXP) { \
fprintf(stderr, "assembyline: " MSG); \
perror("error: "); \
return EXIT_FAILURE; \
perror("error "); \
return RET; \
}

#define FAIL_IF_ERR(EXP) \
Expand Down
Loading

0 comments on commit 459ee0f

Please sign in to comment.