Commit 299117ec authored by Michael Hudson-Doyle's avatar Michael Hudson-Doyle Committed by Ian Lance Taylor

debug/elf: support arm64 relocations

This adds the minimal support for AArch64/arm64 relocations
needed to get cgo to work (when an isomorphic patch is applied
to gccgo) and a test.

This change uses the "AAarch64" name for the architecture rather
than the more widely accepted "arm64" because that's the name that
the relevant docs from ARM such as

   http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf

all use.

Fixes #8533.

LGTM=iant
R=golang-codereviews, aram, gobot, iant, minux
CC=golang-codereviews
https://golang.org/cl/132000043
parent a9b2651a
......@@ -11,6 +11,7 @@
* $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
* $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
* $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
* "ELF for the ARM® 64-bit Architecture (AArch64)" (ARM IHI 0056B)
*
* Copyright (c) 1996-1998 John D. Polstra. All rights reserved.
* Copyright (c) 2001 David E. O'Brien
......@@ -235,6 +236,7 @@ const (
EM_ST100 Machine = 60 /* STMicroelectronics ST100 processor. */
EM_TINYJ Machine = 61 /* Advanced Logic Corp. TinyJ processor. */
EM_X86_64 Machine = 62 /* Advanced Micro Devices x86-64 */
EM_AARCH64 Machine = 183 /* ARM 64-bit Architecture (AArch64) */
/* Non-standard or deprecated. */
EM_486 Machine = 6 /* Intel i486. */
......@@ -774,6 +776,256 @@ var rx86_64Strings = []intName{
func (i R_X86_64) String() string { return stringName(uint32(i), rx86_64Strings, false) }
func (i R_X86_64) GoString() string { return stringName(uint32(i), rx86_64Strings, true) }
// Relocation types for AArch64 (aka arm64)
type R_AARCH64 int
const (
R_AARCH64_NONE R_AARCH64 = 0
R_AARCH64_P32_ABS32 R_AARCH64 = 1
R_AARCH64_P32_ABS16 R_AARCH64 = 2
R_AARCH64_P32_PREL32 R_AARCH64 = 3
R_AARCH64_P32_PREL16 R_AARCH64 = 4
R_AARCH64_P32_MOVW_UABS_G0 R_AARCH64 = 5
R_AARCH64_P32_MOVW_UABS_G0_NC R_AARCH64 = 6
R_AARCH64_P32_MOVW_UABS_G1 R_AARCH64 = 7
R_AARCH64_P32_MOVW_SABS_G0 R_AARCH64 = 8
R_AARCH64_P32_LD_PREL_LO19 R_AARCH64 = 9
R_AARCH64_P32_ADR_PREL_LO21 R_AARCH64 = 10
R_AARCH64_P32_ADR_PREL_PG_HI21 R_AARCH64 = 11
R_AARCH64_P32_ADD_ABS_LO12_NC R_AARCH64 = 12
R_AARCH64_P32_LDST8_ABS_LO12_NC R_AARCH64 = 13
R_AARCH64_P32_LDST16_ABS_LO12_NC R_AARCH64 = 14
R_AARCH64_P32_LDST32_ABS_LO12_NC R_AARCH64 = 15
R_AARCH64_P32_LDST64_ABS_LO12_NC R_AARCH64 = 16
R_AARCH64_P32_LDST128_ABS_LO12_NC R_AARCH64 = 17
R_AARCH64_P32_TSTBR14 R_AARCH64 = 18
R_AARCH64_P32_CONDBR19 R_AARCH64 = 19
R_AARCH64_P32_JUMP26 R_AARCH64 = 20
R_AARCH64_P32_CALL26 R_AARCH64 = 21
R_AARCH64_P32_GOT_LD_PREL19 R_AARCH64 = 25
R_AARCH64_P32_ADR_GOT_PAGE R_AARCH64 = 26
R_AARCH64_P32_LD32_GOT_LO12_NC R_AARCH64 = 27
R_AARCH64_P32_TLSGD_ADR_PAGE21 R_AARCH64 = 81
R_AARCH64_P32_TLSGD_ADD_LO12_NC R_AARCH64 = 82
R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21 R_AARCH64 = 103
R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC R_AARCH64 = 104
R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19 R_AARCH64 = 105
R_AARCH64_P32_TLSLE_MOVW_TPREL_G1 R_AARCH64 = 106
R_AARCH64_P32_TLSLE_MOVW_TPREL_G0 R_AARCH64 = 107
R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC R_AARCH64 = 108
R_AARCH64_P32_TLSLE_ADD_TPREL_HI12 R_AARCH64 = 109
R_AARCH64_P32_TLSLE_ADD_TPREL_LO12 R_AARCH64 = 110
R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC R_AARCH64 = 111
R_AARCH64_P32_TLSDESC_LD_PREL19 R_AARCH64 = 122
R_AARCH64_P32_TLSDESC_ADR_PREL21 R_AARCH64 = 123
R_AARCH64_P32_TLSDESC_ADR_PAGE21 R_AARCH64 = 124
R_AARCH64_P32_TLSDESC_LD32_LO12_NC R_AARCH64 = 125
R_AARCH64_P32_TLSDESC_ADD_LO12_NC R_AARCH64 = 126
R_AARCH64_P32_TLSDESC_CALL R_AARCH64 = 127
R_AARCH64_P32_COPY R_AARCH64 = 180
R_AARCH64_P32_GLOB_DAT R_AARCH64 = 181
R_AARCH64_P32_JUMP_SLOT R_AARCH64 = 182
R_AARCH64_P32_RELATIVE R_AARCH64 = 183
R_AARCH64_P32_TLS_DTPMOD R_AARCH64 = 184
R_AARCH64_P32_TLS_DTPREL R_AARCH64 = 185
R_AARCH64_P32_TLS_TPREL R_AARCH64 = 186
R_AARCH64_P32_TLSDESC R_AARCH64 = 187
R_AARCH64_P32_IRELATIVE R_AARCH64 = 188
R_AARCH64_NULL R_AARCH64 = 256
R_AARCH64_ABS64 R_AARCH64 = 257
R_AARCH64_ABS32 R_AARCH64 = 258
R_AARCH64_ABS16 R_AARCH64 = 259
R_AARCH64_PREL64 R_AARCH64 = 260
R_AARCH64_PREL32 R_AARCH64 = 261
R_AARCH64_PREL16 R_AARCH64 = 262
R_AARCH64_MOVW_UABS_G0 R_AARCH64 = 263
R_AARCH64_MOVW_UABS_G0_NC R_AARCH64 = 264
R_AARCH64_MOVW_UABS_G1 R_AARCH64 = 265
R_AARCH64_MOVW_UABS_G1_NC R_AARCH64 = 266
R_AARCH64_MOVW_UABS_G2 R_AARCH64 = 267
R_AARCH64_MOVW_UABS_G2_NC R_AARCH64 = 268
R_AARCH64_MOVW_UABS_G3 R_AARCH64 = 269
R_AARCH64_MOVW_SABS_G0 R_AARCH64 = 270
R_AARCH64_MOVW_SABS_G1 R_AARCH64 = 271
R_AARCH64_MOVW_SABS_G2 R_AARCH64 = 272
R_AARCH64_LD_PREL_LO19 R_AARCH64 = 273
R_AARCH64_ADR_PREL_LO21 R_AARCH64 = 274
R_AARCH64_ADR_PREL_PG_HI21 R_AARCH64 = 275
R_AARCH64_ADR_PREL_PG_HI21_NC R_AARCH64 = 276
R_AARCH64_ADD_ABS_LO12_NC R_AARCH64 = 277
R_AARCH64_LDST8_ABS_LO12_NC R_AARCH64 = 278
R_AARCH64_TSTBR14 R_AARCH64 = 279
R_AARCH64_CONDBR19 R_AARCH64 = 280
R_AARCH64_JUMP26 R_AARCH64 = 282
R_AARCH64_CALL26 R_AARCH64 = 283
R_AARCH64_LDST16_ABS_LO12_NC R_AARCH64 = 284
R_AARCH64_LDST32_ABS_LO12_NC R_AARCH64 = 285
R_AARCH64_LDST64_ABS_LO12_NC R_AARCH64 = 286
R_AARCH64_LDST128_ABS_LO12_NC R_AARCH64 = 299
R_AARCH64_GOT_LD_PREL19 R_AARCH64 = 309
R_AARCH64_ADR_GOT_PAGE R_AARCH64 = 311
R_AARCH64_LD64_GOT_LO12_NC R_AARCH64 = 312
R_AARCH64_TLSGD_ADR_PAGE21 R_AARCH64 = 513
R_AARCH64_TLSGD_ADD_LO12_NC R_AARCH64 = 514
R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 R_AARCH64 = 539
R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC R_AARCH64 = 540
R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 R_AARCH64 = 541
R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC R_AARCH64 = 542
R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 R_AARCH64 = 543
R_AARCH64_TLSLE_MOVW_TPREL_G2 R_AARCH64 = 544
R_AARCH64_TLSLE_MOVW_TPREL_G1 R_AARCH64 = 545
R_AARCH64_TLSLE_MOVW_TPREL_G1_NC R_AARCH64 = 546
R_AARCH64_TLSLE_MOVW_TPREL_G0 R_AARCH64 = 547
R_AARCH64_TLSLE_MOVW_TPREL_G0_NC R_AARCH64 = 548
R_AARCH64_TLSLE_ADD_TPREL_HI12 R_AARCH64 = 549
R_AARCH64_TLSLE_ADD_TPREL_LO12 R_AARCH64 = 550
R_AARCH64_TLSLE_ADD_TPREL_LO12_NC R_AARCH64 = 551
R_AARCH64_TLSDESC_LD_PREL19 R_AARCH64 = 560
R_AARCH64_TLSDESC_ADR_PREL21 R_AARCH64 = 561
R_AARCH64_TLSDESC_ADR_PAGE21 R_AARCH64 = 562
R_AARCH64_TLSDESC_LD64_LO12_NC R_AARCH64 = 563
R_AARCH64_TLSDESC_ADD_LO12_NC R_AARCH64 = 564
R_AARCH64_TLSDESC_OFF_G1 R_AARCH64 = 565
R_AARCH64_TLSDESC_OFF_G0_NC R_AARCH64 = 566
R_AARCH64_TLSDESC_LDR R_AARCH64 = 567
R_AARCH64_TLSDESC_ADD R_AARCH64 = 568
R_AARCH64_TLSDESC_CALL R_AARCH64 = 569
R_AARCH64_COPY R_AARCH64 = 1024
R_AARCH64_GLOB_DAT R_AARCH64 = 1025
R_AARCH64_JUMP_SLOT R_AARCH64 = 1026
R_AARCH64_RELATIVE R_AARCH64 = 1027
R_AARCH64_TLS_DTPMOD64 R_AARCH64 = 1028
R_AARCH64_TLS_DTPREL64 R_AARCH64 = 1029
R_AARCH64_TLS_TPREL64 R_AARCH64 = 1030
R_AARCH64_TLSDESC R_AARCH64 = 1031
R_AARCH64_IRELATIVE R_AARCH64 = 1032
)
var raarch64Strings = []intName{
{0, "R_AARCH64_NONE"},
{1, "R_AARCH64_P32_ABS32"},
{2, "R_AARCH64_P32_ABS16"},
{3, "R_AARCH64_P32_PREL32"},
{4, "R_AARCH64_P32_PREL16"},
{5, "R_AARCH64_P32_MOVW_UABS_G0"},
{6, "R_AARCH64_P32_MOVW_UABS_G0_NC"},
{7, "R_AARCH64_P32_MOVW_UABS_G1"},
{8, "R_AARCH64_P32_MOVW_SABS_G0"},
{9, "R_AARCH64_P32_LD_PREL_LO19"},
{10, "R_AARCH64_P32_ADR_PREL_LO21"},
{11, "R_AARCH64_P32_ADR_PREL_PG_HI21"},
{12, "R_AARCH64_P32_ADD_ABS_LO12_NC"},
{13, "R_AARCH64_P32_LDST8_ABS_LO12_NC"},
{14, "R_AARCH64_P32_LDST16_ABS_LO12_NC"},
{15, "R_AARCH64_P32_LDST32_ABS_LO12_NC"},
{16, "R_AARCH64_P32_LDST64_ABS_LO12_NC"},
{17, "R_AARCH64_P32_LDST128_ABS_LO12_NC"},
{18, "R_AARCH64_P32_TSTBR14"},
{19, "R_AARCH64_P32_CONDBR19"},
{20, "R_AARCH64_P32_JUMP26"},
{21, "R_AARCH64_P32_CALL26"},
{25, "R_AARCH64_P32_GOT_LD_PREL19"},
{26, "R_AARCH64_P32_ADR_GOT_PAGE"},
{27, "R_AARCH64_P32_LD32_GOT_LO12_NC"},
{81, "R_AARCH64_P32_TLSGD_ADR_PAGE21"},
{82, "R_AARCH64_P32_TLSGD_ADD_LO12_NC"},
{103, "R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21"},
{104, "R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC"},
{105, "R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19"},
{106, "R_AARCH64_P32_TLSLE_MOVW_TPREL_G1"},
{107, "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0"},
{108, "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC"},
{109, "R_AARCH64_P32_TLSLE_ADD_TPREL_HI12"},
{110, "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12"},
{111, "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC"},
{122, "R_AARCH64_P32_TLSDESC_LD_PREL19"},
{123, "R_AARCH64_P32_TLSDESC_ADR_PREL21"},
{124, "R_AARCH64_P32_TLSDESC_ADR_PAGE21"},
{125, "R_AARCH64_P32_TLSDESC_LD32_LO12_NC"},
{126, "R_AARCH64_P32_TLSDESC_ADD_LO12_NC"},
{127, "R_AARCH64_P32_TLSDESC_CALL"},
{180, "R_AARCH64_P32_COPY"},
{181, "R_AARCH64_P32_GLOB_DAT"},
{182, "R_AARCH64_P32_JUMP_SLOT"},
{183, "R_AARCH64_P32_RELATIVE"},
{184, "R_AARCH64_P32_TLS_DTPMOD"},
{185, "R_AARCH64_P32_TLS_DTPREL"},
{186, "R_AARCH64_P32_TLS_TPREL"},
{187, "R_AARCH64_P32_TLSDESC"},
{188, "R_AARCH64_P32_IRELATIVE"},
{256, "R_AARCH64_NULL"},
{257, "R_AARCH64_ABS64"},
{258, "R_AARCH64_ABS32"},
{259, "R_AARCH64_ABS16"},
{260, "R_AARCH64_PREL64"},
{261, "R_AARCH64_PREL32"},
{262, "R_AARCH64_PREL16"},
{263, "R_AARCH64_MOVW_UABS_G0"},
{264, "R_AARCH64_MOVW_UABS_G0_NC"},
{265, "R_AARCH64_MOVW_UABS_G1"},
{266, "R_AARCH64_MOVW_UABS_G1_NC"},
{267, "R_AARCH64_MOVW_UABS_G2"},
{268, "R_AARCH64_MOVW_UABS_G2_NC"},
{269, "R_AARCH64_MOVW_UABS_G3"},
{270, "R_AARCH64_MOVW_SABS_G0"},
{271, "R_AARCH64_MOVW_SABS_G1"},
{272, "R_AARCH64_MOVW_SABS_G2"},
{273, "R_AARCH64_LD_PREL_LO19"},
{274, "R_AARCH64_ADR_PREL_LO21"},
{275, "R_AARCH64_ADR_PREL_PG_HI21"},
{276, "R_AARCH64_ADR_PREL_PG_HI21_NC"},
{277, "R_AARCH64_ADD_ABS_LO12_NC"},
{278, "R_AARCH64_LDST8_ABS_LO12_NC"},
{279, "R_AARCH64_TSTBR14"},
{280, "R_AARCH64_CONDBR19"},
{282, "R_AARCH64_JUMP26"},
{283, "R_AARCH64_CALL26"},
{284, "R_AARCH64_LDST16_ABS_LO12_NC"},
{285, "R_AARCH64_LDST32_ABS_LO12_NC"},
{286, "R_AARCH64_LDST64_ABS_LO12_NC"},
{299, "R_AARCH64_LDST128_ABS_LO12_NC"},
{309, "R_AARCH64_GOT_LD_PREL19"},
{311, "R_AARCH64_ADR_GOT_PAGE"},
{312, "R_AARCH64_LD64_GOT_LO12_NC"},
{513, "R_AARCH64_TLSGD_ADR_PAGE21"},
{514, "R_AARCH64_TLSGD_ADD_LO12_NC"},
{539, "R_AARCH64_TLSIE_MOVW_GOTTPREL_G1"},
{540, "R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC"},
{541, "R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21"},
{542, "R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC"},
{543, "R_AARCH64_TLSIE_LD_GOTTPREL_PREL19"},
{544, "R_AARCH64_TLSLE_MOVW_TPREL_G2"},
{545, "R_AARCH64_TLSLE_MOVW_TPREL_G1"},
{546, "R_AARCH64_TLSLE_MOVW_TPREL_G1_NC"},
{547, "R_AARCH64_TLSLE_MOVW_TPREL_G0"},
{548, "R_AARCH64_TLSLE_MOVW_TPREL_G0_NC"},
{549, "R_AARCH64_TLSLE_ADD_TPREL_HI12"},
{550, "R_AARCH64_TLSLE_ADD_TPREL_LO12"},
{551, "R_AARCH64_TLSLE_ADD_TPREL_LO12_NC"},
{560, "R_AARCH64_TLSDESC_LD_PREL19"},
{561, "R_AARCH64_TLSDESC_ADR_PREL21"},
{562, "R_AARCH64_TLSDESC_ADR_PAGE21"},
{563, "R_AARCH64_TLSDESC_LD64_LO12_NC"},
{564, "R_AARCH64_TLSDESC_ADD_LO12_NC"},
{565, "R_AARCH64_TLSDESC_OFF_G1"},
{566, "R_AARCH64_TLSDESC_OFF_G0_NC"},
{567, "R_AARCH64_TLSDESC_LDR"},
{568, "R_AARCH64_TLSDESC_ADD"},
{569, "R_AARCH64_TLSDESC_CALL"},
{1024, "R_AARCH64_COPY"},
{1025, "R_AARCH64_GLOB_DAT"},
{1026, "R_AARCH64_JUMP_SLOT"},
{1027, "R_AARCH64_RELATIVE"},
{1028, "R_AARCH64_TLS_DTPMOD64"},
{1029, "R_AARCH64_TLS_DTPREL64"},
{1030, "R_AARCH64_TLS_TPREL64"},
{1031, "R_AARCH64_TLSDESC"},
{1032, "R_AARCH64_IRELATIVE"},
}
func (i R_AARCH64) String() string { return stringName(uint32(i), raarch64Strings, false) }
func (i R_AARCH64) GoString() string { return stringName(uint32(i), raarch64Strings, true) }
// Relocation types for Alpha.
type R_ALPHA int
......
......@@ -529,6 +529,9 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error {
if f.Class == ELFCLASS32 && f.Machine == EM_386 {
return f.applyRelocations386(dst, rels)
}
if f.Class == ELFCLASS64 && f.Machine == EM_AARCH64 {
return f.applyRelocationsARM64(dst, rels)
}
return errors.New("not implemented")
}
......@@ -615,6 +618,51 @@ func (f *File) applyRelocations386(dst []byte, rels []byte) error {
return nil
}
func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
// 24 is the size of Rela64.
if len(rels)%24 != 0 {
return errors.New("length of relocation section is not a multiple of 24")
}
symbols, _, err := f.getSymbols(SHT_SYMTAB)
if err != nil {
return err
}
b := bytes.NewReader(rels)
var rela Rela64
for b.Len() > 0 {
binary.Read(b, f.ByteOrder, &rela)
symNo := rela.Info >> 32
t := R_AARCH64(rela.Info & 0xffff)
if symNo == 0 || symNo > uint64(len(symbols)) {
continue
}
sym := &symbols[symNo-1]
if SymType(sym.Info&0xf) != STT_SECTION {
// We don't handle non-section relocations for now.
continue
}
switch t {
case R_AARCH64_ABS64:
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
continue
}
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
case R_AARCH64_ABS32:
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
continue
}
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
}
}
return nil
}
func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package
......@@ -637,7 +685,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
// If there's a relocation table for .debug_info, we have to process it
// now otherwise the data in .debug_info is invalid for x86-64 objects.
rela := f.Section(".rela.debug_info")
if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_AARCH64) {
data, err := rela.Data()
if err != nil {
return nil, err
......
......@@ -260,6 +260,12 @@ var relocationTests = []relocationTest{
{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
},
},
{
"testdata/go-relocation-test-gcc482-aarch64.obj",
[]relocationTestEntry{
{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: int64(0x24)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
},
},
{
"testdata/go-relocation-test-clang-x86.obj",
[]relocationTestEntry{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment