mirror of https://github.com/lianthony/NT4.0
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
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;
|
|
}
|