This is an archive of the discontinued LLVM Phabricator instance.

[Coverage] Comdat section name should be same as the variable name in COFF format
Needs ReviewPublic

Authored by adamf on Apr 30 2017, 2:47 PM.

Details

Reviewers
rnk
vsk
davidxl
Summary

COFF format requires to have Comdat section names same as the variable name.
For Instruction Profile Data Variable the Comdat name wasn't equal to the variable name.
It caused linker error like: "error LNK2005: ___profd_?compute@@YAHH@Z already defined in Source.obj" e.g. for functions included into multiple cpp files.

Diff Detail

Event Timeline

adamf created this revision.Apr 30 2017, 2:47 PM
vsk added a reviewer: davidxl.May 1 2017, 10:54 AM
vsk edited edge metadata.

Could you update some tests in 'test/Instrumentation/InstrProfiling/' to reflect this change? PR23499.ll and linkage.ll are good candidates.

Also, do you know why the change in r256220 ([PGO] Fix another comdat related issue for COFF) was not enough to fix linkage issues when using COFF?

davidxl edited edge metadata.May 1 2017, 11:29 AM

This patch basically splits the comdat section for data, counters and value vars with COFF.

rnk requested changes to this revision.May 1 2017, 11:41 AM

+1 to tests, it would help illustrate what's changing.

This revision now requires changes to proceed.May 1 2017, 11:41 AM
adamf updated this revision to Diff 97413.May 2 2017, 3:16 AM
adamf edited edge metadata.

Fixed use after free from previous patch on non x86_64-pc-win32-coff.
Updated test according to the fix.

adamf added a comment.EditedMay 2 2017, 3:50 AM

Could you update some tests in 'test/Instrumentation/InstrProfiling/' to reflect this change? PR23499.ll and linkage.ll are good candidates.

Thanks, I have updated this test. linkage.ll was broken because of bug in my fix (use after free in ternary operator).

+1 to tests, it would help illustrate what's changing.

I have added some additional checks in PR23499.ll to emphasize my change.

To avoid XY Problem I will start from test case to reproduce my initial problem. Based on this example you can easily reproduce the problem.
In attachment is source code, compilation command and result error (shortly also below).

Shortly how to reproduce this linker error:
I have 3 files

"Header.h"

#pragma once
inline int compute(int i){return i+1;}

"A.cpp"

#include "Header.h"
int main(){return compute(1);}

"B.cpp"

#include "Header.h"
int common(){return compute(2);}

Then I compiled it using command (on Windows):

clang++.exe -fprofile-instr-generate -fcoverage-mapping A.cpp B.cpp

Finally I received linker error message:

B-5be2e4.o : error LNK2005: ___profd_?compute@@YAHH@Z already defined in A-a141c9.o

Now I can describe details about my solution:

In above example the coverage data for function "compute" has linkage type "linkeonce_odr" for variables with prefix _profd_ and _profc_ ("_profc_?compute@@YAHH@Z" and "_profd_?compute@@YAHH@Z").
It is because these data are computed from header function file and are duplicated in A.obj and B.obj so linker has to merge these symbols.
But I have observed if the COMDAT section name is different to the variable name then the linker still fails to merge these symbols.
In the above example the COMDAT section name is "_profc_?compute@@YAHH@Z" and it is equal to variable with prefix __profc_. So the linker complains only about variable with prefix _profd_ .
So my fix creates COMDAT section name equals to the variable name in case of triple: x86_64-pc-win32-coff

Also, do you know why the change in r256220 ([PGO] Fix another comdat related issue for COFF) was not enough to fix linkage issues when using COFF?

COMDAT section generated by the function "getOrCreateProfileComdat" is added to 3 variables: CounterPtr, ValuesVar and Data.
The COMDAT name was always the same (for each variable) based on return value from function: "getInstrProfCountersVarPrefix" (after r260117), after r256220 it was "getInstrProfNameVarPrefix".
Before my patch the linker properly merged symbols for variables with prefix profc_ but not for profd_. After patch r256220, but before r260117 I suppose the problem was with both (profc_ and profd_).

rnk added a comment.May 2 2017, 8:57 AM

I suspect that the appropriate fix is to give the __profd variables internal linkage, not to change the comdat name. The linker will still discard duplicate profc and profd sections with this change.

Actually, I'm surprised that the profiling data isn't comdat associated with the function itself. Is it possible for instrprofiling to be different across different TUs, or to link PGO instrumented code with non-PGO instrumented code? If that's the case, we probably want to make all profiling metadata associated with the function itself.

davidxl added inline comments.May 3 2017, 9:25 AM
lib/Transforms/Instrumentation/InstrProfiling.cpp
373

Please also fix the stale comment.

adamf added a comment.May 3 2017, 2:32 PM

I suspect that the appropriate fix is to give the __profd variables internal linkage, not to change the comdat name. The linker will still discard duplicate profc and profd sections with this change.

I have made few tests and changing to InternalLinkage seems also to work. The patch is in attachment.

.
This patch affects all formats, not only COFF.
With InternalLinkage we should change both _ _profd and _ _profc. (If we change only _ _ profd then counters in the coverage report are not properly interpreted).
Another advantage of using InternalLinkage is that we can check the counters for each translation unit.

Because fixing this problem starts to affect more amount of code and requires wider knowledge I am afraid that I won't be able to provide fully valuable fix.

adamf updated this revision to Diff 98531.May 10 2017, 2:15 PM

Alternative solution with Internal Linkage for COFF format.

davidxl accepted this revision.May 10 2017, 7:22 PM

lgtm

rnk added a comment.May 12 2017, 3:17 PM

Are we sure we want it like this? Doesn't this retain instrprof data structures from both A.obj and B.obj for inline functions present in both objs? Won't that be a problem?

From @davidxl :

It was comdat associated with the function before -- but it was wrong. The problem is that different comdat functions may have different CFGs (due to different early inlining), leading to incompatible profile counter data. Note that a comdat function can be later inlined, so using a shared copy of profile counter will be bad (out of bound access, not to mention profile use phase can not use it).

I agree, if instrprof runs before inlining, then we don't want these to be in a comdat group with the function. It's not safe for other functions to reference the data after inlining.

However, if instrprof runs after "early inlining", which I didn't think we had any of, then how have we solved the problem of different comdat functions having different CFGs at instrumentation time?