diff --git a/cmd/gasm/main.go b/cmd/gasm/main.go index 63dbe0e..4aba239 100644 --- a/cmd/gasm/main.go +++ b/cmd/gasm/main.go @@ -459,7 +459,7 @@ hover, document symbols, diagnostics and semantic-token highlighting. } func cmdAsm(args []string) int { - fs := newCommand("asm", "gasm asm [--format raw|elf|goobj] [-p pkg] [-o out] ", ` + fs := newCommand("asm", "gasm asm [--format raw|elf|goobj] [-p pkg] [-GOARCH arch] [-o out] ", ` Assemble FILE without the Go toolchain: every TEXT function is encoded to machine code and printed as a hex dump. Supported architectures: amd64 (including VEX/AVX2 and EVEX/AVX-512), arm64 (AArch64 integer, FP, @@ -477,13 +477,22 @@ requires -p, the package path, and the installed Go toolchain). out := fs.String("o", "", "write the output to this file") format := fs.String("format", "raw", "output format: raw (concatenated image), elf or goobj (Go object)") pkg := fs.String("p", "", "package path for --format goobj (qualifies the exported symbols)") + archName := fs.String("GOARCH", "", "target architecture: amd64, arm64, riscv64 or loong64 (overrides the file-name suffix)") fs.Parse(args) if fs.NArg() != 1 { - fmt.Fprintln(os.Stderr, "usage: gasm asm [--format raw|elf|goobj] [-p pkg] [-o out] ") + fmt.Fprintln(os.Stderr, "usage: gasm asm [--format raw|elf|goobj] [-p pkg] [-GOARCH arch] [-o out] ") return 2 } path := fs.Arg(0) targetArch := arch.FromFilename(path) + if *archName != "" { + a, err := auditArch(*archName) + if err != nil { + fmt.Fprintf(os.Stderr, "gasm asm: %v\n", err) + return 2 + } + targetArch = a + } src, err := readSource(path) if err != nil { fmt.Fprintln(os.Stderr, "gasm:", err) @@ -594,7 +603,7 @@ requires -p, the package path, and the installed Go toolchain). // cmdDiff compares the machine code of two assembly files. func cmdDiff(args []string) int { - set := newCommand("diff", "gasm diff ", ` + set := newCommand("diff", "gasm diff [-GOARCH arch] ", ` Compare the machine code produced by assembling two files. Shows which functions differ and the byte-level differences. Useful for verifying that two implementations produce identical code, @@ -604,12 +613,22 @@ Use --map to compare functions whose names differ between the files, e.g. --map wideCopyAVX2=wideCopyAVX512 pairs the two regardless of suffix. `) mapSpec := set.String("map", "", "comma-separated old=new pairs to match functions with different names") + archName := set.String("GOARCH", "", "target architecture for both files: amd64, arm64, riscv64 or loong64") set.Parse(args) if set.NArg() != 2 { - fmt.Fprintln(os.Stderr, "usage: gasm diff ") + fmt.Fprintln(os.Stderr, "usage: gasm diff [-GOARCH arch] ") return 2 } path1, path2 := set.Arg(0), set.Arg(1) + forced := arch.Unknown + if *archName != "" { + a, err := auditArch(*archName) + if err != nil { + fmt.Fprintf(os.Stderr, "gasm diff: %v\n", err) + return 2 + } + forced = a + } // Parse the name mapping (file1 name → file2 name). nameMap := make(map[string]string) @@ -625,12 +644,12 @@ e.g. --map wideCopyAVX2=wideCopyAVX512 pairs the two regardless of suffix. } // Assemble both files. - img1, err := assemblePath(path1) + img1, err := assemblePath(path1, forced) if err != nil { fmt.Fprintf(os.Stderr, "gasm diff: %s: %v\n", path1, err) return 1 } - img2, err := assemblePath(path2) + img2, err := assemblePath(path2, forced) if err != nil { fmt.Fprintf(os.Stderr, "gasm diff: %s: %v\n", path2, err) return 1 @@ -705,8 +724,9 @@ func assembleFile(targetArch arch.Arch, f *ast.File) (*asm.Image, error) { } } -// assemblePath reads, parses and assembles a file (used by cmdDiff). -func assemblePath(path string) (*asm.Image, error) { +// assemblePath reads, parses and assembles a file (used by cmdDiff). A +// non-Unknown forced architecture overrides the file-name suffix. +func assemblePath(path string, forced arch.Arch) (*asm.Image, error) { src, err := readSource(path) if err != nil { return nil, err @@ -718,7 +738,11 @@ func assemblePath(path string) (*asm.Image, error) { if len(errs) > 0 { return nil, fmt.Errorf("parse errors") } - return assembleFile(arch.FromFilename(path), f) + target := forced + if target == arch.Unknown { + target = arch.FromFilename(path) + } + return assembleFile(target, f) } // printByteDiff shows the first few byte differences between two code blocks. diff --git a/docs/CLI.md b/docs/CLI.md index af854df..ec72e51 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -134,18 +134,21 @@ gasm lint kernel_amd64.s ## asm ```text -Usage: gasm asm [--format raw|elf|goobj] [-p pkg] [-o out] +Usage: gasm asm [--format raw|elf|goobj] [-p pkg] [-GOARCH arch] [-o out] ``` | Flag | Default | Effect | |---|---|---| | `-format` | `raw` | output format: `raw` (concatenated image), `elf` or `goobj` (Go object) | | `-p` | empty | package path for `--format goobj`, qualifying the exported symbols | +| `-GOARCH` | empty | target architecture: `amd64`, `arm64`, `riscv64` or `loong64`; overrides the file-name suffix | | `-o` | empty | write the output to this file instead of a hex dump on stdout | Supported architectures: amd64 (VEX/AVX2 and EVEX/AVX-512 included), arm64, -riscv64 (RV64IMAFDC and RVC) and loong64, selected from the file's `_arch.s` -suffix. `raw` concatenates the functions and the data section into one +riscv64 (RV64IMAFDC and RVC) and loong64, taken from the file's `_arch.s` +suffix or from `-GOARCH`, which is how files whose names carry no +recognisable suffix (most of GOROOT's, for example `cpu_x86.s`) are +assembled. `raw` concatenates the functions and the data section into one self-consistent image; `elf` emits a relocatable object that links with the system toolchain; `goobj` emits the Go toolchain's own object format, which `cmd/link` consumes directly. @@ -292,11 +295,12 @@ gasm debug --func add --cover hello_amd64.s ## diff ```text -Usage: gasm diff +Usage: gasm diff [-GOARCH arch] ``` | Flag | Default | Effect | |---|---|---| +| `-GOARCH` | empty | target architecture for both files, overriding the file-name suffixes | | `-map` | empty | comma-separated `old=new` pairs to match functions with different names | Functions are paired by exact name unless `--map` says otherwise, so