Skip to content

consider order .init_array .fini_array#1408

Merged
davidlattimore merged 23 commits intowild-linker:mainfrom
YamasouA:ft/consider_order
Jan 9, 2026
Merged

consider order .init_array .fini_array#1408
davidlattimore merged 23 commits intowild-linker:mainfrom
YamasouA:ft/consider_order

Conversation

@YamasouA
Copy link
Copy Markdown
Contributor

@YamasouA YamasouA commented Dec 27, 2025

Sorry—I accidentally made commits while this PR was closed, and I’m no longer able to reopen it, so I’ve created a new PR instead.
#1253

Issue: #588

@YamasouA
Copy link
Copy Markdown
Contributor Author

@davidlattimore
Currently, the tests are not passing. I ran into three issues that I couldn’t resolve and would really appreciate some advice. Some addresses end up as 0x0. This seems to be caused by rewriting part_id in apply_init_fini_secondaries. My intention was to create new part_ids per (priority, primary) section ID, which feels conceptually correct, but it doesn’t work in practice. dummy_frame is not being handled correctly. I can’t control the ordering of init_array and fini_array. I believe I’m already grouping them by (priority, primary) as in (1), and they should also be sorted in add_section, but the order still doesn’t come out as expected.

Comment thread libwild/src/resolution.rs Outdated
return Some(u16::MAX);
}

if name.starts_with(b".init_array.") || name.starts_with(b".fini_array.") {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the parsing code might be simplified slightly if you used strip_prefix. e.g.:

if let Some(rest) = name.strip_prefix(b".init_array.") {
    return parse_priority_suffix(rest);
}

Comment thread libwild/src/output_section_id.rs Outdated

for secondary_id in self.secondary.get(section_id) {
self.events.push(OrderEvent::Section(*secondary_id));
let secondaries: Vec<OutputSectionId> = self.secondary.get(section_id).clone();
Copy link
Copy Markdown
Member

@davidlattimore davidlattimore Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be necessary to clone here if you change the into_iter below to just iter then change sid to &sid in the map arguments.

Comment thread libwild/src/output_section_id.rs Outdated
(key_pri, idx, sid)
})
.collect();
keyed.sort_by(|a, b| a.0.cmp(&b.0).then_with(|| a.1.cmp(&b.1)));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sort_by_key(|a| (a.0, a.1)) is a bit simpler and should be equivalent.

@@ -0,0 +1,35 @@
//#Object:runtime.c
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might help to add //#Object:init.c, then #include "init.h" and in _start call call_init_functions();. See init_test.c for an example. This will cause GNU ld to see that __start_init_array and __end_init_array are referenced so it will emit those symbols. It'll also mean that the init functions will get run when the program runs.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I run the test, I get a failure that looks like this:

      ┌──────────────────┬─────────────┐
      │ wild             │ ld          │
      ├──────────────────┼─────────────┤
      │ 0x40191600000000 │ init_1000a  │
      │ 0x40192100000000 │ init_1000b  │
      │ 0x401a9600000000 │ init_1000c  │
      │ 0x401aa100000000 │ init_1000d  │
      │ 0x40192c00000000 │ init_2000a  │
      │ 0x40193700000000 │ init_2000b  │
      │ 0x401a8000000000 │ init_2000c  │
      │ 0x401a8b00000000 │ init_2000d  │
      │ 0x40190000000000 │ init_a      │
      │ 0x40190b00000000 │ init_b      │
      │ 0x40194200000000 │ init_65535a │
      │ 0x401aac00000000 │ init_c      │
      │ 0x401ab700000000 │ init_d      │
      └──────────────────┴─────────────┘

If I search for the address of init_1000a in Wild's output...

readelf -Ws /home/d/work/wild/wild/tests/build/init-order.c/init-order.c-default-host.wild | grep init_1000a
    14: 0000000000401916    11 FUNC    GLOBAL DEFAULT    3 init_1000a

So the address in .init_array is 0x40191600000000 when it should be 0x0000000000401916. i.e. there's an extra 4 bytes of zeros at the start, then all the pointers are offset by 4 bytes.

My guess as to what's happening is that the primary section (output_section_id::INIT_ARRAY) is empty (as it should be) and has low alignment requirements (probably alignment=1). When we get to the first secondary section, we have an alignment requirement of 8, so add some padding (presumably 4 bytes of padding).

Looking at the .init_array section:

readelf -WS /home/d/work/wild/wild/tests/build/init-order.c/init-order.c-default-host.wild | grep -E '(Flg|init_array)'
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 4] .init_array       INIT_ARRAY      0000000000402b04 000b04 000068 08  WA  0   0  8
  [ 6] .preinit_array    PREINIT_ARRAY   0000000000402bd8 000bd8 000000 00  WA  0   0  1

So it's listed as having alignment 8 (correct), but has an address ending in 0x4, which isn't 8-byte aligned.

Another problem is that __init_array_end is being placed at the end of the primary section, when it needs to be at the end of all the sections that go into that primary.

readelf -Ws /home/d/work/wild/wild/tests/build/init-order.c/init-order.c-default-host.wild | grep __init_array_
     6: 0000000000402b04     0 NOTYPE  GLOBAL DEFAULT    4 __init_array_start
     7: 0000000000402b04     0 NOTYPE  GLOBAL DEFAULT    4 __init_array_end

Note that the addresses of both symbols are equal, indicating that the range is empty.

I'm not sure that we want to change the behaviour of end_symbol_name, since I think for some sections we do want the end symbol to point to the end of a secondary section. But perhaps we can add a new field with the new behaviour. Naming things is hard, but perhaps end_group_symbol_name. Note that I don't think we need an equivalent for start_symbol_name.

@YamasouA
Copy link
Copy Markdown
Contributor Author

YamasouA commented Jan 4, 2026

With the current changes, almost all tests pass locally. Right now INIT_ARRAY and FINI_ARRAY are handled as special cases when computing their values, but if I can generalize this logic it should fully resolve both the alignment mismatch and the issue where the start and end ranges end up identical.

Copy link
Copy Markdown
Member

@lapla-cogito lapla-cogito left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wild runs mold’s test suite in CI. With this change, the mold test init-array-priorities.sh, which previously failed when run under Wild, now passes💯. You can confirm that this test is actually passing in CI by checking, for example, the logs of the “Check tests that should fail still fail” step in this run.

In that step, CI executes the tests listed in mold_skip_tests.toml, which records tests that are expected to fail on the current implementation of Wild, and verifies that they still fail. Ideally, it would be good to remove init-array-priorities.sh from this file as part of this PR. Doing so would also reduce the risk of accidentally breaking the feature implemented in this PR in your follow-up work.

Copy link
Copy Markdown
Member

@davidlattimore davidlattimore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! Looks like this is getting pretty close to being ready to merge!

{
self.events.push(OrderEvent::SetLocation(location));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you restore some of the blank lines that you've removed? I find that they make it easier to quickly see where a multi-line if-statement or for-loop ends.

Comment thread wild/tests/sources/init-order-2.c Outdated
__attribute__((destructor(1000))) void fini_1000c() {}
__attribute__((destructor(1000))) void fini_1000d() {}
__attribute__((destructor)) void fini_c() {}
__attribute__((destructor)) void fini_d() {} No newline at end of file
Copy link
Copy Markdown
Member

@davidlattimore davidlattimore Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a newline at the end of files that don't have one? The red circle that github is showing means that there's no newline at the end of the last line.

Comment thread libwild/src/layout.rs Outdated
let mut mem_end = 0;
let mut alignment = info.min_alignment;

if section_id == crate::output_section_id::INIT_ARRAY {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed? For me, at least locally, none of the tests fail if I comment this out.

Comment thread libwild/src/layout.rs Outdated
|| section_id == crate::output_section_id::FINI_ARRAY)
&& offset == 0
{
let a8 = Alignment::new(8).unwrap();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the alignment of a pointer. Probably nicer to use alignment::USIZE instead

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidlattimore
Is it okay to have INIT_ARRAY in this if condition?
Or should we handle Secondary nicely here too?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than having this if-statement, you could set min_alignment on the built-in sections. i.e. add min_alignment: alignment::USIZE, to the relevant BuiltInSectionDetails {...} in output_section_id.rs.

We might at some point need a more general way to have properties like alignment from merged sections affect the primary section, but just setting the alignment on the built-in section details will probably do for now.

Comment thread libwild/src/output_section_id.rs Outdated
(key_pri, idx, sid)
})
.collect();
keyed.sort_by_key(|a| (a.0, a.1));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sort_by_key is stable, so a.1 shouldn't be needed - the sort will preserve the original order for any elements that have an equal key. That means that it should be possible to get rid of the enumerate() call above.

