From c0240be4630a6b7440fe0fd5be5d381e14d0dae7 Mon Sep 17 00:00:00 2001 From: "James E. Wilson" Date: Wed, 7 Jun 2000 02:27:51 +0000 Subject: [PATCH] Fix gas/gcc unwind/EH discrepancies. And a shared library build problem. * frame.h (struct unwind_info_ptr): Collapse version, flags, and length fields into header field. (IA64_UNW_HDR_LENGTH, IA64_UNW_HDR_FLAGS, IA64_UNW_HDR_VERSION): New macros to access length, flags, and version info from header field. * config/ia64/crtbegin.asm (__do_frame_setup_aux): Delete here. ... From-SVN: r34441 --- gcc/ChangeLog | 20 ++++++++++++ gcc/config/ia64/crtbegin.asm | 35 --------------------- gcc/config/ia64/crtend.asm | 41 ++++++++++++++++++++---- gcc/config/ia64/frame-ia64.c | 60 +++++++++++++++++++++++------------- gcc/config/ia64/ia64.c | 7 ++--- gcc/frame.h | 7 +++-- 6 files changed, 101 insertions(+), 69 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a0db4b4f5d6..2f8e558fa82 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2000-06-06 James E. Wilson + + * frame.h (struct unwind_info_ptr): Collapse version, flags, and length + fields into header field. + (IA64_UNW_HDR_LENGTH, IA64_UNW_HDR_FLAGS, IA64_UNW_HDR_VERSION): New + macros to access length, flags, and version info from header field. + * config/ia64/crtbegin.asm (__do_frame_setup_aux): Delete here. + * config/ia64/crtend.asm (__do_frame_setup_aux): Add here. + (__do_global_ctors_aux): Fix caller. + * config/ia64/frame-ia64.c (get_unwind_record): Change parameter + prologue_flag to header. Pass to read_P_record. + (read_P_record): New argument header. Implement P4 format. + Multiply P7_T_SIZE by 16. + (execute_one_ia64_descriptor): New static local region_header. Pass to + get_unwind_record. Copy r to region_header if r is a header record. + (print_all_records): Likewise. + (__build_ia64_frame_state): Use IA64_UNW_HDR_LENGTH. + (__get_personality, __get_except_table): Likewise. + * config/ia64/ia64.c (process_set): Do not divide offsets by 4. + 2000-06-06 Philipp Thomas * configure.in (AC_C_INLINE): Added. diff --git a/gcc/config/ia64/crtbegin.asm b/gcc/config/ia64/crtbegin.asm index 0e49e20662d..3f2b2f7080a 100644 --- a/gcc/config/ia64/crtbegin.asm +++ b/gcc/config/ia64/crtbegin.asm @@ -296,38 +296,3 @@ __do_frame_setup: #endif .weak __deregister_frame_info# .weak __register_frame_info# - - .text - .align 16 - .global __do_frame_setup_aux# - .proc __do_frame_setup_aux# -__do_frame_setup_aux: - /* - if (__register_frame_info_aux) - __register_frame_info_aux(__EH_FRAME_END__) - */ - alloc loc0 = ar.pfs, 0, 3, 1, 0 - addl r14 = @ltoff(@fptr(__register_frame_info_aux#)), gp - mov loc1 = b0 - ;; - // r16 contains the address of a pointer to __EH_FRAME_END__. - ld8 out0 = [r16] - ld8 r15 = [r14] - mov loc2 = gp - ;; - cmp.eq p6, p7 = 0, r15 - (p6) br.cond.dptk 1f - ld8 r8 = [r15], 8 - ;; - ld8 gp = [r15] - mov b6 = r8 - ;; - br.call.sptk.many b0 = b6 - ;; -1: - mov gp = loc2 - mov ar.pfs = loc0 - mov b0 = loc1 - br.ret.sptk.many b0 - .endp __do_frame_setup# -.weak __register_frame_info_aux# diff --git a/gcc/config/ia64/crtend.asm b/gcc/config/ia64/crtend.asm index 9216cfc7fb7..07b71ea5c10 100644 --- a/gcc/config/ia64/crtend.asm +++ b/gcc/config/ia64/crtend.asm @@ -113,7 +113,6 @@ __do_global_ctors_aux: .section .init,"ax","progbits" { .mlx - // __do_frame_setup_aux is in crtbegin.asm movl r2 = @gprel(__do_frame_setup_aux#) ;; } @@ -123,12 +122,42 @@ __do_global_ctors_aux: ;; mov b6 = r2 } - { .mib - // __do_frame_setup_aux needs the address of __EH_FRAME_END__, - // so we pass it in r16. This is rather evil, but we have no - // output registers. - addl r16 = @ltoff(__EH_FRAME_END__#), gp + { .bbb br.call.sptk.many b0 = b6 ;; } +.text + .align 16 + .proc __do_frame_setup_aux# +__do_frame_setup_aux: + /* + if (__register_frame_info_aux) + __register_frame_info_aux(__EH_FRAME_END__) + */ + alloc loc0 = ar.pfs, 0, 3, 1, 0 + addl r14 = @ltoff(@fptr(__register_frame_info_aux#)), gp + mov loc1 = b0 + ;; + ld8 r15 = [r14] + addl r16 = @ltoff(__EH_FRAME_END__#), gp + mov loc2 = gp + ;; + cmp.eq p6, p7 = 0, r15 + (p6) br.cond.dptk 1f + ld8 r8 = [r15], 8 + ld8 out0 = [r16] + ;; + ld8 gp = [r15] + mov b6 = r8 + ;; + br.call.sptk.many b0 = b6 + ;; +1: + mov gp = loc2 + mov ar.pfs = loc0 + mov b0 = loc1 + br.ret.sptk.many b0 + .endp __do_frame_setup_aux# + +.weak __register_frame_info_aux# diff --git a/gcc/config/ia64/frame-ia64.c b/gcc/config/ia64/frame-ia64.c index 763bc49c0bc..4ff78dd4a4d 100644 --- a/gcc/config/ia64/frame-ia64.c +++ b/gcc/config/ia64/frame-ia64.c @@ -247,23 +247,22 @@ bad_record (ptr, offset) static unsigned char *read_R_record (unwind_record *, unsigned char, unsigned char *); static unsigned char *read_X_record (unwind_record *, unsigned char, unsigned char *); static unsigned char *read_B_record (unwind_record *, unsigned char, unsigned char *); -static unsigned char *read_P_record (unwind_record *, unsigned char, unsigned char *); +static unsigned char *read_P_record (unwind_record *, unsigned char, unsigned char *, unwind_record *); /* This routine will determine what type of record the memory pointer is refering to, and fill in the appropriate fields for that record type. - PROLOGUE_FLAG is TRUE if we are currently processing a PROLOGUE - body. + HEADER is a pointer to the last region header unwind record. DATA is a pointer to an unwind record which will be filled in. PTR is a pointer to the current location in the unwind table where we will read the next record from. The return value is the start of the next record. */ extern unsigned char * -get_unwind_record (prologue_flag, data, ptr) - int prologue_flag; - unwind_record *data; - unsigned char *ptr; +get_unwind_record (header, data, ptr) + unwind_record *header; + unwind_record *data; + unsigned char *ptr; { unsigned char val = *ptr++; @@ -275,8 +274,8 @@ get_unwind_record (prologue_flag, data, ptr) if (val == UNW_X1 || val == UNW_X2 || val == UNW_X3 || val == UNW_X4) return read_X_record (data, val, ptr); - if (prologue_flag) - return read_P_record (data, val, ptr); + if (header->type != body) + return read_P_record (data, val, ptr, header); else return read_B_record (data, val, ptr); } @@ -534,10 +533,11 @@ static unsigned char P8_additional_fields [] = { static unsigned char * -read_P_record (data, val, ptr) +read_P_record (data, val, ptr, header) unwind_record *data; unsigned char val; unsigned char *ptr; + unwind_record *header; { if ((val & 0xe0) == 0x80) { @@ -575,13 +575,12 @@ read_P_record (data, val, ptr) if (val == UNW_P4) { - /* P4 format. Currently unimplemented. */ - int len = 0; /* TODO.. get prologue rlen. */ - int size = (len * 2 + 7) / 8; + /* P4 format. */ + int size = (header->record.r.rlen * 2 + 7) / 8; data->type = spill_mask; data->record.p.imask = (unsigned char *) malloc (size); - /* memcpy (data->record.p.imask, ptr, size); */ + memcpy (data->record.p.imask, ptr, size); return ptr+size; } @@ -617,7 +616,7 @@ read_P_record (data, val, ptr) { case P7_T_SIZE: data->record.p.t = read_uleb128 (&ptr); - data->record.p.size = read_uleb128 (&ptr); + data->record.p.size = read_uleb128 (&ptr) << 4; break; case P7_T: data->record.p.t = read_uleb128 (&ptr); @@ -733,11 +732,14 @@ execute_one_ia64_descriptor (addr, frame, len) long *len; { unwind_record r; + /* The last region_header. Needed to distinguish between prologue and body + descriptors. Also needed for length of P4 format. */ + static unwind_record region_header; ia64_reg_loc *loc_ptr = NULL; int grmask = 0, frmask = 0; *len = -1; - addr = get_unwind_record (1, &r, addr); + addr = get_unwind_record (®ion_header, &r, addr); /* process it in 2 phases, the first phase will either do the work, or set up a pointer to the records we care about @@ -748,6 +750,7 @@ execute_one_ia64_descriptor (addr, frame, len) case prologue: case body: *len = r.record.r.rlen; + memcpy (®ion_header, &r, sizeof (unwind_record)); break; case prologue_gr: { @@ -780,6 +783,7 @@ execute_one_ia64_descriptor (addr, frame, len) frame->pr.loc_type = IA64_UNW_LOC_TYPE_GR; frame->pr.l.regno = reg++; } + memcpy (®ion_header, &r, sizeof (unwind_record)); break; } case mem_stack_f: @@ -1312,7 +1316,7 @@ __build_ia64_frame_state (pc, frame, bsp, pc_base_ptr) start_pc = pc_base + entry->start_offset; unw_info_ptr = ((struct unwind_info_ptr *)(pc_base + entry->unwind_offset)); addr = unw_info_ptr->unwind_descriptors; - end = addr + unw_info_ptr->length * 8; + end = addr + IA64_UNW_HDR_LENGTH (unw_info_ptr->header) * 8; pc_offset = (pc - start_pc) / 16 * 3; init_ia64_unwind_frame (frame); @@ -1345,7 +1349,8 @@ __get_personality (ptr) unwind_info_ptr *ptr; { void **p; - p = (void **) (ptr->unwind_descriptors + ptr->length * 8); + p = (void **) (ptr->unwind_descriptors + + IA64_UNW_HDR_LENGTH (ptr->header) * 8); return *p; } @@ -1354,11 +1359,13 @@ __get_except_table (ptr) unwind_info_ptr *ptr; { void **p, *table; - p = (void **) (ptr->unwind_descriptors + ptr->length * 8); + p = (void **) (ptr->unwind_descriptors + + IA64_UNW_HDR_LENGTH (ptr->header) * 8); /* If there is no personality, there is no handler data. */ if (*p == 0) return 0; - table = (void *) (ptr->unwind_descriptors + ptr->length * 8 + 8); + table = (void *) (ptr->unwind_descriptors + + IA64_UNW_HDR_LENGTH (ptr->header) * 8 + 8); return table; } @@ -1595,12 +1602,23 @@ print_all_records (f, mem, size) { unsigned char *end = mem + size; unwind_record r; + static unwind_record region_header; fprintf (f, "UNWIND IMAGE:\n"); while (mem < end) { - mem = get_unwind_record (1, &r, mem); + mem = get_unwind_record (®ion_header, &r, mem); print_record (f, &r); + switch (r.type) + { + case prologue: + case body: + case prologue_gr: + memcpy (region_header, r, sizeof (unwind_record)); + break; + default: + break; + } } fprintf (f, "--end unwind image--\n\n"); } diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 8328d7f9b56..e9eade30b93 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -3117,8 +3117,7 @@ process_set (asm_out_file, pat) if (!spill_offset_emitted) { fprintf (asm_out_file, "\t.spill %d\n", -/* (frame_size + 16 - spill_offset ) / 4); */ - (-(spill_offset - 8) + 16) / 4); + (-(spill_offset - 8) + 16)); spill_offset_emitted = 1; } } @@ -3138,10 +3137,10 @@ process_set (asm_out_file, pat) /* register 9 is ar.unat. */ if (tmp_saved == 9) fprintf (asm_out_file, "\t.savesp ar.unat, %d\n", - (sp_offset - 8) / 4); + (sp_offset - 8)); else if (tmp_saved == 5) fprintf (asm_out_file, "\t.savesp pr, %d\n", - (sp_offset - 8) / 4); + (sp_offset - 8)); else if (tmp_saved >= BR_REG (1) && tmp_saved <= BR_REG (5)) { /* BR regs are saved this way too. */ diff --git a/gcc/frame.h b/gcc/frame.h index 384e5eb66ca..85c5e436d5b 100644 --- a/gcc/frame.h +++ b/gcc/frame.h @@ -256,12 +256,13 @@ typedef struct ia64_frame_state typedef struct unwind_info_ptr { - unsigned short version; - unsigned short flags; - unsigned int length; + unsigned long header; /* version, flags, & length */ unsigned char unwind_descriptors[1]; } unwind_info_ptr; +#define IA64_UNW_HDR_LENGTH(x) ((x) & 0x00000000ffffffffUL) +#define IA64_UNW_HDR_FLAGS(x) (((x) >> 32) & 0xffffUL) +#define IA64_UNW_HDR_VERSION(x) (((x) >> 48) & 0xffffUL) extern unwind_info_ptr *__build_ia64_frame_state (unsigned char *, ia64_frame_state *, void *,