├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── cc.c ├── cc.h ├── compat.h ├── config.h ├── cpp.c ├── elf.h ├── fmt.c ├── gen.c ├── include ├── float.h ├── iso646.h ├── limits.h ├── stdarg.h ├── stdbool.h └── stddef.h ├── liberty.c ├── liberty.h ├── main.c ├── parse.c ├── section.c ├── sub.c ├── symtab.c ├── tokens.c ├── typechk.c ├── types.c ├── x86_64-gen.c ├── x86_64-opc.c └── x86_64.h /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *~ 3 | #*# 4 | *.s 5 | *.o 6 | *.a 7 | *.bin 8 | *.obj 9 | *.exe 10 | *.stackdump 11 | cscope.* 12 | TAGS 13 | GPATH 14 | GRTAGS 15 | GTAGS 16 | nul 17 | .vscode/ 18 | .vs/ 19 | *.d 20 | *.x 21 | .depend 22 | gmon.out* 23 | core -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | INSTALL_ROOT=/usr/local 2 | INSTALL_BIN=$INSTALL_ROOT/bin 3 | INSTALL_LIB=$INSTALL_ROOT/lib 4 | TARGET=hcc 5 | CFLAGS+=-Wall -O2 -fno-strict-aliasing -Wno-missing-braces -Wno-char-subscripts 6 | LDFLAGS= 7 | 8 | # obects 9 | OBJS = main.o \ 10 | liberty.o \ 11 | symtab.o \ 12 | tokens.o \ 13 | types.o \ 14 | fmt.o \ 15 | cpp.o \ 16 | cc.o \ 17 | parse.o \ 18 | sub.o \ 19 | typechk.o \ 20 | gen.o \ 21 | section.o \ 22 | x86_64-gen.o \ 23 | x86_64-opc.o 24 | 25 | $(TARGET): $(OBJS) 26 | $(CC) $(LDFLAGS) $(OBJS) -o $@ 27 | 28 | headers:: 29 | mkdir -p $(INSTALL_BIN)/$(TARGET) 30 | cp -R include $(INSTALL_LIB)/$(TARGET) 31 | 32 | install:: headers $(TARGET) 33 | mkdir -p $(INSTALL_BIN) 34 | cp $(TARGET) $(INSTALL_BIN) 35 | 36 | uninstall:: 37 | rm -f $(INSTALL_BIN)/$(TARGET) 38 | rm -rf $(INSTALL_LIB)/$(TARGET) 39 | 40 | clean:: 41 | @find . \( -name '.git' \) -prune -o \ 42 | \( -name '*.o' -o -name '*~' -o -name '*.s' \) \ 43 | -type f -print | xargs rm -f 44 | @rm -f $(TARGET) stage1 stage2 stage3 45 | 46 | # bootstrap 47 | 48 | objclean:: 49 | @rm -f *.o 50 | 51 | stage1: 52 | $(MAKE) objclean 53 | $(MAKE) CC=cc 54 | mv $(TARGET) stage1 55 | 56 | stage2: stage1 57 | $(MAKE) objclean 58 | $(MAKE) CC=./stage1 59 | mv $(TARGET) stage2 60 | 61 | stage3: stage2 62 | $(MAKE) objclean 63 | $(MAKE) CC=./stage2 64 | mv $(TARGET) stage3 65 | 66 | bootstrap:: stage3 67 | cmp stage2 stage3 68 | 69 | # Test 70 | test:: 71 | @cd test && make 72 | 73 | help:: 74 | @echo "Usage:" 75 | @echo " make # Compile the compiler" 76 | @echo " make install # Compile and install the compiler" 77 | @echo " make clean # Remove all compiler results and editor backups" 78 | @echo " make uninstall # Uninstall the compiler" 79 | 80 | # depend 81 | cc.o: cc.c cc.h liberty.h 82 | cpp.o: cpp.c compat.h cc.h liberty.h 83 | fmt.o: fmt.c cc.h liberty.h 84 | gen.o: gen.c cc.h liberty.h 85 | liberty.o: liberty.c compat.h liberty.h 86 | main.o: main.c config.h compat.h cc.h liberty.h 87 | parse.o: parse.c cc.h liberty.h 88 | section.o: section.c cc.h liberty.h elf.h 89 | sub.o: sub.c cc.h liberty.h 90 | symtab.o: symtab.c cc.h liberty.h 91 | tokens.o: tokens.c cc.h liberty.h 92 | typechk.o: typechk.c cc.h liberty.h 93 | types.o: types.c cc.h liberty.h 94 | x86_64-gen.o: x86_64-gen.c config.h compat.h cc.h liberty.h x86_64.h elf.h 95 | x86_64-opc.o: x86_64-opc.c cc.h liberty.h x86_64.h 96 | # end depend 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hcc 2 | A tiny C99 compiler 3 | 4 | The compiler is designed to be able to compile itself, so it is written in C. And it is intended to support all C99 language features while keeping the code as simple and small as possible. 5 | 6 | 7 | HOWTO build 8 | ---------------- 9 | Make sure you have Linux installed. (Any distribution is fine) 10 | 11 | To build the compiler, run command: 12 | 13 | ``` 14 | make 15 | make install # root priviledge required 16 | ``` 17 | 18 | To build the bootstrap compiler, run command: 19 | 20 | ``` 21 | make bootstrap 22 | ``` 23 | 24 | If you use Debian based distribution like Ubuntu, just modify these macros in **config.h**. 25 | 26 | ``` 27 | CONFIG_CRT_PREFIX 28 | CONFIG_LIBC_PREFIX 29 | ``` 30 | 31 | 32 | Author 33 | ------- 34 | Feel free to report [issues](https://github.com/huangguiyang/hcc/issues) to me. 35 | 36 | 37 | License 38 | ------- 39 | GPLv3. 40 | 41 | 42 | Reference 43 | --------- 44 | 1. C Standard Draft: 45 | C99: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf 46 | C11: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 47 | 48 | 2. X86-64 ABI: 49 | v0.90 (Dec 2, 2003): http://people.freebsd.org/~obrien/amd64-elf-abi.pdf 50 | v0.99.6 (Oct 7, 2013): http://www.x86-64.org/documentation/abi.pdf 51 | 52 | 3. "Intel 64 and IA-32 Architecture Software Developer Manuals": 53 | http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html 54 | -------------------------------------------------------------------------------- /cc.c: -------------------------------------------------------------------------------- 1 | #include "cc.h" 2 | 3 | static int printed_line = 1; 4 | static int last_line = 1; 5 | static int dirty_line_p; 6 | 7 | const char *main_input_filename; 8 | const char *main_output_filename; 9 | 10 | static void maybe_print_lines(int diff) 11 | { 12 | if (diff > 5) { 13 | if (dirty_line_p) { 14 | dirty_line_p = 0; 15 | fputs("\n", stdout); 16 | } 17 | printed_line += diff; 18 | printf("# %d\n", printed_line); 19 | } else if (diff > 0) { 20 | while (diff) { 21 | fputs("\n", stdout); 22 | printed_line++; 23 | diff--; 24 | } 25 | dirty_line_p = 0; 26 | } 27 | } 28 | 29 | static void cb_file_change(int line, int reason) 30 | { 31 | const char *oname; 32 | int oline; 33 | 34 | switch (reason) { 35 | case FC_ENTER: 36 | if (line > 1) { 37 | cpp_resolve_location(line - 1, NULL, &oline); 38 | maybe_print_lines(oline - printed_line); 39 | } 40 | /* fall thru */ 41 | 42 | case FC_LEAVE: 43 | if (dirty_line_p) { 44 | dirty_line_p = 0; 45 | fputs("\n", stdout); 46 | } 47 | cpp_resolve_location(line, &oname, &oline); 48 | printed_line = oline; 49 | printf("# %d \"%s\"\n", oline, oname); 50 | break; 51 | 52 | case FC_RENAME: 53 | if (dirty_line_p) { 54 | dirty_line_p = 0; 55 | fputs("\n", stdout); 56 | } 57 | printed_line = hist->offset; 58 | if (hist->name) 59 | printf("# %d \"%s\"\n", printed_line, hist->name); 60 | else 61 | printf("# %d\n", printed_line); 62 | break; 63 | } 64 | last_line = line; 65 | } 66 | 67 | static void cb_line_change(int line, struct token *tok) 68 | { 69 | int d; 70 | 71 | if (tok->id == TOK_EOF) 72 | return; 73 | d = line - last_line; 74 | if (d > 0) 75 | maybe_print_lines(d); 76 | last_line = line; 77 | } 78 | 79 | static void preprocess(void) 80 | { 81 | struct token result; 82 | 83 | do { 84 | cpp_get_token(&result); 85 | if (result.id == TOK_EOF) { 86 | if (dirty_line_p) { 87 | dirty_line_p = 0; 88 | fputs("\n", stdout); 89 | } 90 | break; 91 | } 92 | if (result.flags & TOK_FLAG_PREV_WHITE) 93 | fputs(" ", stdout); 94 | fputs(tok2s(&result), stdout); 95 | dirty_line_p = 1; 96 | } while (1); 97 | } 98 | 99 | int cc1(const char *ifile, const char *ofile, char **opts) 100 | { 101 | char *opt; 102 | 103 | /* stdin as input */ 104 | if (ifile && ifile[0] == '-' && ifile[1] == 0) 105 | ifile = ""; 106 | /* stdout as output */ 107 | if (ofile && ofile[0] == '-' && ofile[1] == 0) 108 | ofile = ""; 109 | 110 | main_input_filename = ifile; 111 | main_output_filename = ofile; 112 | 113 | /* set callbacks for standalone mode */ 114 | if (options.preprocess_only) { 115 | cpp_callbacks.file_change = cb_file_change; 116 | cpp_callbacks.line_change = cb_line_change; 117 | } 118 | 119 | fmtinit(); 120 | tokens_init(); 121 | types_init(); 122 | cpp_init(ifile); 123 | 124 | for (; (opt = *opts); opts++) 125 | if (opt[1] == 'D') 126 | cpp_define(opt + 2); 127 | else if (opt[1] == 'U') 128 | cpp_undef(opt + 2); 129 | else if (opt[1] == 'I') 130 | cpp_add_include(opt + 2, 0); 131 | 132 | /* GNU C Common Predefined Macros */ 133 | if (options.optimize > 0) 134 | cpp_define("__OPTIMIZE__"); 135 | /* FIXME: auto set -fPIC when -DPIC */ 136 | if (cpp_macro_defined_p("PIC")) 137 | options.pic = 1; 138 | 139 | if (options.preprocess_only) { 140 | preprocess(); 141 | } else { 142 | ginit(); 143 | parse(); 144 | gfini(); 145 | } 146 | 147 | return errors > 0 ? EXIT_FAILURE : EXIT_SUCCESS; 148 | } 149 | -------------------------------------------------------------------------------- /cc.h: -------------------------------------------------------------------------------- 1 | #ifndef CC_H 2 | #define CC_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "liberty.h" 11 | 12 | #define ISWHITESPACE(c) (map[c] & BLANK) 13 | #define ISNEWLINE(c) (map[c] & NEWLINE) 14 | #define ISDIGITLETTER(c) (map[c] & (DIGIT|LETTER)) 15 | #define ISXALPHA(c) (map[c] & HEX) 16 | #define ISDIGIT(c) (map[c] & DIGIT) 17 | #define ISXDIGIT(c) (map[c] & (DIGIT|HEX)) 18 | #define ISLETTER(c) (map[c] & LETTER) 19 | 20 | #define MACRO_DEFINED_P(sym) ((sym)->kind == SYM_MACRO) 21 | #define Z 0 22 | 23 | /* decoded command-line options */ 24 | struct options { 25 | int preprocess_only; 26 | int leading_underscore; 27 | int warn_unsupported; 28 | int warn_error; 29 | int warn_none; 30 | int pic; 31 | int verbose; 32 | int optimize; 33 | int debug; 34 | }; 35 | 36 | struct init { 37 | int code; 38 | unsigned long value; 39 | const char *s; 40 | }; 41 | 42 | enum { 43 | BLANK = 01, NEWLINE = 02, LETTER = 04, DIGIT = 010, HEX = 020 44 | }; 45 | 46 | /* binary op precedence */ 47 | enum { 48 | PREC_XXX, 49 | PREC_OROR, 50 | PREC_ANDAND, 51 | PREC_OR, 52 | PREC_XOR, 53 | PREC_AND, 54 | PREC_EQ, 55 | PREC_REL, 56 | PREC_SHIFT, 57 | PREC_ADD, 58 | PREC_MUL, 59 | NPREC 60 | }; 61 | 62 | /* reuse ascii value as token id. */ 63 | enum { 64 | TOK_XXX, 65 | TOK_AUTO, /* 1 */ 66 | TOK_EXTERN, 67 | TOK_REGISTER, 68 | TOK_STATIC, 69 | TOK_TYPEDEF, 70 | TOK_BREAK, 71 | TOK_CASE, 72 | TOK_CONTINUE, 73 | TOK_DEFAULT, 74 | TOK_DO, 75 | TOK_ELSE, 76 | TOK_FOR, 77 | TOK_GOTO, 78 | TOK_IF, 79 | TOK_RETURN, 80 | TOK_SWITCH, 81 | TOK_WHILE, 82 | TOK_SIZEOF, 83 | TOK_VOID, 84 | TOK_BOOL, 85 | TOK_CHAR, 86 | TOK_SHORT, 87 | TOK_ENUM, 88 | TOK_SIGNED, 89 | TOK_INT, 90 | TOK_UNSIGNED, 91 | TOK_LONG, 92 | TOK_FLOAT, 93 | TOK_DOUBLE, 94 | TOK_STRUCT, 95 | TOK_UNION, 96 | TOK_INLINE, /* 32, non-used: 34,39 */ 97 | TOK_CONST = 48, 98 | TOK_VOLATILE, 99 | TOK_RESTRICT, 100 | TOK_MULEQ, 101 | TOK_ADDEQ, 102 | TOK_SUBEQ, 103 | TOK_DIVEQ, 104 | TOK_MODEQ, /* 55, non-used: 56,57 */ 105 | TOK_XOREQ = 65, 106 | TOK_ANDEQ, 107 | TOK_OREQ, 108 | TOK_SHLEQ, 109 | TOK_SHREQ, 110 | TOK_SHL, 111 | TOK_SHR, 112 | TOK_GEQ, 113 | TOK_LEQ, 114 | TOK_EQ, 115 | TOK_NEQ, 116 | TOK_INCR, 117 | TOK_DECR, 118 | TOK_DEREF, 119 | TOK_ANDAND, 120 | TOK_OROR, 121 | TOK_ELLIPSIS, 122 | TOK_ICON, 123 | TOK_FCON, 124 | TOK_SCON, 125 | TOK_WSCON, 126 | TOK_NAME, /* 86, non-used: 87-90,92,95-115 */ 127 | TOK_INVALID = 116, 128 | TOK_PASTE, 129 | TOK_PP_NUMBER, 130 | TOK_PP_CHAR, 131 | TOK_PP_WCHAR, 132 | TOK_PP_HEADER_NAME, 133 | TOK_PP_MACRO_ARG, /* 122 */ 134 | TOK_EOF = 127, 135 | NTOKEN 136 | }; 137 | 138 | enum { 139 | TOK_FLAG_BOL = 1 << 0, /* beginning of line */ 140 | TOK_FLAG_PREV_WHITE = 1 << 1, /* leading whitespace */ 141 | TOK_FLAG_STRINGIFY_ARG = 1 << 2, /* stringify argument */ 142 | TOK_FLAG_PASTE_LEFT = 1 << 3, /* appear on the left side of ## */ 143 | TOK_FLAG_BOF = 1 << 4, /* beginning of file */ 144 | TOK_FLAG_NO_EXPAND = 1 << 5, /* do NOT macro-expand this token */ 145 | }; 146 | 147 | struct token { 148 | short id; 149 | short flags; 150 | union { 151 | struct symbol *sym; /* identifier */ 152 | const char *str; /* string or number */ 153 | int macro_arg_i; /* macro arg index */ 154 | } val; 155 | }; 156 | 157 | /* symbol kind */ 158 | enum { SYM_MACRO = 1 }; 159 | 160 | enum { 161 | SYM_FLAG_DISABLED = 1 << 0, /* disabled macro */ 162 | SYM_FLAG_MACRO_ARG = 1 << 2, /* macro argument */ 163 | }; 164 | 165 | /* symtab lookup options */ 166 | enum { OPT_SEARCH = 0, OPT_CREATE }; 167 | 168 | struct symbol { 169 | struct symbol *link; /* next symbol in symtab */ 170 | const char *name; 171 | unsigned int hash; 172 | unsigned int len; 173 | 174 | /* used by cpp */ 175 | struct macro *macro; 176 | int arg_i; 177 | short flags; 178 | short keyword_id; 179 | char kind; 180 | char dir_no; 181 | char directive_p; 182 | char builtin_id; 183 | 184 | /* used by parser */ 185 | struct type *type; 186 | struct type *suetype; /* struct/union/enum type */ 187 | struct node *label; /* label in function */ 188 | long offset; 189 | int block; 190 | int sueblock; /* struct/union/enum blockno */ 191 | int vconst; 192 | int line; 193 | char sclass; 194 | char anonymous; 195 | char defined; 196 | char used; 197 | 198 | /* used by backend */ 199 | int symndx; /* symtab index */ 200 | }; 201 | 202 | struct svalue { 203 | long i; 204 | double d; 205 | short id; 206 | short base; 207 | int suffix; 208 | }; 209 | 210 | struct cpp_dir { 211 | const char **include; 212 | int ninclude, maxinclude; 213 | }; 214 | 215 | struct cached_include { 216 | const char *filename; 217 | struct symbol *sym; 218 | struct cached_include *next; 219 | }; 220 | 221 | struct cpp_state { 222 | int skipping:1; 223 | int in_directive:1; 224 | int bracket_header:1; /* parsing bracket header name */ 225 | int parsing_args:1; /* parsing arguments? */ 226 | int prevent_expansion:8; 227 | int standalone:1; 228 | int seen_eof:1; /* seen EOF */ 229 | }; 230 | 231 | /* file change reason */ 232 | enum { FC_ENTER, FC_LEAVE, FC_RENAME }; 233 | 234 | /* source location history */ 235 | struct hist { 236 | struct hist *link; 237 | const char *name; /* file name */ 238 | int line; /* beginning lineno */ 239 | int offset; /* #line directive */ 240 | int reason; /* file change reason */ 241 | }; 242 | 243 | struct cpp_callbacks { 244 | void (*file_change)(int, int); 245 | void (*line_change)(int, struct token *); 246 | }; 247 | 248 | /* #if stack */ 249 | struct ifstack { 250 | int type:8; 251 | int was_skipping:1; 252 | int skip_else:1; 253 | struct ifstack *link; 254 | }; 255 | 256 | /* macro arguments */ 257 | struct macro_arg { 258 | struct token *token, *exp; 259 | int ntoken, nexp; 260 | struct token *stringified; 261 | int token_alloc, arg_alloc; 262 | }; 263 | 264 | /* macro type */ 265 | enum { MACRO_OBJ, MACRO_FUNC, MACRO_SPECIAL }; 266 | 267 | struct macro { 268 | int type:8; 269 | int variadic:1; 270 | int nparam, maxparam; 271 | int nbody, maxbody; 272 | struct symbol **param; 273 | struct token *body; 274 | const char * (*handler)(struct token *); 275 | }; 276 | 277 | enum { 278 | TOKENS_KIND_INDIRECT, 279 | TOKENS_KIND_DIRECT 280 | }; 281 | 282 | /* macro expansion context */ 283 | struct cpp_context { 284 | struct cpp_context *prev; 285 | union { 286 | struct token *token; 287 | struct token **ptoken; 288 | } first, end; 289 | struct symbol *sym; 290 | void *buff; 291 | int tokens_kind; 292 | }; 293 | 294 | struct directive { 295 | const char *name; 296 | void (*handler)(void); 297 | int flags; 298 | }; 299 | 300 | struct line_note { 301 | const unsigned char *pos; 302 | int type; 303 | }; 304 | 305 | /* A buffer represents a file's content. */ 306 | struct buffer { 307 | const char *path; /* file full path */ 308 | const char *name; /* buffer name */ 309 | int bol:1; /* beginning of line? */ 310 | int bof:1; /* first non-whitespace? */ 311 | int endif:1; /* #endif at the end of file seen */ 312 | int need_line:1; /* need a nextline? */ 313 | const unsigned char *cur; /* current position */ 314 | const unsigned char *limit; /* end position */ 315 | const unsigned char *line_base; /* current line base */ 316 | const unsigned char *next_line; /* next line beginning */ 317 | struct line_note *notes; /* array of notes */ 318 | unsigned int cur_note; /* cuurent note index */ 319 | unsigned int notes_used; /* number of notes */ 320 | unsigned int notes_alloc; /* number of notes allocated */ 321 | struct ifstack *ifstack; /* top of 'if' stack */ 322 | struct ifstack *ifndef_stack; /* #ifndef stack at beginning of file */ 323 | struct symbol *ifndef_sym; /* #ifndef ident at beginning of file */ 324 | struct buffer *prev; /* previous buffer */ 325 | unsigned char *buf; /* content of this buffer */ 326 | }; 327 | 328 | /* storage class */ 329 | enum { 330 | CXXX, 331 | CAUTO, 332 | CEXTERN, 333 | CSTATIC, 334 | CTYPEDEF, 335 | CREGISTER, 336 | CGLOBAL, 337 | CENUM, 338 | CPARAM, 339 | NCTYPE 340 | }; 341 | 342 | /* type qaulifiers */ 343 | enum { 344 | QXXX = 0, 345 | QCONST = 1 << 0, 346 | QVOLATILE = 1 << 1, 347 | QMASK = QCONST | QVOLATILE 348 | }; 349 | 350 | enum { 351 | TXXX, 352 | TBOOL, 353 | TCHAR, 354 | TUCHAR, 355 | TSHORT, 356 | TUSHORT, 357 | TINT, 358 | TUINT, 359 | TLONG, 360 | TULONG, 361 | TLLONG, 362 | TULLONG, 363 | TFLOAT, 364 | TDOUBLE, 365 | TPTR, 366 | TVOID, 367 | TFUNC, 368 | TARRAY, 369 | TSTRUCT, 370 | TUNION, 371 | TENUM, 372 | NTYPE, 373 | 374 | TCONST = NTYPE, 375 | TVOLATILE, 376 | TUNSIGNED, 377 | TSIGNED, 378 | TAUTO, 379 | TEXTERN, 380 | TSTATIC, 381 | TTYPEDEF, 382 | TREGISTER, 383 | TTYPENAME, 384 | NALLTYPE 385 | }; 386 | 387 | enum { 388 | BBOOL = 1 << TBOOL, 389 | BCHAR = 1 << TCHAR, 390 | BUCHAR = 1 << TUCHAR, 391 | BSHORT = 1 << TSHORT, 392 | BUSHORT = 1 << TUSHORT, 393 | BINT = 1 << TINT, 394 | BUINT = 1 << TUINT, 395 | BLONG = 1 << TLONG, 396 | BULONG = 1 << TULONG, 397 | BLLONG = 1 << TLLONG, 398 | BULLONG = 1 << TULLONG, 399 | BFLOAT = 1 << TFLOAT, 400 | BDOUBLE = 1 << TDOUBLE, 401 | BVOID = 1 << TVOID, 402 | BPTR = 1 << TPTR, 403 | BFUNC = 1 << TFUNC, 404 | BARRAY = 1 << TARRAY, 405 | BSTRUCT = 1 << TSTRUCT, 406 | BUNION = 1 << TUNION, 407 | BENUM = 1 << TENUM, 408 | BCONST = 1 << TCONST, 409 | BVOLATILE = 1 << TVOLATILE, 410 | BSIGNED = 1 << TSIGNED, 411 | BUNSIGNED = 1 << TUNSIGNED, 412 | BAUTO = 1 << TAUTO, 413 | BEXTERN = 1 << TEXTERN, 414 | BSTATIC = 1 << TSTATIC, 415 | BTYPEDEF = 1 << TTYPEDEF, 416 | BREGISTER = 1 << TREGISTER, 417 | BTYPENAME = 1 << TTYPENAME, 418 | 419 | BINTEGER = BBOOL | BCHAR | BUCHAR | BSHORT | BUSHORT | BINT | BUINT | 420 | BLONG | BULONG | BLLONG | BULLONG | BENUM, 421 | BNUMBER = BINTEGER | BFLOAT | BDOUBLE, 422 | 423 | BCLASS = BAUTO | BEXTERN | BSTATIC | BTYPEDEF | BREGISTER, 424 | BQUAL = BCONST | BVOLATILE, 425 | }; 426 | 427 | struct type { 428 | struct type *link; /* array,ptr,function return,struct fields */ 429 | struct type *next; /* field/proto list */ 430 | struct symbol *sym; /* field's name */ 431 | struct symbol *tag; /* sue type' name */ 432 | long size; 433 | long offset; 434 | char etype; 435 | char align; 436 | char qual; 437 | char oldstyle; 438 | char nbits; 439 | char bitoff; 440 | }; 441 | 442 | /* decl kind */ 443 | enum { 444 | DMARK, 445 | DAUTO, 446 | DSUE, 447 | DLABEL 448 | }; 449 | 450 | struct decl { 451 | struct decl *link; 452 | struct symbol *sym; 453 | struct type *type; 454 | long offset; 455 | int block; 456 | int vconst; 457 | int line; 458 | char sclass; 459 | char defined; 460 | char used; 461 | char kind; 462 | }; 463 | 464 | /* node op */ 465 | enum { 466 | OXXX, 467 | OLIST, 468 | OCOMMA, 469 | OAS, /* assign */ 470 | OASI, 471 | OASMUL, 472 | OASUMUL, 473 | OASADD, 474 | OASSUB, 475 | OASDIV, 476 | OASUDIV, 477 | OASMOD, 478 | OASUMOD, 479 | OASXOR, 480 | OASAND, 481 | OASOR, 482 | OASSHL, 483 | OASSHR, 484 | OASUSHR, 485 | OCOND, /* conditional */ 486 | OADD, /* binary */ 487 | OSUB, 488 | OMUL, 489 | OUMUL, 490 | ODIV, 491 | OUDIV, 492 | OMOD, 493 | OUMOD, 494 | OAND, 495 | OOR, 496 | OSHL, 497 | OSHR, 498 | OUSHR, 499 | OXOR, 500 | OLT, 501 | OLE, 502 | OGT, 503 | OGE, 504 | OEQ, 505 | ONE, 506 | OANDAND, 507 | OOROR, 508 | OCAST, /* cast */ 509 | OPREINC, /* unary */ 510 | OPREDEC, 511 | OPOS, 512 | ONEG, 513 | OCOM, 514 | ONOT, 515 | OADDR, 516 | OINDIR, 517 | OSIZEOF, 518 | OPOSTINC, /* postfix */ 519 | OPOSTDEC, 520 | ODOT, 521 | OFUNC, 522 | ONAME, /* primary */ 523 | OCONST, 524 | OSTRING, 525 | OCOMPOUND, 526 | OINIT, /* init */ 527 | OELEM, 528 | OARRAY, 529 | OPROTO, /* misc */ 530 | OBIT, 531 | OZERO, 532 | OREGISTER, 533 | OINDREG, 534 | OIF, /* statement */ 535 | OWHILE, 536 | ODOWHILE, 537 | OFOR, 538 | OSWITCH, 539 | OCASE, 540 | OLABEL, 541 | OGOTO, 542 | OBREAK, 543 | OCONTINUE, 544 | ORETURN, 545 | NOTYPE 546 | }; 547 | 548 | union value { 549 | long i; 550 | double d; 551 | void *p; 552 | char *cstring; 553 | int *wstring; 554 | }; 555 | 556 | struct node { 557 | struct node *left; 558 | struct node *right; 559 | struct type *type; 560 | struct symbol *sym; 561 | union value v; 562 | long offset; 563 | int line; 564 | char op; 565 | char sclass; 566 | char addable; 567 | char complex; 568 | 569 | /* used by backend */ 570 | char reg; 571 | char index; 572 | char scale; 573 | char areg1; 574 | char areg2; 575 | int label; 576 | long aoffset; 577 | }; 578 | 579 | struct fmt { 580 | va_list args; 581 | char *start; 582 | char *stop; 583 | char *to; 584 | FILE *stream; 585 | int c; /* the char */ 586 | int nfmt; 587 | }; 588 | 589 | /* builtin symbols */ 590 | enum { 591 | BUILTIN_XXX, 592 | BUILTIN_FUNC, 593 | BUILTIN_VA_START, 594 | BUILTIN_VA_ARG, 595 | BUILTIN_VA_COPY, 596 | BUILTIN_VA_END, 597 | BUILTIN_VA_LIST, 598 | NBUILTIN 599 | }; 600 | 601 | struct section { 602 | int sh_name; /* elf section name */ 603 | int sh_type; /* elf section type */ 604 | int sh_flags; /* elf section flags */ 605 | int sh_info; /* elf misc innformation */ 606 | int sh_addralign; /* elf address alignment boundary */ 607 | int sh_entsize; /* elf size of entries, if section has table */ 608 | unsigned long sh_addr; /* elf virtual address in memory */ 609 | unsigned long sh_offset; /* elf offset in file */ 610 | unsigned long sh_size; /* elf size of section */ 611 | struct section *link; /* link section */ 612 | struct section *reloc; /* relocation section */ 613 | char *data; /* section data */ 614 | size_t data_len; 615 | size_t data_alloc; 616 | int shndx; /* section table index */ 617 | int symndx; /* section symtab index */ 618 | char name[1]; /* section name (MUST BE THE LAST FIELD) */ 619 | }; 620 | 621 | /* cpp.c */ 622 | extern void cpp_init(const char *); 623 | extern void cpp_get_token(struct token *); 624 | extern void cpp_add_include(const char *, int); 625 | extern void cpp_define(const char *); 626 | extern void cpp_undef(const char *); 627 | extern int cpp_macro_defined_p(const char *); 628 | extern const char *tok2s(struct token *); 629 | extern void cpp_resolve_location(int, const char **, int *); 630 | 631 | extern struct cpp_callbacks cpp_callbacks; 632 | extern struct hist *hist; 633 | extern int lineno; 634 | 635 | /* parse.c */ 636 | extern void parse(void); 637 | extern void mkfield(struct type *, struct type *, const char *); 638 | extern struct type *mkproto(struct type *, ...); 639 | extern struct type *mktag(const char *name, int); 640 | extern struct type *thisfn; 641 | extern long stkoffset; 642 | extern int nearln; 643 | 644 | /* sub.c */ 645 | extern void fmtinit(void); 646 | extern void error(struct node *, const char *, ...); 647 | extern void warn(struct node *, const char *, ...); 648 | extern void fatal(struct node *, const char *, ...); 649 | extern int errors, warnings; 650 | 651 | extern void *eval_string(struct token *, int, size_t *); 652 | extern void eval_number(struct token *, struct svalue *); 653 | extern struct node *node(int, struct node *, struct node *); 654 | extern struct node *node1(int, struct node *, struct node *); 655 | extern void nodnew(struct node *, int, struct node *, struct node *); 656 | extern struct node *invert(struct node *); 657 | extern struct node *newlist(struct node *, struct node *); 658 | extern int bitno(int); 659 | extern int bitwiseq(int); 660 | extern int simpleq(int); 661 | extern int btot(int); 662 | extern int ttoq(int); 663 | extern int simplec(int); 664 | extern struct type *simplet(int, struct type *); 665 | extern int typebitor(int, int); 666 | extern struct symbol *anonymous(void); 667 | extern struct symbol *mkstatic(struct symbol *); 668 | extern struct node *cnstnode(struct type *, ...); 669 | extern long convltox(long, int); 670 | extern int log2i(size_t); 671 | extern void prstruct(struct type *); 672 | extern void prdecl(struct symbol *); 673 | extern void prtree(struct node *, const char *); 674 | 675 | /* typechk.c */ 676 | extern int tcompat(struct node *, struct type *, struct type *, int []); 677 | extern int tconv(struct node *); 678 | extern void conv(struct node *); 679 | extern int vbconst(struct node *); 680 | 681 | /* types.c */ 682 | extern void types_init(void); 683 | extern struct type *typcpy(struct type *); 684 | extern struct type *ptrtyp(struct type *); 685 | extern struct type *arraytyp(struct type *, long); 686 | extern struct type *functyp(struct type *, struct type *, int); 687 | extern struct type *suetyp(int); 688 | extern struct type *unqual(struct type *); 689 | extern struct type *qual(int, struct type *); 690 | extern int variadic(struct type *); 691 | extern int eqtype(struct type *, struct type *, int); 692 | extern struct type *compose(struct type *, struct type *); 693 | extern struct type *decay(struct type *); 694 | extern struct type *promote(struct type * ); 695 | extern void sualign(struct type *); 696 | extern struct type *find_field(struct symbol *, struct type *, long *); 697 | 698 | extern struct type *types[NTYPE]; 699 | extern char typei[NTYPE]; 700 | extern char typeu[NTYPE]; 701 | extern char typefd[NTYPE]; 702 | extern char typesu[NTYPE]; 703 | extern char typesue[NTYPE]; 704 | extern char typeaf[NTYPE]; 705 | extern int tand[]; 706 | extern int tnot[]; 707 | extern int tneg[]; 708 | extern int trel[]; 709 | extern int tadd[]; 710 | extern int tsub[]; 711 | extern int tmul[]; 712 | extern int tindir[]; 713 | extern int tdot[]; 714 | extern int tfunc[]; 715 | extern int targ[]; 716 | extern int tcast[]; 717 | extern int tasgn[]; 718 | extern int tasadd[]; 719 | extern char tab[NTYPE][NTYPE]; 720 | 721 | /* tokens.c */ 722 | extern void tokens_init(void); 723 | extern char map[256]; 724 | extern int kinds[NTOKEN]; 725 | extern char precs[NTOKEN]; 726 | extern const char *lexmes[NTOKEN]; 727 | extern int bops[NTOKEN]; 728 | extern int uops[NTOKEN]; 729 | extern const char *tnames[NALLTYPE]; 730 | extern const char *cnames[NCTYPE]; 731 | extern const char *onames[NOTYPE]; 732 | 733 | /* symtab.c */ 734 | extern struct symbol *lookupn(const char *, size_t, int); 735 | extern struct symbol *lookup(const char *, int); 736 | extern void foreach(void (*)(struct symbol *, void *), void *); 737 | extern void dump_symtab(void); 738 | 739 | /* fmt.c */ 740 | extern int fmtinstall(int, int (*)(struct fmt *)); 741 | extern int print(const char *, ...); 742 | extern int vfprint(FILE *, const char *, va_list); 743 | extern int fprint(FILE *, const char *, ...); 744 | extern int vsnprint(char *, size_t, const char *, va_list); 745 | extern int snprint(char *, size_t, const char *, ...); 746 | extern int fmtstrcpy(struct fmt *, const char *); 747 | extern int fmtprint(struct fmt *, const char *, ...); 748 | 749 | /* gen.c */ 750 | extern void codegen(struct node *, struct node *, struct node *); 751 | extern int genlab(int); 752 | 753 | /* cc.c */ 754 | extern int cc1(const char *, const char *, char **); 755 | 756 | extern const char *main_input_filename; 757 | extern const char *main_output_filename; 758 | 759 | /* machine dependent */ 760 | extern void ginit(void); 761 | extern void gfini(void); 762 | extern long gstring(const char *, size_t); 763 | extern void gdata(struct symbol *, struct type *, struct node *); 764 | extern void gconv(struct node *); 765 | extern void gfunc(struct node *, struct node *, struct node *); 766 | extern void gexpr(struct node *, struct node *); 767 | extern void greturn(struct node *); 768 | extern void glabel(int); 769 | extern void gbranch(int, int, int); 770 | extern void gtest(struct node *, int, int); 771 | extern void regalloc(struct node *, struct node *, struct node *); 772 | extern void regfree(struct node *); 773 | 774 | extern char typsize[NTYPE]; 775 | extern int ncast[NTYPE]; 776 | 777 | /* main.c */ 778 | extern struct options options; 779 | 780 | /* section.c */ 781 | extern struct section *newsec(const char *, int, int); 782 | extern void sec_set_data(struct section *, const void *, size_t, size_t); 783 | extern size_t sec_add_data(struct section *, const void *, size_t); 784 | extern size_t sec_add_str(struct section *, const char *); 785 | extern size_t sec_extend(struct section *, size_t); 786 | extern void sec_align(struct section *, int); 787 | extern int sec_find_sym(struct section *, const char *); 788 | extern int sec_add_sym(struct section *, const char *, int, int, int, size_t, size_t); 789 | extern struct section *newsymtab(const char *, int, int, const char *, int); 790 | extern void sec_add_rela(struct section *, struct section *, size_t, int, int, long); 791 | extern void sec_sort_syms(struct section *); 792 | 793 | extern struct section **sections; 794 | extern int sections_used; 795 | 796 | #endif /* CC_H */ 797 | -------------------------------------------------------------------------------- /compat.h: -------------------------------------------------------------------------------- 1 | /* This file imports the system dependent routines. */ 2 | #ifndef COMPAT_H 3 | #define COMPAT_H 4 | 5 | #ifndef _BSD_SOURCE 6 | #define _BSD_SOURCE 7 | #endif 8 | 9 | /* strdup, strndup */ 10 | #ifndef _DEFAULT_SOURCE 11 | #define _DEFAULT_SOURCE 12 | #endif 13 | 14 | /* strndup */ 15 | #define _POSIX_C_SOURCE 200809L 16 | 17 | #if defined(__APPLE__) 18 | #ifndef _DARWIN_C_SOURCE 19 | #define _DARWIN_C_SOURCE 20 | #endif /* _DARWIN_C_SOURCE */ 21 | #endif /* __APPLE__ */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | /* 28 | * NOTE!!! 29 | * The 'dirname()' manual page says: 30 | * Both dirname() and basename() may modify 31 | * the contents of path, so it may be desirable 32 | * to pass a copy when calling one of these functions. 33 | */ 34 | /* dirname, basename */ 35 | #include 36 | /* uname */ 37 | #include 38 | /* file control */ 39 | #include 40 | 41 | /* PATH_MAX */ 42 | #ifndef PATH_MAX 43 | #define PATH_MAX 4096 44 | #endif 45 | 46 | /* strcasecmp */ 47 | #include 48 | 49 | #endif /* COMPAT_H */ 50 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #define CONFIG_VERSION "0.6.0-beta1" 5 | #define CONFIG_TARGET_X86_64 1 6 | #define CONFIG_CC_INCLUDE_DIR "/usr/local/lib/hcc/include" 7 | 8 | #define LINUX 9 | 10 | #ifdef LINUX 11 | 12 | #define CONFIG_TARGET_LINUX 1 13 | #define CONFIG_CRT_PREFIX "/usr/lib64" 14 | #define CONFIG_LIBC_PREFIX "/usr/lib64" 15 | #define CONFIG_DYNAMIC_LINKER "/lib64/ld-linux-x86-64.so.2" 16 | 17 | // #define CONFIG_CRT_PREFIX "/usr/lib/x86_64-linux-gnu" 18 | // #define CONFIG_LIBC_PREFIX "/usr/lib/x86_64-linux-gnu" 19 | // #define CONFIG_DYNAMIC_LINKER "/lib64/ld-linux-x86-64.so.2" 20 | 21 | /* 22 | Other prefix: 23 | CONFIG_CRT_PREFIX "/usr/lib64" 24 | CONFIG_LIBC_PREFIX "/usr/lib64" 25 | CONFIG_LIBGCC_PREFIX: 26 | "/usr/lib/gcc/`gcc -dumpmachine`/`gcc -dumpversion|cut -d. -f1`" 27 | */ 28 | 29 | #elif defined DARWIN 30 | 31 | /* 32 | xcrun --show-sdk-path 33 | xcrun --show-sdk-version 34 | */ 35 | #define CONFIG_TARGET_DARWIN 1 36 | #define CONFIG_MACOS_INCLUDE_DIR "/Applications/Xcode.app/Contents/Developer/\ 37 | Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include" 38 | 39 | #else 40 | #error "unsupported platform" 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /elf.h: -------------------------------------------------------------------------------- 1 | #ifndef ELF_H 2 | #define ELF_H 3 | 4 | #include 5 | 6 | typedef uint64_t Elf64_Addr; 7 | typedef uint64_t Elf64_Off; 8 | typedef uint16_t Elf64_Half; 9 | typedef uint32_t Elf64_Word; 10 | typedef int32_t Elf64_Sword; 11 | typedef uint64_t Elf64_Xword; 12 | typedef int64_t Elf64_Sxword; 13 | 14 | #define EI_NIDENT 16 15 | 16 | typedef struct { 17 | unsigned char e_ident[EI_NIDENT]; /* ELF identification */ 18 | Elf64_Half e_type; /* Object file type */ 19 | Elf64_Half e_machine; /* Machine type */ 20 | Elf64_Word e_version; /* Object file version */ 21 | Elf64_Addr e_entry; /* Entry point address */ 22 | Elf64_Off e_phoff; /* Program header offset */ 23 | Elf64_Off e_shoff; /* Section Header offset */ 24 | Elf64_Word e_flags; /* Processor-specific flags */ 25 | Elf64_Half e_ehsize; /* ELF header size */ 26 | Elf64_Half e_phentsize; /* Size of program header entry */ 27 | Elf64_Half e_phnum; /* Number of program header entries */ 28 | Elf64_Half e_shentsize; /* Size of section header entry */ 29 | Elf64_Half e_shnum; /* Number of section header entries */ 30 | Elf64_Half e_shstrndx; /* Section name string table index */ 31 | } Elf64_Ehdr; 32 | 33 | /* e_ident index */ 34 | #define EI_MAG0 0 /* File identification */ 35 | #define EI_MAG1 1 36 | #define EI_MAG2 2 37 | #define EI_MAG3 3 38 | #define EI_CLASS 4 /* File class */ 39 | #define EI_DATA 5 /* Data encoding */ 40 | #define EI_VERSION 6 /* File version */ 41 | #define EI_OSABI 7 /* OS/ABI identification */ 42 | #define EI_ABIVERSION 8 /* ABI version */ 43 | #define EI_PAD 9 /* start of padding bytes */ 44 | 45 | /* e_ident[EI_CLASS] */ 46 | #define ELFCLASSNONE 0 /* Invalid class */ 47 | #define ELFCLASS32 1 /* 32-bit objects */ 48 | #define ELFCLASS64 2 /* 64-bit objects */ 49 | 50 | /* e_ident[EI_DATA] */ 51 | #define ELFDATANONE 0 /* Invalid data encoding */ 52 | #define ELFDATA2LSB 1 /* little-endian */ 53 | #define ELFDATA2MSB 2 /* big-endian */ 54 | 55 | /* e_ident[EI_OSABI] */ 56 | #define ELFOSABI_SYSV 0 /* System V ABI */ 57 | #define ELFOSABI_HPUX 1 /* HP-UX operating system */ 58 | #define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ 59 | 60 | /* e_ident[EI_VERSION] */ 61 | #define EV_NONE 0 /* Invalid version */ 62 | #define EV_CURRENT 1 /* Current version */ 63 | 64 | /* e_type */ 65 | #define ET_NONE 0 /* No file type */ 66 | #define ET_REL 1 /* Relocatable object file */ 67 | #define ET_EXEC 2 /* Executable file */ 68 | #define ET_DYN 3 /* Shared object file */ 69 | #define ET_CORE 4 /* Core file */ 70 | #define ET_LOSS 0xFE00 /* Environnment-specific use */ 71 | #define ET_HIOS 0xFEFF 72 | #define ET_LOPROC 0xFF00 /* Processor-specific use */ 73 | #define ET_HIPROC 0xFFFF 74 | 75 | /* e_machine */ 76 | #define EM_NONE 0 /* No machine */ 77 | #define EM_M32 1 /* AT&T WE 32100 */ 78 | #define EM_SPARC 2 /* SPARC */ 79 | #define EM_386 3 /* Intel 80386 */ 80 | #define EM_68K 4 /* Motorola 68000 */ 81 | #define EM_88K 5 /* Motorola 88000 */ 82 | #define EM_486 6 /* Intel 80486 */ 83 | #define EM_860 7 /* Intel 80860 */ 84 | #define EM_MIPS 8 /* MIPS RS3000 Big-Endian */ 85 | #define EM_S370 9 /* BM System/370 Processor */ 86 | #define EM_MIPS_RS4_BE 10 /* MIPS RS4000 Big-Endian */ 87 | #define EM_960 19 /* Intel 80960 */ 88 | #define EM_PPC 20 /* PowerPC */ 89 | #define EM_ARM 40 /* ARM 32-bit arch (AARCH32) */ 90 | #define EM_ALPHA 41 /* Digital Alpha */ 91 | #define EM_IA_64 50 /* Intel IA-64 */ 92 | #define EM_X86_64 62 /* AMD x86-64 arch */ 93 | #define EM_VAX 75 /* Digital VAX */ 94 | #define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ 95 | #define EM_AARCH64 183 /* ARM 64-bit arch (AARCH64) */ 96 | 97 | /* special section indices */ 98 | #define SHN_UNDEF 0 99 | #define SHN_LOPROC 0xFF00 /* Processor-specific use */ 100 | #define SHN_HIPROC 0xFF1F 101 | #define SHN_LOOS 0xFF20 /* Environment-specific use */ 102 | #define SHN_HIOS 0xFF3F 103 | #define SHN_ABS 0xFFF1 /* Absolute value */ 104 | #define SHN_COMMON 0xFFF2 /* Common block (C tentative declaration) */ 105 | 106 | /* section header entries */ 107 | typedef struct { 108 | Elf64_Word sh_name; /* Section name */ 109 | Elf64_Word sh_type; /* Section type */ 110 | Elf64_Xword sh_flags; /* Section attributes */ 111 | Elf64_Addr sh_addr; /* Virtual address in memory */ 112 | Elf64_Off sh_offset; /* Offset in file */ 113 | Elf64_Xword sh_size; /* Size of section */ 114 | Elf64_Word sh_link; /* Link to other section */ 115 | Elf64_Word sh_info; /* Misc innformation */ 116 | Elf64_Xword sh_addralign; /* Address alignment boundary */ 117 | Elf64_Xword sh_entsize; /* Size of entries, if section has table */ 118 | } Elf64_Shdr; 119 | 120 | /* sh_type */ 121 | #define SHT_NULL 0 /* Marks an unused section header */ 122 | #define SHT_PROGBITS 1 /* Info defined by the program */ 123 | #define SHT_SYMTAB 2 /* Linker symbol table */ 124 | #define SHT_STRTAB 3 /* String table */ 125 | #define SHT_RELA 4 /* "Rela" type relocation entries */ 126 | #define SHT_HASH 5 /* Symbol hash table */ 127 | #define SHT_DYNAMIC 6 /* Dynamic linking tables */ 128 | #define SHT_NOTE 7 /* Note info */ 129 | #define SHT_NOBITS 8 /* Uninitialized space */ 130 | #define SHT_REL 9 /* "Rel" type relocation entries */ 131 | #define SHT_SHLIB 10 /* Reserved */ 132 | #define SHT_DYNSYM 11 /* Dynamic loader symbol table */ 133 | #define SHT_LOOS 0x60000000 /* Environment-specific use */ 134 | #define SHT_HIOS 0x6FFFFFFF 135 | #define SHT_LOPROC 0x70000000 /* Processor-specific use */ 136 | #define SHT_HIPROC 0x7FFFFFFF 137 | 138 | /* sh_flags */ 139 | #define SHF_WRITE 0x1 /* Writable */ 140 | #define SHF_ALLOC 0x2 /* Allocated in memory */ 141 | #define SHF_EXECINSTR 0x4 /* Executable instructions */ 142 | #define SHF_MASKOS 0x0F000000 /* Environment-specific use */ 143 | #define SHF_MASKPROC 0xF0000000 /* Processor-specific use */ 144 | 145 | /* symbol table entry */ 146 | typedef struct { 147 | Elf64_Word st_name; /* Symbol name */ 148 | unsigned char st_info; /* Type and Binding attributes */ 149 | unsigned char st_other; /* Reserved */ 150 | Elf64_Half st_shndx; /* Section table index */ 151 | Elf64_Addr st_value; /* Symbol value */ 152 | Elf64_Xword st_size; /* Size of object */ 153 | } Elf64_Sym; 154 | 155 | /* st_info */ 156 | #define ELF64_ST_BIND(info) ((info) >> 4) 157 | #define ELF64_ST_TYPE(info) ((info) & 0xF) 158 | #define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xF)) 159 | 160 | /* symbol bindings (high-order four bits of st_info) */ 161 | #define STB_LOCAL 0 /* Not visible outside the object file */ 162 | #define STB_GLOBAL 1 /* Global symbol, visible to all object files */ 163 | #define STB_WEAK 2 /* Global scope with lower precedence than global symbols */ 164 | #define STB_LOOS 10 /* Environment-specific use */ 165 | #define STB_HIOS 12 166 | #define STB_LOPROC 13 /* Processor-specific use */ 167 | #define STB_HIPROC 15 168 | 169 | /* symbol types (low-order four bits of st_info) */ 170 | #define STT_NOTYPE 0 /* No type */ 171 | #define STT_OBJECT 1 /* Data object */ 172 | #define STT_FUNC 2 /* Function entry point */ 173 | #define STT_SECTION 3 /* Symbol is associated with a section */ 174 | #define STT_FILE 4 /* Source file associated with the object file */ 175 | #define STT_LOSS 10 /* Environment-specific use */ 176 | #define STT_HIOS 12 177 | #define STT_LOPROC 13 /* Processor-specific use */ 178 | #define STT_HIPROC 15 179 | 180 | /* 386 relocation types */ 181 | #define R_386_NONE 0 /* none */ 182 | #define R_386_32 1 /* word32: S+A */ 183 | #define R_386_PC32 2 /* word32: S+A-P */ 184 | #define R_386_GOT32 3 /* word32: G+A-P */ 185 | #define R_386_PLT32 4 /* word32: L+A-P */ 186 | #define R_386_COPY 5 /* none */ 187 | #define R_386_GLOB_DAT 6 /* word32: S */ 188 | #define R_386_JMP_SLOT 7 /* word32: S */ 189 | #define R_386_RELATIVE 8 /* word32: B+A */ 190 | #define R_386_GOTOFF 9 /* word32: S+A-GOT */ 191 | #define R_386_GOTPC 10 /* word32: GOT+A-P */ 192 | 193 | /* AMD x86-64 relocations. */ 194 | #define R_X86_64_NONE 0 /* No reloc */ 195 | #define R_X86_64_64 1 /* Direct 64 bit */ 196 | #define R_X86_64_PC32 2 /* PC relative 32 bit signed */ 197 | #define R_X86_64_GOT32 3 /* 32 bit GOT entry */ 198 | #define R_X86_64_PLT32 4 /* 32 bit PLT address */ 199 | #define R_X86_64_COPY 5 /* Copy symbol at runtime */ 200 | #define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ 201 | #define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ 202 | #define R_X86_64_RELATIVE 8 /* Adjust by program base */ 203 | #define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative offset to GOT */ 204 | #define R_X86_64_32 10 /* Direct 32 bit zero extended */ 205 | #define R_X86_64_32S 11 /* Direct 32 bit sign extended */ 206 | #define R_X86_64_16 12 /* Direct 16 bit zero extended */ 207 | #define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ 208 | #define R_X86_64_8 14 /* Direct 8 bit sign extended */ 209 | #define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ 210 | #define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ 211 | #define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ 212 | #define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ 213 | #define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset to \ 214 | two GOT entries for GD symbol */ 215 | #define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset to \ 216 | two GOT entries for LD symbol */ 217 | #define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ 218 | #define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset to \ 219 | GOT entry for IE symbol */ 220 | #define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ 221 | #define R_X86_64_PC64 24 /* PC relative 64 bit */ 222 | #define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ 223 | #define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative offset to GOT */ 224 | #define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ 225 | #define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset to GOT entry */ 226 | #define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ 227 | #define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ 228 | #define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset to PLT entry */ 229 | #define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ 230 | #define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ 231 | #define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ 232 | #define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS descriptor. */ 233 | #define R_X86_64_TLSDESC 36 /* TLS descriptor. */ 234 | #define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ 235 | #define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ 236 | /* 39 Reserved was R_X86_64_PC32_BND */ 237 | /* 40 Reserved was R_X86_64_PLT32_BND */ 238 | #define R_X86_64_GOTPCRELX 41 /* Load from 32 bit signed pc relative offset \ 239 | to GOT entry without REX prefix, relaxable. */ 240 | #define R_X86_64_REX_GOTPCRELX 42 /* Load from 32 bit signed pc relative offset \ 241 | to GOT entry with REX prefix, relaxable. */ 242 | #define R_X86_64_NUM 43 243 | 244 | /* "Rel" relocation */ 245 | typedef struct { 246 | Elf64_Addr r_offset; /* Address of reference */ 247 | Elf64_Xword r_info; /* Symbol index and type of relocation */ 248 | } Elf64_Rel; 249 | 250 | /* "Rela" relocation */ 251 | typedef struct { 252 | Elf64_Addr r_offset; /* Address of reference */ 253 | Elf64_Xword r_info; /* Symbol index and type of relocation */ 254 | Elf64_Sxword r_addend; /* Constant part of expression */ 255 | } Elf64_Rela; 256 | 257 | /* r_info */ 258 | #define ELF64_R_SYM(i) ((i) >> 32) 259 | #define ELF64_R_TYPE(i) ((i) & 0xFFFFFFFFL) 260 | #define ELF64_R_INFO(s, t) (((s) << 32) + ((t) & 0xFFFFFFFFL)) 261 | 262 | typedef struct { 263 | Elf64_Word p_type; /* Type of segment */ 264 | Elf64_Word p_flags; /* Segment attributes */ 265 | Elf64_Off p_offset; /* Offset in file */ 266 | Elf64_Addr p_vaddr; /* Virtual address in memory */ 267 | Elf64_Addr p_paddr; /* Reserved */ 268 | Elf64_Xword p_filesz; /* Size of segment in file */ 269 | Elf64_Xword p_memsz; /* Size of segment in memory */ 270 | Elf64_Xword p_align; /* Alignment of segment */ 271 | } Elf64_Phdr; 272 | 273 | /* p_type */ 274 | #define PT_NULL 0 /* Unused entry */ 275 | #define PT_LOAD 1 /* Loadable segment */ 276 | #define PT_DYNAMIC 2 /* Dynamic linking tables */ 277 | #define PT_INTERP 3 /* Program interpreter path name */ 278 | #define PT_NOTE 4 /* Note sections */ 279 | #define PT_SHLIB 5 /* Reserved */ 280 | #define PT_PHDR 6 /* Program header table */ 281 | #define PT_LOOS 0x60000000 /* Environment-specific use */ 282 | #define PT_HIOS 0x6FFFFFFF 283 | #define PT_LOPROC 0x70000000 /* Processor-specific use */ 284 | #define PT_HIPROC 0x7FFFFFFF 285 | 286 | /* p_flags */ 287 | #define PF_X 0x1 /* Execute permission */ 288 | #define PF_W 0x2 /* Write permission */ 289 | #define PF_R 0x4 /* Read permission */ 290 | #define PF_MASKOS 0x00FF0000 /* Environment-specific use */ 291 | #define PF_MASKPROC 0xFF000000 /* Processor-specific use */ 292 | 293 | /* dynamic */ 294 | typedef struct { 295 | Elf64_Sxword d_tag; /* dynamic table entry type */ 296 | union { 297 | Elf64_Xword d_val; 298 | Elf64_Addr d_ptr; 299 | } d_un; 300 | } Elf64_Dyn; 301 | 302 | /* d_tag */ 303 | #define DT_NULL 0 /* Mask the end of the dynamic entry */ 304 | #define DT_NEEDED 1 305 | #define DT_PLTRELSZ 2 306 | #define DT_PLTGOT 3 307 | #define DT_HASH 4 /* Address of the symbol hash table */ 308 | #define DT_STRTAB 5 309 | #define DT_SYMTAB 6 310 | #define DT_RELA 7 311 | #define DT_RELASZ 8 312 | #define DT_RELAENT 9 313 | #define DT_STRSZ 10 314 | #define DT_SYMENT 11 315 | #define DT_INIT 12 /* Address of the initialization function */ 316 | #define DT_FINI 13 /* Address of the termination function */ 317 | #define DT_SONAME 14 318 | #define DT_RPATH 15 319 | #define DT_SYMBOLIC 16 320 | #define DT_REL 17 321 | #define DT_RELSZ 18 322 | #define DT_RELENT 19 323 | #define DT_PLTREL 20 324 | #define DT_DEBUG 21 325 | #define DT_TEXTREL 22 326 | #define DT_JMPREL 23 327 | #define DT_BIND_NOW 24 328 | #define DT_INIT_ARRAY 25 329 | #define DT_FINI_ARRAY 26 330 | #define DT_INIT_ARRAYSZ 27 331 | #define DT_FINI_ARRAYSZ 28 332 | #define DT_LOOS 0x60000000 333 | #define DT_HIOS 0x6FFFFFFF 334 | #define DT_LOPROC 0x70000000 335 | #define DT_HIPROC 0x7FFFFFFF 336 | 337 | #endif /* ELF_H */ -------------------------------------------------------------------------------- /fmt.c: -------------------------------------------------------------------------------- 1 | #include "cc.h" 2 | 3 | #define MAX_FMT 64 4 | static int badconv(struct fmt *); 5 | 6 | struct convfmt { 7 | int c; 8 | int (*fmt)(struct fmt *); 9 | }; 10 | static struct { 11 | int nfmt; 12 | struct convfmt fmt[MAX_FMT]; 13 | } fmtalloc; 14 | 15 | int fmtinstall(int c, int (*fp)(struct fmt *)) 16 | { 17 | struct convfmt *p, *q; 18 | 19 | if (c <= 0 || c >= 256) 20 | return -1; 21 | if (!fp) 22 | fp = badconv; 23 | 24 | q = &fmtalloc.fmt[fmtalloc.nfmt]; 25 | for (p = fmtalloc.fmt; p < q; p++) 26 | if (p->c == c) 27 | break; 28 | 29 | if (p == &fmtalloc.fmt[MAX_FMT]) 30 | return -1; 31 | 32 | p->fmt = fp; 33 | if (p == q) { 34 | fmtalloc.nfmt++; 35 | p->c = c; 36 | } 37 | 38 | return 0; 39 | } 40 | 41 | static int fmtflush(struct fmt *fp) 42 | { 43 | if (fp->stream) { 44 | for (char *p = fp->start; p < fp->to; p++) 45 | fputc(*p, fp->stream); 46 | 47 | fp->nfmt += fp->to - fp->start; 48 | fp->to = fp->start; 49 | } 50 | return 0; 51 | } 52 | 53 | static int fmtputc(struct fmt *fp, int c) 54 | { 55 | if (fp->to < fp->stop) { 56 | *fp->to = c; 57 | ++fp->to; 58 | } 59 | if (fp->to == fp->stop) 60 | return fmtflush(fp); 61 | return 0; 62 | } 63 | 64 | static int fmtputs(struct fmt *fp, const char *s) 65 | { 66 | if (!s) 67 | return -1; 68 | for (int c; (c = *s); s++) { 69 | if (fp->to < fp->stop) { 70 | *fp->to = c; 71 | ++fp->to; 72 | } 73 | if (fp->to == fp->stop) 74 | fmtflush(fp); 75 | } 76 | return 0; 77 | } 78 | 79 | static int badconv(struct fmt *fp) 80 | { 81 | return fmtputc(fp, fp->c); 82 | } 83 | 84 | static int dofmt(struct fmt *fp, const char *fmt) 85 | { 86 | struct convfmt *p, *q; 87 | char buf[256], *str; 88 | int nfmt = fp->nfmt; 89 | 90 | q = &fmtalloc.fmt[fmtalloc.nfmt]; 91 | for (; *fmt; fmt++) { 92 | if (*fmt != '%') { 93 | fmtputc(fp, *fmt); 94 | continue; 95 | } 96 | 97 | int c = *++fmt; 98 | for (p = fmtalloc.fmt; p < q; p++) 99 | if (p->c == c) 100 | break; 101 | 102 | if (p < q) { 103 | fp->c = c; 104 | p->fmt(fp); 105 | continue; 106 | } 107 | 108 | switch (c) { 109 | case 'c': 110 | snprintf(buf, sizeof(buf), "%c", va_arg(fp->args, int)); 111 | break; 112 | case 'd': 113 | case 'i': 114 | snprintf(buf, sizeof(buf), "%d", va_arg(fp->args, int)); 115 | break; 116 | case 'u': 117 | snprintf(buf, sizeof(buf), "%u", va_arg(fp->args, unsigned int)); 118 | break; 119 | case 'x': 120 | snprintf(buf, sizeof(buf), "%x", va_arg(fp->args, int)); 121 | break; 122 | case 'X': 123 | snprintf(buf, sizeof(buf), "%X", va_arg(fp->args, int)); 124 | break; 125 | case 'o': 126 | snprintf(buf, sizeof(buf), "%o", va_arg(fp->args, int)); 127 | break; 128 | case 's': 129 | str = va_arg(fp->args, char *); 130 | fmtputs(fp, str); 131 | buf[0] = '\0'; 132 | break; 133 | case 'p': 134 | snprintf(buf, sizeof(buf), "%p", va_arg(fp->args, void *)); 135 | break; 136 | case 'f': 137 | snprintf(buf, sizeof(buf), "%f", va_arg(fp->args, double)); 138 | break; 139 | case 'l': 140 | if (fmt[1] == 'd') { 141 | fmt++; 142 | snprintf(buf, sizeof(buf), "%ld", va_arg(fp->args, long)); 143 | } else if (fmt[1] == 'u') { 144 | fmt++; 145 | snprintf(buf, sizeof(buf), "%lu", va_arg(fp->args, unsigned long)); 146 | } else if (fmt[1] == 'x') { 147 | fmt++; 148 | snprintf(buf, sizeof(buf), "%lx", va_arg(fp->args, long)); 149 | } else if (fmt[1] == 'X') { 150 | fmt++; 151 | snprintf(buf, sizeof(buf), "%lX", va_arg(fp->args, long)); 152 | } else if (fmt[1] == 'l' && fmt[2] == 'd') { 153 | fmt += 2; 154 | snprintf(buf, sizeof(buf), "%lld", va_arg(fp->args, long long)); 155 | } else if (fmt[1] == 'l' && fmt[2] == 'u') { 156 | fmt += 2; 157 | snprintf(buf, sizeof(buf), "%llu", va_arg(fp->args, unsigned long long)); 158 | } else { 159 | snprintf(buf, sizeof(buf), "%c", *fmt); 160 | } 161 | break; 162 | case 'L': 163 | if (fmt[1] == 'f') { 164 | fmt++; 165 | snprintf(buf, sizeof(buf), "%Lf", va_arg(fp->args, long double)); 166 | } else { 167 | snprintf(buf, sizeof(buf), "%c", *fmt); 168 | } 169 | break; 170 | default: 171 | snprintf(buf, sizeof(buf), "%c", *fmt); 172 | break; 173 | } 174 | fmtputs(fp, buf); 175 | } 176 | fmtflush(fp); 177 | return fp->nfmt - nfmt; 178 | } 179 | 180 | int print(const char *fmt, ...) 181 | { 182 | va_list ap; 183 | int n; 184 | 185 | va_start(ap, fmt); 186 | n = vfprint(stdout, fmt, ap); 187 | va_end(ap); 188 | return n; 189 | } 190 | 191 | int vfprint(FILE *stream, const char *fmt, va_list ap) 192 | { 193 | struct fmt fp; 194 | char buf[256]; 195 | 196 | va_copy(fp.args, ap); 197 | fp.start = buf; 198 | fp.stop = buf + sizeof(buf); 199 | fp.to = buf; 200 | fp.stream = stream; 201 | fp.nfmt = 0; 202 | return dofmt(&fp, fmt); 203 | } 204 | 205 | int fprint(FILE *stream, const char *fmt, ...) 206 | { 207 | int n; 208 | va_list ap; 209 | 210 | va_start(ap, fmt); 211 | n = vfprint(stream, fmt, ap); 212 | va_end(ap); 213 | return n; 214 | } 215 | 216 | int vsnprint(char *buf, size_t size, const char *fmt, va_list ap) 217 | { 218 | struct fmt fp; 219 | 220 | if (size <= 0) 221 | return -1; 222 | va_copy(fp.args, ap); 223 | fp.start = buf; 224 | fp.stop = buf + size - 1; 225 | fp.to = buf; 226 | fp.stream = NULL; 227 | fp.nfmt = 0; 228 | dofmt(&fp, fmt); 229 | *fp.to = '\0'; 230 | return fp.to - buf; 231 | } 232 | 233 | int snprint(char *s, size_t size, const char *fmt, ...) 234 | { 235 | int n; 236 | va_list ap; 237 | 238 | va_start(ap, fmt); 239 | n = vsnprint(s, size, fmt, ap); 240 | va_end(ap); 241 | return n; 242 | } 243 | 244 | int fmtstrcpy(struct fmt *fp, const char *s) 245 | { 246 | int n; 247 | 248 | n = fmtputs(fp, s); 249 | if (n >= 0) 250 | return 0; 251 | return n; 252 | } 253 | 254 | int fmtprint(struct fmt *fp, const char *fmt, ...) 255 | { 256 | int n; 257 | va_list ap; 258 | 259 | va_copy(ap, fp->args); 260 | va_start(fp->args, fmt); 261 | n = dofmt(fp, fmt); 262 | va_end(fp->args); 263 | va_copy(fp->args, ap); 264 | if (n >= 0) 265 | return 0; 266 | return n; 267 | } 268 | -------------------------------------------------------------------------------- /gen.c: -------------------------------------------------------------------------------- 1 | #include "cc.h" 2 | 3 | struct cse { 4 | int lab; 5 | long value; 6 | }; 7 | 8 | struct swtch { 9 | struct type *type; 10 | struct cse *cases; 11 | int cases_used; 12 | int cases_alloc; 13 | int default_lab; 14 | }; 15 | 16 | static int brk; 17 | static int cnt; 18 | static struct swtch *swtch; 19 | 20 | int genlab(int count) 21 | { 22 | static int lab = 1; 23 | 24 | assert(count > 0); 25 | lab += count; 26 | return lab - count; 27 | } 28 | 29 | static void nodconst(struct node *p, struct type *ty, long val) 30 | { 31 | p->op = OCONST; 32 | p->type = ty; 33 | p->v.i = convltox(val, ty->etype); 34 | p->left = NULL; 35 | p->right = NULL; 36 | } 37 | 38 | static void freeswtch(struct swtch *p) 39 | { 40 | free(p->cases); 41 | free(p); 42 | } 43 | 44 | static struct swtch *newswtch(void) 45 | { 46 | return zmalloc(sizeof (struct swtch)); 47 | } 48 | 49 | static void addcase(struct swtch *s, struct node *p, int lab) 50 | { 51 | int i; 52 | struct cse *c; 53 | 54 | for (i = 0; i < s->cases_used; i++) { 55 | c = &s->cases[i]; 56 | if (c->value == p->v.i) 57 | error(p, "case '%ld' redeclared", p->v.i); 58 | } 59 | 60 | if (s->cases_used + 1 > s->cases_alloc) { 61 | s->cases_alloc = 2 * s->cases_used + 10; 62 | s->cases = xrealloc(s->cases, s->cases_alloc * sizeof (struct cse)); 63 | } 64 | 65 | c = &s->cases[s->cases_used++]; 66 | c->lab = lab; 67 | c->value = p->v.i; 68 | } 69 | 70 | static void boolgen(struct node *p, int lab, int invert) 71 | { 72 | int c; 73 | 74 | if (p == NULL) 75 | goto c_true; /* treated as true */ 76 | 77 | conv(p); 78 | if (p->type == NULL) 79 | goto c_false; 80 | if (tcompat(p, NULL, p->type, tnot)) { 81 | p->type = NULL; 82 | goto c_false; 83 | } 84 | c = vbconst(p); 85 | if (c == 0) 86 | goto c_false; 87 | if (c == 1) 88 | goto c_true; 89 | 90 | gtest(p, lab, invert); 91 | return; 92 | 93 | c_true: 94 | if (!invert) 95 | gbranch(OGOTO, lab, 0); 96 | return; 97 | 98 | c_false: 99 | if (invert) 100 | gbranch(OGOTO, lab, 0); 101 | } 102 | 103 | /** 104 | we can't eliminate such code now before running at least one pass. 105 | 106 | if (0) { 107 | label: 108 | printf("maybe reachable even inside if-false statement"); 109 | } 110 | 111 | goto label; 112 | */ 113 | static void gen(struct node *p) 114 | { 115 | struct node nod, nod1, nod2; 116 | struct node *l, *r; 117 | int i, lab, sbrk, scnt; 118 | struct swtch *sswtch; 119 | struct cse *cse; 120 | 121 | loop: 122 | if (p == NULL) 123 | return; 124 | 125 | switch (p->op) { 126 | case OLIST: 127 | case OCOMMA: 128 | gen(p->left); 129 | p = p->right; 130 | goto loop; 131 | 132 | case OIF: 133 | lab = genlab(2); 134 | boolgen(p->left, lab, 1); 135 | gen(p->right->left); 136 | if (p->right->right) { 137 | gbranch(OGOTO, lab + 1, 0); 138 | glabel(lab); 139 | gen(p->right->right); 140 | glabel(lab + 1); 141 | } else { 142 | glabel(lab); 143 | } 144 | break; 145 | 146 | case OWHILE: 147 | lab = genlab(2); 148 | sbrk = brk; 149 | scnt = cnt; 150 | cnt = lab; 151 | brk = lab + 1; 152 | glabel(lab); 153 | boolgen(p->left, lab + 1, 1); 154 | gen(p->right); 155 | gbranch(OGOTO, lab, 0); 156 | glabel(lab + 1); 157 | brk = sbrk; 158 | cnt = scnt; 159 | break; 160 | 161 | case ODOWHILE: 162 | lab = genlab(3); 163 | sbrk = brk; 164 | scnt = cnt; 165 | cnt = lab + 1; 166 | brk = lab + 2; 167 | glabel(lab); 168 | gen(p->right); 169 | glabel(lab + 1); 170 | boolgen(p->left, lab, 0); 171 | glabel(lab + 2); 172 | brk = sbrk; 173 | cnt = scnt; 174 | break; 175 | 176 | case OFOR: 177 | lab = genlab(3); 178 | scnt = cnt; 179 | sbrk = brk; 180 | cnt = lab + 1; 181 | brk = lab + 2; 182 | gen(p->left->left); 183 | l = p->left->right; 184 | glabel(lab); 185 | boolgen(l->left, lab + 2, 1); 186 | gen(p->right); 187 | glabel(lab + 1); 188 | gen(l->right); 189 | gbranch(OGOTO, lab, 0); 190 | glabel(lab + 2); 191 | cnt = scnt; 192 | brk = sbrk; 193 | break; 194 | 195 | case OSWITCH: 196 | l = p->left; 197 | conv(l); 198 | if (l->type == NULL) 199 | break; 200 | if (!typei[l->type->etype]) { 201 | error(l, "switch expression must have integer type"); 202 | break; 203 | } 204 | if (l->type->size < types[TINT]->size) { 205 | if (l->op != OCONST) { 206 | r = node(OXXX, NULL, NULL); 207 | *r = *l; 208 | l->op = OCAST; 209 | l->left = r; 210 | l->right = NULL; 211 | l->addable = 0; 212 | } 213 | l->type = types[TINT]; 214 | } 215 | sswtch = swtch; 216 | swtch = newswtch(); 217 | swtch->type = l->type; 218 | lab = genlab(2); 219 | sbrk = brk; 220 | brk = lab + 1; 221 | /* free the register to prevent corruption in cases */ 222 | if (l->op != OCONST) { 223 | regalloc(&nod, l, NULL); 224 | gexpr(l, &nod); 225 | regfree(&nod); 226 | } 227 | gbranch(OGOTO, lab, 0); 228 | gen(p->right); 229 | gbranch(OGOTO, lab + 1, 0); 230 | glabel(lab); 231 | /* switch code */ 232 | for (i = 0; i < swtch->cases_used; i++) { 233 | cse = &swtch->cases[i]; 234 | if (l->op == OCONST) { 235 | if (l->v.i == cse->value) { 236 | gbranch(OGOTO, cse->lab, 0); 237 | break; 238 | } 239 | } else { 240 | nodconst(&nod1, swtch->type, cse->value); 241 | nodnew(&nod2, OEQ, &nod, &nod1); 242 | nod2.type = types[TINT]; 243 | gtest(&nod2, cse->lab, 0); 244 | } 245 | } 246 | if (swtch->default_lab) 247 | gbranch(OGOTO, swtch->default_lab, 0); 248 | glabel(lab + 1); 249 | freeswtch(swtch); 250 | brk = sbrk; 251 | swtch = sswtch; 252 | break; 253 | 254 | case OCASE: 255 | if (swtch == NULL) { 256 | error(p, "'case' not in switch statement"); 257 | break; 258 | } 259 | lab = genlab(1); 260 | l = p->left; 261 | if (l) { 262 | conv(l); 263 | if (l->type == NULL) 264 | break; 265 | if (!typei[l->type->etype]) { 266 | error(l, "'case' expression must have integer type"); 267 | break; 268 | } 269 | if (l->op != OCONST) { 270 | error(l, "'case' expression must be a constant"); 271 | break; 272 | } 273 | l->v.i = convltox(l->v.i, swtch->type->etype); 274 | addcase(swtch, l, lab); 275 | } else { 276 | if (swtch->default_lab) 277 | error(l, "label 'default' redeclared"); 278 | swtch->default_lab = lab; 279 | } 280 | glabel(lab); 281 | gen(p->right); 282 | break; 283 | 284 | case OLABEL: 285 | if (p->left->label == 0) 286 | p->left->label = genlab(1); 287 | glabel(p->left->label); 288 | gen(p->right); 289 | break; 290 | 291 | case OGOTO: 292 | l = p->left; 293 | if (l == NULL) 294 | break; 295 | if (l->complex == 0) { 296 | error(l, "label '%s' not declared", l->sym->name); 297 | break; 298 | } 299 | if (l->label == 0) 300 | l->label = genlab(1); 301 | gbranch(OGOTO, l->label, 0); 302 | break; 303 | 304 | case OBREAK: 305 | if (brk == 0) { 306 | error(p, "'break' not in a loop or switch statement"); 307 | break; 308 | } 309 | gbranch(OGOTO, brk, 0); 310 | break; 311 | 312 | case OCONTINUE: 313 | if (cnt == 0) { 314 | error(p, "'continue' not in a loop statement"); 315 | break; 316 | } 317 | gbranch(OGOTO, cnt, 0); 318 | break; 319 | 320 | case ORETURN: 321 | l = p->left; 322 | if (p->type->etype == TVOID) { 323 | /* return cast to void is allowed. */ 324 | if (l) { 325 | conv(l); 326 | if (l->type && l->type->etype != TVOID) 327 | error(l, "return non-void value in void function"); 328 | gexpr(l, NULL); 329 | } 330 | } else { 331 | if (l == NULL) { 332 | error(p, "missing returning value"); 333 | goto gret; 334 | } 335 | l = node(OCAST, l, NULL); 336 | l->type = p->type; 337 | conv(l); 338 | greturn(l); 339 | } 340 | gret: 341 | gbranch(ORETURN, 0, 0); 342 | break; 343 | 344 | default: 345 | conv(p); 346 | gexpr(p, NULL); 347 | break; 348 | } 349 | } 350 | 351 | void codegen(struct node *p, struct node *fn, struct node *params) 352 | { 353 | brk = 0; 354 | cnt = 0; 355 | swtch = NULL; 356 | gen(p); 357 | } -------------------------------------------------------------------------------- /include/float.h: -------------------------------------------------------------------------------- 1 | #ifndef _FLOAT_H 2 | #define _FLOAT_H 3 | 4 | /** 5 | * | sign | exponent | fraction | total bits | exponent bias | 6 | * float: 1 8 23 32 127 7 | * double: 1 11 52 64 1023 8 | * long double: 1 15 64 80 16383 9 | */ 10 | 11 | #define DECIMAL_DIG 21 12 | #define FLT_ROUNDS 1 13 | #define FLT_RADIX 2 14 | #define FLT_EVAL_METHOD 0 15 | 16 | #define FLT_DIG 6 17 | #define FLT_EPSILON 1.19209290e-7F 18 | #define FLT_MANT_DIG 24 19 | #define FLT_MIN 1.17549435e-38F 20 | #define FLT_MIN_EXP -125 21 | #define FLT_MIN_10_EXP -37 22 | #define FLT_MAX 3.40282347e+38F 23 | #define FLT_MAX_EXP 128 24 | #define FLT_MAX_10_EXP 38 25 | 26 | #define DBL_DIG 15 27 | #define DBL_EPSILON 2.2204460492503131e-16 28 | #define DBL_MANT_DIG 53 29 | #define DBL_MIN 2.2250738585072014e-308 30 | #define DBL_MIN_EXP -1021 31 | #define DBL_MIN_10_EXP -307 32 | #define DBL_MAX 1.7976931348623157e+308 33 | #define DBL_MAX_EXP 1024 34 | #define DBL_MAX_10_EXP 308 35 | 36 | #define LDBL_DIG DBL_DIG 37 | #define LDBL_EPSILON DBL_EPSILON 38 | #define LDBL_MANT_DIG DBL_MANT_DIG 39 | #define LDBL_MIN DBL_MIN 40 | #define LDBL_MIN_EXP DBL_MIN_EXP 41 | #define LDBL_MIN_10_EXP DBL_MIN_10_EXP 42 | #define LDBL_MAX DBL_MAX 43 | #define LDBL_MAX_EXP DBL_MAX_EXP 44 | #define LDBL_MAX_10_EXP DBL_MAX_10_EXP 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /include/iso646.h: -------------------------------------------------------------------------------- 1 | #ifndef _ISO646_H 2 | #define _ISO646_H 3 | 4 | #define and && 5 | #define and_eq &= 6 | #define bitand & 7 | #define bitor | 8 | #define compl ~ 9 | #define not ! 10 | #define not_eq != 11 | #define or || 12 | #define or_eq |= 13 | #define xor ^ 14 | #define xor_eq ^= 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/limits.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIMITS_H 2 | #define _LIMITS_H 3 | 4 | #define CHAR_BIT 8 5 | 6 | #define SCHAR_MIN (-127-1) 7 | #define SCHAR_MAX 127 8 | #define UCHAR_MAX 255 9 | 10 | #define SHRT_MIN (-32767-1) 11 | #define SHRT_MAX 32767 12 | #define USHRT_MAX 65535 13 | 14 | #define INT_MIN (-2147483647-1) 15 | #define INT_MAX 2147483647 16 | #define UINT_MAX 4294967295U 17 | 18 | #define LONG_MIN (-9223372036854775807L-1L) 19 | #define LONG_MAX 9223372036854775807L 20 | #define ULONG_MAX 18446744073709551615UL 21 | 22 | #define LLONG_MIN (-9223372036854775807LL-1LL) 23 | #define LLONG_MAX 9223372036854775807LL 24 | #define ULLONG_MAX 18446744073709551615ULL 25 | 26 | #define CHAR_MIN (-127-1) 27 | #define CHAR_MAX 127 28 | 29 | #define MB_LEN_MAX 6 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDARG_H 2 | #define _STDARG_H 3 | 4 | #ifndef _VA_LIST 5 | typedef __builtin_va_list va_list; 6 | #define _VA_LIST 7 | #endif 8 | 9 | #define va_start(ap, param) __builtin_va_start(ap, param) 10 | #define va_end(ap) __builtin_va_end(ap) 11 | #define va_arg(ap, type) __builtin_va_arg(ap, type) 12 | #define va_copy(dest, src) __builtin_va_copy(dest, src) 13 | 14 | // GNU 15 | #define __va_copy(d, s) __builtin_va_copy(d, s) 16 | 17 | #ifndef __GNUC_VA_LIST 18 | #define __GNUC_VA_LIST 1 19 | #endif 20 | typedef __builtin_va_list __gnuc_va_list; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDBOOL_H 2 | #define _STDBOOL_H 3 | 4 | #define bool _Bool 5 | #define true 1 6 | #define false 0 7 | #define __bool_true_false_are_defined 1 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDDEF_H 2 | #define _STDDEF_H 3 | 4 | #define NULL ((void *)0) 5 | 6 | typedef __PTRDIFF_TYPE__ ptrdiff_t; 7 | typedef __SIZE_TYPE__ size_t; 8 | typedef __WCHAR_TYPE__ wchar_t; 9 | 10 | #define offsetof(type, member) ((size_t)&((type *)0)->member) 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /liberty.c: -------------------------------------------------------------------------------- 1 | #include "compat.h" 2 | #include "liberty.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | __noreturn void die_errno(const char *fmt, ...) 9 | { 10 | va_list ap; 11 | va_start(ap, fmt); 12 | fputs("error: ", stderr); 13 | vfprintf(stderr, fmt, ap); 14 | fprintf(stderr, ": %s\n", strerror(errno)); 15 | va_end(ap); 16 | exit(EXIT_FAILURE); 17 | } 18 | 19 | __noreturn void die(const char *fmt, ...) 20 | { 21 | va_list ap; 22 | va_start(ap, fmt); 23 | fputs("error: ", stderr); 24 | vfprintf(stderr, fmt, ap); 25 | fputs("\n", stderr); 26 | va_end(ap); 27 | exit(EXIT_FAILURE); 28 | } 29 | 30 | void *xmalloc(size_t size) 31 | { 32 | void *p = malloc(size); 33 | if (!p) 34 | die("memory exhausted"); 35 | return p; 36 | } 37 | 38 | void *zmalloc(size_t size) 39 | { 40 | return memset(xmalloc(size), 0, size); 41 | } 42 | 43 | void *xcalloc(size_t count, size_t size) 44 | { 45 | void *p = calloc(count, size); 46 | if (!p) 47 | die("memory exhausted"); 48 | return p; 49 | } 50 | 51 | void *xrealloc(void *ptr, size_t size) 52 | { 53 | void *p = realloc(ptr, size); 54 | if (!p) 55 | die("memory exhausted"); 56 | return p; 57 | } 58 | 59 | /* alloc */ 60 | 61 | union align { 62 | long l; 63 | double d; 64 | void (*f)(void); 65 | }; 66 | 67 | struct bucket { 68 | struct bucket *next; 69 | char *cur; 70 | char *limit; 71 | }; 72 | 73 | union header { 74 | struct bucket b; 75 | union align a; 76 | }; 77 | 78 | static struct bucket first[] = { { NULL }, { NULL } }; 79 | static struct bucket *area[] = { &first[0], &first[1] }; 80 | static struct bucket *freebuckets; 81 | 82 | void *allocate(size_t n, enum allocate_area a) 83 | { 84 | struct bucket *p; 85 | assert(a >= 0 && a < NELEMS(area)); 86 | 87 | p = area[a]; 88 | n = ROUNDUP(n, sizeof(union align)); 89 | while (n > p->limit - p->cur) { 90 | if ((p->next = freebuckets) != NULL) { 91 | freebuckets = freebuckets->next; 92 | p = p->next; 93 | } else { 94 | size_t m = sizeof(union header) + n + 95 | ROUNDUP(10 * 1024, sizeof(union align)); 96 | p->next = xmalloc(m); 97 | p = p->next; 98 | p->limit = (char *)p + m; 99 | } 100 | 101 | p->cur = (char *)((union header *)p + 1); 102 | p->next = NULL; 103 | area[a] = p; 104 | } 105 | 106 | p->cur += n; 107 | return p->cur - n; 108 | } 109 | 110 | void *zallocate(size_t n, enum allocate_area a) 111 | { 112 | return memset(allocate(n, a), 0, n); 113 | } 114 | 115 | void deallocate(enum allocate_area a) 116 | { 117 | assert(a >= 0 && a < NELEMS(area)); 118 | area[a]->next = freebuckets; 119 | freebuckets = first[a].next; 120 | first[a].next = NULL; 121 | area[a] = &first[a]; 122 | } 123 | 124 | int file_exist(const char *path) 125 | { 126 | struct stat st; 127 | return stat(path, &st) == 0; 128 | } 129 | 130 | size_t file_size(const char *path) 131 | { 132 | struct stat st; 133 | if (stat(path, &st) == 0) 134 | return st.st_size; 135 | return 0; 136 | } 137 | 138 | /* 139 | * return extension of a file (".c", ".s" etc.) 140 | * (if no extension, return pointer to end-of-string) 141 | */ 142 | char *file_ext(const char *file) 143 | { 144 | char *base = file_basename(file); 145 | char *dot = strrchr(base, '.'); 146 | return dot ? dot : strchr(base, 0); 147 | } 148 | 149 | /* 150 | * change extension of a file to `ext` 151 | * (if no extension, add `ext` to filename) 152 | */ 153 | char *ch_file_ext(const char *file, const char *ext) 154 | { 155 | char *path, *dot, *part; 156 | 157 | path = xmalloc(strlen(file) + strlen(ext) + 2); 158 | dot = file_ext(file); 159 | if (dot[0]) { 160 | part = strrchr(file, '.'); 161 | strncpy(path, file, part - file + 1); 162 | strcpy(path + (part - file + 1), ext); 163 | } else { 164 | strcpy(path, file); 165 | strcat(path, "."); 166 | strcat(path, ext); 167 | } 168 | return path; 169 | } 170 | 171 | char *fullpath(const char *path) 172 | { 173 | if (path == NULL) 174 | return NULL; 175 | 176 | if (path[0] == '~' && path[1] == '/') 177 | return joinpath(getenv("HOME"), path + 2); 178 | else 179 | return strdup(path); 180 | } 181 | 182 | char *joinpath(const char *dir, const char *name) 183 | { 184 | char *path; 185 | size_t len; 186 | 187 | if (dir == NULL || dir[0] == 0) 188 | return name ? strdup(name) : NULL; 189 | if (name == NULL || name[0] == 0) 190 | return dir ? strdup(dir) : NULL; 191 | 192 | if (name[0] == '/') 193 | return strdup(name); 194 | 195 | len = strlen(dir); 196 | path = xmalloc(len + strlen(name) + 2); 197 | strcpy(path, dir); 198 | if (path[len - 1] != '/') 199 | path[len++] = '/'; 200 | strcpy(path + len, name); 201 | return path; 202 | } 203 | 204 | char *file_basename(const char *name) 205 | { 206 | char *p = strchr(name, 0); 207 | while (p > name && !IS_DIRSEP(p[-1])) 208 | p--; 209 | return p; 210 | } 211 | 212 | char *file_dirname(const char *p) 213 | { 214 | return dirname(strdup(p)); 215 | } 216 | 217 | char *mktempfile(const char *suffix) 218 | { 219 | char buf[32]; 220 | int fd; 221 | 222 | if (suffix) 223 | snprintf(buf, sizeof(buf), "/tmp/XXXXXX.%s", suffix); 224 | else 225 | snprintf(buf, sizeof(buf), "/tmp/XXXXXX"); 226 | fd = mkstemps(buf, strlen(buf) - strlen("/tmp/XXXXXX")); 227 | if (fd < 0 || close(fd) < 0) 228 | die_errno("can't make temporary filename"); 229 | return strdup(buf); 230 | } 231 | 232 | #define STR_HASH_INIT 5381 233 | #define STR_HASH_STEP(h, c) (((h) << 5) + (h) + (c)) 234 | 235 | unsigned int strhash(const char *s) 236 | { 237 | unsigned int hash = STR_HASH_INIT; 238 | int c; 239 | 240 | while ((c = *s++)) 241 | hash = STR_HASH_STEP(hash, c); 242 | 243 | return hash; 244 | } 245 | 246 | unsigned int strnhash(const char *s, size_t len) 247 | { 248 | unsigned int hash = STR_HASH_INIT; 249 | 250 | for (const char *d = s + len; s < d; s++) 251 | hash = STR_HASH_STEP(hash, *s); 252 | 253 | return hash; 254 | } 255 | 256 | char *vstringf(const char *fmt, va_list ap) 257 | { 258 | char buf[BUFSIZ]; 259 | va_list ap2; 260 | int total; 261 | char *d; 262 | 263 | va_copy(ap2, ap); 264 | total = vsnprintf(buf, NELEMS(buf), fmt, ap); 265 | if (total >= NELEMS(buf)) { 266 | d = xmalloc(total + 8); 267 | if (vsnprintf(d, total + 8, fmt, ap2) > total) 268 | die("vstringf: how can this happend"); 269 | return d; 270 | } 271 | return strdup(buf); 272 | } 273 | 274 | char *stringf(const char *fmt, ...) 275 | { 276 | char *str; 277 | va_list ap; 278 | 279 | va_start(ap, fmt); 280 | str = vstringf(fmt, ap); 281 | va_end(ap); 282 | return str; 283 | } 284 | 285 | int strstart(const char *prefix, char **pstr) 286 | { 287 | char *str; 288 | size_t n; 289 | 290 | if (!prefix || !pstr || !(str = *pstr)) 291 | return 0; 292 | n = strlen(prefix); 293 | if (strncmp(str, prefix, n) != 0) 294 | return 0; 295 | *pstr = str + n; 296 | return 1; 297 | } 298 | 299 | /* for multi byte and wide char conversion. */ 300 | static void locale_init_once(void) 301 | { 302 | static int once; 303 | if (!once) { 304 | once = 1; 305 | setlocale(LC_ALL, ""); 306 | } 307 | } 308 | 309 | int mb2wc(wchar_t *wc, const char *s, size_t n) 310 | { 311 | locale_init_once(); 312 | return mbtowc(wc, s, n); 313 | } 314 | 315 | size_t mbs2wcs(wchar_t *pwcs, const char *s, size_t n) 316 | { 317 | locale_init_once(); 318 | return mbstowcs(pwcs, s, n); 319 | } 320 | 321 | int wc2mb(char *s, wchar_t wc) 322 | { 323 | locale_init_once(); 324 | return wctomb(s, wc); 325 | } 326 | 327 | size_t wcs2mbs(char *s, const wchar_t *pwcs, size_t n) 328 | { 329 | locale_init_once(); 330 | return wcstombs(s, pwcs, n); 331 | } 332 | 333 | /* strbuf */ 334 | 335 | static void strbuf_grow(struct strbuf *sb, size_t new_size) 336 | { 337 | size_t size = sb->alloc; 338 | 339 | if (size == 0) 340 | size = 12; /* maybe a small string */ 341 | while (size < new_size) 342 | size = size * 2; 343 | sb->str = xrealloc(sb->str, size); 344 | sb->alloc = size; 345 | } 346 | 347 | void strbuf_new(struct strbuf *sb) 348 | { 349 | memset(sb, 0, sizeof(struct strbuf)); 350 | } 351 | 352 | void strbuf_free(struct strbuf *sb) 353 | { 354 | free(sb->str); 355 | strbuf_new(sb); 356 | } 357 | 358 | void strbuf_reset(struct strbuf *sb) 359 | { 360 | sb->len = 0; 361 | } 362 | 363 | void strbuf_catc(struct strbuf *sb, int ch) 364 | { 365 | size_t size; 366 | 367 | size = sb->len + 1; 368 | if (size >= sb->alloc) 369 | strbuf_grow(sb, size); 370 | 371 | sb->str[sb->len] = ch; 372 | sb->len++; 373 | } 374 | 375 | void strbuf_catn(struct strbuf *sb, const char *str, size_t len) 376 | { 377 | while (len--) { 378 | int c = *str; 379 | strbuf_catc(sb, c); 380 | str++; 381 | } 382 | } 383 | 384 | void strbuf_cats(struct strbuf *sb, const char *str) 385 | { 386 | while (1) { 387 | int c = *str; 388 | if (c == '\0') 389 | break; 390 | strbuf_catc(sb, c); 391 | str++; 392 | } 393 | } 394 | 395 | void strbuf_catf(struct strbuf *sb, const char *fmt, ...) 396 | { 397 | char *str; 398 | va_list ap; 399 | 400 | va_start(ap, fmt); 401 | str = vstringf(fmt, ap); 402 | va_end(ap); 403 | strbuf_cats(sb, str); 404 | free(str); 405 | } 406 | 407 | /* list */ 408 | static struct list *freelists; 409 | 410 | void append(struct list **list, void *x) 411 | { 412 | struct list *new; 413 | struct list *old = *list; 414 | 415 | if ((new = freelists) != NULL) 416 | freelists = freelists->link; 417 | else 418 | new = xmalloc(sizeof(*list)); 419 | 420 | if (old) { 421 | new->link = old->link; 422 | old->link = new; 423 | } else { 424 | new->link = new; 425 | } 426 | new->x = x; 427 | *list = new; 428 | } 429 | 430 | size_t nlist(struct list *list) 431 | { 432 | size_t n = 0; 433 | 434 | if (list) { 435 | struct list *p = list; 436 | do 437 | n++; 438 | while ((p = p->link) != list); 439 | } 440 | 441 | return n; 442 | } 443 | 444 | void *ltoa(struct list **list) 445 | { 446 | int i = 0; 447 | void **array = xmalloc(sizeof(array[0]) * (nlist(*list) + 1)); 448 | 449 | if (*list) { 450 | struct list *p = *list; 451 | do { 452 | p = p->link; 453 | array[i++] = p->x; 454 | } while (p != *list); 455 | 456 | p = (*list)->link; 457 | (*list)->link = freelists; 458 | freelists = p; 459 | } 460 | 461 | *list = NULL; 462 | array[i] = NULL; 463 | return array; 464 | } 465 | 466 | size_t length(void *array) 467 | { 468 | size_t i; 469 | void **a; 470 | 471 | if (array == NULL) 472 | return 0; 473 | i = 0; 474 | a = (void **)array; 475 | while (a[i]) 476 | i++; 477 | return i; 478 | } -------------------------------------------------------------------------------- /liberty.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBERTY_H 2 | #define LIBERTY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #if __STDC_VERSION__ >= 201112L 13 | #define __noreturn _Noreturn 14 | #elif __GNUC__ >= 2 15 | #define __noreturn __attribute__((noreturn)) 16 | #else 17 | #define __noreturn 18 | #endif 19 | 20 | #define NELEMS(array) (sizeof(array) / sizeof((array)[0])) 21 | #define FIELD_SIZEOF(st, f) (sizeof(((st*)0)->f)) 22 | 23 | #define ALIGN_SIZE (sizeof (long)) 24 | #define ROUNDUP(x, align) (((x)+((align)-1))&(~((align)-1))) 25 | 26 | #define BYTES(bits) ((ROUNDUP(bits, 8)) / 8) 27 | 28 | #define MAX(x, y) (((x) > (y)) ? (x) : (y)) 29 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) 30 | 31 | #define SIGN(bits) (1UL << (bits-1)) 32 | #define MASK(bits) (SIGN(bits)|(SIGN(bits) - 1)) 33 | #define ONES(bytes) MASK(8*(bytes)) 34 | 35 | #define IS_DIRSEP(c) ((c) == '/') 36 | 37 | extern __noreturn void die_errno(const char *, ...); 38 | extern __noreturn void die(const char *, ...); 39 | 40 | extern void *xmalloc(size_t size); 41 | extern void *zmalloc(size_t size); 42 | extern void *xcalloc(size_t count, size_t size); 43 | extern void *xrealloc(void *p, size_t size); 44 | 45 | /* alloc */ 46 | enum allocate_area { PERM, FUNC }; 47 | extern void *allocate(size_t, enum allocate_area); 48 | extern void *zallocate(size_t, enum allocate_area); 49 | extern void deallocate(enum allocate_area); 50 | 51 | extern char *fullpath(const char *); 52 | extern char *joinpath(const char *, const char *); 53 | extern int file_exist(const char *); 54 | extern size_t file_size(const char *); 55 | extern char *file_ext(const char *); 56 | extern char *ch_file_ext(const char *, const char *); 57 | extern char *file_basename(const char *); 58 | extern char *file_dirname(const char *); 59 | extern char *mktempfile(const char *); 60 | 61 | extern unsigned int strhash(const char *); 62 | extern unsigned int strnhash(const char *, size_t); 63 | extern char *vstringf(const char *, va_list); 64 | extern char *stringf(const char *, ...); 65 | extern int strstart(const char *, char **); 66 | 67 | extern int mb2wc(wchar_t *wc, const char *s, size_t n); 68 | extern size_t mbs2wcs(wchar_t *pwcs, const char *s, size_t n); 69 | extern int wc2mb(char *s, wchar_t wc); 70 | extern size_t wcs2mbs(char *s, const wchar_t *pwcs, size_t n); 71 | 72 | /* strbuf */ 73 | #define STRBUF_INIT {NULL, 0, 0} 74 | struct strbuf { 75 | char *str; 76 | size_t len; 77 | size_t alloc; 78 | }; 79 | 80 | extern void strbuf_new(struct strbuf *); 81 | extern void strbuf_free(struct strbuf *); 82 | extern void strbuf_reset(struct strbuf *); 83 | extern void strbuf_cats(struct strbuf *, const char *); 84 | extern void strbuf_catn(struct strbuf *, const char *, size_t); 85 | extern void strbuf_catc(struct strbuf *, int); 86 | extern void strbuf_catf(struct strbuf *, const char *, ...); 87 | 88 | /* list */ 89 | struct list { 90 | void *x; 91 | struct list *link; 92 | }; 93 | 94 | extern void append(struct list **, void *); 95 | extern size_t nlist(struct list *); 96 | extern void *ltoa(struct list **); 97 | 98 | extern size_t length(void *); 99 | 100 | #endif /* LIBERTY_H */ -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* driver of the c compiler */ 2 | #include "config.h" 3 | #include "compat.h" 4 | #include "cc.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* cmd option */ 11 | struct option { 12 | const char *name; 13 | unsigned short index; 14 | unsigned short flags; 15 | }; 16 | 17 | enum { 18 | OPTION_c, 19 | OPTION_d, 20 | OPTION_D, 21 | OPTION_E, 22 | OPTION_f, 23 | OPTION_g, 24 | OPTION_help, 25 | OPTION_I, 26 | OPTION_l, 27 | OPTION_L, 28 | OPTION_nostdlib, 29 | OPTION_o, 30 | OPTION_O, 31 | OPTION_pthread, 32 | OPTION_rdynamic, 33 | OPTION_r, 34 | OPTION_shared, 35 | OPTION_soname, 36 | OPTION_static, 37 | OPTION_U, 38 | OPTION_version, 39 | OPTION_v, 40 | OPTION_w, 41 | OPTION_Wl, 42 | OPTION_W, 43 | }; 44 | 45 | /* flags */ 46 | #define OPTION_HAS_ARG (1 << 0) 47 | #define OPTION_NO_SPC (1 << 1) 48 | 49 | static const struct option cmd_options[] = { 50 | { "c", OPTION_c, 0 }, 51 | { "d", OPTION_d, 0 }, 52 | { "dumpversion", OPTION_version, 0 }, 53 | { "D", OPTION_D, OPTION_HAS_ARG }, 54 | { "E", OPTION_E, 0 }, 55 | { "f", OPTION_f, OPTION_HAS_ARG | OPTION_NO_SPC }, 56 | { "g", OPTION_g, 0 }, 57 | { "h", OPTION_help, 0 }, 58 | { "-help", OPTION_help, 0 }, 59 | { "I", OPTION_I, OPTION_HAS_ARG }, 60 | { "l", OPTION_l, OPTION_HAS_ARG | OPTION_NO_SPC }, 61 | { "L", OPTION_L, OPTION_HAS_ARG }, 62 | { "nostdlib", OPTION_nostdlib, 0 }, 63 | { "o", OPTION_o, OPTION_HAS_ARG }, 64 | { "O", OPTION_O, OPTION_HAS_ARG }, 65 | { "pthread", OPTION_pthread, 0 }, 66 | { "rdynamic", OPTION_rdynamic, 0 }, 67 | { "r", OPTION_r, 0 }, 68 | { "shared", OPTION_shared, 0 }, 69 | { "static", OPTION_static, 0 }, 70 | { "soname", OPTION_soname, OPTION_HAS_ARG }, 71 | { "U", OPTION_U, OPTION_HAS_ARG }, 72 | { "-version", OPTION_version, 0 }, 73 | { "v", OPTION_v, 0 }, 74 | { "w", OPTION_w, 0 }, 75 | { "Wl,", OPTION_Wl, OPTION_HAS_ARG | OPTION_NO_SPC }, 76 | { "W", OPTION_W, OPTION_HAS_ARG | OPTION_NO_SPC }, 77 | { NULL, 0, 0 }, 78 | }; 79 | 80 | struct flag { 81 | const char *name; 82 | unsigned short offset; 83 | unsigned short flags; 84 | }; 85 | 86 | #define WD_ALL (1 << 0) /* activated when -Wall */ 87 | #define FD_INVERT (1 << 1) /* invert value before set */ 88 | 89 | static const struct flag fflags[] = { 90 | { "leading-underscore", offsetof(struct options, leading_underscore), 0 }, 91 | { "PIC", offsetof(struct options, pic), 0 }, 92 | }; 93 | 94 | static const struct flag wflags[] = { 95 | { "error", offsetof(struct options, warn_error), 0 }, 96 | { "unsupported", offsetof(struct options, warn_unsupported), 0 }, 97 | }; 98 | 99 | enum { 100 | OUT_NONE, 101 | OUT_PP, /* preprocess */ 102 | OUT_OBJ, /* object */ 103 | OUT_DLL, /* dynamic library */ 104 | OUT_EXE, /* executable */ 105 | }; 106 | 107 | struct options options; 108 | static int outputtype; 109 | static char *output; 110 | static struct list *inlist; 111 | static struct list *cclist; 112 | static struct list *ldlist; 113 | static struct list *pplist; 114 | static int show_help; 115 | static int show_version; 116 | static int nostdlib; 117 | static int static_link; 118 | 119 | static void help(void) 120 | { 121 | static char *usage[] = { 122 | "General options:\n", 123 | " -c Compile only\n", 124 | " -f Set or reset (with 'no-' prefix) \n", 125 | " -h, --help Display available options\n", 126 | " -o Write output to \n", 127 | " -v To be verbose\n", 128 | " --version \n", 129 | " -dumpversion Display version\n", 130 | " -w Disable all warnings\n", 131 | " -W Set or reset (with 'no-' prefix) \n", 132 | " - Use stdin as input file\n", 133 | "\n", 134 | "Preprocessor options:\n", 135 | " -Dname[=value] Define 'name' with value 'value'\n", 136 | " -E Only run the preprocessor\n", 137 | " -Idir Add 'dir' to include search path\n", 138 | " -Uname Undefine 'name'\n", 139 | "\n", 140 | "Linker options:\n", 141 | " -L Add to library search path\n", 142 | " -l Search for library \n", 143 | " -nostdlib Do not link with standard crt and libraries\n", 144 | " -pthread link with -lpthread and -D_REENTRANT\n", 145 | " -rdynamic Pass the flag '--export-dynamic' to the linker\n", 146 | " -r Generate relocatable output\n", 147 | " -shared Create a shared library\n", 148 | " -soname Set internal name of shared library\n", 149 | " -static Static linking\n", 150 | " -Wl, Pass comma separated arguments in to linker\n", 151 | "\n", 0 152 | }; 153 | fputs("Usage: hcc [options] \n\n", stdout); 154 | for (char **p = usage; *p; p++) 155 | fputs(*p, stdout); 156 | } 157 | 158 | static int exec(const char *file, char *argv[]) 159 | { 160 | int r = EXIT_SUCCESS; 161 | pid_t pid = vfork(); 162 | if (pid == 0) { 163 | execvp(file, argv); /* child process */ 164 | } else if (pid > 0) { 165 | int status, n; 166 | while ((n = waitpid(pid, &status, 0)) != pid || 167 | (n == -1 && errno == EINTR)) 168 | ; /* may be EINTR by a signal, so loop it. */ 169 | if (n != pid || !WIFEXITED(status) || WEXITSTATUS(status) != 0) 170 | r = EXIT_FAILURE; 171 | /* print signal message */ 172 | if (n == pid && !WIFEXITED(status) && WIFSIGNALED(status)) 173 | fprintf(stderr, "PID %d: %s\n", pid, strsignal(WTERMSIG(status))); 174 | } else { 175 | perror("can't fork"); 176 | r = EXIT_FAILURE; 177 | } 178 | return r; 179 | } 180 | 181 | /* set/reset a flag */ 182 | static int set_flag(struct options *opts, const struct flag *flags, int n, const char *name, int value) 183 | { 184 | const struct flag *p, *q; 185 | 186 | /* no- */ 187 | if (name[0] == 'n' && name[1] == 'o' && name[2] == '-') { 188 | name += 3; 189 | value = !value; 190 | } 191 | 192 | for (p = flags, q = p + n; p < q; p++) 193 | if (!strcasecmp(name, p->name)) { 194 | if (p->flags & FD_INVERT) 195 | value = !value; 196 | *(int *)((unsigned char *)opts + p->offset) = value; 197 | return 0; 198 | } 199 | 200 | return -1; 201 | } 202 | 203 | static int set_w_flag(struct options *opts, const char *name, int value) 204 | { 205 | if (!strcasecmp(name, "all")) { 206 | const struct flag *p, *q; 207 | for (p = wflags, q = p + NELEMS(wflags); p < q; p++) 208 | if (p->flags & WD_ALL) 209 | *(int *)((unsigned char *)opts + p->offset) = 1; 210 | 211 | return 0; 212 | } else { 213 | return set_flag(opts, wflags, NELEMS(wflags), name, value); 214 | } 215 | } 216 | 217 | static int set_f_flag(struct options *opts, const char *name, int value) 218 | { 219 | return set_flag(opts, fflags, NELEMS(fflags), name, value); 220 | } 221 | 222 | static void parse_opts(int argc, char *argv[]) 223 | { 224 | int optind = 0; 225 | char *arg, *optarg, *beg, *cur; 226 | const struct option *popt; 227 | struct options *popts = &options; 228 | 229 | while (optind < argc) { 230 | arg = argv[optind++]; 231 | 232 | if (arg[0] != '-' || arg[1] == '\0') { 233 | append(&inlist, arg); 234 | continue; 235 | } 236 | 237 | for (popt = cmd_options; ; popt++) { 238 | const char *name = popt->name; 239 | char *arg1 = arg + 1; 240 | if (name == NULL) 241 | die("invalid option -- '%s'", arg); 242 | if (!strstart(name, &arg1)) 243 | continue; 244 | optarg = arg1; 245 | if (popt->flags & OPTION_HAS_ARG) { 246 | if (*arg1 == '\0' && !(popt->flags & OPTION_NO_SPC)) { 247 | if (optind >= argc) 248 | die("argument to '%s' is missing", arg); 249 | optarg = argv[optind++]; 250 | } 251 | } else if (*arg1 != '\0') { 252 | continue; 253 | } 254 | break; 255 | } 256 | 257 | switch (popt->index) { 258 | case OPTION_c: 259 | outputtype = OUT_OBJ; 260 | break; 261 | case OPTION_d: 262 | popts->debug = 1; 263 | append(&cclist, arg); 264 | break; 265 | case OPTION_D: 266 | arg = stringf("-D%s", optarg); 267 | append(&pplist, arg); 268 | append(&cclist, arg); 269 | break; 270 | case OPTION_E: 271 | outputtype = OUT_PP; 272 | break; 273 | case OPTION_f: 274 | if (set_f_flag(popts, optarg, 1) < 0 && popts->warn_unsupported) 275 | goto unsupported_option; 276 | append(&cclist, arg); 277 | break; 278 | case OPTION_g: 279 | if (popts->warn_unsupported) 280 | goto unsupported_option; 281 | append(&cclist, arg); 282 | break; 283 | case OPTION_help: 284 | show_help = 1; 285 | break; 286 | case OPTION_I: 287 | arg = stringf("-I%s", optarg); 288 | append(&cclist, arg); 289 | append(&pplist, arg); 290 | break; 291 | case OPTION_L: 292 | append(&ldlist, stringf("-L%s", optarg)); 293 | break; 294 | case OPTION_l: 295 | append(&ldlist, arg); 296 | break; 297 | case OPTION_nostdlib: 298 | nostdlib = 1; 299 | break; 300 | case OPTION_o: 301 | output = optarg; 302 | break; 303 | case OPTION_O: 304 | popts->optimize = *optarg - '0'; 305 | append(&cclist, stringf("-O%s", optarg)); 306 | break; 307 | case OPTION_pthread: 308 | append(&ldlist, "-lpthread"); 309 | append(&pplist, "-D_REENTRANT"); 310 | break; 311 | case OPTION_rdynamic: 312 | append(&ldlist, "--export-dynamic"); 313 | break; 314 | case OPTION_r: 315 | append(&ldlist, "-r"); 316 | break; 317 | case OPTION_shared: 318 | outputtype = OUT_DLL; 319 | append(&ldlist, "-shared"); 320 | break; 321 | case OPTION_soname: 322 | append(&ldlist, stringf("-soname %s", optarg)); 323 | break; 324 | case OPTION_static: 325 | static_link = 1; 326 | append(&ldlist, "-static"); 327 | break; 328 | case OPTION_U: 329 | arg = stringf("-U%s", optarg); 330 | append(&pplist, arg); 331 | append(&cclist, arg); 332 | break; 333 | case OPTION_v: 334 | popts->verbose = 1; 335 | append(&cclist, arg); 336 | break; 337 | case OPTION_version: 338 | show_version = 1; 339 | break; 340 | case OPTION_w: 341 | popts->warn_none = 1; 342 | append(&cclist, arg); 343 | break; 344 | case OPTION_W: 345 | if (set_w_flag(popts, optarg, 1) < 0 && popts->warn_unsupported) 346 | goto unsupported_option; 347 | append(&cclist, arg); 348 | break; 349 | case OPTION_Wl: 350 | for (beg = cur = optarg; *cur; cur++) 351 | if (*cur == ',') { 352 | append(&ldlist, strndup(beg, cur - beg)); 353 | beg = cur + 1; 354 | } 355 | append(&ldlist, strndup(beg, cur - beg)); 356 | break; 357 | default: 358 | if (popts->warn_unsupported) { 359 | unsupported_option: 360 | fprintf(stderr, "warning: unsupported option -- '%s'\n", arg); 361 | } 362 | break; 363 | } 364 | } 365 | 366 | if (outputtype == 0) 367 | outputtype = OUT_EXE; 368 | if (outputtype == OUT_PP) 369 | popts->preprocess_only = 1; 370 | } 371 | 372 | /* $0: output file, $1: input files, $2: additional options */ 373 | static char **subst(char **argv, char **ifiles, char *ofile, char **options) 374 | { 375 | int argc = length(argv); 376 | int nifiles = length(ifiles); 377 | int noptions = length(options); 378 | int ac = argc + nifiles + noptions; 379 | char **av = xmalloc(ac * sizeof(char *)); 380 | int j = 0; 381 | for (int i = 0; i < argc; i++) { 382 | char *arg = argv[i]; 383 | if (arg[0] == '$' && isdigit(arg[1])) { 384 | int k = arg[1] - '0'; 385 | assert(k >= 0 && k <= 2); 386 | if (k == 0) { 387 | av[j++] = ofile ? ofile : "a.out"; 388 | } else if (k == 1) { 389 | for (int i = 0; i < nifiles; i++) 390 | av[j++] = ifiles[i]; 391 | } else { 392 | for (int i = 0; i < noptions; i++) 393 | av[j++] = options[i]; 394 | } 395 | } else { 396 | av[j++] = arg; 397 | } 398 | } 399 | assert(j < ac); 400 | av[j] = NULL; 401 | return av; 402 | } 403 | 404 | static int do_ld(char **ifiles, char *ofile, char **options) 405 | { 406 | #ifdef CONFIG_TARGET_LINUX 407 | static char *ld[] = { 408 | "ld", 409 | #if defined CONFIG_TARGET_X86_64 410 | "-A", "x86_64", 411 | #endif 412 | "-o", "$0", 413 | "-dynamic-linker", CONFIG_DYNAMIC_LINKER, 414 | "-L" CONFIG_LIBC_PREFIX, 415 | "$2", "$1", NULL 416 | }; 417 | /* 418 | * The ouput must be linked in such order: 419 | * crt1.o, crti.o, , , crtn.o 420 | */ 421 | int n = length(ifiles); 422 | char **av = xmalloc((n + 20) * sizeof(char *)); 423 | int i = 0; 424 | 425 | if (nostdlib) { 426 | memcpy(&av[i], ifiles, n * sizeof(char *)); 427 | i += n; 428 | } else { 429 | if (outputtype != OUT_DLL) 430 | av[i++] = CONFIG_CRT_PREFIX "/crt1.o"; 431 | av[i++] = CONFIG_CRT_PREFIX "/crti.o"; 432 | memcpy(&av[i], ifiles, n * sizeof(char *)); 433 | i += n; 434 | if (static_link) 435 | av[i++] = "--start-group"; 436 | av[i++] = "-lc"; 437 | if (static_link) 438 | av[i++] = "--end-group"; 439 | av[i++] = CONFIG_CRT_PREFIX "/crtn.o"; 440 | } 441 | av[i] = NULL; 442 | 443 | return exec(ld[0], subst(ld, av, ofile, options)); 444 | #elif defined CONFIG_TARGET_DARWIN 445 | char *ld[] = { 446 | "ld", 447 | "-o", "$0", 448 | #if defined CONFIG_TARGET_X86_64 449 | "-arch", "x86_64", 450 | #endif 451 | "$1", "$2", 452 | NULL 453 | }; 454 | 455 | int n = length(ifiles); 456 | char **av = xmalloc((n + 20) * sizeof(char *)); 457 | int i = 0; 458 | 459 | if (nostdlib) { 460 | memcpy(&av[i], ifiles, n * sizeof(char *)); 461 | i += n; 462 | } else { 463 | memcpy(&av[i], ifiles, n * sizeof(char *)); 464 | i += n; 465 | av[i++] = "-lc"; 466 | av[i++] = "-lm"; 467 | } 468 | av[i] = NULL; 469 | 470 | return exec(ld[0], subst(ld, av, ofile, options)); 471 | #endif 472 | } 473 | 474 | static void do_sys_opts(void) 475 | { 476 | int a, b, c; 477 | char buf[64]; 478 | 479 | sscanf(CONFIG_VERSION, "%d.%d.%d", &a, &b, &c); 480 | snprintf(buf, sizeof(buf), "-D__HCC__=%d", a * 10000 + b * 100 + c); 481 | append(&pplist, strdup(buf)); 482 | 483 | /* for passing some gnu configure test */ 484 | append(&pplist, "-D__TINYC__"); 485 | 486 | #ifdef CONFIG_TARGET_X86_64 487 | append(&pplist, "-D__x86_64__"); 488 | append(&pplist, "-D__LP64__"); 489 | #endif 490 | 491 | #ifdef CONFIG_TARGET_LINUX 492 | append(&pplist, "-D__linux__"); 493 | append(&pplist, "-D__linux"); 494 | append(&pplist, "-D__unix__"); 495 | append(&pplist, "-D__unix"); 496 | append(&pplist, "-Dunix"); 497 | #elif defined CONFIG_TARGET_DARWIN 498 | append(&pplist, "-D__APPLE__"); 499 | #endif 500 | 501 | /* include */ 502 | append(&pplist, "-I" CONFIG_CC_INCLUDE_DIR); 503 | append(&pplist, "-I/usr/include"); 504 | /* linux */ 505 | #ifdef CONFIG_TARGET_LINUX 506 | append(&pplist, "-I/usr/include/linux"); 507 | append(&pplist, "-I/usr/include/x86_64-linux-gnu"); 508 | #elif defined CONFIG_TARGET_DARWIN 509 | append(&pplist, "-I" CONFIG_MACOS_INCLUDE_DIR); 510 | #endif 511 | } 512 | 513 | static int c_source_file_p(const char *filename) 514 | { 515 | char *ext; 516 | 517 | /* standard input */ 518 | if (!strcmp(filename, "-")) 519 | return 1; 520 | 521 | ext = file_ext(filename); 522 | return !strcasecmp(ext, ".c") || !strcasecmp(ext, ".h"); 523 | } 524 | 525 | int main(int argc, char *argv[]) 526 | { 527 | int ninputs, c; 528 | char **inputs, **cmd, **opt; 529 | char *ifile, *ofile, *base; 530 | struct list *list; 531 | 532 | parse_opts(argc - 1, argv + 1); 533 | /* sys includes follow user defined includes */ 534 | do_sys_opts(); 535 | 536 | if (show_help) { 537 | help(); 538 | return 0; 539 | } 540 | if (show_version) { 541 | fprintf(stdout, "%s\n", CONFIG_VERSION); 542 | return 0; 543 | } 544 | 545 | inputs = ltoa(&inlist); 546 | ninputs = length(inputs); 547 | if (ninputs == 0) 548 | die("no input files"); 549 | if (output && ninputs > 1) 550 | if (outputtype != OUT_EXE && outputtype != OUT_DLL) 551 | die("can't specify -o when generating multiple output files"); 552 | 553 | c = 0; 554 | if (ninputs == 1) { 555 | ifile = inputs[0]; 556 | ofile = output; 557 | /* c source file, header file */ 558 | if (c_source_file_p(ifile)) { 559 | switch (outputtype) { 560 | case OUT_PP: 561 | c = cc1(ifile, ofile, ltoa(&pplist)); 562 | break; 563 | 564 | case OUT_OBJ: 565 | if (ofile == NULL && strcmp(ifile, "-")) { 566 | base = file_basename(ifile); 567 | ofile = ch_file_ext(base, "o"); 568 | } 569 | c = cc1(ifile, ofile, ltoa(&pplist)); 570 | break; 571 | 572 | case OUT_DLL: 573 | case OUT_EXE: 574 | ofile = mktempfile("o"); 575 | c = cc1(ifile, ofile, ltoa(&pplist)); 576 | inputs[0] = ofile; 577 | break; 578 | 579 | default: 580 | die("unknown output type: %d", outputtype); 581 | } 582 | 583 | if (c && ofile) 584 | remove(ofile); 585 | } 586 | } else { 587 | list = NULL; 588 | append(&list, argv[0]); 589 | append(&list, "$1"); /* input file */ 590 | append(&list, "-o"); 591 | append(&list, "$0"); /* output file */ 592 | if (outputtype == OUT_PP) 593 | append(&list, "-E"); 594 | else 595 | append(&list, "-c"); 596 | /* cc options */ 597 | for (opt = ltoa(&cclist); *opt; opt++) 598 | append(&list, *opt); 599 | /* ld options: ignored. */ 600 | 601 | cmd = ltoa(&list); 602 | for (int i = 0; i < ninputs; i++) { 603 | ifile = inputs[i]; 604 | ofile = NULL; 605 | 606 | if (!c_source_file_p(ifile)) 607 | continue; 608 | 609 | switch (outputtype) { 610 | case OUT_PP: 611 | break; 612 | 613 | case OUT_OBJ: 614 | if (ofile == NULL && strcmp(ifile, "-")) { 615 | base = file_basename(ifile); 616 | ofile = ch_file_ext(base, "o"); 617 | } 618 | break; 619 | 620 | case OUT_DLL: 621 | case OUT_EXE: 622 | ofile = mktempfile("o"); 623 | break; 624 | 625 | default: 626 | die("unknown output type: %d", outputtype); 627 | } 628 | 629 | cmd[1] = ifile; 630 | cmd[3] = ofile ? ofile : "-"; 631 | if (exec(argv[0], cmd) != EXIT_SUCCESS) { 632 | c++; 633 | if (ofile) 634 | remove(ofile); 635 | } 636 | inputs[i] = ofile; 637 | } 638 | } 639 | 640 | if (c == 0 && (outputtype == OUT_EXE || outputtype == OUT_DLL)) 641 | c = do_ld(inputs, output, ltoa(&ldlist)); 642 | 643 | return c; 644 | } 645 | -------------------------------------------------------------------------------- /section.c: -------------------------------------------------------------------------------- 1 | #include "cc.h" 2 | #include "elf.h" 3 | #include "liberty.h" 4 | 5 | struct section **sections; 6 | int sections_used; 7 | static int sections_alloc; 8 | 9 | struct section *newsec(const char *name, int type, int flags) 10 | { 11 | struct section *s; 12 | 13 | s = zmalloc(sizeof(struct section) + strlen(name)); 14 | strcpy(s->name, name); 15 | s->sh_type = type; 16 | s->sh_flags = flags; 17 | switch (type) { 18 | case SHT_STRTAB: 19 | /* The first byte of string table must be zero. */ 20 | sec_add_str(s, ""); 21 | s->sh_addralign = 1; 22 | break; 23 | case SHT_PROGBITS: 24 | case SHT_NOBITS: 25 | case SHT_REL: 26 | case SHT_RELA: 27 | case SHT_HASH: 28 | case SHT_DYNAMIC: 29 | case SHT_SYMTAB: 30 | default: 31 | s->sh_addralign = 8; 32 | break; 33 | } 34 | 35 | s->shndx = sections_used; 36 | if (sections_used + 1 > sections_alloc) { 37 | sections_alloc = 2 * (sections_used + 1); 38 | sections = xrealloc(sections, sections_alloc * sizeof(*sections)); 39 | } 40 | sections[sections_used++] = s; 41 | 42 | return s; 43 | } 44 | 45 | static void sec_data_grow(struct section *s, size_t new_size) 46 | { 47 | size_t size = s->data_alloc; 48 | 49 | if (size == 0) 50 | size = 256; 51 | while (size < new_size) 52 | size = size * 2; 53 | if (s->sh_type != SHT_NOBITS) 54 | s->data = xrealloc(s->data, size); 55 | s->data_alloc = size; 56 | } 57 | 58 | void sec_set_data(struct section *s, const void *src, size_t len, size_t offset) 59 | { 60 | size_t newsize = offset + len; 61 | if (newsize > s->data_alloc) 62 | sec_data_grow(s, newsize); 63 | if (newsize > s->data_len) 64 | s->data_len = newsize; 65 | if (s->data) 66 | memcpy(s->data + offset, src, len); 67 | } 68 | 69 | size_t sec_add_data(struct section *s, const void *src, size_t len) 70 | { 71 | size_t offset = s->data_len; 72 | sec_set_data(s, src, len, offset); 73 | return offset; 74 | } 75 | 76 | size_t sec_add_str(struct section *s, const char *str) 77 | { 78 | /* including terminating zero */ 79 | return sec_add_data(s, str, strlen(str) + 1); 80 | } 81 | 82 | size_t sec_extend(struct section *s, size_t exsize) 83 | { 84 | size_t oldsize = s->data_len; 85 | s->data_len += exsize; 86 | if (s->data_len > s->data_alloc) 87 | sec_data_grow(s, s->data_len); 88 | /* always zero bytes to prevent random bytes in bootstrap */ 89 | if (s->data) 90 | memset(s->data + oldsize, 0, exsize); 91 | return oldsize; 92 | } 93 | 94 | void sec_align(struct section *s, int align) 95 | { 96 | if (align > 1) { 97 | size_t size = ROUNDUP(s->data_len, align); 98 | if (size > s->data_len) 99 | sec_extend(s, size - s->data_len); 100 | } 101 | } 102 | 103 | int sec_find_sym(struct section *s, const char *name) 104 | { 105 | Elf64_Sym *pstart, *plimit, *p; 106 | 107 | if (name == NULL) 108 | return 0; 109 | 110 | pstart = (Elf64_Sym *)s->data; 111 | plimit = (Elf64_Sym *)(s->data + s->data_len); 112 | 113 | for (p = pstart; p < plimit; p++) { 114 | const char *symname = s->link->data + p->st_name; 115 | if (!strcmp(symname, name)) 116 | return p - pstart; 117 | } 118 | 119 | return 0; 120 | } 121 | 122 | int sec_add_sym(struct section *s, const char *name, int bind, int type, 123 | int shndx, size_t value, size_t size) 124 | { 125 | Elf64_Sym *sym; 126 | int index; 127 | 128 | index = (Elf64_Sym *)(s->data + s->data_len) - (Elf64_Sym *)s->data; 129 | sym = xmalloc(sizeof *sym); 130 | if (name) 131 | sym->st_name = sec_add_str(s->link, name); 132 | else 133 | sym->st_name = 0; 134 | sym->st_info = ELF64_ST_INFO(bind, type); 135 | sym->st_shndx = shndx; 136 | sym->st_other = 0; 137 | sym->st_value = value; 138 | sym->st_size = size; 139 | sec_add_data(s, sym, sizeof(*sym)); 140 | 141 | return index; 142 | } 143 | 144 | struct section *newsymtab(const char *name, int type, int flags, 145 | const char *strtab, int entsize) 146 | { 147 | struct section *symtab; 148 | 149 | symtab = newsec(name, type, flags); 150 | symtab->sh_entsize = entsize; 151 | symtab->link = newsec(strtab, SHT_STRTAB, 0); 152 | /* The first symbol table entry must be all zero. */ 153 | sec_extend(symtab, entsize); 154 | return symtab; 155 | } 156 | 157 | /* generate a relocation entry */ 158 | void sec_add_rela(struct section *symtab, struct section *s, 159 | size_t offset, int sym, int type, long addend) 160 | { 161 | Elf64_Rela *entry; 162 | 163 | if (s->reloc == NULL) { 164 | s->reloc = newsec(stringf(".rela%s", s->name), SHT_RELA, 0); 165 | s->reloc->link = symtab; 166 | s->reloc->sh_info = s->shndx; 167 | s->reloc->sh_entsize = sizeof(Elf64_Rela); 168 | } 169 | 170 | entry = xmalloc(sizeof(*entry)); 171 | entry->r_offset = offset; 172 | entry->r_info = ELF64_R_INFO((long)sym, type); 173 | entry->r_addend = addend; 174 | sec_add_data(s->reloc, entry, sizeof(*entry)); 175 | } 176 | 177 | /** 178 | * local symbols must be placed in front of global symbols. 179 | * `sh_info` of symbol table must be the index of first non-local symbol. 180 | * (i.e. number of local symbols) 181 | */ 182 | void sec_sort_syms(struct section *s) 183 | { 184 | Elf64_Sym *pstart, *plimit, *p1, *p2, tmp; 185 | int *ndxmap, i; 186 | long type, symndx; 187 | 188 | pstart = (Elf64_Sym *)s->data; 189 | plimit = (Elf64_Sym *)(s->data + s->data_len); 190 | p1 = pstart + 1; /* skip first empty entry */ 191 | p2 = plimit - 1; 192 | 193 | ndxmap = xmalloc((plimit - pstart) * sizeof (int)); 194 | for (i = 0; i < plimit - pstart; i++) 195 | ndxmap[i] = i; 196 | 197 | while (1) { 198 | while (p1 < plimit && ELF64_ST_BIND(p1->st_info) == STB_LOCAL) 199 | p1++; 200 | if (p1 == plimit) 201 | break; 202 | while (p2 > p1 && ELF64_ST_BIND(p2->st_info) != STB_LOCAL) 203 | p2--; 204 | if (p2 <= p1) 205 | break; 206 | 207 | i = p1 - pstart; 208 | ndxmap[p1 - pstart] = ndxmap[p2 - pstart]; 209 | ndxmap[p2 - pstart] = i; 210 | 211 | tmp = *p1; 212 | *p1 = *p2; 213 | *p2 = tmp; 214 | } 215 | 216 | /* number of local symbols */ 217 | s->sh_info = p1 - pstart; 218 | 219 | /* recaculate .rela/.rel symbol index */ 220 | for (i = 0; i < sections_used; i++) { 221 | struct section *s1 = sections[i]; 222 | if (s1->symndx) 223 | s1->symndx = ndxmap[s1->symndx]; 224 | if (s1->sh_type == SHT_RELA && s1->link == s) { 225 | Elf64_Rela *rel, *limit; 226 | limit = (Elf64_Rela *)(s1->data + s1->data_len); 227 | for (rel = (Elf64_Rela *)s1->data; rel < limit; rel++) { 228 | type = ELF64_R_TYPE(rel->r_info); 229 | symndx = ELF64_R_SYM(rel->r_info); 230 | symndx = ndxmap[symndx]; 231 | rel->r_info = ELF64_R_INFO(symndx, type); 232 | } 233 | } 234 | if (s1->sh_type == SHT_REL && s1->link == s) { 235 | Elf64_Rel *rel, *limit; 236 | limit = (Elf64_Rel *)(s1->data + s1->data_len); 237 | for (rel = (Elf64_Rel *)s1->data; rel < limit; rel++) { 238 | type = ELF64_R_TYPE(rel->r_info); 239 | symndx = ELF64_R_SYM(rel->r_info); 240 | symndx = ndxmap[symndx]; 241 | rel->r_info = ELF64_R_INFO(symndx, type); 242 | } 243 | } 244 | } 245 | 246 | free(ndxmap); 247 | } -------------------------------------------------------------------------------- /sub.c: -------------------------------------------------------------------------------- 1 | #include "cc.h" 2 | #include 3 | #include 4 | 5 | #define MAX_ERRORS 6 6 | #define STRINGSZ 512 7 | 8 | enum { WRN = 1, ERR, FTL }; 9 | int errors, warnings; 10 | static const char *prefix[] = { 11 | "null", "warning", "error", "fatal error" 12 | }; 13 | 14 | static void vdiag(struct node *n, const char *fmt, va_list ap, int level) 15 | { 16 | if (level == 0) 17 | return; 18 | if (level == WRN && options.warn_error) 19 | level = ERR; 20 | if (level == WRN && options.warn_none) 21 | return; 22 | 23 | fprint(stderr, "%L: %s: ", n ? n->line : nearln, prefix[level]); 24 | vfprint(stderr, fmt, ap); 25 | fprint(stderr, "\n"); 26 | 27 | if (level == ERR) 28 | errors++; 29 | else if (level == WRN) 30 | warnings++; 31 | else if (level == FTL) 32 | exit(EXIT_FAILURE); 33 | 34 | if (errors >= MAX_ERRORS) { 35 | fprint(stderr, "Too many errors.\n"); 36 | exit(EXIT_FAILURE); 37 | } 38 | } 39 | 40 | void error(struct node *n, const char *fmt, ...) 41 | { 42 | va_list ap; 43 | va_start(ap, fmt); 44 | vdiag(n, fmt, ap, ERR); 45 | va_end(ap); 46 | } 47 | 48 | void warn(struct node *n, const char *fmt, ...) 49 | { 50 | va_list ap; 51 | va_start(ap, fmt); 52 | vdiag(n, fmt, ap, WRN); 53 | va_end(ap); 54 | } 55 | 56 | void fatal(struct node *n, const char *fmt, ...) 57 | { 58 | va_list ap; 59 | va_start(ap, fmt); 60 | vdiag(n, fmt, ap, FTL); 61 | va_end(ap); 62 | } 63 | 64 | static int Oconv(struct fmt *fp) 65 | { 66 | int o = va_arg(fp->args, int); 67 | if (o < OXXX || o > NOTYPE) 68 | return fmtprint(fp, "***badO %d***", o); 69 | 70 | return fmtstrcpy(fp, onames[o]); 71 | } 72 | 73 | static int Tconv(struct fmt *fp) 74 | { 75 | char str[STRINGSZ+20], s[STRINGSZ+20]; 76 | struct type *ty, *ty1; 77 | int et; 78 | size_t n; 79 | 80 | str[0] = 0; 81 | for (ty = va_arg(fp->args, struct type *); ty; ty = ty->link) { 82 | et = ty->etype; 83 | if (str[0]) 84 | strcat(str, " "); 85 | if (ty->qual != QXXX) { 86 | snprint(s, STRINGSZ, "%Q ", bitwiseq(ty->qual)); 87 | if (strlen(str) + strlen(s) < STRINGSZ) 88 | strcat(str, s); 89 | } 90 | snprint(s, STRINGSZ, "%s", tnames[et]); 91 | if (strlen(str) + strlen(s) < STRINGSZ) 92 | strcat(str, s); 93 | if (et == TFUNC && (ty1 = ty->next)) { 94 | snprint(s, STRINGSZ, "(%T", ty1); 95 | if (strlen(str) + strlen(s) < STRINGSZ) 96 | strcat(str, s); 97 | while ((ty1 = ty1->next)) { 98 | snprint(s, STRINGSZ, ", %T", ty1); 99 | if (strlen(str) + strlen(s) < STRINGSZ) 100 | strcat(str, s); 101 | } 102 | if (strlen(str) + strlen(s) < STRINGSZ) 103 | strcat(str, ")"); 104 | } 105 | if (et == TARRAY) { 106 | n = ty->size; 107 | if (ty->link && ty->link->size) 108 | n /= ty->link->size; 109 | snprint(s, STRINGSZ, "[%lu]", n); 110 | if (strlen(str) + strlen(s) < STRINGSZ) 111 | strcat(str, s); 112 | } 113 | if (ty->nbits) { 114 | snprint(s, STRINGSZ, " :%d", ty->nbits); 115 | if (strlen(str) + strlen(s) < STRINGSZ) 116 | strcat(str, s); 117 | } 118 | if (typesue[et]) { 119 | if (ty->tag) { 120 | strcat(str, " "); 121 | if (strlen(str) + strlen(ty->tag->name) < STRINGSZ) 122 | strcat(str, ty->tag->name); 123 | } else { 124 | strcat(str, " {}"); 125 | } 126 | break; 127 | } 128 | } 129 | return fmtstrcpy(fp, str); 130 | } 131 | 132 | static int Qconv(struct fmt *fp) 133 | { 134 | char str[STRINGSZ+20]; 135 | const char *s; 136 | int b; 137 | 138 | str[0] = 0; 139 | for (b = va_arg(fp->args, int); b;) { 140 | int i = bitno(b); 141 | if (str[0]) 142 | strcat(str, " "); 143 | s = tnames[i]; 144 | if (strlen(str) + strlen(s) >= STRINGSZ) 145 | break; 146 | strcat(str, s); 147 | b &= ~(1 << i); 148 | } 149 | return fmtstrcpy(fp, str); 150 | } 151 | 152 | /* print source location */ 153 | static int Lconv(struct fmt *fp) 154 | { 155 | char str[STRINGSZ]; 156 | int line, oline; 157 | const char *oname; 158 | 159 | line = va_arg(fp->args, int); 160 | cpp_resolve_location(line, &oname, &oline); 161 | snprintf(str, STRINGSZ, "%s:%d", oname, oline); 162 | return fmtstrcpy(fp, str); 163 | } 164 | 165 | void fmtinit(void) 166 | { 167 | fmtinstall('T', Tconv); /* type */ 168 | fmtinstall('Q', Qconv); /* qualifier */ 169 | fmtinstall('L', Lconv); /* location */ 170 | fmtinstall('O', Oconv); /* operator */ 171 | } 172 | 173 | static int invalid_ucn(int c) 174 | { 175 | return (c < 0xA0 && (c != 0x24 && c != 0x40 && c != 0x60)) || 176 | (c & 0x80000000) || (c >= 0xD800 && c <= 0xDFFF); 177 | } 178 | 179 | static const char *float_suffix(const char *p, int *suffix) 180 | { 181 | assert(suffix); 182 | 183 | if (*p == 'f' || *p == 'F') { 184 | p++; 185 | *suffix = BFLOAT; 186 | } else if (*p == 'l' || *p == 'L') { 187 | p++; 188 | *suffix = BLONG | BDOUBLE; 189 | } else { 190 | *suffix = 0; 191 | } 192 | 193 | return p; 194 | } 195 | 196 | static void eval_float(struct token *t, struct svalue *v) 197 | { 198 | const char *p = t->val.str; 199 | int suffix; 200 | 201 | if (p[0] == '.') { 202 | assert(ISDIGIT(p[1])); 203 | goto dotted; 204 | } else if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 205 | p += 2; 206 | if (*p == '.') { 207 | if (!ISXDIGIT(p[1])) 208 | error(0, "hex floating constants require a significand"); 209 | goto dotted_hex; 210 | } else { 211 | assert(ISXDIGIT(*p)); 212 | 213 | while (ISXDIGIT(*p)) 214 | p++; 215 | dotted_hex: 216 | if (*p == '.') { 217 | p++; 218 | while (ISXDIGIT(*p)) 219 | p++; 220 | } 221 | if (*p == 'p' || *p == 'P') { 222 | p++; 223 | if (*p == '+' || *p == '-') 224 | p++; 225 | if (ISDIGIT(*p)) { 226 | do 227 | p++; 228 | while (ISDIGIT(*p)); 229 | } else { 230 | error(0, "exponent has no digits"); 231 | } 232 | } else { 233 | error(0, "hex floating constants require an exponent"); 234 | } 235 | } 236 | } else { 237 | assert(ISDIGIT(*p)); 238 | 239 | while (ISDIGIT(*p)) 240 | p++; 241 | dotted: 242 | if (*p == '.') { 243 | p++; 244 | while (ISDIGIT(*p)) 245 | p++; 246 | } 247 | if (*p == 'e' || *p == 'E') { 248 | p++; 249 | if (*p == '+' || *p == '-') 250 | p++; 251 | if (ISDIGIT(*p)) { 252 | do 253 | p++; 254 | while (ISDIGIT(*p)); 255 | } else { 256 | error(0, "exponent used with no following digits"); 257 | } 258 | } 259 | } 260 | 261 | p = float_suffix(p, &suffix); 262 | 263 | if (*p != '\0') 264 | error(0, "illegal float constant '%s'", tok2s(t)); 265 | 266 | if (v) { 267 | errno = 0; 268 | switch (suffix) { 269 | case BFLOAT: 270 | v->d = strtof(t->val.str, NULL); 271 | break; 272 | case BLONG | BDOUBLE: 273 | v->d = strtold(t->val.str, NULL); 274 | break; 275 | default: 276 | v->d = strtod(t->val.str, NULL);; 277 | break; 278 | } 279 | 280 | if (errno == ERANGE) 281 | error(0, "float constant overflow: '%s'", tok2s(t)); 282 | 283 | v->suffix = suffix; 284 | v->id = TOK_FCON; 285 | } 286 | } 287 | 288 | static const char *integer_suffix(const char *p, int *suffix) 289 | { 290 | assert(suffix); 291 | 292 | if ((p[0] == 'u' || p[0] == 'U') && 293 | ((p[1] == 'l' && p[2] == 'l') || (p[1] == 'L' && p[2] == 'L'))) { 294 | p += 3; 295 | *suffix = BUNSIGNED | BLLONG | BLONG; 296 | } else if (((p[0] == 'l' && p[1] == 'l') || (p[0] == 'L' && p[1] == 'L')) && 297 | (p[2] == 'u' || p[2] == 'U')) { 298 | p += 3; 299 | *suffix = BUNSIGNED | BLLONG | BLONG; 300 | } else if ((p[0] == 'l' && p[1] == 'l') || 301 | (p[0] == 'L' && p[1] == 'L')) { 302 | p += 2; 303 | *suffix = BLLONG | BLONG; 304 | } else if ((p[0] == 'l' || p[0] == 'L') && 305 | (p[1] == 'u' || p[1] == 'U')) { 306 | p += 2; 307 | *suffix = BUNSIGNED | BLONG; 308 | } else if ((p[0] == 'u' || p[0] == 'U') && 309 | (p[1] == 'l' || p[1] == 'L')) { 310 | p += 2; 311 | *suffix = BUNSIGNED | BLONG; 312 | } else if (p[0] == 'l' || p[0] == 'L') { 313 | p += 1; 314 | *suffix = BLONG; 315 | } else if (p[0] == 'u' || p[0] == 'U') { 316 | p += 1; 317 | *suffix = BUNSIGNED; 318 | } else { 319 | *suffix = 0; 320 | } 321 | 322 | return p; 323 | } 324 | 325 | static void eval_int(struct token *t, struct svalue *v) 326 | { 327 | const char *p = t->val.str; 328 | int overflow = 0; 329 | unsigned long n = 0; 330 | int suffix; 331 | int base; 332 | 333 | if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 334 | base = 16; 335 | p += 2; 336 | for (; ISXDIGIT(*p); p++) { 337 | int d; 338 | 339 | if (n & ~(~0UL >> 4)) 340 | overflow = 1; 341 | 342 | if (ISXALPHA(*p)) 343 | d = (*p & 0x5f) - 'A' + 10; 344 | else 345 | d = *p - '0'; 346 | 347 | n = (n << 4) + d; 348 | } 349 | } else if (p[0] == '0') { 350 | base = 8; 351 | int err = 0; 352 | for (; ISDIGIT(*p); p++) { 353 | if (*p == '8' || *p == '9') 354 | err = 1; 355 | 356 | if (n & ~(~0UL >> 3)) 357 | overflow = 1; 358 | 359 | n = (n << 3) + (*p - '0'); 360 | } 361 | if (err) 362 | error(0, "illegal digit in octal constant"); 363 | } else { 364 | base = 10; 365 | for (; ISDIGIT(*p); p++) { 366 | int d = *p - '0'; 367 | if (n > (~0UL - d) / 10) 368 | overflow = 1; 369 | 370 | n = n * 10 + d; 371 | } 372 | } 373 | 374 | p = integer_suffix(p, &suffix); 375 | 376 | if (overflow) 377 | error(0, "integer constant overflow: '%s'", tok2s(t)); 378 | if (p[0] != '\0') 379 | error(0, "illegal integer constant: '%s'", tok2s(t)); 380 | 381 | if (v) { 382 | v->i = n; 383 | v->suffix = suffix; 384 | v->base = base; 385 | v->id = TOK_ICON; 386 | } 387 | } 388 | 389 | static const char *read_escape_char(const char *p, int wide, int *result, int *ucn) 390 | { 391 | int c = 0, i, n; 392 | 393 | assert(*p == '\\'); 394 | if (ucn) *ucn = 0; 395 | p++; 396 | switch (*p++) { 397 | case 'a': 398 | c = 7; 399 | break; 400 | case 'b': 401 | c = '\b'; 402 | break; 403 | case 'e': 404 | c = 033; 405 | break; 406 | case 'f': 407 | c = '\f'; 408 | break; 409 | case 'n': 410 | c = '\n'; 411 | break; 412 | case 'r': 413 | c = '\r'; 414 | break; 415 | case 't': 416 | c = '\t'; 417 | break; 418 | case 'v': 419 | c = '\v'; 420 | break; 421 | case '\'': 422 | case '"': 423 | case '\\': 424 | case '\?': 425 | c = p[-1]; 426 | break; 427 | case '0': 428 | case '1': 429 | case '2': 430 | case '3': 431 | case '4': 432 | case '5': 433 | case '6': 434 | case '7': 435 | c = p[-1] - '0'; 436 | if (*p >= '0' && *p <= '7') { 437 | c = (c << 3) + (*p++) - '0'; 438 | if (*p >= '0' && *p <= '7') 439 | c = (c << 3) + (*p++) - '0'; 440 | } 441 | break; 442 | case 'x': 443 | n = wide ? 2 * sizeof(wchar_t) : 2 * sizeof(char); 444 | for (i = 0; ISXDIGIT(*p); p++, i++) { 445 | if (i >= n) 446 | error(0, "hex escape sequence out of range"); 447 | 448 | if (ISDIGIT(*p)) 449 | c = (c << 4) + *p - '0'; 450 | else 451 | c = (c << 4) + (*p & 0x5f) - 'A' + 10; 452 | } 453 | if (i == 0) 454 | error(0, "\\x used with no following hex digits"); 455 | break; 456 | /* 457 | * Univeral Character Name: 458 | * The C99 standard permits $, @ and ` to be specified as UCNs. 459 | */ 460 | case 'u': 461 | n = 4; 462 | goto ucn; 463 | case 'U': 464 | n = 8; 465 | ucn: 466 | if (ucn) *ucn = 1; 467 | for (i = 0; ISXDIGIT(*p); i++, p++) { 468 | if (i == n) 469 | break; 470 | if (ISDIGIT(*p)) 471 | c = (c << 4) + *p - '0'; 472 | else 473 | c = (c << 4) + (*p & 0x5f) - 'A' + 10; 474 | } 475 | if (i < n) 476 | error(0, "incomplete universal character name"); 477 | else if (invalid_ucn(c)) 478 | error(0, "invalid universal character"); 479 | break; 480 | default: 481 | c = p[-1]; 482 | warn(0, "unknown escape sequence '\\x%X'", c); 483 | break; 484 | } 485 | 486 | if (result) 487 | *result = c; 488 | return p; 489 | } 490 | 491 | void *eval_string(struct token *t, int wide, size_t *len) 492 | { 493 | const char *s = t->val.str; 494 | size_t i = 0; 495 | size_t alloc = strlen(s); 496 | char *d = xmalloc(alloc); 497 | 498 | assert(s[0] == '"' || s[0] == 'L'); 499 | 500 | if (s[0] == 'L') 501 | s += 2; 502 | else 503 | s += 1; 504 | 505 | while (*s != '"' && *s != 0) { 506 | int c, ucn; 507 | const char *p; 508 | 509 | if (*s != '\\') { 510 | d[i++] = *s++; 511 | continue; 512 | } 513 | p = read_escape_char(s, wide, &c, &ucn); 514 | if (ucn || (s[1] == 'x' && wide)) { 515 | int mblen; 516 | char mbs[MB_LEN_MAX]; 517 | 518 | mblen = wc2mb(mbs, c); 519 | if (i + mblen > alloc) { 520 | alloc = i + mblen + 16; 521 | d = xrealloc(d, alloc); 522 | } 523 | for (int k = 0; k < mblen; k++) 524 | d[i++] = mbs[k]; 525 | } else { 526 | d[i++] = c; 527 | } 528 | s = p; 529 | } 530 | d[i++] = 0; 531 | 532 | if (wide) { 533 | wchar_t *pwcs = xmalloc(i * sizeof(wchar_t)); 534 | size_t count = mbs2wcs(pwcs, d, i-1); 535 | assert(count < i); 536 | pwcs[count++] = 0; 537 | if (len) *len = count; 538 | free(d); 539 | return pwcs; 540 | } 541 | 542 | if (len) *len = i; 543 | return d; 544 | } 545 | 546 | static void eval_char(struct token *t, struct svalue *v) 547 | { 548 | const char *p = t->val.str; 549 | int n = 0; 550 | int bytes = 0; 551 | 552 | p++; /* skip separator */ 553 | while (*p != 0 && *p != '\'') { 554 | int c, ucn; 555 | 556 | if (bytes >= sizeof(int)) { 557 | error(0, "character constant too large"); 558 | break; 559 | } 560 | 561 | if (*p == '\\') { 562 | p = read_escape_char(p, 0, &c, &ucn); 563 | if (ucn) { 564 | n = c; 565 | bytes += sizeof(int); 566 | } else { 567 | goto non_ucn; 568 | } 569 | } else { 570 | c = *p++; 571 | non_ucn: 572 | n = (n << 8) + c; 573 | bytes++; 574 | } 575 | } 576 | 577 | if (bytes > 1) 578 | warn(0, "multi-character character constant"); 579 | 580 | if (v) { 581 | v->i = n; 582 | v->suffix = 0; 583 | v->base = 10; 584 | v->id = TOK_ICON; 585 | } 586 | } 587 | 588 | static void eval_wchar(struct token *t, struct svalue *v) 589 | { 590 | const char *p = t->val.str; 591 | wchar_t n = 0; 592 | 593 | p += 2; /* skip 'L' and separator */ 594 | if (*p != 0 && *p != '\'') { 595 | int c, ucn, r; 596 | 597 | if (*p == '\\') { 598 | p = read_escape_char(p, 1, &c, &ucn); 599 | if (ucn) { 600 | n = c; 601 | } else { 602 | char ch = c; 603 | errno = 0; 604 | r = mb2wc(&n, &ch, 1); 605 | if (r < 0) 606 | error(0, "invalid multibyte sequence"); 607 | } 608 | } else { 609 | errno = 0; 610 | r = mb2wc(&n, p, strlen(p) - 1); 611 | if (r < 0) 612 | error(0, "invalid multibyte sequence"); 613 | else 614 | p += r; 615 | } 616 | } 617 | 618 | if (*p != 0 && *p != '\'') 619 | error(0, "character constant too large"); 620 | 621 | if (v) { 622 | v->i = n; 623 | v->suffix = 0; 624 | v->base = 10; 625 | v->id = TOK_ICON; 626 | } 627 | } 628 | 629 | /* 0-9 or .[0-9] */ 630 | static int classify_number(struct token *t) 631 | { 632 | const char *p = t->val.str; 633 | 634 | if (p[0] == '.') 635 | return TOK_FCON; 636 | 637 | if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 638 | /* Hex */ 639 | p += 2; 640 | if (*p == '.') 641 | return TOK_FCON; 642 | 643 | while (ISXDIGIT(*p)) 644 | p++; 645 | if (*p == '.' || *p == 'p' || *p == 'P') 646 | return TOK_FCON; 647 | else 648 | return TOK_ICON; 649 | } else { 650 | /* Oct/Dec */ 651 | assert(ISDIGIT(*p)); 652 | 653 | while (ISDIGIT(*p)) 654 | p++; 655 | if (*p == '.' || *p == 'e' || *p == 'E') 656 | return TOK_FCON; 657 | else 658 | return TOK_ICON; 659 | } 660 | } 661 | 662 | void eval_number(struct token *t, struct svalue *v) 663 | { 664 | switch (t->id) { 665 | case TOK_PP_NUMBER: 666 | switch (classify_number(t)) { 667 | case TOK_ICON: 668 | eval_int(t, v); 669 | break; 670 | case TOK_FCON: 671 | eval_float(t, v); 672 | break; 673 | default: 674 | abort(); 675 | } 676 | break; 677 | case TOK_PP_CHAR: 678 | eval_char(t, v); 679 | break; 680 | case TOK_PP_WCHAR: 681 | eval_wchar(t, v); 682 | break; 683 | default: 684 | abort(); 685 | } 686 | } 687 | 688 | struct node *node(int op, struct node *l, struct node *r) 689 | { 690 | struct node *p = zallocate(sizeof(struct node), FUNC); 691 | p->op = op; 692 | p->left = l; 693 | p->right = r; 694 | if (l) 695 | p->line = l->line; 696 | else if (r) 697 | p->line = r->line; 698 | else 699 | p->line = lineno; 700 | return p; 701 | } 702 | 703 | struct node *node1(int op, struct node *l, struct node *r) 704 | { 705 | struct node *p = node(op, l, r); 706 | p->line = nearln; 707 | return p; 708 | } 709 | 710 | void nodnew(struct node *dst, int op, struct node *l, struct node *r) 711 | { 712 | dst->op = op; 713 | dst->left = l; 714 | dst->right = r; 715 | if (l) 716 | dst->line = l->line; 717 | else if (r) 718 | dst->line = r->line; 719 | else 720 | dst->line = lineno; 721 | } 722 | 723 | struct node *invert(struct node *p) 724 | { 725 | if (p == NULL || p->op != OLIST) 726 | return p; 727 | for (struct node *q = p->left; q; q = q->left) { 728 | if (q->op != OLIST) 729 | break; 730 | p->left = q->right; 731 | q->right = p; 732 | p = q; 733 | } 734 | return p; 735 | } 736 | 737 | struct node *newlist(struct node *l, struct node *r) 738 | { 739 | if (r == NULL) 740 | return l; 741 | if (l == NULL) 742 | return r; 743 | return node(OLIST, l, r); 744 | } 745 | 746 | int bitno(int b) 747 | { 748 | for (int i = 0; i < 32; i++) 749 | if (b & (1 << i)) 750 | return i; 751 | error(0, "bad bitno"); 752 | return 0; 753 | } 754 | 755 | int bitwiseq(int q) 756 | { 757 | q &= QMASK; 758 | switch (q) { 759 | case QCONST: 760 | return BCONST; 761 | case QVOLATILE: 762 | return BVOLATILE; 763 | case QCONST | QVOLATILE: 764 | return BCONST | BVOLATILE; 765 | } 766 | return 0; 767 | } 768 | 769 | int simpleq(int b) 770 | { 771 | b &= BQUAL; 772 | switch (b) { 773 | case BCONST: 774 | return QCONST; 775 | case BVOLATILE: 776 | return QVOLATILE; 777 | case BCONST | BVOLATILE: 778 | return QCONST | QVOLATILE; 779 | } 780 | return QXXX; 781 | } 782 | 783 | int btot(int b) 784 | { 785 | b &= BQUAL; 786 | switch (b) { 787 | case BCONST: 788 | return TCONST; 789 | case BVOLATILE: 790 | return TVOLATILE; 791 | case BCONST | BVOLATILE: 792 | return TCONST + TVOLATILE; 793 | } 794 | return TXXX; 795 | } 796 | 797 | int ttoq(int t) 798 | { 799 | switch (t) { 800 | case TCONST: 801 | return QCONST; 802 | case TVOLATILE: 803 | return QVOLATILE; 804 | case TCONST + TVOLATILE: 805 | return QCONST | QVOLATILE; 806 | } 807 | return QXXX; 808 | } 809 | 810 | int simplec(int b) 811 | { 812 | b &= BCLASS; 813 | switch (b) { 814 | case 0: 815 | return CXXX; 816 | case BAUTO: 817 | return CAUTO; 818 | case BEXTERN: 819 | return CEXTERN; 820 | case BSTATIC: 821 | return CSTATIC; 822 | case BTYPEDEF: 823 | return CTYPEDEF; 824 | case BREGISTER: 825 | return CREGISTER; 826 | } 827 | error(0, "illegal combination of storage classes %Q", b); 828 | return CXXX; 829 | } 830 | 831 | struct type *simplet(int b, struct type *ty) 832 | { 833 | b &= ~BCLASS & ~BQUAL; 834 | switch (b) { 835 | case BBOOL: 836 | return types[TBOOL]; 837 | 838 | case BCHAR: 839 | case BCHAR | BSIGNED: 840 | return types[TCHAR]; 841 | 842 | case BCHAR | BUNSIGNED: 843 | return types[TUCHAR]; 844 | 845 | case BSHORT: 846 | case BSHORT | BINT: 847 | case BSHORT | BSIGNED: 848 | case BSHORT | BINT | BSIGNED: 849 | return types[TSHORT]; 850 | 851 | case BSHORT | BUNSIGNED: 852 | case BSHORT | BUNSIGNED | BINT: 853 | return types[TUSHORT]; 854 | 855 | case 0: 856 | warn(0, "type specifier missing, defaults to int"); 857 | case BINT: 858 | case BINT | BSIGNED: 859 | case BSIGNED: 860 | return types[TINT]; 861 | 862 | case BUNSIGNED: 863 | case BUNSIGNED | BINT: 864 | return types[TUINT]; 865 | 866 | case BLONG: 867 | case BLONG | BINT: 868 | case BLONG | BSIGNED: 869 | case BLONG | BINT | BSIGNED: 870 | return types[TLONG]; 871 | 872 | case BLONG | BUNSIGNED: 873 | case BLONG | BUNSIGNED | BINT: 874 | return types[TULONG]; 875 | 876 | case BLLONG | BLONG: 877 | case BLLONG | BLONG | BINT: 878 | case BLLONG | BLONG | BSIGNED: 879 | case BLLONG | BLONG | BINT | BSIGNED: 880 | return types[TLLONG]; 881 | 882 | case BLLONG | BLONG | BUNSIGNED: 883 | case BLLONG | BLONG | BUNSIGNED | BINT: 884 | return types[TULLONG]; 885 | 886 | case BFLOAT: 887 | return types[TFLOAT]; 888 | 889 | case BDOUBLE: 890 | case BDOUBLE | BLONG: 891 | return types[TDOUBLE]; 892 | 893 | case BVOID: 894 | return types[TVOID]; 895 | 896 | case BENUM: 897 | case BSTRUCT: 898 | case BUNION: 899 | case BTYPENAME: 900 | return ty; 901 | } 902 | 903 | error(0, "illegal combination of types %Q", b); 904 | return types[TINT]; 905 | } 906 | 907 | int typebitor(int a, int b) 908 | { 909 | int c = a | b; 910 | if (a & b) { 911 | if (a & b & BQUAL) 912 | warn(0, "duplicate type qualifier %Q", a & b); 913 | else if (a & b & BCLASS) 914 | error(0, "duplicate storage class %Q", a & b); 915 | else if ((a & b) == BLONG && (c & BLLONG) == 0) 916 | c |= BLLONG; /* long long */ 917 | else 918 | error(0, "duplicate type specifier %Q", a & b); 919 | } 920 | return c; 921 | } 922 | 923 | struct symbol *anonymous(void) 924 | { 925 | static int i = 1; 926 | struct symbol *s; 927 | char str[30]; 928 | 929 | snprintf(str, sizeof str, ".L%d", i++); 930 | s = lookup(str, OPT_CREATE); 931 | s->anonymous = 1; 932 | return s; 933 | } 934 | 935 | /* local static variable */ 936 | struct symbol *mkstatic(struct symbol *s) 937 | { 938 | struct symbol *s1; 939 | 940 | if (s->block == 0 || s->sclass != CSTATIC) 941 | return s; 942 | 943 | s1 = lookup(stringf("%s$%d", s->name, s->block), OPT_CREATE); 944 | if (s1->sclass != CSTATIC) { 945 | s1->type = s->type; 946 | s1->offset = s->offset; 947 | s1->block = s->block; 948 | s1->line = s->line; 949 | s1->sclass = CSTATIC; 950 | } 951 | return s1; 952 | } 953 | 954 | struct node *cnstnode(struct type *ty, ...) 955 | { 956 | struct node *p; 957 | va_list ap; 958 | 959 | p = node(OCONST, NULL, NULL); 960 | va_start(ap, ty); 961 | if (typei[ty->etype]) 962 | p->v.i = convltox(va_arg(ap, long), ty->etype); 963 | else if (typefd[ty->etype]) 964 | p->v.d = va_arg(ap, double); 965 | else if (ty->etype == TPTR) 966 | p->v.p = va_arg(ap, void *); 967 | else 968 | abort(); 969 | va_end(ap); 970 | p->type = ty; 971 | 972 | return p; 973 | } 974 | 975 | long convltox(long v, int et) 976 | { 977 | int n; 978 | 979 | n = 8 * typsize[et]; 980 | v &= MASK(n); 981 | if (!typeu[et]) 982 | if (v & SIGN(n)) 983 | v |= ~MASK(n); 984 | return v; 985 | } 986 | 987 | int log2i(size_t i) 988 | { 989 | int r; 990 | 991 | if (i == 0) 992 | return -1; 993 | r = 0; 994 | while ((i & 0x01) == 0) { 995 | r++; 996 | i >>= 1; 997 | } 998 | return i >> 1 ? -1 : r; 999 | } 1000 | 1001 | void prstruct(struct type *ty) 1002 | { 1003 | if (typesu[ty->etype]) { 1004 | print("%s \"%s\": S=%ld A=%d\n", 1005 | tnames[ty->etype], 1006 | ty->tag->anonymous ? "{}" : ty->tag->name, 1007 | ty->size, ty->align); 1008 | for (struct type *q = ty->link; q; q = q->next) 1009 | print(" \"%s\": O=%ld S=%ld BO=%d BS=%d\n", 1010 | q->sym ? q->sym->name : "", 1011 | q->offset, q->size, q->bitoff, q->nbits); 1012 | } 1013 | } 1014 | 1015 | void prdecl(struct symbol *s) 1016 | { 1017 | print("decl \"%s\": C=%s B=%d O=%ld T=%T\n", 1018 | s->name, cnames[s->sclass], s->block, s->offset, s->type); 1019 | } 1020 | 1021 | static void prtree1(struct node *p, int lev, int f) 1022 | { 1023 | static int dumplist = 0; 1024 | int i; 1025 | 1026 | if (f) 1027 | for (i = 0; i < lev; i++) 1028 | print(" "); 1029 | 1030 | if (p == NULL) { 1031 | print("Z\n"); 1032 | return; 1033 | } 1034 | if (p->op == OLIST && dumplist == 0) { 1035 | prtree1(p->left, lev, 0); 1036 | prtree1(p->right, lev, 1); 1037 | return; 1038 | } 1039 | lev++; 1040 | print("%O", p->op); 1041 | i = 3; 1042 | switch (p->op) { 1043 | case OELEM: 1044 | i = 0; 1045 | if (p->sym) 1046 | print(" \".%s\"", p->sym->name); 1047 | break; 1048 | 1049 | case OARRAY: 1050 | i = 0; 1051 | print(" [%ld]", p->v.i); 1052 | break; 1053 | 1054 | case ONAME: 1055 | i = 0; 1056 | if (p->sym) 1057 | print(" \"%s\"", p->sym->name); 1058 | print(" %ld", p->offset); 1059 | break; 1060 | 1061 | case OCOMPOUND: 1062 | print(" \"%s\" %ld", p->sym->name, p->offset); 1063 | break; 1064 | 1065 | case OCONST: 1066 | i = 0; 1067 | if (typefd[p->type->etype]) 1068 | print(" \"%f\"", p->v.d); 1069 | else 1070 | print(" \"%ld\"", p->v.i); 1071 | break; 1072 | 1073 | case OSTRING: 1074 | i = 0; 1075 | print(" \"%s\" %ld", p->v.cstring, p->offset); 1076 | break; 1077 | 1078 | case OREGISTER: 1079 | i = 0; 1080 | print(" \"%d\"", p->reg); 1081 | break; 1082 | 1083 | case OINDREG: 1084 | print(" \"%d\" (%ld)", p->reg, p->offset); 1085 | break; 1086 | } 1087 | if (p->type) 1088 | print(" %T", p->type); 1089 | print(" %L\n", p->line); 1090 | if (i & 1) 1091 | prtree1(p->left, lev, 1); 1092 | if (i & 2) 1093 | prtree1(p->right, lev, 1); 1094 | } 1095 | 1096 | void prtree(struct node *p, const char *s) 1097 | { 1098 | print("=== %s ===\n",s ); 1099 | prtree1(p, 0, 0); 1100 | print("\n"); 1101 | } 1102 | -------------------------------------------------------------------------------- /symtab.c: -------------------------------------------------------------------------------- 1 | #include "cc.h" 2 | 3 | static struct symbol **symtab; 4 | static unsigned int nslots; /* number of slots */ 5 | static unsigned int nelements; /* number of elements */ 6 | static unsigned int searches; 7 | static unsigned int collisions; 8 | static unsigned int expansions; 9 | 10 | static void expand(void) 11 | { 12 | unsigned int oldsize = nslots; 13 | struct symbol **oldtable = symtab; 14 | unsigned int sizemask; 15 | 16 | /* nslots must be 2^n */ 17 | if (oldsize == 0) { 18 | nslots = 8 * 1024; 19 | } else { 20 | nslots = oldsize * 2; 21 | expansions++; 22 | } 23 | 24 | symtab = xcalloc(nslots, sizeof(struct symbol *)); 25 | sizemask = nslots - 1; 26 | 27 | for (unsigned int i = 0; i < oldsize; i++) { 28 | struct symbol *entry = oldtable[i]; 29 | while (entry) { 30 | struct symbol *next = entry->link; 31 | unsigned int index = entry->hash & sizemask; 32 | entry->link = symtab[index]; 33 | symtab[index] = entry; 34 | entry = next; 35 | } 36 | } 37 | free(oldtable); 38 | } 39 | 40 | struct symbol *lookupn(const char *str, size_t len, int opt) 41 | { 42 | unsigned int index, hash; 43 | struct symbol *p; 44 | char *dst; 45 | 46 | if (nelements * 4 >= nslots * 3) 47 | expand(); 48 | 49 | searches++; 50 | hash = strnhash(str, len); 51 | index = hash & (nslots - 1); 52 | 53 | for (p = symtab[index]; p; p = p->link) 54 | if (p->len == len && !memcmp(str, p->name, len)) 55 | return p; 56 | 57 | if (symtab[index]) 58 | collisions++; 59 | if (opt == OPT_SEARCH) 60 | return NULL; 61 | 62 | nelements++; 63 | p = zmalloc(sizeof(struct symbol)); 64 | p->len = len; 65 | p->hash = hash; 66 | dst = xmalloc(len + 1); 67 | memcpy(dst, str, len); 68 | dst[len] = '\0'; 69 | p->name = dst; 70 | 71 | p->link = symtab[index]; 72 | symtab[index] = p; 73 | 74 | return p; 75 | } 76 | 77 | struct symbol *lookup(const char *id, int opt) 78 | { 79 | return lookupn(id, strlen(id), opt); 80 | } 81 | 82 | void foreach(void (*cb)(struct symbol *, void *), void *v) 83 | { 84 | for (unsigned int i = 0; i < nslots; i++) { 85 | struct symbol *entry = symtab[i]; 86 | while (entry) { 87 | struct symbol *next = entry->link; 88 | cb(entry, v); 89 | entry = next; 90 | } 91 | } 92 | } 93 | 94 | void dump_symtab(void) 95 | { 96 | printf("symtab: %u elements, %u slots, %u searches, %u collisions, %u expansions.\n", 97 | nelements, nslots, searches, collisions, expansions); 98 | } -------------------------------------------------------------------------------- /tokens.c: -------------------------------------------------------------------------------- 1 | #include "cc.h" 2 | 3 | char map[256]; 4 | static struct init map_init[] = { 5 | '\t', BLANK, 0, 6 | '\n', NEWLINE, 0, 7 | '\v', BLANK, 0, 8 | '\f', BLANK, 0, 9 | '\r', BLANK, 0, 10 | ' ', BLANK, 0, 11 | '0', DIGIT, 0, 12 | '1', DIGIT, 0, 13 | '2', DIGIT, 0, 14 | '3', DIGIT, 0, 15 | '4', DIGIT, 0, 16 | '5', DIGIT, 0, 17 | '6', DIGIT, 0, 18 | '7', DIGIT, 0, 19 | '8', DIGIT, 0, 20 | '9', DIGIT, 0, 21 | '_', LETTER, 0, 22 | 'A', LETTER|HEX, 0, 'a', LETTER|HEX, 0, 23 | 'B', LETTER|HEX, 0, 'b', LETTER|HEX, 0, 24 | 'C', LETTER|HEX, 0, 'c', LETTER|HEX, 0, 25 | 'D', LETTER|HEX, 0, 'd', LETTER|HEX, 0, 26 | 'E', LETTER|HEX, 0, 'e', LETTER|HEX, 0, 27 | 'F', LETTER|HEX, 0, 'f', LETTER|HEX, 0, 28 | 'G', LETTER, 0, 'g', LETTER, 0, 29 | 'H', LETTER, 0, 'h', LETTER, 0, 30 | 'I', LETTER, 0, 'i', LETTER, 0, 31 | 'J', LETTER, 0, 'j', LETTER, 0, 32 | 'K', LETTER, 0, 'k', LETTER, 0, 33 | 'L', LETTER, 0, 'l', LETTER, 0, 34 | 'M', LETTER, 0, 'm', LETTER, 0, 35 | 'N', LETTER, 0, 'n', LETTER, 0, 36 | 'O', LETTER, 0, 'o', LETTER, 0, 37 | 'P', LETTER, 0, 'p', LETTER, 0, 38 | 'Q', LETTER, 0, 'q', LETTER, 0, 39 | 'R', LETTER, 0, 'r', LETTER, 0, 40 | 'S', LETTER, 0, 's', LETTER, 0, 41 | 'T', LETTER, 0, 't', LETTER, 0, 42 | 'U', LETTER, 0, 'u', LETTER, 0, 43 | 'V', LETTER, 0, 'v', LETTER, 0, 44 | 'W', LETTER, 0, 'w', LETTER, 0, 45 | 'X', LETTER, 0, 'x', LETTER, 0, 46 | 'Y', LETTER, 0, 'y', LETTER, 0, 47 | 'Z', LETTER, 0, 'z', LETTER, 0, 48 | -1, 0, 0 49 | }; 50 | 51 | int kinds[NTOKEN]; 52 | static struct init kinds_init[] = { 53 | TOK_AUTO, TOK_STATIC, 0, 54 | TOK_EXTERN, TOK_STATIC, 0, 55 | TOK_REGISTER, TOK_STATIC, 0, 56 | TOK_STATIC, TOK_STATIC, 0, 57 | TOK_TYPEDEF, TOK_STATIC, 0, 58 | TOK_BREAK, TOK_IF, 0, 59 | TOK_CASE, TOK_IF, 0, 60 | TOK_CONTINUE, TOK_IF, 0, 61 | TOK_DEFAULT, TOK_IF, 0, 62 | TOK_DO, TOK_IF, 0, 63 | TOK_ELSE, TOK_IF, 0, 64 | TOK_FOR, TOK_IF, 0, 65 | TOK_GOTO, TOK_IF, 0, 66 | TOK_IF, TOK_IF, 0, 67 | TOK_RETURN, TOK_IF, 0, 68 | TOK_SWITCH, TOK_IF, 0, 69 | TOK_WHILE, TOK_IF, 0, 70 | ';', TOK_IF, 0, 71 | '{', TOK_IF, 0, 72 | TOK_SIZEOF, TOK_NAME, 0, 73 | '!', TOK_NAME, 0, 74 | '&', TOK_NAME, 0, 75 | '(', TOK_NAME, 0, 76 | '*', TOK_NAME, 0, 77 | '+', TOK_NAME, 0, 78 | '-', TOK_NAME, 0, 79 | TOK_INCR, TOK_NAME, 0, 80 | TOK_DECR, TOK_NAME, 0, 81 | TOK_ICON, TOK_NAME, 0, 82 | TOK_FCON, TOK_NAME, 0, 83 | TOK_SCON, TOK_NAME, 0, 84 | TOK_WSCON, TOK_NAME, 0, 85 | TOK_NAME, TOK_NAME, 0, 86 | TOK_PP_NUMBER, TOK_NAME, 0, 87 | TOK_PP_CHAR, TOK_NAME, 0, 88 | TOK_PP_WCHAR, TOK_NAME, 0, 89 | '~', TOK_NAME, 0, 90 | TOK_VOID, TOK_INT, 0, 91 | TOK_BOOL, TOK_INT, 0, 92 | TOK_CHAR, TOK_INT, 0, 93 | TOK_SHORT, TOK_INT, 0, 94 | TOK_ENUM, TOK_INT, 0, 95 | TOK_SIGNED, TOK_INT, 0, 96 | TOK_INT, TOK_INT, 0, 97 | TOK_UNSIGNED, TOK_INT, 0, 98 | TOK_LONG, TOK_INT, 0, 99 | TOK_FLOAT, TOK_INT, 0, 100 | TOK_DOUBLE, TOK_INT, 0, 101 | TOK_STRUCT, TOK_INT, 0, 102 | TOK_UNION, TOK_INT, 0, 103 | TOK_INLINE, TOK_INT, 0, 104 | TOK_CONST, TOK_CONST, 0, 105 | TOK_RESTRICT, TOK_CONST, 0, 106 | TOK_VOLATILE, TOK_CONST, 0, 107 | '=', '=', 0, 108 | TOK_MULEQ, '=', 0, 109 | TOK_ADDEQ, '=', 0, 110 | TOK_SUBEQ, '=', 0, 111 | TOK_DIVEQ, '=', 0, 112 | TOK_MODEQ, '=', 0, 113 | TOK_XOREQ, '=', 0, 114 | TOK_ANDEQ, '=', 0, 115 | TOK_OREQ, '=', 0, 116 | TOK_SHLEQ, '=', 0, 117 | TOK_SHREQ, '=', 0, 118 | -1, 0, 0 119 | }; 120 | 121 | char precs[NTOKEN]; 122 | static struct init precs_init[] = { 123 | '%', PREC_MUL, 0, 124 | '*', PREC_MUL, 0, 125 | '/', PREC_MUL, 0, 126 | '+', PREC_ADD, 0, 127 | '-', PREC_ADD, 0, 128 | TOK_SHL, PREC_SHIFT, 0, 129 | TOK_SHR, PREC_SHIFT, 0, 130 | '<', PREC_REL, 0, 131 | '>', PREC_REL, 0, 132 | TOK_GEQ, PREC_REL, 0, 133 | TOK_LEQ, PREC_REL, 0, 134 | TOK_EQ, PREC_EQ, 0, 135 | TOK_NEQ, PREC_EQ, 0, 136 | '&', PREC_AND, 0, 137 | '^', PREC_XOR, 0, 138 | '|', PREC_OR, 0, 139 | TOK_ANDAND, PREC_ANDAND, 0, 140 | TOK_OROR, PREC_OROR, 0, 141 | -1, 0, 0 142 | }; 143 | 144 | const char *lexmes[NTOKEN]; 145 | static struct init lexmes_init[] = { 146 | TOK_XXX, 0, "", 147 | TOK_AUTO, 0, "auto", 148 | TOK_EXTERN, 0, "extern", 149 | TOK_REGISTER, 0, "register", 150 | TOK_STATIC, 0, "static", 151 | TOK_TYPEDEF, 0, "typedef", 152 | TOK_BREAK, 0, "break", 153 | TOK_CASE, 0, "case", 154 | TOK_CONTINUE, 0, "continue", 155 | TOK_DEFAULT, 0, "default", 156 | TOK_DO, 0, "do", 157 | TOK_ELSE, 0, "else", 158 | TOK_FOR, 0, "for", 159 | TOK_GOTO, 0, "goto", 160 | TOK_IF, 0, "if", 161 | TOK_RETURN, 0, "return", 162 | TOK_SWITCH, 0, "switch", 163 | TOK_WHILE, 0, "while", 164 | TOK_SIZEOF, 0, "sizeof", 165 | TOK_VOID, 0, "void", 166 | TOK_BOOL, 0, "_Bool", 167 | TOK_CHAR, 0, "char", 168 | TOK_SHORT, 0, "short", 169 | TOK_ENUM, 0, "enum", 170 | TOK_SIGNED, 0, "signed", 171 | TOK_INT, 0, "int", 172 | TOK_UNSIGNED, 0, "unsigned", 173 | TOK_LONG, 0, "long", 174 | TOK_FLOAT, 0, "float", 175 | TOK_DOUBLE, 0, "double", 176 | TOK_STRUCT, 0, "struct", 177 | TOK_UNION, 0, "union", 178 | TOK_INLINE, 0, "inline", 179 | TOK_CONST, 0, "const", 180 | TOK_VOLATILE, 0, "volatile", 181 | TOK_RESTRICT, 0, "restrict", 182 | TOK_MULEQ, 0, "*=", 183 | TOK_ADDEQ, 0, "+=", 184 | TOK_SUBEQ, 0, "-=", 185 | TOK_DIVEQ, 0, "/=", 186 | TOK_MODEQ, 0, "%=", 187 | TOK_XOREQ, 0, "^=", 188 | TOK_ANDEQ, 0, "&=", 189 | TOK_OREQ, 0, "|=", 190 | TOK_SHLEQ, 0, "<<=", 191 | TOK_SHREQ, 0, ">>=", 192 | TOK_SHL, 0, "<<", 193 | TOK_SHR, 0, ">>", 194 | TOK_GEQ, 0, ">=", 195 | TOK_LEQ, 0, "<=", 196 | TOK_EQ, 0, "==", 197 | TOK_NEQ, 0, "!=", 198 | TOK_INCR, 0, "++", 199 | TOK_DECR, 0, "--", 200 | TOK_DEREF, 0, "->", 201 | TOK_ANDAND, 0, "&&", 202 | TOK_OROR, 0, "||", 203 | TOK_ELLIPSIS, 0, "...", 204 | TOK_ICON, 0, "ICON", 205 | TOK_FCON, 0, "FCON", 206 | TOK_SCON, 0, "SCON", 207 | TOK_WSCON, 0, "WSCON", 208 | TOK_NAME, 0, "identifier", 209 | TOK_INVALID, 0, "INVALID", 210 | TOK_PASTE, 0, "##", 211 | TOK_PP_NUMBER, 0, "PP_NUMBER", 212 | TOK_PP_CHAR, 0, "PP_CHAR", 213 | TOK_PP_WCHAR, 0, "PP_WCHAR", 214 | TOK_PP_HEADER_NAME, 0, "PP_HEADER_NAME", 215 | TOK_PP_MACRO_ARG, 0, "PP_MACRO_ARG", 216 | TOK_EOF, 0, "EOF", 217 | '!', 0, "!", 218 | '#', 0, "#", 219 | '$', 0, "$", 220 | '%', 0, "%", 221 | '&', 0, "&", 222 | '(', 0, "(", 223 | ')', 0, ")", 224 | '*', 0, "*", 225 | '+', 0, "+", 226 | ',', 0, ",", 227 | '-', 0, "-", 228 | '.', 0, ".", 229 | '/', 0, "/", 230 | ':', 0, ":", 231 | ';', 0, ";", 232 | '<', 0, "<", 233 | '=', 0, "=", 234 | '>', 0, ">", 235 | '?', 0, "?", 236 | '@', 0, "@", 237 | '[', 0, "[", 238 | ']', 0, "]", 239 | '^', 0, "^", 240 | '{', 0, "{", 241 | '|', 0, "|", 242 | '}', 0, "}", 243 | '~', 0, "~", 244 | -1, 0, 0 245 | }; 246 | 247 | static struct init keyword_init[] = { 248 | TOK_AUTO, 0, 0, 249 | TOK_BREAK, 0, 0, 250 | TOK_CASE, 0, 0, 251 | TOK_CHAR, 0, 0, 252 | TOK_CONST, 0, 0, 253 | TOK_CONST, 0, "__const", 254 | TOK_CONTINUE, 0, 0, 255 | TOK_DEFAULT, 0, 0, 256 | TOK_DO, 0, 0, 257 | TOK_DOUBLE, 0, 0, 258 | TOK_ELSE, 0, 0, 259 | TOK_ENUM, 0, 0, 260 | TOK_EXTERN, 0, 0, 261 | TOK_FLOAT, 0, 0, 262 | TOK_FOR, 0, 0, 263 | TOK_GOTO, 0, 0, 264 | TOK_IF, 0, 0, 265 | TOK_INLINE, 0, 0, 266 | TOK_INLINE, 0, "__inline", 267 | TOK_INLINE, 0, "__inline__", 268 | TOK_INT, 0, 0, 269 | TOK_LONG, 0, 0, 270 | TOK_REGISTER, 0, 0, 271 | TOK_RESTRICT, 0, 0, 272 | TOK_RESTRICT, 0, "__restrict", 273 | TOK_RESTRICT, 0, "__restrict__", 274 | TOK_RETURN, 0, 0, 275 | TOK_SHORT, 0, 0, 276 | TOK_SIGNED, 0, 0, 277 | TOK_SIGNED, 0, "__signed", 278 | TOK_SIGNED, 0, "__signed__", 279 | TOK_SIZEOF, 0, 0, 280 | TOK_STATIC, 0, 0, 281 | TOK_STRUCT, 0, 0, 282 | TOK_SWITCH, 0, 0, 283 | TOK_TYPEDEF, 0, 0, 284 | TOK_UNION, 0, 0, 285 | TOK_UNSIGNED, 0, 0, 286 | TOK_VOID, 0, 0, 287 | TOK_VOLATILE, 0, 0, 288 | TOK_VOLATILE, 0, "__volatile", 289 | TOK_VOLATILE, 0, "__volatile__", 290 | TOK_WHILE, 0, 0, 291 | TOK_BOOL, 0, 0, 292 | -1, 0, 0 293 | }; 294 | 295 | static struct init builtins_init[] = { 296 | BUILTIN_FUNC, 0, "__func__", 297 | BUILTIN_VA_START, 0, "__builtin_va_start", 298 | BUILTIN_VA_ARG, 0, "__builtin_va_arg", 299 | BUILTIN_VA_COPY, 0, "__builtin_va_copy", 300 | BUILTIN_VA_END, 0, "__builtin_va_end", 301 | BUILTIN_VA_LIST, 0, "__builtin_va_list", 302 | -1, 0, 0 303 | }; 304 | 305 | int bops[NTOKEN]; 306 | static struct init bops_init[] = { 307 | '%', OMOD, 0, 308 | '&', OAND, 0, 309 | '*', OMUL, 0, 310 | '+', OADD, 0, 311 | '-', OSUB, 0, 312 | '/', ODIV, 0, 313 | TOK_MULEQ, OASMUL, 0, 314 | TOK_ADDEQ, OASADD, 0, 315 | TOK_SUBEQ, OASSUB, 0, 316 | TOK_DIVEQ, OASDIV, 0, 317 | TOK_MODEQ, OASMOD, 0, 318 | '<', OLT, 0, 319 | '=', OAS, 0, 320 | '>', OGT, 0, 321 | TOK_XOREQ, OASXOR, 0, 322 | TOK_ANDEQ, OASAND, 0, 323 | TOK_OREQ, OASOR, 0, 324 | TOK_SHLEQ, OASSHL, 0, 325 | TOK_SHREQ, OASSHR, 0, 326 | TOK_SHL, OSHL, 0, 327 | TOK_SHR, OSHR, 0, 328 | TOK_GEQ, OGE, 0, 329 | TOK_LEQ, OLE, 0, 330 | TOK_EQ, OEQ, 0, 331 | TOK_NEQ, ONE, 0, 332 | TOK_ANDAND, OANDAND, 0, 333 | TOK_OROR, OOROR, 0, 334 | '^', OXOR, 0, 335 | '|', OOR, 0, 336 | -1, 0, 0, 337 | }; 338 | 339 | int uops[NTOKEN]; 340 | static struct init uops_init[] = { 341 | TOK_INCR, OPREINC, 0, 342 | TOK_DECR, OPREDEC, 0, 343 | '+', OPOS, 0, 344 | '-', ONEG, 0, 345 | '~', OCOM, 0, 346 | '!', ONOT, 0, 347 | '&', OADDR, 0, 348 | '*', OINDIR, 0, 349 | TOK_SIZEOF, OSIZEOF, 0, 350 | -1, 0, 0 351 | }; 352 | 353 | const char *tnames[NALLTYPE]; 354 | static struct init tnames_init[] = { 355 | TXXX, 0, "XXX", 356 | TBOOL, 0, "BOOL", 357 | TCHAR, 0, "CHAR", 358 | TUCHAR, 0, "UCHAR", 359 | TSHORT, 0, "SHORT", 360 | TUSHORT, 0, "USHORT", 361 | TINT, 0, "INT", 362 | TUINT, 0, "UINT", 363 | TLONG, 0, "LONG", 364 | TULONG, 0, "ULONG", 365 | TLLONG, 0, "LLONG", 366 | TULLONG, 0, "ULLONG", 367 | TFLOAT, 0, "FLOAT", 368 | TDOUBLE, 0, "DOUBLE", 369 | TVOID, 0, "VOID", 370 | TPTR, 0, "PTR", 371 | TFUNC, 0, "FUNC", 372 | TARRAY, 0, "ARRAY", 373 | TSTRUCT, 0, "STRUCT", 374 | TUNION, 0, "UNION", 375 | TENUM, 0, "ENUM", 376 | TCONST, 0, "CONST", 377 | TVOLATILE, 0, "VOLATILE", 378 | TUNSIGNED, 0, "UNSIGNED", 379 | TSIGNED, 0, "SIGNED", 380 | TAUTO, 0, "AUTO", 381 | TEXTERN, 0, "EXTERN", 382 | TSTATIC, 0, "STATIC", 383 | TTYPEDEF, 0, "TYPEDEF", 384 | TREGISTER, 0, "REGISTER", 385 | TTYPENAME, 0, "TYPENAME", 386 | -1, 0, 0 387 | }; 388 | 389 | const char *cnames[NCTYPE]; 390 | static struct init cnames_init[] = { 391 | CXXX, 0, "XXX", 392 | CAUTO, 0, "AUTO", 393 | CEXTERN, 0, "EXTERN", 394 | CSTATIC, 0, "STATIC", 395 | CTYPEDEF, 0, "TYPEDEF", 396 | CREGISTER, 0, "REGISTER", 397 | CGLOBAL, 0, "GLOBAL", 398 | CENUM, 0, "ENUM", 399 | CPARAM, 0, "PARAM", 400 | -1, 0, 0 401 | }; 402 | 403 | const char *onames[NOTYPE]; 404 | static struct init onames_init[] = { 405 | OXXX, 0, "XXX", 406 | OLIST, 0, "LIST", 407 | OCOMMA, 0, "COMMA", 408 | OAS, 0, "AS", 409 | OASI, 0, "ASI", 410 | OASMUL, 0, "ASMUL", 411 | OASUMUL, 0, "ASUMUL", 412 | OASADD, 0, "ASADD", 413 | OASSUB, 0, "ASSUB", 414 | OASDIV, 0, "ASDIV", 415 | OASUDIV, 0, "ASUDIV", 416 | OASMOD, 0, "ASMOD", 417 | OASUMOD, 0, "ASUMOD", 418 | OASXOR, 0, "ASXOR", 419 | OASAND, 0, "ASAND", 420 | OASOR, 0, "ASOR", 421 | OASSHL, 0, "ASSHL", 422 | OASSHR, 0, "ASSHR", 423 | OASUSHR, 0, "ASUSHR", 424 | OCOND, 0, "COND", 425 | OADD, 0, "ADD", 426 | OSUB, 0, "SUB", 427 | OMUL, 0, "MUL", 428 | OUMUL, 0, "UMUL", 429 | ODIV, 0, "DIV", 430 | OUDIV, 0, "UDIV", 431 | OMOD, 0, "MOD", 432 | OUMOD, 0, "UMOD", 433 | OAND, 0, "AND", 434 | OOR, 0, "OR", 435 | OSHL, 0, "SHL", 436 | OSHR, 0, "SHR", 437 | OUSHR, 0, "USHR", 438 | OXOR, 0, "XOR", 439 | OLT, 0, "LT", 440 | OLE, 0, "LE", 441 | OGT, 0, "GT", 442 | OGE, 0, "GE", 443 | OEQ, 0, "EQ", 444 | ONE, 0, "NE", 445 | OANDAND, 0, "ANDAND", 446 | OOROR, 0, "OROR", 447 | OCAST, 0, "CAST", 448 | OPREINC, 0, "PREINC", 449 | OPREDEC, 0, "PREDEC", 450 | OPOS, 0, "POS", 451 | ONEG, 0, "NEG", 452 | OCOM, 0, "COM", 453 | ONOT, 0, "NOT", 454 | OADDR, 0, "ADDR", 455 | OINDIR, 0, "INDIR", 456 | OSIZEOF, 0, "SIZEOF", 457 | OPOSTINC, 0, "POSTINC", 458 | OPOSTDEC, 0, "POSTDEC", 459 | ODOT, 0, "DOT", 460 | OFUNC, 0, "FUNC", 461 | ONAME, 0, "NAME", 462 | OCONST, 0, "CONST", 463 | OSTRING, 0, "STRING", 464 | OCOMPOUND, 0, "COMPOUND", 465 | OINIT, 0, "INIT", 466 | OELEM, 0, "ELEM", 467 | OARRAY, 0, "ARRAY", 468 | OPROTO, 0, "PROTO", 469 | OBIT, 0, "BIT", 470 | OZERO, 0, "ZERO", 471 | OREGISTER, 0, "OREGISTER", 472 | OINDREG, 0, "OINDREG", 473 | OIF, 0, "IF", 474 | OWHILE, 0, "WHILE", 475 | ODOWHILE, 0, "DOWHILE", 476 | OFOR, 0, "FOR", 477 | OSWITCH, 0, "SWITCH", 478 | OCASE, 0, "CASE", 479 | OLABEL, 0, "LABEL", 480 | OGOTO, 0, "GOTO", 481 | OBREAK, 0, "BREAK", 482 | OCONTINUE, 0, "CONTINUE", 483 | ORETURN, 0, "RETURN", 484 | -1, 0, 0 485 | }; 486 | 487 | void tokens_init(void) 488 | { 489 | struct init *p; 490 | struct symbol *sym; 491 | 492 | for (p = map_init; p->code >= 0; p++) 493 | map[p->code] = p->value; 494 | for (p = kinds_init; p->code >= 0; p++) 495 | kinds[p->code] = p->value; 496 | for (p = precs_init; p->code >= 0; p++) 497 | precs[p->code] = p->value; 498 | for (p = lexmes_init; p->code >= 0; p++) 499 | lexmes[p->code] = p->s; 500 | for (p = keyword_init; p->code >= 0; p++) { 501 | sym = lookup(p->s ? p->s : lexmes[p->code], OPT_CREATE); 502 | sym->keyword_id = p->code; 503 | } 504 | for (p = bops_init; p->code >= 0; p++) 505 | bops[p->code] = p->value; 506 | for (p = uops_init; p->code >= 0; p++) 507 | uops[p->code] = p->value; 508 | for (p = tnames_init; p->code >= 0; p++) 509 | tnames[p->code] = p->s; 510 | for (p = cnames_init; p->code >= 0; p++) 511 | cnames[p->code] = p->s; 512 | for (p = onames_init; p->code >= 0; p++) 513 | onames[p->code] = p->s; 514 | for (p = builtins_init; p->code >= 0; p++) 515 | if (p->s) { 516 | sym = lookup(p->s, OPT_CREATE); 517 | sym->builtin_id = p->code; 518 | } 519 | } 520 | -------------------------------------------------------------------------------- /types.c: -------------------------------------------------------------------------------- 1 | #include "cc.h" 2 | 3 | struct type *types[NTYPE]; 4 | 5 | /* integer type? */ 6 | char typei[NTYPE]; 7 | static int typei_init[] = { 8 | TBOOL, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, 9 | TLONG, TULONG, TLLONG, TULLONG, TENUM, -1 10 | }; 11 | 12 | /* unsigned type? */ 13 | char typeu[NTYPE]; 14 | static int typeu_init[] = { 15 | TBOOL, TUCHAR, TUSHORT, TUINT, TULONG, TULLONG, TPTR, -1 16 | }; 17 | 18 | /* float/double type? */ 19 | char typefd[NTYPE]; 20 | static int typefd_init[] = { 21 | TFLOAT, TDOUBLE, -1 22 | }; 23 | 24 | /* struct/union type? */ 25 | char typesu[NTYPE]; 26 | static int typesu_init[] = { 27 | TSTRUCT, TUNION, -1 28 | }; 29 | 30 | /* struct/union/enum type? */ 31 | char typesue[NTYPE]; 32 | static int typesue_init[] = { 33 | TSTRUCT, TUNION, TENUM, -1 34 | }; 35 | 36 | /* array/function type? */ 37 | char typeaf[NTYPE]; 38 | static int typeaf_init[] = { 39 | TARRAY, TFUNC, -1 40 | }; 41 | 42 | /* & */ 43 | int tand[NTYPE]; 44 | static struct init tand_init[] = { 45 | TBOOL, BINTEGER, 0, 46 | TCHAR, BINTEGER, 0, 47 | TUCHAR, BINTEGER, 0, 48 | TSHORT, BINTEGER, 0, 49 | TUSHORT, BINTEGER, 0, 50 | TINT, BINTEGER, 0, 51 | TUINT, BINTEGER, 0, 52 | TLONG, BINTEGER, 0, 53 | TULONG, BINTEGER, 0, 54 | TLLONG, BINTEGER, 0, 55 | TULLONG, BINTEGER, 0, 56 | TENUM, BINTEGER, 0, 57 | -1, 0, 0 58 | }; 59 | 60 | /* ! */ 61 | int tnot[1] = { 62 | BNUMBER | BPTR 63 | }; 64 | 65 | /* - */ 66 | int tneg[1] = { 67 | BNUMBER 68 | }; 69 | 70 | /* >, >=, <, <=, ==, != */ 71 | int trel[NTYPE]; 72 | static struct init trel_init[] = { 73 | TBOOL, BNUMBER, 0, 74 | TCHAR, BNUMBER, 0, 75 | TUCHAR, BNUMBER, 0, 76 | TSHORT, BNUMBER, 0, 77 | TUSHORT, BNUMBER, 0, 78 | TINT, BNUMBER, 0, 79 | TUINT, BNUMBER, 0, 80 | TLONG, BNUMBER, 0, 81 | TULONG, BNUMBER, 0, 82 | TLLONG, BNUMBER, 0, 83 | TULLONG, BNUMBER, 0, 84 | TFLOAT, BNUMBER, 0, 85 | TDOUBLE, BNUMBER, 0, 86 | TPTR, BPTR, 0, 87 | TENUM, BNUMBER, 0, 88 | -1, 0, 0 89 | }; 90 | 91 | /* + */ 92 | int tadd[NTYPE]; 93 | static struct init tadd_init[] = { 94 | TBOOL, BNUMBER | BPTR, 0, 95 | TCHAR, BNUMBER | BPTR, 0, 96 | TUCHAR, BNUMBER | BPTR, 0, 97 | TSHORT, BNUMBER | BPTR, 0, 98 | TUSHORT, BNUMBER | BPTR, 0, 99 | TINT, BNUMBER | BPTR, 0, 100 | TUINT, BNUMBER | BPTR, 0, 101 | TLONG, BNUMBER | BPTR, 0, 102 | TULONG, BNUMBER | BPTR, 0, 103 | TLLONG, BNUMBER | BPTR, 0, 104 | TULLONG, BNUMBER | BPTR, 0, 105 | TFLOAT, BNUMBER, 0, 106 | TDOUBLE, BNUMBER, 0, 107 | TPTR, BINTEGER, 0, 108 | TENUM, BNUMBER | BPTR, 0, 109 | -1, 0, 0 110 | }; 111 | 112 | /* - */ 113 | int tsub[NTYPE]; 114 | static struct init tsub_init[] = { 115 | TBOOL, BNUMBER, 0, 116 | TCHAR, BNUMBER, 0, 117 | TUCHAR, BNUMBER, 0, 118 | TSHORT, BNUMBER, 0, 119 | TUSHORT, BNUMBER, 0, 120 | TINT, BNUMBER, 0, 121 | TUINT, BNUMBER, 0, 122 | TLONG, BNUMBER, 0, 123 | TULONG, BNUMBER, 0, 124 | TLLONG, BNUMBER, 0, 125 | TULLONG, BNUMBER, 0, 126 | TFLOAT, BNUMBER, 0, 127 | TDOUBLE, BNUMBER, 0, 128 | TPTR, BINTEGER | BPTR, 0, 129 | TENUM, BNUMBER, 0, 130 | -1, 0, 0 131 | }; 132 | 133 | /* * */ 134 | int tmul[NTYPE]; 135 | static struct init tmul_init[] = { 136 | TBOOL, BNUMBER, 0, 137 | TCHAR, BNUMBER, 0, 138 | TUCHAR, BNUMBER, 0, 139 | TSHORT, BNUMBER, 0, 140 | TUSHORT, BNUMBER, 0, 141 | TINT, BNUMBER, 0, 142 | TUINT, BNUMBER, 0, 143 | TLONG, BNUMBER, 0, 144 | TULONG, BNUMBER, 0, 145 | TLLONG, BNUMBER, 0, 146 | TULLONG, BNUMBER, 0, 147 | TFLOAT, BNUMBER, 0, 148 | TDOUBLE, BNUMBER, 0, 149 | TENUM, BNUMBER, 0, 150 | -1, 0, 0, 151 | }; 152 | 153 | int tindir[1] = { 154 | BPTR 155 | }; 156 | 157 | int tdot[1] = { 158 | BSTRUCT | BUNION 159 | }; 160 | 161 | int tfunc[1] = { 162 | BFUNC 163 | }; 164 | 165 | int targ[1] = { 166 | BNUMBER | BPTR | BSTRUCT | BUNION 167 | }; 168 | 169 | int tcast[NTYPE]; 170 | static struct init tcast_init[] = { 171 | TBOOL, BNUMBER | BPTR | BVOID, 0, 172 | TCHAR, BNUMBER | BPTR | BVOID, 0, 173 | TUCHAR, BNUMBER | BPTR | BVOID, 0, 174 | TSHORT, BNUMBER | BPTR | BVOID, 0, 175 | TUSHORT, BNUMBER | BPTR | BVOID, 0, 176 | TINT, BNUMBER | BPTR | BVOID, 0, 177 | TUINT, BNUMBER | BPTR | BVOID, 0, 178 | TLONG, BNUMBER | BPTR | BVOID, 0, 179 | TULONG, BNUMBER | BPTR | BVOID, 0, 180 | TLLONG, BNUMBER | BPTR | BVOID, 0, 181 | TULLONG, BNUMBER | BPTR | BVOID, 0, 182 | TFLOAT, BNUMBER | BVOID, 0, 183 | TDOUBLE, BNUMBER | BVOID, 0, 184 | TPTR, BINTEGER | BPTR | BVOID, 0, 185 | TVOID, BVOID, 0, 186 | TSTRUCT, BSTRUCT | BVOID, 0, 187 | TUNION, BUNION | BVOID, 0, 188 | TENUM, BNUMBER | BPTR | BVOID, 0, 189 | -1, 0, 0 190 | }; 191 | 192 | int tasgn[NTYPE]; 193 | static struct init tasgn_init[] = { 194 | TBOOL, BNUMBER | BPTR, 0, 195 | TCHAR, BNUMBER, 0, 196 | TUCHAR, BNUMBER, 0, 197 | TSHORT, BNUMBER, 0, 198 | TUSHORT, BNUMBER, 0, 199 | TINT, BNUMBER, 0, 200 | TUINT, BNUMBER, 0, 201 | TLONG, BNUMBER, 0, 202 | TULONG, BNUMBER, 0, 203 | TLLONG, BNUMBER, 0, 204 | TULLONG, BNUMBER, 0, 205 | TFLOAT, BNUMBER, 0, 206 | TDOUBLE, BNUMBER, 0, 207 | TPTR, BPTR, 0, 208 | TSTRUCT, BSTRUCT, 0, 209 | TUNION, BUNION, 0, 210 | TENUM, BNUMBER, 0, 211 | -1, 0, 0 212 | }; 213 | 214 | int tasadd[NTYPE]; 215 | static struct init tasadd_init[] = { 216 | TBOOL, BNUMBER, 0, 217 | TCHAR, BNUMBER, 0, 218 | TUCHAR, BNUMBER, 0, 219 | TSHORT, BNUMBER, 0, 220 | TUSHORT, BNUMBER, 0, 221 | TINT, BNUMBER, 0, 222 | TUINT, BNUMBER, 0, 223 | TLONG, BNUMBER, 0, 224 | TULONG, BNUMBER, 0, 225 | TLLONG, BNUMBER, 0, 226 | TULLONG, BNUMBER, 0, 227 | TFLOAT, BNUMBER, 0, 228 | TDOUBLE, BNUMBER, 0, 229 | TPTR, BINTEGER, 0, 230 | TENUM, BNUMBER, 0, 231 | -1, 0, 0 232 | }; 233 | 234 | char tab[NTYPE][NTYPE] = { 235 | /* TXXX */ 236 | { 0, }, 237 | /* TBOOL */ 238 | { 0, TBOOL, TUCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, 239 | TLONG, TULONG, TLLONG, TULLONG, TFLOAT, TDOUBLE, TPTR, }, 240 | /* TCHAR */ 241 | { 0, TUCHAR, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, 242 | TLONG, TULONG, TLLONG, TULLONG, TFLOAT, TDOUBLE, TPTR, }, 243 | /* TUCHAR */ 244 | { 0, TUCHAR, TUCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, 245 | TULONG, TULONG, TULLONG, TULLONG, TFLOAT, TDOUBLE, TPTR, }, 246 | /* TSHORT */ 247 | { 0, TSHORT, TSHORT, TSHORT, TSHORT, TUSHORT, TINT, TUINT, 248 | TLONG, TULONG, TLLONG, TULLONG, TFLOAT, TDOUBLE, TPTR, }, 249 | /* TUSHORT */ 250 | { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TINT, TUINT, 251 | TLONG, TULONG, TLLONG, TULLONG, TFLOAT, TDOUBLE, TPTR, }, 252 | /* TINT */ 253 | { 0, TINT, TINT, TINT, TINT, TINT, TINT, TUINT, 254 | TLONG, TULONG, TLLONG, TULLONG, TFLOAT, TDOUBLE, TPTR, }, 255 | /* TUINT */ 256 | { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, 257 | TLONG, TULONG, TLLONG, TULLONG, TFLOAT, TDOUBLE, TPTR, }, 258 | /* TLONG */ 259 | { 0, TLONG, TLONG, TLONG, TLONG, TLONG, TLONG, TLONG, 260 | TLONG, TULONG, TLLONG, TULLONG, TFLOAT, TDOUBLE, TPTR, }, 261 | /* TULONG */ 262 | { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, 263 | TULONG, TULONG, TLLONG, TULLONG, TFLOAT, TDOUBLE, TPTR, }, 264 | /* TLLONG */ 265 | { 0, TLLONG, TLLONG, TLLONG, TLLONG, TLLONG, TLLONG, TLLONG, 266 | TLLONG, TLLONG, TLLONG, TULLONG, TFLOAT, TDOUBLE, TPTR, }, 267 | /* TULLONG */ 268 | { 0, TULLONG, TULLONG, TULLONG, TULLONG, TULLONG, TULLONG, TULLONG, 269 | TULLONG, TULLONG, TULLONG, TULLONG, TFLOAT, TDOUBLE, TPTR, }, 270 | /* TFLOAT */ 271 | { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, 272 | TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TPTR, }, 273 | /* TDOUBLE */ 274 | { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, 275 | TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TPTR, }, 276 | /* TPTR */ 277 | { 0, TPTR, TPTR, TPTR, TPTR, TPTR, TPTR, TPTR, 278 | TPTR, TPTR, TPTR, TPTR, TPTR, TPTR, TPTR, }, 279 | }; 280 | 281 | static struct type *newtyp(int etype, struct type *link) 282 | { 283 | struct type *p = zallocate(sizeof *p, PERM); 284 | p->etype = etype; 285 | p->link = link; 286 | p->qual = QXXX; 287 | p->size = typsize[etype]; 288 | p->align = typsize[etype]; 289 | if (p->align < 1) 290 | p->align = 1; 291 | return p; 292 | } 293 | 294 | struct type *typcpy(struct type *ty) 295 | { 296 | struct type *p = newtyp(TXXX, NULL); 297 | *p = *ty; 298 | return p; 299 | } 300 | 301 | struct type *ptrtyp(struct type *ty) 302 | { 303 | return newtyp(TPTR, ty); 304 | } 305 | 306 | struct type *arraytyp(struct type *ty, long n) 307 | { 308 | struct type *p; 309 | 310 | if (ty->etype == TFUNC) { 311 | error(0, "array of function is invalid"); 312 | ty = types[TINT]; 313 | } 314 | if (ty->size < 1) { 315 | error(0, "array of incomplete type '%T'", ty); 316 | ty = types[TINT]; 317 | } 318 | if (n < 0) { 319 | error(0, "array has negetive size '%ld'", n); 320 | n = 1; 321 | } 322 | 323 | p = newtyp(TARRAY, ty); 324 | p->align = ty->align; 325 | p->size = n * ty->size; 326 | return p; 327 | } 328 | 329 | struct type *functyp(struct type *ty, struct type *proto, int oldstyle) 330 | { 331 | struct type *p; 332 | 333 | if (ty->etype == TARRAY || ty->etype == TFUNC) { 334 | error(0, "function can't return type '%T'", ty); 335 | ty = types[TINT]; 336 | } 337 | 338 | p = newtyp(TFUNC, ty); 339 | p->next = proto; 340 | p->oldstyle = oldstyle; 341 | return p; 342 | } 343 | 344 | struct type *suetyp(int t) 345 | { 346 | struct type *p; 347 | switch (t) { 348 | case TSTRUCT: 349 | case TUNION: 350 | p = newtyp(t, NULL); 351 | break; 352 | case TENUM: 353 | p = newtyp(t, types[TINT]); 354 | break; 355 | default: 356 | abort(); 357 | } 358 | return p; 359 | } 360 | 361 | struct type *unqual(struct type *ty) 362 | { 363 | if (ty->qual != QXXX) { 364 | ty = typcpy(ty); 365 | ty->qual = QXXX; 366 | } 367 | return ty; 368 | } 369 | 370 | struct type *qual(int q, struct type *ty) 371 | { 372 | struct type *nty; 373 | 374 | q &= QMASK; 375 | if (q == QXXX) 376 | return unqual(ty); 377 | if (q != (ty->qual & q)) { 378 | nty = typcpy(ty); 379 | nty->qual |= q; 380 | return nty; 381 | } 382 | return ty; 383 | } 384 | 385 | int variadic(struct type *ty) 386 | { 387 | struct type *ty1; 388 | 389 | if (ty->etype == TFUNC && ty->next) 390 | for (ty1 = ty->next; ty1; ty1 = ty1->next) 391 | if (ty1->etype == TVOID && ty1->next == NULL) 392 | return ty1 != ty->next; 393 | 394 | return 0; 395 | } 396 | 397 | /* 0-strict, 1-ignore qual */ 398 | int eqtype(struct type *ty1, struct type *ty2, int f) 399 | { 400 | if (ty1 == ty2) 401 | return 1; 402 | if (ty1 == NULL || ty2 == NULL) 403 | return 0; 404 | if (ty1->etype != ty2->etype) 405 | return 0; 406 | if (ty1->qual != ty2->qual && f == 0) 407 | return 0; 408 | if (ty1->etype == TPTR) 409 | return eqtype(ty1->link, ty2->link, f); 410 | if (ty1->etype == TARRAY) { 411 | if (eqtype(ty1->link, ty2->link, f)) { 412 | if (ty1->size == ty2->size) 413 | return 1; 414 | if (ty1->size == 0 || ty2->size == 0) 415 | return 1; 416 | } 417 | return 0; 418 | } 419 | if (ty1->etype == TFUNC) { 420 | if (eqtype(ty1->link, ty2->link, f)) { 421 | struct type* p1 = ty1->next; 422 | struct type* p2 = ty2->next; 423 | 424 | if (p1 == p2) 425 | return 1; 426 | if (p1 && p2) { 427 | for (; p1 && p2; p1 = p1->next, p2 = p2->next) 428 | if (!eqtype(p1, p2, f)) 429 | return 0; 430 | if (p1 == NULL && p2 == NULL) 431 | return 1; 432 | } else { 433 | if (p1 == NULL) 434 | p1 = p2; 435 | for (int i = 0; p1; p1 = p1->next, i++) { 436 | if (p1->etype == TVOID && i) 437 | return 0; 438 | if (p1->etype == TENUM) 439 | p1 = p1->link; 440 | if (promote(p1)->etype != p1->etype) 441 | return 0; 442 | } 443 | return 1; 444 | } 445 | } 446 | return 0; 447 | } 448 | if (typesue[ty1->etype]) 449 | return ty1->tag == ty2->tag; 450 | return 1; 451 | } 452 | 453 | static struct type *tcompose(struct type *ty1, struct type *ty2) 454 | { 455 | struct type *ty, *p1, *p2, *proto, **pp; 456 | 457 | if (ty1 == ty2) 458 | return ty1; 459 | if (ty1->etype != ty2->etype) 460 | return NULL; 461 | 462 | switch (ty1->etype) { 463 | case TPTR: 464 | ty = tcompose(ty1->link, ty2->link); 465 | if (!ty) return NULL; 466 | return qual(ty1->qual | ty2->qual, ptrtyp(ty)); 467 | 468 | case TARRAY: 469 | ty = tcompose(ty1->link, ty2->link); 470 | if (!ty) return NULL; 471 | 472 | if (ty1->size && ((ty1->link->size && ty2->size == 0) || 473 | ty1->size == ty2->size)) 474 | return arraytyp(ty, ty1->size / ty1->link->size); 475 | if (ty2->size && ty2->link->size && ty1->size == 0) 476 | return arraytyp(ty, ty2->size / ty2->link->size); 477 | 478 | return arraytyp(ty, 0); 479 | 480 | case TFUNC: 481 | ty = tcompose(ty1->link, ty2->link); 482 | if (!ty) 483 | return NULL; 484 | 485 | p1 = ty1->next; 486 | p2 = ty2->next; 487 | if (p1 == NULL && p2 == NULL) 488 | return functyp(ty, NULL, 1); 489 | if (p1 && p2 == NULL) 490 | return functyp(ty, p1, ty1->oldstyle); 491 | if (p2 && p1 == NULL) 492 | return functyp(ty, p2, ty2->oldstyle); 493 | 494 | proto = NULL, pp = &proto; 495 | for (; p1 && p2; p1 = p1->next, p2 = p2->next) { 496 | struct type *ty3 = tcompose(p1, p2); 497 | if (!ty3) 498 | return NULL; 499 | ty3 = typcpy(ty3); 500 | ty3->next = NULL; 501 | *pp = ty3; 502 | pp = &ty3->next; 503 | } 504 | if (p1 || p2) 505 | return NULL; 506 | 507 | return functyp(ty, proto, 0); 508 | 509 | case TSTRUCT: 510 | case TUNION: 511 | case TENUM: 512 | if (ty1->tag != ty2->tag) 513 | return NULL; 514 | /* fall thru */ 515 | default: 516 | return qual(ty1->qual | ty2->qual, ty1); 517 | } 518 | } 519 | 520 | struct type *compose(struct type *ty1, struct type *ty2) 521 | { 522 | struct type *ty = tcompose(ty1, ty2); 523 | if (ty == NULL) 524 | error(0, "compose incompatible types '%T' and '%T'", ty1, ty2); 525 | return ty; 526 | } 527 | 528 | struct type *decay(struct type *ty) 529 | { 530 | switch (ty->etype) { 531 | case TFUNC: 532 | return ptrtyp(ty); 533 | case TARRAY: 534 | return ptrtyp(ty->link); 535 | default: 536 | return ty; 537 | } 538 | } 539 | 540 | struct type *promote(struct type *ty) 541 | { 542 | if (ty->etype == TENUM) 543 | ty = ty->link; 544 | if (ty->etype == TFLOAT) 545 | return types[TDOUBLE]; 546 | if (typei[ty->etype] && ty->size < types[TINT]->size) 547 | return types[TINT]; 548 | return ty; 549 | } 550 | 551 | void sualign(struct type *sty) 552 | { 553 | struct type **pp; 554 | int bits, align; 555 | long offset, size; 556 | 557 | bits = 0, offset = 0; 558 | align = 1, size = 1; 559 | pp = &sty->link; 560 | for (struct type *p = *pp; p; p = p->next) { 561 | int a, has_bit; 562 | 563 | /* flexible array as last field */ 564 | if (p->size < 1 && (p->etype != TARRAY || p->next)) 565 | error(0, "field '%s' has incomplete type", p->sym->name); 566 | 567 | has_bit = p->nbits > 0; 568 | if (has_bit) 569 | p->nbits -= 1; 570 | a = MAX(p->align, 1); 571 | if (sty->etype == TUNION) { 572 | offset = 0; 573 | bits = 0; 574 | } else if (p->nbits == 0 || p->nbits + bits > ROUNDUP(bits, a * 8)) { 575 | offset += BYTES(bits); 576 | offset = ROUNDUP(offset, a); 577 | bits = 0; 578 | } else { 579 | int off = ROUNDUP(BYTES(bits), a) - p->size; 580 | offset += off; 581 | bits -= off * 8; 582 | } 583 | 584 | if (a > align && (!has_bit || (p->nbits > 0 && p->sym))) 585 | align = a; 586 | 587 | p->offset = offset; 588 | if (has_bit) { 589 | p->bitoff = bits; 590 | bits += p->nbits; 591 | } else { 592 | offset += p->size; 593 | } 594 | 595 | if (offset + BYTES(bits) > size) 596 | size = offset + BYTES(bits); 597 | 598 | /* only chain the named field or anonymous record */ 599 | if (p->sym || typesu[p->etype]) { 600 | *pp = p; 601 | pp = &p->next; 602 | } 603 | } 604 | *pp = NULL; 605 | sty->align = align; 606 | sty->size = ROUNDUP(size, align); 607 | } 608 | 609 | struct type *find_field(struct symbol *s, struct type *flist, long *off) 610 | { 611 | struct type *p, *q = NULL; 612 | 613 | for (p = flist; p; p = p->next) 614 | if (p->sym) { 615 | if (p->sym == s) { 616 | q = p; 617 | if (off) *off = p->offset; 618 | break; 619 | } 620 | } else if (typesu[p->etype]) { 621 | /* lookup in unnamed substructure */ 622 | struct type *x = find_field(s, p->link, off); 623 | if (x) { 624 | q = x; 625 | if (off) *off += p->offset; 626 | break; 627 | } 628 | } 629 | 630 | return q; 631 | } 632 | 633 | void types_init(void) 634 | { 635 | int *p; 636 | struct init *q; 637 | 638 | types[TXXX] = NULL; 639 | types[TBOOL] = newtyp(TBOOL, NULL); 640 | types[TCHAR] = newtyp(TCHAR, NULL); 641 | types[TUCHAR] = newtyp(TUCHAR, NULL); 642 | types[TSHORT] = newtyp(TSHORT, NULL); 643 | types[TUSHORT] = newtyp(TUSHORT, NULL); 644 | types[TINT] = newtyp(TINT, NULL); 645 | types[TUINT] = newtyp(TUINT, NULL); 646 | types[TLONG] = newtyp(TLONG, NULL); 647 | types[TULONG] = newtyp(TULONG, NULL); 648 | types[TLLONG] = newtyp(TLLONG, NULL); 649 | types[TULLONG] = newtyp(TULLONG, NULL); 650 | types[TFLOAT] = newtyp(TFLOAT, NULL); 651 | types[TDOUBLE] = newtyp(TDOUBLE, NULL); 652 | types[TVOID] = newtyp(TVOID, NULL); 653 | types[TPTR] = newtyp(TPTR, types[TVOID]); 654 | types[TFUNC] = newtyp(TFUNC, types[TINT]); 655 | 656 | for (p = typei_init; *p >= 0; p++) 657 | typei[*p] = 1; 658 | for (p = typeu_init; *p >= 0; p++) 659 | typeu[*p] = 1; 660 | for (p = typefd_init; *p >= 0; p++) 661 | typefd[*p] = 1; 662 | for (p = typesu_init; *p >= 0; p++) 663 | typesu[*p] = 1; 664 | for (p = typesue_init; *p >= 0; p++) 665 | typesue[*p] = 1; 666 | for (p = typeaf_init; *p >= 0; p++) 667 | typeaf[*p] = 1; 668 | 669 | for (q = tand_init; q->code >= 0; q++) 670 | tand[q->code] = q->value; 671 | for (q = trel_init; q->code >= 0; q++) 672 | trel[q->code] = q->value; 673 | for (q = tadd_init; q->code >= 0; q++) 674 | tadd[q->code] = q->value; 675 | for (q = tsub_init; q->code >= 0; q++) 676 | tsub[q->code] = q->value; 677 | for (q = tmul_init; q->code >= 0; q++) 678 | tmul[q->code] = q->value; 679 | for (q = tcast_init; q->code >= 0; q++) 680 | tcast[q->code] = q->value; 681 | for (q = tasgn_init; q->code >= 0; q++) 682 | tasgn[q->code] = q->value; 683 | for (q = tasadd_init; q->code >= 0; q++) 684 | tasadd[q->code] = q->value; 685 | } -------------------------------------------------------------------------------- /x86_64-opc.c: -------------------------------------------------------------------------------- 1 | #include "cc.h" 2 | #include "x86_64.h" 3 | #include 4 | #include 5 | 6 | #define RL(rc) ((rc) & 7) 7 | #define RH(rc) (((rc) >> 3) & 1) 8 | #define ENC(f, t) (((f) << 8) | ((t) & 0xFF)) 9 | #define ModRM(mod, reg, rm) (((mod) << 6) | (RL(reg) << 3) | RL(rm)) 10 | #define SIB(s, i, b) (((s) << 6) | (RL(i) << 3) | RL(b)) 11 | 12 | /* opcode encoding context */ 13 | struct opc_state { 14 | int opcode; 15 | int flags; 16 | short op; 17 | char info; 18 | char sz; /* operand size */ 19 | char asz; /* address size mode (0:default, 1:non-default) */ 20 | char wrxb; 21 | char mod; 22 | char reg; 23 | char rm; 24 | char index; 25 | char base; 26 | char scale; 27 | char nocode; 28 | int disp; 29 | long imm; 30 | }; 31 | 32 | static struct opc_state opc; 33 | static struct section *text_sec; 34 | 35 | /* op,from,to,opcode,flags,info */ 36 | static struct opc opctab[] = { 37 | ANOP, 0, 0, 0x90, 0, OPF_BWLQ|OPF_NW, 38 | 39 | AMOV, OPC_REG, OPC_RM, 0x88, 0, OPF_R|OPF_B, 40 | AMOV, OPC_REG, OPC_RM, 0x89, 0, OPF_R|OPF_WLQ, 41 | AMOV, OPC_RM, OPC_REG, 0x8a, 0, OPF_R|OPF_B, 42 | AMOV, OPC_RM, OPC_REG, 0x8b, 0, OPF_R|OPF_WLQ, 43 | AMOV, OPC_IMM, OPC_REG, 0xb0, 0, OPF_IX|OPF_RX|OPF_B, 44 | AMOV, OPC_IMM, OPC_REG, 0xb8, 0, OPF_IX|OPF_RX|OPF_WLQ, 45 | AMOV, OPC_IMM, OPC_RM, 0xc6, 0, OPF_IX|OPF_DGT|OPF_B, 46 | AMOV, OPC_IMM, OPC_RM, 0xc7, 0, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM_N64, 47 | 48 | AMOVSX, OPC_RM, OPC_REG, 0x63, 0, OPF_R|OPF_Q|OPF_SRC_L, 49 | AMOVSX, OPC_RM, OPC_REG, 0xbf0f, 0, OPF_R|OPF_LQ|OPF_SRC_W, 50 | AMOVSX, OPC_RM, OPC_REG, 0xbe0f, 0, OPF_R|OPF_WLQ|OPF_SRC_B, 51 | AMOVZX, OPC_RM, OPC_REG, 0xb70f, 0, OPF_R|OPF_LQ|OPF_SRC_W, 52 | AMOVZX, OPC_RM, OPC_REG, 0xb60f, 0, OPF_R|OPF_WLQ|OPF_SRC_B, 53 | 54 | AADD, OPC_REG, OPC_RM, 0x00, 0, OPF_R|OPF_B, 55 | AADD, OPC_REG, OPC_RM, 0x01, 0, OPF_R|OPF_WLQ, 56 | AADD, OPC_RM, OPC_REG, 0x02, 0, OPF_R|OPF_B, 57 | AADD, OPC_RM, OPC_REG, 0x03, 0, OPF_R|OPF_WLQ, 58 | AADD, OPC_IMM, OPC_RM, 0x80, 0, OPF_IX|OPF_DGT|OPF_B, 59 | AADD, OPC_IMM, OPC_RM, 0x81, 0, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM_N64, 60 | AADD, OPC_IMM, OPC_RM, 0x83, 0, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM8, 61 | 62 | ASUB, OPC_REG, OPC_RM, 0x28, 0, OPF_R|OPF_B, 63 | ASUB, OPC_REG, OPC_RM, 0x29, 0, OPF_R|OPF_WLQ, 64 | ASUB, OPC_RM, OPC_REG, 0x2a, 0, OPF_R|OPF_B, 65 | ASUB, OPC_RM, OPC_REG, 0x2b, 0, OPF_R|OPF_WLQ, 66 | ASUB, OPC_IMM, OPC_RM, 0x80, 5, OPF_IX|OPF_DGT|OPF_B, 67 | ASUB, OPC_IMM, OPC_RM, 0x81, 5, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM_N64, 68 | ASUB, OPC_IMM, OPC_RM, 0x83, 5, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM8, 69 | 70 | AMUL, OPC_RM, OPC_REG, 0xaf0f, 0, OPF_R|OPF_WLQ, 71 | AMUL, OPC_IMM, OPC_REG, 0x69, 0, OPF_IX|OPF_R|OPF_WLQ|OPF_IMM_N64, 72 | AMUL, OPC_IMM, OPC_REG, 0x6b, 0, OPF_IX|OPF_R|OPF_WLQ|OPF_IMM8, 73 | 74 | ADIV, 0, OPC_RM, 0xf7, 7, OPF_DGT|OPF_WLQ, 75 | AUDIV, 0, OPC_RM, 0xf7, 6, OPF_DGT|OPF_WLQ, 76 | 77 | AAND, OPC_IMM, OPC_RM, 0x80, 4, OPF_IX|OPF_DGT|OPF_B, 78 | AAND, OPC_IMM, OPC_RM, 0x81, 4, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM_N64, 79 | AAND, OPC_IMM, OPC_RM, 0x83, 4, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM8, 80 | AAND, OPC_REG, OPC_RM, 0x20, 0, OPF_R|OPF_B, 81 | AAND, OPC_REG, OPC_RM, 0x21, 0, OPF_R|OPF_WLQ, 82 | AAND, OPC_RM, OPC_REG, 0x22, 0, OPF_R|OPF_B, 83 | AAND, OPC_RM, OPC_REG, 0x23, 0, OPF_R|OPF_WLQ, 84 | 85 | AOR, OPC_IMM, OPC_RM, 0x80, 1, OPF_IX|OPF_DGT|OPF_B, 86 | AOR, OPC_IMM, OPC_RM, 0x81, 1, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM_N64, 87 | AOR, OPC_IMM, OPC_RM, 0x83, 1, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM8, 88 | AOR, OPC_REG, OPC_RM, 0x08, 0, OPF_R|OPF_B, 89 | AOR, OPC_REG, OPC_RM, 0x09, 0, OPF_R|OPF_WLQ, 90 | AOR, OPC_RM, OPC_REG, 0x0a, 0, OPF_R|OPF_B, 91 | AOR, OPC_RM, OPC_REG, 0x0b, 0, OPF_R|OPF_WLQ, 92 | 93 | ASAL, OPC_IMM, OPC_RM, 0xc0, 4, OPF_IX|OPF_DGT|OPF_B, 94 | ASAL, OPC_IMM, OPC_RM, 0xc1, 4, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM8, 95 | ASAL, OPC_REG, OPC_RM, 0xd2, 4, OPF_R|OPF_DGT|OPF_B, 96 | ASAL, OPC_REG, OPC_RM, 0xd3, 4, OPF_R|OPF_DGT|OPF_WLQ, 97 | 98 | ASAR, OPC_IMM, OPC_RM, 0xc0, 7, OPF_IX|OPF_DGT|OPF_B, 99 | ASAR, OPC_IMM, OPC_RM, 0xc1, 7, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM8, 100 | ASAR, OPC_REG, OPC_RM, 0xd2, 7, OPF_R|OPF_DGT|OPF_B, 101 | ASAR, OPC_REG, OPC_RM, 0xd3, 7, OPF_R|OPF_DGT|OPF_WLQ, 102 | 103 | ASHR, OPC_IMM, OPC_RM, 0xc0, 5, OPF_IX|OPF_DGT|OPF_B, 104 | ASHR, OPC_IMM, OPC_RM, 0xc1, 5, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM8, 105 | ASHR, OPC_REG, OPC_RM, 0xd2, 5, OPF_R|OPF_DGT|OPF_B, 106 | ASHR, OPC_REG, OPC_RM, 0xd3, 5, OPF_R|OPF_DGT|OPF_WLQ, 107 | 108 | AXOR, OPC_IMM, OPC_RM, 0x80, 6, OPF_IX|OPF_DGT|OPF_B, 109 | AXOR, OPC_IMM, OPC_RM, 0x81, 6, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM_N64, 110 | AXOR, OPC_IMM, OPC_RM, 0x83, 6, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM8, 111 | AXOR, OPC_REG, OPC_RM, 0x30, 0, OPF_R|OPF_B, 112 | AXOR, OPC_REG, OPC_RM, 0x31, 0, OPF_R|OPF_WLQ, 113 | AXOR, OPC_RM, OPC_REG, 0x32, 0, OPF_R|OPF_B, 114 | AXOR, OPC_RM, OPC_REG, 0x33, 0, OPF_R|OPF_WLQ, 115 | 116 | ANEG, 0, OPC_RM, 0xf7, 3, OPF_DGT|OPF_WLQ, 117 | ANEG, 0, OPC_RM, 0xf6, 3, OPF_DGT|OPF_B, 118 | 119 | ANOT, 0, OPC_RM, 0xf7, 2, OPF_DGT|OPF_WLQ, 120 | ANOT, 0, OPC_RM, 0xf6, 2, OPF_DGT|OPF_B, 121 | 122 | ALEA, OPC_MEM, OPC_REG, 0x8d, 0, OPF_R|OPF_WLQ|OPF_SRC_ANY, 123 | 124 | ATEST, OPC_REG, OPC_RM, 0x85, 0, OPF_R|OPF_WLQ, 125 | ATEST, OPC_REG, OPC_RM, 0x84, 0, OPF_R|OPF_B, 126 | ATEST, OPC_IMM, OPC_RM, 0xf7, 0, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM_N64, 127 | ATEST, OPC_IMM, OPC_RM, 0xf6, 0, OPF_IX|OPF_DGT|OPF_B, 128 | 129 | ACMP, OPC_IMM, OPC_RM, 0x80, 7, OPF_IX|OPF_DGT|OPF_B, 130 | ACMP, OPC_IMM, OPC_RM, 0x81, 7, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM_N64, 131 | ACMP, OPC_IMM, OPC_RM, 0x83, 7, OPF_IX|OPF_DGT|OPF_WLQ|OPF_IMM8, 132 | ACMP, OPC_REG, OPC_RM, 0x38, 0, OPF_R|OPF_B, 133 | ACMP, OPC_REG, OPC_RM, 0x39, 0, OPF_R|OPF_WLQ, 134 | ACMP, OPC_RM, OPC_REG, 0x3a, 0, OPF_R|OPF_B, 135 | ACMP, OPC_RM, OPC_REG, 0x3b, 0, OPF_R|OPF_WLQ, 136 | 137 | AJMP, 0, OPC_RM, 0xff, 4, OPF_DGT|OPF_Q|OPF_NW, 138 | AJMP, 0, OPC_REL, 0Xeb, 0, OPF_CX|OPF_B|OPF_NW, 139 | AJMP, 0, OPC_REL, 0xe9, 0, OPF_CX|OPF_L|OPF_NW, 140 | 141 | AJE, 0, OPC_REL, 0x74, 0, OPF_CX|OPF_B|OPF_NW, 142 | AJE, 0, OPC_REL, 0x840f, 0, OPF_CX|OPF_L|OPF_NW, 143 | 144 | AJNE, 0, OPC_REL, 0x75, 0, OPF_CX|OPF_B|OPF_NW, 145 | AJNE, 0, OPC_REL, 0x850f, 0, OPF_CX|OPF_L|OPF_NW, 146 | 147 | AJA, 0, OPC_REL, 0x77, 0, OPF_CX|OPF_B|OPF_NW, 148 | AJA, 0, OPC_REL, 0x870f, 0, OPF_CX|OPF_L|OPF_NW, 149 | 150 | AJAE, 0, OPC_REL, 0x73, 0, OPF_CX|OPF_B|OPF_NW, 151 | AJAE, 0, OPC_REL, 0x830f, 0, OPF_CX|OPF_L|OPF_NW, 152 | 153 | AJB, 0, OPC_REL, 0x72, 0, OPF_CX|OPF_B|OPF_NW, 154 | AJB, 0, OPC_REL, 0x820f, 0, OPF_CX|OPF_L|OPF_NW, 155 | 156 | AJBE, 0, OPC_REL, 0x76, 0, OPF_CX|OPF_B|OPF_NW, 157 | AJBE, 0, OPC_REL, 0x860f, 0, OPF_CX|OPF_L|OPF_NW, 158 | 159 | AJG, 0, OPC_REL, 0x7f, 0, OPF_CX|OPF_B|OPF_NW, 160 | AJG, 0, OPC_REL, 0x8f0f, 0, OPF_CX|OPF_L|OPF_NW, 161 | 162 | AJGE, 0, OPC_REL, 0x7d, 0, OPF_CX|OPF_B|OPF_NW, 163 | AJGE, 0, OPC_REL, 0x8d0f, 0, OPF_CX|OPF_L|OPF_NW, 164 | 165 | AJL, 0, OPC_REL, 0x7c, 0, OPF_CX|OPF_B|OPF_NW, 166 | AJL, 0, OPC_REL, 0x8c0f, 0, OPF_CX|OPF_L|OPF_NW, 167 | 168 | AJLE, 0, OPC_REL, 0x7e, 0, OPF_CX|OPF_B|OPF_NW, 169 | AJLE, 0, OPC_REL, 0x8e0f, 0, OPF_CX|OPF_L|OPF_NW, 170 | 171 | ASETE, 0, OPC_RM, 0x940f, 0, OPF_DGT|OPF_B, /* fake DGT */ 172 | ASETNE, 0, OPC_RM, 0x950f, 0, OPF_DGT|OPF_B, 173 | ASETA, 0, OPC_RM, 0x970f, 0, OPF_DGT|OPF_B, 174 | ASETAE, 0, OPC_RM, 0x930f, 0, OPF_DGT|OPF_B, 175 | ASETB, 0, OPC_RM, 0x920f, 0, OPF_DGT|OPF_B, 176 | ASETBE, 0, OPC_RM, 0x960f, 0, OPF_DGT|OPF_B, 177 | ASETG, 0, OPC_RM, 0x9f0f, 0, OPF_DGT|OPF_B, 178 | ASETGE, 0, OPC_RM, 0x9d0f, 0, OPF_DGT|OPF_B, 179 | ASETL, 0, OPC_RM, 0x9c0f, 0, OPF_DGT|OPF_B, 180 | ASETLE, 0, OPC_RM, 0x9e0f, 0, OPF_DGT|OPF_B, 181 | 182 | APUSH, 0, OPC_REG, 0x50, 0, OPF_RX|OPF_WLQ|OPF_NW, 183 | APUSH, 0, OPC_RM, 0xff, 6, OPF_DGT|OPF_WLQ|OPF_NW, 184 | APUSH, 0, OPC_IMM, 0x68, 0, OPF_IX|OPF_WLQ|OPF_IMM32|OPF_NW, 185 | APUSH, 0, OPC_IMM, 0x6a, 0, OPF_IX|OPF_BWLQ|OPF_IMM8|OPF_NW, 186 | 187 | APOP, 0, OPC_REG, 0x58, 0, OPF_RX|OPF_WLQ|OPF_NW, 188 | APOP, 0, OPC_RM, 0x8f, 0, OPF_DGT|OPF_WLQ|OPF_NW, 189 | 190 | ALEAVE, 0, 0, 0xc9, 0, OPF_WLQ|OPF_NW, 191 | 192 | ACALL, 0, OPC_RM, 0xff, 2, OPF_DGT|OPF_WLQ|OPF_NW, 193 | ACALL, 0, OPC_REL, 0xe8, 0, OPF_CX|OPF_WL|OPF_NW, 194 | 195 | ARET, 0, 0, 0xc3, 0, OPF_WLQ|OPF_NW, 196 | 197 | AREPMOVS, OPC_MEM, OPC_MEM, 0xa5, 0, OPF_WLQ|OPF_REP, 198 | AREPSTOS, 0, OPC_MEM, 0xab, 0, OPF_WLQ|OPF_REP, 199 | 200 | AMOVAPS, OPC_REG, OPC_RM, 0x290f, 0, OPF_R|OPF_LQ|OPF_NP|OPF_NW, 201 | 202 | AMOVQ, OPC_REG, OPC_RM, 0xd60f66, 0, OPF_R|OPF_Q|OPF_NW, 203 | AMOVQ, OPC_RM, OPC_REG, 0x7e0ff3, 0, OPF_R|OPF_Q|OPF_NW, 204 | 205 | AMOVSS, OPC_RM, OPC_REG, 0x100ff3, 0, OPF_R|OPF_L|OPF_NW, 206 | AMOVSS, OPC_REG, OPC_RM, 0x110ff3, 0, OPF_R|OPF_L|OPF_NW, 207 | 208 | AMOVSD, OPC_RM, OPC_REG, 0X100ff2, 0, OPF_R|OPF_Q|OPF_NW, 209 | AMOVSD, OPC_REG, OPC_RM, 0x110ff2, 0, OPF_R|OPF_Q|OPF_NW, 210 | 211 | AADDSS, OPC_RM, OPC_REG, 0x580ff3, 0, OPF_R|OPF_L|OPF_NW, 212 | AADDSD, OPC_RM, OPC_REG, 0x580ff2, 0, OPF_R|OPF_Q|OPF_NW, 213 | ASUBSS, OPC_RM, OPC_REG, 0x5c0ff3, 0, OPF_R|OPF_L|OPF_NW, 214 | ASUBSD, OPC_RM, OPC_REG, 0x5c0ff2, 0, OPF_R|OPF_Q|OPF_NW, 215 | AMULSS, OPC_RM, OPC_REG, 0x590ff3, 0, OPF_R|OPF_L|OPF_NW, 216 | AMULSD, OPC_RM, OPC_REG, 0x590ff2, 0, OPF_R|OPF_Q|OPF_NW, 217 | ADIVSS, OPC_RM, OPC_REG, 0x5e0ff3, 0, OPF_R|OPF_L|OPF_NW, 218 | ADIVSD, OPC_RM, OPC_REG, 0x5e0ff2, 0, OPF_R|OPF_Q|OPF_NW, 219 | ACOMISS, OPC_RM, OPC_REG, 0x2f0f, 0, OPF_R|OPF_L|OPF_NP|OPF_NW, 220 | ACOMISD, OPC_RM, OPC_REG, 0x2f0f66, 0, OPF_R|OPF_Q|OPF_NW, 221 | ACVTSI2SS, OPC_RM, OPC_REG, 0x2a0ff3, 0, OPF_R|OPF_L|OPF_SRC_LQ, 222 | ACVTSI2SD, OPC_RM, OPC_REG, 0x2a0ff2, 0, OPF_R|OPF_Q|OPF_SRC_LQ, 223 | ACVTSS2SI, OPC_RM, OPC_REG, 0x2d0ff3, 0, OPF_R|OPF_LQ|OPF_SRC_L, 224 | ACVTSD2SI, OPC_RM, OPC_REG, 0x2d0ff2, 0, OPF_R|OPF_LQ|OPF_SRC_Q, 225 | ACVTSS2SD, OPC_RM, OPC_REG, 0x5a0ff3, 0, OPF_R|OPF_Q|OPF_SRC_L|OPF_NW, 226 | ACVTSD2SS, OPC_RM, OPC_REG, 0x5a0ff2, 0, OPF_R|OPF_L|OPF_SRC_Q|OPF_NW, 227 | -1, 228 | }; 229 | 230 | static unsigned char regcodes[NREG]; 231 | static struct init regcodes_init[] = { 232 | RAX, 0, 0, R8, 8, 0, 233 | RCX, 1, 0, R9, 9, 0, 234 | RDX, 2, 0, R10, 10, 0, 235 | RBX, 3, 0, R11, 11, 0, 236 | RSP, 4, 0, R12, 12, 0, 237 | RBP, 5, 0, R13, 13, 0, 238 | RSI, 6, 0, R14, 14, 0, 239 | RDI, 7, 0, R15, 15, 0, 240 | XMM0, 0, 0, XMM0 + 8, 8, 0, 241 | XMM0 + 1, 1, 0, XMM0 + 9, 9, 0, 242 | XMM0 + 2, 2, 0, XMM0 + 10, 10, 0, 243 | XMM0 + 3, 3, 0, XMM0 + 11, 11, 0, 244 | XMM0 + 4, 4, 0, XMM0 + 12, 12, 0, 245 | XMM0 + 5, 5, 0, XMM0 + 13, 13, 0, 246 | XMM0 + 6, 6, 0, XMM0 + 14, 14, 0, 247 | XMM0 + 7, 7, 0, XMM0 + 15, 15, 0, 248 | -1 249 | }; 250 | 251 | static int sizemap[] = { 252 | 0, OPF_B, OPF_W, 0, OPF_L, 0, 0, 0, OPF_Q, 253 | }; 254 | 255 | static int sizemap1[] = { 256 | 0, OPF_SRC_B, OPF_SRC_W, 0, OPF_SRC_L, 0, 0, 0, OPF_SRC_Q, 257 | }; 258 | 259 | static void out8(int c) 260 | { 261 | sec_add_data(text_sec, &c, 1); 262 | } 263 | 264 | static void out16(int i) 265 | { 266 | out8(i); 267 | out8(i >> 8); 268 | } 269 | 270 | static void out32(int i) 271 | { 272 | out8(i); 273 | out8(i >> 8); 274 | out8(i >> 16); 275 | out8(i >> 24); 276 | } 277 | 278 | static void out64(int64_t i) 279 | { 280 | out8(i); 281 | out8(i >> 8); 282 | out8(i >> 16); 283 | out8(i >> 24); 284 | out8(i >> 32); 285 | out8(i >> 40); 286 | out8(i >> 48); 287 | out8(i >> 56); 288 | } 289 | 290 | static void outx(unsigned int i) 291 | { 292 | while (i) { 293 | out8(i); 294 | i = i >> 8; 295 | } 296 | } 297 | 298 | static void encode_rm(struct node *rm) 299 | { 300 | long disp; 301 | 302 | if (rm == NULL) 303 | return; 304 | 305 | if (rm->reg <= 0) { 306 | error(rm, "bad indirect operand"); 307 | return; 308 | } 309 | 310 | opc.rm = rm->reg; 311 | switch (rm->op) { 312 | case OREGISTER: 313 | opc.mod = 3; 314 | break; 315 | 316 | case OINDREG: 317 | /* $disp(reg) or $disp(base, index, $scale) */ 318 | /* No check: always using default address size */ 319 | disp = rm->offset; 320 | if (disp == 0) 321 | opc.mod = 0; 322 | else if (disp <= CHAR_MAX && disp >= CHAR_MIN) 323 | opc.mod = 1; 324 | else 325 | opc.mod = 2; 326 | if (disp > INT_MAX || disp < INT_MIN) 327 | warn(rm, "displacement overflow: %lx", disp); 328 | opc.disp = disp; 329 | 330 | /* special case: RSP means none, using SIB instead */ 331 | if (opc.rm == RSP) { 332 | opc.index = RSP; 333 | opc.base = RSP; 334 | opc.scale = 0; 335 | } 336 | /* special case: RBP means disp32, using SIB instead */ 337 | if (opc.rm == RBP) 338 | if (opc.mod == 0) 339 | opc.mod = 1; 340 | /* special case: RIP-relative addressing: $disp32(%rip) */ 341 | if (opc.rm == RIP) { 342 | opc.mod = 0; 343 | opc.rm = RBP; 344 | opc.disp = 0; /* rewrite to zero and using reloc */ 345 | } 346 | 347 | if (rm->index > 0) { 348 | opc.index = rm->index; 349 | opc.base = opc.rm; 350 | opc.rm = RSP; /* indicating following SIB byte */ 351 | opc.scale = rm->scale; 352 | if (opc.scale < 0 || opc.scale > 3) { 353 | error(rm, "bad scale(%ld), must be 0,1,2,3", opc.scale); 354 | opc.scale = 0; 355 | } 356 | } 357 | break; 358 | } 359 | } 360 | 361 | static void encode_wrxb(void) 362 | { 363 | int wrxb, reg, rm, index, base; 364 | 365 | wrxb = -1; 366 | index = base = 0; 367 | reg = regcodes[opc.reg]; 368 | rm = regcodes[opc.rm]; 369 | if (opc.index > 0) { 370 | index = regcodes[opc.index]; 371 | base = regcodes[opc.base]; 372 | } 373 | if (reg > 7 || rm > 7 || index > 7 || base > 7) { 374 | wrxb = 0x40; 375 | wrxb |= RH(reg) << 2; 376 | wrxb |= RH(index) << 1; 377 | if (opc.base > 0) 378 | wrxb |= RH(base); 379 | else 380 | wrxb |= RH(rm); 381 | if (opc.flags & OPF_RX) 382 | wrxb |= RH(reg); 383 | } 384 | /* 385 | * Intel manual 2.2.1.7 Default 64-Bit Operand Size 386 | * Two groups of instruction don't need a REX prefix: 387 | * - near branch 388 | * - All instructions implicitly reference RSP except far branches. 389 | */ 390 | if (opc.sz == 8 && (opc.flags & OPF_NW) == 0) { 391 | if (wrxb >= 0) 392 | wrxb |= 0x8; 393 | else 394 | wrxb = 0x48; 395 | } 396 | opc.wrxb = wrxb; 397 | } 398 | 399 | /* find location of '0f' escape byte in opcode */ 400 | static int find0f(void) 401 | { 402 | unsigned int opcode = opc.opcode; 403 | int i = 0; 404 | 405 | while (opcode) { 406 | if ((opcode & 0xFF) == 0x0F) 407 | break; 408 | opcode >>= 8; 409 | i++; 410 | } 411 | 412 | if (opcode) 413 | return i; 414 | 415 | return 0; 416 | } 417 | 418 | static void initopc(struct opc *p, int sz) 419 | { 420 | memset(&opc, 0, sizeof(opc)); 421 | opc.opcode = p->opcode; 422 | opc.flags = p->flags; 423 | opc.op = p->op; 424 | opc.info = p->info; 425 | opc.sz = sz; 426 | opc.wrxb = -1; /* fill with invalid data */ 427 | opc.mod = 4; 428 | } 429 | 430 | static void outopc(long *reloc) 431 | { 432 | int modrm, c, i; 433 | unsigned int opcode; 434 | 435 | if (opc.nocode) 436 | return; 437 | 438 | if (opc.asz) 439 | out8(0x67); 440 | if (opc.sz == 2) 441 | if ((opc.flags & OPF_NP) == 0) 442 | out8(0x66); 443 | if (opc.flags & OPF_REP) 444 | out8(0xf3); 445 | if (opc.wrxb >= 0) { 446 | opcode = opc.opcode; 447 | c = find0f(); 448 | for (i = 0; opcode; i++) { 449 | if (i == c) 450 | out8(opc.wrxb); 451 | out8(opcode); 452 | opcode >>= 8; 453 | } 454 | } else { 455 | outx(opc.opcode); 456 | } 457 | 458 | if (opc.flags & (OPF_R | OPF_DGT)) { 459 | if (opc.flags & OPF_DGT) 460 | c = opc.info; 461 | else 462 | c = regcodes[opc.reg]; 463 | modrm = ModRM(opc.mod, c, regcodes[opc.rm]); 464 | out8(modrm); 465 | /* compute SIB byte */ 466 | if (opc.index > 0) { 467 | c = SIB(opc.scale, regcodes[opc.index], regcodes[opc.base]); 468 | out8(c); 469 | } 470 | /* RIP-relative addressing */ 471 | if (opc.mod == 0 && opc.rm == RBP) { 472 | if (reloc) 473 | *reloc = text_sec->data_len; 474 | out32(opc.disp); 475 | } 476 | if (opc.mod == 1) 477 | out8(opc.disp); 478 | if (opc.mod == 2) 479 | out32(opc.disp); 480 | } else if (opc.flags & OPF_CX) { 481 | /* RIP-relative addressing */ 482 | if (opc.mod == 0 && opc.rm == RBP) { 483 | if (reloc) 484 | *reloc = text_sec->data_len; 485 | if (opc.sz == 1) 486 | out8(opc.disp); 487 | else if (opc.sz == 2) 488 | out16(opc.disp); 489 | else 490 | out32(opc.disp); 491 | } 492 | } 493 | 494 | if (opc.flags & OPF_IX) { 495 | if (opc.flags & OPF_IMM8) 496 | out8(opc.imm); 497 | else if (opc.flags & OPF_IMM32) 498 | out32(opc.imm); 499 | else if (opc.sz == 1) 500 | out8(opc.imm); 501 | else if (opc.sz == 2) 502 | out16(opc.imm); 503 | else if (opc.sz == 4 || opc.flags & OPF_IMM_N64) 504 | out32(opc.imm); 505 | else 506 | out64(opc.imm); 507 | } 508 | } 509 | 510 | static void genopc(struct opc *p, struct node *f, struct node *t) 511 | { 512 | struct node *n; 513 | 514 | switch (ENC(p->from, p->to)) { 515 | case ENC(OPC_MEM, OPC_REG): 516 | case ENC(OPC_RM, OPC_REG): 517 | n = f, f = t, t = n; 518 | /* fall thru */ 519 | 520 | case ENC(OPC_REG, OPC_RM): 521 | opc.reg = f->reg; 522 | encode_rm(t); 523 | encode_wrxb(); 524 | break; 525 | 526 | case ENC(OPC_IMM, OPC_RM): 527 | opc.imm = f->v.i; 528 | if (p->flags & OPF_IMM_N64) 529 | if (opc.imm > INT_MAX || opc.imm < INT_MIN) 530 | warn(f, "immediate overflow: %lx", opc.imm); 531 | /* fall thru */ 532 | 533 | case ENC(0, OPC_RM): 534 | encode_rm(t); 535 | encode_wrxb(); 536 | break; 537 | 538 | case ENC(OPC_IMM, OPC_REG): 539 | opc.imm = f->v.i; 540 | /* special case: IMUL */ 541 | if (opc.op == AMUL) 542 | encode_rm(t); 543 | /* fall thru */ 544 | 545 | case ENC(0, OPC_REG): 546 | opc.reg = t->reg; 547 | if (opc.flags & OPF_RX) 548 | opc.opcode |= RL(regcodes[opc.reg]); 549 | encode_wrxb(); 550 | break; 551 | 552 | case ENC(0, OPC_IMM): 553 | opc.imm = t->v.i; 554 | break; 555 | 556 | case ENC(0, OPC_REL): 557 | encode_rm(t); 558 | break; 559 | 560 | case ENC(OPC_MEM, OPC_MEM): 561 | case ENC(0, OPC_MEM): 562 | encode_wrxb(); 563 | break; 564 | 565 | case 0: 566 | break; 567 | 568 | default: 569 | opc.nocode = 1; 570 | error(t, "unknown opcode encoding %d(%x, %x)", p->op, p->from, p->to); 571 | break; 572 | } 573 | } 574 | 575 | static int nodenc(struct node *p) 576 | { 577 | if (p) { 578 | if (p->op == OREGISTER) 579 | return OPC_REG; 580 | if (p->op == OINDREG) { 581 | if (p->reg == RIP) 582 | return OPC_MEM | OPC_REL; 583 | return OPC_MEM; 584 | } 585 | if (p->op == OCONST) 586 | return OPC_IMM; 587 | } 588 | return 0; 589 | } 590 | 591 | void gopc(int op, struct node *f, struct node *t, long *reloc) 592 | { 593 | struct opc *p, *p1; 594 | int tsz, tc, fsz, fc; 595 | int fenc, tenc; 596 | 597 | if (t == NULL) 598 | tsz = typsize[TLONG]; 599 | else 600 | tsz = t->type->size; 601 | 602 | if (f) { 603 | fsz = f->type->size; 604 | if (fsz < 0 || fsz >= NELEMS(sizemap1)) 605 | fc = OPF_SRC_X; 606 | else 607 | fc = sizemap1[fsz]; 608 | if (fc == 0) 609 | fc = OPF_SRC_X; 610 | } else { 611 | fsz = fc = 0; 612 | } 613 | 614 | fenc = nodenc(f); 615 | tenc = nodenc(t); 616 | 617 | /* special case: func call */ 618 | if (op == ACALL) { 619 | tsz = typsize[TINT]; 620 | if (tenc & OPC_REL) 621 | tenc = OPC_REL; /* direct call */ 622 | } 623 | 624 | if (tsz < 0 || tsz >= NELEMS(sizemap) || (tc = sizemap[tsz]) == 0) { 625 | error(t, "bad operand size(%d) with type '%T'", tsz, t->type); 626 | return; 627 | } 628 | 629 | for (p = opctab, p1 = NULL; p->op > 0; p++) { 630 | if (p->op != op) 631 | continue; 632 | if ((p->flags & tc) == 0) 633 | continue; 634 | if (p->flags & OPF_SRC_ANY) 635 | if ((p->flags & fc) == 0) 636 | continue; 637 | if (p->from) 638 | if ((fenc & p->from) == 0) 639 | continue; 640 | if (p->to) 641 | if ((tenc & p->to) == 0) 642 | continue; 643 | /* optimization for shorter opcode */ 644 | if (p->from == OPC_IMM) 645 | if (f->op == OCONST && f->v.i <= CHAR_MAX && f->v.i >= CHAR_MIN) 646 | if ((p->flags & OPF_IMM8) == 0) { 647 | p1 = p; 648 | continue; 649 | } 650 | break; 651 | } 652 | 653 | if (p->op < 0) 654 | p = p1; 655 | if (p == NULL) { 656 | error(t, "opcode %d(%d,%d)/%d not found", op, tenc, fenc, tsz); 657 | return; 658 | } 659 | /* special instruction check */ 660 | if (p->op == ASAL || p->op == ASAR || p->op == ASHR) 661 | if (fenc == OPC_REG) 662 | if (f->reg != RCX) { 663 | error(f, "source operand must be CL register"); 664 | return; 665 | } 666 | if ((p->flags & OPF_SRC_ANY) == 0) 667 | if (fsz && tsz != fsz) { 668 | error(t, "operands size not match: op=%d,%d!=%d", op, fsz, tsz); 669 | return; 670 | } 671 | 672 | /* infer operand size */ 673 | if (op == ACVTSI2SS || op == ACVTSI2SD) 674 | tsz = fsz; 675 | if (op == AMOVAPS) 676 | tsz = 16; 677 | 678 | initopc(p, tsz); 679 | genopc(p, f, t); 680 | outopc(reloc); 681 | } 682 | 683 | void opc_init(struct section *s) 684 | { 685 | struct init *p; 686 | 687 | for (p = regcodes_init; p->code >= 0; p++) 688 | regcodes[p->code] = p->value; 689 | 690 | text_sec = s; 691 | } -------------------------------------------------------------------------------- /x86_64.h: -------------------------------------------------------------------------------- 1 | #ifndef X86_64_H 2 | #define X86_64_H 3 | 4 | #define GPR_P(reg) ((reg) >= RAX && (reg) <= R15) 5 | #define SSE_P(reg) ((reg) >= XMM0 && (reg) <= XMM15) 6 | 7 | enum { 8 | RXXX, 9 | 10 | /* 11 | Registers for allocation 12 | To keep it simple, callee preserved registers are not used. 13 | Don't reorder or regalloc will break. 14 | */ 15 | RAX, 16 | RCX, 17 | RDX, 18 | RDI, 19 | RSI, 20 | R8, 21 | R9, 22 | R10, 23 | R11, 24 | 25 | /* garbage */ 26 | RSP, 27 | RBP, 28 | RBX, 29 | R12, 30 | R13, 31 | R14, 32 | R15, 33 | 34 | RIP, /* for RIP-relative addressing asm instr */ 35 | 36 | XMM0, 37 | XMM15 = XMM0 + 15, 38 | NREG 39 | }; 40 | 41 | /* asm op */ 42 | enum { 43 | AXXX, 44 | ANOP, 45 | AMOV, 46 | AMOVSX, 47 | AMOVZX, 48 | AADD, 49 | ASUB, 50 | AMUL, 51 | ADIV, 52 | AUDIV, 53 | AAND, 54 | AOR, 55 | ASAL, 56 | ASAR, /* unsigned shift right */ 57 | ASHR, /* signed shift right */ 58 | AXOR, 59 | ANOT, 60 | ANEG, 61 | ALEA, 62 | ACALL, 63 | AJMP, 64 | AJE, 65 | AJNE, 66 | AJA, /* unsigned */ 67 | AJAE, 68 | AJB, 69 | AJBE, 70 | AJG, /* signed */ 71 | AJGE, 72 | AJL, 73 | AJLE, 74 | ASETE, /* set on condition */ 75 | ASETNE, 76 | ASETA, 77 | ASETAE, 78 | ASETB, 79 | ASETBE, 80 | ASETG, 81 | ASETGE, 82 | ASETL, 83 | ASETLE, 84 | ATEST, 85 | ACMP, 86 | ALEAVE, 87 | ARET, 88 | APUSH, 89 | APOP, 90 | AREPMOVS, 91 | AREPSTOS, 92 | ACVTSI2SS, 93 | ACVTSI2SD, 94 | ACVTSS2SI, 95 | ACVTSS2SD, 96 | ACVTSD2SI, 97 | ACVTSD2SS, 98 | AMOVSS, 99 | AMOVSD, 100 | AMOVQ, /* SSE move quadword */ 101 | AMOVAPS, 102 | AADDSS, 103 | AADDSD, 104 | ASUBSS, 105 | ASUBSD, 106 | AMULSS, 107 | AMULSD, 108 | ADIVSS, 109 | ADIVSD, 110 | ACOMISS, 111 | ACOMISD, 112 | NAOP 113 | }; 114 | 115 | /* opcode flags */ 116 | #define OPF_R (1 << 0) /* enable both reg and r/m in ModRM */ 117 | #define OPF_RX (1 << 1) /* register encoded in lower 3 bits of opcode */ 118 | #define OPF_IX (1 << 2) /* immediate operand */ 119 | #define OPF_CX (1 << 3) /* 1,2,4,6,8,10 byte value following opcode */ 120 | #define OPF_DGT (1 << 4) /* enable only r/m, fill reg with digit */ 121 | #define OPF_B (1 << 5) /* accept operand size: 1 byte */ 122 | #define OPF_W (1 << 6) /* accept operand size: 2 bytes */ 123 | #define OPF_L (1 << 7) /* accept operand size: 4 bytes */ 124 | #define OPF_Q (1 << 8) /* accept operand size: 8 bytes */ 125 | #define OPF_SRC_B (1 << 9) /* 1 byte source operand */ 126 | #define OPF_SRC_W (1 << 10) /* 2 byte source operand */ 127 | #define OPF_SRC_L (1 << 11) /* 4 byte source operand */ 128 | #define OPF_SRC_Q (1 << 12) /* 8 byte source operand */ 129 | #define OPF_SRC_X (1 << 13) /* any size except 1,2,4,8 */ 130 | #define OPF_IMM8 (1 << 14) /* accept only imm8 */ 131 | #define OPF_IMM32 (1 << 15) /* accept only imm32 */ 132 | #define OPF_IMM_N64 (1 << 16) /* imm64 not allowed */ 133 | #define OPF_NP (1 << 17) /* 66/F2/F3 prefixes not allowed */ 134 | #define OPF_NW (1 << 18) /* no REX.W when only 8 byte is met */ 135 | #define OPF_REP (1 << 19) /* REP/REPE/REPZ instructions */ 136 | 137 | #define OPF_WL (OPF_W | OPF_L) /* accept 2,4 */ 138 | #define OPF_WLQ (OPF_WL | OPF_Q) /* accept 2,4,8 */ 139 | #define OPF_LQ (OPF_L | OPF_Q) /* accept 4,8 */ 140 | #define OPF_BWLQ (OPF_B | OPF_WLQ) /* accept 1,2,4,8 */ 141 | 142 | #define OPF_SRC_LQ (OPF_SRC_L | OPF_SRC_Q) 143 | #define OPF_SRC_BWLQ (OPF_SRC_B | OPF_SRC_W | OPF_SRC_L | OPF_SRC_Q) 144 | #define OPF_SRC_ANY (OPF_SRC_BWLQ | OPF_SRC_X) 145 | 146 | /* opcode enc */ 147 | #define OPC_REG (1 << 0) /* register */ 148 | #define OPC_MEM (1 << 1) /* memory */ 149 | #define OPC_IMM (1 << 2) /* immediate */ 150 | #define OPC_REL (1 << 3) /* relative offset to PC */ 151 | 152 | #define OPC_RM (OPC_REG | OPC_MEM) 153 | 154 | /* x86 instruction */ 155 | struct opc { 156 | short op; /* asm op */ 157 | char from; /* from encoding */ 158 | char to; /* to encoding */ 159 | int opcode; /* opcode: 1,2 or 3 bytes */ 160 | char info; /* payload */ 161 | int flags; /* opcode flags */ 162 | }; 163 | 164 | /* x86_64-asm.c */ 165 | extern void opc_init(struct section *); 166 | extern void gopc(int, struct node *, struct node *, long *); 167 | 168 | #endif /* X86_64_H */ --------------------------------------------------------------------------------