This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
IA-64 gcc unwind/EH patch, and shared library bug fix
- To: gcc-patches at gcc dot gnu dot org
- Subject: IA-64 gcc unwind/EH patch, and shared library bug fix
- From: Jim Wilson <wilson at cygnus dot com>
- Date: Tue, 06 Jun 2000 19:28:52 -0700
This makes gcc consistent with the recent GNU as changes to the unwind support.
With this patch, the g++ EH testcases work with the current GNU as again,
except for g++.mike/eh50.C and g++.mike/eh51.C.
This also fixes a problem with building shared libraries. The crt*.asm files
had an invalid call to a global function. I fixed it by moving the function
and making it local. This undoes a change I had suggested to fix a bug, so I
asked for a testcase for the original bug so I can check to see if I broke
anything.
2000-06-06 James E. Wilson <wilson@bletchleypark.cygnus.com>
* 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.
Index: frame.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/frame.h,v
retrieving revision 1.12
diff -p -r1.12 frame.h
*** frame.h 2000/05/25 15:21:50 1.12
--- frame.h 2000/06/07 02:23:49
*************** typedef struct ia64_frame_state
*** 256,267 ****
typedef struct unwind_info_ptr
{
! unsigned short version;
! unsigned short flags;
! unsigned int length;
unsigned char unwind_descriptors[1];
} unwind_info_ptr;
extern unwind_info_ptr *__build_ia64_frame_state (unsigned char *,
ia64_frame_state *, void *,
--- 256,268 ----
typedef struct unwind_info_ptr
{
! 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 *,
Index: config/ia64/crtbegin.asm
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/ia64/crtbegin.asm,v
retrieving revision 1.4
diff -p -r1.4 crtbegin.asm
*** crtbegin.asm 2000/05/25 15:21:50 1.4
--- crtbegin.asm 2000/06/07 02:23:50
*************** __do_frame_setup:
*** 296,333 ****
#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#
--- 296,298 ----
Index: config/ia64/crtend.asm
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/ia64/crtend.asm,v
retrieving revision 1.4
diff -p -r1.4 crtend.asm
*** crtend.asm 2000/05/25 15:21:50 1.4
--- crtend.asm 2000/06/07 02:23:50
*************** __do_global_ctors_aux:
*** 113,119 ****
.section .init,"ax","progbits"
{ .mlx
- // __do_frame_setup_aux is in crtbegin.asm
movl r2 = @gprel(__do_frame_setup_aux#)
;;
}
--- 113,118 ----
*************** __do_global_ctors_aux:
*** 123,134 ****
;;
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
br.call.sptk.many b0 = b6
;;
}
--- 122,163 ----
;;
mov b6 = r2
}
! { .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#
Index: config/ia64/frame-ia64.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/ia64/frame-ia64.c,v
retrieving revision 1.1
diff -p -r1.1 frame-ia64.c
*** frame-ia64.c 2000/05/25 15:21:51 1.1
--- frame-ia64.c 2000/06/07 02:23:50
*************** bad_record (ptr, offset)
*** 247,269 ****
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 *);
/* 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.
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;
{
unsigned char val = *ptr++;
--- 247,268 ----
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 *, 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.
! 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 (header, data, ptr)
! unwind_record *header;
! unwind_record *data;
! unsigned char *ptr;
{
unsigned char val = *ptr++;
*************** get_unwind_record (prologue_flag, data,
*** 275,282 ****
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);
else
return read_B_record (data, val, ptr);
}
--- 274,281 ----
if (val == UNW_X1 || val == UNW_X2 || val == UNW_X3 || val == UNW_X4)
return read_X_record (data, val, ptr);
! if (header->type != body)
! return read_P_record (data, val, ptr, header);
else
return read_B_record (data, val, ptr);
}
*************** static unsigned char P8_additional_field
*** 534,543 ****
static unsigned char *
! read_P_record (data, val, ptr)
unwind_record *data;
unsigned char val;
unsigned char *ptr;
{
if ((val & 0xe0) == 0x80)
{
--- 533,543 ----
static unsigned char *
! read_P_record (data, val, ptr, header)
unwind_record *data;
unsigned char val;
unsigned char *ptr;
+ unwind_record *header;
{
if ((val & 0xe0) == 0x80)
{
*************** read_P_record (data, val, ptr)
*** 575,587 ****
if (val == UNW_P4)
{
! /* P4 format. Currently unimplemented. */
! int len = 0; /* TODO.. get prologue rlen. */
! int size = (len * 2 + 7) / 8;
data->type = spill_mask;
data->record.p.imask = (unsigned char *) malloc (size);
! /* memcpy (data->record.p.imask, ptr, size); */
return ptr+size;
}
--- 575,586 ----
if (val == UNW_P4)
{
! /* 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);
return ptr+size;
}
*************** read_P_record (data, val, ptr)
*** 617,623 ****
{
case P7_T_SIZE:
data->record.p.t = read_uleb128 (&ptr);
! data->record.p.size = read_uleb128 (&ptr);
break;
case P7_T:
data->record.p.t = read_uleb128 (&ptr);
--- 616,622 ----
{
case P7_T_SIZE:
data->record.p.t = read_uleb128 (&ptr);
! data->record.p.size = read_uleb128 (&ptr) << 4;
break;
case P7_T:
data->record.p.t = read_uleb128 (&ptr);
*************** execute_one_ia64_descriptor (addr, frame
*** 733,743 ****
long *len;
{
unwind_record r;
ia64_reg_loc *loc_ptr = NULL;
int grmask = 0, frmask = 0;
*len = -1;
! addr = get_unwind_record (1, &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
--- 732,745 ----
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 (®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
*************** execute_one_ia64_descriptor (addr, frame
*** 748,753 ****
--- 750,756 ----
case prologue:
case body:
*len = r.record.r.rlen;
+ memcpy (®ion_header, &r, sizeof (unwind_record));
break;
case prologue_gr:
{
*************** execute_one_ia64_descriptor (addr, frame
*** 780,785 ****
--- 783,789 ----
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:
*************** __build_ia64_frame_state (pc, frame, bsp
*** 1312,1318 ****
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;
pc_offset = (pc - start_pc) / 16 * 3;
init_ia64_unwind_frame (frame);
--- 1316,1322 ----
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 + IA64_UNW_HDR_LENGTH (unw_info_ptr->header) * 8;
pc_offset = (pc - start_pc) / 16 * 3;
init_ia64_unwind_frame (frame);
*************** __get_personality (ptr)
*** 1345,1351 ****
unwind_info_ptr *ptr;
{
void **p;
! p = (void **) (ptr->unwind_descriptors + ptr->length * 8);
return *p;
}
--- 1349,1356 ----
unwind_info_ptr *ptr;
{
void **p;
! p = (void **) (ptr->unwind_descriptors
! + IA64_UNW_HDR_LENGTH (ptr->header) * 8);
return *p;
}
*************** __get_except_table (ptr)
*** 1354,1364 ****
unwind_info_ptr *ptr;
{
void **p, *table;
! p = (void **) (ptr->unwind_descriptors + ptr->length * 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);
return table;
}
--- 1359,1371 ----
unwind_info_ptr *ptr;
{
void **p, *table;
! 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
! + IA64_UNW_HDR_LENGTH (ptr->header) * 8 + 8);
return table;
}
*************** print_all_records (f, mem, size)
*** 1595,1606 ****
{
unsigned char *end = mem + size;
unwind_record r;
fprintf (f, "UNWIND IMAGE:\n");
while (mem < end)
{
! mem = get_unwind_record (1, &r, mem);
print_record (f, &r);
}
fprintf (f, "--end unwind image--\n\n");
}
--- 1602,1624 ----
{
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 (®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");
}
Index: config/ia64/ia64.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/ia64/ia64.c,v
retrieving revision 1.20
diff -p -r1.20 ia64.c
*** ia64.c 2000/06/01 00:14:13 1.20
--- ia64.c 2000/06/07 02:23:50
*************** process_set (asm_out_file, pat)
*** 3117,3124 ****
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_emitted = 1;
}
}
--- 3117,3123 ----
if (!spill_offset_emitted)
{
fprintf (asm_out_file, "\t.spill %d\n",
! (-(spill_offset - 8) + 16));
spill_offset_emitted = 1;
}
}
*************** process_set (asm_out_file, pat)
*** 3138,3147 ****
/* register 9 is ar.unat. */
if (tmp_saved == 9)
fprintf (asm_out_file, "\t.savesp ar.unat, %d\n",
! (sp_offset - 8) / 4);
else if (tmp_saved == 5)
fprintf (asm_out_file, "\t.savesp pr, %d\n",
! (sp_offset - 8) / 4);
else if (tmp_saved >= BR_REG (1) && tmp_saved <= BR_REG (5))
{
/* BR regs are saved this way too. */
--- 3137,3146 ----
/* register 9 is ar.unat. */
if (tmp_saved == 9)
fprintf (asm_out_file, "\t.savesp ar.unat, %d\n",
! (sp_offset - 8));
else if (tmp_saved == 5)
fprintf (asm_out_file, "\t.savesp pr, %d\n",
! (sp_offset - 8));
else if (tmp_saved >= BR_REG (1) && tmp_saved <= BR_REG (5))
{
/* BR regs are saved this way too. */