Skip to content

Commit 6442317

Browse files
committedJun 21, 2019
[llvm-lipo] Implement -thin
Creates thin output file of specified arch_type from the fat input file. Patch by Anusha Basana <anushabasana@fb.com> Differential Revision: https://reviews.llvm.org/D63341 llvm-svn: 364107
1 parent eeb3f99 commit 6442317

8 files changed

+489
-5
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
--- !mach-o
2+
FileHeader:
3+
magic: 0xFEEDFACE
4+
cputype: 0x00000007
5+
cpusubtype: 0x00000003
6+
filetype: 0x00000001
7+
ncmds: 4
8+
sizeofcmds: 312
9+
flags: 0x00002000
10+
LoadCommands:
11+
- cmd: LC_SEGMENT
12+
cmdsize: 192
13+
segname: ''
14+
vmaddr: 0
15+
vmsize: 72
16+
fileoff: 340
17+
filesize: 72
18+
maxprot: 7
19+
initprot: 7
20+
nsects: 2
21+
flags: 0
22+
Sections:
23+
- sectname: __text
24+
segname: __TEXT
25+
addr: 0x0000000000000000
26+
size: 18
27+
offset: 0x00000154
28+
align: 4
29+
reloff: 0x00000000
30+
nreloc: 0
31+
flags: 0x80000400
32+
reserved1: 0x00000000
33+
reserved2: 0x00000000
34+
reserved3: 0x00000000
35+
- sectname: __eh_frame
36+
segname: __TEXT
37+
addr: 0x0000000000000014
38+
size: 52
39+
offset: 0x00000168
40+
align: 2
41+
reloff: 0x00000000
42+
nreloc: 0
43+
flags: 0x6800000B
44+
reserved1: 0x00000000
45+
reserved2: 0x00000000
46+
reserved3: 0x00000000
47+
- cmd: LC_VERSION_MIN_MACOSX
48+
cmdsize: 16
49+
version: 656384
50+
sdk: 0
51+
- cmd: LC_SYMTAB
52+
cmdsize: 24
53+
symoff: 412
54+
nsyms: 1
55+
stroff: 424
56+
strsize: 8
57+
- cmd: LC_DYSYMTAB
58+
cmdsize: 80
59+
ilocalsym: 0
60+
nlocalsym: 0
61+
iextdefsym: 0
62+
nextdefsym: 1
63+
iundefsym: 1
64+
nundefsym: 0
65+
tocoff: 0
66+
ntoc: 0
67+
modtaboff: 0
68+
nmodtab: 0
69+
extrefsymoff: 0
70+
nextrefsyms: 0
71+
indirectsymoff: 0
72+
nindirectsyms: 0
73+
extreloff: 0
74+
nextrel: 0
75+
locreloff: 0
76+
nlocrel: 0
77+
LinkEditData:
78+
NameList:
79+
- n_strx: 1
80+
n_type: 0x0F
81+
n_sect: 1
82+
n_desc: 0
83+
n_value: 0
84+
StringTable:
85+
- ''
86+
- _main
87+
- ''
88+
...
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
--- !fat-mach-o
2+
FatHeader:
3+
magic: 0xCAFEBABE
4+
nfat_arch: 2
5+
FatArchs:
6+
- cputype: 0x00000007
7+
cpusubtype: 0x00000003
8+
offset: 0x0000000000001000
9+
size: 432
10+
align: 12
11+
- cputype: 0x01000007
12+
cpusubtype: 0x00000003
13+
offset: 0x0000000000002000
14+
size: 488
15+
align: 12
16+
Slices:
17+
- !mach-o
18+
FileHeader:
19+
magic: 0xFEEDFACE
20+
cputype: 0x00000007
21+
cpusubtype: 0x00000003
22+
filetype: 0x00000001
23+
ncmds: 4
24+
sizeofcmds: 312
25+
flags: 0x00002000
26+
LoadCommands:
27+
- cmd: LC_SEGMENT
28+
cmdsize: 192
29+
segname: ''
30+
vmaddr: 0
31+
vmsize: 72
32+
fileoff: 340
33+
filesize: 72
34+
maxprot: 7
35+
initprot: 7
36+
nsects: 2
37+
flags: 0
38+
Sections:
39+
- sectname: __text
40+
segname: __TEXT
41+
addr: 0x0000000000000000
42+
size: 18
43+
offset: 0x00000154
44+
align: 4
45+
reloff: 0x00000000
46+
nreloc: 0
47+
flags: 0x80000400
48+
reserved1: 0x00000000
49+
reserved2: 0x00000000
50+
reserved3: 0x00000000
51+
- sectname: __eh_frame
52+
segname: __TEXT
53+
addr: 0x0000000000000014
54+
size: 52
55+
offset: 0x00000168
56+
align: 2
57+
reloff: 0x00000000
58+
nreloc: 0
59+
flags: 0x6800000B
60+
reserved1: 0x00000000
61+
reserved2: 0x00000000
62+
reserved3: 0x00000000
63+
- cmd: LC_VERSION_MIN_MACOSX
64+
cmdsize: 16
65+
version: 656384
66+
sdk: 0
67+
- cmd: LC_SYMTAB
68+
cmdsize: 24
69+
symoff: 412
70+
nsyms: 1
71+
stroff: 424
72+
strsize: 8
73+
- cmd: LC_DYSYMTAB
74+
cmdsize: 80
75+
ilocalsym: 0
76+
nlocalsym: 0
77+
iextdefsym: 0
78+
nextdefsym: 1
79+
iundefsym: 1
80+
nundefsym: 0
81+
tocoff: 0
82+
ntoc: 0
83+
modtaboff: 0
84+
nmodtab: 0
85+
extrefsymoff: 0
86+
nextrefsyms: 0
87+
indirectsymoff: 0
88+
nindirectsyms: 0
89+
extreloff: 0
90+
nextrel: 0
91+
locreloff: 0
92+
nlocrel: 0
93+
LinkEditData:
94+
NameList:
95+
- n_strx: 1
96+
n_type: 0x0F
97+
n_sect: 1
98+
n_desc: 0
99+
n_value: 0
100+
StringTable:
101+
- ''
102+
- _main
103+
- ''
104+
- !mach-o
105+
FileHeader:
106+
magic: 0xFEEDFACF
107+
cputype: 0x01000007
108+
cpusubtype: 0x00000003
109+
filetype: 0x00000001
110+
ncmds: 4
111+
sizeofcmds: 352
112+
flags: 0x00002000
113+
reserved: 0x00000000
114+
LoadCommands:
115+
- cmd: LC_SEGMENT_64
116+
cmdsize: 232
117+
segname: ''
118+
vmaddr: 0
119+
vmsize: 80
120+
fileoff: 384
121+
filesize: 80
122+
maxprot: 7
123+
initprot: 7
124+
nsects: 2
125+
flags: 0
126+
Sections:
127+
- sectname: __text
128+
segname: __TEXT
129+
addr: 0x0000000000000000
130+
size: 15
131+
offset: 0x00000180
132+
align: 4
133+
reloff: 0x00000000
134+
nreloc: 0
135+
flags: 0x80000400
136+
reserved1: 0x00000000
137+
reserved2: 0x00000000
138+
reserved3: 0x00000000
139+
- sectname: __eh_frame
140+
segname: __TEXT
141+
addr: 0x0000000000000010
142+
size: 64
143+
offset: 0x00000190
144+
align: 3
145+
reloff: 0x00000000
146+
nreloc: 0
147+
flags: 0x6800000B
148+
reserved1: 0x00000000
149+
reserved2: 0x00000000
150+
reserved3: 0x00000000
151+
- cmd: LC_VERSION_MIN_MACOSX
152+
cmdsize: 16
153+
version: 656384
154+
sdk: 0
155+
- cmd: LC_SYMTAB
156+
cmdsize: 24
157+
symoff: 464
158+
nsyms: 1
159+
stroff: 480
160+
strsize: 8
161+
- cmd: LC_DYSYMTAB
162+
cmdsize: 80
163+
ilocalsym: 0
164+
nlocalsym: 0
165+
iextdefsym: 0
166+
nextdefsym: 1
167+
iundefsym: 1
168+
nundefsym: 0
169+
tocoff: 0
170+
ntoc: 0
171+
modtaboff: 0
172+
nmodtab: 0
173+
extrefsymoff: 0
174+
nextrefsyms: 0
175+
indirectsymoff: 0
176+
nindirectsyms: 0
177+
extreloff: 0
178+
nextrel: 0
179+
locreloff: 0
180+
nlocrel: 0
181+
LinkEditData:
182+
NameList:
183+
- n_strx: 1
184+
n_type: 0x0F
185+
n_sect: 1
186+
n_desc: 0
187+
n_value: 0
188+
StringTable:
189+
- ''
190+
- _main
191+
- ''
192+
...

‎llvm/test/tools/llvm-lipo/help-error-messages.test

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
# RUN: not llvm-lipo --abcabc 2>&1 | FileCheck --check-prefix=LIPO-UNKNOWN-ARG %s
1010

1111
# RUN: not llvm-lipo %t -archs -verify_arch i386 2>&1 | FileCheck --check-prefix=MULTIPLE_FLAGS %s
12-
# MULTIPLE_FLAGS: only one of the following actions can be specified: -archs -verify_arch
12+
# RUN: not llvm-lipo %t -archs -thin i386 2>&1 | FileCheck --check-prefix=MULTIPLE_FLAGS %s
13+
# RUN: not llvm-lipo %t -thin i386 -verify_arch i386 2>&1 | FileCheck --check-prefix=MULTIPLE_FLAGS %s
14+
# RUN: not llvm-lipo %t -archs -thin i386 -verify_arch i386 2>&1 | FileCheck --check-prefix=MULTIPLE_FLAGS %s
15+
# MULTIPLE_FLAGS: only one of the following actions can be specified:
1316

1417
# LIPO-USAGE: USAGE: llvm-lipo
1518
# LIPO-UNKNOWN-ARG: unknown argument '{{-+}}abcabc'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Executable testing is not supported on Windows, since all files are considered executable
2+
# UNSUPPORTED: windows
3+
# RUN: yaml2obj %s > %t-universal.o
4+
5+
# RUN: chmod -x %t-universal.o
6+
# RUN: llvm-lipo %t-universal.o -thin i386 -output %t32.o
7+
# RUN: test ! -x %t32.o
8+
9+
# RUN: chmod +x %t-universal.o
10+
# RUN: llvm-lipo %t-universal.o -thin i386 -output %t32-ex.o
11+
# RUN: test -x %t32-ex.o
12+
13+
14+
15+
--- !fat-mach-o
16+
FatHeader:
17+
magic: 0xCAFEBABE
18+
nfat_arch: 2
19+
FatArchs:
20+
- cputype: 0x00000007
21+
cpusubtype: 0x00000003
22+
offset: 0x0000000000001000
23+
size: 28
24+
align: 12
25+
- cputype: 0x01000007
26+
cpusubtype: 0x00000003
27+
offset: 0x0000000000002000
28+
size: 32
29+
align: 12
30+
Slices:
31+
- !mach-o
32+
FileHeader:
33+
magic: 0xFEEDFACE
34+
cputype: 0x00000007
35+
cpusubtype: 0x00000003
36+
filetype: 0x00000001
37+
ncmds: 0
38+
sizeofcmds: 0
39+
flags: 0x00002000
40+
- !mach-o
41+
FileHeader:
42+
magic: 0xFEEDFACF
43+
cputype: 0x01000007
44+
cpusubtype: 0x00000003
45+
filetype: 0x00000001
46+
ncmds: 0
47+
sizeofcmds: 0
48+
flags: 0x00002000
49+
reserved: 0x00000000
50+
...
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# RUN: yaml2obj %s > %t
2+
3+
# RUN: not llvm-lipo %t -thin i386 2>&1 | FileCheck --check-prefix=NO_OUTPUT %s
4+
# NO_OUTPUT: error: thin expects a single output file
5+
6+
# RUN: not llvm-lipo %t %t -thin i386 2>&1 | FileCheck --check-prefix=MULTIPLE_INPUT_OBJ %s
7+
# MULTIPLE_INPUT_OBJ: thin expects a single input file
8+
9+
# RUN: not llvm-lipo %t -thin i386 -output %t.out 2>&1 | FileCheck --check-prefix=INPUT_FILE_THIN %s
10+
# INPUT_FILE_THIN: must be a fat file when the -thin option is specified
11+
12+
--- !mach-o
13+
FileHeader:
14+
magic: 0xFEEDFACE
15+
cputype: 0x00000097
16+
cpusubtype: 0x00000003
17+
filetype: 0x00000001
18+
ncmds: 0
19+
sizeofcmds: 0
20+
flags: 0x00002000
21+
...
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# RUN: yaml2obj %s > %t
2+
3+
# RUN: not llvm-lipo %t -thin arc -output %t.out 2>&1 | FileCheck --check-prefix=ARCH_NOT_IN_FILE %s
4+
# ARCH_NOT_IN_FILE: does not contain the specified architecture arc to thin it to
5+
6+
# RUN: not llvm-lipo %t -thin aarch101 -output %t.out 2>&1 | FileCheck --check-prefix=INVALID_ARCH %s
7+
# INVALID_ARCH: Invalid architecture: aarch101
8+
9+
# RUN: yaml2obj %p/Inputs/i386-x86_64-universal.yaml > %t-universal.o
10+
# RUN: llvm-lipo %t-universal.o -thin i386 -output %t32.o
11+
# RUN: yaml2obj %p/Inputs/i386-slice.yaml > %t-basic32.o
12+
# RUN: cmp %t32.o %t-basic32.o
13+
14+
--- !fat-mach-o
15+
FatHeader:
16+
magic: 0xCAFEBABE
17+
nfat_arch: 2
18+
FatArchs:
19+
- cputype: 0x00000007
20+
cpusubtype: 0x00000003
21+
offset: 0x0000000000001000
22+
size: 28
23+
align: 12
24+
- cputype: 0x01000007
25+
cpusubtype: 0x00000003
26+
offset: 0x0000000000002000
27+
size: 32
28+
align: 12
29+
Slices:
30+
- !mach-o
31+
FileHeader:
32+
magic: 0xFEEDFACE
33+
cputype: 0x00000007
34+
cpusubtype: 0x00000003
35+
filetype: 0x00000001
36+
ncmds: 0
37+
sizeofcmds: 0
38+
flags: 0x00002000
39+
- !mach-o
40+
FileHeader:
41+
magic: 0xFEEDFACF
42+
cputype: 0x01000007
43+
cpusubtype: 0x00000003
44+
filetype: 0x00000001
45+
ncmds: 0
46+
sizeofcmds: 0
47+
flags: 0x00002000
48+
reserved: 0x00000000
49+
...

