[llvm] r212108 - Add the -arch flag support to llvm-size like what was done to llvm-nm
Jim Grosbach
grosbach at apple.com
Tue Jul 1 13:29:36 PDT 2014
A few formatting things. Rather than note them individually, I suggest just running clang-format on the patch. I use the vim integration script clang-format.py from the clang/tools/clang-format directory (there’s usage instructions at the top of the script) and works pretty well for me.
Generally, re-walking the -arch command line list multiple times seems odd. Would it be better to walk it once and construct a list of cputype/subtype pairs to compare against in the rest of the code?
> On Jul 1, 2014, at 10:19 AM, Kevin Enderby <enderby at apple.com> wrote:
>
> Author: enderby
> Date: Tue Jul 1 12:19:10 2014
> New Revision: 212108
>
> URL: http://llvm.org/viewvc/llvm-project?rev=212108&view=rev
> Log:
> Add the -arch flag support to llvm-size like what was done to llvm-nm
> to select the slice out of a Mach-O universal file. This also includes
> support for -arch all, selecting the host architecture by default from
> a universal file and checking if -arch is used with a standard Mach-O
> it matches that architecture.
>
> Modified:
> llvm/trunk/test/Object/size-trivial-macho.test
> llvm/trunk/tools/llvm-size/llvm-size.cpp
>
> Modified: llvm/trunk/test/Object/size-trivial-macho.test
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/size-trivial-macho.test?rev=212108&r1=212107&r2=212108&view=diff
> ==============================================================================
> --- llvm/trunk/test/Object/size-trivial-macho.test (original)
> +++ llvm/trunk/test/Object/size-trivial-macho.test Tue Jul 1 12:19:10 2014
> @@ -10,10 +10,14 @@ RUN: llvm-size -format darwin %p/Inputs/
> RUN: | FileCheck %s -check-prefix mAR
> RUN: llvm-size -m -x -l %p/Inputs/hello-world.macho-x86_64 \
> RUN: | FileCheck %s -check-prefix mxl
> -RUN: llvm-size %p/Inputs/macho-universal.x86_64.i386 \
> +RUN: llvm-size -arch all %p/Inputs/macho-universal.x86_64.i386 \
> RUN: | FileCheck %s -check-prefix u
> -RUN: llvm-size %p/Inputs/macho-universal-archive.x86_64.i386 \
> +RUN: llvm-size -arch i386 %p/Inputs/macho-universal.x86_64.i386 \
> +RUN: | FileCheck %s -check-prefix u-i386
> +RUN: llvm-size -arch all %p/Inputs/macho-universal-archive.x86_64.i386 \
> RUN: | FileCheck %s -check-prefix uAR
> +RUN: llvm-size -arch x86_64 %p/Inputs/macho-universal-archive.x86_64.i386 \
> +RUN: | FileCheck %s -check-prefix uAR-x86_64
>
> A: section size addr
> A: __text 12 0
> @@ -74,6 +78,12 @@ u: __TEXT __DATA __OBJC others dec hex
> u: 4096 0 0 4294971392 4294975488 100002000 {{.*}}/macho-universal.x86_64.i386 (for architecture x86_64)
> u: 4096 0 0 8192 12288 3000 {{.*}}/macho-universal.x86_64.i386 (for architecture i386)
>
> +u-i386: __TEXT __DATA __OBJC others dec hex
> +u-i386: 4096 0 0 8192 12288 3000
> +
> uAR: __TEXT __DATA __OBJC others dec hex
> uAR: 136 0 0 32 168 a8 {{.*}}/macho-universal-archive.x86_64.i386(hello.o) (for architecture x86_64)
> uAR: 5 4 0 0 9 9 {{.*}}/macho-universal-archive.x86_64.i386(foo.o) (for architecture i386)
> +
> +uAR-x86_64: __TEXT __DATA __OBJC others dec hex
> +uAR-x86_64: 136 0 0 32 168 a8 {{.*}}/macho-universal-archive.x86_64.i386(hello.o)
>
> Modified: llvm/trunk/tools/llvm-size/llvm-size.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-size/llvm-size.cpp?rev=212108&r1=212107&r2=212108&view=diff
> ==============================================================================
> --- llvm/trunk/tools/llvm-size/llvm-size.cpp (original)
> +++ llvm/trunk/tools/llvm-size/llvm-size.cpp Tue Jul 1 12:19:10 2014
> @@ -57,6 +57,12 @@ cl::opt<bool> DarwinLongFormat("l",
> cl::desc("When format is darwin, use long format "
> "to include addresses and offsets."));
>
> +static cl::list<std::string>
> + ArchFlags("arch",
> + cl::desc("architecture(s) from a Mach-O file to dump"),
> + cl::ZeroOrMore);
> +bool ArchAll = false;
static bool ArchAll.
Later, it’d be really great to get rid of the globals this file uses. Not for this patch, though.
> +
> enum RadixTy {octal = 8, decimal = 10, hexadecimal = 16};
> static cl::opt<unsigned int>
> Radix("-radix",
> @@ -413,6 +419,40 @@ static void PrintObjectSectionSizes(Obje
> }
> }
>
> +/// @brief Checks to see if the @p o ObjectFile is a Mach-O file and if it is
> +/// and there is a list of architecture flags specified then check to
> +/// make sure this Mach-O file is one of those architectures or all
> +/// architectures was specificed. If not then an error is generated and
> +/// this routine returns false. Else it returns true.
> +static bool checkMachOAndArchFlags(ObjectFile *o, StringRef file) {
Variable names start w/ caps. “O” and “File”. Same thing in other places.
> + if (isa<MachOObjectFile>(o) && !ArchAll && ArchFlags.size() != 0) {
> + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
> + bool ArchFound = false;
> + MachO::mach_header H;
> + MachO::mach_header_64 H_64;
> + Triple T;
> + if (MachO->is64Bit()) {
> + H_64 = MachO->MachOObjectFile::getHeader64();
> + T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype);
> + } else {
> + H = MachO->MachOObjectFile::getHeader();
> + T = MachOObjectFile::getArch(H.cputype, H.cpusubtype);
> + }
> + unsigned i;
> + for (i = 0; i < ArchFlags.size(); ++i){
> + if (ArchFlags[i] == T.getArchName())
> + ArchFound = true;
> + break;
> + }
> + if (!ArchFound) {
> + errs() << ToolName << ": file: " << file
> + << " does not contain architecture: " << ArchFlags[i] << ".\n”;
size(1) issues this diagnostic for each listed -arch that isn’t in the fat file and gives normal output for each that is. For example,
enkidu: ~/tmp $ size -arch armv7 -arch armv7s t.o
__TEXT __DATA __OBJC others dec hex
error: /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.10.xctoolchain/usr/bin/size: file: t.o does not contain architecture: armv7
8 0 0 0 8 8
enkidu: ~/tmp $
llvm-size, on the other hand, silently ignores the not-present -arch command option(s) if it finds any of them in the file.
> + return false;
> + }
> + }
> + return true;
> +}
> +
> /// @brief Print the section sizes for @p file. If @p file is an archive, print
> /// the section sizes for each archive member.
> static void PrintFileSectionSizes(StringRef file) {
> @@ -444,6 +484,8 @@ static void PrintFileSectionSizes(String
> }
> if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
> MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
> + if (!checkMachOAndArchFlags(o, file))
> + return;
> if (OutputFormat == sysv)
> outs() << o->getFileName() << " (ex " << a->getFileName()
> << "):\n";
> @@ -460,8 +502,155 @@ static void PrintFileSectionSizes(String
> }
> } else if (MachOUniversalBinary *UB =
> dyn_cast<MachOUniversalBinary>(binary.get())) {
> - // This is a Mach-O universal binary. Iterate over each object and
> - // display its sizes.
> + // If we have a list of architecture flags specified dump only those.
> + if (!ArchAll && ArchFlags.size() != 0) {
> + // Look for a slice in the universal binary that matches each ArchFlag.
> + bool ArchFound;
> + for (unsigned i = 0; i < ArchFlags.size(); ++i){
> + ArchFound = false;
> + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
> + E = UB->end_objects();
> + I != E; ++I) {
These loops can very likely use C++11 style.
"for (const auto Object : UB)"
> + if (ArchFlags[i] == I->getArchTypeName()){
> + ArchFound = true;
> + ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
> + std::unique_ptr<Archive> UA;
> + if (UO) {
> + if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
> + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
> + if (OutputFormat == sysv)
> + outs() << o->getFileName() << " :\n";
> + else if(MachO && OutputFormat == darwin) {
> + if (moreThanOneFile || ArchFlags.size() > 1)
> + outs() << o->getFileName() << " (for architecture "
> + << I->getArchTypeName() << "): \n";
> + }
> + PrintObjectSectionSizes(o);
> + if (OutputFormat == berkeley) {
> + if (!MachO || moreThanOneFile || ArchFlags.size() > 1)
> + outs() << o->getFileName() << " (for architecture "
> + << I->getArchTypeName() << ")";
> + outs() << "\n";
> + }
> + }
> + }
> + else if (!I->getAsArchive(UA)) {
> + // This is an archive. Iterate over each member and display its
> + //sizes.
> + for (object::Archive::child_iterator i = UA->child_begin(),
> + e = UA->child_end();
> + i != e; ++i) {
> + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
> + if (std::error_code EC = ChildOrErr.getError()) {
> + errs() << ToolName << ": " << file << ": " << EC.message()
> + << ".\n";
> + continue;
> + }
> + if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
> + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
> + if (OutputFormat == sysv)
> + outs() << o->getFileName() << " (ex " << UA->getFileName()
> + << "):\n";
> + else if(MachO && OutputFormat == darwin)
> + outs() << UA->getFileName() << "(" << o->getFileName()
> + << ")" << " (for architecture "
> + << I->getArchTypeName() << "):\n";
> + PrintObjectSectionSizes(o);
> + if (OutputFormat == berkeley) {
> + if (MachO) {
> + outs() << UA->getFileName() << "(" << o->getFileName()
> + << ")";
> + if (ArchFlags.size() > 1)
> + outs() << " (for architecture "
> + << I->getArchTypeName() << ")";
> + outs() << "\n";
> + }
> + else
> + outs() << o->getFileName() << " (ex " << UA->getFileName()
> + << ")\n";
> + }
> + }
> + }
> + }
> + }
> + }
> + if (!ArchFound) {
> + errs() << ToolName << ": file: " << file
> + << " does not contain architecture" << ArchFlags[i] << ".\n";
> + return;
> + }
> + }
> + return;
> + }
> + // No architecture flags were specified so if this contains a slice that
> + // matches the host architecture dump only that.
> + if (!ArchAll) {
> + StringRef HostArchName =
> + MachOObjectFile::getHostArch().getArchName();
> + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
> + E = UB->end_objects();
> + I != E; ++I) {
> + if (HostArchName == I->getArchTypeName()){
> + ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
> + std::unique_ptr<Archive> UA;
> + if (UO) {
> + if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
> + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
> + if (OutputFormat == sysv)
> + outs() << o->getFileName() << " :\n";
> + else if(MachO && OutputFormat == darwin) {
> + if (moreThanOneFile)
> + outs() << o->getFileName() << " (for architecture "
> + << I->getArchTypeName() << "):\n";
> + }
> + PrintObjectSectionSizes(o);
> + if (OutputFormat == berkeley) {
> + if (!MachO || moreThanOneFile)
> + outs() << o->getFileName() << " (for architecture "
> + << I->getArchTypeName() << ")";
> + outs() << "\n";
> + }
> + }
> + }
> + else if (!I->getAsArchive(UA)) {
> + // This is an archive. Iterate over each member and display its
> + // sizes.
> + for (object::Archive::child_iterator i = UA->child_begin(),
> + e = UA->child_end();
> + i != e; ++i) {
> + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
> + if (std::error_code EC = ChildOrErr.getError()) {
> + errs() << ToolName << ": " << file << ": " << EC.message()
> + << ".\n";
> + continue;
> + }
> + if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
> + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
> + if (OutputFormat == sysv)
> + outs() << o->getFileName() << " (ex " << UA->getFileName()
> + << "):\n";
> + else if(MachO && OutputFormat == darwin)
> + outs() << UA->getFileName() << "(" << o->getFileName() << ")"
> + << " (for architecture " << I->getArchTypeName()
> + << "):\n";
> + PrintObjectSectionSizes(o);
> + if (OutputFormat == berkeley) {
> + if (MachO)
> + outs() << UA->getFileName() << "(" << o->getFileName()
> + << ")\n";
> + else
> + outs() << o->getFileName() << " (ex " << UA->getFileName()
> + << ")\n";
> + }
> + }
> + }
> + }
> + return;
> + }
> + }
> + }
> + // Either all architectures have been specified or none have been specified
> + // and this does not contain the host architecture so dump all the slices.
> bool moreThanOneArch = UB->getNumberOfObjects() > 1;
> for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
> E = UB->end_objects();
> @@ -521,6 +710,8 @@ static void PrintFileSectionSizes(String
> }
> }
> } else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) {
> + if (!checkMachOAndArchFlags(o, file))
> + return;
> if (OutputFormat == sysv)
> outs() << o->getFileName() << " :\n";
> PrintObjectSectionSizes(o);
> @@ -552,6 +743,20 @@ int main(int argc, char **argv) {
> if (RadixShort.getNumOccurrences())
> Radix = RadixShort;
>
> + for (unsigned i = 0; i < ArchFlags.size(); ++i){
> + if (ArchFlags[i] == "all") {
> + ArchAll = true;
> + }
> + else {
> + Triple T = MachOObjectFile::getArch(ArchFlags[i]);
> + if (T.getArch() == Triple::UnknownArch){
> + outs() << ToolName << ": for the -arch option: Unknown architecture "
> + << "named '" << ArchFlags[i] << "’";
Need a ‘\n’ at the end of the diagnostic.
Phrasing is a bit odd. Maybe just use what size(1) does (w/o the list of valid arch, as that’s pretty long these days). "unknown architecture specification flag: -arch <name>”
Something is odd, here, though. I’m getting this diagnostic for “-arch armv7”.
> + return 1;
> + }
> + }
> + }
> +
> if (InputFilenames.size() == 0)
> InputFilenames.push_back("a.out");
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list