/* * Add __initstr to strings in __init functions * * Copyright (C) 2003 Arnaldo Carvalho de Melo * * Licensed under the Open Software License version 1.1 */ #include #include #include #include #include #include #include #include "token.h" #include "parse.h" #include "symbol.h" #include "expression.h" static int in_init_data_function; static int in_exit_data_function; static int wrapping_string; static int dont_wrap_section_string; static int scope; #if 1 #define INIT_STR_BEGIN "({ static char __str[] __attribute__((__section__" \ "(\".init.data\")))=" #define EXIT_STR_BEGIN "({ static char __str[] __attribute__((__section__" \ "(\".exit.data\")))=" #define INEXIT_STR_END "; __str;})" #else #define INIT_STR_BEGIN "__initstr(" #define EXIT_STR_BEGIN "__exitstr(" #define INEXIT_STR_END ")" #endif struct symbol *ident_attribute(struct ident *ident) { struct symbol *sym; for (sym = ident->symbols; sym; sym = sym->next_id) if (sym->ctype.modifiers & MOD_ATTRIBUTE) break; return sym; } static void handle_ident(struct token *token, struct token *next) { struct ctype ct = { 0, }; if (!ident_attribute(token->ident)) goto out; attribute_specifier(next, &ct); if (ct.modifiers & MOD_SECTION) { static char sign_init[] = ".init.text"; static char sign_exit[] = ".exit.text"; if (ct.section->length == sizeof(sign_init) && (!memcmp(ct.section->data, sign_init, sizeof(sign_init)) || !memcmp(ct.section->data, sign_exit, sizeof(sign_exit)))) { in_init_data_function = ct.section->data[1] == 'i'; in_exit_data_function = ct.section->data[1] == 'e'; dont_wrap_section_string = 1; } } out: printf("%s", show_ident(token->ident)); } void print_init_wrap(const char *s) { if (!dont_wrap_section_string) printf("%s", s); } void print_exit_wrap(void) { if (dont_wrap_section_string) dont_wrap_section_string = 0; else printf(INEXIT_STR_END); } void initstr_create_builtin_stream(void) { add_pre_buffer("#define __i386__ 1\n"); add_pre_buffer("#define __linux__ 1\n"); add_pre_buffer("#define __STDC__ 1\n"); add_pre_buffer("#define linux linux\n"); add_pre_buffer("#define __GNUC__ 2\n"); add_pre_buffer("#define __GNUC_MINOR__ 2.95\n"); } int main(int argc, char **argv) { int fd; char *filename = NULL, **args; struct token *token; init_symbols(); initstr_create_builtin_stream(); args = argv; for (;;) { char *arg = *++args; if (!arg) break; if (arg[0] == '-') { args = handle_switch(arg + 1, args); continue; } filename = arg; } fd = open(filename, O_RDONLY); if (fd < 0) die("No such file: %s", filename); // Tokenize the input stream token = tokenize(filename, fd, NULL); close(fd); // Prepend the initial built-in stream token = tokenize_buffer(pre_buffer, pre_buffer_size, token); token = preprocess(token); while (!eof_token(token)) { int prec = 1; struct token *next = token->next; char *separator = ""; if (next->pos.whitespace) separator = " "; if (next->pos.newline) { separator = "\n\t\t\t\t\t"; prec = next->pos.pos; if (prec > 4) prec = 4; } switch (token_type(token)) { case TOKEN_IDENT: handle_ident(token, next); break; case TOKEN_STRING: if (!wrapping_string) { wrapping_string = 1; if (in_init_data_function) print_init_wrap(INIT_STR_BEGIN); else if (in_exit_data_function) print_init_wrap(EXIT_STR_BEGIN); else wrapping_string = 0; } printf("%s", show_string(token->string)); break; case TOKEN_SPECIAL: switch (token->special) { case '{': ++scope; break; case '}': --scope; if (!scope) { in_init_data_function = 0; in_exit_data_function = 0; } else if (scope < 0) die("error: parse error before '}' " "token"); break; case ';': if (!scope) { in_init_data_function = 0; in_exit_data_function = 0; } break; } printf("%s", show_special(token->special)); break; default: printf("%s", show_token(token)); } printf("%.*s", prec, separator); token = next; if (wrapping_string && (eof_token(token) || token_type(token) != TOKEN_STRING)) { wrapping_string = 0; print_exit_wrap(); } } putchar('\n'); return 0; }