Comment thread libwild/src/layout_rules.rs Outdated
section_id: OutputSectionId,
) -> SectionRule<'data> {
Self::prefix(
SectionRule {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Comment thread libwild/src/resolution.rs
} else {
output_info.section_id.base_part_id()
};
if let Some(priority) = init_fini_priority(section_name) {
Copy link
Copy Markdown
Member

@davidlattimore davidlattimore Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I benchmark linking wild, I see about a 1% slowdown in link time.

Benchmark 1 (1775 runs): /home/david/save/wild/run-with /home/d/wild-builds/2026-01-05 --strip-debug --no-fork
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          33.7ms ±  840us    31.9ms … 37.6ms         41 ( 2%)        0%
  peak_rss            161MB ±  858KB     158MB …  164MB         17 ( 1%)        0%
  cpu_cycles          708M  ± 14.4M      651M  …  806M          38 ( 2%)        0%
  instructions        699M  ± 8.69M      674M  …  767M          32 ( 2%)        0%
  cache_references   20.9M  ±  355K     19.8M  … 22.5M           5 ( 0%)        0%
  cache_misses       4.54M  ± 67.4K     4.28M  … 5.04M          14 ( 1%)        0%
  branch_misses      1.89M  ± 14.8K     1.84M  … 2.00M          27 ( 2%)        0%
Benchmark 2 (1755 runs): /home/david/save/wild/run-with target/release/wild --strip-debug --no-fork
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          34.1ms ±  862us    32.2ms … 37.8ms         46 ( 3%)        💩+  1.2% ±  0.2%
  peak_rss            162MB ±  856KB     159MB …  165MB          6 ( 0%)          +  0.6% ±  0.0%
  cpu_cycles          707M  ± 13.8M      668M  …  808M          36 ( 2%)          -  0.1% ±  0.1%
  instructions        700M  ± 8.41M      678M  …  778M          33 ( 2%)          +  0.2% ±  0.1%
  cache_references   21.0M  ±  356K     20.0M  … 23.3M           4 ( 0%)          +  0.8% ±  0.1%
  cache_misses       4.53M  ± 65.3K     4.29M  … 5.07M          13 ( 1%)          -  0.2% ±  0.1%
  branch_misses      1.90M  ± 16.0K     1.85M  … 2.05M          27 ( 2%)          +  0.6% ±  0.1%

I think it's due to this call to init_fini_priority. If I comment it out, the slowdown more or less goes away. We end up checking every section name to see if it's equal to ".init_array", equal to ".fini_array", starts with ".init_array." or starts with ".fini_array". Those checks take time. Can we make use of the matched SectionRuleOutcome so that we only call it when the section is an .init_array or .fini_array section?

Edit: I suspect you'll need to either add a new variant to SectionRuleOutcome (e.g. SortedSection) or add an additional field to SectionOutputInfo.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried making some adjustments, but I still haven't gotten the Benchmark to run properly locally.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you'd like help running benchmarks, let us know where you're stuck and we'll see what we can figure out.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@YamasouA ➜ /workspaces/wild/ripgrep (master) $ hyperfine --warmup 2 \
  '/tmp/wild/ripgrep/7/run-with ld' \
  '/tmp/wild/ripgrep/7/run-with wild --no-fork'
Benchmark 1: /tmp/wild/ripgrep/7/run-with ld
  Time (mean ± σ):      1.161 s ±  0.025 s    [User: 0.669 s, System: 0.478 s]
  Range (min … max):    1.134 s …  1.210 s    10 runs
 
Benchmark 2: /tmp/wild/ripgrep/7/run-with wild --no-fork
  Time (mean ± σ):     212.4 ms ±  10.7 ms    [User: 254.2 ms, System: 87.2 ms]
  Range (min … max):   196.5 ms … 230.1 ms    13 runs
 
Summary
  /tmp/wild/ripgrep/7/run-with wild --no-fork ran
    5.47 ± 0.30 times faster than /tmp/wild/ripgrep/7/run-with ld

Copy link
Copy Markdown
Contributor Author

@YamasouA YamasouA Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidlattimore
I tried to reproduce your benchmark using poop, but I'm running this in Gitpod.

It looks like Gitpod does not allow perf_event_open, so poop fails with PermissionDenied when trying to collect HW counters (cycles, instructions, cache misses, etc.).

$ ./zig-out/bin/poop
'sh -lc "/tmp/wild/ripgrep/7/run-with ld"'
'sh -lc "/tmp/wild/ripgrep/7/run-with wild --no-fork"'
thread ... panic: unable to open perf event: PermissionDenied

Because of this restriction, I can only measure wall-time (e.g. via hyperfine) in Gitpod, not perf-based metrics.

If you have a recommendation for a Gitpod-friendly way to collect similar metrics, please let me know.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with gitpod, but if perf events aren't available, then I agree that it sounds like poop won't work. Hyperfine is sufficient though, since the main thing that we care about is walltime. I expect that gitpod or any other cloud-based platform, being shared, is likely to have pretty noisy benchmarks - i.e. the standard deviation of the timing results is likely to be quite large. e.g. in your results above, 212.4 ms ± 10.7 ms. i.e. the standard deviation is about 5%. This means that any change in performance that's of a similar or smaller magnitude is going to be lost in the noise.

When checking a PR for performance changes, I do a release build without the change, copy the binary somewhere, then do a release build with the change. I then compare the performance of the two binaries.

I'm happy to run benchmarks for you as-needed. Here's one for wild linking itself:

B=wild F="--strip-debug" R=/home/david/save/$B/run-with OUT=/run/user/1000/ttt bench poop -d 60000 "$R /home/d/wild-builds/2026-01-09 $F" "$R target/release/wild $F"
  Temperature: 51.0 C
Benchmark 1 (2005 runs): /home/david/save/wild/run-with /home/d/wild-builds/2026-01-09 --strip-debug
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          29.3ms ±  836us    27.5ms … 34.7ms         83 ( 4%)        0%
  peak_rss           7.45MB ± 99.6KB    6.91MB … 7.50MB        316 (16%)        0%
  cpu_cycles          709M  ± 13.0M      652M  …  777M          31 ( 2%)        0%
  instructions        703M  ± 8.37M      679M  …  747M          31 ( 2%)        0%
  cache_references   21.8M  ±  330K     20.6M  … 23.5M          57 ( 3%)        0%
  cache_misses       4.58M  ± 60.9K     4.36M  … 4.94M          38 ( 2%)        0%
  branch_misses      1.86M  ± 15.6K     1.82M  … 1.95M          25 ( 1%)        0%
Benchmark 2 (1974 runs): /home/david/save/wild/run-with target/release/wild --strip-debug
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          29.8ms ±  839us    27.7ms … 34.9ms         84 ( 4%)        💩+  1.6% ±  0.2%
  peak_rss           7.44MB ±  108KB    6.91MB … 7.50MB        386 (20%)          -  0.1% ±  0.1%
  cpu_cycles          710M  ± 13.0M      666M  …  797M          30 ( 2%)          +  0.1% ±  0.1%
  instructions        704M  ± 8.20M      679M  …  767M          27 ( 1%)          +  0.2% ±  0.1%
  cache_references   21.8M  ±  297K     20.6M  … 23.9M          41 ( 2%)          -  0.0% ±  0.1%
  cache_misses       4.58M  ± 57.0K     4.34M  … 5.02M          35 ( 2%)          +  0.1% ±  0.1%
  branch_misses      1.91M  ± 20.5K     1.86M  … 2.06M          19 ( 1%)        💩+  2.9% ±  0.1%
  Temperature: 66.4 C

I did more investigation into the performance change. It seems that it's due (or at least mostly due) to the additional output sections. For linking wild, the number of output sections (including secondary sections) went from 46 to 49. It seems that wild is slightly more sensitive to that than I had realised. I think we should not worry about the performance change for merging of this PR. 1.6% isn't too bad given that this is an important feature being implemented. I've got some ideas that I'll probably experiment with at a later stage that might be able to reduce the per-section overhead.

Comment thread libwild/src/layout.rs Outdated
sec.mem_offset + sec.mem_size
};

if section_id == output_section_id::INIT_ARRAY
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like there's probably a different way to do this, but I can't think of anything concrete at the moment, so this will do for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought about this some more. I think perhaps what would work well would be to add a new variant, similar to SymbolPlacement::SectionEnd, but which triggers the relevant logic. It's fine to leave it as-is though if you'd rather not tackle that. Perhaps just add something like // TODO: Make this logic more generic, possibly by adding a new kind of SymbolPlacement

Comment thread libwild/src/resolution.rs
} else {
output_info.section_id.base_part_id()
};
if let Some(priority) = init_fini_priority(section_name) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with gitpod, but if perf events aren't available, then I agree that it sounds like poop won't work. Hyperfine is sufficient though, since the main thing that we care about is walltime. I expect that gitpod or any other cloud-based platform, being shared, is likely to have pretty noisy benchmarks - i.e. the standard deviation of the timing results is likely to be quite large. e.g. in your results above, 212.4 ms ± 10.7 ms. i.e. the standard deviation is about 5%. This means that any change in performance that's of a similar or smaller magnitude is going to be lost in the noise.

When checking a PR for performance changes, I do a release build without the change, copy the binary somewhere, then do a release build with the change. I then compare the performance of the two binaries.

I'm happy to run benchmarks for you as-needed. Here's one for wild linking itself:

B=wild F="--strip-debug" R=/home/david/save/$B/run-with OUT=/run/user/1000/ttt bench poop -d 60000 "$R /home/d/wild-builds/2026-01-09 $F" "$R target/release/wild $F"
  Temperature: 51.0 C
Benchmark 1 (2005 runs): /home/david/save/wild/run-with /home/d/wild-builds/2026-01-09 --strip-debug
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          29.3ms ±  836us    27.5ms … 34.7ms         83 ( 4%)        0%
  peak_rss           7.45MB ± 99.6KB    6.91MB … 7.50MB        316 (16%)        0%
  cpu_cycles          709M  ± 13.0M      652M  …  777M          31 ( 2%)        0%
  instructions        703M  ± 8.37M      679M  …  747M          31 ( 2%)        0%
  cache_references   21.8M  ±  330K     20.6M  … 23.5M          57 ( 3%)        0%
  cache_misses       4.58M  ± 60.9K     4.36M  … 4.94M          38 ( 2%)        0%
  branch_misses      1.86M  ± 15.6K     1.82M  … 1.95M          25 ( 1%)        0%
