From KokHow.Teh@infineon.com Tue Jul  1 07:05:28 2008
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 01 Jul 2008 07:05:35 +0100 (BST)
Received: from smtp3.infineon.com ([203.126.106.229]:10290 "EHLO
	smtp3.infineon.com") by ftp.linux-mips.org with ESMTP
	id S29047646AbYGAGF2 convert rfc822-to-8bit (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Tue, 1 Jul 2008 07:05:28 +0100
X-SBRS:	None
Received: from unknown (HELO sinse301.ap.infineon.com) ([172.20.70.22])
  by smtp3.infineon.com with ESMTP; 01 Jul 2008 14:05:19 +0800
Received: from sinse303.ap.infineon.com ([172.20.70.24]) by sinse301.ap.infineon.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.1830);
	 Tue, 1 Jul 2008 14:05:18 +0800
X-MimeOLE: Produced By Microsoft Exchange V6.5
Content-class: urn:content-classes:message
MIME-Version: 1.0
Content-Type: text/plain;
	charset="us-ascii"
Content-Transfer-Encoding: 8BIT
Subject: Kmem_cache handling in linux-2.6.2x kernel.
Date:	Tue, 1 Jul 2008 14:05:17 +0800
Message-ID: <31E09F73562D7A4D82119D7F6C172986045B6E80@sinse303.ap.infineon.com>
X-MS-Has-Attach: 
X-MS-TNEF-Correlator: 
Thread-Topic: Kmem_cache handling in linux-2.6.2x kernel.
Thread-Index: AcjbQCezWLXpXWxBSj2JrUNDAJRvkw==
From:	<KokHow.Teh@infineon.com>
To:	<linux-mips@linux-mips.org>, <bookquestions@oreilly.com>
Cc:	<Bing-Tao.Xu@infineon.com>
X-OriginalArrivalTime: 01 Jul 2008 06:05:18.0988 (UTC) FILETIME=[706164C0:01C8DB40]
Return-Path: <KokHow.Teh@infineon.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 19677
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: KokHow.Teh@infineon.com
Precedence: bulk
X-list: linux-mips
Content-Length: 1430
Lines: 26

Hi list;
	I have a question about kmem_cache implemented in Linux-2.6.2x
kernel. I have an application that allocates and free 64KByte chunks of
memory (32-byte aligned) quite often. Therefore, I create a lookaside
cache for that purpose and use kmem_cache_alloc(), kmem_cache_free() to
allocate and free the caches. The application works very well in this
model. However, my concern here is if kmem_cache_free() does return the
cache to the system-wide pool so that it could be used by other
applications when need arises; when system is low in memory resources,
for instance. This is a question about the internal workings of the
memory management system of the Linux-2.6.2x kernel as to how efficient
it manages this lookasie caches. The concern is valid because if this
lookaside cache is not managed well, i.e, it is not returned to the
system-wide pool of free memory pools to be used by other applications,
this will penalize the performace and throughput of the whole system due
to the dynamic behaviour of the utilization of system memory resources.
For example, other applications might be swapping in and out of the
harddisk and if the kmem_cache_free()'ed memory objects could be used by
these applications, it will help in this case to reduce the number of
swaps that happen, thereby freeing the CPU and/or DMA from doing the
swapping to do other critical tasks.

	Any insight and advice is appreciated.

Regards,
KH

From nschichan@freebox.fr Tue Jul  1 14:42:37 2008
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 01 Jul 2008 14:42:44 +0100 (BST)
Received: from bobafett.staff.proxad.net ([213.228.1.121]:20421 "EHLO
	bobafett.staff.proxad.net") by ftp.linux-mips.org with ESMTP
	id S30613934AbYGANmh (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 1 Jul 2008 14:42:37 +0100
Received: from localhost (localhost [127.0.0.1])
	by bobafett.staff.proxad.net (Postfix) with ESMTP id CE5302AE93;
	Tue,  1 Jul 2008 15:42:30 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at staff.proxad.net
Received: from bobafett.staff.proxad.net ([127.0.0.1])
	by localhost (bobafett.staff.proxad.net [127.0.0.1]) (amavisd-new, port 10024)
	with LMTP id wyuBsemcEl1S; Tue,  1 Jul 2008 15:42:29 +0200 (CEST)
Received: from nschichan.priv.staff.proxad.net (nschichan.priv.staff.proxad.net [172.18.3.120])
	by bobafett.staff.proxad.net (Postfix) with ESMTP id A42192AE47;
	Tue,  1 Jul 2008 15:42:29 +0200 (CEST)
From:	Nicolas Schichan <nschichan@freebox.fr>
Organization: Freebox
To:	Tomasz Chmielewski <mangoo@wpkg.org>
Subject: Re: kexec on mips - anyone has it working?
Date:	Tue, 1 Jul 2008 15:42:28 +0200
User-Agent: KMail/1.9.6 (enterprise 0.20070907.709405)
Cc:	linux-mips@linux-mips.org,
	Kexec Mailing List <kexec@lists.infradead.org>,
	openwrt-devel@lists.openwrt.org
References: <483BCB75.4050901@wpkg.org> <200805301327.11925.nschichan@freebox.fr> <483FE764.1090901@wpkg.org>
In-Reply-To: <483FE764.1090901@wpkg.org>
MIME-Version: 1.0
Content-Type: text/plain;
  charset="utf-8"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Message-Id: <200807011542.29274.nschichan@freebox.fr>
Return-Path: <nschichan@freebox.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 19678
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: nschichan@freebox.fr
Precedence: bulk
X-list: linux-mips
Content-Length: 1279
Lines: 47

On Friday 30 May 2008 13:39:16 Tomasz Chmielewski wrote:

Hello,

> Nicolas Schichan schrieb:
> > On Thursday 29 May 2008 22:15:47 Tomasz Chmielewski wrote:
> >> Will call new kernel at 00305000
> >
> > The calling address of the kernel looks quite wrong, it should clearly
> > be inside the KSEG0 zone. could  you please indicate the output of the
> > command "mips-linux-readelf -l vmlinux" ?
>
> # uname -m
> mips
> # readelf -l vmlinux
>
> Elf file type is EXEC (Executable file)
> Entry point 0x80251b50

This is  quite surprising.   The jump address  that kexec will  use is
cleary not what  I expected. I would have expected it  to be the Entry
point address given by readelf.

could  you try  the  following patch  to  make sure  that the  kimage*
structure is not corrupted by the code in machine_kexec() ?

Index: linux/arch/mips/kernel/machine_kexec.c
===================================================================
--- linux/arch/mips/kernel/machine_kexec.c	(revision 8056)
+++ linux/arch/mips/kernel/machine_kexec.c	(working copy)
@@ -49,6 +49,8 @@
 	unsigned long entry;
 	unsigned long *ptr;
 
+	printk("image->start = %p", image->start);
+
 	reboot_code_buffer =
 	  (unsigned long)page_address(image->control_code_page);
 


Regards,

-- 
Nicolas Schichan



From mangoo@wpkg.org Tue Jul  1 18:53:34 2008
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 01 Jul 2008 18:53:41 +0100 (BST)
Received: from mx03.syneticon.net ([87.79.32.166]:22534 "EHLO
	mx03.syneticon.net") by ftp.linux-mips.org with ESMTP
	id S32704464AbYGARxe (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 1 Jul 2008 18:53:34 +0100
Received: from localhost (filter1.syneticon.net [192.168.113.3])
	by mx03.syneticon.net (Postfix) with ESMTP id 22DC29601;
	Tue,  1 Jul 2008 19:53:33 +0200 (CEST)
X-Virus-Scanned: amavisd-new at mx03.syneticon.net
Received: from mx03.syneticon.net ([192.168.113.4])
	by localhost (mx03.syneticon.net [192.168.113.3]) (amavisd-new, port 10025)
	with ESMTP id py1CEgWu3J7t; Tue,  1 Jul 2008 19:53:19 +0200 (CEST)
Received: from [192.168.10.145] (koln-4d0b69d5.pool.mediaWays.net [77.11.105.213])
	by mx03.syneticon.net (Postfix) with ESMTP;
	Tue,  1 Jul 2008 19:53:19 +0200 (CEST)
Message-ID: <486A6F0D.4070802@wpkg.org>
Date:	Tue, 01 Jul 2008 19:53:17 +0200
From:	Tomasz Chmielewski <mangoo@wpkg.org>
User-Agent: Thunderbird 2.0.0.12 (X11/20080305)
MIME-Version: 1.0
To:	Nicolas Schichan <nschichan@freebox.fr>
CC:	linux-mips@linux-mips.org,
	Kexec Mailing List <kexec@lists.infradead.org>,
	openwrt-devel@lists.openwrt.org
Subject: Re: kexec on mips - anyone has it working?
References: <483BCB75.4050901@wpkg.org> <200805301327.11925.nschichan@freebox.fr> <483FE764.1090901@wpkg.org> <200807011542.29274.nschichan@freebox.fr>
In-Reply-To: <200807011542.29274.nschichan@freebox.fr>
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <mangoo@wpkg.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 19679
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: mangoo@wpkg.org
Precedence: bulk
X-list: linux-mips
Content-Length: 1832
Lines: 55

Nicolas Schichan schrieb:
> On Friday 30 May 2008 13:39:16 Tomasz Chmielewski wrote:
> 
> Hello,
> 
>> Nicolas Schichan schrieb:
>>> On Thursday 29 May 2008 22:15:47 Tomasz Chmielewski wrote:
>>>> Will call new kernel at 00305000
>>> The calling address of the kernel looks quite wrong, it should clearly
>>> be inside the KSEG0 zone. could  you please indicate the output of the
>>> command "mips-linux-readelf -l vmlinux" ?
>> # uname -m
>> mips
>> # readelf -l vmlinux
>>
>> Elf file type is EXEC (Executable file)
>> Entry point 0x80251b50
> 
> This is  quite surprising.   The jump address  that kexec will  use is
> cleary not what  I expected. I would have expected it  to be the Entry
> point address given by readelf.
> 
> could  you try  the  following patch  to  make sure  that the  kimage*
> structure is not corrupted by the code in machine_kexec() ?
> 
> Index: linux/arch/mips/kernel/machine_kexec.c
> ===================================================================
> --- linux/arch/mips/kernel/machine_kexec.c	(revision 8056)
> +++ linux/arch/mips/kernel/machine_kexec.c	(working copy)
> @@ -49,6 +49,8 @@
>  	unsigned long entry;
>  	unsigned long *ptr;
>  
> +	printk("image->start = %p", image->start);
> +
>  	reboot_code_buffer =
>  	  (unsigned long)page_address(image->control_code_page);

Umm?

   CC      arch/mips/kernel/machine_kexec.o
cc1: warnings being treated as errors
arch/mips/kernel/machine_kexec.c: In function 'machine_kexec':
arch/mips/kernel/machine_kexec.c:52: warning: format '%p' expects type 
'void *', but argument 2 has type 'long unsigned int'
make[6]: *** [arch/mips/kernel/machine_kexec.o] Error 1
make[5]: *** [arch/mips/kernel] Error 2
make[5]: Leaving directory 
`/home/tch-data/openwrt/11612/build_dir/linux-brcm47xx/linux-2.6.25.9'



-- 
Tomasz Chmielewski
http://wpkg.org

From nschichan@freebox.fr Tue Jul  1 19:00:50 2008
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 01 Jul 2008 19:00:56 +0100 (BST)
Received: from bobafett.staff.proxad.net ([213.228.1.121]:28634 "EHLO
	bobafett.staff.proxad.net") by ftp.linux-mips.org with ESMTP
	id S32705264AbYGASAu (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 1 Jul 2008 19:00:50 +0100
Received: from localhost (localhost [127.0.0.1])
	by bobafett.staff.proxad.net (Postfix) with ESMTP id A879F2780D;
	Tue,  1 Jul 2008 20:00:41 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at staff.proxad.net
Received: from bobafett.staff.proxad.net ([127.0.0.1])
	by localhost (bobafett.staff.proxad.net [127.0.0.1]) (amavisd-new, port 10024)
	with LMTP id RtqeFE0FbOl5; Tue,  1 Jul 2008 20:00:40 +0200 (CEST)
Received: from nschichan.priv.staff.proxad.net (nschichan.priv.staff.proxad.net [172.18.3.120])
	by bobafett.staff.proxad.net (Postfix) with ESMTP id 9BA7943BE;
	Tue,  1 Jul 2008 20:00:40 +0200 (CEST)
From:	Nicolas Schichan <nschichan@freebox.fr>
Organization: Freebox
To:	kexec@lists.infradead.org
Subject: Re: kexec on mips - anyone has it working?
Date:	Tue, 1 Jul 2008 20:00:40 +0200
User-Agent: KMail/1.9.6 (enterprise 0.20070907.709405)
Cc:	Tomasz Chmielewski <mangoo@wpkg.org>, linux-mips@linux-mips.org
References: <483BCB75.4050901@wpkg.org> <200807011542.29274.nschichan@freebox.fr> <486A6F0D.4070802@wpkg.org>
In-Reply-To: <486A6F0D.4070802@wpkg.org>
MIME-Version: 1.0
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Message-Id: <200807012000.40421.nschichan@freebox.fr>
Return-Path: <nschichan@freebox.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 19680
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: nschichan@freebox.fr
Precedence: bulk
X-list: linux-mips
Content-Length: 1603
Lines: 50

On Tuesday 01 July 2008 19:53:17 Tomasz Chmielewski wrote:
> > Index: linux/arch/mips/kernel/machine_kexec.c
> > ===================================================================
> > --- linux/arch/mips/kernel/machine_kexec.c	(revision 8056)
> > +++ linux/arch/mips/kernel/machine_kexec.c	(working copy)
> > @@ -49,6 +49,8 @@
> >  	unsigned long entry;
> >  	unsigned long *ptr;
> >
> > +	printk("image->start = %p", image->start);
> > +
> >  	reboot_code_buffer =
> >  	  (unsigned long)page_address(image->control_code_page);
>
> Umm?
>
>    CC      arch/mips/kernel/machine_kexec.o
> cc1: warnings being treated as errors
> arch/mips/kernel/machine_kexec.c: In function 'machine_kexec':
> arch/mips/kernel/machine_kexec.c:52: warning: format '%p' expects type
> 'void *', but argument 2 has type 'long unsigned int'
> make[6]: *** [arch/mips/kernel/machine_kexec.o] Error 1
> make[5]: *** [arch/mips/kernel] Error 2
> make[5]: Leaving directory
> `/home/tch-data/openwrt/11612/build_dir/linux-brcm47xx/linux-2.6.25.9'

-Werror is missing from my kernel cflags.

Try this one, %lx will accept unsigned long parameters without warnings:

Index: linux/arch/mips/kernel/machine_kexec.c
===================================================================
--- linux/arch/mips/kernel/machine_kexec.c	(revision 8056)
+++ linux/arch/mips/kernel/machine_kexec.c	(working copy)
@@ -49,6 +49,8 @@
 	unsigned long entry;
 	unsigned long *ptr;
 
+	printk("image->start = %lx", image->start);
+
 	reboot_code_buffer =
 	  (unsigned long)page_address(image->control_code_page);
 

Regards,


-- 
Nicolas Schichan


From mangoo@wpkg.org Tue Jul  1 19:21:35 2008
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 01 Jul 2008 19:21:42 +0100 (BST)
Received: from mx03.syneticon.net ([87.79.32.166]:56836 "EHLO
	mx03.syneticon.net") by ftp.linux-mips.org with ESMTP
	id S32706994AbYGASVf (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 1 Jul 2008 19:21:35 +0100
Received: from localhost (filter1.syneticon.net [192.168.113.3])
	by mx03.syneticon.net (Postfix) with ESMTP id 5AEB29601;
	Tue,  1 Jul 2008 20:21:34 +0200 (CEST)
X-Virus-Scanned: amavisd-new at mx03.syneticon.net
Received: from mx03.syneticon.net ([192.168.113.4])
	by localhost (mx03.syneticon.net [192.168.113.3]) (amavisd-new, port 10025)
	with ESMTP id BRg5Zo+0PuhB; Tue,  1 Jul 2008 20:21:19 +0200 (CEST)
Received: from [192.168.10.145] (koln-4d0b69d5.pool.mediaWays.net [77.11.105.213])
	by mx03.syneticon.net (Postfix) with ESMTP;
	Tue,  1 Jul 2008 20:21:19 +0200 (CEST)
Message-ID: <486A759D.6080803@wpkg.org>
Date:	Tue, 01 Jul 2008 20:21:17 +0200
From:	Tomasz Chmielewski <mangoo@wpkg.org>
User-Agent: Thunderbird 2.0.0.12 (X11/20080305)
MIME-Version: 1.0
To:	Nicolas Schichan <nschichan@freebox.fr>
CC:	kexec@lists.infradead.org, linux-mips@linux-mips.org
Subject: Re: kexec on mips - anyone has it working?
References: <483BCB75.4050901@wpkg.org> <200807011542.29274.nschichan@freebox.fr> <486A6F0D.4070802@wpkg.org> <200807012000.40421.nschichan@freebox.fr>
In-Reply-To: <200807012000.40421.nschichan@freebox.fr>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <mangoo@wpkg.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 19681
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: mangoo@wpkg.org
Precedence: bulk
X-list: linux-mips
Content-Length: 330
Lines: 18

Nicolas Schichan schrieb:

> +	printk("image->start = %lx", image->start);
> +
>  	reboot_code_buffer =
>  	  (unsigned long)page_address(image->control_code_page);

# kexec -e
b44: eth0: powering down PHY
Starting new kernel
image->start = 304000Will call new kernel at 00304000
Bye ...



-- 
Tomasz Chmielewski
http://wpkg.org

From mangoo@wpkg.org Tue Jul  1 19:25:56 2008
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 01 Jul 2008 19:26:03 +0100 (BST)
Received: from mx03.syneticon.net ([87.79.32.166]:31501 "EHLO
	mx03.syneticon.net") by ftp.linux-mips.org with ESMTP
	id S32707294AbYGASZ4 (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 1 Jul 2008 19:25:56 +0100
Received: from localhost (filter1.syneticon.net [192.168.113.3])
	by mx03.syneticon.net (Postfix) with ESMTP id 3B98F9601;
	Tue,  1 Jul 2008 20:25:55 +0200 (CEST)
X-Virus-Scanned: amavisd-new at mx03.syneticon.net
Received: from mx03.syneticon.net ([192.168.113.4])
	by localhost (mx03.syneticon.net [192.168.113.3]) (amavisd-new, port 10025)
	with ESMTP id IVzukLrygtvA; Tue,  1 Jul 2008 20:25:52 +0200 (CEST)
Received: from [192.168.10.145] (koln-4d0b69d5.pool.mediaWays.net [77.11.105.213])
	by mx03.syneticon.net (Postfix) with ESMTP;
	Tue,  1 Jul 2008 20:25:52 +0200 (CEST)
Message-ID: <486A76AF.9080109@wpkg.org>
Date:	Tue, 01 Jul 2008 20:25:51 +0200
From:	Tomasz Chmielewski <mangoo@wpkg.org>
User-Agent: Thunderbird 2.0.0.12 (X11/20080305)
MIME-Version: 1.0
To:	Nicolas Schichan <nschichan@freebox.fr>
CC:	kexec@lists.infradead.org, linux-mips@linux-mips.org
Subject: Re: kexec on mips - anyone has it working?
References: <483BCB75.4050901@wpkg.org> <200807011542.29274.nschichan@freebox.fr> <486A6F0D.4070802@wpkg.org> <200807012000.40421.nschichan@freebox.fr>
In-Reply-To: <200807012000.40421.nschichan@freebox.fr>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <mangoo@wpkg.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 19682
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: mangoo@wpkg.org
Precedence: bulk
X-list: linux-mips
Content-Length: 350
Lines: 21

Nicolas Schichan schrieb:

(...)

> +	printk("image->start = %lx", image->start);
> +

And this is what happens if I use your "util.c for kexec-userland" - why 
does it use a different address?


# /root/kexec-test/kexec -r
Starting new kernel
image->start = 802520d0Will call new kernel at 802520d0
Bye ...


-- 
Tomasz Chmielewski
http://wpkg.org


From drow@false.org Tue Jul  1 21:22:47 2008
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 01 Jul 2008 21:22:56 +0100 (BST)
Received: from NaN.false.org ([208.75.86.248]:48332 "EHLO nan.false.org")
	by ftp.linux-mips.org with ESMTP id S32713250AbYGAUWr (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Tue, 1 Jul 2008 21:22:47 +0100
Received: from nan.false.org (localhost [127.0.0.1])
	by nan.false.org (Postfix) with ESMTP id 1F02198243;
	Tue,  1 Jul 2008 20:22:43 +0000 (GMT)
Received: from caradoc.them.org (22.svnf5.xdsl.nauticom.net [209.195.183.55])
	by nan.false.org (Postfix) with ESMTP id 0D6CF9809F;
	Tue,  1 Jul 2008 20:22:41 +0000 (GMT)
Received: from drow by caradoc.them.org with local (Exim 4.69)
	(envelope-from <drow@caradoc.them.org>)
	id 1KDmN5-0006pV-UM; Tue, 01 Jul 2008 16:22:40 -0400
Date:	Tue, 1 Jul 2008 16:22:37 -0400
From:	Daniel Jacobowitz <dan@debian.org>
To:	binutils@sourceware.org, gcc@gcc.gnu.org,
	linux-mips@linux-mips.org, rdsandiford@googlemail.com
Subject: Re: RFC: Adding non-PIC executable support to MIPS
Message-ID: <20080701202236.GA1534@caradoc.them.org>
Mail-Followup-To: binutils@sourceware.org, gcc@gcc.gnu.org,
	linux-mips@linux-mips.org, rdsandiford@googlemail.com
References: <87y74pxwyl.fsf@firetop.home>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="vtzGhvizbBRQ85DL"
Content-Disposition: inline
In-Reply-To: <87y74pxwyl.fsf@firetop.home>
User-Agent: Mutt/1.5.17 (2008-05-11)
Return-Path: <drow@false.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 19683
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: dan@debian.org
Precedence: bulk
X-list: linux-mips
Content-Length: 200044
Lines: 5591


--vtzGhvizbBRQ85DL
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Sat, Jun 28, 2008 at 06:58:58PM +0100, Richard Sandiford wrote:
> used on GNU/Linux.  At the same time, CodeSourcery implemented it for
> Sourcery G++.  I only found out about CS's version recently, after
> finishing the Specifix one, and I think the same is true in reverse.
> Oh well!

Yes, that's right - first I heard about this was last week :-(

> I suppose the good news is that we can pick the best bits of each
> implementation as the official one.  I'll describe my implementation
> below, then compare it to what I understand CS's version to be.
> CS folks: please correct me if I'm wrong.  Dan said that he'd be
> submitting CS's version too.

Indeed, and here it is.  I have attached patches for gcc, binutils,
gdb, glibc (EGLIBC trunk but likely to apply fine to FSF GLIBC also),
and glibc-ports (ditto).  There's also a build fix for EGLIBC after
Richard's recent change to the "h" constraint (similar to the one in
Richard's eglibc quilt).  I have also included the ABI writeup we
used.  Changelogs are missing for the binutils/gcc patches.

The patches were written by Mark Shinwell, Catherine Moore, and
myself.  The ABI document was originally written by Nigel Stephens of
MIPS Technologies, Inc., who sponsored this project; I've updated it
as we went along.  Richard, Nigel, and I discussed a version of this
document in 2007; it has changed slightly.  I've had to do some
last minute updates to it today to match the implementation,
so I sincerely hope I got them right.

Most descripions of Richard's implementation also apply to ours.
It is compatible with both existing ET_REL objects and existing
ET_EXEC/ET_DYN modules.  Old binaries continue to work with a
patched C library, existing static libraries can still be used by the
new linker, et cetera.

> Comparison with the CS implementation
> -------------------------------------

Some similarities first: R_MIPS_COPY / R_MIPS_JUMP_SLOT, STO_MIPS_PLT,
EF_MIPS_CPIC, use of .option pic0, the need for linker errors on
non-PIC, the grotty glibc hack to make it check STO_MIPS_PLT
(Richard's duplicates more code, but is considerably less grotty; had
we realized we'd be stuck with a copy of dl-lookup.c I would likely
not have written the awful preprocessor trick you'll see in the
ports patch).

> I think the main differences with CS's implemention are:
> 
> - CS treat .got.plt is part of .got.  See above for why I think it
>   should be separate.  Note that the PLT header is the same size for
>   both implementations, so the extra parameters don't cost much.

No, we don't - they're on opposite sides of .data.  We reserve two
words at the start of the PLT GOT in addition to the two at the
beginning of the GOT.  The PLT header loads the start of .got.plt
and passes that to _dl_runtime_pltresolve in $gp.  The return
address is passed in $t9 and the index in $t8.

> - CS PLT entries pass a PLT index rather than a .got.plt address.
>   This makes no difference for most objects, but a longer stub
>   is needed if there are more than 0x10000 PLT entries.

Yes, this was chosen in order to support MIPS I while still fitting
the PLT entries on a single cache line.

> - I couldn't see any specific support for ld -r in the CS version.

That's right, we do not support this.  I've no complaint about gaining
support :-)  Given the requirement, STO_MIPS_PIC seems sensible.

> - The CS version always uses separate "la $25" trampolines,
>   rather than adding instructions to the beginning of a function.
>   This is an implementation rather than an ABI detail though.

Right.

> - CS support MIPS I, at the cost of using the start of the next
>   PLT entry as a delay slot instruction.

FWIW it also adds one instruction to the header; that's why the delay
slot of the branch is empty.

> - STO_MIPS_PLT is separate from STO_MIPS16.

Right.

> This comparison is based on 4.2-129 and I've probably got it wrong.
> 
> I'm not sure if CS's version supports n32 and n64, but adding
> it wouldn't be a big issue.

Right - it's not there, but we figured we'd add it at some
not-too-future date.

Also:

  - We reserve two words at the start of the PLT GOT rather than
  pass another argument to the resolver.  One of them points to
  the PLT resolver, and the other to the link map (from which
  the dynamic linker can look up whatever it needs).

  - One of the new dynamic tags, DT_MIPS_PLTGOT, exists solely to
  let the dynamic linker fill in those two reserved entries.  So
  this tag is required.

  - The other dynamic tag, DT_MIPS_RWPLT, is for a specified but
  unimplmented optimization a la PowerPC-32 - rewriting resolved
  PLT entries to a direct jump.

OK, that's the ABI comparison.  These are what I'm concerned about for
integrating the two versions; all implementation differences I know we
can decide case-by-case.  And because both Richard's and our versions
apply this behavior by default based on a configure option, I'm not
concerned with the command line options or spelling of configure
options either.

We've shipped our version.  Richard's version has presumably also
shipped.  We did negotiate the ABI changes with MTI; this is not quite
as good as doing it in full view, but it was the best we could manage
and MTI is as close to a central authority for the MIPS psABI as
exists today.

Richard, what are your thoughts on reconciling the differences?  You
can surely guess that I want to avoid changing our ABI now, even for
relatively significant technical reasons - I'm all ears if there's a
major reason, but in the comparisons I do not see one.

If necessary, one of us can end up with a compatibility layer at
runtime thanks to DT_MIPS_RWPLT :-(

Comments welcome from all.

-- 
Daniel Jacobowitz
CodeSourcery

--vtzGhvizbBRQ85DL
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="nonpic.txt"

====
MIPS non-PIC ABI specification
====

Introduction
----

This document describes the specification of the new MIPS ABI to provide
absolute (non-PIC) addressing as used for Linux applications on most
architectures.  MIPS currently uses the existing psABI that mandates
compilation of applications as position-independent code.

The intention is that this extension to the ABI will be a strict
superset of the existing MIPS o32 psABI for non-PIC executables, and will
not break compatibility with legacy PIC object files, allowing
interlinking of new-model and legacy object files both statically and
dynamically (apart from ld.so, of course).

This document does not cover n32 and n64 ABIs; they are expected to be
a straightforward extension of the same design.

At this time we do not propose any change to the position-independent
addressing conventions used by shared objects. Similarly,
position-independent executables compiled with '-fpie' -- as required
for address space randomisation in "hardened" Linux distributions --
shall continue to use the existing psABI addressing and calling
mechanisms.

Identification of Object Files
----

Object files which use this new ABI extension will need to be
identifiable. They will have EF_MIPS_CPIC set and EF_MIPS_PIC
clear in the ELF header's e_flags field. The dynamic linker can
identify new-model executables which use the PLT mechanism by the
existence of DT_JMPREL tag in the dynamic table. It is also suggested
that the EI_ABIVERSION entry in the ELF header ident be incremented
from 0 to 1 for such executables, so that existing dynamic linkers
will refuse to link them, and display a "helpful" error message rather
than linking them incorrectly and having the application crash.

[Ed. note: this does not actually work with glibc's ld.so for
executables; it does not check the ABI version of the executable, or
checks it too late.]

Procedure Linkage Table
----

The Procedure Linkage Table (PLT) consists of a set of stubs generated
by the static linker to stand in for external functions that are in a
shared object. They can be called using an absolute JAL instuction and
then redirect the call from the executable to the actual function via
a pointer in the PLT GOT (the .got.plt section which holds 32-bit
function pointers only).

The PLT is output to the .plt section, which section should be aligned
to a 32 byte boundary so that all PLT entries occupy no more than one
cache line.

The PLT GOT holds function addresses used by the PLT stubs, and the
PLT GOT entries shall be initialised by the static linker to point to
the PLT header (i.e. the base of the .plt section).  In this way the
first call to an external function will invoke the dynamic linker to
resolve the symbol and update the corresponding PLT GOT entry; the
next call will then jump from the PLT straight to the function,
avoiding the dynamic linker.

In the existing version of the ABI, as implemented by glibc,
the first two GOT entries are reserved:

  GOT[0]
	Pointer to dynamic linker's GOT resolver which takes a dynamic
	symbol index argument.

  GOT[1]
	Pointer to this object's link map

In this ABI, the GOT layout will remain the same.  The first two entries
in the PLT GOT will be reserved as follows:

  PLTGOT[0]
	Pointer to dynamic linker's PLT resolver (which takes a PLT
	index argument instead of the dynamic symbol index used by the
	GOT resolver).

  PLTGOT[1]
	Pointer to this object's link map.

Since PLT entries use absolute addresses to access the PLT GOT, the
PLT GOT does not need to be located within 32K of the _gp symbol.
Indeed it would be better to prevent the PLT GOT from occupying this
scarce resource in the address map.  There is no requirement for the
PLT GOT and GOT to be consecutive.

For each PLT entry a R_MIPS_JUMP_SLOT relocation entry shall be output
to the dynamic .rel.plt section: the relocation entry's dynamic symbol
index specifies the symbol to which the PLT entry refers, and the
offset field holds the address of the PLT entry. An addend is never
required (so we remain with REL relocs).  The PLT index passed
by the PLT to the dynamic linker is both an index into the array of
jump slot relocations, and can be transformed into
an index into the PLT GOT by adding two (corresponding to the
reserved PLT resolver and link map slots at PLTGOT[0] and
PLTGOT[1]).  Dynamic
symbol table entries referenced only by jump slot or copy relocations
shall precede the "GOT mapped" symbols whose first index is specified
by the DT_MIPS_GOTSYM dynamic table entry.

PLT Header
----

The first entry in the PLT handles the first call to a PLT only, and
is 32 bytes in size::

  PLT0:	lui	gp, %hi(.got.plt)		# linker needs address of 
  	addiu	gp, %lo(.got.plt)		#  .got.plt to find link map
  	lw	t9, 0(gp)			# PLTGOT[0] == &_dl_runtime_pltresolve()
  	move	t7,ra				# linker needs caller's address
  	jalr	t9				# call _dl_runtime_pltresolve()
  	nop					# bdslot
   	nop					# spare
  	nop					# spare

PLT Type A
''''

If the maximum PLT index is less than or equal to 65535, then a
minimum length PLT of 16 bytes can be generated::

  PLT1:	lui	t7, %hi(%pltgot(name1))	# high PLT GOT pointer
  	lw	t9, %lo(%pltgot(name1))(t7)	# load func pointer from PLT GOT
  	ori	t8, $0, index1			# load plt index (ldslot)
  	jr	t9				# jump to func
  PLT2:	lui	t7, %hi(%pltgot(name2)		# (bdslot)
  	lw	t9, %lo(%pltgot(name2))(t7)
  	ori	t8, $0, index2
  	jr	t9
  PLT3:	...
  PLTn:	nop; nop; nop; nop

(Note that this is effectively pseudocode; the assembler does not need
modifying to understand "%pltgot(...)" since these instructions will
be directly written out by the linker.)

PLT Type B
''''

When the maximum PLT index is greater than 65535, a large PLT is
required, rounded up to 32 bytes in length::

  PLT1:	lui	t7, %hi(%pltgot(name1))		# high PLT GOT pointer
  	lw	t9, %lo(%pltgot(name1))(t7)	# load func pointer from PLT GOT
  	lui	t8, index1>>16			# load hi plt index (ldslot)
  	jr	t9				# jump to func
  	ori	 t8, t8, index1&0xffff		# load lo plt index (bdslot)
  	nop
  	nop
  	nop

Writable PLT Fixup
----

PLT Type C
''''

After resolving the symbol and updating the PLT GOT, then if the PLT
is in a writable section, the dynamic linker shall patch the PLT to use
the absolute address of the function, thereby avoiding the PLT GOT
reference, as follows. The dynamic linker can detect a writable PLT by
the existence of a non-null DT_MIPS_RWPLT entry in the dynamic table::

  PLT1:	lui	t9, %hi(name1)
  	addiu	t9, %lo(name1)
  	jr	t9
  	nop

PLT Type D
''''

Furthermore if the address at which the function is loaded lies within
the same 256MB segment as the PLT entry, then it can avoid the
indirect jump also::

  PLT1:	lui	t9, %hi(name1)
  	j	name1
  	addiu	t9, %lo(name1)
  	nop

Note that the base MIPS32 and MIPS64 MMU does not provide a
"no-execute" bit, and therefore cannot support the "least privilege"
page protection model required by "Hardened" Linux features such as
Exec Shield and PAX. [Actually the SmartMIPS ASE specifies the
execute-inhibit (XI) bit, but that's only available in the 4KSd core.]
However the static linker should be capable of generating a
non-writable (secure) PLT and GOT to conform with SELinux
restrictions, and on a SmartMIPS core this could be used to prevent
writable data areas from becoming executable. This would be at the
cost of some loss of performance for external function calls.

Function addresses
----

To allow comparison of function addresses to work as expected, it is
necessary for the executable and all shared objects to see the same
function address. If the executable takes the address of an external
function it will generate a PLT entry for that function, and that PLT
entry must then be the canonical address for the function throughout
the program.

Taking the address of an external function in a non-PIC executable
will result in a symbol table entry with type STT_FUNC and section
index of SHN_UNDEF, but with a non-zero st_value field that holds the
address of the function's PLT entry; furthermore the new STO_MIPS_PLT
bit shall be set in the symbol's st_other field. If the function's
address is not referenced (i.e. the function is only ever called by
the executable), then the symbol's st_value field will be zero and the
STO_MIPS_PLT bit clear.

The dynamic linker will use an undefined function symbol table entry
with STO_MIPS_PLT set to resolve all references to that symbol in
preference to the actual definition of that symbol, except when
resolving an R_MIPS_JUMP_SLOT relocation.

Note that this is the opposite behaviour to the legacy MIPS psABI
where an undefined function symbol table entry with a zero st_value
field indicates that there is an address reference to the function and
the dynamic linker must resolve the symbol immediately upon loading;
and where undefined function entries are always ignored when searching
for a symbol definition.

Dynamic Section
----

Dynamic section entries give information to the dynamic linker. Some
of the information is processor-specific, including the interpretation
of some entries in the dynamic structure. The following new or changed
dynamic table entries are required by the extended ABI:

  DT_JMPREL (23)
	Previously unused for MIPS, now points to the first jump-slot
	relocation in the dynamic relocation table (i.e. the base of
	.rel.plt).

  DT_PLTREL (20)
	Previously unused for MIPS, now with a value of DT_REL indicating
	that DT_JMPREL points to REL relocations.

  DT_PLTRELSZ (2)
	Previously unused for MIPS, now holding the size of .rel.plt in
	bytes.

  DT_MIPS_PLTGOT (0x70000032)
	(New) Points to the base of the PLT GOT (.got.plt section),
	since it may not be contiguous with the traditional GOT (.got
	section). The standard DT_PLTGOT entry points to the base of
	the GOT.

  DT_MIPS_RWPLT (0x70000034)
	(New) Points to the base of the PLT when the PLT is writable;
	for a non-writable PLT it is omitted or has a zero value.

The dynamic symbol table may have undefined function entries with the
following bit set in the st_other field:

  STO_MIPS_PLT (0x8)
	 (New) Symbol value is the address of a PLT entry.

The dynamic relocation table may now contain two new relocation types
generated by the static linker:

  R_MIPS_COPY (126)
	 A data copy relocation.

  R_MIPS_JUMP_SLOT (127)
	 A PLT relocation.

External Data
----

If a non-PIC executable contains a reference to a data symbol in a
shared object, then the static linker shall allocate space for that
symbol in the executable's writable .dynbss (or .dynsbss) section, and
output an R_MIPS_COPY relocation entry to the dynamic relocation
section.  The offset field of the relocation entry gives the address
of the data in the .dynbss section. During execution the dynamic
linker will copy any initial data associated with the shared object's
symbol to the location specified by the offset, and point all GOT
entries that refer to that symbol to the executable's copy.

Large Code Size
----

The 26-bit offset of a MIPS absolute JAL and J instruction would limit
the executable's code (including the PLT) to fit in a single 256MB
address segment. That's sufficient for most embedded applications, but
could be exceeded by some larger "server" applications. This may be
handled by explicitly compiling large applications with '-mlongcalls'.

A more elegant solution would be for the linker to automatically
insert trampolines when a call site and the function (or its PLT) are
not within the same 256MB segment, similar to the mechanism used for
the PPC32 architecture.  This may be implemented at a later date and
has no ABI implications.

Small Data
----

An optimisation available to statically-linked "bare iron"
applications is to place data with size no greater than some threshold
(default 8 bytes) in a small data section, where it can be referenced
using short offsets from the $gp register. In Dhrystone the lack of
small data addressing accounts for approximately one eighth of the 30%
performance differential between bare-iron and Linux.

Enabling small data addressing for non-PIC executables will enable
some but not all of this performance to be regained, particularly in
functions which reference many small global variables. Because shared
libraries use the $gp register to hold their GOT pointer, the register
will not be constant throughout the application, so the compiler must
reload the small data pointer whenever required by a function. Note
that "small" external data must be allocated in the executable's
.dynsbss section, instead of the .dynbss section.

Since this is a local optimisation the compiler may use an arbitrary
register to hold the small data pointer: it could be any call-clobbered
register, or a call-saved register if its use crosses a function
call. 

The compiler might choose not to use a small data pointer register if
it can determine that there is only one reference to small data in a
function, in which case it will be faster to use an absolute
address. 

For non-PIC executables the compiler may now consider $gp to be a
call-clobbered register that it is free to allocate for any purpose.

Legacy psABI support
----

While new-model code will use the PLT to reference external functions,
any legacy PIC code with which it is statically linked should continue
to use the linker-generated call stubs in the .MIPS.stubs section,
rather than referencing the new-model PLT. This is to avoid the
penalty of a double indirection when calling the function:
i.e. calling indirectly via the GOT to the PLT, and then the PLT
calling the actual function via the PLT GOT.

The exception to this is if the non-PIC code references the same
function, in which case the PIC code must generate a local GOT entry
which points to the associated PLT entry. [A possible optimisation, if
we are willing to have both a PLT GOT and GOT entry referencing the
same function, is to only point the GOT to the PLT only if there are
relocations other than R_MIPS_26, R_MIPS_CALL16 or R_MIPS_GOT16
referencing the function, and otherwise use a global GOT entry
pointing directly to the function.]

Similarly for access to external data, if the non-PIC code generates
an R_MIPS_COPY relocation for a symbol, then PIC code referencing the
same symbol must allocate a local GOT entry pointing to the
executable's copy of the data in .dynbss or .dynsbss. Otherwise a
global GOT entry shall be allocated to point to the symbol.

Finally, if the non-PIC executable references a function in the
statically-linked PIC code, then it will be necessary for the linker
to allocate a call stub which first loads the $t9 register with the
function's address, for use by non-PIC caller.  The call stub would
look like PLT style C or D above, and could be allocated in the PLT or
.MIPS.stubs section, or any other part of the text section. If the
function is globally binding, and is referenced by a non-PIC, non-call
relocation, then its symbol table entry must point to the call stub,
so that the stub is the canonical address of the function.

--vtzGhvizbBRQ85DL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="gcc-nonpic.diff"

Index: gcc/configure
===================================================================
--- gcc/configure	(revision 137143)
+++ gcc/configure	(working copy)
@@ -1048,6 +1048,7 @@ Optional Features:
                           arrange to use setjmp/longjmp exception handling
   --enable-secureplt      enable -msecure-plt by default for PowerPC
   --enable-cld            enable -mcld by default for 32bit x86
+  --enable-mips-nonpic    enable non-PIC ABI by default for MIPS GNU/Linux o32
   --disable-win32-registry
                           disable lookup of installation paths in the
                           Registry on Windows hosts
@@ -13779,6 +13780,12 @@ else
   enable_cld=no
 fi;
 
+# Check whether --enable-mips-nonpic or --disable-mips-nonpic was given.
+if test "${enable_mips_nonpic+set}" = set; then
+  enableval="$enable_mips_nonpic"
+
+fi;
+
 # Windows32 Registry support for specifying GCC installation paths.
 # Check whether --enable-win32-registry or --disable-win32-registry was given.
 if test "${enable_win32_registry+set}" = set; then
Index: gcc/testsuite/gcc.target/mips/lazy-binding-1.c
===================================================================
--- gcc/testsuite/gcc.target/mips/lazy-binding-1.c	(revision 137143)
+++ gcc/testsuite/gcc.target/mips/lazy-binding-1.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile { target nomips16 } } */
-/* { dg-mips-options "-mabicalls -mshared -mexplicit-relocs -O2 -fno-delayed-branch" } */
+/* { dg-mips-options "-mabicalls -mshared -fpic -mexplicit-relocs -O2 -fno-delayed-branch" } */
 
 void bar (void);
 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-addr.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-addr.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-addr.c	(revision 0)
@@ -0,0 +1,9 @@
+extern void nonpic_nothing (void);
+extern int hit_nonpic_addr;
+void
+nonpic_addr ()
+{
+  nonpic_receive_fn_addr (&nonpic_nothing);
+  hit_nonpic_addr++;
+  return;
+}
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-call.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-call.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-call.c	(revision 0)
@@ -0,0 +1,10 @@
+extern void pic_nothing (void);
+extern void pic_addr (void);
+extern int hit_nonpic_call;
+void
+nonpic_call ()
+{
+ pic_nothing ();
+ pic_addr ();
+ hit_nonpic_call++;
+}
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/pic-receive-fn-addr.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/pic-receive-fn-addr.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/pic-receive-fn-addr.c	(revision 0)
@@ -0,0 +1,9 @@
+extern void pic_nothing (void);
+extern void abort (void);
+void
+pic_receive_fn_addr (void *x)
+{
+  if (x != &pic_nothing)
+    abort ();
+  return;
+}
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-10.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-10.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-10.c	(revision 0)
@@ -0,0 +1,25 @@
+/* { dg-options "nonpic-call.o pic-addr.o pic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+extern void nonpic_call ();
+extern void pic_addr();
+int hit_nonpic_call = 0;
+int hit_pic_addr = 0;
+int hit_pic_nothing = 0;
+int hit_nonpic_nothing = 0;
+extern void exit (int);
+extern void abort (void);
+
+main ()
+{
+  nonpic_call ();
+  pic_addr ();
+
+  if (hit_nonpic_call != 1)
+    abort ();
+
+  if (hit_pic_addr != 2)
+    abort ();
+
+  exit (0);
+
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-11.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-11.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-11.c	(revision 0)
@@ -0,0 +1,23 @@
+/* { dg-options "nonpic-addr.o pic-addr.o nonpic-receive-fn-addr.o pic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+extern void nonpic_addr ();
+extern void pic_addr();
+extern void exit (int);
+extern void abort (void);
+int hit_nonpic_addr = 0;
+int hit_pic_addr = 0;
+int hit_pic_nothing = 0;
+int hit_nonpic_nothing = 0;
+main ()
+{
+  nonpic_addr ();
+  pic_addr ();
+
+  if (hit_nonpic_addr != 1)
+    abort ();
+
+  if (hit_pic_addr != 1)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-12.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-12.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-12.c	(revision 0)
@@ -0,0 +1,23 @@
+/* { dg-options "nonpic-addr-call.o pic-addr.o pic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+int hit_nonpic_addr_call = 0;
+int hit_pic_addr = 0;
+int hit_nonpic_nothing = 0;
+int hit_pic_nothing = 0;
+extern void nonpic_addr_call ();
+extern void pic_addr();
+extern void abort (void);
+extern void exit (int);
+main ()
+{
+  nonpic_addr_call ();
+  pic_addr ();
+
+  if (hit_nonpic_addr_call != 1)
+    abort ();
+
+  if (hit_pic_addr != 1)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/mips-nonpic.exp
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/mips-nonpic.exp	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/mips-nonpic.exp	(revision 0)
@@ -0,0 +1,45 @@
+#   Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Exit immediately if this isn't a MIPS target.
+if ![istarget mips*-*-*] {
+  return
+}
+
+load_lib gcc-dg.exp
+
+dg-init
+
+set old-dg-do-what-default "${dg-do-what-default}"
+set dg-do-what-default "assemble"
+
+foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/pic-*.c]] {
+    verbose "Compiling [file tail [file dirname $testcase]]/[file tail $testcase]"
+    dg-test -keep-output $testcase "-fpic" ""
+}
+
+foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/nonpic-\[a-z\]*.c]] {
+    verbose "Compiling [file tail [file dirname $testcase]]/[file tail $testcase]"
+    dg-test -keep-output $testcase "-fno-pic" ""
+}
+
+set dg-do-what-default "run"
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/nonpic-\[0-9\]*.c]] "-fno-pic" ""
+
+set dg-do-what-default "${old-dg-do-what-default}"
+dg-finish
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-addr-call.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-addr-call.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-addr-call.c	(revision 0)
@@ -0,0 +1,10 @@
+extern int hit_nonpic_addr_call;
+extern void pic_nothing (void);
+extern void pic_receive_fn_addr (void *);
+void
+nonpic_addr_call (void)
+{
+  hit_nonpic_addr_call++;
+  pic_receive_fn_addr (&pic_nothing);
+  return;
+}
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-13.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-13.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-13.c	(revision 0)
@@ -0,0 +1,21 @@
+/* { dg-options "pic-addr-call.o nonpic-receive-fn-addr.o nonpic-nothing.o" } */
+
+int hit_pic_addr_call = 0;
+int hit_nonpic_nothing = 0;
+extern void nonpic_nothing ();
+extern void pic_addr_call();
+extern void exit (int);
+extern void abort (void);
+main ()
+{
+  nonpic_nothing ();
+  pic_addr_call ();
+
+  if (hit_nonpic_nothing != 1)
+    abort ();
+
+  if (hit_pic_addr_call != 1)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-14.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-14.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-14.c	(revision 0)
@@ -0,0 +1,24 @@
+/* { dg-options "nonpic-call.o pic-addr.o pic-receive-fn-addr.o pic-addr-call.o nonpic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+int hit_pic_addr_call = 0;
+int hit_nonpic_call = 0;
+int hit_pic_addr = 0;
+int hit_nonpic_nothing = 0;
+int hit_pic_nothing = 0;
+extern void nonpic_call ();
+extern void pic_addr_call();
+extern void abort (void);
+extern void exit (int);
+main ()
+{
+  nonpic_call ();
+  pic_addr_call ();
+
+  if (hit_nonpic_call != 1)
+    abort ();
+
+  if (hit_pic_addr_call != 1)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-15.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-15.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-15.c	(revision 0)
@@ -0,0 +1,23 @@
+/* { dg-options "nonpic-addr.o pic-receive-fn-addr.o pic-addr-call.o nonpic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+int hit_pic_addr_call = 0;
+int hit_nonpic_addr = 0;
+int hit_nonpic_nothing = 0;
+int hit_pic_nothing = 0;
+extern void nonpic_addr ();
+extern void pic_addr_call();
+extern void abort (void);
+extern void exit (int);
+main ()
+{
+  nonpic_addr ();
+  pic_addr_call ();
+
+  if (hit_nonpic_addr != 1)
+    abort ();
+
+  if (hit_pic_addr_call != 1)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-16.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-16.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-16.c	(revision 0)
@@ -0,0 +1,21 @@
+/* { dg-options "nonpic-addr-call.o pic-receive-fn-addr.o pic-addr-call.o nonpic-receive-fn-addr.o pic-nothing.o nonpic-nothing.o" } */
+
+extern void abort (void);
+extern void exit (int);
+extern void nonpic_addr_call ();
+extern void pic_addr_call();
+int hit_nonpic_addr_call = 0;
+int hit_pic_addr_call = 0;
+int hit_nonpic_nothing = 0;
+int hit_pic_nothing = 0;
+main ()
+{
+  nonpic_addr_call ();
+  pic_addr_call ();
+
+  if (hit_nonpic_addr_call != 1)
+    abort ();
+  if (hit_pic_addr_call != 1)
+    abort ();
+  exit (0);
+}
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-receive-fn-addr.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-receive-fn-addr.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-receive-fn-addr.c	(revision 0)
@@ -0,0 +1,8 @@
+extern void nonpic_nothing (void);
+extern void abort (void);
+void
+nonpic_receive_fn_addr (void *x)
+{
+  if (x != &nonpic_nothing)
+    abort ();
+}
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/pic-nothing.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/pic-nothing.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/pic-nothing.c	(revision 0)
@@ -0,0 +1,7 @@
+extern int hit_pic_nothing;
+void
+pic_nothing ()
+{
+  hit_pic_nothing++;
+  return;
+}
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/pic-addr.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/pic-addr.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/pic-addr.c	(revision 0)
@@ -0,0 +1,9 @@
+extern int hit_pic_addr;
+extern void pic_nothing (void);
+void
+pic_addr ()
+{
+  pic_receive_fn_addr (&pic_nothing);
+  hit_pic_addr++;
+  return;
+}
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/pic-call.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/pic-call.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/pic-call.c	(revision 0)
@@ -0,0 +1,10 @@
+extern int hit_pic_call;
+extern void nonpic_nothing (void);
+extern void nonpic_addr (void);
+void
+pic_call ()
+{
+ nonpic_nothing ();
+ nonpic_addr ();
+ hit_pic_call++;
+}
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-1.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-1.c	(revision 0)
@@ -0,0 +1,21 @@
+/* { dg-options "pic-nothing.o nonpic-nothing.o" } */
+
+extern void nonpic_nothing ();
+extern void pic_nothing ();
+int hit_pic_nothing = 0;
+int hit_nonpic_nothing = 0;
+extern void exit (int);
+extern void abort (void);
+main ()
+{
+  nonpic_nothing ();
+  pic_nothing ();
+
+  if (hit_nonpic_nothing != 1)
+    abort ();
+
+  if (hit_pic_nothing != 1)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-2.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-2.c	(revision 0)
@@ -0,0 +1,23 @@
+/* { dg-options "pic-addr.o nonpic-call.o pic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+extern void nonpic_call ();
+extern void pic_nothing ();
+extern void abort (void);
+extern void exit (int);
+int hit_nonpic_call = 0;
+int hit_pic_nothing = 0;
+int hit_pic_addr = 0;
+int hit_nonpic_nothing = 0;
+main ()
+{
+  nonpic_call ();
+  pic_nothing ();
+
+  if (hit_nonpic_call != 1)
+    abort ();
+
+  if (hit_pic_nothing != 2)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-3.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-3.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-3.c	(revision 0)
@@ -0,0 +1,22 @@
+/* { dg-options "nonpic-addr.o nonpic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+extern void nonpic_addr ();
+extern void pic_nothing ();
+extern void abort (void);
+extern void exit (int);
+int hit_nonpic_addr = 0;
+int hit_pic_nothing = 0;
+int hit_nonpic_nothing = 0;
+main ()
+{
+  nonpic_addr ();
+  pic_nothing ();
+
+  if (hit_nonpic_addr != 1)
+    abort ();
+
+  if (hit_pic_nothing != 1)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-4.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-4.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-4.c	(revision 0)
@@ -0,0 +1,24 @@
+/* { dg-options "pic-addr.o pic-receive-fn-addr.o nonpic-addr-call.o nonpic-nothing.o pic-nothing.o" } */
+
+int hit_nonpic_addr_call = 0;
+int hit_pic_nothing = 0;
+int hit_nonpic_nothing = 0;
+int hit_pic_addr = 0;
+int hit_nonpic_addr = 0;
+extern void nonpic_addr_call ();
+extern void pic_nothing ();
+extern void exit (int);
+extern void abort (void);
+main ()
+{
+  nonpic_addr_call ();
+  pic_nothing ();
+
+  if (hit_nonpic_addr_call != 1)
+    abort ();
+
+  if (hit_pic_nothing != 1)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-5.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-5.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-5.c	(revision 0)
@@ -0,0 +1,24 @@
+/* { dg-options "pic-addr.o pic-call.o nonpic-addr.o pic-receive-fn-addr.o nonpic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+extern void nonpic_nothing ();
+extern void pic_call ();
+extern void exit (int);
+extern void abort (void);
+int hit_nonpic_nothing = 0;
+int hit_pic_call = 0;
+int hit_nonpic_addr = 0;
+int hit_pic_nothing = 0;
+int hit_pic_addr = 0;
+main ()
+{
+  nonpic_nothing ();
+  pic_call ();
+
+  if (hit_nonpic_nothing != 2)
+    abort ();
+
+  if (hit_pic_call != 1)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-6.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-6.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-6.c	(revision 0)
@@ -0,0 +1,26 @@
+/* { dg-options "pic-call.o nonpic-call.o nonpic-addr.o pic-addr.o nonpic-receive-fn-addr.o pic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+extern void nonpic_call ();
+extern void pic_call ();
+extern void exit (int);
+extern void abort (void);
+int hit_pic_call = 0;
+int hit_nonpic_call = 0;
+int hit_pic_nothing = 0;
+int hit_nonpic_nothing = 0;
+int hit_nonpic_addr = 0;
+int hit_pic_addr = 0;
+
+main ()
+{
+  pic_call ();
+  nonpic_call ();
+
+  if (hit_pic_call != 1)
+    abort ();
+
+  if (hit_nonpic_call != 1)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-7.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-7.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-7.c	(revision 0)
@@ -0,0 +1,23 @@
+/* { dg-options "pic-call.o nonpic-addr.o nonpic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+int hit_pic_call = 0;
+int hit_nonpic_addr = 0;
+int hit_nonpic_nothing = 0;
+int hit_pic_nothing = 0;
+extern void nonpic_addr ();
+extern void pic_call ();
+extern void exit (int);
+extern void abort (void);
+main ()
+{
+  pic_call ();
+  nonpic_addr ();
+
+  if (hit_pic_call != 1)
+    abort ();
+
+  if (hit_nonpic_addr != 2)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-nothing.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-nothing.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-nothing.c	(revision 0)
@@ -0,0 +1,7 @@
+extern int hit_nonpic_nothing;
+void
+nonpic_nothing ()
+{
+  hit_nonpic_nothing++;
+  return;
+}
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-8.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-8.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-8.c	(revision 0)
@@ -0,0 +1,24 @@
+/* { dg-options "pic-call.o nonpic-addr-call.o nonpic-addr.o nonpic-receive-fn-addr.o pic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+int hit_nonpic_addr_call = 0;
+int hit_pic_call = 0;
+int hit_pic_nothing = 0;
+int hit_nonpic_nothing = 0;
+int hit_nonpic_addr = 0;
+extern void exit (int);
+extern void abort (void);
+extern void nonpic_addr_call ();
+extern void pic_call ();
+main ()
+{
+  pic_call ();
+  nonpic_addr_call ();
+
+  if (hit_pic_call != 1)
+    abort ();
+
+  if (hit_nonpic_addr_call != 1)
+    abort ();
+
+  exit (0);
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-9.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-9.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/nonpic-9.c	(revision 0)
@@ -0,0 +1,15 @@
+/* { dg-options "pic-addr.o pic-receive-fn-addr.o nonpic-nothing.o pic-nothing.o" } */
+
+extern void nonpic_nothing ();
+extern void pic_addr();
+extern void exit (int);
+extern void abort (void);
+int hit_pic_addr = 0;
+int hit_nonpic_nothing = 0;
+int hit_pic_nothing = 0;
+int hit_pic_receive_fn_addr = 0;
+main ()
+{
+  pic_addr ();
+  nonpic_nothing ();
+} 
Index: gcc/testsuite/gcc.target/mips/mips-nonpic/pic-addr-call.c
===================================================================
--- gcc/testsuite/gcc.target/mips/mips-nonpic/pic-addr-call.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/mips-nonpic/pic-addr-call.c	(revision 0)
@@ -0,0 +1,10 @@
+extern int hit_pic_addr_call;
+extern void nonpic_nothing (void);
+extern void nonpic_receive_fn_addr (void *);
+void
+pic_addr_call (void)
+{
+  hit_pic_addr_call++;
+  nonpic_receive_fn_addr (&nonpic_nothing);
+  return;
+}
Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac	(revision 137143)
+++ gcc/configure.ac	(working copy)
@@ -1537,6 +1537,10 @@ AC_ARG_ENABLE(cld,
 [  --enable-cld            enable -mcld by default for 32bit x86], [],
 [enable_cld=no])
 
+AC_ARG_ENABLE(mips-nonpic,
+[  --enable-mips-nonpic    enable non-PIC ABI by default for MIPS GNU/Linux o32],
+[], [])
+
 # Windows32 Registry support for specifying GCC installation paths.
 AC_ARG_ENABLE(win32-registry,
 [  --disable-win32-registry
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 137143)
+++ gcc/config.gcc	(working copy)
@@ -1489,7 +1489,7 @@ mcore-*-pe*)
 mips-sgi-irix[56]*)
 	tm_file="elfos.h ${tm_file} mips/iris.h"
 	tmake_file="mips/t-iris mips/t-slibgcc-irix"
-	target_cpu_default="MASK_ABICALLS"
+	tm_defines="${tm_defines} TARGET_ABICALLS_DEFAULT=1"
 	case ${target} in
 	*-*-irix5*)
 		tm_file="${tm_file} mips/iris5.h"
@@ -1515,12 +1515,16 @@ mips-sgi-irix[56]*)
 	use_fixproto=yes
 	;;
 mips*-*-netbsd*)			# NetBSD/mips, either endian.
-	target_cpu_default="MASK_ABICALLS"
+	tm_defines="${tm_defines} TARGET_ABICALLS_DEFAULT=1"
 	tm_file="elfos.h ${tm_file} mips/elf.h netbsd.h netbsd-elf.h mips/netbsd.h"
 	;;
 mips64*-*-linux*)
 	tm_file="dbxelf.h elfos.h svr4.h linux.h ${tm_file} mips/linux.h mips/linux64.h"
 	tmake_file="${tmake_file} mips/t-linux64"
+	tm_defines="${tm_defines} TARGET_ABICALLS_DEFAULT=1"
+	if test x${enable_mips_nonpic}; then
+		tm_defines="${tm_defines} TARGET_ABICALLS_NONPIC=1"
+	fi
 	tm_defines="${tm_defines} MIPS_ABI_DEFAULT=ABI_N32"
 	case ${target} in
 		mips64el-st-linux-gnu)
@@ -1533,7 +1537,11 @@ mips64*-*-linux*)
 	test x$with_llsc != x || with_llsc=yes
 	;;
 mips*-*-linux*)				# Linux MIPS, either endian.
-        tm_file="dbxelf.h elfos.h svr4.h linux.h ${tm_file} mips/linux.h"
+	tm_file="dbxelf.h elfos.h svr4.h linux.h ${tm_file} mips/linux.h"
+	tm_defines="${tm_defines} TARGET_ABICALLS_DEFAULT=1"
+	if test x${enable_mips_nonpic}; then
+		tm_defines="${tm_defines} TARGET_ABICALLS_NONPIC=1"
+	fi
 	case ${target} in
         mipsisa32r2*)
 		tm_defines="${tm_defines} MIPS_ISA_DEFAULT=33"
@@ -1545,7 +1553,7 @@ mips*-*-linux*)				# Linux MIPS, either 
 	;;
 mips*-*-openbsd*)
 	tm_defines="${tm_defines} OBSD_HAS_DECLARE_FUNCTION_NAME OBSD_HAS_DECLARE_OBJECT OBSD_HAS_CORRECT_SPECS"
-	target_cpu_default="MASK_ABICALLS"
+	tm_defines="${tm_defines} TARGET_ABICALLS_DEFAULT=1"
 	tm_file="mips/mips.h openbsd.h mips/openbsd.h mips/sdb.h"
 	case ${target} in
 	mips*el-*-openbsd*)
