diff options
Diffstat (limited to 'gas/read.c')
-rw-r--r-- | gas/read.c | 480 |
1 files changed, 433 insertions, 47 deletions
@@ -285,7 +285,8 @@ read_begin (void) /* Use more. FIXME-SOMEDAY. */ if (flag_mri) - lex_type['?'] = 3; + lex_type['?'] = LEX_BEGIN_NAME | LEX_NAME; + stabs_begin (); #ifndef WORKING_DOT_WORD @@ -357,6 +358,7 @@ static const pseudo_typeS potable[] = { {"balign", s_align_bytes, 0}, {"balignw", s_align_bytes, -2}, {"balignl", s_align_bytes, -4}, + {"base64", s_base64, 0}, /* block */ #ifdef HANDLE_BUNDLE {"bundle_align_mode", s_bundle_align_mode, 0}, @@ -863,6 +865,29 @@ do_align (unsigned int n, char *fill, unsigned int len, unsigned int max) record_alignment (now_seg, n - OCTETS_PER_BYTE_POWER); } +/* Find first <eol><next_char>NO_APP<eol>, if any, in the supplied buffer. + Return NULL if there's none, or else the position of <next_char>. */ +static char * +find_no_app (const char *s, char next_char) +{ + const char *start = s; + const char srch[] = { next_char, 'N', 'O', '_', 'A', 'P', 'P', '\0' }; + + for (;;) + { + char *ends = strstr (s, srch); + + if (ends == NULL) + break; + if (is_end_of_line (ends[sizeof (srch) - 1]) + && (ends == start || is_end_of_line (ends[-1]))) + return ends; + s = ends + sizeof (srch) - 1; + } + + return NULL; +} + /* We read the file, putting things into a web that represents what we have been reading. */ void @@ -899,7 +924,7 @@ read_a_source_file (const char *name) #endif while (input_line_pointer < buffer_limit) { - bool was_new_line; + char was_new_line; /* We have more of this buffer to parse. */ /* We now have input_line_pointer->1st char of next line. @@ -952,6 +977,61 @@ read_a_source_file (const char *name) listing_newline (NULL); } #endif + + next_char = *input_line_pointer; + if (was_new_line == 1 + && (strchr (line_comment_chars, '#') + ? next_char == '#' + : next_char && strchr (line_comment_chars, next_char))) + { + /* Its a comment. Check for APP followed by NO_APP. */ + sb sbuf; + char *ends; + size_t len; + + s = input_line_pointer + 1; + if (!startswith (s, "APP") || !is_end_of_line (s[3])) + { + /* We ignore it. Note: Not ignore_rest_of_line ()! */ + while (s <= buffer_limit) + if (is_end_of_line (*s++)) + break; + input_line_pointer = s; + continue; + } + s += 4; + + ends = find_no_app (s, next_char); + len = ends ? ends - s : buffer_limit - s; + + sb_build (&sbuf, len + 100); + sb_add_buffer (&sbuf, s, len); + if (!ends) + { + /* The end of the #APP wasn't in this buffer. We + keep reading in buffers until we find the #NO_APP + that goes with this #APP There is one. The specs + guarantee it... */ + do + { + buffer_limit = input_scrub_next_buffer (&buffer); + if (!buffer_limit) + break; + ends = find_no_app (buffer, next_char); + len = ends ? ends - buffer : buffer_limit - buffer; + sb_add_buffer (&sbuf, buffer, len); + } + while (!ends); + } + sb_add_char (&sbuf, '\n'); + + input_line_pointer = ends ? ends + 8 : NULL; + input_scrub_include_sb (&sbuf, input_line_pointer, expanding_app); + sb_kill (&sbuf); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); + continue; + } + if (was_new_line) { line_label = NULL; @@ -1315,48 +1395,12 @@ read_a_source_file (const char *name) } if (next_char && strchr (line_comment_chars, next_char)) - { /* Its a comment. Better say APP or NO_APP. */ - sb sbuf; - char *ends; - size_t len; - - s = input_line_pointer; - if (!startswith (s, "APP\n")) - { - /* We ignore it. */ - ignore_rest_of_line (); - continue; - } - bump_line_counters (); - s += 4; - - ends = strstr (s, "#NO_APP\n"); - len = ends ? ends - s : buffer_limit - s; - - sb_build (&sbuf, len + 100); - sb_add_buffer (&sbuf, s, len); - if (!ends) - { - /* The end of the #APP wasn't in this buffer. We - keep reading in buffers until we find the #NO_APP - that goes with this #APP There is one. The specs - guarantee it... */ - do - { - buffer_limit = input_scrub_next_buffer (&buffer); - if (!buffer_limit) - break; - ends = strstr (buffer, "#NO_APP\n"); - len = ends ? ends - buffer : buffer_limit - buffer; - sb_add_buffer (&sbuf, buffer, len); - } - while (!ends); - } - - input_line_pointer = ends ? ends + 8 : NULL; - input_scrub_include_sb (&sbuf, input_line_pointer, expanding_none); - sb_kill (&sbuf); - buffer_limit = input_scrub_next_buffer (&input_line_pointer); + { + /* Its a comment, ignore it. Note: Not ignore_rest_of_line ()! */ + while (s <= buffer_limit) + if (is_end_of_line (*s++)) + break; + input_line_pointer = s; continue; } @@ -3973,7 +4017,7 @@ demand_empty_rest_of_line (void) /* Return pointing just after end-of-line. */ } -/* Silently advance to the end of line. Use this after already having +/* Silently advance to the end of a statement. Use this after already having issued an error about something bad. Like demand_empty_rest_of_line, this function may leave input_line_pointer one after buffer_limit; Don't call it from within expression parsing code in an attempt to @@ -3983,9 +4027,9 @@ void ignore_rest_of_line (void) { while (input_line_pointer <= buffer_limit) - if (is_end_of_line[(unsigned char) *input_line_pointer++]) + if (is_end_of_stmt (*input_line_pointer++)) break; - /* Return pointing just after end-of-line. */ + /* Return pointing just after end-of-statement. */ } /* Sets frag for given symbol to zero_address_frag, except when the @@ -5412,6 +5456,348 @@ s_leb128 (int sign) demand_empty_rest_of_line (); } +/* Code for handling base64 encoded strings. + Based upon code in sharutils' lib/base64.c source file, written by + Simon Josefsson. Which was partially adapted from GNU MailUtils + (mailbox/filter_trans.c, as of 2004-11-28) and improved by review + from Paul Eggert, Bruno Haible, and Stepan Kasal. */ + +#define B64(_) \ + ( (_) == 'A' ? 0 \ + : (_) == 'B' ? 1 \ + : (_) == 'C' ? 2 \ + : (_) == 'D' ? 3 \ + : (_) == 'E' ? 4 \ + : (_) == 'F' ? 5 \ + : (_) == 'G' ? 6 \ + : (_) == 'H' ? 7 \ + : (_) == 'I' ? 8 \ + : (_) == 'J' ? 9 \ + : (_) == 'K' ? 10 \ + : (_) == 'L' ? 11 \ + : (_) == 'M' ? 12 \ + : (_) == 'N' ? 13 \ + : (_) == 'O' ? 14 \ + : (_) == 'P' ? 15 \ + : (_) == 'Q' ? 16 \ + : (_) == 'R' ? 17 \ + : (_) == 'S' ? 18 \ + : (_) == 'T' ? 19 \ + : (_) == 'U' ? 20 \ + : (_) == 'V' ? 21 \ + : (_) == 'W' ? 22 \ + : (_) == 'X' ? 23 \ + : (_) == 'Y' ? 24 \ + : (_) == 'Z' ? 25 \ + : (_) == 'a' ? 26 \ + : (_) == 'b' ? 27 \ + : (_) == 'c' ? 28 \ + : (_) == 'd' ? 29 \ + : (_) == 'e' ? 30 \ + : (_) == 'f' ? 31 \ + : (_) == 'g' ? 32 \ + : (_) == 'h' ? 33 \ + : (_) == 'i' ? 34 \ + : (_) == 'j' ? 35 \ + : (_) == 'k' ? 36 \ + : (_) == 'l' ? 37 \ + : (_) == 'm' ? 38 \ + : (_) == 'n' ? 39 \ + : (_) == 'o' ? 40 \ + : (_) == 'p' ? 41 \ + : (_) == 'q' ? 42 \ + : (_) == 'r' ? 43 \ + : (_) == 's' ? 44 \ + : (_) == 't' ? 45 \ + : (_) == 'u' ? 46 \ + : (_) == 'v' ? 47 \ + : (_) == 'w' ? 48 \ + : (_) == 'x' ? 49 \ + : (_) == 'y' ? 50 \ + : (_) == 'z' ? 51 \ + : (_) == '0' ? 52 \ + : (_) == '1' ? 53 \ + : (_) == '2' ? 54 \ + : (_) == '3' ? 55 \ + : (_) == '4' ? 56 \ + : (_) == '5' ? 57 \ + : (_) == '6' ? 58 \ + : (_) == '7' ? 59 \ + : (_) == '8' ? 60 \ + : (_) == '9' ? 61 \ + : (_) == '+' ? 62 \ + : (_) == '/' ? 63 \ + : -1) + +static const signed char b64[0x100] = +{ + B64 (0), B64 (1), B64 (2), B64 (3), + B64 (4), B64 (5), B64 (6), B64 (7), + B64 (8), B64 (9), B64 (10), B64 (11), + B64 (12), B64 (13), B64 (14), B64 (15), + B64 (16), B64 (17), B64 (18), B64 (19), + B64 (20), B64 (21), B64 (22), B64 (23), + B64 (24), B64 (25), B64 (26), B64 (27), + B64 (28), B64 (29), B64 (30), B64 (31), + B64 (32), B64 (33), B64 (34), B64 (35), + B64 (36), B64 (37), B64 (38), B64 (39), + B64 (40), B64 (41), B64 (42), B64 (43), + B64 (44), B64 (45), B64 (46), B64 (47), + B64 (48), B64 (49), B64 (50), B64 (51), + B64 (52), B64 (53), B64 (54), B64 (55), + B64 (56), B64 (57), B64 (58), B64 (59), + B64 (60), B64 (61), B64 (62), B64 (63), + B64 (64), B64 (65), B64 (66), B64 (67), + B64 (68), B64 (69), B64 (70), B64 (71), + B64 (72), B64 (73), B64 (74), B64 (75), + B64 (76), B64 (77), B64 (78), B64 (79), + B64 (80), B64 (81), B64 (82), B64 (83), + B64 (84), B64 (85), B64 (86), B64 (87), + B64 (88), B64 (89), B64 (90), B64 (91), + B64 (92), B64 (93), B64 (94), B64 (95), + B64 (96), B64 (97), B64 (98), B64 (99), + B64 (100), B64 (101), B64 (102), B64 (103), + B64 (104), B64 (105), B64 (106), B64 (107), + B64 (108), B64 (109), B64 (110), B64 (111), + B64 (112), B64 (113), B64 (114), B64 (115), + B64 (116), B64 (117), B64 (118), B64 (119), + B64 (120), B64 (121), B64 (122), B64 (123), + B64 (124), B64 (125), B64 (126), B64 (127), + B64 (128), B64 (129), B64 (130), B64 (131), + B64 (132), B64 (133), B64 (134), B64 (135), + B64 (136), B64 (137), B64 (138), B64 (139), + B64 (140), B64 (141), B64 (142), B64 (143), + B64 (144), B64 (145), B64 (146), B64 (147), + B64 (148), B64 (149), B64 (150), B64 (151), + B64 (152), B64 (153), B64 (154), B64 (155), + B64 (156), B64 (157), B64 (158), B64 (159), + B64 (160), B64 (161), B64 (162), B64 (163), + B64 (164), B64 (165), B64 (166), B64 (167), + B64 (168), B64 (169), B64 (170), B64 (171), + B64 (172), B64 (173), B64 (174), B64 (175), + B64 (176), B64 (177), B64 (178), B64 (179), + B64 (180), B64 (181), B64 (182), B64 (183), + B64 (184), B64 (185), B64 (186), B64 (187), + B64 (188), B64 (189), B64 (190), B64 (191), + B64 (192), B64 (193), B64 (194), B64 (195), + B64 (196), B64 (197), B64 (198), B64 (199), + B64 (200), B64 (201), B64 (202), B64 (203), + B64 (204), B64 (205), B64 (206), B64 (207), + B64 (208), B64 (209), B64 (210), B64 (211), + B64 (212), B64 (213), B64 (214), B64 (215), + B64 (216), B64 (217), B64 (218), B64 (219), + B64 (220), B64 (221), B64 (222), B64 (223), + B64 (224), B64 (225), B64 (226), B64 (227), + B64 (228), B64 (229), B64 (230), B64 (231), + B64 (232), B64 (233), B64 (234), B64 (235), + B64 (236), B64 (237), B64 (238), B64 (239), + B64 (240), B64 (241), B64 (242), B64 (243), + B64 (244), B64 (245), B64 (246), B64 (247), + B64 (248), B64 (249), B64 (250), B64 (251), + B64 (252), B64 (253), B64 (254), B64 (255) +}; + +static bool +is_base64_char (unsigned int c) +{ + return (c < 0x100) && (b64[c] != -1); +} + +static void +decode_base64_and_append (unsigned int b[4], int len) +{ + gas_assert (len > 1); + + FRAG_APPEND_1_CHAR ((b64[b[0]] << 2) | (b64[b[1]] >> 4)); + + if (len == 2) + return; /* FIXME: Check for unused bits in b[1] ? */ + + FRAG_APPEND_1_CHAR (((b64[b[1]] << 4) & 0xf0) | (b64[b[2]] >> 2)); + + if (len == 3) + return; /* FIXME: Check for unused bits in b[2] ? */ + + FRAG_APPEND_1_CHAR (((b64[b[2]] << 6) & 0xc0) | b64[b[3]]); +} + +/* Accept one or more comma separated, base64 encoded strings. Decode them + and store them at the current point in the current section. The strings + must be enclosed in double quotes. Line breaks, quoted characters and + escaped characters are not allowed. Only the characters "A-Za-z0-9+/" are + accepted inside the string. The string must be a multiple of four + characters in length. If the encoded string does not fit this requirement + it may use one or more '=' characters at the end as padding. */ + +void +s_base64 (int dummy ATTRIBUTE_UNUSED) +{ + unsigned int c; + unsigned long num_octets = 0; + + /* If we have been switched into the abs_section then we + will not have an obstack onto which we can hang strings. */ + if (now_seg == absolute_section) + { + as_bad (_("base64 strings must be placed into a section")); + ignore_rest_of_line (); + return; + } + + if (is_it_end_of_statement ()) + { + as_bad (_("a string must follow the .base64 pseudo-op")); + return; + } + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + +#ifdef md_cons_align + md_cons_align (1); +#endif + + do + { + SKIP_ALL_WHITESPACE (); + + c = * input_line_pointer ++; + + if (c != '"') + { + as_bad (_("expected double quote enclosed string as argument to .base64 pseudo-op")); + ignore_rest_of_line (); + return; + } + + /* Read a block of four base64 encoded characters. */ + int i; + unsigned int b[4]; + bool seen_equals = false; + + loop: + for (i = 0; i < 4; i++) + { + c = * input_line_pointer ++; + + if (c >= 256 || is_end_of_line [c]) + { + as_bad (_("end of line encountered inside .base64 string")); + ignore_rest_of_line (); + return; + } + + if (c == '"') + { + /* We allow this. But only if there were enough + characters to form a valid base64 encoding. */ + if (i > 1) + { + as_warn (_(".base64 string terminated early")); + -- input_line_pointer; + break; + } + + as_bad (_(".base64 string terminated unexpectedly")); + ignore_rest_of_line (); + return; + } + + if (seen_equals && c != '=') + { + as_bad (_("equals character only allowed at end of .base64 string")); + ignore_rest_of_line (); + return; + } + + if (c == '=') + { + if (i == 0) + { + as_bad (_("the equals character cannot start a block of four base64 encoded bytes")); + ignore_rest_of_line (); + return; + } + else if (i == 1) + { + as_bad (_("the equals character cannot be the second character in a block of four base64 encoded bytes")); + ignore_rest_of_line (); + return; + } + + seen_equals = true; + } + else if (! is_base64_char (c)) + { + if (ISPRINT (c)) + as_bad (_("invalid character '%c' found inside .base64 string"), c); + else + as_bad (_("invalid character %#x found inside .base64 string"), c); + ignore_rest_of_line (); + return; + } + + b[i] = c; + } + + if (seen_equals && i == 4) + { + -- i; + if (b[2] == '=') + -- i; + } + + /* We have a block of up to four valid base64 encoded bytes. */ + decode_base64_and_append (b, i); + num_octets += (i - 1); + + /* Check the next character. */ + c = * input_line_pointer ++; + + if (is_base64_char (c)) + { + if (seen_equals) + { + as_bad (_("no base64 characters expected after '=' padding characters")); + ignore_rest_of_line (); + return; + } + + -- input_line_pointer; + goto loop; + } + else if (c != '"') + { + as_bad (_(".base64 string must have a terminating double quote character")); + ignore_rest_of_line (); + return; + } + + SKIP_ALL_WHITESPACE (); + + c = * input_line_pointer ++; + } + while (c == ','); + + /* Make sure that we have not skipped the EOL marker. */ + -- input_line_pointer; + + while (num_octets % OCTETS_PER_BYTE) + { + /* We have finished emiting the octets for this .base64 pseudo-op, but + we have not filled up enough bytes for the target architecture. So + we emit padding octets here. This is done after all of the arguments + to the pseudo-op have been processed, rather than at the end of each + argument, as it is likely that the user wants the arguments to be + contiguous. */ + FRAG_APPEND_1_CHAR (0); + ++ num_octets; + } + + demand_empty_rest_of_line (); +} + static void stringer_append_char (int c, int bitsize) { |