comparison lwasm/output.c @ 432:58cafa61ab40

Add support for undocumented custom module format (for LW) Nothing to see here. Move along. These are not the droids you are looking for.
author William Astle <lost@l-w.ca>
date Fri, 18 Nov 2016 21:25:43 -0700
parents 9f0448022f1f
children 999ae00d0919
comparison
equal deleted inserted replaced
431:6df8d62302e2 432:58cafa61ab40
40 void write_code_obj(asmstate_t *as, FILE *of); 40 void write_code_obj(asmstate_t *as, FILE *of);
41 void write_code_os9(asmstate_t *as, FILE *of); 41 void write_code_os9(asmstate_t *as, FILE *of);
42 void write_code_hex(asmstate_t *as, FILE *of); 42 void write_code_hex(asmstate_t *as, FILE *of);
43 void write_code_srec(asmstate_t *as, FILE *of); 43 void write_code_srec(asmstate_t *as, FILE *of);
44 void write_code_ihex(asmstate_t *as, FILE *of); 44 void write_code_ihex(asmstate_t *as, FILE *of);
45 void write_code_lwmod(asmstate_t *as, FILE *of);
45 46
46 // this prevents warnings about not using the return value of fwrite() 47 // this prevents warnings about not using the return value of fwrite()
47 // r++ prevents the "set but not used" warnings; should be optimized out 48 // r++ prevents the "set but not used" warnings; should be optimized out
48 #define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); r++; } while (0) 49 #define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); r++; } while (0)
49 50
99 write_code_srec(as, of); 100 write_code_srec(as, of);
100 break; 101 break;
101 102
102 case OUTPUT_IHEX: 103 case OUTPUT_IHEX:
103 write_code_ihex(as, of); 104 write_code_ihex(as, of);
105 break;
106
107 case OUTPUT_LWMOD:
108 write_code_lwmod(as, of);
104 break; 109 break;
105 110
106 default: 111 default:
107 fprintf(stderr, "BUG: unrecognized output format when generating output file\n"); 112 fprintf(stderr, "BUG: unrecognized output format when generating output file\n");
108 fclose(of); 113 fclose(of);
998 1003
999 // flag no more sections 1004 // flag no more sections
1000 // the "" is NOT an error 1005 // the "" is NOT an error
1001 writebytes("", 1, 1, of); 1006 writebytes("", 1, 1, of);
1002 } 1007 }
1008
1009
1010 void write_code_lwmod(asmstate_t *as, FILE *of)
1011 {
1012 line_t *l;
1013 sectiontab_t *s;
1014 reloctab_t *re;
1015 int initsize, bsssize, mainsize, callsnum, namesize;
1016 unsigned char *initcode, *maincode, *callscode, *namecode;
1017 int relocsize;
1018 unsigned char *reloccode;
1019 int tsize, bssoff;
1020 int initaddr = -1;
1021
1022 int i;
1023 unsigned char buf[16];
1024
1025 // the magic number
1026 buf[0] = 0x8f;
1027 buf[1] = 0xcf;
1028
1029 // run through the entire system and build the byte streams for each
1030 // section; we will make sure we only have simple references for
1031 // any undefined references. That means at most an ADD (or SUB) operation
1032 // with a single BSS symbol reference and a single constant value.
1033 // We will use the constant value in the code stream and record the
1034 // offset in a separate code stream for the BSS relocation table.
1035
1036 // We build everything in memory here because we need to calculate the
1037 // sizes of everything before we can output the complete header.
1038
1039 for (l = as -> line_head; l; l = l -> next)
1040 {
1041 if (l -> csect)
1042 {
1043 // we're in a section - need to output some bytes
1044 if (l -> outputl > 0)
1045 for (i = 0; i < l -> outputl; i++)
1046 write_code_obj_sbadd(l -> csect, l -> output[i]);
1047 else if (l -> outputl == 0 || l -> outputl == -1)
1048 for (i = 0; i < l -> len; i++)
1049 write_code_obj_sbadd(l -> csect, 0);
1050 }
1051 }
1052
1053 // now run through sections and set various parameters
1054 initsize = 0;
1055 bsssize = 0;
1056 mainsize = 0;
1057 callsnum = 0;
1058 callscode = NULL;
1059 maincode = NULL;
1060 initcode = NULL;
1061 namecode = NULL;
1062 namesize = 0;
1063 relocsize = 0;
1064 for (s = as -> sections; s; s = s -> next)
1065 {
1066 if (!strcmp(s -> name, "bss"))
1067 {
1068 bsssize = s -> oblen;
1069 }
1070 else if (!strcmp(s -> name, "main"))
1071 {
1072 maincode = s -> obytes;
1073 mainsize = s -> oblen;
1074 }
1075 else if (!strcmp(s -> name, "init"))
1076 {
1077 initcode = s -> obytes;
1078 initsize = s -> oblen;
1079 }
1080 else if (!strcmp(s -> name, "calls"))
1081 {
1082 callscode = s -> obytes;
1083 callsnum = s -> oblen / 2;
1084 }
1085 else if (!strcmp(s -> name, "modname"))
1086 {
1087 namecode = s -> obytes;
1088 namesize = 0;
1089 }
1090 for (re = s -> reloctab; re; re = re -> next)
1091 {
1092 if (re -> expr == NULL)
1093 relocsize += 2;
1094 }
1095 }
1096 if (namesize == 0)
1097 {
1098 namecode = (unsigned char *)(as -> output_file);
1099 }
1100 else
1101 {
1102 if (namecode[namesize - 1] != '\0')
1103 {
1104 namecode[namesize - 1] = '\0';
1105 }
1106 if (!*namecode)
1107 namecode = (unsigned char *)(as -> output_file);
1108 }
1109 namesize = strlen((char *)namecode);
1110
1111 tsize = namesize + 1 + initsize + mainsize + callsnum * 2 + relocsize + 11;
1112 bssoff = namesize + 1 + mainsize + callsnum * 2 + 11;
1113 // set up section base addresses
1114 for (s = as -> sections; s; s = s -> next)
1115 {
1116 if (!strcmp(s -> name, "main"))
1117 {
1118 s -> tbase = 11 + namesize + 1 + callsnum * 2;
1119 }
1120 else if (!strcmp(s -> name, "init"))
1121 {
1122 s -> tbase = bssoff + relocsize;
1123 }
1124 else if (!strcmp(s -> name, "calls"))
1125 {
1126 s -> tbase = 11;
1127 }
1128 else if (!strcmp(s -> name, "modname"))
1129 {
1130 s -> tbase = 11 + callsnum * 2;
1131 }
1132 }
1133
1134 // resolve the "init" address
1135 if (as -> execaddr_expr)
1136 {
1137 // need to resolve address with proper section bases
1138 lwasm_reduce_expr(as, as -> execaddr_expr);
1139 initaddr = lw_expr_intval(as -> execaddr_expr);
1140 }
1141 else
1142 {
1143 initaddr = as -> execaddr;
1144 }
1145
1146 // build relocation data
1147 reloccode = NULL;
1148 if (relocsize)
1149 {
1150 unsigned char *tptr;
1151 reloccode = lw_alloc(relocsize);
1152 tptr = reloccode;
1153
1154 for (s = as -> sections; s; s = s -> next)
1155 {
1156 for (re = s -> reloctab; re; re = re -> next)
1157 {
1158 lw_expr_t te;
1159 line_t tl;
1160 int offset;
1161
1162 tl.as = as;
1163 as -> cl = &tl;
1164 as -> csect = s;
1165 // as -> exportcheck = 1;
1166
1167 if (re -> expr)
1168 {
1169 int val;
1170 int x;
1171
1172 te = lw_expr_copy(re -> expr);
1173 lwasm_reduce_expr(as, te);
1174 if (!lw_expr_istype(te, lw_expr_type_int))
1175 {
1176 val = 0;
1177 }
1178 else
1179 {
1180 val = lw_expr_intval(te);
1181 }
1182 lw_expr_destroy(te);
1183 x = s -> tbase;
1184 s -> tbase = 0;
1185 te = lw_expr_copy(re -> offset);
1186 lwasm_reduce_expr(as, te);
1187 offset = lw_expr_intval(te);
1188 lw_expr_destroy(te);
1189 s -> tbase = x;
1190 // offset *should* be the offset in the section
1191 s -> obytes[offset] = val >> 8;
1192 s -> obytes[offset + 1] = val & 0xff;
1193 continue;
1194 }
1195
1196 offset = 0;
1197 te = lw_expr_copy(re -> offset);
1198 lwasm_reduce_expr(as, te);
1199 if (!lw_expr_istype(te, lw_expr_type_int))
1200 {
1201 lw_expr_destroy(te);
1202 offset = 0;
1203 continue;
1204 }
1205 offset = lw_expr_intval(te);
1206 lw_expr_destroy(te);
1207 //offset += sbase;
1208
1209 *tptr++ = offset >> 8;
1210 *tptr++ = offset & 0xff;
1211 }
1212 }
1213 }
1214
1215 // total size
1216 buf[2] = tsize >> 8;
1217 buf[3] = tsize & 0xff;
1218 // offset to BSS relocs
1219 buf[4] = bssoff >> 8;
1220 buf[5] = bssoff & 0xff;
1221 // BSS size
1222 buf[6] = bsssize >> 8;
1223 buf[7] = bsssize & 0xff;
1224 // init routine offset
1225 buf[8] = initaddr >> 8;
1226 buf[9] = initaddr & 0xff;
1227 // number of call entries
1228 buf[10] = callsnum;
1229 // write the header
1230 writebytes(buf, 11, 1, of);
1231 // call data
1232 if (callsnum)
1233 writebytes(callscode, callsnum * 2, 1, of);
1234 // module name
1235 writebytes(namecode, namesize + 1, 1, of);
1236 // main code
1237 if (mainsize)
1238 writebytes(maincode, mainsize, 1, of);
1239 // bss relocs
1240 if (relocsize)
1241 writebytes(reloccode, relocsize, 1, of);
1242 // init stuff
1243 if (initsize)
1244 writebytes(initcode, initsize, 1, of);
1245 }