<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Sun, Apr 27, 2014 at 7:06 AM, Rafael Espíndola <span dir="ltr"><<a href="mailto:rafael.espindola@gmail.com" target="_blank">rafael.espindola@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">While this is fine and matches what we did first for ELF, the current<br>
strategy on the ELF side is to put target specific bits in the target<br>
streamer interface. Do you think that would work in here?</blockquote><div><br></div><div>I don't immediately see why it wouldn't. It would certainly be nicer. I'll see if I can wrangle COFF into using MCTargetStreamer.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">
On 26 April 2014 23:48, Saleem Abdulrasool <<a href="mailto:compnerd@compnerd.org">compnerd@compnerd.org</a>> wrote:<br>
> Author: compnerd<br>
> Date: Sat Apr 26 22:48:05 2014<br>
> New Revision: 207343<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=207343&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=207343&view=rev</a><br>
> Log:<br>
> MC: rename WinCOFFStreamer and move declaration out-of-line<br>
><br>
> This is in preparation for promoting WinCOFFStreamer to a base class which will<br>
> be shared by the X86 and ARM specific target COFF streamers. Also add a new<br>
> getOrCreateSymbolData interface (like MCELFStreamer) for the ARM COFF Streamer.<br>
> This makes the COFFStreamer more similar to the ELFStreamer.<br>
><br>
> Added:<br>
> llvm/trunk/include/llvm/MC/MCWinCOFFStreamer.h<br>
> Modified:<br>
> llvm/trunk/lib/MC/WinCOFFStreamer.cpp<br>
><br>
> Added: llvm/trunk/include/llvm/MC/MCWinCOFFStreamer.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCWinCOFFStreamer.h?rev=207343&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCWinCOFFStreamer.h?rev=207343&view=auto</a><br>
> ==============================================================================<br>
> --- llvm/trunk/include/llvm/MC/MCWinCOFFStreamer.h (added)<br>
> +++ llvm/trunk/include/llvm/MC/MCWinCOFFStreamer.h Sat Apr 26 22:48:05 2014<br>
> @@ -0,0 +1,74 @@<br>
> +//===- MCWinCOFFStreamer.h - COFF Object File Interface ---------*- C++ -*-===//<br>
> +//<br>
> +// The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is distributed under the University of Illinois Open Source<br>
> +// License. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +#ifndef LLVM_MC_MCWINCOFFSTREAMER_H<br>
> +#define LLVM_MC_MCWINCOFFSTREAMER_H<br>
> +<br>
> +#include "llvm/MC/MCDirectives.h"<br>
> +#include "llvm/MC/MCObjectStreamer.h"<br>
> +<br>
> +namespace llvm {<br>
> +class MCAsmBackend;<br>
> +class MCContext;<br>
> +class MCCodeEmitter;<br>
> +class MCExpr;<br>
> +class MCInst;<br>
> +class MCSection;<br>
> +class MCSubtargetInfo;<br>
> +class MCSymbol;<br>
> +class StringRef;<br>
> +class raw_ostream;<br>
> +<br>
> +class MCWinCOFFStreamer : public MCObjectStreamer {<br>
> +public:<br>
> + MCWinCOFFStreamer(MCContext &Context, MCAsmBackend &MAB, MCCodeEmitter &CE,<br>
> + raw_ostream &OS);<br>
> +<br>
> + /// \name MCStreamer interface<br>
> + /// \{<br>
> +<br>
> + void InitSections() override;<br>
> + void EmitLabel(MCSymbol *Symbol) override;<br>
> + void EmitDebugLabel(MCSymbol *Symbol) override;<br>
> + void EmitAssemblerFlag(MCAssemblerFlag Flag) override;<br>
> + void EmitThumbFunc(MCSymbol *Func) override;<br>
> + bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;<br>
> + void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override;<br>
> + void BeginCOFFSymbolDef(MCSymbol const *Symbol) override;<br>
> + void EmitCOFFSymbolStorageClass(int StorageClass) override;<br>
> + void EmitCOFFSymbolType(int Type) override;<br>
> + void EndCOFFSymbolDef() override;<br>
> + void EmitCOFFSectionIndex(MCSymbol const *Symbol) override;<br>
> + void EmitCOFFSecRel32(MCSymbol const *Symbol) override;<br>
> + void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;<br>
> + void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,<br>
> + unsigned ByteAlignment) override;<br>
> + void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,<br>
> + unsigned ByteAlignment) override;<br>
> + void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, uint64_t Size,<br>
> + unsigned ByteAlignment) override;<br>
> + void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size,<br>
> + unsigned ByteAlignment) override;<br>
> + void EmitFileDirective(StringRef Filename) override;<br>
> + void EmitIdent(StringRef IdentString) override;<br>
> + void EmitWin64EHHandlerData() override;<br>
> + void FinishImpl() override;<br>
> +<br>
> + /// \}<br>
> +<br>
> + MCSymbolData &getOrCreateSymbolData(const MCSymbol *Symbol);<br>
> +<br>
> +protected:<br>
> + const MCSymbol *CurSymbol;<br>
> + void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &STI) override;<br>
> +};<br>
> +}<br>
> +<br>
> +#endif<br>
> +<br>
><br>
> Modified: llvm/trunk/lib/MC/WinCOFFStreamer.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/WinCOFFStreamer.cpp?rev=207343&r1=207342&r2=207343&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/WinCOFFStreamer.cpp?rev=207343&r1=207342&r2=207343&view=diff</a><br>
> ==============================================================================<br>
> --- llvm/trunk/lib/MC/WinCOFFStreamer.cpp (original)<br>
> +++ llvm/trunk/lib/MC/WinCOFFStreamer.cpp Sat Apr 26 22:48:05 2014<br>
> @@ -7,7 +7,7 @@<br>
> //<br>
> //===----------------------------------------------------------------------===//<br>
> //<br>
> -// This file contains an implementation of a Win32 COFF object file streamer.<br>
> +// This file contains an implementation of a Windows COFF object file streamer.<br>
> //<br>
> //===----------------------------------------------------------------------===//<br>
><br>
> @@ -25,6 +25,7 @@<br>
> #include "llvm/MC/MCSymbol.h"<br>
> #include "llvm/MC/MCValue.h"<br>
> #include "llvm/MC/MCWin64EH.h"<br>
> +#include "llvm/MC/MCWinCOFFStreamer.h"<br>
> #include "llvm/Support/COFF.h"<br>
> #include "llvm/Support/Debug.h"<br>
> #include "llvm/Support/ErrorHandling.h"<br>
> @@ -35,70 +36,31 @@ using namespace llvm;<br>
><br>
> #define DEBUG_TYPE "WinCOFFStreamer"<br>
><br>
> -namespace {<br>
> -class WinCOFFStreamer : public MCObjectStreamer {<br>
> -public:<br>
> - MCSymbol const *CurSymbol;<br>
> -<br>
> - WinCOFFStreamer(MCContext &Context, MCAsmBackend &MAB, MCCodeEmitter &CE,<br>
> - raw_ostream &OS);<br>
> -<br>
> - // MCStreamer interface<br>
> -<br>
> - void InitSections() override;<br>
> - void EmitLabel(MCSymbol *Symbol) override;<br>
> - void EmitDebugLabel(MCSymbol *Symbol) override;<br>
> - void EmitAssemblerFlag(MCAssemblerFlag Flag) override;<br>
> - void EmitThumbFunc(MCSymbol *Func) override;<br>
> - bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;<br>
> - void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override;<br>
> - void BeginCOFFSymbolDef(MCSymbol const *Symbol) override;<br>
> - void EmitCOFFSymbolStorageClass(int StorageClass) override;<br>
> - void EmitCOFFSymbolType(int Type) override;<br>
> - void EndCOFFSymbolDef() override;<br>
> - void EmitCOFFSectionIndex(MCSymbol const *Symbol) override;<br>
> - void EmitCOFFSecRel32(MCSymbol const *Symbol) override;<br>
> - void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;<br>
> - void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,<br>
> - unsigned ByteAlignment) override;<br>
> - void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,<br>
> - unsigned ByteAlignment) override;<br>
> - void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, uint64_t Size,<br>
> - unsigned ByteAlignment) override;<br>
> - void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size,<br>
> - unsigned ByteAlignment) override;<br>
> - void EmitFileDirective(StringRef Filename) override;<br>
> - void EmitIdent(StringRef IdentString) override;<br>
> - void EmitWin64EHHandlerData() override;<br>
> - void FinishImpl() override;<br>
> -<br>
> -private:<br>
> - void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &STI) override {<br>
> - MCDataFragment *DF = getOrCreateDataFragment();<br>
> -<br>
> - SmallVector<MCFixup, 4> Fixups;<br>
> - SmallString<256> Code;<br>
> - raw_svector_ostream VecOS(Code);<br>
> - getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups, STI);<br>
> - VecOS.flush();<br>
> -<br>
> - // Add the fixups and data.<br>
> - for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {<br>
> - Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());<br>
> - DF->getFixups().push_back(Fixups[i]);<br>
> - }<br>
> - DF->getContents().append(Code.begin(), Code.end());<br>
> - }<br>
> -};<br>
> -} // end anonymous namespace.<br>
> -<br>
> -WinCOFFStreamer::WinCOFFStreamer(MCContext &Context, MCAsmBackend &MAB,<br>
> - MCCodeEmitter &CE, raw_ostream &OS)<br>
> +namespace llvm {<br>
> +MCWinCOFFStreamer::MCWinCOFFStreamer(MCContext &Context, MCAsmBackend &MAB,<br>
> + MCCodeEmitter &CE, raw_ostream &OS)<br>
> : MCObjectStreamer(Context, MAB, OS, &CE), CurSymbol(nullptr) {}<br>
><br>
> -// MCStreamer interface<br>
> +void MCWinCOFFStreamer::EmitInstToData(const MCInst &Inst,<br>
> + const MCSubtargetInfo &STI) {<br>
> + MCDataFragment *DF = getOrCreateDataFragment();<br>
><br>
> -void WinCOFFStreamer::InitSections() {<br>
> + SmallVector<MCFixup, 4> Fixups;<br>
> + SmallString<256> Code;<br>
> + raw_svector_ostream VecOS(Code);<br>
> + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups, STI);<br>
> + VecOS.flush();<br>
> +<br>
> + // Add the fixups and data.<br>
> + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {<br>
> + Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());<br>
> + DF->getFixups().push_back(Fixups[i]);<br>
> + }<br>
> +<br>
> + DF->getContents().append(Code.begin(), Code.end());<br>
> +}<br>
> +<br>
> +void MCWinCOFFStreamer::InitSections() {<br>
> // FIXME: this is identical to the ELF one.<br>
> // This emulates the same behavior of GNU as. This makes it easier<br>
> // to compare the output as the major sections are in the same order.<br>
> @@ -114,25 +76,25 @@ void WinCOFFStreamer::InitSections() {<br>
> SwitchSection(getContext().getObjectFileInfo()->getTextSection());<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitLabel(MCSymbol *Symbol) {<br>
> +void MCWinCOFFStreamer::EmitLabel(MCSymbol *Symbol) {<br>
> assert(Symbol->isUndefined() && "Cannot define a symbol twice!");<br>
> MCObjectStreamer::EmitLabel(Symbol);<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitDebugLabel(MCSymbol *Symbol) {<br>
> +void MCWinCOFFStreamer::EmitDebugLabel(MCSymbol *Symbol) {<br>
> EmitLabel(Symbol);<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {<br>
> +void MCWinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {<br>
> llvm_unreachable("not implemented");<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) {<br>
> +void MCWinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) {<br>
> llvm_unreachable("not implemented");<br>
> }<br>
><br>
> -bool WinCOFFStreamer::EmitSymbolAttribute(MCSymbol *Symbol,<br>
> - MCSymbolAttr Attribute) {<br>
> +bool MCWinCOFFStreamer::EmitSymbolAttribute(MCSymbol *Symbol,<br>
> + MCSymbolAttr Attribute) {<br>
> assert(Symbol && "Symbol must be non-null!");<br>
> assert((!Symbol->isInSection() ||<br>
> Symbol->getSection().getVariant() == MCSection::SV_COFF) &&<br>
> @@ -155,11 +117,11 @@ bool WinCOFFStreamer::EmitSymbolAttribut<br>
> return true;<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {<br>
> +void MCWinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {<br>
> llvm_unreachable("not implemented");<br>
> }<br>
><br>
> -void WinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *Symbol) {<br>
> +void MCWinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *Symbol) {<br>
> assert((!Symbol->isInSection() ||<br>
> Symbol->getSection().getVariant() == MCSection::SV_COFF) &&<br>
> "Got non-COFF section in the COFF backend!");<br>
> @@ -167,7 +129,7 @@ void WinCOFFStreamer::BeginCOFFSymbolDef<br>
> CurSymbol = Symbol;<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) {<br>
> +void MCWinCOFFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) {<br>
> assert(CurSymbol && "StorageClass specified outside of symbol definition");<br>
> assert((StorageClass & ~0xFF) == 0 &&<br>
> "StorageClass must only have data in the first byte!");<br>
> @@ -176,7 +138,7 @@ void WinCOFFStreamer::EmitCOFFSymbolStor<br>
> SD.modifyFlags(StorageClass << COFF::SF_ClassShift, COFF::SF_ClassMask);<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitCOFFSymbolType(int Type) {<br>
> +void MCWinCOFFStreamer::EmitCOFFSymbolType(int Type) {<br>
> assert(CurSymbol && "SymbolType specified outside of a symbol definition");<br>
> assert((Type & ~0xFFFF) == 0 &&<br>
> "Type must only have data in the first 2 bytes");<br>
> @@ -185,12 +147,12 @@ void WinCOFFStreamer::EmitCOFFSymbolType<br>
> SD.modifyFlags(Type << COFF::SF_TypeShift, COFF::SF_TypeMask);<br>
> }<br>
><br>
> -void WinCOFFStreamer::EndCOFFSymbolDef() {<br>
> +void MCWinCOFFStreamer::EndCOFFSymbolDef() {<br>
> assert(CurSymbol && "ending symbol definition without beginning one");<br>
> CurSymbol = nullptr;<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) {<br>
> +void MCWinCOFFStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) {<br>
> MCDataFragment *DF = getOrCreateDataFragment();<br>
> const MCSymbolRefExpr *SRE = MCSymbolRefExpr::Create(Symbol, getContext());<br>
> MCFixup Fixup = MCFixup::Create(DF->getContents().size(), SRE, FK_SecRel_2);<br>
> @@ -198,7 +160,7 @@ void WinCOFFStreamer::EmitCOFFSectionInd<br>
> DF->getContents().resize(DF->getContents().size() + 4, 0);<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) {<br>
> +void MCWinCOFFStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) {<br>
> MCDataFragment *DF = getOrCreateDataFragment();<br>
> const MCSymbolRefExpr *SRE = MCSymbolRefExpr::Create(Symbol, getContext());<br>
> MCFixup Fixup = MCFixup::Create(DF->getContents().size(), SRE, FK_SecRel_4);<br>
> @@ -206,12 +168,12 @@ void WinCOFFStreamer::EmitCOFFSecRel32(M<br>
> DF->getContents().resize(DF->getContents().size() + 4, 0);<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {<br>
> +void MCWinCOFFStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {<br>
> llvm_unreachable("not supported");<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,<br>
> - unsigned ByteAlignment) {<br>
> +void MCWinCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,<br>
> + unsigned ByteAlignment) {<br>
> assert((!Symbol->isInSection() ||<br>
> Symbol->getSection().getVariant() == MCSection::SV_COFF) &&<br>
> "Got non-COFF section in the COFF backend!");<br>
> @@ -226,8 +188,8 @@ void WinCOFFStreamer::EmitCommonSymbol(M<br>
> SD.setCommon(Size, ByteAlignment);<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,<br>
> - unsigned ByteAlignment) {<br>
> +void MCWinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,<br>
> + unsigned ByteAlignment) {<br>
> assert(!Symbol->isInSection() && "Symbol must not already have a section!");<br>
><br>
> const MCSection *Section = getContext().getObjectFileInfo()->getBSSSection();<br>
> @@ -249,26 +211,28 @@ void WinCOFFStreamer::EmitLocalCommonSym<br>
> SD.setFragment(Fragment);<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,<br>
> - uint64_t Size, unsigned ByteAlignment) {<br>
> +void MCWinCOFFStreamer::EmitZerofill(const MCSection *Section,<br>
> + MCSymbol *Symbol, uint64_t Size,<br>
> + unsigned ByteAlignment) {<br>
> llvm_unreachable("not implemented");<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,<br>
> - uint64_t Size, unsigned ByteAlignment) {<br>
> +void MCWinCOFFStreamer::EmitTBSSSymbol(const MCSection *Section,<br>
> + MCSymbol *Symbol, uint64_t Size,<br>
> + unsigned ByteAlignment) {<br>
> llvm_unreachable("not implemented");<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitFileDirective(StringRef Filename) {<br>
> +void MCWinCOFFStreamer::EmitFileDirective(StringRef Filename) {<br>
> getAssembler().addFileName(Filename);<br>
> }<br>
><br>
> // TODO: Implement this if you want to emit .comment section in COFF obj files.<br>
> -void WinCOFFStreamer::EmitIdent(StringRef IdentString) {<br>
> +void MCWinCOFFStreamer::EmitIdent(StringRef IdentString) {<br>
> llvm_unreachable("not implemented");<br>
> }<br>
><br>
> -void WinCOFFStreamer::EmitWin64EHHandlerData() {<br>
> +void MCWinCOFFStreamer::EmitWin64EHHandlerData() {<br>
> MCStreamer::EmitWin64EHHandlerData();<br>
><br>
> // We have to emit the unwind info now, because this directive<br>
> @@ -276,17 +240,20 @@ void WinCOFFStreamer::EmitWin64EHHandler<br>
> MCWin64EHUnwindEmitter::EmitUnwindInfo(*this, getCurrentW64UnwindInfo());<br>
> }<br>
><br>
> -void WinCOFFStreamer::FinishImpl() {<br>
> +void MCWinCOFFStreamer::FinishImpl() {<br>
> EmitFrames(nullptr, true);<br>
> EmitW64Tables();<br>
> MCObjectStreamer::FinishImpl();<br>
> }<br>
><br>
> -namespace llvm {<br>
> +MCSymbolData &MCWinCOFFStreamer::getOrCreateSymbolData(const MCSymbol *Symbol) {<br>
> + return getAssembler().getOrCreateSymbolData(*Symbol);<br>
> +}<br>
> +<br>
> MCStreamer *createWinCOFFStreamer(MCContext &Context, MCAsmBackend &MAB,<br>
> MCCodeEmitter &CE, raw_ostream &OS,<br>
> bool RelaxAll) {<br>
> - WinCOFFStreamer *S = new WinCOFFStreamer(Context, MAB, CE, OS);<br>
> + MCWinCOFFStreamer *S = new MCWinCOFFStreamer(Context, MAB, CE, OS);<br>
> S->getAssembler().setRelaxAll(RelaxAll);<br>
> return S;<br>
> }<br>
><br>
><br>
> _______________________________________________<br>
> llvm-commits mailing list<br>
> <a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br>Saleem Abdulrasool<br>compnerd (at) compnerd (dot) org
</div></div>