aboutsummaryrefslogtreecommitdiff
path: root/test/ELF/linkerscript
diff options
context:
space:
mode:
Diffstat (limited to 'test/ELF/linkerscript')
-rw-r--r--test/ELF/linkerscript/Inputs/comdat-gc.s5
-rw-r--r--test/ELF/linkerscript/Inputs/exclude-multiple1.s8
-rw-r--r--test/ELF/linkerscript/Inputs/exclude-multiple2.s8
-rw-r--r--test/ELF/linkerscript/Inputs/filename-spec.s2
-rw-r--r--test/ELF/linkerscript/Inputs/implicit-program-header.script12
-rw-r--r--test/ELF/linkerscript/Inputs/include.s5
-rw-r--r--test/ELF/linkerscript/Inputs/keep.s2
-rw-r--r--test/ELF/linkerscript/Inputs/libsearch-dyn.s3
-rw-r--r--test/ELF/linkerscript/Inputs/libsearch-st.s3
-rw-r--r--test/ELF/linkerscript/Inputs/merge-sections-reloc.s3
-rw-r--r--test/ELF/linkerscript/Inputs/notinclude.s4
-rw-r--r--test/ELF/linkerscript/Inputs/segment-start.script7
-rw-r--r--test/ELF/linkerscript/Inputs/shared.s10
-rw-r--r--test/ELF/linkerscript/Inputs/sort-nested.s7
-rw-r--r--test/ELF/linkerscript/Inputs/sort.s19
-rw-r--r--test/ELF/linkerscript/absolute-expr.s82
-rw-r--r--test/ELF/linkerscript/absolute.s18
-rw-r--r--test/ELF/linkerscript/addr.s32
-rw-r--r--test/ELF/linkerscript/align-empty.s18
-rw-r--r--test/ELF/linkerscript/align.s83
-rw-r--r--test/ELF/linkerscript/alignof.s41
-rw-r--r--test/ELF/linkerscript/alternate-sections.s34
-rw-r--r--test/ELF/linkerscript/arm-exidx-phdrs.s16
-rw-r--r--test/ELF/linkerscript/assert.s43
-rw-r--r--test/ELF/linkerscript/at.s119
-rw-r--r--test/ELF/linkerscript/comdat-gc.s14
-rw-r--r--test/ELF/linkerscript/common.s49
-rw-r--r--test/ELF/linkerscript/data-commands.s81
-rw-r--r--test/ELF/linkerscript/data-segment-relro.s70
-rw-r--r--test/ELF/linkerscript/define.s25
-rw-r--r--test/ELF/linkerscript/diagnostic.s106
-rw-r--r--test/ELF/linkerscript/discard-interp.s12
-rw-r--r--test/ELF/linkerscript/discard-section.s14
-rw-r--r--test/ELF/linkerscript/dot-is-not-abs.s53
-rw-r--r--test/ELF/linkerscript/double-bss.s21
-rw-r--r--test/ELF/linkerscript/dynamic-sym.s17
-rw-r--r--test/ELF/linkerscript/dynamic.s28
-rw-r--r--test/ELF/linkerscript/edata-etext.s20
-rw-r--r--test/ELF/linkerscript/eh-frame-hdr.s20
-rw-r--r--test/ELF/linkerscript/ehdr_start.s11
-rw-r--r--test/ELF/linkerscript/empty-load.s22
-rw-r--r--test/ELF/linkerscript/empty-tls.s14
-rw-r--r--test/ELF/linkerscript/entry.s42
-rw-r--r--test/ELF/linkerscript/exclude-multiple.s37
-rw-r--r--test/ELF/linkerscript/excludefile.s46
-rw-r--r--test/ELF/linkerscript/extend-pt-load.s69
-rw-r--r--test/ELF/linkerscript/filename-spec.s59
-rw-r--r--test/ELF/linkerscript/fill.s30
-rw-r--r--test/ELF/linkerscript/group.s56
-rw-r--r--test/ELF/linkerscript/header-addr.s47
-rw-r--r--test/ELF/linkerscript/implicit-program-header.s13
-rw-r--r--test/ELF/linkerscript/input-order.s38
-rw-r--r--test/ELF/linkerscript/input-sec-dup.s18
-rw-r--r--test/ELF/linkerscript/linkerscript.s54
-rw-r--r--test/ELF/linkerscript/loadaddr.s42
-rw-r--r--test/ELF/linkerscript/locationcounter.s189
-rw-r--r--test/ELF/linkerscript/locationcountererr.s9
-rw-r--r--test/ELF/linkerscript/merge-sections-reloc.s16
-rw-r--r--test/ELF/linkerscript/merge-sections.s94
-rw-r--r--test/ELF/linkerscript/multi-sections-constraint.s34
-rw-r--r--test/ELF/linkerscript/multiple-tbss.s45
-rw-r--r--test/ELF/linkerscript/no-pt-load.s5
-rw-r--r--test/ELF/linkerscript/no-space.s26
-rw-r--r--test/ELF/linkerscript/non-alloc.s25
-rw-r--r--test/ELF/linkerscript/numbers.s72
-rw-r--r--test/ELF/linkerscript/openbsd-bootdata.s7
-rw-r--r--test/ELF/linkerscript/openbsd-randomize.s23
-rw-r--r--test/ELF/linkerscript/openbsd-wxneeded.s17
-rw-r--r--test/ELF/linkerscript/orphan-align.s28
-rw-r--r--test/ELF/linkerscript/orphan-first-cmd.s18
-rw-r--r--test/ELF/linkerscript/orphan.s36
-rw-r--r--test/ELF/linkerscript/orphans.s31
-rw-r--r--test/ELF/linkerscript/ouputformat.s9
-rw-r--r--test/ELF/linkerscript/outputarch.s10
-rw-r--r--test/ELF/linkerscript/outsections-addr.s122
-rw-r--r--test/ELF/linkerscript/page-size-align.s22
-rw-r--r--test/ELF/linkerscript/page-size.s68
-rw-r--r--test/ELF/linkerscript/phdr-check.s15
-rw-r--r--test/ELF/linkerscript/phdrs-flags.s58
-rw-r--r--test/ELF/linkerscript/phdrs.s143
-rw-r--r--test/ELF/linkerscript/repsection-symbol.s28
-rw-r--r--test/ELF/linkerscript/repsection-va.s24
-rw-r--r--test/ELF/linkerscript/rosegment.s24
-rw-r--r--test/ELF/linkerscript/searchdir.s12
-rw-r--r--test/ELF/linkerscript/sections-constraint.s46
-rw-r--r--test/ELF/linkerscript/sections-constraint2.s14
-rw-r--r--test/ELF/linkerscript/sections-constraint3.s11
-rw-r--r--test/ELF/linkerscript/sections-constraint4.s20
-rw-r--r--test/ELF/linkerscript/sections-constraint5.s32
-rw-r--r--test/ELF/linkerscript/sections-keep.s95
-rw-r--r--test/ELF/linkerscript/sections-padding.s49
-rw-r--r--test/ELF/linkerscript/sections-sort.s30
-rw-r--r--test/ELF/linkerscript/sections.s124
-rw-r--r--test/ELF/linkerscript/segment-start.s27
-rw-r--r--test/ELF/linkerscript/sizeof.s53
-rw-r--r--test/ELF/linkerscript/sizeofheaders.s18
-rw-r--r--test/ELF/linkerscript/sort-constructors.s5
-rw-r--r--test/ELF/linkerscript/sort-init.s24
-rw-r--r--test/ELF/linkerscript/sort-nested.s50
-rw-r--r--test/ELF/linkerscript/sort-non-script.s16
-rw-r--r--test/ELF/linkerscript/sort.s120
-rw-r--r--test/ELF/linkerscript/sort2.s39
-rw-r--r--test/ELF/linkerscript/start-end.s16
-rw-r--r--test/ELF/linkerscript/subalign.s43
-rw-r--r--test/ELF/linkerscript/symbol-assignexpr.s48
-rw-r--r--test/ELF/linkerscript/symbol-conflict.s11
-rw-r--r--test/ELF/linkerscript/symbol-only.s21
-rw-r--r--test/ELF/linkerscript/symbolreferenced.s22
-rw-r--r--test/ELF/linkerscript/symbols-synthetic.s98
-rw-r--r--test/ELF/linkerscript/symbols.s84
-rw-r--r--test/ELF/linkerscript/tbss.s42
-rw-r--r--test/ELF/linkerscript/undef.s11
-rw-r--r--test/ELF/linkerscript/va.s24
-rw-r--r--test/ELF/linkerscript/visibility.s22
-rw-r--r--test/ELF/linkerscript/wildcards.s83
-rw-r--r--test/ELF/linkerscript/wildcards2.s25
116 files changed, 4245 insertions, 0 deletions
diff --git a/test/ELF/linkerscript/Inputs/comdat-gc.s b/test/ELF/linkerscript/Inputs/comdat-gc.s
new file mode 100644
index 000000000000..da29d5b3830b
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/comdat-gc.s
@@ -0,0 +1,5 @@
+.file 1 "test/ELF/linkerscript/Inputs/comdat_gc.s"
+
+.section .text._Z3fooIiEvv,"axG",@progbits,_Z3fooIiEvv,comdat
+.loc 1 5
+ ret
diff --git a/test/ELF/linkerscript/Inputs/exclude-multiple1.s b/test/ELF/linkerscript/Inputs/exclude-multiple1.s
new file mode 100644
index 000000000000..1e0f741df40f
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/exclude-multiple1.s
@@ -0,0 +1,8 @@
+.section .foo.1,"a"
+ .quad 4
+
+.section .foo.2,"a"
+ .quad 5
+
+.section .foo.3,"a"
+ .quad 6
diff --git a/test/ELF/linkerscript/Inputs/exclude-multiple2.s b/test/ELF/linkerscript/Inputs/exclude-multiple2.s
new file mode 100644
index 000000000000..60f790fa2356
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/exclude-multiple2.s
@@ -0,0 +1,8 @@
+.section .foo.1,"a"
+ .quad 7
+
+.section .foo.2,"a"
+ .quad 8
+
+.section .foo.3,"a"
+ .quad 9
diff --git a/test/ELF/linkerscript/Inputs/filename-spec.s b/test/ELF/linkerscript/Inputs/filename-spec.s
new file mode 100644
index 000000000000..a688b4db4b60
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/filename-spec.s
@@ -0,0 +1,2 @@
+.section .foo,"a"
+ .quad 0x11
diff --git a/test/ELF/linkerscript/Inputs/implicit-program-header.script b/test/ELF/linkerscript/Inputs/implicit-program-header.script
new file mode 100644
index 000000000000..27dbea84c4e4
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/implicit-program-header.script
@@ -0,0 +1,12 @@
+PHDRS
+{
+ ph_write PT_LOAD FLAGS(2);
+ ph_exec PT_LOAD FLAGS(1);
+}
+
+SECTIONS
+{
+ .bar : { *(.bar) } : ph_exec
+ .foo : { *(.foo) }
+ .text : { *(.text) } : ph_write
+}
diff --git a/test/ELF/linkerscript/Inputs/include.s b/test/ELF/linkerscript/Inputs/include.s
new file mode 100644
index 000000000000..a2f809b522f3
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/include.s
@@ -0,0 +1,5 @@
+.section .text
+.globl _potato
+_potato:
+ nop
+ nop
diff --git a/test/ELF/linkerscript/Inputs/keep.s b/test/ELF/linkerscript/Inputs/keep.s
new file mode 100644
index 000000000000..20fa41c1adff
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/keep.s
@@ -0,0 +1,2 @@
+.section .keep, "a"
+ .long 0x41414141
diff --git a/test/ELF/linkerscript/Inputs/libsearch-dyn.s b/test/ELF/linkerscript/Inputs/libsearch-dyn.s
new file mode 100644
index 000000000000..091b3b9b6ece
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/libsearch-dyn.s
@@ -0,0 +1,3 @@
+.globl _bar,_dynamic
+_bar:
+_dynamic:
diff --git a/test/ELF/linkerscript/Inputs/libsearch-st.s b/test/ELF/linkerscript/Inputs/libsearch-st.s
new file mode 100644
index 000000000000..6da62f79d52f
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/libsearch-st.s
@@ -0,0 +1,3 @@
+.globl _bar,_static
+_bar:
+_static:
diff --git a/test/ELF/linkerscript/Inputs/merge-sections-reloc.s b/test/ELF/linkerscript/Inputs/merge-sections-reloc.s
new file mode 100644
index 000000000000..07e599b2820f
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/merge-sections-reloc.s
@@ -0,0 +1,3 @@
+.globl _start
+_start:
+ .quad 0x11223344
diff --git a/test/ELF/linkerscript/Inputs/notinclude.s b/test/ELF/linkerscript/Inputs/notinclude.s
new file mode 100644
index 000000000000..46c0509b56cc
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/notinclude.s
@@ -0,0 +1,4 @@
+.section .text
+.globl tomato
+tomato:
+ movl $1, %eax
diff --git a/test/ELF/linkerscript/Inputs/segment-start.script b/test/ELF/linkerscript/Inputs/segment-start.script
new file mode 100644
index 000000000000..9f1a59360105
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/segment-start.script
@@ -0,0 +1,7 @@
+SECTIONS
+{
+ PROVIDE (foobar1 = SEGMENT_START("text-segment", 0x8001));
+ PROVIDE (foobar2 = SEGMENT_START("data-segment", 0x8002));
+ PROVIDE (foobar3 = SEGMENT_START("bss-segment", 0x8000 + (4 - 1)));
+ PROVIDE (foobar4 = SEGMENT_START("abc-segment", 0x8004));
+}
diff --git a/test/ELF/linkerscript/Inputs/shared.s b/test/ELF/linkerscript/Inputs/shared.s
new file mode 100644
index 000000000000..c3c22fe4b4fb
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/shared.s
@@ -0,0 +1,10 @@
+.global bar
+.type bar, @function
+bar:
+
+.global bar2
+.type bar2, @function
+bar2:
+
+.global zed
+zed:
diff --git a/test/ELF/linkerscript/Inputs/sort-nested.s b/test/ELF/linkerscript/Inputs/sort-nested.s
new file mode 100644
index 000000000000..c42fa9cd7ed8
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/sort-nested.s
@@ -0,0 +1,7 @@
+.section .aaa.1, "a"
+.align 16
+.quad 0x11
+
+.section .aaa.2, "a"
+.align 4
+.quad 0x22
diff --git a/test/ELF/linkerscript/Inputs/sort.s b/test/ELF/linkerscript/Inputs/sort.s
new file mode 100644
index 000000000000..22e65ad19e1e
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/sort.s
@@ -0,0 +1,19 @@
+.section .aaa.5, "a"
+.align 2
+.quad 0x55
+
+.section .aaa.1, "a"
+.align 32
+.quad 0x11
+
+.section .aaa.3, "a"
+.align 8
+.quad 0x33
+
+.section .aaa.2, "a"
+.align 16
+.quad 0x22
+
+.section .aaa.4, "a"
+.align 4
+.quad 0x44
diff --git a/test/ELF/linkerscript/absolute-expr.s b/test/ELF/linkerscript/absolute-expr.s
new file mode 100644
index 000000000000..a9a674b859f4
--- /dev/null
+++ b/test/ELF/linkerscript/absolute-expr.s
@@ -0,0 +1,82 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN: .text : { \
+# RUN: bar1 = ALIGNOF(.text); \
+# RUN: bar2 = CONSTANT (MAXPAGESIZE); \
+# RUN: bar3 = SIZEOF (.text); \
+# RUN: bar4 = SIZEOF_HEADERS; \
+# RUN: bar5 = 0x42; \
+# RUN: bar6 = foo + 1; \
+# RUN: *(.text) \
+# RUN: } \
+# RUN: };" > %t.script
+# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
+# RUN: llvm-readobj -t %t.so | FileCheck %s
+
+.global foo
+foo = 0x123
+
+# CHECK: Symbol {
+# CHECK: Name: foo
+# CHECK-NEXT: Value: 0x123
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: None
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Absolute (0xFFF1)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: bar1
+# CHECK-NEXT: Value: 0x4
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: None
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: bar2
+# CHECK-NEXT: Value: 0x1000
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: None
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: bar3
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: None
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: bar4
+# CHECK-NEXT: Value: 0x190
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: None
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: bar5
+# CHECK-NEXT: Value: 0x42
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: None
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: bar6
+# CHECK-NEXT: Value: 0x124
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Absolute (0xFFF1)
+# CHECK-NEXT: }
diff --git a/test/ELF/linkerscript/absolute.s b/test/ELF/linkerscript/absolute.s
new file mode 100644
index 000000000000..e4b156e2f012
--- /dev/null
+++ b/test/ELF/linkerscript/absolute.s
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { foo = ABSOLUTE(.) + 1; };" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj --symbols %t | FileCheck %s
+
+# CHECK: Name: foo
+# CHECK-NEXT: Value:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Binding:
+# CHECK-NEXT: Type:
+# CHECK-NEXT: Other:
+# CHECK-NEXT: Section: Absolute
+# CHECK-NEXT: }
+
+.text
+.globl _start
+_start:
diff --git a/test/ELF/linkerscript/addr.s b/test/ELF/linkerscript/addr.s
new file mode 100644
index 000000000000..2d3a7ab35767
--- /dev/null
+++ b/test/ELF/linkerscript/addr.s
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x1000; \
+# RUN: .text : { *(.text*) } \
+# RUN: .foo.1 : { *(.foo.1) } \
+# RUN: .foo.2 ADDR(.foo.1) + 0x100 : { *(.foo.2) } \
+# RUN: .foo.3 : { *(.foo.3) } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t1
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size Address Type
+# CHECK-NEXT: 0 00000000 0000000000000000
+# CHECK-NEXT: 1 .text 00000000 0000000000001000 TEXT DATA
+# CHECK-NEXT: 2 .foo.1 00000008 0000000000001000 DATA
+# CHECK-NEXT: 3 .foo.2 00000008 0000000000001100 DATA
+# CHECK-NEXT: 4 .foo.3 00000008 0000000000001108 DATA
+
+.text
+.globl _start
+_start:
+
+.section .foo.1,"a"
+ .quad 1
+
+.section .foo.2,"a"
+ .quad 2
+
+.section .foo.3,"a"
+ .quad 3
diff --git a/test/ELF/linkerscript/align-empty.s b/test/ELF/linkerscript/align-empty.s
new file mode 100644
index 000000000000..3ff71578410a
--- /dev/null
+++ b/test/ELF/linkerscript/align-empty.s
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: abc : { } \
+# RUN: . = ALIGN(0x1000); \
+# RUN: foo : { *(foo) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size Address
+# CHECK-NEXT: 0 00000000 0000000000000000
+# CHECK-NEXT: 1 foo 00000001 0000000000001000
+
+ .section foo, "a"
+ .byte 0
diff --git a/test/ELF/linkerscript/align.s b/test/ELF/linkerscript/align.s
new file mode 100644
index 000000000000..1e50fed3fa83
--- /dev/null
+++ b/test/ELF/linkerscript/align.s
@@ -0,0 +1,83 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Check that ALIGN command workable using location counter
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x10000; \
+# RUN: .aaa : \
+# RUN: { \
+# RUN: *(.aaa) \
+# RUN: } \
+# RUN: . = ALIGN(4096); \
+# RUN: .bbb : \
+# RUN: { \
+# RUN: *(.bbb) \
+# RUN: } \
+# RUN: . = ALIGN(4096 * 4); \
+# RUN: .ccc : \
+# RUN: { \
+# RUN: *(.ccc) \
+# RUN: } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+## Check that the two argument version of ALIGN command works
+# RUN: echo "SECTIONS { \
+# RUN: . = ALIGN(0x1234, 0x10000); \
+# RUN: .aaa : \
+# RUN: { \
+# RUN: *(.aaa) \
+# RUN: } \
+# RUN: . = ALIGN(., 4096); \
+# RUN: .bbb : \
+# RUN: { \
+# RUN: *(.bbb) \
+# RUN: } \
+# RUN: . = ALIGN(., 4096 * 4); \
+# RUN: .ccc : \
+# RUN: { \
+# RUN: *(.ccc) \
+# RUN: } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size Address Type
+# CHECK-NEXT: 0 00000000 0000000000000000
+# CHECK-NEXT: 1 .aaa 00000008 0000000000010000 DATA
+# CHECK-NEXT: 2 .bbb 00000008 0000000000011000 DATA
+# CHECK-NEXT: 3 .ccc 00000008 0000000000014000 DATA
+
+## Check output sections ALIGN modificator
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x10000; \
+# RUN: .aaa : \
+# RUN: { \
+# RUN: *(.aaa) \
+# RUN: } \
+# RUN: .bbb : ALIGN(4096) \
+# RUN: { \
+# RUN: *(.bbb) \
+# RUN: } \
+# RUN: .ccc : ALIGN(4096 * 4) \
+# RUN: { \
+# RUN: *(.ccc) \
+# RUN: } \
+# RUN: }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+.global _start
+_start:
+ nop
+
+.section .aaa, "a"
+.quad 0
+
+.section .bbb, "a"
+.quad 0
+
+.section .ccc, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/alignof.s b/test/ELF/linkerscript/alignof.s
new file mode 100644
index 000000000000..8880634df243
--- /dev/null
+++ b/test/ELF/linkerscript/alignof.s
@@ -0,0 +1,41 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN: .aaa : { *(.aaa) } \
+# RUN: .bbb : { *(.bbb) } \
+# RUN: .ccc : { *(.ccc) } \
+# RUN: _aaa = ALIGNOF(.aaa); \
+# RUN: _bbb = ALIGNOF(.bbb); \
+# RUN: _ccc = ALIGNOF(.ccc); \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+# CHECK: SYMBOL TABLE:
+# CHECK: 0000000000000008 *ABS* 00000000 _aaa
+# CHECK-NEXT: 0000000000000010 *ABS* 00000000 _bbb
+# CHECK-NEXT: 0000000000000020 *ABS* 00000000 _ccc
+
+## Check that we error out if trying to get alignment of
+## section that does not exist.
+# RUN: echo "SECTIONS { \
+# RUN: _aaa = ALIGNOF(.foo); \
+# RUN: }" > %t.script
+# RUN: not ld.lld -o %t1 --script %t.script %t 2>&1 \
+# RUN: | FileCheck -check-prefix=ERR %s
+# ERR: {{.*}}.script:1: undefined section .foo
+.global _start
+_start:
+ nop
+
+.section .aaa,"a"
+ .align 8
+ .quad 0
+
+.section .bbb,"a"
+ .align 16
+ .quad 0
+
+.section .ccc,"a"
+ .align 32
+ .quad 0
diff --git a/test/ELF/linkerscript/alternate-sections.s b/test/ELF/linkerscript/alternate-sections.s
new file mode 100644
index 000000000000..6d3004af9a80
--- /dev/null
+++ b/test/ELF/linkerscript/alternate-sections.s
@@ -0,0 +1,34 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { abc : { *(foo) *(bar) *(zed) } }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o -shared
+# RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+# This test shows an oddity in lld. When a linker script alternates among
+# different types of output section in the same command, the sections are
+# reordered.
+# In this test we go from regular, to merge and back to regular. The reason
+# for the reordering is that we need two create two output sections and
+# one cannot be in the middle of another.
+# If this ever becomes a problem, some options would be:
+# * Adding an extra layer in between input section and output sections (Chunk).
+# With that this example would have 3 chunks, but only one output section.
+# This would unfortunately complicate the non-script case too.
+# * Just create three output sections.
+# * If having three output sections causes problem, have linkerscript specific
+# code to write the section table and section indexes. That way we could
+# keep 3 sections internally but not expose that.
+
+# CHECK: Name: abc
+# CHECK: 0000: 01000000 00000000 02000000 00000000 |
+# CHECK: Name: abc
+# CHECK: 0000: 61626331 323300 |abc123.|
+
+ .section foo, "a"
+ .quad 1
+
+ .section bar,"aMS",@progbits,1
+ .asciz "abc123"
+
+ .section zed, "a"
+ .quad 2
diff --git a/test/ELF/linkerscript/arm-exidx-phdrs.s b/test/ELF/linkerscript/arm-exidx-phdrs.s
new file mode 100644
index 000000000000..971702f55d7b
--- /dev/null
+++ b/test/ELF/linkerscript/arm-exidx-phdrs.s
@@ -0,0 +1,16 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: echo "PHDRS { ph_text PT_LOAD; } \
+// RUN: SECTIONS { \
+// RUN: . = SIZEOF_HEADERS; \
+// RUN: .text : { *(.text) } : ph_text \
+// RUN: }" > %t.script
+// RUN: ld.lld -T %t.script %t.o -shared -o %t.so
+// RUN: llvm-readobj --program-headers %t.so | FileCheck %s
+
+// CHECK: Type: PT_ARM_EXIDX
+
+.fnstart
+bx lr
+.cantunwind
+.fnend
diff --git a/test/ELF/linkerscript/assert.s b/test/ELF/linkerscript/assert.s
new file mode 100644
index 000000000000..06eeaeec3b99
--- /dev/null
+++ b/test/ELF/linkerscript/assert.s
@@ -0,0 +1,43 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+
+# RUN: echo "SECTIONS { ASSERT(1, fail) }" > %t1.script
+# RUN: ld.lld -shared -o %t1 --script %t1.script %t1.o
+# RUN: llvm-readobj %t1 > /dev/null
+
+# RUN: echo "SECTIONS { ASSERT(ASSERT(42, fail) == 42, fail) }" > %t2.script
+# RUN: ld.lld -shared -o %t2 --script %t2.script %t1.o
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "SECTIONS { ASSERT(0, fail) }" > %t3.script
+# RUN: not ld.lld -shared -o %t3 --script %t3.script %t1.o > %t.log 2>&1
+# RUN: FileCheck %s -check-prefix=FAIL < %t.log
+# FAIL: fail
+
+# RUN: echo "SECTIONS { . = ASSERT(0x1000, fail); }" > %t4.script
+# RUN: ld.lld -shared -o %t4 --script %t4.script %t1.o
+# RUN: llvm-readobj %t4 > /dev/null
+
+# RUN: echo "SECTIONS { .foo : { *(.foo) } }" > %t5.script
+# RUN: echo "ASSERT(SIZEOF(.foo) == 8, fail);" >> %t5.script
+# RUN: ld.lld -shared -o %t5 --script %t5.script %t1.o
+# RUN: llvm-readobj %t5 > /dev/null
+
+## Even without SECTIONS block we still use section names
+## in expressions
+# RUN: echo "ASSERT(SIZEOF(.foo) == 8, fail);" > %t5.script
+# RUN: ld.lld -shared -o %t5 --script %t5.script %t1.o
+# RUN: llvm-readobj %t5 > /dev/null
+
+## Test assertions inside of output section decriptions.
+# RUN: echo "SECTIONS { .foo : { *(.foo) ASSERT(SIZEOF(.foo) == 8, \"true\"); } }" > %t6.script
+# RUN: ld.lld -shared -o %t6 --script %t6.script %t1.o
+# RUN: llvm-readobj %t6 > /dev/null
+
+# RUN: echo "SECTIONS { .foo : { ASSERT(1, \"true\") } }" > %t7.script
+# RUN: not ld.lld -shared -o %t7 --script %t7.script %t1.o > %t.log 2>&1
+# RUN: FileCheck %s -check-prefix=CHECK-SEMI < %t.log
+# CHECK-SEMI: error: {{.*}}.script:1: ; expected, but got }
+
+.section .foo, "a"
+ .quad 0
diff --git a/test/ELF/linkerscript/at.s b/test/ELF/linkerscript/at.s
new file mode 100644
index 000000000000..a6b6198710ea
--- /dev/null
+++ b/test/ELF/linkerscript/at.s
@@ -0,0 +1,119 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x1000; \
+# RUN: .aaa : AT(0x2000) \
+# RUN: { \
+# RUN: *(.aaa) \
+# RUN: } \
+# RUN: .bbb : \
+# RUN: { \
+# RUN: *(.bbb) \
+# RUN: } \
+# RUN: .ccc : AT(0x3000) \
+# RUN: { \
+# RUN: *(.ccc) \
+# RUN: } \
+# RUN: .ddd : AT(0x4000) \
+# RUN: { \
+# RUN: *(.ddd) \
+# RUN: } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
+
+# CHECK: ProgramHeaders [
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_PHDR
+# CHECK-NEXT: Offset: 0x40
+# CHECK-NEXT: VirtualAddress: 0x40
+# CHECK-NEXT: PhysicalAddress: 0x40
+# CHECK-NEXT: FileSize:
+# CHECK-NEXT: MemSize:
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 8
+# CHECK-NEXT: }
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x0
+# CHECK-NEXT: VirtualAddress: 0x0
+# CHECK-NEXT: PhysicalAddress: 0x0
+# CHECK-NEXT: FileSize:
+# CHECK-NEXT: MemSize:
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_X
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment:
+# CHECK-NEXT: }
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x1000
+# CHECK-NEXT: VirtualAddress: 0x1000
+# CHECK-NEXT: PhysicalAddress: 0x2000
+# CHECK-NEXT: FileSize: 16
+# CHECK-NEXT: MemSize: 16
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_X
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment:
+# CHECK-NEXT: }
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x1010
+# CHECK-NEXT: VirtualAddress: 0x1010
+# CHECK-NEXT: PhysicalAddress: 0x3000
+# CHECK-NEXT: FileSize: 8
+# CHECK-NEXT: MemSize: 8
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_X
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 4096
+# CHECK-NEXT: }
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x1018
+# CHECK-NEXT: VirtualAddress: 0x1018
+# CHECK-NEXT: PhysicalAddress: 0x4000
+# CHECK-NEXT: FileSize: 9
+# CHECK-NEXT: MemSize: 9
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_X
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 4096
+# CHECK-NEXT: }
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_GNU_STACK
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: VirtualAddress: 0x0
+# CHECK-NEXT: PhysicalAddress: 0x0
+# CHECK-NEXT: FileSize:
+# CHECK-NEXT: MemSize:
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_W
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+.global _start
+_start:
+ nop
+
+.section .aaa, "a"
+.quad 0
+
+.section .bbb, "a"
+.quad 0
+
+.section .ccc, "a"
+.quad 0
+
+.section .ddd, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/comdat-gc.s b/test/ELF/linkerscript/comdat-gc.s
new file mode 100644
index 000000000000..63dcf85c5a67
--- /dev/null
+++ b/test/ELF/linkerscript/comdat-gc.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/comdat-gc.s -o %t1
+# RUN: echo "SECTIONS { .text : { *(.text*) } }" > %t.script
+# RUN: ld.lld --gc-sections --script %t.script %t %t1 -o %t2
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=GC1 %s
+
+# GC1: Name: .debug_line
+
+.file 1 "test/ELF/linkerscript/comdat_gc.s"
+.section .text._Z3fooIiEvv,"axG",@progbits,_Z3fooIiEvv,comdat
+.loc 1 14
+ ret
diff --git a/test/ELF/linkerscript/common.s b/test/ELF/linkerscript/common.s
new file mode 100644
index 000000000000..2e5972d52379
--- /dev/null
+++ b/test/ELF/linkerscript/common.s
@@ -0,0 +1,49 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .common : { *(COMMON) } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -s -t %t1 | FileCheck %s
+
+# q2 alignment is greater than q1, so it should have smaller offset
+# because of sorting
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .common
+# CHECK-NEXT: Type: SHT_NOBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x200
+# CHECK-NEXT: Offset: 0x
+# CHECK-NEXT: Size: 256
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 256
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: }
+# CHECK: Symbol {
+# CHECK: Name: q1
+# CHECK-NEXT: Value: 0x280
+# CHECK-NEXT: Size: 128
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: Object
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .common
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: q2
+# CHECK-NEXT: Value: 0x200
+# CHECK-NEXT: Size: 128
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: Object
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .common
+# CHECK-NEXT: }
+
+.globl _start
+_start:
+ jmp _start
+
+.comm q1,128,8
+.comm q2,128,256
diff --git a/test/ELF/linkerscript/data-commands.s b/test/ELF/linkerscript/data-commands.s
new file mode 100644
index 000000000000..ef154eda9f83
--- /dev/null
+++ b/test/ELF/linkerscript/data-commands.s
@@ -0,0 +1,81 @@
+# REQUIRES: x86,mips
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS \
+# RUN: { \
+# RUN: .foo : { \
+# RUN: *(.foo.1) \
+# RUN: BYTE(0x11) \
+# RUN: *(.foo.2) \
+# RUN: SHORT(0x1122) \
+# RUN: *(.foo.3) \
+# RUN: LONG(0x11223344) \
+# RUN: *(.foo.4) \
+# RUN: QUAD(0x1122334455667788) \
+# RUN: } \
+# RUN: .bar : { \
+# RUN: *(.bar.1) \
+# RUN: BYTE(a + 1) \
+# RUN: *(.bar.2) \
+# RUN: SHORT(b) \
+# RUN: *(.bar.3) \
+# RUN: LONG(c + 2) \
+# RUN: *(.bar.4) \
+# RUN: QUAD(d) \
+# RUN: } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t %t.o --script %t.script
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+# CHECK: Contents of section .foo:
+# CHECK-NEXT: ff11ff22 11ff4433 2211ff88 77665544
+# CHECK-NEXT: 332211
+
+# CHECK: Contents of section .bar:
+# CHECK-NEXT: ff12ff22 11ff4633 2211ff88 77665544
+# CHECK-NEXT: 332211
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %tmips64be
+# RUN: ld.lld --script %t.script %tmips64be -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck %s --check-prefix=BE
+# BE: Contents of section .foo:
+# BE-NEXT: ff11ff11 22ff1122 3344ff11 22334455
+# BE-NEXT: 667788
+# BE-NEXT: Contents of section .bar:
+# BE-NEXT: ff12ff11 22ff1122 3346ff11 22334455
+# BE-NEXT: 667788
+
+.global a
+a = 0x11
+
+.global b
+b = 0x1122
+
+.global c
+c = 0x11223344
+
+.global d
+d = 0x1122334455667788
+
+.section .foo.1, "a"
+ .byte 0xFF
+
+.section .foo.2, "a"
+ .byte 0xFF
+
+.section .foo.3, "a"
+ .byte 0xFF
+
+.section .foo.4, "a"
+ .byte 0xFF
+
+.section .bar.1, "a"
+ .byte 0xFF
+
+.section .bar.2, "a"
+ .byte 0xFF
+
+.section .bar.3, "a"
+ .byte 0xFF
+
+.section .bar.4, "a"
+ .byte 0xFF
diff --git a/test/ELF/linkerscript/data-segment-relro.s b/test/ELF/linkerscript/data-segment-relro.s
new file mode 100644
index 000000000000..7f69319dde7a
--- /dev/null
+++ b/test/ELF/linkerscript/data-segment-relro.s
@@ -0,0 +1,70 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .plt : { *(.plt) } \
+# RUN: .text : { *(.text) } \
+# RUN: . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); \
+# RUN: .dynamic : { *(.dynamic) } \
+# RUN: .got : { *(.got) } \
+# RUN: . = DATA_SEGMENT_RELRO_END (1 ? 24 : 0, .); \
+# RUN: .got.plt : { *(.got.plt) } \
+# RUN: .data : { *(.data) } \
+# RUN: .bss : { *(.bss) } \
+# RUN: . = DATA_SEGMENT_END (.); \
+# RUN: }" > %t.script
+
+## With relro or without DATA_SEGMENT_RELRO_END just aligns to
+## page boundary.
+# RUN: ld.lld -z norelro %t1.o %t2.so --script %t.script -o %t
+# RUN: llvm-readobj -s %t | FileCheck %s
+# RUN: ld.lld -z relro %t1.o %t2.so --script %t.script -o %t2
+# RUN: llvm-readobj -s %t2 | FileCheck %s
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .got
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x10F0
+# CHECK-NEXT: Offset: 0x10F0
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index:
+# CHECK-NEXT: Name: .got.plt
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x2000
+# CHECK-NEXT: Offset: 0x2000
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: }
+
+.global _start
+_start:
+ .long bar
+ jmp *bar2@GOTPCREL(%rip)
+
+.section .data,"aw"
+.quad 0
+
+.zero 4
+.section .foo,"aw"
+.section .bss,"",@nobits
diff --git a/test/ELF/linkerscript/define.s b/test/ELF/linkerscript/define.s
new file mode 100644
index 000000000000..b5f0b76e9e6b
--- /dev/null
+++ b/test/ELF/linkerscript/define.s
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS \
+# RUN: { \
+# RUN: . = DEFINED(defined) ? 0x11000 : .; \
+# RUN: .foo : { *(.foo*) } \
+# RUN: . = DEFINED(notdefined) ? 0x12000 : 0x13000; \
+# RUN: .bar : { *(.bar*) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK: 1 .foo 00000008 0000000000011000 DATA
+# CHECK: 2 .bar 00000008 0000000000013000 DATA
+# CHECK: 3 .text 00000000 0000000000013008 TEXT DATA
+
+.global defined
+defined = 0
+
+.section .foo,"a"
+.quad 1
+
+.section .bar,"a"
+.quad 1
diff --git a/test/ELF/linkerscript/diagnostic.s b/test/ELF/linkerscript/diagnostic.s
new file mode 100644
index 000000000000..bd1ebd01b5d2
--- /dev/null
+++ b/test/ELF/linkerscript/diagnostic.s
@@ -0,0 +1,106 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Take some valid script with multiline comments
+## and check it actually works:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: ld.lld -shared %t -o %t1 --script %t.script
+
+## Change ":" to "+" at line 2, check that error
+## message starts from correct line number:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text + { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR1 %s
+# ERR1: {{.*}}.script:2:
+
+## Change ":" to "+" at line 3 now, check correct error line number:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep + { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: {{.*}}.script:3:
+
+## Change ":" to "+" at line 6, after multiline comment,
+## check correct error line number:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp + { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: {{.*}}.script:6:
+
+## Check that text of lines and pointer to 'bad' token are working ok.
+# RUN: echo "UNKNOWN_TAG {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) }" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN: FileCheck -check-prefix=ERR6 -strict-whitespace %s
+# ERR6: error: {{.*}}.script:1:
+# ERR6-NEXT: error: {{.*}}.script:1: UNKNOWN_TAG {
+# ERR6-NEXT: error: {{.*}}.script:1: ^
+
+## One more check that text of lines and pointer to 'bad' token are working ok.
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) }" >> %t.script
+# RUN: echo "boom .temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN: FileCheck -check-prefix=ERR7 -strict-whitespace %s
+# ERR7: error: {{.*}}.script:4: malformed number: .temp
+# ERR7-NEXT: error: {{.*}}.script:4: boom .temp : { *(.temp) } }
+# ERR7-NEXT: error: {{.*}}.script:4: ^
+
+## Check tokenize() error
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: echo "\"" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN: FileCheck -check-prefix=ERR8 -strict-whitespace %s
+# ERR8: {{.*}}.script:2: unclosed quote
+
+## Check tokenize() error in included script file
+# RUN: echo "SECTIONS {}" > %t.script.inc
+# RUN: echo "\"" >> %t.script.inc
+# RUN: echo "INCLUDE \"%t.script.inc\"" > %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN: FileCheck -check-prefix=ERR9 -strict-whitespace %s
+# ERR9: {{.*}}.script.inc:2: unclosed quote
+
+## Check error reporting correctness for included files.
+# RUN: echo "SECTIONS {" > %t.script.inc
+# RUN: echo ".text : { *(.text) }" >> %t.script.inc
+# RUN: echo ".keep : { *(.keep) }" >> %t.script.inc
+# RUN: echo "boom .temp : { *(.temp) } }" >> %t.script.inc
+# RUN: echo "INCLUDE \"%t.script.inc\"" > %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN: FileCheck -check-prefix=ERR10 -strict-whitespace %s
+# ERR10: error: {{.*}}.script.inc:4: malformed number: .temp
+# ERR10-NEXT: error: {{.*}}.script.inc:4: boom .temp : { *(.temp) } }
+# ERR10-NEXT: error: {{.*}}.script.inc:4: ^
+
+## Check error reporting in script with INCLUDE directive.
+# RUN: echo "SECTIONS {" > %t.script.inc
+# RUN: echo ".text : { *(.text) }" >> %t.script.inc
+# RUN: echo ".keep : { *(.keep) }" >> %t.script.inc
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script.inc
+# RUN: echo "/* One line before INCLUDE */" > %t.script
+# RUN: echo "INCLUDE \"%t.script.inc\"" >> %t.script
+# RUN: echo "/* One line ater INCLUDE */" >> %t.script
+# RUN: echo "Error" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN: FileCheck -check-prefix=ERR11 -strict-whitespace %s
+# ERR11: error: {{.*}}.script:4: unexpected EOF
diff --git a/test/ELF/linkerscript/discard-interp.s b/test/ELF/linkerscript/discard-interp.s
new file mode 100644
index 000000000000..261509e2e76b
--- /dev/null
+++ b/test/ELF/linkerscript/discard-interp.s
@@ -0,0 +1,12 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/../Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; } \
+// RUN: SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text) } : text }" > %t.script
+// RUN: ld.lld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -rpath foo -rpath bar --script %t.script --export-dynamic %t.o %t2.so -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+
+// CHECK-NOT: Name: .interp
+
+.global _start
+_start:
diff --git a/test/ELF/linkerscript/discard-section.s b/test/ELF/linkerscript/discard-section.s
new file mode 100644
index 000000000000..a5af90806829
--- /dev/null
+++ b/test/ELF/linkerscript/discard-section.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.aaa*) } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK-NOT: .aaa
+
+.section .aaa,"a"
+aab:
+ .quad 0
+
+.section .zzz,"a"
+ .quad aab
diff --git a/test/ELF/linkerscript/dot-is-not-abs.s b/test/ELF/linkerscript/dot-is-not-abs.s
new file mode 100644
index 000000000000..4532cd59f2a1
--- /dev/null
+++ b/test/ELF/linkerscript/dot-is-not-abs.s
@@ -0,0 +1,53 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { .text : { *(.text) } \
+# RUN: foo = .; \
+# RUN: .bar : { *(.bar) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t.o -shared
+# RUN: llvm-readobj -t -s -section-data %t1 | FileCheck %s
+
+.hidden foo
+.long foo - .
+
+.section .bar, "a"
+.long 0
+
+# The symbol foo is defined as a position in the file. This means that it is
+# not absolute and it is possible to compute the distance from foo to some other
+# position in the file. The symbol is not really in any output section, but
+# ELF has no magic constant for not absolute, but not in any section.
+# Fortunately the value of a symbol in a non relocatable file is a virtual
+# address, so the section can be arbitrary.
+
+# CHECK: Section {
+# CHECK: Index:
+# CHECK: Name: .text
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_EXECINSTR
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x0
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 04000000 |
+# CHECK-NEXT: )
+# CHECK-NEXT: }
+
+# CHECK: Symbol {
+# CHECK: Name: foo
+# CHECK-NEXT: Value: 0x4
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local
+# CHECK-NEXT: Type: None
+# CHECK-NEXT: Other [
+# CHECK-NEXT: STV_HIDDEN
+# CHECK-NEXT: ]
+# CHECK-NEXT: Section: .text
+# CHECK-NEXT: }
diff --git a/test/ELF/linkerscript/double-bss.s b/test/ELF/linkerscript/double-bss.s
new file mode 100644
index 000000000000..c24332f5e5a6
--- /dev/null
+++ b/test/ELF/linkerscript/double-bss.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; " > %t.script
+# RUN: echo ".text : { *(.text*) }" >> %t.script
+# RUN: echo ".bss1 : { *(.bss) }" >> %t.script
+# RUN: echo ".bss2 : { *(COMMON) }" >> %t.script
+# RUN: echo "}" >> %t.script
+
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK: .bss1 00000004 0000000000000122 BSS
+# CHECK-NEXT: .bss2 00000080 0000000000000128 BSS
+
+.globl _start
+_start:
+ jmp _start
+
+.bss
+.zero 4
+
+.comm q,128,8
diff --git a/test/ELF/linkerscript/dynamic-sym.s b/test/ELF/linkerscript/dynamic-sym.s
new file mode 100644
index 000000000000..e3193b1a765d
--- /dev/null
+++ b/test/ELF/linkerscript/dynamic-sym.s
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "_DYNAMIC = 0x123;" > %t.script
+# RUN: ld.lld -T %t.script %t.o -shared -o %t.so
+# RUN: llvm-readobj -t %t.so | FileCheck %s
+
+# CHECK: Symbol {
+# CHECK: Name: _DYNAMIC
+# CHECK-NEXT: Value: 0x123
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local
+# CHECK-NEXT: Type: None
+# CHECK-NEXT: Other [
+# CHECK-NEXT: STV_HIDDEN
+# CHECK-NEXT: ]
+# CHECK-NEXT: Section: Absolute
+# CHECK-NEXT: }
diff --git a/test/ELF/linkerscript/dynamic.s b/test/ELF/linkerscript/dynamic.s
new file mode 100644
index 000000000000..ab65ab831f8f
--- /dev/null
+++ b/test/ELF/linkerscript/dynamic.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+
+# RUN: echo "SECTIONS { }" > %t.script
+# RUN: ld.lld %t1.o %t2.so -o %t
+# RUN: llvm-readobj -dynamic-table %t | FileCheck %s
+
+# CHECK: DynamicSection [
+# CHECK-NEXT: Tag Type Name/Value
+# CHECK: 0x0000000000000021 PREINIT_ARRAYSZ 9 (bytes)
+# CHECK: 0x000000000000001B INIT_ARRAYSZ 8 (bytes)
+# CHECK: 0x000000000000001C FINI_ARRAYSZ 10 (bytes)
+
+.globl _start
+_start:
+
+.section .init_array,"aw",@init_array
+ .quad 0
+
+.section .preinit_array,"aw",@preinit_array
+ .quad 0
+ .byte 0
+
+.section .fini_array,"aw",@fini_array
+ .quad 0
+ .short 0
diff --git a/test/ELF/linkerscript/edata-etext.s b/test/ELF/linkerscript/edata-etext.s
new file mode 100644
index 000000000000..fdf5ec1f5671
--- /dev/null
+++ b/test/ELF/linkerscript/edata-etext.s
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { }" > %t.script
+# RUN: not ld.lld %t.o -script %t.script -o %t 2>&1 | FileCheck %s
+# CHECK: error: {{.*}}:(.text+0x0): undefined symbol '_edata'
+# CHECK: error: {{.*}}:(.text+0x8): undefined symbol '_etext'
+# CHECK: error: {{.*}}:(.text+0x10): undefined symbol '_end'
+
+.global _start,_end,_etext,_edata
+.text
+_start:
+ .quad _edata + 0x1
+ .quad _etext + 0x1
+ .quad _end + 0x1
+
+.data
+ .word 1
+.bss
+ .align 4
+ .space 6
diff --git a/test/ELF/linkerscript/eh-frame-hdr.s b/test/ELF/linkerscript/eh-frame-hdr.s
new file mode 100644
index 000000000000..d1545be632a3
--- /dev/null
+++ b/test/ELF/linkerscript/eh-frame-hdr.s
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: .eh_frame_hdr : {} \
+# RUN: .eh_frame : {} \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# RUN: llvm-objdump -s -section=".eh_frame_hdr" %t1 | FileCheck %s
+
+# CHECK: 011b033b 14000000 01000000 49000000
+# CHECK-NEXT: 30000000
+
+.global _start
+_start:
+ nop
+
+.section .dah,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
diff --git a/test/ELF/linkerscript/ehdr_start.s b/test/ELF/linkerscript/ehdr_start.s
new file mode 100644
index 000000000000..0ae4a4dcfbc9
--- /dev/null
+++ b/test/ELF/linkerscript/ehdr_start.s
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { }" > %t.script
+# RUN: not ld.lld %t.o -script %t.script -o %t 2>&1 | FileCheck %s
+# CHECK: error: {{.*}}:(.text+0x0): undefined symbol '__ehdr_start'
+
+.text
+.global _start, __ehdr_start
+_start:
+ .quad __ehdr_start
diff --git a/test/ELF/linkerscript/empty-load.s b/test/ELF/linkerscript/empty-load.s
new file mode 100644
index 000000000000..0a87d5727474
--- /dev/null
+++ b/test/ELF/linkerscript/empty-load.s
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { .rw : { *(.rw) } .text : { *(.text) } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -private-headers %t1 | FileCheck %s
+
+## We expect 2 PT_LOAD segments
+# CHECK: PHDR
+# CHECK-NEXT: filesz {{0x[0-9a-f]+}} memsz {{0x[0-9a-f]+}} flags r--
+# CHECK-NEXT: LOAD
+# CHECK-NEXT: filesz {{0x[0-9a-f]+}} memsz {{0x[0-9a-f]+}} flags rw-
+# CHECK-NEXT: LOAD
+# CHECK-NEXT: filesz {{0x[0-9a-f]+}} memsz {{0x[0-9a-f]+}} flags r-x
+# CHECK-NEXT: STACK
+# CHECK-NEXT: filesz
+
+.globl _start
+_start:
+ jmp _start
+
+.section .rw, "aw"
+ .quad 0
diff --git a/test/ELF/linkerscript/empty-tls.s b/test/ELF/linkerscript/empty-tls.s
new file mode 100644
index 000000000000..919ccbffbe43
--- /dev/null
+++ b/test/ELF/linkerscript/empty-tls.s
@@ -0,0 +1,14 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: echo "PHDRS { ph_tls PT_TLS; }" > %t.script
+// RUN: ld.lld -o %t.so -T %t.script %t.o -shared
+// RUN: llvm-readobj -l %t.so | FileCheck %s
+
+// test that we don't crash with an empty PT_TLS
+
+// CHECK: Type: PT_TLS
+// CHECK-NEXT: Offset: 0x0
+// CHECK-NEXT: VirtualAddress: 0x0
+// CHECK-NEXT: PhysicalAddress: 0x0
+// CHECK-NEXT: FileSize: 0
+// CHECK-NEXT: MemSize: 0
diff --git a/test/ELF/linkerscript/entry.s b/test/ELF/linkerscript/entry.s
new file mode 100644
index 000000000000..d75b1345a8aa
--- /dev/null
+++ b/test/ELF/linkerscript/entry.s
@@ -0,0 +1,42 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "ENTRY(_label)" > %t.script
+# RUN: ld.lld -o %t2 %t.script %t
+# RUN: llvm-readobj %t2 > /dev/null
+
+# The entry symbol should not cause an undefined error.
+# RUN: echo "ENTRY(_wrong_label)" > %t.script
+# RUN: ld.lld -o %t2 %t.script %t
+# RUN: ld.lld --entry=abc -o %t2 %t
+
+# -e has precedence over linker script's ENTRY.
+# RUN: echo "ENTRY(_label)" > %t.script
+# RUN: ld.lld -e _start -o %t2 %t.script %t
+# RUN: llvm-readobj -file-headers -symbols %t2 | \
+# RUN: FileCheck -check-prefix=OVERLOAD %s
+
+# OVERLOAD: Entry: [[ENTRY:0x[0-9A-F]+]]
+# OVERLOAD: Name: _start
+# OVERLOAD-NEXT: Value: [[ENTRY]]
+
+# The entry symbol can be a linker-script-defined symbol.
+# RUN: echo "ENTRY(foo); foo = 1;" > %t.script
+# RUN: ld.lld -o %t2 %t.script %t
+# RUN: llvm-readobj -file-headers -symbols %t2 | \
+# RUN: FileCheck -check-prefix=SCRIPT %s
+
+# SCRIPT: Entry: 0x1
+
+# RUN: echo "ENTRY(no_such_symbol);" > %t.script
+# RUN: ld.lld -o %t2 %t.script %t 2>&1 | \
+# RUN: FileCheck -check-prefix=MISSING %s
+
+# MISSING: warning: cannot find entry symbol no_such_symbol
+
+.globl _start, _label
+_start:
+ ret
+_label:
+ ret
diff --git a/test/ELF/linkerscript/exclude-multiple.s b/test/ELF/linkerscript/exclude-multiple.s
new file mode 100644
index 000000000000..46ec18cfa125
--- /dev/null
+++ b/test/ELF/linkerscript/exclude-multiple.s
@@ -0,0 +1,37 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfile1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/exclude-multiple1.s -o %tfile2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/exclude-multiple2.s -o %tfile3.o
+# RUN: echo "SECTIONS { \
+# RUN: .foo : { *(.foo.1 EXCLUDE_FILE (*file1.o) .foo.2 EXCLUDE_FILE (*file2.o) .foo.3) } \
+# RUN: }" > %t1.script
+# RUN: ld.lld -script %t1.script %tfile1.o %tfile2.o %tfile3.o -o %t1.o
+# RUN: llvm-objdump -s %t1.o | FileCheck %s
+
+# CHECK: Contents of section .foo:
+# CHECK-NEXT: 01000000 00000000 04000000 00000000
+# CHECK-NEXT: 07000000 00000000 05000000 00000000
+# CHECK-NEXT: 08000000 00000000 03000000 00000000
+# CHECK-NEXT: 09000000 00000000
+# CHECK-NEXT: Contents of section .foo.2:
+# CHECK-NEXT: 02000000 00000000
+# CHECK-NEXT: Contents of section .foo.3:
+# CHECK-NEXT: 06000000 00000000
+
+# RUN: echo "SECTIONS { .foo : { *(EXCLUDE_FILE (*file1.o) EXCLUDE_FILE (*file2.o) .foo.3) } }" > %t2.script
+# RUN: not ld.lld -script %t2.script %tfile1.o %tfile2.o %tfile3.o -o %t2.o 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ERR
+# ERR: section pattern is expected
+
+# RUN: echo "SECTIONS { .foo : { *(EXCLUDE_FILE (*file1.o)) } }" > %t3.script
+# RUN: not ld.lld -script %t3.script %tfile1.o %tfile2.o %tfile3.o -o %t2.o 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ERR
+
+.section .foo.1,"a"
+ .quad 1
+
+.section .foo.2,"a"
+ .quad 2
+
+.section .foo.3,"a"
+ .quad 3
diff --git a/test/ELF/linkerscript/excludefile.s b/test/ELF/linkerscript/excludefile.s
new file mode 100644
index 000000000000..8a154354dbc2
--- /dev/null
+++ b/test/ELF/linkerscript/excludefile.s
@@ -0,0 +1,46 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/include.s -o %t2
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/notinclude.s -o %t3.notinclude
+
+# RUN: echo "SECTIONS {} " > %t.script
+# RUN: ld.lld -o %t --script %t.script %t1 %t2 %t3.notinclude
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK: _start:
+# CHECK-NEXT: : 48 c7 c0 3c 00 00 00 movq $60, %rax
+# CHECK-NEXT: : 48 c7 c7 2a 00 00 00 movq $42, %rdi
+# CHECK-NEXT: : 00 00 addb %al, (%rax)
+# CHECK: _potato:
+# CHECK-NEXT: : 90 nop
+# CHECK-NEXT: : 90 nop
+# CHECK-NEXT: : 00 00 addb %al, (%rax)
+# CHECK: tomato:
+# CHECK-NEXT: : b8 01 00 00 00 movl $1, %eax
+
+# RUN: echo "SECTIONS { .patatino : \
+# RUN: { KEEP(*(EXCLUDE_FILE(*notinclude) .text)) } }" \
+# RUN: > %t.script
+# RUN: ld.lld -o %t4 --script %t.script %t1 %t2 %t3.notinclude
+# RUN: llvm-objdump -d %t4 | FileCheck %s --check-prefix=EXCLUDE
+
+# EXCLUDE: Disassembly of section .patatino:
+# EXCLUDE: _start:
+# EXCLUDE-NEXT: : 48 c7 c0 3c 00 00 00 movq $60, %rax
+# EXCLUDE-NEXT: : 48 c7 c7 2a 00 00 00 movq $42, %rdi
+# EXCLUDE-NEXT: : 00 00 addb %al, (%rax)
+# EXCLUDE: _potato:
+# EXCLUDE-NEXT: : 90 nop
+# EXCLUDE-NEXT: : 90 nop
+# EXCLUDE: Disassembly of section .text:
+# EXCLUDE: tomato:
+# EXCLUDE-NEXT: : b8 01 00 00 00 movl $1, %eax
+
+.section .text
+.globl _start
+_start:
+ mov $60, %rax
+ mov $42, %rdi
diff --git a/test/ELF/linkerscript/extend-pt-load.s b/test/ELF/linkerscript/extend-pt-load.s
new file mode 100644
index 000000000000..f9a77c8c12bf
--- /dev/null
+++ b/test/ELF/linkerscript/extend-pt-load.s
@@ -0,0 +1,69 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# This test demonstrates an odd consequence of the way we handle sections with just symbol
+# assignments.
+
+# First, run a test with no such section.
+
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .dynsym : { } \
+# RUN: .hash : { } \
+# RUN: .dynstr : { } \
+# RUN: .text : { *(.text) } \
+# RUN: . = ALIGN(0x1000); \
+# RUN: .data.rel.ro : { *(.data.rel.ro) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t.o -shared
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t1 | FileCheck --check-prefix=CHECK1 %s
+
+# CHECK1: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX
+# CHECK1-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA
+
+# CHECK1: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x0001bd R E
+# CHECK1-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW
+
+# Then add the section bar. Note how bar is given AX flags, which causes the PT_LOAD to now
+# cover the padding bits created by ALIGN.
+
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .dynsym : { } \
+# RUN: .hash : { } \
+# RUN: .dynstr : { } \
+# RUN: .text : { *(.text) } \
+# RUN: . = ALIGN(0x1000); \
+# RUN: bar : { HIDDEN(bar_sym = .); } \
+# RUN: .data.rel.ro : { *(.data.rel.ro) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t2 --script %t.script %t.o -shared
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck --check-prefix=CHECK2 %s
+
+# CHECK2: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX
+# CHECK2-NEXT: bar PROGBITS 0000000000001000 001000 000000 00 AX
+# CHECK2-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA
+
+# CHECK2: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x001000 0x001000 R E
+# CHECK2-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW
+
+# If the current behavior becomes a problem we should consider just moving the commands out
+# of the section. That is, handle the above like the following test.
+
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .dynsym : { } \
+# RUN: .hash : { } \
+# RUN: .dynstr : { } \
+# RUN: .text : { *(.text) } \
+# RUN: . = ALIGN(0x1000); \
+# RUN: HIDDEN(bar_sym = .); \
+# RUN: .data.rel.ro : { *(.data.rel.ro) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t3 --script %t.script %t.o -shared
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t3 | FileCheck --check-prefix=CHECK1 %s
+
+nop
+
+.section .data.rel.ro, "aw"
+.byte 0
diff --git a/test/ELF/linkerscript/filename-spec.s b/test/ELF/linkerscript/filename-spec.s
new file mode 100644
index 000000000000..d4bc495efb81
--- /dev/null
+++ b/test/ELF/linkerscript/filename-spec.s
@@ -0,0 +1,59 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfirst.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/filename-spec.s -o %tsecond.o
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN: KEEP(*first.o(.foo)) \
+# RUN: KEEP(*second.o(.foo)) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t1 | FileCheck --check-prefix=FIRSTSECOND %s
+# FIRSTSECOND: Contents of section .foo:
+# FIRSTSECOND-NEXT: 01000000 00000000 11000000 00000000
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN: KEEP(*second.o(.foo)) \
+# RUN: KEEP(*first.o(.foo)) } }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=SECONDFIRST %s
+# SECONDFIRST: Contents of section .foo:
+# SECONDFIRST-NEXT: 11000000 00000000 01000000 00000000
+
+## Now the same tests but without KEEP. Checking that file name inside
+## KEEP is parsed fine.
+# RUN: echo "SECTIONS { .foo : { \
+# RUN: *first.o(.foo) \
+# RUN: *second.o(.foo) } }" > %t3.script
+# RUN: ld.lld -o %t3 --script %t3.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t3 | FileCheck --check-prefix=FIRSTSECOND %s
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN: *second.o(.foo) \
+# RUN: *first.o(.foo) } }" > %t4.script
+# RUN: ld.lld -o %t4 --script %t4.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t4 | FileCheck --check-prefix=SECONDFIRST %s
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %T/filename-spec1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/filename-spec.s -o %T/filename-spec2.o
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN: filename-spec2.o(.foo) \
+# RUN: filename-spec1.o(.foo) } }" > %t5.script
+# RUN: ld.lld -o %t5 --script %t5.script \
+# RUN: %T/filename-spec1.o %T/filename-spec2.o
+# RUN: llvm-objdump -s %t5 | FileCheck --check-prefix=SECONDFIRST %s
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN: filename-spec1.o(.foo) \
+# RUN: filename-spec2.o(.foo) } }" > %t6.script
+# RUN: ld.lld -o %t6 --script %t6.script \
+# RUN: %T/filename-spec1.o %T/filename-spec2.o
+# RUN: llvm-objdump -s %t6 | FileCheck --check-prefix=FIRSTSECOND %s
+
+.global _start
+_start:
+ nop
+
+.section .foo,"a"
+ .quad 1
diff --git a/test/ELF/linkerscript/fill.s b/test/ELF/linkerscript/fill.s
new file mode 100644
index 000000000000..57a19e0943d0
--- /dev/null
+++ b/test/ELF/linkerscript/fill.s
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN: .out : { \
+# RUN: FILL(0x11111111); \
+# RUN: *(.aaa) \
+# RUN: . += 4; \
+# RUN: *(.bbb) \
+# RUN: . += 4; \
+# RUN: FILL(0x22222222); \
+# RUN: . += 4; \
+# RUN: } \
+# RUN: }; " > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+# CHECK: Contents of section .out:
+# CHECK-NEXT: aa222222 22bb2222 22222222 2222
+
+.text
+.globl _start
+_start:
+
+.section .aaa, "a"
+.align 1
+.byte 0xAA
+
+.section .bbb, "a"
+.align 1
+.byte 0xBB
diff --git a/test/ELF/linkerscript/group.s b/test/ELF/linkerscript/group.s
new file mode 100644
index 000000000000..53a1c89ebfe3
--- /dev/null
+++ b/test/ELF/linkerscript/group.s
@@ -0,0 +1,56 @@
+# REQUIRES: x86
+
+# RUN: mkdir -p %t.dir
+# RUN: rm -f %t.dir/libxyz.a
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/libsearch-st.s -o %t2.o
+# RUN: llvm-ar rcs %t.dir/libxyz.a %t2.o
+
+# RUN: echo "GROUP(\"%t\")" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "INPUT(\"%t\")" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" libxyz.a )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script 2>/dev/null
+# RUN: ld.lld -o %t2 %t.script -L%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" =libxyz.a )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script 2>/dev/null
+# RUN: ld.lld -o %t2 %t.script --sysroot=%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" -lxyz )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script 2>/dev/null
+# RUN: ld.lld -o %t2 %t.script -L%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" libxyz.a )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script 2>/dev/null
+# RUN: ld.lld -o %t2 %t.script -L%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" /libxyz.a )" > %t.script
+# RUN: echo "GROUP(\"%t\" /libxyz.a )" > %t.dir/xyz.script
+# RUN: not ld.lld -o %t2 %t.script 2>/dev/null
+# RUN: not ld.lld -o %t2 %t.script --sysroot=%t.dir 2>/dev/null
+# RUN: ld.lld -o %t2 %t.dir/xyz.script --sysroot=%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t.script2\")" > %t.script1
+# RUN: echo "GROUP(\"%t\")" > %t.script2
+# RUN: ld.lld -o %t2 %t.script1
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(AS_NEEDED(\"%t\"))" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+.globl _start
+_start:
+ ret
diff --git a/test/ELF/linkerscript/header-addr.s b/test/ELF/linkerscript/header-addr.s
new file mode 100644
index 000000000000..f37d319aaabe
--- /dev/null
+++ b/test/ELF/linkerscript/header-addr.s
@@ -0,0 +1,47 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "PHDRS {all PT_LOAD PHDRS;} \
+# RUN: SECTIONS { \
+# RUN: . = 0x2000; \
+# RUN: .text : {*(.text)} :all \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
+# RUN: llvm-readobj -program-headers %t.so | FileCheck %s
+
+# CHECK: ProgramHeaders [
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x40
+# CHECK-NEXT: VirtualAddress: 0x1040
+# CHECK-NEXT: PhysicalAddress: 0x1040
+# CHECK-NEXT: FileSize: 4176
+# CHECK-NEXT: MemSize: 4176
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R (0x4)
+# CHECK-NEXT: PF_W (0x2)
+# CHECK-NEXT: PF_X (0x1)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 4096
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# RUN: ld.lld -o %t2.so --script %t.script %t.o -shared -z max-page-size=0x2000
+# RUN: llvm-readobj -program-headers %t2.so \
+# RUN: | FileCheck --check-prefix=MAXPAGE %s
+
+# MAXPAGE: ProgramHeaders [
+# MAXPAGE-NEXT: ProgramHeader {
+# MAXPAGE-NEXT: Type: PT_LOAD
+# MAXPAGE-NEXT: Offset: 0x40
+# MAXPAGE-NEXT: VirtualAddress: 0x40
+# MAXPAGE-NEXT: PhysicalAddress: 0x40
+# MAXPAGE-NEXT: FileSize: 8272
+# MAXPAGE-NEXT: MemSize: 8272
+# MAXPAGE-NEXT: Flags [
+# MAXPAGE-NEXT: PF_R
+# MAXPAGE-NEXT: PF_W
+# MAXPAGE-NEXT: PF_X
+# MAXPAGE-NEXT: ]
+# MAXPAGE-NEXT: Alignment: 8192
+# MAXPAGE-NEXT: }
+# MAXPAGE-NEXT: ]
diff --git a/test/ELF/linkerscript/implicit-program-header.s b/test/ELF/linkerscript/implicit-program-header.s
new file mode 100644
index 000000000000..9598a6abebb0
--- /dev/null
+++ b/test/ELF/linkerscript/implicit-program-header.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -o %t1 --script %S/Inputs/implicit-program-header.script \
+# RUN: %t.o -shared
+# RUN: llvm-readobj -elf-output-style=GNU -l %t1 | FileCheck %s
+
+# CHECK: Segment Sections...
+# CHECK-NEXT: 00 .text .dynsym .hash .dynstr .dynamic
+# CHECK-NEXT: 01 .foo
+
+.quad 0
+.section .foo,"ax"
+.quad 0
diff --git a/test/ELF/linkerscript/input-order.s b/test/ELF/linkerscript/input-order.s
new file mode 100644
index 000000000000..cb9ea354cdbf
--- /dev/null
+++ b/test/ELF/linkerscript/input-order.s
@@ -0,0 +1,38 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# This test case should place input sections in script order:
+# .foo.1 .foo.2 .bar.1 .bar.2
+# RUN: echo "SECTIONS { . = 0x1000; .foo : {*(.foo.*) *(.bar.*) } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section=.foo -s %t1 | FileCheck --check-prefix=SCRIPT_ORDER %s
+# SCRIPT_ORDER: Contents of section .foo:
+# SCRIPT_ORDER-NEXT: 1000 00000000 00000000 ffffffff eeeeeeee
+
+# This test case should place input sections in native order:
+# .bar.1 .foo.1 .bar.2 .foo.2
+# RUN: echo "SECTIONS { . = 0x1000; .foo : {*(.foo.* .bar.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section=.foo -s %t1 | FileCheck --check-prefix=FILE_ORDER %s
+# FILE_ORDER: Contents of section .foo:
+# FILE_ORDER-NEXT: 1000 ffffffff 00000000 eeeeeeee 00000000
+
+.global _start
+_start:
+ nop
+
+.section .bar.1,"a"
+bar1:
+ .long 0xFFFFFFFF
+
+.section .foo.1,"a"
+foo1:
+ .long 0
+
+.section .bar.2,"a"
+bar2:
+ .long 0xEEEEEEEE
+
+.section .foo.2,"a"
+foo2:
+ .long 0
diff --git a/test/ELF/linkerscript/input-sec-dup.s b/test/ELF/linkerscript/input-sec-dup.s
new file mode 100644
index 000000000000..fd889393c74c
--- /dev/null
+++ b/test/ELF/linkerscript/input-sec-dup.s
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {.foo : { *(.foo) *(.foo) } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size
+# CHECK-NEXT: 0 00000000
+# CHECK-NEXT: 1 .foo 00000004
+# CHECK-NEXT: 2 .text 00000001
+
+.global _start
+_start:
+ nop
+
+.section .foo,"a"
+ .long 0
diff --git a/test/ELF/linkerscript/linkerscript.s b/test/ELF/linkerscript/linkerscript.s
new file mode 100644
index 000000000000..cac902af4270
--- /dev/null
+++ b/test/ELF/linkerscript/linkerscript.s
@@ -0,0 +1,54 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/libsearch-st.s -o %t2.o
+
+# RUN: echo "EXTERN( undef undef2 )" > %t.script
+# RUN: ld.lld %t -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "OUTPUT_FORMAT(elf64-x86-64) /*/*/ GROUP(\"%t\" )" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: rm -f %t.out
+# RUN: echo "OUTPUT(\"%t.out\")" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo "SEARCH_DIR(/lib/foo/blah)" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo ";SEARCH_DIR(x);SEARCH_DIR(y);" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo ";" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo "INCLUDE \"%t.script2\" OUTPUT(\"%t.out\")" > %t.script1
+# RUN: echo "GROUP(\"%t\")" > %t.script2
+# RUN: ld.lld %t.script1
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "INCLUDE \"foo.script\"" > %t.script
+# RUN: echo "OUTPUT(\"%t.out\")" > %T/foo.script
+# RUN: not ld.lld %t.script > %t.log 2>&1
+# RUN: FileCheck -check-prefix=INCLUDE_ERR %s < %t.log
+# INCLUDE_ERR: error: {{.+}}.script:1: cannot open foo.script
+# INCLUDE_ERR-NEXT: error: {{.+}}.script:1: INCLUDE "foo.script"
+# RUN: ld.lld -L %T %t.script %t
+
+# RUN: echo "FOO(BAR)" > %t.script
+# RUN: not ld.lld -o foo %t.script > %t.log 2>&1
+# RUN: FileCheck -check-prefix=ERR1 %s < %t.log
+
+# ERR1: unknown directive: FOO
+
+.globl _start, _label
+_start:
+ ret
+_label:
+ ret
diff --git a/test/ELF/linkerscript/loadaddr.s b/test/ELF/linkerscript/loadaddr.s
new file mode 100644
index 000000000000..33c5f21b52ba
--- /dev/null
+++ b/test/ELF/linkerscript/loadaddr.s
@@ -0,0 +1,42 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x1000; \
+# RUN: .aaa : AT(0x2000) { *(.aaa) } \
+# RUN: .bbb : { *(.bbb) } \
+# RUN: .ccc : AT(0x3000) { *(.ccc) } \
+# RUN: .ddd : AT(0x4000) { *(.ddd) } \
+# RUN: .text : { *(.text) } \
+# RUN: aaa_lma = LOADADDR(.aaa); \
+# RUN: bbb_lma = LOADADDR(.bbb); \
+# RUN: ccc_lma = LOADADDR(.ccc); \
+# RUN: ddd_lma = LOADADDR(.ddd); \
+# RUN: txt_lma = LOADADDR(.text); \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-objdump -t %t2 | FileCheck %s
+# RUN: echo "SECTIONS { v = LOADADDR(.zzz); }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | FileCheck --check-prefix=ERROR %s
+
+# CHECK: 0000000000002000 *ABS* 00000000 aaa_lma
+# CHECK-NEXT: 0000000000002008 *ABS* 00000000 bbb_lma
+# CHECK-NEXT: 0000000000003000 *ABS* 00000000 ccc_lma
+# CHECK-NEXT: 0000000000004000 *ABS* 00000000 ddd_lma
+# CHECK-NEXT: 0000000000004008 *ABS* 00000000 txt_lma
+# ERROR: {{.*}}.script:1: undefined section .zzz
+
+.global _start
+_start:
+ nop
+
+.section .aaa, "a"
+.quad 0
+
+.section .bbb, "a"
+.quad 0
+
+.section .ccc, "a"
+.quad 0
+
+.section .ddd, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/locationcounter.s b/test/ELF/linkerscript/locationcounter.s
new file mode 100644
index 000000000000..c57a17c5c9cb
--- /dev/null
+++ b/test/ELF/linkerscript/locationcounter.s
@@ -0,0 +1,189 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: . = 0xFFF0; \
+# RUN: . = . + 0x10; \
+# RUN: .plus : { *(.plus) } \
+# RUN: . = 0x11010 - 0x10; \
+# RUN: .minus : { *(.minus) } \
+# RUN: . = 0x24000 / 0x2; \
+# RUN: .div : { *(.div) } \
+# RUN: . = 0x11000 + 0x1000 * 0x2; \
+# RUN: .mul : { *(.mul) } \
+# RUN: . = 0x10000 + (0x1000 + 0x1000) * 0x2; \
+# RUN: .bracket : { *(.bracket) } \
+# RUN: . = 0x17000 & 0x15000; \
+# RUN: .and : { *(.and) } \
+# RUN: . = 0x1 ? 0x16000 : 0x999999; \
+# RUN: .ternary1 : { *(.ternary1) } \
+# RUN: . = 0x0 ? 0x999999 : 0x17000; \
+# RUN: .ternary2 : { *(.ternary2) } \
+# RUN: . = 0x0 < 0x1 ? 0x18000 : 0x999999; \
+# RUN: .less : { *(.less) } \
+# RUN: . = 0x1 <= 0x1 ? 0x19000 : 0x999999; \
+# RUN: .lesseq : { *(.lesseq) } \
+# RUN: . = 0x1 > 0x0 ? 0x20000 : 0x999999; \
+# RUN: .great : { *(.great) } \
+# RUN: . = 0x1 >= 0x1 ? 0x21000 : 0x999999; \
+# RUN: .greateq : { *(.greateq) } \
+# RUN: . = 0x1 == 0x1 ? 0x22000 : 0x999999; \
+# RUN: .eq : { *(.eq) } \
+# RUN: . = 0x2 != 0x1 ? 0x23000 : 0x999999; \
+# RUN: .neq : { *(.neq) } \
+# RUN: . = CONSTANT (MAXPAGESIZE) * 0x24; \
+# RUN: .maxpagesize : { *(.maxpagesize) } \
+# RUN: . = CONSTANT (COMMONPAGESIZE) * 0x25; \
+# RUN: .commonpagesize : { *(.commonpagesize) } \
+# RUN: . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); \
+# RUN: .datasegmentalign : { *(.datasegmentalign) } \
+# RUN: . = DATA_SEGMENT_END (.); \
+# RUN: . = 0x27000; \
+# RUN: . += 0x1000; \
+# RUN: .plusassign : { *(.plusassign) } \
+# RUN: . = ((. + 0x1fff) & ~(0x1000 + -1)); \
+# RUN: .unary : { *(.unary) } \
+# RUN: . = 0x30000 + (1 + 1 << 5); \
+# RUN: .shiftl : { *(.shiftl) } \
+# RUN: . = 0x30000 + (1 + 1023 >> 2); \
+# RUN: .shiftr : { *(.shiftr) } \
+
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-objdump -section-headers %t2 | FileCheck %s
+
+# CHECK: .plus {{.*}} 0000000000010000
+# CHECK: .minus {{.*}} 0000000000011000
+# CHECK: .div {{.*}} 0000000000012000
+# CHECK: .mul {{.*}} 0000000000013000
+# CHECK: .bracket {{.*}} 0000000000014000
+# CHECK: .and {{.*}} 0000000000015000
+# CHECK: .ternary1 {{.*}} 0000000000016000
+# CHECK: .ternary2 {{.*}} 0000000000017000
+# CHECK: .less {{.*}} 0000000000018000
+# CHECK: .lesseq {{.*}} 0000000000019000
+# CHECK: .great {{.*}} 0000000000020000
+# CHECK: .greateq {{.*}} 0000000000021000
+# CHECK: .eq {{.*}} 0000000000022000
+# CHECK: .neq {{.*}} 0000000000023000
+# CHECK: .maxpagesize {{.*}} 0000000000024000
+# CHECK: .commonpagesize {{.*}} 0000000000025000
+# CHECK: .datasegmentalign {{.*}} 0000000000026000
+# CHECK: .plusassign {{.*}} 0000000000028000
+# CHECK: .unary {{.*}} 000000000002a000
+# CHECK: .shiftl {{.*}} 0000000000030040
+# CHECK: .shiftr {{.*}} 0000000000030100
+
+## Mailformed number error.
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x12Q41; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=NUMERR %s
+# NUMERR: malformed number: 0x12Q41
+
+## Missing closing bracket.
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x10000 + (0x1000 + 0x1000 * 0x2; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=BRACKETERR %s
+# BRACKETERR: ) expected, but got ;
+
+## Missing opening bracket.
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x10000 + 0x1000 + 0x1000) * 0x2; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=BRACKETERR2 %s
+# BRACKETERR2: ; expected, but got )
+
+## Empty expression.
+# RUN: echo "SECTIONS { \
+# RUN: . = ; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=ERREXPR %s
+# ERREXPR: malformed number: ;
+
+## Div by zero error.
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x10000 / 0x0; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=DIVZERO %s
+# DIVZERO: division by zero
+
+## Broken ternary operator expression.
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x1 ? 0x2; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=TERNERR %s
+# TERNERR: : expected, but got ;
+
+.globl _start
+_start:
+nop
+
+.section .plus, "a"
+.quad 0
+
+.section .minus, "a"
+.quad 0
+
+.section .div, "a"
+.quad 0
+
+.section .mul, "a"
+.quad 0
+
+.section .bracket, "a"
+.quad 0
+
+.section .and, "a"
+.quad 0
+
+.section .ternary1, "a"
+.quad 0
+
+.section .ternary2, "a"
+.quad 0
+
+.section .less, "a"
+.quad 0
+
+.section .lesseq, "a"
+.quad 0
+
+.section .great, "a"
+.quad 0
+
+.section .greateq, "a"
+.quad 0
+
+.section .eq, "a"
+.quad 0
+
+.section .neq, "a"
+.quad 0
+
+.section .maxpagesize, "a"
+.quad 0
+
+.section .commonpagesize, "a"
+.quad 0
+
+.section .datasegmentalign, "a"
+.quad 0
+
+.section .plusassign, "a"
+.quad 0
+
+.section .unary, "a"
+.quad 0
+
+.section .shiftl, "a"
+.quad 0
+
+.section .shiftr, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/locationcountererr.s b/test/ELF/linkerscript/locationcountererr.s
new file mode 100644
index 000000000000..7664d8d46917
--- /dev/null
+++ b/test/ELF/linkerscript/locationcountererr.s
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { .text 0x2000 : {. = 0x10 ; *(.text) } }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t1 2>&1 | FileCheck %s
+# CHECK: unable to move location counter backward for: .text
+
+.globl _start
+_start:
+nop
diff --git a/test/ELF/linkerscript/merge-sections-reloc.s b/test/ELF/linkerscript/merge-sections-reloc.s
new file mode 100644
index 000000000000..639341540350
--- /dev/null
+++ b/test/ELF/linkerscript/merge-sections-reloc.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/merge-sections-reloc.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+## Check that sections content is not corrupted.
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 44332211 00000000 44332211 00000000
+# CHECK-NEXT: f0ffffff ffffffff
+
+.globl _start
+_foo:
+ .quad 0x11223344
+ .quad _start - .
diff --git a/test/ELF/linkerscript/merge-sections.s b/test/ELF/linkerscript/merge-sections.s
new file mode 100644
index 000000000000..7252fe576674
--- /dev/null
+++ b/test/ELF/linkerscript/merge-sections.s
@@ -0,0 +1,94 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .foo : { begin = .; *(.foo.*) end = .;} \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -s -t %t1 | FileCheck %s
+
+# CHECK: Name: .foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_MERGE
+# CHECK-NEXT: SHF_STRINGS
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x[[ADDR1:.*]]
+# CHECK-NEXT: Offset: 0x[[ADDR1]]
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 1
+# CHECK-NEXT: EntrySize: 1
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index:
+# CHECK-NEXT: Name: .foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_MERGE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x
+# CHECK-NEXT: Offset: 0x
+# CHECK-NEXT: Size: 1
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 1
+# CHECK-NEXT: EntrySize: 1
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index:
+# CHECK-NEXT: Name: .foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_MERGE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x
+# CHECK-NEXT: Offset: 0x
+# CHECK-NEXT: Size: 2
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 2
+# CHECK-NEXT: EntrySize: 2
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index:
+# CHECK-NEXT: Name:
+# CHECK-NEXT: Type:
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_EXECINSTR
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x[[ADDR2:.*]]
+# CHECK-NEXT: Offset: 0x[[ADDR2]]
+
+
+# CHECK: Name: begin
+# CHECK-NEXT: Value: 0x[[ADDR1]]
+
+# CHECK: Name: end
+# CHECK-NEXT: Value: 0x[[ADDR2]]
+
+.section .foo.1a,"aMS",@progbits,1
+.asciz "foo"
+
+.section .foo.1b,"aMS",@progbits,1
+.asciz "foo"
+
+.section .foo.2a,"aM",@progbits,1
+.byte 42
+
+.section .foo.2b,"aM",@progbits,1
+.byte 42
+
+.section .foo.3a,"aM",@progbits,2
+.align 2
+.short 42
+
+.section .foo.3b,"aM",@progbits,2
+.align 2
+.short 42
diff --git a/test/ELF/linkerscript/multi-sections-constraint.s b/test/ELF/linkerscript/multi-sections-constraint.s
new file mode 100644
index 000000000000..bfedd10fc285
--- /dev/null
+++ b/test/ELF/linkerscript/multi-sections-constraint.s
@@ -0,0 +1,34 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: . = 0x1000; .aaa : ONLY_IF_RO { *(.aaa.*) } \
+# RUN: . = 0x2000; .aaa : ONLY_IF_RW { *(.aaa.*) } } " > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size Address Type
+# CHECK: .aaa 00000010 0000000000002000 DATA
+
+
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: . = 0x1000; .aaa : ONLY_IF_RW { *(.aaa.*) } \
+# RUN: . = 0x2000; .aaa : ONLY_IF_RO { *(.aaa.*) } } " > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t
+# RUN: llvm-objdump -section-headers %t2 | FileCheck %s --check-prefix=REV
+
+# REV: Sections:
+# REV-NEXT: Idx Name Size Address Type
+# REV: .aaa 00000010 0000000000001000 DATA
+
+.global _start
+_start:
+ nop
+
+.section .aaa.1, "aw"
+.quad 1
+
+.section .aaa.2, "aw"
+.quad 1
diff --git a/test/ELF/linkerscript/multiple-tbss.s b/test/ELF/linkerscript/multiple-tbss.s
new file mode 100644
index 000000000000..6bbbca92c239
--- /dev/null
+++ b/test/ELF/linkerscript/multiple-tbss.s
@@ -0,0 +1,45 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { }" > %t.script
+# RUN: ld.lld -T %t.script %t.o -o %t
+# RUN: llvm-readobj -l -s %t | FileCheck %s
+
+# CHECK: Name: .tbss
+# CHECK-NEXT: Type: SHT_NOBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_TLS
+# CHECK-NEXT: SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index:
+# CHECK-NEXT: Name: foo
+# CHECK-NEXT: Type: SHT_NOBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_TLS
+# CHECK-NEXT: SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 1
+
+# CHECK: Type: PT_TLS
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: VirtualAddress:
+# CHECK-NEXT: PhysicalAddress:
+# CHECK-NEXT: FileSize: 0
+# CHECK-NEXT: MemSize: 9
+
+.section .tbss,"awT",@nobits
+.quad 0
+.section foo,"awT",@nobits
+.byte 0
diff --git a/test/ELF/linkerscript/no-pt-load.s b/test/ELF/linkerscript/no-pt-load.s
new file mode 100644
index 000000000000..c70402501391
--- /dev/null
+++ b/test/ELF/linkerscript/no-pt-load.s
@@ -0,0 +1,5 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "PHDRS {foo PT_DYNAMIC ;} " \
+# RUN: "SECTIONS { .text : { *(.text) } : foo }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t.o
diff --git a/test/ELF/linkerscript/no-space.s b/test/ELF/linkerscript/no-space.s
new file mode 100644
index 000000000000..a96797269e43
--- /dev/null
+++ b/test/ELF/linkerscript/no-space.s
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS {foo 0 : {*(foo*)} }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o -shared
+# RUN: llvm-readobj -elf-output-style=GNU -l %t | FileCheck %s
+
+# RUN: echo "SECTIONS {foo : {*(foo*)} }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o -shared
+# RUN: llvm-readobj -elf-output-style=GNU -l %t | FileCheck %s
+
+# There is not enough address space available for the header, so just start the PT_LOAD
+# after it.
+
+# CHECK: Program Headers:
+# CHECK-NEXT: Type Offset VirtAddr PhysAddr
+# CHECK-NEXT: PHDR
+# CHECK-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000
+
+# CHECK: Section to Segment mapping:
+# CHECK-NEXT: Segment Sections...
+# CHECK-NEXT: 00
+# CHECK-NEXT: 01 foo .text .dynsym .hash .dynstr
+
+.section foo, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/non-alloc.s b/test/ELF/linkerscript/non-alloc.s
new file mode 100644
index 000000000000..2060129a8020
--- /dev/null
+++ b/test/ELF/linkerscript/non-alloc.s
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+
+# RUN: echo "SECTIONS { .foo 0 : {*(foo)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -elf-output-style=GNU -s -l %t1 | FileCheck %s
+
+# Test that we create all necessary PT_LOAD. We use to stop at the first
+# non-alloc, causing us to not create PT_LOAD for linker generated sections.
+
+# CHECK: Program Headers:
+# CHECK-NEXT: Type
+# CHECK-NEXT: PHDR
+# CHECK-NEXT: LOAD {{.*}} R E
+# CHECK-NEXT: LOAD {{.*}} RW
+
+# CHECK: Section to Segment mapping:
+# CHECK-NEXT: Segment Sections...
+# CHECK-NEXT: 00
+# CHECK-NEXT: 01 .text .dynsym .hash .dynstr
+# CHECK-NEXT: 02 .dynamic
+
+nop
+.section foo
+.quad 0
diff --git a/test/ELF/linkerscript/numbers.s b/test/ELF/linkerscript/numbers.s
new file mode 100644
index 000000000000..653f94bd4e6e
--- /dev/null
+++ b/test/ELF/linkerscript/numbers.s
@@ -0,0 +1,72 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: . = 1000h; \
+# RUN: .hex1 : { *(.hex.1) } \
+# RUN: . = 1010H; \
+# RUN: .hex2 : { *(.hex.2) } \
+# RUN: . = 10k; \
+# RUN: .kilo1 : { *(.kilo.1) } \
+# RUN: . = 11K; \
+# RUN: .kilo2 : { *(.kilo.2) } \
+# RUN: . = 1m; \
+# RUN: .mega1 : { *(.mega.1) } \
+# RUN: . = 2M; \
+# RUN: .mega2 : { *(.mega.2) } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-objdump -section-headers %t2 | FileCheck %s
+
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size Address
+# CHECK-NEXT: 0 00000000 0000000000000000
+# CHECK-NEXT: 1 .hex1 00000008 0000000000001000
+# CHECK-NEXT: 2 .hex2 00000008 0000000000001010
+# CHECK-NEXT: 3 .kilo1 00000008 0000000000002800
+# CHECK-NEXT: 4 .kilo2 00000008 0000000000002c00
+# CHECK-NEXT: 5 .mega1 00000008 0000000000100000
+# CHECK-NEXT: 6 .mega2 00000008 0000000000200000
+
+## Mailformed number errors.
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x11h; \
+# RUN: }" > %t2.script
+# RUN: not ld.lld %t --script %t2.script -o %t3 2>&1 | \
+# RUN: FileCheck --check-prefix=ERR1 %s
+# ERR1: malformed number: 0x11h
+
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x11k; \
+# RUN: }" > %t3.script
+# RUN: not ld.lld %t --script %t3.script -o %t4 2>&1 | \
+# RUN: FileCheck --check-prefix=ERR2 %s
+# ERR2: malformed number: 0x11k
+
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x11m; \
+# RUN: }" > %t4.script
+# RUN: not ld.lld %t --script %t4.script -o %t5 2>&1 | \
+# RUN: FileCheck --check-prefix=ERR3 %s
+# ERR3: malformed number: 0x11m
+
+.globl _start
+_start:
+nop
+
+.section .hex.1, "a"
+.quad 0
+
+.section .kilo.1, "a"
+.quad 0
+
+.section .mega.1, "a"
+.quad 0
+
+.section .hex.2, "a"
+.quad 0
+
+.section .kilo.2, "a"
+.quad 0
+
+.section .mega.2, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/openbsd-bootdata.s b/test/ELF/linkerscript/openbsd-bootdata.s
new file mode 100644
index 000000000000..3e90574bb3a3
--- /dev/null
+++ b/test/ELF/linkerscript/openbsd-bootdata.s
@@ -0,0 +1,7 @@
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+# RUN: echo "PHDRS { boot PT_OPENBSD_BOOTDATA; }" > %t.script
+# RUN: ld.lld --script %t.script %t.o -o %t
+# RUN: llvm-readobj --program-headers -s %t | FileCheck %s
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_OPENBSD_BOOTDATA (0x65A41BE6)
diff --git a/test/ELF/linkerscript/openbsd-randomize.s b/test/ELF/linkerscript/openbsd-randomize.s
new file mode 100644
index 000000000000..bf885f423b02
--- /dev/null
+++ b/test/ELF/linkerscript/openbsd-randomize.s
@@ -0,0 +1,23 @@
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+# RUN: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; rand PT_OPENBSD_RANDOMIZE; } \
+# RUN: SECTIONS { . = SIZEOF_HEADERS; \
+# RUN: .text : { *(.text) } \
+# RUN: .openbsd.randomdata : { *(.openbsd.randomdata) } : rand }" > %t.script
+# RUN: ld.lld --script %t.script %t.o -o %t
+# RUN: llvm-readobj --program-headers -s %t | FileCheck %s
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_OPENBSD_RANDOMIZE (0x65A3DBE6)
+# CHECK-NEXT: Offset: 0x74
+# CHECK-NEXT: VirtualAddress: 0x74
+# CHECK-NEXT: PhysicalAddress: 0x74
+# CHECK-NEXT: FileSize: 8
+# CHECK-NEXT: MemSize: 8
+# CHECK-NEXT: Flags [ (0x4)
+# CHECK-NEXT: PF_R (0x4)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 1
+# CHECK-NEXT: }
+
+.section .openbsd.randomdata, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/openbsd-wxneeded.s b/test/ELF/linkerscript/openbsd-wxneeded.s
new file mode 100644
index 000000000000..d371da9d8645
--- /dev/null
+++ b/test/ELF/linkerscript/openbsd-wxneeded.s
@@ -0,0 +1,17 @@
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+# RUN: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; wxneeded PT_OPENBSD_WXNEEDED; }" > %t.script
+# RUN: ld.lld -z wxneeded --script %t.script %t.o -o %t
+# RUN: llvm-readobj --program-headers %t | FileCheck %s
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_OPENBSD_WXNEEDED (0x65A3DBE7)
+# CHECK-NEXT: Offset: 0x0
+# CHECK-NEXT: VirtualAddress: 0x0
+# CHECK-NEXT: PhysicalAddress: 0x0
+# CHECK-NEXT: FileSize: 0
+# CHECK-NEXT: MemSize: 0
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 0
+# CHECK-NEXT: }
diff --git a/test/ELF/linkerscript/orphan-align.s b/test/ELF/linkerscript/orphan-align.s
new file mode 100644
index 000000000000..edd637b92820
--- /dev/null
+++ b/test/ELF/linkerscript/orphan-align.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .text : { *(.text) } \
+# RUN: . = ALIGN(0x1000); \
+# RUN: .data.rel.ro : { *(.data.rel.ro) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t -T %t.script %t.o -shared
+# RUN: llvm-readobj -l %t | FileCheck %s
+
+
+# Test that the orphan section foo is placed before the ALIGN and so the second
+# PT_LOAD is aligned.
+
+
+# CHECK: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x0
+
+# CHECK: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x1000
+
+nop
+.section .data.rel.ro, "aw"
+.byte 0
+
+.section foo, "ax"
+nop
diff --git a/test/ELF/linkerscript/orphan-first-cmd.s b/test/ELF/linkerscript/orphan-first-cmd.s
new file mode 100644
index 000000000000..3fb3b31b9a40
--- /dev/null
+++ b/test/ELF/linkerscript/orphan-first-cmd.s
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN: foo = 123; \
+# RUN: . = 0x1000; \
+# RUN: . = 0x2000; \
+# RUN: .bar : { . = . + 1; } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t -T %t.script %t.o -shared
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# CHECK: Name: .text
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_EXECINSTR
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x1000
diff --git a/test/ELF/linkerscript/orphan.s b/test/ELF/linkerscript/orphan.s
new file mode 100644
index 000000000000..3daa6fbf63c9
--- /dev/null
+++ b/test/ELF/linkerscript/orphan.s
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: .rw1 : { *(.rw1) } \
+# RUN: .rw2 : { *(.rw2) } \
+# RUN: .rw3 : { *(.rw3) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+## .jcr is a relro section and should be placed before other RW sections.
+## .bss is SHT_NOBITS section and should be last RW section, so some space
+## in ELF file could be saved.
+# CHECK: 0 00000000 0000000000000000
+# CHECK-NEXT: 1 .text 00000000 0000000000000000 TEXT DATA
+# CHECK-NEXT: 2 .jcr 00000008 0000000000000000 DATA
+# CHECK-NEXT: 3 .rw1 00000008 0000000000000008 DATA
+# CHECK-NEXT: 4 .rw2 00000008 0000000000000010 DATA
+# CHECK-NEXT: 5 .rw3 00000008 0000000000000018 DATA
+# CHECK-NEXT: 6 .bss 00000008 0000000000000020 BSS
+
+.section .rw1, "aw"
+ .quad 0
+
+.section .rw2, "aw"
+ .quad 0
+
+.section .rw3, "aw"
+ .quad 0
+
+.section .jcr, "aw"
+ .quad 0
+
+.section .bss, "aw",@nobits
+ .quad 0
diff --git a/test/ELF/linkerscript/orphans.s b/test/ELF/linkerscript/orphans.s
new file mode 100644
index 000000000000..0a8c7ab1129b
--- /dev/null
+++ b/test/ELF/linkerscript/orphans.s
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { .writable : { *(.writable) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN: FileCheck -check-prefix=TEXTORPHAN %s
+
+# RUN: echo "SECTIONS { .text : { *(.text) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN: FileCheck -check-prefix=WRITABLEORPHAN %s
+
+# TEXTORPHAN: Sections:
+# TEXTORPHAN-NEXT: Idx Name
+# TEXTORPHAN-NEXT: 0
+# TEXTORPHAN-NEXT: 1 .text
+# TEXTORPHAN-NEXT: 2 .writable
+
+# WRITABLEORPHAN: Sections:
+# WRITABLEORPHAN-NEXT: Idx Name
+# WRITABLEORPHAN-NEXT: 0
+# WRITABLEORPHAN-NEXT: 1 .text
+# WRITABLEORPHAN-NEXT: 2 .writable
+
+.global _start
+_start:
+ nop
+
+.section .writable,"aw"
+ .zero 4
diff --git a/test/ELF/linkerscript/ouputformat.s b/test/ELF/linkerscript/ouputformat.s
new file mode 100644
index 000000000000..7d4402a557a0
--- /dev/null
+++ b/test/ELF/linkerscript/ouputformat.s
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: echo "OUTPUT_FORMAT(x, y, z)" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
+# RUN: ld.lld -shared -o %t2 %t1 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "OUTPUT_FORMAT(x, y)" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
+# RUN: not ld.lld -shared -o %t2 %t1 %t.script
diff --git a/test/ELF/linkerscript/outputarch.s b/test/ELF/linkerscript/outputarch.s
new file mode 100644
index 000000000000..99089615cb17
--- /dev/null
+++ b/test/ELF/linkerscript/outputarch.s
@@ -0,0 +1,10 @@
+# REQUIRES: x86
+# RUN: echo "OUTPUT_ARCH(x)" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
+# RUN: ld.lld -shared -o %t2 %t1 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "OUTPUT_ARCH(x, y)" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
+# RUN: not ld.lld -shared -o %t2 %t1 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
diff --git a/test/ELF/linkerscript/outsections-addr.s b/test/ELF/linkerscript/outsections-addr.s
new file mode 100644
index 000000000000..003b2771c336
--- /dev/null
+++ b/test/ELF/linkerscript/outsections-addr.s
@@ -0,0 +1,122 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: .aaa 0x2000 : \
+# RUN: { \
+# RUN: *(.aaa) \
+# RUN: } \
+# RUN: .bbb 0x1 ? 0x3000 : 0x4000 : \
+# RUN: { \
+# RUN: *(.bbb) \
+# RUN: } \
+# RUN: .ccc ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : \
+# RUN: { \
+# RUN: *(.ccc) \
+# RUN: } \
+# RUN: .ddd 0x5001 : \
+# RUN: { \
+# RUN: *(.ddd) \
+# RUN: } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %tout
+# RUN: llvm-readobj -s %tout | FileCheck %s
+
+## Check:
+## 1) Simple constant as address.
+## 2) That something that contains ":" character, like ternary
+## operator works as expression.
+## 3) That complex expressions work.
+## 4) That section alignment still applied to explicitly specified address.
+
+#CHECK:Sections [
+#CHECK: Section {
+#CHECK: Index: 0
+#CHECK: Name:
+#CHECK: Type: SHT_NULL
+#CHECK: Flags [
+#CHECK: ]
+#CHECK: Address: 0x0
+#CHECK: Offset: 0x0
+#CHECK: Size: 0
+#CHECK: Link: 0
+#CHECK: Info: 0
+#CHECK: AddressAlignment: 0
+#CHECK: EntrySize: 0
+#CHECK: }
+#CHECK: Section {
+#CHECK: Index: 1
+#CHECK: Name: .aaa
+#CHECK: Type: SHT_PROGBITS
+#CHECK: Flags [
+#CHECK: SHF_ALLOC
+#CHECK: ]
+#CHECK: Address: 0x2000
+#CHECK: Offset: 0x1000
+#CHECK: Size: 8
+#CHECK: Link: 0
+#CHECK: Info: 0
+#CHECK: AddressAlignment: 1
+#CHECK: EntrySize: 0
+#CHECK: }
+#CHECK: Section {
+#CHECK: Index: 2
+#CHECK: Name: .bbb
+#CHECK: Type: SHT_PROGBITS
+#CHECK: Flags [
+#CHECK: SHF_ALLOC
+#CHECK: ]
+#CHECK: Address: 0x3000
+#CHECK: Offset: 0x2000
+#CHECK: Size: 8
+#CHECK: Link: 0
+#CHECK: Info: 0
+#CHECK: AddressAlignment: 1
+#CHECK: EntrySize: 0
+#CHECK: }
+#CHECK: Section {
+#CHECK: Index: 3
+#CHECK: Name: .ccc
+#CHECK: Type: SHT_PROGBITS
+#CHECK: Flags [
+#CHECK: SHF_ALLOC
+#CHECK: ]
+#CHECK: Address: 0x4008
+#CHECK: Offset: 0x3008
+#CHECK: Size: 8
+#CHECK: Link: 0
+#CHECK: Info: 0
+#CHECK: AddressAlignment: 1
+#CHECK: EntrySize: 0
+#CHECK: }
+#CHECK: Section {
+#CHECK: Index: 4
+#CHECK: Name: .ddd
+#CHECK: Type: SHT_PROGBITS
+#CHECK: Flags [
+#CHECK: SHF_ALLOC
+#CHECK: ]
+#CHECK: Address: 0x5010
+#CHECK: Offset: 0x4010
+#CHECK: Size: 8
+#CHECK: Link: 0
+#CHECK: Info: 0
+#CHECK: AddressAlignment: 16
+#CHECK: EntrySize: 0
+#CHECK: }
+
+.globl _start
+_start:
+nop
+
+.section .aaa, "a"
+.quad 0
+
+.section .bbb, "a"
+.quad 0
+
+.section .ccc, "a"
+.quad 0
+
+.section .ddd, "a"
+.align 16
+.quad 0
diff --git a/test/ELF/linkerscript/page-size-align.s b/test/ELF/linkerscript/page-size-align.s
new file mode 100644
index 000000000000..771bb13a8e6d
--- /dev/null
+++ b/test/ELF/linkerscript/page-size-align.s
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .text : { *(.text) } \
+# RUN: . = ALIGN(CONSTANT(MAXPAGESIZE)); \
+# RUN: . = . + 0x3000; \
+# RUN: .dynamic : { *(.dynamic) } \
+# RUN: }" > %t.script
+
+# RUN: ld.lld -T %t.script -z max-page-size=0x4000 %t.o -o %t.so -shared
+# RUN: llvm-readobj -s %t.so | FileCheck %s
+
+# CHECK: Name: .dynamic
+# CHECK-NEXT: Type: SHT_DYNAMIC
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x7000
+# CHECK-NEXT: Offset: 0x3000
diff --git a/test/ELF/linkerscript/page-size.s b/test/ELF/linkerscript/page-size.s
new file mode 100644
index 000000000000..3d97816a68ee
--- /dev/null
+++ b/test/ELF/linkerscript/page-size.s
@@ -0,0 +1,68 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: ld.lld -z max-page-size=0x4000 %t -o %t2
+# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
+
+# CHECK: ProgramHeaders [
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x0
+# CHECK-NEXT: VirtualAddress: 0x200000
+# CHECK-NEXT: PhysicalAddress: 0x200000
+# CHECK-NEXT: FileSize: 344
+# CHECK-NEXT: MemSize: 344
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 16384
+# CHECK-NEXT: }
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x4000
+# CHECK-NEXT: VirtualAddress: 0x204000
+# CHECK-NEXT: PhysicalAddress: 0x204000
+# CHECK-NEXT: FileSize: 1
+# CHECK-NEXT: MemSize: 1
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_X
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 16384
+# CHECK-NEXT: }
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x8000
+# CHECK-NEXT: VirtualAddress: 0x208000
+# CHECK-NEXT: PhysicalAddress: 0x208000
+# CHECK-NEXT: FileSize: 8
+# CHECK-NEXT: MemSize: 8
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_W
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 16384
+# CHECK-NEXT: }
+
+# RUN: echo "SECTIONS { \
+# RUN: symbol = CONSTANT(MAXPAGESIZE); \
+# RUN: }" > %t.script
+# RUN: ld.lld -z max-page-size=0x4000 -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck -check-prefix CHECK-SCRIPT %s
+
+# CHECK-SCRIPT: 0000000000004000 *ABS* 00000000 symbol
+
+# RUN: not ld.lld -z max-page-size=0x1001 -o %t1 --script %t.script %t 2>&1 \
+# RUN: | FileCheck -check-prefix=ERR1 %s
+# ERR1: max-page-size: value isn't a power of 2
+
+# RUN: not ld.lld -z max-page-size=-0x1000 -o %t1 --script %t.script %t 2>&1 \
+# RUN: | FileCheck -check-prefix=ERR2 %s
+# ERR2: invalid max-page-size: -0x1000
+
+.global _start
+_start:
+ nop
+
+.section .a, "aw"
+.quad 0
diff --git a/test/ELF/linkerscript/phdr-check.s b/test/ELF/linkerscript/phdr-check.s
new file mode 100644
index 000000000000..c7229ed3312c
--- /dev/null
+++ b/test/ELF/linkerscript/phdr-check.s
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { . = 0x10000000; .text : {*(.text.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+# CHECK: ProgramHeaders [
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_PHDR (0x6)
+# CHECK-NEXT: Offset: 0x40
+# CHECK-NEXT: VirtualAddress: 0xFFFF040
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript/phdrs-flags.s b/test/ELF/linkerscript/phdrs-flags.s
new file mode 100644
index 000000000000..3cb6432db09c
--- /dev/null
+++ b/test/ELF/linkerscript/phdrs-flags.s
@@ -0,0 +1,58 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS FLAGS (1 | 1 + 0x1);} \
+# RUN: SECTIONS { \
+# RUN: . = 0x10000200; \
+# RUN: .text : {*(.text*)} :all \
+# RUN: .foo : {*(.foo.*)} :all \
+# RUN: .data : {*(.data.*)} :all}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+
+# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS FLAGS (0x1);} \
+# RUN: SECTIONS { \
+# RUN: . = 0x10000200; \
+# RUN: .text : {*(.text*)} :all \
+# RUN: .foo : {*(.foo.*)} \
+# RUN: .data : {*(.data.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=DEFHDR %s
+
+# CHECK: ProgramHeaders [
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD (0x1)
+# CHECK-NEXT: Offset: 0x0
+# CHECK-NEXT: VirtualAddress: 0x10000000
+# CHECK-NEXT: PhysicalAddress: 0x10000000
+# CHECK-NEXT: FileSize: 521
+# CHECK-NEXT: MemSize: 521
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_W (0x2)
+# CHECK-NEXT: PF_X (0x1)
+# CHECK-NEXT: ]
+
+# DEFHDR: ProgramHeaders [
+# DEFHDR-NEXT: ProgramHeader {
+# DEFHDR-NEXT: Type: PT_LOAD (0x1)
+# DEFHDR-NEXT: Offset: 0x0
+# DEFHDR-NEXT: VirtualAddress: 0x10000000
+# DEFHDR-NEXT: PhysicalAddress: 0x10000000
+# DEFHDR-NEXT: FileSize: 521
+# DEFHDR-NEXT: MemSize: 521
+# DEFHDR-NEXT: Flags [ (0x1)
+# DEFHDR-NEXT: PF_X (0x1)
+# DEFHDR-NEXT: ]
+# DEFHDR-NEXT: Alignment: 4096
+# DEFHDR-NEXT: }
+
+.global _start
+_start:
+ nop
+
+.section .foo.1,"a"
+foo1:
+ .long 0
+
+.section .foo.2,"aw"
+foo2:
+ .long 0
diff --git a/test/ELF/linkerscript/phdrs.s b/test/ELF/linkerscript/phdrs.s
new file mode 100644
index 000000000000..a7476e802341
--- /dev/null
+++ b/test/ELF/linkerscript/phdrs.s
@@ -0,0 +1,143 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS ;} \
+# RUN: SECTIONS { \
+# RUN: . = 0x10000200; \
+# RUN: .text : {*(.text*)} :all \
+# RUN: .foo : {*(.foo.*)} :all \
+# RUN: .data : {*(.data.*)} :all}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+
+## Check that program headers are not written, unless we explicitly tell
+## lld to do this.
+# RUN: echo "PHDRS {all PT_LOAD;} \
+# RUN: SECTIONS { \
+# RUN: . = 0x10000200; \
+# RUN: /DISCARD/ : {*(.text*)} \
+# RUN: .foo : {*(.foo.*)} :all \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=NOPHDR %s
+
+## Check the AT(expr)
+# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS AT(0x500 + 0x500) ;} \
+# RUN: SECTIONS { \
+# RUN: . = 0x10000200; \
+# RUN: .text : {*(.text*)} :all \
+# RUN: .foo : {*(.foo.*)} :all \
+# RUN: .data : {*(.data.*)} :all}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=AT %s
+
+# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS ;} \
+# RUN: SECTIONS { \
+# RUN: . = 0x10000200; \
+# RUN: .text : {*(.text*)} :all \
+# RUN: .foo : {*(.foo.*)} \
+# RUN: .data : {*(.data.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=DEFHDR %s
+
+## Check that error is reported when trying to use phdr which is not listed
+## inside PHDRS {} block
+## TODO: If script doesn't contain PHDRS {} block then default phdr is always
+## created and error is not reported.
+# RUN: echo "PHDRS { all PT_LOAD; } \
+# RUN: SECTIONS { .baz : {*(.foo.*)} :bar }" > %t.script
+# RUN: not ld.lld -o %t1 --script %t.script %t 2>&1 | FileCheck --check-prefix=BADHDR %s
+
+# CHECK: ProgramHeaders [
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD (0x1)
+# CHECK-NEXT: Offset: 0x0
+# CHECK-NEXT: VirtualAddress: 0x10000000
+# CHECK-NEXT: PhysicalAddress: 0x10000000
+# CHECK-NEXT: FileSize: 521
+# CHECK-NEXT: MemSize: 521
+# CHECK-NEXT: Flags [ (0x7)
+# CHECK-NEXT: PF_R (0x4)
+# CHECK-NEXT: PF_W (0x2)
+# CHECK-NEXT: PF_X (0x1)
+# CHECK-NEXT: ]
+
+# NOPHDR: ProgramHeaders [
+# NOPHDR-NEXT: ProgramHeader {
+# NOPHDR-NEXT: Type: PT_LOAD (0x1)
+# NOPHDR-NEXT: Offset: 0x200
+# NOPHDR-NEXT: VirtualAddress: 0x10000200
+# NOPHDR-NEXT: PhysicalAddress: 0x10000200
+# NOPHDR-NEXT: FileSize: 8
+# NOPHDR-NEXT: MemSize: 8
+# NOPHDR-NEXT: Flags [ (0x6)
+# NOPHDR-NEXT: PF_R (0x4)
+# NOPHDR-NEXT: PF_W (0x2)
+# NOPHDR-NEXT: ]
+# NOPHDR-NEXT: Alignment: 4096
+# NOPHDR-NEXT: }
+# NOPHDR-NEXT: ]
+
+# AT: ProgramHeaders [
+# AT-NEXT: ProgramHeader {
+# AT-NEXT: Type: PT_LOAD (0x1)
+# AT-NEXT: Offset: 0x0
+# AT-NEXT: VirtualAddress: 0x10000000
+# AT-NEXT: PhysicalAddress: 0xA00
+# AT-NEXT: FileSize: 521
+# AT-NEXT: MemSize: 521
+# AT-NEXT: Flags [ (0x7)
+# AT-NEXT: PF_R (0x4)
+# AT-NEXT: PF_W (0x2)
+# AT-NEXT: PF_X (0x1)
+# AT-NEXT: ]
+
+## Check the numetic values for PHDRS.
+# RUN: echo "PHDRS {text PT_LOAD FILEHDR PHDRS; foo 0x11223344; } \
+# RUN: SECTIONS { . = SIZEOF_HEADERS; .foo : { *(.*) } : text : foo}" > %t1.script
+# RUN: ld.lld -o %t2 --script %t1.script %t
+# RUN: llvm-readobj -program-headers %t2 | FileCheck --check-prefix=INT-PHDRS %s
+
+# INT-PHDRS: ProgramHeaders [
+# INT-PHDRS: ProgramHeader {
+# INT-PHDRS: Type: (0x11223344)
+# INT-PHDRS-NEXT: Offset: 0xB0
+# INT-PHDRS-NEXT: VirtualAddress: 0xB0
+# INT-PHDRS-NEXT: PhysicalAddress: 0xB0
+# INT-PHDRS-NEXT: FileSize:
+# INT-PHDRS-NEXT: MemSize:
+# INT-PHDRS-NEXT: Flags [
+# INT-PHDRS-NEXT: PF_R
+# INT-PHDRS-NEXT: PF_W
+# INT-PHDRS-NEXT: PF_X
+# INT-PHDRS-NEXT: ]
+# INT-PHDRS-NEXT: Alignment:
+# INT-PHDRS-NEXT: }
+# INT-PHDRS-NEXT: ]
+
+# DEFHDR: ProgramHeaders [
+# DEFHDR-NEXT: ProgramHeader {
+# DEFHDR-NEXT: Type: PT_LOAD (0x1)
+# DEFHDR-NEXT: Offset: 0x0
+# DEFHDR-NEXT: VirtualAddress: 0x10000000
+# DEFHDR-NEXT: PhysicalAddress: 0x10000000
+# DEFHDR-NEXT: FileSize: 521
+# DEFHDR-NEXT: MemSize: 521
+# DEFHDR-NEXT: Flags [ (0x7)
+# DEFHDR-NEXT: PF_R (0x4)
+# DEFHDR-NEXT: PF_W (0x2)
+# DEFHDR-NEXT: PF_X (0x1)
+# DEFHDR-NEXT: ]
+
+# BADHDR: {{.*}}.script:1: section header 'bar' is not listed in PHDRS
+
+.global _start
+_start:
+ nop
+
+.section .foo.1,"a"
+foo1:
+ .long 0
+
+.section .foo.2,"aw"
+foo2:
+ .long 0
diff --git a/test/ELF/linkerscript/repsection-symbol.s b/test/ELF/linkerscript/repsection-symbol.s
new file mode 100644
index 000000000000..6786ac47255c
--- /dev/null
+++ b/test/ELF/linkerscript/repsection-symbol.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .text : { *(.text) } \
+# RUN: .foo : {foo1 = .; *(.foo.*) foo2 = .; *(.bar) foo3 = .;} \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -t %t1 | FileCheck %s
+
+# CHECK: Name: foo1
+# CHECK-NEXT: Value: 0x288
+
+# CHECK: Name: foo2
+# CHECK-NEXT: Value: 0x290
+
+# CHECK: Name: foo3
+# CHECK-NEXT: Value: 0x294
+
+.section .foo.1,"a"
+ .long 1
+
+.section .foo.2,"aw"
+ .long 2
+
+ .section .bar,"aw"
+ .long 3
diff --git a/test/ELF/linkerscript/repsection-va.s b/test/ELF/linkerscript/repsection-va.s
new file mode 100644
index 000000000000..8a50fc0998f9
--- /dev/null
+++ b/test/ELF/linkerscript/repsection-va.s
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {.foo : {*(.foo.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size Address Type
+# CHECK-NOT: .foo
+# CHECK: .foo 00000008 {{.*}} DATA
+# CHECK-NOT: .foo
+
+
+.global _start
+_start:
+ nop
+
+.section .foo.1,"a"
+foo1:
+ .long 0
+
+.section .foo.2,"aw"
+foo2:
+ .long 0
diff --git a/test/ELF/linkerscript/rosegment.s b/test/ELF/linkerscript/rosegment.s
new file mode 100644
index 000000000000..3201b8bda9fb
--- /dev/null
+++ b/test/ELF/linkerscript/rosegment.s
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Test that with linker scripts we don't create a RO PT_LOAD.
+
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -l %t1 | FileCheck %s
+
+# CHECK-NOT: Type: PT_LOAD
+
+# CHECK: Type: PT_LOAD
+# CHECK: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_X
+# CHECK-NEXT: ]
+
+# CHECK: Type: PT_LOAD
+# CHECK: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_W
+# CHECK-NEXT: ]
+
+# CHECK-NOT: Type: PT_LOAD
diff --git a/test/ELF/linkerscript/searchdir.s b/test/ELF/linkerscript/searchdir.s
new file mode 100644
index 000000000000..9fc1a6a49a90
--- /dev/null
+++ b/test/ELF/linkerscript/searchdir.s
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd \
+# RUN: %p/Inputs/libsearch-dyn.s -o %tdyn.o
+# RUN: mkdir -p %t.dir
+# RUN: ld.lld -shared %tdyn.o -o %t.dir/libls.so
+# RUN: echo "SEARCH_DIR(\"%t.dir\")" > %t.script
+# RUN: ld.lld -o %t2 --script %t.script -lls %t
+
+.globl _start,_bar
+_start:
diff --git a/test/ELF/linkerscript/sections-constraint.s b/test/ELF/linkerscript/sections-constraint.s
new file mode 100644
index 000000000000..4d95ec18336c
--- /dev/null
+++ b/test/ELF/linkerscript/sections-constraint.s
@@ -0,0 +1,46 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: .writable : ONLY_IF_RW { *(.writable) } \
+# RUN: .readable : ONLY_IF_RO { *(.readable) }}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN: FileCheck -check-prefix=BASE %s
+# BASE: Sections:
+# BASE-NEXT: Idx Name Size
+# BASE-NEXT: 0 00000000
+# BASE: .writable 00000004
+# BASE: .readable 00000004
+
+# RUN: echo "SECTIONS { \
+# RUN: .foo : ONLY_IF_RO { *(.foo.*) } \
+# RUN: .writable : ONLY_IF_RW { *(.writable) } \
+# RUN: .readable : ONLY_IF_RO { *(.readable) }}" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t
+# RUN: llvm-objdump -section-headers %t2 | \
+# RUN: FileCheck -check-prefix=NO1 %s
+# NO1: Sections:
+# NO1-NEXT: Idx Name Size
+# NO1-NEXT: 0 00000000
+# NO1: .writable 00000004
+# NO1: .foo.2 00000004
+# NO1: .readable 00000004
+# NO1: .foo.1 00000004
+
+.global _start
+_start:
+ nop
+
+.section .writable, "aw"
+writable:
+ .long 1
+
+.section .readable, "a"
+readable:
+ .long 2
+
+.section .foo.1, "awx"
+ .long 0
+
+.section .foo.2, "aw"
+ .long 0
diff --git a/test/ELF/linkerscript/sections-constraint2.s b/test/ELF/linkerscript/sections-constraint2.s
new file mode 100644
index 000000000000..e726365582d8
--- /dev/null
+++ b/test/ELF/linkerscript/sections-constraint2.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { zed : ONLY_IF_RO { *(foo) *(bar) } }" > %t.script
+# RUN: ld.lld -T %t.script %t.o -o %t.so -shared
+# RUN: llvm-readobj -s %t.so | FileCheck %s
+
+# CHECK: Sections [
+# CHECK-NOT: zed
+
+.section foo,"aw"
+.quad 1
+
+.section bar, "a"
+.quad 2
diff --git a/test/ELF/linkerscript/sections-constraint3.s b/test/ELF/linkerscript/sections-constraint3.s
new file mode 100644
index 000000000000..259f11e91dd1
--- /dev/null
+++ b/test/ELF/linkerscript/sections-constraint3.s
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { zed : ONLY_IF_RO { abc = 1; *(foo) } }" > %t.script
+# RUN: ld.lld -T %t.script %t.o -o %t.so -shared
+# RUN: llvm-readobj -t %t.so | FileCheck %s
+
+# CHECK: Symbols [
+# CHECK-NOT: abc
+
+.section foo,"aw"
+.quad 1
diff --git a/test/ELF/linkerscript/sections-constraint4.s b/test/ELF/linkerscript/sections-constraint4.s
new file mode 100644
index 000000000000..6c2d4c8e1ee4
--- /dev/null
+++ b/test/ELF/linkerscript/sections-constraint4.s
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN: .foo : ONLY_IF_RO { *(.foo) } \
+# RUN: .bar : {bar1 = .; *(.bar) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t
+# RUN: llvm-readobj -t %t1 | FileCheck %s
+
+# CHECK: Name: bar1
+
+.global _start
+_start:
+ nop
+
+.section .bar, "aw"
+bar:
+ .long 1
+
+.section .foo, "aw"
+ .long 0
diff --git a/test/ELF/linkerscript/sections-constraint5.s b/test/ELF/linkerscript/sections-constraint5.s
new file mode 100644
index 000000000000..ea14aad5247e
--- /dev/null
+++ b/test/ELF/linkerscript/sections-constraint5.s
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN: bar : ONLY_IF_RO { sym1 = .; *(foo*) } \
+# RUN: bar : ONLY_IF_RW { sym2 = .; *(foo*) } \
+# RUN: }" > %t.script
+
+# RUN: ld.lld -o %t -T %t.script %t.o
+# RUN: llvm-readobj -s -t %t | FileCheck %s
+
+# CHECK: Sections [
+# CHECK: Name: bar
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 2
+
+# CHECK: Symbols [
+# CHECK-NOT: sym1
+# CHECK: sym2
+# CHECK-NOT: sym1
+
+.section foo1,"a"
+.byte 0
+
+.section foo2,"aw"
+.byte 0
+
diff --git a/test/ELF/linkerscript/sections-keep.s b/test/ELF/linkerscript/sections-keep.s
new file mode 100644
index 000000000000..feb0baca9c3d
--- /dev/null
+++ b/test/ELF/linkerscript/sections-keep.s
@@ -0,0 +1,95 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/keep.s -o %t2.o
+
+## First check that section "keep" is garbage collected without using KEEP
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: .keep : { *(.keep) } \
+# RUN: .temp : { *(.temp) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN: FileCheck -check-prefix=SECGC %s
+# SECGC: Sections:
+# SECGC-NEXT: Idx Name Size
+# SECGC-NEXT: 0 00000000
+# SECGC-NEXT: 1 .text 00000007
+# SECGC-NEXT: 2 .temp 00000004
+
+## Now apply KEEP command to preserve the section.
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: .keep : { KEEP(*(.keep)) } \
+# RUN: .temp : { *(.temp) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN: FileCheck -check-prefix=SECNOGC %s
+# SECNOGC: Sections:
+# SECNOGC-NEXT: Idx Name Size
+# SECNOGC-NEXT: 0 00000000
+# SECNOGC-NEXT: 1 .text 00000007
+# SECNOGC-NEXT: 2 .keep 00000004
+# SECNOGC-NEXT: 3 .temp 00000004
+
+## A section name matches two entries in the SECTIONS directive. The
+## first one doesn't have KEEP, the second one does. If section that have
+## KEEP is the first in order then section is NOT collected.
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .keep : { KEEP(*(.keep)) } \
+# RUN: .nokeep : { *(.keep) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED1 %s
+# MIXED1: Sections:
+# MIXED1-NEXT: Idx Name Size
+# MIXED1-NEXT: 0 00000000
+# MIXED1-NEXT: 1 .keep 00000004
+# MIXED1-NEXT: 2 .text 00000007 00000000000000ec TEXT DATA
+# MIXED1-NEXT: 3 .temp 00000004 00000000000000f3 DATA
+# MIXED1-NEXT: 4 .comment 00000008 0000000000000000
+# MIXED1-NEXT: 5 .symtab 00000060 0000000000000000
+# MIXED1-NEXT: 6 .shstrtab 00000036 0000000000000000
+# MIXED1-NEXT: 7 .strtab 00000012 0000000000000000
+
+## The same, but now section without KEEP is at first place.
+## gold and bfd linkers disagree here. gold collects .keep while
+## bfd keeps it. Our current behavior is compatible with bfd although
+## we can choose either way.
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .nokeep : { *(.keep) } \
+# RUN: .keep : { KEEP(*(.keep)) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED2 %s
+# MIXED2: Sections:
+# MIXED2-NEXT: Idx Name Size
+# MIXED2-NEXT: 0 00000000
+# MIXED2-NEXT: 1 .nokeep 00000004 00000000000000e8 DATA
+# MIXED2-NEXT: 2 .text 00000007 00000000000000ec TEXT DATA
+# MIXED2-NEXT: 3 .temp 00000004 00000000000000f3 DATA
+# MIXED2-NEXT: 4 .comment 00000008 0000000000000000
+# MIXED2-NEXT: 5 .symtab 00000060 0000000000000000
+# MIXED2-NEXT: 6 .shstrtab 00000038 0000000000000000
+# MIXED2-NEXT: 7 .strtab 00000012 0000000000000000
+
+# Check file pattern for kept sections.
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .keep : { KEEP(*2.o(.keep)) } \
+# RUN: }" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t2.o %t
+# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=FILEMATCH %s
+# FILEMATCH: Contents of section .keep:
+# FILEMATCH-NEXT: 00e8 41414141 AAAA
+
+.global _start
+_start:
+ mov temp, %eax
+
+.section .keep, "a"
+keep:
+ .long 1
+
+.section .temp, "a"
+temp:
+ .long 2
diff --git a/test/ELF/linkerscript/sections-padding.s b/test/ELF/linkerscript/sections-padding.s
new file mode 100644
index 000000000000..51d3a88fadf6
--- /dev/null
+++ b/test/ELF/linkerscript/sections-padding.s
@@ -0,0 +1,49 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Check that padding value works:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x1122 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s
+# YES: 66001122 00001122 00001122 00001122
+
+## Confirming that address was correct:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99887766 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES2 %s
+# YES2: 66887766 99887766 99887766 99887766
+
+## Default padding value is 0x00:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=NO %s
+# NO: 66000000 00000000 00000000 00000000
+
+## Decimal value.
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =777 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=DEC %s
+# DEC: 66000309 00000309 00000309 00000309
+
+## Invalid hex value:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99XX }" > %t.script
+# RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 \
+# RUN: | FileCheck --check-prefix=ERR2 %s
+# ERR2: invalid filler expression: 0x99XX
+
+## Check case with space between '=' and expression:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } = 0x1122 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s
+
+.section .mysec.1,"a"
+.align 16
+.byte 0x66
+
+.section .mysec.2,"a"
+.align 16
+.byte 0x66
+
+.globl _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript/sections-sort.s b/test/ELF/linkerscript/sections-sort.s
new file mode 100644
index 000000000000..cf1fd3e57827
--- /dev/null
+++ b/test/ELF/linkerscript/sections-sort.s
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: foo : { *(foo) } \
+# RUN: } " > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o -shared
+# RUN: llvm-objdump --section-headers %t | FileCheck %s
+
+# Test the section order. This is a case where at least with libstdc++'s
+# stable_sort we used to get a different result.
+
+nop
+
+.section foo, "a"
+.byte 0
+
+# CHECK: Id
+# CHECK-NEXT: 0
+# CHECK-NEXT: 1 .text
+# CHECK-NEXT: 2 foo
+# CHECK-NEXT: 3 .dynsym
+# CHECK-NEXT: 4 .hash
+# CHECK-NEXT: 5 .dynstr
+# CHECK-NEXT: 6 .dynamic
+# CHECK-NEXT: 7 .comment
+# CHECK-NEXT: 8 .symtab
+# CHECK-NEXT: 9 .shstrtab
+# CHECK-NEXT: 10 .strtab
diff --git a/test/ELF/linkerscript/sections.s b/test/ELF/linkerscript/sections.s
new file mode 100644
index 000000000000..416e77346a59
--- /dev/null
+++ b/test/ELF/linkerscript/sections.s
@@ -0,0 +1,124 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Empty SECTIONS command.
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN: FileCheck -check-prefix=SEC-DEFAULT %s
+
+# SECTIONS command with the same order as default.
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: .data : { *(.data) } }" > %t.script
+# RUN: ld.lld -o %t2 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t2 | \
+# RUN: FileCheck -check-prefix=SEC-DEFAULT %s
+
+# Idx Name Size
+# SEC-DEFAULT: 1 .text 0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-DEFAULT: 2 .data 00000020 {{[0-9a-f]*}} DATA
+# SEC-DEFAULT: 3 other 00000003 {{[0-9a-f]*}} DATA
+# SEC-DEFAULT: 4 .bss 00000002 {{[0-9a-f]*}} BSS
+# SEC-DEFAULT: 5 .shstrtab 00000002 {{[0-9a-f]*}}
+# SEC-DEFAULT: 6 .comment 00000008 {{[0-9a-f]*}}
+# SEC-DEFAULT: 7 .symtab 00000030 {{[0-9a-f]*}}
+# SEC-DEFAULT: 8 .shstrtab 0000003b {{[0-9a-f]*}}
+# SEC-DEFAULT: 9 .strtab 00000008 {{[0-9a-f]*}}
+
+# Sections are put in order specified in linker script, other than alloc
+# sections going first.
+# RUN: echo "SECTIONS { \
+# RUN: .bss : { *(.bss) } \
+# RUN: other : { *(other) } \
+# RUN: .shstrtab : { *(.shstrtab) } \
+# RUN: .symtab : { *(.symtab) } \
+# RUN: .strtab : { *(.strtab) } \
+# RUN: .data : { *(.data) } \
+# RUN: .text : { *(.text) } }" > %t.script
+# RUN: ld.lld -o %t3 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t3 | \
+# RUN: FileCheck -check-prefix=SEC-ORDER %s
+
+# Idx Name Size
+# SEC-ORDER: 1 .bss 00000002 {{[0-9a-f]*}} BSS
+# SEC-ORDER: 2 other 00000003 {{[0-9a-f]*}} DATA
+# SEC-ORDER: 3 .shstrtab 00000002 {{[0-9a-f]*}}
+# SEC-ORDER: 4 .shstrtab 0000003b {{[0-9a-f]*}}
+# SEC-ORDER: 5 .symtab 00000030 {{[0-9a-f]*}}
+# SEC-ORDER: 6 .strtab 00000008 {{[0-9a-f]*}}
+# SEC-ORDER: 7 .data 00000020 {{[0-9a-f]*}} DATA
+# SEC-ORDER: 8 .text 0000000e {{[0-9a-f]*}} TEXT DATA
+
+# .text and .data have swapped names but proper sizes and types.
+# RUN: echo "SECTIONS { \
+# RUN: .data : { *(.text) } \
+# RUN: .text : { *(.data) } }" > %t.script
+# RUN: ld.lld -o %t4 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t4 | \
+# RUN: FileCheck -check-prefix=SEC-SWAP-NAMES %s
+
+# Idx Name Size
+# SEC-SWAP-NAMES: 1 .data 0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-SWAP-NAMES: 2 .text 00000020 {{[0-9a-f]*}} DATA
+# SEC-SWAP-NAMES: 3 other 00000003 {{[0-9a-f]*}} DATA
+# SEC-SWAP-NAMES: 4 .bss 00000002 {{[0-9a-f]*}} BSS
+# SEC-SWAP-NAMES: 5 .shstrtab 00000002 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 6 .comment 00000008 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 7 .symtab 00000030 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 8 .shstrtab 0000003b {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 9 .strtab 00000008 {{[0-9a-f]*}}
+
+# .shstrtab from the input object file is discarded.
+# RUN: echo "SECTIONS { \
+# RUN: /DISCARD/ : { *(.shstrtab) } }" > %t.script
+# RUN: ld.lld -o %t5 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t5 | \
+# RUN: FileCheck -check-prefix=SEC-DISCARD %s
+
+# Idx Name Size
+# SEC-DISCARD: 1 .text 0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-DISCARD: 2 .data 00000020 {{[0-9a-f]*}} DATA
+# SEC-DISCARD: 3 other 00000003 {{[0-9a-f]*}} DATA
+# SEC-DISCARD: 4 .bss 00000002 {{[0-9a-f]*}} BSS
+# SEC-DISCARD: 5 .comment 00000008 {{[0-9a-f]*}}
+# SEC-DISCARD: 6 .symtab 00000030 {{[0-9a-f]*}}
+# SEC-DISCARD: 7 .shstrtab 0000003b {{[0-9a-f]*}}
+# SEC-DISCARD: 8 .strtab 00000008 {{[0-9a-f]*}}
+
+# Multiple SECTIONS command specifying additional input section descriptions
+# for the same output section description - input sections are merged into
+# one output section.
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: .data : { *(.data) } } \
+# RUN: SECTIONS { \
+# RUN: .data : { *(other) } }" > %t.script
+# RUN: ld.lld -o %t6 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t6 | \
+# RUN: FileCheck -check-prefix=SEC-MULTI %s
+
+# Idx Name Size
+# SEC-MULTI: 1 .text 0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-MULTI: 2 .data 00000023 {{[0-9a-f]*}} DATA
+# SEC-MULTI: 3 .bss 00000002 {{[0-9a-f]*}} BSS
+# SEC-MULTI: 4 .shstrtab 00000002 {{[0-9a-f]*}}
+# SEC-MULTI: 5 .comment 00000008 {{[0-9a-f]*}}
+# SEC-MULTI: 6 .symtab 00000030 {{[0-9a-f]*}}
+# SEC-MULTI: 7 .shstrtab 00000035 {{[0-9a-f]*}}
+# SEC-MULTI: 8 .strtab 00000008 {{[0-9a-f]*}}
+
+.globl _start
+_start:
+ mov $60, %rax
+ mov $42, %rdi
+
+.section .data,"aw"
+.quad 10, 10, 20, 20
+.section other,"aw"
+.short 10
+.byte 20
+.section .shstrtab,""
+.short 20
+.section .bss,"",@nobits
+.short 0
diff --git a/test/ELF/linkerscript/segment-start.s b/test/ELF/linkerscript/segment-start.s
new file mode 100644
index 000000000000..e46c398f63f9
--- /dev/null
+++ b/test/ELF/linkerscript/segment-start.s
@@ -0,0 +1,27 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o %S/Inputs/segment-start.script -shared -o %t.so
+// RUN: llvm-readobj --dyn-symbols %t.so | FileCheck %s
+
+// CHECK: Name: foobar1
+// CHECK-NEXT: Value: 0x8001
+
+// CHECK: Name: foobar2
+// CHECK-NEXT: Value: 0x8002
+
+// CHECK: Name: foobar3
+// CHECK-NEXT: Value: 0x8003
+
+// CHECK: Name: foobar4
+// CHECK-NEXT: Value: 0x8004
+
+.data
+.quad foobar1
+.quad foobar2
+.quad foobar3
+.quad foobar4
+
+// RUN: echo "SECTIONS { . = SEGMENT_START(\"foobar\", foo); }" > %t.script
+// RUN: not ld.lld %t.o %t.script -shared -o %t2.so 2>&1 \
+// RUN: | FileCheck --check-prefix=ERR %s
+// ERR: {{.*}}.script:1: symbol not found: foo
diff --git a/test/ELF/linkerscript/sizeof.s b/test/ELF/linkerscript/sizeof.s
new file mode 100644
index 000000000000..4618f79d3db6
--- /dev/null
+++ b/test/ELF/linkerscript/sizeof.s
@@ -0,0 +1,53 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN: .aaa : { *(.aaa) } \
+# RUN: .bbb : { *(.bbb) } \
+# RUN: .ccc : { *(.ccc) } \
+# RUN: _aaa = SIZEOF(.aaa); \
+# RUN: _bbb = SIZEOF(.bbb); \
+# RUN: _ccc = SIZEOF(.ccc); \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t -section-headers %t1 | FileCheck %s
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size
+# CHECK-NEXT: 0 00000000
+# CHECK-NEXT: 1 .aaa 00000008
+# CHECK-NEXT: 2 .bbb 00000010
+# CHECK-NEXT: 3 .ccc 00000018
+# CHECK: SYMBOL TABLE:
+# CHECK-NEXT: 0000000000000000 *UND* 00000000
+# CHECK-NEXT: .text 00000000 _start
+# CHECK-NEXT: 0000000000000008 *ABS* 00000000 _aaa
+# CHECK-NEXT: 0000000000000010 *ABS* 00000000 _bbb
+# CHECK-NEXT: 0000000000000018 *ABS* 00000000 _ccc
+
+## SIZEOF(.nonexistent_section) should return 0.
+# RUN: echo "SECTIONS { \
+# RUN: .aaa : { *(.aaa) } \
+# RUN: .bbb : { *(.bbb) } \
+# RUN: .ccc : { *(.ccc) } \
+# RUN: _aaa = SIZEOF(.foo); \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t -section-headers %t1 | FileCheck -check-prefix=CHECK2 %s
+
+# CHECK2: 0000000000000000 *ABS* 00000000 _aaa
+
+.global _start
+_start:
+ nop
+
+.section .aaa,"a"
+ .quad 0
+
+.section .bbb,"a"
+ .quad 0
+ .quad 0
+
+.section .ccc,"a"
+ .quad 0
+ .quad 0
+ .quad 0
diff --git a/test/ELF/linkerscript/sizeofheaders.s b/test/ELF/linkerscript/sizeofheaders.s
new file mode 100644
index 000000000000..3cc70747280c
--- /dev/null
+++ b/test/ELF/linkerscript/sizeofheaders.s
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo " SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: _size = SIZEOF_HEADERS; \
+# RUN: .text : {*(.text*)} \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+
+#CHECK: SYMBOL TABLE:
+#CHECK-NEXT: 0000000000000000 *UND* 00000000
+#CHECK-NEXT: 00000000000000e8 .text 00000000 _start
+#CHECK-NEXT: 00000000000000e8 *ABS* 00000000 _size
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript/sort-constructors.s b/test/ELF/linkerscript/sort-constructors.s
new file mode 100644
index 000000000000..a0c23af6de79
--- /dev/null
+++ b/test/ELF/linkerscript/sort-constructors.s
@@ -0,0 +1,5 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: echo "SECTIONS { .aaa : { SORT(CONSTRUCTORS) } }" > %t1.script
+# RUN: ld.lld -shared -o %t1 --script %t1.script %t1.o
+# RUN: llvm-readobj %t1 > /dev/null
diff --git a/test/ELF/linkerscript/sort-init.s b/test/ELF/linkerscript/sort-init.s
new file mode 100644
index 000000000000..894b8ae882b7
--- /dev/null
+++ b/test/ELF/linkerscript/sort-init.s
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: echo "SECTIONS { .init_array : { *(SORT_BY_INIT_PRIORITY(.init_array.*)) } }" > %t1.script
+# RUN: ld.lld --script %t1.script %t1.o -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck %s
+
+# CHECK: Contents of section .init_array:
+# CHECK-NEXT: 03020000 00000000 010405
+
+.globl _start
+_start:
+ nop
+
+.section .init_array, "aw", @init_array
+ .align 8
+ .byte 1
+.section .init_array.100, "aw", @init_array
+ .long 2
+.section .init_array.5, "aw", @init_array
+ .byte 3
+.section .init_array, "aw", @init_array
+ .byte 4
+.section .init_array, "aw", @init_array
+ .byte 5
diff --git a/test/ELF/linkerscript/sort-nested.s b/test/ELF/linkerscript/sort-nested.s
new file mode 100644
index 000000000000..fb1d1a3dd070
--- /dev/null
+++ b/test/ELF/linkerscript/sort-nested.s
@@ -0,0 +1,50 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/sort-nested.s -o %t2.o
+
+## Check sorting first by alignment and then by name.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.aaa.*))) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=SORTED_AN %s
+# SORTED_AN: Contents of section .aaa:
+# SORTED_AN-NEXT: 01000000 00000000 00000000 00000000
+# SORTED_AN-NEXT: 11000000 00000000 00000000 00000000
+# SORTED_AN-NEXT: 55000000 00000000 22000000 00000000
+# SORTED_AN-NEXT: 02000000 00000000
+
+## Check sorting first by name and then by alignment.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_NAME(SORT_BY_ALIGNMENT(.aaa.*))) } }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SORTED_NA %s
+# SORTED_NA: Contents of section .aaa:
+# SORTED_NA: 01000000 00000000 00000000 00000000
+# SORTED_NA: 11000000 00000000 22000000 00000000
+# SORTED_NA: 02000000 00000000 00000000 00000000
+# SORTED_NA: 55000000 00000000
+
+## If the section sorting command in linker script isn't nested, the
+## command line option will make the section sorting command to be treated
+## as nested sorting command.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_ALIGNMENT(.aaa.*)) } }" > %t3.script
+# RUN: ld.lld --sort-section name -o %t3 --script %t3.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t3 | FileCheck -check-prefix=SORTED_AN %s
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_NAME(.aaa.*)) } }" > %t4.script
+# RUN: ld.lld --sort-section alignment -o %t4 --script %t4.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t4 | FileCheck -check-prefix=SORTED_NA %s
+
+.global _start
+_start:
+ nop
+
+.section .aaa.1, "a"
+.align 32
+.quad 1
+
+.section .aaa.2, "a"
+.align 2
+.quad 2
+
+.section .aaa.5, "a"
+.align 16
+.quad 0x55
diff --git a/test/ELF/linkerscript/sort-non-script.s b/test/ELF/linkerscript/sort-non-script.s
new file mode 100644
index 000000000000..75a2d450adcc
--- /dev/null
+++ b/test/ELF/linkerscript/sort-non-script.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+
+# RUN: echo "SECTIONS { foo : {*(foo)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -elf-output-style=GNU -s %t1 | FileCheck %s
+
+# CHECK: .text {{.*}} AX
+# CHECK-NEXT: .dynsym {{.*}} A
+# CHECK-NEXT: .hash {{.*}} A
+# CHECK-NEXT: .dynstr {{.*}} A
+# CHECK-NEXT: .dynamic {{.*}} WA
+# CHECK-NEXT: foo {{.*}} WA
+
+.section foo, "aw"
+.byte 0
diff --git a/test/ELF/linkerscript/sort.s b/test/ELF/linkerscript/sort.s
new file mode 100644
index 000000000000..6390ced12289
--- /dev/null
+++ b/test/ELF/linkerscript/sort.s
@@ -0,0 +1,120 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/sort.s -o %t2.o
+
+# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=UNSORTED %s
+# UNSORTED: Contents of section .aaa:
+# UNSORTED-NEXT: 55000000 00000000 00000000 00000000
+# UNSORTED-NEXT: 00000000 00000000 00000000 00000000
+# UNSORTED-NEXT: 11000000 00000000 33000000 00000000
+# UNSORTED-NEXT: 22000000 00000000 44000000 00000000
+# UNSORTED-NEXT: 05000000 00000000 01000000 00000000
+# UNSORTED-NEXT: 03000000 00000000 02000000 00000000
+# UNSORTED-NEXT: 04000000 00000000
+
+## Check that SORT works (sorted by name of section).
+# RUN: echo "SECTIONS { .aaa : { *(SORT(.aaa.*)) } }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SORTED_A %s
+# SORTED_A: Contents of section .aaa:
+# SORTED_A-NEXT: 11000000 00000000 01000000 00000000
+# SORTED_A-NEXT: 22000000 00000000 02000000 00000000
+# SORTED_A-NEXT: 33000000 00000000 03000000 00000000
+# SORTED_A-NEXT: 44000000 00000000 00000000 00000000
+# SORTED_A-NEXT: 04000000 00000000 55000000 00000000
+# SORTED_A-NEXT: 00000000 00000000 00000000 00000000
+# SORTED_A-NEXT: 05000000 00000000
+
+## When we switch the order of files, check that sorting by
+## section names is stable.
+# RUN: echo "SECTIONS { .aaa : { *(SORT(.aaa.*)) } }" > %t3.script
+# RUN: ld.lld -o %t3 --script %t3.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t3 | FileCheck -check-prefix=SORTED_B %s
+# SORTED_B: Contents of section .aaa:
+# SORTED_B-NEXT: 01000000 00000000 00000000 00000000
+# SORTED_B-NEXT: 00000000 00000000 00000000 00000000
+# SORTED_B-NEXT: 11000000 00000000 02000000 00000000
+# SORTED_B-NEXT: 22000000 00000000 03000000 00000000
+# SORTED_B-NEXT: 33000000 00000000 00000000 00000000
+# SORTED_B-NEXT: 04000000 00000000 44000000 00000000
+# SORTED_B-NEXT: 05000000 00000000 55000000 00000000
+
+## Check that SORT surrounded with KEEP also works.
+# RUN: echo "SECTIONS { .aaa : { KEEP (*(SORT(.aaa.*))) } }" > %t3.script
+# RUN: ld.lld -o %t3 --script %t3.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t3 | FileCheck -check-prefix=SORTED_A %s
+
+## Check that SORT_BY_NAME works (SORT is alias).
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_NAME(.aaa.*)) } }" > %t4.script
+# RUN: ld.lld -o %t4 --script %t4.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t4 | FileCheck -check-prefix=SORTED_A %s
+
+## Check that sections ordered by alignment.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_ALIGNMENT(.aaa.*)) } }" > %t5.script
+# RUN: ld.lld -o %t5 --script %t5.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t5 | FileCheck -check-prefix=SORTED_ALIGNMENT %s
+# SORTED_ALIGNMENT: Contents of section .aaa:
+# SORTED_ALIGNMENT-NEXT: 05000000 00000000 00000000 00000000
+# SORTED_ALIGNMENT-NEXT: 00000000 00000000 00000000 00000000
+# SORTED_ALIGNMENT-NEXT: 11000000 00000000 00000000 00000000
+# SORTED_ALIGNMENT-NEXT: 04000000 00000000 00000000 00000000
+# SORTED_ALIGNMENT-NEXT: 22000000 00000000 03000000 00000000
+# SORTED_ALIGNMENT-NEXT: 33000000 00000000 02000000 00000000
+# SORTED_ALIGNMENT-NEXT: 44000000 00000000 01000000 00000000
+# SORTED_ALIGNMENT-NEXT: 55000000 00000000
+
+## SORT_NONE itself does not sort anything.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_NONE(.aaa.*)) } }" > %t6.script
+# RUN: ld.lld -o %t7 --script %t6.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t7 | FileCheck -check-prefix=UNSORTED %s
+
+## Check --sort-section alignment option.
+# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t7.script
+# RUN: ld.lld --sort-section alignment -o %t8 --script %t7.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t8 | FileCheck -check-prefix=SORTED_ALIGNMENT %s
+
+## Check --sort-section= form.
+# RUN: ld.lld --sort-section=alignment -o %t8_1 --script %t7.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t8_1 | FileCheck -check-prefix=SORTED_ALIGNMENT %s
+
+## Check --sort-section name option.
+# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t8.script
+# RUN: ld.lld --sort-section name -o %t9 --script %t8.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t9 | FileCheck -check-prefix=SORTED_B %s
+
+## SORT_NONE disables the --sort-section.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_NONE(.aaa.*)) } }" > %t9.script
+# RUN: ld.lld --sort-section name -o %t10 --script %t9.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t10 | FileCheck -check-prefix=UNSORTED %s
+
+## SORT_NONE as a inner sort directive.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_NAME(SORT_NONE(.aaa.*))) } }" > %t10.script
+# RUN: ld.lld -o %t11 --script %t10.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t11 | FileCheck -check-prefix=SORTED_A %s
+
+.global _start
+_start:
+ nop
+
+.section .aaa.5, "a"
+.align 32
+.quad 5
+
+.section .aaa.1, "a"
+.align 2
+.quad 1
+
+.section .aaa.3, "a"
+.align 8
+.quad 3
+
+.section .aaa.2, "a"
+.align 4
+.quad 2
+
+.section .aaa.4, "a"
+.align 16
+.quad 4
diff --git a/test/ELF/linkerscript/sort2.s b/test/ELF/linkerscript/sort2.s
new file mode 100644
index 000000000000..1d42093d5aa0
--- /dev/null
+++ b/test/ELF/linkerscript/sort2.s
@@ -0,0 +1,39 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfile1.o
+
+# RUN: echo "SECTIONS { .abc : { *(SORT(.foo.*) .bar.*) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %tfile1.o
+# RUN: llvm-objdump -s %t1 | FileCheck %s
+
+# CHECK: Contents of section .abc:
+# CHECK: 01000000 00000000 02000000 00000000
+# CHECK: 03000000 00000000 04000000 00000000
+# CHECK: 06000000 00000000 05000000 00000000
+
+# RUN: echo "SECTIONS { \
+# RUN: .abc : { *(SORT(.foo.* EXCLUDE_FILE (*file1.o) .bar.*) .bar.*) } \
+# RUN: }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %tfile1.o
+# RUN: llvm-objdump -s %t2 | FileCheck %s
+
+.text
+.globl _start
+_start:
+
+.section .foo.2,"a"
+ .quad 2
+
+.section .foo.3,"a"
+ .quad 3
+
+.section .foo.1,"a"
+ .quad 1
+
+.section .bar.4,"a"
+ .quad 4
+
+.section .bar.6,"a"
+ .quad 6
+
+.section .bar.5,"a"
+ .quad 5
diff --git a/test/ELF/linkerscript/start-end.s b/test/ELF/linkerscript/start-end.s
new file mode 100644
index 000000000000..b68606abc181
--- /dev/null
+++ b/test/ELF/linkerscript/start-end.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN: .init_array : { \
+# RUN: __init_array_start = .; \
+# RUN: *(.init_array) \
+# RUN: __init_array_end = .; } }" > %t.script
+# RUN: ld.lld %t.o -script %t.script -o %t 2>&1
+
+.globl _start
+.text
+_start:
+ nop
+
+.section .init_array, "aw"
+ .quad 0
diff --git a/test/ELF/linkerscript/subalign.s b/test/ELF/linkerscript/subalign.s
new file mode 100644
index 000000000000..8b441d440b0e
--- /dev/null
+++ b/test/ELF/linkerscript/subalign.s
@@ -0,0 +1,43 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+
+# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t1.o
+# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=NOALIGN %s
+# NOALIGN: Contents of section .aaa:
+# NOALIGN-NEXT: 01000000 00000000 00000000 00000000
+# NOALIGN-NEXT: 00000000 00000000 00000000 00000000
+# NOALIGN-NEXT: 02000000 00000000 00000000 00000000
+# NOALIGN-NEXT: 00000000 00000000 00000000 00000000
+# NOALIGN-NEXT: 03000000 00000000 00000000 00000000
+# NOALIGN-NEXT: 00000000 00000000 00000000 00000000
+# NOALIGN-NEXT: 00000000 00000000 00000000 00000000
+# NOALIGN-NEXT: 00000000 00000000 00000000 00000000
+# NOALIGN-NEXT: 04000000 00000000
+
+# RUN: echo "SECTIONS { .aaa : SUBALIGN(1) { *(.aaa.*) } }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t1.o
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SUBALIGN %s
+# SUBALIGN: Contents of section .aaa:
+# SUBALIGN: 01000000 00000000 02000000 00000000
+# SUBALIGN: 03000000 00000000 04000000 00000000
+
+.global _start
+_start:
+ nop
+
+.section .aaa.1, "a"
+.align 16
+.quad 1
+
+.section .aaa.2, "a"
+.align 32
+.quad 2
+
+.section .aaa.3, "a"
+.align 64
+.quad 3
+
+.section .aaa.4, "a"
+.align 128
+.quad 4
diff --git a/test/ELF/linkerscript/symbol-assignexpr.s b/test/ELF/linkerscript/symbol-assignexpr.s
new file mode 100644
index 000000000000..b988abcdfe98
--- /dev/null
+++ b/test/ELF/linkerscript/symbol-assignexpr.s
@@ -0,0 +1,48 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN: symbol = CONSTANT(MAXPAGESIZE); \
+# RUN: symbol2 = symbol + 0x1234; \
+# RUN: symbol3 = symbol2; \
+# RUN: symbol4 = symbol + -4; \
+# RUN: symbol5 = symbol - ~ 0xfffb; \
+# RUN: symbol6 = symbol - ~(0xfff0 + 0xb); \
+# RUN: symbol7 = symbol - ~ 0xfffb + 4; \
+# RUN: symbol8 = ~ 0xffff + 4; \
+# RUN: symbol9 = - 4; \
+# RUN: symbol10 = 0xfedcba9876543210; \
+# RUN: symbol11 = ((0x28000 + 0x1fff) & ~(0x1000 + -1)); \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+
+# CHECK: SYMBOL TABLE:
+# CHECK-NEXT: 0000000000000000 *UND* 00000000
+# CHECK-NEXT: .text 00000000 _start
+# CHECK-NEXT: .text 00000000 foo
+# CHECK-NEXT: 0000000000001000 *ABS* 00000000 symbol
+# CHECK-NEXT: 0000000000002234 *ABS* 00000000 symbol2
+# CHECK-NEXT: 0000000000002234 *ABS* 00000000 symbol3
+# CHECK-NEXT: 0000000000000ffc *ABS* 00000000 symbol4
+# CHECK-NEXT: 0000000000010ffc *ABS* 00000000 symbol5
+# CHECK-NEXT: 0000000000010ffc *ABS* 00000000 symbol6
+# CHECK-NEXT: 0000000000011000 *ABS* 00000000 symbol7
+# CHECK-NEXT: ffffffffffff0004 *ABS* 00000000 symbol8
+# CHECK-NEXT: fffffffffffffffc *ABS* 00000000 symbol9
+# CHECK-NEXT: fedcba9876543210 *ABS* 00000000 symbol10
+# CHECK-NEXT: 0000000000029000 *ABS* 00000000 symbol11
+
+# RUN: echo "SECTIONS { \
+# RUN: symbol2 = symbol; \
+# RUN: }" > %t2.script
+# RUN: not ld.lld -o %t2 --script %t2.script %t 2>&1 \
+# RUN: | FileCheck -check-prefix=ERR %s
+# ERR: {{.*}}.script:1: symbol not found: symbol
+
+.global _start
+_start:
+ nop
+
+.global foo
+foo:
diff --git a/test/ELF/linkerscript/symbol-conflict.s b/test/ELF/linkerscript/symbol-conflict.s
new file mode 100644
index 000000000000..dcca7c13de6e
--- /dev/null
+++ b/test/ELF/linkerscript/symbol-conflict.s
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .text : {*(.text.*)} end = .;}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+# CHECK: 00000000000000e9 .text 00000000 end
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript/symbol-only.s b/test/ELF/linkerscript/symbol-only.s
new file mode 100644
index 000000000000..76d54f01cdc7
--- /dev/null
+++ b/test/ELF/linkerscript/symbol-only.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: abc : { foo = .; } \
+# RUN: . = ALIGN(0x1000); \
+# RUN: bar : { *(bar) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-objdump -section-headers -t %t1 | FileCheck %s
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size Address
+# CHECK-NEXT: 0 00000000 0000000000000000
+# CHECK: abc 00000000 [[ADDR:[0-9a-f]*]] BSS
+# CHECK-NEXT: bar 00000000 0000000000001000 DATA
+
+# CHECK: SYMBOL TABLE:
+# CHECK: [[ADDR]] abc 00000000 foo
+
+.section bar, "a"
diff --git a/test/ELF/linkerscript/symbolreferenced.s b/test/ELF/linkerscript/symbolreferenced.s
new file mode 100644
index 000000000000..c2925b179ad5
--- /dev/null
+++ b/test/ELF/linkerscript/symbolreferenced.s
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Provide new symbol. The value should be 1, like set in PROVIDE()
+# RUN: echo "SECTIONS { PROVIDE(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE1 %s
+# PROVIDE1: 0000000000000001 *ABS* 00000000 newsym
+
+# Provide new symbol (hidden). The value should be 1
+# RUN: echo "SECTIONS { PROVIDE_HIDDEN(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN1 %s
+# HIDDEN1: 0000000000000001 *ABS* 00000000 .hidden newsym
+
+.global _start
+_start:
+ nop
+
+.globl patatino
+patatino:
+ movl newsym, %eax
diff --git a/test/ELF/linkerscript/symbols-synthetic.s b/test/ELF/linkerscript/symbols-synthetic.s
new file mode 100644
index 000000000000..95cdae9a929e
--- /dev/null
+++ b/test/ELF/linkerscript/symbols-synthetic.s
@@ -0,0 +1,98 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# Simple symbol assignment within input section list. The '.' symbol
+# is not location counter but offset from the beginning of output
+# section .foo
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .foo : { \
+# RUN: begin_foo = .; \
+# RUN: PROVIDE(_begin_sec = .); \
+# RUN: *(.foo) \
+# RUN: end_foo = .; \
+# RUN: PROVIDE_HIDDEN(_end_sec = .); \
+# RUN: PROVIDE(_end_sec_abs = ABSOLUTE(.)); \
+# RUN: size_foo_1 = SIZEOF(.foo); \
+# RUN: size_foo_1_abs = ABSOLUTE(SIZEOF(.foo)); \
+# RUN: . = ALIGN(0x1000); \
+# RUN: begin_bar = .; \
+# RUN: *(.bar) \
+# RUN: end_bar = .; \
+# RUN: size_foo_2 = SIZEOF(.foo); } \
+# RUN: size_foo_3 = SIZEOF(.foo); \
+# RUN: .eh_frame_hdr : { \
+# RUN: __eh_frame_hdr_start = .; \
+# RUN: __eh_frame_hdr_start2 = ABSOLUTE(ALIGN(0x10)); \
+# RUN: *(.eh_frame_hdr) \
+# RUN: __eh_frame_hdr_end = .; \
+# RUN: __eh_frame_hdr_end2 = ABSOLUTE(ALIGN(0x10)); } \
+# RUN: .eh_frame : { } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s
+
+# Check that the following script is processed without errors
+# RUN: echo "SECTIONS { \
+# RUN: .eh_frame_hdr : { \
+# RUN: PROVIDE_HIDDEN(_begin_sec = .); \
+# RUN: *(.eh_frame_hdr) \
+# RUN: *(.eh_frame_hdr) \
+# RUN: PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.)); \
+# RUN: PROVIDE_HIDDEN(_end_sec = .); } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+
+# Check that we can specify synthetic symbols without defining SECTIONS.
+# RUN: echo "PROVIDE_HIDDEN(_begin_sec = _start); \
+# RUN: PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text));" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=NO-SEC %s
+
+# Check that we can do the same as above inside SECTIONS block.
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x201000; \
+# RUN: .text : { *(.text) } \
+# RUN: PROVIDE_HIDDEN(_begin_sec = ADDR(.text)); \
+# RUN: PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text)); }" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=IN-SEC %s
+
+# SIMPLE: 0000000000000128 .foo 00000000 .hidden _end_sec
+# SIMPLE-NEXT: 0000000000000120 .foo 00000000 _begin_sec
+# SIMPLE-NEXT: 0000000000000128 *ABS* 00000000 _end_sec_abs
+# SIMPLE-NEXT: 0000000000001048 .text 00000000 _start
+# SIMPLE-NEXT: 0000000000000120 .foo 00000000 begin_foo
+# SIMPLE-NEXT: 0000000000000128 .foo 00000000 end_foo
+# SIMPLE-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1
+# SIMPLE-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1_abs
+# SIMPLE-NEXT: 0000000000001000 .foo 00000000 begin_bar
+# SIMPLE-NEXT: 0000000000001004 .foo 00000000 end_bar
+# SIMPLE-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_2
+# SIMPLE-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_3
+# SIMPLE-NEXT: 0000000000001004 .eh_frame_hdr 00000000 __eh_frame_hdr_start
+# SIMPLE-NEXT: 0000000000001010 *ABS* 00000000 __eh_frame_hdr_start2
+# SIMPLE-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end
+# SIMPLE-NEXT: 0000000000001020 *ABS* 00000000 __eh_frame_hdr_end2
+
+# NO-SEC: 0000000000201000 .text 00000000 .hidden _begin_sec
+# NO-SEC-NEXT: 0000000000201001 .text 00000000 .hidden _end_sec
+
+# IN-SEC: 0000000000201000 .text 00000000 .hidden _begin_sec
+# IN-SEC-NEXT: 0000000000201001 .text 00000000 .hidden _end_sec
+
+.global _start
+_start:
+ nop
+
+.section .foo,"a"
+ .quad 0
+
+.section .bar,"a"
+ .long 0
+
+.section .dah,"ax",@progbits
+ .cfi_startproc
+ nop
+ .cfi_endproc
+
+.global _begin_sec, _end_sec, _end_sec_abs
diff --git a/test/ELF/linkerscript/symbols.s b/test/ELF/linkerscript/symbols.s
new file mode 100644
index 000000000000..4656635171c8
--- /dev/null
+++ b/test/ELF/linkerscript/symbols.s
@@ -0,0 +1,84 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Simple symbol assignment. Should raise conflict in case we
+# have duplicates in any input section, but currently simply
+# replaces the value.
+# RUN: echo "SECTIONS {.text : {*(.text.*)} text_end = .;}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s
+# SIMPLE: .text 00000000 text_end
+
+# The symbol is not referenced. Don't provide it.
+# RUN: echo "SECTIONS { PROVIDE(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE1 %s
+# PROVIDE1-NOT: 0000000000000001 *ABS* 00000000 newsym
+
+# The symbol is not referenced. Don't provide it.
+# RUN: echo "SECTIONS { PROVIDE_HIDDEN(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN1 %s
+# HIDDEN1-NOT: 0000000000000001 *ABS* 00000000 .hidden newsym
+
+# Provide existing symbol. The value should be 0, even though we
+# have value of 1 in PROVIDE()
+# RUN: echo "SECTIONS { PROVIDE(somesym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE2 %s
+# PROVIDE2: 0000000000000000 *ABS* 00000000 somesym
+
+# Provide existing symbol. The value should be 0, even though we
+# have value of 1 in PROVIDE_HIDDEN(). Visibility should not change
+# RUN: echo "SECTIONS { PROVIDE_HIDDEN(somesym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN2 %s
+# HIDDEN2: 0000000000000000 *ABS* 00000000 somesym
+
+# Hidden symbol assignment.
+# RUN: echo "SECTIONS { HIDDEN(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN3 %s
+# HIDDEN3: 0000000000000001 *ABS* 00000000 .hidden newsym
+
+# The symbol is not referenced. Don't provide it.
+# RUN: echo "PROVIDE(newsym = 1);" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE4 %s
+# PROVIDE4-NOT: 0000000000000001 *ABS* 00000000 newsym
+
+# The symbol is not referenced. Don't provide it.
+# RUN: echo "PROVIDE_HIDDEN(newsym = 1);" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN4 %s
+# HIDDEN4-NOT: 0000000000000001 *ABS* 00000000 .hidden newsym
+
+# Provide existing symbol. The value should be 0, even though we
+# have value of 1 in PROVIDE()
+# RUN: echo "PROVIDE(somesym = 1);" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE5 %s
+# PROVIDE5: 0000000000000000 *ABS* 00000000 somesym
+
+# Provide existing symbol. The value should be 0, even though we
+# have value of 1 in PROVIDE_HIDDEN(). Visibility should not change
+# RUN: echo "PROVIDE_HIDDEN(somesym = 1);" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN5 %s
+# HIDDEN5: 0000000000000000 *ABS* 00000000 somesym
+
+# Simple symbol assignment. All three symbols should have the
+# same value.
+# RUN: echo "foo = 0x100; SECTIONS { bar = foo; } baz = bar;" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE2 %s
+# SIMPLE2: 0000000000000100 *ABS* 00000000 foo
+# SIMPLE2: 0000000000000100 *ABS* 00000000 bar
+# SIMPLE2: 0000000000000100 *ABS* 00000000 baz
+
+.global _start
+_start:
+ nop
+
+.global somesym
+somesym = 0
diff --git a/test/ELF/linkerscript/tbss.s b/test/ELF/linkerscript/tbss.s
new file mode 100644
index 000000000000..de8ed50cb4a4
--- /dev/null
+++ b/test/ELF/linkerscript/tbss.s
@@ -0,0 +1,42 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN: . = SIZEOF_HEADERS; \
+# RUN: .text : { *(.text) } \
+# RUN: foo : { *(foo) } \
+# RUN: bar : { *(bar) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -T %t.script %t.o -o %t
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# test that a tbss section doesn't use address space.
+
+# CHECK: Name: foo
+# CHECK-NEXT: Type: SHT_NOBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_TLS
+# CHECK-NEXT: SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x[[ADDR:.*]]
+# CHECK-NEXT: Offset: 0x[[ADDR]]
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 1
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index:
+# CHECK-NEXT: Name: bar
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x[[ADDR]]
+
+ .section foo,"awT",@nobits
+ .long 0
+ .section bar, "aw"
+ .long 0
diff --git a/test/ELF/linkerscript/undef.s b/test/ELF/linkerscript/undef.s
new file mode 100644
index 000000000000..85ad0767b5ed
--- /dev/null
+++ b/test/ELF/linkerscript/undef.s
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { patatino = 0x1234; }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+# CHECK: 0000000000001234 *ABS* 00000000 patatino
+
+.global _start
+_start:
+ call patatino
diff --git a/test/ELF/linkerscript/va.s b/test/ELF/linkerscript/va.s
new file mode 100644
index 000000000000..854ebcef0146
--- /dev/null
+++ b/test/ELF/linkerscript/va.s
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size Address Type
+# CHECK-NEXT: 0 00000000 0000000000000000
+# CHECK-NEXT: 1 .text 00000001 0000000000000000 TEXT DATA
+# CHECK-NEXT: 2 .foo 00000004 0000000000000001 DATA
+# CHECK-NEXT: 3 .boo 00000004 0000000000000005 DATA
+
+.global _start
+_start:
+ nop
+
+.section .foo, "a"
+foo:
+ .long 0
+
+.section .boo, "a"
+boo:
+ .long 0
diff --git a/test/ELF/linkerscript/visibility.s b/test/ELF/linkerscript/visibility.s
new file mode 100644
index 000000000000..9d9fcf0c5cdc
--- /dev/null
+++ b/test/ELF/linkerscript/visibility.s
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { foo = .; }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t.o -shared
+# RUN: llvm-readobj -t %t1 | FileCheck %s
+
+# CHECK: Symbol {
+# CHECK: Name: foo
+# CHECK-NEXT: Value:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Binding: Local
+# CHECK-NEXT: Type:
+# CHECK-NEXT: Other [
+# CHECK-NEXT: STV_HIDDEN
+# CHECK-NEXT: ]
+# CHECK-NEXT: Section:
+# CHECK-NEXT: }
+
+ .data
+ .hidden foo
+ .long foo
diff --git a/test/ELF/linkerscript/wildcards.s b/test/ELF/linkerscript/wildcards.s
new file mode 100644
index 000000000000..4e9469e40773
--- /dev/null
+++ b/test/ELF/linkerscript/wildcards.s
@@ -0,0 +1,83 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Default case: abc and abx included in text.
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.abc .abx) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN: FileCheck -check-prefix=SEC-DEFAULT %s
+# SEC-DEFAULT: Sections:
+# SEC-DEFAULT-NEXT: Idx Name Size
+# SEC-DEFAULT-NEXT: 0 00000000
+# SEC-DEFAULT-NEXT: 1 .text 00000008
+# SEC-DEFAULT-NEXT: 2 .abcd 00000004
+# SEC-DEFAULT-NEXT: 3 .ad 00000004
+# SEC-DEFAULT-NEXT: 4 .ag 00000004
+# SEC-DEFAULT-NEXT: 5 .comment 00000008 {{[0-9a-f]*}}
+# SEC-DEFAULT-NEXT: 6 .symtab 00000030
+# SEC-DEFAULT-NEXT: 7 .shstrtab 00000038
+# SEC-DEFAULT-NEXT: 8 .strtab 00000008
+
+## Now replace the symbol with '?' and check that results are the same.
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.abc .ab?) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN: FileCheck -check-prefix=SEC-DEFAULT %s
+
+## Now see how replacing '?' with '*' will consume whole abcd.
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.abc .ab*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN: FileCheck -check-prefix=SEC-ALL %s
+# SEC-ALL: Sections:
+# SEC-ALL-NEXT: Idx Name Size
+# SEC-ALL-NEXT: 0 00000000
+# SEC-ALL-NEXT: 1 .text 0000000c
+# SEC-ALL-NEXT: 2 .ad 00000004
+# SEC-ALL-NEXT: 3 .ag 00000004
+# SEC-ALL-NEXT: 4 .comment 00000008
+# SEC-ALL-NEXT: 5 .symtab 00000030
+# SEC-ALL-NEXT: 6 .shstrtab 00000032
+# SEC-ALL-NEXT: 7 .strtab 00000008
+
+## All sections started with .a are merged.
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.a*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN: FileCheck -check-prefix=SEC-NO %s
+# SEC-NO: Sections:
+# SEC-NO-NEXT: Idx Name Size
+# SEC-NO-NEXT: 0 00000000
+# SEC-NO-NEXT: 1 .text 00000014
+# SEC-NO-NEXT: 2 .comment 00000008
+# SEC-NO-NEXT: 3 .symtab 00000030
+# SEC-NO-NEXT: 4 .shstrtab 0000002a
+# SEC-NO-NEXT: 5 .strtab 00000008
+
+.text
+.section .abc,"ax",@progbits
+.long 0
+
+.text
+.section .abx,"ax",@progbits
+.long 0
+
+.text
+.section .abcd,"ax",@progbits
+.long 0
+
+.text
+.section .ad,"ax",@progbits
+.long 0
+
+.text
+.section .ag,"ax",@progbits
+.long 0
+
+
+.globl _start
+_start:
diff --git a/test/ELF/linkerscript/wildcards2.s b/test/ELF/linkerscript/wildcards2.s
new file mode 100644
index 000000000000..5e8d6a3d309a
--- /dev/null
+++ b/test/ELF/linkerscript/wildcards2.s
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+## Check that aabc is not included in text.
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.abc) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN: FileCheck %s
+# CHECK: Sections:
+# CHECK-NEXT: Idx Name Size
+# CHECK-NEXT: 0 00000000
+# CHECK-NEXT: 1 .text 00000004
+# CHECK-NEXT: 2 aabc 00000004
+
+.text
+.section .abc,"ax",@progbits
+.long 0
+
+.text
+.section aabc,"ax",@progbits
+.long 0
+
+.globl _start
+_start: