Ctxt.DiagFlush = flusherrors
        Ctxt.Bso = bufio.NewWriter(os.Stdout)
 
+       // UseBASEntries is preferred because it shaves about 2% off build time, but LLDB, dsymutil, and dwarfdump
+       // on Darwin don't support it properly, especially since macOS 10.14 (Mojave).  This is exposed as a flag
+       // to allow testing with LLVM tools on Linux, and to help with reporting this bug to the LLVM project.
+       // See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
+       Ctxt.UseBASEntries = Ctxt.Headtype != objabi.Hdarwin
+
        localpkg = types.NewPkg("", "")
        localpkg.Prefix = "\"\""
 
        flag.StringVar(&mutexprofile, "mutexprofile", "", "write mutex profile to `file`")
        flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
        flag.BoolVar(&newescape, "newescape", true, "enable new escape analysis")
+       flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
        objabi.Flagparse(usage)
 
        // Record flags that affect the build result. (And don't
        // record flags that don't, since that would cause spurious
        // changes in the binary.)
-       recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "newescape")
+       recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "newescape", "dwarfbasentries")
 
        Ctxt.Flag_shared = flag_dynlink || flag_shared
        Ctxt.Flag_dynlink = flag_dynlink
 
 // PutLocationList adds list (a location list in its intermediate representation) to listSym.
 func (debugInfo *FuncDebug) PutLocationList(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) {
        getPC := debugInfo.GetPC
+
+       if ctxt.UseBASEntries {
+               listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, ^0)
+               listSym.WriteAddr(ctxt, listSym.Size, ctxt.Arch.PtrSize, startPC, 0)
+       }
+
        // Re-read list, translating its address from block/value ID to PC.
        for i := 0; i < len(list); {
                begin := getPC(decodeValue(ctxt, readPtr(ctxt, list[i:])))
                        end = 1
                }
 
-               writePtr(ctxt, list[i:], uint64(begin))
-               writePtr(ctxt, list[i+ctxt.Arch.PtrSize:], uint64(end))
+               if ctxt.UseBASEntries {
+                       listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, int64(begin))
+                       listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, int64(end))
+               } else {
+                       listSym.WriteCURelativeAddr(ctxt, listSym.Size, startPC, int64(begin))
+                       listSym.WriteCURelativeAddr(ctxt, listSym.Size, startPC, int64(end))
+               }
+
                i += 2 * ctxt.Arch.PtrSize
-               i += 2 + int(ctxt.Arch.ByteOrder.Uint16(list[i:]))
+               datalen := 2 + int(ctxt.Arch.ByteOrder.Uint16(list[i:]))
+               listSym.WriteBytes(ctxt, listSym.Size, list[i:i+datalen]) // copy datalen and location encoding
+               i += datalen
        }
 
-       // Base address entry.
-       listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, ^0)
-       listSym.WriteAddr(ctxt, listSym.Size, ctxt.Arch.PtrSize, startPC, 0)
        // Location list contents, now with real PCs.
-       listSym.WriteBytes(ctxt, listSym.Size, list)
        // End entry.
        listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0)
        listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0)
 
 // This container is used by the PutFunc* variants below when
 // creating the DWARF subprogram DIE(s) for a function.
 type FnState struct {
-       Name       string
-       Importpath string
-       Info       Sym
-       Filesym    Sym
-       Loc        Sym
-       Ranges     Sym
-       Absfn      Sym
-       StartPC    Sym
-       Size       int64
-       External   bool
-       Scopes     []Scope
-       InlCalls   InlCalls
+       Name          string
+       Importpath    string
+       Info          Sym
+       Filesym       Sym
+       Loc           Sym
+       Ranges        Sym
+       Absfn         Sym
+       StartPC       Sym
+       Size          int64
+       External      bool
+       Scopes        []Scope
+       InlCalls      InlCalls
+       UseBASEntries bool
 }
 
 func EnableLogging(doit bool) {
        AddInt(s Sym, size int, i int64)
        AddBytes(s Sym, b []byte)
        AddAddress(s Sym, t interface{}, ofs int64)
+       AddCURelativeAddress(s Sym, t interface{}, ofs int64)
        AddSectionOffset(s Sym, size int, t interface{}, ofs int64)
        AddDWARFAddrSectionOffset(s Sym, t interface{}, ofs int64)
        CurrentOffset(s Sym) int64
        putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_sdata, DW_CLS_CONSTANT, val, nil)
 }
 
