summaryrefslogtreecommitdiff
path: root/objectivec/objc.cpp
diff options
context:
space:
mode:
authorMark Rowe <mrowe@bdash.net.nz>2025-02-17 11:04:35 -0800
committerkat <kat@vector35.com>2025-07-08 15:12:46 -0400
commitd7445e232501ba60fb780f2c18500c0b509fc97e (patch)
treedfaff0a3c5f64786424a8ba0eb2ad4f53f9ebd5a /objectivec/objc.cpp
parent9ff07a92f51ded6376174a0a023875256d6776bd (diff)
Parse sections containing Objective-C constants
This adds support for the `__objc_arrayobj`, `_objc_dictobj`, `__objc_intobj`, `__objc_floatobj`, `__objc_doubleobj` and `__objc_dateobj` sections that contain Objective-C constants. These are emitted by Apple's versions of Clang for `const` literals, amongst other things.
Diffstat (limited to 'objectivec/objc.cpp')
-rw-r--r--objectivec/objc.cpp277
1 files changed, 277 insertions, 0 deletions
diff --git a/objectivec/objc.cpp b/objectivec/objc.cpp
index e4b21ff6..b45cb3ed 100644
--- a/objectivec/objc.cpp
+++ b/objectivec/objc.cpp
@@ -1535,6 +1535,15 @@ void ObjCProcessor::ProcessObjCData()
m_relocationPointerRewrites.clear();
}
+void ObjCProcessor::ProcessObjCLiterals()
+{
+ ProcessCFStrings();
+ ProcessNSConstantArrays();
+ ProcessNSConstantDictionaries();
+ ProcessNSConstantIntegerNumbers();
+ ProcessNSConstantFloatingPointNumbers();
+ ProcessNSConstantDatas();
+}
void ObjCProcessor::ProcessCFStrings()
{
@@ -1651,6 +1660,274 @@ void ObjCProcessor::ProcessCFStrings()
}
}
+void ObjCProcessor::ProcessNSConstantArrays()
+{
+ m_symbolQueue = new SymbolQueue();
+ uint64_t ptrSize = m_data->GetAddressSize();
+
+ auto idType = Type::NamedType(m_data, m_typeNames.id);
+ StructureBuilder nsConstantArrayBuilder;
+ nsConstantArrayBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
+ nsConstantArrayBuilder.AddMember(Type::IntegerType(ptrSize, false), "count");
+ nsConstantArrayBuilder.AddMember(Type::PointerType(ptrSize, idType), "objects");
+ auto type = finalizeStructureBuilder(m_data, nsConstantArrayBuilder, "__NSConstantArray");
+ m_typeNames.nsConstantArray = type.first;
+
+ auto reader = GetReader();
+ if (auto arrays = GetSectionWithName("__objc_arrayobj"))
+ {
+ auto start = arrays->GetStart();
+ auto end = arrays->GetEnd();
+ auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantArray)->GetWidth();
+ m_data->BeginBulkModifySymbols();
+ for (view_ptr_t i = start; i < end; i += typeWidth)
+ {
+ reader->Seek(i + ptrSize);
+ uint64_t count = reader->ReadPointer();
+ auto dataLoc = ReadPointerAccountingForRelocations(reader.get());
+ DefineObjCSymbol(
+ DataSymbol, Type::ArrayType(idType, count), fmt::format("nsarray_{:x}_data", i), dataLoc, true);
+ DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantArray),
+ fmt::format("nsarray_{:x}", i), i, true);
+ }
+ auto id = m_data->BeginUndoActions();
+ m_symbolQueue->Process();
+ m_data->EndBulkModifySymbols();
+ m_data->ForgetUndoActions(id);
+ }
+ delete m_symbolQueue;
+}
+
+void ObjCProcessor::ProcessNSConstantDictionaries()
+{
+ m_symbolQueue = new SymbolQueue();
+ uint64_t ptrSize = m_data->GetAddressSize();
+
+ auto idType = Type::NamedType(m_data, m_typeNames.id);
+ StructureBuilder nsConstantDictionaryBuilder;
+ nsConstantDictionaryBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
+ nsConstantDictionaryBuilder.AddMember(Type::IntegerType(ptrSize, false), "options");
+ nsConstantDictionaryBuilder.AddMember(Type::IntegerType(ptrSize, false), "count");
+ nsConstantDictionaryBuilder.AddMember(Type::PointerType(ptrSize, idType), "keys");
+ nsConstantDictionaryBuilder.AddMember(Type::PointerType(ptrSize, idType), "objects");
+ auto type = finalizeStructureBuilder(m_data, nsConstantDictionaryBuilder, "__NSConstantDictionary");
+ m_typeNames.nsConstantDictionary = type.first;
+
+ auto reader = GetReader();
+ if (auto dicts = GetSectionWithName("__objc_dictobj"))
+ {
+ auto start = dicts->GetStart();
+ auto end = dicts->GetEnd();
+ auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantDictionary)->GetWidth();
+ m_data->BeginBulkModifySymbols();
+ for (view_ptr_t i = start; i < end; i += typeWidth)
+ {
+ reader->Seek(i + (ptrSize * 2));
+ // TODO: Do we need to do anything with `options`? It appears to always be 1.
+ uint64_t count = reader->ReadPointer();
+ auto keysLoc = ReadPointerAccountingForRelocations(reader.get());
+ auto objectsLoc = ReadPointerAccountingForRelocations(reader.get());
+ DefineObjCSymbol(
+ DataSymbol, Type::ArrayType(idType, count), fmt::format("nsdict_{:x}_keys", i), keysLoc, true);
+ DefineObjCSymbol(
+ DataSymbol, Type::ArrayType(idType, count), fmt::format("nsdict_{:x}_objects", i), objectsLoc, true);
+ DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantDictionary),
+ fmt::format("nsdict_{:x}", i), i, true);
+ }
+ auto id = m_data->BeginUndoActions();
+ m_symbolQueue->Process();
+ m_data->EndBulkModifySymbols();
+ m_data->ForgetUndoActions(id);
+ }
+ delete m_symbolQueue;
+}
+
+void ObjCProcessor::ProcessNSConstantIntegerNumbers()
+{
+ m_symbolQueue = new SymbolQueue();
+ uint64_t ptrSize = m_data->GetAddressSize();
+
+ StructureBuilder nsConstantIntegerNumberBuilder;
+ nsConstantIntegerNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
+ nsConstantIntegerNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::IntegerType(1, true)), "encoding");
+ nsConstantIntegerNumberBuilder.AddMember(Type::IntegerType(ptrSize, true), "value");
+ auto type = finalizeStructureBuilder(m_data, nsConstantIntegerNumberBuilder, "__NSConstantIntegerNumber");
+ m_typeNames.nsConstantIntegerNumber = type.first;
+
+ auto reader = GetReader();
+ if (auto numbers = GetSectionWithName("__objc_intobj"))
+ {
+ auto start = numbers->GetStart();
+ auto end = numbers->GetEnd();
+ auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantIntegerNumber)->GetWidth();
+ m_data->BeginBulkModifySymbols();
+ for (view_ptr_t i = start; i < end; i += typeWidth)
+ {
+ reader->Seek(i + ptrSize);
+ uint64_t encodingLoc = ReadPointerAccountingForRelocations(reader.get());
+ uint64_t value = reader->Read64();
+ reader->Seek(encodingLoc);
+ uint8_t encoding = reader->Read8();
+
+ switch (encoding)
+ {
+ case 'c':
+ case 's':
+ case 'i':
+ case 'l':
+ case 'q':
+ DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantIntegerNumber),
+ fmt::format("nsint_{:x}_{}", i, (int64_t)value), i, true);
+ break;
+ case 'C':
+ case 'S':
+ case 'I':
+ case 'L':
+ case 'Q':
+ DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantIntegerNumber),
+ fmt::format("nsint_{:x}_{}", i, value), i, true);
+ break;
+ default:
+ m_logger->LogWarn("Unknown type encoding '%c' in number literal object at %p", encoding, i);
+ continue;
+ }
+ }
+ auto id = m_data->BeginUndoActions();
+ m_symbolQueue->Process();
+ m_data->EndBulkModifySymbols();
+ m_data->ForgetUndoActions(id);
+ }
+ delete m_symbolQueue;
+}
+
+void ObjCProcessor::ProcessNSConstantFloatingPointNumbers()
+{
+ uint64_t ptrSize = m_data->GetAddressSize();
+
+ StructureBuilder nsConstantFloatNumberBuilder;
+ nsConstantFloatNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
+ nsConstantFloatNumberBuilder.AddMember(Type::FloatType(4), "value");
+ auto type = finalizeStructureBuilder(m_data, nsConstantFloatNumberBuilder, "__NSConstantFloatNumber");
+ m_typeNames.nsConstantFloatNumber = type.first;
+
+ StructureBuilder nsConstantDoubleNumberBuilder;
+ nsConstantDoubleNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
+ nsConstantDoubleNumberBuilder.AddMember(Type::FloatType(8), "value");
+ type = finalizeStructureBuilder(m_data, nsConstantDoubleNumberBuilder, "__NSConstantDoubleNumber");
+ m_typeNames.nsConstantDoubleNumber = type.first;
+
+ StructureBuilder nsConstantDateBuilder;
+ nsConstantDateBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
+ nsConstantDateBuilder.AddMember(Type::FloatType(8), "ti");
+ type = finalizeStructureBuilder(m_data, nsConstantDateBuilder, "__NSConstantDate");
+ m_typeNames.nsConstantDate = type.first;
+
+ enum SectionType
+ {
+ Float,
+ Double,
+ Date,
+ };
+
+ constexpr std::pair<std::string_view, SectionType> sections[] = {
+ {"__objc_floatobj", Float},
+ {"__objc_doubleobj", Double},
+ {"__objc_dateobj", Date},
+ };
+
+ auto reader = GetReader();
+ for (auto& [sectionName, sectionType] : sections)
+ {
+ auto numbers = GetSectionWithName(sectionName.data());
+ if (!numbers)
+ continue;
+
+ m_symbolQueue = new SymbolQueue();
+ auto start = numbers->GetStart();
+ auto end = numbers->GetEnd();
+ auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantDoubleNumber)->GetWidth();
+ m_data->BeginBulkModifySymbols();
+ for (view_ptr_t i = start; i < end; i += typeWidth)
+ {
+ reader->Seek(i + ptrSize);
+
+ QualifiedName* typeName = nullptr;
+ std::string name;
+
+ switch (sectionType)
+ {
+ case Float:
+ {
+ float value = 0;
+ reader->Read(&value, sizeof(value));
+ name = fmt::format("nsfloat_{:x}_{}", i, value);
+ typeName = &m_typeNames.nsConstantFloatNumber;
+ break;
+ }
+ case Double:
+ {
+ double value = 0;
+ reader->Read(&value, sizeof(value));
+ name = fmt::format("nsdouble_{:x}_{}", i, value);
+ typeName = &m_typeNames.nsConstantDoubleNumber;
+ break;
+ }
+ case Date:
+ {
+ double value = 0;
+ reader->Read(&value, sizeof(value));
+ name = fmt::format("nsdate_{:x}_{}", i, value);
+ typeName = &m_typeNames.nsConstantDate;
+ break;
+ }
+ }
+ DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, *typeName), name, i, true);
+ }
+ auto id = m_data->BeginUndoActions();
+ m_symbolQueue->Process();
+ m_data->EndBulkModifySymbols();
+ m_data->ForgetUndoActions(id);
+ delete m_symbolQueue;
+ }
+}
+
+void ObjCProcessor::ProcessNSConstantDatas()
+{
+ m_symbolQueue = new SymbolQueue();
+ uint64_t ptrSize = m_data->GetAddressSize();
+
+ StructureBuilder nsConstantDataBuilder;
+ nsConstantDataBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
+ nsConstantDataBuilder.AddMember(Type::IntegerType(ptrSize, false), "length");
+ nsConstantDataBuilder.AddMember(Type::PointerType(ptrSize, Type::IntegerType(1, false)), "bytes");
+ auto type = finalizeStructureBuilder(m_data, nsConstantDataBuilder, "__NSConstantData");
+ m_typeNames.nsConstantData = type.first;
+
+ auto reader = GetReader();
+ if (auto datas = GetSectionWithName("__objc_dataobj"))
+ {
+ auto start = datas->GetStart();
+ auto end = datas->GetEnd();
+ auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantData)->GetWidth();
+ m_data->BeginBulkModifySymbols();
+ for (view_ptr_t i = start; i < end; i += typeWidth)
+ {
+ reader->Seek(i + ptrSize);
+ uint64_t length = reader->ReadPointer();
+ auto dataLoc = ReadPointerAccountingForRelocations(reader.get());
+ DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, false), length),
+ fmt::format("nsdata_{:x}_data", i), dataLoc, true);
+ DefineObjCSymbol(
+ DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantData), fmt::format("nsdata_{:x}", i), i, true);
+ }
+ auto id = m_data->BeginUndoActions();
+ m_symbolQueue->Process();
+ m_data->EndBulkModifySymbols();
+ m_data->ForgetUndoActions(id);
+ }
+ delete m_symbolQueue;
+}
+
void ObjCProcessor::AddRelocatedPointer(uint64_t location, uint64_t rewrite)
{
m_relocationPointerRewrites[location] = rewrite;