Index: gcc/config/mips/linux.h
===================================================================
--- gcc/config/mips/linux.h	(revision 137143)
+++ gcc/config/mips/linux.h	(working copy)
@@ -37,10 +37,6 @@ along with GCC; see the file COPYING3.  
 #undef MD_EXEC_PREFIX
 #undef MD_STARTFILE_PREFIX
 
-/* If we don't set MASK_ABICALLS, we can't default to PIC.  */
-#undef TARGET_DEFAULT
-#define TARGET_DEFAULT MASK_ABICALLS
-
 #define TARGET_OS_CPP_BUILTINS()				\
   do {								\
     LINUX_TARGET_OS_CPP_BUILTINS();				\
@@ -79,7 +75,8 @@ along with GCC; see the file COPYING3.  
         %{static:-static}}}"
 
 #undef SUBTARGET_ASM_SPEC
-#define SUBTARGET_ASM_SPEC "%{mabi=64: -64} %{!mno-abicalls:-KPIC}"
+#define SUBTARGET_ASM_SPEC \
+ "%{mabi=64: -64} %{mabicalls:%{fpic|fPIC:-KPIC;:-mnon-pic-abicalls}}"
 
 /* The MIPS assembler has different syntax for .set. We set it to
    .dummy to trap any errors.  */
