Skip to content

Commit a02a875

Browse files
parth-07quic-seaswara
authored andcommitted
Support 'archive: member' file-pattern in input section description
This commit adds support for 'archive: member' pattern in input section description. Generally, there should be no space between the 'archive:' and 'member'. However, it is a common mistake to put a space here. This commit makes this common use-case work as expected and reports a deprecated warning for the same. Closes #67 Signed-off-by: Parth Arora <[email protected]>
1 parent 34a065f commit a02a875

File tree

10 files changed

+140
-4
lines changed

10 files changed

+140
-4
lines changed

docs/userguide/documentation/linker_faq.rst

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,6 +2302,59 @@ into both the :code:`PT_TLS` and a :code:`PT_LOAD` section. For example:
23022302
...
23032303
}
23042304
2305+
Why am I getting the warning 'Space between archive:member file pattern is deprecated'
2306+
-----------------------------------------------------------------------------------------
2307+
2308+
Linker script allows to specify archive members in input section descriptions
2309+
using the `<archive-pattern>:<member-pattern>` syntax. For example in the below
2310+
linker script `SECTIONS` command snippet, `foo_text` output section contains the
2311+
`.text*` sections from the `foo.o` member of `libfoobar.a` archive.
2312+
2313+
.. code-block:: bash
2314+
2315+
SECTIONS {
2316+
foo_text : { libfoobar.a:foo.o(.text*) }
2317+
}
2318+
2319+
2320+
Please note that there should be no space between the `<archive-pattern>:`
2321+
and the `<member-pattern>`. Previously, the linker accepted the space
2322+
between the two patterns for convenience. This behavior is now
2323+
deprecated and will be removed in the future.
2324+
2325+
The below linker script snippet demonstrates some of the cases where
2326+
the warning will be emitted and why.
2327+
2328+
.. code-block:: bash
2329+
2330+
cat > 1.c << \!
2331+
int data = 10;
2332+
!
2333+
2334+
cat > script.t << \!
2335+
SECTIONS {
2336+
.data : {
2337+
/* The warning will be displayed because there is a space between
2338+
'*lib1.a:' and '1.o' */
2339+
*lib1.a: 1.o(.*data*)
2340+
/* No warning. When member-pattern is missing, all members of the
2341+
matched archives are matched. */
2342+
/tmp/lib1.a*: (.*data*)
2343+
*lib1.a: (.*data*)
2344+
/* The warning will be displayed because there is a space between
2345+
'*lib1.a:' and '*' */
2346+
*lib1.a: *(.*data*)
2347+
/* No warning. '*lib1.a:' and '*(.data*)' are considered as separate
2348+
input section descriptions. */
2349+
*lib1.a:
2350+
*(.data*)
2351+
}
2352+
}
2353+
!
2354+
2355+
clang -c -c 1.c -g
2356+
llvm-ar cr lib1.a 1.o
2357+
ld.eld --whole-archive lib1.a -T script.t -Map x -Wlinker-script
23052358
23062359
Linker Script PHDRS
23072360
====================

include/eld/Diagnostics/DiagLDScript.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,4 @@ DIAG(warn_non_power_of_2_value_to_align_builtin, DiagnosticEngine::Warning,
123123
DIAG(error_non_power_of_2_value_to_align_output_section, DiagnosticEngine::Error,
124124
"%0: non-power-of-2 value 0x%1 passed to ALIGN in '%2' output section description, value must "
125125
"be 0 or a power of 2")
126+
DIAG(warn_linker_script, DiagnosticEngine::Warning, "%0")

include/eld/ScriptParser/ScriptLexer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ class ScriptLexer {
4444
void setNote(const llvm::Twine &msg,
4545
std::optional<llvm::StringRef> columnTok = std::nullopt) const;
4646

47+
void setWarn(const llvm::Twine &Msg);
48+
4749
void lex();
4850

4951
// Skip spaces
@@ -100,6 +102,12 @@ class ScriptLexer {
100102
/// is no previous token, this function is no-op.
101103
void prev();
102104

105+
size_t computeLineNumber(llvm::StringRef tok);
106+
107+
size_t getCurrentLineNumber() {
108+
return PrevTokLine;
109+
}
110+
103111
protected:
104112
// Get current memory buffer
105113
llvm::MemoryBufferRef getCurrentMB() const;

lib/ScriptParser/ScriptLexer.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,14 @@ void ScriptLexer::setNote(const Twine &msg,
117117
ThisConfig.raise(Diag::note_linker_script) << s;
118118
}
119119

120+
void ScriptLexer::setWarn(const Twine &Msg) {
121+
std::string S = (getCurrentLocation() + ": " + Msg).str();
122+
if (PrevTok.size())
123+
S += "\n>>> " + getLine().str() + "\n>>> " +
124+
std::string(getColumnNumber(), ' ') + "^";
125+
ThisConfig.raise(Diag::warn_linker_script) << S;
126+
}
127+
120128
void ScriptLexer::lex() {
121129
for (;;) {
122130
StringRef &S = CurBuf.S;
@@ -145,10 +153,9 @@ void ScriptLexer::lex() {
145153
if (S.starts_with("\"")) {
146154
size_t E = S.find("\"", 1);
147155
if (E == StringRef::npos) {
148-
size_t Lineno =
149-
StringRef(CurBuf.Begin, S.data() - CurBuf.Begin).count('\n');
156+
size_t Lineno = computeLineNumber(S);
150157
ThisConfig.raise(Diag::error_linker_script)
151-
<< llvm::Twine(CurBuf.Filename + ":" + Twine(Lineno + 1) +
158+
<< llvm::Twine(CurBuf.Filename + ":" + Twine(Lineno) +
152159
": unclosed quote")
153160
.str();
154161
return;
@@ -330,6 +337,7 @@ StringRef ScriptLexer::unquote(StringRef S) {
330337

331338
void ScriptLexer::prev() {
332339
if (!PrevTok.empty()) {
340+
// FIXME: CurBuf.LineNumber needs to be updated!
333341
CurBuf.S = PrevTok.data();
334342
CurTok = {};
335343
}
@@ -357,3 +365,9 @@ size_t ScriptLexer::computeColumnWidth(llvm::StringRef s,
357365
});
358366
return e.data() - s.data() - nonASCIIColumnOffset;
359367
}
368+
369+
size_t ScriptLexer::computeLineNumber(llvm::StringRef tok) {
370+
size_t LineNumber =
371+
llvm::StringRef(CurBuf.Begin, tok.data() - CurBuf.Begin).count('\n');
372+
return LineNumber + 1;
373+
}

lib/ScriptParser/ScriptParser.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,8 +684,17 @@ InputSectDesc::Spec ScriptParser::readInputSectionDescSpec(StringRef Tok) {
684684
else {
685685
std::pair<llvm::StringRef, llvm::StringRef> Split = Tok.split(':');
686686
FilePat = ThisScriptFile.createWildCardPattern(Split.first);
687-
if (!Split.second.empty())
687+
if (!Split.second.empty()) {
688688
ArchiveMem = ThisScriptFile.createWildCardPattern(Split.second);
689+
}
690+
llvm::StringRef peekTok = peek();
691+
if (!atEOF() && peekTok != "(" &&
692+
computeLineNumber(peekTok) == getCurrentLineNumber()) {
693+
next();
694+
if (ThisConfig.showLinkerScriptWarnings())
695+
setWarn("Space between archive:member file pattern is deprecated");
696+
ArchiveMem = ThisScriptFile.createWildCardPattern(peekTok);
697+
}
689698
IsArchive = true;
690699
}
691700
StringList *WildcardSections = nullptr;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#---ArchiveFilePatternWithSpace.test--------------------- Executable ------------------#
2+
#BEGIN_COMMENT
3+
# This tests that checks that 'archive: file' pattern works for now and a
4+
# deprecated diagnostic is emitted for this usage.
5+
#END_COMMENT
6+
RUN: %clang %clangopts -o %t1.1.o %p/Inputs/1.c -c -ffunction-sections
7+
RUN: %clang %clangopts -o %t1.2.o %p/Inputs/2.c -c -ffunction-sections
8+
RUN: %ar cr %t1.lib12.a %t1.1.o %t1.2.o
9+
RUN: %link %linkopts -o %t1.a1.out --whole-archive %t1.lib12.a \
10+
RUN: -T %p/Inputs/script.1.t -Map %t1.a1.map.txt -Wno-linker-script 2>&1 | %filecheck %s --allow-empty --check-prefix NO_WARN
11+
RUN: %link %linkopts -o %t1.a1.out --whole-archive %t1.lib12.a \
12+
RUN: -T %p/Inputs/script.1.t -Map %t1.a1.map.txt -Wlinker-script 2>&1 | %filecheck %s --check-prefix WARN
13+
RUN: %filecheck %s --check-prefix MAP < %t1.a1.map.txt
14+
RUN: %link %linkopts -o %t1.a2.out --whole-archive %t1.lib12.a \
15+
RUN: -T %p/Inputs/script.2.t -Map %t1.a2.map.txt
16+
RUN: %filecheck %s --check-prefix MEMBER_PATTERN_NEXT_LINE < %t1.a2.map.txt
17+
18+
NO_WARN-NOT: Space between
19+
20+
WARN: Warning: {{.*}}script.1.t:2: Space between archive:member file pattern is deprecated
21+
WARN: >>> FOO: { *lib12.a: *1.o(*foo*) }
22+
WARN: >>> ^
23+
WARN: Warning: {{.*}}script.1.t:3: Space between archive:member file pattern is deprecated
24+
WARN: >>> BAR: { *lib12.a: *(*bar*) }
25+
WARN: >>>
26+
27+
MAP: FOO
28+
MAP: *lib12.a:*1.o(*foo*)
29+
MAP: .text.foo
30+
31+
MAP: BAR
32+
MAP: *lib12.a:*(*bar*)
33+
MAP: .text.bar
34+
35+
MEMBER_PATTERN_NEXT_LINE: WRONG_DATA
36+
MEMBER_PATTERN_NEXT_LINE: *lib12.a:(*)
37+
MEMBER_PATTERN_NEXT_LINE: .text.foo
38+
MEMBER_PATTERN_NEXT_LINE: .text.bar
39+
MEMBER_PATTERN_NEXT_LINE: *(*data*)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int foo() { return 1; }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int bar() { return 3; }
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SECTIONS {
2+
FOO: { *lib12.a: *1.o(*foo*) }
3+
BAR: { *lib12.a: *(*bar*) }
4+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SECTIONS {
2+
WRONG_DATA: {
3+
*lib12.a:
4+
*(*data*)
5+
}
6+
}

0 commit comments

Comments
 (0)