Index: test/tools/llvm-objcopy/COFF/Inputs/x86_64-debug-exe.yaml
===================================================================
--- /dev/null
+++ test/tools/llvm-objcopy/COFF/Inputs/x86_64-debug-exe.yaml
@@ -0,0 +1,203 @@
+--- !COFF
+OptionalHeader:  
+  AddressOfEntryPoint: 4144
+  ImageBase:       1073741824
+  SectionAlignment: 4096
+  FileAlignment:   512
+  MajorOperatingSystemVersion: 6
+  MinorOperatingSystemVersion: 0
+  MajorImageVersion: 0
+  MinorImageVersion: 0
+  MajorSubsystemVersion: 6
+  MinorSubsystemVersion: 0
+  Subsystem:       IMAGE_SUBSYSTEM_WINDOWS_CUI
+  DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ]
+  SizeOfStackReserve: 1048576
+  SizeOfStackCommit: 4096
+  SizeOfHeapReserve: 1048576
+  SizeOfHeapCommit: 4096
+  ExportTable:     
+    RelativeVirtualAddress: 0
+    Size:            0
+  ImportTable:     
+    RelativeVirtualAddress: 0
+    Size:            0
+  ResourceTable:   
+    RelativeVirtualAddress: 0
+    Size:            0
+  ExceptionTable:  
+    RelativeVirtualAddress: 20480
+    Size:            24
+  CertificateTable: 
+    RelativeVirtualAddress: 0
+    Size:            0
+  BaseRelocationTable: 
+    RelativeVirtualAddress: 0
+    Size:            0
+  Debug:           
+    RelativeVirtualAddress: 12288
+    Size:            28
+  Architecture:    
+    RelativeVirtualAddress: 0
+    Size:            0
+  GlobalPtr:       
+    RelativeVirtualAddress: 0
+    Size:            0
+  TlsTable:        
+    RelativeVirtualAddress: 0
+    Size:            0
+  LoadConfigTable: 
+    RelativeVirtualAddress: 0
+    Size:            0
+  BoundImport:     
+    RelativeVirtualAddress: 0
+    Size:            0
+  IAT:             
+    RelativeVirtualAddress: 0
+    Size:            0
+  DelayImportDescriptor: 
+    RelativeVirtualAddress: 0
+    Size:            0
+  ClrRuntimeHeader: 
+    RelativeVirtualAddress: 0
+    Size:            0
+header:          
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
+sections:        
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  4096
+    VirtualSize:     87
+    SectionData:     50894C24048B0DF52F0000034C240489C859C3662E0F1F8400000000000F1F00C3662E0F1F8400000000000F1F440000554883EC30488D6C2430E8E1FFFFFFC745FC00000000B902000000E8B0FFFFFF904883C4305DC3
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  8192
+    VirtualSize:     52
+    SectionData:     FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF00000000000000000101010001020000010A03350A03055201500000
+  - Name:            .buildid
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  12288
+    VirtualSize:     53
+    SectionData:     000000007C39FD5B0000000002000000190000001C3000001C0800005253445308D09F90668CDB1D4C4C44205044422E0100000000
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    VirtualAddress:  16384
+    VirtualSize:     4
+    SectionData:     '01000000'
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  20480
+    VirtualSize:     24
+    SectionData:     '001000001310000020200000301000005710000028200000'
+  - Name:            .debug_abbrev
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  24576
+    VirtualSize:     126
+    SectionData:     011101250E1305030E10171B0E110112060000023400030E49133A0B3B0B02180000032400030E3E0B0B0B0000042E01110112064018030E3A0B3B0B271949133F1900000505000218030E3A0B3B0B49130000062E00110112064018030E3A0B3B0B27193F190000072E00110112064018030E3A0B3B0B49133F19000000
+  - Name:            .debug_info
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  28672
+    VirtualSize:     157
+    SectionData:     990000000400000000000801000000000C00370000000000000040000000001000400100000057000000026B0000003F000000010109030040004001000000036D00000005040400100040010000001300000001577100000001033F000000050291047F00000001033F000000000620100040010000000100000001577300000001070730100040010000002700000001567A00000001093F00000000
+  - Name:            .debug_line
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  32768
+    VirtualSize:     91
+    SectionData:     57000000040020000000010101FB0E0D00010101010000000100000100736F757263652E630000000000000902001000400100000014050A0A59050C066605034A050006081505010A130500F3050A0A08590503069E0207000101
+  - Name:            .debug_macinfo
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  36864
+    VirtualSize:     1
+    SectionData:     '00'
+  - Name:            .debug_str
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  40960
+    VirtualSize:     129
+    SectionData:     636C616E672076657273696F6E20382E302E3020287472756E6B203334363337382920286C6C766D2F7472756E6B203334363339302900736F757263652E63002F686F6D652F6D617274696E2F636F64652F6C6C766D2F6275696C642F6F626A636F70792D696E707574007800696E740066005F5F6D61696E006D61696E007900
+symbols:         
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .data
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .bss
+    Value:           4
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .xdata
+    Value:           32
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .debug_str
+    Value:           0
+    SectionNumber:   10
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .debug_abbrev
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .debug_info
+    Value:           0
+    SectionNumber:   7
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .debug_macinfo
+    Value:           0
+    SectionNumber:   9
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .debug_line
+    Value:           0
+    SectionNumber:   8
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            f
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            x
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            __main
+    Value:           32
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            main
+    Value:           48
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
Index: test/tools/llvm-objcopy/COFF/X86/lit.local.cfg
===================================================================
--- /dev/null
+++ test/tools/llvm-objcopy/COFF/X86/lit.local.cfg
@@ -0,0 +1,4 @@
+# These tests require a registered x86 backend.
+
+if not 'X86' in config.root.targets:
+    config.unsupported = True
Index: test/tools/llvm-objcopy/COFF/X86/remove-local-symbols.s
===================================================================
--- /dev/null
+++ test/tools/llvm-objcopy/COFF/X86/remove-local-symbols.s
@@ -0,0 +1,37 @@
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o
+
+# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefix=RELOCS
+# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-PRE
+# RUN: llvm-strip -x %t.o
+# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefix=RELOCS
+# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-POST
+
+# RELOCS:      Relocations [
+# RELOCS-NEXT:   Section (1) .text {
+# RELOCS-NEXT:     0x2 IMAGE_REL_AMD64_REL32 ptr
+# RELOCS-NEXT:   }
+# RELOCS-NEXT: ]
+
+# SYMBOLS-PRE: 00000000 T mainfunc
+# SYMBOLS-PRE: 0000000c t otherfunc
+# SYMBOLS-PRE: 00000000 d ptr
+# SYMBOLS-PRE-EMPTY:
+
+# SYMBOLS-POST: 00000000 T mainfunc
+# SYMBOLS-POST: 00000000 d ptr
+# SYMBOLS-POST-EMPTY:
+
+
+        .text
+        .globl  mainfunc
+mainfunc:
+        movl    ptr(%rip), %eax
+        # This doesn't produce any relocation, and otherfunc can be dropped.
+        call    otherfunc
+        ret
+otherfunc:
+        ret
+
+        .data
+ptr:
+        .long   42
Index: test/tools/llvm-objcopy/COFF/X86/remove-section1.s
===================================================================
--- /dev/null
+++ test/tools/llvm-objcopy/COFF/X86/remove-section1.s
@@ -0,0 +1,34 @@
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o
+
+# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-PRE
+# RUN: llvm-objcopy -R .data %t.o
+# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-POST
+
+# SYMBOLS-PRE: 00000000 T mainfunc
+# SYMBOLS-PRE: 00000001 T otherfunc
+# SYMBOLS-PRE: 00000002 T otherfunc2
+# SYMBOLS-PRE: 00000000 D ptr
+# SYMBOLS-PRE-EMPTY:
+
+# SYMBOLS-POST: 00000000 T mainfunc
+# SYMBOLS-POST: 00000001 T otherfunc
+# SYMBOLS-POST: 00000002 T otherfunc2
+# SYMBOLS-POST-NOT: ptr
+# SYMBOLS-POST-EMPTY:
+
+
+        .text
+        .globl  mainfunc
+mainfunc:
+        ret
+        .globl  otherfunc
+otherfunc:
+        ret
+        .globl  otherfunc2
+otherfunc2:
+        ret
+
+        .data
+        .globl  ptr
+ptr:
+        .long   42
Index: test/tools/llvm-objcopy/COFF/X86/remove-section2.s
===================================================================
--- /dev/null
+++ test/tools/llvm-objcopy/COFF/X86/remove-section2.s
@@ -0,0 +1,25 @@
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o
+
+# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefix=RELOCS
+# RUN: not llvm-objcopy -R .data %t.o 2>&1 | FileCheck %s --check-prefix=ERROR
+
+# RELOCS:      Relocations [
+# RELOCS-NEXT:   Section (1) .text {
+# RELOCS-NEXT:     0x2 IMAGE_REL_AMD64_REL32 ptr
+# RELOCS-NEXT:   }
+# RELOCS-NEXT: ]
+
+# GNU objcopy doesn't error out here, but instead changes the relocation
+# target to the .text symbol instead.
+
+# ERROR: Relocation to removed symbol ptr
+
+        .text
+        .globl  mainfunc
+mainfunc:
+        movl    ptr(%rip), %eax
+        ret
+
+        .data
+ptr:
+        .long   42
Index: test/tools/llvm-objcopy/COFF/X86/remove-symbol1.s
===================================================================
--- /dev/null
+++ test/tools/llvm-objcopy/COFF/X86/remove-symbol1.s
@@ -0,0 +1,43 @@
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o
+
+# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefix=RELOCS
+# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-PRE
+# RUN: llvm-objcopy -N otherfunc %t.o
+# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefix=RELOCS
+# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-POST
+
+# RELOCS:      Relocations [
+# RELOCS-NEXT:   Section (1) .text {
+# RELOCS-NEXT:     0x2 IMAGE_REL_AMD64_REL32 ptr
+# RELOCS-NEXT:   }
+# RELOCS-NEXT: ]
+
+# SYMBOLS-PRE: 00000000 T mainfunc
+# SYMBOLS-PRE: 0000000c T otherfunc
+# SYMBOLS-PRE: 0000000d T otherfunc2
+# SYMBOLS-PRE: 00000000 d ptr
+# SYMBOLS-PRE-EMPTY:
+
+# SYMBOLS-POST: 00000000 T mainfunc
+# SYMBOLS-POST-NOT: otherfunc
+# SYMBOLS-POST: 0000000d T otherfunc2
+# SYMBOLS-POST: 00000000 d ptr
+# SYMBOLS-POST-EMPTY:
+
+
+        .text
+        .globl  mainfunc
+mainfunc:
+        movl    ptr(%rip), %eax
+        call    otherfunc
+        ret
+        .globl  otherfunc
+otherfunc:
+        ret
+        .globl  otherfunc2
+otherfunc2:
+        ret
+
+        .data
+ptr:
+        .long   42
Index: test/tools/llvm-objcopy/COFF/X86/remove-symbol2.s
===================================================================
--- /dev/null
+++ test/tools/llvm-objcopy/COFF/X86/remove-symbol2.s
@@ -0,0 +1,29 @@
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o
+
+# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-PRE
+# RUN: not llvm-objcopy -N ptr %t.o 2>&1 | FileCheck %s --check-prefix=ERROR
+
+# SYMBOLS-PRE: 00000000 T mainfunc
+# SYMBOLS-PRE: 0000000c T otherfunc
+# SYMBOLS-PRE: 0000000d T otherfunc2
+# SYMBOLS-PRE: 00000000 d ptr
+# SYMBOLS-PRE-EMPTY:
+
+# ERROR: Can't remove referenced symbol ptr
+
+        .text
+        .globl  mainfunc
+mainfunc:
+        movl    ptr(%rip), %eax
+        call    otherfunc
+        ret
+        .globl  otherfunc
+otherfunc:
+        ret
+        .globl  otherfunc2
+otherfunc2:
+        ret
+
+        .data
+ptr:
+        .long   42
Index: test/tools/llvm-objcopy/COFF/discard-all.test
===================================================================
--- /dev/null
+++ test/tools/llvm-objcopy/COFF/discard-all.test
@@ -0,0 +1,87 @@
+RUN: yaml2obj %p/Inputs/x86_64-obj.yaml > %t.o
+RUN: llvm-readobj -symbols %t.o | FileCheck %s --check-prefix=SYMS-ORIG
+
+RUN: llvm-strip -x %t.o
+RUN: llvm-readobj -symbols %t.o | FileCheck %s --check-prefix=SYMS-NEW
+
+RUN: llvm-readobj -sections %t.o | FileCheck %s --check-prefix=SECTIONS
+
+For this specific input, the debug sections and symbols relating
+to the debug sections are removed.
+
+SYMS-ORIG:     Name: .text
+SYMS-ORIG:     Name: .data
+SYMS-ORIG:     Name: .bss
+SYMS-ORIG:     Name: .xdata
+SYMS-ORIG:     Name: .debug_str
+SYMS-ORIG:     Name: .debug_abbrev
+SYMS-ORIG:     Name: .debug_info
+SYMS-ORIG:     Name: .debug_macinfo
+SYMS-ORIG:     Name: .pdata
+SYMS-ORIG:     Name: .debug_line
+SYMS-ORIG:     Name: .llvm_addrsig
+SYMS-ORIG:     Name: @feat.00
+SYMS-ORIG:     Name: f
+SYMS-ORIG:     Name: x
+SYMS-ORIG:     Name: __main
+SYMS-ORIG:     Name: main
+
+SYMS-NEW-NOT:     Name: .text
+SYMS-NEW-NOT:     Name: .data
+SYMS-NEW-NOT:     Name: .bss
+SYMS-NEW:     Name: .xdata
+SYMS-NEW-NOT:     Name: .debug_str
+SYMS-NEW-NOT:     Name: .debug_abbrev
+SYMS-NEW-NOT:     Name: .debug_info
+SYMS-NEW-NOT:     Name: .debug_macinfo
+SYMS-NEW-NOT:     Name: .pdata
+SYMS-NEW-NOT:     Name: .debug_line
+SYMS-NEW-NOT:     Name: .llvm_addrsig
+SYMS-NEW-NOT:     Name: @feat.00
+SYMS-NEW:     Name: f
+SYMS-NEW:     Name: x
+SYMS-NEW:     Name: __main
+SYMS-NEW:     Name: main
+
+SECTIONS:      Sections [
+SECTIONS-NEXT:  Section {
+SECTIONS-NEXT:    Number: 1
+SECTIONS-NEXT:     Name: .text
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 87
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 2
+SECTIONS-NEXT:     Name: .data
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 4
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 3
+SECTIONS-NEXT:     Name: .bss
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 0
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 4
+SECTIONS-NEXT:     Name: .xdata
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 20
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 5
+SECTIONS-NEXT:     Name: .pdata
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 24
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 6
+SECTIONS-NEXT:     Name: .llvm_addrsig
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 2
+SECTIONS-NOT:      Name: .debug_abbrev
+SECTIONS-NOT:      Name: .debug_info
+SECTIONS-NOT:      Name: .debug_line
+SECTIONS-NOT:      Name: .debug_macinfo
+SECTIONS-NOT:      Name: .debug_str
Index: test/tools/llvm-objcopy/COFF/strip-executable.test
===================================================================
--- /dev/null
+++ test/tools/llvm-objcopy/COFF/strip-executable.test
@@ -0,0 +1,71 @@
+RUN: yaml2obj %p/Inputs/x86_64-debug-exe.yaml > %t.input.exe
+RUN: llvm-nm %t.input.exe | FileCheck %s --check-prefix=SYMS-ORIG
+
+RUN: llvm-objcopy --strip-all %t.input.exe %t.exe
+RUN: llvm-nm %t.exe 2>&1 | FileCheck %s --check-prefix=SYMS-NEW
+RUN: llvm-readobj -sections %t.exe | FileCheck %s --check-prefix=SECTIONS
+
+RUN: llvm-objcopy --strip-unneeded %t.input.exe %t.exe
+RUN: llvm-nm %t.exe 2>&1 | FileCheck %s --check-prefix=SYMS-NEW
+RUN: llvm-readobj -sections %t.exe | FileCheck %s --check-prefix=SECTIONS
+
+RUN: cp %t.input.exe %t.exe
+RUN: llvm-strip %t.exe
+RUN: llvm-nm %t.exe 2>&1 | FileCheck %s --check-prefix=SYMS-NEW
+RUN: llvm-readobj -sections %t.exe | FileCheck %s --check-prefix=SECTIONS
+
+The debug sections and all symbols are removed.
+
+SYMS-ORIG: 40004004 d .bss
+SYMS-ORIG: 40004000 d .data
+SYMS-ORIG: 40006000 N .debug_abbrev
+SYMS-ORIG: 40007000 N .debug_info
+SYMS-ORIG: 40008000 N .debug_line
+SYMS-ORIG: 40009000 N .debug_macinfo
+SYMS-ORIG: 4000a000 N .debug_str
+SYMS-ORIG: 40005000 r .pdata
+SYMS-ORIG: 40001000 t .text
+SYMS-ORIG: 40002020 r .xdata
+SYMS-ORIG: 40001020 T __main
+SYMS-ORIG: 40001000 T f
+SYMS-ORIG: 40001030 T main
+SYMS-ORIG: 40004000 d x
+
+SYMS-NEW: no symbols
+
+SECTIONS:      Sections [
+SECTIONS-NEXT:  Section {
+SECTIONS-NEXT:    Number: 1
+SECTIONS-NEXT:     Name: .text
+SECTIONS-NEXT:     VirtualSize: 0x57
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 512
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 2
+SECTIONS-NEXT:     Name: .rdata
+SECTIONS-NEXT:     VirtualSize: 0x34
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 512
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 3
+SECTIONS-NEXT:     Name: .buildid
+SECTIONS-NEXT:     VirtualSize: 0x35
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 512
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 4
+SECTIONS-NEXT:     Name: .data
+SECTIONS-NEXT:     VirtualSize: 0x4
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 512
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 5
+SECTIONS-NEXT:     Name: .pdata
+SECTIONS-NEXT:     VirtualSize: 0x18
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 512
+SECTIONS-NOT:      Name: .debug_abbrev
+SECTIONS-NOT:      Name: .debug_info
+SECTIONS-NOT:      Name: .debug_line
+SECTIONS-NOT:      Name: .debug_macinfo
+SECTIONS-NOT:      Name: .debug_str
Index: test/tools/llvm-objcopy/COFF/strip-object.test
===================================================================
--- /dev/null
+++ test/tools/llvm-objcopy/COFF/strip-object.test
@@ -0,0 +1,87 @@
+RUN: yaml2obj %p/Inputs/x86_64-obj.yaml > %t.input.o
+RUN: llvm-readobj -symbols %t.input.o | FileCheck %s --check-prefix=SYMS-ORIG
+
+RUN: llvm-objcopy --strip-debug %t.input.o %t.o
+RUN: llvm-readobj -symbols %t.o | FileCheck %s --check-prefix=SYMS-NEW
+
+RUN: llvm-readobj -sections %t.o | FileCheck %s --check-prefix=SECTIONS
+
+The debug sections are removed, symbols relating to the debug sections
+are removed.
+
+SYMS-ORIG:     Name: .text
+SYMS-ORIG:     Name: .data
+SYMS-ORIG:     Name: .bss
+SYMS-ORIG:     Name: .xdata
+SYMS-ORIG:     Name: .debug_str
+SYMS-ORIG:     Name: .debug_abbrev
+SYMS-ORIG:     Name: .debug_info
+SYMS-ORIG:     Name: .debug_macinfo
+SYMS-ORIG:     Name: .pdata
+SYMS-ORIG:     Name: .debug_line
+SYMS-ORIG:     Name: .llvm_addrsig
+SYMS-ORIG:     Name: @feat.00
+SYMS-ORIG:     Name: f
+SYMS-ORIG:     Name: x
+SYMS-ORIG:     Name: __main
+SYMS-ORIG:     Name: main
+
+SYMS-NEW:     Name: .text
+SYMS-NEW:     Name: .data
+SYMS-NEW:     Name: .bss
+SYMS-NEW:     Name: .xdata
+SYMS-NEW-NOT:     Name: .debug_str
+SYMS-NEW-NOT:     Name: .debug_abbrev
+SYMS-NEW-NOT:     Name: .debug_info
+SYMS-NEW-NOT:     Name: .debug_macinfo
+SYMS-NEW:     Name: .pdata
+SYMS-NEW-NOT:     Name: .debug_line
+SYMS-NEW:     Name: .llvm_addrsig
+SYMS-NEW:     Name: @feat.00
+SYMS-NEW:     Name: f
+SYMS-NEW:     Name: x
+SYMS-NEW:     Name: __main
+SYMS-NEW:     Name: main
+
+SECTIONS:      Sections [
+SECTIONS-NEXT:  Section {
+SECTIONS-NEXT:    Number: 1
+SECTIONS-NEXT:     Name: .text
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 87
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 2
+SECTIONS-NEXT:     Name: .data
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 4
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 3
+SECTIONS-NEXT:     Name: .bss
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 0
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 4
+SECTIONS-NEXT:     Name: .xdata
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 20
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 5
+SECTIONS-NEXT:     Name: .pdata
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 24
+SECTIONS:        Section {
+SECTIONS-NEXT:     Number: 6
+SECTIONS-NEXT:     Name: .llvm_addrsig
+SECTIONS-NEXT:     VirtualSize:
+SECTIONS-NEXT:     VirtualAddress:
+SECTIONS-NEXT:     RawDataSize: 2
+SECTIONS-NOT:      Name: .debug_abbrev
+SECTIONS-NOT:      Name: .debug_info
+SECTIONS-NOT:      Name: .debug_line
+SECTIONS-NOT:      Name: .debug_macinfo
+SECTIONS-NOT:      Name: .debug_str
Index: tools/llvm-objcopy/CMakeLists.txt
===================================================================
--- tools/llvm-objcopy/CMakeLists.txt
+++ tools/llvm-objcopy/CMakeLists.txt
@@ -18,6 +18,7 @@
   CopyConfig.cpp
   llvm-objcopy.cpp
   COFF/COFFObjcopy.cpp
+  COFF/Object.cpp
   COFF/Reader.cpp
   COFF/Writer.cpp
   ELF/ELFObjcopy.cpp
Index: tools/llvm-objcopy/COFF/COFFObjcopy.cpp
===================================================================
--- tools/llvm-objcopy/COFF/COFFObjcopy.cpp
+++ tools/llvm-objcopy/COFF/COFFObjcopy.cpp
@@ -15,8 +15,13 @@
 #include "Writer.h"
 #include "llvm-objcopy.h"
 
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Object/Binary.h"
 #include "llvm/Object/COFF.h"
+#include "llvm/Support/JamCRC.h"
+#include "llvm/Support/Path.h"
 #include <cassert>
 
 namespace llvm {
@@ -26,11 +31,151 @@
 using namespace object;
 using namespace COFF;
 
+static bool isDebugSection(const Section &Sec) {
+  return Sec.Name.startswith(".debug");
+}
+
+static void handleArgs(const CopyConfig &Config, Object &Obj) {
+  size_t OrigNumSymbols = Obj.Symbols.size();
+  // Initialize mappings for the relocations. Relocations refer to symbols
+  // by index, which has to be remapped and updated after removing symbols.
+  Obj.initRawSymbolTable();
+  Obj.initRelocTargets(Config.InputFilename);
+
+  std::function<bool(const Section &)> RemovePred = [](const Section &) {
+    return false;
+  };
+
+  // Removes:
+  if (!Config.ToRemove.empty()) {
+    RemovePred = [&Config](const Section &Sec) {
+      return is_contained(Config.ToRemove, Sec.Name);
+    };
+  }
+
+  if (Config.StripAllGNU || Config.StripDebug || Config.StripAll ||
+      Config.DiscardAll || Config.StripUnneeded) {
+    RemovePred = [RemovePred](const Section &Sec) {
+      return RemovePred(Sec) || isDebugSection(Sec);
+    };
+  }
+
+  // Explicit copies:
+  if (!Config.OnlySection.empty()) {
+    RemovePred = [&Config, &Obj](const Section &Sec) {
+      // Explicitly keep these sections regardless of previous removes.
+      if (is_contained(Config.OnlySection, Sec.Name))
+        return false;
+
+      // Remove everything else. In case there are special sections we always
+      // want to keep, we would check RemovePred first and then check for
+      // the special sections, before returning true here.
+      return true;
+    };
+  }
+
+  if (!Config.KeepSection.empty()) {
+    RemovePred = [&Config, RemovePred](const Section &Sec) {
+      // Explicitly keep these sections regardless of previous removes.
+      if (is_contained(Config.KeepSection, Sec.Name))
+        return false;
+      // Otherwise defer to RemovePred.
+      return RemovePred(Sec);
+    };
+  }
+
+  size_t SecIdx = 1;
+  for (Section &Sec : Obj.Sections)
+    Sec.Idx = SecIdx++;
+
+  DenseSet<size_t> RemovedSections;
+  RemovePred = [&RemovedSections, RemovePred](const Section &Sec) {
+    // A no-op lambda wrapper, that keeps track of which sections actually
+    // were removed.
+    bool Remove = RemovePred(Sec);
+    if (Remove)
+      RemovedSections.insert(Sec.Idx);
+    return Remove;
+  };
+
+  // Perform the actual section removals.
+  Obj.removeSections(RemovePred);
+
+  // If we need to do per-symbol removals, initialize the Referenced field,
+  // based on the remaining sections. The setReferencedSymbols method can
+  // be used only before removing any symbols.
+  if (Config.StripUnneeded || Config.DiscardAll ||
+      !Config.SymbolsToRemove.empty())
+    Obj.setReferencedSymbols(Config.InputFilename);
+
+  // If we did remove sections, remove all symbols pointing to those sections
+  // and update symbols to point to new section numbers.
+
+  // NOTE: We don't update section number references in
+  // coff_aux_section_definition for associative comdats pointing behind
+  // removed sections. Config.StripUnneeded or Config.DiscardAll will likely
+  // also break comdats.
+  if (!RemovedSections.empty()) {
+    // Initialize a mapping from old to new section indices.
+    DenseMap<size_t, size_t> NewSectionIndex;
+    SecIdx = 1;
+    for (Section &Sec : Obj.Sections) {
+      NewSectionIndex[Sec.Idx] = SecIdx;
+      Sec.Idx = SecIdx++;
+    }
+    // Remove all symbols where the section number exists in RemovedSections.
+    Obj.removeSymbols([&](const Symbol &Sym) {
+      return RemovedSections.count(Sym.Sym.SectionNumber) == 1;
+    });
+    // Update SectionNumber to point to the new section indices.
+    for (Symbol &Sym : Obj.Symbols)
+      Sym.Sym.SectionNumber = NewSectionIndex[Sym.Sym.SectionNumber];
+  }
+
+  // Actually do removals of symbols.
+  Obj.removeSymbols([&](const Symbol &Sym) {
+    if (!Config.SymbolsToKeep.empty() &&
+        is_contained(Config.SymbolsToKeep, Sym.Name))
+      return false;
+
+    if (Config.StripAll || Config.StripAllGNU)
+      return true;
+
+    if (!Config.SymbolsToRemove.empty() &&
+        is_contained(Config.SymbolsToRemove, Sym.Name)) {
+      // Explicitly removing a referenced symbol is an error, while
+      // implicitly removing them as part of a blanket removal above is
+      // accepted.
+      if (Sym.Referenced)
+        reportError(Config.OutputFilename,
+                    make_error<StringError>("Can't remove referenced symbol " +
+                                                Sym.Name,
+                                            object_error::parse_failed));
+      return true;
+    }
+
+    // GNU binutils objcopy keeps referenced local symbols if Config.DiscaredAll
+    // is set.
+    if ((Config.StripUnneeded || Config.DiscardAll) && !Sym.Referenced &&
+        (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC || Obj.IsPE))
+      return true;
+
+    return false;
+  });
+
+  // If the number of symbols have changed, either by removing symbols
+  // from removed sections, or explicitly removing symbols, update relocations
+  // accordingly.
+  if (Obj.Symbols.size() != OrigNumSymbols)
+    Obj.updateRelocTargets(Config.OutputFilename);
+}
+
 void executeObjcopyOnBinary(const CopyConfig &Config,
                             object::COFFObjectFile &In, Buffer &Out) {
   COFFReader Reader(In);
   std::unique_ptr<Object> Obj = Reader.create();
   assert(Obj && "Unable to deserialize COFF object");
+  handleArgs(Config, *Obj);
   COFFWriter Writer(*Obj, Out);
   Writer.write();
 }
Index: tools/llvm-objcopy/COFF/Object.h
===================================================================
--- tools/llvm-objcopy/COFF/Object.h
+++ tools/llvm-objcopy/COFF/Object.h
@@ -27,12 +27,21 @@
   ArrayRef<uint8_t> Contents;
   std::vector<object::coff_relocation> Relocs;
   StringRef Name;
+
+  // Fields used by some transformations in objcopy, but not necessary
+  // for actually writing back to a file.
+  std::vector<StringRef> RelocTargets;
+  size_t Idx;
 };
 
 struct Symbol {
   object::coff_symbol32 Sym;
   StringRef Name;
   ArrayRef<uint8_t> AuxData;
+
+  // Fields used by some transformations in objcopy, but not necessary
+  // for actually writing back to a file.
+  bool Referenced = false;
 };
 
 struct Object {
@@ -50,6 +59,20 @@
   std::vector<object::data_directory> DataDirectories;
   std::vector<Section> Sections;
   std::vector<Symbol> Symbols;
+
+  // Fields used for transformations in objcopy, but not necessary
+  // for actually writing back to a file.
+  std::vector<Symbol *> RawSymbolTable;
+
+  void removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
+  void removeSections(function_ref<bool(const Section &)> ToRemove);
+
+  // StringRef taken as parameter for error reporting.
+  void initRawSymbolTable();
+  void setReferencedSymbols(StringRef Filename);
+
+  void initRelocTargets(StringRef Filename);
+  void updateRelocTargets(StringRef Filename);
 };
 
 // Copy between coff_symbol16 and coff_symbol32.
Index: tools/llvm-objcopy/COFF/Object.cpp
===================================================================
--- /dev/null
+++ tools/llvm-objcopy/COFF/Object.cpp
@@ -0,0 +1,115 @@
+//===- Object.cpp ---------------------------------------------------------===//
+//
+//                      The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Object.h"
+#include "llvm-objcopy.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+using namespace object;
+
+void Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
+  Symbols.erase(
+      std::remove_if(std::begin(Symbols), std::end(Symbols),
+                     [ToRemove](const Symbol &Sym) { return ToRemove(Sym); }),
+      std::end(Symbols));
+  RawSymbolTable.clear();
+}
+
+void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
+  Sections.erase(
+      std::remove_if(std::begin(Sections), std::end(Sections),
+                     [ToRemove](const Section &Sec) { return ToRemove(Sec); }),
+      std::end(Sections));
+}
+
+void Object::initRawSymbolTable() {
+  for (Symbol &S : Symbols) {
+    RawSymbolTable.push_back(&S);
+    for (size_t I = 0; I < S.Sym.NumberOfAuxSymbols; I++)
+      RawSymbolTable.push_back(nullptr);
+  }
+}
+
+void Object::setReferencedSymbols(StringRef Filename) {
+  // This function is meant to be used before pruning any symbols.
+  // It uses raw symbol indexes from Reloc.SymbolTableIndex instead of
+  // looking things up using the symbol names. (After pruning the symbol
+  // table, this would need to use a StringMap for finding the right symbols,
+  // like updateRelocTargets below.)
+  assert(RawSymbolTable.size() == CoffFileHeader.NumberOfSymbols);
+  for (const Section &Sec : Sections) {
+    for (const coff_relocation &Reloc : Sec.Relocs) {
+      if (Reloc.SymbolTableIndex >= RawSymbolTable.size())
+        reportError(Filename,
+                    make_error<StringError>("SymbolTableIndex out of range",
+                                            object_error::parse_failed));
+      else if (RawSymbolTable[Reloc.SymbolTableIndex] == nullptr)
+        reportError(Filename,
+                    make_error<StringError>("Invalid SymbolTableIndex",
+                                            object_error::parse_failed));
+      RawSymbolTable[Reloc.SymbolTableIndex]->Referenced = true;
+    }
+  }
+}
+
+void Object::initRelocTargets(StringRef Filename) {
+  // This function must be called before pruning any symbols.
+  assert(RawSymbolTable.size() == CoffFileHeader.NumberOfSymbols);
+  for (Section &Sec : Sections) {
+    for (const coff_relocation &Reloc : Sec.Relocs) {
+      if (Reloc.SymbolTableIndex >= RawSymbolTable.size())
+        reportError(Filename,
+                    make_error<StringError>("SymbolTableIndex out of range",
+                                            object_error::parse_failed));
+      else if (RawSymbolTable[Reloc.SymbolTableIndex] == nullptr)
+        reportError(Filename,
+                    make_error<StringError>("Invalid SymbolTableIndex",
+                                            object_error::parse_failed));
+      Sec.RelocTargets.push_back(RawSymbolTable[Reloc.SymbolTableIndex]->Name);
+    }
+  }
+}
+
+void Object::updateRelocTargets(StringRef Filename) {
+  // Initialize a mapping from symbol name to raw symbol index.
+  StringMap<uint32_t> SymMap;
+  uint32_t RawSymIdx = 0;
+  for (const Symbol &Sym : Symbols) {
+    SymMap[Sym.Name] = RawSymIdx;
+    RawSymIdx += 1 + Sym.Sym.NumberOfAuxSymbols;
+  }
+  // Update relocations with new symbol indices, or error out if the
+  // target symbol can't be found.
+  for (Section &Sec : Sections) {
+    assert(Sec.Relocs.size() == Sec.RelocTargets.size());
+    for (size_t I = 0, E = Sec.Relocs.size(); I < E; I++) {
+      auto It = SymMap.find(Sec.RelocTargets[I]);
+      if (It != SymMap.end())
+        Sec.Relocs[I].SymbolTableIndex = It->second;
+      else
+        reportError(Filename,
+                    make_error<StringError>("Relocation to removed symbol " +
+                                                Sec.RelocTargets[I],
+                                            object_error::parse_failed));
+    }
+  }
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm