Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

396 lines
10 KiB

/***********************************************************************
* Microsoft (R) 32-Bit Incremental Linker
*
* Copyright (C) Microsoft Corp 1992-95. All rights reserved.
*
* File: textpad.cpp
*
* File Comments:
*
* This module computes the pad required to align the specified text
* section so a branch does not cross a page boundary such that the
* delay slot is in the next page and the branch is dependent on a
* register load that is within the two preceeding instructions or
* the branch is preceeded by a divide instruction which is preceeded
* by any load or store instruction. This problem is present for R4000
* parts that are earlier than revision three.
*
***********************************************************************/
#include "link.h"
#include "mipsinst.h"
BOOL
CheckForDependentLoad (
PMIPS_INSTRUCTION Load,
DWORD Rs,
DWORD Rt
)
/*++
Routine Description:
This function checks for a load dependency in the specified instruction.
Arguments:
Load - Supplies a pointer to a possible load instruction that preceeds
a branch instruction that crosses a page boundary.
Rs - Supplies the register number of the Rs source register.
Rt - Supplies the register number of the Rt source register.
Return Value:
A value of TRUE is returned if a dependency is discovered. Otherwise,
a value of FALSE is returned.
--*/
{
// Switch on the opcode value.
switch (Load->i_format.Opcode) {
// Lb, lh, lwl, lw, lbu, lhu, lwr, ld, ll, and sc.
case LB_OP :
case LH_OP :
case LWL_OP :
case LW_OP :
case LBU_OP :
case LHU_OP :
case LWR_OP :
case LD_OP :
case LL_OP :
case SC_OP :
if ((Load->i_format.Rt == Rs) || (Load->i_format.Rt == Rt)) {
return TRUE;
}
break;
}
// No load dependency discovered.
return FALSE;
}
BOOL
CheckForDivideProblem (
PMIPS_INSTRUCTION Divide
)
/*++
Routine Description:
This function checks for a divide instruction preceeded by a load
or store instruction.
Arguments:
Divide - Supplies a pointer to a possible divide instruction that
preceeds a branch instruction that crosses a page boundary.
Return Value:
A value of TRUE is returned if a problem is discovered. Otherwise,
a value of FALSE is returned.
--*/
{
// If the opcode is a special opcode and the function is a divide,
// then check if the preceeding instruction is a load instruction.
if ((Divide->r_format.Opcode == SPEC_OP) &&
((Divide->r_format.Function == DIV_OP) ||
(Divide->r_format.Function == DIVU_OP))) {
// Switch on the next opcode value.
switch ((Divide - 1)->i_format.Opcode) {
// Lb, lh, lwl, lw, lbu, lhu, lwr, ld, ll, sb, sh, sw, swr,
// swl, sd, and sc.
case LB_OP :
case LH_OP :
case LWL_OP :
case LW_OP :
case LBU_OP :
case LHU_OP :
case LWR_OP :
case LD_OP :
case LL_OP :
case SB_OP :
case SH_OP :
case SWL_OP :
case SW_OP :
case SWR_OP :
case SD_OP :
case SC_OP :
return TRUE;
}
}
// No divide problem discovered.
return FALSE;
}
BOOL
CheckForProblemSequence (
DWORD *TextSection,
DWORD Offset
)
/*++
Routine Description:
This function determines if:
1) A branch instruction crosses a page and is dependent on a load
that lies within the previous two instructions.
2) A branch instruction crosses a page boundary and is preceeded
by a divide instruction which is preceeded by a load instruction.
3) A load instruction is the last instruction in a page and is
dependent on a load that lies within the previous two instructions.
Arguments:
TextSection - Supplies a pointer to the text section which contains
MIPS instructions.
Offset - Supplies the offset in the text section to the start of the
next page.
Return Value:
A value of TRUE is returned if a dependency is discovered. Otherwise,
a value of FALSE is returned.
--*/
{
PMIPS_INSTRUCTION Instruction;
// If there is room for an instruction and at least one load, then
// check for a problem at the next page boundary.
if (Offset <= 4) {
return(FALSE);
}
Instruction = (PMIPS_INSTRUCTION) ((BYTE *) TextSection + Offset - 4);
// Switch on the opcode value.
switch (Instruction->i_format.Opcode) {
// Beq, beql, bne, bnel, blez, blezl, bgtz, and, bgtzl.
case BEQ_OP :
case BEQL_OP :
case BNE_OP :
case BNEL_OP :
case BLEZ_OP :
case BLEZL_OP :
case BGTZ_OP :
case BGTZL_OP :
if (CheckForDependentLoad(Instruction - 1,
Instruction->i_format.Rs,
Instruction->i_format.Rt)) {
return TRUE;
}
if (Offset > 8) {
if (CheckForDependentLoad(Instruction - 2,
Instruction->i_format.Rs,
Instruction->i_format.Rt)) {
return TRUE;
}
if (CheckForDivideProblem(Instruction - 1)) {
return TRUE;
}
}
break;
// Special branch opcode - switch again on the rt field.
case BCOND_OP :
switch (Instruction->i_format.Rt) {
// Bltz, bgez, bltzl, bgezl, bltzal, bgezal, bltzall, and bgezall.
case BLTZ_OP :
case BGEZ_OP :
case BLTZL_OP :
case BGEZL_OP :
case BLTZAL_OP :
case BGEZAL_OP :
case BLTZALL_OP :
case BGEZALL_OP :
if (CheckForDependentLoad(Instruction - 1,
Instruction->i_format.Rs,
0)) {
return TRUE;
}
if (Offset > 8) {
if (CheckForDependentLoad(Instruction - 2,
Instruction->i_format.Rs,
0)) {
return TRUE;
}
if (CheckForDivideProblem(Instruction - 1)) {
return TRUE;
}
}
break;
}
break;
// J and jal.
case J_OP :
case JAL_OP :
if (Offset > 8) {
if (CheckForDivideProblem(Instruction - 1)) {
return TRUE;
}
}
break;
// Special opcode - switch again on the function code.
case SPEC_OP:
switch (Instruction->r_format.Function) {
// Div or Divu.
case DIV_OP :
case DIVU_OP :
return TRUE;
// Jalr or jr.
case JALR_OP :
case JR_OP :
if (CheckForDependentLoad(Instruction - 1,
Instruction->r_format.Rs,
0)) {
return TRUE;
}
if (Offset > 8) {
if (CheckForDependentLoad(Instruction - 2,
Instruction->r_format.Rs,
0)) {
return TRUE;
}
if (CheckForDivideProblem(Instruction -1)) {
return TRUE;
}
}
break;
}
break;
}
// No problems were found.
return FALSE;
}
BOOL
ComputeTextPad (
DWORD VirtualBase,
DWORD *TextSection,
DWORD Length,
DWORD PageSize,
DWORD *NewOffset
)
/*++
Routine Description:
This function computes the pad required to properly align the specified
text section.
Arguments:
VirtualBase - Supplies a pointer to the proposed virtual base of the
text section.
TextSection - Supplies a pointer to the text section which contains
MIPS instructions.
Length - Supplies the length of the text section in bytes.
PageSize - Supplies the page size for the target system the image is
being linked for.
AlignSize - The minimum alignment adjustment that can be made ( To preserve CON alignment)
Return Value:
A value less than zero is returned if the specified text section cannot
be aligned. Otherwise, the required alignment value is returned.
--*/
{
DWORD Offset;
DWORD NewBase;
// Attempt to align the section.
NewBase = VirtualBase;
do {
// Compute the offset to the end of the first page.
Offset = PageSize - (NewBase & (PageSize - 1));
// Iterate over the text section and check for problem branches.
while (Offset < Length) {
if (CheckForProblemSequence(TextSection, Offset)) {
break;
}
// Advance to next page boundary.
Offset += PageSize;
}
// If no dependencies were found, then return the correct padding
// value. Otherwise, advance to the next pad boundary and try again.
if (Offset >= Length) {
*NewOffset = NewBase - VirtualBase;
return TRUE;
}
NewBase += 4;
}
while ((NewBase - VirtualBase) < PageSize);
// The specified text section cannot be aligned within the specified
// number of iterations.
*NewOffset = Offset;
return FALSE;
}