-// PutRanges writes a range table to sym. All addresses in ranges are
-// relative to some base address. If base is not nil, then they're
-// relative to the start of base. If base is nil, then the caller must
-// arrange a base address some other way (such as a DW_AT_low_pc
-// attribute).
-func PutRanges(ctxt Context, sym Sym, base Sym, ranges []Range) {
+// PutBasedRanges writes a range table to sym. All addresses in ranges are
+// relative to some base address, which must be arranged by the caller
+// (e.g., with a DW_AT_low_pc attribute, or in a BASE-prefixed range).
+func PutBasedRanges(ctxt Context, sym Sym, ranges []Range) {
        ps := ctxt.PtrSize()
-       // Write base address entry.
-       if base != nil {
-               ctxt.AddInt(sym, ps, -1)
-               ctxt.AddAddress(sym, base, 0)
-       }
        // Write ranges.
        for _, r := range ranges {
                ctxt.AddInt(sym, ps, r.Start)
        ctxt.AddInt(sym, ps, 0)
 }
 
+// PutRanges writes a range table to s.Ranges.
+// All addresses in ranges are relative to s.base.
+func (s *FnState) PutRanges(ctxt Context, ranges []Range) {
+       ps := ctxt.PtrSize()
+       sym, base := s.Ranges, s.StartPC
+
+       if s.UseBASEntries {
+               // Using a Base Address Selection Entry reduces the number of relocations, but
+               // this is not done on macOS because it is not supported by dsymutil/dwarfdump/lldb
+               ctxt.AddInt(sym, ps, -1)
+               ctxt.AddAddress(sym, base, 0)
+               PutBasedRanges(ctxt, sym, ranges)
+               return
+       }
+
+       // Write ranges full of relocations
+       for _, r := range ranges {
+               ctxt.AddCURelativeAddress(sym, base, r.Start)
+               ctxt.AddCURelativeAddress(sym, base, r.End)
+       }
+       // Write trailer.
+       ctxt.AddInt(sym, ps, 0)
+       ctxt.AddInt(sym, ps, 0)
+}
+
 // Return TRUE if the inlined call in the specified slot is empty,
 // meaning it has a zero-length range (no instructions), and all
 // of its children are empty.
 
        if abbrev == DW_ABRV_INLINED_SUBROUTINE_RANGES {
                putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, s.Ranges.Len(), s.Ranges)
-               PutRanges(ctxt, s.Ranges, s.StartPC, ic.Ranges)
+               s.PutRanges(ctxt, ic.Ranges)
        } else {
                st := ic.Ranges[0].Start
                en := ic.Ranges[0].End
                        Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES)
                        putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, s.Ranges.Len(), s.Ranges)
 
-                       PutRanges(ctxt, s.Ranges, s.StartPC, scope.Ranges)
+                       s.PutRanges(ctxt, scope.Ranges)
                }
 
                curscope = putscope(ctxt, s, scopes, curscope, fnabbrev, encbuf)
 
        }
 }
 
-// WriteAddr writes an address of size siz into s at offset off.
-// rsym and roff specify the relocation for the address.
-func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) {
+func (s *LSym) writeAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64, rtype objabi.RelocType) {
        // Allow 4-byte addresses for DWARF.
        if siz != ctxt.Arch.PtrSize && siz != 4 {
                ctxt.Diag("WriteAddr: bad address size %d in %s", siz, s.Name)
        }
        r.Siz = uint8(siz)
        r.Sym = rsym
-       r.Type = objabi.R_ADDR
+       r.Type = rtype
        r.Add = roff
 }
 
