ardump: todo

This commit is contained in:
xushiwei
2024-04-19 13:29:56 +08:00
parent 6463e2cc2a
commit 4f5a656a9f
8 changed files with 405 additions and 12 deletions

52
chore/ardump/ardump.go Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"fmt"
"log"
"os"
"github.com/goplus/llgo/x/ar"
)
func main() {
if len(os.Args) != 2 {
fmt.Fprintln(os.Stderr, "Usage: ardump xxx.a")
return
}
f, err := os.Open(os.Args[1])
check(err)
defer f.Close()
r := ar.NewReader(f)
for {
hdr, err := r.Next()
if err != nil {
log.Println(err)
break
}
fmt.Println("==>", hdr.Name)
}
}
func check(err error) {
if err != nil {
panic(err)
}
}

1
go.mod
View File

@@ -4,7 +4,6 @@ go 1.18
require (
github.com/aykevl/go-wasm v0.0.1
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/goplus/gop v1.2.6
github.com/goplus/llvm v0.7.1-0.20240418160956-6233231cbcc9
github.com/qiniu/x v1.13.10

10
go.sum
View File

@@ -1,19 +1,9 @@
github.com/aykevl/go-wasm v0.0.1 h1:lPxy8l48P39W7I0tLrtCrLfZBOUq9IWZ7odGdyJP2AM=
github.com/aykevl/go-wasm v0.0.1/go.mod h1:b4nggwg3lEkNKOU4wzhtLKz2q2sLxSHFnc98aGt6z/Y=
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/goplus/gogen v1.15.2 h1:Q6XaSx/Zi5tWnjfAziYsQI6Jv6MgODRpFtOYqNkiiqM=
github.com/goplus/gogen v1.15.2/go.mod h1:92qEzVgv7y8JEFICWG9GvYI5IzfEkxYdsA1DbmnTkqk=
github.com/goplus/gop v1.2.6 h1:kog3c5Js+8EopqmI4+CwueXsqibnBwYVt5q5N7juRVY=
github.com/goplus/gop v1.2.6/go.mod h1:uREWbR1MrFaviZ4Mbx4ZCcAYDoqzO0iv1Qo6Np0Xx4E=
github.com/goplus/llvm v0.7.0 h1:b8XzmRA97U0V0BPSaYuZ2vw+lLO2JSpRLMtR6dAenIo=
github.com/goplus/llvm v0.7.0/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
github.com/goplus/llvm v0.7.1-0.20240417171659-4fb15c5dc82a h1:pKOqI/f4lyPAlto2MT0JJsDCNMvRyF8jBT2saegwIK8=
github.com/goplus/llvm v0.7.1-0.20240417171659-4fb15c5dc82a/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
github.com/goplus/llvm v0.7.1-0.20240418070213-5013f6a4299b h1:sRVmYXGgKjqgaoVQ1bshnw9Ar77stDtjHC4A/PDJ0fk=
github.com/goplus/llvm v0.7.1-0.20240418070213-5013f6a4299b/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
github.com/goplus/llvm v0.7.1-0.20240418094455-718cc880283b h1:vSEAK8m49NUX0YKyF+7m/wAkrRe8pf94PfFmJ/5+xKo=
github.com/goplus/llvm v0.7.1-0.20240418094455-718cc880283b/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
github.com/goplus/llvm v0.7.1-0.20240418160956-6233231cbcc9 h1:E/NBN5tDh6COcJmygdBb9RAJhE4uIHfT51VBlP3tglU=
github.com/goplus/llvm v0.7.1-0.20240418160956-6233231cbcc9/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
github.com/goplus/mod v0.13.10 h1:5Om6KOvo31daN7N30kWU1vC5zhsJPM+uPbcEN/FnlzE=

View File

@@ -29,7 +29,7 @@ import (
"time"
wasm "github.com/aykevl/go-wasm"
"github.com/blakesmith/ar"
"github.com/goplus/llgo/x/ar"
)
// Create creates an arcive for static linking from a list of object files

43
x/ar/common.go Normal file
View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ar
import (
"time"
)
const (
headerByteSize = 60
globalHeader = "!<arch>\n"
)
type Header struct {
Name string
ModTime time.Time
Uid int
Gid int
Mode int64
Size int64
}
type slicer []byte
func (sp *slicer) next(n int) (b []byte) {
s := *sp
b, *sp = s[0:n], s[n:]
return
}

148
x/ar/reader.go Normal file
View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ar
import (
"io"
"strconv"
"time"
)
// Provides read access to an ar archive.
// Call next to skip files
//
// Example:
// reader := NewReader(f)
// var buf bytes.Buffer
// for {
// _, err := reader.Next()
// if err == io.EOF {
// break
// }
// if err != nil {
// t.Errorf(err.Error())
// }
// io.Copy(&buf, reader)
// }
type Reader struct {
r io.Reader
nb int64
pad int64
}
// Copies read data to r. Strips the global ar header.
func NewReader(r io.Reader) *Reader {
io.CopyN(io.Discard, r, 8) // Discard global header
return &Reader{r: r}
}
func (rd *Reader) string(b []byte) string {
i := len(b) - 1
for i > 0 && b[i] == 32 {
i--
}
return string(b[0 : i+1])
}
func (rd *Reader) numeric(b []byte) int64 {
i := len(b) - 1
for i > 0 && b[i] == 32 {
i--
}
n, _ := strconv.ParseInt(string(b[0:i+1]), 10, 64)
return n
}
func (rd *Reader) octal(b []byte) int64 {
i := len(b) - 1
for i > 0 && b[i] == 32 {
i--
}
n, _ := strconv.ParseInt(string(b[3:i+1]), 8, 64)
return n
}
func (rd *Reader) skipUnread() error {
skip := rd.nb + rd.pad
rd.nb, rd.pad = 0, 0
if seeker, ok := rd.r.(io.Seeker); ok {
_, err := seeker.Seek(skip, io.SeekCurrent)
return err
}
_, err := io.CopyN(io.Discard, rd.r, skip)
return err
}
func (rd *Reader) readHeader() (*Header, error) {
headerBuf := make([]byte, headerByteSize)
if _, err := io.ReadFull(rd.r, headerBuf); err != nil {
return nil, err
}
header := new(Header)
s := slicer(headerBuf)
header.Name = rd.string(s.next(16))
header.ModTime = time.Unix(rd.numeric(s.next(12)), 0)
header.Uid = int(rd.numeric(s.next(6)))
header.Gid = int(rd.numeric(s.next(6)))
header.Mode = rd.octal(s.next(8))
header.Size = rd.numeric(s.next(10))
rd.nb = int64(header.Size)
if header.Size%2 == 1 {
rd.pad = 1
} else {
rd.pad = 0
}
return header, nil
}
// Call Next() to skip to the next file in the archive file.
// Returns a Header which contains the metadata about the
// file in the archive.
func (rd *Reader) Next() (*Header, error) {
err := rd.skipUnread()
if err != nil {
return nil, err
}
return rd.readHeader()
}
// Read data from the current entry in the archive.
func (rd *Reader) Read(b []byte) (n int, err error) {
if rd.nb == 0 {
return 0, io.EOF
}
if int64(len(b)) > rd.nb {
b = b[0:rd.nb]
}
n, err = rd.r.Read(b)
rd.nb -= int64(n)
return
}

121
x/ar/writer.go Normal file
View File

@@ -0,0 +1,121 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ar
import (
"errors"
"io"
"strconv"
)
var (
errWriteTooLong = errors.New("ar: write too long")
)
// Writer provides sequential writing of an ar archive.
// An ar archive is sequence of header file pairs
// Call WriteHeader to begin writing a new file, then call Write to supply the file's data
//
// Example:
// archive := ar.NewWriter(writer)
// archive.WriteGlobalHeader()
// header := new(ar.Header)
// header.Size = 15 // bytes
//
// if err := archive.WriteHeader(header); err != nil {
// return err
// }
//
// io.Copy(archive, data)
type Writer struct {
w io.Writer
nb int64 // number of unwritten bytes for the current file entry
}
// Create a new ar writer that writes to w
func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
func (aw *Writer) numeric(b []byte, x int64) {
s := strconv.FormatInt(x, 10)
for len(s) < len(b) {
s = s + " "
}
copy(b, []byte(s))
}
func (aw *Writer) octal(b []byte, x int64) {
s := "100" + strconv.FormatInt(x, 8)
for len(s) < len(b) {
s = s + " "
}
copy(b, []byte(s))
}
func (aw *Writer) string(b []byte, str string) {
s := str
for len(s) < len(b) {
s = s + " "
}
copy(b, []byte(s))
}
// Writes to the current entry in the ar archive
// Returns ErrWriteTooLong if more than header.Size
// bytes are written after a call to WriteHeader
func (aw *Writer) Write(b []byte) (n int, err error) {
if int64(len(b)) > aw.nb {
b = b[0:aw.nb]
err = errWriteTooLong
}
n, werr := aw.w.Write(b)
aw.nb -= int64(n)
if werr != nil {
return n, werr
}
if len(b)%2 == 1 { // data size must be aligned to an even byte
n2, _ := aw.w.Write([]byte{'\n'})
return n + n2, err
}
return
}
func (aw *Writer) WriteGlobalHeader() error {
_, err := aw.w.Write([]byte(globalHeader))
return err
}
// Writes the header to the underlying writer and prepares
// to receive the file payload
func (aw *Writer) WriteHeader(hdr *Header) error {
aw.nb = int64(hdr.Size)
header := make([]byte, headerByteSize)
s := slicer(header)
aw.string(s.next(16), hdr.Name)
aw.numeric(s.next(12), hdr.ModTime.Unix())
aw.numeric(s.next(6), int64(hdr.Uid))
aw.numeric(s.next(6), int64(hdr.Gid))
aw.octal(s.next(8), hdr.Mode)
aw.numeric(s.next(10), hdr.Size)
aw.string(s.next(2), "`\n")
_, err := aw.w.Write(header)
return err
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package llexportdata
import (
"go/token"
"go/types"
"io"
)
// Read reads export data from in, decodes it, and returns type information for the package.
//
// The package path (effectively its linker symbol prefix) is specified by path, since unlike
// the package name, this information may not be recorded in the export data.
//
// File position information is added to fset.
//
// Read may inspect and add to the imports map to ensure that references within the export data
// to other packages are consistent. The caller must ensure that imports[path] does not exist,
// or exists but is incomplete (see types.Package.Complete), and Read inserts the resulting package
// into this map entry.
//
// On return, the state of the reader is undefined.
func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) {
panic("todo")
}