Error[8]: Undefined offset: 17, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

概述我想使用精确的基于事件的采样(PEBS)在XeonE5 Sandy Bridge上记录特定事件的所有地址(例如高速缓存未命中). 但是,CoreTM i7处理器和英特尔®至强™5500处理器的性能分析指南(第24页)包含以下警告: As the PEBS mechanism captures the values of the register at completion of the instr 我想使用精确的基于事件的采样(PEBS)在XeonE5 Sandy BrIDge上记录特定事件的所有地址(例如高速缓存未命中).

但是,CoreTM i7处理器和英特尔®至强™5500处理器的性能分析指南(第24页)包含以下警告:

As the PEBS mechanism captures the values of the register at
completion of the instruction,the dereferenced address for the
following type of load instruction (Intel asm convention) cannot be
reconstructed.
MOV RAX,[RAX+const]
This kind of
instruction is mostly associated with pointer chasing
mystruc = mystruc->next;
This is a significant shortcoming of this
approach to capturing memory instruction addresses.

我根据objdump在我的程序中有一些加载说明.有什么办法可以避免吗?

由于这是一个特定于英特尔的问题,解决方案无须以任何方式进行移植,只需要运行.我的代码是用C编写的,我理想地寻找一个编译器级别的解决方案(gcc或icc),但是任何建议都是可以接受的.

一些例子:

mov    0x18(%rdi),%rdimov    (%rcx,%rax,8),%rax

在这两种情况下,在指令退出后(因此当我查看寄存器值以确定我加载到/从哪里)地址的值(这些示例中的%rdi 18和%rcx 8 *%rax)被覆盖由mov的结果.