‎llvm/tools/llvm-lipo/LipoOpts.td

+9
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,12 @@ def verify_arch
1717
def archs : Option<["-", "--"], "archs", KIND_FLAG>,
1818
Group<action_group>,
1919
HelpText<"Display the arch_types present in the input file">;
20+
21+
def thin : Option<["-", "--"], "thin", KIND_SEPARATE>,
22+
Group<action_group>,
23+
HelpText<"Create a thin output file of specified arch_type from the "
24+
"fat input file. Requires -output option">;
25+
26+
def output : Option<["-", "--"], "output", KIND_SEPARATE>,
27+
HelpText<"Create output file with specified name">;
28+
def o : JoinedOrSeparate<["-"], "o">, Alias<output>;

‎llvm/tools/llvm-lipo/llvm-lipo.cpp

+76-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/Option/ArgList.h"
2020
#include "llvm/Support/CommandLine.h"
2121
#include "llvm/Support/Error.h"
22+
#include "llvm/Support/FileOutputBuffer.h"
2223
#include "llvm/Support/InitLLVM.h"
2324
#include "llvm/Support/WithColor.h"
2425

@@ -78,23 +79,36 @@ class LipoOptTable : public opt::OptTable {
7879
enum class LipoAction {
7980
PrintArchs,
8081
VerifyArch,
82+
ThinArch,
8183
};
8284

8385
struct Config {
8486
SmallVector<std::string, 1> InputFiles;
8587
SmallVector<std::string, 1> VerifyArchList;
88+
std::string ThinArchType;
89+
std::string OutputFile;
8690
LipoAction ActionToPerform;
8791
};
8892

8993
} // end namespace
9094

