]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/LinkEditClassic.hpp
ld64-123.2.tar.gz
[apple/ld64.git] / src / ld / LinkEditClassic.hpp
diff --git a/src/ld/LinkEditClassic.hpp b/src/ld/LinkEditClassic.hpp
new file mode 100644 (file)
index 0000000..d5438ac
--- /dev/null
@@ -0,0 +1,2542 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __LINKEDIT_CLASSIC_HPP__
+#define __LINKEDIT_CLASSIC_HPP__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "Options.h"
+#include "ld.hpp"
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+
+namespace ld {
+namespace tool {
+
+
+
+class ClassicLinkEditAtom : public ld::Atom
+{
+public:
+
+       // overrides of ld::Atom
+       virtual ld::File*                                                       file() const            { return NULL; }
+       virtual bool                                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                                       { return false; }
+       virtual uint64_t                                                        objectAddress() const { return 0; }
+
+       virtual void                                                            encode() = 0;
+       virtual bool                                                            hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe) { return false; }
+
+                                                                                               ClassicLinkEditAtom(const Options& opts, ld::Internal& state, 
+                                                                                                                               OutputFile& writer, const ld::Section& sect,
+                                                                                                                               unsigned int pointerSize)
+                                                                                               : ld::Atom(sect, ld::Atom::definitionRegular,
+                                                                                                                       ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
+                                                                                                                       ld::Atom::typeUnclassified, ld::Atom::symbolTableNotIn,
+                                                                                                                       false, false, false, ld::Atom::Alignment(log2(pointerSize))), 
+                                                                                                               _options(opts), _state(state), _writer(writer) { }
+protected:     
+       const Options&                          _options;
+       ld::Internal&                           _state;
+       OutputFile&                                     _writer;
+};
+
+
+
+class StringPoolAtom : public ClassicLinkEditAtom
+{
+public:
+                                                                                               StringPoolAtom(const Options& opts, ld::Internal& state, 
+                                                                                                                               OutputFile& writer, int pointerSize);
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "string pool"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode() { }
+
+       int32_t                                                                         add(const char* name);
+       int32_t                                                                         addUnique(const char* name);
+       int32_t                                                                         emptyString()                   { return 1; }
+       const char*                                                                     stringForIndex(int32_t) const;
+       uint32_t                                                                        currentOffset();
+
+private:
+       class CStringEquals
+       {
+       public:
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       enum { kBufferSize = 0x01000000 };
+       typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
+
+       const uint32_t                                                  _pointerSize;
+       std::vector<char*>                                              _fullBuffers;
+       char*                                                                   _currentBuffer;
+       uint32_t                                                                _currentBufferUsed;
+       StringToOffset                                                  _uniqueStrings;
+
+       static ld::Section                      _s_section;
+};
+
+ld::Section StringPoolAtom::_s_section("__LINKEDIT", "__string_pool", ld::Section::typeLinkEdit, true);
+
+
+StringPoolAtom::StringPoolAtom(const Options& opts, ld::Internal& state, OutputFile& writer, int pointerSize)
+       : ClassicLinkEditAtom(opts, state, writer, _s_section, pointerSize), 
+        _pointerSize(pointerSize), _currentBuffer(NULL), _currentBufferUsed(0)
+{
+       _currentBuffer = new char[kBufferSize];
+       // burn first byte of string pool (so zero is never a valid string offset)
+       _currentBuffer[_currentBufferUsed++] = ' ';
+       // make offset 1 always point to an empty string
+       _currentBuffer[_currentBufferUsed++] = '\0';
+}
+
+uint64_t StringPoolAtom::size() const
+{
+       // pointer size align size
+       return (kBufferSize * _fullBuffers.size() + _currentBufferUsed + _pointerSize-1) & (-_pointerSize);
+}
+
+void StringPoolAtom::copyRawContent(uint8_t buffer[]) const
+{
+       uint64_t offset = 0;
+       for (unsigned int i=0; i < _fullBuffers.size(); ++i) {
+               memcpy(&buffer[offset], _fullBuffers[i], kBufferSize);
+               offset += kBufferSize;
+       }
+       memcpy(&buffer[offset], _currentBuffer, _currentBufferUsed);
+       // zero fill end to align
+       offset += _currentBufferUsed;
+       while ( (offset % _pointerSize) != 0 )
+               buffer[offset++] = 0;
+}
+
+int32_t StringPoolAtom::add(const char* str)
+{
+       int32_t offset = kBufferSize * _fullBuffers.size() + _currentBufferUsed;
+       int lenNeeded = strlcpy(&_currentBuffer[_currentBufferUsed], str, kBufferSize-_currentBufferUsed)+1;
+       if ( (_currentBufferUsed+lenNeeded) < kBufferSize ) {
+               _currentBufferUsed += lenNeeded;
+       }
+       else {
+               int copied = kBufferSize-_currentBufferUsed-1;
+               // change trailing '\0' that strlcpy added to real char
+               _currentBuffer[kBufferSize-1] = str[copied];
+               // alloc next buffer
+               _fullBuffers.push_back(_currentBuffer);
+               _currentBuffer = new char[kBufferSize];
+               _currentBufferUsed = 0;
+               // append rest of string
+               this->add(&str[copied+1]);
+       }
+       return offset;
+}
+
+uint32_t StringPoolAtom::currentOffset()
+{
+       return kBufferSize * _fullBuffers.size() + _currentBufferUsed;
+}
+
+
+int32_t StringPoolAtom::addUnique(const char* str)
+{
+       StringToOffset::iterator pos = _uniqueStrings.find(str);
+       if ( pos != _uniqueStrings.end() ) {
+               return pos->second;
+       }
+       else {
+               int32_t offset = this->add(str);
+               _uniqueStrings[str] = offset;
+               return offset;
+       }
+}
+
+
+const char* StringPoolAtom::stringForIndex(int32_t index) const
+{
+       int32_t currentBufferStartIndex = kBufferSize * _fullBuffers.size();
+       int32_t maxIndex = currentBufferStartIndex + _currentBufferUsed;
+       // check for out of bounds
+       if ( index > maxIndex )
+               return "";
+       // check for index in _currentBuffer
+       if ( index > currentBufferStartIndex )
+               return &_currentBuffer[index-currentBufferStartIndex];
+       // otherwise index is in a full buffer
+       uint32_t fullBufferIndex = index/kBufferSize;
+       return &_fullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
+}
+
+
+
+template <typename A>
+class SymbolTableAtom : public ClassicLinkEditAtom
+{
+public:
+                                                                                               SymbolTableAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : ClassicLinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)),
+                                                                                                               _stabsStringsOffsetStart(0), _stabsStringsOffsetEnd(0),
+                                                                                                               _stabsIndexStart(0), _stabsIndexEnd(0) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "symbol table"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode();
+       virtual bool                                                            hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe);
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+
+       bool                                                    addLocal(const ld::Atom* atom, StringPoolAtom* pool);
+       void                                                    addGlobal(const ld::Atom* atom, StringPoolAtom* pool);
+       void                                                    addImport(const ld::Atom* atom, StringPoolAtom* pool);
+       uint8_t                                                 classicOrdinalForProxy(const ld::Atom* atom);
+       uint32_t                                                stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool);
+       uint64_t                                                valueForStab(const ld::relocatable::File::Stab& stab);
+       uint8_t                                                 sectionIndexForStab(const ld::relocatable::File::Stab& stab);
+       
+
+       mutable std::vector<macho_nlist<P> >    _globals;
+       mutable std::vector<macho_nlist<P> >    _locals;
+       mutable std::vector<macho_nlist<P> >    _imports;
+       
+       uint32_t                                                                _stabsStringsOffsetStart;
+       uint32_t                                                                _stabsStringsOffsetEnd;
+       uint32_t                                                                _stabsIndexStart;
+       uint32_t                                                                _stabsIndexEnd;
+
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section SymbolTableAtom<A>::_s_section("__LINKEDIT", "__symbol_table", ld::Section::typeLinkEdit, true);
+
+
+
+template <typename A>
+bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool) 
+{
+       macho_nlist<P> entry;
+       static int s_anonNameIndex = 1;
+       assert(atom->symbolTableInclusion() != ld::Atom::symbolTableNotIn);
+        
+       // set n_strx
+       const char* symbolName = atom->name();
+       char anonName[32];
+       if ( this->_options.outputKind() == Options::kObjectFile ) {
+               if ( atom->contentType() == ld::Atom::typeCString ) {
+                       if ( atom->combine() == ld::Atom::combineByNameAndContent ) {
+                               // don't use 'l' labels for x86_64 strings
+                               // <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
+                               sprintf(anonName, "LC%u", s_anonNameIndex++);
+                               symbolName = anonName;
+                       }
+               }
+               else if ( atom->contentType() == ld::Atom::typeCFI ) {
+                       if ( _options.removeEHLabels() )
+                               return false;
+                       // synthesize .eh name
+                       if ( strcmp(atom->name(), "CIE") == 0 )
+                               symbolName = "EH_Frame1";
+                       else
+                               symbolName = "func.eh";
+               }
+               else if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) {
+                       // make auto-strip anonymous name for symbol 
+                       sprintf(anonName, "l%03u", s_anonNameIndex++);
+                       symbolName = anonName;
+               }
+       }
+       entry.set_n_strx(pool->add(symbolName));
+
+       // set n_type
+       uint8_t type = N_SECT;
+       if ( atom->definition() == ld::Atom::definitionAbsolute ) {
+               type = N_ABS;
+       }
+       else if ( (atom->section().type() == ld::Section::typeObjC1Classes) 
+                               && (this->_options.outputKind() == Options::kObjectFile) ) {
+               // __OBJC __class has floating abs symbols for each class data structure
+               type = N_ABS;
+       }
+       if ( atom->scope() == ld::Atom::scopeLinkageUnit )
+               type |= N_PEXT;
+       entry.set_n_type(type);
+
+       // set n_sect (section number of implementation )
+       if ( atom->definition() == ld::Atom::definitionAbsolute )
+               entry.set_n_sect(0);
+       else
+               entry.set_n_sect(atom->machoSection());
+
+       // set n_desc
+       uint16_t desc = 0;
+    if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip )
+        desc |= REFERENCED_DYNAMICALLY;
+    if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) )
+        desc |= N_NO_DEAD_STRIP;
+       if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
+               desc |= N_WEAK_DEF;
+       if ( atom->isThumb() )
+               desc |= N_ARM_THUMB_DEF;
+       entry.set_n_desc(desc);
+
+       // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+       if ( atom->definition() == ld::Atom::definitionAbsolute ) 
+               entry.set_n_value(atom->objectAddress());
+       else
+               entry.set_n_value(atom->finalAddress());
+       
+       // add to array
+       _locals.push_back(entry);
+       return true;
+}
+
+
+template <typename A>
+void SymbolTableAtom<A>::addGlobal(const ld::Atom* atom, StringPoolAtom* pool) 
+{
+       macho_nlist<P> entry;
+
+       // set n_strx
+       entry.set_n_strx(pool->add(atom->name()));
+
+       // set n_type
+       if ( atom->definition() == ld::Atom::definitionAbsolute ) {
+               entry.set_n_type(N_EXT | N_ABS);
+       }
+       else if ( (atom->section().type() == ld::Section::typeObjC1Classes)
+                               && (this->_options.outputKind() == Options::kObjectFile) ) {
+               // __OBJC __class has floating abs symbols for each class data structure
+               entry.set_n_type(N_EXT | N_ABS);
+       }
+       else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) ) {
+               entry.set_n_type(N_EXT | N_INDR);
+       }
+       else {
+               entry.set_n_type(N_EXT | N_SECT);
+               if ( (atom->scope() == ld::Atom::scopeLinkageUnit) && (this->_options.outputKind() == Options::kObjectFile) ) {
+                       if ( this->_options.keepPrivateExterns() )
+                               entry.set_n_type(N_EXT | N_SECT | N_PEXT);
+               }
+               else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)
+                                       && (atom->section().type() == ld::Section::typeMachHeader) ) {
+                       // the __mh_execute_header is historical magic and must be an absolute symbol
+                       entry.set_n_type(N_EXT | N_ABS);
+               }
+       }
+
+       // set n_sect (section number of implementation)
+       if ( atom->definition() == ld::Atom::definitionAbsolute )
+               entry.set_n_sect(0);
+       else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) )
+               entry.set_n_sect(0); 
+       else
+               entry.set_n_sect(atom->machoSection());
+
+       // set n_desc
+       uint16_t desc = 0;
+    if ( atom->isThumb() )
+        desc |= N_ARM_THUMB_DEF;
+    if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip )
+        desc |= REFERENCED_DYNAMICALLY;
+    if ( (atom->contentType() == ld::Atom::typeResolver) && (this->_options.outputKind() == Options::kObjectFile) )
+        desc |= N_SYMBOL_RESOLVER;
+    if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) )
+        desc |= N_NO_DEAD_STRIP;
+       if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) ) {
+               desc |= N_WEAK_DEF;
+               // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
+               if ( (atom->scope() == ld::Atom::scopeGlobal) && atom->autoHide() && (this->_options.outputKind() == Options::kObjectFile) ) 
+                       desc |= N_WEAK_REF;
+       }
+       entry.set_n_desc(desc);
+
+       // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+       if ( atom->definition() == ld::Atom::definitionAbsolute ) 
+               entry.set_n_value(atom->objectAddress());
+       else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) ) {
+               if ( atom->isAlias() ) {
+                       // this re-export also renames
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                               if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                                       assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                                       entry.set_n_value(pool->add(fit->u.target->name()));
+                               }
+                       }
+               }
+               else
+                       entry.set_n_value(entry.n_strx());
+       }
+       else
+               entry.set_n_value(atom->finalAddress());
+               
+       // add to array
+       _globals.push_back(entry);
+}
+
+template <typename A>
+uint8_t        SymbolTableAtom<A>::classicOrdinalForProxy(const ld::Atom* atom)
+{
+       assert(atom->definition() == ld::Atom::definitionProxy);
+       // when linking for flat-namespace ordinals are always zero 
+       if ( _options.nameSpace() != Options::kTwoLevelNameSpace )
+               return 0;
+       const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(atom->file());
+       // when linking -undefined dynamic_lookup, unbound symbols use DYNAMIC_LOOKUP_ORDINAL
+       if ( dylib == NULL ) {
+               if (_options.undefinedTreatment() == Options::kUndefinedDynamicLookup )
+                       return DYNAMIC_LOOKUP_ORDINAL;
+               if (_options.allowedUndefined(atom->name()) )
+                       return DYNAMIC_LOOKUP_ORDINAL;
+       }
+       assert(dylib != NULL);
+       int ord = this->_writer.dylibToOrdinal(dylib);
+       if ( ord == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE )
+               return EXECUTABLE_ORDINAL;
+       return ord;
+}
+
+
+template <typename A>
+void SymbolTableAtom<A>::addImport(const ld::Atom* atom, StringPoolAtom* pool) 
+{
+       macho_nlist<P> entry;
+
+       // set n_strx
+       entry.set_n_strx(pool->add(atom->name()));
+
+       // set n_type
+       if ( this->_options.outputKind() == Options::kObjectFile ) {
+               if ( (atom->scope() == ld::Atom::scopeLinkageUnit) 
+                               && (atom->definition() == ld::Atom::definitionTentative) )
+                       entry.set_n_type(N_UNDF | N_EXT | N_PEXT);
+               else 
+                       entry.set_n_type(N_UNDF | N_EXT);
+       }
+       else {
+               if ( this->_options.prebind() )
+                       entry.set_n_type(N_PBUD | N_EXT);
+               else 
+                       entry.set_n_type(N_UNDF | N_EXT);
+       }
+
+       // set n_sect
+       entry.set_n_sect(0);
+
+       uint16_t desc = 0;
+       if ( this->_options.outputKind() != Options::kObjectFile ) {
+               uint8_t ordinal = this->classicOrdinalForProxy(atom);
+               //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
+               SET_LIBRARY_ORDINAL(desc, ordinal);
+               
+#if 0
+               // set n_desc ( high byte is library ordinal, low byte is reference type )
+               std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
+               if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
+                       desc |= REFERENCE_FLAG_UNDEFINED_LAZY;
+               else
+                       desc |= REFERENCE_FLAG_UNDEFINED_NON_LAZY;
+#endif
+       }
+       else if ( atom->definition() == ld::Atom::definitionTentative ) {
+               uint8_t align = atom->alignment().powerOf2;
+               // always record custom alignment of common symbols to match what compiler does
+               SET_COMM_ALIGN(desc, align);
+       }
+       if ( (this->_options.outputKind() != Options::kObjectFile)
+               && (atom->definition() == ld::Atom::definitionProxy) 
+               && (atom->combine() == ld::Atom::combineByName) ) {
+                       desc |= N_REF_TO_WEAK;
+       }
+       if ( atom->weakImported() )     
+               desc |= N_WEAK_REF;
+       entry.set_n_desc(desc);
+
+       // set n_value, zero for import proxy and size for tentative definition
+       if ( atom->definition() == ld::Atom::definitionTentative )
+               entry.set_n_value(atom->size());
+       else
+               entry.set_n_value(0);
+       
+       // add to array
+       _imports.push_back(entry);
+}
+
+template <typename A>
+uint8_t SymbolTableAtom<A>::sectionIndexForStab(const ld::relocatable::File::Stab& stab)
+{
+       // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
+       if ( stab.type == N_FUN )
+               return stab.other;
+       else if ( stab.type == N_GSYM ) 
+               return 0;
+       else if ( stab.atom != NULL ) 
+               return stab.atom->machoSection();
+       else
+               return stab.other;
+}
+
+
+template <typename A>
+uint64_t SymbolTableAtom<A>::valueForStab(const ld::relocatable::File::Stab& stab)
+{
+       switch ( stab.type ) {
+               case N_FUN:
+                       if ( stab.atom == NULL ) {
+                               // <rdar://problem/5591394> Add support to ld64 for N_FUN stabs when used for symbolic constants
+                               return stab.value;
+                       }
+                       if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
+                               // end of function N_FUN has size
+                               return stab.atom->size();
+                       }
+                       else {
+                               // start of function N_FUN has address
+                               return stab.atom->finalAddress();
+                       }
+               case N_LBRAC:
+               case N_RBRAC:
+               case N_SLINE:
+                       if ( stab.atom == NULL )
+                               // some weird assembly files have slines not associated with a function
+                               return stab.value;
+                       else
+                               // all these stab types need their value changed from an offset in the atom to an address
+                               return stab.atom->finalAddress() + stab.value;
+               case N_STSYM:
+               case N_LCSYM:
+               case N_BNSYM:
+                       // all these need address of atom
+                       if ( stab.atom != NULL )
+                               return stab.atom->finalAddress();
+                       else
+                               return 0;  // <rdar://problem/7811357> work around for mismatch N_BNSYM 
+               case N_ENSYM:
+                       return stab.atom->size();
+               case N_SO:
+                       if ( stab.atom == NULL ) {
+                               return 0;
+                       }
+                       else {
+                               if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
+                                       // end of translation unit N_SO has address of end of last atom
+                                       return stab.atom->finalAddress() + stab.atom->size();
+                               }
+                               else {
+                                       // start of translation unit N_SO has address of end of first atom
+                                       return stab.atom->finalAddress();
+                               }
+                       }
+                       break;
+               default:
+                       return stab.value;
+       }
+}
+
+template <typename A>
+uint32_t SymbolTableAtom<A>::stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool)
+{
+       switch (stab.type) {
+               case N_SO:
+                       if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
+                               return pool->emptyString();
+                               break;
+                       }
+                       // fall into uniquing case
+               case N_SOL:
+               case N_BINCL:
+               case N_EXCL:
+                       return pool->addUnique(stab.string);
+                       break;
+               default:
+                       if ( stab.string == NULL )
+                               return 0;
+                       else if ( stab.string[0] == '\0' )
+                               return pool->emptyString();
+                       else
+                               return pool->add(stab.string);
+       }
+       return 0;
+}
+
+
+
+template <typename A>
+bool SymbolTableAtom<A>::hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe)
+{
+       ssos = _stabsStringsOffsetStart;
+       ssoe = _stabsStringsOffsetEnd;
+       sos = _stabsIndexStart * sizeof(macho_nlist<P>);
+       soe = _stabsIndexEnd * sizeof(macho_nlist<P>);
+       return ( (_stabsIndexStart != _stabsIndexEnd) || (_stabsStringsOffsetStart != _stabsStringsOffsetEnd) );
+}
+
+template <typename A>
+void SymbolTableAtom<A>::encode()
+{
+       uint32_t symbolIndex = 0;
+
+       // make nlist entries for all local symbols
+       std::vector<const ld::Atom*>& localAtoms = this->_writer._localAtoms;
+       _locals.reserve(localAtoms.size()+this->_state.stabs.size());
+       this->_writer._localSymbolsStartIndex = 0;
+       // make nlist entries for all debug notes
+       _stabsIndexStart = symbolIndex;
+       _stabsStringsOffsetStart = this->_writer._stringPoolAtom->currentOffset();
+       for (std::vector<ld::relocatable::File::Stab>::const_iterator sit=this->_state.stabs.begin(); sit != this->_state.stabs.end(); ++sit) {
+               macho_nlist<P> entry;
+               entry.set_n_type(sit->type);
+               entry.set_n_sect(sectionIndexForStab(*sit));
+               entry.set_n_desc(sit->desc);
+               entry.set_n_value(valueForStab(*sit));
+               entry.set_n_strx(stringOffsetForStab(*sit, this->_writer._stringPoolAtom));
+               _locals.push_back(entry);
+               ++symbolIndex;
+       }
+       _stabsIndexEnd = symbolIndex;
+       _stabsStringsOffsetEnd = this->_writer._stringPoolAtom->currentOffset();
+       for (std::vector<const ld::Atom*>::const_iterator it=localAtoms.begin(); it != localAtoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               if ( this->addLocal(atom, this->_writer._stringPoolAtom) )
+                       this->_writer._atomToSymbolIndex[atom] = symbolIndex++;
+       }
+       this->_writer._localSymbolsCount = symbolIndex;
+       
+
+       // make nlist entries for all global symbols
+       std::vector<const ld::Atom*>& globalAtoms = this->_writer._exportedAtoms;
+       _globals.reserve(globalAtoms.size());
+       this->_writer._globalSymbolsStartIndex = symbolIndex;
+       for (std::vector<const ld::Atom*>::const_iterator it=globalAtoms.begin(); it != globalAtoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               this->addGlobal(atom, this->_writer._stringPoolAtom);
+               this->_writer._atomToSymbolIndex[atom] = symbolIndex++;
+       }
+       this->_writer._globalSymbolsCount = symbolIndex - this->_writer._globalSymbolsStartIndex;
+
+       // make nlist entries for all undefined (imported) symbols
+       std::vector<const ld::Atom*>& importAtoms = this->_writer._importedAtoms;
+       _imports.reserve(importAtoms.size());
+       this->_writer._importSymbolsStartIndex = symbolIndex;
+       for (std::vector<const ld::Atom*>::const_iterator it=importAtoms.begin(); it != importAtoms.end(); ++it) {
+               this->addImport(*it, this->_writer._stringPoolAtom);
+               this->_writer._atomToSymbolIndex[*it] = symbolIndex++;
+       }
+       this->_writer._importSymbolsCount = symbolIndex - this->_writer._importSymbolsStartIndex;
+}
+
+template <typename A>
+uint64_t SymbolTableAtom<A>::size() const
+{
+       return sizeof(macho_nlist<P>) * (_locals.size() + _globals.size() + _imports.size());
+}
+
+template <typename A>
+void SymbolTableAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       memcpy(&buffer[this->_writer._localSymbolsStartIndex*sizeof(macho_nlist<P>)], &_locals[0], 
+                                                                                               this->_writer._localSymbolsCount*sizeof(macho_nlist<P>));
+       memcpy(&buffer[this->_writer._globalSymbolsStartIndex*sizeof(macho_nlist<P>)], &_globals[0],
+                                                                                               this->_writer._globalSymbolsCount*sizeof(macho_nlist<P>));
+       memcpy(&buffer[this->_writer._importSymbolsStartIndex *sizeof(macho_nlist<P>)], &_imports[0], 
+                                                                                               this->_writer._importSymbolsCount*sizeof(macho_nlist<P>));
+}
+
+
+
+
+class RelocationsAtomAbstract : public ClassicLinkEditAtom
+{
+public:
+                                                                                               RelocationsAtomAbstract(const Options& opts, ld::Internal& state, 
+                                                                                                                               OutputFile& writer, const ld::Section& sect,
+                                                                                                                               unsigned int pointerSize)
+                                                                                                       : ClassicLinkEditAtom(opts, state, writer, sect, pointerSize) { }
+
+       virtual void                                                    addPointerReloc(uint64_t addr, uint32_t symNum) = 0;
+       virtual void                                                    addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) = 0;
+       virtual void                                                    addExternalPointerReloc(uint64_t addr, const ld::Atom*) = 0;
+       virtual void                                                    addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) = 0;
+       virtual uint64_t                                                relocBaseAddress(ld::Internal& state) = 0;
+       virtual void                                                    addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
+                                                                                                                       const ld::Atom* inAtom, uint32_t offsetInAtom, 
+                                                                                                                       bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+                                                                                                                       const ld::Atom* toTarget, uint64_t toAddend, 
+                                                                                                                       const ld::Atom* fromTarget, uint64_t fromAddend) = 0;
+protected:
+       uint32_t                                                                symbolIndex(const ld::Atom* atom) const;
+
+};
+
+
+
+uint32_t RelocationsAtomAbstract::symbolIndex(const ld::Atom* atom) const
+{
+       std::map<const ld::Atom*, uint32_t>::iterator pos = this->_writer._atomToSymbolIndex.find(atom);
+       if ( pos != this->_writer._atomToSymbolIndex.end() )
+               return pos->second;
+       fprintf(stderr, "_atomToSymbolIndex content:\n");
+       for(std::map<const ld::Atom*, uint32_t>::iterator it = this->_writer._atomToSymbolIndex.begin(); it != this->_writer._atomToSymbolIndex.end(); ++it) {
+                       fprintf(stderr, "%p(%s) => %d\n", it->first, it->first->name(), it->second);
+       }
+       throwf("internal error: atom not found in symbolIndex(%s)", atom->name());
+}
+
+
+template <typename A>
+class LocalRelocationsAtom : public RelocationsAtomAbstract
+{
+public:
+                                                                                               LocalRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "local relocations"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode() {}
+       // overrides of RelocationsAtomAbstract
+       virtual void                                                            addPointerReloc(uint64_t addr, uint32_t symNum);
+       virtual void                                                            addExternalPointerReloc(uint64_t addr, const ld::Atom*) {}
+       virtual void                                                            addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) {}
+       virtual uint64_t                                                        relocBaseAddress(ld::Internal& state);
+       virtual void                                                            addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum);
+       virtual void                                                            addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
+                                                                                                                       const ld::Atom* inAtom, uint32_t offsetInAtom, 
+                                                                                                                       bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+                                                                                                                       const ld::Atom* toTarget, uint64_t toAddend, 
+                                                                                                                       const ld::Atom* fromTarget, uint64_t fromAddend) { }
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+       
+       std::vector<macho_relocation_info<P> >          _relocs;
+
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section LocalRelocationsAtom<A>::_s_section("__LINKEDIT", "__local_relocs", ld::Section::typeLinkEdit, true);
+
+
+template <>
+uint64_t LocalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
+{
+       if ( _options.outputKind() == Options::kKextBundle ) {
+               // for kext bundles the reloc base address starts at __TEXT segment
+               return _options.baseAddress();
+       }
+       // for all other kinds, the x86_64 reloc base address starts at __DATA segment
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+                       return sect->address;
+       }
+       throw "__DATA segment not found";
+}
+
+template <typename A>
+uint64_t LocalRelocationsAtom<A>::relocBaseAddress(ld::Internal& state)
+{
+       return _options.baseAddress();
+}
+
+template <typename A>
+void LocalRelocationsAtom<A>::addPointerReloc(uint64_t addr, uint32_t symNum)
+{
+       macho_relocation_info<P> reloc;
+       reloc.set_r_address(addr);
+       reloc.set_r_symbolnum(symNum);
+       reloc.set_r_pcrel(false);
+       reloc.set_r_length();
+       reloc.set_r_extern(false);
+       reloc.set_r_type(GENERIC_RELOC_VANILLA);
+       _relocs.push_back(reloc);
+}
+
+template <typename A>
+void LocalRelocationsAtom<A>::addTextReloc(uint64_t addr, ld::Fixup::Kind kind, uint64_t targetAddr, uint32_t symNum)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       switch ( kind ) {
+               case ld::Fixup::kindStorePPCAbsLow14:
+               case ld::Fixup::kindStorePPCAbsLow16:
+                       // a reference to the absolute address of something in this same linkage unit can be 
+                       // encoded as a local text reloc in a dylib or bundle 
+                       if ( _options.outputSlidable() ) {
+                               reloc1.set_r_address(addr);
+                               reloc1.set_r_symbolnum(symNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(false);
+                               reloc1.set_r_type(kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
+                               reloc2.set_r_address(targetAddr >> 16);
+                               reloc2.set_r_symbolnum(0);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(PPC_RELOC_PAIR);
+                               _relocs.push_back(reloc1);
+                               _relocs.push_back(reloc2);
+                       }
+                       break;
+               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
+               case ld::Fixup::kindStorePPCAbsHigh16:
+                       if ( _options.outputSlidable() ) {
+                               reloc1.set_r_address(addr);
+                               reloc1.set_r_symbolnum(symNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(false);
+                               reloc1.set_r_type(kind==ld::Fixup::kindStorePPCAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16);
+                               reloc2.set_r_address(targetAddr & 0xFFFF);
+                               reloc2.set_r_symbolnum(0);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(PPC_RELOC_PAIR);
+                               _relocs.push_back(reloc1);
+                               _relocs.push_back(reloc2);
+                       }
+                       break;
+               default:
+                       break;
+       }
+}
+
+
+template <typename A>
+uint64_t LocalRelocationsAtom<A>::size() const
+{
+       return _relocs.size() * sizeof(macho_relocation_info<P>);
+}
+
+template <typename A>
+void LocalRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       memcpy(buffer, &_relocs[0], _relocs.size()*sizeof(macho_relocation_info<P>));
+}
+
+
+
+
+
+
+template <typename A>
+class ExternalRelocationsAtom : public RelocationsAtomAbstract
+{
+public:
+                                                                                               ExternalRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "external relocations"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode() {}
+       // overrides of RelocationsAtomAbstract
+       virtual void                                                            addPointerReloc(uint64_t addr, uint32_t symNum) {}
+       virtual void                                                            addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) {}
+       virtual void                                                            addExternalPointerReloc(uint64_t addr, const ld::Atom*);
+       virtual void                                                            addExternalCallSiteReloc(uint64_t addr, const ld::Atom*);
+       virtual uint64_t                                                        relocBaseAddress(ld::Internal& state);
+       virtual void                                                            addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
+                                                                                                                       const ld::Atom* inAtom, uint32_t offsetInAtom, 
+                                                                                                                       bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+                                                                                                                       const ld::Atom* toTarget, uint64_t toAddend, 
+                                                                                                                       const ld::Atom* fromTarget, uint64_t fromAddend) { }
+       
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+       
+       struct LocAndAtom { 
+                                                       LocAndAtom(uint64_t l, const ld::Atom* a) : loc(l), atom(a), symbolIndex(0) {}
+
+               uint64_t                        loc; 
+               const ld::Atom*         atom; 
+               uint32_t                        symbolIndex;
+               
+               bool operator<(const LocAndAtom& rhs) const {
+                       // sort first by symbol number
+                       if ( this->symbolIndex != rhs.symbolIndex )
+                               return (this->symbolIndex < rhs.symbolIndex);
+                       // then sort all uses of the same symbol by address
+                       return (this->loc < rhs.loc);
+               }
+               
+       };
+
+       static uint32_t         pointerReloc();
+       static uint32_t         callReloc();
+
+       mutable std::vector<LocAndAtom>                 _pointerLocations;
+       mutable std::vector<LocAndAtom>                 _callSiteLocations;
+
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section ExternalRelocationsAtom<A>::_s_section("__LINKEDIT", "__extrn_relocs", ld::Section::typeLinkEdit, true);
+
+template <>
+uint64_t ExternalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
+{
+       // for x86_64 the reloc base address starts at __DATA segment
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+                       return sect->address;
+       }
+       throw "__DATA segment not found";
+}
+
+template <typename A>
+uint64_t ExternalRelocationsAtom<A>::relocBaseAddress(ld::Internal& state)
+{
+       return 0;
+}
+
+template <typename A>
+void ExternalRelocationsAtom<A>::addExternalPointerReloc(uint64_t addr, const ld::Atom* target)
+{
+       _pointerLocations.push_back(LocAndAtom(addr, target));
+}
+
+template <typename A>
+void ExternalRelocationsAtom<A>::addExternalCallSiteReloc(uint64_t addr, const ld::Atom* target)
+{
+       _callSiteLocations.push_back(LocAndAtom(addr, target));
+}
+
+
+template <typename A>
+uint64_t ExternalRelocationsAtom<A>::size() const
+{
+       if ( _options.outputKind() == Options::kStaticExecutable ) {
+               assert(_pointerLocations.size() == 0);
+               assert(_callSiteLocations.size() == 0);
+       }
+       return (_pointerLocations.size() + _callSiteLocations.size()) * sizeof(macho_relocation_info<P>);
+}
+
+template <> uint32_t ExternalRelocationsAtom<arm>::pointerReloc() { return ARM_RELOC_VANILLA; }
+template <> uint32_t ExternalRelocationsAtom<x86>::pointerReloc() { return GENERIC_RELOC_VANILLA; }
+template <> uint32_t ExternalRelocationsAtom<ppc>::pointerReloc() { return PPC_RELOC_VANILLA; }
+template <> uint32_t ExternalRelocationsAtom<x86_64>::pointerReloc() { return X86_64_RELOC_UNSIGNED; }
+template <> uint32_t ExternalRelocationsAtom<ppc64>::pointerReloc() { return PPC_RELOC_VANILLA; }
+
+
+template <> uint32_t ExternalRelocationsAtom<x86_64>::callReloc() { return X86_64_RELOC_BRANCH; }
+template <> uint32_t ExternalRelocationsAtom<x86>::callReloc() { return GENERIC_RELOC_VANILLA; }
+template <typename A> 
+uint32_t ExternalRelocationsAtom<A>::callReloc() 
+{ 
+       assert(0 && "external call relocs not implemented");
+       return 0; 
+}
+
+
+template <typename A>
+void ExternalRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       macho_relocation_info<P>* r = (macho_relocation_info<P>*)buffer;
+       
+       // assign symbol index, now that symbol table is built
+       for (typename std::vector<LocAndAtom>::iterator it = _pointerLocations.begin(); it != _pointerLocations.end(); ++it) {
+               it->symbolIndex = symbolIndex(it->atom);
+       }
+       std::sort(_pointerLocations.begin(), _pointerLocations.end());
+       for (typename std::vector<LocAndAtom>::const_iterator it = _pointerLocations.begin(); it != _pointerLocations.end(); ++it, ++r) {
+               r->set_r_address(it->loc);
+               r->set_r_symbolnum(it->symbolIndex);
+               r->set_r_pcrel(false);
+               r->set_r_length();
+               r->set_r_extern(true);
+               r->set_r_type(this->pointerReloc());
+       }
+       
+       for (typename std::vector<LocAndAtom>::iterator it = _callSiteLocations.begin(); it != _callSiteLocations.end(); ++it) {
+               it->symbolIndex = symbolIndex(it->atom);
+       }
+       std::sort(_callSiteLocations.begin(), _callSiteLocations.end());
+       for (typename std::vector<LocAndAtom>::const_iterator it = _callSiteLocations.begin(); it != _callSiteLocations.end(); ++it, ++r) {
+               r->set_r_address(it->loc);
+               r->set_r_symbolnum(it->symbolIndex);
+               r->set_r_pcrel(true);
+               r->set_r_length(2);
+               r->set_r_extern(true);
+               r->set_r_type(this->callReloc());
+       }
+}
+
+
+template <typename A>
+class SectionRelocationsAtom : public RelocationsAtomAbstract
+{
+public:
+                                                                                               SectionRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "section relocations"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode();
+       // overrides of RelocationsAtomAbstract
+       virtual void                                                            addPointerReloc(uint64_t addr, uint32_t symNum) {}
+       virtual void                                                            addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) {}
+       virtual void                                                            addExternalPointerReloc(uint64_t addr, const ld::Atom*) {}
+       virtual void                                                            addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) {}
+       virtual uint64_t                                                        relocBaseAddress(ld::Internal& state) { return 0; }
+       virtual void                                                            addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
+                                                                                                                       const ld::Atom* inAtom, uint32_t offsetInAtom, 
+                                                                                                                       bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+                                                                                                                       const ld::Atom* toTarget, uint64_t toAddend, 
+                                                                                                                       const ld::Atom* fromTarget, uint64_t fromAddend);
+               
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+       
+
+       struct Entry {
+               ld::Fixup::Kind                         kind;
+               bool                                            toTargetUsesExternalReloc;
+               bool                                            fromTargetUsesExternalReloc;
+               const ld::Atom*                         inAtom;
+               uint32_t                                        offsetInAtom;
+               const ld::Atom*                         toTarget; 
+               uint64_t                                        toAddend; 
+               const ld::Atom*                         fromTarget; 
+               uint64_t                                        fromAddend;
+       };
+       uint32_t                                                                        sectSymNum(bool external, const ld::Atom* target);
+       void                                                                            encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                                               const Entry& entry, std::vector<macho_relocation_info<P> >& relocs);
+       
+       struct SectionAndEntries {
+               ld::Internal::FinalSection*                             sect;
+               std::vector<Entry>                                              entries;
+               std::vector<macho_relocation_info<P> >  relocs;
+       };
+       
+       std::vector<SectionAndEntries>                          _entriesBySection;
+
+       static ld::Section                                                      _s_section;
+};
+
+template <typename A>
+ld::Section SectionRelocationsAtom<A>::_s_section("__LINKEDIT", "__sect_relocs", ld::Section::typeLinkEdit, true);
+
+
+
+
+template <typename A>
+uint64_t SectionRelocationsAtom<A>::size() const
+{
+       uint32_t count = 0;
+       for(typename std::vector<SectionAndEntries>::const_iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+               const SectionAndEntries& se = *it;
+               count += se.relocs.size();
+       }
+       return count * sizeof(macho_relocation_info<P>);
+}
+
+template <typename A>
+void SectionRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       uint32_t offset = 0;
+       for(typename std::vector<SectionAndEntries>::const_iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+               const SectionAndEntries& se = *it;
+               memcpy(&buffer[offset], &se.relocs[0], se.relocs.size()*sizeof(macho_relocation_info<P>));
+               offset += (se.relocs.size() * sizeof(macho_relocation_info<P>));
+       }
+}
+
+
+template <>
+void SectionRelocationsAtom<x86_64>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+       bool external = entry.toTargetUsesExternalReloc;
+       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+       bool fromExternal = false;
+       uint32_t fromSymbolNum = 0;
+       if ( entry.fromTarget != NULL ) {
+               fromExternal = entry.fromTargetUsesExternalReloc;
+               fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+       }
+       
+       
+       switch ( entry.kind ) {
+               case ld::Fixup::kindStoreX86BranchPCRel32:
+               case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+               case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+               case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_BRANCH);
+                       relocs.push_back(reloc1);
+                       break;
+                       
+               case ld::Fixup::kindStoreX86BranchPCRel8:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(0);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_BRANCH);
+                       relocs.push_back(reloc1);
+                       break;
+                       
+               case ld::Fixup::kindStoreX86PCRel32:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_SIGNED);
+                       relocs.push_back(reloc1);
+                       break;
+                       
+               case ld::Fixup::kindStoreX86PCRel32_1:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
+                       relocs.push_back(reloc1);
+                       break;
+                       
+               case ld::Fixup::kindStoreX86PCRel32_2:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
+                       relocs.push_back(reloc1);
+                       break;
+                       
+               case ld::Fixup::kindStoreX86PCRel32_4:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
+                       relocs.push_back(reloc1);
+                       break;
+               
+               case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreX86PCRel32GOT:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_GOT);
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreLittleEndian64:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(3);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(fromSymbolNum);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(3);
+                               reloc2.set_r_extern(fromExternal);
+                               reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
+                               relocs.push_back(reloc2);
+                               relocs.push_back(reloc1);
+                       }
+                       else {
+                               // regular pointer
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(3);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(fromSymbolNum);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(fromExternal);
+                               reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
+                               relocs.push_back(reloc2);
+                               relocs.push_back(reloc1);
+                       }
+                       else {
+                               // regular pointer
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+               default:
+                       assert(0 && "need to handle -r reloc");
+               
+       }
+
+}
+
+
+
+template <typename A>
+uint32_t SectionRelocationsAtom<A>::sectSymNum(bool external, const ld::Atom* target)
+{
+       if ( target->definition() == ld::Atom::definitionAbsolute ) 
+               return R_ABS;
+       if ( external )
+               return this->symbolIndex(target);       // in external relocations, r_symbolnum field is symbol index
+       else
+               return target->machoSection();          // in non-extern relocations, r_symbolnum is mach-o section index of target
+}
+
+template <>
+void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+       bool external = entry.toTargetUsesExternalReloc;
+       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+       bool fromExternal = false;
+       uint32_t fromSymbolNum = 0;
+       if ( entry.fromTarget != NULL ) {
+               fromExternal = entry.fromTargetUsesExternalReloc;
+               fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+       }
+       
+       
+       switch ( entry.kind ) {
+               case ld::Fixup::kindStoreX86PCRel32:
+               case ld::Fixup::kindStoreX86BranchPCRel32:
+               case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+               case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+               case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc is target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+       
+               case ld::Fixup::kindStoreX86BranchPCRel8:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc is target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(0);
+                               sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(0);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreX86PCRel16:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc is target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(1);
+                               sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(1);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+                                       sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
+                               else
+                                       sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               if ( entry.toTarget == entry.inAtom )
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               else
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(2);
+                               sreloc2->set_r_type(GENERIC_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               if ( entry.fromTarget == entry.inAtom ) {
+                                       if ( entry.fromAddend > entry.fromTarget->size() )
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else
+                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                               relocs.push_back(reloc1);
+                               relocs.push_back(reloc2);
+                       }
+                       else {
+                               // regular pointer
+                               if ( !external && (entry.toAddend != 0) ) {
+                                       // use scattered reloc is target offset is non-zero
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(2);
+                                       sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
+                               else {
+                                       reloc1.set_r_address(address);
+                                       reloc1.set_r_symbolnum(symbolNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(2);
+                                       reloc1.set_r_extern(external);
+                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                               }
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+               default:
+                       assert(0 && "need to handle -r reloc");
+               
+       }
+}
+
+
+template <>
+void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+       bool external = entry.toTargetUsesExternalReloc;
+       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+       bool fromExternal = false;
+       uint32_t fromSymbolNum = 0;
+       if ( entry.fromTarget != NULL ) {
+               fromExternal = entry.fromTargetUsesExternalReloc;
+               fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+       }
+       
+
+       switch ( entry.kind ) {
+               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+               case ld::Fixup::kindStoreARMBranch24:
+               case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+               case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc is target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(ARM_RELOC_BR24);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(ARM_RELOC_BR24);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+       
+               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+               case ld::Fixup::kindStoreThumbBranch22:
+               case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+               case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc is target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(ARM_THUMB_RELOC_BR22);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(ARM_THUMB_RELOC_BR22);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+                                       sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF);
+                               else
+                                       sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               if ( entry.toTarget == entry.inAtom )
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               else
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(2);
+                               sreloc2->set_r_type(ARM_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               if ( entry.fromTarget == entry.inAtom ) {
+                                       //unsigned int pcBaseOffset = entry.inAtom->isThumb() ? 4 : 8;
+                                       //if ( entry.fromAddend > pcBaseOffset )
+                                       //      sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend-pcBaseOffset);
+                                       //else
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else {
+                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                               }
+                               relocs.push_back(reloc1);
+                               relocs.push_back(reloc2);
+                       }
+                       else {
+                               // regular pointer
+                               if ( !external && (entry.toAddend != 0) ) {
+                                       // use scattered reloc is target offset is non-zero
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(2);
+                                       sreloc1->set_r_type(ARM_RELOC_VANILLA);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
+                               else {
+                                       reloc1.set_r_address(address);
+                                       reloc1.set_r_symbolnum(symbolNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(2);
+                                       reloc1.set_r_extern(external);
+                                       reloc1.set_r_type(ARM_RELOC_VANILLA);
+                               }
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+                       
+               case ld::Fixup::kindStoreARMLow16:
+               case ld::Fixup::kindStoreARMHigh16:
+               case ld::Fixup::kindStoreThumbLow16:
+               case ld::Fixup::kindStoreThumbHigh16:
+                       {
+                               int len = 0;
+                               uint32_t otherHalf = 0;
+                               uint32_t value = entry.toTarget->finalAddress()+entry.toAddend;
+                               if ( entry.fromTarget != NULL ) 
+                                       value -= (entry.fromTarget->finalAddress()+entry.fromAddend);
+                               switch ( entry.kind ) {
+                                       case ld::Fixup::kindStoreARMLow16:
+                                               len = 0;
+                                               otherHalf = value >> 16;
+                                               break;
+                                       case ld::Fixup::kindStoreARMHigh16:
+                                               len = 1;
+                                               otherHalf = value & 0xFFFF;
+                                               break;
+                                       case ld::Fixup::kindStoreThumbLow16:
+                                               len = 2;
+                                               otherHalf = value >> 16;
+                                               break;
+                                       case ld::Fixup::kindStoreThumbHigh16:
+                                               len = 3;
+                                               otherHalf = value & 0xFFFF;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               if ( entry.fromTarget != NULL ) {
+                                       // this is a sect-diff
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(len);
+                                       sreloc1->set_r_type(ARM_RELOC_HALF_SECTDIFF);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                                       sreloc2->set_r_scattered(true);
+                                       sreloc2->set_r_pcrel(false);
+                                       sreloc2->set_r_length(len);
+                                       sreloc2->set_r_type(ARM_RELOC_PAIR);
+                                       sreloc2->set_r_address(otherHalf);
+                                       if ( entry.fromTarget == entry.inAtom ) 
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                                       else 
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                                       relocs.push_back(reloc1);
+                                       relocs.push_back(reloc2);
+                               }
+                               else {
+                                       // this is absolute address
+                                       if ( !external && (entry.toAddend != 0) ) {
+                                               // use scattered reloc is target offset is non-zero
+                                               sreloc1->set_r_scattered(true);
+                                               sreloc1->set_r_pcrel(false);
+                                               sreloc1->set_r_length(len); 
+                                               sreloc1->set_r_type(ARM_RELOC_HALF);
+                                               sreloc1->set_r_address(address);
+                                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                                               reloc2.set_r_address(otherHalf);
+                                               reloc2.set_r_symbolnum(0);
+                                               reloc2.set_r_pcrel(false);
+                                               reloc2.set_r_length(len); 
+                                               reloc2.set_r_extern(false);
+                                               reloc2.set_r_type(ARM_RELOC_PAIR);
+                                               relocs.push_back(reloc1);
+                                               relocs.push_back(reloc2);
+                                       }
+                                       else {
+                                               reloc1.set_r_address(address);
+                                               reloc1.set_r_symbolnum(symbolNum);
+                                               reloc1.set_r_pcrel(false);
+                                               reloc1.set_r_length(len);
+                                               reloc1.set_r_extern(false);
+                                               reloc1.set_r_type(ARM_RELOC_HALF);
+                                               reloc2.set_r_address(otherHalf);  // other half
+                                               reloc2.set_r_symbolnum(0);
+                                               reloc2.set_r_pcrel(false);
+                                               reloc2.set_r_length(len); 
+                                               reloc2.set_r_extern(false);
+                                               reloc2.set_r_type(ARM_RELOC_PAIR);
+                                               relocs.push_back(reloc1);
+                                               relocs.push_back(reloc2);
+                                       }
+                               }
+                       }
+                       break;
+                                       
+               default:
+                       assert(0 && "need to handle -r reloc");
+               
+       }
+}
+
+
+template <>
+void SectionRelocationsAtom<ppc>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+       bool external = entry.toTargetUsesExternalReloc;
+       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+       bool fromExternal = false;
+       uint32_t fromSymbolNum = 0;
+       if ( entry.fromTarget != NULL ) {
+               fromExternal = entry.fromTargetUsesExternalReloc;
+               fromSymbolNum= sectSymNum(fromExternal, entry.fromTarget);
+       }
+       uint32_t toAddr;
+       uint32_t fromAddr;
+       
+       switch ( entry.kind ) {
+       
+               case ld::Fixup::kindStorePPCBranch24:
+               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+               case ld::Fixup::kindStorePPCDtraceCallSiteNop:
+               case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_BR24);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_BR24);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStorePPCBranch14:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_BR14);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_BR14);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreBigEndian32:
+               case ld::Fixup::kindStoreTargetAddressBigEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+                                       sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
+                               else
+                                       sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               if ( entry.toTarget == entry.inAtom )
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               else
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(2);
+                               sreloc2->set_r_type(PPC_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               if ( entry.fromTarget == entry.inAtom ) {
+                                       if ( entry.fromAddend > entry.fromTarget->size() )
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else
+                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                               relocs.push_back(reloc1);
+                               relocs.push_back(reloc2);
+                       }
+                       else {
+                               // regular pointer
+                               if ( !external && (entry.toAddend != 0) ) {
+                                       // use scattered reloc is target offset is non-zero
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(2);
+                                       sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
+                               else {
+                                       reloc1.set_r_address(address);
+                                       reloc1.set_r_symbolnum(symbolNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(2);
+                                       reloc1.set_r_extern(external);
+                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                               }
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+                       
+               case ld::Fixup::kindStorePPCAbsLow14:
+               case ld::Fixup::kindStorePPCAbsLow16:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend >> 16);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) >> 16);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCAbsHigh16:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_HI16);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_HI16);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_HA16);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_HA16);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCPicLow14:
+               case ld::Fixup::kindStorePPCPicLow16:
+                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
+                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
+                       sreloc1->set_r_scattered(true);
+                       sreloc1->set_r_pcrel(false);
+                       sreloc1->set_r_length(2);
+                       sreloc1->set_r_type(entry.kind == ld::Fixup::kindStorePPCPicLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
+                       sreloc1->set_r_address(address);
+                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       sreloc2->set_r_scattered(true);
+                       sreloc2->set_r_pcrel(false);
+                       sreloc2->set_r_length(2);
+                       sreloc2->set_r_type(PPC_RELOC_PAIR);
+                       sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
+                       sreloc2->set_r_value(fromAddr);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCPicHigh16AddLow:
+                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
+                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
+                       sreloc1->set_r_scattered(true);
+                       sreloc1->set_r_pcrel(false);
+                       sreloc1->set_r_length(2);
+                       sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
+                       sreloc1->set_r_address(address);
+                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       sreloc2->set_r_scattered(true);
+                       sreloc2->set_r_pcrel(false);
+                       sreloc2->set_r_length(2);
+                       sreloc2->set_r_type(PPC_RELOC_PAIR);
+                       sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
+                       sreloc2->set_r_value(fromAddr);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               default:
+                       assert(0 && "need to handle -r reloc");
+               
+       }
+}
+
+template <>
+void SectionRelocationsAtom<ppc64>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+       bool external = entry.toTargetUsesExternalReloc;
+       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+       bool fromExternal = false;
+       uint32_t fromSymbolNum = 0;
+       if ( entry.fromTarget != NULL ) {
+               fromExternal = entry.fromTargetUsesExternalReloc;
+               fromSymbolNum= sectSymNum(fromExternal, entry.fromTarget);
+       }
+       uint32_t toAddr;
+       uint32_t fromAddr;
+       
+       switch ( entry.kind ) {
+       
+               case ld::Fixup::kindStorePPCBranch24:
+               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+               case ld::Fixup::kindStorePPCDtraceCallSiteNop:
+               case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_BR24);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_BR24);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStorePPCBranch14:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_BR14);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_BR14);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreBigEndian32:
+               case ld::Fixup::kindStoreTargetAddressBigEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+                                       sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
+                               else
+                                       sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               if ( entry.toTarget == entry.inAtom )
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               else
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(2);
+                               sreloc2->set_r_type(PPC_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               if ( entry.fromTarget == entry.inAtom ) {
+                                       if ( entry.fromAddend > entry.fromTarget->size() )
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else
+                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                               relocs.push_back(reloc1);
+                               relocs.push_back(reloc2);
+                       }
+                       else {
+                               // regular pointer
+                               if ( !external && (entry.toAddend != 0) ) {
+                                       // use scattered reloc is target offset is non-zero
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(2);
+                                       sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
+                               else {
+                                       reloc1.set_r_address(address);
+                                       reloc1.set_r_symbolnum(symbolNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(2);
+                                       reloc1.set_r_extern(external);
+                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                               }
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+                       
+               case ld::Fixup::kindStoreBigEndian64:
+               case ld::Fixup::kindStoreTargetAddressBigEndian64:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(3);
+                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+                                       sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
+                               else
+                                       sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               if ( entry.toTarget == entry.inAtom )
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               else
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(3);
+                               sreloc2->set_r_type(PPC_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               if ( entry.fromTarget == entry.inAtom ) {
+                                       if ( entry.fromAddend > entry.fromTarget->size() )
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else
+                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                               relocs.push_back(reloc1);
+                               relocs.push_back(reloc2);
+                       }
+                       else {
+                               // regular pointer
+                               if ( !external && (entry.toAddend != 0) ) {
+                                       // use scattered reloc is target offset is non-zero
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(3);
+                                       sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
+                               else {
+                                       reloc1.set_r_address(address);
+                                       reloc1.set_r_symbolnum(symbolNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(3);
+                                       reloc1.set_r_extern(external);
+                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                               }
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+
+               case ld::Fixup::kindStorePPCAbsLow14:
+               case ld::Fixup::kindStorePPCAbsLow16:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend >> 16);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) >> 16);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCAbsHigh16:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_HI16);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_HI16);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_HA16);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_HA16);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCPicLow14:
+               case ld::Fixup::kindStorePPCPicLow16:
+                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
+                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
+                       sreloc1->set_r_scattered(true);
+                       sreloc1->set_r_pcrel(false);
+                       sreloc1->set_r_length(2);
+                       sreloc1->set_r_type(entry.kind == ld::Fixup::kindStorePPCPicLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
+                       sreloc1->set_r_address(address);
+                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       sreloc2->set_r_scattered(true);
+                       sreloc2->set_r_pcrel(false);
+                       sreloc2->set_r_length(2);
+                       sreloc2->set_r_type(PPC_RELOC_PAIR);
+                       sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
+                       sreloc2->set_r_value(fromAddr);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCPicHigh16AddLow:
+                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
+                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
+                       sreloc1->set_r_scattered(true);
+                       sreloc1->set_r_pcrel(false);
+                       sreloc1->set_r_length(2);
+                       sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
+                       sreloc1->set_r_address(address);
+                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       sreloc2->set_r_scattered(true);
+                       sreloc2->set_r_pcrel(false);
+                       sreloc2->set_r_length(2);
+                       sreloc2->set_r_type(PPC_RELOC_PAIR);
+                       sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
+                       sreloc2->set_r_value(fromAddr);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               default:
+                       assert(0 && "need to handle -r reloc");
+               
+       }
+}
+
+template <typename A>
+void SectionRelocationsAtom<A>::addSectionReloc(ld::Internal::FinalSection*    sect, ld::Fixup::Kind kind, 
+                                                                                               const ld::Atom* inAtom, uint32_t offsetInAtom,  
+                                                                                               bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+                                                                                               const ld::Atom* toTarget, uint64_t toAddend, 
+                                                                                               const ld::Atom* fromTarget, uint64_t fromAddend)
+{
+       Entry entry;
+       entry.kind = kind;
+       entry.toTargetUsesExternalReloc = toTargetUsesExternalReloc;
+       entry.fromTargetUsesExternalReloc = fromTargetExternalReloc;
+       entry.inAtom = inAtom;
+       entry.offsetInAtom = offsetInAtom;
+       entry.toTarget = toTarget;
+       entry.toAddend = toAddend;
+       entry.fromTarget = fromTarget;
+       entry.fromAddend = fromAddend;
+       
+       static ld::Internal::FinalSection* lastSection = NULL;
+       static SectionAndEntries* lastSectionAndEntries = NULL;
+               
+       if ( sect != lastSection ) {
+               for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+                       if ( sect == it->sect ) {
+                               lastSection = sect;
+                               lastSectionAndEntries = &*it;
+                               break;
+                       }
+               }
+               if ( sect != lastSection ) {
+                       SectionAndEntries tmp;
+                       tmp.sect = sect;
+                       _entriesBySection.push_back(tmp);
+                       lastSection = sect;
+                       lastSectionAndEntries = &_entriesBySection.back();
+               }
+       }
+       lastSectionAndEntries->entries.push_back(entry);
+}
+
+template <typename A>
+void SectionRelocationsAtom<A>::encode()
+{
+       // convert each Entry record to one or two reloc records
+       for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+               SectionAndEntries& se = *it;
+               for(typename std::vector<Entry>::iterator eit=se.entries.begin(); eit != se.entries.end(); ++eit) {
+                       encodeSectionReloc(se.sect, *eit, se.relocs);
+               }
+       }
+       
+       // update sections with start and count or relocs
+       uint32_t index = 0;
+       for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+               SectionAndEntries& se = *it;
+               se.sect->relocStart = index;
+               se.sect->relocCount = se.relocs.size();
+               index += se.sect->relocCount;
+       }
+
+}
+
+
+
+template <typename A>
+class IndirectSymbolTableAtom : public ClassicLinkEditAtom
+{
+public:
+                                                                                               IndirectSymbolTableAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : ClassicLinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "indirect symbol table"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode();
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+       
+       void                                                                            encodeStubSection(ld::Internal::FinalSection* sect);
+       void                                                                            encodeLazyPointerSection(ld::Internal::FinalSection* sect);
+       void                                                                            encodeNonLazyPointerSection(ld::Internal::FinalSection* sect);
+       uint32_t                                                                        symIndexOfStubAtom(const ld::Atom*);
+       uint32_t                                                                        symIndexOfLazyPointerAtom(const ld::Atom*);
+       uint32_t                                                                        symIndexOfNonLazyPointerAtom(const ld::Atom*);
+       uint32_t                                                                        symbolIndex(const ld::Atom*);
+       bool                                                                            kextBundlesDontHaveIndirectSymbolTable();
+
+
+       std::vector<uint32_t>                                           _entries;
+       
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section IndirectSymbolTableAtom<A>::_s_section("__LINKEDIT", "__ind_sym_tab", ld::Section::typeLinkEdit, true);
+
+
+
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symbolIndex(const ld::Atom* atom)
+{
+       std::map<const ld::Atom*, uint32_t>::iterator pos = this->_writer._atomToSymbolIndex.find(atom);
+       if ( pos != this->_writer._atomToSymbolIndex.end() )
+               return pos->second;
+       //fprintf(stderr, "_atomToSymbolIndex content:\n");
+       //for(std::map<const ld::Atom*, uint32_t>::iterator it = this->_writer._atomToSymbolIndex.begin(); it != this->_writer._atomToSymbolIndex.end(); ++it) {
+       //              fprintf(stderr, "%p(%s) => %d\n", it->first, it->first->name(), it->second);
+       //}
+       throwf("internal error: atom not found in symbolIndex(%s)", atom->name());
+}
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symIndexOfStubAtom(const ld::Atom* stubAtom)
+{
+       for (ld::Fixup::iterator fit = stubAtom->fixupsBegin(); fit != stubAtom->fixupsEnd(); ++fit) {
+               if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                       assert((fit->u.target->contentType() == ld::Atom::typeLazyPointer) 
+                                       || (fit->u.target->contentType() == ld::Atom::typeLazyDylibPointer));
+                       return symIndexOfLazyPointerAtom(fit->u.target);
+               }
+       }
+       throw "internal error: stub missing fixup to lazy pointer";
+}
+
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symIndexOfLazyPointerAtom(const ld::Atom* lpAtom)
+{
+       for (ld::Fixup::iterator fit = lpAtom->fixupsBegin(); fit != lpAtom->fixupsEnd(); ++fit) {
+               if ( fit->kind == ld::Fixup::kindLazyTarget ) {
+                       assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                       return symbolIndex(fit->u.target);
+               }
+       }
+       throw "internal error: lazy pointer missing fixupLazyTarget fixup";
+}
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symIndexOfNonLazyPointerAtom(const ld::Atom* nlpAtom)
+{
+       //fprintf(stderr, "symIndexOfNonLazyPointerAtom(%p) %s\n", nlpAtom, nlpAtom->name());
+       for (ld::Fixup::iterator fit = nlpAtom->fixupsBegin(); fit != nlpAtom->fixupsEnd(); ++fit) {
+               // non-lazy-pointer to a stripped symbol => no symbol index
+               if ( fit->clusterSize != ld::Fixup::k1of1 )
+                       return INDIRECT_SYMBOL_LOCAL;
+               const ld::Atom* target;
+               switch ( fit->binding ) {
+                       case ld::Fixup::bindingDirectlyBound:
+                               target = fit->u.target;
+                               break;
+                       case ld::Fixup::bindingsIndirectlyBound:
+                               target = _state.indirectBindingTable[fit->u.bindingIndex];
+                               break;
+                       default:
+                               throw "internal error: unexpected non-lazy pointer binding";
+               }
+               // Special case non-lazy-pointer slot used to point to "dyld_stub_binder"
+               // That slot is never bound using indirect symbol table
+               if ( target == _state.compressedFastBinderProxy )
+                       return INDIRECT_SYMBOL_ABS;
+               bool targetIsGlobal = (target->scope() == ld::Atom::scopeGlobal);
+               switch ( target->definition() ) {
+                       case ld::Atom::definitionRegular:
+                               if ( targetIsGlobal ) {
+                                       if ( _options.outputKind() == Options::kObjectFile ) {
+                                               // nlpointer to global symbol uses indirect symbol table in .o files
+                                               return symbolIndex(target);
+                                       } 
+                                       else if ( target->combine() == ld::Atom::combineByName ) {
+                                               // dyld needs to bind nlpointer to global weak def
+                                               return symbolIndex(target);
+                                       }
+                                       else if ( _options.nameSpace() != Options::kTwoLevelNameSpace ) {
+                                               // dyld needs to bind nlpointer to global def linked for flat namespace
+                                               return symbolIndex(target);
+                                       }
+                               }
+                               break;
+                       case ld::Atom::definitionTentative:
+                       case ld::Atom::definitionAbsolute:
+                               if ( _options.outputKind() == Options::kObjectFile ) {
+                                       // tentative def in .o file always uses symbol index
+                                       return symbolIndex(target);
+                               }
+                               // dyld needs to bind nlpointer to global def linked for flat namespace
+                               if ( targetIsGlobal && _options.nameSpace() != Options::kTwoLevelNameSpace ) 
+                                       return symbolIndex(target);
+                               break;
+                       case ld::Atom::definitionProxy:
+                               // dyld needs to bind nlpointer to something in another dylib
+                               {
+                                       const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+                                       if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
+                                               throwf("illegal data reference to %s in lazy loaded dylib %s", target->name(), dylib->path());
+                               }
+                               return symbolIndex(target);
+               }
+       }
+       if ( nlpAtom->fixupsBegin() == nlpAtom->fixupsEnd() ) {
+               // no fixups means this is the ImageLoader cache slot
+               return INDIRECT_SYMBOL_ABS;
+       }
+       
+       // The magic index INDIRECT_SYMBOL_LOCAL tells dyld it should does not need to bind
+       // this non-lazy pointer.
+       return INDIRECT_SYMBOL_LOCAL;
+}
+
+
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encodeStubSection(ld::Internal::FinalSection* sect)
+{
+       sect->indirectSymTabStartIndex = _entries.size();
+       sect->indirectSymTabElementSize = sect->atoms[0]->size();
+       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+               _entries.push_back(symIndexOfStubAtom(*ait));
+       }
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encodeLazyPointerSection(ld::Internal::FinalSection* sect)
+{
+       sect->indirectSymTabStartIndex = _entries.size();
+       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+               _entries.push_back(symIndexOfLazyPointerAtom(*ait));
+       }
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encodeNonLazyPointerSection(ld::Internal::FinalSection* sect)
+{
+       sect->indirectSymTabStartIndex = _entries.size();
+       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+               _entries.push_back(symIndexOfNonLazyPointerAtom(*ait));
+       }
+}
+
+template <typename A>
+bool IndirectSymbolTableAtom<A>::kextBundlesDontHaveIndirectSymbolTable()
+{
+       return true;    
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encode()
+{
+       // static executables should not have an indirect symbol table
+       if ( this->_options.outputKind() == Options::kStaticExecutable ) 
+               return;
+
+       // x86_64 kext bundles should not have an indirect symbol table
+       if ( (this->_options.outputKind() == Options::kKextBundle) && kextBundlesDontHaveIndirectSymbolTable() ) 
+               return;
+
+       // find all special sections that need a range of the indirect symbol table section
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = this->_state.sections.begin(); sit != this->_state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               switch ( sect->type() ) {
+                       case ld::Section::typeStub:
+                       case ld::Section::typeStubClose:
+                               this->encodeStubSection(sect);
+                               break;
+                       case ld::Section::typeLazyPointerClose:
+                       case ld::Section::typeLazyPointer:
+                       case ld::Section::typeLazyDylibPointer:
+                               this->encodeLazyPointerSection(sect);
+                               break;
+                       case ld::Section::typeNonLazyPointer:
+                               this->encodeNonLazyPointerSection(sect);
+                               break;
+                       default:
+                               break;
+               }
+       }
+}
+
+template <typename A>
+uint64_t IndirectSymbolTableAtom<A>::size() const
+{
+       return _entries.size() * sizeof(uint32_t);
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       uint32_t* array = (uint32_t*)buffer;
+       for(unsigned long i=0; i < _entries.size(); ++i) {
+               E::set32(array[i], _entries[i]);
+       }
+}
+
+
+
+
+
+
+
+
+} // namespace tool 
+} // namespace ld 
+
+#endif // __LINKEDIT_CLASSIC_HPP__