/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Wrapper for the GNU assembler to make it accept the Sun assembler
* arguments where possible.
*
* There are several limitations; the Sun assembler takes multiple
* source files, we only take one.
*
* -b, -s, -xF, -T plain not supported.
* -S isn't supported either, because while GNU as does generate
* listings with -a, there's no obvious mapping between sub-options.
* -K pic, -K PIC not supported either, though it's not clear what
* these actually do ..
* -Qy (not supported) adds a string to the .comment section
* describing the assembler version, while
* -Qn (supported) suppresses the string (also the default).
*
* We also add '-#' support to see invocation lines..
* We also add '-xarch=amd64' in case we need to feed the assembler
* something different (or in case we need to invoke a different binary
* altogether!)
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
static const char *progname;
static int verbose;
struct aelist {
int ael_argc;
struct ae {
char *ae_arg;
};
static struct aelist *
newael(void)
{
}
static void
{
else
}
static void
{
}
static char **
{
char **argv;
int argc;
break;
}
return (argv);
}
static int
{
return (2);
}
static int
{
"\t[-xarch=architecture]\n"
"\t[-o objfile] [-L]\n"
"\t[-P [[-Ipath] [-Dname] [-Dname=def] [-Uname]]...]\n"
return (3);
}
static void
{
int c;
exit(1);
if (c == termchar)
break;
}
}
/*
* Variant of copyuntil(), used for copying the path used
* for .file directives. This version removes the workspace
* from the head of the path, or failing that, attempts to remove
* these directives. The objects produced by gas contain STT_FILE
* symbols for every .file directive. These FILE symbols contain our
* workspace paths, leading to wsdiff incorrectly flagging them as
* having changed. By clipping off the workspace from these paths,
* we eliminate these false positives.
*/
static void
{
/*
* Dynamically sized buffer for reading paths. Retained
* and reused between calls.
*/
char *bufptr;
int c;
/* Read the path into the buffer */
/*
* If we need a buffer, or need a larger buffer,
* fix that here.
*/
perror("realloc");
exit(1);
}
}
if (c == termchar)
break;
}
if (bufcnt == 0)
return;
/*
* We have a non-empty buffer, and thus the opportunity
* to do some surgery on it before passing it to the output.
*/
/*
* If our workspace is at the start, remove it.
*/
bufptr += wspace_len;
bufcnt -= wspace_len;
/*
* Further opportunity: Also clip the prefix
*/
if ((proto_inc_len < bufcnt) &&
bufptr += proto_inc_len;
bufcnt -= proto_inc_len;
}
} else if ((sys_inc_len < bufcnt) &&
bufptr += sys_inc_len;
bufcnt -= sys_inc_len;
}
/* Output whatever is left */
perror("fwrite");
exit(1);
}
}
/*
* The idea here is to take directives like this emitted
* by cpp:
*
* # num
*
* and convert them to directives like this that are
* understood by the GNU assembler:
*
* .line num
*
* and similarly:
*
* # num "string" optional stuff
*
* is converted to
*
* .line num
* .file "string"
*
* While this could be done with a sequence of sed
* commands, this is simpler and faster..
*/
static pid_t
{
char *wspace;
if (verbose)
case 0:
perror("dup2");
exit(1);
}
closefrom(3);
break;
case -1:
perror("fork");
default:
return (pid);
}
/*
* Key off the CODEMGR_WS environment variable to detect
* if we're in an activated workspace, and to get the
* path to the workspace.
*/
int c, num;
case '#':
case 0:
/*
* discard comment lines completely
* discard ident strings completely too.
* (GNU as politely ignores them..)
*/
break;
default:
/*FALLTHROUGH*/
case EOF:
exit(1);
/*NOTREACHED*/
case 1:
/*
* This line has a number at the beginning;
* if it has a string after the number, then
* it's a filename.
*
* If this is an activated workspace, use
* copyuntil_path() to do path rewriting
* that will prevent workspace paths from
* being burned into the resulting object.
* If not in an activated workspace, then
* copy the existing path straight through
* without interpretation.
*/
wspace, wspace_len);
else
}
/*
* discard the rest of the line
*/
break;
}
break;
case '\n':
/*
* preserve newlines
*/
break;
case EOF:
/*
* don't write EOF!
*/
break;
default:
/*
* lines that don't begin with '#' are copied
*/
break;
}
exit(1);
}
exit(0);
/*NOTREACHED*/
}
static pid_t
{
if (verbose) {
while (*dargv)
}
case 0:
perror("dup2");
exit(1);
}
perror("dup2");
exit(1);
}
closefrom(3);
perror("execvp");
break;
case -1:
perror("fork");
default:
return (pid);
}
exit(2);
/*NOTREACHED*/
}
static int
{
int active = 0;
int rval = 0;
perror("pipe");
return (4);
}
active++;
if (verbose)
active++;
if (verbose)
active++;
if (verbose) {
}
closefrom(3);
if (active != 3)
return (5);
while (active != 0) {
int stat;
rval++;
break;
}
continue;
active--;
if (WEXITSTATUS(stat) != 0)
rval++;
}
}
return (rval);
}
int
{
char **asargv;
int as64 = 0;
int code;
else
progname++;
/*
* Helpful when debugging, or when changing tool versions..
*/
else {
}
else {
}
else {
}
else {
}
else {
}
/*
* Walk the argument list, translating as we go ..
*/
while (--argc > 0) {
char *arg;
int arglen;
if (*arg != '-') {
char *filename;
/*
* filenames ending in '.s' are taken to be
* assembler files, and provide the default
* basename of the output file.
*
* other files are passed through to the
* preprocessor, if present, or to gas if not.
*/
if ((arglen > 2) &&
/*
* Though 'as' allows multiple assembler
* files to be processed in one invocation
* of the assembler, ON only processes one
* file at a time, which makes things a lot
* simpler!
*/
else
return (usage(
"one assembler file at a time"));
/*
* If we haven't seen a -o option yet,
* default the output to the basename
* of the input, substituting a .o on the end
*/
char *argcopy;
else
outfile++;
}
}
if (cpp)
else if (m4)
else
continue;
} else
arglen--;
switch (arg[1]) {
case 'K':
/*
* -K pic
* -K PIC
*/
if (arglen == 1) {
return (usage("malformed -K"));
argc--;
} else {
arg += 2;
}
return (usage("malformed -K"));
break; /* just ignore -Kpic for gcc */
case 'Q':
break;
/*FALLTHROUGH*/
case 'b':
case 's':
case 'T':
/*
* -b Extra symbol table for source browser ..
* not relevant to gas, thus should error.
* -s Put stabs in .stabs section not stabs.excl
* not clear if there's an equivalent
* -T 4.x migration option
*/
default:
case 'x':
/*
* Accept -xarch special case to invoke alternate
* assemblers or assembler flags for different
* architectures.
*/
as64++;
break;
}
/*
* XX64: Is this useful to gas?
*/
break;
/*
* -xF Generates performance analysis data
* no equivalent
*/
case 'V':
break;
case '#':
verbose++;
break;
case 'L':
break;
case 'n':
break;
case 'o':
if (arglen != 1)
return (usage("bad -o flag"));
return (usage("bad -o flag"));
argc--;
break;
case 'm':
if (cpp)
return (usage("-m conflicts with -P"));
}
break;
case 'P':
if (m4)
return (usage("-P conflicts with -m"));
}
break;
case 'D':
case 'U':
if (cpp)
else if (m4)
else
break;
case 'I':
if (cpp)
else
break;
case '-': /* a gas-specific option */
break;
}
}
#if defined(__i386)
if (as64)
else
#endif
return (usage("no source file(s) specified"));
outfile = "a.out";
if (cpp) {
#if defined(__sparc)
if (as64)
else
if (as64) {
} else {
}
#else
#error "need isa-dependent defines"
#endif
} else if (m4)
else {
/*
* can unlink the output file if errors are
* detected..
*/
perror("execvp");
code = 7;
}
if (code != 0)
return (code);
}