Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f3d3a683f | |||
| 49621cbaa0 | |||
| 2054828fa8 | |||
| 4e339bc1ae | |||
| fe28e6e4e8 | |||
| 5036a533c6 | |||
| 4db348ac63 | |||
| 79b2b6d9f5 | |||
| 39c5f62ec2 | |||
|
|
7377a594e4 | ||
|
|
a513517459 | ||
| 145839b147 | |||
| 03ac74ede9 |
2
Makefile
2
Makefile
@@ -136,7 +136,7 @@ _SRC_TOP_OBJ_=
|
||||
# _SUBDIR is used to set SUBDIR, after removing directories that have
|
||||
# BUILD_${dir}=no, or that have no ${dir}/Makefile.
|
||||
#
|
||||
_SUBDIR= tools lib include gnu external crypto/external bin games
|
||||
_SUBDIR= tools lib include external crypto/external bin games
|
||||
_SUBDIR+= libexec sbin usr.bin
|
||||
_SUBDIR+= usr.sbin share sys etc tests compat
|
||||
_SUBDIR+= .WAIT rescue .WAIT distrib regress
|
||||
|
||||
17
README.md
Normal file
17
README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Build MINIX/arm with clang
|
||||
|
||||
It is now possible to build a full minix distribution for BeaglBone White/Black and BeagleBoardxM using clang instead of GCC.
|
||||
|
||||
This also add support to run the Kuya tests on ARM, which was not possible when GCC was used, because of problems in the C++ exception handling.
|
||||
|
||||
## Known Bugs
|
||||
|
||||
The following tests still fails:
|
||||
1. 53: Division by zero does not trigger exceptions
|
||||
2. 75: ru.tv_secs can't be zero (and is zero)
|
||||
3. 85: hangs
|
||||
4. isofs: Fails because of an out of memory condition
|
||||
5. vnd: crash
|
||||
6. Running two times the kyua tests in a row, without rebooting in between will lead to a mostly failed second run because of copy-on-write errors.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: cat.c,v 1.55 2015/07/25 16:17:01 sevan Exp $ */
|
||||
/* $NetBSD: cat.c,v 1.57 2016/06/16 00:52:37 sevan Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
@@ -44,7 +44,7 @@ __COPYRIGHT(
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: cat.c,v 1.55 2015/07/25 16:17:01 sevan Exp $");
|
||||
__RCSID("$NetBSD: cat.c,v 1.57 2016/06/16 00:52:37 sevan Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
@@ -113,6 +113,7 @@ main(int argc, char *argv[])
|
||||
vflag = 1;
|
||||
break;
|
||||
default:
|
||||
case '?':
|
||||
(void)fprintf(stderr,
|
||||
"Usage: %s [-beflnstuv] [-B bsize] [-] "
|
||||
"[file ...]\n", getprogname());
|
||||
@@ -174,18 +175,16 @@ cook_buf(FILE *fp)
|
||||
line = gobble = 0;
|
||||
for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
|
||||
if (prev == '\n') {
|
||||
if (ch == '\n') {
|
||||
if (sflag) {
|
||||
if (!gobble && nflag && !bflag)
|
||||
(void)fprintf(stdout,
|
||||
"%6d\t\n", ++line);
|
||||
else if (!gobble && putchar(ch) == EOF)
|
||||
break;
|
||||
if (sflag) {
|
||||
if (ch == '\n') {
|
||||
if (gobble)
|
||||
continue;
|
||||
gobble = 1;
|
||||
continue;
|
||||
} else
|
||||
gobble = 0;
|
||||
}
|
||||
if (nflag) {
|
||||
if (!bflag) {
|
||||
if (!bflag || ch != '\n') {
|
||||
(void)fprintf(stdout,
|
||||
"%6d\t", ++line);
|
||||
if (ferror(stdout))
|
||||
@@ -197,13 +196,7 @@ cook_buf(FILE *fp)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (nflag) {
|
||||
(void)fprintf(stdout, "%6d\t", ++line);
|
||||
if (ferror(stdout))
|
||||
break;
|
||||
}
|
||||
}
|
||||
gobble = 0;
|
||||
if (ch == '\n') {
|
||||
if (eflag)
|
||||
if (putchar('$') == EOF)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: chmod.1,v 1.25 2013/12/17 09:54:08 apb Exp $
|
||||
.\" $NetBSD: chmod.1,v 1.26 2016/08/11 00:10:42 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1989, 1990, 1993, 1994
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)chmod.1 8.4 (Berkeley) 3/31/94
|
||||
.\"
|
||||
.Dd October 22, 2012
|
||||
.Dd August 11, 2016
|
||||
.Dt CHMOD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -304,6 +304,11 @@ compatible with the exception of the
|
||||
symbol
|
||||
.Dq t
|
||||
which is not included in that standard.
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v1 .
|
||||
.Sh BUGS
|
||||
There's no
|
||||
.Ar perm
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: cp.1,v 1.44 2015/06/28 16:22:54 wiz Exp $
|
||||
.\" $NetBSD: cp.1,v 1.45 2016/08/11 00:17:23 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1989, 1990, 1993, 1994
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)cp.1 8.3 (Berkeley) 4/18/94
|
||||
.\"
|
||||
.Dd March 25, 2012
|
||||
.Dd August 11, 2016
|
||||
.Dt CP 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -255,3 +255,8 @@ The
|
||||
.Fl v
|
||||
option is an extension to
|
||||
.St -p1003.2 .
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v1 .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: csh.1,v 1.52 2013/01/22 21:20:26 wiz Exp $
|
||||
.\" $NetBSD: csh.1,v 1.53 2016/08/10 17:16:47 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" @(#)csh.1 8.2 (Berkeley) 1/21/94
|
||||
.\"
|
||||
.Dd January 22, 2013
|
||||
.Dd August 8, 2016
|
||||
.Dt CSH 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -2233,7 +2233,7 @@ substitutions on a single line to 20.
|
||||
.Sh HISTORY
|
||||
.Nm
|
||||
appeared in
|
||||
.Bx 3 .
|
||||
.Bx 2 .
|
||||
It was a first implementation of a command language interpreter
|
||||
incorporating a history mechanism (see
|
||||
.Sx History substitutions ) ,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: date.1,v 1.42 2012/04/06 11:36:56 wiz Exp $
|
||||
.\" $NetBSD: date.1,v 1.44 2017/01/03 16:01:05 abhinav Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)date.1 8.3 (Berkeley) 4/28/95
|
||||
.\"
|
||||
.Dd November 15, 2006
|
||||
.Dd August 11, 2016
|
||||
.Dt DATE 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -148,7 +148,7 @@ The hour of the day, from 00 to 23.
|
||||
.It Ar MM
|
||||
The minute of the hour, from 00 to 59.
|
||||
.It Ar SS
|
||||
The second of the minute, from 00 to 61.
|
||||
The second of the minute, from 00 to 60.
|
||||
.El
|
||||
.Pp
|
||||
Everything but the minutes is optional.
|
||||
@@ -244,3 +244,8 @@ The
|
||||
.Nm
|
||||
utility is expected to be compatible with
|
||||
.St -p1003.2 .
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v1 .
|
||||
|
||||
12
bin/dd/dd.1
12
bin/dd/dd.1
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: dd.1,v 1.27 2015/03/18 13:30:13 wiz Exp $
|
||||
.\" $NetBSD: dd.1,v 1.32 2016/08/18 22:43:49 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)dd.1 8.2 (Berkeley) 1/13/94
|
||||
.\"
|
||||
.Dd March 18, 2015
|
||||
.Dd August 18, 2016
|
||||
.Dt DD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -209,7 +209,7 @@ in order to output to a nonexistent file.
|
||||
The default or specified value is or'ed with
|
||||
.Va rdwr
|
||||
for a first
|
||||
.Xt open 2
|
||||
.Xr open 2
|
||||
attempt, then on failure with
|
||||
.Va wronly
|
||||
on a second attempt.
|
||||
@@ -486,7 +486,6 @@ To print summary information in human-readable form:
|
||||
.Pp
|
||||
To customize the information summary output and print it through
|
||||
.Xr unvis 3 :
|
||||
.Pp
|
||||
.Bd -literal -offset indent
|
||||
dd if=/dev/zero of=/dev/null count=1 \e
|
||||
msgfmt='speed:%E, in %s seconds\en' 2\*[Gt]\*[Am]1 | unvis
|
||||
@@ -516,3 +515,8 @@ and
|
||||
values are extensions to the
|
||||
.Tn POSIX
|
||||
standard.
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v5 .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: df.1,v 1.44 2010/04/05 21:17:28 joerg Exp $
|
||||
.\" $NetBSD: df.1,v 1.46 2016/08/10 23:48:14 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1989, 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" @(#)df.1 8.2 (Berkeley) 1/13/92
|
||||
.\"
|
||||
.Dd March 4, 2008
|
||||
.Dd August 10, 2016
|
||||
.Dt DF 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -203,4 +203,4 @@ size block.
|
||||
A
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v6 .
|
||||
.At v1 .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: echo.1,v 1.13 2003/08/07 09:05:12 agc Exp $
|
||||
.\" $NetBSD: echo.1,v 1.15 2016/08/14 22:59:22 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)echo.1 8.1 (Berkeley) 7/22/93
|
||||
.\"
|
||||
.Dd July 22, 1993
|
||||
.Dd August 14, 2016
|
||||
.Dt ECHO 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -66,3 +66,8 @@ The
|
||||
utility is expected to be
|
||||
.St -p1003.2
|
||||
compatible.
|
||||
.Sh HISTORY
|
||||
An
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v2 .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: expr.1,v 1.33 2012/08/12 17:27:04 wiz Exp $
|
||||
.\" $NetBSD: expr.1,v 1.36 2016/08/23 20:34:23 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2000,2003 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
@@ -27,7 +27,7 @@
|
||||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd April 20, 2004
|
||||
.Dd August 23, 2016
|
||||
.Dt EXPR 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -214,7 +214,7 @@ treat it as a delimiter to mark the end of command
|
||||
line options, and ignore it.
|
||||
Some
|
||||
.Nm
|
||||
implementations don't recognize it at all; others
|
||||
implementations do not recognize it at all; others
|
||||
might ignore it even in cases where doing so results in syntax
|
||||
error.
|
||||
There should be same result for both following examples,
|
||||
@@ -242,15 +242,28 @@ The
|
||||
.Ar length
|
||||
keyword is an extension for compatibility with GNU
|
||||
.Nm .
|
||||
.Sh HISTORY
|
||||
An
|
||||
.Nm
|
||||
utility first appeared in the Programmer's Workbench (PWB/UNIX).
|
||||
A public domain version of
|
||||
.Nm
|
||||
written by
|
||||
.An Pace Willisson
|
||||
.Aq pace@blitz.com
|
||||
appeared in
|
||||
.Bx 386 0.1 .
|
||||
.Sh AUTHORS
|
||||
Original implementation was written by
|
||||
.An J.T. Conklin
|
||||
.Aq jtc@NetBSD.org .
|
||||
It was rewritten for
|
||||
Initial implementation by
|
||||
.An Pace Willisson Aq Mt pace@blitz.com
|
||||
was largely rewritten by
|
||||
.An -nosplit
|
||||
.An J.T. Conklin Aq Mt jtc@NetBSD.org .
|
||||
It was rewritten again for
|
||||
.Nx 1.6
|
||||
by
|
||||
.An Jaromir Dolecek
|
||||
.Aq jdolecek@NetBSD.org .
|
||||
.An -nosplit
|
||||
.An Jaromir Dolecek Aq Mt jdolecek@NetBSD.org .
|
||||
.Sh NOTES
|
||||
The empty string
|
||||
.Do Dc
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: kill.1,v 1.22 2012/03/22 07:58:17 wiz Exp $
|
||||
.\" $NetBSD: kill.1,v 1.28 2017/04/22 23:01:36 christos Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)kill.1 8.2 (Berkeley) 4/28/95
|
||||
.\"
|
||||
.Dd April 28, 1995
|
||||
.Dd April 22, 2017
|
||||
.Dt KILL 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -63,7 +63,6 @@ by the pid operand(s).
|
||||
Only the super-user may send signals to other users' processes.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Pp
|
||||
.Bl -tag -width Ds
|
||||
.It Fl s Ar signal_name
|
||||
A symbolic signal name specifying the signal to be sent instead of the
|
||||
@@ -104,6 +103,9 @@ belonging to the user.
|
||||
.Pp
|
||||
Some of the more commonly used signals:
|
||||
.Bl -tag -width Ds -compact
|
||||
.It 0
|
||||
0 (does not affect the process; can be used to test whether the
|
||||
process exists)
|
||||
.It 1
|
||||
HUP (hang up)
|
||||
.It 2
|
||||
@@ -130,6 +132,8 @@ arguments.
|
||||
See
|
||||
.Xr csh 1
|
||||
for details.
|
||||
.Sh DIAGNOSTICS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr csh 1 ,
|
||||
.Xr pgrep 1 ,
|
||||
@@ -141,11 +145,12 @@ for details.
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
function is expected to be
|
||||
utility is expected to be
|
||||
.St -p1003.2
|
||||
compatible.
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
command appeared in
|
||||
.At v6 .
|
||||
.At v3
|
||||
in section 8 of the manual.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: ls.1,v 1.78 2014/10/18 01:49:01 jschauma Exp $
|
||||
.\" $NetBSD: ls.1,v 1.79 2016/08/10 17:45:12 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1990, 1991, 1993, 1994
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)ls.1 8.7 (Berkeley) 7/29/94
|
||||
.\"
|
||||
.Dd October 17, 2014
|
||||
.Dd August 10, 2016
|
||||
.Dt LS 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -513,4 +513,4 @@ specification.
|
||||
An
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v5 .
|
||||
.At v1 .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: mkdir.1,v 1.17 2012/03/22 07:58:17 wiz Exp $
|
||||
.\" $NetBSD: mkdir.1,v 1.19 2016/08/10 18:42:00 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1989, 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)mkdir.1 8.2 (Berkeley) 1/25/94
|
||||
.\"
|
||||
.Dd January 25, 1994
|
||||
.Dd August 10, 2016
|
||||
.Dt MKDIR 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -92,3 +92,8 @@ The
|
||||
utility is expected to be
|
||||
.St -p1003.2
|
||||
compatible.
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v1 .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: mv.1,v 1.26 2012/03/22 07:58:17 wiz Exp $
|
||||
.\" $NetBSD: mv.1,v 1.28 2016/08/10 18:08:14 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1989, 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)mv.1 8.1 (Berkeley) 5/31/93
|
||||
.\"
|
||||
.Dd December 26, 2002
|
||||
.Dd August 10, 2016
|
||||
.Dt MV 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -144,3 +144,8 @@ The
|
||||
.Fl v
|
||||
option is an extension to
|
||||
.St -p1003.2 .
|
||||
.Sh HISTORY
|
||||
An
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v1 .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: cpio.1,v 1.13 2011/06/19 07:34:24 wiz Exp $
|
||||
.\" $NetBSD: cpio.1,v 1.14 2015/12/19 18:48:33 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997 SigmaSoft, Th. Lockert
|
||||
.\" All rights reserved.
|
||||
@@ -297,7 +297,8 @@ specific archive format specification.
|
||||
.Xr pax 1 ,
|
||||
.Xr tar 1
|
||||
.Sh AUTHORS
|
||||
Keith Muller at the University of California, San Diego.
|
||||
.An Keith Muller
|
||||
at the University of California, San Diego.
|
||||
.Sh BUGS
|
||||
The
|
||||
.Fl s
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: pwd.1,v 1.24 2003/10/30 14:58:23 wiz Exp $
|
||||
.\" $NetBSD: pwd.1,v 1.25 2016/08/12 02:03:26 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)pwd.1 8.2 (Berkeley) 4/28/95
|
||||
.\"
|
||||
.Dd October 30, 2003
|
||||
.Dd August 12, 2016
|
||||
.Dt PWD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -87,6 +87,11 @@ except that the default is
|
||||
.Fl P
|
||||
not
|
||||
.Fl L .
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v5 .
|
||||
.Sh BUGS
|
||||
In
|
||||
.Xr csh 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: rm.1,v 1.27 2013/04/26 19:34:34 wiz Exp $
|
||||
.\" $NetBSD: rm.1,v 1.28 2016/08/12 02:26:42 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993, 1994, 2003
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)rm.1 8.5 (Berkeley) 12/5/94
|
||||
.\"
|
||||
.Dd April 26, 2013
|
||||
.Dd August 12, 2016
|
||||
.Dt RM 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -190,6 +190,11 @@ magnetic disk.
|
||||
.Em Because these requirements are not met, the
|
||||
.Fl P
|
||||
.Em option does not conform to the standard .
|
||||
.Sh HISTORY
|
||||
An
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v1 .
|
||||
.Sh BUGS
|
||||
The
|
||||
.Fl P
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: rmdir.1,v 1.15 2003/08/07 09:05:29 agc Exp $
|
||||
.\" $NetBSD: rmdir.1,v 1.16 2016/08/12 02:30:37 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)rmdir.1 8.1 (Berkeley) 5/31/93
|
||||
.\"
|
||||
.Dd May 31, 1993
|
||||
.Dd August 12, 2016
|
||||
.Dt RMDIR 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -88,3 +88,8 @@ The
|
||||
utility is expected to be
|
||||
.St -p1003.2
|
||||
compatible.
|
||||
.Sh HISTORY
|
||||
An
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v1 .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: sleep.1,v 1.22 2011/08/15 14:45:36 wiz Exp $
|
||||
.\" $NetBSD: sleep.1,v 1.23 2016/08/12 02:36:38 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993, 1994
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)sleep.1 8.3 (Berkeley) 4/18/94
|
||||
.\"
|
||||
.Dd August 13, 2011
|
||||
.Dd August 12, 2016
|
||||
.Dt SLEEP 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -121,3 +121,8 @@ The
|
||||
command is expected to be
|
||||
.St -p1003.2
|
||||
compatible.
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v4 .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: stty.1,v 1.41 2012/06/20 14:19:39 wiz Exp $
|
||||
.\" $NetBSD: stty.1,v 1.43 2016/08/14 23:29:43 sevan Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993, 1994
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" @(#)stty.1 8.5 (Berkeley) 6/1/94
|
||||
.\"
|
||||
.Dd June 16, 2012
|
||||
.Dd August 15, 2016
|
||||
.Dt STTY 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -633,3 +633,8 @@ and
|
||||
flags are
|
||||
extensions to the standard, as are the operands mentioned in the control
|
||||
operations section.
|
||||
.Sh HISTORY
|
||||
An
|
||||
.Nm
|
||||
utility appeared in
|
||||
.At v2 .
|
||||
|
||||
@@ -81,6 +81,9 @@
|
||||
./usr/include/arm/vm.h minix-comp
|
||||
./usr/include/arm/vmparam.h minix-comp
|
||||
./usr/include/arm/wchar_limits.h minix-comp
|
||||
./usr/include/clang-3.6/arm_acle.h minix-comp llvm,llvmcmds
|
||||
./usr/include/clang-3.6/arm_neon.h minix-comp llvm,llvmcmds
|
||||
./usr/include/clang-3.6/stdatomic.h minix-comp llvm,llvmcmds
|
||||
./usr/include/evbarm minix-comp
|
||||
./usr/include/evbarm/disklabel.h minix-comp
|
||||
./usr/include/evbarm/intr.h minix-comp
|
||||
|
||||
2
external/Makefile
vendored
2
external/Makefile
vendored
@@ -1,6 +1,6 @@
|
||||
# $NetBSD: Makefile,v 1.18 2012/06/14 04:14:36 riz Exp $
|
||||
#MINIX
|
||||
SUBDIR+= bsd gpl3 historical
|
||||
SUBDIR+= bsd historical
|
||||
SUBDIR+= mit public-domain
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
||||
4
external/bsd/bind/bin/named/Makefile
vendored
4
external/bsd/bind/bin/named/Makefile
vendored
@@ -7,6 +7,10 @@ MAN= named.8 lwresd.8 named.conf.5
|
||||
BINDIR= /usr/sbin
|
||||
LINKS= ${BINDIR}/named ${BINDIR}/lwresd
|
||||
|
||||
.if defined(__MINIX)
|
||||
CWARNFLAGS.gcc+= -Wno-maybe-uninitialized
|
||||
.endif # defined(__MINIX)
|
||||
|
||||
.include "${.CURDIR}/../Makefile.inc"
|
||||
|
||||
DIST=${IDIST}/bin/named
|
||||
|
||||
6
external/bsd/bind/dist/lib/lwres/lwconfig.c
vendored
6
external/bsd/bind/dist/lib/lwres/lwconfig.c
vendored
@@ -606,15 +606,21 @@ lwres_conf_parse(lwres_context_t *ctx, const char *filename) {
|
||||
FILE *fp = NULL;
|
||||
char word[256];
|
||||
lwres_result_t rval, ret;
|
||||
#if !defined(NDEBUG) && defined(__minix)
|
||||
lwres_conf_t *confdata;
|
||||
#endif /* !defined(NDEBUG) && defined(__minix) */
|
||||
int stopchar;
|
||||
|
||||
REQUIRE(ctx != NULL);
|
||||
#if !defined(NDEBUG) && defined(__minix)
|
||||
confdata = &ctx->confdata;
|
||||
#endif /* !defined(NDEBUG) && defined(__minix) */
|
||||
|
||||
REQUIRE(filename != NULL);
|
||||
REQUIRE(strlen(filename) > 0U);
|
||||
#if !defined(NDEBUG) && defined(__minix)
|
||||
REQUIRE(confdata != NULL);
|
||||
#endif /* !defined(NDEBUG) && defined(__minix) */
|
||||
|
||||
errno = 0;
|
||||
if ((fp = fopen(filename, "r")) == NULL)
|
||||
|
||||
5
external/bsd/bind/lib/libdns/Makefile
vendored
5
external/bsd/bind/lib/libdns/Makefile
vendored
@@ -7,6 +7,11 @@ LIB=dns
|
||||
|
||||
.include "${.CURDIR}/../Makefile.inc"
|
||||
|
||||
.if defined(__MINIX)
|
||||
#LSC: -Wno-maybe-uninitialized while compiling with -DNDEBUG -Os
|
||||
CWARNFLAGS.gcc+= -Wno-maybe-uninitialized
|
||||
.endif # defined(__MINIX)
|
||||
|
||||
DIST= ${IDIST}/lib/dns
|
||||
.include "${DIST}/api"
|
||||
.include "${DIST}/mapapi"
|
||||
|
||||
5
external/bsd/bind/lib/libisc/Makefile
vendored
5
external/bsd/bind/lib/libisc/Makefile
vendored
@@ -5,6 +5,11 @@ LIB=isc
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
.if defined(__MINIX)
|
||||
#LSC: -Wno-maybe-uninitialized while compiling with -DNDEBUG -Os
|
||||
CWARNFLAGS.gcc+= -Wno-maybe-uninitialized
|
||||
.endif # defined(__MINIX)
|
||||
|
||||
.include "${.CURDIR}/../Makefile.inc"
|
||||
|
||||
DIST= ${IDIST}/lib/isc
|
||||
|
||||
8
external/bsd/dhcp/lib/common/Makefile
vendored
8
external/bsd/dhcp/lib/common/Makefile
vendored
@@ -12,3 +12,11 @@ MAN = dhcp-options.5 dhcp-eval.5
|
||||
DHCPSRCDIR= common
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
|
||||
.if defined(__MINIX)
|
||||
.if !empty(DBG:M-Og) || !empty(CFLAGS:M-Og) || \
|
||||
!empty(DBG:M-g) || !empty(CFLAGS:M-g)
|
||||
#LSC: -Wno-maybe-uninitialized while compiling with -DNDEBUG -Og
|
||||
CWARNFLAGS.gcc+= -Wno-maybe-uninitialized
|
||||
.endif
|
||||
.endif # defined(__MINIX)
|
||||
|
||||
4
external/bsd/dhcpcd/sbin/dhcpcd/Makefile
vendored
4
external/bsd/dhcpcd/sbin/dhcpcd/Makefile
vendored
@@ -14,6 +14,10 @@ CPPFLAGS+= -DHAVE_CONFIG_H
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
.if defined(__MINIX)
|
||||
CWARNFLAGS.gcc+= -Wno-maybe-uninitialized
|
||||
.endif # defined(__MINIX)
|
||||
|
||||
SRCS+= auth.c hmac_md5.c
|
||||
|
||||
USE_INET?= yes
|
||||
|
||||
@@ -3816,6 +3816,7 @@ class ARMTargetInfo : public TargetInfo {
|
||||
SizeType = UnsignedInt;
|
||||
|
||||
switch (T.getOS()) {
|
||||
case llvm::Triple::Minix:
|
||||
case llvm::Triple::NetBSD:
|
||||
WCharType = SignedInt;
|
||||
break;
|
||||
|
||||
@@ -275,7 +275,7 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
|
||||
// FIXME: Thumb should just be another -target-feaure, not in the triple.
|
||||
#if defined(__minix) || 1
|
||||
// Minix/ARM-specific force to ARMv7 and EABI.
|
||||
StringRef Suffix = "v7";
|
||||
StringRef Suffix = "v7a";
|
||||
Triple.setEnvironment(llvm::Triple::EABI);
|
||||
#else
|
||||
StringRef Suffix = Triple.isOSBinFormatMachO()
|
||||
|
||||
@@ -665,6 +665,10 @@ StringRef tools::arm::getARMFloatABI(const Driver &D, const ArgList &Args,
|
||||
}
|
||||
break;
|
||||
|
||||
case llvm::Triple::Minix:
|
||||
FloatABI = "softfp";
|
||||
break;
|
||||
|
||||
default:
|
||||
switch(Triple.getEnvironment()) {
|
||||
case llvm::Triple::GNUEABIHF:
|
||||
@@ -796,6 +800,9 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
|
||||
ABIName = "aapcs";
|
||||
break;
|
||||
default:
|
||||
if (Triple.getOS() == llvm::Triple::Minix)
|
||||
ABIName = "apcs-gnu";
|
||||
|
||||
if (Triple.getOS() == llvm::Triple::NetBSD)
|
||||
ABIName = "apcs-gnu";
|
||||
else
|
||||
@@ -7733,6 +7740,11 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
// Many NetBSD architectures support more than one ABI.
|
||||
// Determine the correct emulation for ld.
|
||||
switch (getToolChain().getArch()) {
|
||||
case llvm::Triple::arm:
|
||||
case llvm::Triple::thumb:
|
||||
CmdArgs.push_back("-m");
|
||||
CmdArgs.push_back("armelf_minix");
|
||||
break;
|
||||
case llvm::Triple::x86:
|
||||
CmdArgs.push_back("-m");
|
||||
CmdArgs.push_back("elf_i386_minix");
|
||||
|
||||
@@ -638,6 +638,8 @@ llvm::Optional<ProgramStateRef> MallocChecker::performKernelMalloc(
|
||||
if (!KernelZeroFlagVal.hasValue()) {
|
||||
if (OS == llvm::Triple::FreeBSD)
|
||||
KernelZeroFlagVal = 0x0100;
|
||||
else if (OS == llvm::Triple::Minix)
|
||||
KernelZeroFlagVal = 0x0002;
|
||||
else if (OS == llvm::Triple::NetBSD)
|
||||
KernelZeroFlagVal = 0x0002;
|
||||
else if (OS == llvm::Triple::OpenBSD)
|
||||
|
||||
4
external/bsd/llvm/dist/lld/.arcconfig
vendored
4
external/bsd/llvm/dist/lld/.arcconfig
vendored
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"project_id" : "lld",
|
||||
"conduit_uri" : "http://llvm-reviews.chandlerc.com/"
|
||||
}
|
||||
169
external/bsd/llvm/dist/lld/CMakeLists.txt
vendored
169
external/bsd/llvm/dist/lld/CMakeLists.txt
vendored
@@ -1,169 +0,0 @@
|
||||
# If we are not building as a part of LLVM, build lld as a standalone project,
|
||||
# using LLVM as an external library.
|
||||
|
||||
|
||||
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
project(lld)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(LLD_PATH_TO_LLVM_SOURCE "" CACHE PATH
|
||||
"Path to LLVM source code. Not necessary if using an installed LLVM.")
|
||||
set(LLD_PATH_TO_LLVM_BUILD "" CACHE PATH
|
||||
"Path to the directory where LLVM was built or installed.")
|
||||
|
||||
if (LLD_PATH_TO_LLVM_SOURCE)
|
||||
if (NOT EXISTS "${LLD_PATH_TO_LLVM_SOURCE}/cmake/config-ix.cmake")
|
||||
message(FATAL_ERROR "Please set LLD_PATH_TO_LLVM_SOURCE to the root "
|
||||
"directory of LLVM source code.")
|
||||
else()
|
||||
get_filename_component(LLVM_MAIN_SRC_DIR ${LLD_PATH_TO_LLVM_SOURCE}
|
||||
ABSOLUTE)
|
||||
list(APPEND CMAKE_MODULE_PATH "${LLVM_MAIN_SRC_DIR}/cmake/modules")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${LLD_PATH_TO_LLVM_BUILD}/share/llvm/cmake")
|
||||
|
||||
get_filename_component(PATH_TO_LLVM_BUILD ${LLD_PATH_TO_LLVM_BUILD}
|
||||
ABSOLUTE)
|
||||
|
||||
option(LLVM_INSTALL_TOOLCHAIN_ONLY
|
||||
"Only include toolchain files in the 'install' target." OFF)
|
||||
|
||||
include(AddLLVM)
|
||||
include(TableGen)
|
||||
include("${LLD_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVMConfig.cmake")
|
||||
include(HandleLLVMOptions)
|
||||
|
||||
set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
|
||||
|
||||
set(LLVM_MAIN_INCLUDE_DIR "${LLVM_MAIN_SRC_DIR}/include")
|
||||
set(LLVM_BINARY_DIR ${CMAKE_BINARY_DIR})
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
include_directories("${PATH_TO_LLVM_BUILD}/include"
|
||||
"${LLVM_MAIN_INCLUDE_DIR}")
|
||||
link_directories("${PATH_TO_LLVM_BUILD}/lib")
|
||||
|
||||
if (EXISTS "${LLD_PATH_TO_LLVM_BUILD}/bin/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
set (PATH_TO_LLVM_CONFIG "${LLD_PATH_TO_LLVM_BUILD}/bin/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
elseif (EXISTS "${LLD_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
# FIXME: This is an utter hack.
|
||||
set (PATH_TO_LLVM_CONFIG "${LLD_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
else()
|
||||
message(FATAL_ERROR "Please set LLD_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
|
||||
endif()
|
||||
|
||||
exec_program("${PATH_TO_LLVM_CONFIG} --bindir" OUTPUT_VARIABLE LLVM_BINARY_DIR)
|
||||
set(LLVM_TABLEGEN_EXE "${LLVM_BINARY_DIR}/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
|
||||
set(LLD_BUILT_STANDALONE 1)
|
||||
endif()
|
||||
|
||||
set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(LLD_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
||||
message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite "
|
||||
"the makefiles distributed with LLVM. Please create a directory and run cmake "
|
||||
"from there, passing the path to this source directory as the last argument. "
|
||||
"This process created the file `CMakeCache.txt' and the directory "
|
||||
"`CMakeFiles'. Please delete them.")
|
||||
endif()
|
||||
|
||||
list (APPEND CMAKE_MODULE_PATH "${LLD_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
option(LLD_USE_VTUNE
|
||||
"Enable VTune user task tracking."
|
||||
OFF)
|
||||
if (LLD_USE_VTUNE)
|
||||
find_package(VTune)
|
||||
if (VTUNE_FOUND)
|
||||
include_directories(${VTune_INCLUDE_DIRS})
|
||||
list(APPEND LLVM_COMMON_LIBS ${VTune_LIBRARIES})
|
||||
add_definitions(-DLLD_HAS_VTUNE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# lld requires c++11 to build. Make sure that we have a compiler and standard
|
||||
# library combination that can do that.
|
||||
if (NOT MSVC)
|
||||
# gcc and clang require the -std=c++0x or -std=c++11 flag.
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang" AND
|
||||
NOT ("${CMAKE_CXX_FLAGS}" MATCHES ".*-std=(c|gnu)\\+\\+(0x|11).*"))
|
||||
message(FATAL_ERROR
|
||||
"lld requires c++11. Clang and gcc require -std=c++0x or -std=c++11 to "
|
||||
"enter this mode. Please set CMAKE_CXX_FLAGS accordingly.")
|
||||
endif()
|
||||
elseif (MSVC_VERSION LESS 1700)
|
||||
message(FATAL_ERROR "The selected compiler does not support c++11 which is "
|
||||
"required to build lld.")
|
||||
endif()
|
||||
|
||||
macro(add_lld_library name)
|
||||
llvm_process_sources(srcs ${ARGN})
|
||||
if (MSVC_IDE OR XCODE)
|
||||
string(REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list(GET split_path -1 dir)
|
||||
file(GLOB_RECURSE headers
|
||||
../../include/lld${dir}/*.h)
|
||||
set(srcs ${srcs} ${headers})
|
||||
endif()
|
||||
if (MODULE)
|
||||
set(libkind MODULE)
|
||||
elseif (SHARED_LIBRARY)
|
||||
set(libkind SHARED)
|
||||
else()
|
||||
set(libkind)
|
||||
endif()
|
||||
add_library(${name} ${libkind} ${srcs})
|
||||
if (LLVM_COMMON_DEPENDS)
|
||||
add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${name} ${LLVM_USED_LIBS})
|
||||
llvm_config(${name} ${LLVM_LINK_COMPONENTS})
|
||||
target_link_libraries(${name} ${LLVM_COMMON_LIBS})
|
||||
link_system_libs(${name})
|
||||
|
||||
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
|
||||
install(TARGETS ${name}
|
||||
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX})
|
||||
endif()
|
||||
set_target_properties(${name} PROPERTIES FOLDER "lld libraries")
|
||||
endmacro(add_lld_library)
|
||||
|
||||
macro(add_lld_executable name)
|
||||
add_llvm_executable(${name} ${ARGN})
|
||||
set_target_properties(${name} PROPERTIES FOLDER "lld executables")
|
||||
endmacro(add_lld_executable)
|
||||
|
||||
include_directories(BEFORE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
|
||||
install(DIRECTORY include/
|
||||
DESTINATION include
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h"
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
endif()
|
||||
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(utils)
|
||||
|
||||
add_subdirectory(test)
|
||||
|
||||
if (LLVM_INCLUDE_TESTS AND NOT LLD_BUILT_STANDALONE)
|
||||
add_subdirectory(unittests)
|
||||
endif()
|
||||
62
external/bsd/llvm/dist/lld/LICENSE.TXT
vendored
62
external/bsd/llvm/dist/lld/LICENSE.TXT
vendored
@@ -1,62 +0,0 @@
|
||||
==============================================================================
|
||||
lld License
|
||||
==============================================================================
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2011-2013 by the contributors listed in CREDITS.TXT
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLVM Team
|
||||
|
||||
University of Illinois at Urbana-Champaign
|
||||
|
||||
http://llvm.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLVM Team, University of Illinois at
|
||||
Urbana-Champaign, nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this Software without specific
|
||||
prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
The lld software contains code written by third parties. Such software will
|
||||
have its own individual LICENSE.TXT file in the directory in which it appears.
|
||||
This file will describe the copyrights, license, and restrictions which apply
|
||||
to that code.
|
||||
|
||||
The disclaimer of warranty in the University of Illinois Open Source License
|
||||
applies to all code in the lld Distribution, and nothing in any of the
|
||||
other licenses gives permission to use the names of the LLVM Team or the
|
||||
University of Illinois to endorse or promote products derived from this
|
||||
Software.
|
||||
|
||||
The following pieces of software have additional or alternate copyrights,
|
||||
licenses, and/or restrictions:
|
||||
|
||||
Program Directory
|
||||
------- ---------
|
||||
<none yet>
|
||||
10
external/bsd/llvm/dist/lld/README.md
vendored
10
external/bsd/llvm/dist/lld/README.md
vendored
@@ -1,10 +0,0 @@
|
||||
|
||||
LLVM Linker (lld)
|
||||
==============================
|
||||
|
||||
This directory and its subdirectories contain source code for the LLVM Linker, a
|
||||
modular cross platform linker which is built as part of the LLVM compiler
|
||||
infrastructure project.
|
||||
|
||||
lld is open source software. You may freely distribute it under the terms of
|
||||
the license agreement found in LICENSE.txt.
|
||||
@@ -1,31 +0,0 @@
|
||||
# - Find VTune ittnotify.
|
||||
# Defines:
|
||||
# VTune_FOUND
|
||||
# VTune_INCLUDE_DIRS
|
||||
# VTune_LIBRARIES
|
||||
|
||||
set(dirs
|
||||
"$ENV{VTUNE_AMPLIFIER_XE_2013_DIR}/"
|
||||
"C:/Program Files (x86)/Intel/VTune Amplifier XE 2013/"
|
||||
"$ENV{VTUNE_AMPLIFIER_XE_2011_DIR}/"
|
||||
"C:/Program Files (x86)/Intel/VTune Amplifier XE 2011/"
|
||||
)
|
||||
|
||||
find_path(VTune_INCLUDE_DIRS ittnotify.h
|
||||
PATHS ${dirs}
|
||||
PATH_SUFFIXES include)
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
set(vtune_lib_dir lib64)
|
||||
else()
|
||||
set(vtune_lib_dir lib32)
|
||||
endif()
|
||||
|
||||
find_library(VTune_LIBRARIES libittnotify
|
||||
HINTS "${VTune_INCLUDE_DIRS}/.."
|
||||
PATHS ${dirs}
|
||||
PATH_SUFFIXES ${vtune_lib_dir})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(
|
||||
VTune DEFAULT_MSG VTune_LIBRARIES VTune_INCLUDE_DIRS)
|
||||
35
external/bsd/llvm/dist/lld/docs/C++11.rst
vendored
35
external/bsd/llvm/dist/lld/docs/C++11.rst
vendored
@@ -1,35 +0,0 @@
|
||||
C++11
|
||||
=====
|
||||
|
||||
lld is developed in a limited subset of C++11. Supported compilers are:
|
||||
|
||||
* Clang 3.1+
|
||||
* g++ 4.6+
|
||||
* MSVC 2012+
|
||||
|
||||
Allowed Features
|
||||
----------------
|
||||
|
||||
Allowed features are based on what these compilers support. Features that are ok
|
||||
to omit (such as final or = delete) may be conditionally used via macros.
|
||||
|
||||
* All of the C++11 standard library, including threading and atomics
|
||||
* auto
|
||||
* constexpr via LLVM_CONSTEXPR
|
||||
* decltype
|
||||
* deleted functions via LLVM_DELETED_FUNCTION
|
||||
* Forward enum declarations
|
||||
* Lambdas
|
||||
* Local and unnamed types as template args
|
||||
* Trailing return type
|
||||
* nullptr
|
||||
* >> instead of > >
|
||||
* R-Value references excluding R-Value references for this
|
||||
* static_assert
|
||||
* Strongly typed enums
|
||||
* Range based for loop
|
||||
* final via LLVM_FINAL
|
||||
|
||||
Note that some of these features may not be fully or correctly implemented in
|
||||
all compilers. Issues using these features should be added here as they are
|
||||
encountered.
|
||||
79
external/bsd/llvm/dist/lld/docs/Driver.rst
vendored
79
external/bsd/llvm/dist/lld/docs/Driver.rst
vendored
@@ -1,79 +0,0 @@
|
||||
======
|
||||
Driver
|
||||
======
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This document describes the lld driver. The purpose of this document is to
|
||||
describe both the motivation and design goals for the driver, as well as details
|
||||
of the internal implementation.
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
The lld driver is designed to support a number of different command line
|
||||
interfaces. The main interfaces we plan to support are binutils' ld, Apple's
|
||||
ld, and Microsoft's link.exe.
|
||||
|
||||
Flavors
|
||||
-------
|
||||
|
||||
Each of these different interfaces is referred to as a flavor. There is also an
|
||||
extra flavor "core" which is used to exercise the core functionality of the
|
||||
linker it the test suite.
|
||||
|
||||
* gnu
|
||||
* darwin
|
||||
* link
|
||||
* core
|
||||
|
||||
Selecting a Flavor
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are two different ways to tell lld which flavor to be. They are checked in
|
||||
order, so the second overrides the first. The first is to symlink :program:`lld`
|
||||
as :program:`lld-{flavor}` or just :program:`{flavor}`. You can also specify
|
||||
it as the first command line argument using ``-flavor``::
|
||||
|
||||
$ lld -flavor gnu
|
||||
|
||||
There is a shortcut for ``-flavor core`` as ``-core``.
|
||||
|
||||
|
||||
Adding an Option to an existing Flavor
|
||||
======================================
|
||||
|
||||
#. Add the option to the desired :file:`lib/Driver/{flavor}Options.td`.
|
||||
|
||||
#. Add to :cpp:class:`lld::FlavorLinkingContext` a getter and setter method
|
||||
for the option.
|
||||
|
||||
#. Modify :cpp:func:`lld::FlavorDriver::parse` in :file:
|
||||
`lib/Driver/{Flavor}Driver.cpp` to call the targetInfo setter
|
||||
for corresponding to the option.
|
||||
|
||||
#. Modify {Flavor}Reader and {Flavor}Writer to use the new targtInfo option.
|
||||
|
||||
|
||||
Adding a Flavor
|
||||
===============
|
||||
|
||||
#. Add an entry for the flavor in :file:`include/lld/Driver/Driver.h` to
|
||||
:cpp:class:`lld::UniversalDriver::Flavor`.
|
||||
|
||||
#. Add an entry in :file:`lib/Driver/UniversalDriver.cpp` to
|
||||
:cpp:func:`lld::Driver::strToFlavor` and
|
||||
:cpp:func:`lld::UniversalDriver::link`.
|
||||
This allows the flavor to be selected via symlink and :option:`-flavor`.
|
||||
|
||||
#. Add a tablegen file called :file:`lib/Driver/{flavor}Options.td` that
|
||||
describes the options. If the options are a superset of another driver, that
|
||||
driver's td file can simply be included. The :file:`{flavor}Options.td` file
|
||||
must also be added to :file:`lib/Driver/CMakeLists.txt`.
|
||||
|
||||
#. Add a ``{flavor}Driver`` as a subclass of :cpp:class:`lld::Driver`
|
||||
in :file:`lib/Driver/{flavor}Driver.cpp`.
|
||||
155
external/bsd/llvm/dist/lld/docs/Makefile
vendored
155
external/bsd/llvm/dist/lld/docs/Makefile
vendored
@@ -1,155 +0,0 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
all: html
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/lld.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/lld.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/lld"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/lld"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
12
external/bsd/llvm/dist/lld/docs/README.txt
vendored
12
external/bsd/llvm/dist/lld/docs/README.txt
vendored
@@ -1,12 +0,0 @@
|
||||
lld Documentation
|
||||
=================
|
||||
|
||||
The lld documentation is written using the Sphinx documentation generator. It is
|
||||
currently tested with Sphinx 1.1.3.
|
||||
|
||||
We currently use the 'nature' theme and a Beaker inspired structure.
|
||||
|
||||
To rebuild documents into html:
|
||||
|
||||
[/lld/docs]> make html
|
||||
|
||||
172
external/bsd/llvm/dist/lld/docs/Readers.rst
vendored
172
external/bsd/llvm/dist/lld/docs/Readers.rst
vendored
@@ -1,172 +0,0 @@
|
||||
.. _Readers:
|
||||
|
||||
Developing lld Readers
|
||||
======================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The purpose of a "Reader" is to take an object file in a particular format
|
||||
and create an `lld::File`:cpp:class: (which is a graph of Atoms)
|
||||
representing the object file. A Reader inherits from
|
||||
`lld::Reader`:cpp:class: which lives in
|
||||
:file:`include/lld/ReaderWriter/Reader.h` and
|
||||
:file:`lib/ReaderWriter/Reader.cpp`.
|
||||
|
||||
The Reader infrastructure for an object format ``Foo`` requires the
|
||||
following pieces in order to fit into lld:
|
||||
|
||||
:file:`include/lld/ReaderWriter/ReaderFoo.h`
|
||||
|
||||
.. cpp:class:: ReaderOptionsFoo : public ReaderOptions
|
||||
|
||||
This Options class is the only way to configure how the Reader will
|
||||
parse any file into an `lld::Reader`:cpp:class: object. This class
|
||||
should be declared in the `lld`:cpp:class: namespace.
|
||||
|
||||
.. cpp:function:: Reader *createReaderFoo(ReaderOptionsFoo &reader)
|
||||
|
||||
This factory function configures and create the Reader. This function
|
||||
should be declared in the `lld`:cpp:class: namespace.
|
||||
|
||||
:file:`lib/ReaderWriter/Foo/ReaderFoo.cpp`
|
||||
|
||||
.. cpp:class:: ReaderFoo : public Reader
|
||||
|
||||
This is the concrete Reader class which can be called to parse
|
||||
object files. It should be declared in an anonymous namespace or
|
||||
if there is shared code with the `lld::WriterFoo`:cpp:class: you
|
||||
can make a nested namespace (e.g. `lld::foo`:cpp:class:).
|
||||
|
||||
You may have noticed that :cpp:class:`ReaderFoo` is not declared in the
|
||||
``.h`` file. An important design aspect of lld is that all Readers are
|
||||
created *only* through an object-format-specific
|
||||
:cpp:func:`createReaderFoo` factory function. The creation of the Reader is
|
||||
parametrized through a :cpp:class:`ReaderOptionsFoo` class. This options
|
||||
class is the one-and-only way to control how the Reader operates when
|
||||
parsing an input file into an Atom graph. For instance, you may want the
|
||||
Reader to only accept certain architectures. The options class can be
|
||||
instantiated from command line options or be programmatically configured.
|
||||
|
||||
Where to start
|
||||
--------------
|
||||
|
||||
The lld project already has a skeleton of source code for Readers for
|
||||
``ELF``, ``PECOFF``, ``MachO``, and lld's native Atom graph format
|
||||
(both binary ``Native`` and ``YAML`` representations). If your file format
|
||||
is a variant of one of those, you should modify the existing Reader to
|
||||
support your variant. This is done by customizing the Options
|
||||
class for the Reader and making appropriate changes to the ``.cpp`` file to
|
||||
interpret those options and act accordingly.
|
||||
|
||||
If your object file format is not a variant of any existing Reader, you'll need
|
||||
to create a new Reader subclass with the organization described above.
|
||||
|
||||
Readers are factories
|
||||
---------------------
|
||||
|
||||
The linker will usually only instantiate your Reader once. That one Reader will
|
||||
have its parseFile() method called many times with different input files.
|
||||
To support multithreaded linking, the Reader may be parsing multiple input
|
||||
files in parallel. Therefore, there should be no parsing state in you Reader
|
||||
object. Any parsing state should be in ivars of your File subclass or in
|
||||
some temporary object.
|
||||
|
||||
The key method to implement in a reader is::
|
||||
|
||||
virtual error_code parseFile(LinkerInput &input,
|
||||
std::vector<std::unique_ptr<File>> &result);
|
||||
|
||||
It takes a memory buffer (which contains the contents of the object file
|
||||
being read) and returns an instantiated lld::File object which is
|
||||
a collection of Atoms. The result is a vector of File pointers (instead of
|
||||
simple a File pointer) because some file formats allow multiple object
|
||||
"files" to be encoded in one file system file.
|
||||
|
||||
|
||||
Memory Ownership
|
||||
----------------
|
||||
|
||||
Atoms are always owned by their File object. During core linking when Atoms
|
||||
are coalesced or stripped away, core linking does not delete them.
|
||||
Core linking just removes those unused Atoms from its internal list.
|
||||
The destructor of a File object is responsible for deleting all Atoms it
|
||||
owns, and if ownership of the MemoryBuffer was passed to it, the File
|
||||
destructor needs to delete that too.
|
||||
|
||||
Making Atoms
|
||||
------------
|
||||
|
||||
The internal model of lld is purely Atom based. But most object files do not
|
||||
have an explicit concept of Atoms, instead most have "sections". The way
|
||||
to think of this is that a section is just a list of Atoms with common
|
||||
attributes.
|
||||
|
||||
The first step in parsing section-based object files is to cleave each
|
||||
section into a list of Atoms. The technique may vary by section type. For
|
||||
code sections (e.g. .text), there are usually symbols at the start of each
|
||||
function. Those symbol addresses are the points at which the section is
|
||||
cleaved into discrete Atoms. Some file formats (like ELF) also include the
|
||||
length of each symbol in the symbol table. Otherwise, the length of each
|
||||
Atom is calculated to run to the start of the next symbol or the end of the
|
||||
section.
|
||||
|
||||
Other sections types can be implicitly cleaved. For instance c-string literals
|
||||
or unwind info (e.g. .eh_frame) can be cleaved by having the Reader look at
|
||||
the content of the section. It is important to cleave sections into Atoms
|
||||
to remove false dependencies. For instance the .eh_frame section often
|
||||
has no symbols, but contains "pointers" to the functions for which it
|
||||
has unwind info. If the .eh_frame section was not cleaved (but left as one
|
||||
big Atom), there would always be a reference (from the eh_frame Atom) to
|
||||
each function. So the linker would be unable to coalesce or dead stripped
|
||||
away the function atoms.
|
||||
|
||||
The lld Atom model also requires that a reference to an undefined symbol be
|
||||
modeled as a Reference to an UndefinedAtom. So the Reader also needs to
|
||||
create an UndefinedAtom for each undefined symbol in the object file.
|
||||
|
||||
Once all Atoms have been created, the second step is to create References
|
||||
(recall that Atoms are "nodes" and References are "edges"). Most References
|
||||
are created by looking at the "relocation records" in the object file. If
|
||||
a function contains a call to "malloc", there is usually a relocation record
|
||||
specifying the address in the section and the symbol table index. Your
|
||||
Reader will need to convert the address to an Atom and offset and the symbol
|
||||
table index into a target Atom. If "malloc" is not defined in the object file,
|
||||
the target Atom of the Reference will be an UndefinedAtom.
|
||||
|
||||
|
||||
Performance
|
||||
-----------
|
||||
Once you have the above working to parse an object file into Atoms and
|
||||
References, you'll want to look at performance. Some techniques that can
|
||||
help performance are:
|
||||
|
||||
* Use llvm::BumpPtrAllocator or pre-allocate one big vector<Reference> and then
|
||||
just have each atom point to its subrange of References in that vector.
|
||||
This can be faster that allocating each Reference as separate object.
|
||||
* Pre-scan the symbol table and determine how many atoms are in each section
|
||||
then allocate space for all the Atom objects at once.
|
||||
* Don't copy symbol names or section content to each Atom, instead use
|
||||
StringRef and ArrayRef in each Atom to point to its name and content in the
|
||||
MemoryBuffer.
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
We are still working on infrastructure to test Readers. The issue is that
|
||||
you don't want to check in binary files to the test suite. And the tools
|
||||
for creating your object file from assembly source may not be available on
|
||||
every OS.
|
||||
|
||||
We are investigating a way to use YAML to describe the section, symbols,
|
||||
and content of a file. Then have some code which will write out an object
|
||||
file from that YAML description.
|
||||
|
||||
Once that is in place, you can write test cases that contain section/symbols
|
||||
YAML and is run through the linker to produce Atom/References based YAML which
|
||||
is then run through FileCheck to verify the Atoms and References are as
|
||||
expected.
|
||||
|
||||
|
||||
|
||||
BIN
external/bsd/llvm/dist/lld/docs/_static/favicon.ico
vendored
BIN
external/bsd/llvm/dist/lld/docs/_static/favicon.ico
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,4 +0,0 @@
|
||||
<h3>Bugs</h3>
|
||||
|
||||
<p>lld bugs should be reported at the
|
||||
LLVM <a href="http://llvm.org/bugs">Bugzilla</a>.</p>
|
||||
@@ -1,12 +0,0 @@
|
||||
{% extends "!layout.html" %}
|
||||
|
||||
{% block extrahead %}
|
||||
<style type="text/css">
|
||||
table.right { float: right; margin-left: 20px; }
|
||||
table.right td { border: 1px solid #ccc; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block rootrellink %}
|
||||
<li><a href="{{ pathto('index') }}">lld Home</a> | </li>
|
||||
{% endblock %}
|
||||
251
external/bsd/llvm/dist/lld/docs/conf.py
vendored
251
external/bsd/llvm/dist/lld/docs/conf.py
vendored
@@ -1,251 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# lld documentation build configuration file.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'lld'
|
||||
copyright = u'2011-2013, LLVM Project'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '3.2'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '3.2'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
today_fmt = '%Y-%m-%d'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
show_authors = True
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'friendly'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'llvm-theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
html_theme_path = ["."]
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
html_favicon = 'favicon.ico'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
html_last_updated_fmt = '%Y-%m-%d'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
html_sidebars = {'index': 'indexsidebar.html'}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
# html_additional_pages = {'index': 'index.html'}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'llddoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('contents', 'lld.tex', u'lld Documentation',
|
||||
u'LLVM project', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('contents', 'lld', u'lld Documentation',
|
||||
[u'LLVM project'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('contents', 'lld', u'lld Documentation',
|
||||
u'LLVM project', 'lld', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
|
||||
# FIXME: Define intersphinx configration.
|
||||
intersphinx_mapping = {}
|
||||
|
||||
|
||||
# -- Options for extensions ----------------------------------------------------
|
||||
|
||||
# Enable this if you want TODOs to show up in the generated documentation.
|
||||
todo_include_todos = True
|
||||
470
external/bsd/llvm/dist/lld/docs/design.rst
vendored
470
external/bsd/llvm/dist/lld/docs/design.rst
vendored
@@ -1,470 +0,0 @@
|
||||
.. _design:
|
||||
|
||||
Linker Design
|
||||
=============
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
lld is a new generation of linker. It is not "section" based like traditional
|
||||
linkers which mostly just interlace sections from multiple object files into the
|
||||
output file. Instead, lld is based on "Atoms". Traditional section based
|
||||
linking work well for simple linking, but their model makes advanced linking
|
||||
features difficult to implement. Features like dead code stripping, reordering
|
||||
functions for locality, and C++ coalescing require the linker to work at a finer
|
||||
grain.
|
||||
|
||||
An atom is an indivisible chunk of code or data. An atom has a set of
|
||||
attributes, such as: name, scope, content-type, alignment, etc. An atom also
|
||||
has a list of References. A Reference contains: a kind, an optional offset, an
|
||||
optional addend, and an optional target atom.
|
||||
|
||||
The Atom model allows the linker to use standard graph theory models for linking
|
||||
data structures. Each atom is a node, and each Reference is an edge. The
|
||||
feature of dead code stripping is implemented by following edges to mark all
|
||||
live atoms, and then delete the non-live atoms.
|
||||
|
||||
|
||||
Atom Model
|
||||
----------
|
||||
|
||||
An atom is an indivisible chunk of code or data. Typically each user written
|
||||
function or global variable is an atom. In addition, the compiler may emit
|
||||
other atoms, such as for literal c-strings or floating point constants, or for
|
||||
runtime data structures like dwarf unwind info or pointers to initializers.
|
||||
|
||||
A simple "hello world" object file would be modeled like this:
|
||||
|
||||
.. image:: hello.png
|
||||
|
||||
There are three atoms: main, a proxy for printf, and an anonymous atom
|
||||
containing the c-string literal "hello world". The Atom "main" has two
|
||||
references. One is the call site for the call to printf, and the other is a
|
||||
reference for the instruction that loads the address of the c-string literal.
|
||||
|
||||
There are only four different types of atoms:
|
||||
|
||||
* DefinedAtom
|
||||
95% of all atoms. This is a chunk of code or data
|
||||
|
||||
* UndefinedAtom
|
||||
This is a place holder in object files for a reference to some atom
|
||||
outside the translation unit.During core linking it is usually replaced
|
||||
by (coalesced into) another Atom.
|
||||
|
||||
* SharedLibraryAtom
|
||||
If a required symbol name turns out to be defined in a dynamic shared
|
||||
library (and not some object file). A SharedLibraryAtom is the
|
||||
placeholder Atom used to represent that fact.
|
||||
|
||||
It is similar to an UndefinedAtom, but it also tracks information
|
||||
about the associated shared library.
|
||||
|
||||
* AbsoluteAtom
|
||||
This is for embedded support where some stuff is implemented in ROM at
|
||||
some fixed address. This atom has no content. It is just an address
|
||||
that the Writer needs to fix up any references to point to.
|
||||
|
||||
|
||||
File Model
|
||||
----------
|
||||
|
||||
The linker views the input files as basically containers of Atoms and
|
||||
References, and just a few attributes of their own. The linker works with three
|
||||
kinds of files: object files, static libraries, and dynamic shared libraries.
|
||||
Each kind of file has reader object which presents the file in the model
|
||||
expected by the linker.
|
||||
|
||||
Object File
|
||||
~~~~~~~~~~~
|
||||
|
||||
An object file is just a container of atoms. When linking an object file, a
|
||||
reader is instantiated which parses the object file and instantiates a set of
|
||||
atoms representing all content in the .o file. The linker adds all those atoms
|
||||
to a master graph.
|
||||
|
||||
Static Library (Archive)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is the traditional unix static archive which is just a collection of object
|
||||
files with a "table of contents". When linking with a static library, by default
|
||||
nothing is added to the master graph of atoms. Instead, if after merging all
|
||||
atoms from object files into a master graph, if any "undefined" atoms are left
|
||||
remaining in the master graph, the linker reads the table of contents for each
|
||||
static library to see if any have the needed definitions. If so, the set of
|
||||
atoms from the specified object file in the static library is added to the
|
||||
master graph of atoms.
|
||||
|
||||
Dynamic Library (Shared Object)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Dynamic libraries are different than object files and static libraries in that
|
||||
they don't directly add any content. Their purpose is to check at build time
|
||||
that the remaining undefined references can be resolved at runtime, and provide
|
||||
a list of dynamic libraries (SO_NEEDED) that will be needed at runtime. The way
|
||||
this is modeled in the linker is that a dynamic library contributes no atoms to
|
||||
the initial graph of atoms. Instead, (like static libraries) if there are
|
||||
"undefined" atoms in the master graph of all atoms, then each dynamic library is
|
||||
checked to see if exports the required symbol. If so, a "shared library" atom is
|
||||
instantiated by the by the reader which the linker uses to replace the
|
||||
"undefined" atom.
|
||||
|
||||
Linking Steps
|
||||
-------------
|
||||
|
||||
Through the use of abstract Atoms, the core of linking is architecture
|
||||
independent and file format independent. All command line parsing is factored
|
||||
out into a separate "options" abstraction which enables the linker to be driven
|
||||
with different command line sets.
|
||||
|
||||
The overall steps in linking are:
|
||||
|
||||
#. Command line processing
|
||||
|
||||
#. Parsing input files
|
||||
|
||||
#. Resolving
|
||||
|
||||
#. Passes/Optimizations
|
||||
|
||||
#. Generate output file
|
||||
|
||||
The Resolving and Passes steps are done purely on the master graph of atoms, so
|
||||
they have no notion of file formats such as mach-o or ELF.
|
||||
|
||||
|
||||
Input Files
|
||||
~~~~~~~~~~~
|
||||
|
||||
Existing developer tools using different file formats for object files.
|
||||
A goal of lld is to be file format independent. This is done
|
||||
through a plug-in model for reading object files. The lld::Reader is the base
|
||||
class for all object file readers. A Reader follows the factory method pattern.
|
||||
A Reader instantiates an lld::File object (which is a graph of Atoms) from a
|
||||
given object file (on disk or in-memory).
|
||||
|
||||
Every Reader subclass defines its own "options" class (for instance the mach-o
|
||||
Reader defines the class ReaderOptionsMachO). This options class is the
|
||||
one-and-only way to control how the Reader operates when parsing an input file
|
||||
into an Atom graph. For instance, you may want the Reader to only accept
|
||||
certain architectures. The options class can be instantiated from command
|
||||
line options, or it can be subclassed and the ivars programmatically set.
|
||||
|
||||
|
||||
Resolving
|
||||
~~~~~~~~~
|
||||
|
||||
The resolving step takes all the atoms' graphs from each object file and
|
||||
combines them into one master object graph. Unfortunately, it is not as simple
|
||||
as appending the atom list from each file into one big list. There are many
|
||||
cases where atoms need to be coalesced. That is, two or more atoms need to be
|
||||
coalesced into one atom. This is necessary to support: C language "tentative
|
||||
definitions", C++ weak symbols for templates and inlines defined in headers,
|
||||
replacing undefined atoms with actual definition atoms, and for merging copies
|
||||
of constants like c-strings and floating point constants.
|
||||
|
||||
The linker support coalescing by-name and by-content. By-name is used for
|
||||
tentative definitions and weak symbols. By-content is used for constant data
|
||||
that can be merged.
|
||||
|
||||
The resolving process maintains some global linking "state", including a "symbol
|
||||
table" which is a map from llvm::StringRef to lld::Atom*. With these data
|
||||
structures, the linker iterates all atoms in all input files. For each atom, it
|
||||
checks if the atom is named and has a global or hidden scope. If so, the atom
|
||||
is added to the symbol table map. If there already is a matching atom in that
|
||||
table, that means the current atom needs to be coalesced with the found atom, or
|
||||
it is a multiple definition error.
|
||||
|
||||
When all initial input file atoms have been processed by the resolver, a scan is
|
||||
made to see if there are any undefined atoms in the graph. If there are, the
|
||||
linker scans all libraries (both static and dynamic) looking for definitions to
|
||||
replace the undefined atoms. It is an error if any undefined atoms are left
|
||||
remaining.
|
||||
|
||||
Dead code stripping (if requested) is done at the end of resolving. The linker
|
||||
does a simple mark-and-sweep. It starts with "root" atoms (like "main" in a main
|
||||
executable) and follows each references and marks each Atom that it visits as
|
||||
"live". When done, all atoms not marked "live" are removed.
|
||||
|
||||
The result of the Resolving phase is the creation of an lld::File object. The
|
||||
goal is that the lld::File model is **the** internal representation
|
||||
throughout the linker. The file readers parse (mach-o, ELF, COFF) into an
|
||||
lld::File. The file writers (mach-o, ELF, COFF) taken an lld::File and produce
|
||||
their file kind, and every Pass only operates on an lld::File. This is not only
|
||||
a simpler, consistent model, but it enables the state of the linker to be dumped
|
||||
at any point in the link for testing purposes.
|
||||
|
||||
|
||||
Passes
|
||||
~~~~~~
|
||||
|
||||
The Passes step is an open ended set of routines that each get a change to
|
||||
modify or enhance the current lld::File object. Some example Passes are:
|
||||
|
||||
* stub (PLT) generation
|
||||
|
||||
* GOT instantiation
|
||||
|
||||
* order_file optimization
|
||||
|
||||
* branch island generation
|
||||
|
||||
* branch shim generation
|
||||
|
||||
* Objective-C optimizations (Darwin specific)
|
||||
|
||||
* TLV instantiation (Darwin specific)
|
||||
|
||||
* DTrace probe processing (Darwin specific)
|
||||
|
||||
* compact unwind encoding (Darwin specific)
|
||||
|
||||
|
||||
Some of these passes are specific to Darwin's runtime environments. But many of
|
||||
the passes are applicable to any OS (such as generating branch island for out of
|
||||
range branch instructions).
|
||||
|
||||
The general structure of a pass is to iterate through the atoms in the current
|
||||
lld::File object, inspecting each atom and doing something. For instance, the
|
||||
stub pass, looks for call sites to shared library atoms (e.g. call to printf).
|
||||
It then instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for
|
||||
each proxy atom needed, and these new atoms are added to the current lld::File
|
||||
object. Next, all the noted call sites to shared library atoms have their
|
||||
References altered to point to the stub atom instead of the shared library atom.
|
||||
|
||||
|
||||
Generate Output File
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Once the passes are done, the output file writer is given current lld::File
|
||||
object. The writer's job is to create the executable content file wrapper and
|
||||
place the content of the atoms into it.
|
||||
|
||||
lld uses a plug-in model for writing output files. All concrete writers (e.g.
|
||||
ELF, mach-o, etc) are subclasses of the lld::Writer class.
|
||||
|
||||
Unlike the Reader class which has just one method to instantiate an lld::File,
|
||||
the Writer class has multiple methods. The crucial method is to generate the
|
||||
output file, but there are also methods which allow the Writer to contribute
|
||||
Atoms to the resolver and specify passes to run.
|
||||
|
||||
An example of contributing
|
||||
atoms is that if the Writer knows a main executable is being linked and such
|
||||
an executable requires a specially named entry point (e.g. "_main"), the Writer
|
||||
can add an UndefinedAtom with that special name to the resolver. This will
|
||||
cause the resolver to issue an error if that symbol is not defined.
|
||||
|
||||
Sometimes a Writer supports lazily created symbols, such as names for the start
|
||||
of sections. To support this, the Writer can create a File object which vends
|
||||
no initial atoms, but does lazily supply atoms by name as needed.
|
||||
|
||||
Every Writer subclass defines its own "options" class (for instance the mach-o
|
||||
Writer defines the class WriterOptionsMachO). This options class is the
|
||||
one-and-only way to control how the Writer operates when producing an output
|
||||
file from an Atom graph. For instance, you may want the Writer to optimize
|
||||
the output for certain OS versions, or strip local symbols, etc. The options
|
||||
class can be instantiated from command line options, or it can be subclassed
|
||||
and the ivars programmatically set.
|
||||
|
||||
|
||||
lld::File representations
|
||||
-------------------------
|
||||
|
||||
Just as LLVM has three representations of its IR model, lld has three
|
||||
representations of its File/Atom/Reference model:
|
||||
|
||||
* In memory, abstract C++ classes (lld::Atom, lld::Reference, and lld::File).
|
||||
|
||||
* textual (in YAML)
|
||||
|
||||
* binary format ("native")
|
||||
|
||||
Binary File Format
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In theory, lld::File objects could be written to disk in an existing Object File
|
||||
format standard (e.g. ELF). Instead we choose to define a new binary file
|
||||
format. There are two main reasons for this: fidelity and performance. In order
|
||||
for lld to work as a linker on all platforms, its internal model must be rich
|
||||
enough to model all CPU and OS linking features. But if we choose an existing
|
||||
Object File format as the lld binary format, that means an on going need to
|
||||
retrofit each platform specific feature needed from alternate platforms into the
|
||||
existing Object File format. Having our own "native" binary format side steps
|
||||
that issue. We still need to be able to binary encode all the features, but
|
||||
once the in-memory model can represent the feature, it is straight forward to
|
||||
binary encode it.
|
||||
|
||||
The reason to use a binary file format at all, instead of a textual file format,
|
||||
is speed. You want the binary format to be as fast as possible to read into the
|
||||
in-memory model. Given that we control the in-memory model and the binary
|
||||
format, the obvious way to make reading super fast it to make the file format be
|
||||
basically just an array of atoms. The reader just mmaps in the file and looks
|
||||
at the header to see how many atoms there are and instantiate that many atom
|
||||
objects with the atom attribute information coming from that array. The trick
|
||||
is designing this in a way that can be extended as the Atom mode evolves and new
|
||||
attributes are added.
|
||||
|
||||
The native object file format starts with a header that lists how many "chunks"
|
||||
are in the file. A chunk is an array of "ivar data". The native file reader
|
||||
instantiates an array of Atom objects (with one large malloc call). Each atom
|
||||
contains just a pointer to its vtable and a pointer to its ivar data. All
|
||||
methods on lld::Atom are virtual, so all the method implementations return
|
||||
values based on the ivar data to which it has a pointer. If a new linking
|
||||
features is added which requires a change to the lld::Atom model, a new native
|
||||
reader class (e.g. version 2) is defined which knows how to read the new feature
|
||||
information from the new ivar data. The old reader class (e.g. version 1) is
|
||||
updated to do its best to model (the lack of the new feature) given the old ivar
|
||||
data in existing native object files.
|
||||
|
||||
With this model for the native file format, files can be read and turned
|
||||
into the in-memory graph of lld::Atoms with just a few memory allocations.
|
||||
And the format can easily adapt over time to new features.
|
||||
|
||||
The binary file format follows the ReaderWriter patterns used in lld. The lld
|
||||
library comes with the classes: ReaderNative and WriterNative. So, switching
|
||||
between file formats is as easy as switching which Reader subclass is used.
|
||||
|
||||
|
||||
Textual representations in YAML
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In designing a textual format we want something easy for humans to read and easy
|
||||
for the linker to parse. Since an atom has lots of attributes most of which are
|
||||
usually just the default, we should define default values for every attribute so
|
||||
that those can be omitted from the text representation. Here is the atoms for a
|
||||
simple hello world program expressed in YAML::
|
||||
|
||||
target-triple: x86_64-apple-darwin11
|
||||
|
||||
atoms:
|
||||
- name: _main
|
||||
scope: global
|
||||
type: code
|
||||
content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00,
|
||||
00, 00, 31, c0, 5d, c3 ]
|
||||
fixups:
|
||||
- offset: 07
|
||||
kind: pcrel32
|
||||
target: 2
|
||||
- offset: 0E
|
||||
kind: call32
|
||||
target: _fprintf
|
||||
|
||||
- type: c-string
|
||||
content: [ 73, 5A, 00 ]
|
||||
|
||||
...
|
||||
|
||||
The biggest use for the textual format will be writing test cases. Writing test
|
||||
cases in C is problematic because the compiler may vary its output over time for
|
||||
its own optimization reasons which my inadvertently disable or break the linker
|
||||
feature trying to be tested. By writing test cases in the linkers own textual
|
||||
format, we can exactly specify every attribute of every atom and thus target
|
||||
specific linker logic.
|
||||
|
||||
The textual/YAML format follows the ReaderWriter patterns used in lld. The lld
|
||||
library comes with the classes: ReaderYAML and WriterYAML.
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
The lld project contains a test suite which is being built up as new code is
|
||||
added to lld. All new lld functionality should have a tests added to the test
|
||||
suite. The test suite is `lit <http://llvm.org/cmds/lit.html/>`_ driven. Each
|
||||
test is a text file with comments telling lit how to run the test and check the
|
||||
result To facilitate testing, the lld project builds a tool called lld-core.
|
||||
This tool reads a YAML file (default from stdin), parses it into one or more
|
||||
lld::File objects in memory and then feeds those lld::File objects to the
|
||||
resolver phase. The output of the resolver is written as a native object file.
|
||||
It is then read back in using the native object file reader and then pass to the
|
||||
YAML writer. This round-about path means that all three representations
|
||||
(in-memory, binary, and text) are exercised, and any new feature has to work in
|
||||
all the representations to pass the test.
|
||||
|
||||
|
||||
Resolver testing
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Basic testing is the "core linking" or resolving phase. That is where the
|
||||
linker merges object files. All test cases are written in YAML. One feature of
|
||||
YAML is that it allows multiple "documents" to be encoding in one YAML stream.
|
||||
That means one text file can appear to the linker as multiple .o files - the
|
||||
normal case for the linker.
|
||||
|
||||
Here is a simple example of a core linking test case. It checks that an
|
||||
undefined atom from one file will be replaced by a definition from another
|
||||
file::
|
||||
|
||||
# RUN: lld-core %s | FileCheck %s
|
||||
|
||||
#
|
||||
# Test that undefined atoms are replaced with defined atoms.
|
||||
#
|
||||
|
||||
---
|
||||
atoms:
|
||||
- name: foo
|
||||
definition: undefined
|
||||
---
|
||||
atoms:
|
||||
- name: foo
|
||||
scope: global
|
||||
type: code
|
||||
...
|
||||
|
||||
# CHECK: name: foo
|
||||
# CHECK: scope: global
|
||||
# CHECK: type: code
|
||||
# CHECK-NOT: name: foo
|
||||
# CHECK: ...
|
||||
|
||||
|
||||
Passes testing
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Since Passes just operate on an lld::File object, the lld-core tool has the
|
||||
option to run a particular pass (after resolving). Thus, you can write a YAML
|
||||
test case with carefully crafted input to exercise areas of a Pass and the check
|
||||
the resulting lld::File object as represented in YAML.
|
||||
|
||||
|
||||
Design Issues
|
||||
-------------
|
||||
|
||||
There are a number of open issues in the design of lld. The plan is to wait and
|
||||
make these design decisions when we need to.
|
||||
|
||||
|
||||
Debug Info
|
||||
~~~~~~~~~~
|
||||
|
||||
Currently, the lld model says nothing about debug info. But the most popular
|
||||
debug format is DWARF and there is some impedance mismatch with the lld model
|
||||
and DWARF. In lld there are just Atoms and only Atoms that need to be in a
|
||||
special section at runtime have an associated section. Also, Atoms do not have
|
||||
addresses. The way DWARF is spec'ed different parts of DWARF are supposed to go
|
||||
into specially named sections and the DWARF references function code by address.
|
||||
|
||||
CPU and OS specific functionality
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Currently, lld has an abstract "Platform" that deals with any CPU or OS specific
|
||||
differences in linking. We just keep adding virtual methods to the base
|
||||
Platform class as we find linking areas that might need customization. At some
|
||||
point we'll need to structure this better.
|
||||
|
||||
|
||||
File Attributes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Currently, lld::File just has a path and a way to iterate its atoms. We will
|
||||
need to add more attributes on a File. For example, some equivalent to the
|
||||
target triple. There is also a number of cached or computed attributes that
|
||||
could make various Passes more efficient. For instance, on Darwin there are a
|
||||
number of Objective-C optimizations that can be done by a Pass. But it would
|
||||
improve the plain C case if the Objective-C optimization Pass did not have to
|
||||
scan all atoms looking for any Objective-C data structures. This could be done
|
||||
if the lld::File object had an attribute that said if the file had any
|
||||
Objective-C data in it. The Resolving phase would then be required to "merge"
|
||||
that attribute as object files are added.
|
||||
48
external/bsd/llvm/dist/lld/docs/development.rst
vendored
48
external/bsd/llvm/dist/lld/docs/development.rst
vendored
@@ -1,48 +0,0 @@
|
||||
.. _development:
|
||||
|
||||
Development
|
||||
===========
|
||||
|
||||
lld is developed as part of the `LLVM <http://llvm.org>`_ project.
|
||||
|
||||
Using C++11 in lld
|
||||
------------------
|
||||
|
||||
:doc:`C++11`.
|
||||
|
||||
Creating a Reader
|
||||
-----------------
|
||||
|
||||
See the :ref:`Creating a Reader <Readers>` guide.
|
||||
|
||||
|
||||
Modifying the Driver
|
||||
--------------------
|
||||
|
||||
See :doc:`Driver`.
|
||||
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
You can run lld with ``-mllvm -debug`` command line options to enable debugging
|
||||
printouts. If you want to enable debug information for some specific pass, you
|
||||
can run it with ``-mllvm '-debug-only=<pass>'``, where pass is a name used in
|
||||
the ``DEBUG_WITH_TYPE()`` macro.
|
||||
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
The project documentation is written in reStructuredText and generated using the
|
||||
`Sphinx <http://sphinx.pocoo.org/>`_ documentation generator. For more
|
||||
information on writing documentation for the project, see the
|
||||
:ref:`sphinx_intro`.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
C++11
|
||||
Readers
|
||||
Driver
|
||||
106
external/bsd/llvm/dist/lld/docs/getting_started.rst
vendored
106
external/bsd/llvm/dist/lld/docs/getting_started.rst
vendored
@@ -1,106 +0,0 @@
|
||||
.. _getting_started:
|
||||
|
||||
Getting Started: Building and Running lld
|
||||
=========================================
|
||||
|
||||
This page gives you the shortest path to checking out and building lld. If you
|
||||
run into problems, please file bugs in the `LLVM Bugzilla`__
|
||||
|
||||
__ http://llvm.org/bugs/
|
||||
|
||||
Building lld
|
||||
------------
|
||||
|
||||
On Unix-like Systems
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
1. Get the required tools.
|
||||
|
||||
* `CMake 2.8`_\+.
|
||||
* make (or any build system CMake supports).
|
||||
* `Clang 3.1`_\+ or GCC 4.7+ (C++11 support is required).
|
||||
|
||||
* If using Clang, you will also need `libc++`_.
|
||||
* `Python 2.4`_\+ (not 3.x) for running tests.
|
||||
|
||||
.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html
|
||||
.. _Clang 3.1: http://clang.llvm.org/
|
||||
.. _libc++: http://libcxx.llvm.org/
|
||||
.. _Python 2.4: http://python.org/download/
|
||||
|
||||
2. Check out LLVM::
|
||||
|
||||
$ cd path/to/llvm-project
|
||||
$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
|
||||
|
||||
3. Check out lld::
|
||||
|
||||
$ cd llvm/tools
|
||||
$ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
|
||||
|
||||
* lld can also be checked out to ``path/to/llvm-project`` and built as an external
|
||||
project.
|
||||
|
||||
4. Build LLVM and lld::
|
||||
|
||||
$ cd path/to/llvm-build/llvm (out of source build required)
|
||||
$ cmake -G "Unix Makefiles" path/to/llvm-project/llvm
|
||||
$ make
|
||||
|
||||
* If you want to build with clang and it is not the default compiler or
|
||||
it is installed in an alternate location, you'll need to tell the cmake tool
|
||||
the location of the C and C++ compiler via CMAKE_C_COMPILER and
|
||||
CMAKE_CXX_COMPILER. For example::
|
||||
|
||||
$ cmake -DCMAKE_CXX_COMPILER=/path/to/clang++ -DCMAKE_C_COMPILER=/path/to/clang ...
|
||||
|
||||
5. Test::
|
||||
|
||||
$ make lld-test
|
||||
|
||||
Using Visual Studio
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#. Get the required tools.
|
||||
|
||||
* `CMake 2.8`_\+.
|
||||
* `Visual Studio 11`_ (required for C++11 support)
|
||||
* `Python 2.4`_\+ (not 3.x) for running tests.
|
||||
|
||||
.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html
|
||||
.. _Visual Studio 11: http://www.microsoft.com/visualstudio/11/en-us
|
||||
.. _Python 2.4: http://python.org/download/
|
||||
|
||||
#. Check out LLVM::
|
||||
|
||||
$ cd path/to/llvm-project
|
||||
$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
|
||||
|
||||
#. Check out lld::
|
||||
|
||||
$ cd llvm/tools
|
||||
$ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
|
||||
|
||||
* lld can also be checked out to ``path/to/llvm-project`` and built as an external
|
||||
project.
|
||||
|
||||
#. Generate Visual Studio project files::
|
||||
|
||||
$ cd path/to/llvm-build/llvm (out of source build required)
|
||||
$ cmake -G "Visual Studio 11" path/to/llvm-project/llvm
|
||||
|
||||
#. Build
|
||||
|
||||
* Open LLVM.sln in Visual Studio.
|
||||
* Build the ``ALL_BUILD`` target.
|
||||
|
||||
#. Test
|
||||
|
||||
* Build the ``lld-test`` target.
|
||||
|
||||
More Information
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
For more information on using CMake see the `LLVM CMake guide`_.
|
||||
|
||||
.. _LLVM CMake guide: http://llvm.org/docs/CMake.html
|
||||
BIN
external/bsd/llvm/dist/lld/docs/hello.png
vendored
BIN
external/bsd/llvm/dist/lld/docs/hello.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 27 KiB |
82
external/bsd/llvm/dist/lld/docs/index.rst
vendored
82
external/bsd/llvm/dist/lld/docs/index.rst
vendored
@@ -1,82 +0,0 @@
|
||||
.. _index:
|
||||
|
||||
lld - The LLVM Linker
|
||||
=====================
|
||||
|
||||
lld is a new set of modular code for creating linker tools.
|
||||
|
||||
* End-User Features:
|
||||
|
||||
* Compatible with existing linker options
|
||||
* Reads standard Object Files (e.g. ELF, Mach-O, PE/COFF)
|
||||
* Writes standard Executable Files (e.g. ELF, Mach-O, PE)
|
||||
* Fast link times
|
||||
* Minimal memory use
|
||||
* Remove clang's reliance on "the system linker"
|
||||
* Uses the LLVM `"UIUC" BSD-Style license`__.
|
||||
|
||||
* Applications:
|
||||
|
||||
* Modular design
|
||||
* Support cross linking
|
||||
* Easy to add new CPU support
|
||||
* Can be built as static tool or library
|
||||
|
||||
* Design and Implementation:
|
||||
|
||||
* Extensive unit tests
|
||||
* Internal linker model can be dumped/read to textual format
|
||||
* Internal linker model can be dumped/read to a new native format
|
||||
* Native format designed to be fast to read and write
|
||||
* Additional linking features can be plugged in as "passes"
|
||||
* OS specific and CPU specific code factored out
|
||||
|
||||
Why a new linker?
|
||||
-----------------
|
||||
|
||||
The fact that clang relies on whatever linker tool you happen to have installed
|
||||
means that clang has been very conservative adopting features which require a
|
||||
recent linker.
|
||||
|
||||
In the same way that the MC layer of LLVM has removed clang's reliance on the
|
||||
system assembler tool, the lld project will remove clang's reliance on the
|
||||
system linker tool.
|
||||
|
||||
|
||||
Current Status
|
||||
--------------
|
||||
|
||||
lld is in its early stages of development.
|
||||
|
||||
It can currently self host on Linux x86-64 with -static.
|
||||
|
||||
Source
|
||||
------
|
||||
|
||||
lld is available in the LLVM SVN repository::
|
||||
|
||||
svn co http://llvm.org/svn/llvm-project/lld/trunk
|
||||
|
||||
lld is also available via the read-only git mirror::
|
||||
|
||||
git clone http://llvm.org/git/lld.git
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
design
|
||||
getting_started
|
||||
development
|
||||
open_projects
|
||||
sphinx_intro
|
||||
|
||||
Indices and tables
|
||||
------------------
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
||||
|
||||
__ http://llvm.org/docs/DeveloperPolicy.html#license
|
||||
@@ -1,22 +0,0 @@
|
||||
{#
|
||||
sphinxdoc/layout.html
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sphinx layout template for the sphinxdoc theme.
|
||||
|
||||
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{% extends "basic/layout.html" %}
|
||||
|
||||
{% block relbar1 %}
|
||||
<div class="logo">
|
||||
<a href="{{ pathto('index') }}"><img src="{{
|
||||
pathto("_static/logo.png", 1) }}" alt="LLVM Documentation"/></a>
|
||||
</div>
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
|
||||
{# put the sidebar before the body #}
|
||||
{% block sidebar1 %}{{ sidebar() }}{% endblock %}
|
||||
{% block sidebar2 %}{% endblock %}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 202 B |
@@ -1,345 +0,0 @@
|
||||
/*
|
||||
* sphinxdoc.css_t
|
||||
* ~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Sphinx stylesheet -- sphinxdoc theme. Originally created by
|
||||
* Armin Ronacher for Werkzeug.
|
||||
*
|
||||
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
@import url("basic.css");
|
||||
|
||||
/* -- page layout ----------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
|
||||
'Verdana', sans-serif;
|
||||
font-size: 14px;
|
||||
letter-spacing: -0.01em;
|
||||
line-height: 150%;
|
||||
text-align: center;
|
||||
background-color: #BFD1D4;
|
||||
color: black;
|
||||
padding: 0;
|
||||
border: 1px solid #aaa;
|
||||
|
||||
margin: 0px 80px 0px 80px;
|
||||
min-width: 740px;
|
||||
}
|
||||
|
||||
div.logo {
|
||||
background-color: white;
|
||||
text-align: left;
|
||||
padding: 10px 10px 15px 15px;
|
||||
}
|
||||
|
||||
div.document {
|
||||
background-color: white;
|
||||
text-align: left;
|
||||
background-image: url(contents.png);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
div.bodywrapper {
|
||||
margin: 0 240px 0 0;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.body {
|
||||
margin: 0;
|
||||
padding: 0.5em 20px 20px 20px;
|
||||
}
|
||||
|
||||
div.related {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
div.related ul {
|
||||
background-image: url(navigation.png);
|
||||
height: 2em;
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
div.related ul li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 2em;
|
||||
float: left;
|
||||
}
|
||||
|
||||
div.related ul li.right {
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
div.related ul li a {
|
||||
margin: 0;
|
||||
padding: 0 5px 0 5px;
|
||||
line-height: 1.75em;
|
||||
color: #EE9816;
|
||||
}
|
||||
|
||||
div.related ul li a:hover {
|
||||
color: #3CA8E7;
|
||||
}
|
||||
|
||||
div.sphinxsidebarwrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
margin: 0;
|
||||
padding: 0.5em 15px 15px 0;
|
||||
width: 210px;
|
||||
float: right;
|
||||
font-size: 1em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3, div.sphinxsidebar h4 {
|
||||
margin: 1em 0 0.5em 0;
|
||||
font-size: 1em;
|
||||
padding: 0.1em 0 0.1em 0.5em;
|
||||
color: white;
|
||||
border: 1px solid #86989B;
|
||||
background-color: #AFC1C4;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3 a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
padding-left: 1.5em;
|
||||
margin-top: 7px;
|
||||
padding: 0;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
background-color: #E3EFF1;
|
||||
color: #86989B;
|
||||
padding: 3px 8px 3px 0;
|
||||
clear: both;
|
||||
font-size: 0.8em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.footer a {
|
||||
color: #86989B;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* -- body styles ----------------------------------------------------------- */
|
||||
|
||||
p {
|
||||
margin: 0.8em 0 0.5em 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #CA7900;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #2491CF;
|
||||
}
|
||||
|
||||
div.body a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
padding: 0.7em 0 0.3em 0;
|
||||
font-size: 1.5em;
|
||||
color: #11557C;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 1.3em 0 0.2em 0;
|
||||
font-size: 1.35em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 1em 0 -0.3em 0;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
|
||||
color: black!important;
|
||||
}
|
||||
|
||||
h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
|
||||
display: none;
|
||||
margin: 0 0 0 0.3em;
|
||||
padding: 0 0.2em 0 0.2em;
|
||||
color: #aaa!important;
|
||||
}
|
||||
|
||||
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
|
||||
h5:hover a.anchor, h6:hover a.anchor {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
|
||||
h5 a.anchor:hover, h6 a.anchor:hover {
|
||||
color: #777;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
a.headerlink {
|
||||
color: #c60f0f!important;
|
||||
font-size: 1em;
|
||||
margin-left: 6px;
|
||||
padding: 0 4px 0 4px;
|
||||
text-decoration: none!important;
|
||||
}
|
||||
|
||||
a.headerlink:hover {
|
||||
background-color: #ccc;
|
||||
color: white!important;
|
||||
}
|
||||
|
||||
cite, code, tt {
|
||||
font-family: 'Consolas', 'Deja Vu Sans Mono',
|
||||
'Bitstream Vera Sans Mono', monospace;
|
||||
font-size: 0.95em;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
tt {
|
||||
background-color: #f2f2f2;
|
||||
border-bottom: 1px solid #ddd;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
tt.descname, tt.descclassname, tt.xref {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid #abc;
|
||||
margin: 2em;
|
||||
}
|
||||
|
||||
a tt {
|
||||
border: 0;
|
||||
color: #CA7900;
|
||||
}
|
||||
|
||||
a tt:hover {
|
||||
color: #2491CF;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: 'Consolas', 'Deja Vu Sans Mono',
|
||||
'Bitstream Vera Sans Mono', monospace;
|
||||
font-size: 0.95em;
|
||||
letter-spacing: 0.015em;
|
||||
line-height: 120%;
|
||||
padding: 0.5em;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
pre a {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
td.linenos pre {
|
||||
padding: 0.5em 0;
|
||||
}
|
||||
|
||||
div.quotebar {
|
||||
background-color: #f8f8f8;
|
||||
max-width: 250px;
|
||||
float: right;
|
||||
padding: 2px 7px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.topic {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
margin: 0 -0.5em 0 -0.5em;
|
||||
}
|
||||
|
||||
table td, table th {
|
||||
padding: 0.2em 0.5em 0.2em 0.5em;
|
||||
}
|
||||
|
||||
div.admonition, div.warning {
|
||||
font-size: 0.9em;
|
||||
margin: 1em 0 1em 0;
|
||||
border: 1px solid #86989B;
|
||||
background-color: #f7f7f7;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.admonition p, div.warning p {
|
||||
margin: 0.5em 1em 0.5em 1em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.admonition pre, div.warning pre {
|
||||
margin: 0.4em 1em 0.4em 1em;
|
||||
}
|
||||
|
||||
div.admonition p.admonition-title,
|
||||
div.warning p.admonition-title {
|
||||
margin: 0;
|
||||
padding: 0.1em 0 0.1em 0.5em;
|
||||
color: white;
|
||||
border-bottom: 1px solid #86989B;
|
||||
font-weight: bold;
|
||||
background-color: #AFC1C4;
|
||||
}
|
||||
|
||||
div.warning {
|
||||
border: 1px solid #940000;
|
||||
}
|
||||
|
||||
div.warning p.admonition-title {
|
||||
background-color: #CF0000;
|
||||
border-bottom-color: #940000;
|
||||
}
|
||||
|
||||
div.admonition ul, div.admonition ol,
|
||||
div.warning ul, div.warning ol {
|
||||
margin: 0.1em 0.5em 0.5em 3em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.versioninfo {
|
||||
margin: 1em 0 0 0;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #DDEAF0;
|
||||
padding: 8px;
|
||||
line-height: 1.3em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.viewcode-back {
|
||||
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
|
||||
'Verdana', sans-serif;
|
||||
}
|
||||
|
||||
div.viewcode-block:target {
|
||||
background-color: #f4debf;
|
||||
border-top: 1px solid #ac9;
|
||||
border-bottom: 1px solid #ac9;
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 218 B |
@@ -1,4 +0,0 @@
|
||||
[theme]
|
||||
inherit = basic
|
||||
stylesheet = llvm.css
|
||||
pygments_style = friendly
|
||||
190
external/bsd/llvm/dist/lld/docs/make.bat
vendored
190
external/bsd/llvm/dist/lld/docs/make.bat
vendored
@@ -1,190 +0,0 @@
|
||||
@ECHO OFF
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set BUILDDIR=_build
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. singlehtml to make a single large HTML file
|
||||
echo. pickle to make pickle files
|
||||
echo. json to make JSON files
|
||||
echo. htmlhelp to make HTML files and a HTML help project
|
||||
echo. qthelp to make HTML files and a qthelp project
|
||||
echo. devhelp to make HTML files and a Devhelp project
|
||||
echo. epub to make an epub
|
||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||
echo. text to make text files
|
||||
echo. man to make manual pages
|
||||
echo. texinfo to make Texinfo files
|
||||
echo. gettext to make PO message catalogs
|
||||
echo. changes to make an overview over all changed/added/deprecated items
|
||||
echo. linkcheck to check all external links for integrity
|
||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||
del /q /s %BUILDDIR%\*
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "html" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "singlehtml" (
|
||||
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pickle" (
|
||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the pickle files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "json" (
|
||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the JSON files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "htmlhelp" (
|
||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "qthelp" (
|
||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\lld.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\lld.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "devhelp" (
|
||||
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "epub" (
|
||||
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latex" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "text" (
|
||||
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The text files are in %BUILDDIR%/text.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "man" (
|
||||
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "texinfo" (
|
||||
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "gettext" (
|
||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.The overview file is in %BUILDDIR%/changes.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "linkcheck" (
|
||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Link check complete; look for any errors in the above output ^
|
||||
or in %BUILDDIR%/linkcheck/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "doctest" (
|
||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Testing of doctests in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/doctest/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
:end
|
||||
@@ -1,13 +0,0 @@
|
||||
.. _open_projects:
|
||||
|
||||
Open Projects
|
||||
=============
|
||||
|
||||
.. include:: ../include/lld/Core/TODO.txt
|
||||
.. include:: ../lib/Core/TODO.txt
|
||||
.. include:: ../tools/lld/TODO.txt
|
||||
|
||||
Documentation TODOs
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. todolist::
|
||||
147
external/bsd/llvm/dist/lld/docs/sphinx_intro.rst
vendored
147
external/bsd/llvm/dist/lld/docs/sphinx_intro.rst
vendored
@@ -1,147 +0,0 @@
|
||||
.. _sphinx_intro:
|
||||
|
||||
Sphinx Introduction for LLVM Developers
|
||||
=======================================
|
||||
|
||||
This document is intended as a short and simple introduction to the Sphinx
|
||||
documentation generation system for LLVM developers.
|
||||
|
||||
Quickstart
|
||||
----------
|
||||
|
||||
To get started writing documentation, you will need to:
|
||||
|
||||
1. Have the Sphinx tools :ref:`installed <installing_sphinx>`.
|
||||
|
||||
2. Understand how to :ref:`build the documentation
|
||||
<building_the_documentation>`.
|
||||
|
||||
3. Start :ref:`writing documentation <writing_documentation>`!
|
||||
|
||||
.. _installing_sphinx:
|
||||
|
||||
Installing Sphinx
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
You should be able to install Sphinx using the standard Python package
|
||||
installation tool ``easy_install``, as follows::
|
||||
|
||||
$ sudo easy_install sphinx
|
||||
Searching for sphinx
|
||||
Reading http://pypi.python.org/simple/sphinx/
|
||||
Reading http://sphinx.pocoo.org/
|
||||
Best match: Sphinx 1.1.3
|
||||
... more lines here ..
|
||||
|
||||
If you do not have root access (or otherwise want to avoid installing Sphinx in
|
||||
system directories) see the section on :ref:`installing_sphinx_in_a_venv` .
|
||||
|
||||
If you do not have the ``easy_install`` tool on your system, you should be able
|
||||
to install it using:
|
||||
|
||||
Linux
|
||||
Use your distribution's standard package management tool to install it,
|
||||
i.e., ``apt-get install easy_install`` or ``yum install easy_install``.
|
||||
|
||||
Mac OS X
|
||||
All modern Mac OS X systems come with ``easy_install`` as part of the base
|
||||
system.
|
||||
|
||||
Windows
|
||||
See the `setuptools <http://pypi.python.org/pypi/setuptools>`_ package web
|
||||
page for instructions.
|
||||
|
||||
|
||||
.. _building_the_documentation:
|
||||
|
||||
Building the documentation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In order to build the documentation, all you should need to do is change to the
|
||||
``docs`` directory and invoke make as follows::
|
||||
|
||||
$ cd path/to/project/docs
|
||||
$ make html
|
||||
|
||||
Note that on Windows there is a ``make.bat`` command in the docs directory which
|
||||
supplies the same interface as the ``Makefile``.
|
||||
|
||||
That command will invoke ``sphinx-build`` with the appropriate options for the
|
||||
project, and generate the HTML documentation in a ``_build`` subdirectory. You
|
||||
can browse it starting from the index page by visiting
|
||||
``_build/html/index.html``.
|
||||
|
||||
Sphinx supports a wide variety of generation formats (including LaTeX, man
|
||||
pages, and plain text). The ``Makefile`` includes a number of convenience
|
||||
targets for invoking ``sphinx-build`` appropriately, the common ones are:
|
||||
|
||||
make html
|
||||
Generate the HTML output.
|
||||
|
||||
make latexpdf
|
||||
Generate LaTeX documentation and convert to a PDF.
|
||||
|
||||
make man
|
||||
Generate man pages.
|
||||
|
||||
|
||||
.. _writing_documentation:
|
||||
|
||||
Writing documentation
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The documentation itself is written in the reStructuredText (ReST) format, and Sphinx
|
||||
defines additional tags to support features like cross-referencing.
|
||||
|
||||
The ReST format itself is organized around documents mostly being readable
|
||||
plaintext documents. You should generally be able to write new documentation
|
||||
easily just by following the style of the existing documentation.
|
||||
|
||||
If you want to understand the formatting of the documents more, the best place
|
||||
to start is Sphinx's own `ReST Primer <http://sphinx.pocoo.org/rest.html>`_.
|
||||
|
||||
|
||||
Learning More
|
||||
-------------
|
||||
|
||||
If you want to learn more about the Sphinx system, the best place to start is
|
||||
the Sphinx documentation itself, available `here
|
||||
<http://sphinx.pocoo.org/contents.html>`_.
|
||||
|
||||
|
||||
.. _installing_sphinx_in_a_venv:
|
||||
|
||||
Installing Sphinx in a Virtual Environment
|
||||
------------------------------------------
|
||||
|
||||
Most Python developers prefer to work with tools inside a *virtualenv* (virtual
|
||||
environment) instance, which functions as an application sandbox. This avoids
|
||||
polluting your system installation with different packages used by various
|
||||
projects (and ensures that dependencies for different packages don't conflict
|
||||
with one another). Of course, you need to first have the virtualenv software
|
||||
itself which generally would be installed at the system level::
|
||||
|
||||
$ sudo easy_install virtualenv
|
||||
|
||||
but after that you no longer need to install additional packages in the system
|
||||
directories.
|
||||
|
||||
Once you have the *virtualenv* tool itself installed, you can create a
|
||||
virtualenv for Sphinx using::
|
||||
|
||||
$ virtualenv ~/my-sphinx-install
|
||||
New python executable in /Users/dummy/my-sphinx-install/bin/python
|
||||
Installing setuptools............done.
|
||||
Installing pip...............done.
|
||||
|
||||
$ ~/my-sphinx-install/bin/easy_install sphinx
|
||||
... install messages here ...
|
||||
|
||||
and from now on you can "activate" the *virtualenv* using::
|
||||
|
||||
$ source ~/my-sphinx-install/bin/activate
|
||||
|
||||
which will change your PATH to ensure the sphinx-build tool from inside the
|
||||
virtual environment will be used. See the `virtualenv website
|
||||
<http://www.virtualenv.org/en/latest/index.html>`_ for more information on using
|
||||
virtual environments.
|
||||
@@ -1,43 +0,0 @@
|
||||
//===- Core/AbsoluteAtom.h - An absolute Atom -----------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_ABSOLUTE_ATOM_H
|
||||
#define LLD_CORE_ABSOLUTE_ATOM_H
|
||||
|
||||
#include "lld/Core/Atom.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// An AbsoluteAtom has no content.
|
||||
/// It exists to represent content at fixed addresses in memory.
|
||||
class AbsoluteAtom : public Atom {
|
||||
public:
|
||||
|
||||
virtual uint64_t value() const = 0;
|
||||
|
||||
/// scope - The visibility of this atom to other atoms. C static functions
|
||||
/// have scope scopeTranslationUnit. Regular C functions have scope
|
||||
/// scopeGlobal. Functions compiled with visibility=hidden have scope
|
||||
/// scopeLinkageUnit so they can be see by other atoms being linked but not
|
||||
/// by the OS loader.
|
||||
virtual Scope scope() const = 0;
|
||||
|
||||
static inline bool classof(const Atom *a) {
|
||||
return a->definition() == definitionAbsolute;
|
||||
}
|
||||
static inline bool classof(const AbsoluteAtom *) { return true; }
|
||||
|
||||
protected:
|
||||
AbsoluteAtom() : Atom(definitionAbsolute) {}
|
||||
virtual ~AbsoluteAtom() {}
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_CORE_ABSOLUTE_ATOM_H
|
||||
@@ -1,48 +0,0 @@
|
||||
//===- Core/ArchiveLibraryFile.h - Models static library ------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_ARCHIVE_LIBRARY_FILE_H
|
||||
#define LLD_CORE_ARCHIVE_LIBRARY_FILE_H
|
||||
|
||||
#include "lld/Core/File.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
///
|
||||
/// The ArchiveLibraryFile subclass of File is used to represent unix
|
||||
/// static library archives. These libraries provide no atoms to the
|
||||
/// initial set of atoms linked. Instead, when the Resolver will query
|
||||
/// ArchiveLibraryFile instances for specific symbols names using the
|
||||
/// find() method. If the archive contains an object file which has a
|
||||
/// DefinedAtom whose scope is not translationUnit, then that entire
|
||||
/// object file File is returned.
|
||||
///
|
||||
class ArchiveLibraryFile : public File {
|
||||
public:
|
||||
static inline bool classof(const File *f) {
|
||||
return f->kind() == kindArchiveLibrary;
|
||||
}
|
||||
|
||||
/// Check if any member of the archive contains an Atom with the
|
||||
/// specified name and return the File object for that member, or nullptr.
|
||||
virtual const File *find(StringRef name, bool dataSymbolOnly) const = 0;
|
||||
|
||||
virtual const LinkingContext &getLinkingContext() const { return _context; }
|
||||
|
||||
protected:
|
||||
/// only subclasses of ArchiveLibraryFile can be instantiated
|
||||
ArchiveLibraryFile(const LinkingContext &context, StringRef path)
|
||||
: File(path, kindArchiveLibrary), _context(context) {}
|
||||
|
||||
const LinkingContext &_context;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_CORE_ARCHIVE_LIBRARY_FILE_H
|
||||
@@ -1,84 +0,0 @@
|
||||
//===- Core/Atom.h - A node in linking graph ------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_ATOM_H
|
||||
#define LLD_CORE_ATOM_H
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
class StringRef;
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
|
||||
class File;
|
||||
|
||||
///
|
||||
/// The linker has a Graph Theory model of linking. An object file is seen
|
||||
/// as a set of Atoms with References to other Atoms. Each Atom is a node
|
||||
/// and each Reference is an edge. An Atom can be a DefinedAtom which has
|
||||
/// content or a UndefinedAtom which is a placeholder and represents an
|
||||
/// undefined symbol (extern declaration).
|
||||
///
|
||||
class Atom {
|
||||
public:
|
||||
/// Whether this atom is defined or a proxy for an undefined symbol
|
||||
enum Definition {
|
||||
definitionRegular, ///< Normal C/C++ function or global variable.
|
||||
definitionAbsolute, ///< Asm-only (foo = 10). Not tied to any content.
|
||||
definitionUndefined, ///< Only in .o files to model reference to undef.
|
||||
definitionSharedLibrary ///< Only in shared libraries to model export.
|
||||
};
|
||||
|
||||
/// The scope in which this atom is acessible to other atoms.
|
||||
enum Scope {
|
||||
scopeTranslationUnit, ///< Accessible only to atoms in the same translation
|
||||
/// unit (e.g. a C static).
|
||||
scopeLinkageUnit, ///< Accessible to atoms being linked but not visible
|
||||
/// to runtime loader (e.g. visibility=hidden).
|
||||
scopeGlobal ///< Accessible to all atoms and visible to runtime
|
||||
/// loader (e.g. visibility=default).
|
||||
};
|
||||
|
||||
|
||||
/// file - returns the File that produced/owns this Atom
|
||||
virtual const File& file() const = 0;
|
||||
|
||||
/// name - The name of the atom. For a function atom, it is the (mangled)
|
||||
/// name of the function.
|
||||
virtual StringRef name() const = 0;
|
||||
|
||||
/// definition - Whether this atom is a definition or represents an undefined
|
||||
/// symbol.
|
||||
Definition definition() const { return _definition; }
|
||||
|
||||
static inline bool classof(const Atom *a) { return true; }
|
||||
|
||||
protected:
|
||||
/// Atom is an abstract base class. Only subclasses can access constructor.
|
||||
explicit Atom(Definition def) : _definition(def) {}
|
||||
|
||||
/// The memory for Atom objects is always managed by the owning File
|
||||
/// object. Therefore, no one but the owning File object should call
|
||||
/// delete on an Atom. In fact, some File objects may bulk allocate
|
||||
/// an array of Atoms, so they cannot be individually deleted by anyone.
|
||||
virtual ~Atom() {}
|
||||
|
||||
private:
|
||||
Definition _definition;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_CORE_ATOM_H
|
||||
@@ -1,357 +0,0 @@
|
||||
//===- Core/DefinedAtom.h - An Atom with content --------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_DEFINED_ATOM_H
|
||||
#define LLD_CORE_DEFINED_ATOM_H
|
||||
|
||||
#include "lld/Core/Atom.h"
|
||||
#include "lld/Core/Reference.h"
|
||||
|
||||
namespace llvm {
|
||||
template <typename T>
|
||||
class ArrayRef;
|
||||
class StringRef;
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
class File;
|
||||
|
||||
/// \brief The fundamental unit of linking.
|
||||
///
|
||||
/// A C function or global variable is an atom. An atom has content and
|
||||
/// attributes. The content of a function atom is the instructions that
|
||||
/// implement the function. The content of a global variable atom is its
|
||||
/// initial bytes.
|
||||
///
|
||||
/// Here are some example attribute sets for common atoms. If a particular
|
||||
/// attribute is not listed, the default values are: definition=regular,
|
||||
/// sectionChoice=basedOnContent, scope=translationUnit, merge=no,
|
||||
/// deadStrip=normal, interposable=no
|
||||
///
|
||||
/// C function: void foo() {} <br>
|
||||
/// name=foo, type=code, perm=r_x, scope=global
|
||||
///
|
||||
/// C static function: staic void func() {} <br>
|
||||
/// name=func, type=code, perm=r_x
|
||||
///
|
||||
/// C global variable: int count = 1; <br>
|
||||
/// name=count, type=data, perm=rw_, scope=global
|
||||
///
|
||||
/// C tentative definition: int bar; <br>
|
||||
/// name=bar, type=zerofill, perm=rw_, scope=global,
|
||||
/// merge=asTentative, interposable=yesAndRuntimeWeak
|
||||
///
|
||||
/// Uninitialized C static variable: static int stuff; <br>
|
||||
/// name=stuff, type=zerofill, perm=rw_
|
||||
///
|
||||
/// Weak C function: __attribute__((weak)) void foo() {} <br>
|
||||
/// name=foo, type=code, perm=r_x, scope=global, merge=asWeak
|
||||
///
|
||||
/// Hidden C function: __attribute__((visibility("hidden"))) void foo() {}<br>
|
||||
/// name=foo, type=code, perm=r_x, scope=linkageUnit
|
||||
///
|
||||
/// No-dead-strip function: __attribute__((used)) void foo() {} <br>
|
||||
/// name=foo, type=code, perm=r_x, scope=global, deadStrip=never
|
||||
///
|
||||
/// Non-inlined C++ inline method: inline void Foo::doit() {} <br>
|
||||
/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
|
||||
/// mergeDupes=asWeak
|
||||
///
|
||||
/// Non-inlined C++ inline method whose address is taken:
|
||||
/// inline void Foo::doit() {} <br>
|
||||
/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
|
||||
/// mergeDupes=asAddressedWeak
|
||||
///
|
||||
/// literal c-string: "hello" <br>
|
||||
/// name="" type=cstring, perm=r__, scope=linkageUnit
|
||||
///
|
||||
/// literal double: 1.234 <br>
|
||||
/// name="" type=literal8, perm=r__, scope=linkageUnit
|
||||
///
|
||||
/// constant: { 1,2,3 } <br>
|
||||
/// name="" type=constant, perm=r__, scope=linkageUnit
|
||||
///
|
||||
/// Pointer to initializer function: <br>
|
||||
/// name="" type=initializer, perm=rw_l,
|
||||
/// sectionChoice=customRequired
|
||||
///
|
||||
/// C function place in custom section: __attribute__((section("__foo")))
|
||||
/// void foo() {} <br>
|
||||
/// name=foo, type=code, perm=r_x, scope=global,
|
||||
/// sectionChoice=customRequired, customSectionName=__foo
|
||||
///
|
||||
class DefinedAtom : public Atom {
|
||||
public:
|
||||
enum Interposable {
|
||||
interposeNo, // linker can directly bind uses of this atom
|
||||
interposeYes, // linker must indirect (through GOT) uses
|
||||
interposeYesAndRuntimeWeak // must indirect and mark symbol weak in final
|
||||
// linked image
|
||||
};
|
||||
|
||||
enum Merge {
|
||||
mergeNo, // Another atom with same name is error
|
||||
mergeAsTentative, // Is ANSI C tentative defintion, can be coalesced
|
||||
mergeAsWeak, // is C++ inline definition that was not inlined,
|
||||
// but address was not taken, so atom can be hidden
|
||||
// by linker
|
||||
mergeAsWeakAndAddressUsed,// is C++ definition inline definition whose
|
||||
// address was taken.
|
||||
mergeByContent // merge with other constants with same content
|
||||
};
|
||||
|
||||
enum ContentType {
|
||||
typeUnknown, // for use with definitionUndefined
|
||||
typeCode, // executable code
|
||||
typeResolver, // function which returns address of target
|
||||
typeBranchIsland, // linker created for large binaries
|
||||
typeBranchShim, // linker created to switch thumb mode
|
||||
typeStub, // linker created for calling external function
|
||||
typeStubHelper, // linker created for initial stub binding
|
||||
typeConstant, // a read-only constant
|
||||
typeCString, // a zero terminated UTF8 C string
|
||||
typeUTF16String, // a zero terminated UTF16 string
|
||||
typeCFI, // a FDE or CIE from dwarf unwind info
|
||||
typeLSDA, // extra unwinding info
|
||||
typeLiteral4, // a four-btye read-only constant
|
||||
typeLiteral8, // an eight-btye read-only constant
|
||||
typeLiteral16, // a sixteen-btye read-only constant
|
||||
typeData, // read-write data
|
||||
typeDataFast, // allow data to be quickly accessed
|
||||
typeZeroFill, // zero-fill data
|
||||
typeZeroFillFast, // allow zero-fill data to be quicky accessed
|
||||
typeConstData, // read-only data after dynamic linker is done
|
||||
typeObjC1Class, // ObjC1 class [Darwin]
|
||||
typeLazyPointer, // pointer through which a stub jumps
|
||||
typeLazyDylibPointer, // pointer through which a stub jumps [Darwin]
|
||||
typeCFString, // NS/CFString object [Darwin]
|
||||
typeGOT, // pointer to external symbol
|
||||
typeInitializerPtr, // pointer to initializer function
|
||||
typeTerminatorPtr, // pointer to terminator function
|
||||
typeCStringPtr, // pointer to UTF8 C string [Darwin]
|
||||
typeObjCClassPtr, // pointer to ObjC class [Darwin]
|
||||
typeObjC2CategoryList, // pointers to ObjC category [Darwin]
|
||||
typeDTraceDOF, // runtime data for Dtrace [Darwin]
|
||||
typeTempLTO, // temporary atom for bitcode reader
|
||||
typeCompactUnwindInfo, // runtime data for unwinder [Darwin]
|
||||
typeThunkTLV, // thunk used to access a TLV [Darwin]
|
||||
typeTLVInitialData, // initial data for a TLV [Darwin]
|
||||
typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
|
||||
typeTLVInitializerPtr, // pointer to thread local initializer [Darwin]
|
||||
typeDataDirectoryEntry, // linker created for data directory header [PECOFF]
|
||||
typeThreadZeroFill, // Uninitialized thread local data(TBSS) [ELF]
|
||||
typeThreadData, // Initialized thread local data(TDATA) [ELF]
|
||||
typeRONote, // Identifies readonly note sections [ELF]
|
||||
typeRWNote, // Identifies readwrite note sections [ELF]
|
||||
typeNoAlloc, // Identifies non allocatable sections [ELF]
|
||||
};
|
||||
|
||||
// Permission bits for atoms and segments. The order of these values are
|
||||
// important, because the layout pass may sort atoms by permission if other
|
||||
// attributes are the same.
|
||||
enum ContentPermissions {
|
||||
perm___ = 0, // mapped as unaccessible
|
||||
permR__ = 8, // mapped read-only
|
||||
permRW_ = 8 + 2, // mapped readable and writable
|
||||
permRW_L = 8 + 2 + 1, // initially mapped r/w, then made read-only
|
||||
// loader writable
|
||||
permR_X = 8 + 4, // mapped readable and executable
|
||||
permRWX = 8 + 2 + 4, // mapped readable and writable and executable
|
||||
permUnknown = 16 // unknown or invalid permissions
|
||||
};
|
||||
|
||||
enum SectionChoice {
|
||||
sectionBasedOnContent, // linker infers final section based on content
|
||||
sectionCustomPreferred, // linker may place in specific section
|
||||
sectionCustomRequired // linker must place in specific section
|
||||
};
|
||||
|
||||
enum SectionPosition {
|
||||
sectionPositionStart, // atom must be at start of section (and zero size)
|
||||
sectionPositionEarly, // atom should be near start of section
|
||||
sectionPositionAny, // atom can be anywhere in section
|
||||
sectionPositionEnd // atom must be at end of section (and zero size)
|
||||
};
|
||||
|
||||
enum DeadStripKind {
|
||||
deadStripNormal, // linker may dead strip this atom
|
||||
deadStripNever, // linker must never dead strip this atom
|
||||
deadStripAlways // linker must remove this atom if unused
|
||||
};
|
||||
|
||||
enum DynamicExport {
|
||||
/// \brief The linker may or may not export this atom dynamically depending
|
||||
/// on the output type and other context of the link.
|
||||
dynamicExportNormal,
|
||||
/// \brief The linker will always export this atom dynamically.
|
||||
dynamicExportAlways,
|
||||
};
|
||||
|
||||
struct Alignment {
|
||||
Alignment(int p2, int m = 0)
|
||||
: powerOf2(p2)
|
||||
, modulus(m) {}
|
||||
|
||||
uint16_t powerOf2;
|
||||
uint16_t modulus;
|
||||
|
||||
bool operator==(const Alignment &rhs) const {
|
||||
return (powerOf2 == rhs.powerOf2) && (modulus == rhs.modulus);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief returns a value for the order of this Atom within its file.
|
||||
///
|
||||
/// This is used by the linker to order the layout of Atoms so that the
|
||||
/// resulting image is stable and reproducible.
|
||||
///
|
||||
/// Note that this should not be confused with ordinals of exported symbols in
|
||||
/// Windows DLLs. In Windows terminology, ordinals are symbols' export table
|
||||
/// indices (small integers) which can be used instead of symbol names to
|
||||
/// refer items in a DLL.
|
||||
virtual uint64_t ordinal() const = 0;
|
||||
|
||||
/// \brief the number of bytes of space this atom's content will occupy in the
|
||||
/// final linked image.
|
||||
///
|
||||
/// For a function atom, it is the number of bytes of code in the function.
|
||||
virtual uint64_t size() const = 0;
|
||||
|
||||
/// \brief The visibility of this atom to other atoms.
|
||||
///
|
||||
/// C static functions have scope scopeTranslationUnit. Regular C functions
|
||||
/// have scope scopeGlobal. Functions compiled with visibility=hidden have
|
||||
/// scope scopeLinkageUnit so they can be see by other atoms being linked but
|
||||
/// not by the OS loader.
|
||||
virtual Scope scope() const = 0;
|
||||
|
||||
/// \brief Whether the linker should use direct or indirect access to this
|
||||
/// atom.
|
||||
virtual Interposable interposable() const = 0;
|
||||
|
||||
/// \brief how the linker should handle if multiple atoms have the same name.
|
||||
virtual Merge merge() const = 0;
|
||||
|
||||
/// \brief The type of this atom, such as code or data.
|
||||
virtual ContentType contentType() const = 0;
|
||||
|
||||
/// \brief The alignment constraints on how this atom must be laid out in the
|
||||
/// final linked image (e.g. 16-byte aligned).
|
||||
virtual Alignment alignment() const = 0;
|
||||
|
||||
/// \brief Whether this atom must be in a specially named section in the final
|
||||
/// linked image, or if the linker can infer the section based on the
|
||||
/// contentType().
|
||||
virtual SectionChoice sectionChoice() const = 0;
|
||||
|
||||
/// \brief If sectionChoice() != sectionBasedOnContent, then this return the
|
||||
/// name of the section the atom should be placed into.
|
||||
virtual StringRef customSectionName() const = 0;
|
||||
|
||||
/// \brief constraints on whether the linker may dead strip away this atom.
|
||||
virtual SectionPosition sectionPosition() const = 0;
|
||||
|
||||
/// \brief constraints on whether the linker may dead strip away this atom.
|
||||
virtual DeadStripKind deadStrip() const = 0;
|
||||
|
||||
/// \brief Under which conditions should this atom be dynamically exported.
|
||||
virtual DynamicExport dynamicExport() const {
|
||||
return dynamicExportNormal;
|
||||
}
|
||||
|
||||
/// \brief Returns the OS memory protections required for this atom's content
|
||||
/// at runtime.
|
||||
///
|
||||
/// A function atom is R_X, a global variable is RW_, and a read-only constant
|
||||
/// is R__.
|
||||
virtual ContentPermissions permissions() const;
|
||||
|
||||
/// \brief means this is a zero size atom that exists to provide an alternate
|
||||
/// name for another atom. Alias atoms must have a special Reference to the
|
||||
/// atom they alias which the layout engine recognizes and forces the alias
|
||||
/// atom to layout right before the target atom.
|
||||
virtual bool isAlias() const = 0;
|
||||
|
||||
/// \brief returns a reference to the raw (unrelocated) bytes of this Atom's
|
||||
/// content.
|
||||
virtual ArrayRef<uint8_t> rawContent() const = 0;
|
||||
|
||||
/// This class abstracts iterating over the sequence of References
|
||||
/// in an Atom. Concrete instances of DefinedAtom must implement
|
||||
/// the derefIterator() and incrementIterator() methods.
|
||||
class reference_iterator {
|
||||
public:
|
||||
reference_iterator(const DefinedAtom &a, const void *it)
|
||||
: _atom(a), _it(it) { }
|
||||
|
||||
const Reference *operator*() const {
|
||||
return _atom.derefIterator(_it);
|
||||
}
|
||||
|
||||
const Reference *operator->() const {
|
||||
return _atom.derefIterator(_it);
|
||||
}
|
||||
|
||||
bool operator!=(const reference_iterator &other) const {
|
||||
return _it != other._it;
|
||||
}
|
||||
|
||||
reference_iterator &operator++() {
|
||||
_atom.incrementIterator(_it);
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
const DefinedAtom &_atom;
|
||||
const void *_it;
|
||||
};
|
||||
|
||||
/// \brief Returns an iterator to the beginning of this Atom's References.
|
||||
virtual reference_iterator begin() const = 0;
|
||||
|
||||
/// \brief Returns an iterator to the end of this Atom's References.
|
||||
virtual reference_iterator end() const = 0;
|
||||
|
||||
static inline bool classof(const Atom *a) {
|
||||
return a->definition() == definitionRegular;
|
||||
}
|
||||
|
||||
/// Utility for deriving permissions from content type
|
||||
static ContentPermissions permissions(ContentType type);
|
||||
|
||||
/// Utility function to check if the atom occupies file space
|
||||
virtual bool occupiesDiskSpace() const {
|
||||
ContentType atomContentType = contentType();
|
||||
return !(atomContentType == DefinedAtom::typeZeroFill ||
|
||||
atomContentType == DefinedAtom::typeZeroFillFast ||
|
||||
atomContentType == DefinedAtom::typeTLVInitialZeroFill ||
|
||||
atomContentType == DefinedAtom::typeThreadZeroFill);
|
||||
}
|
||||
|
||||
protected:
|
||||
// DefinedAtom is an abstract base class. Only subclasses can access
|
||||
// constructor.
|
||||
DefinedAtom() : Atom(definitionRegular) { }
|
||||
|
||||
// The memory for DefinedAtom objects is always managed by the owning File
|
||||
// object. Therefore, no one but the owning File object should call delete on
|
||||
// an Atom. In fact, some File objects may bulk allocate an array of Atoms,
|
||||
// so they cannot be individually deleted by anyone.
|
||||
virtual ~DefinedAtom() {}
|
||||
|
||||
/// \brief Returns a pointer to the Reference object that the abstract
|
||||
/// iterator "points" to.
|
||||
virtual const Reference *derefIterator(const void *iter) const = 0;
|
||||
|
||||
/// \brief Adjusts the abstract iterator to "point" to the next Reference
|
||||
/// object for this Atom.
|
||||
virtual void incrementIterator(const void *&iter) const = 0;
|
||||
};
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,84 +0,0 @@
|
||||
//===- Error.h - system_error extensions for lld ----------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This declares a new error_category for the lld library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_ERROR_H
|
||||
#define LLD_CORE_ERROR_H
|
||||
|
||||
#include "llvm/Support/system_error.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
const llvm::error_category &native_reader_category();
|
||||
|
||||
enum class NativeReaderError {
|
||||
success = 0,
|
||||
unknown_file_format,
|
||||
file_too_short,
|
||||
file_malformed,
|
||||
unknown_chunk_type,
|
||||
memory_error,
|
||||
};
|
||||
|
||||
inline llvm::error_code make_error_code(NativeReaderError e) {
|
||||
return llvm::error_code(static_cast<int>(e), native_reader_category());
|
||||
}
|
||||
|
||||
const llvm::error_category &YamlReaderCategory();
|
||||
|
||||
enum class YamlReaderError {
|
||||
success = 0,
|
||||
unknown_keyword,
|
||||
illegal_value
|
||||
};
|
||||
|
||||
inline llvm::error_code make_error_code(YamlReaderError e) {
|
||||
return llvm::error_code(static_cast<int>(e), YamlReaderCategory());
|
||||
}
|
||||
|
||||
const llvm::error_category &LinkerScriptReaderCategory();
|
||||
|
||||
enum class LinkerScriptReaderError {
|
||||
success = 0,
|
||||
parse_error
|
||||
};
|
||||
|
||||
inline llvm::error_code make_error_code(LinkerScriptReaderError e) {
|
||||
return llvm::error_code(static_cast<int>(e), LinkerScriptReaderCategory());
|
||||
}
|
||||
|
||||
/// \brief Errors returned by InputGraph functionality
|
||||
const llvm::error_category &InputGraphErrorCategory();
|
||||
|
||||
enum class InputGraphError {
|
||||
success = 0,
|
||||
failure = 1,
|
||||
no_more_elements,
|
||||
no_more_files
|
||||
};
|
||||
|
||||
inline llvm::error_code make_error_code(InputGraphError e) {
|
||||
return llvm::error_code(static_cast<int>(e), InputGraphErrorCategory());
|
||||
}
|
||||
|
||||
} // end namespace lld
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <> struct is_error_code_enum<lld::NativeReaderError> : true_type {};
|
||||
template <> struct is_error_code_enum<lld::YamlReaderError> : true_type {};
|
||||
template <>
|
||||
struct is_error_code_enum<lld::LinkerScriptReaderError> : true_type {};
|
||||
template <> struct is_error_code_enum<lld::InputGraphError> : true_type {};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
251
external/bsd/llvm/dist/lld/include/lld/Core/File.h
vendored
251
external/bsd/llvm/dist/lld/include/lld/Core/File.h
vendored
@@ -1,251 +0,0 @@
|
||||
//===- Core/File.h - A Container of Atoms ---------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_FILE_H
|
||||
#define LLD_CORE_FILE_H
|
||||
|
||||
#include "lld/Core/AbsoluteAtom.h"
|
||||
#include "lld/Core/DefinedAtom.h"
|
||||
#include "lld/Core/range.h"
|
||||
#include "lld/Core/SharedLibraryAtom.h"
|
||||
#include "lld/Core/LinkingContext.h"
|
||||
#include "lld/Core/UndefinedAtom.h"
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
|
||||
class LinkingContext;
|
||||
|
||||
/// Every Atom is owned by some File. A common scenario is for a single
|
||||
/// object file (.o) to be parsed by some reader and produce a single
|
||||
/// File object that represents the content of that object file.
|
||||
///
|
||||
/// To iterate through the Atoms in a File there are four methods that
|
||||
/// return collections. For instance to iterate through all the DefinedAtoms
|
||||
/// in a File object use:
|
||||
/// for (const DefinedAtoms *atom : file->defined()) {
|
||||
/// }
|
||||
///
|
||||
/// The Atom objects in a File are owned by the File object. The Atom objects
|
||||
/// are destroyed when the File object is destroyed.
|
||||
class File {
|
||||
public:
|
||||
virtual ~File();
|
||||
|
||||
/// \brief Kinds of files that are supported.
|
||||
enum Kind {
|
||||
kindObject, ///< object file (.o)
|
||||
kindSharedLibrary, ///< shared library (.so)
|
||||
kindArchiveLibrary, ///< archive (.a)
|
||||
kindLinkerScript, ///< linker script
|
||||
};
|
||||
|
||||
/// \brief Returns file kind. Need for dyn_cast<> on File objects.
|
||||
Kind kind() const {
|
||||
return _kind;
|
||||
}
|
||||
|
||||
/// \brief For error messages and debugging, this returns the path to the file
|
||||
/// which was used to create this object (e.g. "/tmp/foo.o").
|
||||
StringRef path() const {
|
||||
return _path;
|
||||
}
|
||||
|
||||
/// \brief Returns the path of the source file used to create the object
|
||||
/// file which this (File) object represents. This information is usually
|
||||
/// parsed out of the DWARF debug information. If the source file cannot
|
||||
/// be ascertained, this method returns the empty string.
|
||||
virtual StringRef translationUnitSource() const;
|
||||
|
||||
/// Returns the command line order of the file.
|
||||
uint64_t ordinal() const {
|
||||
assert(_ordinal != UINT64_MAX);
|
||||
return _ordinal;
|
||||
}
|
||||
|
||||
/// Returns true/false depending on whether an ordinal has been set.
|
||||
bool hasOrdinal() const { return (_ordinal != UINT64_MAX); }
|
||||
|
||||
/// Sets the command line order of the file.
|
||||
void setOrdinal(uint64_t ordinal) const { _ordinal = ordinal; }
|
||||
|
||||
public:
|
||||
template <typename T> class atom_iterator; // forward reference
|
||||
|
||||
/// \brief For use interating over DefinedAtoms in this File.
|
||||
typedef atom_iterator<DefinedAtom> defined_iterator;
|
||||
|
||||
/// \brief For use interating over UndefinedAtoms in this File.
|
||||
typedef atom_iterator<UndefinedAtom> undefined_iterator;
|
||||
|
||||
/// \brief For use interating over SharedLibraryAtoms in this File.
|
||||
typedef atom_iterator<SharedLibraryAtom> shared_library_iterator;
|
||||
|
||||
/// \brief For use interating over AbsoluteAtoms in this File.
|
||||
typedef atom_iterator<AbsoluteAtom> absolute_iterator;
|
||||
|
||||
/// \brief Different object file readers may instantiate and manage atoms with
|
||||
/// different data structures. This class is a collection abstraction.
|
||||
/// Each concrete File instance must implement these atom_collection
|
||||
/// methods to enable clients to interate the File's atoms.
|
||||
template <typename T>
|
||||
class atom_collection {
|
||||
public:
|
||||
virtual ~atom_collection() { }
|
||||
virtual atom_iterator<T> begin() const = 0;
|
||||
virtual atom_iterator<T> end() const = 0;
|
||||
virtual const T *deref(const void *it) const = 0;
|
||||
virtual void next(const void *&it) const = 0;
|
||||
virtual uint64_t size() const = 0;
|
||||
};
|
||||
|
||||
/// \brief The class is the iterator type used to iterate through a File's
|
||||
/// Atoms. This iterator delegates the work to the associated atom_collection
|
||||
/// object. There are four kinds of Atoms, so this iterator is templated on
|
||||
/// the four base Atom kinds.
|
||||
template <typename T>
|
||||
class atom_iterator {
|
||||
public:
|
||||
atom_iterator(const atom_collection<T> &c, const void *it)
|
||||
: _collection(c), _it(it) { }
|
||||
|
||||
const T *operator*() const {
|
||||
return _collection.deref(_it);
|
||||
}
|
||||
const T *operator->() const {
|
||||
|
||||
return _collection.deref(_it);
|
||||
}
|
||||
|
||||
bool operator!=(const atom_iterator<T> &other) const {
|
||||
return (this->_it != other._it);
|
||||
}
|
||||
|
||||
atom_iterator<T> &operator++() {
|
||||
_collection.next(_it);
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
const atom_collection<T> &_collection;
|
||||
const void *_it;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Must be implemented to return the atom_collection object for
|
||||
/// all DefinedAtoms in this File.
|
||||
virtual const atom_collection<DefinedAtom> &defined() const = 0;
|
||||
|
||||
/// \brief Must be implemented to return the atom_collection object for
|
||||
/// all UndefinedAtomw in this File.
|
||||
virtual const atom_collection<UndefinedAtom> &undefined() const = 0;
|
||||
|
||||
/// \brief Must be implemented to return the atom_collection object for
|
||||
/// all SharedLibraryAtoms in this File.
|
||||
virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const = 0;
|
||||
|
||||
/// \brief Must be implemented to return the atom_collection object for
|
||||
/// all AbsoluteAtoms in this File.
|
||||
virtual const atom_collection<AbsoluteAtom> &absolute() const = 0;
|
||||
|
||||
virtual const LinkingContext &getLinkingContext() const = 0;
|
||||
|
||||
protected:
|
||||
/// \brief only subclasses of File can be instantiated
|
||||
File(StringRef p, Kind kind) : _path(p), _kind(kind), _ordinal(UINT64_MAX) {}
|
||||
|
||||
/// \brief This is a convenience class for File subclasses which manage their
|
||||
/// atoms as a simple std::vector<>.
|
||||
template <typename T>
|
||||
class atom_collection_vector : public atom_collection<T> {
|
||||
public:
|
||||
virtual atom_iterator<T> begin() const {
|
||||
return atom_iterator<T>(*this,
|
||||
_atoms.empty() ? 0 : reinterpret_cast<const void *>(_atoms.data()));
|
||||
}
|
||||
|
||||
virtual atom_iterator<T> end() const{
|
||||
return atom_iterator<T>(*this, _atoms.empty() ? 0 :
|
||||
reinterpret_cast<const void *>(_atoms.data() + _atoms.size()));
|
||||
}
|
||||
|
||||
virtual const T *deref(const void *it) const {
|
||||
return *reinterpret_cast<const T* const*>(it);
|
||||
}
|
||||
|
||||
virtual void next(const void *&it) const {
|
||||
const T *const *p = reinterpret_cast<const T *const*>(it);
|
||||
++p;
|
||||
it = reinterpret_cast<const void*>(p);
|
||||
}
|
||||
|
||||
virtual uint64_t size() const { return _atoms.size(); }
|
||||
|
||||
std::vector<const T *> _atoms;
|
||||
};
|
||||
|
||||
/// \brief This is a convenience class for File subclasses which need to
|
||||
/// return an empty collection.
|
||||
template <typename T>
|
||||
class atom_collection_empty : public atom_collection<T> {
|
||||
public:
|
||||
virtual atom_iterator<T> begin() const {
|
||||
return atom_iterator<T>(*this, nullptr);
|
||||
}
|
||||
virtual atom_iterator<T> end() const{
|
||||
return atom_iterator<T>(*this, nullptr);
|
||||
}
|
||||
virtual const T *deref(const void *it) const {
|
||||
llvm_unreachable("empty collection should never be accessed");
|
||||
}
|
||||
virtual void next(const void *&it) const {
|
||||
}
|
||||
virtual void push_back(const T *element) {
|
||||
llvm_unreachable("empty collection should never be grown");
|
||||
}
|
||||
virtual uint64_t size() const { return 0; }
|
||||
};
|
||||
|
||||
static atom_collection_empty<DefinedAtom> _noDefinedAtoms;
|
||||
static atom_collection_empty<UndefinedAtom> _noUndefinedAtoms;
|
||||
static atom_collection_empty<SharedLibraryAtom> _noSharedLibraryAtoms;
|
||||
static atom_collection_empty<AbsoluteAtom> _noAbsoluteAtoms;
|
||||
|
||||
private:
|
||||
StringRef _path;
|
||||
Kind _kind;
|
||||
mutable uint64_t _ordinal;
|
||||
};
|
||||
|
||||
/// \brief A mutable File.
|
||||
class MutableFile : public File {
|
||||
public:
|
||||
/// \brief Add an atom to the file. Invalidates iterators for all returned
|
||||
/// containters.
|
||||
virtual void addAtom(const Atom&) = 0;
|
||||
|
||||
typedef range<std::vector<const DefinedAtom *>::iterator> DefinedAtomRange;
|
||||
virtual DefinedAtomRange definedAtoms() = 0;
|
||||
|
||||
virtual const LinkingContext &getLinkingContext() const { return _context; }
|
||||
|
||||
protected:
|
||||
/// \brief only subclasses of MutableFile can be instantiated
|
||||
MutableFile(const LinkingContext &ctx, StringRef p)
|
||||
: File(p, kindObject), _context(ctx) {}
|
||||
|
||||
private:
|
||||
const LinkingContext &_context;
|
||||
};
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,411 +0,0 @@
|
||||
//===- lld/Core/InputGraph.h - Input Graph --------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
///
|
||||
/// Inputs to the linker in the form of a Graph.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_INPUT_GRAPH_H
|
||||
#define LLD_CORE_INPUT_GRAPH_H
|
||||
|
||||
#include "lld/Core/File.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
|
||||
class InputElement;
|
||||
class LinkingContext;
|
||||
|
||||
/// \brief The inputs to the linker are represented by an InputGraph. The
|
||||
/// nodes in the input graph contains Input elements. The InputElements are
|
||||
/// either Input Files or Control Options. The Input Files represent each Input
|
||||
/// File to the linker and the control option specify what the linker needs
|
||||
/// to do when it processes the option.
|
||||
/// Each InputElement that is part of the Graph has an Ordinal value
|
||||
/// associated with it. The ordinal value is needed for the Writer to figure out
|
||||
/// the relative position of the arguments that appeared in the Command Line.
|
||||
/// InputElements have a weight function that can be used to determine the
|
||||
/// weight of the file, for statistical purposes.
|
||||
class InputGraph {
|
||||
public:
|
||||
typedef std::vector<std::unique_ptr<InputElement> > InputElementVectorT;
|
||||
typedef InputElementVectorT::iterator InputElementIterT;
|
||||
typedef std::vector<std::unique_ptr<File> > FileVectorT;
|
||||
typedef FileVectorT::iterator FileIterT;
|
||||
|
||||
/// Where do we want to insert the input element when calling the
|
||||
/// insertElementAt, insertOneElementAt API's.
|
||||
enum Position : uint8_t {
|
||||
ANY,
|
||||
BEGIN,
|
||||
END
|
||||
};
|
||||
|
||||
/// \brief Initialize the inputgraph
|
||||
InputGraph() : _ordinal(0), _nextElementIndex(0) {}
|
||||
|
||||
/// \brief Adds a node into the InputGraph
|
||||
virtual bool addInputElement(std::unique_ptr<InputElement>);
|
||||
|
||||
/// \brief Set Ordinals for all the InputElements that form the InputGraph
|
||||
virtual bool assignOrdinals();
|
||||
|
||||
/// Destructor
|
||||
virtual ~InputGraph() {}
|
||||
|
||||
/// \brief Do postprocessing of the InputGraph if there is a need for the
|
||||
/// to provide additional information to the user, also rearranges
|
||||
/// InputElements by their ordinals. If an user wants to place an input file
|
||||
/// at the desired position, the user can do that
|
||||
virtual void doPostProcess();
|
||||
|
||||
range<InputElementIterT> inputElements() {
|
||||
return make_range(_inputArgs.begin(), _inputArgs.end());
|
||||
}
|
||||
|
||||
/// \brief Validate the input graph
|
||||
virtual bool validate();
|
||||
|
||||
// \brief Does the inputGraph contain any elements
|
||||
size_t size() const { return _inputArgs.size(); }
|
||||
|
||||
/// \brief Dump the input Graph
|
||||
virtual bool dump(raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
InputElement &operator[](size_t index) const {
|
||||
return (*_inputArgs[index]);
|
||||
}
|
||||
|
||||
/// \brief Insert a vector of elements into the input graph at position.
|
||||
virtual void insertElementsAt(std::vector<std::unique_ptr<InputElement> >,
|
||||
Position position, size_t pos = 0);
|
||||
|
||||
/// \brief Insert an element into the input graph at position.
|
||||
virtual void insertOneElementAt(std::unique_ptr<InputElement>,
|
||||
Position position, size_t pos = 0);
|
||||
|
||||
/// \brief Helper functions for the resolver
|
||||
virtual ErrorOr<InputElement *> getNextInputElement();
|
||||
|
||||
/// \brief Set the index on what inputElement has to be returned
|
||||
virtual error_code setNextElementIndex(uint32_t index = 0);
|
||||
|
||||
/// \brief Reset the inputGraph for the inputGraph to start processing
|
||||
/// files from the beginning
|
||||
virtual error_code reset() { return setNextElementIndex(0); }
|
||||
|
||||
protected:
|
||||
// Input arguments
|
||||
InputElementVectorT _inputArgs;
|
||||
// Ordinals
|
||||
int64_t _ordinal;
|
||||
// Index of the next element to be processed
|
||||
uint32_t _nextElementIndex;
|
||||
};
|
||||
|
||||
/// \brief This describes each element in the InputGraph. The Kind
|
||||
/// determines what the current node contains.
|
||||
class InputElement {
|
||||
public:
|
||||
/// Each input element in the graph can be a File or a control
|
||||
enum class Kind : uint8_t {
|
||||
Control, // Represents a type associated with ControlNodes
|
||||
SimpleFile, // Represents a type reserved for internal files
|
||||
File // Represents a type associated with File Nodes
|
||||
};
|
||||
|
||||
/// \brief Initialize the Input Element, The ordinal value of an input Element
|
||||
/// is initially set to -1, if the user wants to override its ordinal,
|
||||
/// let the user do it
|
||||
InputElement(Kind type, int64_t ordinal = -1);
|
||||
|
||||
virtual ~InputElement() {}
|
||||
|
||||
/// Return the Element Type for an Input Element
|
||||
virtual Kind kind() const { return _kind; }
|
||||
|
||||
virtual void setOrdinal(int64_t ordinal) {
|
||||
if (_ordinal != -1)
|
||||
_ordinal = ordinal;
|
||||
}
|
||||
|
||||
virtual int64_t getOrdinal() const { return _ordinal; }
|
||||
|
||||
virtual int64_t weight() const { return _weight; }
|
||||
|
||||
virtual void setWeight(int64_t weight) { _weight = weight; }
|
||||
|
||||
/// \brief validates the Input Element
|
||||
virtual bool validate() = 0;
|
||||
|
||||
/// \brief Dump the Input Element
|
||||
virtual bool dump(raw_ostream &diagnostics) = 0;
|
||||
|
||||
/// \brief parse the input element
|
||||
virtual error_code parse(const LinkingContext &, raw_ostream &) = 0;
|
||||
|
||||
/// \brief functions for the resolver to use
|
||||
|
||||
/// Get the next file to be processed by the resolver
|
||||
virtual ErrorOr<File &> getNextFile() = 0;
|
||||
|
||||
/// \brief Set the resolve state for the element
|
||||
virtual void setResolveState(uint32_t state) = 0;
|
||||
|
||||
/// \brief Get the resolve state for the element
|
||||
virtual uint32_t getResolveState() const = 0;
|
||||
|
||||
/// \brief Reset the next index
|
||||
virtual void resetNextIndex() = 0;
|
||||
|
||||
protected:
|
||||
Kind _kind; // The type of the Element
|
||||
int64_t _ordinal; // The ordinal value
|
||||
int64_t _weight; // Weight of the file
|
||||
};
|
||||
|
||||
/// \brief The Control class represents a control node in the InputGraph
|
||||
class ControlNode : public InputElement {
|
||||
public:
|
||||
/// A control node could be of several types supported by InputGraph
|
||||
/// Future kinds of Control node could be added
|
||||
enum class ControlKind : uint8_t{
|
||||
Simple, // Represents a simple control node
|
||||
Group // Represents a type associated with ControlNodes
|
||||
};
|
||||
|
||||
ControlNode(ControlNode::ControlKind controlKind =
|
||||
ControlNode::ControlKind::Simple,
|
||||
int64_t _ordinal = -1)
|
||||
: InputElement(InputElement::Kind::Control, _ordinal),
|
||||
_controlKind(controlKind), _currentElementIndex(0),
|
||||
_nextElementIndex(0) {}
|
||||
|
||||
virtual ~ControlNode() {}
|
||||
|
||||
/// \brief Return the kind of control node
|
||||
virtual ControlNode::ControlKind controlKind() { return _controlKind; }
|
||||
|
||||
/// \brief Process control start/exit
|
||||
virtual bool processControlEnter() { return true; }
|
||||
|
||||
/// \brief Process control start/exit
|
||||
virtual bool processControlExit() { return true; }
|
||||
|
||||
/// Process the input Elemenet
|
||||
virtual bool processInputElement(std::unique_ptr<InputElement> element) = 0;
|
||||
|
||||
/// \brief Casting support
|
||||
static inline bool classof(const InputElement *a) {
|
||||
return a->kind() == InputElement::Kind::Control;
|
||||
}
|
||||
|
||||
range<InputGraph::InputElementIterT> elements() {
|
||||
return make_range(_elements.begin(), _elements.end());
|
||||
}
|
||||
|
||||
virtual void resetNextIndex() {
|
||||
_currentElementIndex = _nextElementIndex = 0;
|
||||
for (auto &elem : _elements)
|
||||
elem->resetNextIndex();
|
||||
}
|
||||
|
||||
virtual uint32_t getResolveState() const;
|
||||
|
||||
virtual void setResolveState(uint32_t);
|
||||
|
||||
protected:
|
||||
ControlKind _controlKind;
|
||||
InputGraph::InputElementVectorT _elements;
|
||||
uint32_t _currentElementIndex;
|
||||
uint32_t _nextElementIndex;
|
||||
};
|
||||
|
||||
/// \brief Represents an Input file in the graph
|
||||
///
|
||||
/// This class represents an input to the linker. It create the MemoryBuffer
|
||||
/// lazily when needed based on the file path. It can also take a MemoryBuffer
|
||||
/// directly.
|
||||
class FileNode : public InputElement {
|
||||
public:
|
||||
FileNode(StringRef path, int64_t ordinal = -1);
|
||||
|
||||
virtual ErrorOr<StringRef> getPath(const LinkingContext &) const {
|
||||
return _path;
|
||||
}
|
||||
|
||||
// The saved input path thats used when a file is not found while
|
||||
// trying to parse a file
|
||||
StringRef getUserPath() const { return _path; }
|
||||
|
||||
virtual ~FileNode() {}
|
||||
|
||||
/// \brief Casting support
|
||||
static inline bool classof(const InputElement *a) {
|
||||
return a->kind() == InputElement::Kind::File;
|
||||
}
|
||||
|
||||
/// \brief create an error string for printing purposes
|
||||
virtual std::string errStr(error_code errc) {
|
||||
std::string msg = errc.message();
|
||||
Twine twine = Twine("Cannot open ") + _path + ": " + msg;
|
||||
return twine.str();
|
||||
}
|
||||
|
||||
/// \brief Get the list of files
|
||||
range<InputGraph::FileIterT> files() {
|
||||
return make_range(_files.begin(), _files.end());
|
||||
}
|
||||
|
||||
/// \brief number of files.
|
||||
size_t numFiles() const { return _files.size(); }
|
||||
|
||||
/// \brief add a file to the list of files
|
||||
virtual void addFiles(InputGraph::FileVectorT files) {
|
||||
for (auto &ai : files)
|
||||
_files.push_back(std::move(ai));
|
||||
}
|
||||
|
||||
/// \brief Reset the file index if the resolver needs to process
|
||||
/// the node again.
|
||||
virtual void resetNextIndex();
|
||||
|
||||
/// \brief Set the resolve state for the FileNode.
|
||||
virtual void setResolveState(uint32_t resolveState) {
|
||||
_resolveState = resolveState;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the resolve state of the FileNode.
|
||||
virtual uint32_t getResolveState() const { return _resolveState; }
|
||||
|
||||
protected:
|
||||
/// \brief Read the file into _buffer.
|
||||
error_code getBuffer(StringRef filePath);
|
||||
|
||||
StringRef _path; // The path of the Input file
|
||||
InputGraph::FileVectorT _files; // A vector of lld File objects
|
||||
std::unique_ptr<MemoryBuffer> _buffer; // Memory buffer to actual
|
||||
// contents
|
||||
uint32_t _resolveState; // The resolve state of the file
|
||||
uint32_t _nextFileIndex; // The next file that would be processed by the
|
||||
// resolver
|
||||
};
|
||||
|
||||
/// \brief A Control node which contains a group of InputElements
|
||||
/// This affects the resolver so that it resolves undefined symbols
|
||||
/// in the group completely before looking at other input files that
|
||||
/// follow the group
|
||||
class Group : public ControlNode {
|
||||
public:
|
||||
Group(int64_t ordinal)
|
||||
: ControlNode(ControlNode::ControlKind::Group, ordinal) {}
|
||||
|
||||
static inline bool classof(const InputElement *a) {
|
||||
return a->kind() == InputElement::Kind::Control;
|
||||
}
|
||||
|
||||
/// \brief Process input element and add it to the group
|
||||
virtual bool processInputElement(std::unique_ptr<InputElement> element) {
|
||||
_elements.push_back(std::move(element));
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual ErrorOr<File &> getNextFile();
|
||||
};
|
||||
|
||||
/// \brief Represents Internal Input files
|
||||
class SimpleFileNode : public InputElement {
|
||||
public:
|
||||
SimpleFileNode(StringRef path, int64_t ordinal = -1);
|
||||
|
||||
virtual ErrorOr<StringRef> path(const LinkingContext &) const {
|
||||
return _path;
|
||||
}
|
||||
|
||||
// The saved input path thats used when a file is not found while
|
||||
// trying to parse a file
|
||||
StringRef getUserPath() const { return _path; }
|
||||
|
||||
virtual ~SimpleFileNode() {}
|
||||
|
||||
/// \brief Casting support
|
||||
static inline bool classof(const InputElement *a) {
|
||||
return a->kind() == InputElement::Kind::SimpleFile;
|
||||
}
|
||||
|
||||
/// \brief Get the list of files
|
||||
range<InputGraph::FileIterT> files() {
|
||||
return make_range(_files.begin(), _files.end());
|
||||
}
|
||||
|
||||
/// \brief number of files.
|
||||
size_t numFiles() const { return _files.size(); }
|
||||
|
||||
/// \brief add a file to the list of files
|
||||
virtual void appendInputFile(std::unique_ptr<File> f) {
|
||||
_files.push_back(std::move(f));
|
||||
}
|
||||
|
||||
/// \brief add a file to the list of files
|
||||
virtual void appendInputFiles(InputGraph::FileVectorT files) {
|
||||
for (auto &ai : files)
|
||||
_files.push_back(std::move(ai));
|
||||
}
|
||||
|
||||
/// \brief validates the Input Element
|
||||
virtual bool validate() { return true; }
|
||||
|
||||
/// \brief Dump the Input Element
|
||||
virtual bool dump(raw_ostream &) { return true; }
|
||||
|
||||
/// \brief parse the input element
|
||||
virtual error_code parse(const LinkingContext &, raw_ostream &) {
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
/// \brief Return the next File thats part of this node to the
|
||||
/// resolver.
|
||||
virtual ErrorOr<File &> getNextFile() {
|
||||
if (_nextFileIndex == _files.size())
|
||||
return make_error_code(InputGraphError::no_more_files);
|
||||
return *_files[_nextFileIndex++];
|
||||
}
|
||||
|
||||
/// \brief Set the resolver state.
|
||||
virtual void setResolveState(uint32_t resolveState) {
|
||||
_resolveState = resolveState;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the resolve state.
|
||||
virtual uint32_t getResolveState() const { return _resolveState; }
|
||||
|
||||
// Do nothing here.
|
||||
virtual void resetNextIndex() {}
|
||||
|
||||
protected:
|
||||
StringRef _path; // A string associated with this file.
|
||||
InputGraph::FileVectorT _files; // Vector of lld::File objects
|
||||
uint32_t _nextFileIndex; // The next file that would be processed by the
|
||||
// resolver
|
||||
uint32_t _resolveState; // The resolve state associated with this Node
|
||||
};
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_DRIVER_INPUT_GRAPH_H
|
||||
@@ -1,133 +0,0 @@
|
||||
//===- include/Core/Instrumentation.h - Instrumentation API ---------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Provide an Instrumentation API that optionally uses VTune interfaces.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_INSTRUMENTATION_H
|
||||
#define LLD_CORE_INSTRUMENTATION_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#ifdef LLD_HAS_VTUNE
|
||||
# include <ittnotify.h>
|
||||
#endif
|
||||
|
||||
namespace lld {
|
||||
#ifdef LLD_HAS_VTUNE
|
||||
/// \brief A unique global scope for instrumentation data.
|
||||
///
|
||||
/// Domains last for the lifetime of the application and cannot be destroyed.
|
||||
/// Multiple Domains created with the same name represent the same domain.
|
||||
class Domain {
|
||||
__itt_domain *_domain;
|
||||
|
||||
public:
|
||||
explicit Domain(const char *name) : _domain(__itt_domain_createA(name)) {}
|
||||
|
||||
operator __itt_domain *() const { return _domain; }
|
||||
__itt_domain *operator->() const { return _domain; }
|
||||
};
|
||||
|
||||
/// \brief A global reference to a string constant.
|
||||
///
|
||||
/// These are uniqued by the ITT runtime and cannot be deleted. They are not
|
||||
/// specific to a domain.
|
||||
///
|
||||
/// Prefer reusing a single StringHandle over passing a ntbs when the same
|
||||
/// string will be used often.
|
||||
class StringHandle {
|
||||
__itt_string_handle *_handle;
|
||||
|
||||
public:
|
||||
StringHandle(const char *name) : _handle(__itt_string_handle_createA(name)) {}
|
||||
|
||||
operator __itt_string_handle *() const { return _handle; }
|
||||
};
|
||||
|
||||
/// \brief A task on a single thread. Nests within other tasks.
|
||||
///
|
||||
/// Each thread has its own task stack and tasks nest recursively on that stack.
|
||||
/// A task cannot transfer threads.
|
||||
///
|
||||
/// SBRM is used to ensure task starts and ends are ballanced. The lifetime of
|
||||
/// a task is either the liftime of this object, or until end is called.
|
||||
class ScopedTask {
|
||||
__itt_domain *_domain;
|
||||
|
||||
ScopedTask(const ScopedTask &) LLVM_DELETED_FUNCTION;
|
||||
ScopedTask &operator=(const ScopedTask &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
public:
|
||||
/// \brief Create a task in Domain \p d named \p s.
|
||||
ScopedTask(const Domain &d, const StringHandle &s) : _domain(d) {
|
||||
__itt_task_begin(d, __itt_null, __itt_null, s);
|
||||
}
|
||||
|
||||
ScopedTask(ScopedTask &&other) {
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
ScopedTask &operator=(ScopedTask &&other) {
|
||||
_domain = other._domain;
|
||||
other._domain = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Prematurely end this task.
|
||||
void end() {
|
||||
if (_domain)
|
||||
__itt_task_end(_domain);
|
||||
_domain = nullptr;
|
||||
}
|
||||
|
||||
~ScopedTask() { end(); }
|
||||
};
|
||||
|
||||
/// \brief A specific point in time. Allows metadata to be associated.
|
||||
class Marker {
|
||||
public:
|
||||
Marker(const Domain &d, const StringHandle &s) {
|
||||
__itt_marker(d, __itt_null, s, __itt_scope_global);
|
||||
}
|
||||
};
|
||||
#else
|
||||
class Domain {
|
||||
public:
|
||||
Domain(const char *name) {}
|
||||
};
|
||||
|
||||
class StringHandle {
|
||||
public:
|
||||
StringHandle(const char *name) {}
|
||||
};
|
||||
|
||||
class ScopedTask {
|
||||
public:
|
||||
ScopedTask(const Domain &d, const StringHandle &s) {}
|
||||
void end() {}
|
||||
};
|
||||
|
||||
class Marker {
|
||||
public:
|
||||
Marker(const Domain &d, const StringHandle &s) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
inline const Domain &getDefaultDomain() {
|
||||
static Domain domain("org.llvm.lld");
|
||||
return domain;
|
||||
}
|
||||
} // end namespace lld.
|
||||
|
||||
#endif
|
||||
@@ -1,92 +0,0 @@
|
||||
//===--- LLVM.h - Import various common LLVM datatypes ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file forward declares and imports various common LLVM datatypes that
|
||||
// lld wants to use unqualified.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_LLVM_H
|
||||
#define LLD_CORE_LLVM_H
|
||||
|
||||
// This should be the only #include, force #includes of all the others on
|
||||
// clients.
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
// ADT's.
|
||||
class StringRef;
|
||||
class Twine;
|
||||
class MemoryBuffer;
|
||||
template<typename T> class ArrayRef;
|
||||
template<class T> class OwningPtr;
|
||||
template<unsigned InternalLen> class SmallString;
|
||||
template<typename T, unsigned N> class SmallVector;
|
||||
template<typename T> class SmallVectorImpl;
|
||||
|
||||
template<typename T>
|
||||
struct SaveAndRestore;
|
||||
|
||||
template<typename T>
|
||||
class ErrorOr;
|
||||
|
||||
// Reference counting.
|
||||
template <typename T> class IntrusiveRefCntPtr;
|
||||
template <typename T> struct IntrusiveRefCntPtrInfo;
|
||||
template <class Derived> class RefCountedBase;
|
||||
class RefCountedBaseVPTR;
|
||||
|
||||
class error_code;
|
||||
class raw_ostream;
|
||||
// TODO: DenseMap, ...
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
// Casting operators.
|
||||
using llvm::isa;
|
||||
using llvm::cast;
|
||||
using llvm::dyn_cast;
|
||||
using llvm::dyn_cast_or_null;
|
||||
using llvm::cast_or_null;
|
||||
|
||||
// ADT's.
|
||||
using llvm::StringRef;
|
||||
using llvm::Twine;
|
||||
using llvm::MemoryBuffer;
|
||||
using llvm::ArrayRef;
|
||||
using llvm::OwningPtr;
|
||||
using llvm::SmallString;
|
||||
using llvm::SmallVector;
|
||||
using llvm::SmallVectorImpl;
|
||||
using llvm::SaveAndRestore;
|
||||
using llvm::ErrorOr;
|
||||
|
||||
// Reference counting.
|
||||
using llvm::IntrusiveRefCntPtr;
|
||||
using llvm::IntrusiveRefCntPtrInfo;
|
||||
using llvm::RefCountedBase;
|
||||
using llvm::RefCountedBaseVPTR;
|
||||
|
||||
using llvm::error_code;
|
||||
using llvm::raw_ostream;
|
||||
} // end namespace clang.
|
||||
|
||||
namespace std {
|
||||
template <> struct hash<llvm::StringRef> {
|
||||
public:
|
||||
size_t operator()(const llvm::StringRef &s) const {
|
||||
return llvm::hash_value(s);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,378 +0,0 @@
|
||||
//===- lld/Core/LinkingContext.h - Linker Target Info Interface -----------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_LINKING_CONTEXT_H
|
||||
#define LLD_CORE_LINKING_CONTEXT_H
|
||||
|
||||
#include "lld/Core/Error.h"
|
||||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/Core/LLVM.h"
|
||||
#include "lld/Core/range.h"
|
||||
#include "lld/Core/Reference.h"
|
||||
|
||||
#include "lld/ReaderWriter/Reader.h"
|
||||
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class Triple;
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
class PassManager;
|
||||
class File;
|
||||
class Writer;
|
||||
class InputGraph;
|
||||
class InputElement;
|
||||
|
||||
/// \brief The LinkingContext class encapsulates "what and how" to link.
|
||||
///
|
||||
/// The base class LinkingContext contains the options needed by core linking.
|
||||
/// Subclasses of LinkingContext have additional options needed by specific
|
||||
/// Readers
|
||||
/// and Writers. For example, ELFLinkingContext has methods that supplies
|
||||
/// options
|
||||
/// to the ELF Reader and Writer.
|
||||
class LinkingContext {
|
||||
public:
|
||||
/// \brief The types of output file that the linker
|
||||
/// creates.
|
||||
enum class OutputFileType : uint8_t {
|
||||
Default, // The default output type for this target
|
||||
YAML, // The output type is set to YAML
|
||||
Native // The output file format is Native (Atoms)
|
||||
};
|
||||
|
||||
virtual ~LinkingContext();
|
||||
|
||||
/// \name Methods needed by core linking
|
||||
/// @{
|
||||
|
||||
/// Name of symbol linker should use as "entry point" to program,
|
||||
/// usually "main" or "start".
|
||||
virtual StringRef entrySymbolName() const { return _entrySymbolName; }
|
||||
|
||||
/// Whether core linking should remove Atoms not reachable by following
|
||||
/// References from the entry point Atom or from all global scope Atoms
|
||||
/// if globalsAreDeadStripRoots() is true.
|
||||
bool deadStrip() const { return _deadStrip; }
|
||||
|
||||
/// Only used if deadStrip() returns true. Means all global scope Atoms
|
||||
/// should be marked live (along with all Atoms they reference). Usually
|
||||
/// this method returns false for main executables, but true for dynamic
|
||||
/// shared libraries.
|
||||
bool globalsAreDeadStripRoots() const {
|
||||
assert(_deadStrip && "only applicable when deadstripping enabled");
|
||||
return _globalsAreDeadStripRoots;
|
||||
}
|
||||
|
||||
/// Only used if deadStrip() returns true. This method returns the names
|
||||
/// of DefinedAtoms that should be marked live (along with all Atoms they
|
||||
/// reference). Only Atoms with scope scopeLinkageUnit or scopeGlobal can
|
||||
/// be kept live using this method.
|
||||
const std::vector<StringRef> &deadStripRoots() const {
|
||||
return _deadStripRoots;
|
||||
}
|
||||
|
||||
/// Add the given symbol name to the dead strip root set. Only used if
|
||||
/// deadStrip() returns true.
|
||||
void addDeadStripRoot(StringRef symbolName) {
|
||||
assert(_deadStrip && "only applicable when deadstripping enabled");
|
||||
assert(!symbolName.empty() && "Empty symbol cannot be a dead strip root");
|
||||
_deadStripRoots.push_back(symbolName);
|
||||
}
|
||||
|
||||
/// Archive files (aka static libraries) are normally lazily loaded. That is,
|
||||
/// object files within an archive are only loaded and linked in, if the
|
||||
/// object file contains a DefinedAtom which will replace an existing
|
||||
/// UndefinedAtom. If this method returns true, core linking will also look
|
||||
/// for archive members to replace existing tentative definitions in addition
|
||||
/// to replacing undefines. Note: a "tentative definition" (also called a
|
||||
/// "common" symbols) is a C (but not C++) concept. They are modeled in lld
|
||||
/// as a DefinedAtom with merge() of mergeAsTentative.
|
||||
bool searchArchivesToOverrideTentativeDefinitions() const {
|
||||
return _searchArchivesToOverrideTentativeDefinitions;
|
||||
}
|
||||
|
||||
/// Normally core linking will turn a tentative definition into a real
|
||||
/// definition if not replaced by a real DefinedAtom from some object file.
|
||||
/// If this method returns true, core linking will search all supplied
|
||||
/// dynamic shared libraries for symbol names that match remaining tentative
|
||||
/// definitions. If any are found, the corresponding tentative definition
|
||||
/// atom is replaced with SharedLibraryAtom.
|
||||
bool searchSharedLibrariesToOverrideTentativeDefinitions() const {
|
||||
return _searchSharedLibrariesToOverrideTentativeDefinitions;
|
||||
}
|
||||
|
||||
/// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
|
||||
/// SharedLibraryAtom for the link to be successful. This method controls
|
||||
/// whether core linking prints out a list of remaining UndefinedAtoms.
|
||||
///
|
||||
/// \todo This should be a method core linking calls with a list of the
|
||||
/// UndefinedAtoms so that different drivers can format the error message
|
||||
/// as needed.
|
||||
bool printRemainingUndefines() const { return _printRemainingUndefines; }
|
||||
|
||||
/// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
|
||||
/// SharedLibraryAtom for the link to be successful. This method controls
|
||||
/// whether core linking considers remaining undefines to be an error.
|
||||
bool allowRemainingUndefines() const { return _allowRemainingUndefines; }
|
||||
|
||||
/// In the lld model, a SharedLibraryAtom is a proxy atom for something
|
||||
/// that will be found in a dynamic shared library when the program runs.
|
||||
/// A SharedLibraryAtom optionally contains the name of the shared library
|
||||
/// in which to find the symbol name at runtime. Core linking may merge
|
||||
/// two SharedLibraryAtom with the same name. If this method returns true,
|
||||
/// when merging core linking will also verify that they both have the same
|
||||
/// loadName() and if not print a warning.
|
||||
///
|
||||
/// \todo This should be a method core linking calls so that drivers can
|
||||
/// format the warning as needed.
|
||||
bool warnIfCoalesableAtomsHaveDifferentLoadName() const {
|
||||
return _warnIfCoalesableAtomsHaveDifferentLoadName;
|
||||
}
|
||||
|
||||
/// In C/C++ you can mark a function's prototype with
|
||||
/// __attribute__((weak_import)) or __attribute__((weak)) to say the function
|
||||
/// may not be available at runtime and/or build time and in which case its
|
||||
/// address will evaluate to NULL. In lld this is modeled using the
|
||||
/// UndefinedAtom::canBeNull() method. During core linking, UndefinedAtom
|
||||
/// with the same name are automatically merged. If this method returns
|
||||
/// true, core link also verfies that the canBeNull() value for merged
|
||||
/// UndefinedAtoms are the same and warns if not.
|
||||
///
|
||||
/// \todo This should be a method core linking calls so that drivers can
|
||||
/// format the warning as needed.
|
||||
bool warnIfCoalesableAtomsHaveDifferentCanBeNull() const {
|
||||
return _warnIfCoalesableAtomsHaveDifferentCanBeNull;
|
||||
}
|
||||
|
||||
/// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
|
||||
/// SharedLibraryAtom for the link to be successful. This method controls
|
||||
/// whether core linking considers remaining undefines from the shared library
|
||||
/// to be an error.
|
||||
bool allowShlibUndefines() const { return _allowShlibUndefines; }
|
||||
|
||||
/// If true, core linking will write the path to each input file to stdout
|
||||
/// (i.e. llvm::outs()) as it is used. This is used to implement the -t
|
||||
/// linker option.
|
||||
///
|
||||
/// \todo This should be a method core linking calls so that drivers can
|
||||
/// format the line as needed.
|
||||
bool logInputFiles() const { return _logInputFiles; }
|
||||
|
||||
/// Parts of LLVM use global variables which are bound to command line
|
||||
/// options (see llvm::cl::Options). This method returns "command line"
|
||||
/// options which are used to configure LLVM's command line settings.
|
||||
/// For instance the -debug-only XXX option can be used to dynamically
|
||||
/// trace different parts of LLVM and lld.
|
||||
const std::vector<const char *> &llvmOptions() const { return _llvmOptions; }
|
||||
|
||||
/// \name Methods used by Drivers to configure TargetInfo
|
||||
/// @{
|
||||
void setOutputPath(StringRef str) { _outputPath = str; }
|
||||
|
||||
// Set the entry symbol name. You may also need to call addDeadStripRoot() for
|
||||
// the symbol if your platform supports dead-stripping, so that the symbol
|
||||
// will not be removed from the output.
|
||||
void setEntrySymbolName(StringRef name) {
|
||||
_entrySymbolName = name;
|
||||
}
|
||||
|
||||
void setDeadStripping(bool enable) { _deadStrip = enable; }
|
||||
void setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; }
|
||||
void setSearchArchivesToOverrideTentativeDefinitions(bool search) {
|
||||
_searchArchivesToOverrideTentativeDefinitions = search;
|
||||
}
|
||||
void setSearchSharedLibrariesToOverrideTentativeDefinitions(bool search) {
|
||||
_searchSharedLibrariesToOverrideTentativeDefinitions = search;
|
||||
}
|
||||
void setWarnIfCoalesableAtomsHaveDifferentCanBeNull(bool warn) {
|
||||
_warnIfCoalesableAtomsHaveDifferentCanBeNull = warn;
|
||||
}
|
||||
void setWarnIfCoalesableAtomsHaveDifferentLoadName(bool warn) {
|
||||
_warnIfCoalesableAtomsHaveDifferentLoadName = warn;
|
||||
}
|
||||
void setPrintRemainingUndefines(bool print) {
|
||||
_printRemainingUndefines = print;
|
||||
}
|
||||
void setAllowRemainingUndefines(bool allow) {
|
||||
_allowRemainingUndefines = allow;
|
||||
}
|
||||
void setAllowShlibUndefines(bool allow) { _allowShlibUndefines = allow; }
|
||||
void setLogInputFiles(bool log) { _logInputFiles = log; }
|
||||
|
||||
void appendLLVMOption(const char *opt) { _llvmOptions.push_back(opt); }
|
||||
virtual void setInputGraph(std::unique_ptr<InputGraph> inputGraph) {
|
||||
_inputGraph = std::move(inputGraph);
|
||||
}
|
||||
virtual InputGraph &inputGraph() const { return *_inputGraph; }
|
||||
|
||||
/// This method adds undefined symbols specified by the -u option to the to
|
||||
/// the list of undefined symbols known to the linker. This option essentially
|
||||
/// forces an undefined symbol to be create. You may also need to call
|
||||
/// addDeadStripRoot() for the symbol if your platform supports dead
|
||||
/// stripping, so that the symbol will not be removed from the output.
|
||||
void addInitialUndefinedSymbol(StringRef symbolName) {
|
||||
_initialUndefinedSymbols.push_back(symbolName);
|
||||
}
|
||||
|
||||
/// Iterators for symbols that appear on the command line
|
||||
typedef std::vector<StringRef> StringRefVector;
|
||||
typedef StringRefVector::iterator StringRefVectorIter;
|
||||
typedef StringRefVector::const_iterator StringRefVectorConstIter;
|
||||
|
||||
/// Create linker internal files containing atoms for the linker to include
|
||||
/// during link. Flavors can override this function in their LinkingContext
|
||||
/// to add more internal files. These internal files are positioned before
|
||||
/// the actual input files.
|
||||
virtual bool createInternalFiles(std::vector<std::unique_ptr<File> > &) const;
|
||||
|
||||
/// Return the list of undefined symbols that are specified in the
|
||||
/// linker command line, using the -u option.
|
||||
range<const StringRef *> initialUndefinedSymbols() const {
|
||||
return _initialUndefinedSymbols;
|
||||
}
|
||||
|
||||
/// After all set* methods are called, the Driver calls this method
|
||||
/// to validate that there are no missing options or invalid combinations
|
||||
/// of options. If there is a problem, a description of the problem
|
||||
/// is written to the supplied stream.
|
||||
///
|
||||
/// \returns true if there is an error with the current settings.
|
||||
bool validate(raw_ostream &diagnostics);
|
||||
|
||||
/// @}
|
||||
/// \name Methods used by Driver::link()
|
||||
/// @{
|
||||
|
||||
/// Returns the file system path to which the linked output should be written.
|
||||
///
|
||||
/// \todo To support in-memory linking, we need an abstraction that allows
|
||||
/// the linker to write to an in-memory buffer.
|
||||
StringRef outputPath() const { return _outputPath; }
|
||||
|
||||
/// Set the various output file types that the linker would
|
||||
/// create
|
||||
bool setOutputFileType(StringRef outputFileType) {
|
||||
if (outputFileType.equals_lower("yaml"))
|
||||
_outputFileType = OutputFileType::YAML;
|
||||
else if (outputFileType.equals_lower("native"))
|
||||
_outputFileType = OutputFileType::YAML;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns the output file that that the linker needs to create
|
||||
OutputFileType outputFileType() const { return _outputFileType; }
|
||||
|
||||
/// Returns the YAML reader.
|
||||
virtual Reader &getYAMLReader() const { return *_yamlReader; }
|
||||
|
||||
/// Returns the LLD Native file format reader.
|
||||
virtual Reader &getNativeReader() const { return *_nativeReader; }
|
||||
|
||||
/// Return the default reader for the target
|
||||
virtual Reader &getDefaultReader() const = 0;
|
||||
|
||||
/// This method is called by core linking to give the Writer a chance
|
||||
/// to add file format specific "files" to set of files to be linked. This is
|
||||
/// how file format specific atoms can be added to the link.
|
||||
virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &) const;
|
||||
|
||||
/// This method is called by core linking to build the list of Passes to be
|
||||
/// run on the merged/linked graph of all input files.
|
||||
virtual void addPasses(PassManager &pm);
|
||||
|
||||
/// Calls through to the writeFile() method on the specified Writer.
|
||||
///
|
||||
/// \param linkedFile This is the merged/linked graph of all input file Atoms.
|
||||
virtual error_code writeFile(const File &linkedFile) const;
|
||||
|
||||
/// nextFile returns the next file that needs to be processed by the resolver.
|
||||
/// The LinkingContext's can override the default behavior to change the way
|
||||
/// the resolver operates. This uses the currentInputElement. When there are
|
||||
/// no more files to be processed an appropriate InputGraphError is
|
||||
/// returned. Ordinals are assigned to files returned by nextFile, which means
|
||||
/// ordinals would be assigned in the way files are resolved.
|
||||
virtual ErrorOr<File &> nextFile();
|
||||
|
||||
/// Set the resolver state for the current Input element This is used by the
|
||||
/// InputGraph to decide the next file that needs to be processed for various
|
||||
/// types of nodes in the InputGraph. The resolver state is nothing but a
|
||||
/// bitmask of various types of states that the resolver handles when adding
|
||||
/// atoms.
|
||||
virtual void setResolverState(uint32_t resolverState);
|
||||
|
||||
/// Return the next ordinal and Increment it.
|
||||
virtual uint64_t getNextOrdinalAndIncrement() const { return _nextOrdinal++; }
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Methods needed by YAML I/O and error messages to convert Kind values
|
||||
/// to and from strings.
|
||||
/// @{
|
||||
|
||||
/// Abstract method to parse a kind name string into an integral
|
||||
/// Reference::Kind
|
||||
virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const = 0;
|
||||
|
||||
/// Abstract method to return the name for a given integral
|
||||
/// Reference::Kind.
|
||||
virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind k) const = 0;
|
||||
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
LinkingContext(); // Must be subclassed
|
||||
|
||||
/// Abstract method to lazily instantiate the Writer.
|
||||
virtual Writer &writer() const = 0;
|
||||
|
||||
/// Method to create a internal file for the entry symbol
|
||||
virtual std::unique_ptr<File> createEntrySymbolFile() const;
|
||||
|
||||
/// Method to create a internal file for an undefined symbol
|
||||
virtual std::unique_ptr<File> createUndefinedSymbolFile() const;
|
||||
|
||||
StringRef _outputPath;
|
||||
StringRef _entrySymbolName;
|
||||
bool _deadStrip;
|
||||
bool _globalsAreDeadStripRoots;
|
||||
bool _searchArchivesToOverrideTentativeDefinitions;
|
||||
bool _searchSharedLibrariesToOverrideTentativeDefinitions;
|
||||
bool _warnIfCoalesableAtomsHaveDifferentCanBeNull;
|
||||
bool _warnIfCoalesableAtomsHaveDifferentLoadName;
|
||||
bool _printRemainingUndefines;
|
||||
bool _allowRemainingUndefines;
|
||||
bool _logInputFiles;
|
||||
bool _allowShlibUndefines;
|
||||
OutputFileType _outputFileType;
|
||||
std::vector<StringRef> _deadStripRoots;
|
||||
std::vector<const char *> _llvmOptions;
|
||||
std::unique_ptr<Reader> _yamlReader;
|
||||
std::unique_ptr<Reader> _nativeReader;
|
||||
StringRefVector _initialUndefinedSymbols;
|
||||
std::unique_ptr<InputGraph> _inputGraph;
|
||||
mutable llvm::BumpPtrAllocator _allocator;
|
||||
InputElement *_currentInputElement;
|
||||
mutable uint64_t _nextOrdinal;
|
||||
|
||||
private:
|
||||
/// Validate the subclass bits. Only called by validate.
|
||||
virtual bool validateImpl(raw_ostream &diagnostics) = 0;
|
||||
};
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,271 +0,0 @@
|
||||
//===- lld/Core/Parallel.h - Parallel utilities ---------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_PARALLEL_H
|
||||
#define LLD_CORE_PARALLEL_H
|
||||
|
||||
#include "lld/Core/Instrumentation.h"
|
||||
#include "lld/Core/LLVM.h"
|
||||
#include "lld/Core/range.h"
|
||||
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Exceptions are disabled so this isn't defined, but concrt assumes it is.
|
||||
namespace {
|
||||
void *__uncaught_exception() { return nullptr; }
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <stack>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <concrt.h>
|
||||
#include <ppl.h>
|
||||
#endif
|
||||
|
||||
namespace lld {
|
||||
/// \brief Allows one or more threads to wait on a potentially unknown number of
|
||||
/// events.
|
||||
///
|
||||
/// A latch starts at \p count. inc() increments this, and dec() decrements it.
|
||||
/// All calls to sync() will block while the count is not 0.
|
||||
///
|
||||
/// Calling dec() on a Latch with a count of 0 has undefined behaivor.
|
||||
class Latch {
|
||||
uint32_t _count;
|
||||
mutable std::mutex _condMut;
|
||||
mutable std::condition_variable _cond;
|
||||
|
||||
public:
|
||||
explicit Latch(uint32_t count = 0) : _count(count) {}
|
||||
~Latch() { sync(); }
|
||||
|
||||
void inc() {
|
||||
std::unique_lock<std::mutex> lock(_condMut);
|
||||
++_count;
|
||||
}
|
||||
|
||||
void dec() {
|
||||
std::unique_lock<std::mutex> lock(_condMut);
|
||||
if (--_count == 0)
|
||||
_cond.notify_all();
|
||||
}
|
||||
|
||||
void sync() const {
|
||||
std::unique_lock<std::mutex> lock(_condMut);
|
||||
_cond.wait(lock, [&] {
|
||||
return _count == 0;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief An abstract class that takes closures and runs them asynchronously.
|
||||
class Executor {
|
||||
public:
|
||||
virtual ~Executor() {}
|
||||
virtual void add(std::function<void()> func) = 0;
|
||||
};
|
||||
|
||||
/// \brief An implementation of an Executor that runs closures on a thread pool
|
||||
/// in filo order.
|
||||
class ThreadPoolExecutor : public Executor {
|
||||
public:
|
||||
explicit ThreadPoolExecutor(unsigned threadCount =
|
||||
std::thread::hardware_concurrency())
|
||||
: _stop(false), _done(threadCount) {
|
||||
// Spawn all but one of the threads in another thread as spawning threads
|
||||
// can take a while.
|
||||
std::thread([&, threadCount] {
|
||||
for (std::size_t i = 1; i < threadCount; ++i) {
|
||||
std::thread([=] {
|
||||
work();
|
||||
}).detach();
|
||||
}
|
||||
work();
|
||||
}).detach();
|
||||
}
|
||||
|
||||
~ThreadPoolExecutor() {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_stop = true;
|
||||
lock.unlock();
|
||||
_cond.notify_all();
|
||||
// Wait for ~Latch.
|
||||
}
|
||||
|
||||
virtual void add(std::function<void()> f) {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_workStack.push(f);
|
||||
lock.unlock();
|
||||
_cond.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
void work() {
|
||||
while (true) {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_cond.wait(lock, [&] {
|
||||
return _stop || !_workStack.empty();
|
||||
});
|
||||
if (_stop)
|
||||
break;
|
||||
auto task = _workStack.top();
|
||||
_workStack.pop();
|
||||
lock.unlock();
|
||||
task();
|
||||
}
|
||||
_done.dec();
|
||||
}
|
||||
|
||||
std::atomic<bool> _stop;
|
||||
std::stack<std::function<void()>> _workStack;
|
||||
std::mutex _mutex;
|
||||
std::condition_variable _cond;
|
||||
Latch _done;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/// \brief An Executor that runs tasks via ConcRT.
|
||||
class ConcRTExecutor : public Executor {
|
||||
struct Taskish {
|
||||
Taskish(std::function<void()> task) : _task(task) {}
|
||||
|
||||
std::function<void()> _task;
|
||||
|
||||
static void run(void *p) {
|
||||
Taskish *self = static_cast<Taskish *>(p);
|
||||
self->_task();
|
||||
concurrency::Free(self);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
virtual void add(std::function<void()> func) {
|
||||
Concurrency::CurrentScheduler::ScheduleTask(Taskish::run,
|
||||
new (concurrency::Alloc(sizeof(Taskish))) Taskish(func));
|
||||
}
|
||||
};
|
||||
|
||||
inline Executor *getDefaultExecutor() {
|
||||
static ConcRTExecutor exec;
|
||||
return &exec;
|
||||
}
|
||||
#else
|
||||
inline Executor *getDefaultExecutor() {
|
||||
static ThreadPoolExecutor exec;
|
||||
return &exec;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \brief Allows launching a number of tasks and waiting for them to finish
|
||||
/// either explicitly via sync() or implicitly on destruction.
|
||||
class TaskGroup {
|
||||
Latch _latch;
|
||||
|
||||
public:
|
||||
void spawn(std::function<void()> f) {
|
||||
_latch.inc();
|
||||
getDefaultExecutor()->add([&, f] {
|
||||
f();
|
||||
_latch.dec();
|
||||
});
|
||||
}
|
||||
|
||||
void sync() const { _latch.sync(); }
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Use ppl parallel_sort on Windows.
|
||||
template <class RandomAccessIterator, class Comp>
|
||||
void parallel_sort(
|
||||
RandomAccessIterator start, RandomAccessIterator end,
|
||||
const Comp &comp = std::less<
|
||||
typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
|
||||
concurrency::parallel_sort(start, end, comp);
|
||||
}
|
||||
#else
|
||||
namespace detail {
|
||||
const ptrdiff_t minParallelSize = 1024;
|
||||
|
||||
/// \brief Inclusive median.
|
||||
template <class RandomAccessIterator, class Comp>
|
||||
RandomAccessIterator medianOf3(RandomAccessIterator start,
|
||||
RandomAccessIterator end, const Comp &comp) {
|
||||
RandomAccessIterator mid = start + (std::distance(start, end) / 2);
|
||||
return comp(*start, *(end - 1))
|
||||
? (comp(*mid, *(end - 1)) ? (comp(*start, *mid) ? mid : start)
|
||||
: end - 1)
|
||||
: (comp(*mid, *start) ? (comp(*(end - 1), *mid) ? mid : end - 1)
|
||||
: start);
|
||||
}
|
||||
|
||||
template <class RandomAccessIterator, class Comp>
|
||||
void parallel_quick_sort(RandomAccessIterator start, RandomAccessIterator end,
|
||||
const Comp &comp, TaskGroup &tg, size_t depth) {
|
||||
// Do a sequential sort for small inputs.
|
||||
if (std::distance(start, end) < detail::minParallelSize || depth == 0) {
|
||||
std::sort(start, end, comp);
|
||||
return;
|
||||
}
|
||||
|
||||
// Partition.
|
||||
auto pivot = medianOf3(start, end, comp);
|
||||
// Move pivot to end.
|
||||
std::swap(*(end - 1), *pivot);
|
||||
pivot = std::partition(start, end - 1, [end](decltype(*start) v) {
|
||||
return v < *(end - 1);
|
||||
});
|
||||
// Move pivot to middle of partition.
|
||||
std::swap(*pivot, *(end - 1));
|
||||
|
||||
// Recurse.
|
||||
tg.spawn([=, &tg] {
|
||||
parallel_quick_sort(start, pivot, comp, tg, depth - 1);
|
||||
});
|
||||
parallel_quick_sort(pivot + 1, end, comp, tg, depth - 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <class RandomAccessIterator, class Comp>
|
||||
void parallel_sort(
|
||||
RandomAccessIterator start, RandomAccessIterator end,
|
||||
const Comp &comp = std::less<
|
||||
typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
|
||||
TaskGroup tg;
|
||||
detail::parallel_quick_sort(start, end, comp, tg,
|
||||
llvm::Log2_64(std::distance(start, end)) + 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T> void parallel_sort(T *start, T *end) {
|
||||
parallel_sort(start, end, std::less<T>());
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Use ppl parallel_for_each on Windows.
|
||||
template <class Iterator, class Func>
|
||||
void parallel_for_each(Iterator begin, Iterator end, Func func) {
|
||||
concurrency::parallel_for_each(begin, end, func);
|
||||
}
|
||||
#else
|
||||
template <class Iterator, class Func>
|
||||
void parallel_for_each(Iterator begin, Iterator end, Func func) {
|
||||
// TODO: Make this parallel.
|
||||
std::for_each(begin, end, func);
|
||||
}
|
||||
#endif
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
118
external/bsd/llvm/dist/lld/include/lld/Core/Pass.h
vendored
118
external/bsd/llvm/dist/lld/include/lld/Core/Pass.h
vendored
@@ -1,118 +0,0 @@
|
||||
//===------ Core/Pass.h - Base class for linker passes --------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_PASS_H
|
||||
#define LLD_CORE_PASS_H
|
||||
|
||||
#include "lld/Core/Atom.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/range.h"
|
||||
#include "lld/Core/Reference.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
class DefinedAtom;
|
||||
class MutableFile;
|
||||
|
||||
/// Once the core linking is done (which resolves references, coalesces atoms
|
||||
/// and produces a complete Atom graph), the linker runs a series of passes
|
||||
/// on the Atom graph. The graph is modeled as a File, which means the pass
|
||||
/// has access to all the atoms and to File level attributes. Each pass does
|
||||
/// a particular transformation to the Atom graph or to the File attributes.
|
||||
///
|
||||
/// This is the abstract base class for all passes. A Pass does its
|
||||
/// actual work in it perform() method. It can iterator over Atoms in the
|
||||
/// graph using the *begin()/*end() atom iterator of the File. It can add
|
||||
/// new Atoms to the graph using the File's addAtom() method.
|
||||
class Pass {
|
||||
public:
|
||||
virtual ~Pass() { }
|
||||
|
||||
/// Do the actual work of the Pass.
|
||||
virtual void perform(std::unique_ptr<MutableFile> &mergedFile) = 0;
|
||||
|
||||
protected:
|
||||
// Only subclassess can be instantiated.
|
||||
Pass() { }
|
||||
};
|
||||
|
||||
/// Pass for adding stubs (PLT entries) for calls to functions
|
||||
/// outside the linkage unit. This class is subclassed by each
|
||||
/// file format Writer which implements the pure virtual methods.
|
||||
class StubsPass : public Pass {
|
||||
public:
|
||||
StubsPass() : Pass() {}
|
||||
|
||||
/// Scans all Atoms looking for call-site uses of SharedLibraryAtoms
|
||||
/// and transfroms the call-site to call a stub instead using the
|
||||
/// helper methods below.
|
||||
virtual void perform(std::unique_ptr<MutableFile> &mergedFile);
|
||||
|
||||
/// If true, the pass should use stubs for references
|
||||
/// to shared library symbols. If false, the pass
|
||||
/// will generate relocations on the text segment which the
|
||||
/// runtime loader will use to patch the program at runtime.
|
||||
virtual bool noTextRelocs() = 0;
|
||||
|
||||
/// Returns whether the Reference kind is for a call site. The pass
|
||||
/// uses this to find calls that need to be indirected through a stub.
|
||||
virtual bool isCallSite(int32_t) = 0;
|
||||
|
||||
/// Returns a file format specific atom for a stub/PLT entry which contains
|
||||
/// instructions which jump to the specified atom. May be called multiple
|
||||
/// times for the same target atom, in which case this method should return
|
||||
/// the same stub atom.
|
||||
virtual const DefinedAtom *getStub(const Atom &target) = 0;
|
||||
|
||||
/// After the default implementation of perform() is done calling getStub(),
|
||||
/// it will call this method to add all the stub (and support) atoms to the
|
||||
/// master file object.
|
||||
virtual void addStubAtoms(MutableFile &masterFile) = 0;
|
||||
};
|
||||
|
||||
/// Pass for adding GOT entries for pointers to functions/data
|
||||
/// outside the linkage unit. This class is subclassed by each
|
||||
/// file format Writer which implements the pure virtual methods.
|
||||
class GOTPass : public Pass {
|
||||
public:
|
||||
GOTPass() : Pass() {}
|
||||
|
||||
/// Scans all Atoms looking for pointer to SharedLibraryAtoms
|
||||
/// and transfroms them to a pointer to a GOT entry using the
|
||||
/// helper methods below.
|
||||
virtual void perform(std::unique_ptr<MutableFile> &mergedFile);
|
||||
|
||||
/// If true, the pass will use GOT entries for references
|
||||
/// to shared library symbols. If false, the pass
|
||||
/// will generate relocations on the text segment which the
|
||||
/// runtime loader will use to patch the program at runtime.
|
||||
virtual bool noTextRelocs() = 0;
|
||||
|
||||
/// Returns whether the Reference kind is a pre-instantiated GOT access.
|
||||
/// The default implementation of perform() uses this to figure out
|
||||
/// what GOT entries to instantiate.
|
||||
virtual bool isGOTAccess(int32_t, bool &canBypassGOT) = 0;
|
||||
|
||||
/// The file format Writer needs to alter the reference kind from a
|
||||
/// pre-instantiated GOT access to an actual access. If targetIsNowGOT is
|
||||
/// true, the pass has instantiated a GOT atom and altered the reference's
|
||||
/// target to point to that atom. If targetIsNowGOT is false, the pass
|
||||
/// determined a GOT entry is not needed because the reference site can
|
||||
/// directly access the target.
|
||||
virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) = 0;
|
||||
|
||||
/// Returns a file format specific atom for a GOT entry targeting
|
||||
/// the specified atom.
|
||||
virtual const DefinedAtom *makeGOTEntry(const Atom &target) = 0;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_CORE_PASS_H
|
||||
@@ -1,43 +0,0 @@
|
||||
//===- lld/Core/PassManager.h - Manage linker passes ----------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_PASS_MANAGER_H
|
||||
#define LLD_CORE_PASS_MANAGER_H
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
class MutableFile;
|
||||
class Pass;
|
||||
|
||||
/// \brief Owns and runs a collection of passes.
|
||||
///
|
||||
/// This class is currently just a container for passes and a way to run them.
|
||||
///
|
||||
/// In the future this should handle timing pass runs, running parallel passes,
|
||||
/// and validate/satisfy pass dependencies.
|
||||
class PassManager {
|
||||
public:
|
||||
void add(std::unique_ptr<Pass> pass) {
|
||||
_passes.push_back(std::move(pass));
|
||||
}
|
||||
|
||||
error_code runOnFile(std::unique_ptr<MutableFile> &);
|
||||
|
||||
private:
|
||||
/// \brief Passes in the order they should run.
|
||||
std::vector<std::unique_ptr<Pass>> _passes;
|
||||
};
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
//===- Core/References.h - A Reference to Another Atom --------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_REFERENCES_H
|
||||
#define LLD_CORE_REFERENCES_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
|
||||
namespace lld {
|
||||
class Atom;
|
||||
|
||||
///
|
||||
/// The linker has a Graph Theory model of linking. An object file is seen
|
||||
/// as a set of Atoms with References to other Atoms. Each Atom is a node
|
||||
/// and each Reference is an edge.
|
||||
///
|
||||
/// For example if a function contains a call site to "malloc" 40 bytes into
|
||||
/// the Atom, then the function Atom will have a Reference of: offsetInAtom=40,
|
||||
/// kind=callsite, target=malloc, addend=0.
|
||||
///
|
||||
/// Besides supporting traditional "relocations", References are also used
|
||||
/// grouping atoms (group comdat), forcing layout (one atom must follow
|
||||
/// another), marking data-in-code (jump tables or ARM constants), etc.
|
||||
///
|
||||
class Reference {
|
||||
public:
|
||||
/// The meaning of positive kind values is architecture specific.
|
||||
/// Negative kind values are architecture independent.
|
||||
typedef int32_t Kind;
|
||||
|
||||
enum {
|
||||
kindInGroup = -3,
|
||||
kindLayoutAfter = -2,
|
||||
kindLayoutBefore = -1,
|
||||
kindTargetLow = 0
|
||||
};
|
||||
|
||||
// A value to be added to the value of a target
|
||||
typedef int64_t Addend;
|
||||
|
||||
/// What sort of reference this is.
|
||||
Kind kind() const { return _kind; }
|
||||
|
||||
/// During linking, some optimizations may change the code gen and
|
||||
/// hence the reference kind.
|
||||
void setKind(Kind kind) { _kind = kind; };
|
||||
|
||||
virtual StringRef kindToString() const {
|
||||
switch (kind()) {
|
||||
case kindLayoutBefore:
|
||||
return "layout-before";
|
||||
case kindLayoutAfter:
|
||||
return "layout-after";
|
||||
case kindInGroup:
|
||||
return "in-group";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
virtual int32_t stringToKind(StringRef kindString) const {
|
||||
if (kindString == "in-group")
|
||||
return kindInGroup;
|
||||
else if (kindString == "layout-before")
|
||||
return kindLayoutBefore;
|
||||
else if (kindString == "layout-after")
|
||||
return kindLayoutAfter;
|
||||
assert(0 && "unknown relocation kind");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// If the reference is a fixup in the Atom, then this returns the
|
||||
/// byte offset into the Atom's content to do the fix up.
|
||||
virtual uint64_t offsetInAtom() const = 0;
|
||||
|
||||
/// If the reference is an edge to another Atom, then this returns the
|
||||
/// other Atom. Otherwise, it returns nullptr.
|
||||
virtual const Atom *target() const = 0;
|
||||
|
||||
/// During linking, the linker may merge graphs which coalesces some nodes
|
||||
/// (i.e. Atoms). To switch the target of a reference, this method is called.
|
||||
virtual void setTarget(const Atom *) = 0;
|
||||
|
||||
/// Some relocations require a symbol and a value (e.g. foo + 4).
|
||||
virtual Addend addend() const = 0;
|
||||
|
||||
/// During linking, some optimzations may change addend value.
|
||||
virtual void setAddend(Addend) = 0;
|
||||
|
||||
protected:
|
||||
/// Atom is an abstract base class. Only subclasses can access constructor.
|
||||
Reference() {}
|
||||
|
||||
/// The memory for Reference objects is always managed by the owning File
|
||||
/// object. Therefore, no one but the owning File object should call
|
||||
/// delete on an Reference. In fact, some File objects may bulk allocate
|
||||
/// an array of References, so they cannot be individually deleted by anyone.
|
||||
virtual ~Reference() {}
|
||||
|
||||
Kind _kind;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_CORE_REFERENCES_H
|
||||
@@ -1,128 +0,0 @@
|
||||
//===- Core/Resolver.h - Resolves Atom References -------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_RESOLVER_H
|
||||
#define LLD_CORE_RESOLVER_H
|
||||
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/SharedLibraryFile.h"
|
||||
#include "lld/Core/SymbolTable.h"
|
||||
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
|
||||
class Atom;
|
||||
class LinkingContext;
|
||||
|
||||
/// \brief The Resolver is responsible for merging all input object files
|
||||
/// and producing a merged graph.
|
||||
class Resolver {
|
||||
public:
|
||||
enum ResolverState {
|
||||
StateNoChange = 0, // The default resolver state
|
||||
StateNewDefinedAtoms = 1, // New defined atoms were added
|
||||
StateNewUndefinedAtoms = 2, // New undefined atoms were added
|
||||
StateNewSharedLibraryAtoms = 4, // New shared library atoms were added
|
||||
StateNewAbsoluteAtoms = 8 // New absolute atoms were added
|
||||
};
|
||||
|
||||
Resolver(LinkingContext &context)
|
||||
: _context(context), _symbolTable(context),
|
||||
_result(new MergedFile(context)), _haveLLVMObjs(false),
|
||||
_addToFinalSection(false) {}
|
||||
|
||||
virtual ~Resolver() {}
|
||||
|
||||
// InputFiles::Handler methods
|
||||
virtual void doDefinedAtom(const DefinedAtom&);
|
||||
virtual void doUndefinedAtom(const UndefinedAtom&);
|
||||
virtual void doSharedLibraryAtom(const SharedLibraryAtom &);
|
||||
virtual void doAbsoluteAtom(const AbsoluteAtom &);
|
||||
virtual void doFile(const File&);
|
||||
|
||||
// Handle files, this adds atoms from the current file thats
|
||||
// being processed by the resolver
|
||||
virtual void handleFile(const File &);
|
||||
|
||||
// Handle an archive library file.
|
||||
virtual void handleArchiveFile(const File &);
|
||||
|
||||
// Handle a shared library file.
|
||||
virtual void handleSharedLibrary(const File &);
|
||||
|
||||
/// @brief do work of merging and resolving and return list
|
||||
bool resolve();
|
||||
|
||||
std::unique_ptr<MutableFile> resultFile() { return std::move(_result); }
|
||||
|
||||
private:
|
||||
typedef std::function<void(StringRef, bool)> UndefCallback;
|
||||
|
||||
/// \brief The main function that iterates over the files to resolve
|
||||
bool resolveUndefines();
|
||||
void updateReferences();
|
||||
void deadStripOptimize();
|
||||
bool checkUndefines(bool final);
|
||||
void removeCoalescedAwayAtoms();
|
||||
void checkDylibSymbolCollisions();
|
||||
void linkTimeOptimize();
|
||||
void tweakAtoms();
|
||||
void forEachUndefines(UndefCallback callback, bool searchForOverrides);
|
||||
|
||||
void markLive(const Atom &atom);
|
||||
void addAtoms(const std::vector<const DefinedAtom *>&);
|
||||
|
||||
class MergedFile : public MutableFile {
|
||||
public:
|
||||
MergedFile(const LinkingContext &context)
|
||||
: MutableFile(context, "<linker-internal>") {}
|
||||
|
||||
virtual const atom_collection<DefinedAtom> &defined() const {
|
||||
return _definedAtoms;
|
||||
}
|
||||
virtual const atom_collection<UndefinedAtom>& undefined() const {
|
||||
return _undefinedAtoms;
|
||||
}
|
||||
virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const {
|
||||
return _sharedLibraryAtoms;
|
||||
}
|
||||
virtual const atom_collection<AbsoluteAtom>& absolute() const {
|
||||
return _absoluteAtoms;
|
||||
}
|
||||
|
||||
void addAtoms(std::vector<const Atom*>& atoms);
|
||||
|
||||
virtual void addAtom(const Atom& atom);
|
||||
virtual DefinedAtomRange definedAtoms();
|
||||
|
||||
private:
|
||||
atom_collection_vector<DefinedAtom> _definedAtoms;
|
||||
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
|
||||
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
|
||||
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
|
||||
};
|
||||
|
||||
LinkingContext &_context;
|
||||
SymbolTable _symbolTable;
|
||||
std::vector<const Atom *> _atoms;
|
||||
std::set<const Atom *> _deadStripRoots;
|
||||
std::vector<const Atom *> _atomsWithUnresolvedReferences;
|
||||
llvm::DenseSet<const Atom *> _liveAtoms;
|
||||
std::unique_ptr<MergedFile> _result;
|
||||
bool _haveLLVMObjs;
|
||||
bool _addToFinalSection;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_CORE_RESOLVER_H
|
||||
@@ -1,33 +0,0 @@
|
||||
//===- lld/Core/STDExtra.h - Helpers for the stdlib -----------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_STD_EXTRA_H
|
||||
#define LLD_CORE_STD_EXTRA_H
|
||||
|
||||
namespace lld {
|
||||
/// \brief Deleter for smart pointers that only calls the destructor. Memory is
|
||||
/// managed elsewhere. A common use of this is for things allocated with a
|
||||
/// BumpPtrAllocator.
|
||||
template <class T>
|
||||
struct destruct_delete {
|
||||
void operator ()(T *ptr) {
|
||||
ptr->~T();
|
||||
}
|
||||
};
|
||||
|
||||
// Sadly VS 2012 doesn't support template aliases.
|
||||
// template <class T>
|
||||
// using unique_bump_ptr = std::unique_ptr<T, destruct_delete<T>>;
|
||||
|
||||
#define LLD_UNIQUE_BUMP_PTR(...) \
|
||||
std::unique_ptr<__VA_ARGS__, destruct_delete<__VA_ARGS__>>
|
||||
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,57 +0,0 @@
|
||||
//===- Core/SharedLibraryAtom.h - A Shared Library Atom -------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_SHARED_LIBRARY_ATOM_H
|
||||
#define LLD_CORE_SHARED_LIBRARY_ATOM_H
|
||||
|
||||
#include "lld/Core/Atom.h"
|
||||
|
||||
namespace llvm {
|
||||
class StringRef;
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// A SharedLibraryAtom has no content.
|
||||
/// It exists to represent a symbol which will be bound at runtime.
|
||||
class SharedLibraryAtom : public Atom {
|
||||
public:
|
||||
enum class Type : uint32_t {
|
||||
Unknown,
|
||||
Code,
|
||||
Data,
|
||||
};
|
||||
|
||||
/// Returns shared library name used to load it at runtime.
|
||||
/// On linux that is the DT_NEEDED name.
|
||||
/// On Darwin it is the LC_DYLIB_LOAD dylib name.
|
||||
/// On Windows it is the DLL name that to be referred from .idata section.
|
||||
virtual StringRef loadName() const = 0;
|
||||
|
||||
/// Returns if shared library symbol can be missing at runtime and if
|
||||
/// so the loader should silently resolve address of symbol to be nullptr.
|
||||
virtual bool canBeNullAtRuntime() const = 0;
|
||||
|
||||
virtual Type type() const = 0;
|
||||
|
||||
virtual uint64_t size() const = 0;
|
||||
|
||||
static inline bool classof(const Atom *a) {
|
||||
return a->definition() == definitionSharedLibrary;
|
||||
}
|
||||
static inline bool classof(const SharedLibraryAtom *) { return true; }
|
||||
|
||||
protected:
|
||||
SharedLibraryAtom() : Atom(definitionSharedLibrary) {}
|
||||
virtual ~SharedLibraryAtom() {}
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_CORE_SHARED_LIBRARY_ATOM_H
|
||||
@@ -1,42 +0,0 @@
|
||||
//===- Core/SharedLibraryFile.h - Models shared libraries as Atoms --------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_SHARED_LIBRARY_FILE_H
|
||||
#define LLD_CORE_SHARED_LIBRARY_FILE_H
|
||||
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/SharedLibraryAtom.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
///
|
||||
/// The SharedLibraryFile subclass of File is used to represent dynamic
|
||||
/// shared libraries being linked against.
|
||||
///
|
||||
class SharedLibraryFile : public File {
|
||||
public:
|
||||
virtual ~SharedLibraryFile() {}
|
||||
|
||||
static inline bool classof(const File *f) {
|
||||
return f->kind() == kindSharedLibrary;
|
||||
}
|
||||
|
||||
/// Check if the shared library exports a symbol with the specified name.
|
||||
/// If so, return a SharedLibraryAtom which represents that exported
|
||||
/// symbol. Otherwise return nullptr.
|
||||
virtual const SharedLibraryAtom *exports(StringRef name,
|
||||
bool dataSymbolOnly) const = 0;
|
||||
protected:
|
||||
/// only subclasses of SharedLibraryFile can be instantiated
|
||||
explicit SharedLibraryFile(StringRef path) : File(path, kindSharedLibrary) {}
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_CORE_SHARED_LIBRARY_FILE_H
|
||||
@@ -1,110 +0,0 @@
|
||||
//===- Core/SymbolTable.h - Main Symbol Table -----------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_SYMBOL_TABLE_H
|
||||
#define LLD_CORE_SYMBOL_TABLE_H
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
|
||||
class AbsoluteAtom;
|
||||
class Atom;
|
||||
class DefinedAtom;
|
||||
class LinkingContext;
|
||||
class ResolverOptions;
|
||||
class SharedLibraryAtom;
|
||||
class UndefinedAtom;
|
||||
|
||||
/// \brief The SymbolTable class is responsible for coalescing atoms.
|
||||
///
|
||||
/// All atoms coalescable by-name or by-content should be added.
|
||||
/// The method replacement() can be used to find the replacement atom
|
||||
/// if an atom has been coalesced away.
|
||||
class SymbolTable {
|
||||
public:
|
||||
explicit SymbolTable(const LinkingContext &);
|
||||
|
||||
/// @brief add atom to symbol table
|
||||
void add(const DefinedAtom &);
|
||||
|
||||
/// @brief add atom to symbol table
|
||||
void add(const UndefinedAtom &);
|
||||
|
||||
/// @brief add atom to symbol table
|
||||
void add(const SharedLibraryAtom &);
|
||||
|
||||
/// @brief add atom to symbol table
|
||||
void add(const AbsoluteAtom &);
|
||||
|
||||
/// @brief checks if name is in symbol table and if so atom is not
|
||||
/// UndefinedAtom
|
||||
bool isDefined(StringRef sym);
|
||||
|
||||
/// @brief returns atom in symbol table for specified name (or nullptr)
|
||||
const Atom *findByName(StringRef sym);
|
||||
|
||||
/// @brief returns vector of remaining UndefinedAtoms
|
||||
void undefines(std::vector<const UndefinedAtom *>&);
|
||||
|
||||
/// returns vector of tentative definitions
|
||||
void tentativeDefinitions(std::vector<StringRef> &);
|
||||
|
||||
/// @brief count of by-name entries in symbol table
|
||||
unsigned int size();
|
||||
|
||||
/// @brief add atom to replacement table
|
||||
void addReplacement(const Atom *replaced, const Atom *replacement);
|
||||
|
||||
/// @brief if atom has been coalesced away, return replacement, else return atom
|
||||
const Atom *replacement(const Atom *);
|
||||
|
||||
private:
|
||||
typedef llvm::DenseMap<const Atom *, const Atom *> AtomToAtom;
|
||||
|
||||
struct StringRefMappingInfo {
|
||||
static StringRef getEmptyKey() { return StringRef(); }
|
||||
static StringRef getTombstoneKey() { return StringRef(" ", 0); }
|
||||
static unsigned getHashValue(StringRef const val) {
|
||||
return llvm::HashString(val); }
|
||||
static bool isEqual(StringRef const lhs,
|
||||
StringRef const rhs) { return lhs.equals(rhs); }
|
||||
};
|
||||
typedef llvm::DenseMap<StringRef, const Atom *,
|
||||
StringRefMappingInfo> NameToAtom;
|
||||
|
||||
struct AtomMappingInfo {
|
||||
static const DefinedAtom * getEmptyKey() { return nullptr; }
|
||||
static const DefinedAtom * getTombstoneKey() { return (DefinedAtom*)(-1); }
|
||||
static unsigned getHashValue(const DefinedAtom * const Val);
|
||||
static bool isEqual(const DefinedAtom * const LHS,
|
||||
const DefinedAtom * const RHS);
|
||||
};
|
||||
typedef llvm::DenseSet<const DefinedAtom*, AtomMappingInfo> AtomContentSet;
|
||||
|
||||
void addByName(const Atom &);
|
||||
void addByContent(const DefinedAtom &);
|
||||
|
||||
const LinkingContext &_context;
|
||||
AtomToAtom _replacedAtoms;
|
||||
NameToAtom _nameTable;
|
||||
AtomContentSet _contentTable;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_CORE_SYMBOL_TABLE_H
|
||||
@@ -1,17 +0,0 @@
|
||||
include/lld/Core
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
* The native/yaml reader/writer interfaces should be changed to return
|
||||
an explanatory string if there is an error. The existing error_code
|
||||
abstraction only works for returning low level OS errors. It does not
|
||||
work for describing formatting issues.
|
||||
|
||||
* We need to design a diagnostics interface. It would be nice to share code
|
||||
with Clang_ where possible.
|
||||
|
||||
* We need to add more attributes to File. In particular, we need cpu
|
||||
and OS information (like target triples). We should also provide explicit
|
||||
support for `LLVM IR module flags metadata`__.
|
||||
|
||||
.. __: http://llvm.org/docs/LangRef.html#module_flags
|
||||
.. _Clang: http://clang.llvm.org/docs/InternalsManual.html#Diagnostics
|
||||
@@ -1,74 +0,0 @@
|
||||
//===- Core/UndefinedAtom.h - An Undefined Atom ---------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_UNDEFINED_ATOM_H
|
||||
#define LLD_CORE_UNDEFINED_ATOM_H
|
||||
|
||||
#include "lld/Core/Atom.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// An UndefinedAtom has no content.
|
||||
/// It exists as a place holder for a future atom.
|
||||
class UndefinedAtom : public Atom {
|
||||
public:
|
||||
/// Whether this undefined symbol needs to be resolved,
|
||||
/// or whether it can just evaluate to nullptr.
|
||||
/// This concept is often called "weak", but that term
|
||||
/// is overloaded to mean other things too.
|
||||
enum CanBeNull {
|
||||
/// Normal symbols must be resolved at build time
|
||||
canBeNullNever,
|
||||
|
||||
/// This symbol can be missing at runtime and will evalute to nullptr.
|
||||
/// That is, the static linker still must find a definition (usually
|
||||
/// is some shared library), but at runtime, the dynamic loader
|
||||
/// will allow the symbol to be missing and resolved to nullptr.
|
||||
///
|
||||
/// On Darwin this is generated using a function prototype with
|
||||
/// __attribute__((weak_import)).
|
||||
/// On linux this is generated using a function prototype with
|
||||
/// __attribute__((weak)).
|
||||
/// On Windows this feature is not supported.
|
||||
canBeNullAtRuntime,
|
||||
|
||||
/// This symbol can be missing at build time.
|
||||
/// That is, the static linker will not error if a definition for
|
||||
/// this symbol is not found at build time. Instead, the linker
|
||||
/// will build an executable that lets the dynamic loader find the
|
||||
/// symbol at runtime.
|
||||
/// This feature is not supported on Darwin nor Windows.
|
||||
/// On linux this is generated using a function prototype with
|
||||
/// __attribute__((weak)).
|
||||
canBeNullAtBuildtime
|
||||
};
|
||||
|
||||
virtual CanBeNull canBeNull() const = 0;
|
||||
|
||||
static inline bool classof(const Atom *a) {
|
||||
return a->definition() == definitionUndefined;
|
||||
}
|
||||
static inline bool classof(const UndefinedAtom *) { return true; }
|
||||
|
||||
/// Returns an undefined atom if this undefined symbol has a synonym. This is
|
||||
/// mainly used in COFF. In COFF, an unresolved external symbol can have up to
|
||||
/// one optional name (sym2) in addition to its regular name (sym1). If a
|
||||
/// definition of sym1 exists, sym1 is resolved normally. Otherwise, all
|
||||
/// references to sym1 refer to sym2 instead. In that case sym2 must be
|
||||
/// resolved, or link will fail.
|
||||
virtual const UndefinedAtom *fallback() const { return nullptr; }
|
||||
|
||||
protected:
|
||||
UndefinedAtom() : Atom(definitionUndefined) {}
|
||||
virtual ~UndefinedAtom() {}
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_CORE_UNDEFINED_ATOM_H
|
||||
739
external/bsd/llvm/dist/lld/include/lld/Core/range.h
vendored
739
external/bsd/llvm/dist/lld/include/lld/Core/range.h
vendored
@@ -1,739 +0,0 @@
|
||||
//===-- lld/Core/range.h - Iterator ranges ----------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Iterator range type based on c++1y range proposal.
|
||||
///
|
||||
/// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3350.html
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_CORE_RANGE_H
|
||||
#define LLD_CORE_RANGE_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
// Nothing in this namespace is part of the exported interface.
|
||||
namespace detail {
|
||||
using std::begin;
|
||||
using std::end;
|
||||
/// Used as the result type of undefined functions.
|
||||
struct undefined {};
|
||||
|
||||
template <typename R> class begin_result {
|
||||
template <typename T> static auto check(T &&t) -> decltype(begin(t));
|
||||
static undefined check(...);
|
||||
public:
|
||||
typedef decltype(check(std::declval<R>())) type;
|
||||
};
|
||||
|
||||
template <typename R> class end_result {
|
||||
template <typename T> static auto check(T &&t) -> decltype(end(t));
|
||||
static undefined check(...);
|
||||
public:
|
||||
typedef decltype(check(std::declval<R>())) type;
|
||||
};
|
||||
|
||||
// Things that begin and end work on, in compatible ways, are
|
||||
// ranges. [stmt.ranged]
|
||||
template <typename R>
|
||||
struct is_range : std::is_same<typename detail::begin_result<R>::type,
|
||||
typename detail::end_result<R>::type> {};
|
||||
|
||||
// This currently requires specialization and doesn't work for
|
||||
// detecting \c range<>s or iterators. We should add
|
||||
// \c contiguous_iterator_tag to fix that.
|
||||
template <typename R> struct is_contiguous_range : std::false_type {};
|
||||
template <typename R>
|
||||
struct is_contiguous_range<R &> : is_contiguous_range<R> {};
|
||||
template <typename R>
|
||||
struct is_contiguous_range <R &&> : is_contiguous_range<R> {};
|
||||
template <typename R>
|
||||
struct is_contiguous_range<const R> : is_contiguous_range<R> {};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct is_contiguous_range<T[N]> : std::true_type {};
|
||||
template <typename T, size_t N>
|
||||
struct is_contiguous_range<const T[N]> : std::true_type {};
|
||||
template <typename T, size_t N>
|
||||
struct is_contiguous_range<std::array<T, N> > : std::true_type {};
|
||||
template <typename charT, typename traits, typename Allocator>
|
||||
struct is_contiguous_range<
|
||||
std::basic_string<charT, traits, Allocator> > : std::true_type {};
|
||||
template <typename T, typename Allocator>
|
||||
struct is_contiguous_range<std::vector<T, Allocator> > : std::true_type {};
|
||||
|
||||
// Removes cv qualifiers from all levels of a multi-level pointer
|
||||
// type, not just the type level.
|
||||
template <typename T> struct remove_all_cv_ptr {
|
||||
typedef T type;
|
||||
};
|
||||
template <typename T> struct remove_all_cv_ptr<T *> {
|
||||
typedef typename remove_all_cv_ptr<T>::type *type;
|
||||
};
|
||||
template <typename T> struct remove_all_cv_ptr<const T> {
|
||||
typedef typename remove_all_cv_ptr<T>::type type;
|
||||
};
|
||||
template <typename T> struct remove_all_cv_ptr<volatile T> {
|
||||
typedef typename remove_all_cv_ptr<T>::type type;
|
||||
};
|
||||
template <typename T> struct remove_all_cv_ptr<const volatile T> {
|
||||
typedef typename remove_all_cv_ptr<T>::type type;
|
||||
};
|
||||
|
||||
template <typename From, typename To>
|
||||
struct conversion_preserves_array_indexing : std::false_type {};
|
||||
|
||||
template <typename FromVal, typename ToVal>
|
||||
struct conversion_preserves_array_indexing<FromVal *,
|
||||
ToVal *> : std::integral_constant<
|
||||
bool, std::is_convertible<FromVal *, ToVal *>::value &&
|
||||
std::is_same<typename remove_all_cv_ptr<FromVal>::type,
|
||||
typename remove_all_cv_ptr<ToVal>::type>::value> {};
|
||||
|
||||
template <typename T>
|
||||
LLVM_CONSTEXPR auto adl_begin(T &&t) -> decltype(begin(t)) {
|
||||
return begin(std::forward<T>(t));
|
||||
}
|
||||
|
||||
template <typename T> LLVM_CONSTEXPR auto adl_end(T &&t) -> decltype(end(t)) {
|
||||
return end(std::forward<T>(t));
|
||||
}
|
||||
} // end namespace detail
|
||||
|
||||
/// A \c std::range<Iterator> represents a half-open iterator range
|
||||
/// built from two iterators, \c 'begin', and \c 'end'. If \c end is
|
||||
/// not reachable from \c begin, the behavior is undefined.
|
||||
///
|
||||
/// The mutability of elements of the range is controlled by the
|
||||
/// Iterator argument. Instantiate
|
||||
/// <code>range<<var>Foo</var>::iterator></code> or
|
||||
/// <code>range<<var>T</var>*></code>, or call
|
||||
/// <code>make_range(<var>non_const_container</var>)</code>, and you
|
||||
/// get a mutable range. Instantiate
|
||||
/// <code>range<<var>Foo</var>::const_iterator></code> or
|
||||
/// <code>range<const <var>T</var>*></code>, or call
|
||||
/// <code>make_range(<var>const_container</var>)</code>, and you get a
|
||||
/// constant range.
|
||||
///
|
||||
/// \todo Inherit from std::pair<Iterator, Iterator>?
|
||||
///
|
||||
/// \todo This interface contains some functions that could be
|
||||
/// provided as free algorithms rather than member functions, and all
|
||||
/// of the <code>pop_*()</code> functions could be replaced by \c
|
||||
/// slice() at the cost of some extra iterator copies. This makes
|
||||
/// them more awkward to use, but makes it easier for users to write
|
||||
/// their own types that follow the same interface. On the other hand,
|
||||
/// a \c range_facade could be provided to help users write new
|
||||
/// ranges, and it could provide the members. Such functions are
|
||||
/// marked with a note in their documentation. (Of course, all of
|
||||
/// these member functions could be provided as free functions using
|
||||
/// the iterator access methods, but one goal here is to allow people
|
||||
/// to program without touching iterators at all.)
|
||||
template <typename Iterator> class range {
|
||||
Iterator begin_, end_;
|
||||
public:
|
||||
/// \name types
|
||||
/// @{
|
||||
|
||||
/// The iterator category of \c Iterator.
|
||||
/// \todo Consider defining range categories. If they don't add
|
||||
/// anything over the corresponding iterator categories, then
|
||||
/// they're probably not worth defining.
|
||||
typedef typename std::iterator_traits<
|
||||
Iterator>::iterator_category iterator_category;
|
||||
/// The type of elements of the range. Not cv-qualified.
|
||||
typedef typename std::iterator_traits<Iterator>::value_type value_type;
|
||||
/// The type of the size of the range and offsets within the range.
|
||||
typedef typename std::iterator_traits<
|
||||
Iterator>::difference_type difference_type;
|
||||
/// The return type of element access methods: \c front(), \c back(), etc.
|
||||
typedef typename std::iterator_traits<Iterator>::reference reference;
|
||||
typedef typename std::iterator_traits<Iterator>::pointer pointer;
|
||||
/// @}
|
||||
|
||||
/// \name constructors
|
||||
/// @{
|
||||
|
||||
/// Creates a range of default-constructed (<em>not</em>
|
||||
/// value-initialized) iterators. For most \c Iterator types, this
|
||||
/// will be an invalid range.
|
||||
range() : begin_(), end_() {}
|
||||
|
||||
/// \pre \c end is reachable from \c begin.
|
||||
/// \post <code>this->begin() == begin && this->end() == end</code>
|
||||
LLVM_CONSTEXPR range(Iterator begin, Iterator end)
|
||||
: begin_(begin), end_(end) {}
|
||||
|
||||
/// \par Participates in overload resolution if:
|
||||
/// - \c Iterator is not a pointer type,
|
||||
/// - \c begin(r) and \c end(r) return the same type, and
|
||||
/// - that type is convertible to \c Iterator.
|
||||
///
|
||||
/// \todo std::begin and std::end are overloaded between T& and
|
||||
/// const T&, which means that if a container has only a non-const
|
||||
/// begin or end method, then it's ill-formed to pass an rvalue to
|
||||
/// the free function. To avoid that problem, we don't use
|
||||
/// std::forward<> here, so begin() and end() are always called with
|
||||
/// an lvalue. Another option would be to insist that rvalue
|
||||
/// arguments to range() must have const begin() and end() methods.
|
||||
template <typename R> LLVM_CONSTEXPR range(
|
||||
R &&r,
|
||||
typename std::enable_if<
|
||||
!std::is_pointer<Iterator>::value &&
|
||||
detail::is_range<R>::value &&
|
||||
std::is_convertible<typename detail::begin_result<R>::type,
|
||||
Iterator>::value>::type* = 0)
|
||||
: begin_(detail::adl_begin(r)), end_(detail::adl_end(r)) {}
|
||||
|
||||
/// This constructor creates a \c range<T*> from any range with
|
||||
/// contiguous iterators. Because dereferencing a past-the-end
|
||||
/// iterator can be undefined behavior, empty ranges get initialized
|
||||
/// with \c nullptr rather than \c &*begin().
|
||||
///
|
||||
/// \par Participates in overload resolution if:
|
||||
/// - \c Iterator is a pointer type \c T*,
|
||||
/// - \c begin(r) and \c end(r) return the same type,
|
||||
/// - elements \c i of that type satisfy the invariant
|
||||
/// <code>&*(i + N) == (&*i) + N</code>, and
|
||||
/// - The result of <code>&*begin()</code> is convertible to \c T*
|
||||
/// using only qualification conversions [conv.qual] (since
|
||||
/// pointer conversions stop the pointer from pointing to an
|
||||
/// array element).
|
||||
///
|
||||
/// \todo The <code>&*(i + N) == (&*i) + N</code> invariant is
|
||||
/// currently impossible to check for user-defined types. We need a
|
||||
/// \c contiguous_iterator_tag to let users assert it.
|
||||
template <typename R> LLVM_CONSTEXPR range(
|
||||
R &&r,
|
||||
typename std::enable_if<
|
||||
std::is_pointer<Iterator>::value &&
|
||||
detail::is_contiguous_range<R>::value
|
||||
// MSVC returns false for this in this context, but not if we lift it out of the
|
||||
// constructor.
|
||||
#ifndef _MSC_VER
|
||||
&& detail::conversion_preserves_array_indexing<
|
||||
decltype(&*detail::adl_begin(r)), Iterator>::value
|
||||
#endif
|
||||
>::type* = 0)
|
||||
: begin_((detail::adl_begin(r) == detail::adl_end(r) &&
|
||||
!std::is_pointer<decltype(detail::adl_begin(r))>::value)
|
||||
// For non-pointers, &*begin(r) is only defined behavior
|
||||
// if there's an element there. Otherwise, use nullptr
|
||||
// since the user can't dereference it anyway. This _is_
|
||||
// detectable.
|
||||
? nullptr : &*detail::adl_begin(r)),
|
||||
end_(begin_ + (detail::adl_end(r) - detail::adl_begin(r))) {}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name iterator access
|
||||
/// @{
|
||||
LLVM_CONSTEXPR Iterator begin() const { return begin_; }
|
||||
LLVM_CONSTEXPR Iterator end() const { return end_; }
|
||||
/// @}
|
||||
|
||||
/// \name element access
|
||||
/// @{
|
||||
|
||||
/// \par Complexity:
|
||||
/// O(1)
|
||||
/// \pre \c !empty()
|
||||
/// \returns a reference to the element at the front of the range.
|
||||
LLVM_CONSTEXPR reference front() const { return *begin(); }
|
||||
|
||||
/// \par Ill-formed unless:
|
||||
/// \c iterator_category is convertible to \c
|
||||
/// std::bidirectional_iterator_tag.
|
||||
///
|
||||
/// \par Complexity:
|
||||
/// O(2) (Involves copying and decrementing an iterator, so not
|
||||
/// quite as cheap as \c front())
|
||||
///
|
||||
/// \pre \c !empty()
|
||||
/// \returns a reference to the element at the front of the range.
|
||||
LLVM_CONSTEXPR reference back() const {
|
||||
static_assert(
|
||||
std::is_convertible<iterator_category,
|
||||
std::bidirectional_iterator_tag>::value,
|
||||
"Can only retrieve the last element of a bidirectional range.");
|
||||
using std::prev;
|
||||
return *prev(end());
|
||||
}
|
||||
|
||||
/// This method is drawn from scripting language indexing. It
|
||||
/// indexes std::forward from the beginning of the range if the argument
|
||||
/// is positive, or backwards from the end of the array if the
|
||||
/// argument is negative.
|
||||
///
|
||||
/// \par Ill-formed unless:
|
||||
/// \c iterator_category is convertible to \c
|
||||
/// std::random_access_iterator_tag.
|
||||
///
|
||||
/// \par Complexity:
|
||||
/// O(1)
|
||||
///
|
||||
/// \pre <code>abs(index) < size() || index == -size()</code>
|
||||
///
|
||||
/// \returns if <code>index >= 0</code>, a reference to the
|
||||
/// <code>index</code>'th element in the range. Otherwise, a
|
||||
/// reference to the <code>size()+index</code>'th element.
|
||||
LLVM_CONSTEXPR reference operator[](difference_type index) const {
|
||||
static_assert(std::is_convertible<iterator_category,
|
||||
std::random_access_iterator_tag>::value,
|
||||
"Can only index into a random-access range.");
|
||||
// Less readable construction for constexpr support.
|
||||
return index < 0 ? end()[index]
|
||||
: begin()[index];
|
||||
}
|
||||
/// @}
|
||||
|
||||
/// \name size
|
||||
/// @{
|
||||
|
||||
/// \par Complexity:
|
||||
/// O(1)
|
||||
/// \returns \c true if the range contains no elements.
|
||||
LLVM_CONSTEXPR bool empty() const { return begin() == end(); }
|
||||
|
||||
/// \par Ill-formed unless:
|
||||
/// \c iterator_category is convertible to
|
||||
/// \c std::forward_iterator_tag.
|
||||
///
|
||||
/// \par Complexity:
|
||||
/// O(1) if \c iterator_category is convertible to \c
|
||||
/// std::random_access_iterator_tag. O(<code>size()</code>)
|
||||
/// otherwise.
|
||||
///
|
||||
/// \returns the number of times \c pop_front() can be called before
|
||||
/// \c empty() becomes true.
|
||||
LLVM_CONSTEXPR difference_type size() const {
|
||||
static_assert(std::is_convertible<iterator_category,
|
||||
std::forward_iterator_tag>::value,
|
||||
"Calling size on an input range would destroy the range.");
|
||||
return dispatch_size(iterator_category());
|
||||
}
|
||||
/// @}
|
||||
|
||||
/// \name traversal from the beginning of the range
|
||||
/// @{
|
||||
|
||||
/// Advances the beginning of the range by one element.
|
||||
/// \pre \c !empty()
|
||||
void pop_front() { ++begin_; }
|
||||
|
||||
/// Advances the beginning of the range by \c n elements.
|
||||
///
|
||||
/// \par Complexity:
|
||||
/// O(1) if \c iterator_category is convertible to \c
|
||||
/// std::random_access_iterator_tag, O(<code>n</code>) otherwise.
|
||||
///
|
||||
/// \pre <code>n >= 0</code>, and there must be at least \c n
|
||||
/// elements in the range.
|
||||
void pop_front(difference_type n) { advance(begin_, n); }
|
||||
|
||||
/// Advances the beginning of the range by at most \c n elements,
|
||||
/// stopping if the range becomes empty. A negative argument causes
|
||||
/// no change.
|
||||
///
|
||||
/// \par Complexity:
|
||||
/// O(1) if \c iterator_category is convertible to \c
|
||||
/// std::random_access_iterator_tag, O(<code>min(n,
|
||||
/// <var>#-elements-in-range</var>)</code>) otherwise.
|
||||
///
|
||||
/// \note Could be provided as a free function with little-to-no
|
||||
/// loss in efficiency.
|
||||
void pop_front_upto(difference_type n) {
|
||||
advance_upto(begin_, std::max<difference_type>(0, n), end_,
|
||||
iterator_category());
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name traversal from the end of the range
|
||||
/// @{
|
||||
|
||||
/// Moves the end of the range earlier by one element.
|
||||
///
|
||||
/// \par Ill-formed unless:
|
||||
/// \c iterator_category is convertible to
|
||||
/// \c std::bidirectional_iterator_tag.
|
||||
///
|
||||
/// \par Complexity:
|
||||
/// O(1)
|
||||
///
|
||||
/// \pre \c !empty()
|
||||
void pop_back() {
|
||||
static_assert(std::is_convertible<iterator_category,
|
||||
std::bidirectional_iterator_tag>::value,
|
||||
"Can only access the end of a bidirectional range.");
|
||||
--end_;
|
||||
}
|
||||
|
||||
/// Moves the end of the range earlier by \c n elements.
|
||||
///
|
||||
/// \par Ill-formed unless:
|
||||
/// \c iterator_category is convertible to
|
||||
/// \c std::bidirectional_iterator_tag.
|
||||
///
|
||||
/// \par Complexity:
|
||||
/// O(1) if \c iterator_category is convertible to \c
|
||||
/// std::random_access_iterator_tag, O(<code>n</code>) otherwise.
|
||||
///
|
||||
/// \pre <code>n >= 0</code>, and there must be at least \c n
|
||||
/// elements in the range.
|
||||
void pop_back(difference_type n) {
|
||||
static_assert(std::is_convertible<iterator_category,
|
||||
std::bidirectional_iterator_tag>::value,
|
||||
"Can only access the end of a bidirectional range.");
|
||||
advance(end_, -n);
|
||||
}
|
||||
|
||||
/// Moves the end of the range earlier by <code>min(n,
|
||||
/// size())</code> elements. A negative argument causes no change.
|
||||
///
|
||||
/// \par Ill-formed unless:
|
||||
/// \c iterator_category is convertible to
|
||||
/// \c std::bidirectional_iterator_tag.
|
||||
///
|
||||
/// \par Complexity:
|
||||
/// O(1) if \c iterator_category is convertible to \c
|
||||
/// std::random_access_iterator_tag, O(<code>min(n,
|
||||
/// <var>#-elements-in-range</var>)</code>) otherwise.
|
||||
///
|
||||
/// \note Could be provided as a free function with little-to-no
|
||||
/// loss in efficiency.
|
||||
void pop_back_upto(difference_type n) {
|
||||
static_assert(std::is_convertible<iterator_category,
|
||||
std::bidirectional_iterator_tag>::value,
|
||||
"Can only access the end of a bidirectional range.");
|
||||
advance_upto(end_, -std::max<difference_type>(0, n), begin_,
|
||||
iterator_category());
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name creating derived ranges
|
||||
/// @{
|
||||
|
||||
/// Divides the range into two pieces at \c index, where a positive
|
||||
/// \c index represents an offset from the beginning of the range
|
||||
/// and a negative \c index represents an offset from the end.
|
||||
/// <code>range[index]</code> is the first element in the second
|
||||
/// piece. If <code>index >= size()</code>, the second piece
|
||||
/// will be empty. If <code>index < -size()</code>, the first
|
||||
/// piece will be empty.
|
||||
///
|
||||
/// \par Ill-formed unless:
|
||||
/// \c iterator_category is convertible to
|
||||
/// \c std::forward_iterator_tag.
|
||||
///
|
||||
/// \par Complexity:
|
||||
/// - If \c iterator_category is convertible to \c
|
||||
/// std::random_access_iterator_tag: O(1)
|
||||
/// - Otherwise, if \c iterator_category is convertible to \c
|
||||
/// std::bidirectional_iterator_tag, \c abs(index) iterator increments
|
||||
/// or decrements
|
||||
/// - Otherwise, if <code>index >= 0</code>, \c index iterator
|
||||
/// increments
|
||||
/// - Otherwise, <code>size() + (size() + index)</code>
|
||||
/// iterator increments.
|
||||
///
|
||||
/// \returns a pair of adjacent ranges.
|
||||
///
|
||||
/// \post
|
||||
/// - <code>result.first.size() == min(index, this->size())</code>
|
||||
/// - <code>result.first.end() == result.second.begin()</code>
|
||||
/// - <code>result.first.size() + result.second.size()</code> <code>==
|
||||
/// this->size()</code>
|
||||
///
|
||||
/// \todo split() could take an arbitrary number of indices and
|
||||
/// return an <code>N+1</code>-element \c tuple<>. This is tricky to
|
||||
/// implement with negative indices in the optimal number of
|
||||
/// increments or decrements for a bidirectional iterator, but it
|
||||
/// should be possible. Do we want it?
|
||||
std::pair<range, range> split(difference_type index) const {
|
||||
static_assert(
|
||||
std::is_convertible<iterator_category,
|
||||
std::forward_iterator_tag>::value,
|
||||
"Calling split on a non-std::forward range would return a useless "
|
||||
"first result.");
|
||||
if (index >= 0) {
|
||||
range second = *this;
|
||||
second.pop_front_upto(index);
|
||||
return make_pair(range(begin(), second.begin()), second);
|
||||
} else {
|
||||
return dispatch_split_neg(index, iterator_category());
|
||||
}
|
||||
}
|
||||
|
||||
/// \returns A sub-range from \c start to \c stop (not including \c
|
||||
/// stop, as usual). \c start and \c stop are interpreted as for
|
||||
/// <code>operator[]</code>, with negative values offsetting from
|
||||
/// the end of the range. Omitting the \c stop argument makes the
|
||||
/// sub-range continue to the end of the original range. Positive
|
||||
/// arguments saturate to the end of the range, and negative
|
||||
/// arguments saturate to the beginning. If \c stop is before \c
|
||||
/// start, returns an empty range beginning and ending at \c start.
|
||||
///
|
||||
/// \par Ill-formed unless:
|
||||
/// \c iterator_category is convertible to
|
||||
/// \c std::forward_iterator_tag.
|
||||
///
|
||||
/// \par Complexity:
|
||||
/// - If \c iterator_category is convertible to \c
|
||||
/// std::random_access_iterator_tag: O(1)
|
||||
/// - Otherwise, if \c iterator_category is convertible to \c
|
||||
/// std::bidirectional_iterator_tag, at most <code>min(abs(start),
|
||||
/// size()) + min(abs(stop), size())</code> iterator
|
||||
/// increments or decrements
|
||||
/// - Otherwise, if <code>start >= 0 && stop >= 0</code>,
|
||||
/// <code>max(start, stop)</code> iterator increments
|
||||
/// - Otherwise, <code>size() + max(start', stop')</code>
|
||||
/// iterator increments, where \c start' and \c stop' are the
|
||||
/// offsets of the elements \c start and \c stop refer to.
|
||||
///
|
||||
/// \note \c slice(start) should be implemented with a different
|
||||
/// overload, rather than defaulting \c stop to
|
||||
/// <code>numeric_limits<difference_type>::max()</code>, because
|
||||
/// using a default would force non-random-access ranges to use an
|
||||
/// O(<code>size()</code>) algorithm to compute the end rather
|
||||
/// than the O(1) they're capable of.
|
||||
range slice(difference_type start, difference_type stop) const {
|
||||
static_assert(
|
||||
std::is_convertible<iterator_category,
|
||||
std::forward_iterator_tag>::value,
|
||||
"Calling slice on a non-std::forward range would destroy the original "
|
||||
"range.");
|
||||
return dispatch_slice(start, stop, iterator_category());
|
||||
}
|
||||
|
||||
range slice(difference_type start) const {
|
||||
static_assert(
|
||||
std::is_convertible<iterator_category,
|
||||
std::forward_iterator_tag>::value,
|
||||
"Calling slice on a non-std::forward range would destroy the original "
|
||||
"range.");
|
||||
return split(start).second;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
// advance_upto: should be added to <algorithm>, but I'll use it as
|
||||
// a helper function here.
|
||||
//
|
||||
// These return the number of increments that weren't applied
|
||||
// because we ran into 'limit' (or 0 if we didn't run into limit).
|
||||
static difference_type advance_upto(Iterator &it, difference_type n,
|
||||
Iterator limit, std::input_iterator_tag) {
|
||||
if (n < 0)
|
||||
return 0;
|
||||
while (it != limit && n > 0) {
|
||||
++it;
|
||||
--n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static difference_type advance_upto(Iterator &it, difference_type n,
|
||||
Iterator limit,
|
||||
std::bidirectional_iterator_tag) {
|
||||
if (n < 0) {
|
||||
while (it != limit && n < 0) {
|
||||
--it;
|
||||
++n;
|
||||
}
|
||||
} else {
|
||||
while (it != limit && n > 0) {
|
||||
++it;
|
||||
--n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static difference_type advance_upto(Iterator &it, difference_type n,
|
||||
Iterator limit,
|
||||
std::random_access_iterator_tag) {
|
||||
difference_type distance = limit - it;
|
||||
if (distance < 0)
|
||||
assert(n <= 0);
|
||||
else if (distance > 0)
|
||||
assert(n >= 0);
|
||||
|
||||
if (abs(distance) > abs(n)) {
|
||||
it += n;
|
||||
return 0;
|
||||
} else {
|
||||
it = limit;
|
||||
return n - distance;
|
||||
}
|
||||
}
|
||||
|
||||
// Dispatch functions.
|
||||
difference_type dispatch_size(std::forward_iterator_tag) const {
|
||||
return std::distance(begin(), end());
|
||||
}
|
||||
|
||||
LLVM_CONSTEXPR difference_type dispatch_size(
|
||||
std::random_access_iterator_tag) const {
|
||||
return end() - begin();
|
||||
}
|
||||
|
||||
std::pair<range, range> dispatch_split_neg(difference_type index,
|
||||
std::forward_iterator_tag) const {
|
||||
assert(index < 0);
|
||||
difference_type size = this->size();
|
||||
return split(std::max<difference_type>(0, size + index));
|
||||
}
|
||||
|
||||
std::pair<range, range> dispatch_split_neg(
|
||||
difference_type index, std::bidirectional_iterator_tag) const {
|
||||
assert(index < 0);
|
||||
range first = *this;
|
||||
first.pop_back_upto(-index);
|
||||
return make_pair(first, range(first.end(), end()));
|
||||
}
|
||||
|
||||
range dispatch_slice(difference_type start, difference_type stop,
|
||||
std::forward_iterator_tag) const {
|
||||
if (start < 0 || stop < 0) {
|
||||
difference_type size = this->size();
|
||||
if (start < 0)
|
||||
start = std::max<difference_type>(0, size + start);
|
||||
if (stop < 0)
|
||||
stop = size + stop; // Possibly negative; will be fixed in 2 lines.
|
||||
}
|
||||
stop = std::max<difference_type>(start, stop);
|
||||
|
||||
Iterator first = begin();
|
||||
advance_upto(first, start, end(), iterator_category());
|
||||
Iterator last = first;
|
||||
advance_upto(last, stop - start, end(), iterator_category());
|
||||
return range(first, last);
|
||||
}
|
||||
|
||||
range dispatch_slice(const difference_type start, const difference_type stop,
|
||||
std::bidirectional_iterator_tag) const {
|
||||
Iterator first;
|
||||
if (start < 0) {
|
||||
first = end();
|
||||
advance_upto(first, start, begin(), iterator_category());
|
||||
} else {
|
||||
first = begin();
|
||||
advance_upto(first, start, end(), iterator_category());
|
||||
}
|
||||
Iterator last;
|
||||
if (stop < 0) {
|
||||
last = end();
|
||||
advance_upto(last, stop, first, iterator_category());
|
||||
} else {
|
||||
if (start >= 0) {
|
||||
last = first;
|
||||
if (stop > start)
|
||||
advance_upto(last, stop - start, end(), iterator_category());
|
||||
} else {
|
||||
// Complicated: 'start' walked from the end of the sequence,
|
||||
// but 'stop' needs to walk from the beginning.
|
||||
Iterator dummy = begin();
|
||||
// Walk up to 'stop' increments from begin(), stopping when we
|
||||
// get to 'first', and capturing the remaining number of
|
||||
// increments.
|
||||
difference_type increments_past_start =
|
||||
advance_upto(dummy, stop, first, iterator_category());
|
||||
if (increments_past_start == 0) {
|
||||
// If this is 0, then stop was before start.
|
||||
last = first;
|
||||
} else {
|
||||
// Otherwise, count that many spaces beyond first.
|
||||
last = first;
|
||||
advance_upto(last, increments_past_start, end(), iterator_category());
|
||||
}
|
||||
}
|
||||
}
|
||||
return range(first, last);
|
||||
}
|
||||
|
||||
range dispatch_slice(difference_type start, difference_type stop,
|
||||
std::random_access_iterator_tag) const {
|
||||
const difference_type size = this->size();
|
||||
if (start < 0)
|
||||
start = size + start;
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (start > size)
|
||||
start = size;
|
||||
|
||||
if (stop < 0)
|
||||
stop = size + stop;
|
||||
if (stop < start)
|
||||
stop = start;
|
||||
if (stop > size)
|
||||
stop = size;
|
||||
|
||||
return range(begin() + start, begin() + stop);
|
||||
}
|
||||
};
|
||||
|
||||
/// \name deducing constructor wrappers
|
||||
/// \relates std::range
|
||||
/// \xmlonly <nonmember/> \endxmlonly
|
||||
///
|
||||
/// These functions do the same thing as the constructor with the same
|
||||
/// signature. They just allow users to avoid writing the iterator
|
||||
/// type.
|
||||
/// @{
|
||||
|
||||
/// \todo I'd like to define a \c make_range taking a single iterator
|
||||
/// argument representing the beginning of a range that ends with a
|
||||
/// default-constructed \c Iterator. This would help with using
|
||||
/// iterators like \c istream_iterator. However, using just \c
|
||||
/// make_range() could be confusing and lead to people writing
|
||||
/// incorrect ranges of more common iterators. Is there a better name?
|
||||
template <typename Iterator>
|
||||
LLVM_CONSTEXPR range<Iterator> make_range(Iterator begin, Iterator end) {
|
||||
return range<Iterator>(begin, end);
|
||||
}
|
||||
|
||||
/// \par Participates in overload resolution if:
|
||||
/// \c begin(r) and \c end(r) return the same type.
|
||||
template <typename Range> LLVM_CONSTEXPR auto make_range(
|
||||
Range &&r,
|
||||
typename std::enable_if<detail::is_range<Range>::value>::type* = 0)
|
||||
-> range<decltype(detail::adl_begin(r))> {
|
||||
return range<decltype(detail::adl_begin(r))>(r);
|
||||
}
|
||||
|
||||
/// \par Participates in overload resolution if:
|
||||
/// - \c begin(r) and \c end(r) return the same type,
|
||||
/// - that type satisfies the invariant that <code>&*(i + N) ==
|
||||
/// (&*i) + N</code>, and
|
||||
/// - \c &*begin(r) has a pointer type.
|
||||
template <typename Range> LLVM_CONSTEXPR auto make_ptr_range(
|
||||
Range &&r,
|
||||
typename std::enable_if<
|
||||
detail::is_contiguous_range<Range>::value &&
|
||||
std::is_pointer<decltype(&*detail::adl_begin(r))>::value>::type* = 0)
|
||||
-> range<decltype(&*detail::adl_begin(r))> {
|
||||
return range<decltype(&*detail::adl_begin(r))>(r);
|
||||
}
|
||||
/// @}
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,79 +0,0 @@
|
||||
//===- lld/Driver/CoreInputGraph.h - Input Graph Node for Core linker -----===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
///
|
||||
/// Handles Options for CORE linking and provides InputElements
|
||||
/// for the CORE linker
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_DRIVER_CORE_INPUT_GRAPH_H
|
||||
#define LLD_DRIVER_CORE_INPUT_GRAPH_H
|
||||
|
||||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/ReaderWriter/CoreLinkingContext.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// \brief Represents a CORE File
|
||||
class COREFileNode : public FileNode {
|
||||
public:
|
||||
COREFileNode(CoreLinkingContext &ctx, StringRef path)
|
||||
: FileNode(path), _ctx(ctx) {}
|
||||
|
||||
static inline bool classof(const InputElement *a) {
|
||||
return a->kind() == InputElement::Kind::File;
|
||||
}
|
||||
|
||||
/// \brief validates the Input Element
|
||||
virtual bool validate() {
|
||||
(void)_ctx;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Parse the input file to lld::File.
|
||||
error_code parse(const LinkingContext &ctx, raw_ostream &diagnostics) {
|
||||
ErrorOr<StringRef> filePath = getPath(ctx);
|
||||
if (!filePath &&
|
||||
error_code(filePath) == llvm::errc::no_such_file_or_directory)
|
||||
return make_error_code(llvm::errc::no_such_file_or_directory);
|
||||
|
||||
// Create a memory buffer
|
||||
OwningPtr<MemoryBuffer> opmb;
|
||||
if (error_code ec = MemoryBuffer::getFileOrSTDIN(*filePath, opmb))
|
||||
return ec;
|
||||
|
||||
std::unique_ptr<MemoryBuffer> mb(opmb.take());
|
||||
_buffer = std::move(mb);
|
||||
return _ctx.getDefaultReader().parseFile(_buffer, _files);
|
||||
}
|
||||
|
||||
/// \brief Return the file that has to be processed by the resolver
|
||||
/// to resolve atoms. This iterates over all the files thats part
|
||||
/// of this node. Returns no_more_files when there are no files to be
|
||||
/// processed
|
||||
virtual ErrorOr<File &> getNextFile() {
|
||||
if (_files.size() == _nextFileIndex)
|
||||
return make_error_code(InputGraphError::no_more_files);
|
||||
return *_files[_nextFileIndex++];
|
||||
}
|
||||
|
||||
/// \brief Dump the Input Element
|
||||
virtual bool dump(raw_ostream &) { return true; }
|
||||
|
||||
private:
|
||||
CoreLinkingContext &_ctx;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,82 +0,0 @@
|
||||
//===- lld/Driver/DarwinInputGraph.h - Input Graph Node for Mach-O linker -===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
///
|
||||
/// Handles Options for MachO linking and provides InputElements
|
||||
/// for MachO linker
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_DRIVER_DARWIN_INPUT_GRAPH_H
|
||||
#define LLD_DRIVER_DARWIN_INPUT_GRAPH_H
|
||||
|
||||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/ReaderWriter/MachOLinkingContext.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// \brief Represents a MachO File
|
||||
class MachOFileNode : public FileNode {
|
||||
public:
|
||||
MachOFileNode(MachOLinkingContext &ctx, StringRef path, bool isWholeArchive)
|
||||
: FileNode(path), _ctx(ctx), _isWholeArchive(isWholeArchive) {}
|
||||
|
||||
static inline bool classof(const InputElement *a) {
|
||||
return a->kind() == InputElement::Kind::File;
|
||||
}
|
||||
|
||||
/// \brief validates the Input Element
|
||||
virtual bool validate() {
|
||||
(void)_ctx;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Parse the input file to lld::File.
|
||||
error_code parse(const LinkingContext &ctx, raw_ostream &diagnostics) {
|
||||
ErrorOr<StringRef> filePath = getPath(ctx);
|
||||
if (!filePath)
|
||||
return error_code(filePath);
|
||||
|
||||
if (error_code ec = getBuffer(*filePath))
|
||||
return ec;
|
||||
|
||||
if (ctx.logInputFiles())
|
||||
diagnostics << *filePath << "\n";
|
||||
|
||||
if (filePath->endswith(".objtxt"))
|
||||
return ctx.getYAMLReader().parseFile(_buffer, _files);
|
||||
|
||||
(void) (_isWholeArchive);
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
/// \brief Return the file that has to be processed by the resolver
|
||||
/// to resolve atoms. This iterates over all the files thats part
|
||||
/// of this node. Returns no_more_files when there are no files to be
|
||||
/// processed
|
||||
virtual ErrorOr<File &> getNextFile() {
|
||||
if (_files.size() == _nextFileIndex)
|
||||
return make_error_code(InputGraphError::no_more_files);
|
||||
return *_files[_nextFileIndex++];
|
||||
}
|
||||
|
||||
/// \brief Dump the Input Element
|
||||
virtual bool dump(raw_ostream &) { return true; }
|
||||
|
||||
private:
|
||||
const MachOLinkingContext &_ctx;
|
||||
bool _isWholeArchive;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,135 +0,0 @@
|
||||
//===- lld/Driver/Driver.h - Linker Driver Emulator -----------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
///
|
||||
/// Interface for Drivers which convert command line arguments into
|
||||
/// LinkingContext objects, then perform the link.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_DRIVER_DRIVER_H
|
||||
#define LLD_DRIVER_DRIVER_H
|
||||
|
||||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/Core/LLVM.h"
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
class LinkingContext;
|
||||
class CoreLinkingContext;
|
||||
class MachOLinkingContext;
|
||||
class PECOFFLinkingContext;
|
||||
class ELFLinkingContext;
|
||||
|
||||
/// Base class for all Drivers.
|
||||
class Driver {
|
||||
protected:
|
||||
|
||||
/// Performs link using specified options
|
||||
static bool link(LinkingContext &context,
|
||||
raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
private:
|
||||
Driver() LLVM_DELETED_FUNCTION;
|
||||
};
|
||||
|
||||
/// Driver for "universal" lld tool which can mimic any linker command line
|
||||
/// parsing once it figures out which command line flavor to use.
|
||||
class UniversalDriver : public Driver {
|
||||
public:
|
||||
/// Determine flavor and pass control to Driver for that flavor.
|
||||
static bool link(int argc, const char *argv[],
|
||||
raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
private:
|
||||
UniversalDriver() LLVM_DELETED_FUNCTION;
|
||||
};
|
||||
|
||||
/// Driver for gnu/binutil 'ld' command line options.
|
||||
class GnuLdDriver : public Driver {
|
||||
public:
|
||||
/// Parses command line arguments same as gnu/binutils ld and performs link.
|
||||
/// Returns true iff an error occurred.
|
||||
static bool linkELF(int argc, const char *argv[],
|
||||
raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
/// Uses gnu/binutils style ld command line options to fill in options struct.
|
||||
/// Returns true iff there was an error.
|
||||
static bool parse(int argc, const char *argv[],
|
||||
std::unique_ptr<ELFLinkingContext> &context,
|
||||
raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
private:
|
||||
static llvm::Triple getDefaultTarget(const char *progName);
|
||||
|
||||
GnuLdDriver() LLVM_DELETED_FUNCTION;
|
||||
};
|
||||
|
||||
/// Driver for darwin/ld64 'ld' command line options.
|
||||
class DarwinLdDriver : public Driver {
|
||||
public:
|
||||
/// Parses command line arguments same as darwin's ld and performs link.
|
||||
/// Returns true iff there was an error.
|
||||
static bool linkMachO(int argc, const char *argv[],
|
||||
raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
/// Uses darwin style ld command line options to update LinkingContext object.
|
||||
/// Returns true iff there was an error.
|
||||
static bool parse(int argc, const char *argv[], MachOLinkingContext &info,
|
||||
raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
private:
|
||||
DarwinLdDriver() LLVM_DELETED_FUNCTION;
|
||||
};
|
||||
|
||||
/// Driver for Windows 'link.exe' command line options
|
||||
class WinLinkDriver : public Driver {
|
||||
public:
|
||||
/// Parses command line arguments same as Windows link.exe and performs link.
|
||||
/// Returns true iff there was an error.
|
||||
static bool linkPECOFF(int argc, const char *argv[],
|
||||
raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
/// Uses Windows style link command line options to fill in options struct.
|
||||
/// Returns true iff there was an error.
|
||||
static bool parse(int argc, const char *argv[], PECOFFLinkingContext &info,
|
||||
raw_ostream &diagnostics = llvm::errs(),
|
||||
bool isDirective = false);
|
||||
|
||||
private:
|
||||
WinLinkDriver() LLVM_DELETED_FUNCTION;
|
||||
};
|
||||
|
||||
/// Driver for lld unit tests
|
||||
class CoreDriver : public Driver {
|
||||
public:
|
||||
|
||||
/// Parses command line arguments same as lld-core and performs link.
|
||||
/// Returns true iff there was an error.
|
||||
static bool link(int argc, const char *argv[],
|
||||
raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
/// Uses lld-core command line options to fill in options struct.
|
||||
/// Returns true iff there was an error.
|
||||
static bool parse(int argc, const char *argv[], CoreLinkingContext &info,
|
||||
raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
private:
|
||||
CoreDriver() LLVM_DELETED_FUNCTION;
|
||||
};
|
||||
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,187 +0,0 @@
|
||||
//===- lld/Driver/GnuLdInputGraph.h - Input Graph Node for ELF linker------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
///
|
||||
/// Handles Options for the GNU style linker for ELF and provides InputElements
|
||||
/// for the GNU style linker for ELF
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_DRIVER_GNU_LD_INPUT_GRAPH_H
|
||||
#define LLD_DRIVER_GNU_LD_INPUT_GRAPH_H
|
||||
|
||||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/Core/Resolver.h"
|
||||
#include "lld/ReaderWriter/ELFLinkingContext.h"
|
||||
#include "lld/ReaderWriter/FileArchive.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// \brief Represents a ELF File
|
||||
class ELFFileNode : public FileNode {
|
||||
public:
|
||||
ELFFileNode(ELFLinkingContext &ctx, StringRef path,
|
||||
std::vector<StringRef> searchPath, int64_t ordinal = -1,
|
||||
bool isWholeArchive = false, bool asNeeded = false,
|
||||
bool dashlPrefix = false)
|
||||
: FileNode(path, ordinal), _elfLinkingContext(ctx),
|
||||
_isWholeArchive(isWholeArchive), _asNeeded(asNeeded),
|
||||
_isDashlPrefix(dashlPrefix) {
|
||||
std::copy(searchPath.begin(), searchPath.end(),
|
||||
std::back_inserter(_libraryPaths));
|
||||
}
|
||||
|
||||
static inline bool classof(const InputElement *a) {
|
||||
return a->kind() == InputElement::Kind::File;
|
||||
}
|
||||
|
||||
virtual ErrorOr<StringRef> getPath(const LinkingContext &ctx) const;
|
||||
|
||||
/// \brief validates the Input Element
|
||||
virtual bool validate() { return true; }
|
||||
|
||||
/// \brief create an error string for printing purposes
|
||||
virtual std::string errStr(error_code);
|
||||
|
||||
/// \brief Dump the Input Element
|
||||
virtual bool dump(raw_ostream &diagnostics) {
|
||||
diagnostics << "Name : " << *getPath(_elfLinkingContext) << "\n";
|
||||
diagnostics << "Type : "
|
||||
<< "ELF File"
|
||||
<< "\n";
|
||||
diagnostics << "Ordinal : " << getOrdinal() << "\n";
|
||||
diagnostics << "Attributes : "
|
||||
<< "\n";
|
||||
diagnostics << " - wholeArchive : "
|
||||
<< ((_isWholeArchive) ? "true" : "false") << "\n";
|
||||
diagnostics << " - asNeeded : " << ((_asNeeded) ? "true" : "false")
|
||||
<< "\n";
|
||||
diagnostics << " contextPath : " << ((_libraryPaths.size()) ? "" : "None")
|
||||
<< "\n";
|
||||
for (auto path : _libraryPaths)
|
||||
diagnostics << " - " << path << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Parse the input file to lld::File.
|
||||
error_code parse(const LinkingContext &ctx, raw_ostream &diagnostics) {
|
||||
ErrorOr<StringRef> filePath = getPath(ctx);
|
||||
if (!filePath)
|
||||
return error_code(filePath);
|
||||
|
||||
if (error_code ec = getBuffer(*filePath))
|
||||
return ec;
|
||||
|
||||
if (ctx.logInputFiles())
|
||||
diagnostics << *filePath << "\n";
|
||||
|
||||
if (filePath->endswith(".objtxt"))
|
||||
return ctx.getYAMLReader().parseFile(_buffer, _files);
|
||||
|
||||
// Identify File type
|
||||
llvm::sys::fs::file_magic FileType =
|
||||
llvm::sys::fs::identify_magic(_buffer->getBuffer());
|
||||
|
||||
switch (FileType) {
|
||||
case llvm::sys::fs::file_magic::elf_relocatable:
|
||||
case llvm::sys::fs::file_magic::elf_shared_object:
|
||||
// Call the default reader to read object files and shared objects
|
||||
return _elfLinkingContext.getDefaultReader().parseFile(_buffer, _files);
|
||||
|
||||
case llvm::sys::fs::file_magic::archive: {
|
||||
// Process archive files. If Whole Archive option is set,
|
||||
// parse all members of the archive.
|
||||
error_code ec;
|
||||
std::unique_ptr<FileArchive> fileArchive(
|
||||
new FileArchive(ctx, std::move(_buffer), ec, _isWholeArchive));
|
||||
if (_isWholeArchive) {
|
||||
fileArchive->parseAllMembers(_files);
|
||||
_archiveFile = std::move(fileArchive);
|
||||
} else {
|
||||
_files.push_back(std::move(fileArchive));
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
|
||||
default:
|
||||
// Process Linker script
|
||||
return _elfLinkingContext.getLinkerScriptReader().parseFile(_buffer,
|
||||
_files);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief This is used by Group Nodes, when there is a need to reset the
|
||||
/// the file to be processed next. When handling a group node that contains
|
||||
/// Input elements, if the group node has to be reprocessed, the linker needs
|
||||
/// to start processing files as part of the inputelement from beginning.
|
||||
/// reset the next file index to 0 only if the node is an archive library or
|
||||
/// a shared library
|
||||
virtual void resetNextIndex() {
|
||||
if ((!_isWholeArchive && (_files[0]->kind() == File::kindArchiveLibrary)) ||
|
||||
(_files[0]->kind() == File::kindSharedLibrary))
|
||||
_nextFileIndex = 0;
|
||||
setResolveState(Resolver::StateNoChange);
|
||||
return;
|
||||
}
|
||||
|
||||
/// \brief Return the file that has to be processed by the resolver
|
||||
/// to resolve atoms. This iterates over all the files thats part
|
||||
/// of this node. Returns no_more_files when there are no files to be
|
||||
/// processed
|
||||
virtual ErrorOr<File &> getNextFile() {
|
||||
if (_nextFileIndex == _files.size())
|
||||
return make_error_code(InputGraphError::no_more_files);
|
||||
return *_files[_nextFileIndex++];
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
const ELFLinkingContext &_elfLinkingContext;
|
||||
bool _isWholeArchive;
|
||||
bool _asNeeded;
|
||||
bool _isDashlPrefix;
|
||||
std::vector<StringRef> _libraryPaths;
|
||||
std::unique_ptr<FileArchive> _archiveFile;
|
||||
};
|
||||
|
||||
/// \brief Represents a ELF control node
|
||||
class ELFGroup : public Group {
|
||||
public:
|
||||
ELFGroup(ELFLinkingContext &ctx, int64_t ordinal)
|
||||
: Group(ordinal), _elfLinkingContext(ctx) {}
|
||||
|
||||
static inline bool classof(const InputElement *a) {
|
||||
return a->kind() == InputElement::Kind::Control;
|
||||
}
|
||||
|
||||
/// \brief Validate the options
|
||||
virtual bool validate() {
|
||||
(void)_elfLinkingContext;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Dump the ELFGroup
|
||||
virtual bool dump(raw_ostream &) { return true; }
|
||||
|
||||
/// \brief Parse the group members.
|
||||
error_code parse(const LinkingContext &ctx, raw_ostream &diagnostics) {
|
||||
for (auto &ei : _elements)
|
||||
if (error_code ec = ei->parse(ctx, diagnostics))
|
||||
return ec;
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
private:
|
||||
const ELFLinkingContext &_elfLinkingContext;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,101 +0,0 @@
|
||||
//===- lld/Driver/WinLinkInputGraph.h - Input Graph Node for COFF linker --===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
///
|
||||
/// Handles Options for PECOFF linking and provides InputElements
|
||||
/// for PECOFF linker
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_DRIVER_WIN_LINK_INPUT_GRAPH_H
|
||||
#define LLD_DRIVER_WIN_LINK_INPUT_GRAPH_H
|
||||
|
||||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include "lld/ReaderWriter/FileArchive.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// \brief Represents a PECOFF File
|
||||
class PECOFFFileNode : public FileNode {
|
||||
public:
|
||||
PECOFFFileNode(PECOFFLinkingContext &ctx, StringRef path)
|
||||
: FileNode(path), _ctx(ctx) {}
|
||||
|
||||
static inline bool classof(const InputElement *a) {
|
||||
return a->kind() == InputElement::Kind::File;
|
||||
}
|
||||
|
||||
virtual ErrorOr<StringRef> getPath(const LinkingContext &ctx) const;
|
||||
|
||||
/// \brief Parse the input file to lld::File.
|
||||
error_code parse(const LinkingContext &ctx, raw_ostream &diagnostics) {
|
||||
ErrorOr<StringRef> filePath = getPath(ctx);
|
||||
if (!filePath)
|
||||
return error_code(filePath);
|
||||
|
||||
if (error_code ec = getBuffer(*filePath))
|
||||
return ec;
|
||||
|
||||
if (ctx.logInputFiles())
|
||||
diagnostics << *filePath << "\n";
|
||||
|
||||
if (filePath->endswith(".objtxt"))
|
||||
return ctx.getYAMLReader().parseFile(_buffer, _files);
|
||||
|
||||
llvm::sys::fs::file_magic FileType =
|
||||
llvm::sys::fs::identify_magic(_buffer->getBuffer());
|
||||
std::unique_ptr<File> f;
|
||||
|
||||
switch (FileType) {
|
||||
case llvm::sys::fs::file_magic::archive: {
|
||||
// Archive File
|
||||
error_code ec;
|
||||
f.reset(new FileArchive(ctx, std::move(_buffer), ec, false));
|
||||
_files.push_back(std::move(f));
|
||||
return ec;
|
||||
}
|
||||
|
||||
case llvm::sys::fs::file_magic::coff_object:
|
||||
default:
|
||||
return _ctx.getDefaultReader().parseFile(_buffer, _files);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief validates the Input Element
|
||||
virtual bool validate() { return true; }
|
||||
|
||||
/// \brief Dump the Input Element
|
||||
virtual bool dump(raw_ostream &) { return true; }
|
||||
|
||||
virtual ErrorOr<File &> getNextFile() {
|
||||
if (_nextFileIndex == _files.size())
|
||||
return make_error_code(InputGraphError::no_more_files);
|
||||
return *_files[_nextFileIndex++];
|
||||
}
|
||||
|
||||
protected:
|
||||
const PECOFFLinkingContext &_ctx;
|
||||
};
|
||||
|
||||
/// \brief Represents a PECOFF Library File
|
||||
class PECOFFLibraryNode : public PECOFFFileNode {
|
||||
public:
|
||||
PECOFFLibraryNode(PECOFFLinkingContext &ctx, StringRef path)
|
||||
: PECOFFFileNode(ctx, path) {}
|
||||
|
||||
virtual ErrorOr<StringRef> getPath(const LinkingContext &ctx) const;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,106 +0,0 @@
|
||||
//===------ Passes/LayoutPass.h - Handles Layout of atoms ------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_PASSES_LAYOUT_PASS_H
|
||||
#define LLD_PASSES_LAYOUT_PASS_H
|
||||
|
||||
#include "lld/Core/Atom.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "lld/Core/range.h"
|
||||
#include "lld/Core/Reference.h"
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
class DefinedAtom;
|
||||
class MutableFile;
|
||||
|
||||
/// This linker pass does the layout of the atoms. The pass is done after the
|
||||
/// order their .o files were found on the command line, then by order of the
|
||||
/// atoms (address) in the .o file. But some atoms have a prefered location
|
||||
/// in their section (such as pinned to the start or end of the section), so
|
||||
/// the sort must take that into account too.
|
||||
class LayoutPass : public Pass {
|
||||
public:
|
||||
|
||||
// Compare and Sort Atoms by their ordinals
|
||||
class CompareAtoms {
|
||||
public:
|
||||
explicit CompareAtoms(const LayoutPass &pass) : _layout(pass) {}
|
||||
bool operator()(const DefinedAtom *left, const DefinedAtom *right) const;
|
||||
private:
|
||||
bool compare(const DefinedAtom *left, const DefinedAtom *right,
|
||||
std::string &reason) const;
|
||||
const LayoutPass &_layout;
|
||||
};
|
||||
|
||||
LayoutPass() : Pass(), _compareAtoms(*this) {}
|
||||
|
||||
/// Sorts atoms in mergedFile by content type then by command line order.
|
||||
virtual void perform(std::unique_ptr<MutableFile> &mergedFile);
|
||||
|
||||
virtual ~LayoutPass() {}
|
||||
|
||||
private:
|
||||
// Build the followOn atoms chain as specified by the kindLayoutAfter
|
||||
// reference type
|
||||
void buildFollowOnTable(MutableFile::DefinedAtomRange &range);
|
||||
|
||||
// Build the followOn atoms chain as specified by the kindInGroup
|
||||
// reference type
|
||||
void buildInGroupTable(MutableFile::DefinedAtomRange &range);
|
||||
|
||||
// Build the PrecededBy Table as specified by the kindLayoutBefore
|
||||
// reference type
|
||||
void buildPrecededByTable(MutableFile::DefinedAtomRange &range);
|
||||
|
||||
// Build a map of Atoms to ordinals for sorting the atoms
|
||||
void buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range);
|
||||
|
||||
typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
|
||||
typedef llvm::DenseMap<const DefinedAtom *, uint64_t> AtomToOrdinalT;
|
||||
|
||||
// A map to be used to sort atoms. It represents the order of atoms in the
|
||||
// result; if Atom X is mapped to atom Y in this map, X will be located
|
||||
// immediately before Y in the output file. Y might be mapped to another
|
||||
// atom, constructing a follow-on chain. An atom cannot be mapped to more
|
||||
// than one atom unless all but one atom are of size zero.
|
||||
AtomToAtomT _followOnNexts;
|
||||
|
||||
// A map to be used to sort atoms. It's a map from an atom to its root of
|
||||
// follow-on chain. A root atom is mapped to itself. If an atom is not in
|
||||
// _followOnNexts, the atom is not in this map, and vice versa.
|
||||
AtomToAtomT _followOnRoots;
|
||||
|
||||
AtomToOrdinalT _ordinalOverrideMap;
|
||||
CompareAtoms _compareAtoms;
|
||||
|
||||
// Helper methods for buildFollowOnTable().
|
||||
const DefinedAtom *findAtomFollowedBy(const DefinedAtom *targetAtom);
|
||||
bool checkAllPrevAtomsZeroSize(const DefinedAtom *targetAtom);
|
||||
|
||||
void setChainRoot(const DefinedAtom *targetAtom, const DefinedAtom *root);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Check if the follow-on graph is a correct structure. For debugging only.
|
||||
void checkFollowonChain(MutableFile::DefinedAtomRange &range);
|
||||
|
||||
typedef std::vector<const DefinedAtom *>::iterator DefinedAtomIter;
|
||||
void checkTransitivity(DefinedAtomIter begin, DefinedAtomIter end) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_PASSES_LAYOUT_PASS_H
|
||||
@@ -1,41 +0,0 @@
|
||||
//===--Passes/RoundTripNativePass.h - Write Native file/Read it back------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_PASSES_ROUND_TRIP_NATIVE_PASS_H
|
||||
#define LLD_PASSES_ROUND_TRIP_NATIVE_PASS_H
|
||||
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/LinkingContext.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
class RoundTripNativePass : public Pass {
|
||||
public:
|
||||
RoundTripNativePass(LinkingContext &context) : Pass(), _context(context) {}
|
||||
|
||||
/// Writes to a native file and reads the atoms from the native file back.
|
||||
/// Replaces mergedFile with the contents of the native File.
|
||||
virtual void perform(std::unique_ptr<MutableFile> &mergedFile);
|
||||
|
||||
virtual ~RoundTripNativePass() {}
|
||||
|
||||
private:
|
||||
LinkingContext &_context;
|
||||
// Keep the parsed file alive for the rest of the link. All atoms
|
||||
// that are created by the RoundTripNativePass are owned by the
|
||||
// nativeFile.
|
||||
std::vector<std::unique_ptr<File> > _nativeFile;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_PASSES_ROUND_TRIP_NATIVE_PASS_H
|
||||
@@ -1,41 +0,0 @@
|
||||
//===--Passes/RoundTripYAMLPass.h- Write YAML file/Read it back-----------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_PASSES_ROUND_TRIP_YAML_PASS_H
|
||||
#define LLD_PASSES_ROUND_TRIP_YAML_PASS_H
|
||||
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/LinkingContext.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
class RoundTripYAMLPass : public Pass {
|
||||
public:
|
||||
RoundTripYAMLPass(LinkingContext &context) : Pass(), _context(context) {}
|
||||
|
||||
/// Writes to a YAML file and reads the atoms from the YAML file back.
|
||||
/// Replaces the mergedFile with new contents.
|
||||
virtual void perform(std::unique_ptr<MutableFile> &mergedFile);
|
||||
|
||||
virtual ~RoundTripYAMLPass() {}
|
||||
|
||||
private:
|
||||
LinkingContext &_context;
|
||||
// Keep the parsed file alive for the rest of the link. All atoms
|
||||
// that are created by the RoundTripYAMLPass are owned by the
|
||||
// yamlFile.
|
||||
std::vector<std::unique_ptr<File> > _yamlFile;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_PASSES_ROUND_TRIP_YAML_PASS_H
|
||||
@@ -1,41 +0,0 @@
|
||||
//===- include/lld/ReaderWriter/AtomLayout.h ------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_ATOM_LAYOUT_H
|
||||
#define LLD_READER_WRITER_ATOM_LAYOUT_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace lld {
|
||||
class Atom;
|
||||
|
||||
/// AtomLayouts are used by a writer to manage physical positions of atoms.
|
||||
/// AtomLayout has two positions; one is file offset, and the other is the
|
||||
/// address when loaded into memory.
|
||||
///
|
||||
/// Construction of AtomLayouts is usually a multi-pass process. When an atom
|
||||
/// is appended to a section, we don't know the starting address of the
|
||||
/// section. Thus, we have no choice but to store the offset from the
|
||||
/// beginning of the section as AtomLayout values. After all sections starting
|
||||
/// address are fixed, AtomLayout is revisited to get the offsets updated by
|
||||
/// adding the starting addresses of the section.
|
||||
struct AtomLayout {
|
||||
AtomLayout(const Atom *a, uint64_t fileOff, uint64_t virAddr)
|
||||
: _atom(a), _fileOffset(fileOff), _virtualAddr(virAddr) {}
|
||||
|
||||
AtomLayout() : _atom(nullptr), _fileOffset(0), _virtualAddr(0) {}
|
||||
|
||||
const Atom *_atom;
|
||||
uint64_t _fileOffset;
|
||||
uint64_t _virtualAddr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,45 +0,0 @@
|
||||
//===- lld/ReaderWriter/CoreLinkingContext.h ------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_CORE_LINKER_CONTEXT_H
|
||||
#define LLD_READER_WRITER_CORE_LINKER_CONTEXT_H
|
||||
|
||||
#include "lld/Core/LinkingContext.h"
|
||||
#include "lld/ReaderWriter/Reader.h"
|
||||
#include "lld/ReaderWriter/Writer.h"
|
||||
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
class CoreLinkingContext : public LinkingContext {
|
||||
public:
|
||||
CoreLinkingContext();
|
||||
|
||||
virtual bool validateImpl(raw_ostream &diagnostics);
|
||||
virtual void addPasses(PassManager &pm);
|
||||
virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const;
|
||||
virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
|
||||
|
||||
void addPassNamed(StringRef name) { _passNames.push_back(name); }
|
||||
|
||||
virtual Reader &getDefaultReader() const { return *_reader; }
|
||||
|
||||
protected:
|
||||
virtual Writer &writer() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Reader> _reader;
|
||||
std::unique_ptr<Writer> _writer;
|
||||
std::vector<StringRef> _passNames;
|
||||
};
|
||||
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,246 +0,0 @@
|
||||
//===- lld/ReaderWriter/ELFLinkingContext.h -------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_ELF_LINKER_CONTEXT_H
|
||||
#define LLD_READER_WRITER_ELF_LINKER_CONTEXT_H
|
||||
|
||||
#include "lld/Core/LinkingContext.h"
|
||||
#include "lld/Core/PassManager.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "lld/Core/range.h"
|
||||
|
||||
#include "lld/ReaderWriter/Reader.h"
|
||||
#include "lld/ReaderWriter/Writer.h"
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Object/ELF.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace lld {
|
||||
class DefinedAtom;
|
||||
class Reference;
|
||||
|
||||
namespace elf {
|
||||
template <typename ELFT> class TargetHandler;
|
||||
}
|
||||
|
||||
class TargetHandlerBase {
|
||||
public:
|
||||
virtual ~TargetHandlerBase() {}
|
||||
};
|
||||
|
||||
class ELFLinkingContext : public LinkingContext {
|
||||
public:
|
||||
|
||||
/// \brief The type of ELF executable that the linker
|
||||
/// creates.
|
||||
enum class OutputMagic : uint8_t {
|
||||
DEFAULT, // The default mode, no specific magic set
|
||||
NMAGIC, // Disallow shared libraries and dont align sections
|
||||
// PageAlign Data, Mark Text Segment/Data segment RW
|
||||
OMAGIC // Disallow shared libraries and dont align sections,
|
||||
// Mark Text Segment/Data segment RW
|
||||
};
|
||||
|
||||
llvm::Triple getTriple() const { return _triple; }
|
||||
virtual bool is64Bits() const;
|
||||
virtual bool isLittleEndian() const;
|
||||
virtual uint64_t getPageSize() const { return 0x1000; }
|
||||
OutputMagic getOutputMagic() const { return _outputMagic; }
|
||||
uint16_t getOutputELFType() const { return _outputELFType; }
|
||||
uint16_t getOutputMachine() const;
|
||||
bool mergeCommonStrings() const { return _mergeCommonStrings; }
|
||||
virtual uint64_t getBaseAddress() const { return _baseAddress; }
|
||||
|
||||
/// This controls if undefined atoms need to be created for undefines that are
|
||||
/// present in a SharedLibrary. If this option is set, undefined atoms are
|
||||
/// created for every undefined symbol that are present in the dynamic table
|
||||
/// in the shared library
|
||||
bool useShlibUndefines() const { return _useShlibUndefines; }
|
||||
/// @}
|
||||
|
||||
/// \brief Does this relocation belong in the dynamic relocation table?
|
||||
///
|
||||
/// This table is evaluated at loadtime by the dynamic loader and is
|
||||
/// referenced by the DT_RELA{,ENT,SZ} entries in the dynamic table.
|
||||
/// Relocations that return true will be added to the dynamic relocation
|
||||
/// table.
|
||||
virtual bool isDynamicRelocation(const DefinedAtom &,
|
||||
const Reference &) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool validateImpl(raw_ostream &diagnostics);
|
||||
|
||||
/// \brief Does the linker allow dynamic libraries to be linked with ?
|
||||
/// This is true when the output mode of the executable is set to be
|
||||
/// having NMAGIC/OMAGIC
|
||||
virtual bool allowLinkWithDynamicLibraries() const {
|
||||
if (_outputMagic == OutputMagic::NMAGIC ||
|
||||
_outputMagic == OutputMagic::OMAGIC || _noAllowDynamicLibraries)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
|
||||
|
||||
/// \brief Does this relocation belong in the dynamic plt relocation table?
|
||||
///
|
||||
/// This table holds all of the relocations used for delayed symbol binding.
|
||||
/// It will be evaluated at load time if LD_BIND_NOW is set. It is referenced
|
||||
/// by the DT_{JMPREL,PLTRELSZ} entries in the dynamic table.
|
||||
/// Relocations that return true will be added to the dynamic plt relocation
|
||||
/// table.
|
||||
virtual bool isPLTRelocation(const DefinedAtom &, const Reference &) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief The path to the dynamic interpreter
|
||||
virtual StringRef getDefaultInterpreter() const {
|
||||
return "/lib64/ld-linux-x86-64.so.2";
|
||||
}
|
||||
|
||||
/// \brief The dynamic linker path set by the --dynamic-linker option
|
||||
virtual StringRef getInterpreter() const {
|
||||
if (_dynamicLinkerArg)
|
||||
return _dynamicLinkerPath;
|
||||
return getDefaultInterpreter();
|
||||
}
|
||||
|
||||
virtual Reader &getDefaultReader() const { return *_elfReader; }
|
||||
|
||||
virtual Reader &getLinkerScriptReader() const { return *_linkerScriptReader; }
|
||||
|
||||
/// \brief Does the output have dynamic sections.
|
||||
virtual bool isDynamic() const;
|
||||
|
||||
/// \brief Is the relocation a relative relocation
|
||||
virtual bool isRelativeReloc(const Reference &r) const;
|
||||
|
||||
template <typename ELFT>
|
||||
lld::elf::TargetHandler<ELFT> &getTargetHandler() const {
|
||||
assert(_targetHandler && "Got null TargetHandler!");
|
||||
return static_cast<lld::elf::TargetHandler<ELFT> &>(*_targetHandler.get());
|
||||
}
|
||||
|
||||
virtual void addPasses(PassManager &pm);
|
||||
|
||||
void setTriple(llvm::Triple trip) { _triple = trip; }
|
||||
void setNoInhibitExec(bool v) { _noInhibitExec = v; }
|
||||
void setIsStaticExecutable(bool v) { _isStaticExecutable = v; }
|
||||
void setMergeCommonStrings(bool v) { _mergeCommonStrings = v; }
|
||||
void setUseShlibUndefines(bool use) { _useShlibUndefines = use; }
|
||||
|
||||
void setOutputELFType(uint32_t type) { _outputELFType = type; }
|
||||
|
||||
/// \brief Set the dynamic linker path
|
||||
void setInterpreter(StringRef dynamicLinker) {
|
||||
_dynamicLinkerArg = true;
|
||||
_dynamicLinkerPath = dynamicLinker;
|
||||
}
|
||||
|
||||
/// \brief Set NMAGIC output kind when the linker specifies --nmagic
|
||||
/// or -n in the command line
|
||||
/// Set OMAGIC output kind when the linker specifies --omagic
|
||||
/// or -N in the command line
|
||||
virtual void setOutputMagic(OutputMagic magic) { _outputMagic = magic; }
|
||||
|
||||
/// \brief Disallow dynamic libraries during linking
|
||||
virtual void setNoAllowDynamicLibraries() { _noAllowDynamicLibraries = true; }
|
||||
|
||||
/// Searches directories for a match on the input File
|
||||
ErrorOr<StringRef>
|
||||
searchLibrary(StringRef libName,
|
||||
const std::vector<StringRef> &searchPath) const;
|
||||
|
||||
/// Get the entry symbol name
|
||||
virtual StringRef entrySymbolName() const;
|
||||
|
||||
/// add to the list of initializer functions
|
||||
void addInitFunction(StringRef name) { _initFunctions.push_back(name); }
|
||||
|
||||
/// add to the list of finalizer functions
|
||||
void addFiniFunction(StringRef name) { _finiFunctions.push_back(name); }
|
||||
|
||||
/// Return the list of initializer symbols that are specified in the
|
||||
/// linker command line, using the -init option.
|
||||
range<const StringRef *> initFunctions() const {
|
||||
return _initFunctions;
|
||||
}
|
||||
|
||||
/// Return the list of finalizer symbols that are specified in the
|
||||
/// linker command line, using the -fini option.
|
||||
range<const StringRef *> finiFunctions() const { return _finiFunctions; }
|
||||
|
||||
void setSharedObjectName(StringRef soname) {
|
||||
_soname = soname;
|
||||
}
|
||||
|
||||
StringRef sharedObjectName() const { return _soname; }
|
||||
|
||||
/// \brief Set path to the system root
|
||||
void setSysroot(StringRef path) {
|
||||
_sysrootPath = path;
|
||||
}
|
||||
|
||||
void addRpath(StringRef path) {
|
||||
_rpathList.push_back(path);
|
||||
}
|
||||
|
||||
range<const StringRef *> getRpathList() const {
|
||||
return _rpathList;
|
||||
}
|
||||
|
||||
void addRpathLink(StringRef path) {
|
||||
_rpathLinkList.push_back(path);
|
||||
}
|
||||
|
||||
range<const StringRef *> getRpathLinkList() const {
|
||||
return _rpathLinkList;
|
||||
}
|
||||
|
||||
private:
|
||||
ELFLinkingContext() LLVM_DELETED_FUNCTION;
|
||||
|
||||
protected:
|
||||
ELFLinkingContext(llvm::Triple, std::unique_ptr<TargetHandlerBase>);
|
||||
|
||||
virtual Writer &writer() const;
|
||||
|
||||
/// Method to create a internal file for an undefined symbol
|
||||
virtual std::unique_ptr<File> createUndefinedSymbolFile() const;
|
||||
|
||||
uint16_t _outputELFType; // e.g ET_EXEC
|
||||
llvm::Triple _triple;
|
||||
std::unique_ptr<TargetHandlerBase> _targetHandler;
|
||||
uint64_t _baseAddress;
|
||||
bool _isStaticExecutable;
|
||||
bool _noInhibitExec;
|
||||
bool _mergeCommonStrings;
|
||||
bool _runLayoutPass;
|
||||
bool _useShlibUndefines;
|
||||
bool _dynamicLinkerArg;
|
||||
bool _noAllowDynamicLibraries;
|
||||
OutputMagic _outputMagic;
|
||||
StringRefVector _inputSearchPaths;
|
||||
std::unique_ptr<Reader> _elfReader;
|
||||
std::unique_ptr<Writer> _writer;
|
||||
std::unique_ptr<Reader> _linkerScriptReader;
|
||||
StringRef _dynamicLinkerPath;
|
||||
StringRefVector _initFunctions;
|
||||
StringRefVector _finiFunctions;
|
||||
StringRef _sysrootPath;
|
||||
StringRef _soname;
|
||||
StringRefVector _rpathList;
|
||||
StringRefVector _rpathLinkList;
|
||||
};
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,176 +0,0 @@
|
||||
//===- lld/ReaderWriter/FileArchive.h - Archive Library File -----------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===---------------------------------------------------------------------===//
|
||||
#ifndef LLD_READER_WRITER_FILE_ARCHIVE_H
|
||||
#define LLD_READER_WRITER_FILE_ARCHIVE_H
|
||||
|
||||
#include "lld/Core/ArchiveLibraryFile.h"
|
||||
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Object/Archive.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// \brief The FileArchive class represents an Archive Library file
|
||||
class FileArchive : public ArchiveLibraryFile {
|
||||
public:
|
||||
|
||||
virtual ~FileArchive() { }
|
||||
|
||||
/// \brief Check if any member of the archive contains an Atom with the
|
||||
/// specified name and return the File object for that member, or nullptr.
|
||||
virtual const File *find(StringRef name, bool dataSymbolOnly) const {
|
||||
auto member = _symbolMemberMap.find(name);
|
||||
if (member == _symbolMemberMap.end())
|
||||
return nullptr;
|
||||
|
||||
llvm::object::Archive::child_iterator ci = member->second;
|
||||
|
||||
if (dataSymbolOnly) {
|
||||
OwningPtr<MemoryBuffer> buff;
|
||||
if (ci->getMemoryBuffer(buff, true))
|
||||
return nullptr;
|
||||
if (isDataSymbol(buff.take(), name))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<File>> result;
|
||||
|
||||
OwningPtr<MemoryBuffer> buff;
|
||||
if (ci->getMemoryBuffer(buff, true))
|
||||
return nullptr;
|
||||
if (_context.logInputFiles())
|
||||
llvm::outs() << buff->getBufferIdentifier() << "\n";
|
||||
std::unique_ptr<MemoryBuffer> mb(buff.take());
|
||||
if (_context.getDefaultReader().parseFile(mb, result))
|
||||
return nullptr;
|
||||
|
||||
assert(result.size() == 1);
|
||||
|
||||
// give up the pointer so that this object no longer manages it
|
||||
return result[0].release();
|
||||
}
|
||||
|
||||
/// \brief Load all members of the archive ?
|
||||
virtual bool isWholeArchive() const { return _isWholeArchive; }
|
||||
|
||||
/// \brief parse each member
|
||||
virtual error_code
|
||||
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const {
|
||||
for (auto mf = _archive->begin_children(),
|
||||
me = _archive->end_children(); mf != me; ++mf) {
|
||||
OwningPtr<MemoryBuffer> buff;
|
||||
error_code ec;
|
||||
if ((ec = mf->getMemoryBuffer(buff, true)))
|
||||
return ec;
|
||||
if (_context.logInputFiles())
|
||||
llvm::outs() << buff->getBufferIdentifier() << "\n";
|
||||
std::unique_ptr<MemoryBuffer> mbc(buff.take());
|
||||
if ((ec = _context.getDefaultReader().parseFile(mbc, result)))
|
||||
return ec;
|
||||
}
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
virtual const atom_collection<DefinedAtom> &defined() const {
|
||||
return _definedAtoms;
|
||||
}
|
||||
|
||||
virtual const atom_collection<UndefinedAtom> &undefined() const {
|
||||
return _undefinedAtoms;
|
||||
}
|
||||
|
||||
virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
|
||||
return _sharedLibraryAtoms;
|
||||
}
|
||||
|
||||
virtual const atom_collection<AbsoluteAtom> &absolute() const {
|
||||
return _absoluteAtoms;
|
||||
}
|
||||
|
||||
protected:
|
||||
error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const {
|
||||
std::unique_ptr<llvm::object::ObjectFile>
|
||||
obj(llvm::object::ObjectFile::createObjectFile(mb));
|
||||
error_code ec;
|
||||
llvm::object::SymbolRef::Type symtype;
|
||||
uint32_t symflags;
|
||||
llvm::object::symbol_iterator ibegin = obj->begin_symbols();
|
||||
llvm::object::symbol_iterator iend = obj->end_symbols();
|
||||
StringRef symbolname;
|
||||
|
||||
for (llvm::object::symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
|
||||
if (ec) return ec;
|
||||
|
||||
// Get symbol name
|
||||
if ((ec = (i->getName(symbolname)))) return ec;
|
||||
|
||||
if (symbolname != symbol)
|
||||
continue;
|
||||
|
||||
// Get symbol flags
|
||||
if ((ec = (i->getFlags(symflags)))) return ec;
|
||||
|
||||
if (symflags <= llvm::object::SymbolRef::SF_Undefined)
|
||||
continue;
|
||||
|
||||
// Get Symbol Type
|
||||
if ((ec = (i->getType(symtype)))) return ec;
|
||||
|
||||
if (symtype == llvm::object::SymbolRef::ST_Data) {
|
||||
return error_code::success();
|
||||
}
|
||||
}
|
||||
return llvm::object::object_error::parse_failed;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<llvm::object::Archive> _archive;
|
||||
atom_collection_vector<DefinedAtom> _definedAtoms;
|
||||
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
|
||||
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
|
||||
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
|
||||
bool _isWholeArchive;
|
||||
|
||||
public:
|
||||
/// only subclasses of ArchiveLibraryFile can be instantiated
|
||||
FileArchive(const LinkingContext &context,
|
||||
std::unique_ptr<MemoryBuffer> mb, error_code &ec,
|
||||
bool isWholeArchive)
|
||||
: ArchiveLibraryFile(context, mb->getBufferIdentifier()),
|
||||
_isWholeArchive(isWholeArchive) {
|
||||
std::unique_ptr<llvm::object::Archive> archive_obj(
|
||||
new llvm::object::Archive(mb.release(), ec));
|
||||
if (ec)
|
||||
return;
|
||||
_archive.swap(archive_obj);
|
||||
|
||||
// Cache symbols.
|
||||
for (auto i = _archive->begin_symbols(), e = _archive->end_symbols();
|
||||
i != e; ++i) {
|
||||
StringRef name;
|
||||
llvm::object::Archive::child_iterator member;
|
||||
if ((ec = i->getName(name)))
|
||||
return;
|
||||
if ((ec = i->getMember(member)))
|
||||
return;
|
||||
_symbolMemberMap[name] = member;
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<StringRef,
|
||||
llvm::object::Archive::child_iterator> _symbolMemberMap;
|
||||
}; // class FileArchive
|
||||
|
||||
} // end namespace lld
|
||||
|
||||
#endif // LLD_READER_WRITER_FILE_ARCHIVE_H
|
||||
@@ -1,228 +0,0 @@
|
||||
//===- ReaderWriter/LinkerScript.h ----------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Linker script parser.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_LINKER_SCRIPT_H
|
||||
#define LLD_READER_WRITER_LINKER_SCRIPT_H
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
|
||||
namespace lld {
|
||||
namespace script {
|
||||
class Token {
|
||||
public:
|
||||
enum Kind {
|
||||
unknown,
|
||||
eof,
|
||||
identifier,
|
||||
l_paren,
|
||||
r_paren,
|
||||
kw_entry,
|
||||
kw_group,
|
||||
kw_output_format,
|
||||
kw_as_needed
|
||||
};
|
||||
|
||||
Token() : _kind(unknown) {}
|
||||
Token(StringRef range, Kind kind) : _range(range), _kind(kind) {}
|
||||
|
||||
void dump(raw_ostream &os) const;
|
||||
|
||||
StringRef _range;
|
||||
Kind _kind;
|
||||
};
|
||||
|
||||
class Lexer {
|
||||
public:
|
||||
explicit Lexer(std::unique_ptr<MemoryBuffer> mb)
|
||||
: _buffer(mb->getBuffer()) {
|
||||
_sourceManager.AddNewSourceBuffer(mb.release(), llvm::SMLoc());
|
||||
}
|
||||
|
||||
void lex(Token &tok);
|
||||
|
||||
const llvm::SourceMgr &getSourceMgr() const { return _sourceManager; }
|
||||
|
||||
private:
|
||||
bool canStartName(char c) const;
|
||||
bool canContinueName(char c) const;
|
||||
void skipWhitespace();
|
||||
|
||||
Token _current;
|
||||
/// \brief The current buffer state.
|
||||
StringRef _buffer;
|
||||
// Lexer owns the input files.
|
||||
llvm::SourceMgr _sourceManager;
|
||||
};
|
||||
|
||||
class Command {
|
||||
public:
|
||||
enum class Kind {
|
||||
Entry,
|
||||
OutputFormat,
|
||||
Group,
|
||||
};
|
||||
|
||||
Kind getKind() const { return _kind; }
|
||||
|
||||
virtual void dump(raw_ostream &os) const = 0;
|
||||
|
||||
virtual ~Command() {}
|
||||
|
||||
protected:
|
||||
explicit Command(Kind k) : _kind(k) {}
|
||||
|
||||
private:
|
||||
Kind _kind;
|
||||
};
|
||||
|
||||
class OutputFormat : public Command {
|
||||
public:
|
||||
explicit OutputFormat(StringRef format)
|
||||
: Command(Kind::OutputFormat), _format(format) {}
|
||||
|
||||
static bool classof(const Command *c) {
|
||||
return c->getKind() == Kind::OutputFormat;
|
||||
}
|
||||
|
||||
virtual void dump(raw_ostream &os) const {
|
||||
os << "OUTPUT_FORMAT(" << getFormat() << ")\n";
|
||||
}
|
||||
|
||||
StringRef getFormat() const { return _format; }
|
||||
|
||||
private:
|
||||
StringRef _format;
|
||||
};
|
||||
|
||||
struct Path {
|
||||
StringRef _path;
|
||||
bool _asNeeded;
|
||||
|
||||
Path() : _asNeeded(false) {}
|
||||
explicit Path(StringRef path, bool asNeeded = false)
|
||||
: _path(path), _asNeeded(asNeeded) {}
|
||||
};
|
||||
|
||||
class Group : public Command {
|
||||
public:
|
||||
template <class RangeT>
|
||||
explicit Group(RangeT range) : Command(Kind::Group) {
|
||||
using std::begin;
|
||||
using std::end;
|
||||
std::copy(begin(range), end(range), std::back_inserter(_paths));
|
||||
}
|
||||
|
||||
static bool classof(const Command *c) { return c->getKind() == Kind::Group; }
|
||||
|
||||
virtual void dump(raw_ostream &os) const {
|
||||
os << "GROUP(";
|
||||
bool first = true;
|
||||
for (const auto &path : getPaths()) {
|
||||
if (!first)
|
||||
os << " ";
|
||||
else
|
||||
first = false;
|
||||
if (path._asNeeded)
|
||||
os << "AS_NEEDED(";
|
||||
os << path._path;
|
||||
if (path._asNeeded)
|
||||
os << ")";
|
||||
}
|
||||
os << ")\n";
|
||||
}
|
||||
|
||||
const std::vector<Path> &getPaths() const { return _paths; }
|
||||
|
||||
private:
|
||||
std::vector<Path> _paths;
|
||||
};
|
||||
|
||||
class Entry : public Command {
|
||||
public:
|
||||
explicit Entry(StringRef entryName) :
|
||||
Command(Kind::Entry), _entryName(entryName) { }
|
||||
|
||||
static bool classof(const Command *c) {
|
||||
return c->getKind() == Kind::Entry;
|
||||
}
|
||||
|
||||
virtual void dump(raw_ostream &os) const {
|
||||
os << "ENTRY(" << _entryName << ")\n";
|
||||
}
|
||||
|
||||
const StringRef getEntryName() const {
|
||||
return _entryName;
|
||||
}
|
||||
|
||||
private:
|
||||
StringRef _entryName;
|
||||
};
|
||||
|
||||
class LinkerScript {
|
||||
public:
|
||||
void dump(raw_ostream &os) const {
|
||||
for (const auto &c : _commands)
|
||||
c->dump(os);
|
||||
}
|
||||
|
||||
std::vector<Command *> _commands;
|
||||
};
|
||||
|
||||
class Parser {
|
||||
public:
|
||||
explicit Parser(Lexer &lex) : _lex(lex) {}
|
||||
|
||||
LinkerScript *parse();
|
||||
|
||||
private:
|
||||
void consumeToken() { _lex.lex(_tok); }
|
||||
|
||||
void error(const Token &tok, Twine msg) {
|
||||
_lex.getSourceMgr()
|
||||
.PrintMessage(llvm::SMLoc::getFromPointer(tok._range.data()),
|
||||
llvm::SourceMgr::DK_Error, msg);
|
||||
}
|
||||
|
||||
bool expectAndConsume(Token::Kind kind, Twine msg) {
|
||||
if (_tok._kind != kind) {
|
||||
error(_tok, msg);
|
||||
return false;
|
||||
}
|
||||
consumeToken();
|
||||
return true;
|
||||
}
|
||||
|
||||
OutputFormat *parseOutputFormat();
|
||||
Group *parseGroup();
|
||||
bool parseAsNeeded(std::vector<Path> &paths);
|
||||
Entry *parseEntry();
|
||||
|
||||
private:
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
LinkerScript _script;
|
||||
Lexer &_lex;
|
||||
Token _tok;
|
||||
};
|
||||
} // end namespace script
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,627 +0,0 @@
|
||||
//===- lib/ReaderWriter/MachO/MachOFormat.hpp -----------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//
|
||||
// This file contains all the structs and constants needed to write a
|
||||
// mach-o final linked image. The names of the structs and constants
|
||||
// are the same as in the darwin native header <mach-o/loader.h> so
|
||||
// they will be familiar to anyone who has used that header.
|
||||
//
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
|
||||
#ifndef LLD_READER_WRITER_MACHO_FORMAT_H
|
||||
#define LLD_READER_WRITER_MACHO_FORMAT_H
|
||||
|
||||
namespace lld {
|
||||
namespace mach_o {
|
||||
|
||||
|
||||
enum {
|
||||
MH_MAGIC = 0xfeedface,
|
||||
MH_MAGIC_64 = 0xfeedfacf
|
||||
};
|
||||
|
||||
enum {
|
||||
CPU_TYPE_ARM = 0x0000000C,
|
||||
CPU_TYPE_I386 = 0x00000007,
|
||||
CPU_TYPE_X86_64 = 0x01000007
|
||||
};
|
||||
|
||||
enum {
|
||||
CPU_SUBTYPE_X86_ALL = 0x00000003,
|
||||
CPU_SUBTYPE_X86_64_ALL = 0x00000003,
|
||||
CPU_SUBTYPE_ARM_V6 = 0x00000006,
|
||||
CPU_SUBTYPE_ARM_V7 = 0x00000009,
|
||||
CPU_SUBTYPE_ARM_V7S = 0x0000000B
|
||||
};
|
||||
|
||||
enum {
|
||||
MH_OBJECT = 0x1,
|
||||
MH_EXECUTE = 0x2,
|
||||
MH_PRELOAD = 0x5,
|
||||
MH_DYLIB = 0x6,
|
||||
MH_DYLINKER = 0x7,
|
||||
MH_BUNDLE = 0x8,
|
||||
MH_DYLIB_STUB = 0x9,
|
||||
MH_KEXT_BUNDLE= 0xB
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Every mach-o file starts with this header. The header size is
|
||||
// 28 bytes for 32-bit architecures and 32-bytes for 64-bit architectures.
|
||||
//
|
||||
class mach_header {
|
||||
public:
|
||||
uint32_t magic;
|
||||
uint32_t cputype;
|
||||
uint32_t cpusubtype;
|
||||
uint32_t filetype;
|
||||
uint32_t ncmds;
|
||||
uint32_t sizeofcmds;
|
||||
uint32_t flags;
|
||||
uint32_t reserved;
|
||||
|
||||
uint64_t size() {
|
||||
return (magic == 0xfeedfacf) ? 32 : 28;
|
||||
}
|
||||
|
||||
void copyTo(uint8_t *to, bool swap=false) {
|
||||
::memcpy(to, (char*)&magic, this->size());
|
||||
}
|
||||
|
||||
void recordLoadCommand(const class load_command *lc);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Every mach-o file has a list of load commands after the mach_header.
|
||||
// Each load command starts with a type and length, so you can iterate
|
||||
// through the load commands even if you don't understand the content
|
||||
// of a particular type.
|
||||
//
|
||||
// The model for handling endianness and 32 vs 64 bitness is that the in-memory
|
||||
// object is always 64-bit and the native endianess. The endianess swapping
|
||||
// and pointer sizing is done when writing (copyTo method) or when reading
|
||||
// (constructor that takes a buffer).
|
||||
//
|
||||
// The load_command subclasses are designed so to mirror the traditional "C"
|
||||
// structs, so you can get and set the same field names (e.g. seg->vmaddr = 0).
|
||||
//
|
||||
class load_command {
|
||||
public:
|
||||
const uint32_t cmd; // type of load command
|
||||
const uint32_t cmdsize; // length of load command including this header
|
||||
|
||||
load_command(uint32_t cmdNumber, uint32_t sz, bool is64, bool align=false)
|
||||
: cmd(cmdNumber), cmdsize(pointerAlign(sz, is64, align)) {
|
||||
}
|
||||
|
||||
virtual ~load_command() {
|
||||
}
|
||||
|
||||
virtual void copyTo(uint8_t *to, bool swap=false) = 0;
|
||||
private:
|
||||
// Load commands must be pointer-size aligned. Most load commands are
|
||||
// a fixed size, so there is a runtime assert to check those. For variable
|
||||
// length load commands, setting the align option to true will add padding
|
||||
// at the end of the load command to round up its size for proper alignment.
|
||||
uint32_t pointerAlign(uint32_t size, bool is64, bool align) {
|
||||
if ( align ) {
|
||||
if ( is64 )
|
||||
return (size + 7) & (-8);
|
||||
else
|
||||
return (size + 3) & (-4);
|
||||
}
|
||||
else {
|
||||
if ( is64 )
|
||||
assert((size % 8) == 0);
|
||||
else
|
||||
assert((size % 4) == 0);
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline void mach_header::recordLoadCommand(const load_command *lc) {
|
||||
++ncmds;
|
||||
sizeofcmds += lc->cmdsize;
|
||||
}
|
||||
|
||||
// Supported load command types
|
||||
enum {
|
||||
LC_SEGMENT = 0x00000001,
|
||||
LC_SYMTAB = 0x00000002,
|
||||
LC_UNIXTHREAD = 0x00000005,
|
||||
LC_LOAD_DYLIB = 0x0000000C,
|
||||
LC_LOAD_DYLINKER = 0x0000000E,
|
||||
LC_SEGMENT_64 = 0x00000019,
|
||||
LC_MAIN = 0x80000028,
|
||||
LC_DYLD_INFO_ONLY = 0x80000022
|
||||
};
|
||||
|
||||
// Memory protection bit used in segment_command.initprot
|
||||
enum {
|
||||
VM_PROT_NONE = 0x0,
|
||||
VM_PROT_READ = 0x1,
|
||||
VM_PROT_WRITE = 0x2,
|
||||
VM_PROT_EXECUTE = 0x4,
|
||||
};
|
||||
|
||||
// Bits for the section.flags field
|
||||
enum {
|
||||
// Section "type" is the low byte
|
||||
SECTION_TYPE = 0x000000FF,
|
||||
S_REGULAR = 0x00000000,
|
||||
S_ZEROFILL = 0x00000001,
|
||||
S_CSTRING_LITERALS = 0x00000002,
|
||||
S_NON_LAZY_SYMBOL_POINTERS= 0x00000006,
|
||||
S_LAZY_SYMBOL_POINTERS = 0x00000007,
|
||||
S_SYMBOL_STUBS = 0x00000008,
|
||||
|
||||
// Other bits in section.flags
|
||||
S_ATTR_PURE_INSTRUCTIONS = 0x80000000,
|
||||
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
|
||||
};
|
||||
|
||||
|
||||
// section record for 32-bit architectures
|
||||
struct section {
|
||||
char sectname[16];
|
||||
char segname[16];
|
||||
uint32_t addr;
|
||||
uint32_t size;
|
||||
uint32_t offset;
|
||||
uint32_t align;
|
||||
uint32_t reloff;
|
||||
uint32_t nreloc;
|
||||
uint32_t flags;
|
||||
uint32_t reserved1;
|
||||
uint32_t reserved2;
|
||||
};
|
||||
|
||||
// section record for 64-bit architectures
|
||||
struct section_64 {
|
||||
char sectname[16];
|
||||
char segname[16];
|
||||
uint64_t addr;
|
||||
uint64_t size;
|
||||
uint32_t offset;
|
||||
uint32_t align;
|
||||
uint32_t reloff;
|
||||
uint32_t nreloc;
|
||||
uint32_t flags;
|
||||
uint32_t reserved1;
|
||||
uint32_t reserved2;
|
||||
uint32_t reserved3;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// A segment load command has a fixed set of fields followed by an 'nsect'
|
||||
// array of section records. The in-memory object uses a pointer to
|
||||
// a dynamically allocated array of sections.
|
||||
//
|
||||
class segment_command : public load_command {
|
||||
public:
|
||||
char segname[16];
|
||||
uint64_t vmaddr;
|
||||
uint64_t vmsize;
|
||||
uint64_t fileoff;
|
||||
uint64_t filesize;
|
||||
uint32_t maxprot;
|
||||
uint32_t initprot;
|
||||
uint32_t nsects;
|
||||
uint32_t flags;
|
||||
section_64 *sections;
|
||||
|
||||
segment_command(unsigned sectCount, bool is64)
|
||||
: load_command((is64 ? LC_SEGMENT_64 : LC_SEGMENT),
|
||||
(is64 ? (72 + sectCount*80) : (56 + sectCount*68)),
|
||||
is64),
|
||||
vmaddr(0), vmsize(0), fileoff(0), filesize(0),
|
||||
maxprot(0), initprot(0), nsects(sectCount), flags(0) {
|
||||
sections = new section_64[sectCount];
|
||||
this->nsects = sectCount;
|
||||
}
|
||||
|
||||
~segment_command() {
|
||||
delete sections;
|
||||
}
|
||||
|
||||
void copyTo(uint8_t *to, bool swap) {
|
||||
if ( swap ) {
|
||||
assert(0 && "non-native endianness not supported yet");
|
||||
}
|
||||
else {
|
||||
if( is64() ) {
|
||||
// in-memory matches on-disk, so copy segment fields followed by sections
|
||||
::memcpy(to, (uint8_t*)&cmd, 72);
|
||||
if ( nsects != 0 )
|
||||
::memcpy(&to[72], sections, sizeof(section_64)*nsects);
|
||||
}
|
||||
else {
|
||||
// on-disk is 32-bit struct, so copy each field
|
||||
::memcpy(to, (uint8_t*)&cmd, 24);
|
||||
copy32(to, 24, vmaddr);
|
||||
copy32(to, 28, vmsize);
|
||||
copy32(to, 32, fileoff);
|
||||
copy32(to, 36, filesize);
|
||||
copy32(to, 40, maxprot);
|
||||
copy32(to, 44, initprot);
|
||||
copy32(to, 48, nsects);
|
||||
copy32(to, 52, flags);
|
||||
for(uint32_t i=0; i < nsects; ++i) {
|
||||
unsigned off = 56+i*68;
|
||||
::memcpy(&to[off], sections[i].sectname, 32);
|
||||
copy32(to, off+32, sections[i].addr);
|
||||
copy32(to, off+36, sections[i].size);
|
||||
copy32(to, off+40, sections[i].offset);
|
||||
copy32(to, off+44, sections[i].align);
|
||||
copy32(to, off+48, sections[i].reloff);
|
||||
copy32(to, off+52, sections[i].nreloc);
|
||||
copy32(to, off+56, sections[i].flags);
|
||||
copy32(to, off+60, sections[i].reserved1);
|
||||
copy32(to, off+64, sections[i].reserved2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void copy32(uint8_t *to, unsigned offset, uint64_t value) {
|
||||
uint32_t value32 = value; // FIXME: range check
|
||||
::memcpy(&to[offset], &value32, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
bool is64() {
|
||||
return (cmd == LC_SEGMENT_64);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The dylinker_command contains the path to the dynamic loader to use
|
||||
// with the program (e.g. "/usr/lib/dyld"). So, it is variable length.
|
||||
// But load commands must be pointer size aligned.
|
||||
//
|
||||
//
|
||||
class dylinker_command : public load_command {
|
||||
public:
|
||||
uint32_t name_offset;
|
||||
private:
|
||||
StringRef _name;
|
||||
public:
|
||||
dylinker_command(StringRef path, bool is64)
|
||||
: load_command(LC_LOAD_DYLINKER,12 + path.size(), is64, true),
|
||||
name_offset(12), _name(path) {
|
||||
}
|
||||
|
||||
virtual void copyTo(uint8_t *to, bool swap=false) {
|
||||
if ( swap ) {
|
||||
assert(0 && "non-native endianness not supported yet");
|
||||
}
|
||||
else {
|
||||
// in-memory matches on-disk, so copy first fields followed by path
|
||||
::memcpy(to, (uint8_t*)&cmd, 12);
|
||||
::memcpy(&to[12], _name.data(), _name.size());
|
||||
::memset(&to[12+_name.size()], 0, cmdsize-(12+_name.size()));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The symtab_command just holds the offset to the array of nlist structs
|
||||
// and the offsets to the string pool for all symbol names.
|
||||
//
|
||||
class symtab_command : public load_command {
|
||||
public:
|
||||
uint32_t symoff;
|
||||
uint32_t nsyms;
|
||||
uint32_t stroff;
|
||||
uint32_t strsize;
|
||||
|
||||
symtab_command(bool is64)
|
||||
: load_command(LC_SYMTAB, 24, is64),
|
||||
symoff(0), nsyms(0), stroff(0), strsize(0) {
|
||||
}
|
||||
|
||||
virtual void copyTo(uint8_t *to, bool swap=false) {
|
||||
if ( swap ) {
|
||||
assert(0 && "non-native endianness not supported yet");
|
||||
}
|
||||
else {
|
||||
// in-memory matches on-disk, so copy fields
|
||||
::memcpy(to, (uint8_t*)&cmd, 24);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// The entry_point_command load command holds the offset to the function
|
||||
// _main in a dynamic executable.
|
||||
//
|
||||
class entry_point_command : public load_command {
|
||||
public:
|
||||
uint64_t entryoff;
|
||||
uint64_t stacksize;
|
||||
|
||||
entry_point_command(bool is64)
|
||||
: load_command(LC_MAIN, 24, is64), entryoff(0), stacksize(0) {
|
||||
}
|
||||
|
||||
virtual void copyTo(uint8_t *to, bool swap=false) {
|
||||
if ( swap ) {
|
||||
assert(0 && "non-native endianness not supported yet");
|
||||
}
|
||||
else {
|
||||
// in-memory matches on-disk, so copy fields
|
||||
::memcpy(to, (uint8_t*)&cmd, 24);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// The thread_command load command holds the set of initial register values
|
||||
// for a dynamic executable. In reality, only the PC and SP are used.
|
||||
//
|
||||
class thread_command : public load_command {
|
||||
public:
|
||||
uint32_t fields_flavor;
|
||||
uint32_t fields_count;
|
||||
private:
|
||||
uint32_t _cpuType;
|
||||
uint8_t *_registerArray;
|
||||
|
||||
public:
|
||||
thread_command(uint32_t cpuType, bool is64)
|
||||
: load_command(LC_UNIXTHREAD, 16+registersBufferSize(cpuType), is64),
|
||||
fields_count(registersBufferSize(cpuType)/4), _cpuType(cpuType) {
|
||||
switch ( cpuType ) {
|
||||
case CPU_TYPE_I386:
|
||||
fields_flavor = 1; // i386_THREAD_STATE
|
||||
break;
|
||||
case CPU_TYPE_X86_64:
|
||||
fields_flavor = 4; // x86_THREAD_STATE64;
|
||||
break;
|
||||
case CPU_TYPE_ARM:
|
||||
fields_flavor = 1; // ARM_THREAD_STATE
|
||||
break;
|
||||
default:
|
||||
assert(0 && "unsupported cpu type");
|
||||
}
|
||||
_registerArray = reinterpret_cast<uint8_t*>(
|
||||
::calloc(registersBufferSize(cpuType), 1));
|
||||
assert(_registerArray);
|
||||
}
|
||||
|
||||
virtual void copyTo(uint8_t *to, bool swap=false) {
|
||||
if ( swap ) {
|
||||
assert(0 && "non-native endianness not supported yet");
|
||||
}
|
||||
else {
|
||||
// in-memory matches on-disk, so copy fixed fields
|
||||
::memcpy(to, (uint8_t*)&cmd, 16);
|
||||
// that register array
|
||||
::memcpy(&to[16], _registerArray, registersBufferSize(_cpuType));
|
||||
}
|
||||
}
|
||||
|
||||
void setPC(uint64_t pc) {
|
||||
uint32_t *regs32 = reinterpret_cast<uint32_t*>(_registerArray);
|
||||
uint64_t *regs64 = reinterpret_cast<uint64_t*>(_registerArray);
|
||||
switch ( _cpuType ) {
|
||||
case CPU_TYPE_I386:
|
||||
regs32[10] = pc;
|
||||
break;
|
||||
case CPU_TYPE_X86_64:
|
||||
regs64[16] = pc;
|
||||
break;
|
||||
case CPU_TYPE_ARM:
|
||||
regs32[15] = pc;
|
||||
break;
|
||||
default:
|
||||
assert(0 && "unsupported cpu type");
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~thread_command() {
|
||||
::free(_registerArray);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t registersBufferSize(uint32_t cpuType) {
|
||||
switch ( cpuType ) {
|
||||
case CPU_TYPE_I386:
|
||||
return 64; // i386_THREAD_STATE_COUNT * 4
|
||||
case CPU_TYPE_X86_64:
|
||||
return 168; // x86_THREAD_STATE64_COUNT * 4
|
||||
case CPU_TYPE_ARM:
|
||||
return 68; // ARM_THREAD_STATE_COUNT * 4
|
||||
}
|
||||
assert(0 && "unsupported cpu type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The dylib_command load command holds the name/path of a dynamic shared
|
||||
// library which this mach-o image depends on.
|
||||
//
|
||||
struct dylib_command : public load_command {
|
||||
uint32_t name_offset;
|
||||
uint32_t timestamp;
|
||||
uint32_t current_version;
|
||||
uint32_t compatibility_version;
|
||||
private:
|
||||
StringRef _loadPath;
|
||||
public:
|
||||
|
||||
dylib_command(StringRef path, bool is64)
|
||||
: load_command(LC_LOAD_DYLIB, 24 + path.size(), is64, true),
|
||||
name_offset(24), timestamp(0),
|
||||
current_version(0x10000), compatibility_version(0x10000),
|
||||
_loadPath(path) {
|
||||
}
|
||||
|
||||
virtual void copyTo(uint8_t *to, bool swap=false) {
|
||||
if ( swap ) {
|
||||
assert(0 && "non-native endianness not supported yet");
|
||||
}
|
||||
else {
|
||||
// in-memory matches on-disk, so copy first fields followed by path
|
||||
::memcpy(to, (uint8_t*)&cmd, 24);
|
||||
::memcpy(&to[24], _loadPath.data(), _loadPath.size());
|
||||
::memset(&to[24+_loadPath.size()], 0, cmdsize-(24+_loadPath.size()));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// The dyld_info_command load command holds the offsets to various tables
|
||||
// of information needed by dyld to prepare the image for execution.
|
||||
//
|
||||
struct dyld_info_command : public load_command {
|
||||
uint32_t rebase_off;
|
||||
uint32_t rebase_size;
|
||||
uint32_t bind_off;
|
||||
uint32_t bind_size;
|
||||
uint32_t weak_bind_off;
|
||||
uint32_t weak_bind_size;
|
||||
uint32_t lazy_bind_off;
|
||||
uint32_t lazy_bind_size;
|
||||
uint32_t export_off;
|
||||
uint32_t export_size;
|
||||
|
||||
dyld_info_command(bool is64)
|
||||
: load_command(LC_DYLD_INFO_ONLY, 48, is64),
|
||||
rebase_off(0), rebase_size(0),
|
||||
bind_off(0), bind_size(0), weak_bind_off(0), weak_bind_size(0),
|
||||
lazy_bind_off(0), lazy_bind_size(0), export_off(0), export_size(0) {
|
||||
}
|
||||
|
||||
virtual void copyTo(uint8_t *to, bool swap=false) {
|
||||
if ( swap ) {
|
||||
assert(0 && "non-native endianness not supported yet");
|
||||
}
|
||||
else {
|
||||
// in-memory matches on-disk, so copy fields
|
||||
::memcpy(to, (uint8_t*)&cmd, 48);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
BIND_TYPE_POINTER = 1,
|
||||
BIND_TYPE_TEXT_ABSOLUTE32 = 2,
|
||||
BIND_TYPE_TEXT_PCREL32 = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
BIND_SPECIAL_DYLIB_SELF = 0,
|
||||
BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1,
|
||||
BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2
|
||||
};
|
||||
|
||||
enum {
|
||||
BIND_SYMBOL_FLAGS_WEAK_IMPORT = 0x1,
|
||||
BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION = 0x8
|
||||
};
|
||||
|
||||
enum {
|
||||
BIND_OPCODE_MASK = 0xF0,
|
||||
BIND_IMMEDIATE_MASK = 0x0F,
|
||||
BIND_OPCODE_DONE = 0x00,
|
||||
BIND_OPCODE_SET_DYLIB_ORDINAL_IMM = 0x10,
|
||||
BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB = 0x20,
|
||||
BIND_OPCODE_SET_DYLIB_SPECIAL_IMM = 0x30,
|
||||
BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM = 0x40,
|
||||
BIND_OPCODE_SET_TYPE_IMM = 0x50,
|
||||
BIND_OPCODE_SET_ADDEND_SLEB = 0x60,
|
||||
BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x70,
|
||||
BIND_OPCODE_ADD_ADDR_ULEB = 0x80,
|
||||
BIND_OPCODE_DO_BIND = 0x90,
|
||||
BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB = 0xA0,
|
||||
BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED = 0xB0,
|
||||
BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB = 0xC0
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
enum {
|
||||
N_UNDF = 0x00,
|
||||
N_EXT = 0x01,
|
||||
N_PEXT = 0x10,
|
||||
N_SECT = 0x0e
|
||||
};
|
||||
|
||||
class nlist {
|
||||
public:
|
||||
uint32_t n_strx;
|
||||
uint8_t n_type;
|
||||
uint8_t n_sect;
|
||||
uint16_t n_desc;
|
||||
uint64_t n_value;
|
||||
|
||||
static unsigned size(bool is64) {
|
||||
return (is64 ? 16 : 12);
|
||||
}
|
||||
|
||||
void copyTo(uint8_t *to, bool is64, bool swap=false) {
|
||||
if ( swap ) {
|
||||
assert(0 && "non-native endianness not supported yet");
|
||||
}
|
||||
else {
|
||||
if ( is64 ) {
|
||||
// in-memory matches on-disk, so just copy whole struct
|
||||
::memcpy(to, (uint8_t*)&n_strx, 16);
|
||||
}
|
||||
else {
|
||||
// on-disk uses 32-bit n_value, so special case n_value
|
||||
::memcpy(to, (uint8_t*)&n_strx, 8);
|
||||
uint32_t value32 = n_value; // FIXME: range check
|
||||
::memcpy(&to[8], &value32, sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace mach_o
|
||||
} // namespace lld
|
||||
|
||||
|
||||
|
||||
#endif // LLD_READER_WRITER_MACHO_FORMAT_H
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
//===- lld/ReaderWriter/MachOLinkingContext.h -----------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
|
||||
#define LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
|
||||
|
||||
#include "lld/Core/LinkingContext.h"
|
||||
#include "lld/ReaderWriter/Reader.h"
|
||||
#include "lld/ReaderWriter/Writer.h"
|
||||
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/MachO.h"
|
||||
|
||||
using llvm::MachO::HeaderFileType;
|
||||
|
||||
namespace lld {
|
||||
|
||||
namespace mach_o {
|
||||
class KindHandler; // defined in lib. this header is in include.
|
||||
}
|
||||
|
||||
class MachOLinkingContext : public LinkingContext {
|
||||
public:
|
||||
MachOLinkingContext();
|
||||
~MachOLinkingContext();
|
||||
|
||||
virtual void addPasses(PassManager &pm);
|
||||
virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const;
|
||||
virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
|
||||
virtual bool validateImpl(raw_ostream &diagnostics);
|
||||
|
||||
uint32_t getCPUType() const;
|
||||
uint32_t getCPUSubType() const;
|
||||
|
||||
bool addEntryPointLoadCommand() const;
|
||||
bool addUnixThreadLoadCommand() const;
|
||||
bool outputTypeHasEntry() const;
|
||||
bool is64Bit() const;
|
||||
|
||||
virtual uint64_t pageZeroSize() const { return _pageZeroSize; }
|
||||
virtual uint64_t pageSize() const { return _pageSize; }
|
||||
|
||||
mach_o::KindHandler &kindHandler() const;
|
||||
|
||||
HeaderFileType outputFileType() const { return _outputFileType; }
|
||||
|
||||
enum Arch {
|
||||
arch_unknown,
|
||||
arch_ppc,
|
||||
arch_x86,
|
||||
arch_x86_64,
|
||||
arch_armv6,
|
||||
arch_armv7,
|
||||
arch_armv7s,
|
||||
};
|
||||
|
||||
enum class OS {
|
||||
unknown, macOSX, iOS, iOS_simulator
|
||||
};
|
||||
|
||||
Arch arch() const { return _arch; }
|
||||
OS os() const { return _os; }
|
||||
|
||||
void setOutputFileType(HeaderFileType type) { _outputFileType = type; }
|
||||
void setArch(Arch arch) { _arch = arch; }
|
||||
bool setOS(OS os, StringRef minOSVersion);
|
||||
bool minOS(StringRef mac, StringRef iOS) const;
|
||||
void setDoNothing(bool value) { _doNothing = value; }
|
||||
bool doNothing() const { return _doNothing; }
|
||||
|
||||
virtual Reader &getDefaultReader() const { return *_machoReader; }
|
||||
|
||||
/// \brief The dylib's binary compatibility version, in the raw uint32 format.
|
||||
///
|
||||
/// When building a dynamic library, this is the compatibility version that
|
||||
/// gets embedded into the result. Other Mach-O binaries that link against
|
||||
/// this library will store the compatibility version in its load command. At
|
||||
/// runtime, the loader will verify that the binary is compatible with the
|
||||
/// installed dynamic library.
|
||||
uint32_t compatibilityVersion() const { return _compatibilityVersion; }
|
||||
|
||||
/// \brief The dylib's current version, in the the raw uint32 format.
|
||||
///
|
||||
/// When building a dynamic library, this is the current version that gets
|
||||
/// embedded into the result. Other Mach-O binaries that link against
|
||||
/// this library will store the compatibility version in its load command.
|
||||
uint32_t currentVersion() const { return _currentVersion; }
|
||||
|
||||
/// \brief The dylib's install name.
|
||||
///
|
||||
/// Binaries that link against the dylib will embed this path into the dylib
|
||||
/// load command. When loading the binaries at runtime, this is the location
|
||||
/// on disk that the loader will look for the dylib.
|
||||
StringRef installName() const { return _installName; }
|
||||
|
||||
/// \brief Whether or not the dylib has side effects during initialization.
|
||||
///
|
||||
/// Dylibs marked as being dead strippable provide the guarantee that loading
|
||||
/// the dylib has no side effects, allowing the linker to strip out the dylib
|
||||
/// when linking a binary that does not use any of its symbols.
|
||||
bool deadStrippableDylib() const { return _deadStrippableDylib; }
|
||||
|
||||
/// \brief The path to the executable that will load the bundle at runtime.
|
||||
///
|
||||
/// When building a Mach-O bundle, this executable will be examined if there
|
||||
/// are undefined symbols after the main link phase. It is expected that this
|
||||
/// binary will be loading the bundle at runtime and will provide the symbols
|
||||
/// at that point.
|
||||
StringRef bundleLoader() const { return _bundleLoader; }
|
||||
|
||||
void setCompatibilityVersion(uint32_t vers) { _compatibilityVersion = vers; }
|
||||
void setCurrentVersion(uint32_t vers) { _currentVersion = vers; }
|
||||
void setInstallName(StringRef name) { _installName = name; }
|
||||
void setDeadStrippableDylib(bool deadStrippable) {
|
||||
_deadStrippableDylib = deadStrippable;
|
||||
}
|
||||
void setBundleLoader(StringRef loader) { _bundleLoader = loader; }
|
||||
StringRef dyldPath() const { return "/usr/lib/dyld"; }
|
||||
|
||||
static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
|
||||
static Arch archFromName(StringRef archName);
|
||||
static uint32_t cpuTypeFromArch(Arch arch);
|
||||
static uint32_t cpuSubtypeFromArch(Arch arch);
|
||||
static bool is64Bit(Arch arch);
|
||||
static bool isHostEndian(Arch arch);
|
||||
static bool isBigEndian(Arch arch);
|
||||
|
||||
/// Construct 32-bit value from string "X.Y.Z" where
|
||||
/// bits are xxxx.yy.zz. Largest number is 65535.255.255
|
||||
static bool parsePackedVersion(StringRef str, uint32_t &result);
|
||||
|
||||
private:
|
||||
virtual Writer &writer() const;
|
||||
|
||||
struct ArchInfo {
|
||||
StringRef archName;
|
||||
MachOLinkingContext::Arch arch;
|
||||
bool littleEndian;
|
||||
uint32_t cputype;
|
||||
uint32_t cpusubtype;
|
||||
};
|
||||
|
||||
static ArchInfo _s_archInfos[];
|
||||
static const uint64_t unspecifiedPageZeroSize = UINT64_MAX;
|
||||
|
||||
HeaderFileType _outputFileType; // e.g MH_EXECUTE
|
||||
bool _outputFileTypeStatic; // Disambiguate static vs dynamic prog
|
||||
bool _doNothing; // for -help and -v which just print info
|
||||
Arch _arch;
|
||||
OS _os;
|
||||
uint32_t _osMinVersion;
|
||||
uint64_t _pageZeroSize;
|
||||
uint64_t _pageSize;
|
||||
uint32_t _compatibilityVersion;
|
||||
uint32_t _currentVersion;
|
||||
StringRef _installName;
|
||||
bool _deadStrippableDylib;
|
||||
StringRef _bundleLoader;
|
||||
mutable std::unique_ptr<mach_o::KindHandler> _kindHandler;
|
||||
mutable std::unique_ptr<Reader> _machoReader;
|
||||
mutable std::unique_ptr<Writer> _writer;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,338 +0,0 @@
|
||||
//===- lld/ReaderWriter/PECOFFLinkingContext.h ----------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_PECOFF_LINKING_CONTEXT_H
|
||||
#define LLD_READER_WRITER_PECOFF_LINKING_CONTEXT_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "lld/Core/LinkingContext.h"
|
||||
#include "lld/ReaderWriter/Reader.h"
|
||||
#include "lld/ReaderWriter/Writer.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
|
||||
using llvm::COFF::MachineTypes;
|
||||
using llvm::COFF::WindowsSubsystem;
|
||||
|
||||
static const uint8_t DEFAULT_DOS_STUB[128] = {'M', 'Z'};
|
||||
|
||||
namespace lld {
|
||||
|
||||
class PECOFFLinkingContext : public LinkingContext {
|
||||
public:
|
||||
PECOFFLinkingContext()
|
||||
: _baseAddress(0x400000), _stackReserve(1024 * 1024), _stackCommit(4096),
|
||||
_heapReserve(1024 * 1024), _heapCommit(4096), _noDefaultLibAll(false),
|
||||
_sectionDefaultAlignment(4096),
|
||||
_subsystem(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN),
|
||||
_machineType(llvm::COFF::IMAGE_FILE_MACHINE_I386), _imageVersion(0, 0),
|
||||
_minOSVersion(6, 0), _nxCompat(true), _largeAddressAware(false),
|
||||
_allowBind(true), _allowIsolation(true), _swapRunFromCD(false),
|
||||
_swapRunFromNet(false), _baseRelocationEnabled(true),
|
||||
_terminalServerAware(true), _dynamicBaseEnabled(true),
|
||||
_createManifest(true), _embedManifest(false), _manifestId(1),
|
||||
_manifestLevel("'asInvoker'"), _manifestUiAccess("'false'"),
|
||||
_imageType(ImageType::IMAGE_EXE),
|
||||
_dosStub(llvm::makeArrayRef(DEFAULT_DOS_STUB)) {
|
||||
setDeadStripping(true);
|
||||
}
|
||||
|
||||
struct Version {
|
||||
Version(int v1, int v2) : majorVersion(v1), minorVersion(v2) {}
|
||||
int majorVersion;
|
||||
int minorVersion;
|
||||
};
|
||||
|
||||
/// \brief Casting support
|
||||
static inline bool classof(const LinkingContext *info) { return true; }
|
||||
|
||||
enum ImageType {
|
||||
IMAGE_EXE,
|
||||
IMAGE_DLL
|
||||
};
|
||||
|
||||
virtual Reader &getDefaultReader() const { return *_reader; }
|
||||
|
||||
virtual Writer &writer() const;
|
||||
virtual bool validateImpl(raw_ostream &diagnostics);
|
||||
|
||||
virtual void addPasses(PassManager &pm);
|
||||
|
||||
virtual bool
|
||||
createImplicitFiles(std::vector<std::unique_ptr<File> > &result) const;
|
||||
|
||||
void appendInputSearchPath(StringRef dirPath) {
|
||||
_inputSearchPaths.push_back(dirPath);
|
||||
}
|
||||
|
||||
const std::vector<StringRef> getInputSearchPaths() {
|
||||
return _inputSearchPaths;
|
||||
}
|
||||
|
||||
void registerTemporaryFile(StringRef path) {
|
||||
std::unique_ptr<llvm::FileRemover> fileRemover(
|
||||
new llvm::FileRemover(Twine(allocateString(path))));
|
||||
_tempFiles.push_back(std::move(fileRemover));
|
||||
}
|
||||
|
||||
StringRef searchLibraryFile(StringRef path) const;
|
||||
|
||||
/// Returns the decorated name of the given symbol name. On 32-bit x86, it
|
||||
/// adds "_" at the beginning of the string. On other architectures, the
|
||||
/// return value is the same as the argument.
|
||||
StringRef decorateSymbol(StringRef name) const {
|
||||
if (_machineType != llvm::COFF::IMAGE_FILE_MACHINE_I386)
|
||||
return name;
|
||||
std::string str = "_";
|
||||
str.append(name);
|
||||
return allocateString(str);
|
||||
}
|
||||
|
||||
void setEntrySymbolName(StringRef name) {
|
||||
if (!name.empty())
|
||||
LinkingContext::setEntrySymbolName(decorateSymbol(name));
|
||||
}
|
||||
|
||||
void setBaseAddress(uint64_t addr) { _baseAddress = addr; }
|
||||
uint64_t getBaseAddress() const { return _baseAddress; }
|
||||
|
||||
void setStackReserve(uint64_t size) { _stackReserve = size; }
|
||||
void setStackCommit(uint64_t size) { _stackCommit = size; }
|
||||
uint64_t getStackReserve() const { return _stackReserve; }
|
||||
uint64_t getStackCommit() const { return _stackCommit; }
|
||||
|
||||
void setHeapReserve(uint64_t size) { _heapReserve = size; }
|
||||
void setHeapCommit(uint64_t size) { _heapCommit = size; }
|
||||
uint64_t getHeapReserve() const { return _heapReserve; }
|
||||
uint64_t getHeapCommit() const { return _heapCommit; }
|
||||
|
||||
void setSectionDefaultAlignment(uint32_t val) {
|
||||
_sectionDefaultAlignment = val;
|
||||
}
|
||||
uint32_t getSectionDefaultAlignment() const {
|
||||
return _sectionDefaultAlignment;
|
||||
}
|
||||
|
||||
void setSubsystem(WindowsSubsystem ss) { _subsystem = ss; }
|
||||
WindowsSubsystem getSubsystem() const { return _subsystem; }
|
||||
|
||||
void setMachineType(MachineTypes type) { _machineType = type; }
|
||||
MachineTypes getMachineType() const { return _machineType; }
|
||||
|
||||
void setImageVersion(const Version &version) { _imageVersion = version; }
|
||||
Version getImageVersion() const { return _imageVersion; }
|
||||
|
||||
void setMinOSVersion(const Version &version) { _minOSVersion = version; }
|
||||
Version getMinOSVersion() const { return _minOSVersion; }
|
||||
|
||||
void setNxCompat(bool nxCompat) { _nxCompat = nxCompat; }
|
||||
bool isNxCompat() const { return _nxCompat; }
|
||||
|
||||
void setLargeAddressAware(bool val) { _largeAddressAware = val; }
|
||||
bool getLargeAddressAware() const { return _largeAddressAware; }
|
||||
|
||||
void setAllowBind(bool val) { _allowBind = val; }
|
||||
bool getAllowBind() const { return _allowBind; }
|
||||
|
||||
void setAllowIsolation(bool val) { _allowIsolation = val; }
|
||||
bool getAllowIsolation() const { return _allowIsolation; }
|
||||
|
||||
void setSwapRunFromCD(bool val) { _swapRunFromCD = val; }
|
||||
bool getSwapRunFromCD() const { return _swapRunFromCD; }
|
||||
|
||||
void setSwapRunFromNet(bool val) { _swapRunFromNet = val; }
|
||||
bool getSwapRunFromNet() const { return _swapRunFromNet; }
|
||||
|
||||
void setBaseRelocationEnabled(bool val) { _baseRelocationEnabled = val; }
|
||||
bool getBaseRelocationEnabled() const { return _baseRelocationEnabled; }
|
||||
|
||||
void setTerminalServerAware(bool val) { _terminalServerAware = val; }
|
||||
bool isTerminalServerAware() const { return _terminalServerAware; }
|
||||
|
||||
void setDynamicBaseEnabled(bool val) { _dynamicBaseEnabled = val; }
|
||||
bool getDynamicBaseEnabled() const { return _dynamicBaseEnabled; }
|
||||
|
||||
void setCreateManifest(bool val) { _createManifest = val; }
|
||||
bool getCreateManifest() const { return _createManifest; }
|
||||
|
||||
void setManifestOutputPath(std::string val) { _manifestOutputPath = val; }
|
||||
const std::string &getManifestOutputPath() const {
|
||||
return _manifestOutputPath;
|
||||
}
|
||||
|
||||
void setEmbedManifest(bool val) { _embedManifest = val; }
|
||||
bool getEmbedManifest() const { return _embedManifest; }
|
||||
|
||||
void setManifestId(int val) { _manifestId = val; }
|
||||
int getManifestId() const { return _manifestId; }
|
||||
|
||||
void setManifestLevel(std::string val) { _manifestLevel = std::move(val); }
|
||||
const std::string &getManifestLevel() const { return _manifestLevel; }
|
||||
|
||||
void setManifestUiAccess(std::string val) { _manifestUiAccess = val; }
|
||||
const std::string &getManifestUiAccess() const { return _manifestUiAccess; }
|
||||
|
||||
void setManifestDependency(std::string val) { _manifestDependency = val; }
|
||||
const std::string &getManifestDependency() const {
|
||||
return _manifestDependency;
|
||||
}
|
||||
|
||||
void setImageType(ImageType type) { _imageType = type; }
|
||||
ImageType getImageType() const { return _imageType; }
|
||||
|
||||
StringRef getFinalSectionName(StringRef sectionName) const;
|
||||
bool addSectionRenaming(raw_ostream &diagnostics,
|
||||
StringRef from, StringRef to);
|
||||
|
||||
void addNoDefaultLib(StringRef path) { _noDefaultLibs.insert(path); }
|
||||
bool hasNoDefaultLib(StringRef path) const {
|
||||
return _noDefaultLibs.count(path) == 1;
|
||||
}
|
||||
|
||||
void addDefaultLib(StringRef path) { _defaultLibs.insert(path); }
|
||||
bool hasDefaultLib(StringRef path) const {
|
||||
return _defaultLibs.count(path) == 1;
|
||||
}
|
||||
|
||||
void setNoDefaultLibAll(bool val) { _noDefaultLibAll = val; }
|
||||
bool getNoDefaultLibAll() const { return _noDefaultLibAll; }
|
||||
|
||||
virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const;
|
||||
virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
|
||||
|
||||
void setSectionAttributes(StringRef sectionName, uint32_t flags) {
|
||||
_sectionAttributes[sectionName] = flags;
|
||||
}
|
||||
|
||||
llvm::Optional<uint32_t> getSectionAttributes(StringRef sectionName) const {
|
||||
auto it = _sectionAttributes.find(sectionName);
|
||||
if (it == _sectionAttributes.end())
|
||||
return llvm::None;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void setSectionAttributeMask(StringRef sectionName, uint32_t flags) {
|
||||
_sectionAttributeMask[sectionName] = flags;
|
||||
}
|
||||
|
||||
uint32_t getSectionAttributeMask(StringRef sectionName) const {
|
||||
auto it = _sectionAttributeMask.find(sectionName);
|
||||
return it == _sectionAttributeMask.end() ? 0 : it->second;
|
||||
}
|
||||
|
||||
void setDosStub(ArrayRef<uint8_t> data) { _dosStub = data; }
|
||||
ArrayRef<uint8_t> getDosStub() const { return _dosStub; }
|
||||
|
||||
StringRef allocateString(StringRef ref) const {
|
||||
char *x = _allocator.Allocate<char>(ref.size() + 1);
|
||||
memcpy(x, ref.data(), ref.size());
|
||||
x[ref.size()] = '\0';
|
||||
return x;
|
||||
}
|
||||
|
||||
ArrayRef<uint8_t> allocate(ArrayRef<uint8_t> array) const {
|
||||
size_t size = array.size();
|
||||
uint8_t *p = _allocator.Allocate<uint8_t>(size);
|
||||
memcpy(p, array.data(), size);
|
||||
return ArrayRef<uint8_t>(p, p + array.size());
|
||||
}
|
||||
|
||||
virtual bool hasInputGraph() {
|
||||
if (_inputGraph)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Method to create a internal file for the entry symbol
|
||||
virtual std::unique_ptr<File> createEntrySymbolFile() const;
|
||||
|
||||
/// Method to create a internal file for an undefined symbol
|
||||
virtual std::unique_ptr<File> createUndefinedSymbolFile() const;
|
||||
|
||||
private:
|
||||
// The start address for the program. The default value for the executable is
|
||||
// 0x400000, but can be altered using -base command line option.
|
||||
uint64_t _baseAddress;
|
||||
|
||||
uint64_t _stackReserve;
|
||||
uint64_t _stackCommit;
|
||||
uint64_t _heapReserve;
|
||||
uint64_t _heapCommit;
|
||||
bool _noDefaultLibAll;
|
||||
uint32_t _sectionDefaultAlignment;
|
||||
WindowsSubsystem _subsystem;
|
||||
MachineTypes _machineType;
|
||||
Version _imageVersion;
|
||||
Version _minOSVersion;
|
||||
bool _nxCompat;
|
||||
bool _largeAddressAware;
|
||||
bool _allowBind;
|
||||
bool _allowIsolation;
|
||||
bool _swapRunFromCD;
|
||||
bool _swapRunFromNet;
|
||||
bool _baseRelocationEnabled;
|
||||
bool _terminalServerAware;
|
||||
bool _dynamicBaseEnabled;
|
||||
bool _createManifest;
|
||||
std::string _manifestOutputPath;
|
||||
bool _embedManifest;
|
||||
int _manifestId;
|
||||
std::string _manifestLevel;
|
||||
std::string _manifestUiAccess;
|
||||
std::string _manifestDependency;
|
||||
ImageType _imageType;
|
||||
|
||||
// The set to store /nodefaultlib arguments.
|
||||
std::set<std::string> _noDefaultLibs;
|
||||
|
||||
// A set containing all the library files specified by /defaultlib. This is to
|
||||
// keep track what files are already added to the input graph, in order to
|
||||
// prevent adding the same file more than once to the input graph.
|
||||
std::set<std::string> _defaultLibs;
|
||||
|
||||
std::vector<StringRef> _inputSearchPaths;
|
||||
std::unique_ptr<Reader> _reader;
|
||||
std::unique_ptr<Writer> _writer;
|
||||
|
||||
// A map for section renaming. For example, if there is an entry in the map
|
||||
// whose value is .rdata -> .text, the section contens of .rdata will be
|
||||
// merged to .text in the resulting executable.
|
||||
std::map<std::string, std::string> _renamedSections;
|
||||
|
||||
// Section attributes specified by /section option. The uint32_t value will be
|
||||
// copied to the Characteristics field of the section header.
|
||||
std::map<std::string, uint32_t> _sectionAttributes;
|
||||
|
||||
// Section attributes specified by /section option in conjunction with the
|
||||
// negative flag "!". The uint32_t value is a mask of section attributes that
|
||||
// should be disabled.
|
||||
std::map<std::string, uint32_t> _sectionAttributeMask;
|
||||
|
||||
// List of files that will be removed on destruction.
|
||||
std::vector<std::unique_ptr<llvm::FileRemover> > _tempFiles;
|
||||
|
||||
// DOS Stub. DOS stub is data located at the beginning of PE/COFF file.
|
||||
// Windows loader do not really care about DOS stub contents, but it's usually
|
||||
// a small DOS program that prints out a message "This program requires
|
||||
// Microsoft Windows." This feature was somewhat useful before Windows 95.
|
||||
ArrayRef<uint8_t> _dosStub;
|
||||
};
|
||||
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
//===- lld/ReaderWriter/Reader.h - Abstract File Format Reading Interface -===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_READER_H
|
||||
#define LLD_READER_WRITER_READER_H
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
class ELFLinkingContext;
|
||||
class File;
|
||||
class LinkingContext;
|
||||
class PECOFFLinkingContext;
|
||||
|
||||
/// \brief An abstract class for reading object files, library files, and
|
||||
/// executable files.
|
||||
///
|
||||
/// Each file format (e.g. ELF, mach-o, PECOFF, native, etc) have a concrete
|
||||
/// subclass of Reader.
|
||||
class Reader {
|
||||
public:
|
||||
virtual ~Reader();
|
||||
|
||||
/// \brief Parse a supplied buffer (already filled with the contents of a
|
||||
/// file) and create a File object.
|
||||
///
|
||||
/// On success, the resulting File object takes ownership of the MemoryBuffer.
|
||||
virtual error_code
|
||||
parseFile(std::unique_ptr<MemoryBuffer> &mb,
|
||||
std::vector<std::unique_ptr<File> > &result) const = 0;
|
||||
|
||||
protected:
|
||||
// only concrete subclasses can be instantiated
|
||||
Reader(const LinkingContext &context) : _context(context) {}
|
||||
|
||||
const LinkingContext &_context;
|
||||
};
|
||||
|
||||
std::unique_ptr<Reader> createReaderELF(const ELFLinkingContext &);
|
||||
std::unique_ptr<Reader> createReaderMachO(const LinkingContext &);
|
||||
std::unique_ptr<Reader> createReaderNative(const LinkingContext &);
|
||||
std::unique_ptr<Reader> createReaderPECOFF(PECOFFLinkingContext &);
|
||||
std::unique_ptr<Reader> createReaderYAML(const LinkingContext &);
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user