+ //
+ // ld::File::Ordinal
+ //
+ // Codifies the rules of ordering input files for symbol precedence. These are:
+ // - Input files listed on the command line are ordered according to their index in the argument list.
+ // - Input files listed in a file list are ordered first at the index of the file list argument, then
+ // by index in the file list
+ // - Input files extracted from archives are ordered using the ordinal of the archive itself plus the
+ // index of the object file within the archive
+ // - Indirect dylibs are ordered after all input files derived from the command line, in the order that
+ // they are discovered.
+ // - The LTO object file is last.
+ //
+ class Ordinal
+ {
+ private:
+ // The actual numeric ordinal. Lower values have higher precedence and a zero value is invalid.
+ // The 64 bit ordinal is broken into 4 16 bit chunks. The high 16 bits are a "partition" that
+ // is used to distinguish major ordinal groups: command line, indirect dylib, LTO.
+ // The remaining chunks are used according to the partition (see below).
+ uint64_t _ordinal;
+
+ Ordinal (uint64_t ordinal) : _ordinal(ordinal) {}
+
+ enum { kArgListPartition=0, kIndirectDylibPartition=1, kLTOPartition = 2, kLinkerOptionPartition = 2, InvalidParition=0xffff };
+ Ordinal(uint16_t partition, uint16_t majorIndex, uint16_t minorIndex, uint16_t counter) {
+ _ordinal = ((uint64_t)partition<<48) | ((uint64_t)majorIndex<<32) | ((uint64_t)minorIndex<<16) | ((uint64_t)counter<<0);
+ }
+
+ const uint16_t partition() const { return (_ordinal>>48)&0xffff; }
+ const uint16_t majorIndex() const { return (_ordinal>>32)&0xffff; }
+ const uint16_t minorIndex() const { return (_ordinal>>16)&0xffff; }
+ const uint16_t counter() const { return (_ordinal>>00)&0xffff; }
+
+ const Ordinal nextMajorIndex() const { assert(majorIndex() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<32)); }
+ const Ordinal nextMinorIndex() const { assert(minorIndex() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<16)); }
+ const Ordinal nextCounter() const { assert(counter() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<0)); }
+
+ public:
+ Ordinal() : _ordinal(0) {};
+
+ static const Ordinal NullOrdinal() { return Ordinal((uint64_t)0); }
+
+ const bool validOrdinal() const { return _ordinal != 0; }
+
+ bool operator ==(const Ordinal& rhs) const { return _ordinal == rhs._ordinal; }
+ bool operator !=(const Ordinal& rhs) const { return _ordinal != rhs._ordinal; }
+ bool operator < (const Ordinal& rhs) const { return _ordinal < rhs._ordinal; }
+ bool operator > (const Ordinal& rhs) const { return _ordinal > rhs._ordinal; }
+
+ // For ordinals derived from the command line args the partition is ArgListPartition
+ // The majorIndex is the arg index that pulls in the file, file list, or archive.
+ // The minorIndex is used for files pulled in by a file list and the value is the index of the file in the file list.
+ // The counter is used for .a files and the value is the index of the object in the archive.
+ // Thus, an object pulled in from a .a that was listed in a file list could use all three fields.
+ static const Ordinal makeArgOrdinal(uint16_t argIndex) { return Ordinal(kArgListPartition, argIndex, 0, 0); };
+ const Ordinal nextFileListOrdinal() const { return nextMinorIndex(); }
+ const Ordinal archiveOrdinalWithMemberIndex(uint16_t index) const { return Ordinal(kArgListPartition, majorIndex(), minorIndex(), index); }
+
+ // For indirect libraries the partition is IndirectDylibPartition and the counter is used or order the libraries.
+ static const ld::File::Ordinal indirectDylibBase() { return Ordinal(kIndirectDylibPartition, 0, 0, 0); }
+ const Ordinal nextIndirectDylibOrdinal() const { return nextCounter(); }
+
+ // For the LTO mach-o the partition is LTOPartition. As there is only one LTO file no other fields are needed.
+ static const ld::File::Ordinal LTOOrdinal() { return Ordinal(kLTOPartition, 0, 0, 0); }
+
+ // For linker options embedded in object files
+ static const ld::File::Ordinal linkeOptionBase() { return Ordinal(kIndirectDylibPartition, 1, 0, 0); }
+ const Ordinal nextLinkerOptionOrdinal() { nextCounter(); return *this; };
+
+ };
+
+ typedef enum { Reloc, Dylib, Archive, Other } Type;
+
+ File(const char* pth, time_t modTime, Ordinal ord, Type type)
+ : _path(pth), _modTime(modTime), _ordinal(ord), _type(type) { }