├── test ├── _test │ ├── .gitignore │ ├── refs │ │ ├── test4.ref │ │ ├── test5.ref │ │ ├── test8.ref │ │ ├── test3.ref │ │ ├── test9.ref │ │ └── test2.ref │ ├── inputs │ │ ├── check_exec.c │ │ ├── inv_perm.c │ │ ├── no_perm.c │ │ ├── .gitignore │ │ ├── hello.S │ │ ├── bss.c │ │ ├── data_bss.c │ │ ├── lib.c │ │ ├── Makefile │ │ ├── check_perm.c │ │ ├── sum.c │ │ └── qsort.c │ ├── outputs │ │ ├── test3.out │ │ └── test3.tmp │ ├── Makefile │ ├── loader.h │ ├── run_test.c │ ├── test_lib.sh │ └── run_test.sh ├── Makefile.checker ├── util │ └── loader.h ├── run_all.sh └── README.md ├── src ├── .gitignore ├── test_prog │ └── hello.S ├── exec │ └── exec.c ├── loader │ ├── debug.h │ ├── loader.h │ ├── exec_parser.h │ ├── loader.c │ └── exec_parser.c ├── Makefile └── Makefile.example ├── res └── ubuntu-logo.png ├── makefile ├── LICENSE └── README.md /test/_test/.gitignore: -------------------------------------------------------------------------------- 1 | /run_test 2 | -------------------------------------------------------------------------------- /test/_test/refs/test4.ref: -------------------------------------------------------------------------------- 1 | SUCCESS 2 | -------------------------------------------------------------------------------- /test/_test/refs/test5.ref: -------------------------------------------------------------------------------- 1 | SUCCESS 2 | -------------------------------------------------------------------------------- /test/_test/refs/test8.ref: -------------------------------------------------------------------------------- 1 | SUCCESS 2 | -------------------------------------------------------------------------------- /test/_test/refs/test3.ref: -------------------------------------------------------------------------------- 1 | 1720232652 2 | -------------------------------------------------------------------------------- /test/_test/refs/test9.ref: -------------------------------------------------------------------------------- 1 | 0x605c7ecf 2 | -------------------------------------------------------------------------------- /test/_test/refs/test2.ref: -------------------------------------------------------------------------------- 1 | Hello, world! 2 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | /so_exec 2 | /so_test_prog 3 | /libso_loader.so 4 | -------------------------------------------------------------------------------- /test/_test/inputs/check_exec.c: -------------------------------------------------------------------------------- 1 | void exit(int); 2 | 3 | void _start() 4 | { 5 | exit(0); 6 | } 7 | -------------------------------------------------------------------------------- /res/ubuntu-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabriel-rusu/E.L.F-Executable-Loader/HEAD/res/ubuntu-logo.png -------------------------------------------------------------------------------- /test/_test/outputs/test3.out: -------------------------------------------------------------------------------- 1 | ./_test/run_test.sh: line 142: _test/run_test: cannot execute binary file: Exec format error 2 | -------------------------------------------------------------------------------- /test/_test/inputs/inv_perm.c: -------------------------------------------------------------------------------- 1 | void exit(int code); 2 | 3 | void _start() 4 | { 5 | *(int *)&_start = 0; 6 | exit(0); 7 | } 8 | -------------------------------------------------------------------------------- /test/_test/inputs/no_perm.c: -------------------------------------------------------------------------------- 1 | void exit(int code); 2 | 3 | void _start() 4 | { 5 | *(int *)0x44444444 = 0; 6 | exit(0); 7 | } 8 | -------------------------------------------------------------------------------- /test/_test/inputs/.gitignore: -------------------------------------------------------------------------------- 1 | /bss 2 | /check_exec 3 | /check_perm 4 | /data_bss 5 | /hello 6 | /inv_perm 7 | /no_perm 8 | /qsort 9 | /sum 10 | -------------------------------------------------------------------------------- /test/_test/outputs/test3.tmp: -------------------------------------------------------------------------------- 1 | _test/outputs/test3.out vs _test/refs/test3.ref: 2 | --- _test/outputs/test3.out 2020-04-08 20:37:01.358507500 +0300 3 | +++ _test/refs/test3.ref 2020-03-21 11:45:46.357158600 +0200 4 | @@ -1 +1 @@ 5 | -./_test/run_test.sh: line 142: _test/run_test: cannot execute binary file: Exec format error 6 | +1720232652 7 | -------------------------------------------------------------------------------- /src/test_prog/hello.S: -------------------------------------------------------------------------------- 1 | .section .data 2 | str: 3 | .ascii "Hello, world!\n" 4 | str_len = . - str 5 | 6 | .section .text 7 | 8 | .global _start 9 | _start: 10 | mov str, %al 11 | mov $1, %ebx 12 | mov $str, %ecx 13 | mov $str_len, %edx 14 | mov $4, %eax 15 | 16 | int $0x80 17 | 18 | mov $0, %ebx 19 | mov $1, %eax 20 | int $0x80 21 | -------------------------------------------------------------------------------- /test/_test/inputs/hello.S: -------------------------------------------------------------------------------- 1 | .section .data 2 | str: 3 | .ascii "Hello, world!\n" 4 | str_len = . - str 5 | 6 | .section .text 7 | 8 | .global _start 9 | _start: 10 | mov str, %al 11 | mov $1, %ebx 12 | mov $str, %ecx 13 | mov $str_len, %edx 14 | mov $4, %eax 15 | 16 | int $0x80 17 | 18 | mov $0, %ebx 19 | mov $1, %eax 20 | int $0x80 21 | -------------------------------------------------------------------------------- /test/_test/inputs/bss.c: -------------------------------------------------------------------------------- 1 | int __attribute__((aligned(4096))) arr[1024]; 2 | 3 | void exit(int code); 4 | int write(int fd, char *buf, int len); 5 | 6 | void _start() 7 | { 8 | int i; 9 | 10 | for (i = 0; i < 1024; i++) 11 | if (arr[i] != 0) { 12 | write(1, "FAIL\n", 5); 13 | exit(1); 14 | } 15 | 16 | write(1, "SUCCESS\n", 8); 17 | exit(0); 18 | } 19 | -------------------------------------------------------------------------------- /test/Makefile.checker: -------------------------------------------------------------------------------- 1 | .PHONY: all clean run pack build-pre build-post 2 | 3 | all: build-pre build-post run 4 | 5 | build-pre: 6 | 7 | build-post: 8 | @make --no-print-directory -C _test 9 | 10 | run: 11 | @./run_all.sh 12 | 13 | pack: 14 | zip -r run_test_lin.zip _test/ Makefile.checker \ 15 | run_all.sh README 16 | 17 | clean: 18 | @make --no-print-directory -C _test clean 19 | -rm -f *~ 20 | -------------------------------------------------------------------------------- /src/exec/exec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Operating System Executable Loader Exec tester 3 | * 4 | * 2018, Operating Systems 5 | */ 6 | 7 | #include 8 | #include "loader.h" 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | if (argc < 2) { 13 | fprintf(stderr, "Please provide an executable!\n"); 14 | return 1; 15 | } 16 | 17 | so_init_loader(); 18 | so_execute(argv[1], argv + 1); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/_test/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -m32 -Wall -fno-pic 3 | LDFLAGS = -m32 -no-pie 4 | LDLIBS = -lso_loader 5 | 6 | .PHONY: build 7 | build: run_test 8 | $(MAKE) -C inputs 9 | 10 | run_test: run_test.o 11 | $(CC) $(LDFLAGS) -L.. -Wl,-Ttext-segment=0x20000000 -o $@ $^ $(LDLIBS) 12 | 13 | %.o: %.c 14 | $(CC) $(CFLAGS) -o $@ -c $< 15 | 16 | .PHONY: clean 17 | clean: 18 | -@rm -f run_test.o run_test 19 | $(MAKE) -C inputs clean 20 | -------------------------------------------------------------------------------- /src/loader/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_H_ 2 | #define DEBUG_H_ 3 | 4 | #include 5 | 6 | #if defined DEBUG 7 | #define dprintf(format, ...) \ 8 | fprintf(stderr, " [%s(), %s:%u] " format, \ 9 | __FUNCTION__, __FILE__, __LINE__, \ 10 | ##__VA_ARGS__) 11 | #else 12 | #define dprintf(format, ...) \ 13 | do {} while (0) 14 | #endif 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -fPIC -m32 -Wall 3 | LDFLAGS = -m32 4 | 5 | .PHONY: build 6 | build: libso_loader.so 7 | 8 | libso_loader.so: loader.o exec_parser.o 9 | $(CC) $(LDFLAGS) -shared -o $@ $^ 10 | 11 | exec_parser.o: loader/exec_parser.c loader/exec_parser.h 12 | $(CC) $(CFLAGS) -o $@ -c $< 13 | 14 | loader.o: loader/loader.c 15 | $(CC) $(CFLAGS) -o $@ -c $< 16 | 17 | .PHONY: clean 18 | clean: 19 | -rm -f exec_parser.o loader.o libso_loader.so 20 | -------------------------------------------------------------------------------- /src/loader/loader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Operating System Executable Loader header 3 | * 4 | * 2018, Operating Systems 5 | */ 6 | 7 | #ifndef LOADER_H_ 8 | #define LOADER_H_ 9 | 10 | #if defined _WIN32 11 | #if defined DLL_EXPORTS 12 | #define FUNC_DECL_PREFIX __declspec(dllexport) 13 | #else 14 | #define FUNC_DECL_PREFIX __declspec(dllimport) 15 | #endif /* DLL_EXPORTS */ 16 | #else 17 | #define FUNC_DECL_PREFIX 18 | #endif /* _WIN32 */ 19 | 20 | FUNC_DECL_PREFIX int so_init_loader(void); 21 | FUNC_DECL_PREFIX int so_execute(char *path, char *argv[]); 22 | 23 | #endif -------------------------------------------------------------------------------- /test/_test/loader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Operating System Executable Loader header 3 | * 4 | * 2018, Operating Systems 5 | */ 6 | 7 | #ifndef LOADER_H_ 8 | #define LOADER_H_ 9 | 10 | #if defined _WIN32 11 | #if defined DLL_EXPORTS 12 | #define FUNC_DECL_PREFIX __declspec(dllexport) 13 | #else 14 | #define FUNC_DECL_PREFIX __declspec(dllimport) 15 | #endif /* DLL_EXPORTS */ 16 | #else 17 | #define FUNC_DECL_PREFIX 18 | #endif /* _WIN32 */ 19 | 20 | FUNC_DECL_PREFIX int so_init_loader(void); 21 | FUNC_DECL_PREFIX int so_execute(char *path, char *argv[]); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /test/util/loader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Operating System Executable Loader header 3 | * 4 | * 2018, Operating Systems 5 | */ 6 | 7 | #ifndef LOADER_H_ 8 | #define LOADER_H_ 9 | 10 | #if defined _WIN32 11 | #if defined DLL_EXPORTS 12 | #define FUNC_DECL_PREFIX __declspec(dllexport) 13 | #else 14 | #define FUNC_DECL_PREFIX __declspec(dllimport) 15 | #endif /* DLL_EXPORTS */ 16 | #else 17 | #define FUNC_DECL_PREFIX 18 | #endif /* _WIN32 */ 19 | 20 | FUNC_DECL_PREFIX int so_init_loader(void); 21 | FUNC_DECL_PREFIX int so_execute(char *path, char *argv[]); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /test/run_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | first_test=0 4 | last_test=9 5 | script=run_test.sh 6 | 7 | # Call init to set up testing environment 8 | bash ./_test/"$script" init 9 | 10 | for i in $(seq $first_test $last_test); do 11 | bash ./_test/"$script" $i 12 | done | tee results.txt 13 | 14 | cat results.txt | grep '\[.*\]$' | awk -F '[] /[]+' ' 15 | BEGIN { 16 | sum=0 17 | } 18 | 19 | { 20 | sum += $(NF-2); 21 | } 22 | 23 | END { 24 | printf "\n%66s [%02d/95]\n", "Total:", sum; 25 | }' 26 | 27 | # Cleanup testing environment 28 | bash ./_test/"$script" cleanup 29 | rm -f results.txt 30 | -------------------------------------------------------------------------------- /src/Makefile.example: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -m32 -Wall -fno-pic 3 | LDFLAGS = -m32 -no-pie 4 | LDLIBS = -lso_loader 5 | 6 | .PHONY: build 7 | build: so_exec so_test_prog 8 | 9 | so_exec: exec.o 10 | $(CC) $(LDFLAGS) -L. -Wl,-Ttext-segment=0x20000000 -o $@ $< $(LDLIBS) 11 | 12 | exec.o: exec/exec.c 13 | $(CC) $(CFLAGS) -Iloader -o $@ -c $< 14 | 15 | so_test_prog: test_prog.o 16 | $(CC) $(LDFLAGS) -nostdlib -o $@ $< 17 | 18 | test_prog.o: test_prog/hello.S 19 | $(CC) $(CFLAGS) -o $@ -c $< 20 | 21 | .PHONY: clean 22 | clean: 23 | -rm -f exec.o so_exec so_test_prog test_prog.o 24 | -------------------------------------------------------------------------------- /test/_test/inputs/data_bss.c: -------------------------------------------------------------------------------- 1 | int __attribute__((aligned(4096))) arr_init[512] = { 0xdeadbeef }; 2 | int arr_uninit[1024]; 3 | 4 | void exit(int code); 5 | int write(int fd, char *buf, int len); 6 | 7 | void _start() 8 | { 9 | int i; 10 | 11 | /* check initialized data */ 12 | if (arr_init[0] != 0xdeadbeef) { 13 | write(1, "FAIL: initialized data\n", 23); 14 | exit(1); 15 | } else { 16 | /* check uninitialized data */ 17 | for (i = 0; i < 1024; i++) 18 | if (arr_uninit[i] != 0) { 19 | write(1, "FAIL: bss\n", 10); 20 | exit(1); 21 | } 22 | } 23 | 24 | write(1, "SUCCESS\n", 8); 25 | 26 | exit(0); 27 | } 28 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | build: 2 | cd ./src &&\ 3 | make &&\ 4 | cp libso_loader.so ./../test 5 | run_test: build 6 | cd ./src;\ 7 | make -f Makefile.example;\ 8 | LD_LIBRARY_PATH=. ./so_exec so_test_prog > ../result.out 9 | run: build 10 | cd ./test &&\ 11 | make -f Makefile.checker > ../results.out 12 | run_test_no: 13 | cd ./test &&\ 14 | _test/run_test.sh init &&\ 15 | _test/run_test.sh 5 &&\ 16 | _test/run_test.sh clean 17 | save: clean 18 | git add -A &&\ 19 | echo Enter commit message: &&\ 20 | read line &&\ 21 | git commit -m "$$line" &&\ 22 | git push 23 | clean: clean_src clean_test 24 | 25 | clean_test: 26 | cd ./test;\ 27 | rm -f libso_loader.so;\ 28 | make -f Makefile.checker clean 29 | 30 | clean_src: 31 | cd ./src;\ 32 | rm -f *.o so_exec so_test_prog libso_loader.so ../results.out ../results.out -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Gabriel Rusu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/loader/exec_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Executable Parser Header 3 | * 4 | * 2018, Operating Systems 5 | */ 6 | 7 | #ifndef SO_EXEC_PARSER_H_ 8 | #define SO_EXEC_PARSER_H_ 9 | 10 | #include 11 | 12 | #define ALIGN_DOWN(v, a) ((v) & ~((a) - 1)) 13 | #define ALIGN_UP(v, a) (((v) + ((a) - 1)) & ~((a)-1)) 14 | 15 | #define PERM_R 0x1 16 | #define PERM_W 0x2 17 | #define PERM_X 0x4 18 | 19 | typedef struct so_seg { 20 | /* virtual address */ 21 | uintptr_t vaddr; 22 | /* size inside the executable file */ 23 | unsigned int file_size; 24 | /* size in memory (can be larger than file_size */ 25 | unsigned int mem_size; 26 | /* offset in file */ 27 | unsigned int offset; 28 | /* permissions */ 29 | unsigned int perm; 30 | /* custom data */ 31 | void *data; 32 | } so_seg_t; 33 | 34 | typedef struct so_exec { 35 | /* base adress */ 36 | uintptr_t base_addr; 37 | /* address of entry point */ 38 | uintptr_t entry; 39 | /* number of segments */ 40 | int segments_no; 41 | /* array of segments */ 42 | so_seg_t *segments; 43 | } so_exec_t; 44 | 45 | /* parse an executable file */ 46 | so_exec_t *so_parse_exec(char *path); 47 | 48 | /* 49 | * start an executable file, previously parsed in a so_exec_t structure 50 | * (jumps to the executable's entry point) 51 | */ 52 | void so_start_exec(so_exec_t *exec, char *argv[]); 53 | 54 | #endif /* SO_EXEC_PARSER_H_ */ 55 | -------------------------------------------------------------------------------- /test/_test/inputs/lib.c: -------------------------------------------------------------------------------- 1 | int write(int fd, char *buf, int len) 2 | { 3 | int rc; 4 | 5 | asm volatile( 6 | "int $0x80 \n" 7 | :"=a"(rc) 8 | :"a"(4), "b"(fd), "c"(buf), "d"(len) 9 | ); 10 | return rc; 11 | } 12 | 13 | int read(int fd, char *buf, int len) 14 | { 15 | int rc; 16 | 17 | asm volatile( 18 | "int $0x80 \n" 19 | :"=a"(rc) 20 | :"a"(3), "b"(fd), "c"(buf), "d"(len) 21 | ); 22 | return rc; 23 | } 24 | 25 | int open(char *path, int flags, int mode) 26 | { 27 | int rc; 28 | 29 | asm volatile( 30 | "int $0x80 \n" 31 | :"=a"(rc) 32 | :"a"(5), "b"(path), "c"(flags), "d"(mode) 33 | ); 34 | return rc; 35 | } 36 | 37 | int close(int fd) 38 | { 39 | int rc; 40 | 41 | asm volatile( 42 | "int $0x80 \n" 43 | :"=a"(rc) 44 | :"a"(6), "b"(fd) 45 | ); 46 | return rc; 47 | } 48 | 49 | void exit(int code) 50 | { 51 | while (1) { 52 | asm volatile( 53 | "int $0x80 \n" 54 | "hlt \n" 55 | : 56 | :"a"(1), "b"(code) 57 | ); 58 | } 59 | } 60 | 61 | int itoa(int n, char *buf) 62 | { 63 | int num_digits = 0; 64 | int n2 = n; 65 | int i; 66 | int c; 67 | 68 | while (n) { 69 | n /= 10; 70 | num_digits++; 71 | } 72 | 73 | n = n2; 74 | i = num_digits-1; 75 | 76 | while(n) { 77 | c = n % 10; 78 | n /= 10; 79 | buf[i] = '0' + c; 80 | i--; 81 | } 82 | 83 | return num_digits; 84 | } 85 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | This archive contains a test suite for testing the Operating System loader 2 | library for Linux (`libso_loader.so`). The test suite consists of several 3 | unit tests, each of them testing a different functionality of the loader. 4 | 5 | # Archive Files 6 | The checker consists of the following files: 7 | * `README.md` - this file 8 | * `Makefile.checker` - Makefile for automating the build process on Linux 9 | * `run_all.sh` - script to run all tests defined 10 | * `_test` - directory that contains the following: 11 | * `run_test.sh` - runs only a specific test 12 | * `test_lib.sh` - a shell library used to run tests 13 | * `run_test.c` - source file used to run the executable using the 14 | `so_loader` library and dump the page fault information in a file 15 | * `loader.h` - SO loader's header 16 | * `Makefile` - Makefile used for building the testing binary 17 | * `inputs/` - directory where the testing executables are located 18 | * `refs/` - directory where tests reference files are stored 19 | 20 | # Checker 21 | The local directory must contain the so_loader library (`libso_loader.so`). 22 | Use Makefile.checker to properly run the entire test suite: 23 | ``` 24 | make -f Makefile.checker 25 | ``` 26 | 27 | # Debug 28 | If you want to keep the reference files after running a test, you have to set 29 | the `DO_CLEANUP` environment variable to `no`: 30 | ``` 31 | DO_CLEANUP=no make -f Makefile.checker 32 | ``` 33 | 34 | In order to run a single test, you can manually run the `run_test.sh` script: 35 | ``` 36 | _test/run_test.sh init 37 | _test/run_test.sh 38 | _test/run_test.sh clean 39 | ``` 40 | 41 | # Cleanup 42 | To clean the files generated by the checker you have to run: 43 | ``` 44 | make -f Makefile.checker clean 45 | ``` 46 | -------------------------------------------------------------------------------- /test/_test/inputs/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | BINS = hello sum bss data_bss no_perm inv_perm check_perm check_exec qsort 3 | CFLAGS = -m32 -Wall -fno-pic -fno-stack-protector -g 4 | LDFLAGS = -m32 -static -no-pie 5 | 6 | all: $(BINS) 7 | 8 | hello: hello.o 9 | $(CC) $(LDFLAGS) -nostdlib -o $@ $< 10 | 11 | hello.o: hello.S 12 | $(CC) -m32 -o $@ -c $< 13 | 14 | sum: sum.o lib.o 15 | $(CC) $(LDFLAGS) -nostdlib -o $@ $^ 16 | 17 | sum.o: sum.c 18 | $(CC) $(CFLAGS) -o $@ -c $< 19 | 20 | bss: bss.o lib.o 21 | $(CC) $(LDFLAGS) -nostdlib -o $@ $^ 22 | 23 | bss.o: bss.c 24 | $(CC) $(CFLAGS) -o $@ -c $< 25 | 26 | data_bss: data_bss.o lib.o 27 | $(CC) $(LDFLAGS) -nostdlib -o $@ $^ 28 | 29 | data_bss.o: data_bss.c 30 | $(CC) $(CFLAGS) -o $@ -c $< 31 | 32 | no_perm: no_perm.o lib.o 33 | $(CC) $(LDFLAGS) -nostdlib -o $@ $^ 34 | 35 | no_perm.o: no_perm.c 36 | $(CC) $(CFLAGS) -o $@ -c $< 37 | 38 | inv_perm: inv_perm.o lib.o 39 | $(CC) $(LDFLAGS) -nostdlib -o $@ $^ 40 | 41 | inv_perm.o: inv_perm.c 42 | $(CC) $(CFLAGS) -o $@ -c $< 43 | 44 | check_perm: check_perm.o lib.o 45 | $(CC) $(LDFLAGS) -nostdlib -o $@ $^ 46 | 47 | check_perm.o: check_perm.c 48 | $(CC) $(CFLAGS) -o $@ -c $< 49 | 50 | check_exec: check_exec.o lib.o 51 | $(CC) $(LDFLAGS) -nostdlib -o $@ $^ 52 | 53 | check_exec.o: check_exec.c 54 | $(CC) $(CFLAGS) -o $@ -c $< 55 | 56 | qsort: qsort.o 57 | $(CC) $(LDFLAGS) -o $@ $^ 58 | 59 | qsort.o: qsort.c 60 | $(CC) $(CFLAGS) -o $@ -c $< 61 | 62 | lib.o: lib.c 63 | $(CC) $(CFLAGS) -O2 -o $@ -c $< 64 | 65 | clean: 66 | -@rm -f hello.o hello 67 | -@rm -f sum.o sum 68 | -@rm -f bss.o bss 69 | -@rm -f data_bss.o data_bss 70 | -@rm -f no_perm no_perm.o 71 | -@rm -f inv_perm inv_perm.o 72 | -@rm -f check_perm check_perm.o 73 | -@rm -f check_exec check_exec.o 74 | -@rm -f qsort qsort.o 75 | -@rm -f lib.o 76 | -------------------------------------------------------------------------------- /test/_test/run_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Operating System Executable Loader Tester 3 | * 4 | * 2018, Operating Systems 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "loader.h" 17 | 18 | static int no_page_faults; 19 | static char *fault_count_fname; 20 | static void (*previous_handler)(int, siginfo_t *, void *); 21 | 22 | static int itoa(int n, char *buf) 23 | { 24 | int num_digits = 0; 25 | int n2 = n; 26 | int i; 27 | int c; 28 | 29 | while (n) { 30 | n /= 10; 31 | num_digits++; 32 | } 33 | 34 | n = n2; 35 | i = num_digits-1; 36 | 37 | while (n) { 38 | c = n % 10; 39 | n /= 10; 40 | buf[i] = '0' + c; 41 | i--; 42 | } 43 | 44 | return num_digits; 45 | } 46 | 47 | static void test_segv_handler(int signum, siginfo_t *info, void *context) 48 | { 49 | int fd; 50 | char buf[128]; 51 | int len; 52 | 53 | if (signum != SIGSEGV) 54 | return; 55 | if (info->si_signo != SIGSEGV) 56 | return; 57 | 58 | if (info->si_code == SEGV_MAPERR) 59 | no_page_faults++; 60 | 61 | fd = open(fault_count_fname, O_RDWR|O_CREAT|O_TRUNC, 0644); 62 | if (fd >= 0) { 63 | len = itoa(no_page_faults, buf); 64 | buf[len++] = '\n'; 65 | write(fd, buf, len); 66 | close(fd); 67 | } 68 | 69 | previous_handler(signum, info, context); 70 | } 71 | 72 | int main(int argc, char *argv[]) 73 | { 74 | struct sigaction sa; 75 | struct sigaction prev; 76 | 77 | if (argc != 2 && argc != 3) { 78 | fprintf(stderr, "Usage: %s \n", argv[0]); 79 | return 1; 80 | } 81 | 82 | if (argc == 3) 83 | fault_count_fname = argv[2]; 84 | else 85 | fault_count_fname = "fault_cnt.out"; 86 | 87 | so_init_loader(); 88 | 89 | memset(&sa, 0, sizeof(sa)); 90 | sa.sa_sigaction = test_segv_handler; 91 | sa.sa_flags = SA_SIGINFO; 92 | 93 | if (sigaction(SIGSEGV, &sa, &prev) < 0) { 94 | fprintf(stderr, "cannot get previous signal handler\n"); 95 | return 1; 96 | } 97 | 98 | if ((void(*)())prev.sa_sigaction == SIG_DFL) { 99 | fprintf(stderr, "so_init_loader didn't set a signal handler\n"); 100 | return 1; 101 | } 102 | previous_handler = prev.sa_sigaction; 103 | 104 | so_execute(argv[1], argv+1); 105 | 106 | // shouldn't reach here 107 | return 1; 108 | } 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Project logo 4 |

5 | 6 |

E.L.F Executable Loader

7 | 8 |

9 | The E.L.F Executable Loader loads the executable file into memory page-by-page, using a request-paging mechanism - a page will only be loaded when it is needed. For simplicity, the loader runs only static executable files - which is not linked to shared / dynamic libraries. 10 |
11 |

12 | 13 | ## 📝 Table of Contents 14 | - [About](#about) 15 | - [Getting Started](#getting_started) 16 | - [Usage](#usage) 17 | - [Built Using](#built_using) 18 | - [Authors](#authors) 19 | 20 | ## 🧐 About 21 | The interface of the loader is presented in the header loader.h file. This has functions to initialize a loader (so_init loader) and execute a binary (so_execute) 22 | 23 | * The so_init_loader function performs the library initialization. Within the function, the page fault action will be a routine for handling the **SIGSEGV** signal. 24 | * The so_execute function performs the parsing of the binary specified in the path and executes the first entry point of the executable. 25 | 26 | ## 🏁 Getting Started 27 | These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. 28 | 29 | ### Prerequisites 30 | To use the loader.h library on your projects you must have: 31 | 32 | * for UNIX based operating systems: 33 | * gcc - is a tool from the GNU Compiler Collection used to compile and link C programs 34 | 35 | ### Installing 36 | This is a step by step series of examples that tell you how to get a development env running. 37 | 38 | * Linux: 39 | * start by updating the packages list 40 | ```bash 41 | sudo apt-get update 42 | ``` 43 | * install the build-essential package(a bundle of packages including gcc, g++ and make) by typing: 44 | ```bash 45 | sudo apt-get install build-essential 46 | ``` 47 | ## 🔧 Running the tests 48 | If you want to run the automated tests for Linux system you must follow the following steps: 49 | * clone the repository by copping the following command in your terminal: 50 | ``` 51 | git clone https://github.com/gabriel-rusu/E.L.F-Executable-Loader.git 52 | ``` 53 | * go into the project director and run the following command: 54 | ```bash 55 | make test 56 | ``` 57 | * the results of the tests will be in the newly created file result.out 58 | 59 | ## 🎈 Usage 60 | If you want to use the ***libso_loader.so*** library in your projects then you must add the ***loader.h*** header in the desired source file and specify at the compile time the path to the libso_loader.so library. 61 | 62 | * running the following command in the project director will generate the libso_loader.so: 63 | ```bash 64 | make build 65 | ``` 66 | ## ⛏️ Built Using 67 | - [Visual Studio Code](https://code.visualstudio.com/) - code editor 68 | - [gcc](https://gcc.gnu.org/) - used to compile the library on my Linux machine 69 | 70 | ## ✍️ Authors 71 | - [@gabriel-rusu](https://github.com/gabriel-rusu) - implementation 72 | -------------------------------------------------------------------------------- /test/_test/inputs/check_perm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void exit(int); 9 | 10 | int x; 11 | 12 | #define BUF_SIZE 8192 13 | 14 | static char *strchr(const char *s, int c) 15 | { 16 | int i; 17 | 18 | for (i = 0; s[i]; i++) 19 | if (s[i] == c) 20 | return (char *)(s+i); 21 | 22 | return NULL; 23 | } 24 | 25 | unsigned long strtoul(char *s, char **endptr) 26 | { 27 | unsigned long val = 0; 28 | int negative = 0; 29 | 30 | if (*s == '-') { 31 | negative = 1; 32 | s++; 33 | } 34 | 35 | if (*s == '0' && ((*s == 'x') || (*s == 'X'))) 36 | s += 2; 37 | 38 | while (1) { 39 | if (!*s) 40 | break; 41 | 42 | if (*s >= '0' && *s <= '9') 43 | val = (val << 4) + (*s - '0'); 44 | else if (*s >= 'a' && *s <= 'f') 45 | val = (val << 4) + (*s - 'a' + 10); 46 | else if (*s >= 'A' && *s <= 'F') 47 | val = (val << 4) + (*s - 'A' + 10); 48 | else 49 | break; 50 | 51 | s++; 52 | } 53 | 54 | *endptr = s; 55 | 56 | if (negative) 57 | val = -val; 58 | 59 | return val; 60 | } 61 | 62 | int virtual_query(void *addr, int *perm) 63 | { 64 | char buf[BUF_SIZE]; 65 | uintptr_t __addr, start, end; 66 | char *p; 67 | char *q; 68 | char *line; 69 | int fd; 70 | int found = 0; 71 | int ret = 0; 72 | int rc; 73 | 74 | *perm = 0; 75 | 76 | fd = open("/proc/self/maps", O_RDONLY); 77 | if (fd < 0) { 78 | write(1, "Couldn't open /proc/self/maps\n", 30); 79 | goto out; 80 | } 81 | 82 | rc = read(fd, buf, BUF_SIZE); 83 | if (rc < 0) { 84 | write(1, "Read error\n", 11); 85 | goto out_close; 86 | } 87 | 88 | __addr = (uintptr_t)addr; 89 | line = buf; 90 | 91 | /* 92 | * a line looks like this: 93 | * 08048000-080ea000 r-xp 00000000 08:01 6555842 ... 94 | */ 95 | while(1) { 96 | p = strchr(line, '-'); 97 | if (!p) { 98 | write(1, "Error parsing /proc/self/maps\n", 30); 99 | goto out_close; 100 | } 101 | 102 | start = strtoul(line, &q); 103 | if (q != p) { 104 | write(1, "Error parsing /proc/self/maps\n", 30); 105 | goto out_close; 106 | } 107 | 108 | end = strtoul(p+1, &q); 109 | if (*q != ' ') { 110 | write(1, "Error parsing /proc/self/maps\n", 30); 111 | goto out_close; 112 | } 113 | 114 | q++; 115 | if (__addr >= start && __addr < end) { 116 | found = 1; 117 | break; 118 | } 119 | 120 | line = strchr(line, '\n'); 121 | if (!line) 122 | break; 123 | line++; 124 | } 125 | 126 | if (!found) 127 | goto out_close; 128 | 129 | if (q[0] == 'r') 130 | *perm |= PROT_READ; 131 | if (q[1] == 'w') 132 | *perm |= PROT_WRITE; 133 | if (q[2] == 'x') 134 | *perm |= PROT_EXEC; 135 | 136 | ret = 1; 137 | 138 | out_close: 139 | close(fd); 140 | out: 141 | return ret; 142 | } 143 | 144 | void _start() 145 | { 146 | int perm; 147 | int ret; 148 | 149 | // make sure x is loaded into memory 150 | x = 200; 151 | 152 | // query an address inside the code area 153 | ret = virtual_query(&_start, &perm); 154 | if (!ret) { 155 | write(1, "virtual_query failed\n", 21); 156 | exit(1); 157 | } 158 | 159 | // the permissions should be rx 160 | if (perm != (PROT_READ|PROT_EXEC)) { 161 | write(1, "Code area doesn't have rx permissions\n", 38); 162 | exit(1); 163 | } 164 | 165 | // query an address inside the data area 166 | ret = virtual_query(&x, &perm); 167 | if (!ret) { 168 | write(1, "virtual_query failed\n", 21); 169 | exit(1); 170 | } 171 | 172 | // the permissions should be rw 173 | if (perm != (PROT_READ|PROT_WRITE)) { 174 | write(1, "Data area doesn't have rw permissions\n", 38); 175 | exit(1); 176 | } 177 | 178 | write(1, "SUCCESS\n", 8); 179 | 180 | exit(0); 181 | } 182 | -------------------------------------------------------------------------------- /src/loader/loader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Loader Implementation 3 | * 4 | * 2018, Operating Systems 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "exec_parser.h" 18 | #include 19 | 20 | #define SIGSEGV_ERROR 139 21 | 22 | typedef struct page 23 | { 24 | void *pageAddress; 25 | struct page *nextPage; 26 | } Page; 27 | 28 | typedef struct list 29 | { 30 | Page *cachedPages; 31 | int pageSize; 32 | } Loader; 33 | 34 | static so_exec_t *exec; 35 | static int exec_decriptor; 36 | static Loader *loader; 37 | 38 | // initialize the loader structure 39 | void init(Loader **loader) 40 | { 41 | *loader = malloc(sizeof(Loader)); 42 | (*loader)->cachedPages = NULL; 43 | (*loader)->pageSize = getpagesize(); 44 | } 45 | 46 | // adds a page to the loader mapped pages for the program in execution 47 | void addPage(void *pageAddress, Loader *loader) 48 | { 49 | Page *newPage = malloc(sizeof(Page)); 50 | newPage->pageAddress = pageAddress; 51 | newPage->nextPage = loader->cachedPages; 52 | loader->cachedPages = newPage; 53 | } 54 | 55 | // search & find the pageAddress in the loader already mapped pages 56 | bool find(void *pageAddress, Loader *loader) 57 | { 58 | Page *cachedPage = loader->cachedPages; 59 | while (cachedPage) 60 | { 61 | if (((char *)pageAddress - (char *)cachedPage->pageAddress) < loader->pageSize && (pageAddress - cachedPage->pageAddress) > 1) 62 | return true; 63 | cachedPage = cachedPage->nextPage; 64 | } 65 | return false; 66 | } 67 | 68 | //reads into the buffer buf count bytes 69 | ssize_t xread(int fd, void *buf, size_t count) 70 | { 71 | size_t bytes_read = 0; 72 | 73 | while (bytes_read < count) 74 | { 75 | ssize_t bytes_read_now = 76 | read(fd, buf + bytes_read, 77 | count - bytes_read); 78 | 79 | if (bytes_read_now == 0) /* EOF */ 80 | return bytes_read; 81 | 82 | if (bytes_read_now < 0) /* I/O error */ 83 | return -1; 84 | 85 | bytes_read += bytes_read_now; 86 | } 87 | 88 | return bytes_read; 89 | } 90 | 91 | // copy the instructions into the pages 92 | void copy_into(so_seg_t *segment,size_t offset, void *pageAddress) 93 | { 94 | ssize_t pageSize = getpagesize(); 95 | char *buffer = malloc(sizeof(char)*pageSize); 96 | lseek(exec_decriptor, segment->offset + offset, SEEK_SET); 97 | if (offset + pageSize <= segment->file_size) 98 | { 99 | xread(exec_decriptor, buffer, pageSize); 100 | memcpy(pageAddress, buffer, pageSize); 101 | } 102 | else if (offset <= segment->file_size) 103 | { 104 | xread(exec_decriptor, buffer, segment->file_size - offset); 105 | memset(buffer + segment->file_size - offset, 0, offset + pageSize - segment->file_size); 106 | memcpy(pageAddress, buffer, pageSize); 107 | } 108 | else if (offset > segment->file_size) 109 | memset(pageAddress, 0, pageSize); 110 | free(buffer); 111 | } 112 | 113 | //find the segment that caused the segfault 114 | so_seg_t *find_segment_of(void *addr) 115 | { 116 | long diff; 117 | for (int i = 0; i < exec->segments_no; i++) 118 | { 119 | diff = (char *)addr - (char *)exec->segments[i].vaddr; 120 | if (diff <= exec->segments[i].mem_size && diff >= 0) 121 | return &(exec->segments[i]); 122 | } 123 | return NULL; 124 | } 125 | 126 | //the definition of the new handler for the SIGSEGV signal 127 | static void signal_handler(int sig, siginfo_t *si, void *unused) 128 | { 129 | size_t pagesize = getpagesize(); 130 | so_seg_t *segment = find_segment_of(si->si_addr); 131 | size_t segment_offset = (char *)si->si_addr - (char *)segment->vaddr; 132 | size_t page_offset = segment_offset % pagesize; 133 | segment_offset -= page_offset; 134 | 135 | if (!segment) 136 | { 137 | perror("I don't find a segmnt!"); 138 | exit(SIGSEGV_ERROR); 139 | } 140 | if (find(si->si_addr, loader)) 141 | { 142 | perror("I found a page!"); 143 | exit(SIGSEGV_ERROR); 144 | } 145 | //map the addres that generated the SIGSEGV signal 146 | void *pageAddress = mmap((void *)segment->vaddr + segment_offset, getpagesize(), PERM_R | PERM_W, MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS, -1, 0); 147 | copy_into(segment, segment_offset, pageAddress); 148 | addPage(pageAddress, loader); 149 | mprotect(pageAddress, getpagesize(), segment->perm); 150 | } 151 | 152 | //initialize loader structure and assigns the new handler for SIGSEGV 153 | int so_init_loader(void) 154 | { 155 | struct sigaction sig; 156 | 157 | init(&loader); 158 | memset(&sig, 0, sizeof(sig)); 159 | sig.sa_flags = SA_SIGINFO; 160 | sigemptyset(&sig.sa_mask); 161 | sig.sa_sigaction = signal_handler; 162 | sigaction(SIGSEGV, &sig, NULL); 163 | 164 | return -1; 165 | } 166 | 167 | int so_execute(char *path, char *argv[]) 168 | { 169 | 170 | exec_decriptor = open(path, O_RDONLY); //tests for file existance are made in the so_parse_exec 171 | //if this fails then the so_parse_exec will exit 172 | exec = so_parse_exec(path); 173 | if (!exec) 174 | return -1; 175 | 176 | so_start_exec(exec, argv); 177 | 178 | return -1; 179 | } 180 | -------------------------------------------------------------------------------- /src/loader/exec_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Executable Parser Implementation 3 | * 4 | * 2018, Operating Systems 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "exec_parser.h" 16 | 17 | #define BUFSIZE 1024 18 | 19 | static void fix_auxv(uintptr_t base, char *envp[]) 20 | { 21 | Elf32_auxv_t *auxv; 22 | Elf32_Ehdr *ehdr; 23 | Elf32_Phdr *phdr; 24 | 25 | ehdr = (Elf32_Ehdr *)base; 26 | phdr = (Elf32_Phdr *)((uintptr_t)ehdr + ehdr->e_phoff); 27 | 28 | while (*envp) 29 | envp++; 30 | 31 | auxv = (Elf32_auxv_t *)(++envp); 32 | 33 | while (*envp) 34 | envp++; 35 | 36 | while (auxv->a_type != AT_NULL) { 37 | switch (auxv->a_type) { 38 | case AT_PHDR: 39 | auxv->a_un.a_val = (uint32_t)(unsigned long)phdr; 40 | break; 41 | case AT_BASE: 42 | auxv->a_un.a_val = 0; 43 | break; 44 | case AT_ENTRY: 45 | auxv->a_un.a_val = ehdr->e_entry; 46 | break; 47 | case AT_EXECFN: 48 | auxv->a_un.a_val = 0; 49 | break; 50 | } 51 | auxv++; 52 | } 53 | 54 | } 55 | 56 | 57 | void so_start_exec(so_exec_t *exec, char *argv[]) 58 | { 59 | int *pargc; 60 | 61 | fix_auxv(exec->base_addr, __environ); 62 | /* fix argv to use the one from the main prog */ 63 | argv--; 64 | 65 | pargc = (int *)argv - 1; 66 | 67 | pargc[1] = pargc[0] - 1; 68 | 69 | asm volatile( 70 | "mov %0, %%eax\n" 71 | "mov %1, %%ebx\n" 72 | "mov %%ebx, %%esp\n" 73 | "xor %%ebx, %%ebx\n" 74 | "xor %%ecx, %%ecx\n" 75 | "xor %%edx, %%edx\n" 76 | "xor %%ebp, %%ebp\n" 77 | "xor %%esi, %%esi\n" 78 | "xor %%edi, %%edi\n" 79 | "jmp *%%eax\n" 80 | ::"m"(exec->entry), "m"(argv) :); 81 | } 82 | 83 | so_exec_t *so_parse_exec(char *path) 84 | { 85 | so_exec_t *exec = NULL; 86 | so_seg_t *seg; 87 | char hdr[BUFSIZE]; 88 | int ret; 89 | Elf32_Ehdr *ehdr; 90 | Elf32_Phdr *phdr; 91 | int i; 92 | int j; 93 | int num_load_phdr; 94 | int pagesz; 95 | int fd; 96 | size_t diff; 97 | 98 | pagesz = getpagesize(); 99 | 100 | fd = open(path, O_RDONLY); 101 | if (fd < 0) { 102 | perror("open"); 103 | goto out; 104 | } 105 | 106 | ret = read(fd, hdr, BUFSIZE); 107 | if (ret < 0) { 108 | perror("read"); 109 | goto out_close; 110 | } 111 | 112 | if (ret < (sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr))) { 113 | fprintf(stderr, "file too small\n"); 114 | goto out_close; 115 | } 116 | 117 | ehdr = (Elf32_Ehdr *)hdr; 118 | phdr = (Elf32_Phdr *)((intptr_t)ehdr + ehdr->e_phoff); 119 | 120 | /* allow only 32-bit ELF executables (no PIE) for i386 */ 121 | if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || 122 | ehdr->e_ident[EI_MAG1] != ELFMAG1 || 123 | ehdr->e_ident[EI_MAG2] != ELFMAG2 || 124 | ehdr->e_ident[EI_MAG3] != ELFMAG3) { 125 | fprintf(stderr, "not an ELF file: invalid magic\n"); 126 | goto out_close; 127 | } 128 | 129 | if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) { 130 | fprintf(stderr, "not a 32-bit ELF file\n"); 131 | goto out_close; 132 | } 133 | 134 | if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { 135 | fprintf(stderr, "not a LSB ELF file\n"); 136 | goto out_close; 137 | } 138 | 139 | if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) { 140 | fprintf(stderr, "invalid EI_VERSION\n"); 141 | goto out_close; 142 | } 143 | 144 | if (ehdr->e_ident[EI_OSABI] != ELFOSABI_GNU && 145 | ehdr->e_ident[EI_OSABI] != ELFOSABI_SYSV) { 146 | fprintf(stderr, "invalid ABI\n"); 147 | goto out_close; 148 | } 149 | 150 | if (ehdr->e_type != ET_EXEC) { 151 | fprintf(stderr, "invalid executable type\n"); 152 | goto out_close; 153 | } 154 | 155 | if (ehdr->e_machine != EM_386) { 156 | fprintf(stderr, "invalid machine\n"); 157 | goto out_close; 158 | } 159 | 160 | if (ehdr->e_version != EV_CURRENT) { 161 | fprintf(stderr, "invalid version\n"); 162 | goto out_close; 163 | } 164 | 165 | if (ret < (sizeof(Elf32_Ehdr) + ehdr->e_phnum * ehdr->e_phentsize)) { 166 | fprintf(stderr, "too many program headers\n"); 167 | goto out_close; 168 | } 169 | 170 | exec = malloc(sizeof(*exec)); 171 | if (!exec) { 172 | fprintf(stderr, "out of memory\n"); 173 | goto out_close; 174 | } 175 | 176 | num_load_phdr = 0; 177 | for (i = 0; i < ehdr->e_phnum; i++) { 178 | if (phdr[i].p_type == PT_LOAD) 179 | num_load_phdr++; 180 | } 181 | 182 | exec->base_addr = 0xffffffff; 183 | exec->entry = ehdr->e_entry; 184 | exec->segments_no = num_load_phdr; 185 | exec->segments = (so_seg_t *)malloc(num_load_phdr * sizeof(so_seg_t)); 186 | 187 | /* convert ELF phdrs to so_segments */ 188 | j = 0; 189 | for (i = 0; i < ehdr->e_phnum; i++) { 190 | if (phdr[i].p_type == PT_LOAD) { 191 | seg = &exec->segments[j]; 192 | 193 | seg->vaddr = ALIGN_DOWN(phdr[i].p_vaddr, pagesz); 194 | diff = phdr[i].p_vaddr - seg->vaddr; 195 | seg->offset = phdr[i].p_offset - diff; 196 | seg->file_size = phdr[i].p_filesz + diff; 197 | seg->mem_size = phdr[i].p_memsz + diff; 198 | seg->perm = 0; 199 | 200 | if (phdr[i].p_flags & PF_X) 201 | seg->perm |= PERM_X; 202 | if (phdr[i].p_flags & PF_R) 203 | seg->perm |= PERM_R; 204 | if (phdr[i].p_flags & PF_W) 205 | seg->perm |= PERM_W; 206 | 207 | if (seg->vaddr < exec->base_addr) 208 | exec->base_addr = seg->vaddr; 209 | 210 | j++; 211 | } 212 | } 213 | 214 | out_close: 215 | close(fd); 216 | out: 217 | return exec; 218 | } 219 | -------------------------------------------------------------------------------- /test/_test/test_lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Tema1 Test Suite 5 | # 6 | # 2012-2017, Operating Systems 7 | # 8 | 9 | # ----------------- General declarations and util functions ------------------ # 10 | 11 | if [ $(uname -s) = "Linux" ]; then 12 | OS_PLATFORM="lin" 13 | else 14 | OS_PLATFORM="win" 15 | fi 16 | 17 | # Enable/disable exiting when program fails. 18 | EXIT_IF_FAIL=0 19 | # Enable/disable debug (1/0). 20 | DEBUG_=0 21 | # checkpatch.pl URL 22 | CHECKPATCH_URL="https://raw.githubusercontent.com/torvalds/linux/master/scripts/checkpatch.pl" 23 | COMMON_IGNORE_FLAGS=" 24 | SPLIT_STRING,SSCANF_TO_KSTRTO,NEW_TYPEDEFS,VOLATILE,INLINE,USE_FUNC,AVOID_EXTERNS,CONST_STRUCT,SYMBOLIC_PERMS,FUNCTION_ARGUMENTS,SPDX_LICENSE_TAG" 25 | LIN_IGNORE_FLAGS="$COMMON_IGNORE_FLAGS" 26 | WIN_IGNORE_FLAGS="$COMMON_IGNORE_FLAGS,DOS_LINE_ENDINGS" 27 | 28 | if [ $OS_PLATFORM == "lin" ]; then 29 | CHECKPATCH_IGNORE_FLAGS=$LIN_IGNORE_FLAGS 30 | else 31 | CHECKPATCH_IGNORE_FLAGS=$WIN_IGNORE_FLAGS 32 | fi 33 | 34 | CHECKPATCH_ARGS=" 35 | --no-tree 36 | --no-summary 37 | --terse 38 | --ignore $CHECKPATCH_IGNORE_FLAGS 39 | --show-types" 40 | 41 | DEBUG() 42 | { 43 | if test "x$DEBUG_" = "x1"; then 44 | $@ 1>&2 45 | fi 46 | } 47 | 48 | print_header() 49 | { 50 | header="${1}" 51 | header_len=${#header} 52 | printf "\n" 53 | if [ $header_len -lt 71 ]; then 54 | padding=$(((71 - $header_len) / 2)) 55 | for ((i = 0; i < $padding; i++)); do 56 | printf " " 57 | done 58 | fi 59 | printf "= %s =\n\n" "${header}" 60 | } 61 | 62 | 63 | test_do_fail() 64 | { 65 | printf "failed [ 0/%02d]\n" "$max_points" 66 | if test "x$EXIT_IF_FAIL" = "x1"; then 67 | exit 1 68 | fi 69 | } 70 | 71 | test_do_pass() 72 | { 73 | printf "passed [%02d/%02d]\n" "$points" "$max_points" 74 | } 75 | 76 | 77 | DF=${DF:--BEbwu} 78 | 79 | # Compares to files and prints the first 10 80 | # lines if the files differ 81 | function compare() 82 | { 83 | diff $DF $1 $2 > __result 84 | ret=$? 85 | if [ $ret != 0 ] ; then 86 | echo "$1 vs $2:" 87 | cat __result | head -n 10 88 | fi 89 | rm -f __result 90 | return $ret 91 | } 92 | 93 | basic_test() 94 | { 95 | DEBUG echo "TEST: $@" 96 | printf "%02d) %s" "$test_index" "$description" 97 | 98 | for ((i = 0; i < 56 - ${#description}; i++)); do 99 | printf "." 100 | done 101 | 102 | $@ > /dev/null 2>&1 103 | if test $? -eq 0; then 104 | test_do_pass "$points" 105 | else 106 | test_do_fail "$points" 107 | fi 108 | } 109 | 110 | 111 | check_source() 112 | { 113 | # SKIP some files from checking 114 | local SKIP 115 | [ -n "$CHECK_SKIP" ] && SKIP="grep -v $CHECK_SKIP" || SKIP="cat" 116 | 117 | # check to see if we have checkpatch 118 | check_patch=$(which checkpatch.pl 2> /dev/null) 119 | if ! [ -x "$check_patch" ]; then 120 | echo "'checkpatch.pl' tool not found on your system."\ 121 | "Skipping source check..." 122 | echo "Please download 'checkpatch.pl' from '$CHECKPATCH_URL'"\ 123 | "and install it in your \$PATH." 124 | echo 125 | return 126 | fi 127 | 128 | # try to find sources in the current directory 129 | src_files="$(find "${SRC_DIR:-.}" -type f -iregex \ 130 | '.*\.\(c\|h\|cpp\|hpp\|cc\|hh\|cxx\|hxx\)' | $SKIP)" 131 | if [ -z "$src_files" ]; then 132 | read -t 60 -e -p 'Please provide path to your sources: ' SRC_DIR 133 | if [ "$?" -ne "0" -o -z "$SRC_DIR" ]; then 134 | echo -e "No path provided! Skipping source check...\n" 135 | return 136 | fi 137 | if ! [ -e "$SRC_DIR" ]; then 138 | echo -e "File or directory '$SRC_DIR' does not exist. " \ 139 | "Skipping source check...\n" 140 | return 141 | fi 142 | src_files="$(find "$SRC_DIR" -type f -iregex \ 143 | '.*\.\(c\|h\|cpp\|hpp\|cc\|hh\|cxx\|hxx\)' | $SKIP)" 144 | if [ -z "$src_files" ]; then 145 | echo -e "No sources found in '$SRC_DIR'. " \ 146 | "Skipping source check...\n" 147 | return 148 | fi 149 | fi 150 | # now we have sources in $SRC_DIR or . 151 | touch $(dirname $check_patch)/const_structs.checkpatch &> /dev/null 152 | OUT=$(find "${SRC_DIR:-.}" -type f -iregex \ 153 | '.*\.\(c\|h\|cpp\|hpp\|cc\|hh\|cxx\|hxx\)' | $SKIP | \ 154 | xargs $check_patch $CHECKPATCH_ARGS -f 2>&1 | tail -n +2 | \ 155 | sort -u -t":" -k4,4 | head -n 20) 156 | echo "$OUT" 157 | } 158 | 159 | test_coding_style() 160 | { 161 | check_source 162 | [ -n "$src_files" -a -z "$OUT" ] 163 | basic_test [ $? -eq 0 ] 164 | } 165 | 166 | check_tests() 167 | { 168 | # we need to have the test_fun_array defined 169 | if [ -z "$test_fun_array" ]; then 170 | echo "test_fun_array is not defined - don't know what to run" 1>&2 171 | exit 1 172 | fi 173 | 174 | # max_points 175 | if [ -z "$max_points" ]; then 176 | echo "max_points is not defined - don't the total number of points" 1>&2 177 | exit 1 178 | fi 179 | } 180 | 181 | run_tests() 182 | { 183 | if test $# -ne 1; then 184 | echo "Usage: $0 test_number | init | cleanup" 1>&2 185 | exit 1 186 | fi 187 | 188 | test_index=$1 189 | 190 | if test $test_index == "init"; then 191 | init_world 192 | exit 0 193 | fi 194 | 195 | if test $test_index == "cleanup"; then 196 | cleanup_world 197 | exit 0 198 | fi 199 | 200 | if test $test_index == "check"; then 201 | check_source 202 | exit 0 203 | fi 204 | 205 | arr_index=$(($test_index * 3)) 206 | last_test=$((${#test_fun_array[@]} / 3)) 207 | description=${test_fun_array[$(($arr_index + 1))]} 208 | points=${test_fun_array[$(($arr_index + 2))]} 209 | 210 | if test "$test_index" -gt "$last_test" -o "$arr_index" -lt 0; then 211 | echo "Error: Test index is out range (1 < test_index <= $last_test)." 1>&2 212 | exit 1 213 | fi 214 | 215 | # Run proper function 216 | ${test_fun_array[$(($arr_index))]} 217 | } 218 | -------------------------------------------------------------------------------- /test/_test/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Tema 3 - Loader de Executabile - Test Suite 5 | # 6 | # 2018, Operating Systems 7 | # 8 | 9 | # ----------------- General declarations and util functions ------------------ # 10 | 11 | loader_main="_test/run_test" 12 | MAIN_TEST_DIR="_test/outputs" 13 | INPUT_DIR="_test/inputs" 14 | REFS_DIR="_test/refs" 15 | LOG_FILE="/dev/null" 16 | max_points=95 17 | TEST_TIMEOUT=30 18 | 19 | # change this of you want to keep the logs after execution 20 | DO_CLEANUP=${DO_CLEANUP:-yes} 21 | 22 | TEST_LIB=_test/test_lib.sh 23 | CHECK_SKIP='_test/inputs' 24 | 25 | # load the lib functions 26 | if ! [ -e "$TEST_LIB" ]; then 27 | echo "Test library not found. Check \$TEST_LIB ($TEST_LIB)" 28 | exit 1 29 | fi 30 | source "$TEST_LIB" 31 | 32 | # ---------------------------------------------------------------------------- # 33 | 34 | # ----------------- Init and cleanup tests ----------------------------------- # 35 | 36 | # Initializes a test 37 | init_test() 38 | { 39 | OUT_F=$MAIN_TEST_DIR"/test"$test_index".out" 40 | TMP_F=$MAIN_TEST_DIR"/test"$test_index".tmp" 41 | REF_F=$REFS_DIR"/test"$test_index".ref" 42 | FAULT_CNT_F=$MAIN_TEST_DIR"/test"$test_index"_fault_cnt.out" 43 | } 44 | 45 | # Cleanups a test 46 | cleanup_test() 47 | { 48 | [ "$DO_CLEANUP" = "yes" ] && rm -f $OUT_F $TMP_F &> /dev/null 49 | } 50 | 51 | # Initializes the whole testing environment 52 | # Should be the first test called 53 | init_world() 54 | { 55 | [ -d $MAIN_TEST_DIR ] && rm -rf $MAIN_TEST_DIR 56 | mkdir -p $MAIN_TEST_DIR 57 | } 58 | 59 | # Cleanups the whole testing environment 60 | # Should be the last test called 61 | cleanup_world() 62 | { 63 | [ "$DO_CLEANUP" = "yes" ] && rm -rf $MAIN_TEST_DIR 64 | } 65 | 66 | # ---------------------------------------------------------------------------- # 67 | 68 | # ----------------- Test Suite ----------------------------------------------- # 69 | 70 | get_recorded_faults() 71 | { 72 | if [ -f "$FAULT_CNT_F" ]; then 73 | echo $(($(cat "$FAULT_CNT_F"))) 74 | else 75 | echo 0 76 | fi 77 | } 78 | 79 | 80 | # Tests if a program exits with success 81 | test_success() 82 | { 83 | init_test 84 | 85 | bin="$1" 86 | num_faults=$2 87 | 88 | LD_LIBRARY_PATH=. "$loader_main" "$bin" "$FAULT_CNT_F" &> $OUT_F 89 | RUN_RC=$? 90 | 91 | recorded_faults=$(get_recorded_faults) 92 | 93 | basic_test test $RUN_RC -eq 0 -a $num_faults -eq $recorded_faults 94 | 95 | if [ $RUN_RC -ne 0 ]; then 96 | echo "Incorrect exit code: got $RUN_RC, expected 0" 97 | fi 98 | 99 | if [ $recorded_faults -ne $num_faults ]; then 100 | echo "Incorrect number of faults: got $recorded_faults, expected $num_faults" 101 | fi 102 | 103 | cleanup_test 104 | } 105 | 106 | # Tests if a program crashes with SIGSEGV 107 | test_segv() 108 | { 109 | init_test 110 | 111 | bin="$1" 112 | num_faults=$2 113 | 114 | # use { } to supress the "Segmentation fault" message 115 | { LD_LIBRARY_PATH=. "$loader_main" "$bin" "$FAULT_CNT_F" &> $OUT_F; } 2> /dev/null 116 | RUN_RC=$? 117 | 118 | recorded_faults=$(get_recorded_faults) 119 | 120 | basic_test test $RUN_RC -eq 139 -a $num_faults -eq $recorded_faults 121 | 122 | if [ $RUN_RC -ne 139 ]; then 123 | echo "Incorrect exit code: got $RUN_RC, expected 139" 124 | fi 125 | 126 | if [ $recorded_faults -ne $num_faults ]; then 127 | echo "Incorrect number of faults: got $recorded_faults, expected $num_faults" 128 | fi 129 | 130 | cleanup_test 131 | } 132 | 133 | test_ref() 134 | { 135 | init_test 136 | 137 | bin="$1" 138 | num_faults=$2 139 | op=$3 140 | [ -z "$op" ] && op="-eq" 141 | 142 | LD_LIBRARY_PATH=. "$loader_main" "$bin" "$FAULT_CNT_F" &> $OUT_F 143 | RUN_RC=$? 144 | 145 | recorded_faults=$(get_recorded_faults) 146 | 147 | compare $OUT_F $REF_F > $TMP_F 148 | DIFF_RC=$? 149 | 150 | basic_test test $DIFF_RC -eq 0 -a $RUN_RC -eq 0 -a $recorded_faults $op $num_faults 151 | [ -s "$TMP_F" ] && cat "$TMP_F" 152 | 153 | if [ $RUN_RC -ne 0 ]; then 154 | echo "Incorrect exit code: got $RUN_RC, expected 0" 155 | fi 156 | 157 | if [ ! $recorded_faults $op $num_faults ]; then 158 | if [ "$op" = "-gt" ]; then 159 | op_str=">" 160 | fi 161 | echo "Incorrect number of faults: got $recorded_faults, expected $op_str $num_faults" 162 | fi 163 | 164 | cleanup_test 165 | } 166 | 167 | test_exec() 168 | { 169 | test_success "_test/inputs/check_exec" 1 170 | } 171 | 172 | test_hello() 173 | { 174 | test_ref "_test/inputs/hello" 2 175 | } 176 | 177 | test_sum() 178 | { 179 | test_ref "_test/inputs/sum" 3 180 | } 181 | 182 | test_bss() 183 | { 184 | test_ref "_test/inputs/bss" 2 185 | } 186 | 187 | test_data_bss() 188 | { 189 | test_ref "_test/inputs/data_bss" 3 190 | } 191 | 192 | test_no_perm() 193 | { 194 | test_segv "_test/inputs/no_perm" 2 195 | } 196 | 197 | test_inv_perm() 198 | { 199 | test_segv "_test/inputs/inv_perm" 1 200 | } 201 | 202 | test_perms() 203 | { 204 | test_ref "_test/inputs/check_perm" 2 205 | } 206 | 207 | test_qsort() 208 | { 209 | test_ref "_test/inputs/qsort" 50 "-gt" 210 | } 211 | 212 | # ---------------------------------------------------------------------------- # 213 | 214 | # ----------------- Run test ------------------------------------------------- # 215 | 216 | test_fun_array=( \ 217 | test_coding_style "Sources check" 5 \ 218 | test_exec "Test simple execution" 5 \ 219 | test_hello "Test hello" 10 \ 220 | test_sum "Test sum" 10 \ 221 | test_bss "Test bss" 10 \ 222 | test_data_bss "Test data and bss" 10 \ 223 | test_no_perm "Test no permissions" 10 \ 224 | test_inv_perm "Test invalid permissions" 10 \ 225 | test_perms "Test permissions" 10 \ 226 | test_qsort "Test complex program" 15 \ 227 | ) 228 | 229 | # ---------------------------------------------------------------------------- # 230 | 231 | # ----------------- Run test ------------------------------------------------- # 232 | 233 | # first we check if we have everything defined 234 | check_tests 235 | 236 | # run tests 237 | run_tests $@ 238 | 239 | exit 0 240 | -------------------------------------------------------------------------------- /test/_test/inputs/sum.c: -------------------------------------------------------------------------------- 1 | int __attribute__((aligned(4096))) arr[2048] = { 0x11223344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x55667788, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 2 | 3 | void exit(int code); 4 | int write(int fd, char *buf, int len); 5 | int itoa(int n, char *buf); 6 | 7 | void _start() 8 | { 9 | int i; 10 | int sum = 0; 11 | char buf[128]; 12 | int len; 13 | 14 | for (i = 0; i < sizeof(buf); i++) 15 | buf[i] = 0; 16 | 17 | for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) 18 | sum += arr[i]; 19 | 20 | len = itoa(sum, buf); 21 | 22 | buf[len++] = '\n'; 23 | 24 | write(1, buf, len); 25 | 26 | exit(0); 27 | } 28 | -------------------------------------------------------------------------------- /test/_test/inputs/qsort.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int arr[] = { 1187898861, 1709463188, -102719713, 1917143680, -302005966, 1813565133, 1100086806, -1426930656, -880188594, -640487181, -1333854366, -1837940600, -1446206856, -1960819430, -769966052, -1066604514, -262220002, 71782855, 137816478, -670226473, 99933832, 2082310340, -1563311558, -1469852006, 1341327948, -863696992, 1472994747, 298142638, -1235385788, -631017202, 349763559, -2071552039, -869544450, 477566651, -350607110, -1041162370, 295799742, -2058479100, -2032926875, 1180086940, 714405362, -1192515517, -312663645, 296952844, 962505109, -1865472020, -1761795818, 1687924098, -316313595, 476922355, -111010879, 1984975485, -1572139315, -175697641, -1818396412, 1515480812, 1865754341, 1860467084, -583605730, 1207468419, -1857942890, 745574485, 109891635, -743154179, -1452233022, 1696506137, 705776988, -1616354481, 765490156, 506818484, 1060532719, 419966440, -1852404312, -1218428945, 176096363, -879878014, 1370578469, 951046643, 279259783, 2016268677, 1189029268, 1056839376, -655568893, 958267583, 835562392, 1606023994, 2011488101, 1193023929, -924053621, -2051500001, 631754003, 1146080090, 1792998347, 1134352055, -1552701798, 2033267000, -1367489217, -795178222, -1765993719, -180595129, -429528557, 2018657458, -2135207923, 1197075388, -1071471587, 385811074, 365347114, -1160255856, 1677857389, 431710302, -505322933, 1542139561, 1697300523, 1545035390, 1736520544, 1732113252, 1383888761, 1387649541, -936732693, -1438426346, -1988680525, 2042796050, 1694955364, -42608081, -427792176, 553670299, -539515040, -961504777, -475708243, 128307812, -907529649, -2119029873, 713700466, 919649901, 1344209939, 769927959, -1668292527, 1616674511, -622670101, -1264958162, 1179446370, 519950446, -900189513, 932602357, 1450802947, -2081147969, -1040306289, -776429969, 1683888396, -479911459, -1119638527, -280750690, -1074600885, -1201263781, -566772998, -1874947241, -799788824, -1947372301, -873013901, -1032867554, -1691407724, 1596801433, -1383680186, -705347343, -1092472711, -1080767766, 1111236826, -1727716605, 1817968304, -1312197307, -1407295837, 1460944959, -706503645, 1644264729, 94571746, 1997708438, 179057563, 274340735, -1301247660, -1216086099, 600447310, 180796055, 100652592, -1870667475, 1740688338, -1937064797, 1483595292, -1860213117, -1184014673, -1333101609, 153142897, 1422504666, 1867385513, -1662691797, -627233956, 1785793515, 492560196, 1607423982, 703143259, 1338709104, 254566477, -1761126495, 1566200262, 1027523354, 1522678065, 948823819, 609941232, 1000115437, -1436196806, -215565624, 1176505937, -923200352, 56167786, 679747902, -555660440, 1117601102, -483577332, 1648517202, 1047544017, 1591551084, 1834441160, 1079601666, -1420578680, -495545969, -1970637324, -1449868690, 868057486, 1544828495, 342026689, 2031894125, 83765028, 884594475, -903760054, -650897674, -1334931889, -250446341, -1658989517, -956005967, -341332403, -1204205837, -1061516120, 87721598, 1621746983, 1236531323, -1693278358, 923561674, 1778341314, -236879452, 1690989759, 1331101137, -712303520, 975007560, -1523714975, 1126720584, 380615531, 924529644, 599755599, 1747330254, -682875860, 1512983532, 877159372, 2119491015, 1895545712, 586402851, -2135055972, 891587785, -399796165, -99080548, -986083197, -412890463, -2011067896, 2036610972, -482104627, -142726089, 421202037, -1764760396, 1048879908, -1743486405, -534254927, 1013103794, -893608164, -1845019701, 2076511288, -1517624188, -1016775239, -389794285, -1114844372, 1578332798, 517675157, 596220387, -456277818, -793602202, -969413964, -1601143819, -891750102, -903019749, -20170908, 1852440826, -978844676, -331615038, 538231941, 1316834854, 1790840650, -764356300, 632998309, -2146479927, -1403727373, -1378856692, 406064449, 75573571, 422414120, -779492973, -156510016, 1197606542, -623452649, -1375787505, 1756941309, -1255191727, 1220920463, -218554965, 1592252580, 1500770982, 11807279, 1452573002, -1002924362, 892478975, -1293999141, 1560482841, -1954915243, 1401913734, -1089628872, 196172729, 1464526670, -1527803590, -1813664204, 831612448, -28357372, 1534287680, -1928713835, -1413343717, 233005155, -448037005, 56543991, -1592935401, -2047628911, -1840557363, -641355769, -1830886572, -531966698, 1112328673, 1948323956, 562666254, 902649358, -1629125529, 267485420, 1627982110, 336915681, -994462053, 1268179643, 1597863499, 1149679610, 413370316, -1308400988, 34222155, 1101348566, -1300774511, -463136474, 1300699935, 1348812080, -361557037, 60956277, -1027135168, -694878118, 1653768231, -340832707, 1841631657, -14001672, -1856553710, 921732050, -784255326, -758093047, 1508903791, -1652278594, 453057689, -224524961, -105641440, 978923004, -2146711870, 2116049981, -1069723782, -1850091357, 784947218, 1084759970, 1934606930, -99842318, 122141799, 676762074, -585140855, 535603546, 951101198, 808481126, 1266716144, 1190166690, 1207038283, 1541139273, 219147129, 1772593226, -414241408, 647345058, -316609196, -2101493825, -2024797320, 2130719511, 1815311932, -1992290316, 871694741, 931279081, -1429823162, 594434305, -92073224, -755226123, 187093346, 294623995, 1025966303, -11561723, 12365493, 309261379, -998612046, -2002776246, 1642719007, 550326167, -584418186, -1288845761, 288984454, -1259177186, 442594544, 1244774217, -1858166859, -1211073170, 877331902, 567192575, -338990545, 232283604, -295395386, 1564155126, -847110194, -70277498, 306664189, -10248222, -2019247807, -641133431, -802836327, -515704585, 1393601668, 1978730188, -1749538481, -650792334, -1981396432, 864896860, -228879894, -921382013, 690743633, -716762151, 1898599051, -983005458, 678569698, -293151940, 1973334436, 1281175398, 1975732058, 1147095427, -404284087, 1610941981, -317940386, -1799712188, 2129008532, -230850162, -612630970, 1744758559, -517261475, 575463515, -1369473005, 499798089, -87262410, -305336621, 1393392850, 1731651984, -1810125803, -356946206, -1115592635, -248273451, 1760549511, -501895394, 1737485684, 205892124, -844476241, -2027390495, -1347783646, 347360322, -1688319048, 2103080745, 350281692, -1189559205, -892060270, -1534985002, -1297778924, -2123708060, 1417964125, -1015385239, -222776912, 1302163939, -2108107965, -1643060162, 1480106784, -2050748609, -1330068279, -1063449499, 1955239193, 799106271, 1643903875, -165434223, -1096812230, 1425594014, 1741711147, -548036468, -1199213194, 1003697376, -1120562622, 2107789074, -1464266060, -1602126444, 782776946, -525319077, 890185740, -273617691, -938020997, 1821714209, 1187938480, 275839461, -1282787490, -1358646373, 1009835530, 533507366, -1264579379, -1936681661, 1303927510, -1553576747, -615838328, -286893190, 340491309, -937516043, 736253182, -434450403, -1421381607, -1256893184, -592302996, 533064717, 111328275, -804048455, -1361424387, -939559119, 855236196, -575064327, 1481949359, 825808425, -2146665020, 761905753, -1310903274, -686766657, 405323982, -2046127370, 93980725, -73078669, 1254464731, -1560983694, 1821453868, 461731011, -16355300, 939067269, -378630567, -1882304437, -1647133859, -1351104262, -139972533, -1148429507, 1901873494, -1244505339, -1726452573, 913150438, 1371002130, -1650082832, -1900837146, -864070895, 1612555078, 443049956, -180336570, -1806839146, 374549175, 1875138352, 1730158007, 1391790179, -691508365, -1348795693, -288380234, 392660310, 1178634858, 193558784, 781870685, 1392587944, -905095935, 1031707820, -1291043382, -897567215, -786268269, 1553647688, -770761105, 201583744, 2021245679, -345103559, 1959865513, 1049429427, 790151036, 306700893, 286160621, -295099976, -1384366589, -604500386, -1149122271, -1048556488, 694804477, 560494797, -1928859170, -1108558030, 856458611, -1786237949, -2037883401, -124132971, -954793372, -1170881135, 1201232704, -413125807, -1135258415, 1826239900, 411881155, 1488000037, 1718526768, -425497344, -713672299, 1869444848, -370024239, 706833728, -543810823, 1199004959, 1237290235, 1393936033, 1392474681, 949553707, 167456185, 1119505002, -376024776, -81281286, -1526491346, -1223516031, -1487582028, 1864713980, -119142936, -2104707878, 1376025527, 99124230, -228266979, 20777531, 2111709558, 200410934, -1271694359, -1745996447, 1271884907, 1804610261, 612911933, -1921352398, 40908312, 474908869, -506321963, -1639133754, 1068088460, -943054623, 1931513545, -1437374023, 724242698, -1290623839, -321202155, -2048839041, 1338413491, 512482379, -1289440332, 1861199858, -1643750733, -2140980372, 1778777969, 1519596802, 633021840, -1579559091, -1553419580, 1740551174, 276783552, -441700422, 947170608, 176830168, -1527474311, 982424605, 1982699999, -304389288, -1321617170, 2010180523, -697149365, -583846100, 1672165116, -170778469, -1464744766, -798843064, 331463747, -1917988566, 1419650655, -1707750368, -648052915, -1093962655, 108749813, -396624001, -2073360843, 990162762, -576240787, 570993873, -74796990, -1250524253, 822256474, 1354544811, -1532001525, -1833584415, -1910261646, -923468146, -1409506238, 1484804189, -637379320, 1031932167, 387999496, 1452656336, 247593332, 2005968985, -784878246, 1534317400, 135279858, -1231475245, -1816369876, -2145921544, -368461678, 566036103, -1300045571, -418800869, -1234334184, 2138576991, 1119537606, 973886720, -241288551, 1355706221, -1296240853, 1436995223, -1375131606, -1579184415, 1654603889, 1937457024, 211660247, 932922275, 2046457972, -1364400433, 1048911414, 1193863858, 1764253915, 1012571079, 2056125695, 770544988, 15595527, 1179164252, 946171105, 113421550, -885191245, 636470428, 913152605, -1296921851, -1918121551, -529100769, -555148353, 326711022, -2011900344, -579029113, -2116493195, 1883114479, -257808021, -853986685, 1529489320, 153154299, 145339425, 473924135, -1923171737, -1389585464, 531479944, 1625562097, -240378233, 1752504068, -213091432, -990597053, 1294167550, 473899683, 634733009, 886504536, 810861798, -1470040619, 383142204, 717531967, 2004738025, 363332221, -69684608, -885428152, 2100874225, 587277990, -855616737, -1561720221, 277254808, 628519170, 2079422440, 1331243294, -807782850, -757326849, -1255082091, 29732793, -424129867, 2015825456, 513563850, 637460430, -488810046, 1600816497, -296634427, 680540543, -660537711, 1581588647, 215775290, -748802216, 1180576346, 56202293, 864647475, -1953302839, 270063932, -1322209986, -949871032, -684693841, -1473332524, 1338993885, 263522063, -1372754593, -2126265538, 1750007851, 1259899860, -443776221, 1866573579, 647233377, 1129210540, -987572048, -1278604913, -504670155, 2005687347, 886451853, 1699431034, -551655106, -1476158137, -1346862833, -82454241, -998845366, 1585038275, 23838581, -1318238887, -617457374, -1740716099, 98260341, 1087068101, -1993388397, 1977767650, 1750811349, -833185368, 871086812, 900007557, -1391187664, -885563201, 1429168535, -2039396294, 243483148, 2074456162, 1930782505, -941546900, 1316772845, 1750239868, 1175263386, -1191591328, 1132329257, -2084506879, 293235777, -1951943541, 2110639212, -892893072, -871169469, 1160031754, -403569445, 1431192519, -1996484653, -1017849880, -1322709643, -2109945272, -255617559, -1435629499, 826056224, -1557762633, -1626320610, 2113370986, -420026277, 1201390595, -548246879, 1893616575, 1574701016, -1739970053, 1525976626, 1223971413, 1653893850, -749219020, -139734171, 1667306292, 321799218, -1108048078, -2012422015, 53744806, -1955165557, -251446673, -186138580, 1294186620, -771835106, -88454637, 128553067, 1919946295, -1538721066, 1099127462, 647556013, -579111848, 1099518480, -961060423, -73474696, -177787708, 213113508, -1919241121, -733424766, 1252282961, 598170371, 1351824345, 1105489730, -1962717310, -1097097999, 1783856417, -35010996, 713453034, -743314580, 1818120712, 230268217, -237767067, 371437554, 2144133972, 1284389286, -574748233, -1627749696, 1551933327, 485934128, -584336725, 2109192594, 596656127, -1900766816, 732355869, -48758713, -1862348965, 2143872137, 1435097769, -1344836815, 1739740008, -1946404071, 1883169107, -1638196162, 1944659783, 831357515, 1989092554, -1773955468, 515640391, -1008563874, -2127264855, 1988769763, -824218472, 359596080, -258344665, 338548583, -455313, -694767915, 1089051731, 2113072413, 684683273, -1282384741, 911781487, -2138981519, 1340787399, 1435704064, -1062733612, 1556372582, 1285700862, -896748269, 1276994458, -2122471826, 1449368449, 2050842030, 15831398, -27406538, 1989649691, 690713135, 330100493 }; 6 | 7 | int cmp_func(const void *lhs, const void *rhs) 8 | { 9 | int *__lhs = (int *)lhs; 10 | int *__rhs = (int *)rhs; 11 | 12 | if (*__lhs == *__rhs) 13 | return 0; 14 | else if (*__lhs < *__rhs) 15 | return -1; 16 | else 17 | return 1; 18 | } 19 | 20 | int main() 21 | { 22 | int *a; 23 | int n; 24 | int i; 25 | int sum; 26 | 27 | n = sizeof(arr) / sizeof(int); 28 | 29 | a = malloc(n * sizeof(int)); 30 | memcpy(a, arr, n * sizeof(int)); 31 | 32 | qsort(a, n, sizeof(int), cmp_func); 33 | 34 | for (i = 0; i < n; i += 128) 35 | sum = a[i]; 36 | free(a); 37 | 38 | printf("%#x\n", sum); 39 | 40 | return 0; 41 | } 42 | --------------------------------------------------------------------------------