@@ -163,7 +160,8 @@ extern const char *host_detect_local_cpu
 # define MARCH_MTUNE_NATIVE_SPECS ""
 #endif
 
-#define BASE_DRIVER_SELF_SPECS \
+#define LINUX_DRIVER_SELF_SPECS \
   NO_SHARED_SPECS \
   MARCH_MTUNE_NATIVE_SPECS
-#define DRIVER_SELF_SPECS BASE_DRIVER_SELF_SPECS
+#undef SUBTARGET_SELF_SPECS
+#define SUBTARGET_SELF_SPECS LINUX_DRIVER_SELF_SPECS
Index: gcc/config/mips/elfoabi.h
===================================================================
--- gcc/config/mips/elfoabi.h	(revision 137143)
+++ gcc/config/mips/elfoabi.h	(working copy)
@@ -19,7 +19,8 @@ You should have received a copy of the G
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-#define DRIVER_SELF_SPECS						\
+#undef SUBTARGET_SELF_SPECS
+#define SUBTARGET_SELF_SPECS						\
   /* Make sure a -mips option is present.  This helps us to pick	\
      the right multilib, and also makes the later specs easier		\
      to write.  */							\
Index: gcc/config/mips/linux64.h
===================================================================
--- gcc/config/mips/linux64.h	(revision 137143)
+++ gcc/config/mips/linux64.h	(working copy)
@@ -20,9 +20,9 @@ along with GCC; see the file COPYING3.  
 
 /* Force the default endianness and ABI flags onto the command line
    in order to make the other specs easier to write.  */
