Mach-O symbol tables: Translating addresses in the main binary to addresses in a corresponding object file

I am trying to understand Mach-O symbol tables and essentially reproduce the output of dsymutil -dump-debug-map.

I have a binary with a symbol table that looks like

...
[   157] 00000001 64 (N_SO         ) 01     0000   0000000000000000
[   158] 00003756 64 (N_SO         ) 00     0000   0000000000000000 '/path/to/project/'
[   159] 00003773 64 (N_SO         ) 00     0000   0000000000000000 'test.cpp'
[   160] 0000377c 66 (N_OSO        ) 03     0001   000000006510bf32 '/path/to/project/test.cpp.o'
[   161] 00000001 2e (N_BNSYM      ) 01     0000   0000000100004e60
[   162] 000037bd 24 (N_FUN        ) 01     0000   0000000100004e60 '_Z3fooi'
[   163] 00000001 24 (N_FUN        ) 00     0000   0000000000000170
[   164] 00000001 4e (N_ENSYM      ) 01     0000   0000000100004e60
[   165] 00000001 2e (N_BNSYM      ) 01     0000   0000000100004fd0
...
[   213] 00000001 2e (N_BNSYM      ) 01     0000   0000000100005470
[   214] 00003a90 24 (N_FUN        ) 01     0000   0000000100005470 '_Z3bari'
[   215] 00000001 24 (N_FUN        ) 00     0000   0000000000000020
[   216] 00000001 4e (N_ENSYM      ) 01     0000   0000000100005470

The dumped debug map includes

---
triple:          'x86_64-apple-darwin'
binary-path:     test
objects:
  - filename:        '/path/to/project/test.cpp.o'
    timestamp:       1695596338
    symbols:
      - { sym: _Z3fooi, objAddr: 0x610, binAddr: 0x100005470, size: 0x20 }

An nm confirms _Z3fooi is at address 0x610 in /path/to/project/test.cpp.o.

I'm trying to figure out how the address 0x610 is computed. 0x100005470 -> 0x5470 is from the base of the __TEXT section but then the difference between 0x5470 and 0x610 is 0x4e60, which happens to be the address of the first symbol listed after the N_OSO entry. But it feels suspicious to try to rely on that for computing the corresponding offset in the .o file.

How is this computation supposed to be done?

I have started reading through the dsymutil source code in llvm but I have not found where this computation takes place.

Mach-O symbol tables: Translating addresses in the main binary to addresses in a corresponding object file
 
 
Q