@@ -60,6 +60,8 @@ var ErrNoTbss = errors.New("no thread-local uninitialized data section (tbss)")
6060// ErrNoTdata is returned when the tdata section cannot be found
6161var ErrNoTdata = errors .New ("no thread-local initialized data section (tdata)" )
6262
63+ var ErrNoTls = errors .New ("no TLS program header" )
64+
6365// File represents an open ELF file
6466type File struct {
6567 // closer is called internally when resources for this File are to be released
@@ -451,6 +453,16 @@ func (f *File) Tdata() (*Section, error) {
451453 return nil , ErrNoTdata
452454}
453455
456+ // Tls gets the TLS segment (program header)
457+ func (f * File ) Tls () (* Prog , error ) {
458+ for _ , seg := range f .Progs {
459+ if seg .Type == elf .PT_TLS {
460+ return & seg , nil
461+ }
462+ }
463+ return nil , ErrNoTls
464+ }
465+
454466// ReadVirtualMemory reads bytes from given virtual address
455467func (f * File ) ReadVirtualMemory (p []byte , addr int64 ) (int , error ) {
456468 if len (p ) == 0 {
@@ -840,25 +852,20 @@ func (f *File) LookupTlsSymbolOffset(symbol libpf.SymbolName) (int64, error) {
840852 // of the image. So we need to find the size of the image in order to know where the
841853 // beginning is.
842854 //
843- // The image is just .tdata followed by .tbss,
844- // but we also have to respect the alignment.
845- tbss , err := f .Tbss ()
855+ // Furthermore, the thread pointer (fs-base) respects the TLS segment's alignment
856+ // (which is a bit weird given that offsets are negative, but it is in fact true).
857+ //
858+ // So if the segment is 32-byte aligned, and some object is at byte 4 in the segment,
859+ // it will be at offset -28 from fs-base.
860+ //
861+ // See "ELF Handling For Thread-Local Storage" (https://www.uclibc.org/docs/tls.pdf),
862+ // pp. 8 ("Variant II"), 11 ("IA-32 Specific"), 14 ("x86-64 Specific").
863+ tls , err := f .Tls ()
846864 if err != nil {
847865 return 0 , err
848866 }
849- tdata , err := f .Tdata ()
850- var tdataSize uint64
851- if err != nil {
852- // No Tdata is ok, it's the same as size 0
853- if err != ErrNoTdata {
854- return 0 , err
855- }
856- } else {
857- tdataSize = tdata .Size
858- }
867+ offset := int64 (tlsSym .Address ) - int64 (roundUp (tls .Align , tls .Memsz ))
859868
860- imageSize := roundUp (tbss .Addralign , tdataSize ) + tbss .Size
861- offset := int64 (tlsSym .Address ) - int64 (imageSize )
862869 return offset , nil
863870 }
864871 return 0 , fmt .Errorf ("unrecognized machine: %s" , f .Machine .String ())
0 commit comments