Use binutils objcopy and strip if available
For x86 architectures, binutils objcopy and strip can be used as such. For armv7 and aarch64, binutils doesn't recognize the architectures and refuse to touch the files. For most/everything that objcopy/strip do, the actual architecture doesn't really matter though. Therefore, provide a wrapper script and a minimal tool for editing PE executables, that change the architecture from armv7 and aarch64 to i686 and x86_64 respectively before invoking binutils, and change it back afterwards. In case the binutils tools are missing, just return a successful result without doing anything for stripping operations (previously, we had the <triplet>-strip tool symlinked to /bin/true, so this isn't any worse than before) and fail for other objcopy operations.
This commit is contained in:
1 parent
86d8400cae
commit
609fe4b81d
5 files changed
+278
-3
No files matched your search
+10
@@ -21,8 +21,18 @@ ENV TOOLCHAIN_ARCHS="i686 x86_64 armv7 aarch64"
|
||||
# Build everything and clean up, in one step
|
||||
COPY *.sh libssp-Makefile ./
|
||||
COPY wrappers/*.sh ./wrappers/
|
||||
COPY wrappers/*.c ./wrappers/
|
||||
RUN ./build-all.sh $TOOLCHAIN_PREFIX && \
|
||||
./strip-llvm.sh $TOOLCHAIN_PREFIX && \
|
||||
rm -rf /build
|
||||
|
||||
# Cheating: Pull strip and objcopy from the normal binutils package.
|
||||
RUN apt-get update -qq && \
|
||||
apt-get install -qqy binutils-mingw-w64-x86-64 && \
|
||||
cp /usr/bin/x86_64-w64-mingw32-strip $TOOLCHAIN_PREFIX/bin/binutils-strip && \
|
||||
cp /usr/bin/x86_64-w64-mingw32-objcopy $TOOLCHAIN_PREFIX/bin/binutils-objcopy && \
|
||||
apt-get remove -qqy binutils-mingw-w64-x86-64 && \
|
||||
apt-get clean -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV PATH=$TOOLCHAIN_PREFIX/bin:$PATH
|
||||
@@ -25,6 +25,7 @@ ENV TOOLCHAIN_ARCHS="i686 x86_64 armv7 aarch64"
|
||||
|
||||
# Install the usual $TUPLE-clang binaries
|
||||
COPY wrappers/*.sh ./wrappers/
|
||||
COPY wrappers/*.c ./wrappers/
|
||||
COPY install-wrappers.sh .
|
||||
RUN ./install-wrappers.sh $TOOLCHAIN_PREFIX
|
||||
|
||||
@@ -72,3 +73,12 @@ RUN ./build-libssp.sh $TOOLCHAIN_PREFIX
|
||||
# size as long as it is in a separate RUN layer though.)
|
||||
COPY strip-llvm.sh .
|
||||
RUN ./strip-llvm.sh $TOOLCHAIN_PREFIX
|
||||
|
||||
# Cheating: Pull strip and objcopy from the normal binutils package.
|
||||
RUN apt-get update -qq && \
|
||||
apt-get install -qqy binutils-mingw-w64-x86-64 && \
|
||||
cp /usr/bin/x86_64-w64-mingw32-strip $TOOLCHAIN_PREFIX/bin/binutils-strip && \
|
||||
cp /usr/bin/x86_64-w64-mingw32-objcopy $TOOLCHAIN_PREFIX/bin/binutils-objcopy && \
|
||||
apt-get remove -qqy binutils-mingw-w64-x86-64 && \
|
||||
apt-get clean -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
+4
-3
@@ -12,6 +12,7 @@ PREFIX="$1"
|
||||
|
||||
mkdir -p $PREFIX/bin
|
||||
cp wrappers/*-wrapper.sh $PREFIX/bin
|
||||
cc wrappers/change-pe-arch.c -o $PREFIX/bin/change-pe-arch
|
||||
cd $PREFIX/bin
|
||||
for arch in $ARCHS; do
|
||||
for exec in clang clang++ gcc g++; do
|
||||
@@ -20,10 +21,10 @@ for arch in $ARCHS; do
|
||||
for exec in ar ranlib nm strings; do
|
||||
ln -sf llvm-$exec $arch-w64-mingw32-$exec || true
|
||||
done
|
||||
for exec in strip; do
|
||||
ln -sf $(which true) $arch-w64-mingw32-$exec
|
||||
done
|
||||
for exec in ld objdump windres dlltool; do
|
||||
ln -sf $exec-wrapper.sh $arch-w64-mingw32-$exec
|
||||
done
|
||||
for exec in objcopy strip; do
|
||||
ln -sf objcopy-wrapper.sh $arch-w64-mingw32-$exec
|
||||
done
|
||||
done
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Martin Storsjo
|
||||
*
|
||||
* This file is part of llvm-mingw.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define IMAGE_DOS_SIGNATURE 0x5A4D
|
||||
#define IMAGE_NT_SIGNATURE 0x00004550
|
||||
|
||||
#define IMAGE_FILE_MACHINE_AMD64 0x8664
|
||||
#define IMAGE_FILE_MACHINE_ARMNT 0x1C4
|
||||
#define IMAGE_FILE_MACHINE_ARM64 0xAA64
|
||||
#define IMAGE_FILE_MACHINE_I386 0x14C
|
||||
|
||||
static uint16_t readUint16(FILE *f) {
|
||||
uint8_t buf[2];
|
||||
if (fread(buf, 1, 2, f) != 2)
|
||||
return -1;
|
||||
return buf[0] | (buf[1] << 8);
|
||||
}
|
||||
|
||||
static uint32_t readUint32(FILE *f) {
|
||||
uint8_t buf[4];
|
||||
if (fread(buf, 1, 4, f) != 4)
|
||||
return -1;
|
||||
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
}
|
||||
|
||||
static void writeUint16(FILE *f, uint16_t val) {
|
||||
uint8_t buf[2];
|
||||
buf[0] = val & 0xff;
|
||||
buf[1] = (val >> 8) & 0xff;
|
||||
if (fwrite(buf, 1, 2, f) != 2)
|
||||
perror("fwrite");
|
||||
}
|
||||
|
||||
static void writeUint32(FILE *f, uint32_t val) {
|
||||
uint8_t buf[4];
|
||||
buf[0] = val & 0xff;
|
||||
buf[1] = (val >> 8) & 0xff;
|
||||
buf[2] = (val >> 16) & 0xff;
|
||||
buf[3] = (val >> 24) & 0xff;
|
||||
if (fwrite(buf, 1, 4, f) != 4)
|
||||
perror("fwrite");
|
||||
}
|
||||
|
||||
static uint16_t archToInt(const char *str) {
|
||||
if (!strcmp(str, "i686"))
|
||||
return IMAGE_FILE_MACHINE_I386;
|
||||
else if (!strcmp(str, "x86_64"))
|
||||
return IMAGE_FILE_MACHINE_AMD64;
|
||||
else if (!strcmp(str, "armv7"))
|
||||
return IMAGE_FILE_MACHINE_ARMNT;
|
||||
else if (!strcmp(str, "aarch64"))
|
||||
return IMAGE_FILE_MACHINE_ARM64;
|
||||
fprintf(stderr, "Unknown architecture %s\n", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is64Bit(uint16_t arch) {
|
||||
switch (arch) {
|
||||
case IMAGE_FILE_MACHINE_AMD64:
|
||||
case IMAGE_FILE_MACHINE_ARM64:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void help(const char *argv0) {
|
||||
printf("%s [-check] [-from arch] [-to arch] file\n", argv0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int check = 0;
|
||||
uint16_t from = 0, to = 0;
|
||||
int i;
|
||||
const char *filename = NULL;
|
||||
FILE *f;
|
||||
uint32_t offset;
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-check")) {
|
||||
check = 1;
|
||||
} else if (!strcmp(argv[i], "-from") && i + 1 < argc) {
|
||||
from = archToInt(argv[++i]);
|
||||
} else if (!strcmp(argv[i], "-to") && i + 1 < argc) {
|
||||
to = archToInt(argv[++i]);
|
||||
} else if (!filename) {
|
||||
filename = argv[i];
|
||||
} else {
|
||||
help(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if ((!check && (!from || !to)) || !filename) {
|
||||
help(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
if (!check && is64Bit(from) != is64Bit(to)) {
|
||||
fprintf(stderr, "Mismatched atchitecture bitness\n");
|
||||
return 1;
|
||||
}
|
||||
f = fopen(filename, "r+b");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
return 1;
|
||||
}
|
||||
if (readUint16(f) != IMAGE_DOS_SIGNATURE) {
|
||||
if (!check)
|
||||
fprintf(stderr, "Incorrect DOS header signature\n");
|
||||
goto fail;
|
||||
}
|
||||
if (fseek(f, 0x3c, SEEK_SET) == -1) { // offsetof(IMAGE_DOS_HEADER, e_lfanew)
|
||||
if (!check)
|
||||
fprintf(stderr, "Unable to seek\n");
|
||||
goto fail;
|
||||
}
|
||||
offset = readUint32(f);
|
||||
if (fseek(f, offset, SEEK_SET) == -1) {
|
||||
if (!check)
|
||||
fprintf(stderr, "Unable to seek\n");
|
||||
goto fail;
|
||||
}
|
||||
if (readUint32(f) != IMAGE_NT_SIGNATURE) {
|
||||
if (!check)
|
||||
fprintf(stderr, "Incorrect NT header signature\n");
|
||||
goto fail;
|
||||
}
|
||||
if (check)
|
||||
goto done;
|
||||
if (readUint16(f) != from) {
|
||||
fprintf(stderr, "Unexpected architecture\n");
|
||||
goto fail;
|
||||
}
|
||||
fseek(f, -2, SEEK_CUR);
|
||||
writeUint16(f, to);
|
||||
if (fseek(f, offset + 0x58, SEEK_SET) == -1) { // offsetof(IMAGE_NT_HEADERS, OptionalHeader.CheckSum)
|
||||
fprintf(stderr, "Unable to seek\n");
|
||||
goto fail;
|
||||
}
|
||||
writeUint32(f, 0);
|
||||
done:
|
||||
fclose(f);
|
||||
return 0;
|
||||
fail:
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
TARGET="$(basename $0 | sed 's/-[^-]*$//')"
|
||||
EXE=$(basename $0 | sed 's/.*-\([^-]*\)/\1/')
|
||||
ARCH=$(echo $TARGET | sed 's/-.*//')
|
||||
|
||||
IN=""
|
||||
OUT=""
|
||||
ARGS=""
|
||||
STRIP=""
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
--strip*|-g|-S)
|
||||
STRIP=1
|
||||
;;
|
||||
-*)
|
||||
;;
|
||||
*)
|
||||
if [ -z "$IN" ]; then
|
||||
IN="$1"
|
||||
elif [ -z "$OUT" ]; then
|
||||
OUT="$1"
|
||||
else
|
||||
echo Unhandled arg $1
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
ARGS="$ARGS $1"
|
||||
shift
|
||||
done
|
||||
if [ -n "$IN" ] && [ -z "$OUT" ]; then
|
||||
OUT="$IN"
|
||||
fi
|
||||
|
||||
case $ARCH in
|
||||
i686|x86_64) COMPAT_ARCH=$ARCH;;
|
||||
armv7) COMPAT_ARCH=i686;;
|
||||
aarch64) COMPAT_ARCH=x86_64;;
|
||||
esac
|
||||
|
||||
convert() {
|
||||
if [ "$ARCH" = "$COMPAT_ARCH" ]; then
|
||||
return
|
||||
fi
|
||||
$DIR/change-pe-arch "$@"
|
||||
}
|
||||
|
||||
checkstrip() {
|
||||
if [ "$EXE" = "strip" ]; then
|
||||
return 0
|
||||
elif [ -n "$STRIP" ]; then
|
||||
if [ "$IN" != "$OUT" ]; then
|
||||
cp "$IN" "$OUT"
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$ARCH" != "$COMPAT_ARCH" ] && ! $DIR/change-pe-arch -check "$IN"; then
|
||||
if checkstrip; then
|
||||
echo Ignoring strip of non-executable \(object file\?\) >&2
|
||||
exit 0
|
||||
else
|
||||
echo Unsupported "$0 $ARGS", not supported for non-executable \(object file\?\) >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -x $DIR/binutils-$EXE ]; then
|
||||
convert -from $ARCH -to $COMPAT_ARCH "$IN"
|
||||
$DIR/binutils-$EXE $ARGS
|
||||
convert -from $COMPAT_ARCH -to $ARCH "$OUT"
|
||||
if [ "$OUT" != "$IN" ]; then
|
||||
convert -from $COMPAT_ARCH -to $ARCH "$IN"
|
||||
fi
|
||||
else
|
||||
if checkstrip; then
|
||||
echo Ignoring strip, missing binutils-$EXE >&2
|
||||
exit 0
|
||||
else
|
||||
echo Unsupported "$0 $ARGS", missing binutils-$EXE >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
Reference in new issue
Block a user