1 // Copyright 2022 Chaos Mesh Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 16 package time 17 18 import ( 19 "debug/elf" 20 "encoding/binary" 21 ) 22 23 func AssetLD(rela elf.Rela64, imageOffset map[string]int, imageContent *[]byte, sym elf.Symbol, byteorder binary.ByteOrder) { 24 imageOffset[sym.Name] = len(*imageContent) 25 26 targetOffset := uint32(len(*imageContent)) - uint32(rela.Off) + uint32(rela.Addend) 27 28 // The relocation of a aarch64 image is like: 29 // Offset Info Type Sym. Value Sym. Name + Addend 30 // 000000000010 000b00000135 R_AARCH64_GOT_LD_ 0000000000000000 CLOCK_IDS_MASK + 0 31 // 00000000002c 000c00000135 R_AARCH64_GOT_LD_ 0000000000000000 TV_NSEC_DELTA + 0 32 // 000000000034 000d00000135 R_AARCH64_GOT_LD_ 0000000000000000 TV_SEC_DELTA + 0 33 34 // we assume the type is always R_AARCH64_GOT_LD_PREL19, with `-mcmodel=tiny` 35 36 // In this situation, we need to push two uint64 to the end: 37 // One for the location of variable, and one for the variable 38 39 // For example, if the entry starts at 0x00, and we have two variables whose value are 40 // 0xFF and 0xFE. We will have 32 bytes after the content: 41 // | 0x00 | 0x08 | 0x10 | 0x18 | 42 // | 0x08 | 0xFF | 0x18 | 0xFE | 43 44 // See the manual of LDR (literal) and LDR (register) to understand the 45 // relocation based on the following assemblies: 46 // 47 // ldr x1, #OFFSET_OF_ADDR ; in this step, the address of variable is loaded 48 // into the x1 register 49 // ldr x1, [x1] ; in this step, the variable itself is loaded into 50 // the register 51 52 targetOffset >>= 2 53 instr := byteorder.Uint32((*imageContent)[rela.Off : rela.Off+4]) 54 55 // See the document of instruction 56 // [ldr](https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/LDR--literal---Load-Register--literal--?lang=en) 57 // the offset is saved in `imm19`, and the max length is 19 (bit) 58 // 59 // 1. cut `instr` at [0:4] and [23:31] 60 // 2. cut the little 19 bit of `targetOffset`, and shift it to [5:23] 61 // 3. concat them 62 instr = uint32(int(instr) & ^((1<<19-1)<<5)) | ((targetOffset & (1<<19 - 1)) << 5) 63 byteorder.PutUint32((*imageContent)[rela.Off:rela.Off+4], instr) 64 65 // TODO: support other length besides uint64 (which is 8 bytes) 66 *imageContent = append(*imageContent, make([]byte, varLength)...) 67 } 68