解决方法 您想要做的是转换表单的所有说明:
mov    (%rcx,%rax

成:

mov    (%rcx,%r11mov    %r11,%rax

这可以通过修改编译器生成的汇编器源来更容易地完成.下面是一个Perl脚本,它将通过读取和修改.s文件来完成所有必要的转换.

只需更改生成.s文件而不是.o文件,应用脚本,然后使用as或gcc生成.o

这是实际的脚本.我已经在几个我自己的来源测试了,按照下面的评论中的构建过程.

该脚本具有以下功能:

>扫描并定位所有函数定义
>标识给定功能中使用的所有寄存器
>定位函数的所有返回点
>根据功能的寄存器使用情况选择要使用的临时寄存器(即将使用尚未由功能使用的临时寄存器)
>用两个指令序列代替所有“麻烦”指令
>尝试使用未使用的临时寄存器(例如%r11或未使用的参数寄存器),然后尝试使用被调用方保存的寄存器
>如果选择的注册表被保留,则会添加push到函数prolog并d出功能[multiple] ret语句
>维护所有分析和转换的日志,并将其作为注释追加到输出.s文件

#!/usr/bin/perl# pebsfix/pebsfixup -- fix assembler source for PEBS usage## command line options:#   "-a" -- use only full 64 bit targets#   "-l" -- do _not_ use lea#   "-D[diff-file]" -- show differences (default output: "./DIFF")#   "-n10" -- do _not_ use register %r10 for temporary (default is use it)#   "-o" -- overwrite input files (can be multiple)#   "-O<outfile>" -- output file (only one .s input allowed)#   "-q" -- suppress warnings#   "-T[lvl]" -- deBUG trace## "-o" and "-O" are mutually exclusive## command line script test options:#   "-N[TPA]" -- disable temp register types [for testing]#   "-P" -- force push/pop on all functions## command line arguments:#   1-- List of .s files to process [or directory to search]#       for a given file "foo.s",output is to "foo.TMP"#       if (-o is given,"foo.TMP" is renamed to "foo.s")## suggested usage:#   change build to produce .s files#   FROM:#     cc [options] -c foo.c#   TO:#     cc [options] -c -S foo.c#     pebsfixup -o foo.s#     cc -c foo.s## suggested compiler options:# [probably only really needed if push/pop required. use -NP to verify]#   (1) use either of#       -O2 -fno-optimize-sibling-calls#       -O1#   (2) use -mno-omit-leaf-frame-pointer#   (3) use -mno-red-zone [probably not required in any case]## NOTES:#   (1) red zones are only really useful for leaf functions (i.e. if fncA calls#       fncB,fncA's red zone would be clobbered)#   (2) pushing onto the stack isn't a problem if there is a formal stack frame#   (3) the push is okay if the function has no more than six arguments (i.e.#       does _not_ use positive offsets from %rsp to access them)#pragma pgmlnsuse strict qw(vars subs);our $pgmtail;our $opt_a;our $opt_T;our $opt_D;our $opt_l;our $opt_n10;our $opt_N;our $opt_P;our $opt_q;our $opt_o;our $opt_O;our $opt_s;our @reguse;our %reguse_tobase;our %reguse_isbase;our $regusergx;our @regtmpList;our %regtmp_type;our $diff;our $sepflg;our $fatal;our @cmtprt;master(@ARGV);exit(0);# master -- master controlsub master{    my(@argv) = @_;    my($xfsrc);    my($file,@files);    my($bf);    $pgmtail = "pebsfixup";    optget(\@argv);    # define all kNown/usable registers    regusejoin();    # define all registers that we may use as a temporary    regtmpall();    if (defined($opt_D)) {        unlink($opt_D);    }    # show usage    if (@argv <= 0) {        $file = cmpl %ebp,%r14);        open($xfsrc,"<$file") ||            sysfault("$pgmtail: unable to open '%s' -- $!\n",$file);        while ($bf = <$xfsrc>) {            chomp($bf);            next if ($bf =~ /^#!/);            last unless ($bf =~ s/^#//);            $bf =~ s/^# ?//;            print($bf,"\n");        }        close($xfsrc);        exit(1);    }    foreach $file (@argv) {        if (-d $file) {            dodir(\@files,$file);        }        else {            push(@files,$file);        }    }    if (defined($opt_O)) {        sysfault("$pgmtail: -O may have only one input file\n")            if (@files != 1);        sysfault("$pgmtail: -O and -o are mutually exclusive\n")            if ($opt_o);    }    foreach $file (@files) {        dofile($file);    }    if (defined($opt_D)) {        exec("less",$opt_D);    }}# dodir -- process directorysub dodir{    my($files,$dir) = @_;    my($file,@files);    @files = (`find $dir -type f -name '*.s'`);    foreach $file (@files) {        chomp($file);        push(@$files,$file);    }}# dofile -- process filesub dofile{    my($file) = @_;    my($ofile);    my($xfsrc);    my($xfdst);    my($bf,$lno,$outoff);    my($fixoff);    my($lhs,$rhs);    my($xop,$arg);    my($ix);    my($sym,$val,$typ);    my(%sym_type);    my($fnc,$fnx,%fnx_lookup,@fnxList);    my($retList);    my($uselook,@useList,%avail);    my($fixreg,$fixrtyp);    my($sixList);    my($fix,$fixList);    my($fixtot);    my(@fix);    my(@outList);    my($relaxflg);    my($cmtchr);    undef($fatal);    undef(@cmtprt);    msgprt("\n")        if ($sepflg);    $sepflg = 1;    msgprt("$pgmtail: processing %s ...\n",$file);    $cmtchr = "#";    cmtprt("%s\n","-" x 78);    cmtprt("file: %s\n",$file);    # get the output file    $ofile = $file;    sysfault("$pgmtail: bad suffix -- file='%s'\n",$file)        unless ($ofile =~ s/[.]s$//);    $ofile .= ".TMP";    # use explicit output file    if (defined($opt_O)) {        $ofile = $opt_O;        sysfault("$pgmtail: output file may not be input file -- use -o instead\n")            if ($ofile eq $file);    }    open($xfsrc,"<$file") ||        sysfault("$pgmtail: unable to open '%s' -- $!\n",$file);    $lno = 0;    while ($bf = <$xfsrc>) {        chomp($bf);        $bf =~ s/\s+$//;        $outoff = $lno;        ++$lno;        push(@outList,$bf);        # clang adds comments        $ix = index($bf,"#");        if ($ix >= 0) {            $bf = substr($bf,$ix);            $bf =~ s/\s+$//;        }        # look for ".type blah,@function"        # NOTE: this always comes before the actual label line [we hope ;-)]        if ($bf =~ /^\s+[.]type\s+([^,]+),\s*(\S+)/) {            ($sym,$val) = (,);            $val =~ s/^\@//;            $sym_type{$sym} = $val;            cmtprt("\n");            cmtprt("TYPE: %s --> %s\n",$sym,$val);            next;        }        # look for "label:"        if ($bf =~ /^([a-z_A-Z][a-z_A-Z0-9]*):$/) {            $sym = ;            next if ($sym_type{$sym} ne "function");            $fnc = $sym;            cmtprt("FUNCTION: %s\n",$fnc);            $fnx = {};            $fnx_lookup{$sym} = $fnx;            push(@fnxList,$fnx);            $fnx->{fnx_fnc} = $fnc;            $fnx->{fnx_outoff} = $outoff;            $uselook = {};            $fnx->{fnx_used} = $uselook;            $retList = [];            $fnx->{fnx_retList} = $retList;            $fixList = [];            $fnx->{fnx_fixList} = $fixList;            $sixList = [];            $fnx->{fnx_sixList} = $sixList;            next;        }        # remember all registers used by function:        while ($bf =~ /($regusergx)/gpo) {            $sym = ${^MATCH};            $val = $reguse_tobase{$sym};            dbgprt(3,"dofile: REGUSE sym='%s' val='%s'\n",$val);            $uselook->{$sym} += 1;            $uselook->{$val} += 1                if ($val ne $sym);        }        # handle returns        if ($bf =~ /^\s+ret/) {            push(@$retList,$outoff);            next;        }        if ($bf =~ /^\s+rep[a-z]*\s+ret/) {            push(@$retList,$outoff);            next;        }        # split up "movq 16(%rax),%rax" ...        $ix = rindex($bf,",");        next if ($ix < 0);        # ... into "movq 16(%rax)"        $lhs = substr($bf,$ix);        $lhs =~ s/\s+$//;        # check for "movq 16(%rsp)" -- this means that the function has/uses        # more than six arguments (i.e. we may _not_ push/pop because it        # wreaks havoc with positive offsets)        # FIXME/CAE -- we'd have to adjust them by 8 which we don't do        (undef,$rhs) = split(" ",$lhs);        if ($rhs =~ /^(\d+)[(]%rsp[)]$/) {            push(@$sixList,$outoff);            cmtprt("SIXARG: %s (line %d)\n",$rhs,$lno);        }        # ... and "%rax"        $rhs = substr($bf,$ix + 1);        $rhs =~ s/^\s+//;        # target must be a [simple] register [or source scan will blow up]        # (e.g. we actually had "cmp %ebp,(%rax,%r14)")        next if ($rhs =~ /[)]/);        # ensure we have the "%" prefix        next unless ($rhs =~ /^%/);        # we only want the full 64 bit reg as target        # (e.g. "mov (%rbx),%al" doesn't count)        $val = $reguse_tobase{$rhs};        if ($opt_a) {            next if ($val ne $rhs);        }        else {            next unless (defined($val));        }        # source operand must contain target [base] register        next unless ($lhs =~ /$val/);        ###cmtprt("1: %s,%s\n",$lhs,$rhs);        # source operand must be of the "right" type        # FIXME/CAE -- we may need to revise this        next unless ($lhs =~ /[(]/);        cmtprt("NEEDFIX: %s,%s (line %d)\n",$lno);        # remember the place we need to fix for later        $fix = {};        push(@$fixList,$fix);        $fix->{fix_outoff} = $outoff;        $fix->{fix_lhs} = $lhs;        $fix->{fix_rhs} = $rhs;    }    close($xfsrc);    # get total number of fixups    foreach $fnx (@fnxList) {        $fixList = $fnx->{fnx_fixList};        $fixtot += @$fixList;    }    msgprt("$pgmtail: needs %d fixups\n",$fixtot)        if ($fixtot > 0);    # fix each function    foreach $fnx (@fnxList) {        cmtprt("\n");        cmtprt("FNC: %s\n",$fnx->{fnx_fnc});        $fixList = $fnx->{fnx_fixList};        # get the fixup register        ($fixreg,$fixrtyp) = regtmploc($fnx,$fixList);        # show number of return points        {            $retList = $fnx->{fnx_retList};            cmtprt("  RET: %d\n",scalar(@$retList));            last if (@$retList >= 1);            # NOTE: we display this warning because we may not be able to            # handle all situations            $relaxflg = (@$fixList <= 0) || ($fixrtyp ne "P");            last if ($relaxflg && $opt_q);            errprt("$pgmtail: in file '%s'\n",$file);            errprt("$pgmtail: function '%s' has no return points\n",$fnx->{fnx_fnc});            errprt("$pgmtail: suggest recompile with correct options\n");            if (@$fixList <= 0) {                errprt("$pgmtail: working around because function needs no fixups\n");                last;            }            if ($fixrtyp ne "P") {                errprt("$pgmtail: working around because fixup reg does not need to be saved\n");                last;            }        }        # show stats on register usage in function        $uselook = $fnx->{fnx_used};        @useList = sort(keys(%$uselook));        cmtprt("  USED:\n");        %avail = %reguse_isbase;        foreach $sym (@useList) {            $val = $uselook->{$sym};            $typ = $regtmp_type{$sym};            $typ = sprintf(" (TYPE: %s)",$typ)                if (defined($typ));            cmtprt("    %s used %d%s\n",$typ);            $val = $reguse_tobase{$sym};            delete($avail{$val});        }        # show function's available [unused] registers        @useList = keys(%avail);        @useList = sort(regusesort @useList);        if (@useList > 0) {            cmtprt("  AVAIL:\n");            foreach $sym (@useList) {                $typ = $regtmp_type{$sym};                $typ = sprintf(" (TYPE: %s)",$typ)                    if (defined($typ));                cmtprt("    %s%s\n",$typ);            }        }        # skip over any functions that don't need fixing _and_ have a temp        # register        if (@$fixList <= 0 && (! $opt_P)) {            next if (defined($fixreg));        }        msgprt("$pgmtail: function %s\n",$fnx->{fnx_fnc});        # skip function because we don't have a fixup register but report it        # here        unless (defined($fixreg)) {            $bf = (@$fixList > 0) ? "FATAL" : "can be ignored -- no fixups needed";            msgprt("$pgmtail: FIXnorEG (%s)\n",$bf);            cmtprt("  FIXnorEG (%s)\n",$bf);            next;        }        msgprt("$pgmtail: FIXREG --> %s (TYPE: %s)\n",$fixreg,$fixrtyp);        cmtprt("  FIXREG --> %s (TYPE: %s)\n",$fixrtyp);        foreach $fix (@$fixList) {            $outoff = $fix->{fix_outoff};            undef(@fix);            cmtprt("  FIXolD %s\n",$outList[$outoff]);            # original            if ($opt_l) {                $bf = sprintf("%s,%s",$fix->{fix_lhs},$fixreg);                push(@fix,$bf);                $bf = sprintf("\tmov\t%s,$fix->{fix_rhs});                push(@fix,$bf);            }            # use lea            else {                ($xop,$arg) = split(" ",$fix->{fix_lhs});                $bf = sprintf("\tlea\t\t%s,$arg,$bf);                $bf = sprintf("\t%s\t(%s),$xop,$bf);            }            foreach $bf (@fix) {                cmtprt("  FIXNEW %s\n",$bf);            }            $outList[$outoff] = [@fix];        }        unless ($opt_P) {            next if ($fixrtyp ne "P");        }        # fix the function prolog        $outoff = $fnx->{fnx_outoff};        $lhs = $outList[$outoff];        $rhs = sprintf("\tpush\t%s",$fixreg);        $bf = [$lhs,""];        $outList[$outoff] = $bf;        # fix the function return points        $retList = $fnx->{fnx_retList};        foreach $outoff (@$retList) {            $rhs = $outList[$outoff];            $lhs = sprintf("\tpop\t%s",$fixreg);            $bf = ["",$rhs];            $outList[$outoff] = $bf;        }    }    open($xfdst,">$ofile") ||        sysfault("$pgmtail: unable to open '%s' -- $!\n",$ofile);    # output all the assembler text    foreach $bf (@outList) {        # ordinary line        unless (ref($bf)) {            print($xfdst $bf,"\n");            next;        }        # apply a fixup        foreach $rhs (@$bf) {            print($xfdst $rhs,"\n");        }    }    # output all our reasoning as comments at the bottom    foreach $bf (@cmtprt) {        if ($bf eq "") {            print($xfdst $cmtchr,$bf,"\n");        }        else {            print($xfdst $cmtchr," ","\n");        }    }    close($xfdst);    # get difference    if (defined($opt_D)) {        system("diff -u $file $ofile >> $opt_D");    }    # install fixed/modifIEd file    {        last unless ($opt_o || defined($opt_O));        last if ($fatal);        msgprt("$pgmtail: installing ...\n");        rename($ofile,$file);    }}# regtmpall -- define all temporary register candIDatessub regtmpall{    dbgprt(1,"regtmpall: ENTER\n");    regtmpdef("%r11","T");    # NOTES:    # (1) see notes on %r10 in ABI at bottom -- should we use it?    # (2) a web search on "shared chain" and "x86" only produces 28 results    # (3) some gcc code uses it as an ordinary register    # (4) so,use it unless told not to    regtmpdef("%r10","T")        unless ($opt_n10);    # argument registers (a6-a1)    regtmpdef("%r9","A6");    regtmpdef("%r8","A5");    regtmpdef("%rcx","A4");    regtmpdef("%rdx","A3");    regtmpdef("%rsi","A2");    regtmpdef("%rdi","A1");    # callee preserved registers    regtmpdef("%r15","P");    regtmpdef("%r14","P");    regtmpdef("%r13","P");    regtmpdef("%r12","P");    dbgprt(1,"regtmpall: EXIT\n");}# regtmpdef -- define usable temp registerssub regtmpdef{    my($sym,$typ) = @_;    dbgprt(1,"regtmpdef: SYM sym='%s' typ='%s'\n",$typ);    push(@regtmpList,$sym);    $regtmp_type{$sym} = $typ;}# regtmploc -- locate temp register to fix problemsub regtmploc{    my($fnx,$fixList) = @_;    my($sixList);    my($uselook);    my($regrhs);    my($fixcnt);    my($coretyp);    my($reglhs,$regtyp);    dbgprt(2,"regtmploc: ENTER fnx_fnc='%s'\n",$fnx->{fnx_fnc});    $sixList = $fnx->{fnx_sixList};    $fixcnt = @$fixList;    $fixcnt = 1        if ($opt_P);    $uselook = $fnx->{fnx_used};    foreach $regrhs (@regtmpList) {        dbgprt(2,"regtmploc: TRYREG regrhs='%s' uselook=%d\n",$regrhs,$uselook->{$regrhs});        unless ($uselook->{$regrhs}) {            $regtyp = $regtmp_type{$regrhs};            $coretyp = $regtyp;            $coretyp =~ s/\d+$//;            # function uses stack arguments -- we can't push/pop            if (($coretyp eq "P") && (@$sixList > 0)) {                dbgprt(2,"regtmploc: SIXREJ\n");                next;            }            if (defined($opt_N)) {                dbgprt(2,"regtmploc: TRYREJ opt_N='%s' regtyp='%s'\n",$opt_N,$regtyp);                next if ($opt_N =~ /$coretyp/);            }            $reglhs = $regrhs;            last;        }    }    {        last if (defined($reglhs));        errprt("regtmploc: unable to locate usable fixup register for function '%s'\n",$fnx->{fnx_fnc});        last if ($fixcnt <= 0);        $fatal = 1;    }    dbgprt(2,"regtmploc: EXIT reglhs='%s' regtyp='%s'\n",$reglhs,$regtyp);    ($reglhs,$regtyp);}# regusejoin -- get regex for all registerssub regusejoin{    my($reg);    dbgprt(1,"regusejoin: ENTER\n");    # rax    foreach $reg (qw(a b c d))  {        regusedef($reg,"r_x","e_x","_l","_h");    }    #   rdi/rsi    foreach $reg (qw(d s)) {        regusedef($reg,"r_i","e_i","_i","_il");    }    # rsp/rbp    foreach $reg (qw(b s)) {        regusedef($reg,"r_p","e_p");    }    foreach $reg (8,9,10,11,12,13,14,15) {        regusedef($reg,"r_","r_d","r_w","r_b");    }    $regusergx = join("|",reverse(sort(@reguse)));    dbgprt(1,"regusejoin: EXIT regusergx='%s'\n",$regusergx);}# regusedef -- define all registerssub regusedef{    my(@argv) = @_;    my($mID);    my($pat);    my($base);    $mID = shift(@argv);    dbgprt(1,"regusedef: ENTER mID='%s'\n",$mID);    foreach $pat (@argv) {        $pat = "%" . $pat;        $pat =~ s/_/$mID/;        $base //= $pat;        dbgprt(1,"regusedef: PAT pat='%s' base='%s'\n",$pat,$base);        push(@reguse,$pat);        $reguse_tobase{$pat} = $base;    }    $reguse_isbase{$base} = 1;    dbgprt(1,"regusedef: EXIT\n");}# regusesort -- sort base register namessub regusesort{    my($symlhs,$numlhs);    my($symrhs,$numrhs);    my($cmpflg);    {        ($symlhs,$numlhs) = _regusesort($a);        ($symrhs,$numrhs) = _regusesort($b);        $cmpflg = $symlhs cmp $symrhs;        last if ($cmpflg);        $cmpflg = $numlhs <=> $numrhs;    }    $cmpflg;}# _regusesort -- split up base register namesub _regusesort{    my($sym) = @_;    my($num);    if ($sym =~ s/(\d+)$//) {        $num = ;        $num += 0;        $sym =~ s/[^%]/z/g;    }    ($sym,$num);}# optget -- get optionssub optget{    my($argv) = @_;    my($bf);    my($sym,$val);    my($dft,%dft);    foreach $sym (qw(a l n10 P q o s T)) {        $dft{$sym} = 1;    }    $dft{"N"} = "T";    $dft{"D"} = "DIFF";    while (1) {        $bf = $argv->[0];        $sym = $bf;        last unless ($sym =~ s/^-//);        last if ($sym eq "-");        shift(@$argv);        {            if ($sym =~ /([^=]+)=(.+)$/) {                ($sym,);                last;            }            if ($sym =~ /^(.)(.+)$/) {                ($sym,);                last;            }            undef($val);        }        $dft = $dft{$sym};        sysfault("$pgmtail: unkNown option -- '%s'\n",$bf)            unless (defined($dft));        $val //= $dft;        ${"opt_" . $sym} = $val;    }}# cmtprt -- transformation commentssub cmtprt{    $_ = shift(@_);    $_ = sprintf($_,@_);    chomp($_);    push(@cmtprt,$_);}# msgprt -- progress outputsub msgprt{    printf(STDERR @_);}# errprt -- show errorssub errprt{    cmtprt(@_);    printf(STDERR @_);}# sysfault -- abort on errorsub sysfault{    printf(STDERR @_);    exit(1);}# dbgprt -- deBUG printsub dbgprt{    $_ = shift(@_);    goto &_dbgprt        if ($opt_T >= $_);}# _dbgprt -- deBUG printsub _dbgprt{    printf(STDERR @_);}

更新:

我已经更新了脚本来修复错误,添加更多的检查和更多的选项.注意:我不得不删除ABI在底部以适应30,000限制.

Otherwise weird results appear on other commands with parentheses for example lhs='cmpl %ebp,(%rax' splits into rhs='%r14)' and /$rhs/ which in turn causes $rhs =~ /%[er](.x|\d+)/ to fail.

是的,那是一个BUG.固定.

Your di doesn’t match byte or word loads to ax,or rdi / rsi. That’s unlikely,though. Oh,also,I think it fails to match

# function_original -- original function before pebsfixup# RETURNS: 23function_original:    mov     ,-4(%rsp)                # red zone code generated by compiler    ...    mov     -4(%rsp),%rax               # will still have     ret# function_pebsfixup -- pebsfixup modifIEd# RETURNS: 23function_pebsfixup:    push    %r12                        # pebsfixup injected    mov     ,%rax               # will still have     pop     %r12                        # pebsfixup injected    ret# function_inline -- function with inline asm block and red zone# RETURNS: unkNown valuefunction_inline:    mov     ,-4(%rsp)                # red zone code generated by compiler    # inline asm block -- steps on red zone    push    %rdx    push    %rcx    ...    pop     %rcx    pop     %rdx    ...    mov     -4(%rsp),%rax               # Now -4(%rsp) no longer has     ret
. so you don’t need the trailing d in r10d

固定.查找所有变体.

Wow,I assumed something like this would have to happen at compile time,and that doing it after the fact would be too messy.

无耻的插件:感谢“哇!”. perl对于像这样的凌乱的工作是非常好的.我以前写过这样的汇编器“注入”脚本. (例如)返回到[在编译器支持之前]添加分析调用的那一天.

You Could mark %r10 as another call-preserved register.

经过几次网页搜索,我只能在“静态链”x86上找到大约84场比赛.唯一的一个相关性是x86 ABI.而且,它不提供任何解释,除了提及它作为脚注.另外,一些gcc代码使用r10,没有任何保存作为被调用者注册.所以,我现在默认程序使用r10(如果需要,使用命令行选项来禁用它).

What happens if a function already uses all the registers?

如果真的是这样,那我们就不幸了.该脚本将检测并报告,并且如果找不到备用寄存器,则禁止fixup.

并且,它将使用“被调用者必须保留”注册,通过注入一个推送作为第一功能和相应的d出就在ret inst [可以有多个]之前.这可以通过选项禁用.

You can’t just push/pop,because that steps on the red-zone

不,不是的.原因如下:

(1)几乎作为附注:红色区域仅在叶子功能中有用.否则,如果fncA调用fncB,则fncA执行此 *** 作的唯一方法就是自己的红色区域.请参阅脚本的顶部注释块中的编译选项.

(2)更重要的是,由于push / pop的注入方式.推动发生在任何其他行为之前.流行音乐发生在任何其他动作之后[在ret之前].

红色区域仍然存在 – 完好无损.它只是偏离了-8,否则将被拒绝.所有红区活动都将被保留,因为这些insts使用来自%rsp的负偏移

这不同于内联asm块中的push / pop.通常的情况是红色区域代码(例如)mov $23,-4(%rsp).随后进行推送/d出的内嵌asm块将会顺利进行.

一些功能显示:

mov     32(%rsp),%rax

push / pop确实让我们陷入麻烦的是如果函数使用六个以上的参数(即args 7在堆栈上).访问这些参数使用%rsp的正偏移:

mov     40(%rsp),%rax

通过我们的“窍门”按钮,偏移量将不正确.现在正确的偏移量将高8:

[+++]

脚本会检测到这个并抱怨.但是,由于这种情况是低概率,它还没有调整正偏移量.它可能需要大约五行代码来解决这个问题.现在打乒乓球

总结

以上是内存溢出为你收集整理的将目标地址保持在寄存器中,直到指令退出全部内容,希望文章能够帮你解决将目标地址保持在寄存器中,直到指令退出所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
将目标地址保持在寄存器中,直到指令退出_C_内存溢出

将目标地址保持在寄存器中,直到指令退出

将目标地址保持在寄存器中,直到指令退出,第1张

概述我想使用精确的基于事件的采样(PEBS)在XeonE5 Sandy Bridge上记录特定事件的所有地址(例如高速缓存未命中). 但是,CoreTM i7处理器和英特尔®至强™5500处理器的性能分析指南(第24页)包含以下警告: As the PEBS mechanism captures the values of the register at completion of the instr 我想使用精确的基于事件的采样(PEBS)在XeonE5 Sandy BrIDge上记录特定事件的所有地址(例如高速缓存未命中).

但是,CoreTM i7处理器和英特尔®至强™5500处理器的性能分析指南(第24页)包含以下警告:

As the PEBS mechanism captures the values of the register at
completion of the instruction,the dereferenced address for the
following type of load instruction (Intel asm convention) cannot be
reconstructed.
MOV RAX,[RAX+const]
This kind of
instruction is mostly associated with pointer chasing
mystruc = mystruc->next;
This is a significant shortcoming of this
approach to capturing memory instruction addresses.

我根据objdump在我的程序中有一些加载说明.有什么办法可以避免吗?

由于这是一个特定于英特尔的问题,解决方案无须以任何方式进行移植,只需要运行.我的代码是用C编写的,我理想地寻找一个编译器级别的解决方案(gcc或icc),但是任何建议都是可以接受的.

一些例子:

mov    0x18(%rdi),%rdimov    (%rcx,%rax,8),%rax

在这两种情况下,在指令退出后(因此当我查看寄存器值以确定我加载到/从哪里)地址的值(这些示例中的%rdi 18和%rcx 8 *%rax)被覆盖由mov的结果.

解决方法 您想要做的是转换表单的所有说明:
mov    (%rcx,%rax

成:

mov    (%rcx,%r11mov    %r11,%rax

这可以通过修改编译器生成的汇编器源来更容易地完成.下面是一个Perl脚本,它将通过读取和修改.s文件来完成所有必要的转换.

只需更改生成.s文件而不是.o文件,应用脚本,然后使用as或gcc生成.o

这是实际的脚本.我已经在几个我自己的来源测试了,按照下面的评论中的构建过程.

该脚本具有以下功能:

>扫描并定位所有函数定义
>标识给定功能中使用的所有寄存器
>定位函数的所有返回点
>根据功能的寄存器使用情况选择要使用的临时寄存器(即将使用尚未由功能使用的临时寄存器)
>用两个指令序列代替所有“麻烦”指令
>尝试使用未使用的临时寄存器(例如%r11或未使用的参数寄存器),然后尝试使用被调用方保存的寄存器
>如果选择的注册表被保留,则会添加push到函数prolog并d出功能[multiple] ret语句
>维护所有分析和转换的日志,并将其作为注释追加到输出.s文件

#!/usr/bin/perl# pebsfix/pebsfixup -- fix assembler source for PEBS usage## command line options:#   "-a" -- use only full 64 bit targets#   "-l" -- do _not_ use lea#   "-D[diff-file]" -- show differences (default output: "./DIFF")#   "-n10" -- do _not_ use register %r10 for temporary (default is use it)#   "-o" -- overwrite input files (can be multiple)#   "-O<outfile>" -- output file (only one .s input allowed)#   "-q" -- suppress warnings#   "-T[lvl]" -- deBUG trace## "-o" and "-O" are mutually exclusive## command line script test options:#   "-N[TPA]" -- disable temp register types [for testing]#   "-P" -- force push/pop on all functions## command line arguments:#   1-- List of .s files to process [or directory to search]#       for a given file "foo.s",output is to "foo.TMP"#       if (-o is given,"foo.TMP" is renamed to "foo.s")## suggested usage:#   change build to produce .s files#   FROM:#     cc [options] -c foo.c#   TO:#     cc [options] -c -S foo.c#     pebsfixup -o foo.s#     cc -c foo.s## suggested compiler options:# [probably only really needed if push/pop required. use -NP to verify]#   (1) use either of#       -O2 -fno-optimize-sibling-calls#       -O1#   (2) use -mno-omit-leaf-frame-pointer#   (3) use -mno-red-zone [probably not required in any case]## NOTES:#   (1) red zones are only really useful for leaf functions (i.e. if fncA calls#       fncB,fncA's red zone would be clobbered)#   (2) pushing onto the stack isn't a problem if there is a formal stack frame#   (3) the push is okay if the function has no more than six arguments (i.e.#       does _not_ use positive offsets from %rsp to access them)#pragma pgmlnsuse strict qw(vars subs);our $pgmtail;our $opt_a;our $opt_T;our $opt_D;our $opt_l;our $opt_n10;our $opt_N;our $opt_P;our $opt_q;our $opt_o;our $opt_O;our $opt_s;our @reguse;our %reguse_tobase;our %reguse_isbase;our $regusergx;our @regtmpList;our %regtmp_type;our $diff;our $sepflg;our $fatal;our @cmtprt;master(@ARGV);exit(0);# master -- master controlsub master{    my(@argv) = @_;    my($xfsrc);    my($file,@files);    my($bf);    $pgmtail = "pebsfixup";    optget(\@argv);    # define all kNown/usable registers    regusejoin();    # define all registers that we may use as a temporary    regtmpall();    if (defined($opt_D)) {        unlink($opt_D);    }    # show usage    if (@argv <= 0) {        $file = cmpl %ebp,%r14);        open($xfsrc,"<$file") ||            sysfault("$pgmtail: unable to open '%s' -- $!\n",$file);        while ($bf = <$xfsrc>) {            chomp($bf);            next if ($bf =~ /^#!/);            last unless ($bf =~ s/^#//);            $bf =~ s/^# ?//;            print($bf,"\n");        }        close($xfsrc);        exit(1);    }    foreach $file (@argv) {        if (-d $file) {            dodir(\@files,$file);        }        else {            push(@files,$file);        }    }    if (defined($opt_O)) {        sysfault("$pgmtail: -O may have only one input file\n")            if (@files != 1);        sysfault("$pgmtail: -O and -o are mutually exclusive\n")            if ($opt_o);    }    foreach $file (@files) {        dofile($file);    }    if (defined($opt_D)) {        exec("less",$opt_D);    }}# dodir -- process directorysub dodir{    my($files,$dir) = @_;    my($file,@files);    @files = (`find $dir -type f -name '*.s'`);    foreach $file (@files) {        chomp($file);        push(@$files,$file);    }}# dofile -- process filesub dofile{    my($file) = @_;    my($ofile);    my($xfsrc);    my($xfdst);    my($bf,$lno,$outoff);    my($fixoff);    my($lhs,$rhs);    my($xop,$arg);    my($ix);    my($sym,$val,$typ);    my(%sym_type);    my($fnc,$fnx,%fnx_lookup,@fnxList);    my($retList);    my($uselook,@useList,%avail);    my($fixreg,$fixrtyp);    my($sixList);    my($fix,$fixList);    my($fixtot);    my(@fix);    my(@outList);    my($relaxflg);    my($cmtchr);    undef($fatal);    undef(@cmtprt);    msgprt("\n")        if ($sepflg);    $sepflg = 1;    msgprt("$pgmtail: processing %s ...\n",$file);    $cmtchr = "#";    cmtprt("%s\n","-" x 78);    cmtprt("file: %s\n",$file);    # get the output file    $ofile = $file;    sysfault("$pgmtail: bad suffix -- file='%s'\n",$file)        unless ($ofile =~ s/[.]s$//);    $ofile .= ".TMP";    # use explicit output file    if (defined($opt_O)) {        $ofile = $opt_O;        sysfault("$pgmtail: output file may not be input file -- use -o instead\n")            if ($ofile eq $file);    }    open($xfsrc,"<$file") ||        sysfault("$pgmtail: unable to open '%s' -- $!\n",$file);    $lno = 0;    while ($bf = <$xfsrc>) {        chomp($bf);        $bf =~ s/\s+$//;        $outoff = $lno;        ++$lno;        push(@outList,$bf);        # clang adds comments        $ix = index($bf,"#");        if ($ix >= 0) {            $bf = substr($bf,$ix);            $bf =~ s/\s+$//;        }        # look for ".type blah,@function"        # NOTE: this always comes before the actual label line [we hope ;-)]        if ($bf =~ /^\s+[.]type\s+([^,]+),\s*(\S+)/) {            ($sym,$val) = (,);            $val =~ s/^\@//;            $sym_type{$sym} = $val;            cmtprt("\n");            cmtprt("TYPE: %s --> %s\n",$sym,$val);            next;        }        # look for "label:"        if ($bf =~ /^([a-z_A-Z][a-z_A-Z0-9]*):$/) {            $sym = ;            next if ($sym_type{$sym} ne "function");            $fnc = $sym;            cmtprt("FUNCTION: %s\n",$fnc);            $fnx = {};            $fnx_lookup{$sym} = $fnx;            push(@fnxList,$fnx);            $fnx->{fnx_fnc} = $fnc;            $fnx->{fnx_outoff} = $outoff;            $uselook = {};            $fnx->{fnx_used} = $uselook;            $retList = [];            $fnx->{fnx_retList} = $retList;            $fixList = [];            $fnx->{fnx_fixList} = $fixList;            $sixList = [];            $fnx->{fnx_sixList} = $sixList;            next;        }        # remember all registers used by function:        while ($bf =~ /($regusergx)/gpo) {            $sym = ${^MATCH};            $val = $reguse_tobase{$sym};            dbgprt(3,"dofile: REGUSE sym='%s' val='%s'\n",$val);            $uselook->{$sym} += 1;            $uselook->{$val} += 1                if ($val ne $sym);        }        # handle returns        if ($bf =~ /^\s+ret/) {            push(@$retList,$outoff);            next;        }        if ($bf =~ /^\s+rep[a-z]*\s+ret/) {            push(@$retList,$outoff);            next;        }        # split up "movq 16(%rax),%rax" ...        $ix = rindex($bf,",");        next if ($ix < 0);        # ... into "movq 16(%rax)"        $lhs = substr($bf,$ix);        $lhs =~ s/\s+$//;        # check for "movq 16(%rsp)" -- this means that the function has/uses        # more than six arguments (i.e. we may _not_ push/pop because it        # wreaks havoc with positive offsets)        # FIXME/CAE -- we'd have to adjust them by 8 which we don't do        (undef,$rhs) = split(" ",$lhs);        if ($rhs =~ /^(\d+)[(]%rsp[)]$/) {            push(@$sixList,$outoff);            cmtprt("SIXARG: %s (line %d)\n",$rhs,$lno);        }        # ... and "%rax"        $rhs = substr($bf,$ix + 1);        $rhs =~ s/^\s+//;        # target must be a [simple] register [or source scan will blow up]        # (e.g. we actually had "cmp %ebp,(%rax,%r14)")        next if ($rhs =~ /[)]/);        # ensure we have the "%" prefix        next unless ($rhs =~ /^%/);        # we only want the full 64 bit reg as target        # (e.g. "mov (%rbx),%al" doesn't count)        $val = $reguse_tobase{$rhs};        if ($opt_a) {            next if ($val ne $rhs);        }        else {            next unless (defined($val));        }        # source operand must contain target [base] register        next unless ($lhs =~ /$val/);        ###cmtprt("1: %s,%s\n",$lhs,$rhs);        # source operand must be of the "right" type        # FIXME/CAE -- we may need to revise this        next unless ($lhs =~ /[(]/);        cmtprt("NEEDFIX: %s,%s (line %d)\n",$lno);        # remember the place we need to fix for later        $fix = {};        push(@$fixList,$fix);        $fix->{fix_outoff} = $outoff;        $fix->{fix_lhs} = $lhs;        $fix->{fix_rhs} = $rhs;    }    close($xfsrc);    # get total number of fixups    foreach $fnx (@fnxList) {        $fixList = $fnx->{fnx_fixList};        $fixtot += @$fixList;    }    msgprt("$pgmtail: needs %d fixups\n",$fixtot)        if ($fixtot > 0);    # fix each function    foreach $fnx (@fnxList) {        cmtprt("\n");        cmtprt("FNC: %s\n",$fnx->{fnx_fnc});        $fixList = $fnx->{fnx_fixList};        # get the fixup register        ($fixreg,$fixrtyp) = regtmploc($fnx,$fixList);        # show number of return points        {            $retList = $fnx->{fnx_retList};            cmtprt("  RET: %d\n",scalar(@$retList));            last if (@$retList >= 1);            # NOTE: we display this warning because we may not be able to            # handle all situations            $relaxflg = (@$fixList <= 0) || ($fixrtyp ne "P");            last if ($relaxflg && $opt_q);            errprt("$pgmtail: in file '%s'\n",$file);            errprt("$pgmtail: function '%s' has no return points\n",$fnx->{fnx_fnc});            errprt("$pgmtail: suggest recompile with correct options\n");            if (@$fixList <= 0) {                errprt("$pgmtail: working around because function needs no fixups\n");                last;            }            if ($fixrtyp ne "P") {                errprt("$pgmtail: working around because fixup reg does not need to be saved\n");                last;            }        }        # show stats on register usage in function        $uselook = $fnx->{fnx_used};        @useList = sort(keys(%$uselook));        cmtprt("  USED:\n");        %avail = %reguse_isbase;        foreach $sym (@useList) {            $val = $uselook->{$sym};            $typ = $regtmp_type{$sym};            $typ = sprintf(" (TYPE: %s)",$typ)                if (defined($typ));            cmtprt("    %s used %d%s\n",$typ);            $val = $reguse_tobase{$sym};            delete($avail{$val});        }        # show function's available [unused] registers        @useList = keys(%avail);        @useList = sort(regusesort @useList);        if (@useList > 0) {            cmtprt("  AVAIL:\n");            foreach $sym (@useList) {                $typ = $regtmp_type{$sym};                $typ = sprintf(" (TYPE: %s)",$typ)                    if (defined($typ));                cmtprt("    %s%s\n",$typ);            }        }        # skip over any functions that don't need fixing _and_ have a temp        # register        if (@$fixList <= 0 && (! $opt_P)) {            next if (defined($fixreg));        }        msgprt("$pgmtail: function %s\n",$fnx->{fnx_fnc});        # skip function because we don't have a fixup register but report it        # here        unless (defined($fixreg)) {            $bf = (@$fixList > 0) ? "FATAL" : "can be ignored -- no fixups needed";            msgprt("$pgmtail: FIXnorEG (%s)\n",$bf);            cmtprt("  FIXnorEG (%s)\n",$bf);            next;        }        msgprt("$pgmtail: FIXREG --> %s (TYPE: %s)\n",$fixreg,$fixrtyp);        cmtprt("  FIXREG --> %s (TYPE: %s)\n",$fixrtyp);        foreach $fix (@$fixList) {            $outoff = $fix->{fix_outoff};            undef(@fix);            cmtprt("  FIXolD %s\n",$outList[$outoff]);            # original            if ($opt_l) {                $bf = sprintf("%s,%s",$fix->{fix_lhs},$fixreg);                push(@fix,$bf);                $bf = sprintf("\tmov\t%s,$fix->{fix_rhs});                push(@fix,$bf);            }            # use lea            else {                ($xop,$arg) = split(" ",$fix->{fix_lhs});                $bf = sprintf("\tlea\t\t%s,$arg,$bf);                $bf = sprintf("\t%s\t(%s),$xop,$bf);            }            foreach $bf (@fix) {                cmtprt("  FIXNEW %s\n",$bf);            }            $outList[$outoff] = [@fix];        }        unless ($opt_P) {            next if ($fixrtyp ne "P");        }        # fix the function prolog        $outoff = $fnx->{fnx_outoff};        $lhs = $outList[$outoff];        $rhs = sprintf("\tpush\t%s",$fixreg);        $bf = [$lhs,""];        $outList[$outoff] = $bf;        # fix the function return points        $retList = $fnx->{fnx_retList};        foreach $outoff (@$retList) {            $rhs = $outList[$outoff];            $lhs = sprintf("\tpop\t%s",$fixreg);            $bf = ["",$rhs];            $outList[$outoff] = $bf;        }    }    open($xfdst,">$ofile") ||        sysfault("$pgmtail: unable to open '%s' -- $!\n",$ofile);    # output all the assembler text    foreach $bf (@outList) {        # ordinary line        unless (ref($bf)) {            print($xfdst $bf,"\n");            next;        }        # apply a fixup        foreach $rhs (@$bf) {            print($xfdst $rhs,"\n");        }    }    # output all our reasoning as comments at the bottom    foreach $bf (@cmtprt) {        if ($bf eq "") {            print($xfdst $cmtchr,$bf,"\n");        }        else {            print($xfdst $cmtchr," ","\n");        }    }    close($xfdst);    # get difference    if (defined($opt_D)) {        system("diff -u $file $ofile >> $opt_D");    }    # install fixed/modifIEd file    {        last unless ($opt_o || defined($opt_O));        last if ($fatal);        msgprt("$pgmtail: installing ...\n");        rename($ofile,$file);    }}# regtmpall -- define all temporary register candIDatessub regtmpall{    dbgprt(1,"regtmpall: ENTER\n");    regtmpdef("%r11","T");    # NOTES:    # (1) see notes on %r10 in ABI at bottom -- should we use it?    # (2) a web search on "shared chain" and "x86" only produces 28 results    # (3) some gcc code uses it as an ordinary register    # (4) so,use it unless told not to    regtmpdef("%r10","T")        unless ($opt_n10);    # argument registers (a6-a1)    regtmpdef("%r9","A6");    regtmpdef("%r8","A5");    regtmpdef("%rcx","A4");    regtmpdef("%rdx","A3");    regtmpdef("%rsi","A2");    regtmpdef("%rdi","A1");    # callee preserved registers    regtmpdef("%r15","P");    regtmpdef("%r14","P");    regtmpdef("%r13","P");    regtmpdef("%r12","P");    dbgprt(1,"regtmpall: EXIT\n");}# regtmpdef -- define usable temp registerssub regtmpdef{    my($sym,$typ) = @_;    dbgprt(1,"regtmpdef: SYM sym='%s' typ='%s'\n",$typ);    push(@regtmpList,$sym);    $regtmp_type{$sym} = $typ;}# regtmploc -- locate temp register to fix problemsub regtmploc{    my($fnx,$fixList) = @_;    my($sixList);    my($uselook);    my($regrhs);    my($fixcnt);    my($coretyp);    my($reglhs,$regtyp);    dbgprt(2,"regtmploc: ENTER fnx_fnc='%s'\n",$fnx->{fnx_fnc});    $sixList = $fnx->{fnx_sixList};    $fixcnt = @$fixList;    $fixcnt = 1        if ($opt_P);    $uselook = $fnx->{fnx_used};    foreach $regrhs (@regtmpList) {        dbgprt(2,"regtmploc: TRYREG regrhs='%s' uselook=%d\n",$regrhs,$uselook->{$regrhs});        unless ($uselook->{$regrhs}) {            $regtyp = $regtmp_type{$regrhs};            $coretyp = $regtyp;            $coretyp =~ s/\d+$//;            # function uses stack arguments -- we can't push/pop            if (($coretyp eq "P") && (@$sixList > 0)) {                dbgprt(2,"regtmploc: SIXREJ\n");                next;            }            if (defined($opt_N)) {                dbgprt(2,"regtmploc: TRYREJ opt_N='%s' regtyp='%s'\n",$opt_N,$regtyp);                next if ($opt_N =~ /$coretyp/);            }            $reglhs = $regrhs;            last;        }    }    {        last if (defined($reglhs));        errprt("regtmploc: unable to locate usable fixup register for function '%s'\n",$fnx->{fnx_fnc});        last if ($fixcnt <= 0);        $fatal = 1;    }    dbgprt(2,"regtmploc: EXIT reglhs='%s' regtyp='%s'\n",$reglhs,$regtyp);    ($reglhs,$regtyp);}# regusejoin -- get regex for all registerssub regusejoin{    my($reg);    dbgprt(1,"regusejoin: ENTER\n");    # rax    foreach $reg (qw(a b c d))  {        regusedef($reg,"r_x","e_x","_l","_h");    }    #   rdi/rsi    foreach $reg (qw(d s)) {        regusedef($reg,"r_i","e_i","_i","_il");    }    # rsp/rbp    foreach $reg (qw(b s)) {        regusedef($reg,"r_p","e_p");    }    foreach $reg (8,9,10,11,12,13,14,15) {        regusedef($reg,"r_","r_d","r_w","r_b");    }    $regusergx = join("|",reverse(sort(@reguse)));    dbgprt(1,"regusejoin: EXIT regusergx='%s'\n",$regusergx);}# regusedef -- define all registerssub regusedef{    my(@argv) = @_;    my($mID);    my($pat);    my($base);    $mID = shift(@argv);    dbgprt(1,"regusedef: ENTER mID='%s'\n",$mID);    foreach $pat (@argv) {        $pat = "%" . $pat;        $pat =~ s/_/$mID/;        $base //= $pat;        dbgprt(1,"regusedef: PAT pat='%s' base='%s'\n",$pat,$base);        push(@reguse,$pat);        $reguse_tobase{$pat} = $base;    }    $reguse_isbase{$base} = 1;    dbgprt(1,"regusedef: EXIT\n");}# regusesort -- sort base register namessub regusesort{    my($symlhs,$numlhs);    my($symrhs,$numrhs);    my($cmpflg);    {        ($symlhs,$numlhs) = _regusesort($a);        ($symrhs,$numrhs) = _regusesort($b);        $cmpflg = $symlhs cmp $symrhs;        last if ($cmpflg);        $cmpflg = $numlhs <=> $numrhs;    }    $cmpflg;}# _regusesort -- split up base register namesub _regusesort{    my($sym) = @_;    my($num);    if ($sym =~ s/(\d+)$//) {        $num = ;        $num += 0;        $sym =~ s/[^%]/z/g;    }    ($sym,$num);}# optget -- get optionssub optget{    my($argv) = @_;    my($bf);    my($sym,$val);    my($dft,%dft);    foreach $sym (qw(a l n10 P q o s T)) {        $dft{$sym} = 1;    }    $dft{"N"} = "T";    $dft{"D"} = "DIFF";    while (1) {        $bf = $argv->[0];        $sym = $bf;        last unless ($sym =~ s/^-//);        last if ($sym eq "-");        shift(@$argv);        {            if ($sym =~ /([^=]+)=(.+)$/) {                ($sym,);                last;            }            if ($sym =~ /^(.)(.+)$/) {                ($sym,);                last;            }            undef($val);        }        $dft = $dft{$sym};        sysfault("$pgmtail: unkNown option -- '%s'\n",$bf)            unless (defined($dft));        $val //= $dft;        ${"opt_" . $sym} = $val;    }}# cmtprt -- transformation commentssub cmtprt{    $_ = shift(@_);    $_ = sprintf($_,@_);    chomp($_);    push(@cmtprt,$_);}# msgprt -- progress outputsub msgprt{    printf(STDERR @_);}# errprt -- show errorssub errprt{    cmtprt(@_);    printf(STDERR @_);}# sysfault -- abort on errorsub sysfault{    printf(STDERR @_);    exit(1);}# dbgprt -- deBUG printsub dbgprt{    $_ = shift(@_);    goto &_dbgprt        if ($opt_T >= $_);}# _dbgprt -- deBUG printsub _dbgprt{    printf(STDERR @_);}

更新:

我已经更新了脚本来修复错误,添加更多的检查和更多的选项.注意:我不得不删除ABI在底部以适应30,000限制.

Otherwise weird results appear on other commands with parentheses for example lhs='cmpl %ebp,(%rax' splits into rhs='%r14)' and /$rhs/ which in turn causes $rhs =~ /%[er](.x|\d+)/ to fail.

是的,那是一个BUG.固定.

Your di doesn’t match byte or word loads to ax,or rdi / rsi. That’s unlikely,though. Oh,also,I think it fails to match

# function_original -- original function before pebsfixup# RETURNS: 23function_original:    mov     ,-4(%rsp)                # red zone code generated by compiler    ...    mov     -4(%rsp),%rax               # will still have     ret# function_pebsfixup -- pebsfixup modifIEd# RETURNS: 23function_pebsfixup:    push    %r12                        # pebsfixup injected    mov     ,%rax               # will still have     pop     %r12                        # pebsfixup injected    ret# function_inline -- function with inline asm block and red zone# RETURNS: unkNown valuefunction_inline:    mov     ,-4(%rsp)                # red zone code generated by compiler    # inline asm block -- steps on red zone    push    %rdx    push    %rcx    ...    pop     %rcx    pop     %rdx    ...    mov     -4(%rsp),%rax               # Now -4(%rsp) no longer has     ret
. so you don’t need the trailing d in r10d

固定.查找所有变体.

Wow,I assumed something like this would have to happen at compile time,and that doing it after the fact would be too messy.

无耻的插件:感谢“哇!”. perl对于像这样的凌乱的工作是非常好的.我以前写过这样的汇编器“注入”脚本. (例如)返回到[在编译器支持之前]添加分析调用的那一天.

You Could mark %r10 as another call-preserved register.

经过几次网页搜索,我只能在“静态链”x86上找到大约84场比赛.唯一的一个相关性是x86 ABI.而且,它不提供任何解释,除了提及它作为脚注.另外,一些gcc代码使用r10,没有任何保存作为被调用者注册.所以,我现在默认程序使用r10(如果需要,使用命令行选项来禁用它).

What happens if a function already uses all the registers?

如果真的是这样,那我们就不幸了.该脚本将检测并报告,并且如果找不到备用寄存器,则禁止fixup.

并且,它将使用“被调用者必须保留”注册,通过注入一个推送作为第一功能和相应的d出就在ret inst [可以有多个]之前.这可以通过选项禁用.

You can’t just push/pop,because that steps on the red-zone

不,不是的.原因如下:

(1)几乎作为附注:红色区域仅在叶子功能中有用.否则,如果fncA调用fncB,则fncA执行此 *** 作的唯一方法就是自己的红色区域.请参阅脚本的顶部注释块中的编译选项.

(2)更重要的是,由于push / pop的注入方式.推动发生在任何其他行为之前.流行音乐发生在任何其他动作之后[在ret之前].

红色区域仍然存在 – 完好无损.它只是偏离了-8,否则将被拒绝.所有红区活动都将被保留,因为这些insts使用来自%rsp的负偏移

这不同于内联asm块中的push / pop.通常的情况是红色区域代码(例如)mov $23,-4(%rsp).随后进行推送/d出的内嵌asm块将会顺利进行.

一些功能显示:

mov     32(%rsp),%rax

push / pop确实让我们陷入麻烦的是如果函数使用六个以上的参数(即args 7在堆栈上).访问这些参数使用%rsp的正偏移:

mov     40(%rsp),%rax

通过我们的“窍门”按钮,偏移量将不正确.现在正确的偏移量将高8:

脚本会检测到这个并抱怨.但是,由于这种情况是低概率,它还没有调整正偏移量.它可能需要大约五行代码来解决这个问题.现在打乒乓球

总结

以上是内存溢出为你收集整理的将目标地址保持在寄存器中,直到指令退出全部内容,希望文章能够帮你解决将目标地址保持在寄存器中,直到指令退出所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1233273.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存