+// WriteAddr writes an address of size siz into s at offset off.
+// rsym and roff specify the relocation for the address.
+func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) {
+       s.writeAddr(ctxt, off, siz, rsym, roff, objabi.R_ADDR)
+}
+
+// WriteCURelativeAddr writes a pointer-sized address into s at offset off.
+// rsym and roff specify the relocation for the address which will be
+// resolved by the linker to an offset from the DW_AT_low_pc attribute of
+// the DWARF Compile Unit of rsym.
+func (s *LSym) WriteCURelativeAddr(ctxt *Link, off int64, rsym *LSym, roff int64) {
+       s.writeAddr(ctxt, off, ctxt.Arch.PtrSize, rsym, roff, objabi.R_ADDRCUOFF)
+}
+
 // WriteOff writes a 4 byte offset to rsym+roff into s at offset off.
 // After linking the 4 bytes stored at s+off will be
 // rsym+roff-(start of section that s is in).
 
 
        InParallel           bool // parallel backend phase in effect
        Framepointer_enabled bool
+       UseBASEntries        bool // Use Base Address Selection Entries in location lists and PC ranges
 
        // state for writing objects
        Text []*LSym
 
                ls.WriteInt(c.Link, ls.Size, size, value)
        }
 }
+func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
+       ls := s.(*LSym)
+       rsym := data.(*LSym)
+       ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
+}
 func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
        panic("should be used only in the linker")
 }
        dwctxt := dwCtxt{ctxt}
        filesym := ctxt.fileSymbol(s)
        fnstate := &dwarf.FnState{
-               Name:       s.Name,
-               Importpath: myimportpath,
-               Info:       info,
-               Filesym:    filesym,
-               Loc:        loc,
-               Ranges:     ranges,
-               Absfn:      absfunc,
-               StartPC:    s,
-               Size:       s.Size,
-               External:   !s.Static(),
-               Scopes:     scopes,
-               InlCalls:   inlcalls,
+               Name:          s.Name,
+               Importpath:    myimportpath,
+               Info:          info,
+               Filesym:       filesym,
+               Loc:           loc,
+               Ranges:        ranges,
+               Absfn:         absfunc,
+               StartPC:       s,
+               Size:          s.Size,
+               External:      !s.Static(),
+               Scopes:        scopes,
+               InlCalls:      inlcalls,
+               UseBASEntries: ctxt.UseBASEntries,
        }
        if absfunc != nil {
                err = dwarf.PutAbstractFunc(dwctxt, fnstate)
        dwctxt := dwCtxt{ctxt}
        filesym := ctxt.fileSymbol(s)
        fnstate := dwarf.FnState{
-               Name:       s.Name,
-               Importpath: myimportpath,
-               Info:       absfn,
-               Filesym:    filesym,
-               Absfn:      absfn,
-               External:   !s.Static(),
-               Scopes:     scopes,
+               Name:          s.Name,
+               Importpath:    myimportpath,
+               Info:          absfn,
+               Filesym:       filesym,
+               Absfn:         absfn,
+               External:      !s.Static(),
+               Scopes:        scopes,
+               UseBASEntries: ctxt.UseBASEntries,
        }
        if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
                ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
 
        s.(*sym.Symbol).AddAddrPlus(c.linkctxt.Arch, data.(*sym.Symbol), value)
 }
 
+func (c dwctxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
+       if value != 0 {
+               value -= (data.(*sym.Symbol)).Value
+       }
+       s.(*sym.Symbol).AddCURelativeAddrPlus(c.linkctxt.Arch, data.(*sym.Symbol), value)
+}
+
 func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
        ls := s.(*sym.Symbol)
        switch size {
        // Create PC ranges for this CU.
        newattr(unit.dwinfo, dwarf.DW_AT_ranges, dwarf.DW_CLS_PTR, ranges.Size, ranges)
        newattr(unit.dwinfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, base.Value, base)
-       dwarf.PutRanges(dwarfctxt, ranges, nil, pcs)
+       dwarf.PutBasedRanges(dwarfctxt, ranges, pcs)
 
        if ctxt.HeadType == objabi.Haix {
                addDwsectCUSize(".debug_ranges", unit.lib.String(), uint64(ranges.Size-unitLengthOffset))
                        if rangeSym != nil && rangeSym.Size > 0 {
                                rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
                                rangeSym.Type = sym.SDWARFRANGE
-                               // LLVM doesn't support base address entries. Strip them out so LLDB and dsymutil don't get confused.
-                               if ctxt.HeadType == objabi.Hdarwin {
-                                       removeDwarfAddrListBaseAddress(ctxt, dsym, rangeSym, false)
-                               }
                                if ctxt.HeadType == objabi.Haix {
                                        addDwsectCUSize(".debug_ranges", unit.lib.String(), uint64(rangeSym.Size))
 
                                        reloc.Sym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
                                        syms = append(syms, reloc.Sym)
                                        empty = false
-                                       // LLVM doesn't support base address entries. Strip them out so LLDB and dsymutil don't get confused.
-                                       if ctxt.HeadType == objabi.Hdarwin {
-                                               removeDwarfAddrListBaseAddress(ctxt, fn, reloc.Sym, true)
-                                       }
                                        // One location list entry per function, but many relocations to it. Don't duplicate.
                                        break
                                }
        return syms
 }
 
-// removeDwarfAddrListBaseAddress removes base address selector entries from
-// DWARF location lists and range lists.
-func removeDwarfAddrListBaseAddress(ctxt *Link, info, list *sym.Symbol, isloclist bool) {
-       // The list symbol contains multiple lists, but they're all for the
-       // same function, and it's not empty.
-       fn := list.R[0].Sym
-
-       // Discard the relocations for the base address entries.
-       list.R = list.R[:0]
-
-       // Add relocations for each location entry's start and end addresses,
-       // so that the base address entries aren't necessary.
-       // We could remove them entirely, but that's more work for a relatively
-       // small size win. If dsymutil runs it'll throw them away anyway.
-
-       // relocate adds a CU-relative relocation to fn+addr at offset.
-       relocate := func(addr uint64, offset int) {
-               list.R = append(list.R, sym.Reloc{
-                       Off:  int32(offset),
-                       Siz:  uint8(ctxt.Arch.PtrSize),
-                       Type: objabi.R_ADDRCUOFF,
-                       Add:  int64(addr),
-                       Sym:  fn,
-               })
-       }
-
-       for i := 0; i < len(list.P); {
-               first := readPtr(ctxt, list.P[i:])
-               second := readPtr(ctxt, list.P[i+ctxt.Arch.PtrSize:])
-
-               if (first == 0 && second == 0) ||
-                       first == ^uint64(0) ||
-                       (ctxt.Arch.PtrSize == 4 && first == uint64(^uint32(0))) {
-                       // Base address selection entry or end of list. Ignore.
-                       i += ctxt.Arch.PtrSize * 2
-                       continue
-               }
-
-               relocate(first, i)
-               relocate(second, i+ctxt.Arch.PtrSize)
-
-               // Skip past the actual location.
-               i += ctxt.Arch.PtrSize * 2
-               if isloclist {
-                       i += 2 + int(ctxt.Arch.ByteOrder.Uint16(list.P[i:]))
-               }
-       }
-
-       // Rewrite the DIE's relocations to point to the first location entry,
-       // not the now-useless base address selection entry.
-       for i := range info.R {
-               r := &info.R[i]
-               if r.Sym != list {
-                       continue
-               }
-               r.Add += int64(2 * ctxt.Arch.PtrSize)
-       }
-}
-
 // Read a pointer-sized uint from the beginning of buf.
 func readPtr(ctxt *Link, buf []byte) uint64 {
        switch ctxt.Arch.PtrSize {
 
        return s.setUintXX(arch, r, v, int64(arch.PtrSize))
 }
 
-func (s *Symbol) AddAddrPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
+func (s *Symbol) addAddrPlus(arch *sys.Arch, t *Symbol, add int64, typ objabi.RelocType) int64 {
        if s.Type == 0 {
                s.Type = SDATA
        }
        r.Sym = t
        r.Off = int32(i)
        r.Siz = uint8(arch.PtrSize)
-       r.Type = objabi.R_ADDR
+       r.Type = typ
        r.Add = add
        return i + int64(r.Siz)
 }
 
+func (s *Symbol) AddAddrPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
+       return s.addAddrPlus(arch, t, add, objabi.R_ADDR)
+}
+
+func (s *Symbol) AddCURelativeAddrPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
+       return s.addAddrPlus(arch, t, add, objabi.R_ADDRCUOFF)
+}
+
 func (s *Symbol) AddPCRelPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
        if s.Type == 0 {
                s.Type = SDATA