Label renaming is typically needed when replicating code. The modifications must be applied at two distinct types of locations: in label declarations, and in the references to the labels in instructions.
To rename label references, we have to modify expressions appearing in instruction arguments. This is performed using the expression substitution primitive on operand abstractions. Labels themselves are replaced with new labels, built from scratch using the new name.
The application code in the example below performs a brute-force, substring-based renaming of all labels and symbols appearing in the code sections of the assembly file. However, it is presented for illustrative purposes and does not handle the directives and labels which are located in sections other than "text", thus potentially introducing inconsistencies between declarations and uses of data labels.
#include "salto.h"
// replace all non-overlapping occurrences of oldTxt with newTxt in
// src, leaving hte result in dst. NO CHECKS FOR OVERFLOWS ARE MADE.
// NOTE: the argument order follows the conventions of str...() functions.
unsigned int
strSubstitute(char *dst, char *src, char *newTxt, char
*oldTxt)
{
unsigned int res = 0 ;
char *occurrence ;
while ((occurrence = strstr(src, oldTxt))) {
strncpy(dst, src, occurrence - src) ; // leading common text
dst += occurrence - src ;
strcpy(dst, newTxt) ; // new text where old one should be
dst += strlen(newTxt) ;
src = occurrence + strlen(oldTxt) ; // new begin of common txt
res++ ;
}
strcpy(dst, src) ; // final step: txt past last occurrence
return res ; // number of substitutions performed
}
char *oldText, *newText;
void usage(void)
{
fprintf(stderr,
"Simple renaming module. Module-specific parameters (after '--'):"
"\n\n"
" -h print this help message and exit\n"
" -from <word> label (sub-)string to be replaced\n"
" -to <word> label (sub-)string to use instead\n\n"
"Both '-from' and '-to' arguments must be given.\n") ;
}
void Salto_init_hook(int argc, char **argv)
{
int i;
oldText = NULL ;
newText = NULL ;
for (i = 0; i < argc - 1; i++) { // we leave out the last arg
// (should be a value, not an option)
if (!strcmp(argv[i], "-from")) // (sub-)string to be replaced
oldText = argv[i + 1] ; // it necessarily exists...
if (!strcmp(argv[i], "-to")) // new value to be used in renaming
newText = argv[i + 1] ; // it necessarily exists...
if (!strcmp(argv[i], "-h")) {
usage() ; // print help message and exit
exit (0) ; // successfully
}
}
if (!strcmp(argv[i], "-h")) { // help asked for ==> exit successfully
usage() ;
exit (0) ;
}
if ((!oldText)
||
(!newText)) { // help badly needed ==> fail
usage() ;
exit (1) ;
}
// here, things go ahead normally
}
// user application entry point... Either linked dynamically
// (default), or statically (through "make static")
void Salto_hook(void)
{
BB *bb;
CFG *cfg;
INST *insn, *label, *directive;
unsigned int ncfg, nbb, ninsts, nopds, i, j, k, l;
int substitutions;
ncfg = numberOfCFG() ; // number of CFG in program
if (!ncfg) return ; // nothing to do if no procedures found
for (i = 0; i < ncfg; i++) { // FOR ALL PROCEDURES
cfg = getCFG(i) ; // get current CFG
nbb = cfg -> numberOfBB() ; // number of basic blocks
for (j = 0; j < nbb; j++) { // FOR ALL BASIC BLOCKS
bb = cfg -> getBB(j) ; // get current BB
ninsts = bb -> numberOfInstructions(); // number of insns in BB
for (k = 1; k < ninsts - 1; k++) { // FOR ALL INSTRUCTIONS...
// NOTE: first and last insn are
// reserved oned and shouldn't be
// scanned, hence the range 1..n-2
insn = bb -> getInstruction(k) ; // get current instruction
if (insn -> isAsm()) {
// for ASM insns, replace name substring in operands by
// substituting all non-overlapping occurrences of oldText with
// newText. The replacement is performed on operand abstractions.
nopds = insn -> numberOfOperands() ;
// scan all operands of the instruction
for (l = 0; l < nopds; l++) {
OperandInfo &op = insn -> getOperand(l) ;
if (op . isExpr()) { // only for expressions
// substitute the strings; retvalue is number of substits
substitutions = op . substitute(oldText, newText) ;
if (substitutions) {
insn -> setOperand(l, op) ; // make it effective
fprintf(stderr,
"Operand substitution succeeded @"
" CFG/BB/INST/OPD=%d/%d/%d/%d...\n",
i,j,k,l) ;
}
}
}
}
else if (insn -> isLabel()) {
// for labels, replace the label by a new one, whose name
// results from the substitution of oldText with newText...
char *oldLabelName, newLabelName[80];
oldLabelName = insn -> getName() ; // get name of label
// replace all non-overlapping occurrences of oldText with
// newText. Note the the str...() argument ordering.
substitutions =
strSubstitute(newLabelName, oldLabelName, newText, oldText) ;
// if at least one substitution succeeded
if (substitutions) {
label = newLabel(newLabelName) ; // make a new label
bb -> insertInstruction(k, label) ; // insert in place
// of original insn at pos k (= old label).
// The old label gets shifted by 1 position
bb -> removeInstruction(k + 1) ; // remove the old label
fprintf(stderr,
"Label replacement succeeded @"
" CFG/BB/INST = %d/%d/%d...\n",
i, j, k) ;
} // if (substitutions)
} // if (insn -> isLabel())
else if (insn -> isPseudo()) {
// for directives, we have to go a little bit into Salto
// internals (note the type cast :-)
char *oldDirective, newDirective[256] ;
// get the full text of the directive
oldDirective = ((xPseudo *) insn) -> getText() ;
// substitute strings
substitutions =
strSubstitute(newDirective, oldDirective, newText, oldText) ;
// process if successful
if (substitutions) {
directive = newPseudo(newDirective) ; // make the new one
bb -> insertInstruction(k, directive) ; // insert in BB
bb -> removeInstruction(k + 1) ; // remove the old label
fprintf(stderr,
"Directive replacement succeeded @"
" CFG/BB/INST = %d/%d/%d...\n",
i, j, k) ;
} // if (substitutions)
} // if (insn -> isPseudo())
} // for all insns
} // for all basic blocks
} // for all procedures
// generate the modified code...
produceCode(stdout) ;
}