Full Code of pwaller/goupx for AI

master 1d58e01d5ce2 cached
5 files
8.7 KB
2.7k tokens
12 symbols
1 requests
Download .txt
Repository: pwaller/goupx
Branch: master
Commit: 1d58e01d5ce2
Files: 5
Total size: 8.7 KB

Directory structure:
gitextract_f5pnkk7l/

├── .gitignore
├── LICENSE
├── README.md
├── hemfix/
│   └── hemfix.go
└── main.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/goupx


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2012 Peter Waller

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
goupx - Fix golang Linux ELF executables to work with upx
---------------------------------------------------

## Update: 2016/03/10

As far as I (pwaller) know, goupx is no longer necessary for Linux binaries since it was fixed in
go1.6.

## About

Installation: `go get github.com/pwaller/goupx`

(or if you don't want to do it with root, `GOPATH=${HOME}/.local go get github.com/pwaller/goupx` will install it to `${HOME}/.local/bin/goupx`).

Usage: `goupx [filename]`

Fixes the `PT_LOAD` offset of [filename] and then runs `upx`.

This is only necessary for Linux ELF executables (not Mach-O executables or windows binaries, for example).

Based on [code found on the upx bugtracker](http://sourceforge.net/tracker/?func=detail&atid=102331&aid=3408066&group_id=2331).

MIT licensed.

Fixes the following issue
=========================

    $ upx [linux ELF go binary]
                           Ultimate Packer for eXecutables
                              Copyright (C) 1996 - 2011
    UPX 3.08        Markus Oberhumer, Laszlo Molnar & John Reiser   Dec 12th 2011

            File size         Ratio      Format      Name
       --------------------   ------   -----------   -----------
    upx: goupx: EOFException: premature end of file                                

    Packed 1 file: 0 ok, 1 error.

Typical compression ratio
=========================

Resulting filesizes are typically 25% of the original go executable. Your mileage my vary.


================================================
FILE: hemfix/hemfix.go
================================================
package hemfix

/*

goupx: Fix compiled go binaries so that they can be packed by
       the universal packer for executables (upx)

Copyright (c) 2012 Peter Waller <peter@pwaller.net>
All rights reserved.

Based on code found at http://sourceforge.net/tracker/?func=detail&atid=102331&aid=3408066&group_id=2331

Based on hemfix.c Copyright (C) 2012 John Reiser, BitWagon Software LLC

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 3, or (at your option)
  any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import (
	ELF "debug/elf"
	"encoding/binary"
	"errors"
	"io"
	"log"
	"os"
)

// The functions gethdr and writephdr are heavily influenced by code found at
// http://golang.org/src/pkg/debug/elf/file.go

// Returns the Prog header offset and size
func gethdr(f *ELF.File, sr io.ReadSeeker) (int64, int, error) {
	sr.Seek(0, os.SEEK_SET)

	switch f.Class {
	case ELF.ELFCLASS32:
		hdr := new(ELF.Header32)
		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
			return 0, 0, err
		}
		return int64(hdr.Phoff), int(hdr.Phentsize), nil

	case ELF.ELFCLASS64:
		hdr := new(ELF.Header64)
		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
			return 0, 0, err
		}
		return int64(hdr.Phoff), int(hdr.Phentsize), nil
	}
	return 0, 0, errors.New("Unexpected ELF class")
}

// Write out a Prog header to an elf with a given destination
// Writes out `p` to `sw` at `dst` using information from `f`
func writephdr(f *ELF.File, dst int64, sw io.WriteSeeker, p *ELF.Prog) error {
	sw.Seek(dst, os.SEEK_SET)

	switch f.Class {
	case ELF.ELFCLASS32:
		hdr := ELF.Prog32{
			Type:   uint32(p.Type),
			Flags:  uint32(p.Flags),
			Off:    uint32(p.Off),
			Vaddr:  uint32(p.Vaddr),
			Paddr:  uint32(p.Paddr),
			Filesz: uint32(p.Filesz),
			Memsz:  uint32(p.Memsz),
			Align:  uint32(p.Align),
		}
		if err := binary.Write(sw, f.ByteOrder, hdr); err != nil {
			return err
		}

	case ELF.ELFCLASS64:
		hdr := ELF.Prog64{
			Type:   uint32(p.Type),
			Flags:  uint32(p.Flags),
			Off:    p.Off,
			Vaddr:  p.Vaddr,
			Paddr:  p.Paddr,
			Filesz: p.Filesz,
			Memsz:  p.Memsz,
			Align:  p.Align,
		}
		if err := binary.Write(sw, f.ByteOrder, hdr); err != nil {
			return err
		}
	}
	return nil
}

func fixelf(elf *ELF.File, fd io.ReadWriteSeeker) error {

	// Determine where to write header (need
	off, sz, err := gethdr(elf, fd)
	if err != nil {
		return err
	}

	for i := range elf.Progs {
		p := elf.Progs[i]

		if p.ProgHeader.Type != ELF.PT_LOAD {
			// Only consider PT_LOAD sections
			continue
		}

		if p.Flags&ELF.PF_X != ELF.PF_X {
			continue
		}

		mask := -p.Align
		if ^mask&p.Vaddr != 0 && (^mask&(p.Vaddr-p.Off)) == 0 {
			log.Printf("Hemming PT_LOAD section")
			hem := ^mask & p.Off
			p.Off -= hem
			p.Vaddr -= hem
			if p.Paddr != 0 {
				p.Paddr -= hem
			}
			p.Filesz += hem
			p.Memsz += hem

			dst := off + int64(sz*i)
			writephdr(elf, dst, fd, p)
			break
		}
	}
	return nil
}

func FixFile(filename string) error {
	fd, err := os.OpenFile(filename, os.O_RDWR, 0)
	if err != nil {
		return err
	}
	defer fd.Close()

	elf, err := ELF.NewFile(fd)
	if err != nil {
		log.Print("Failed to parse ELF. This can happen if the binary is already packed.")
		return err
	}
	defer elf.Close()

	log.Printf("%+v", elf.FileHeader)
	err = fixelf(elf, fd)
	if err != nil {
		log.Fatal("Failure to read ELF header")
		return err
	}
	return nil
}


================================================
FILE: main.go
================================================
package main

import (
	"log"
	"os"
	"os/exec"

	"github.com/pwaller/goupx/hemfix"
)

const usageText = `usage: goupx [args...] files...

    --no-upx: Disables UPX from running.
    --strip-binary: Strips binaries before compressing them.

See UPX's documentation (man upx) for information on UPX's flags.
`

var run_strip = false
var run_upx = true
var upxPath string

// usage prints some nice output instead of panic stacktrace when an user calls
// goupx without arguments
func usage() {
	os.Stderr.WriteString(usageText)
}

// findUpxBinary searches for the upx binary in PATH.
func findUpxBinary() {
	var err error
	upxPath, err = exec.LookPath("upx")
	if err != nil {
		log.Fatal("Couldn't find upx binary in PATH")
	}
}

// parseArguments parses arguments from os.Args and separates the goupx flags
// from the UPX flags, as well as separating the files from the arguments.
func parseArguments() (args []string, files []string) {
	if len(os.Args) == 1 {
		usage()
	}
	args = append(args, upxPath)
	for _, arg := range os.Args[1:] {
		switch {
		case arg == "-h" || arg == "--help":
			usage()
		case arg == "--no-upx":
			run_upx = false
		case arg == "--strip-binary":
			run_strip = true
		case arg[0] != '-':
			files = append(files, arg)
		default:
			args = append(args, arg)
		}
	}
	return
}

// compressBinary attempts to compress the binary with UPX.
func compressBinary(input_file string, arguments []string) {
	if run_upx {
		cmd := &exec.Cmd{
			Path: upxPath,
			Args: append(arguments, input_file),
		}
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			log.Panic("upx failed: ", err)
		}
	}
}

// stripBinary attempts to strip the binary.
func stripBinary(input_file string) {
	if run_strip {
		cmd := exec.Command("strip", "-s", input_file)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			log.Panic("strip failed: ", err)
		}
	}
}

// runHemfix will attempt to fix the current input file.
func runHemfix(input_file string) {
	if err := hemfix.FixFile(input_file); err != nil {
		log.Panicf("Failed to fix '%s': %v", input_file, err)
	}
	log.Print("File fixed!")
}

func main() {
	findUpxBinary()
	arguments, files := parseArguments()
	for _, file := range files {
		runHemfix(file)
		stripBinary(file)
		compressBinary(file, arguments)
	}
	if err := recover(); err != nil {
		log.Print("Panicked. Giving up.")
		panic(err)
		return
	}
}
Download .txt
gitextract_f5pnkk7l/

├── .gitignore
├── LICENSE
├── README.md
├── hemfix/
│   └── hemfix.go
└── main.go
Download .txt
SYMBOL INDEX (12 symbols across 2 files)

FILE: hemfix/hemfix.go
  function gethdr (line 43) | func gethdr(f *ELF.File, sr io.ReadSeeker) (int64, int, error) {
  function writephdr (line 66) | func writephdr(f *ELF.File, dst int64, sw io.WriteSeeker, p *ELF.Prog) e...
  function fixelf (line 103) | func fixelf(elf *ELF.File, fd io.ReadWriteSeeker) error {
  function FixFile (line 143) | func FixFile(filename string) error {

FILE: main.go
  constant usageText (line 11) | usageText = `usage: goupx [args...] files...
  function usage (line 25) | func usage() {
  function findUpxBinary (line 30) | func findUpxBinary() {
  function parseArguments (line 40) | func parseArguments() (args []string, files []string) {
  function compressBinary (line 63) | func compressBinary(input_file string, arguments []string) {
  function stripBinary (line 78) | func stripBinary(input_file string) {
  function runHemfix (line 90) | func runHemfix(input_file string) {
  function main (line 97) | func main() {
Condensed preview — 5 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (10K chars).
[
  {
    "path": ".gitignore",
    "chars": 7,
    "preview": "/goupx\n"
  },
  {
    "path": "LICENSE",
    "chars": 1079,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2012 Peter Waller\n\nPermission is hereby granted, free of charge, to any person obta"
  },
  {
    "path": "README.md",
    "chars": 1459,
    "preview": "goupx - Fix golang Linux ELF executables to work with upx\n---------------------------------------------------\n\n## Update"
  },
  {
    "path": "hemfix/hemfix.go",
    "chars": 3937,
    "preview": "package hemfix\n\n/*\n\ngoupx: Fix compiled go binaries so that they can be packed by\n       the universal packer for execut"
  },
  {
    "path": "main.go",
    "chars": 2440,
    "preview": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"os/exec\"\n\n\t\"github.com/pwaller/goupx/hemfix\"\n)\n\nconst usageText = `usage: goupx [a"
  }
]

About this extraction

This page contains the full source code of the pwaller/goupx GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 5 files (8.7 KB), approximately 2.7k tokens, and a symbol index with 12 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!