-#undef DRIVER_SELF_SPECS
-#define DRIVER_SELF_SPECS \
-BASE_DRIVER_SELF_SPECS \
+#undef SUBTARGET_SELF_SPECS
+#define SUBTARGET_SELF_SPECS \
+LINUX_DRIVER_SELF_SPECS \
 " %{!EB:%{!EL:%(endian_spec)}}" \
 " %{!mabi=*: -mabi=n32}"
 
Index: gcc/config/mips/sde.h
===================================================================
--- gcc/config/mips/sde.h	(revision 137143)
+++ gcc/config/mips/sde.h	(working copy)
@@ -19,7 +19,8 @@ You should have received a copy of the G
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-#define DRIVER_SELF_SPECS						\
+#undef SUBTARGET_SELF_SPECS
+#define SUBTARGET_SELF_SPECS						\
   /* Make sure a -mips option is present.  This helps us to pick	\
      the right multilib, and also makes the later specs easier		\
      to write.  */							\
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 137143)
+++ gcc/config/mips/mips.md	(working copy)
@@ -4462,6 +4462,22 @@
   [(set (match_operand:P 0 "register_operand" "=d")
 	(const:P (unspec:P [(const_int 0)] UNSPEC_GP)))])
 
+;; Move the constant value of __gnu_local_gp (operand 1) into
+;; operand 0, for non-PIC abicalls code.  All uses of the result
+;; are explicit, so there's no need for unspec_volatile here.
+(define_insn_and_split "loadgp_nonpic_<mode>"
+  [(set (match_operand:P 0 "register_operand" "=d")
+	(const:P (unspec:P [(match_operand 1 "" "")] UNSPEC_LOADGP)))]
+  "TARGET_NONPIC_ABICALLS"
+  "#"
+  ""
+  [(const_int 0)]
+{
+  mips_emit_move (operands[0], operands[1]);
+  DONE;
+}
+  [(set_attr "length" "8")])
+
 ;; Insn to initialize $gp for n32/n64 abicalls.  Operand 0 is the offset
 ;; of _gp from the start of this function.  Operand 1 is the incoming
 ;; function address.
@@ -5827,11 +5843,12 @@
 
 ;; Restore the gp that we saved above.  Despite the earlier comment, it seems
 ;; that older code did recalculate the gp from $25.  Continue to jump through
