void test_clist(void) { /* CU_ASSERT(NULL == ex_path_normalize(NULL)); */ int i = 0; int test_cnt = 10000; clist *list = clist_new(); CU_ASSERT(0 == clist_len(list)); for(i = 0; i < test_cnt; ++i) { clist_append(list, cobj_int_new(i)); } CU_ASSERT(test_cnt == clist_len(list)); CU_ASSERT(false == clist_is_empty(list)); CU_ASSERT(0 == cobj_int_val(clist_at_obj(list, 0))); CU_ASSERT(1 == cobj_int_val(clist_at_obj(list, 1))); CU_ASSERT(test_cnt - 1 == cobj_int_val(clist_at_obj(list, test_cnt - 1))); for(i = 0; i < test_cnt; ++i) { void *obj = clist_pop_front(list); CU_ASSERT(i == cobj_int_val(obj)); cobj_free(obj); } CU_ASSERT(0 == clist_len(list)); CU_ASSERT(true == clist_is_empty(list)); for(i = 0; i < test_cnt; ++i) { clist_append(list, cobj_int_new(i)); } clist_clear(list); CU_ASSERT(0 == clist_len(list)); for(i = 0; i < test_cnt; ++i) { clist_append(list, cobj_int_new(i)); } clist_node *node = NULL; void *obj = NULL; i = 0; clist_foreach_val(list, node, obj) { CU_ASSERT(i == cobj_int_val(obj)); ++i; }
int main(int argc, char *argv[]) { struct clist comp_units; clist_init(&comp_units); char *outfile = "out.rpx"; _Bool final_link = 0; // usage: rpl [-x] [-o <outfile>] <infiles...> int opt; while((opt = getopt(argc, argv, "o:x")) != -1) { switch(opt) { case 'o': outfile = optarg; break; case 'x': // this option enables the assumption that this will be the final // link operation and absolute jump targets can now be resolved. final_link = 1; break; default: { printf("usage: %s -o <outfile> <infile> ...\n", argv[0]); return -1; } break; } } struct comp_unit out_u; comp_unit_init(&out_u); size_t out_text_cap = 0; struct clist abs_patch_addrs; clist_init(&abs_patch_addrs); struct clist rel_patch_addrs; clist_init(&rel_patch_addrs); for(int i = optind; i < argc; i++) { struct comp_unit *u = comp_unit_read(argv[i]); if(u == NULL) return -1; // for each infile: // emit its code size_t text_start_off = out_u.text_len; array_append_bytes( &out_u.text, &out_u.text_len, &out_text_cap, u->text, u->text_len); // collate export locations for(struct clnode *i = clist_first(&u->exported); i != clist_end(&u->exported); i = clnode_next(i)) { struct name_addr_node *uex = (struct name_addr_node *)i; struct name_addr_node *ex = name_addr_node_init( malloc(sizeof(struct name_addr_node)), uex->name, uex->addr + text_start_off); clist_queue(&out_u.exported, &ex->hdr); } // collate abs-dep locations for(struct clnode *i = clist_first(&u->abs_deps); i != clist_end(&u->abs_deps); i = clnode_next(i)) { struct name_addr_node *udep = (struct name_addr_node *)i; struct name_addr_node *dep = name_addr_node_init( malloc(sizeof(struct name_addr_node)), udep->name, udep->addr + text_start_off); clist_queue(&abs_patch_addrs, &dep->hdr); } // collate rel-dep locations for(struct clnode *i = clist_first(&u->rel_deps); i != clist_end(&u->rel_deps); i = clnode_next(i)) { struct name_addr_node *udep = (struct name_addr_node *)i; struct name_addr_node *dep = name_addr_node_init( malloc(sizeof(struct name_addr_node)), udep->name, udep->addr + text_start_off); clist_queue(&rel_patch_addrs, &dep->hdr); } // collate foreign locations for(struct clnode *i = clist_first(&u->foreign_deps); i != clist_end(&u->foreign_deps); i = clnode_next(i)) { struct name_addr_node *ufdep = (struct name_addr_node *)i; struct name_addr_node *fdep = name_addr_node_init( malloc(sizeof(struct name_addr_node)), ufdep->name, ufdep->addr + text_start_off); clist_queue(&out_u.foreign_deps, &fdep->hdr); } } // // fixup deps if they can be resolved // while(! clist_is_empty(&rel_patch_addrs)) { struct clnode *i = clnode_remove(clist_first(&rel_patch_addrs)); struct name_addr_node *patch_dst = (struct name_addr_node *)i; struct name_addr_node *patch_src = name_addr_node_find(&out_u.exported, patch_dst->name); if(! patch_src) { // external dep clist_queue(&out_u.rel_deps, &patch_dst->hdr); } else { jump_t jump_target = patch_src->addr; jump_t jump_source = patch_dst->addr; jump_t jump = jump_target - jump_source; jump = htobe32(jump); memcpy(out_u.text + patch_dst->addr, &jump, sizeof(jump)); free(i); } } if(final_link) { while(! clist_is_empty(&abs_patch_addrs)) { struct clnode *i = clnode_remove(clist_first(&abs_patch_addrs)); struct name_addr_node *patch_dst = (struct name_addr_node *)i; struct name_addr_node *patch_src = name_addr_node_find(&out_u.exported, patch_dst->name); if(! patch_src) { // external dep fprintf(stderr, "error: unresolved absolute link target: %s\n", patch_dst->name); } else { jump_t jump = patch_src->addr; jump = htobe32(jump); memcpy(out_u.text + patch_dst->addr, &jump, sizeof(jump)); free(i); } } } else { while(! clist_is_empty(&abs_patch_addrs)) { struct clnode *i = clnode_remove(clist_first(&abs_patch_addrs)); struct name_addr_node *patch_dst = (struct name_addr_node *)i; clist_queue(&out_u.abs_deps, &patch_dst->hdr); } } // // emit object file // comp_unit_write(&out_u, outfile); return 0; }
int main(int argc, char *argv[]) { if(argc != 3) { printf("usage: %s <infile> <outfile>\n", argv[0]); return -1; } char *infile = argv[1]; char *outfile = argv[2]; FILE *instream; if(strcmp(infile, "--") == 0) instream = stdin; else instream = fopen(infile, "r"); if(! instream) { perror("fopen()"); fprintf(stderr, "file %s\n", infile); return -1; } FILE *outstream; if(strcmp(outfile, "--") == 0) outstream = stdout; else outstream = fopen(outfile, "w"); if(! outstream) { perror("fopen()"); fprintf(stderr, "file %s\n", outfile); return -1; } // tokenize struct clist words; clist_init(&words); read_words_from_FILE(instream, &words, ';'); struct comp_unit cu; size_t out_text_cap = 0; comp_unit_init(&cu); // pass 1: // identify and store all labels and addressess // identify exported labels // identify patch locations // generate code and immediates struct clist label_addrs; clist_init(&label_addrs); struct clist abs_patch_addrs; clist_init(&abs_patch_addrs); struct clist rel_patch_addrs; clist_init(&rel_patch_addrs); for(struct clnode *i = clist_first(&words); i != clist_end(&words); i = clnode_next(i)) { struct word_node *wn = (struct word_node *)i; char *directive = wn->word; if(*directive != '.') { printf("expected directive: %s\n", directive); return -1; } directive++; i = clnode_next(i); if(i == clist_end(&words)) { printf("all directives require an argument\n"); return -1; } struct word_node *wn_arg = (struct word_node *)i; char *arg = wn_arg->word; if(*arg == '.') { printf("expected arg: %s\n", arg); return -1; } struct name_addr_node *n_a_node; char *endp; unsigned long long arg_uval; long long arg_sval; if(strcmp(directive, "label") == 0) { n_a_node = name_addr_node_init( malloc(sizeof(struct name_addr_node)), arg, cu.text_len); clist_queue(&label_addrs, &n_a_node->hdr); } else if(strcmp(directive, "export") == 0) { n_a_node= name_addr_node_init( malloc(sizeof(struct name_addr_node)), arg, cu.text_len); clist_queue(&label_addrs, &n_a_node->hdr); n_a_node = name_addr_node_init( malloc(sizeof(struct name_addr_node)), arg, cu.text_len); clist_queue(&cu.exported, &n_a_node->hdr); } else if(strcmp(directive, "data_u1") == 0) { arg_uval = strtoull(arg, &endp, 0); if(*endp) { printf("parse u1 immedate error for %s\n", arg); return 0; } if(arg_uval > 0xFFULL) { printf("parse u1 immedate too large %s\n", arg); return 0; } uint8_t v = arg_uval; array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, &v, sizeof(v)); } else if(strcmp(directive, "data_u2") == 0) { arg_uval = strtoull(arg, &endp, 0); if(*endp) { printf("parse u2 immedate error for %s\n", arg); return 0; } if(arg_uval > 0xFFFFULL) { printf("parse u2 immedate too large %s\n", arg); return 0; } uint16_t v = arg_uval; v = htobe16(v); array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, (unsigned char*)&v, sizeof(v)); } else if(strcmp(directive, "data_u4") == 0) { arg_uval = strtoull(arg, &endp, 0); if(*endp) { printf("parse u4 immedate error for %s\n", arg); return 0; } if(arg_uval > 0xFFFFFFFFULL) { printf("parse u4 immedate too large %s\n", arg); return 0; } uint32_t v = arg_uval; v = htobe32(v); array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, (unsigned char*)&v, sizeof(v)); } else if(strcmp(directive, "data_u8") == 0) { arg_uval = strtoull(arg, &endp, 0); if(*endp) { printf("parse u8 immedate error for %s\n", arg); return 0; } uint64_t v = arg_uval; v = htobe64(v); array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, (unsigned char*)&v, sizeof(v)); } else if(strcmp(directive, "data_s1") == 0) { arg_sval = strtoll(arg, &endp, 0); if(*endp) { printf("parse s1 immedate error for %s\n", arg); return 0; } if(arg_sval > 0x7FLL || arg_sval < -0x80LL) { printf("parse s1 immedate out of range %s\n", arg); return 0; } int8_t v = arg_sval; array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, (unsigned char*)&v, sizeof(v)); } else if(strcmp(directive, "data_s2") == 0) { arg_sval = strtoll(arg, &endp, 0); if(*endp) { printf("parse s2 immedate error for %s\n", arg); return 0; } if(arg_sval > 0x7FFFLL || arg_sval < -0x8000LL) { printf("parse s2 immedate out of range %s\n", arg); return 0; } int16_t v = arg_sval; v = htobe16(v); array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, (unsigned char*)&v, sizeof(v)); } else if(strcmp(directive, "data_s4") == 0) { arg_sval = strtoll(arg, &endp, 0); if(*endp) { printf("parse s4 immedate error for %s\n", arg); return 0; } if(arg_sval > 0x7FFFFFFFLL || arg_sval < -0x80000000LL) { printf("parse s4 immedate out of range %s\n", arg); return 0; } int32_t v = arg_sval; v = htobe32(v); array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, (unsigned char*)&v, sizeof(v)); } else if(strcmp(directive, "data_s8") == 0) { arg_sval = strtoll(arg, &endp, 0); if(*endp) { printf("parse s8 immedate error for %s\n", arg); return 0; } int64_t v = arg_sval; v = htobe64(v); array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, (unsigned char*)&v, sizeof(v)); } else if(strcmp(directive, "addr") == 0) { n_a_node = name_addr_node_init( malloc(sizeof(struct name_addr_node)), arg, cu.text_len); clist_queue(&abs_patch_addrs, &n_a_node->hdr); uint32_t v = 0; array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, (unsigned char*)&v, sizeof(v)); } else if(strcmp(directive, "reladdr") == 0) { n_a_node = name_addr_node_init( malloc(sizeof(struct name_addr_node)), arg, cu.text_len); clist_queue(&rel_patch_addrs, &n_a_node->hdr); int32_t v = 0; array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, (unsigned char*)&v, sizeof(v)); } else if(strcmp(directive, "foreign_id") == 0) { n_a_node = name_addr_node_init( malloc(sizeof(struct name_addr_node)), arg, cu.text_len); clist_queue(&cu.foreign_deps, &n_a_node->hdr); // patched up later uint32_t v = 0; array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, (unsigned char*)&v, sizeof(v)); } else if(strcmp(directive, "mnemonic") == 0) { uint8_t op; for(op = 0; op < ARRLEN(mnemonics); op++) if(strcasecmp(mnemonics[op], arg) == 0) break; if(op == ARRLEN(mnemonics)) { printf("unknown mnemonic: %s\n", arg); return -1; } array_append_bytes( &cu.text, &cu.text_len, &out_text_cap, &op, sizeof(op)); } else { printf("unknown assembler directive: %s\n", directive); return -1; } } // pass 2: // fixup patch addresses while(! clist_is_empty(&rel_patch_addrs)) { struct clnode *i = clnode_remove(clist_first(&rel_patch_addrs)); struct name_addr_node *patch_dst = (struct name_addr_node *)i; struct name_addr_node *patch_src = name_addr_node_find(&label_addrs, patch_dst->name); if(! patch_src) { // external dep clist_queue(&cu.rel_deps, &patch_dst->hdr); } else { jump_t jump_target = patch_src->addr; jump_t jump_source = patch_dst->addr; jump_t jump = jump_target - jump_source; jump = htobe32(jump); memcpy(cu.text + patch_dst->addr, &jump, sizeof(jump)); free(i); } } while(! clist_is_empty(&abs_patch_addrs)) { struct clnode *i = clnode_remove(clist_first(&abs_patch_addrs)); struct name_addr_node *patch_dst = (struct name_addr_node *)i; struct name_addr_node *patch_src = name_addr_node_find(&label_addrs, patch_dst->name); if(! patch_src) { // external dep clist_queue(&cu.abs_deps, &patch_dst->hdr); } else { jump_t jump = patch_src->addr; jump = htobe32(jump); memcpy(cu.text + patch_dst->addr, &jump, sizeof(jump)); free(i); } } // // write object file // comp_unit_write(&cu, argv[2]); return 0; }
EC_BOOL cset_is_empty(const CSET *cset) { return clist_is_empty(cset); }