Files
valgrind/auxprogs/s390-runone
Florian Krohm b8a91ecb77 s390-runone: Add command line option --cc=... to choose a compiler.
gcc is still default, --cc=whatever overrides.
2025-10-23 21:06:41 +00:00

221 lines
5.5 KiB
Perl
Executable File

#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long;
#-----------------------------------------------------------------------
# Compile a small C program containing a sequence of assembler
# instructions into an executable that does not need a dynamic linker.
# Very handy for debugging new insns or small snippets without going
# through the multi-pass process of figuring out which SB contains the
# code we're interested in.
#
# Step #1: s390-runone -t bla.c
#
# Creates a template which looks like so:
#
# int main(void)
# {
# asm volatile ("csch"); // begin mark: do not remove
# //FIXME: insert test code here:
# asm volatile ("lghi %r1,1"); // __NR_exit
# asm volatile ("lghi %r2,0"); // return code = 0
# asm volatile ("svc 0"); // terminate process
# asm volatile ("csch"); // end mark: do not remove
# return 0;
# }
#
# Step #2: Replace the FIXME line with one or more asm statements.
# Skip this step if you used --insn=... in step #1.
#
# Step #3: s390-runone --build bla.c
#
# Compiles and links "bla.c" into an executable "bla" which does not
# require the dynamic loader and which contains only those insns between
# the two marker insns (csch).
#
# objdump -d:
#
# 00000000010000b0 <_start>:
# 10000b0: a7 19 00 01 lghi %r1,1
# 10000b4: a7 29 00 00 lghi %r2,0
# 10000b8: 0a 00 svc 0
#
#-----------------------------------------------------------------------
#
&main;
sub usage {
my $text =<<END
Usage: s390-runone [options] FILE
Options:
--template Write template
--build Build executable from C file
--insn INSN Add INSN to template
--arch ARCH Passed as -march=ARCH to the compiler
--cc COMP Use COMP as compiler
--help Write this text
FILE is mandatory with --build
END
;
print $text;
exit 0;
}
sub main {
my $template = 0;
my $build = 0;
my $help = 0;
my $insn = "";
my $arch = "arch14";
my $cc = "gcc";
GetOptions("template|t" => sub { $template = 1; $build = 0; },
"build|b" => sub { $template = 0; $build = 1; },
"help|h" => \$help,
"insn|i=s" => \$insn,
"arch|a=s" => \$arch,
"cc=s" => \$cc
) or usage();
usage() if ($help);
my $num_arg = $#ARGV + 1;
my $file = "";
if ($num_arg != 1) {
fatal("Missing file name") if ($build);
} else {
$file = $ARGV[0];
}
my $rc = 0;
if ($template) {
write_template($file, $insn);
} elsif ($build) {
$rc = build_exe($file, $arch, $cc);
} else {
print "Nothing happens\n";
}
exit $rc;
}
sub write_template
{
my ($file, $insn) = @_;
my $asm;
if ($insn eq "") {
$asm = "//FIXME: insert test code here:";
} else {
$asm = "asm volatile (\"$insn\");";
}
my $template = <<END2
int main(void)
{
asm volatile ("csch"); // begin mark: do not remove
$asm
asm volatile ("lghi %r1,1"); // __NR_exit
asm volatile ("lghi %r2,0"); // return code = 0
asm volatile ("svc 0"); // terminate process
asm volatile ("csch"); // end mark: do not remove
return 0;
}
END2
;
if ($file ne "") {
open(OUT, ">$file") || fatal("Cannot open '$file': $!\n");
print OUT $template;
close(OUT);
} else {
print $template;
}
}
sub build_exe
{
my ($file, $arch, $cc) = @_;
my $base = `basename "$file" .c`;
chomp($base);
my $asm = "$base.s";
my $exe = "$base";
# Compile the testprogram to assembler
my $stderr = `$cc -S -fno-ident -march=$arch $file 2>&1`;
if ($? != 0) {
error("$cc: Compilation failed\n $stderr");
return 1;
}
`mv "$asm" "$asm.orig"`; # save before massaging
# Massage assembler file:
# - rename main ---> _start
# - remove cfi stuff
# - remove comment lines
# - remove insns preceeding 1st mark (csch)
# - remove insns succeeding 2nd mark (csch)
my $in_main = 0;
my $mark_seen = 0;
my $output = "";
open(IN, "$asm.orig") || fatal("Cannot open '$file': $!\n");
while (my $line = <IN>) {
chomp($line);
next if ($line =~ /^\s*#/); # comment
next if ($line =~ /\.cfi_/); # cfi stuff
if ($in_main == 0) {
$in_main = 1 if ($line =~ /^main:/);
} else {
if ($mark_seen == 0) {
if ($line =~ /csch/) {
$mark_seen = 1;
next;
}
next if ($line =~ /^\t[a-z]/); # skip insn
} else {
if ($line =~ /csch/) {
$mark_seen = 0;
next;
}
}
}
$line =~ s/main/_start/g;
$output .= "$line\n";
}
open(OUT, ">$asm") || fatal("Cannot open '$asm': $!\n");
print OUT $output;
close(OUT);
# Assemble file and link to executable
my $ccc = "$cc -static -Wa,--fatal-warnings -Wl,--build-id=none"
. " -nodefaultlibs -nostartfiles";
$stderr = `$ccc "$asm" -o "$exe" 2>&1`;
if ($? != 0) {
error("$cc: Linking executable failed");
for my $line (split /\n/,$stderr) {
print STDERR "$line\n" if ($line !~ /treating warnings as errors/);
}
return 1;
}
}
sub error
{
print STDERR "*** $_[0]\n";
}
sub fatal
{
error($_[0]);
exit 1;
}