-;; $25 for compatibility (we lose nothing by doing so).
+;; $25 for compatibility (we lose nothing by doing so).  Similarly restore
+;; $gp if we might be jumping to code which expects that.
 
 (define_expand "builtin_longjmp"
   [(use (match_operand 0 "register_operand"))]
-  "TARGET_USE_GOT"
+  "TARGET_USE_GOT || TARGET_ABICALLS"
 {
   /* The elements of the buffer are, in order:  */
   int W = GET_MODE_SIZE (Pmode);
Index: gcc/config/mips/iris6.h
===================================================================
--- gcc/config/mips/iris6.h	(revision 137143)
+++ gcc/config/mips/iris6.h	(working copy)
@@ -29,7 +29,8 @@ along with GCC; see the file COPYING3.  
 
 /* Force the default ABI onto the command line in order to make the specs
    easier to write.  Default to the mips2 ISA for the O32 ABI.  */
-#define DRIVER_SELF_SPECS \
+#undef SUBTARGET_SELF_SPECS
+#define SUBTARGET_SELF_SPECS \
   "%{!mabi=*: -mabi=n32}", \
   "%{mabi=32: %{!mips*: %{!march*: -mips2}}}"
 
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	(revision 137143)
+++ gcc/config/mips/mips.c	(working copy)
@@ -1415,7 +1415,7 @@ mips_classify_symbol (const_rtx x, enum 
       if (TARGET_MIPS16_SHORT_JUMP_TABLES)
 	return SYMBOL_PC_RELATIVE;
 
-      if (TARGET_ABICALLS && !TARGET_ABSOLUTE_ABICALLS)
+      if (TARGET_PIC_ABICALLS && !TARGET_ABSOLUTE_ABICALLS)
 	return SYMBOL_GOT_PAGE_OFST;
 
       return SYMBOL_ABSOLUTE;
@@ -1438,14 +1438,15 @@ mips_classify_symbol (const_rtx x, enum 
 	return SYMBOL_GP_RELATIVE;
     }
 
-  /* Do not use small-data accesses for weak symbols; they may end up
-     being zero.  */
+  /* Use a small-data access if appropriate; but do not use small-data
+     accesses for weak symbols; they may end up being zero.  */
   if (TARGET_GPOPT && SYMBOL_REF_SMALL_P (x) && !SYMBOL_REF_WEAK (x))
     return SYMBOL_GP_RELATIVE;
 
-  /* Don't use GOT accesses for locally-binding symbols when -mno-shared
-     is in effect.  */
-  if (TARGET_ABICALLS
+  /* Use GOT accesses for PIC abicalls, except for locally-binding
+     symbols when -mno-shared is in effect - in that case the symbol
+     address is constant.  */
+  if (TARGET_PIC_ABICALLS
       && !(TARGET_ABSOLUTE_ABICALLS && mips_symbol_binds_local_p (x)))
     {
       /* There are three cases to consider:
@@ -2243,6 +2244,21 @@ mips_emit_call_insn (rtx pattern, bool l
   return insn;
 }
 
+/* The __gnu_local_gp symbol.  */
+
+static GTY(()) rtx mips_gnu_local_gp_rtx;
+
+static rtx
+mips_gnu_local_gp (void)
+{
+  if (mips_gnu_local_gp_rtx == NULL)
+    {
+      mips_gnu_local_gp_rtx = gen_rtx_SYMBOL_REF (Pmode, "__gnu_local_gp");
+      SYMBOL_REF_FLAGS (mips_gnu_local_gp_rtx) |= SYMBOL_FLAG_LOCAL;
+    }
+  return mips_gnu_local_gp_rtx;
+}
+
 /* Return an instruction that copies $gp into register REG.  We want
    GCC to treat the register's value as constant, so that its value
    can be rematerialized on demand.  */
@@ -2255,9 +2271,22 @@ gen_load_const_gp (rtx reg)
 	  : gen_load_const_gp_di (reg));
 }
 
+/* Return an instruction that moves the constant value of
+   __gnu_local_gp into register REG.  */
+
+static rtx
+gen_loadgp_nonpic (rtx reg)
+{
+  return (Pmode == SImode
+	  ? gen_loadgp_nonpic_si (reg, mips_gnu_local_gp ())
+	  : gen_loadgp_nonpic_di (reg, mips_gnu_local_gp ()));
+}
+
 /* Return a pseudo register that contains the value of $gp throughout
    the current function.  Such registers are needed by MIPS16 functions,
-   for which $gp itself is not a valid base register or addition operand.  */
+   for which $gp itself is not a valid base register or addition operand.
+   Also hold the GP in a non-PIC abicalls function which refers to TLS
+   data - such functions do not require $28 or even a hard register.  */
 
 static rtx
 mips16_gp_pseudo_reg (void)
@@ -2273,7 +2302,10 @@ mips16_gp_pseudo_reg (void)
     {
       rtx insn, scan, after;
 
-      insn = gen_load_const_gp (cfun->machine->mips16_gp_pseudo_rtx);
+      if (TARGET_NONPIC_ABICALLS)
+	insn = gen_loadgp_nonpic (cfun->machine->mips16_gp_pseudo_rtx);
+      else
+	insn = gen_load_const_gp (cfun->machine->mips16_gp_pseudo_rtx);
 
       push_topmost_sequence ();
       /* We need to emit the initialization after the FUNCTION_BEG
@@ -2415,6 +2447,19 @@ mips_add_offset (rtx temp, rtx reg, HOST
   return plus_constant (reg, offset);
 }
 
+/* Return the RTX to use for explicit GOT accesses.  Uses a pseudo if
+   possible.  */
+
+static rtx
+mips_got_base (void)
+{
+  gcc_assert (can_create_pseudo_p ());
+  if (TARGET_NONPIC_ABICALLS)
+    return mips16_gp_pseudo_reg ();
+  else
+    return pic_offset_table_rtx;
+}
+
 /* The __tls_get_attr symbol.  */
 static GTY(()) rtx mips_tls_symbol;
 
@@ -2438,7 +2483,7 @@ mips_call_tls_get_addr (rtx sym, enum mi
   start_sequence ();
 
   emit_insn (gen_rtx_SET (Pmode, a0,
-			  gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, loc)));
+			  gen_rtx_LO_SUM (Pmode, mips_got_base (), loc)));
   insn = mips_expand_call (v0, mips_tls_symbol, const0_rtx, const0_rtx, false);
   RTL_CONST_CALL_P (insn) = 1;
   use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0);
@@ -2504,12 +2549,12 @@ mips_legitimize_tls_address (rtx loc)
       if (Pmode == DImode)
 	{
 	  emit_insn (gen_tls_get_tp_di (v1));
-	  emit_insn (gen_load_gotdi (tmp1, pic_offset_table_rtx, tmp2));
+	  emit_insn (gen_load_gotdi (tmp1, mips_got_base (), tmp2));
 	}
       else
 	{
 	  emit_insn (gen_tls_get_tp_si (v1));
-	  emit_insn (gen_load_gotsi (tmp1, pic_offset_table_rtx, tmp2));
+	  emit_insn (gen_load_gotsi (tmp1, mips_got_base (), tmp2));
 	}
       dest = gen_reg_rtx (Pmode);
       emit_insn (gen_add3_insn (dest, tmp1, v1));
@@ -6835,7 +6880,7 @@ mips_select_rtx_section (enum machine_mo
 
 /* Implement TARGET_ASM_FUNCTION_RODATA_SECTION.
 
-   The complication here is that, with the combination TARGET_ABICALLS
+   The complication here is that, with the combination TARGET_PIC_ABICALLS
    && !TARGET_GPWORD, jump tables will use absolute addresses, and should
    therefore not be included in the read-only part of a DSO.  Handle such
    cases by selecting a normal data section instead of a read-only one.
@@ -6844,7 +6889,7 @@ mips_select_rtx_section (enum machine_mo
 static section *
 mips_function_rodata_section (tree decl)
 {
-  if (!TARGET_ABICALLS || TARGET_GPWORD)
+  if (!TARGET_PIC_ABICALLS || TARGET_GPWORD)
     return default_function_rodata_section (decl);
 
   if (decl && DECL_SECTION_NAME (decl))
@@ -7344,6 +7389,8 @@ mips_file_start (void)
   /* If TARGET_ABICALLS, tell GAS to generate -KPIC code.  */
   if (TARGET_ABICALLS)
     fprintf (asm_out_file, "\t.abicalls\n");
+  if (TARGET_NONPIC_ABICALLS)
+    fprintf (asm_out_file, "\t.option\tpic0\n");
 
   if (flag_verbose_asm)
     fprintf (asm_out_file, "\n%s -G value = %d, Arch = %s, ISA = %d\n",
@@ -7937,7 +7984,7 @@ mips_save_reg_p (unsigned int regno)
 {
   /* We only need to save $gp if TARGET_CALL_SAVED_GP and only then
      if we have not chosen a call-clobbered substitute.  */
-  if (regno == GLOBAL_POINTER_REGNUM)
+  if (regno == GLOBAL_POINTER_REGNUM && fixed_regs[regno])
     return TARGET_CALL_SAVED_GP && cfun->machine->global_pointer == regno;
 
   /* Check call-saved registers.  */
@@ -8161,7 +8208,7 @@ mips_current_loadgp_style (void)
   if (TARGET_RTP_PIC)
     return LOADGP_RTP;
 
-  if (TARGET_ABSOLUTE_ABICALLS)
+  if (TARGET_ABSOLUTE_ABICALLS || !flag_pic)
     return LOADGP_ABSOLUTE;
 
   return TARGET_NEWABI ? LOADGP_NEWABI : LOADGP_OLDABI;
@@ -8276,7 +8323,7 @@ mips_restore_gp (void)
 {
   rtx base, address;
 
-  gcc_assert (TARGET_ABICALLS && TARGET_OLDABI);
+  gcc_assert (TARGET_PIC_ABICALLS && TARGET_OLDABI);
 
   base = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
   address = mips_add_offset (pic_offset_table_rtx, base,
@@ -8527,10 +8574,6 @@ mips_save_reg (rtx reg, rtx mem)
     }
 }
 
-/* The __gnu_local_gp symbol.  */
-
-static GTY(()) rtx mips_gnu_local_gp;
-
 /* If we're generating n32 or n64 abicalls, emit instructions
    to set up the global pointer.  */
 
@@ -8543,14 +8586,9 @@ mips_emit_loadgp (void)
   switch (mips_current_loadgp_style ())
     {
     case LOADGP_ABSOLUTE:
-      if (mips_gnu_local_gp == NULL)
-	{
-	  mips_gnu_local_gp = gen_rtx_SYMBOL_REF (Pmode, "__gnu_local_gp");
-	  SYMBOL_REF_FLAGS (mips_gnu_local_gp) |= SYMBOL_FLAG_LOCAL;
-	}
       emit_insn (Pmode == SImode
-		 ? gen_loadgp_absolute_si (pic_reg, mips_gnu_local_gp)
-		 : gen_loadgp_absolute_di (pic_reg, mips_gnu_local_gp));
+		 ? gen_loadgp_absolute_si (pic_reg, mips_gnu_local_gp ())
+		 : gen_loadgp_absolute_di (pic_reg, mips_gnu_local_gp ()));
       break;
 
     case LOADGP_NEWABI:
@@ -12702,6 +12740,10 @@ mips_override_options (void)
 
   /* End of code shared with GAS.  */
 
+  /* The non-PIC ABI may only be used in conjunction with the o32 ABI.  */
+  if (TARGET_NONPIC_ABICALLS && mips_abi != ABI_32)
+    sorry ("non-PIC abicalls may only be used with the o32 ABI");
+
   /* If no -mlong* option was given, infer it from the other options.  */
   if ((target_flags_explicit & MASK_LONG64) == 0)
     {
@@ -12750,24 +12792,14 @@ mips_override_options (void)
       target_flags &= ~MASK_ABICALLS;
     }
 
-  /* MIPS16 cannot generate PIC yet.  */
+  /* MIPS16 cannot generate PIC or abicalls yet.  */
   if (TARGET_MIPS16 && (flag_pic || TARGET_ABICALLS))
     {
-      sorry ("MIPS16 PIC");
+      sorry ("MIPS16 PIC and abicalls are not yet implemented");
       target_flags &= ~MASK_ABICALLS;
       flag_pic = flag_pie = flag_shlib = 0;
     }
 
-  if (TARGET_ABICALLS)
-    /* We need to set flag_pic for executables as well as DSOs
-       because we may reference symbols that are not defined in
-       the final executable.  (MIPS does not use things like
-       copy relocs, for example.)
-
-       Also, there is a body of code that uses __PIC__ to distinguish
-       between -mabicalls and -mno-abicalls code.  */
-    flag_pic = 1;
-
   /* -mvr4130-align is a "speed over size" optimization: it usually produces
      faster code, but at the expense of more nops.  Enable it at -O3 and
      above.  */
@@ -12781,6 +12813,7 @@ mips_override_options (void)
 
   /* If we have a nonzero small-data limit, check that the -mgpopt
      setting is consistent with the other target flags.  */
+
   if (mips_small_data_threshold > 0)
     {
       if (!TARGET_GPOPT)
@@ -13001,6 +13034,14 @@ mips_conditional_register_usage (void)
       for (regno = DSP_ACC_REG_FIRST; regno <= DSP_ACC_REG_LAST; regno += 2)
 	mips_swap_registers (regno);
     }
+  /* In non-PIC abicalls, $gp is completely ordinary; we can use a pseudo
+     for TLS GOT entries.  */
+  if (TARGET_NONPIC_ABICALLS)
+    {
+      call_used_regs[GLOBAL_POINTER_REGNUM] = TARGET_OLDABI;
+      call_really_used_regs[GLOBAL_POINTER_REGNUM] = TARGET_OLDABI;
+      fixed_regs[GLOBAL_POINTER_REGNUM] = 0;
+    }
 }
 
 /* Initialize vector TARGET to VALS.  */
Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h	(revision 137143)
+++ gcc/config/mips/mips.h	(working copy)
@@ -163,7 +163,7 @@ enum mips_code_readable_setting {
    accesses are so much shorter.  */
 
 #define TARGET_ABSOLUTE_ABICALLS	\
-  (TARGET_ABICALLS			\
+  (TARGET_PIC_ABICALLS			\
    && !TARGET_SHARED			\
    && TARGET_EXPLICIT_RELOCS		\
    && !ABI_HAS_64BIT_SYMBOLS)
@@ -182,11 +182,19 @@ enum mips_code_readable_setting {
 #define TARGET_SIBCALLS \
   (!TARGET_MIPS16 && (!TARGET_USE_GOT || TARGET_EXPLICIT_RELOCS))
 
-/* True if we need to use a global offset table to access some symbols.  */
-#define TARGET_USE_GOT (TARGET_ABICALLS || TARGET_RTP_PIC)
+/* True if using abicalls, and position-independent (even if
+   -mno-shared).  */
+#define TARGET_PIC_ABICALLS (TARGET_ABICALLS && flag_pic)
+
+/* True if using abicalls, but not ourselves PIC.  */
+#define TARGET_NONPIC_ABICALLS (TARGET_ABICALLS && !flag_pic)
+
+/* True if we need to use a global offset table to access some symbols.
+   Small data and TLS may use the GOT even without this.  */
+#define TARGET_USE_GOT (TARGET_PIC_ABICALLS || TARGET_RTP_PIC)
 
 /* True if TARGET_USE_GOT and if $gp is a call-clobbered register.  */
-#define TARGET_CALL_CLOBBERED_GP (TARGET_ABICALLS && TARGET_OLDABI)
+#define TARGET_CALL_CLOBBERED_GP (TARGET_PIC_ABICALLS && TARGET_OLDABI)
 
 /* True if TARGET_USE_GOT and if $gp is a call-saved register.  */
 #define TARGET_CALL_SAVED_GP (TARGET_USE_GOT && !TARGET_CALL_CLOBBERED_GP)
@@ -200,7 +208,8 @@ enum mips_code_readable_setting {
    Although GAS does understand .gpdword, the SGI linker mishandles
    the relocations GAS generates (R_MIPS_GPREL32 followed by R_MIPS_64).
    We therefore disable GP-relative switch tables for n64 on IRIX targets.  */
-#define TARGET_GPWORD (TARGET_ABICALLS && !(mips_abi == ABI_64 && TARGET_IRIX))
+#define TARGET_GPWORD \
+  (TARGET_PIC_ABICALLS && !(mips_abi == ABI_64 && TARGET_IRIX))
 
 /* Generate mips16 code */
 #define TARGET_MIPS16		((target_flags & MASK_MIPS16) != 0)
@@ -973,6 +982,47 @@ enum mips_code_readable_setting {
 #endif
 
 
+/* Some targets (most of those with dynamic linking, e.g. Irix,
+   GNU/Linux, BSD) default to -mabicalls.  They mostly default to PIC
+   also.  Force the appropriate -mabicalls setting into the command
+   line for the benefit of the -fno-pic spec just below.  */
+#ifdef TARGET_ABICALLS_DEFAULT
+#define ABICALLS_SPEC "%{!mno-abicalls:%{!mabicalls:-mabicalls}}"
+#else
+#define ABICALLS_SPEC "%{!mno-abicalls:%{!mabicalls:-mno-abicalls}}"
+#endif
+
+/* Make -mabicalls imply PIC unless the target supports non-PIC
+   abicalls.  Targets which do not support non-PIC abicalls must set
+   flag_pic for executables as well as DSOs
+   because we may reference symbols that are not defined in
+   the final executable - these targets do not have copy relocs.
+
+   All 64-bit targets are assumed to not support PIC abicalls.
+   CSL NOTE: It would be nice to remove this restriction before
+   contributing upstream; 64-bit support should be a small project.
+
+   Also, there is a body of code that uses __PIC__ to distinguish
+   between -mabicalls and -mno-abicalls code.  For targets with
+   non-PIC abicalls support any such code will have to be corrected.
+   All you need to do if !__PIC__ is use $t9 for indirect calls
+   and be careful about assuming $gp is set up in inline asm.  */
+#ifdef TARGET_ABICALLS_NONPIC
+#define ABICALLS_SELF_SPECS ABICALLS_SPEC, \
+  "%{mabicalls:%{!fno-pic:%{mabi=o64|mabi=64|mabi=n32:-fpic}}}"
+#else
+#define ABICALLS_SELF_SPECS ABICALLS_SPEC, \
+  "%{mabicalls:%{!fno-pic:-fpic}}"
+#endif
+
+/* Any additional self specs defined by the subtarget.  */
+#define SUBTARGET_SELF_SPECS ""
+
+#define DRIVER_SELF_SPECS \
+ SUBTARGET_SELF_SPECS, \
+ ABICALLS_SELF_SPECS
+
+
 #ifndef MIPS_ABI_DEFAULT
 #define MIPS_ABI_DEFAULT ABI_32
 #endif
@@ -1044,7 +1094,7 @@ enum mips_code_readable_setting {
 %{mfix-vr4120} %{mfix-vr4130} \
 %(subtarget_asm_optimizing_spec) \
 %(subtarget_asm_debugging_spec) \
-%{mabi=*} %{!mabi*: %(asm_abi_default_spec)} \
+%{mabi=*} %{!mabi=*: %(asm_abi_default_spec)} \
 %{mgp32} %{mgp64} %{march=*} %{mxgot:-xgot} \
 %{mfp32} %{mfp64} \
 %{mshared} %{mno-shared} \
@@ -2484,7 +2534,7 @@ typedef struct mips_args {
    ? "%*" INSN "\t%" #OPNO "%/"					\
    : REG_P (OPERANDS[OPNO])					\
    ? "%*" INSN "r\t%" #OPNO "%/"				\
-   : TARGET_ABICALLS						\
+   : TARGET_PIC_ABICALLS					\
    ? (".option\tpic0\n\t"					\
       "%*" INSN "\t%" #OPNO "%/\n\t"				\
       ".option\tpic2")						\
Index: gcc/config/mips/vr.h
===================================================================
--- gcc/config/mips/vr.h	(revision 137143)
+++ gcc/config/mips/vr.h	(working copy)
@@ -26,7 +26,8 @@ along with GCC; see the file COPYING3.  
 	  MULTILIB_ABI_DEFAULT,			\
 	  DEFAULT_VR_ARCH }
 
-#define DRIVER_SELF_SPECS \
+#undef SUBTARGET_SELF_SPECS
+#define SUBTARGET_SELF_SPECS \
 	/* Enforce the default architecture.  This is mostly for	\
 	   the assembler's benefit.  */					\
 	"%{!march=*:%{!mfix-vr4120:%{!mfix-vr4130:"			\

--vtzGhvizbBRQ85DL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="gdb-nonpic.patch"

2008-03-07  Daniel Jacobowitz  <dan@codesourcery.com>

	gdb/
	* mips-tdep.c (mips32_scan_prologue): Stop scanning at branches.

2008-03-10  Daniel Jacobowitz  <dan@codesourcery.com>

	gdb/
	* mips-linux-tdep.c (mips_linux_in_dynsym_resolve_code): Update
	comments.
	(mips_linux_skip_resolver): Also use glibc_skip_solib_resolver.
	(mips_linux_init_abi): Do not override skip_trampoline_code.
	* configure.tgt (mips*-*-linux*): Add glibc-tdep.o.
	* mips-tdep.c (mips_stub_frame_sniffer): Use the stub frame sniffer
	for .MIPS.pic_stubs.
	(mips_skip_mips16_trampoline_code): Rename from
	mips_skip_trampoline_code.
	(mips_skip_pic_trampoline_code, mips_skip_trampoline_code): New.
	* infrun.c (handle_inferior_event): Do not check
	IN_SOLIB_DYNSYM_RESOLVE_CODE.  Do not pass zero to
	in_solib_dynsym_resolve_code.
	* Makefile.in (mips-linux-tdep.o): Update.

Index: gdb/Makefile.in
===================================================================
RCS file: /scratch/gcc/repos/src/src/gdb/Makefile.in,v
retrieving revision 1.1027
diff -u -p -r1.1027 Makefile.in
--- gdb/Makefile.in	10 Jun 2008 10:23:53 -0000	1.1027
+++ gdb/Makefile.in	27 Jun 2008 14:28:26 -0000
@@ -2519,7 +2519,7 @@ mips-linux-tdep.o: mips-linux-tdep.c $(d
 	$(gdb_assert_h) $(frame_h) $(regcache_h) $(trad_frame_h) \
 	$(tramp_frame_h) $(gdbtypes_h) $(solib_h) $(symtab_h) \
 	$(mips_linux_tdep_h) $(solist_h) $(solib_svr4_h) \
-	$(target_descriptions_h)
+	$(target_descriptions_h) $(glibc_tdep_h)
 mipsnbsd-nat.o: mipsnbsd-nat.c $(defs_h) $(inferior_h) $(regcache_h) \
 	$(target_h) $(mips_tdep_h) $(mipsnbsd_tdep_h) $(inf_ptrace_h)
 mipsnbsd-tdep.o: mipsnbsd-tdep.c $(defs_h) $(gdbcore_h) $(regcache_h) \
Index: gdb/configure.tgt
===================================================================
RCS file: /scratch/gcc/repos/src/src/gdb/configure.tgt,v
retrieving revision 1.203
diff -u -p -r1.203 configure.tgt
--- gdb/configure.tgt	1 May 2008 23:09:14 -0000	1.203
+++ gdb/configure.tgt	27 Jun 2008 14:28:26 -0000
@@ -297,7 +297,7 @@ mips*-sgi-irix6*)
 	;;
 mips*-*-linux*)
 	# Target: Linux/MIPS
-	gdb_target_obs="mips-tdep.o mips-linux-tdep.o \
+	gdb_target_obs="mips-tdep.o mips-linux-tdep.o glibc-tdep.o \
 			corelow.o solib.o solib-svr4.o symfile-mem.o"
 	gdb_sim=../sim/mips/libsim.a
 	build_gdbserver=yes
Index: gdb/infrun.c
===================================================================
RCS file: /scratch/gcc/repos/src/src/gdb/infrun.c,v
retrieving revision 1.282
diff -u -p -r1.282 infrun.c
--- gdb/infrun.c	24 Jun 2008 19:30:18 -0000	1.282
+++ gdb/infrun.c	27 Jun 2008 14:28:26 -0000
@@ -2863,12 +2863,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (
      until we exit the run time loader code and reach the callee's
      address.  */
   if (step_over_calls == STEP_OVER_UNDEBUGGABLE
-#ifdef IN_SOLIB_DYNSYM_RESOLVE_CODE
-      && IN_SOLIB_DYNSYM_RESOLVE_CODE (stop_pc)
-#else
-      && in_solib_dynsym_resolve_code (stop_pc)
-#endif
-      )
+      && in_solib_dynsym_resolve_code (stop_pc))
     {
       CORE_ADDR pc_after_resolver =
 	gdbarch_skip_solib_resolver (current_gdbarch, stop_pc);
@@ -2961,13 +2956,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (
       if (real_stop_pc != 0)
 	ecs->stop_func_start = real_stop_pc;
 
-      if (
-#ifdef IN_SOLIB_DYNSYM_RESOLVE_CODE
-	  IN_SOLIB_DYNSYM_RESOLVE_CODE (ecs->stop_func_start)
-#else
-	  in_solib_dynsym_resolve_code (ecs->stop_func_start)
-#endif
-)
+      if (real_stop_pc != 0 && in_solib_dynsym_resolve_code (real_stop_pc))
 	{
 	  struct symtab_and_line sr_sal;
 	  init_sal (&sr_sal);
Index: gdb/mips-linux-tdep.c
===================================================================
RCS file: /scratch/gcc/repos/src/src/gdb/mips-linux-tdep.c,v
retrieving revision 1.71
diff -u -p -r1.71 mips-linux-tdep.c
--- gdb/mips-linux-tdep.c	30 Apr 2008 21:25:16 -0000	1.71
+++ gdb/mips-linux-tdep.c	27 Jun 2008 14:28:26 -0000
@@ -37,6 +37,7 @@
 #include "symtab.h"
 #include "target-descriptions.h"
 #include "mips-linux-tdep.h"
+#include "glibc-tdep.h"
 
 static struct target_so_ops mips_svr4_so_ops;
 
@@ -666,13 +667,13 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc,
 }
 
 /* Return non-zero iff PC belongs to the dynamic linker resolution
-   code or to a stub.  */
+   code, a PLT entry, or a lazy binding stub.  */
 
 static int
 mips_linux_in_dynsym_resolve_code (CORE_ADDR pc)
 {
   /* Check whether PC is in the dynamic linker.  This also checks
-     whether it is in the .plt section, which MIPS does not use.  */
+     whether it is in the .plt section, used by non-PIC executables.  */
   if (svr4_in_dynsym_resolve_code (pc))
     return 1;
 
@@ -688,8 +689,8 @@ mips_linux_in_dynsym_resolve_code (CORE_
    and glibc_skip_solib_resolver in glibc-tdep.c.  The normal glibc
    implementation of this triggers at "fixup" from the same objfile as
    "_dl_runtime_resolve"; MIPS GNU/Linux can trigger at
-   "__dl_runtime_resolve" directly.  An unresolved PLT entry will
-   point to _dl_runtime_resolve, which will first call
+   "__dl_runtime_resolve" directly.  An unresolved lazy binding
+   stub will point to _dl_runtime_resolve, which will first call
    __dl_runtime_resolve, and then pass control to the resolved
    function.  */
 
@@ -703,7 +704,7 @@ mips_linux_skip_resolver (struct gdbarch
   if (resolver && SYMBOL_VALUE_ADDRESS (resolver) == pc)
     return frame_pc_unwind (get_current_frame ());
 
-  return 0;
+  return glibc_skip_solib_resolver (gdbarch, pc);
 }
 
 /* Signal trampoline support.  There are four supported layouts for a
@@ -1151,7 +1152,6 @@ mips_linux_init_abi (struct gdbarch_info
 	break;
     }
 
-  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
   set_gdbarch_skip_solib_resolver (gdbarch, mips_linux_skip_resolver);
 
   set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
Index: gdb/mips-tdep.c
===================================================================
RCS file: /scratch/gcc/repos/src/src/gdb/mips-tdep.c,v
retrieving revision 1.475
diff -u -p -r1.475 mips-tdep.c
--- gdb/mips-tdep.c	3 Jun 2008 10:53:34 -0000	1.475
+++ gdb/mips-tdep.c	27 Jun 2008 14:29:07 -0000
@@ -1928,6 +1928,7 @@ mips32_scan_prologue (CORE_ADDR start_pc
   CORE_ADDR end_prologue_addr = 0;
   int seen_sp_adjust = 0;
   int load_immediate_bytes = 0;
+  int in_delay_slot = 0;
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   int regsize_is_64_bits = (mips_abi_regsize (gdbarch) == 8);
 
@@ -2085,7 +2086,18 @@ restart:
             instructions?  */
          if (end_prologue_addr == 0)
            end_prologue_addr = cur_pc;
+
+	 /* Check for branches and jumps.  For now, only jump to
+	    register are caught (i.e. returns).  */
+	 if ((itype_op (inst) & 0x07) == 0 && rtype_funct (inst) == 8)
+	   in_delay_slot = 1;
        }
+
+      /* If the previous instruction was a jump, we must have reached
+	 the end of the prologue by now.  Stop scanning so that we do
+	 not go past the function return.  */
+      if (in_delay_slot)
+	break;
     }
 
   if (this_cache != NULL)
@@ -2303,6 +2315,13 @@ mips_stub_frame_sniffer (const struct fr
 		 ".MIPS.stubs") == 0)
     return 1;
 
+  /* Calling a PIC function from a non-PIC function passes through a stub
+     section; binutils calls it ".MIPS.pic_stubs".  */
+  if (s != NULL
+      && strcmp (bfd_get_section_name (s->objfile->obfd, s->the_bfd_section),
+		 ".MIPS.pic_stubs") == 0)
+    return 1;
+
   return 0;
 }
 
@@ -5020,7 +5039,7 @@ mips_breakpoint_from_pc (struct gdbarch 
    gory details.  */
 
 static CORE_ADDR
-mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+mips_skip_mips16_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 {
   char *name;
   CORE_ADDR start_addr;
@@ -5099,6 +5118,67 @@ mips_skip_trampoline_code (struct frame_
   return 0;			/* not a stub */
 }
 
+/* If the current PC is the start of a non-PIC-to-PIC stub, return the
+   PC of the stub target.  The stub just loads $t9 and jumps to it,
+   so that $t9 has the correct value at function entry.  */
+
+static CORE_ADDR
+mips_skip_pic_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+  struct obj_section *s;
+  int i;
+  gdb_byte stub_code[16];
+  int32_t stub_words[4];
+
+  s = find_pc_section (pc);
+  if (s == NULL
+      || strcmp (bfd_get_section_name (s->objfile->obfd, s->the_bfd_section),
+		 ".MIPS.pic_stubs") != 0)
+    return 0;
+
+  if (target_read_memory (pc, stub_code, 16) != 0)
+    return 0;
+  for (i = 0; i < 4; i++)
+    stub_words[i] = extract_unsigned_integer (stub_code + i * 4, 4);
+
+  /* A stub contains these instructions:
+     lui	t9, %hi(target)
+     addiu	t9, t9, %lo(target)
+     jr		t9
+      nop
+
+      N64 stubs will require more instructions.  */
+  if ((stub_words[0] & 0xffff0000U) == 0x3c190000
+      && (stub_words[1] & 0xffff0000U) == 0x27390000
+      && stub_words[2] == 0x03200008
+      && stub_words[3] == 0x00000000)
+    return (((stub_words[0] & 0x0000ffff) << 16)
+	    + (stub_words[1] & 0x0000ffff));
+
+  /* Not a recognized stub.  */
+  return 0;
+}
+
+static CORE_ADDR
+mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+  CORE_ADDR target_pc;
+
+  target_pc = mips_skip_mips16_trampoline_code (frame, pc);
+  if (target_pc)
+    return target_pc;
+
+  target_pc = find_solib_trampoline_target (frame, pc);
+  if (target_pc)
+    return target_pc;
+
+  target_pc = mips_skip_pic_trampoline_code (frame, pc);
+  if (target_pc)
+    return target_pc;
+
+  return 0;
+}
+
 /* Convert a dbx stab register number (from `r' declaration) to a GDB
    [1 * gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM.  */
 

--vtzGhvizbBRQ85DL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="glibc-longlong.patch"

2008-06-27  Daniel Jacobowitz  <dan@codesourcery.com>

	* longlong.h: Update from GCC.

Index: stdlib/longlong.h
===================================================================
RCS file: /cvs/glibc/libc/stdlib/longlong.h,v
retrieving revision 1.31
diff -u -p -r1.31 longlong.h
--- stdlib/longlong.h	15 May 2006 20:25:33 -0000	1.31
+++ stdlib/longlong.h	27 Jun 2008 13:05:23 -0000
@@ -229,6 +229,19 @@ UDItype __umulsidi3 (USItype, USItype);
 #define UDIV_TIME 100
 #endif /* __arm__ */
 
+#if defined(__arm__)
+/* Let gcc decide how best to implement count_leading_zeros.  */
+#define count_leading_zeros(COUNT,X)	((COUNT) = __builtin_clz (X))
+#define COUNT_LEADING_ZEROS_0 32
+#endif
+
+#if defined (__CRIS__) && __CRIS_arch_version >= 3
+#define count_leading_zeros(COUNT, X) ((COUNT) = __builtin_clz (X))
+#if __CRIS_arch_version >= 8
+#define count_trailing_zeros(COUNT, X) ((COUNT) = __builtin_ctz (X))
+#endif
+#endif /* __CRIS__ */
+
 #if defined (__hppa) && W_TYPE_SIZE == 32
 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \
   __asm__ ("add %4,%5,%1\n\taddc %2,%3,%0"				\
@@ -315,7 +328,7 @@ UDItype __umulsidi3 (USItype, USItype);
 
 #if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32
 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \
-  __asm__ ("addl %5,%1\n\tadcl %3,%0"					\
+  __asm__ ("add{l} {%5,%1|%1,%5}\n\tadc{l} {%3,%0|%0,%3}"		\
 	   : "=r" ((USItype) (sh)),					\
 	     "=&r" ((USItype) (sl))					\
 	   : "%0" ((USItype) (ah)),					\
@@ -323,7 +336,7 @@ UDItype __umulsidi3 (USItype, USItype);
 	     "%1" ((USItype) (al)),					\
 	     "g" ((USItype) (bl)))
 #define sub_ddmmss(sh, sl, ah, al, bh, bl) \
-  __asm__ ("subl %5,%1\n\tsbbl %3,%0"					\
+  __asm__ ("sub{l} {%5,%1|%1,%5}\n\tsbb{l} {%3,%0|%0,%3}"		\
 	   : "=r" ((USItype) (sh)),					\
 	     "=&r" ((USItype) (sl))					\
 	   : "0" ((USItype) (ah)),					\
@@ -331,31 +344,60 @@ UDItype __umulsidi3 (USItype, USItype);
 	     "1" ((USItype) (al)),					\
 	     "g" ((USItype) (bl)))
 #define umul_ppmm(w1, w0, u, v) \
-  __asm__ ("mull %3"							\
+  __asm__ ("mul{l} %3"							\
 	   : "=a" ((USItype) (w0)),					\
 	     "=d" ((USItype) (w1))					\
 	   : "%0" ((USItype) (u)),					\
 	     "rm" ((USItype) (v)))
 #define udiv_qrnnd(q, r, n1, n0, dv) \
-  __asm__ ("divl %4"							\
+  __asm__ ("div{l} %4"							\
 	   : "=a" ((USItype) (q)),					\
 	     "=d" ((USItype) (r))					\
 	   : "0" ((USItype) (n0)),					\
 	     "1" ((USItype) (n1)),					\
 	     "rm" ((USItype) (dv)))
-#define count_leading_zeros(count, x) \
-  do {									\
-    USItype __cbtmp;							\
-    __asm__ ("bsrl %1,%0"						\
-	     : "=r" (__cbtmp) : "rm" ((USItype) (x)));			\
-    (count) = __cbtmp ^ 31;						\
-  } while (0)
-#define count_trailing_zeros(count, x) \
-  __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x)))
+#define count_leading_zeros(count, x)	((count) = __builtin_clz (x))
+#define count_trailing_zeros(count, x)	((count) = __builtin_ctz (x))
 #define UMUL_TIME 40
 #define UDIV_TIME 40
 #endif /* 80x86 */
 
+#if (defined (__x86_64__) || defined (__i386__)) && W_TYPE_SIZE == 64
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add{q} {%5,%1|%1,%5}\n\tadc{q} {%3,%0|%0,%3}"		\
+	   : "=r" ((UDItype) (sh)),					\
+	     "=&r" ((UDItype) (sl))					\
+	   : "%0" ((UDItype) (ah)),					\
+	     "rme" ((UDItype) (bh)),					\
+	     "%1" ((UDItype) (al)),					\
+	     "rme" ((UDItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub{q} {%5,%1|%1,%5}\n\tsbb{q} {%3,%0|%0,%3}"		\
+	   : "=r" ((UDItype) (sh)),					\
+	     "=&r" ((UDItype) (sl))					\
+	   : "0" ((UDItype) (ah)),					\
+	     "rme" ((UDItype) (bh)),					\
+	     "1" ((UDItype) (al)),					\
+	     "rme" ((UDItype) (bl)))
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mul{q} %3"							\
+	   : "=a" ((UDItype) (w0)),					\
+	     "=d" ((UDItype) (w1))					\
+	   : "%0" ((UDItype) (u)),					\
+	     "rm" ((UDItype) (v)))
+#define udiv_qrnnd(q, r, n1, n0, dv) \
+  __asm__ ("div{q} %4"							\
+	   : "=a" ((UDItype) (q)),					\
+	     "=d" ((UDItype) (r))					\
+	   : "0" ((UDItype) (n0)),					\
+	     "1" ((UDItype) (n1)),					\
+	     "rm" ((UDItype) (dv)))
+#define count_leading_zeros(count, x)	((count) = __builtin_clzl (x))
+#define count_trailing_zeros(count, x)	((count) = __builtin_ctzl (x))
+#define UMUL_TIME 40
+#define UDIV_TIME 40
+#endif /* x86_64 */
+
 #if defined (__i960__) && W_TYPE_SIZE == 32
 #define umul_ppmm(w1, w0, u, v) \
   ({union {UDItype __ll;						\
@@ -523,6 +565,11 @@ UDItype __umulsidi3 (USItype, USItype);
   __asm__ ("bfffo %1{%b2:%b2},%0"					\
 	   : "=d" ((USItype) (count))					\
 	   : "od" ((USItype) (x)), "n" (0))
+/* Some ColdFire architectures have a ff1 instruction supported via
+   __builtin_clz. */
+#elif defined (__mcfisaaplus__) || defined (__mcfisac__)
+#define count_leading_zeros(count,x) ((count) = __builtin_clz (x))
+#define COUNT_LEADING_ZEROS_0 32
 #endif
 #endif /* mc68000 */
 
@@ -585,14 +632,19 @@ UDItype __umulsidi3 (USItype, USItype);
 #endif /* __m88000__ */
 
 #if defined (__mips__) && W_TYPE_SIZE == 32
-#define umul_ppmm(w1, w0, u, v) \
-  __asm__ ("multu %2,%3"						\
-	   : "=l" ((USItype) (w0)),					\
-	     "=h" ((USItype) (w1))					\
-	   : "d" ((USItype) (u)),					\
-	     "d" ((USItype) (v)))
+#define umul_ppmm(w1, w0, u, v)						\
+  do {									\
+    UDItype __x = (UDItype) (USItype) (u) * (USItype) (v);		\
+    (w1) = (USItype) (__x >> 32);					\
+    (w0) = (USItype) (__x);						\
+  } while (0)
 #define UMUL_TIME 10
 #define UDIV_TIME 100
+
+#if (__mips == 32 || __mips == 64) && ! __mips16
+#define count_leading_zeros(COUNT,X)	((COUNT) = __builtin_clz (X))
+#define COUNT_LEADING_ZEROS_0 32
+#endif
 #endif /* __mips__ */
 
 #if defined (__ns32000__) && W_TYPE_SIZE == 32
@@ -641,7 +693,9 @@ UDItype __umulsidi3 (USItype, USItype);
      || defined (__powerpc__)	/* gcc */				\
      || defined (__POWERPC__)	/* BEOS */				\
      || defined (__ppc__)	/* Darwin */				\
-     || defined (PPC)		/* GNU/Linux, SysV */			\
+     || (defined (PPC) && ! defined (CPU_FAMILY)) /* gcc 2.7.x GNU&SysV */    \
+     || (defined (PPC) && defined (CPU_FAMILY)    /* VxWorks */               \
+         && CPU_FAMILY == PPC)                                                \
      ) && W_TYPE_SIZE == 32
 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \
   do {									\
@@ -679,7 +733,10 @@ UDItype __umulsidi3 (USItype, USItype);
   __asm__ ("{cntlz|cntlzw} %0,%1" : "=r" (count) : "r" (x))
 #define COUNT_LEADING_ZEROS_0 32
 #if defined (_ARCH_PPC) || defined (__powerpc__) || defined (__POWERPC__) \
-  || defined (__ppc__) || defined (PPC)
+  || defined (__ppc__)                                                    \
+  || (defined (PPC) && ! defined (CPU_FAMILY)) /* gcc 2.7.x GNU&SysV */       \
+  || (defined (PPC) && defined (CPU_FAMILY)    /* VxWorks */                  \
+         && CPU_FAMILY == PPC)
 #define umul_ppmm(ph, pl, m0, m1) \
   do {									\
     USItype __m0 = (m0), __m1 = (m1);					\
@@ -828,18 +885,51 @@ UDItype __umulsidi3 (USItype, USItype);
   } while (0)
 #endif
 
-#if defined (__sh2__) && W_TYPE_SIZE == 32
+#if defined(__sh__) && !__SHMEDIA__ && W_TYPE_SIZE == 32
+#ifndef __sh1__
 #define umul_ppmm(w1, w0, u, v) \
   __asm__ (								\
-       "dmulu.l	%2,%3\n\tsts	macl,%1\n\tsts	mach,%0"		\
-	   : "=r" ((USItype)(w1)),					\
-	     "=r" ((USItype)(w0))					\
+       "dmulu.l	%2,%3\n\tsts%M1	macl,%1\n\tsts%M0	mach,%0"	\
+	   : "=r<" ((USItype)(w1)),					\
+	     "=r<" ((USItype)(w0))					\
 	   : "r" ((USItype)(u)),					\
 	     "r" ((USItype)(v))						\
 	   : "macl", "mach")
 #define UMUL_TIME 5
 #endif
 
+/* This is the same algorithm as __udiv_qrnnd_c.  */
+#define UDIV_NEEDS_NORMALIZATION 1
+
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do {									\
+    extern UWtype __udiv_qrnnd_16 (UWtype, UWtype)			\
+                        __attribute__ ((visibility ("hidden")));	\
+    /* r0: rn r1: qn */ /* r0: n1 r4: n0 r5: d r6: d1 */ /* r2: __m */	\
+    __asm__ (								\
+	"mov%M4 %4,r5\n"						\
+"	swap.w %3,r4\n"							\
+"	swap.w r5,r6\n"							\
+"	jsr @%5\n"							\
+"	shll16 r6\n"							\
+"	swap.w r4,r4\n"							\
+"	jsr @%5\n"							\
+"	swap.w r1,%0\n"							\
+"	or r1,%0"							\
+	: "=r" (q), "=&z" (r)						\
+	: "1" (n1), "r" (n0), "rm" (d), "r" (&__udiv_qrnnd_16)		\
+	: "r1", "r2", "r4", "r5", "r6", "pr");				\
+  } while (0)
+
+#define UDIV_TIME 80
+
+#define sub_ddmmss(sh, sl, ah, al, bh, bl)				\
+  __asm__ ("clrt;subc %5,%1; subc %4,%0"				\
+	   : "=r" (sh), "=r" (sl)					\
+	   : "0" (ah), "1" (al), "r" (bh), "r" (bl))
+
+#endif /* __sh__ */
+
 #if defined (__SH5__) && __SHMEDIA__ && W_TYPE_SIZE == 32
 #define __umulsidi3(u,v) ((UDItype)(USItype)u*(USItype)v)
 #define count_leading_zeros(count, x) \
@@ -1153,6 +1243,23 @@ UDItype __umulsidi3 (USItype, USItype);
   } while (0)
 #endif /* __vax__ */
 
+#if defined (__xtensa__) && W_TYPE_SIZE == 32
+/* This code is not Xtensa-configuration-specific, so rely on the compiler
+   to expand builtin functions depending on what configuration features
+   are available.  This avoids library calls when the operation can be
+   performed in-line.  */
+#define umul_ppmm(w1, w0, u, v)						\
+  do {									\
+    DWunion __w;							\
+    __w.ll = __builtin_umulsidi3 (u, v);				\
+    w1 = __w.s.high;							\
+    w0 = __w.s.low;							\
+  } while (0)
+#define __umulsidi3(u, v)		__builtin_umulsidi3 (u, v)
+#define count_leading_zeros(COUNT, X)	((COUNT) = __builtin_clz (X))
+#define count_trailing_zeros(COUNT, X)	((COUNT) = __builtin_ctz (X))
+#endif /* __xtensa__ */
+
 #if defined (__z8000__) && W_TYPE_SIZE == 16
 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \
   __asm__ ("add	%H1,%H5\n\tadc	%H0,%H3"				\

--vtzGhvizbBRQ85DL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="glibc-ports-nonpic.patch"

2008-03-28  Mark Shinwell  <shinwell@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* sysdeps/mips/dl-lookup.c: New.
	* sysdeps/mips/do-lookup.h: New.
	* sysdeps/mips/dl-machine.h (ELF_MACHINE_NO_PLT): Remove
	definition.
	(ELF_MACHINE_JMP_SLOT): Alter definition and update comment.
	(elf_machine_type_class): Likewise.
	(ELF_MACHINE_PLT_REL): Define.
	(elf_machine_fixup_plt): New.
	(elf_machine_plt_value): New.
	(elf_machine_reloc): Handle jump slot and copy relocations.
	(elf_machine_lazy_rel): Point relocation place at PLT if
	required.
	(elf_machine_runtime_setup): Fill in .got.plt header.
	* sysdeps/mips/dl-trampoline.c: New.
	* sysdeps/mips/bits/linkmap.h (link_map_machine): New.
	* sysdeps/mips/tls-macros.h: Load $gp as required.

	* sysdeps/unix/sysv/linux/mips/mips32/sysdep.h (SYSCALL_ERROR_LABEL):
	Delete definition.
	* sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h (PSEUDO_CPLOAD,
	PSEUDO_ERRJMP, PSEUDO_SAVEGP, PSEUDO_LOADGP): Define.
	(PSEUDO): Use them.  Move outside __PIC__.
	(PSEUDO_JMP): New.
	(CENABLE, CDISABLE): Use it.

Index: sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
===================================================================
--- sysdeps/unix/sysv/linux/mips/mips32/sysdep.h	(revision 213009)
+++ sysdeps/unix/sysv/linux/mips/mips32/sysdep.h	(working copy)
@@ -35,15 +35,7 @@
 # define SYS_ify(syscall_name)	__NR_/**/syscall_name
 #endif
 
-#ifdef __ASSEMBLER__
-
-/* We don't want the label for the error handler to be visible in the symbol
-   table when we define it here.  */
-#ifdef __PIC__
-# define SYSCALL_ERROR_LABEL 99b
-#endif
-
-#else   /* ! __ASSEMBLER__ */
+#ifndef __ASSEMBLER__
 
 /* Define a macro which expands into the inline wrapper code for a system
    call.  */
Index: sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h
===================================================================
--- sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h	(revision 213009)
+++ sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h	(working copy)
@@ -25,28 +25,38 @@
 
 #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
 
-#ifdef __PIC__
+# ifdef __PIC__
+#  define PSEUDO_CPLOAD .cpload t9;
+#  define PSEUDO_ERRJMP la t9, __syscall_error; jr t9;
+#  define PSEUDO_SAVEGP sw gp, 32(sp); cfi_rel_offset (gp, 32);
+#  define PSEUDO_LOADGP lw gp, 32(sp);
+# else
+#  define PSEUDO_CPLOAD
+#  define PSEUDO_ERRJMP j __syscall_error;
+#  define PSEUDO_SAVEGP
+#  define PSEUDO_LOADGP
+# endif
+
 # undef PSEUDO
 # define PSEUDO(name, syscall_name, args)				      \
       .align 2;								      \
   L(pseudo_start):							      \
       cfi_startproc;							      \
-  99: la t9,__syscall_error;						      \
-      jr t9;								      \
+  99: PSEUDO_ERRJMP							      \
   .type __##syscall_name##_nocancel, @function;				      \
   .globl __##syscall_name##_nocancel;					      \
   __##syscall_name##_nocancel:						      \
     .set noreorder;							      \
-    .cpload t9;								      \
+    PSEUDO_CPLOAD							      \
     li v0, SYS_ify(syscall_name);					      \
     syscall;								      \
     .set reorder;							      \
-    bne a3, zero, SYSCALL_ERROR_LABEL;			       		      \
+    bne a3, zero, 99b;					       		      \
     ret;								      \
   .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \
   ENTRY (name)								      \
     .set noreorder;							      \
-    .cpload t9;								      \
+    PSEUDO_CPLOAD							      \
     .set reorder;							      \
     SINGLE_THREAD_P(v1);						      \
     bne zero, v1, L(pseudo_cancel);					      \
@@ -54,17 +64,16 @@
     li v0, SYS_ify(syscall_name);					      \
     syscall;								      \
     .set reorder;							      \
-    bne a3, zero, SYSCALL_ERROR_LABEL;			       		      \
+    bne a3, zero, 99b;					       		      \
     ret;								      \
   L(pseudo_cancel):							      \
     SAVESTK_##args;						              \
     sw ra, 28(sp);							      \
     cfi_rel_offset (ra, 28);						      \
-    sw gp, 32(sp);							      \
-    cfi_rel_offset (gp, 32);						      \
+    PSEUDO_SAVEGP							      \
     PUSHARGS_##args;			/* save syscall args */	      	      \
     CENABLE;								      \
-    lw gp, 32(sp);							      \
+    PSEUDO_LOADGP							      \
     sw v0, 44(sp);			/* save mask */			      \
     POPARGS_##args;			/* restore syscall args */	      \
     .set noreorder;							      \
@@ -75,12 +84,12 @@
     sw a3, 40(sp);			/* save syscall error flag */	      \
     lw a0, 44(sp);			/* pass mask as arg1 */		      \
     CDISABLE;								      \
-    lw gp, 32(sp);							      \
+    PSEUDO_LOADGP							      \
     lw v0, 36(sp);			/* restore syscall result */          \
     lw a3, 40(sp);			/* restore syscall error flag */      \
     lw ra, 28(sp);			/* restore return address */	      \
     .set noreorder;							      \
-    bne a3, zero, SYSCALL_ERROR_LABEL;					      \
+    bne a3, zero, 99b;							      \
      RESTORESTK;						              \
   L(pseudo_end):							      \
     .set reorder;
@@ -88,8 +97,6 @@
 # undef PSEUDO_END
 # define PSEUDO_END(sym) cfi_endproc; .end sym; .size sym,.-sym
 
-#endif
-
 # define PUSHARGS_0	/* nothing to do */
 # define PUSHARGS_1	PUSHARGS_0 sw a0, 0(sp); cfi_rel_offset (a0, 0);
 # define PUSHARGS_2	PUSHARGS_1 sw a1, 4(sp); cfi_rel_offset (a1, 4);
@@ -136,19 +143,25 @@
 # define RESTORESTK 	addu sp, STKSPACE; cfi_adjust_cfa_offset(-STKSPACE)
 
 
+# ifdef __PIC__
 /* We use jalr rather than jal.  This means that the assembler will not
    automatically restore $gp (in case libc has multiple GOTs) so we must
    do it manually - which we have to do anyway since we don't use .cprestore.
    It also shuts up the assembler warning about not using .cprestore.  */
+#  define PSEUDO_JMP(sym) la t9, sym; jalr t9;
+# else
+#  define PSEUDO_JMP(sym) jal sym;
+# endif
+
 # ifdef IS_IN_libpthread
-#  define CENABLE	la t9, __pthread_enable_asynccancel; jalr t9;
-#  define CDISABLE	la t9, __pthread_disable_asynccancel; jalr t9;
+#  define CENABLE	PSEUDO_JMP (__pthread_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__pthread_disable_asynccancel)
 # elif defined IS_IN_librt
-#  define CENABLE	la t9, __librt_enable_asynccancel; jalr t9;
-#  define CDISABLE	la t9, __librt_disable_asynccancel; jalr t9;
+#  define CENABLE	PSEUDO_JMP (__librt_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__librt_disable_asynccancel)
 # else
-#  define CENABLE	la t9, __libc_enable_asynccancel; jalr t9;
-#  define CDISABLE	la t9, __libc_disable_asynccancel; jalr t9;
+#  define CENABLE	PSEUDO_JMP (__libc_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__libc_disable_asynccancel)
 # endif
 
 # ifndef __ASSEMBLER__
Index: sysdeps/mips/do-lookup.h
===================================================================
--- sysdeps/mips/do-lookup.h	(revision 0)
+++ sysdeps/mips/do-lookup.h	(revision 0)
@@ -0,0 +1,37 @@
+/* MIPS-specific veneer to GLIBC's do-lookup.h.
+   Copyright (C) 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* The semantics of zero/non-zero values of undefined symbols differs
+   depending on whether the non-PIC ABI is in use.  Under the non-PIC ABI,
+   a non-zero value indicates that there is an address reference to the
+   symbol and thus it must always be resolved (except when resolving a jump
+   slot relocation) to the PLT entry whose address is provided as the
+   symbol's value; a zero value indicates that this canonical-address
+   behaviour is not required.  Yet under the classic MIPS psABI, a zero value
+   indicates that there is an address reference to the function and the
+   dynamic linker must resolve the symbol immediately upon loading.  To
+   avoid conflict, symbols for which the dynamic linker must assume the
+   non-PIC ABI semantics are marked with the STO_MIPS_PLT flag.  The
+   following ugly hack causes the code in the platform-independent
+   do-lookup.h file to check this flag correctly.  */
+#define st_value st_shndx == SHN_UNDEF && !(sym->st_other & STO_MIPS_PLT)) \
+		 || (sym->st_value
+#include_next "do-lookup.h"
+#undef st_value
+
Index: sysdeps/mips/tls-macros.h
===================================================================
--- sysdeps/mips/tls-macros.h	(revision 213009)
+++ sysdeps/mips/tls-macros.h	(working copy)
@@ -4,27 +4,27 @@
 
 /* These versions are for o32 and n32.  */
 
-# define TLS_GD(x)					\
-  ({ void *__result;					\
-     extern void *__tls_get_addr (void *);		\
-     asm ("addiu %0, $28, %%tlsgd(" #x ")"		\
-	  : "=r" (__result));				\
-     (int *)__tls_get_addr (__result); })
+#ifndef __PIC__
+# define LOAD_GP "move %[tmp], $28\n\tla $28, __gnu_local_gp\n\t"
+# define UNLOAD_GP "\n\tmove $28, %[tmp]"
 #else
+# define LOAD_GP
+# define UNLOAD_GP
+#endif
+
 # define TLS_GD(x)					\
-  ({ void *__result;					\
+  ({ void *__result, *__tmp;				\
      extern void *__tls_get_addr (void *);		\
-     asm ("daddiu %0, $28, %%tlsgd(" #x ")"		\
-	  : "=r" (__result));				\
+     asm (LOAD_GP "addiu %0, $28, %%tlsgd(" #x ")"	\
+	  UNLOAD_GP					\
+	  : "=r" (__result), [tmp] "=&r" (__tmp));	\
      (int *)__tls_get_addr (__result); })
-#endif
-
-#if _MIPS_SIM != _ABI64
 # define TLS_LD(x)					\
-  ({ void *__result;					\
+  ({ void *__result, *__tmp;				\
      extern void *__tls_get_addr (void *);		\
-     asm ("addiu %0, $28, %%tlsldm(" #x ")"		\
-	  : "=r" (__result));				\
+     asm (LOAD_GP "addiu %0, $28, %%tlsldm(" #x ")"	\
+	  UNLOAD_GP					\
+	  : "=r" (__result), [tmp] "=&r" (__tmp));	\
      __result = __tls_get_addr (__result);		\
      asm ("lui $3,%%dtprel_hi(" #x ")\n\t"		\
 	  "addiu $3,$3,%%dtprel_lo(" #x ")\n\t"		\
@@ -32,13 +32,15 @@
 	  : "+r" (__result) : : "$3");			\
      __result; })
 # define TLS_IE(x)					\
-  ({ void *__result;					\
+  ({ void *__result, *__tmp;				\
      asm (".set push\n\t.set mips32r2\n\t"		\
 	  "rdhwr\t%0,$29\n\t.set pop"			\
 	  : "=v" (__result));				\
-     asm ("lw $3,%%gottprel(" #x ")($28)\n\t"		\
+     asm (LOAD_GP "lw $3,%%gottprel(" #x ")($28)\n\t"	\
 	  "addu %0,%0,$3"				\
-	  : "+r" (__result) : : "$3");			\
+	  UNLOAD_GP					\
+	  : "+r" (__result), [tmp] "=&r" (__tmp)	\
+	  : : "$3");					\
      __result; })
 # define TLS_LE(x)					\
   ({ void *__result;					\
@@ -55,6 +57,12 @@
 
 /* These versions are for n64.  */
 
+# define TLS_GD(x)					\
+  ({ void *__result;					\
+     extern void *__tls_get_addr (void *);		\
+     asm ("daddiu %0, $28, %%tlsgd(" #x ")"		\
+	  : "=r" (__result));				\
+     (int *)__tls_get_addr (__result); })
 # define TLS_LD(x)					\
   ({ void *__result;					\
      extern void *__tls_get_addr (void *);		\
Index: sysdeps/mips/dl-machine.h
===================================================================
--- sysdeps/mips/dl-machine.h	(revision 213009)
+++ sysdeps/mips/dl-machine.h	(working copy)
@@ -25,8 +25,6 @@
 
 #define ELF_MACHINE_NAME "MIPS"
 
-#define ELF_MACHINE_NO_PLT
-
 #include <entry.h>
 
 #ifndef ENTRY_POINT
@@ -56,10 +54,15 @@
 #endif
 
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.
-   This makes no sense on MIPS but we have to define this to R_MIPS_REL32
-   to avoid the asserts in dl-lookup.c from blowing.  */
-#define ELF_MACHINE_JMP_SLOT			R_MIPS_REL32
-#define elf_machine_type_class(type)		ELF_RTYPE_CLASS_PLT
+   This makes no sense on MIPS unless using the non-PIC ABI but we have
+   to define this to avoid the asserts in dl-lookup.c from blowing.
+   We choose the value that makes sense for the non-PIC ABI.  */
+#define ELF_MACHINE_JMP_SLOT			R_MIPS_JUMP_SLOT
+#define elf_machine_type_class(type) \
+  ((((type) == ELF_MACHINE_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
+   | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY))
+
+#define ELF_MACHINE_PLT_REL 1
 
 /* Translate a processor specific dynamic tag to the index
    in l_info array.  */
@@ -73,6 +76,14 @@ do { if ((l)->l_info[DT_MIPS (RLD_MAP)])
        (ElfW(Addr)) (r); \
    } while (0)
 
+/* Allow ABIVERSION == 1, meaning non-PIC abicalls.  */
+#define VALID_ELF_ABIVERSION(ver)	(ver == 0 || ver == 2)
+#define VALID_ELF_OSABI(osabi)		(osabi == ELFOSABI_SYSV)
+#define VALID_ELF_HEADER(hdr,exp,size) \
+  memcmp (hdr,exp,size-2) == 0 \
+  && VALID_ELF_OSABI (hdr[EI_OSABI]) \
+  && VALID_ELF_ABIVERSION (hdr[EI_ABIVERSION])
+
 /* Return nonzero iff ELF header is compatible with the running host.  */
 static inline int __attribute_used__
 elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
@@ -294,6 +305,24 @@ do {									\
 #  define ARCH_LA_PLTEXIT mips_n64_gnu_pltexit
 # endif
 
+/* For a non-writable PLT, rewrite the .got.plt entry at RELOC_ADDR to
+   point at the symbol with address VALUE.  For a writable PLT, rewrite
+   the corresponding PLT entry instead.  */
+static inline Elf32_Addr
+elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const Elf32_Rel *reloc,
+		       Elf32_Addr *reloc_addr, Elf32_Addr value)
+{
+  return *reloc_addr = value;
+}
+
+static inline Elf32_Addr
+elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
+		       Elf32_Addr value)
+{
+  return value;
+}
+
 #endif /* !dl_machine_h */
 
 #ifdef RESOLVE_MAP
@@ -461,6 +490,60 @@ elf_machine_reloc (struct link_map *map,
 #endif
     case R_MIPS_NONE:		/* Alright, Wilbur.  */
       break;
+
+    case R_MIPS_JUMP_SLOT:
+      {
+	/* Handle a jump slot relocation (only for the non-PIC ABI).  */
+
+	struct link_map *sym_map;
+	Elf32_Addr value;
+
+	/* The addend for a jump slot relocation must always be zero:
+	   calls via the PLT always branch to the symbol's address and
+	   not to the address plus a non-zero offset.  */
+	if (r_addend != 0)
+	  _dl_signal_error (0, map->l_name, NULL,
+			    "found jump slot relocation with non-zero addend");
+
+	sym_map = RESOLVE_MAP (&sym, version, r_type);
+	value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
+	*addr_field = value;
+
+	break;
+      }
+
+    case R_MIPS_COPY:
+      {
+	/* Handle a copy relocation (only for the non-PIC ABI).  */
+
+	const Elf32_Sym *const refsym = sym;
+	struct link_map *sym_map;
+	Elf32_Addr value;
+
+	/* Calculate the address of the symbol.  */
+	sym_map = RESOLVE_MAP (&sym, version, r_type);
+	value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
+
+	if (sym == NULL)
+	  /* This can happen in trace mode if an object could not be
+	     found.  */
+	  break;
+	if (sym->st_size > refsym->st_size
+	    || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
+	  {
+	    const char *strtab;
+
+	    strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+	    _dl_error_printf ("\
+  %s: Symbol `%s' has different size in shared object, consider re-linking\n",
+			      rtld_progname ?: "<program name unknown>",
+			      strtab + refsym->st_name);
+	  }
+	memcpy (reloc_addr, (void *) value,
+	        MIN (sym->st_size, refsym->st_size));
+	break;
+      }
+
 #if _MIPS_SIM == _ABI64
     case R_MIPS_64:
       /* For full compliance with the ELF64 ABI, one must precede the
@@ -505,9 +588,23 @@ elf_machine_rel_relative (ElfW(Addr) l_a
 auto inline void
 __attribute__((always_inline))
 elf_machine_lazy_rel (struct link_map *map,
-		      ElfW(Addr) l_addr, const ElfW(Rela) *reloc)
+		      ElfW(Addr) l_addr, const ElfW(Rel) *reloc)
 {
-  /* Do nothing.  */
+  Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
+  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
+  /* Check for unexpected PLT reloc type.  */
+  if (__builtin_expect (r_type == R_MIPS_JUMP_SLOT, 1))
+    {
+      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+	{
+	  /* Nothing is required here since we only support lazy
+	     relocation in executables.  */
+	}
+      else
+	*reloc_addr = map->l_mach.plt;
+    }
+  else
+    _dl_reloc_bad_type (map, r_type, 1);
 }
 
 auto inline void
@@ -650,6 +747,22 @@ elf_machine_runtime_setup (struct link_m
   /* Relocate global offset table.  */
   elf_machine_got_rel (l, lazy);
 
+  /* If using the non-PIC ABI, fill in the first two entries of
+     .got.plt.  */
+  if (l->l_info[DT_JMPREL] && lazy)
+    {
+      extern void _dl_runtime_pltresolve (void);
+      Elf32_Addr *gotplt;
+      gotplt = (Elf32_Addr *) D_PTR (l, l_info[DT_MIPS (PLTGOT)]);
+      /* If a library is prelinked but we have to relocate anyway,
+	 we have to be able to undo the prelinking of .got.plt.
+	 The prelinker saved the address of .plt for us here.  */
+      if (gotplt[1])
+	l->l_mach.plt = gotplt[1] + l->l_addr;
+      gotplt[0] = (Elf32_Addr) &_dl_runtime_pltresolve;
+      gotplt[1] = (Elf32_Addr) l;
+    }
+
 # endif
   return lazy;
 }
Index: sysdeps/mips/dl-lookup.c
===================================================================
--- sysdeps/mips/dl-lookup.c	(revision 0)
+++ sysdeps/mips/dl-lookup.c	(revision 0)
@@ -0,0 +1,581 @@
+/* Look up a symbol in the loaded objects.
+   MIPS/Linux version - this is identical to the common version, but
+   because it is in sysdeps/mips, it gets sysdeps/mips/do-lookup.h.
+   Using <do-lookup.h> instead of "do-lookup.h" would work too.
+
+   Copyright (C) 1995-2005, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <alloca.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <dl-hash.h>
+#include <dl-machine.h>
+#include <sysdep-cancel.h>
+#include <bits/libc-lock.h>
+#include <tls.h>
+
+#include <assert.h>
+
+#define VERSTAG(tag)	(DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
+
+/* We need this string more than once.  */
+static const char undefined_msg[] = "undefined symbol: ";
+
+
+struct sym_val
+  {
+    const ElfW(Sym) *s;
+    struct link_map *m;
+  };
+
+
+#define make_string(string, rest...) \
+  ({									      \
+    const char *all[] = { string, ## rest };				      \
+    size_t len, cnt;							      \
+    char *result, *cp;							      \
+									      \
+    len = 1;								      \
+    for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)		      \
+      len += strlen (all[cnt]);						      \
+									      \
+    cp = result = alloca (len);						      \
+    for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)		      \
+      cp = __stpcpy (cp, all[cnt]);					      \
+									      \
+    result;								      \
+  })
+
+/* Statistics function.  */
+#ifdef SHARED
+# define bump_num_relocations() ++GL(dl_num_relocations)
+#else
+# define bump_num_relocations() ((void) 0)
+#endif
+
+
+/* The actual lookup code.  */
+#include "do-lookup.h"
+
+
+static uint_fast32_t
+dl_new_hash (const char *s)
+{
+  uint_fast32_t h = 5381;
+  for (unsigned char c = *s; c != '\0'; c = *++s)
+    h = h * 33 + c;
+  return h & 0xffffffff;
+}
+
+
+/* Add extra dependency on MAP to UNDEF_MAP.  */
+static int
+internal_function
+add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
+{
+  struct link_map *runp;
+  unsigned int i;
+  int result = 0;
+
+  /* Avoid self-references and references to objects which cannot be
+     unloaded anyway.  */
+  if (undef_map == map)
+    return 0;
+
+  /* Avoid references to objects which cannot be unloaded anyway.  */
+  assert (map->l_type == lt_loaded);
+  if ((map->l_flags_1 & DF_1_NODELETE) != 0)
+    return 0;
+
+  struct link_map_reldeps *l_reldeps
+    = atomic_forced_read (undef_map->l_reldeps);
+
+  /* Make sure l_reldeps is read before l_initfini.  */
+  atomic_read_barrier ();
+
+  /* Determine whether UNDEF_MAP already has a reference to MAP.  First
+     look in the normal dependencies.  */
+  struct link_map **l_initfini = atomic_forced_read (undef_map->l_initfini);
+  if (l_initfini != NULL)
+    {
+      for (i = 0; l_initfini[i] != NULL; ++i)
+	if (l_initfini[i] == map)
+	  return 0;
+    }
+
+  /* No normal dependency.  See whether we already had to add it
+     to the special list of dynamic dependencies.  */
+  unsigned int l_reldepsact = 0;
+  if (l_reldeps != NULL)
+    {
+      struct link_map **list = &l_reldeps->list[0];
+      l_reldepsact = l_reldeps->act;
+      for (i = 0; i < l_reldepsact; ++i)
+	if (list[i] == map)
+	  return 0;
+    }
+
+  /* Save serial number of the target MAP.  */
+  unsigned long long serial = map->l_serial;
+
+  /* Make sure nobody can unload the object while we are at it.  */
+  if (__builtin_expect (flags & DL_LOOKUP_GSCOPE_LOCK, 0))
+    {
+      /* We can't just call __rtld_lock_lock_recursive (GL(dl_load_lock))
+	 here, that can result in ABBA deadlock.  */
+      THREAD_GSCOPE_RESET_FLAG ();
+      __rtld_lock_lock_recursive (GL(dl_load_lock));
+      /* While MAP value won't change, after THREAD_GSCOPE_RESET_FLAG ()
+	 it can e.g. point to unallocated memory.  So avoid the optimizer
+	 treating the above read from MAP->l_serial as ensurance it
+	 can safely dereference it.  */
+      map = atomic_forced_read (map);
+
+      /* From this point on it is unsafe to dereference MAP, until it
+	 has been found in one of the lists.  */
+
+      /* Redo the l_initfini check in case undef_map's l_initfini
+	 changed in the mean time.  */
+      if (undef_map->l_initfini != l_initfini
+	  && undef_map->l_initfini != NULL)
+	{
+	  l_initfini = undef_map->l_initfini;
+	  for (i = 0; l_initfini[i] != NULL; ++i)
+	    if (l_initfini[i] == map)
+	      goto out_check;
+	}
+
+      /* Redo the l_reldeps check if undef_map's l_reldeps changed in
+	 the mean time.  */
+      if (undef_map->l_reldeps != NULL)
+	{
+	  if (undef_map->l_reldeps != l_reldeps)
+	    {
+	      struct link_map **list = &undef_map->l_reldeps->list[0];
+	      l_reldepsact = undef_map->l_reldeps->act;
+	      for (i = 0; i < l_reldepsact; ++i)
+		if (list[i] == map)
+		  goto out_check;
+	    }
+	  else if (undef_map->l_reldeps->act > l_reldepsact)
+	    {
+	      struct link_map **list
+		= &undef_map->l_reldeps->list[0];
+	      i = l_reldepsact;
+	      l_reldepsact = undef_map->l_reldeps->act;
+	      for (; i < l_reldepsact; ++i)
+		if (list[i] == map)
+		  goto out_check;
+	    }
+	}
+    }
+  else
+    __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+  /* The object is not yet in the dependency list.  Before we add
+     it make sure just one more time the object we are about to
+     reference is still available.  There is a brief period in
+     which the object could have been removed since we found the
+     definition.  */
+  runp = GL(dl_ns)[undef_map->l_ns]._ns_loaded;
+  while (runp != NULL && runp != map)
+    runp = runp->l_next;
+
+  if (runp != NULL)
+    {
+      /* The object is still available.  */
+
+      /* MAP could have been dlclosed, freed and then some other dlopened
+	 library could have the same link_map pointer.  */
+      if (map->l_serial != serial)
+	goto out_check;
+
+      /* Redo the NODELETE check, as when dl_load_lock wasn't held
+	 yet this could have changed.  */
+      if ((map->l_flags_1 & DF_1_NODELETE) != 0)
+	goto out;
+
+      /* If the object with the undefined reference cannot be removed ever
+	 just make sure the same is true for the object which contains the
+	 definition.  */
+      if (undef_map->l_type != lt_loaded
+	  || (undef_map->l_flags_1 & DF_1_NODELETE) != 0)
+	{
+	  map->l_flags_1 |= DF_1_NODELETE;
+	  goto out;
+	}
+
+      /* Add the reference now.  */
+      if (__builtin_expect (l_reldepsact >= undef_map->l_reldepsmax, 0))
+	{
+	  /* Allocate more memory for the dependency list.  Since this
+	     can never happen during the startup phase we can use
+	     `realloc'.  */
+	  struct link_map_reldeps *newp;
+	  unsigned int max
+	    = undef_map->l_reldepsmax ? undef_map->l_reldepsmax * 2 : 10;
+
+	  newp = malloc (sizeof (*newp) + max * sizeof (struct link_map *));
+	  if (newp == NULL)
+	    {
+	      /* If we didn't manage to allocate memory for the list this is
+		 no fatal problem.  We simply make sure the referenced object
+		 cannot be unloaded.  This is semantically the correct
+		 behav