* libjava failed to build on ia64 @ 2003-05-13 23:36 H. J. Lu 2003-05-14 7:56 ` Richard Henderson 0 siblings, 1 reply; 7+ messages in thread From: H. J. Lu @ 2003-05-13 23:36 UTC (permalink / raw) To: gcc As of Tue May 13 14:38:59 PDT 2003, gcc mainline failed in libjava: gnu/java/locale/.libs/LocaleInformation_en_PH.o(.text+0x52): In function `gnu::java::locale::LocaleInformation_en_PH::<clinit>()': /net/gnu/export/gnu/src/gcc/gcc/libjava/gnu/java/locale/LocaleInformation_en_PH.java:47: relocation truncated to fit: GPREL22 .text collect2: ld returned 1 exit status make[5]: *** [libgcj.la] Error 1 I am not sure if it is the right usage of LTOFF22X 0000000000000050 <_ZN3gnu4java6locale23LocaleInformation_en_PH18__U3c_clinit__U3e_Ev>: 50: 08 30 ae 50 80 05 [MMI] alloc r70=ar.pfs,43,40,0 52: LTOFF22X .data.rel.local 56: c0 00 32 7c 46 00 adds r12=-192,r12 5c: 04 08 00 90 addl r32=0,r1 60: 09 08 02 02 00 24 [MMI] addl r65=0,r1 60: LTOFF22X _ZN3gnu4java6locale23LocaleInformation_en_PH16decimalSeparatorE 61: LTOFF22X _ZN3gnu4java6locale23LocaleInformation_en_PH17groupingSeparatorE 62: LTOFF22X _ZN3gnu4java6locale23LocaleInformation_en_PH12numberFormatE 66: 20 04 04 00 48 60 addl r66=0,r1 6c: 08 08 00 90 addl r67=0,r1;; H.J. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: libjava failed to build on ia64 2003-05-13 23:36 libjava failed to build on ia64 H. J. Lu @ 2003-05-14 7:56 ` Richard Henderson 2003-05-14 22:53 ` PATCH: Fix the relax finalize pass H. J. Lu 0 siblings, 1 reply; 7+ messages in thread From: Richard Henderson @ 2003-05-14 7:56 UTC (permalink / raw) To: H. J. Lu; +Cc: gcc On Tue, May 13, 2003 at 04:36:47PM -0700, H. J. Lu wrote: > I am not sure if it is the right usage of LTOFF22X It is. You're allowed to use it with any operand whatsoever. r~ ^ permalink raw reply [flat|nested] 7+ messages in thread
* PATCH: Fix the relax finalize pass 2003-05-14 7:56 ` Richard Henderson @ 2003-05-14 22:53 ` H. J. Lu 2003-05-15 1:04 ` Richard Henderson 0 siblings, 1 reply; 7+ messages in thread From: H. J. Lu @ 2003-05-14 22:53 UTC (permalink / raw) To: Richard Henderson, gcc; +Cc: binutils, amodra, jakub [-- Attachment #1: Type: text/plain, Size: 453 bytes --] On Wed, May 14, 2003 at 12:53:30AM -0700, Richard Henderson wrote: > On Tue, May 13, 2003 at 04:36:47PM -0700, H. J. Lu wrote: > > I am not sure if it is the right usage of LTOFF22X > > It is. You're allowed to use it with any operand whatsoever. > > The problem is linker keeps changing data segment address after the relax finalize pass starts. It makes the GP calculation in the relax finalize pass invalid. This patch tries to avoid it. H.J. [-- Attachment #2: ld-final.patch --] [-- Type: text/plain, Size: 11106 bytes --] 2003-05-14 H.J. Lu <hongjiu.lu@intel.com> * ldlang.c (lang_size_sections_1): Take one more argument to indicate if the relax finalize pass is needed. (lang_size_sections): Updated. (lang_process): Likewise. * ldlang.h (lang_size_sections_1): Likewise. * pe-dll.c (pe_dll_fill_sections): Likewise. (pe_exe_fill_sections): Likewise. * emultempl/elf32.em (gld${EMULATION_NAME}_finish): Likewise. * emultempl/hppaelf.em (hppaelf_layout_sections_again): Likewise. * emultempl/ppc64elf.em (ppc_before_allocation): Likewise. (ppc_layout_sections_again): Likewise. * ldlang.c (lang_size_sections): Don't adjust data segment address after the relax finalize pass starts. (lang_process): Perform the relax finalize pass only when needed. Finalize addresses before the relax finalize pass. --- ld/emultempl/elf32.em.final 2003-05-09 08:13:31.000000000 -0700 +++ ld/emultempl/elf32.em 2003-05-14 15:21:48.000000000 -0700 @@ -1430,7 +1430,8 @@ gld${EMULATION_NAME}_finish () /* Resize the sections. */ lang_size_sections (stat_ptr->head, abs_output_section, - &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE); + &stat_ptr->head, 0, (bfd_vma) 0, NULL, + NULL, TRUE); /* Redo special stuff. */ ldemul_after_allocation (); --- ld/emultempl/hppaelf.em.final 2003-02-28 12:53:34.000000000 -0800 +++ ld/emultempl/hppaelf.em 2003-05-14 15:21:57.000000000 -0700 @@ -231,7 +231,8 @@ hppaelf_layout_sections_again () /* Resize the sections. */ lang_size_sections (stat_ptr->head, abs_output_section, - &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE); + &stat_ptr->head, 0, (bfd_vma) 0, NULL, NULL, + TRUE); /* Redo special stuff. */ ldemul_after_allocation (); --- ld/emultempl/ppc64elf.em.final 2003-02-28 12:53:38.000000000 -0800 +++ ld/emultempl/ppc64elf.em 2003-05-14 15:22:16.000000000 -0700 @@ -118,7 +118,8 @@ ppc_before_allocation () /* Size the sections. This is premature, but we want to know the TLS segment layout so that certain optimizations can be done. */ lang_size_sections (stat_ptr->head, abs_output_section, - &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE); + &stat_ptr->head, 0, (bfd_vma) 0, + NULL, NULL, TRUE); if (!ppc64_elf_tls_optimize (output_bfd, &link_info)) { @@ -273,7 +274,8 @@ ppc_layout_sections_again () /* Resize the sections. */ lang_size_sections (stat_ptr->head, abs_output_section, - &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE); + &stat_ptr->head, 0, (bfd_vma) 0, + NULL, NULL, TRUE); /* Recalculate TOC base. */ ldemul_after_allocation (); --- ld/ldlang.c.final 2003-05-13 08:45:34.000000000 -0700 +++ ld/ldlang.c 2003-05-14 15:36:47.000000000 -0700 @@ -199,9 +199,10 @@ static void os_region_check PARAMS ((lang_output_section_statement_type *, struct memory_region_struct *, etree_type *, bfd_vma)); static bfd_vma lang_size_sections_1 - PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *, - lang_statement_union_type **, fill_type *, bfd_vma, bfd_boolean *, - bfd_boolean)); + PARAMS ((lang_statement_union_type *, + lang_output_section_statement_type *, + lang_statement_union_type **, fill_type *, bfd_vma, + bfd_boolean *, bfd_boolean *, bfd_boolean)); typedef void (*callback_t) PARAMS ((lang_wild_statement_type *, struct wildcard_list *, asection *, lang_input_statement_type *, PTR)); @@ -2978,14 +2979,15 @@ os_region_check (os, region, tree, base) /* Set the sizes for all the output sections. */ static bfd_vma -lang_size_sections_1 (s, output_section_statement, prev, fill, dot, relax, - check_regions) +lang_size_sections_1 (s, output_section_statement, prev, fill, dot, + relax, need_finalize_relax, check_regions) lang_statement_union_type *s; lang_output_section_statement_type *output_section_statement; lang_statement_union_type **prev; fill_type *fill; bfd_vma dot; bfd_boolean *relax; + bfd_boolean *need_finalize_relax; bfd_boolean check_regions; { unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, @@ -3123,8 +3125,10 @@ lang_size_sections_1 (s, output_section_ os->bfd_section->output_offset = 0; } - lang_size_sections_1 (os->children.head, os, &os->children.head, - os->fill, dot, relax, check_regions); + lang_size_sections_1 (os->children.head, os, + &os->children.head, os->fill, dot, + relax, need_finalize_relax, + check_regions); /* Put the section within the requested block size, or align at the block boundary. */ @@ -3193,7 +3197,9 @@ lang_size_sections_1 (s, output_section_ dot = lang_size_sections_1 (constructor_list.head, output_section_statement, &s->wild_statement.children.head, - fill, dot, relax, check_regions); + fill, dot, relax, + need_finalize_relax, + check_regions); break; case lang_data_statement_enum: @@ -3257,7 +3263,9 @@ lang_size_sections_1 (s, output_section_ dot = lang_size_sections_1 (s->wild_statement.children.head, output_section_statement, &s->wild_statement.children.head, - fill, dot, relax, check_regions); + fill, dot, relax, + need_finalize_relax, + check_regions); break; @@ -3286,6 +3294,7 @@ lang_size_sections_1 (s, output_section_ einfo (_("%P%F: can't relax section: %E\n")); if (again) *relax = TRUE; + *need_finalize_relax |= i->need_finalize_relax; } dot = size_input_section (prev, output_section_statement, output_section_statement->fill, dot); @@ -3355,7 +3364,9 @@ lang_size_sections_1 (s, output_section_ dot = lang_size_sections_1 (s->group_statement.children.head, output_section_statement, &s->group_statement.children.head, - fill, dot, relax, check_regions); + fill, dot, relax, + need_finalize_relax, + check_regions); break; default: @@ -3372,22 +3383,28 @@ lang_size_sections_1 (s, output_section_ } bfd_vma -lang_size_sections (s, output_section_statement, prev, fill, dot, relax, - check_regions) +lang_size_sections (s, output_section_statement, prev, fill, dot, + relax, need_finalize_relax, check_regions) lang_statement_union_type *s; lang_output_section_statement_type *output_section_statement; lang_statement_union_type **prev; fill_type *fill; bfd_vma dot; bfd_boolean *relax; + bfd_boolean *need_finalize_relax; bfd_boolean check_regions; { bfd_vma result; exp_data_seg.phase = exp_dataseg_none; - result = lang_size_sections_1 (s, output_section_statement, prev, fill, - dot, relax, check_regions); - if (exp_data_seg.phase == exp_dataseg_end_seen) + result = lang_size_sections_1 (s, output_section_statement, prev, + fill, dot, relax, need_finalize_relax, + check_regions); + + /* We can't change addresses after the relax finalize pass starts + since the relaxation may assume addresses won't be changes. */ + if (!link_info.relax_finalizing + && exp_data_seg.phase == exp_dataseg_end_seen) { /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether a page could be saved in the data segment. */ @@ -3401,8 +3418,10 @@ lang_size_sections (s, output_section_st && first + last <= exp_data_seg.pagesize) { exp_data_seg.phase = exp_dataseg_adjust; - result = lang_size_sections_1 (s, output_section_statement, prev, - fill, dot, relax, check_regions); + result = lang_size_sections_1 (s, output_section_statement, + prev, fill, dot, relax, + need_finalize_relax, + check_regions); } } @@ -4378,7 +4397,7 @@ lang_process () /* Size up the sections. */ lang_size_sections (statement_list.head, abs_output_section, - &statement_list.head, 0, (bfd_vma) 0, NULL, + &statement_list.head, 0, (bfd_vma) 0, NULL, NULL, command_line.relax ? FALSE : TRUE); /* Now run around and relax if we can. */ @@ -4386,6 +4405,7 @@ lang_process () { /* Keep relaxing until bfd_relax_section gives up. */ bfd_boolean relax_again; + bfd_boolean need_finalize_relax; do { @@ -4408,14 +4428,29 @@ lang_process () lang_size_sections (statement_list.head, abs_output_section, &statement_list.head, 0, (bfd_vma) 0, - &relax_again, FALSE); + &relax_again, &need_finalize_relax, + FALSE); /* If the normal relax is done and the relax finalize pass is not performed yet, we perform another relax pass. */ - if (!relax_again && !link_info.relax_finalizing) + if (!relax_again + && need_finalize_relax + && !link_info.relax_finalizing) { link_info.relax_finalizing = TRUE; relax_again = TRUE; + if (exp_data_seg.phase == exp_dataseg_adjust) + { + /* Make sure addresses are finalized. */ + lang_reset_memory_regions (); + lang_do_assignments (statement_list.head, + abs_output_section, + (fill_type *) 0, (bfd_vma) 0); + lang_size_sections (statement_list.head, + abs_output_section, + &statement_list.head, 0, + (bfd_vma) 0, NULL, NULL, TRUE); + } } } while (relax_again); @@ -4428,7 +4463,7 @@ lang_process () lang_size_sections (statement_list.head, abs_output_section, & statement_list.head, 0, (bfd_vma) 0, - NULL, TRUE); + NULL, NULL, TRUE); } /* See if anything special should be done now we know how big --- ld/ldlang.h.final 2003-03-04 11:11:00.000000000 -0800 +++ ld/ldlang.h 2003-05-14 15:09:58.000000000 -0700 @@ -482,7 +482,9 @@ extern bfd_vma lang_size_sections PARAMS ((lang_statement_union_type *s, lang_output_section_statement_type *output_section_statement, lang_statement_union_type **prev, fill_type *fill, - bfd_vma dot, bfd_boolean *relax, bfd_boolean check_regions)); + bfd_vma dot, bfd_boolean *relax, + bfd_boolean *need_finalize_relax, + bfd_boolean check_regions)); extern void lang_enter_group PARAMS ((void)); extern void lang_leave_group --- ld/pe-dll.c.final 2003-04-02 13:42:02.000000000 -0800 +++ ld/pe-dll.c 2003-05-14 15:10:50.000000000 -0700 @@ -2703,7 +2703,8 @@ pe_dll_fill_sections (abfd, info) /* Resize the sections. */ lang_size_sections (stat_ptr->head, abs_output_section, - &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE); + &stat_ptr->head, 0, (bfd_vma) 0, + NULL, NULL, TRUE); /* Redo special stuff. */ ldemul_after_allocation (); @@ -2738,7 +2739,8 @@ pe_exe_fill_sections (abfd, info) /* Resize the sections. */ lang_size_sections (stat_ptr->head, abs_output_section, - &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE); + &stat_ptr->head, 0, (bfd_vma) 0, + NULL, NULL, TRUE); /* Redo special stuff. */ ldemul_after_allocation (); ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: PATCH: Fix the relax finalize pass 2003-05-14 22:53 ` PATCH: Fix the relax finalize pass H. J. Lu @ 2003-05-15 1:04 ` Richard Henderson 2003-05-15 5:24 ` H. J. Lu 0 siblings, 1 reply; 7+ messages in thread From: Richard Henderson @ 2003-05-15 1:04 UTC (permalink / raw) To: H. J. Lu; +Cc: gcc, binutils, amodra, jakub On Wed, May 14, 2003 at 03:53:46PM -0700, H. J. Lu wrote: > * ldlang.c (lang_size_sections_1): Take one more argument to > indicate if the relax finalize pass is needed. > (lang_size_sections): Updated. > (lang_process): Likewise. > * ldlang.h (lang_size_sections_1): Likewise. > * pe-dll.c (pe_dll_fill_sections): Likewise. > (pe_exe_fill_sections): Likewise. > * emultempl/elf32.em (gld${EMULATION_NAME}_finish): Likewise. > * emultempl/hppaelf.em (hppaelf_layout_sections_again): Likewise. > * emultempl/ppc64elf.em (ppc_before_allocation): Likewise. > (ppc_layout_sections_again): Likewise. > > * ldlang.c (lang_size_sections): Don't adjust data segment > address after the relax finalize pass starts. > (lang_process): Perform the relax finalize pass only when > needed. Finalize addresses before the relax finalize pass. Ug. This is becoming gross. I think the proper way to handle this is to break up the relax pass in bfd so that the backend gets more control. (1) We need a "beginning of new pass" hook that is called after sizes are guessed and addresses are assigned. This is where we'd assign a new GP if needed. We'd like for this to be able to allocate a data structure private to the backend, so that the pieces and passes can communicate. (2) Existing relax hook operates on each section as usual. It records information into the private data structure as needed. (3) An "end of pass" hook that is called after all sections are processed. Using data collected from sections it may decide to re-layout the GOT, or adjust dynamic relocations or whatever. Currently we do this kind of thing for every section, which wastes time. If this "end of pass" hook returns "no more iterations", then it is also the case that the private data has been deallocated. Operation for ia64 would indeed pass through two phases, one in which we expand code by adding trampolines, and one in which we shrink data by eliminating got entries. But all this would be controlled by the backend, and all lang_size_sections knows is that it's been told to continue around the relaxation loop. As a side benefit, ia64 would get to keep track of the trampolines that it has added between sections and iterations, so that they can be re-used when they're in range. r~ ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: PATCH: Fix the relax finalize pass 2003-05-15 1:04 ` Richard Henderson @ 2003-05-15 5:24 ` H. J. Lu 2003-05-15 5:40 ` Richard Henderson 0 siblings, 1 reply; 7+ messages in thread From: H. J. Lu @ 2003-05-15 5:24 UTC (permalink / raw) To: Richard Henderson, gcc, binutils, amodra, jakub On Wed, May 14, 2003 at 06:01:25PM -0700, Richard Henderson wrote: > On Wed, May 14, 2003 at 03:53:46PM -0700, H. J. Lu wrote: > > * ldlang.c (lang_size_sections_1): Take one more argument to > > indicate if the relax finalize pass is needed. > > (lang_size_sections): Updated. > > (lang_process): Likewise. > > * ldlang.h (lang_size_sections_1): Likewise. > > * pe-dll.c (pe_dll_fill_sections): Likewise. > > (pe_exe_fill_sections): Likewise. > > * emultempl/elf32.em (gld${EMULATION_NAME}_finish): Likewise. > > * emultempl/hppaelf.em (hppaelf_layout_sections_again): Likewise. > > * emultempl/ppc64elf.em (ppc_before_allocation): Likewise. > > (ppc_layout_sections_again): Likewise. > > > > * ldlang.c (lang_size_sections): Don't adjust data segment > > address after the relax finalize pass starts. > > (lang_process): Perform the relax finalize pass only when > > needed. Finalize addresses before the relax finalize pass. > > Ug. This is becoming gross. > > I think the proper way to handle this is to break up the relax > pass in bfd so that the backend gets more control. > > (1) We need a "beginning of new pass" hook that is called > after sizes are guessed and addresses are assigned. > This is where we'd assign a new GP if needed. > The problem is . = DATA_SEGMENT_ALIGN (0x10000, 0x4000); used in elf64_ia64.xs and the corresponding code in lang_size_sections exp_data_seg.phase = exp_dataseg_none; result = lang_size_sections_1 (s, output_section_statement, prev, fill, dot, relax, check_regions); if (exp_data_seg.phase == exp_dataseg_end_seen) { /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether a page could be saved in the data segment. */ bfd_vma first, last; first = -exp_data_seg.base & (exp_data_seg.pagesize - 1); last = exp_data_seg.end & (exp_data_seg.pagesize - 1); if (first && last && ((exp_data_seg.base & ~(exp_data_seg.pagesize - 1)) != (exp_data_seg.end & ~(exp_data_seg.pagesize - 1))) && first + last <= exp_data_seg.pagesize) { exp_data_seg.phase = exp_dataseg_adjust; result = lang_size_sections_1 (s, output_section_statement, prev, fill, dot, relax, check_regions); } } That means every time when you start a relax pass, ld will try to squeeze one page out of the data segment. Unless you tell it not to do it, when the final pass starts, any section size change in the final pass may lead to data segment address change due to the call to lang_do_assignments after the final relax pass. > We'd like for this to be able to allocate a data structure > private to the backend, so that the pieces and passes can > communicate. > > (2) Existing relax hook operates on each section as usual. > It records information into the private data structure > as needed. > > (3) An "end of pass" hook that is called after all sections > are processed. Using data collected from sections it > may decide to re-layout the GOT, or adjust dynamic > relocations or whatever. Currently we do this kind of > thing for every section, which wastes time. The current code has if ((sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0 || (link_info->relax_finalizing && sec->need_finalize_relax == 0)) return TRUE; If need_finalize_relax is 0, it will return immediately. > > If this "end of pass" hook returns "no more iterations", > then it is also the case that the private data has been > deallocated. > > Operation for ia64 would indeed pass through two phases, one > in which we expand code by adding trampolines, and one in which > we shrink data by eliminating got entries. But all this would > be controlled by the backend, and all lang_size_sections knows > is that it's been told to continue around the relaxation loop. > > As a side benefit, ia64 would get to keep track of the > trampolines that it has added between sections and iterations, > so that they can be re-used when they're in range. > The only thing my current patch doesn't do is sharing trampolines. The current linker doesn't work too well on ia64. My current patch is an improvement. I can spend time to investigate a better solution. But I'd like to see a working linker in the meantime. Another simple kludge is to disable the if (exp_data_seg.phase == exp_dataseg_end_seen) { /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether a page could be saved in the data segment. */ ... } block. We can put a FIXME there. H.J. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: PATCH: Fix the relax finalize pass 2003-05-15 5:24 ` H. J. Lu @ 2003-05-15 5:40 ` Richard Henderson 2003-05-15 5:42 ` H. J. Lu 0 siblings, 1 reply; 7+ messages in thread From: Richard Henderson @ 2003-05-15 5:40 UTC (permalink / raw) To: H. J. Lu; +Cc: gcc, binutils, amodra, jakub On Wed, May 14, 2003 at 10:24:51PM -0700, H. J. Lu wrote: > ... when the final pass starts, any section size change in the > final pass may lead to data segment address change due to the call > to lang_do_assignments after the final relax pass. Seems to me then you shouldn't be calling into the bfd backend if that's the case. So after bfd says it's done, you go one more round to finalize the data section start. > Another simple kludge is to disable the > > if (exp_data_seg.phase == exp_dataseg_end_seen) > { > /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether > a page could be saved in the data segment. */ > ... > } > > block. We can put a FIXME there. Maybe that would be better. It'd mean less kruft to have to back out of the main linker. r~ ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: PATCH: Fix the relax finalize pass 2003-05-15 5:40 ` Richard Henderson @ 2003-05-15 5:42 ` H. J. Lu 0 siblings, 0 replies; 7+ messages in thread From: H. J. Lu @ 2003-05-15 5:42 UTC (permalink / raw) To: Richard Henderson, gcc, binutils, amodra, jakub On Wed, May 14, 2003 at 10:37:48PM -0700, Richard Henderson wrote: > > Another simple kludge is to disable the > > > > if (exp_data_seg.phase == exp_dataseg_end_seen) > > { > > /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether > > a page could be saved in the data segment. */ > > ... > > } > > > > block. We can put a FIXME there. > > Maybe that would be better. It'd mean less kruft to have > to back out of the main linker. > I just posted one. H.J. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2003-05-15 5:42 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2003-05-13 23:36 libjava failed to build on ia64 H. J. Lu 2003-05-14 7:56 ` Richard Henderson 2003-05-14 22:53 ` PATCH: Fix the relax finalize pass H. J. Lu 2003-05-15 1:04 ` Richard Henderson 2003-05-15 5:24 ` H. J. Lu 2003-05-15 5:40 ` Richard Henderson 2003-05-15 5:42 ` H. J. Lu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).