'Programming/golang'에 해당되는 글 103건

  1. 2023.08.23 golang goarch=arm64 와 디스어셈블러
  2. 2023.06.27 golang echo 서버 이상한 버그 발견?
  3. 2023.06.08 go ws server client example
  4. 2023.05.24 golang waitgroup
  5. 2023.05.24 golang echo server middleware
  6. 2023.05.24 golang 동시성
  7. 2023.05.16 golang 고루틴과 채널
  8. 2023.05.16 golang switch, select
  9. 2023.05.16 golang uds
  10. 2023.05.16 golang mutex (sync)
Programming/golang2023. 8. 23. 17:19

go 프로그램도 java와 같은 독립된 환경이 아닌 일반적인 c와 같은 실행환경에서 도는 애다 보니

결국에는 기계어로 전환되고 objdump를 통해 디스어셈블을 할 수 있긴한데

go tool objdump를 통해 나오는 결과와 objdump를 통해 나오는 결과가 상이하다

go build -gcflags -S program.go
If you already have a compiled program and want to see the assembly code you can disassemble it with 
go tool objdump binaryFile.

[링크 : https://www.grant.pizza/blog/dissecting-go-binaries/]

 

명렁어 자체는 특이한 건 없다.

go tool objdump [-s symregexp] binary

[링크 : https://pkg.go.dev/cmd/objdump]

 

요런 go 소스를 작성하고

$ vi neon.go 
  1 package main
  2 
  3 func main() {
  4         add()
  5 }
  6 
  7 func add() {
  8         a := make([]int32, 256)
  9         b := make([]int32, 256)
 10         c := make([]int32, 256)
 11 
 12         var i int32
 13         for i = 0; i < 256; i++ {
 14                 b[i] = i;
 15                 c[i] = 256 - i;
 16         }
 17 
 18         for i = 0; i < 256; i++ {
 19                 a[i] = b[i] + c[i]
 20         }
 21 }

 

go build를 통해 빌드하면 디스어셈블 해주는데

출력 포맷이 objdump와 다른데다가.. 소스 라인만 보이고 매칭이 안되서 이래저래 불편..

그 와중에 먼가.. x86 ASM 같은 느낌은 왜일까..

일종의 중간(?) 언어로 어셈을 쓰고 이걸 다시 아키텍쳐별로 변환하는건가?

$ GOARCH=arm64 go build -gcflags -S .
# tt
main.main STEXT size=240 args=0x0 locals=0x818 funcid=0x0 align=0x0
0x0000 00000 (/home/user/work/src/goneon/neon.go:3) TEXT main.main(SB), ABIInternal, $2080-0
0x0000 00000 (/home/user/work/src/goneon/neon.go:3) MOVD 16(g), R16
0x0004 00004 (/home/user/work/src/goneon/neon.go:3) PCDATA $0, $-2
0x0004 00004 (/home/user/work/src/goneon/neon.go:3) SUB $1952, RSP, R17
0x0008 00008 (/home/user/work/src/goneon/neon.go:3) CMP R16, R17
0x000c 00012 (/home/user/work/src/goneon/neon.go:3) BLS 220
0x0010 00016 (/home/user/work/src/goneon/neon.go:3) PCDATA $0, $-1
0x0010 00016 (/home/user/work/src/goneon/neon.go:3) SUB $2080, RSP, R20
0x0014 00020 (/home/user/work/src/goneon/neon.go:3) STP (R29, R30), -8(R20)
0x0018 00024 (/home/user/work/src/goneon/neon.go:3) PCDATA $0, $-2
0x0018 00024 (/home/user/work/src/goneon/neon.go:3) MOVD R20, RSP
0x001c 00028 (/home/user/work/src/goneon/neon.go:3) PCDATA $0, $-1
0x001c 00028 (/home/user/work/src/goneon/neon.go:3) SUB $8, RSP, R29
0x0020 00032 (/home/user/work/src/goneon/neon.go:3) FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
0x0020 00032 (/home/user/work/src/goneon/neon.go:3) FUNCDATA $1, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
0x0020 00032 (<unknown line number>) NOP
0x0020 00032 (/home/user/work/src/goneon/neon.go:4) MOVD $main..autotmp_5-1024(SP), R20
0x0024 00036 (/home/user/work/src/goneon/neon.go:9) PCDATA $0, $-2
0x0024 00036 (/home/user/work/src/goneon/neon.go:9) ADR 52, runtime.duffzero(R27)(R27)(REG)
0x0028 00040 (/home/user/work/src/goneon/neon.go:9) STP (R29, R27), -24(RSP)
0x002c 00044 (/home/user/work/src/goneon/neon.go:9) SUB $24, RSP, R29
0x0030 00048 (/home/user/work/src/goneon/neon.go:9) DUFFZERO runtime.duffzero(SB)
0x0034 00052 (/home/user/work/src/goneon/neon.go:9) SUB $8, RSP, R29
0x0038 00056 (/home/user/work/src/goneon/neon.go:10) PCDATA $0, $-1
0x0038 00056 (/home/user/work/src/goneon/neon.go:10) MOVD $main..autotmp_6-2048(SP), R20
0x003c 00060 (/home/user/work/src/goneon/neon.go:10) PCDATA $0, $-2
0x003c 00060 (/home/user/work/src/goneon/neon.go:10) ADR 76, runtime.duffzero(R27)(R27)(REG)
0x0040 00064 (/home/user/work/src/goneon/neon.go:10) STP (R29, R27), -24(RSP)
0x0044 00068 (/home/user/work/src/goneon/neon.go:10) SUB $24, RSP, R29
0x0048 00072 (/home/user/work/src/goneon/neon.go:10) DUFFZERO runtime.duffzero(SB)
0x004c 00076 (/home/user/work/src/goneon/neon.go:10) SUB $8, RSP, R29
0x0050 00080 (/home/user/work/src/goneon/neon.go:10) PCDATA $0, $-1
0x0050 00080 (/home/user/work/src/goneon/neon.go:10) MOVD ZR, R0
0x0054 00084 (/home/user/work/src/goneon/neon.go:13) JMP 120
0x0058 00088 (/home/user/work/src/goneon/neon.go:14) SBFIZ $2, R0, $32, R2
0x005c 00092 (/home/user/work/src/goneon/neon.go:14) MOVD $main..autotmp_5-1024(SP), R3
0x0060 00096 (/home/user/work/src/goneon/neon.go:14) MOVW R0, (R3)(R2)
0x0064 00100 (/home/user/work/src/goneon/neon.go:15) MOVD $256, R4
0x0068 00104 (/home/user/work/src/goneon/neon.go:15) SUB R0, R4, R5
0x006c 00108 (/home/user/work/src/goneon/neon.go:15) MOVD $main..autotmp_6-2048(SP), R6
0x0070 00112 (/home/user/work/src/goneon/neon.go:15) MOVW R5, (R6)(R2)
0x0074 00116 (/home/user/work/src/goneon/neon.go:13) ADD $1, R0, R0
0x0078 00120 (/home/user/work/src/goneon/neon.go:13) CMPW $256, R0
0x007c 00124 (/home/user/work/src/goneon/neon.go:13) BGE 144
0x0080 00128 (/home/user/work/src/goneon/neon.go:14) MOVW R0, R2
0x0084 00132 (/home/user/work/src/goneon/neon.go:14) CMP $256, R2
0x0088 00136 (/home/user/work/src/goneon/neon.go:14) BLO 88
0x008c 00140 (/home/user/work/src/goneon/neon.go:14) JMP 204
0x0090 00144 (/home/user/work/src/goneon/neon.go:14) MOVD ZR, R0
0x0094 00148 (/home/user/work/src/goneon/neon.go:13) JMP 156
0x0098 00152 (/home/user/work/src/goneon/neon.go:18) ADD $1, R0, R0
0x009c 00156 (/home/user/work/src/goneon/neon.go:18) CMPW $256, R0
0x00a0 00160 (/home/user/work/src/goneon/neon.go:18) BGE 180
0x00a4 00164 (/home/user/work/src/goneon/neon.go:19) MOVW R0, R2
0x00a8 00168 (/home/user/work/src/goneon/neon.go:19) CMP $256, R2
0x00ac 00172 (/home/user/work/src/goneon/neon.go:19) BLO 152
0x00b0 00176 (/home/user/work/src/goneon/neon.go:19) JMP 192
0x00b4 00180 (/home/user/work/src/goneon/neon.go:5) LDP -8(RSP), (R29, R30)
0x00b8 00184 (/home/user/work/src/goneon/neon.go:5) ADD $2080, RSP
0x00bc 00188 (/home/user/work/src/goneon/neon.go:5) RET (R30)
0x00c0 00192 (/home/user/work/src/goneon/neon.go:19) MOVD R2, R0
0x00c4 00196 (/home/user/work/src/goneon/neon.go:19) MOVD $256, R1
0x00c8 00200 (/home/user/work/src/goneon/neon.go:19) PCDATA $1, $0
0x00c8 00200 (/home/user/work/src/goneon/neon.go:19) CALL runtime.panicIndex(SB)
0x00cc 00204 (/home/user/work/src/goneon/neon.go:14) MOVD R2, R0
0x00d0 00208 (/home/user/work/src/goneon/neon.go:14) MOVD $256, R1
0x00d4 00212 (/home/user/work/src/goneon/neon.go:14) CALL runtime.panicIndex(SB)
0x00d8 00216 (/home/user/work/src/goneon/neon.go:14) HINT $0
0x00dc 00220 (/home/user/work/src/goneon/neon.go:14) NOP
0x00dc 00220 (/home/user/work/src/goneon/neon.go:3) PCDATA $1, $-1
0x00dc 00220 (/home/user/work/src/goneon/neon.go:3) PCDATA $0, $-2
0x00dc 00220 (/home/user/work/src/goneon/neon.go:3) MOVD R30, R3
0x00e0 00224 (/home/user/work/src/goneon/neon.go:3) CALL runtime.morestack_noctxt(SB)
0x00e4 00228 (/home/user/work/src/goneon/neon.go:3) PCDATA $0, $-1
0x00e4 00228 (/home/user/work/src/goneon/neon.go:3) JMP 0
0x0000 90 0b 40 f9 f1 83 1e d1 3f 02 10 eb 89 06 00 54  ..@.....?......T
0x0010 f4 83 20 d1 9d fa 3f a9 9f 02 00 91 fd 23 00 d1  .. ...?......#..
0x0020 f4 63 10 91 9b 00 00 10 fd ef 3e a9 fd 63 00 d1  .c........>..c..
0x0030 00 00 00 94 fd 23 00 d1 f4 63 00 91 9b 00 00 10  .....#...c......
0x0040 fd ef 3e a9 fd 63 00 d1 00 00 00 94 fd 23 00 d1  ..>..c.......#..
0x0050 e0 03 1f aa 09 00 00 14 02 7c 7e 93 e3 63 10 91  .........|~..c..
0x0060 60 68 22 b8 e4 03 78 b2 85 00 00 cb e6 63 00 91  `h"...x......c..
0x0070 c5 68 22 b8 00 04 00 91 1f 00 04 71 aa 00 00 54  .h"........q...T
0x0080 02 7c 40 93 5f 00 04 f1 83 fe ff 54 10 00 00 14  .|@._......T....
0x0090 e0 03 1f aa 02 00 00 14 00 04 00 91 1f 00 04 71  ...............q
0x00a0 aa 00 00 54 02 7c 40 93 5f 00 04 f1 63 ff ff 54  ...T.|@._...c..T
0x00b0 04 00 00 14 fd fb 7f a9 ff 83 20 91 c0 03 5f d6  .......... ..._.
0x00c0 e0 03 02 aa e1 03 78 b2 00 00 00 94 e0 03 02 aa  ......x.........
0x00d0 e1 03 78 b2 00 00 00 94 1f 20 03 d5 e3 03 1e aa  ..x...... ......
0x00e0 00 00 00 94 c7 ff ff 17 00 00 00 00 00 00 00 00  ................
rel 48+4 t=9 runtime.duffzero+0
rel 72+4 t=9 runtime.duffzero+0
rel 200+4 t=9 runtime.panicIndex+0
rel 212+4 t=9 runtime.panicIndex+0
rel 224+4 t=9 runtime.morestack_noctxt+0
main.add STEXT size=240 args=0x0 locals=0x818 funcid=0x0 align=0x0
0x0000 00000 (/home/user/work/src/goneon/neon.go:7) TEXT main.add(SB), ABIInternal, $2080-0
0x0000 00000 (/home/user/work/src/goneon/neon.go:7) MOVD 16(g), R16
0x0004 00004 (/home/user/work/src/goneon/neon.go:7) PCDATA $0, $-2
0x0004 00004 (/home/user/work/src/goneon/neon.go:7) SUB $1952, RSP, R17
var symregexp = flag.String("s", "", "only dump symbols matching this regexp")
var gnuAsm = flag.Bool("gnu", false, "print GNU assembly next to Go assembly (where supported)")
var symRE *regexp.Regexp
0x0008 00008 (/home/user/work/src/goneon/neon.go:7) CMP R16, R17
0x000c 00012 (/home/user/work/src/goneon/neon.go:7) BLS 220
0x0010 00016 (/home/user/work/src/goneon/neon.go:7) PCDATA $0, $-1
0x0010 00016 (/home/user/work/src/goneon/neon.go:7) SUB $2080, RSP, R20
0x0014 00020 (/home/user/work/src/goneon/neon.go:7) STP (R29, R30), -8(R20)
0x0018 00024 (/home/user/work/src/goneon/neon.go:7) PCDATA $0, $-2
0x0018 00024 (/home/user/work/src/goneon/neon.go:7) MOVD R20, RSP
0x001c 00028 (/home/user/work/src/goneon/neon.go:7) PCDATA $0, $-1
0x001c 00028 (/home/user/work/src/goneon/neon.go:7) SUB $8, RSP, R29
0x0020 00032 (/home/user/work/src/goneon/neon.go:7) FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
0x0020 00032 (/home/user/work/src/goneon/neon.go:7) FUNCDATA $1, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
0x0020 00032 (/home/user/work/src/goneon/neon.go:9) MOVD $main..autotmp_5-1024(SP), R20
0x0024 00036 (/home/user/work/src/goneon/neon.go:9) PCDATA $0, $-2
0x0024 00036 (/home/user/work/src/goneon/neon.go:9) ADR 52, runtime.duffzero(R27)(R27)(REG)
0x0028 00040 (/home/user/work/src/goneon/neon.go:9) STP (R29, R27), -24(RSP)
0x002c 00044 (/home/user/work/src/goneon/neon.go:9) SUB $24, RSP, R29
0x0030 00048 (/home/user/work/src/goneon/neon.go:9) DUFFZERO runtime.duffzero(SB)
0x0034 00052 (/home/user/work/src/goneon/neon.go:9) SUB $8, RSP, R29
0x0038 00056 (/home/user/work/src/goneon/neon.go:10) PCDATA $0, $-1
0x0038 00056 (/home/user/work/src/goneon/neon.go:10) MOVD $main..autotmp_6-2048(SP), R20
0x003c 00060 (/home/user/work/src/goneon/neon.go:10) PCDATA $0, $-2
0x003c 00060 (/home/user/work/src/goneon/neon.go:10) ADR 76, runtime.duffzero(R27)(R27)(REG)
0x0040 00064 (/home/user/work/src/goneon/neon.go:10) STP (R29, R27), -24(RSP)
0x0044 00068 (/home/user/work/src/goneon/neon.go:10) SUB $24, RSP, R29
0x0048 00072 (/home/user/work/src/goneon/neon.go:10) DUFFZERO runtime.duffzero(SB)
0x004c 00076 (/home/user/work/src/goneon/neon.go:10) SUB $8, RSP, R29
0x0050 00080 (/home/user/work/src/goneon/neon.go:10) PCDATA $0, $-1
0x0050 00080 (/home/user/work/src/goneon/neon.go:10) MOVD ZR, R0
0x0054 00084 (/home/user/work/src/goneon/neon.go:13) JMP 120
0x0058 00088 (/home/user/work/src/goneon/neon.go:14) SBFIZ $2, R0, $32, R2
0x005c 00092 (/home/user/work/src/goneon/neon.go:14) MOVD $main..autotmp_5-1024(SP), R3
0x0060 00096 (/home/user/work/src/goneon/neon.go:14) MOVW R0, (R3)(R2)
0x0064 00100 (/home/user/work/src/goneon/neon.go:15) MOVD $256, R4
0x0068 00104 (/home/user/work/src/goneon/neon.go:15) SUB R0, R4, R5
0x006c 00108 (/home/user/work/src/goneon/neon.go:15) MOVD $main..autotmp_6-2048(SP), R6
0x0070 00112 (/home/user/work/src/goneon/neon.go:15) MOVW R5, (R6)(R2)
0x0074 00116 (/home/user/work/src/goneon/neon.go:13) ADD $1, R0, R0
0x0078 00120 (/home/user/work/src/goneon/neon.go:13) CMPW $256, R0
0x007c 00124 (/home/user/work/src/goneon/neon.go:13) BGE 144
0x0080 00128 (/home/user/work/src/goneon/neon.go:14) MOVW R0, R2
0x0084 00132 (/home/user/work/src/goneon/neon.go:14) CMP $256, R2
0x0088 00136 (/home/user/work/src/goneon/neon.go:14) BLO 88
0x008c 00140 (/home/user/work/src/goneon/neon.go:14) JMP 204
0x0090 00144 (/home/user/work/src/goneon/neon.go:14) MOVD ZR, R0
0x0094 00148 (/home/user/work/src/goneon/neon.go:13) JMP 156
0x0098 00152 (/home/user/work/src/goneon/neon.go:18) ADD $1, R0, R0
0x009c 00156 (/home/user/work/src/goneon/neon.go:18) CMPW $256, R0
0x00a0 00160 (/home/user/work/src/goneon/neon.go:18) BGE 180
0x00a4 00164 (/home/user/work/src/goneon/neon.go:19) MOVW R0, R2
0x00a8 00168 (/home/user/work/src/goneon/neon.go:19) CMP $256, R2
0x00ac 00172 (/home/user/work/src/goneon/neon.go:19) BLO 152
0x00b0 00176 (/home/user/work/src/goneon/neon.go:19) JMP 192
0x00b4 00180 (/home/user/work/src/goneon/neon.go:21) LDP -8(RSP), (R29, R30)
0x00b8 00184 (/home/user/work/src/goneon/neon.go:21) ADD $2080, RSP
0x00bc 00188 (/home/user/work/src/goneon/neon.go:21) RET (R30)
0x00c0 00192 (/home/user/work/src/goneon/neon.go:19) MOVD R2, R0
0x00c4 00196 (/home/user/work/src/goneon/neon.go:19) MOVD $256, R1
0x00c8 00200 (/home/user/work/src/goneon/neon.go:19) PCDATA $1, $0
0x00c8 00200 (/home/user/work/src/goneon/neon.go:19) CALL runtime.panicIndex(SB)
0x00cc 00204 (/home/user/work/src/goneon/neon.go:14) MOVD R2, R0
0x00d0 00208 (/home/user/work/src/goneon/neon.go:14) MOVD $256, R1
0x00d4 00212 (/home/user/work/src/goneon/neon.go:14) CALL runtime.panicIndex(SB)
0x00d8 00216 (/home/user/work/src/goneon/neon.go:14) HINT $0
0x00dc 00220 (/home/user/work/src/goneon/neon.go:14) NOP
0x00dc 00220 (/home/user/work/src/goneon/neon.go:7) PCDATA $1, $-1
0x00dc 00220 (/home/user/work/src/goneon/neon.go:7) PCDATA $0, $-2
0x00dc 00220 (/home/user/work/src/goneon/neon.go:7) MOVD R30, R3
0x00e0 00224 (/home/user/work/src/goneon/neon.go:7) CALL runtime.morestack_noctxt(SB)
0x00e4 00228 (/home/user/work/src/goneon/neon.go:7) PCDATA $0, $-1
0x00e4 00228 (/home/user/work/src/goneon/neon.go:7) JMP 0
0x0000 90 0b 40 f9 f1 83 1e d1 3f 02 10 eb 89 06 00 54  ..@.....?......T
0x0010 f4 83 20 d1 9d fa 3f a9 9f 02 00 91 fd 23 00 d1  .. ...?......#..
0x0020 f4 63 10 91 9b 00 00 10 fd ef 3e a9 fd 63 00 d1  .c........>..c..
0x0030 00 00 00 94 fd 23 00 d1 f4 63 00 91 9b 00 00 10  .....#...c......
0x0040 fd ef 3e a9 fd 63 00 d1 00 00 00 94 fd 23 00 d1  ..>..c.......#..
0x0050 e0 03 1f aa 09 00 00 14 02 7c 7e 93 e3 63 10 91  .........|~..c..
0x0060 60 68 22 b8 e4 03 78 b2 85 00 00 cb e6 63 00 91  `h"...x......c..
0x0070 c5 68 22 b8 00 04 00 91 1f 00 04 71 aa 00 00 54  .h"........q...T
0x0080 02 7c 40 93 5f 00 04 f1 83 fe ff 54 10 00 00 14  .|@._......T....
0x0090 e0 03 1f aa 02 00 00 14 00 04 00 91 1f 00 04 71  ...............q
0x00a0 aa 00 00 54 02 7c 40 93 5f 00 04 f1 63 ff ff 54  ...T.|@._...c..T
0x00b0 04 00 00 14 fd fb 7f a9 ff 83 20 91 c0 03 5f d6  .......... ..._.
0x00c0 e0 03 02 aa e1 03 78 b2 00 00 00 94 e0 03 02 aa  ......x.........
0x00d0 e1 03 78 b2 00 00 00 94 1f 20 03 d5 e3 03 1e aa  ..x...... ......
0x00e0 00 00 00 94 c7 ff ff 17 00 00 00 00 00 00 00 00  ................
rel 48+4 t=9 runtime.duffzero+0
rel 72+4 t=9 runtime.duffzero+0
rel 200+4 t=9 runtime.panicIndex+0
rel 212+4 t=9 runtime.panicIndex+0
rel 224+4 t=9 runtime.morestack_noctxt+0
go:cuinfo.producer.main SDWARFCUINFO dupok size=0
0x0000 72 65 67 61 62 69                                regabi
go:cuinfo.packagename.main SDWARFCUINFO dupok size=0
0x0000 6d 61 69 6e                                      main
go:info.main.add$abstract SDWARFABSFCN dupok size=45
0x0000 05 6d 61 69 6e 2e 61 64 64 00 01 01 0e 61 00 08  .main.add....a..
0x0010 00 00 00 00 0e 62 00 09 00 00 00 00 0e 63 00 0a  .....b.......c..
0x0020 00 00 00 00 0e 69 00 0c 00 00 00 00 00           .....i.......
rel 16+4 t=31 go:info.[]int32+0
rel 24+4 t=31 go:info.[]int32+0
rel 32+4 t=31 go:info.[]int32+0
rel 40+4 t=31 go:info.int32+0
main..inittask SNOPTRDATA size=24
0x0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x0010 00 00 00 00 00 00 00 00                          ........
type:.eqfunc1024 SRODATA dupok size=16
0x0000 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00  ................
rel 0+8 t=1 runtime.memequal_varlen+0
runtime.memequal64·f SRODATA dupok size=8
0x0000 00 00 00 00 00 00 00 00                          ........
rel 0+8 t=1 runtime.memequal64+0
runtime.gcbits.0100000000000000 SRODATA dupok size=8
0x0000 01 00 00 00 00 00 00 00                          ........
type:.namedata.*[256]int32- SRODATA dupok size=13
0x0000 00 0b 2a 5b 32 35 36 5d 69 6e 74 33 32           ..*[256]int32
type:*[256]int32 SRODATA dupok size=56
0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00  ................
0x0010 5c eb 0a 2f 08 08 08 36 00 00 00 00 00 00 00 00  \../...6........
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x0030 00 00 00 00 00 00 00 00                          ........
rel 24+8 t=1 runtime.memequal64·f+0
rel 32+8 t=1 runtime.gcbits.0100000000000000+0
rel 40+4 t=5 type:.namedata.*[256]int32-+0
rel 48+8 t=1 type:[256]int32+0
runtime.gcbits. SRODATA dupok size=0
type:[256]int32 SRODATA dupok size=72
0x0000 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x0010 1e 16 ae f5 0a 04 04 11 00 00 00 00 00 00 00 00  ................
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x0040 00 01 00 00 00 00 00 00                          ........
rel 24+8 t=1 type:.eqfunc1024+0
rel 32+8 t=1 runtime.gcbits.+0
rel 40+4 t=5 type:.namedata.*[256]int32-+0
rel 44+4 t=-32763 type:*[256]int32+0
rel 48+8 t=1 type:int32+0
rel 56+8 t=1 type:[]int32+0
gclocals·g2BeySu+wFnoycgXfElmcg== SRODATA dupok size=8
0x0000 01 00 00 00 00 00 00 00                          ........

 

go tool objdump를 통해 디스어셈블 하고 vadd를 찾으면 먼가 나오는데

위에서 테스트한 코드가 아니라 다른 어셈블리 코드의 것이 나온다.

go tool objdump tt | grep -i vadd
  indexbyte_arm64.s:61 0x11cc4 4e24bc66 VADDP V4.B16, V3.B16, V6.B16
  indexbyte_arm64.s:62 0x11cc8 4e26bcc6 VADDP V6.B16, V6.B16, V6.B16
  indexbyte_arm64.s:82 0x11cfc 4ee6bcc6 VADDP V6.D2, V6.D2, V6.D2
  indexbyte_arm64.s:91 0x11d10 4e24bc66 VADDP V4.B16, V3.B16, V6.B16
  indexbyte_arm64.s:92 0x11d14 4e26bcc6 VADDP V6.B16, V6.B16, V6.B16

 

경로와 파일명만 보면 arm64용 배열에 대한 내부 변환 알고리즘 같긴한데..

Text file src/internal/bytealg/indexbyte_arm64.s

[링크 : https://tip.golang.org/src/internal/bytealg/indexbyte_arm64.s]

 

그래서 그냥 디스어셈블 하니 87만 라인?

$ aarch64-linux-gnu-objdump -d tt > t2
$ wc -l t2
87170 t2

 

vadd로 검색하면 하나도 안나온다 -_-

$ aarch64-linux-gnu-objdump -d tt | grep -i vadd
$

 

그래서 된다고 봐야 하나 말아야 하나..

 

 

+

일단 실행시간으로 비교!

$ cat neon.go 
package main

func main() {
add()
}

func add() {
cnt := 10000000
a := make([]int32, cnt)
b := make([]int32, cnt)
c := make([]int32, cnt)

i := 0
for i = 0; i < cnt; i++ {
b[i] = int32(i);
c[i] = int32(cnt - i);
}

for i = 0; i < cnt; i++ {
a[i] = b[i] + c[i]
}
}

 

위의 소스로 테스트를 해보니 arm64가 좀 빨라지긴 한데... 미묘하네

/// GOARCH=arm go build -gcflags -S .
# time ./tt

real    0m0.196s
user    0m0.161s
sys     0m0.036s
/// GOARCH=arm64 go build -gcflags -S .
# time ./tt.aarch64 

real    0m0.162s
user    0m0.087s
sys     0m0.075s

 

 

+

c로 하려는데

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 void main()
  5 {
  6         int cnt = 10000000;
  7         int *a,*b,*c;
  8         a = malloc(sizeof(int) * cnt);
  9         b = malloc(sizeof(int) * cnt);
 10         c = malloc(sizeof(int) * cnt);
 11 
 12         for(int i = 0; i < cnt; i++)
 13         {
 14                 b[i] = i;
 15                 c[i] = cnt - i;
 16         }
 17 
 18         for(int i = 0; i < cnt; i++)
 19         {
 20                 a[i] = b[i] + c[i];
 21         }
 22 
 23         printf("%d %d %d\n",a[0],b[0],c[0]);
 24 
 25         return 0;
 26 }

 

아무래도 printf가 없어서 계산은 하지만 사용하지 않는(출력이 없어서) 그냥 최적화 옵션에서 제외해버리니까

결과에 대해서만 출력하도록 두고 해보니

$ aarch64-poky-linux-gcc --sysroot=/opt/fsl-imx-wayland/5.15-kirkstone/sysroots/armv8a-poky-linux -march=armv8-a -O3 -fopt-info-vec neon.c
neon.c:18:19: optimized: loop vectorized using 16 byte vectors
neon.c:12:19: optimized: loop vectorized using 16 byte vectors

 

음.. 0.213s라.. go가 오히려 빠른가 싶었는데, user space로 보면 그래도 c가 빠르긴 한 듯.

# time ./a.out 
10000000 0 10000000

real    0m0.213s
user    0m0.076s
sys     0m0.135s

 

다시 출력을 추가해서

  1 package main
  2 
  3 import "fmt"
  4 
  5 func main() {
  6         add()
  7 }
  8 
  9 func add() {
 10         cnt := 10000000
 11         a := make([]int32, cnt)
 12         b := make([]int32, cnt)
 13         c := make([]int32, cnt)
 14 
 15         i := 0
 16         for i = 0; i < cnt; i++ {
 17                 b[i] = int32(i);
 18                 c[i] = int32(cnt - i);
 19         }
 20 
 21         for i = 0; i < cnt; i++ {
 22                 a[i] = b[i] + c[i]
 23         }
 24 
 25         fmt.Println("neon");
 26         fmt.Println(a[0], b[0], c[0])
 27 }

 

실행해보니 0.204s go가 조금 더 빠르다? 그런데 희한할 정도로 sys가 짧은 건 왜일까?

# time ./neon
neon
10000000 0 10000000

real    0m0.204s
user    0m0.179s
sys     0m0.025s

 

혹시나 해서 c로 짠걸 neon 옵션 빼고(-O3) 해보니 속도 상으로는 맞는 듯?

# time ./a.out.none
10000000 0 10000000

real    0m0.699s
user    0m0.550s
sys     0m0.144s

 

'Programming > golang' 카테고리의 다른 글

go packed struct  (0) 2023.09.01
golang asm  (0) 2023.08.24
golang echo 서버 이상한 버그 발견?  (0) 2023.06.27
go ws server client example  (0) 2023.06.08
golang waitgroup  (0) 2023.05.24
Posted by 구차니
Programming/golang2023. 6. 27. 18:23

아래와 같이 staticweb을 띠우도록 하고 browse 기능을 켜면 되는데

e := echo.New()
e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
Root:   "html",
Browse: true,
}))

 

문제는 index.html이 있을 경우

index.html 와 같은 레벨에 있는 sub directory의 경우

들어가서 파일을 보면 경로가 이상하게 작동한다.

 

머 이런 개뼉다구 같은 버그가 -_-

 

+

2023.09.13

끝에 / 을 붙여주면 잘 된다.

예를 들어 html/test 라는 디렉토리가 있으면

localhost:5000/test 는 오작동하지만

localhost:5000/test/ 는 정상작동 한다.

directory면 trailing / 정도는 해주란 말이야... ㅠㅠ

 

'Programming > golang' 카테고리의 다른 글

golang asm  (0) 2023.08.24
golang goarch=arm64 와 디스어셈블러  (0) 2023.08.23
go ws server client example  (0) 2023.06.08
golang waitgroup  (0) 2023.05.24
golang echo server middleware  (0) 2023.05.24
Posted by 구차니
Programming/golang2023. 6. 8. 22:21

'Programming > golang' 카테고리의 다른 글

golang goarch=arm64 와 디스어셈블러  (0) 2023.08.23
golang echo 서버 이상한 버그 발견?  (0) 2023.06.27
golang waitgroup  (0) 2023.05.24
golang echo server middleware  (0) 2023.05.24
golang 동시성  (0) 2023.05.24
Posted by 구차니
Programming/golang2023. 5. 24. 16:10

고루틴이 종료되는 시점을 확인하는 방법으로 보면 되려나?

 

여러개의 고루틴을 종료할때 까지 기다리기 위해  wait gorup을 이용할 수 있다.

package main

import (
    "fmt"
    "sync"
    "time"
)

func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)

    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

func main() {

    var wg sync.WaitGroup

    for i := 1; i <= 5; i++ {
        wg.Add(1)

        i := i

        go func() {
            defer wg.Done()
            worker(i)
        }()
    }

    wg.Wait()

}

[링크 : https://gobyexample.com/waitgroups]

[링크 : https://pyrasis.com/book/GoForTheReallyImpatient/Unit35/06]

[링크 : https://pkg.go.dev/sync#WaitGroup.Add]

'Programming > golang' 카테고리의 다른 글

golang echo 서버 이상한 버그 발견?  (0) 2023.06.27
go ws server client example  (0) 2023.06.08
golang echo server middleware  (0) 2023.05.24
golang 동시성  (0) 2023.05.24
golang 고루틴과 채널  (0) 2023.05.16
Posted by 구차니
Programming/golang2023. 5. 24. 15:41

golang의 echo를 이용해서 웹서버 만드는건 쉬운데

서버 돌려 두면 별도의 go routine으로 돌테니 어떻게 구성을 해야

IPC를 통해 받은 변수를 깨지지 않게 처리할 수 있을까?

 

걍 결론은.. mutex로 귀결인가?

func (s *Stats) Handle(c echo.Context) error {
s.mutex.RLock()
defer s.mutex.RUnlock()
return c.JSON(http.StatusOK, s)
}

func main() {
e := echo.New()

// Debug mode
e.Debug = true

//-------------------
// Custom middleware
//-------------------
// Stats
s := NewStats()
e.Use(s.Process)
e.GET("/stats", s.Handle) // Endpoint to get stats

// Server header
e.Use(ServerHeader)

// Handler
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})

// Start server
e.Logger.Fatal(e.Start(":1323"))
}

[링크 : https://echo.labstack.com/cookbook/middleware/]

'Programming > golang' 카테고리의 다른 글

go ws server client example  (0) 2023.06.08
golang waitgroup  (0) 2023.05.24
golang 동시성  (0) 2023.05.24
golang 고루틴과 채널  (0) 2023.05.16
golang switch, select  (0) 2023.05.16
Posted by 구차니
Programming/golang2023. 5. 24. 15:38

atomic 패키지는 특정 변수의 값 증가등에 대해서 atomic operation 해주는 것 같고 copy는 없는 것 같고

sync.mutex가 역시 가장 무난한 선택인가 싶다.

channel은 내가 원하는 패키지에서 사용가능한 방법은 아난 것 같군..

 

atomic > mutex > channel

[링크 : https://woojinger.tistory.com/100]

[링크 : https://dev-yakuza.posstree.com/ko/golang/goroutine/]

[링크 : https://pkg.go.dev/sync/atomic]

'Programming > golang' 카테고리의 다른 글

golang waitgroup  (0) 2023.05.24
golang echo server middleware  (0) 2023.05.24
golang 고루틴과 채널  (0) 2023.05.16
golang switch, select  (0) 2023.05.16
golang uds  (0) 2023.05.16
Posted by 구차니
Programming/golang2023. 5. 16. 15:39

채널의 경우 1개로 해두면 하나가 들어갈 때 까지 해당 위치에서 블로킹 된다.

아래 예제는 받는 부분을 삭제했는데 그렇기에 채널을 통해 전송은 되지만 수신하지 않아 비워지지 않기 때문에

one을 출력하지 못하고 멈춰있는 것을 확인할 수 있다.

package main

import (
f "fmt"
"time"
)

func main() {

f.Println("select")

c1 := make(chan string)
c2 := make(chan string)

go func() {
time.Sleep(time.Second * 1)
f.Println("---")
c1 <- "one"
f.Println("one")
c1 <- "two"
f.Println("two")
c1 <- "three"
f.Println("three")
c1 <- "four"
f.Println("four")
}()

go func() {
time.Sleep(time.Second * 2)
c2 <- "fifth"
}()

for i := 0; i < 10000000000; i++ {
time.Sleep(time.Second)
}

}
$ go run go.go 
select
---
^Csignal: interrupt

 

다만, make를 통해 채널 버퍼를 n개로 만들어 두면, 넣을 수 있는 동안은 넣고 블로킹 되지 않고 넘어갈 수 있다.

package main

import (
f "fmt"
"time"
)

func main() {

f.Println("select")

c1 := make(chan string, 4)
c2 := make(chan string)

go func() {
time.Sleep(time.Second * 1)
f.Println("---")
c1 <- "one"
f.Println("one")
c1 <- "two"
f.Println("two")
c1 <- "three"
f.Println("three")
c1 <- "four"
f.Println("four")
}()

go func() {
time.Sleep(time.Second * 2)
c2 <- "fifth"
}()

for i := 0; i < 10000000000; i++ {
time.Sleep(time.Second)
}

}
$ go run go.go 
select
---
one
two
three
four
^Csignal: interrupt

 

[링크 : https://judo0179.tistory.com/88]

'Programming > golang' 카테고리의 다른 글

golang echo server middleware  (0) 2023.05.24
golang 동시성  (0) 2023.05.24
golang switch, select  (0) 2023.05.16
golang uds  (0) 2023.05.16
golang mutex (sync)  (0) 2023.05.16
Posted by 구차니
Programming/golang2023. 5. 16. 11:32

golang switch는 신형 언어에 확장되서 그런가 꽤나 만능이다.

특이하게 조건식도 가능하고, 케이스 리스트도 된다.(c#에서 얼핏 봤던 느낌..)

package main

import (
"fmt"
"time"
)

func main() {
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
}

[링크 :https://go.dev/tour/flowcontrol/11]

 

func WhiteSpace(c rune) bool {
switch c {
case ' ', '\t', '\n', '\f', '\r':
return true
}
return false
}

[링크 : https://hamait.tistory.com/1017]

 

아무튼 select는 channel 처리에 좀더 특화된 구문으로 생긴것 자체는 switch - case와 동일하게 작성된다.

다만, 동시에 여러개가 들어왔을 경우 랜덤하게 실행된다고 한다.

(생각이 꼬였는지 동시에 들어오면 가장 위에꺼 부터 실행되어야 하는거 아냐? 싶은데 동시성이니까 랜덤하게 처리되는건가..)

The select statement lets a goroutine wait on multiple communication operations.

A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.

 

package main

import "fmt"

func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}

func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}

[링크 : https://go.dev/tour/concurrency/5]

 

[링크 : https://edu.goorm.io/learn/lecture/2010/한-눈에-끝내는-고랭-기초/lesson/382961/채널-select문]

 

'Programming > golang' 카테고리의 다른 글

golang 동시성  (0) 2023.05.24
golang 고루틴과 채널  (0) 2023.05.16
golang uds  (0) 2023.05.16
golang mutex (sync)  (0) 2023.05.16
go 포맷터  (0) 2023.05.11
Posted by 구차니
Programming/golang2023. 5. 16. 10:46

쓸만하려나?

server client
package main

import (
"fmt"
"log"
"os"
"path/filepath"
"time"

"github.com/google/uuid"
"github.com/johnsiilver/golib/ipc/uds"
)

func main() {
socketAddr := filepath.Join(os.TempDir(), uuid.New().String())

cred, _, err := uds.Current()
if err != nil {
panic(err)
}

// This will set the socket file to have a uid and gid of whatever the
// current user is. 0770 will be set for the file permissions (though on some
// systems the sticky bit gets set, resulting in 1770.
serv, err := uds.NewServer(socketAddr, cred.UID.Int(), cred.GID.Int(), 0770)
if err != nil {
panic(err)
}

fmt.Println("Listening on socket: ", socketAddr)

// This listens for a client connecting and returns the connection object.
for conn := range serv.Conn() {
conn := conn

// We spinoff handling of this connection to its own goroutine and
// go back to listening for another connection.
go func() {
// We are checking the client's user ID to make sure its the same
// user ID or we reject it. Cred objects give you the user's
// uid/gid/pid for filtering.
if conn.Cred.UID.Int() != cred.UID.Int() {
log.Printf("unauthorized user uid %d attempted a connection", conn.Cred.UID.Int())
conn.Close()
return
}
// Write to the stream every 10 seconds until the connection closes.
for {
if _, err := conn.Write([]byte(fmt.Sprintf("%s\n", time.Now().UTC()))); err != nil {
conn.Close()
}
time.Sleep(10 * time.Second)
}
}()
}
}
package main

import (
"flag"
"fmt"
"io"
"os"

"github.com/johnsiilver/golib/ipc/uds"
)

var (
addr = flag.String("addr", "", "The path to the unix socket to dial")
)

func main() {
flag.Parse()

if *addr == "" {
fmt.Println("did not pass --addr")
os.Exit(1)
}

cred, _, err := uds.Current()
if err != nil {
panic(err)
}

// Connects to the server at socketAddr that must have the file uid/gid of
// our current user and one of the os.FileMode specified.
client, err := uds.NewClient(*addr, cred.UID.Int(), cred.GID.Int(), []os.FileMode{0770, 1770})
if err != nil {
fmt.Println(err)
os.Exit(1)
}

// client implements io.ReadWriteCloser and this will print to the screen
// whatever the server sends until the connection is closed.
io.Copy(os.Stdout, client)
}

[링크 : https://github.com/johnsiilver/golib/blob/v1.1.2/ipc/uds/example/server/server.go]

[링크 : https://github.com/johnsiilver/golib/blob/v1.1.2/ipc/uds/example/client/client.go]

[링크 : https://pkg.go.dev/github.com/johnsiilver/golib/ipc/uds]

'Programming > golang' 카테고리의 다른 글

golang 고루틴과 채널  (0) 2023.05.16
golang switch, select  (0) 2023.05.16
golang mutex (sync)  (0) 2023.05.16
go 포맷터  (0) 2023.05.11
golang echo directory listing  (0) 2023.05.08
Posted by 구차니
Programming/golang2023. 5. 16. 10:36

 

package main

import (
"fmt"
"sync"
"time"
)

// SafeCounter is safe to use concurrently.
type SafeCounter struct {
mu sync.Mutex
v  map[string]int
}

// Inc increments the counter for the given key.
func (c *SafeCounter) Inc(key string) {
c.mu.Lock()
// Lock so only one goroutine at a time can access the map c.v.
c.v[key]++
c.mu.Unlock()
}

// Value returns the current value of the counter for the given key.
func (c *SafeCounter) Value(key string) int {
c.mu.Lock()
// Lock so only one goroutine at a time can access the map c.v.
defer c.mu.Unlock()
return c.v[key]
}

func main() {
c := SafeCounter{v: make(map[string]int)}
for i := 0; i < 1000; i++ {
go c.Inc("somekey")
}

time.Sleep(time.Second)
fmt.Println(c.Value("somekey"))
}

[링크 : https://go.dev/tour/concurrency/9]

 

func (*Mutex) Lock ¶
func (m *Mutex) Lock()
Lock locks m. If the lock is already in use, the calling goroutine blocks until the mutex is available.

func (*Mutex) TryLock ¶
added in go1.18
func (m *Mutex) TryLock() bool
TryLock tries to lock m and reports whether it succeeded.

Note that while correct uses of TryLock do exist, they are rare, and use of TryLock is often a sign of a deeper problem in a particular use of mutexes.

func (*Mutex) Unlock ¶
func (m *Mutex) Unlock()
Unlock unlocks m. It is a run-time error if m is not locked on entry to Unlock.

A locked Mutex is not associated with a particular goroutine. It is allowed for one goroutine to lock a Mutex and then arrange for another goroutine to unlock it.

[링크 : https://pkg.go.dev/sync#Mutex.Lock]

 

[링크 : https://mingrammer.com/gobyexample/mutexes/]

[링크 : https://www.joinc.co.kr/w/GoLang/example/mutexex]

[링크 : https://pyrasis.com/book/GoForTheReallyImpatient/Unit35]

 

'Programming > golang' 카테고리의 다른 글

golang switch, select  (0) 2023.05.16
golang uds  (0) 2023.05.16
go 포맷터  (0) 2023.05.11
golang echo directory listing  (0) 2023.05.08
golang websocket binary  (0) 2023.03.28
Posted by 구차니