Benchmark 2 (1974 runs): /home/david/save/wild/run-with target/release/wild --strip-debug
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          29.8ms ±  839us    27.7ms … 34.9ms         84 ( 4%)        💩+  1.6% ±  0.2%
  peak_rss           7.44MB ±  108KB    6.91MB … 7.50MB        386 (20%)          -  0.1% ±  0.1%
  cpu_cycles          710M  ± 13.0M      666M  …  797M          30 ( 2%)          +  0.1% ±  0.1%
  instructions        704M  ± 8.20M      679M  …  767M          27 ( 1%)          +  0.2% ±  0.1%
  cache_references   21.8M  ±  297K     20.6M  … 23.9M          41 ( 2%)          -  0.0% ±  0.1%
  cache_misses       4.58M  ± 57.0K     4.34M  … 5.02M          35 ( 2%)          +  0.1% ±  0.1%
  branch_misses      1.91M  ± 20.5K     1.86M  … 2.06M          19 ( 1%)        💩+  2.9% ±  0.1%
  Temperature: 66.4 C

I did more investigation into the performance change. It seems that it's due (or at least mostly due) to the additional output sections. For linking wild, the number of output sections (including secondary sections) went from 46 to 49. It seems that wild is slightly more sensitive to that than I had realised. I think we should not worry about the performance change for merging of this PR. 1.6% isn't too bad given that this is an important feature being implemented. I've got some ideas that I'll probably experiment with at a later stage that might be able to reduce the per-section overhead.

Comment thread libwild/src/layout_rules.rs Outdated
must_keep: matcher.must_keep,
};

let outcome = if section_id
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seems to be done in order to make init-order apply when a linker script is used, but there isn't a test for this. At least when I tried reverting this bit of the change, no tests failed. As far as I know the ordering should probably only be done when the script specifies SORT_BY_INIT_PRIORITY such as in the following snippet of GNU ld's built-in script (which you can see by running ld --verbose.

    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))

I'd probably suggest reverting this and dealing with init ordering for linker scripts in a separate PR. That said, I don't feel strongly, so it'd be OK to keep this if you've got reason to do so. In that case, it could perhaps do with some comments saying in what ways the behaviour here differs from GNU ld's behaviour of requiring SORT_BY_INIT_PRIORITY in order to sort the sections.

@YamasouA YamasouA changed the title [WIP] consider order .init_array .fini_array consider order .init_array .fini_array Jan 9, 2026
@YamasouA
Copy link
Copy Markdown
Contributor Author

YamasouA commented Jan 9, 2026

@davidlattimore
Thank you for running the performance benchmarks.
From your results, I understand that the performance regression in this PR is acceptable.
I also learned there are some issues with running benchmarks in shared cloud environments.

I’ve also updated the linker script-related changes, so I’d appreciate it if you could take a look at those as well.

Copy link
Copy Markdown
Member

@davidlattimore davidlattimore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all your work on this!

@davidlattimore davidlattimore merged commit a152d28 into wild-linker:main Jan 9, 2026
22 checks passed
davidlattimore pushed a commit that referenced this pull request Jan 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants