[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