Posts

  • 16th March 2025

Relocation generation in assemblers

This post explores how GNU Assembler and LLVM integrated assembler generate relocations, an important step to generate a relocatable file. Relocations identify parts of instructions or data that cannot be fully determined during assembly because they depend on the final memory layout, which is only established at link time or load time. These are essentially placeholders that will be filled in (typically with absolute addresses or PC-relative offsets) during the linking process.

Relocation generation: the basics

Symbol references are the primary candidates for relocations. For instance, in the x86-64 instruction movl sym(%rip), %eax (GNU syntax), the assembler calculates the displacement between the program counter (PC) and sym. This distance affects the instruction's encoding and typically triggers a R_X86_64_PC32 relocation, unless sym is a local symbol defined within the current section.

Both the GNU assembler and LLVM integrated assembler utilize multiple passes during assembly, with several key phases relevant to relocation generation:

…

Read more →
  • 9th March 2025

Compiling C++ with the Clang API

This post describes how to compile a single C++ source file to an object file with the Clang API. Here is the code. It behaves like a simplified clang executable that handles -c and -S.

…

Read more →
  • 17th February 2025
  • 2nd February 2025

lld 20 ELF changes

LLVM 20 will be released. As usual, I maintain lld/ELF and have added some notes to https://github.com/llvm/llvm-project/blob/release/20.x/lld/docs/ReleaseNotes.rst. I've meticulously reviewed nearly all the patches that are not authored by me. I'll delve into some of the key changes.

…

Read more →
  • 20th January 2025

Natural loops

A dominator tree can be used to compute natural loops.

  • For every node H in a post-order traversal of the dominator tree (or the original CFG), find all predecessors that are dominated by H. This identifies all back edges.
  • Each back edge T->H identifies a natural loop with H as the header.
    • Perform a flood fill starting from T in the reversed dominator tree (from exiting block to header)
    • All visited nodes reachable from the root belong to the natural loop associated with the back edge. These nodes are guaranteed to be reachable from H due to the dominator property.
    • Visited nodes unreachable from the root should be ignored.
    • Loops associated with visited nodes are considered subloops.
…

Read more →
  • 12th January 2025

Understanding and improving Clang -ftime-report

Clang provides a few options to generate timing report. Among them, -ftime-report and -ftime-trace can be used to analyze the performance of Clang's internal passes.

  • -fproc-stat-report records time and memory on spawned processes (ld, and gas if -fno-integrated-as).
  • -ftime-trace, introduced in 2019, generates Clang timing information in the Chrome Trace Event format (JSON). The format supports nested events, providing a rich view of the front end.
  • -ftime-report: The option name is borrowed from GCC.

This post focuses on the traditional -ftime-report, which uses a line-based textual format.

Understanding -ftime-report output

The output consists of information about multiple timer groups. The last group spans the largest interval and encompasses timing data from other groups.

Up to Clang 19, the last group is called "Clang front-end time report". You would see something like the following.

…

Read more →
  • 31st December 2024

2024年总结

一如既往,主要在工具链领域耕耘。

Blogging

I have been busy creating posts, authoring a total of 31 blog posts (including this one). 7 posts resonated on Hacker News, garnering over 50 points. (https://news.ycombinator.com/from?site=maskray.me).

I have also revised many posts initially written between 2020 and 2024.

Mastodon: https://hachyderm.io/@meowray

…

Read more →
  • 30th December 2024

Skipping boring functions in debuggers

In debuggers, stepping into a function with arguments that involve function calls may step into the nested function calls, even if they are simple and uninteresting, such as those found in the C++ STL.

GDB

Consider the following example:

#include <cstdio>
#include <memory>
#include <vector>
using namespace std;

void foo(int i, int j) {
  printf("%d %d\n", i, j);
}

int main() {
  auto i = make_unique<int>(3);
  vector v{1,2};
  foo(*i, v.back()); // step into
}

When GDB stops at the foo call, the step (s) command will step into std::vector::back and std::unique_ptr::operator*. While you can execute finish (fin) and then execute s again, it's time-consuming and distracting, especially when dealing with complex argument expressions.

…

Read more →
  • 25th December 2024
  • 22nd December 2024

Simplifying disassembly with LLVM tools

Both compiler developers and security researchers have built disassemblers. They often prioritize different aspects. Compiler toolchains, benefiting from direct contributions from CPU vendors, tend to offer more accurate and robust decoding. Security-focused tools, on the other hand, often excel in user interface design.

For quick disassembly tasks, rizin provides a convenient command-line interface.

…

Read more →