<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/111240>111240</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
Does clang define the behavior for an "array" manually created with a linker script?
</td>
</tr>
<tr>
<th>Labels</th>
<td>
clang
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
fekir
</td>
</tr>
</table>
<pre>
Hello, does clang, as extension, define in any way the interaction with the linker?
In particular, I have following program
~~~~
using test_signature = void();
void test2(){std::puts("test2");}
[[gnu::used]] constexpr test_signature* const t1 [[gnu::section(".tests")]] = +[]{std::puts("test1");};
[[gnu::used]] constexpr test_signature* const t2 [[gnu::section(".tests")]] = test2;
[[gnu::used]] constexpr test_signature* const t3 [[gnu::section(".tests")]] = test2;
// eventually many other
auto get_tests() noexcept {
extern const test_signature* const tests_begin[];
extern const test_signature* const tests_end[];
return std::span<test_signature* const>(tests_begin, tests_end);
}
int main(){
auto funcs = get_tests();
for(const auto& v : funcs){
v();
}
}
~~~~
And following file linkerscript.ld
~~~~
SECTIONS
{
.tests : {
PROVIDE(tests_begin = .);
KEEP(*(.tests))
PROVIDE(tests_end = .);
}
}
INSERT AFTER .text;
~~~~
And compile it with `clang --std=c++20 -Wl,-Tlinkerscript.ld main.cpp`.
The code seems to work, but strictly speaking, creating a span over tests_begin and tests_end is UB because no array has been declared in c++.
In c++23, one could change the code to
~~~~
auto get_tests() noexcept {
extern const test_signature* const tests_begin[];
extern const test_signature* const tests_end[];
const auto tests_size = ((uintptr_t)(&tests_end) - (uintptr_t)(&tests_begin))/sizeof(test_signature*);
auto begin = std::start_lifetime_as_array<test_signature* const>(tests_begin, tests_size);
return std::span<test_signature* const>(begin, begin + tests_size);
}
~~~~
With the cast to uintptr_t to avoid UB for determining the size of the array, and then std::start_lifetime_as_array to begin the lifetime of the array over the area or memory one wants to iterate over.
The question is, in case one does not have yet `start_lifetime_as_array`, if this is necessary.
GCC recommends to use a generic inline-asm constraint: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107010, thus changing the code to
~~~~
auto get_tests() noexcept {
extern const test_signature* const tests_begin[];
extern const test_signature* const tests_end[];
const auto tests_size = ((uintptr_t)(&tests_end) - (uintptr_t)
test_signature** begin = tests_begin;
asm("":"+r"(begin));
return std::span<test_signature* const>(begin, begin + tests_size);
}
~~~~
this code compiles fine on clang too and also seems to work, but does it avoid UB too like in GCC?
And is the generic inline-asm constraint supported on all platforms that clang support? (ie are there any portability concerns when (cross-)compiling with clang on different architectures/platforms?)
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzcV1uP4joS_jXmpQRKHGjggQcuzdnWSmdGMz07j8g4ReJtx87aDt3MQ__2VTnhOt2zUu9Iqz0SggS7yl_dPlcJ71VhEGdstGCjVU80obRutsMn5Xpbmx9mf0OtLeNLyC16kFqYgt6EB3wJaLyyJq7iThkEZUCYAzyLA4SSXgM6IYOyBp5VKOOfWpkndCxbs2TFknn7_WCgFi4o2WjhSOEDlGKPsLNa22dlCqidLZyoLoVeX19f26fG05aAPmzIIBEah8CyFeytyhmfMD5l2eJSlhaiAO-WxwsfcpbNWTavm-Djv7zbwDv58epSRfTZojBNK9V4zNloxUYrkNb4gC-1u4HE-Lxdg5DCjbjH6Kf23AHJ-e7gVidZw_iiDdT7aNMrtCeb_xuo_CNQW8_9lvOz33A-XzO-BtyjCY3Q-gAV5akNJbrLkIomWCgwbDqllBlgLL5IrAOwcacOYvI7c0T4HnJSstlioUwXtuwjCtDkP4k7DI0zcEoCXwvDsuU7ilh2z_jkEg5fXii_LI7rFFcmQCWUOdXI8fzoqF1jpI_evnHZGejOOsYnrTUkw_gd7IFl81b4WinA_lYezoCOD-eqv_yem_yCLHZKH4nGS6fqMND528zx9X75-PDpz6_HQ04Ht3kVoV5B_Pzl0z8eVjf-jE4YXCMH-Pv9_edo0JzxyTFPp_Rpt9yqQpO_pehnFzz8-fX-yyPM14_3XwjoSzhtv_UO-UXaqiaHqNCyMLtLIpFDvx8TaCWJWPiCJ9D_rhlf9h9vfBeTYCDrmt0lg0v1jyWCtDmCR6w8BAvP1j1Rem2bAD44JYM-gK9RPKn26pAORaAgCaCsBbtHd1kqIEx-Tk5QHr4tYItSNB7BWBDOiQOUwsMW0UCOUguHOd09nR2Dm5vlaF5Gx1tDiBudgyyFKTDeSdGEYN9Okf8XUjhXWbfHqx_Y3RsTxieNMqEObhNiEk4Yv7ukAOjDL_Z0rBGTl69Jsd11eXuF8TpzI5ZzgZzZKggXNlrtMKgKN8JvYlA_RGCE5frUj3DjSWmHli_eUf8uDX0_9jdSUJAsnFxJLyL2G98WRIiQY0BXKRN7lhIhxsnu4nPrCOqwqApKNP_Ra3DycdtdtctX-roai68owDqosLLuEIvhWZgQK1dRsxYwbv6pyP_VoI99nPKEjopNeIwKYmdobGg7tgMGIpj3QnyXRHECpzwVt0GJ3gt3uDryj-USHEpbVWjyiI6qX0CBBp2SoIxWBvvCV20UnVAmEFeXIdSe_BVv_ELKQWGagXUF4-ttU_xQWgvK4NI-b7ZNMZCFYtlaEQumyThJI7xQNr6lh2OI_hIE8fsZotP7Bg3ML-r-0qITGOGrtoGjD8WLM75w8WdyyTb_67qOeRrD312jHuKoY007DUGwNhar0N6-fQ3GAlHhTAIkotVTnJf-WC5Ps9C8ve8o4X6Z6OCburYuYE4whNZQaxF21tHZpQgdsm4Xy9YUOBWrn5Q7jFMarYmt0iocSLdEZzw8E-VQy-as933Gp63VVAexd2g1WwO52u3QoQkgnCxVQEnu94yvT1jILj7t5bMsn2ZT0cNZOuaTNB0lw2GvnMlsglMuhtscRzwd343H2-mUp3ycZNtxOhr21IwnfJgmySgZj8Z8OEg4pjJFnkmZTPhwyoYJVkLpgdb7ioq8p7xvcJamKR8mPS22qH2cbTnvRldOY66bkUB_2xSeDROtfPBnFUEFjbPVadw9zrYUlS2WYq-sizQuyFG8I2xOE0U7WsQGB_PWX6JrQ6HtpVi27jVOz25oSoWy2Q6krRhfE5Dup187-0-UgfF1NIy829m2n_F_BwAA__8VIPU9">