podman

Форк
0
461 строка · 15.0 Кб
1
//go:build go1.16 && !go1.18
2
// +build go1.16,!go1.18
3

4
/*
5
 * Copyright 2021 ByteDance Inc.
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19

20
package loader
21

22
import (
23
   `os`
24
   `unsafe`
25
   `sort`
26

27
   `github.com/bytedance/sonic/internal/rt`
28
)
29

30
const (
31
    _Magic uint32 = 0xfffffffa
32
)
33

34
type pcHeader struct {
35
    magic          uint32  // 0xFFFFFFF0
36
    pad1, pad2     uint8   // 0,0
37
    minLC          uint8   // min instruction size
38
    ptrSize        uint8   // size of a ptr in bytes
39
    nfunc          int     // number of functions in the module
40
    nfiles         uint    // number of entries in the file tab
41
    funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
42
    cuOffset       uintptr // offset to the cutab variable from pcHeader
43
    filetabOffset  uintptr // offset to the filetab variable from pcHeader
44
    pctabOffset    uintptr // offset to the pctab variable from pcHeader
45
    pclnOffset     uintptr // offset to the pclntab variable from pcHeader
46
}
47

48
type moduledata struct {
49
    pcHeader     *pcHeader
50
    funcnametab  []byte
51
    cutab        []uint32
52
    filetab      []byte
53
    pctab        []byte
54
    pclntable    []byte
55
    ftab         []funcTab
56
    findfunctab  uintptr
57
    minpc, maxpc uintptr // first func address, last func address + last func size
58

59
    text, etext           uintptr // start/end of text, (etext-text) must be greater than MIN_FUNC
60
    noptrdata, enoptrdata uintptr
61
    data, edata           uintptr
62
    bss, ebss             uintptr
63
    noptrbss, enoptrbss   uintptr
64
    end, gcdata, gcbss    uintptr
65
    types, etypes         uintptr
66
    
67
    textsectmap []textSection // see runtime/symtab.go: textAddr()
68
    typelinks   []int32 // offsets from types
69
    itablinks   []*rt.GoItab
70

71
    ptab []ptabEntry
72

73
    pluginpath string
74
    pkghashes  []modulehash
75

76
    modulename   string
77
    modulehashes []modulehash
78

79
    hasmain uint8 // 1 if module contains the main function, 0 otherwise
80

81
    gcdatamask, gcbssmask bitVector
82

83
    typemap map[int32]*rt.GoType // offset to *_rtype in previous module
84

85
    bad bool // module failed to load and should be ignored
86

87
    next *moduledata
88
}
89

90
type _func struct {
91
    entry    uintptr // start pc, as offset from moduledata.text/pcHeader.textStart
92
    nameOff  int32  // function name, as index into moduledata.funcnametab.
93

94
    args        int32  // in/out args size
95
    deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
96

97
    pcsp      uint32 
98
    pcfile    uint32
99
    pcln      uint32
100
    npcdata   uint32
101
    cuOffset  uint32 // runtime.cutab offset of this function's CU
102
    funcID    uint8  // set for certain special runtime functions
103
    _         [2]byte // pad
104
    nfuncdata uint8   // 
105
    
106
    // The end of the struct is followed immediately by two variable-length
107
    // arrays that reference the pcdata and funcdata locations for this
108
    // function.
109

110
    // pcdata contains the offset into moduledata.pctab for the start of
111
    // that index's table. e.g.,
112
    // &moduledata.pctab[_func.pcdata[_PCDATA_UnsafePoint]] is the start of
113
    // the unsafe point table.
114
    //
115
    // An offset of 0 indicates that there is no table.
116
    //
117
    // pcdata [npcdata]uint32
118

119
    // funcdata contains the offset past moduledata.gofunc which contains a
120
    // pointer to that index's funcdata. e.g.,
121
    // *(moduledata.gofunc +  _func.funcdata[_FUNCDATA_ArgsPointerMaps]) is
122
    // the argument pointer map.
123
    //
124
    // An offset of ^uint32(0) indicates that there is no entry.
125
    //
126
    // funcdata [nfuncdata]uint32
127
}
128

129
type funcTab struct {
130
    entry   uintptr
131
    funcoff uintptr
132
}
133

134
type bitVector struct {
135
    n        int32 // # of bits
136
    bytedata *uint8
137
}
138

139
type ptabEntry struct {
140
    name int32
141
    typ  int32
142
}
143

144
type textSection struct {
145
    vaddr    uintptr // prelinked section vaddr
146
    end      uintptr // vaddr + section length
147
    baseaddr uintptr // relocated section address
148
}
149

150
type modulehash struct {
151
    modulename   string
152
    linktimehash string
153
    runtimehash  *string
154
}
155

156
// findfuncbucket is an array of these structures.
157
// Each bucket represents 4096 bytes of the text segment.
158
// Each subbucket represents 256 bytes of the text segment.
159
// To find a function given a pc, locate the bucket and subbucket for
160
// that pc. Add together the idx and subbucket value to obtain a
161
// function index. Then scan the functab array starting at that
162
// index to find the target function.
163
// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
164
type findfuncbucket struct {
165
    idx        uint32
166
    _SUBBUCKETS [16]byte
167
}
168

169

170
type compilationUnit struct {
171
    fileNames []string
172
}
173

174
func makeFtab(funcs []_func, maxpc uintptr) (ftab []funcTab, pclntabSize int64, startLocations []uint32) {
175
    // Allocate space for the pc->func table. This structure consists of a pc offset
176
    // and an offset to the func structure. After that, we have a single pc
177
    // value that marks the end of the last function in the binary.
178
    pclntabSize = int64(len(funcs)*2*int(_PtrSize) + int(_PtrSize))
179
    startLocations = make([]uint32, len(funcs))
180
    for i, f := range funcs {
181
        pclntabSize = rnd(pclntabSize, int64(_PtrSize))
182
        //writePCToFunc
183
        startLocations[i] = uint32(pclntabSize)
184
        pclntabSize += int64(uint8(_FUNC_SIZE) + f.nfuncdata*_PtrSize + uint8(f.npcdata)*4)
185
    }
186
    ftab = make([]funcTab, 0, len(funcs)+1)
187

188
    // write a map of pc->func info offsets 
189
    for i, f := range funcs {
190
        ftab = append(ftab, funcTab{uintptr(f.entry), uintptr(startLocations[i])})
191
    }
192

193
    // Final entry of table is just end pc offset.
194
    ftab = append(ftab, funcTab{maxpc, 0})
195

196
    return
197
}
198

199
// Pcln table format: [...]funcTab + [...]_Func
200
func makePclntable(size int64, startLocations []uint32, funcs []_func, maxpc uintptr, pcdataOffs [][]uint32, funcdataAddr uintptr, funcdataOffs [][]uint32) (pclntab []byte) {
201
    pclntab = make([]byte, size, size)
202

203
    // write a map of pc->func info offsets 
204
    offs := 0
205
    for i, f := range funcs {
206
        byteOrder.PutUint64(pclntab[offs:offs+8], uint64(f.entry))
207
        byteOrder.PutUint64(pclntab[offs+8:offs+16], uint64(startLocations[i]))
208
        offs += 16
209
    }
210
    // Final entry of table is just end pc offset.
211
    byteOrder.PutUint64(pclntab[offs:offs+8], uint64(maxpc))
212
    offs += 8
213

214
    // write func info table
215
    for i, f := range funcs {
216
        off := startLocations[i]
217

218
        // write _func structure to pclntab
219
        byteOrder.PutUint64(pclntab[off:off+8], uint64(f.entry))
220
        off += 8
221
        byteOrder.PutUint32(pclntab[off:off+4], uint32(f.nameOff))
222
        off += 4
223
        byteOrder.PutUint32(pclntab[off:off+4], uint32(f.args))
224
        off += 4
225
        byteOrder.PutUint32(pclntab[off:off+4], uint32(f.deferreturn))
226
        off += 4
227
        byteOrder.PutUint32(pclntab[off:off+4], uint32(f.pcsp))
228
        off += 4
229
        byteOrder.PutUint32(pclntab[off:off+4], uint32(f.pcfile))
230
        off += 4
231
        byteOrder.PutUint32(pclntab[off:off+4], uint32(f.pcln))
232
        off += 4
233
        byteOrder.PutUint32(pclntab[off:off+4], uint32(f.npcdata))
234
        off += 4
235
        byteOrder.PutUint32(pclntab[off:off+4], uint32(f.cuOffset))
236
        off += 4
237
        pclntab[off] = f.funcID
238
        // NOTICE: _[2]byte alignment
239
        off += 3
240
        pclntab[off] = f.nfuncdata
241
        off += 1
242

243
        // NOTICE: _func.pcdata always starts from PcUnsafePoint, which is index 3
244
        for j := 3; j < len(pcdataOffs[i]); j++ {
245
            byteOrder.PutUint32(pclntab[off:off+4], uint32(pcdataOffs[i][j]))
246
            off += 4
247
        }
248

249
        off = uint32(rnd(int64(off), int64(_PtrSize)))
250

251
        // funcdata refs as offsets from gofunc
252
        for _, funcdata := range funcdataOffs[i] {
253
            if funcdata == _INVALID_FUNCDATA_OFFSET {
254
                byteOrder.PutUint64(pclntab[off:off+8], 0)
255
            } else {
256
                byteOrder.PutUint64(pclntab[off:off+8], uint64(funcdataAddr)+uint64(funcdata))
257
            }
258
            off += 8
259
        }
260
    }
261

262
    return
263
}
264

265
// findfunc table used to map pc to belonging func, 
266
// returns the index in the func table.
267
//
268
// All text section are divided into buckets sized _BUCKETSIZE(4K):
269
//   every bucket is divided into _SUBBUCKETS sized _SUB_BUCKETSIZE(64),
270
//   and it has a base idx to plus the offset stored in jth subbucket.
271
// see findfunc() in runtime/symtab.go
272
func writeFindfunctab(out *[]byte, ftab []funcTab) (start int) {
273
    start = len(*out)
274

275
    max := ftab[len(ftab)-1].entry
276
    min := ftab[0].entry
277
    nbuckets := (max - min + _BUCKETSIZE - 1) / _BUCKETSIZE
278
    n := (max - min + _SUB_BUCKETSIZE - 1) / _SUB_BUCKETSIZE
279

280
    tab := make([]findfuncbucket, 0, nbuckets)
281
    var s, e = 0, 0
282
    for i := 0; i<int(nbuckets); i++ {
283
        // store the start func of the bucket
284
        var fb = findfuncbucket{idx: uint32(s)}
285

286
        // find the last e-th func of the bucket
287
        var pc = min + uintptr((i+1)*_BUCKETSIZE)
288
        for ; e < len(ftab)-1 && ftab[e+1].entry <= pc; e++ {}
289
        
290
        for j := 0; j<_SUBBUCKETS && (i*_SUBBUCKETS+j)<int(n); j++ {
291
            // store the start func of the subbucket
292
            fb._SUBBUCKETS[j] = byte(uint32(s) - fb.idx)
293
            
294
            // find the s-th end func of the subbucket
295
            pc = min + uintptr(i*_BUCKETSIZE) + uintptr((j+1)*_SUB_BUCKETSIZE)
296
            for ; s < len(ftab)-1 && ftab[s+1].entry <= pc; s++ {}            
297
        }
298

299
        s = e
300
        tab = append(tab, fb)
301
    }
302

303
    // write findfuncbucket
304
    if len(tab) > 0 {
305
        size := int(unsafe.Sizeof(findfuncbucket{}))*len(tab)
306
        *out = append(*out, rt.BytesFrom(unsafe.Pointer(&tab[0]), size, size)...)
307
    }
308
    return 
309
}
310

311
func makeModuledata(name string, filenames []string, funcsp *[]Func, text []byte) (mod *moduledata) {
312
    mod = new(moduledata)
313
    mod.modulename = name
314

315
    // sort funcs by entry
316
    funcs := *funcsp
317
    sort.Slice(funcs, func(i, j int) bool {
318
        return funcs[i].EntryOff < funcs[j].EntryOff
319
    })
320
    *funcsp = funcs
321

322
    // make filename table
323
    cu := make([]string, 0, len(filenames))
324
    cu = append(cu, filenames...)
325
    cutab, filetab, cuOffs := makeFilenametab([]compilationUnit{{cu}})
326
    mod.cutab = cutab
327
    mod.filetab = filetab
328

329
    // make funcname table
330
    funcnametab, nameOffs := makeFuncnameTab(funcs)
331
    mod.funcnametab = funcnametab
332

333
    // mmap() text and funcdata segements
334
    p := os.Getpagesize()
335
    size := int(rnd(int64(len(text)), int64(p)))
336
    addr := mmap(size)
337
    // copy the machine code
338
    s := rt.BytesFrom(unsafe.Pointer(addr), len(text), size)
339
    copy(s, text)
340
    // make it executable
341
    mprotect(addr, size)
342

343
    // assign addresses
344
    mod.text = addr
345
    mod.etext = addr + uintptr(size)
346
    mod.minpc = addr
347
    mod.maxpc = addr + uintptr(len(text))
348

349
    // make pcdata table
350
    // NOTICE: _func only use offset to index pcdata, thus no need mmap() pcdata 
351
    cuOff := cuOffs[0]
352
    pctab, pcdataOffs, _funcs := makePctab(funcs, addr, cuOff, nameOffs)
353
    mod.pctab = pctab
354

355
    // write func data
356
    // NOTICE: _func use mod.gofunc+offset to directly point funcdata, thus need cache funcdata
357
    // TODO: estimate accurate capacity
358
    cache := make([]byte, 0, len(funcs)*int(_PtrSize)) 
359
    fstart, funcdataOffs := writeFuncdata(&cache, funcs)
360

361
    // make pc->func (binary search) func table
362
    ftab, pclntSize, startLocations := makeFtab(_funcs, mod.maxpc)
363
    mod.ftab = ftab
364

365
    // write pc->func (modmap) findfunc table
366
    ffstart := writeFindfunctab(&cache, ftab)
367

368
    // cache funcdata and findfuncbucket
369
    moduleCache.Lock()
370
    moduleCache.m[mod] = cache
371
    moduleCache.Unlock()
372
    mod.findfunctab = uintptr(rt.IndexByte(cache, ffstart))
373
    funcdataAddr := uintptr(rt.IndexByte(cache, fstart))
374

375
    // make pclnt table
376
    pclntab := makePclntable(pclntSize, startLocations, _funcs, mod.maxpc, pcdataOffs, funcdataAddr, funcdataOffs)
377
    mod.pclntable = pclntab
378

379
    // make pc header
380
    mod.pcHeader = &pcHeader {
381
        magic   : _Magic,
382
        minLC   : _MinLC,
383
        ptrSize : _PtrSize,
384
        nfunc   : len(funcs),
385
        nfiles: uint(len(cu)),
386
        funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
387
        cuOffset: getOffsetOf(moduledata{}, "cutab"),
388
        filetabOffset: getOffsetOf(moduledata{}, "filetab"),
389
        pctabOffset: getOffsetOf(moduledata{}, "pctab"),
390
        pclnOffset: getOffsetOf(moduledata{}, "pclntable"),
391
    }
392

393
    // sepecial case: gcdata and gcbss must by non-empty
394
    mod.gcdata = uintptr(unsafe.Pointer(&emptyByte))
395
    mod.gcbss = uintptr(unsafe.Pointer(&emptyByte))
396

397
    return
398
}
399

400
// makePctab generates pcdelta->valuedelta tables for functions,
401
// and returns the table and the entry offset of every kind pcdata in the table.
402
func makePctab(funcs []Func, addr uintptr, cuOffset uint32, nameOffset []int32) (pctab []byte, pcdataOffs [][]uint32, _funcs []_func) {
403
    _funcs = make([]_func, len(funcs))
404

405
    // Pctab offsets of 0 are considered invalid in the runtime. We respect
406
    // that by just padding a single byte at the beginning of runtime.pctab,
407
    // that way no real offsets can be zero.
408
    pctab = make([]byte, 1, 12*len(funcs)+1)
409
    pcdataOffs = make([][]uint32, len(funcs))
410

411
    for i, f := range funcs {
412
        _f := &_funcs[i]
413

414
        var writer = func(pc *Pcdata) {
415
            var ab []byte
416
            var err error
417
            if pc != nil {
418
                ab, err = pc.MarshalBinary()
419
                if err != nil {
420
                    panic(err)
421
                }
422
                pcdataOffs[i] = append(pcdataOffs[i], uint32(len(pctab)))
423
            } else {
424
                ab = []byte{0}
425
                pcdataOffs[i] = append(pcdataOffs[i], _PCDATA_INVALID_OFFSET)
426
            }
427
            pctab = append(pctab, ab...)
428
        }
429

430
        if f.Pcsp != nil {
431
            _f.pcsp = uint32(len(pctab))
432
        }
433
        writer(f.Pcsp)
434
        if f.Pcfile != nil {
435
            _f.pcfile = uint32(len(pctab))
436
        }
437
        writer(f.Pcfile)
438
        if f.Pcline != nil {
439
            _f.pcln = uint32(len(pctab))
440
        }
441
        writer(f.Pcline)
442
        writer(f.PcUnsafePoint)
443
        writer(f.PcStackMapIndex)
444
        writer(f.PcInlTreeIndex)
445
        writer(f.PcArgLiveIndex)
446
        
447
        _f.entry = addr + uintptr(f.EntryOff)
448
        _f.nameOff = nameOffset[i]
449
        _f.args = f.ArgsSize
450
        _f.deferreturn = f.DeferReturn
451
        // NOTICE: _func.pcdata is always as [PCDATA_UnsafePoint(0) : PCDATA_ArgLiveIndex(3)]
452
        _f.npcdata = uint32(_N_PCDATA)
453
        _f.cuOffset = cuOffset
454
        _f.funcID = f.ID
455
        _f.nfuncdata = uint8(_N_FUNCDATA)
456
    }
457

458
    return
459
}
460

461
func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {} 
462

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.