M

MaskRay

maskray.me · Personal blog · on HN since 2018

MaskRay, an LLVM and linker developer, writes technical posts on linkers, ELF, thread-local storage and compiler toolchain performance.

What HN saysHN commenters link it for linker and dynamic linking details, and one notes a renamed post caused a changed link.
43HN people shared it
17linked it in comments
134stories submitted
1.6Kstory points
3 months agolast shared
2018people per year2026

Most-shared posts

  1. 1
    Long branches in compilers, assemblers, and linkers
    5 people · 6 points · first shared 2026 · discussion on HN
  2. 2
    Evolution of the ELF object file format
    4 people · 207 points · first shared 2024 · 51 comments on HN
  3. 3
    Exploring Object File Formats
    4 people · 119 points · first shared 2024 · 19 comments on HN
  4. 4
    All about thread-local storage
    4 people · 55 points · first shared 2021 · 10 comments on HN
  5. 5
    Why Isn't Ld.lld Faster
    4 people · 12 points · first shared 2021 · discussion on HN
  6. 6
  7. 7
    Precompiled Headers
    4 people · 6 points · first shared 2023 · discussion on HN
  8. 8
  9. 9
    When can glibc be built with Clang?
    3 people · 158 points · first shared 2021 · 28 comments on HN
  10. 10
  11. 11
    MMU-less systems and FDPIC
    3 people · 40 points · first shared 2024 · 4 comments on HN
  12. 12
    Relocation Generation in Assemblers
    3 people · 12 points · first shared 2025 · discussion on HN
  13. 13
    A compact relocation format for ELF
    3 people · 5 points · first shared 2024 · discussion on HN
  14. 14
    Reflections on LLVM's switch to GitHub pull requests
    3 people · 4 points · first shared 2023 · discussion on HN
  15. 15
    Compiling C++ with the Clang API
    2 people · 105 points · first shared 2025 · 20 comments on HN

What HN people wrote when they linked it

MaskRay · 2026-01-24
Amazing! I read you article in 2012 when the link was https://homepages.cwi.nl/~tromp/maze.html I was learning Haskell and Ocaml and wrote my own article in Chinese then https://maskray.me/blog/2012-11-02-perfect-maze-generation Now I should fix the link.
mananaysiempre · 2025-05-14
I’m also a bit weirded out by the lack of mentions of dominators (in TFA or in the article[1] it links to). Once you have the dominator tree, though, you’re still going to need to answer LCA queries on it (in this problem and in an SSA-based compiler both), so there seems to be no way around this part. The algorithm in the article does O(1) queries with O(V+E) preprocessing (assuming linear-preprocessing LCA, which, yeah). What’s the best algorithm for dominator trees? People usually talk about Lengauer–Tarjan[2], which is linear in practice (linear except for UNION-FIND), and not the linear one by Georgiadis[3,4]. Unfortunately, I’m not a compiler person. [1] https://doi.org/10.1016/j.ipl.2010.02.014 [2] https://maskray.me/blog/2020-12-11-dominator-tree [3] https://www.cs.princeton.edu/research/techreps/43 [4] https://dl.acm.org/doi/abs/10.1137/070693217
AdelaideSimone · 2025-06-28
A lot of vendors use non-lazy binding for security reasons, and some platforms don't support anything other than RTLD_NOW (e.g., Android). Anyway, while what you said is theoretically half-true, a fairly large number of libraries are not designed/encapsulated well. This means almost all of their symbols are exported dynamically, so, the idea that there are only "few public exported symbols" is unfortunately false. However, something almost no one ever mentions is that ELF was actually designed to allow dynamic libraries to be fairly performant. It isn't something I would recommend, as it breaks many assumptions on Unices, (while you don't get the benefits of LTO) you can achieve code generation almost equivalent to static linking by using something like "-fno-semantic-interposition -Wl,-Bsymbolic,-z,now". MaskRay has a good explanation on it: https://maskray.me/blog/2021-05-16-elf-interposition-and-bsymbolic
saidinesh5 · 2026-02-15
Let's say you need to use a function like: int add(int a, int b){ // Long logic and then this return a+b; } Let's say this is your main.c. #include "add.h" int main(void) { return add(5,6); } The preprocessor just copies the contents of add.h into your main.c whenever you're trying to compile main.c. (let's ignore the concept of precompiled headers for now). What you can instead do is just put the add function declaration in add.h that just tells the compiler that add function takes two integers and returns an integer. int add(int a, int b); You can then put the add function definition in add.c , compile that to an add.o and link it to your main.o at link time to get your final binary - without having to recompile add.o every time you change your main.c. Precompiled headers: https://maskray.me/blog/2023-07-16-precompiled-headers
netule · 2026-01-27
It looks like the author has renamed their blog post, and thus the link has changed: https://maskray.me/blog/2026-01-25-long-branches-in-compilers-assemble…
loeg · 2025-12-29
It is: https://maskray.me/blog/2022-01-23-compressed-debug-sections But the compression ratio isn't magical (approx. 1:0.25, for both zlib and zstd in the examples given). You'd probably still want to set aside debuginfo in separate files.
jcalvinowens · 2025-12-11
While I certainly empathize with the author of that article and respect the work they put into debugging it, this is a better explanation of that whole thing: https://maskray.me/blog/2022-08-21-glibc-and-dt-gnu-hash
kbolino · 2025-09-02
Thanks! I was able to find some additional info on no-MMU Linux [1], [2], [3]. It seems position-independent executables are the norm on regular (MMU) Linux now anyway (and probably have been for a long time). I took a look under the covers of uClibc and it seems like malloc just delegates most of its work to mmap, at least for the malloc-simple implementation [4]. That implies to me that different processes' heaps can be interleaved (without overlapping), but the kernel manages the allocations. [1]: https://maskray.me/blog/2024-02-20-mmu-less-systems-and-fdpic [2]: https://popovicu.com/posts/789-kb-linux-without-mmu-riscv/ [3]: https://www.kernel.org/doc/Documentation/nommu-mmap.txt [4]: https://github.com/kraj/uClibc/blob/ca1c74d67dd115d059a875150e10b8560a…
atq2119 · 2025-02-17
Take a look at https://maskray.me/blog/2021-02-14-all-about-thread-local-storage I think what you want is to force the "initial exec" model using an attribute to get the more efficient code. IIRC this (or something equivalent) is what libGL does because basically every OpenGL function call needs to read the thread-local variable holding the current GL context. The downside is that dlopen()ing your library may fail.
tliltocatl · 2025-01-23
Having fixed instruction length doesn't make the need to load large constants magically disappear. These just get split between multiple instructions. If anything, RISC-V might be worse. See also https://maskray.me/blog/2021-03-14-the-dark-side-of-riscv-linker-relax…
xvilka · 2024-01-16
Always quality content in that blog. We used MaskRay's article[1] on stack unwinding to improve our debuginfo (DWARF) support[2] in the past. If someone wants to have a more hands-on approach to executable file formats, e.g., XCOFF or GOFF, they can check Rizin's ideas for new formats[3] to support. [1] https://maskray.me/blog/2020-11-08-stack-unwinding [2] https://rizin.re/posts/gsoc-2023-dwarf/ [3] https://github.com/rizinorg/ideas/issues?q=is%3Aissue+is%3Aopen+label%…
wyldfire · 2023-09-09
Interesting blog post by Fangrui Song "ELF interposition and -Bsymbolic" [1] - talks about the real world cost of this feature that's imposed by ELF. On one hand it enables incredible extensibility, OTOH codegen is obligated to be pessimistic about resolving symbols. [1]https://maskray.me/blog/2021-05-16-elf-interposition-and-bsymbolic
housel · 2022-02-07
https://maskray.me/blog/ has plenty of solid information on the LLVM and GCC/Binutils toolchains.
sitkack · 2022-01-31
You can do somethings like this using the .init and .fini sections in a dynamically loaded shared lib. https://maskray.me/blog/2021-11-07-init-ctors-init-array
pm215 · 2022-01-01
I put my question to a friend of mine who works on linkers, and his take was that for a single threaded linker like ld.bfd the copy-bytes part would probably dominate, but that for a multithreaded linker like lld that part trivially parallelizes and so the slow part tends to be elsewhere. He also pointed me at a recent blogpost by the lld maintainer on this topic: https://maskray.me/blog/2021-12-19-why-isnt-ld.lld-faster which I should go and read...
wz1000 · 2018-05-19
Xmonad has something called grid select, which works kind of like a combination of pie menus and a grid, while also being keyboard navigable(I use vim keybindings hjkl). http://maskray.me/static/xmonad-grid-select.jpg https://hackage.haskell.org/package/xmonad-contrib-0.13/docs/XMonad-Ac…

Keyboard shortcuts

/Search
j kNext / previous blog
EnterOpen selected blog
vVisit the blog site
fFollow / unfollow
lSwitch grid / list view
dSwitch dark mode
g hHome
g pTop posts
g tTopics
g fFollowing
g lLiked
g yHistory
g qFAQ
EscBack / close