├── README.md ├── build ├── commands.txt └── run.sh ├── doc ├── ELF for the ARM Architecture.pdf └── ELF_Format.pdf ├── src ├── elfs.h ├── main.c ├── main.h └── runner.s ├── testbin ├── test1.o ├── test2.o └── test3.o └── testsrc ├── test1.s ├── test2.s └── test3.c /README.md: -------------------------------------------------------------------------------- 1 | # linker-and-loader 2 | Linker and loader for elf relocatable files. Developed in C for ARM architecture. 3 | 4 | This was a project for the course ”System Programming” on my faculty. 5 | 6 | 7 | Department of Computer Engineering and Information Theory. 8 | 9 | 10 | School of Electrical Engineering, University of Belgrade, Serbia. 11 | 12 | 13 | Developed by Marin Markić. No licence. April - June 2013. 14 | 15 | ### How to use: (see tests) 16 | 17 | - Application works with binary relocatable files in elf format, called program. Application links program with other libraries, performs necessary relocations, loads it to operating memory and executes program code from entry point. Programs are acccepted as ARM assembly or C programs. In case of C program additionally external functions printf and scanf are supported. 18 | - Use QEMU, machine emulator and virtualizer for ARM architecture on linux. Start application by executing run.sh in bash. 19 | 20 | ### Create binaries: 21 | ```asm 22 | arm-linux-gnueabi-as test1.s -o test1.o // creates elf from ARM assembly file 23 | arm-linux-gnueabi-gcc -r -c -nostdlib -marm test3.c -o test3.o // creates elf from C file 24 | ``` 25 | 26 | Pass created .o files to application to execute program with linking and loading. 27 | -------------------------------------------------------------------------------- /build/commands.txt: -------------------------------------------------------------------------------- 1 | arm-linux-gnueabi-as test1.s -o test1.o 2 | arm-linux-gnueabi-as test2.s -o test2.o 3 | arm-linux-gnueabi-gcc -r -c -nostdlib -marm test3.c -o test3.o 4 | -------------------------------------------------------------------------------- /build/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export QEMU_LD_PREFIX=/usr/arm-linux-gnueabi 4 | arm-linux-gnueabi-gcc -marm runner.s main.c -o main 5 | ./main 6 | 7 | read -p "Press any key to continue... " -n1 -s 8 | -------------------------------------------------------------------------------- /doc/ELF for the ARM Architecture.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markic/linker-and-loader/0aa9a5557247dec7faa8b1630eb2cb557bb876f2/doc/ELF for the ARM Architecture.pdf -------------------------------------------------------------------------------- /doc/ELF_Format.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markic/linker-and-loader/0aa9a5557247dec7faa8b1630eb2cb557bb876f2/doc/ELF_Format.pdf -------------------------------------------------------------------------------- /src/elfs.h: -------------------------------------------------------------------------------- 1 | // elfs.h - Course: System Programming 2 | // author: Marin Markic 3 | #ifndef _ELF_H 4 | #define _ELF_H 5 | 6 | /* TYPE DEFINITIONS */ 7 | 8 | typedef unsigned short uint16_t; 9 | typedef unsigned long uint32_t; 10 | 11 | /* Standard ELF types. */ 12 | 13 | typedef uint16_t Elf32_Half; /* Type for a 16-bit quantity. */ 14 | typedef uint32_t Elf32_Word; /* Types for signed and unsigned 32-bit quantities. */ 15 | typedef uint32_t Elf32_Addr; /* Type of addresses. */ 16 | typedef uint32_t Elf32_Off; /* Type of file offsets. */ 17 | typedef uint16_t Elf32_Section; /* Type for section indices, which are 16-bit quantities. */ 18 | 19 | /* The ELF file header. This appears at the start of every ELF file. */ 20 | 21 | #define EI_NIDENT (16) 22 | 23 | struct Elf32_Ehdr 24 | { 25 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ 26 | Elf32_Half e_type; /* Object file type */ 27 | Elf32_Half e_machine; /* Architecture */ 28 | Elf32_Word e_version; /* Object file version */ 29 | Elf32_Addr e_entry; /* Entry point virtual address */ 30 | Elf32_Off e_phoff; /* Program header table file offset */ 31 | Elf32_Off e_shoff; /* Section header table file offset */ 32 | Elf32_Word e_flags; /* Processor-specific flags */ 33 | Elf32_Half e_ehsize; /* ELF header size in bytes */ 34 | Elf32_Half e_phentsize; /* Program header table entry size */ 35 | Elf32_Half e_phnum; /* Program header table entry count */ 36 | Elf32_Half e_shentsize; /* Section header table entry size */ 37 | Elf32_Half e_shnum; /* Section header table entry count */ 38 | Elf32_Half e_shstrndx; /* Section header string table index */ 39 | }; 40 | 41 | /* Section header. */ 42 | 43 | struct Elf32_Shdr 44 | { 45 | Elf32_Word sh_name; /* Section name (string tbl index) */ 46 | Elf32_Word sh_type; /* Section type */ 47 | Elf32_Word sh_flags; /* Section flags */ 48 | Elf32_Addr sh_addr; /* Section virtual addr at execution */ 49 | Elf32_Off sh_offset; /* Section file offset */ 50 | Elf32_Word sh_size; /* Section size in bytes */ 51 | Elf32_Word sh_link; /* Link to another section */ 52 | Elf32_Word sh_info; /* Additional section information */ 53 | Elf32_Word sh_addralign; /* Section alignment */ 54 | Elf32_Word sh_entsize; /* Entry size if section holds table */ 55 | }; 56 | 57 | /* Legal values for sh_type (section type). */ 58 | 59 | #define SHT_NULL 0 /* Section header table entry unused */ 60 | #define SHT_PROGBITS 1 /* Program data */ 61 | #define SHT_SYMTAB 2 /* Symbol table */ 62 | #define SHT_STRTAB 3 /* String table */ 63 | #define SHT_RELA 4 /* Relocation entries with addends */ 64 | #define SHT_HASH 5 /* Symbol hash table */ 65 | #define SHT_DYNAMIC 6 /* Dynamic linking information */ 66 | #define SHT_NOTE 7 /* Notes */ 67 | #define SHT_NOBITS 8 /* Program space with no data (bss) */ 68 | #define SHT_REL 9 /* Relocation entries, no addends */ 69 | 70 | /* Legal values for sh_flags (section flags). */ 71 | 72 | #define SHF_WRITE (1 << 0) /* Writable */ 73 | #define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ 74 | #define SHF_EXECINSTR (1 << 2) /* Executable */ 75 | 76 | /* Symbol table entry. */ 77 | 78 | struct Elf32_Sym 79 | { 80 | Elf32_Word st_name; /* Symbol name (string tbl index) */ 81 | Elf32_Addr st_value; /* Symbol value */ 82 | Elf32_Word st_size; /* Symbol size */ 83 | unsigned char st_info; /* Symbol type and binding */ 84 | unsigned char st_other; /* Symbol visibility */ 85 | Elf32_Section st_shndx; /* Section index */ 86 | }; 87 | 88 | /* Special section indices. */ 89 | 90 | #define SHN_UNDEF 0 /* Undefined section */ 91 | #define SHN_ABS 0xfff1 /* Associated symbol is absolute */ 92 | #define SHN_COMMON 0xfff2 /* Associated symbol is common */ 93 | 94 | /* Relocation table entry without addend (in section of type SHT_REL). */ 95 | 96 | struct Elf32_Rel 97 | { 98 | Elf32_Addr r_offset; /* Address */ 99 | Elf32_Word r_info; /* Relocation type and symbol index */ 100 | Elf32_Word sh_link; /* The section header index of the associated symbol table */ 101 | Elf32_Word sh_info; /* The section header index of the section to which the relocation applies */ 102 | }; 103 | 104 | /* How to extract and insert information held in the r_info field. */ 105 | 106 | #define ELF32_R_SYM(val) ((val) >> 8) 107 | #define ELF32_R_TYPE(val) ((val) & 0xff) 108 | #define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) 109 | 110 | /* ARM relocs. */ 111 | 112 | #define R_ARM_NONE 0 /* No reloc */ 113 | #define R_ARM_PC24 1 /* PC relative 26 bit branch */ 114 | #define R_ARM_ABS32 2 /* Direct 32 bit */ 115 | #define R_ARM_REL32 3 /* PC relative 32 bit */ 116 | #define R_ARM_PC13 4 117 | #define R_ARM_ABS16 5 /* Direct 16 bit */ 118 | #define R_ARM_ABS12 6 /* Direct 12 bit */ 119 | #define R_ARM_THM_ABS5 7 120 | #define R_ARM_ABS8 8 /* Direct 8 bit */ 121 | 122 | #define R_ARM_CALL 0x1c 123 | #define R_ARM_JUMP24 0x1d 124 | #define R_ARM_MOVW_ABS_NC 0x2b 125 | #define R_ARM_MOVT_ABS 0x2c 126 | 127 | 128 | #endif /* elfs.h */ 129 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | // main.c - Course: System Programming 2 | // author: Marin Markic 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "elfs.h" 9 | #include "main.h" 10 | 11 | extern void run(int argc, char **arvg); 12 | 13 | // global variables 14 | void *runAddr; 15 | void *stack; 16 | int argc; 17 | char **argv; 18 | 19 | void initErrStruct(){ 20 | err.cannotOpen = "Error: File %s cannot be opened!\n\n\n"; 21 | err.cannotAlloc = "Error: Memory allocation failure!\n\n\n"; 22 | err.cannotRead = "Error: Cannot read file!\n\n\n"; 23 | err.notElfFile = "Error: Input file is not in ELF format!\n\n\n"; 24 | err.mapFailed = "Error: Cannot memory map ELF section!\n\n\n"; 25 | err.munFailed = "Error: Cannot unmap memory section!\n\n\n"; 26 | } 27 | 28 | // returns string from ID until NULL from String Table Section 29 | char *getSectionNameFromTable(uint16_t id){ 30 | char *res = (char*) malloc(10); 31 | int cnt = 0; 32 | 33 | while(1){ 34 | res[cnt] = file.buffer[file.sectionStrTabOff + id++]; 35 | if(res[cnt++] == '\0') return res; 36 | } 37 | } 38 | 39 | // returns string from ID until NULL from String Table Section 40 | char *getSymbolNameFromTable(uint16_t id){ 41 | char *res = (char*) malloc(50); 42 | int cnt = 0; 43 | 44 | while(1){ 45 | res[cnt] = file.buffer[file.symbolStrTabOff + id++]; 46 | if(res[cnt++] == '\0') return res; 47 | } 48 | } 49 | 50 | // parse input 51 | int load() 52 | { 53 | argc = 0; 54 | argv = 0; 55 | 56 | // load all until end of line 57 | char *s = malloc(100); 58 | argv = (char **) malloc (20 * sizeof(char *)); 59 | 60 | printf ("Enter name of elf file and parameters or exit.\n"); 61 | scanf(" %[^\n]", s); 62 | 63 | argv[argc] = strtok(s, " "); 64 | 65 | argv[argc] = s; 66 | file.name = s; 67 | if ( !strcmp(argv[argc],"exit") ) return 0; 68 | 69 | do{ argv[++argc] = strtok (NULL, " "); } while (argv[argc] != NULL); 70 | 71 | return 1; 72 | } 73 | 74 | int main() 75 | { 76 | initErrStruct(); 77 | 78 | while(1) 79 | { 80 | // variables 81 | unsigned int cnt = 0; 82 | unsigned long shoff = 0; 83 | struct Elf32_Ehdr elfHeader; 84 | struct Elf32_Shdr *elfSectionHeaders = 0; 85 | struct Elf32_Sym *elfSymbolTable = 0; 86 | struct Elf32_Rel *elfRelTable = 0; 87 | 88 | if ( !load() ) break; // parse input 89 | 90 | // open object file 91 | file.ptr = fopen (file.name,"rb"); 92 | if (file.ptr == NULL) { fprintf (stderr,err.cannotOpen,file.name); continue; } 93 | 94 | // obtain file size 95 | fseek (file.ptr , 0 , SEEK_END); 96 | file.size = ftell (file.ptr); 97 | rewind (file.ptr); 98 | 99 | // allocate memory to contain the whole file 100 | file.buffer = (char*) malloc (sizeof(char) * file.size); 101 | if (file.buffer == NULL) error(err.cannotAlloc) 102 | 103 | // copy the file into the buffer: 104 | cnt = fread (file.buffer, 1, file.size, file.ptr); 105 | if (cnt != file.size) error(err.cannotRead) 106 | 107 | fclose (file.ptr); 108 | 109 | // check if file is in ELF 110 | if (file.buffer[0] != 127 || file.buffer[1] != 'E' || file.buffer[2] != 'L' || file.buffer[3] != 'F') 111 | error(err.notElfFile) 112 | 113 | // load Elf header from OM buffer 114 | memcpy (&elfHeader, &file.buffer[0], sizeof (struct Elf32_Ehdr)); 115 | shoff = elfHeader.e_shoff; // section headers offset 116 | file.sectionStrTabOff = 0; 117 | 118 | // alloc array of section header entries 119 | elfSectionHeaders = (struct Elf32_Shdr*) malloc ((elfHeader.e_shnum) * sizeof (struct Elf32_Shdr)); 120 | if (elfSectionHeaders == NULL) error(err.cannotAlloc) 121 | 122 | // load section header entries, load symbol table and relocs, map sections 123 | for (cnt = 0; cnt < elfHeader.e_shnum; cnt++) 124 | { 125 | // load Elf Section Header Table Entry from OM buffer 126 | memcpy (&elfSectionHeaders[cnt], &file.buffer[shoff], sizeof (struct Elf32_Shdr)); 127 | shoff += elfHeader.e_shentsize; 128 | 129 | unsigned long offset = elfSectionHeaders[cnt].sh_offset; 130 | if(offset == SHT_NOBITS) continue; 131 | 132 | size_t size = elfSectionHeaders[cnt].sh_size; 133 | if(size == 0) continue; 134 | 135 | // Alloc and Exec sections - example .TEXT 136 | if (elfSectionHeaders[cnt].sh_flags == (SHF_ALLOC | SHF_EXECINSTR)) 137 | { 138 | void *addr = mmap (NULL, size + 16, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1 ,0); 139 | if (addr == MAP_FAILED) error(err.mapFailed) 140 | 141 | memcpy (addr, file.buffer + offset, size); //dst, src, size 142 | elfSectionHeaders[cnt].sh_addr = (uint32_t) addr; 143 | file.mainVA = addr; 144 | runAddr = addr; 145 | 146 | unsigned long printfAddr = (unsigned long) &printf; 147 | unsigned long scanfAddr = (unsigned long) &scanf; 148 | unsigned long instrHex = 0xE59FF000; // instruction - ldr pc, [pc] 149 | 150 | memcpy (addr + size, &instrHex, sizeof (unsigned long)); 151 | memcpy (addr + size + sizeof (unsigned long), &instrHex, sizeof (unsigned long)); 152 | memcpy (addr + size + 2 * sizeof (unsigned long), &printfAddr, sizeof (unsigned long)); 153 | memcpy (addr + size + 3 * sizeof (unsigned long), &scanfAddr, sizeof (unsigned long)); 154 | 155 | file.myPrintfAddr = addr + size; 156 | file.myScanfAddr = addr + size + sizeof(unsigned long); 157 | } 158 | 159 | // Alloc and Write sections - example .DATA 160 | if (elfSectionHeaders[cnt].sh_flags == (SHF_ALLOC | SHF_WRITE)) 161 | { 162 | void* addr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1 ,0); 163 | if (addr == MAP_FAILED) error(err.mapFailed) 164 | 165 | memcpy (addr, file.buffer + offset, size); //dst, src, size 166 | elfSectionHeaders[cnt].sh_addr = (uint32_t)addr; 167 | } 168 | 169 | // Alloc sections - read only - example .RODATA 170 | if (elfSectionHeaders[cnt].sh_flags == SHF_ALLOC) 171 | { 172 | void* addr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1 ,0); 173 | if (addr == MAP_FAILED) error(err.mapFailed) 174 | 175 | memcpy (addr, file.buffer + offset, size); //dst, src, size 176 | elfSectionHeaders[cnt].sh_addr = (uint32_t)addr; 177 | } 178 | 179 | // Relocation table 180 | if (elfSectionHeaders[cnt].sh_type == SHT_REL) 181 | { 182 | unsigned long i; 183 | file.numOfRelocs = size / elfSectionHeaders[cnt].sh_entsize; 184 | 185 | elfRelTable = (struct Elf32_Rel*) malloc ((file.numOfRelocs) * sizeof (struct Elf32_Rel)); 186 | if (elfRelTable == NULL) error(err.cannotAlloc) 187 | 188 | // load all reloc entries from OM buffer 189 | for (i = 0; i < file.numOfRelocs; i++){ 190 | memcpy (&elfRelTable[i], &file.buffer[offset], sizeof (struct Elf32_Rel)); 191 | elfRelTable[i].sh_link = elfSectionHeaders[cnt].sh_link; 192 | elfRelTable[i].sh_info = elfSectionHeaders[cnt].sh_info; 193 | offset += elfSectionHeaders[cnt].sh_entsize; 194 | } 195 | } 196 | 197 | // Symbol table 198 | if (elfSectionHeaders[cnt].sh_type == SHT_SYMTAB) 199 | { 200 | unsigned long i; 201 | file.numOfSymbols = size / elfSectionHeaders[cnt].sh_entsize; 202 | file.symTableOff = offset; 203 | 204 | elfSymbolTable = (struct Elf32_Sym*) malloc (file.numOfSymbols * sizeof (struct Elf32_Sym)); 205 | if (elfSymbolTable == NULL) error(err.cannotAlloc) 206 | 207 | // load all symbol table entries from OM buffer 208 | for (i = 0; i < file.numOfSymbols; i++){ 209 | memcpy (&elfSymbolTable[i], &file.buffer[offset], sizeof (struct Elf32_Sym)); 210 | offset += elfSectionHeaders[cnt].sh_entsize; 211 | } 212 | } 213 | 214 | // String tables 215 | if (elfSectionHeaders[cnt].sh_type == SHT_STRTAB ) 216 | { 217 | if (!file.sectionStrTabOff){ 218 | file.sectionStrTabOff = offset; 219 | continue; 220 | } 221 | 222 | file.symbolStrTabOff = offset; 223 | } 224 | } // end of for - all section headers loaded 225 | 226 | // relocations 227 | for (cnt = 0; cnt < file.numOfRelocs; cnt++) 228 | { 229 | char type = ELF32_R_TYPE (elfRelTable[cnt].r_info); 230 | unsigned long symId = ELF32_R_SYM (elfRelTable[cnt].r_info); // symbol table index 231 | unsigned long sectionId = elfSymbolTable[symId].st_shndx; // symbol is defined in this section 232 | 233 | // offset to symbol + VA of section in which symbol is used (example .TEXT) 234 | unsigned long usingAddr = elfRelTable[cnt].r_offset + elfSectionHeaders[ elfRelTable[cnt].sh_info ].sh_addr; 235 | 236 | if (type == R_ARM_ABS32) 237 | { 238 | unsigned long symValue = 0; // offset to symbol in its defined section (example .DATA) 239 | memcpy ( &symValue, (void*) usingAddr, sizeof (unsigned long)); // old value - just offset 240 | 241 | symValue += elfSectionHeaders[sectionId].sh_addr; // add VA of section - where symbol is defined (example .DATA) 242 | memcpy ( (void*) usingAddr, &symValue, sizeof (unsigned long)); // write offset + VA back 243 | continue; 244 | } 245 | 246 | if (type == R_ARM_MOVW_ABS_NC || type == R_ARM_MOVT_ABS) 247 | { 248 | unsigned long instruction = 0; 249 | memcpy (&instruction, (void*) usingAddr, sizeof (unsigned long)); 250 | instruction &= 0xFFF0F000; //clear bits 19-16 and 11-0 251 | 252 | unsigned long adr = elfSymbolTable[symId].st_value + elfSectionHeaders[sectionId].sh_addr; // VA 253 | 254 | if (type == R_ARM_MOVT_ABS) adr >>= 16; // "Up is down" CJS 255 | adr &= 0xFFFF; // 2B 256 | 257 | unsigned long up = (adr & 0xF000) << 4; // bits 19-16 258 | unsigned long down = adr & 0x0FFF; // bits 11-0 259 | 260 | instruction = instruction + up + down; 261 | memcpy ((void*) usingAddr, &instruction, sizeof (unsigned long)); 262 | continue; 263 | } 264 | 265 | 266 | char *symbolName = getSymbolNameFromTable (elfSymbolTable[symId].st_name); 267 | if (symbolName == 0x00){ free (symbolName); continue; } 268 | 269 | if( !strcmp (symbolName, "main") ) runAddr += elfSymbolTable[symId].st_value; 270 | 271 | if ( !strcmp (symbolName, "printf") ) 272 | { 273 | unsigned long temp = (unsigned long) file.myPrintfAddr - usingAddr - 8; 274 | temp = temp/4; 275 | memcpy ( (void*) usingAddr, &temp, 3); 276 | } 277 | 278 | if ( !strcmp (symbolName, "scanf") ) 279 | { 280 | unsigned long temp = (unsigned long) file.myScanfAddr - usingAddr - 8; 281 | temp = temp/4; 282 | memcpy ( (void*) usingAddr, &temp, 3); 283 | } 284 | 285 | free (symbolName); 286 | } 287 | 288 | // change protection for readonly sections 289 | for (cnt = 0; cnt < elfHeader.e_shnum; cnt++) 290 | if (elfSectionHeaders[cnt].sh_flags == SHF_ALLOC) 291 | mprotect ((void*) elfSectionHeaders[cnt].sh_addr, elfSectionHeaders[cnt].sh_size, PROT_READ); 292 | 293 | // create 1MB stack 294 | stack = malloc (STACK_SIZE); 295 | if (stack == 0) error(err.cannotAlloc) 296 | stack = stack + STACK_SIZE - 4; // last location 297 | 298 | // run program - jump to symbol main 299 | run (argc, argv); 300 | 301 | // remove sections from memory maped space 302 | for (cnt = 0; cnt < elfHeader.e_shnum; cnt++) 303 | if (elfSectionHeaders[cnt].sh_addr != 0) 304 | if (munmap ((void*) elfSectionHeaders[cnt].sh_addr, elfSectionHeaders[cnt].sh_size) == -1) error(err.munFailed) 305 | 306 | printf ("\n\n\nProgram is successfully executed.\n"); 307 | 308 | // free 309 | free (stack - STACK_SIZE + 4); 310 | free (argv[0]); 311 | free (argv); 312 | free (file.buffer); 313 | free (elfSectionHeaders); 314 | free (elfSymbolTable); 315 | free (elfRelTable); 316 | } // end of while 317 | 318 | return 0; 319 | } 320 | -------------------------------------------------------------------------------- /src/main.h: -------------------------------------------------------------------------------- 1 | // main.h - Course: System Programming 2 | // author: Marin Markic 3 | #ifndef _MAIN_H 4 | #define _MAIN_H 5 | 6 | // Macros 7 | #define error(x){\ 8 | fputs (x,stderr);\ 9 | fclose (file.ptr);\ 10 | free (file.buffer);\ 11 | continue;\ 12 | } 13 | 14 | #define STACK_SIZE 1024*1024 15 | 16 | // Data Structures 17 | 18 | struct FileDescriptor 19 | { 20 | char *name; 21 | FILE *ptr; 22 | unsigned long size; 23 | char *buffer; 24 | 25 | unsigned long numOfSymbols; 26 | unsigned long numOfRelocs; 27 | 28 | unsigned long symTableOff; 29 | unsigned long sectionStrTabOff; 30 | unsigned long symbolStrTabOff; 31 | 32 | void* myPrintfAddr; 33 | void* myScanfAddr; 34 | 35 | void *mainVA; 36 | 37 | }file; 38 | 39 | struct Errors 40 | { 41 | const char* cannotOpen; 42 | const char* cannotAlloc; 43 | const char* cannotRead; 44 | const char* notElfFile; 45 | const char* mapFailed; 46 | const char* munFailed; 47 | 48 | }err; 49 | 50 | 51 | #endif /* main.h */ 52 | -------------------------------------------------------------------------------- /src/runner.s: -------------------------------------------------------------------------------- 1 | @ file: runner.s - Course: System Programming 2 | @ author: Marin Markic 3 | .text 4 | .global run 5 | .extern runAddr 6 | .extern stack 7 | .func run 8 | run: 9 | push {r8, r9, lr} 10 | 11 | ldr r8, =oldsp 12 | str sp, [r8] @ save sp 13 | 14 | ldr r9, =stack 15 | ldr sp, [r9] 16 | 17 | ldr r9, =runAddr 18 | ldr r9, [r9] 19 | blx r9 @ jump to main 20 | 21 | ldr r8, =oldsp 22 | ldr sp, [r8] @ restore sp 23 | 24 | pop {r8, r9, pc} 25 | 26 | .endfunc 27 | .data 28 | oldsp:.long 0 29 | 30 | .end 31 | -------------------------------------------------------------------------------- /testbin/test1.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markic/linker-and-loader/0aa9a5557247dec7faa8b1630eb2cb557bb876f2/testbin/test1.o -------------------------------------------------------------------------------- /testbin/test2.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markic/linker-and-loader/0aa9a5557247dec7faa8b1630eb2cb557bb876f2/testbin/test2.o -------------------------------------------------------------------------------- /testbin/test3.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markic/linker-and-loader/0aa9a5557247dec7faa8b1630eb2cb557bb876f2/testbin/test3.o -------------------------------------------------------------------------------- /testsrc/test1.s: -------------------------------------------------------------------------------- 1 | @test1.s - writes number of arguments 2 | 3 | .section .text 4 | .global main 5 | .extern printf 6 | main: 7 | push {r0, r1, lr} 8 | mov r1, r0 @r1 = argc 9 | ldr r0, =format @r0 = format 10 | bl printf 11 | pop {r0, r1, pc} 12 | 13 | .section .data 14 | format: .asciz "Number of arguments is: %d\n" 15 | .end 16 | -------------------------------------------------------------------------------- /testsrc/test2.s: -------------------------------------------------------------------------------- 1 | @test2.s - square root 2 | 3 | .section .text 4 | .extern printf 5 | .extern scanf 6 | .global main 7 | main: 8 | push {r0, r1, r2, lr} 9 | 10 | @ input message 11 | ldr r0, =input 12 | bl printf 13 | 14 | @ citanje vrednosti 15 | ldr r0, =value 16 | ldr r1, =number 17 | bl scanf 18 | 19 | ldr r1, =number 20 | ldr r1, [r1] @ number is in r1 21 | mul r2, r1, r1 @ square root is in r2 22 | 23 | @result 24 | ldr r0, =output 25 | bl printf 26 | 27 | pop {r0, r1, r2, pc} 28 | 29 | .section .data 30 | input: .asciz "Enter integer:" 31 | value: .asciz "%d" 32 | number: .long 0 33 | output: .asciz "Square root of %d is %d." 34 | .end 35 | -------------------------------------------------------------------------------- /testsrc/test3.c: -------------------------------------------------------------------------------- 1 | //test3.c - sum of two numbers 2 | 3 | void main(){ 4 | int a, b, c; 5 | printf("Enter two integer numbers:"); 6 | scanf("%d%d", &a, &b); 7 | c =a + b; 8 | printf("Sum is: %d\n", c); 9 | 10 | } 11 | --------------------------------------------------------------------------------