95+
static void validateArchitectureName(StringRef ArchitectureName) {
96+
if (Triple(ArchitectureName).getArch() == Triple::ArchType::UnknownArch)
97+
reportError("Invalid architecture: " + ArchitectureName);
98+
}
99+
91100
static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) {
92101
Config C;
93102
LipoOptTable T;
94103
unsigned MissingArgumentIndex, MissingArgumentCount;
95104
llvm::opt::InputArgList InputArgs =
96105
T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
97106

107+
if (MissingArgumentCount)
108+
reportError("missing argument to " +
109+
StringRef(InputArgs.getArgString(MissingArgumentIndex)) +
110+
" option");
111+
98112
if (InputArgs.size() == 0) {
99113
// PrintHelp does not accept Twine.
100114
T.PrintHelp(errs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
@@ -121,6 +135,9 @@ static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) {
121135
if (C.InputFiles.empty())
122136
reportError("at least one input file should be specified");
123137

138+
if (InputArgs.hasArg(LIPO_output))
139+
C.OutputFile = InputArgs.getLastArgValue(LIPO_output);
140+
124141
SmallVector<opt::Arg *, 1> ActionArgs(InputArgs.filtered(LIPO_action_group));
125142
if (ActionArgs.empty())
126143
reportError("at least one action should be specified");
@@ -151,6 +168,17 @@ static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) {
151168
C.ActionToPerform = LipoAction::PrintArchs;
152169
return C;
153170

171+
case LIPO_thin:
172+
if (C.InputFiles.size() > 1)
173+
reportError("thin expects a single input file");
174+
C.ThinArchType = ActionArgs[0]->getValue();
175+
validateArchitectureName(C.ThinArchType);
176+
if (C.OutputFile.empty())
177+
reportError("thin expects a single output file");
178+
179+
C.ActionToPerform = LipoAction::ThinArch;
180+
return C;
181+
154182
default:
155183
reportError("llvm-lipo action unspecified");
156184
}
@@ -164,8 +192,12 @@ readInputBinaries(ArrayRef<std::string> InputFiles) {
164192
createBinary(InputFile);
165193
if (!BinaryOrErr)
166194
reportError(InputFile, BinaryOrErr.takeError());
167-
if (!isa<MachOObjectFile>(BinaryOrErr->getBinary()) &&
168-
!isa<MachOUniversalBinary>(BinaryOrErr->getBinary()))
195+
// TODO: Add compatibility for archive files
196+
if (BinaryOrErr->getBinary()->isArchive())
197+
reportError("File " + InputFile +
198+
" is an archive file and is not yet supported.");
199+
if (!BinaryOrErr->getBinary()->isMachO() &&
200+
!BinaryOrErr->getBinary()->isMachOUniversalBinary())
169201
reportError("File " + InputFile + " has unsupported binary format");
170202
InputBinaries.push_back(std::move(*BinaryOrErr));
171203
}
@@ -180,8 +212,7 @@ static void verifyArch(ArrayRef<OwningBinary<Binary>> InputBinaries,
180212
assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
181213

182214
for (StringRef Arch : VerifyArchList)
183-
if (Triple(Arch).getArch() == Triple::ArchType::UnknownArch)
184-
reportError("Invalid architecture: " + Arch);
215+
validateArchitectureName(Arch);
185216

186217
if (auto UO =
187218
dyn_cast<MachOUniversalBinary>(InputBinaries.front().getBinary())) {
@@ -238,6 +269,44 @@ static void printArchs(ArrayRef<OwningBinary<Binary>> InputBinaries) {
238269
exit(EXIT_SUCCESS);
239270
}
240271

272+
LLVM_ATTRIBUTE_NORETURN
273+
static void extractSlice(ArrayRef<OwningBinary<Binary>> InputBinaries,
274+
StringRef ThinArchType, StringRef OutputFileName) {
275+
assert(!ThinArchType.empty() && "The architecture type should be non-empty");
276+
assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
277+
assert(!OutputFileName.empty() && "Thin expects a single output file");
278+
279+
if (InputBinaries.front().getBinary()->isMachO()) {
280+
reportError("input file " +
281+
InputBinaries.front().getBinary()->getFileName() +
282+
" must be a fat file when the -thin option is specified");
283+
exit(EXIT_FAILURE);
284+
}
285+
286+
auto *UO = cast<MachOUniversalBinary>(InputBinaries.front().getBinary());
287+
Expected<std::unique_ptr<MachOObjectFile>> Obj =
288+
UO->getObjectForArch(ThinArchType);
289+
if (!Obj)
290+
reportError("fat input file " + UO->getFileName() +
291+
" does not contain the specified architecture " + ThinArchType +
292+
" to thin it to");
293+
294+
Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError =
295+
FileOutputBuffer::create(OutputFileName,
296+
Obj.get()->getMemoryBufferRef().getBufferSize(),
297+
sys::fs::can_execute(UO->getFileName())
298+
? FileOutputBuffer::F_executable
299+
: 0);
300+
if (!OutFileOrError)
301+
reportError(OutputFileName, OutFileOrError.takeError());
302+
std::copy(Obj.get()->getMemoryBufferRef().getBufferStart(),
303+
Obj.get()->getMemoryBufferRef().getBufferEnd(),
304+
OutFileOrError.get()->getBufferStart());
305+
if (Error E = OutFileOrError.get()->commit())
306+
reportError(OutputFileName, std::move(E));
307+
exit(EXIT_SUCCESS);
308+
}
309+
241310
int main(int argc, char **argv) {
242311
InitLLVM X(argc, argv);
243312
Config C = parseLipoOptions(makeArrayRef(argv + 1, argc));
@@ -251,6 +320,9 @@ int main(int argc, char **argv) {
251320
case LipoAction::PrintArchs:
252321
printArchs(InputBinaries);
253322
break;
323+
case LipoAction::ThinArch:
324+
extractSlice(InputBinaries, C.ThinArchType, C.OutputFile);
325+
break;
254326
}
255327
return EXIT_SUCCESS;
256328
}

0 commit comments

Comments
 (0)
Please sign in to comment.