{"id":13722616,"url":"https://github.com/minio/c2goasm","last_synced_at":"2025-09-26T22:31:33.426Z","repository":{"id":45927035,"uuid":"86103984","full_name":"minio/c2goasm","owner":"minio","description":"C to Go Assembly","archived":true,"fork":false,"pushed_at":"2021-11-27T14:34:32.000Z","size":175,"stargazers_count":1298,"open_issues_count":12,"forks_count":108,"subscribers_count":50,"default_branch":"master","last_synced_at":"2024-04-14T12:06:00.083Z","etag":null,"topics":["asm","clang","gcc","go","golang","llvm","plan9","runtime"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/minio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-24T19:30:35.000Z","updated_at":"2024-04-03T10:38:52.000Z","dependencies_parsed_at":"2022-09-13T08:12:22.853Z","dependency_job_id":null,"html_url":"https://github.com/minio/c2goasm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minio%2Fc2goasm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minio%2Fc2goasm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minio%2Fc2goasm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minio%2Fc2goasm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/minio","download_url":"https://codeload.github.com/minio/c2goasm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234356506,"owners_count":18819378,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asm","clang","gcc","go","golang","llvm","plan9","runtime"],"created_at":"2024-08-03T01:01:30.885Z","updated_at":"2025-09-26T22:31:33.096Z","avatar_url":"https://github.com/minio.png","language":"Go","readme":"# c2goasm: C to Go Assembly \n\n## Introduction\n\nThis is a tool to convert assembly as generated by a C/C++ compiler into Golang assembly. It is meant to be used in combination with [asm2plan9s](https://github.com/minio/asm2plan9s) in order to automatically generate pure Go wrappers for C/C++ code (that may for instance take advantage of compiler SIMD intrinsics or `template\u003c\u003e` code).\n\nMode of operation:\n```\n$ c2goasm -a /path/to/some/great/c-code.s /path/to/now/great/golang-code_amd64.s\n```\n\nYou can optionally nicely format the code using [asmfmt](https://github.com/klauspost/asmfmt) by passing in an `-f` flag. \n\nThis project has been developed as part of developing a Go wrapper around [Simd](https://github.com/fwessels/go-cv-simd). However it should also work with other projects and libraries. Keep in mind though that it is not intented to 'port' a complete C/C++ project in a single action but rather do it on a case-by-case basis per function/source file (and create accompanying high level Go code to call into the assembly code).\n\n## Command line options\n```\n$ c2goasm --help\nUsage of c2goasm:\n  -a\tImmediately invoke asm2plan9s\n  -c\tCompact byte codes\n  -f\tFormat using asmfmt\n  -s\tStrip comments\n```\n\n## A simple example\n\nHere is a simple C function doing an AVX2 intrinsics computation:\n```\nvoid MultiplyAndAdd(float* arg1, float* arg2, float* arg3, float* result) {\n    __m256 vec1 = _mm256_load_ps(arg1);\n    __m256 vec2 = _mm256_load_ps(arg2);\n    __m256 vec3 = _mm256_load_ps(arg3);\n    __m256 res  = _mm256_fmadd_ps(vec1, vec2, vec3);\n    _mm256_storeu_ps(result, res);\n}\n```\n\nCompiling into assembly gives the following\n```\n__ZN14MultiplyAndAddEPfS1_S1_S1_: ## @_ZN14MultiplyAndAddEPfS1_S1_S1_\n## BB#0:\n        push          rbp\n        mov           rbp, rsp\n        vmovups       ymm0, ymmword ptr [rdi]\n        vmovups       ymm1, ymmword ptr [rsi]\n        vfmadd213ps   ymm1, ymm0, ymmword ptr [rdx]\n        vmovups       ymmword ptr [rcx], ymm1\n        pop           rbp\n        vzeroupper\n        ret\n```\n\nRunning `c2goasm` will generate the following Go assembly (eg. saved in `MultiplyAndAdd_amd64.s`)\n```\n//+build !noasm !appengine\n// AUTO-GENERATED BY C2GOASM -- DO NOT EDIT\n\nTEXT ·_MultiplyAndAdd(SB), $0-32\n\n\tMOVQ vec1+0(FP), DI\n\tMOVQ vec2+8(FP), SI\n\tMOVQ vec3+16(FP), DX\n\tMOVQ result+24(FP), CX\n\n\tLONG $0x0710fcc5             // vmovups    ymm0, yword [rdi]\n\tLONG $0x0e10fcc5             // vmovups    ymm1, yword [rsi]\n\tLONG $0xa87de2c4; BYTE $0x0a // vfmadd213ps    ymm1, ymm0, yword [rdx]\n\tLONG $0x0911fcc5             // vmovups    yword [rcx], ymm1\n\n\tVZEROUPPER\n\tRET\n```\n\nThis needs to be accompanied by the following Go code (in `MultiplyAndAdd_amd64.go`)\n```\n//go:noescape\nfunc _MultiplyAndAdd(vec1, vec2, vec3, result unsafe.Pointer)\n\nfunc MultiplyAndAdd(someObj Object) {\n\n\t_MultiplyAndAdd(someObj.GetVec1(), someObj.GetVec2(), someObj.GetVec3(), someObj.GetResult()))\n}\n```\n\nAnd as you may have gathered the amd64.go file needs to be in place in order for the arguments names to be derived (and allow `go vet` to succeed).\n\n## Benchmark against cgo\n\nWe have run benchmarks of `c2goasm` versus `cgo` for both Go version 1.7.5 and 1.8.1. You can find the `c2goasm` benchmark test in `test/` and the `cgo` test in `cgocmp/` respectively. Here are the results for both versions:\n```\n$ benchcmp ../cgocmp/cgo-1.7.5.out c2goasm.out \nbenchmark                      old ns/op     new ns/op     delta\nBenchmarkMultiplyAndAdd-12     382           10.9          -97.15%\n```\n```\n$ benchcmp ../cgocmp/cgo-1.8.1.out c2goasm.out \nbenchmark                      old ns/op     new ns/op     delta\nBenchmarkMultiplyAndAdd-12     236           10.9          -95.38%\n```\n\nAs you can see Golang 1.8 has made a significant improvement (38.2%) over 1.7.5, but it is still about 20x slower than directly calling into assembly code as wrapped by `c2goasm`.\n\n## Converted projects\n\n- [go-cv-simd (WIP)](https://github.com/fwessels/go-cv-simd)\n\n## Internals\n\nThe basic process is to (in the prologue) setup the stack and registers as how the C code expects this to be the case, and upon exiting the subroutine (in the epilogue) to revert back to the golang world and pass a return value back if required. In more details:\n- Define assembly subroutine with proper golang decoration in terms of needed stack space and overall size of arguments plus return value. \n- Function arguments are loaded from the golang stack into registers and prior to starting the C code any arguments beyond 6 are stored in C stack space.\n- Stack space is reserved and setup for the C code. Depending on the C code, the stack pointer maybe aligned on a certain boundary (especially needed for code that takes advantages of SIMD instructions such as AVX etc.).\n- A constants table is generated (if needed) and any `rip`-based references are replaced with proper offsets to where Go will put the table. \n\n## Limitations\n\n- Arguments need (for now) to be 64-bit size, meaning either a value or a pointer (this requirement will be lifted)\n- Maximum number of 14 arguments (hard limit -- if you hit this maybe you should rethink your api anyway...)\n- Generally no `call` statements (thus inline your C code) with a couple of exceptions for functions such as `memset` and `memcpy` (see `clib_amd64.s`)\n\n## Generate assembly from C/C++\n\nFor eg. projects using cmake, here is how to see a list of assembly targets\n```\n$ make help | grep \"\\.s\"\n```\n\nTo see the actual command to generate the assembly\n```\n$ make -n SimdAvx2BgraToGray.s\n```\n\n## Supported golang architectures\n\nFor now just the AMD64 architecture is supported. Also ARM64 should work just fine in a similar fashion but support is lacking at the moment.\n\n## Compatible compilers\n\nThe following compilers have been tested:\n- `clang` (Apple LLVM version) on OSX/darwin\n- `clang` on linux\n\nCompiler flags:\n```\n-masm=intel -mno-red-zone -mstackrealign -mllvm -inline-threshold=1000 -fno-asynchronous-unwind-tables -fno-exceptions -fno-rtti\n```\n\n| Flag                              | Explanation                                        |\n|:----------------------------------| :--------------------------------------------------|\n| `-masm=intel`                     | Output Intel syntax for assembly                   |\n| `-mno-red-zone`                   | Do not write below stack pointer (avoid [red zone](https://en.wikipedia.org/wiki/Red_zone_(computing)))  |\n| `-mstackrealign`                  | Use explicit stack initialization                  |\n| `-mllvm -inline-threshold=1000`   | Higher limit for inlining heuristic (default=255)  |\n| `-fno-asynchronous-unwind-tables` | Do not generate unwind tables (for debug purposes) |\n| `-fno-exceptions`                 | Disable exception handling                         |\n| `-fno-rtti`                       | Disable run-time type information                  |\n\nThe following flags are only available in `clang -cc1` frontend mode (see [below]()):\n\n| Flag                              | Explanation                                                        |\n|:----------------------------------| :------------------------------------------------------------------|\n| `-fno-jump-tables`                | Do not use jump tables as may be generated for `select` statements |\n\n#### `clang` vs `clang -cc1` \n\nAs per the clang [FAQ](https://clang.llvm.org/docs/FAQ.html#driver), `clang -cc1` is the frontend, and `clang` is a (mostly GCC compatible) driver for the frontend. To see all options that the driver passes on to the frontend, use `-###` like this:\n\n```\n$ clang -### -c hello.c\n\"/usr/lib/llvm/bin/clang\" \"-cc1\" \"-triple\" \"x86_64-pc-linux-gnu\" etc. etc. etc.\n```\n\n#### Command line flags for clang\n\nTo see all command line flags use either `clang --help` or `clang --help-hidden` for the clang driver or `clang -cc1 -help` for the frontend.\n\n#### Further optimization and fine tuning\n\nUsing the LLVM optimizer ([opt](http://llvm.org/docs/CommandGuide/opt.html)) you can further optimize the code generation. Use `opt -help` or `opt -help-hidden` for all available options.\n\nAn option can be passed in via `clang` using the `-mllvm \u003cvalue\u003e` option, such as `-mllvm -inline-threshold=1000` as discussed above.\n\nAlso LLVM allows you to tune specific functions via [function attributes](http://llvm.org/docs/LangRef.html#function-attributes) like `define void @f() alwaysinline norecurse { ... }`.\n\n#### What about GCC support?\n\nFor now GCC code will not work out of the box. However there is no reason why GCC should not work fundamentally (PRs are welcome).\n\n## Resources\n\n- [A Primer on Go Assembly](https://github.com/teh-cmc/go-internals/blob/master/chapter1_assembly_primer/README.md)\n- [Go Function in Assembly](https://github.com/golang/go/files/447163/GoFunctionsInAssembly.pdf)\n- [Stack frame layout on x86-64](http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64)\n- [Compiler Explorer (interactive)](https://go.godbolt.org/)\n\n## License\n\nc2goasm is released under the Apache License v2.0. You can find the complete text in the file LICENSE.\n\n## Contributing\n\nContributions are welcome, please send PRs for any enhancements.\n","funding_links":[],"categories":["Assembly","Tools"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminio%2Fc2goasm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fminio%2Fc2goasm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminio%2Fc2goasm/lists"}