-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[LLD][COFF] Add support for custom section layout #152779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
d2c8f20
8fe1010
0e9b1ef
e1bb9c6
a0f6226
81d8d83
cf6ed7d
968b1c8
7e5dd4a
41b76ab
7c92443
33b92f2
d7b531e
bac6deb
01af3b7
752ca98
7ad63ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -214,6 +214,46 @@ void LinkerDriver::parseSection(StringRef s) { | |
| ctx.config.section[name] = parseSectionAttributes(ctx, attrs); | ||
| } | ||
|
|
||
| // Parses /sectionlayout:@ option argument. | ||
kkent030315 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| void LinkerDriver::parseSectionLayout(StringRef path) { | ||
| if (path.starts_with("@")) | ||
| path = path.substr(1); | ||
| std::unique_ptr<MemoryBuffer> layoutFile = | ||
| CHECK(MemoryBuffer::getFile(path), "could not open " + path); | ||
| StringRef content = layoutFile->getBuffer(); | ||
| int index = 0; | ||
|
|
||
| while (!content.empty()) { | ||
| size_t pos = content.find_first_of("\r\n"); | ||
| StringRef line; | ||
|
|
||
| if (pos == StringRef::npos) { | ||
| line = content; | ||
| content = StringRef(); | ||
| } else { | ||
| line = content.substr(0, pos); | ||
| content = content.substr(pos); | ||
| while (!content.empty() && (content[0] == '\r' || content[0] == '\n')) | ||
| content = content.substr(1); | ||
kkent030315 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| line = line.trim(); | ||
| if (line.empty()) | ||
| continue; | ||
|
|
||
| StringRef sectionName = line.split(' ').first; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this ignores anything after a space on each line? On a quick glance through the tests, I don't see any of the tests exercising that aspect.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MS link.exe accepts a line with more tokens like It's good to have tests as you mentioned, I agree. I'll add tests for ignored tokens. |
||
| std::string sectionNameStr = sectionName.str(); | ||
kkent030315 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if (ctx.config.sectionOrder.count(sectionNameStr)) { | ||
| Warn(ctx) << "duplicate section '" << sectionNameStr | ||
| << "' in section layout file, ignoring"; | ||
| continue; | ||
| } | ||
|
|
||
| ctx.config.sectionOrder[sectionNameStr] = index++; | ||
| } | ||
| } | ||
|
|
||
| void LinkerDriver::parseDosStub(StringRef path) { | ||
| std::unique_ptr<MemoryBuffer> stub = | ||
| CHECK(MemoryBuffer::getFile(path), "could not open " + path); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| --- !COFF | ||
| header: | ||
| Machine: IMAGE_FILE_MACHINE_AMD64 | ||
| Characteristics: [] | ||
| sections: | ||
| - Name: '.text1' | ||
| Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | ||
| Alignment: 16 | ||
| SectionData: B82A000000C3 | ||
| - Name: '.text2' | ||
| Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | ||
| Alignment: 16 | ||
| SectionData: CC | ||
| - Name: '.text3' | ||
| Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | ||
| Alignment: 16 | ||
| SectionData: CC | ||
| symbols: | ||
| - Name: main | ||
| Value: 0 | ||
| SectionNumber: 1 | ||
| SimpleType: IMAGE_SYM_TYPE_NULL | ||
| ComplexType: IMAGE_SYM_DTYPE_FUNCTION | ||
| StorageClass: IMAGE_SYM_CLASS_EXTERNAL | ||
| ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| RUN: yaml2obj %p/Inputs/sectionlayout.yaml -o %t.obj | ||
|
|
||
| ## Error on non-exist input layout file | ||
| RUN: not lld-link /entry:main /sectionlayout:doesnotexist.txt %t.obj | ||
|
|
||
| ## Order in 1 -> 3 -> 2 | ||
| RUN: echo ".text1" > %t.layout.txt | ||
| RUN: echo ".text3" >> %t.layout.txt | ||
| RUN: echo ".text2" >> %t.layout.txt | ||
| RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj | ||
| RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK1 %s | ||
|
|
||
| ## While /sectionlayout:abc is valid, /sectionlayout:@abc is also accepted (to align with MS link.exe) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a curiousity, do you know why the @ syntax exists?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah it's a bit odd. The |
||
| RUN: lld-link /out:%t.exe /entry:main /sectionlayout:@%t.layout.txt %t.obj | ||
| RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK1 %s | ||
|
|
||
| CHECK1: Sections [ | ||
| CHECK1: Section { | ||
| CHECK1: Number: 1 | ||
| CHECK1: Name: .text1 | ||
| CHECK1: } | ||
| CHECK1: Section { | ||
| CHECK1: Number: 2 | ||
| CHECK1: Name: .text3 | ||
| CHECK1: } | ||
| CHECK1: Section { | ||
| CHECK1: Number: 3 | ||
| CHECK1: Name: .text2 | ||
| CHECK1: } | ||
| CHECK1: ] | ||
|
|
||
| ## Order in 3 -> 2 -> 1 | ||
| RUN: echo ".text3" > %t.layout.txt | ||
| RUN: echo ".text2" >> %t.layout.txt | ||
| RUN: echo ".text1" >> %t.layout.txt | ||
| RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj | ||
| RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK2 %s | ||
|
|
||
| CHECK2: Sections [ | ||
| CHECK2: Section { | ||
| CHECK2: Number: 1 | ||
| CHECK2: Name: .text3 | ||
| CHECK2: } | ||
| CHECK2: Section { | ||
| CHECK2: Number: 2 | ||
| CHECK2: Name: .text2 | ||
| CHECK2: } | ||
| CHECK2: Section { | ||
| CHECK2: Number: 3 | ||
| CHECK2: Name: .text1 | ||
| CHECK2: } | ||
| CHECK2: ] | ||
|
|
||
| ## Put non-exisist section in layout file has no effect; original order is respected | ||
| RUN: echo "notexist" > %t.layout.txt | ||
| RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj | ||
| RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK3 %s | ||
|
|
||
| ## Empty layout file has no effect | ||
| RUN: echo "" > %t.layout.txt | ||
| RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj | ||
| RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK3 %s | ||
|
|
||
| ## Empty layout file has no effect | ||
| RUN: echo " " > %t.layout.txt | ||
| RUN: echo " " >> %t.layout.txt | ||
| RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj | ||
| RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK3 %s | ||
|
|
||
| CHECK3: Sections [ | ||
| CHECK3: Section { | ||
| CHECK3: Number: 1 | ||
| CHECK3: Name: .text1 | ||
| CHECK3: } | ||
| CHECK3: Section { | ||
| CHECK3: Number: 2 | ||
| CHECK3: Name: .text2 | ||
| CHECK3: } | ||
| CHECK3: Section { | ||
| CHECK3: Number: 3 | ||
| CHECK3: Name: .text3 | ||
| CHECK3: } | ||
| CHECK3: ] | ||
|
|
||
| ## Order in 3 -> 1, but 2 remains unspecified | ||
| RUN: echo ".text3" > %t.layout.txt | ||
| RUN: echo ".text1" >> %t.layout.txt | ||
| RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj | ||
| RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK4 %s | ||
|
|
||
| CHECK4: Sections [ | ||
| CHECK4: Section { | ||
| CHECK4: Number: 1 | ||
| CHECK4: Name: .text3 | ||
| CHECK4: } | ||
| CHECK4: Section { | ||
| CHECK4: Number: 2 | ||
| CHECK4: Name: .text1 | ||
| CHECK4: } | ||
| CHECK4: Section { | ||
| CHECK4: Number: 3 | ||
| CHECK4: Name: .text2 | ||
| CHECK4: } | ||
| CHECK4: ] | ||
|
|
||
| ## Order in 3 -> 2, but 1 remains unspecified. | ||
| ## 1 should be the first, as the original order (1 -> 2 -> 3) is respected | ||
| RUN: echo ".text3" > %t.layout.txt | ||
| RUN: echo ".text2" >> %t.layout.txt | ||
| RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj | ||
| RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK1 %s | ||
|
|
||
| ## Order in 3 -> 2 -> 1, multiple specification has no effect (the first one is used) | ||
| RUN: echo ".text3" > %t.layout.txt | ||
| RUN: echo ".text3" >> %t.layout.txt | ||
| RUN: echo ".text3" >> %t.layout.txt | ||
| RUN: echo ".text2" >> %t.layout.txt | ||
| RUN: echo ".text2" >> %t.layout.txt | ||
| RUN: echo ".text1" >> %t.layout.txt | ||
| RUN: echo ".text3" >> %t.layout.txt | ||
| RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj | ||
| RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK2 %s | ||
Uh oh!
There was an error while loading. Please reload this page.