1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027
|
/* tc-tahoe.c
Not part of GAS yet. */
#include "as.h"
#include "obstack.h"
/* this bit glommed from tahoe-inst.h */
typedef unsigned char byte;
typedef byte tahoe_opcodeT;
/*
* This is part of tahoe-ins-parse.c & friends.
* We want to parse a tahoe instruction text into a tree defined here.
*/
#define TIT_MAX_OPERANDS (4) /* maximum number of operands in one
single tahoe instruction */
struct top /* tahoe instruction operand */
{
int top_ndx; /* -1, or index register. eg 7=[R7] */
int top_reg; /* -1, or register number. eg 7 = R7 or (R7) */
byte top_mode; /* Addressing mode byte. This byte, defines
which of the 11 modes opcode is. */
char top_access; /* Access type wanted for this opperand
'b'branch ' 'no-instruction 'amrvw' */
char top_width; /* Operand width expected, one of "bwlq?-:!" */
char *top_error; /* Say if operand is inappropriate */
segT seg_of_operand; /* segment as returned by expression()*/
expressionS exp_of_operand; /* The expression as parsed by expression()*/
byte top_dispsize; /* Number of bytes in the displacement if we
can figure it out */
};
/* The addressing modes for an operand. These numbers are the acutal values
for certain modes, so be carefull if you screw with them. */
#define TAHOE_DIRECT_REG (0x50)
#define TAHOE_REG_DEFERRED (0x60)
#define TAHOE_REG_DISP (0xE0)
#define TAHOE_REG_DISP_DEFERRED (0xF0)
#define TAHOE_IMMEDIATE (0x8F)
#define TAHOE_IMMEDIATE_BYTE (0x88)
#define TAHOE_IMMEDIATE_WORD (0x89)
#define TAHOE_IMMEDIATE_LONGWORD (0x8F)
#define TAHOE_ABSOLUTE_ADDR (0x9F)
#define TAHOE_DISPLACED_RELATIVE (0xEF)
#define TAHOE_DISP_REL_DEFERRED (0xFF)
#define TAHOE_AUTO_DEC (0x7E)
#define TAHOE_AUTO_INC (0x8E)
#define TAHOE_AUTO_INC_DEFERRED (0x9E)
/* INDEXED_REG is decided by the existance or lack of a [reg] */
/* These are encoded into top_width when top_access=='b'
and it's a psuedo op.*/
#define TAHOE_WIDTH_ALWAYS_JUMP '-'
#define TAHOE_WIDTH_CONDITIONAL_JUMP '?'
#define TAHOE_WIDTH_BIG_REV_JUMP '!'
#define TAHOE_WIDTH_BIG_NON_REV_JUMP ':'
/* The hex code for certain tahoe commands and modes.
This is just for readability. */
#define TAHOE_JMP (0x71)
#define TAHOE_PC_REL_LONG (0xEF)
#define TAHOE_BRB (0x11)
#define TAHOE_BRW (0x13)
/* These, when 'ored' with, or added to, a register number,
set up the number for the displacement mode. */
#define TAHOE_PC_OR_BYTE (0xA0)
#define TAHOE_PC_OR_WORD (0xC0)
#define TAHOE_PC_OR_LONG (0xE0)
struct tit /* get it out of the sewer, it stands for
tahoe instruction tree (Geeze!) */
{
tahoe_opcodeT tit_opcode; /* The opcode. */
byte tit_operands; /* How many operands are here. */
struct top tit_operand[TIT_MAX_OPERANDS]; /* Operands */
char *tit_error; /* "" or fatal error text */
};
/* end: tahoe-inst.h */
/* tahoe.c - tahoe-specific -
Not part of gas yet.
*/
#include "opcode/tahoe.h"
/* This is the number to put at the beginning of the a.out file */
long omagic = OMAGIC;
/* These chars start a comment anywhere in a source file (except inside
another comment or a quoted string. */
const char comment_chars[] = "#;";
/* These chars only start a comment at the beginning of a line. */
const char line_comment_chars[] = "#";
/* Chars that can be used to separate mant from exp in floating point nums */
const char EXP_CHARS[] = "eE";
/* Chars that mean this number is a floating point constant
as in 0f123.456
or 0d1.234E-12 (see exp chars above)
Note: The Tahoe port doesn't support floating point constants. This is
consistant with 'as' If it's needed, I can always add it later. */
const char FLT_CHARS[] = "df";
/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
changed in read.c . Ideally it shouldn't have to know about it at all,
but nothing is ideal around here.
(The tahoe has plenty of room, so the change currently isn't needed.)
*/
static struct tit t; /* A tahoe instruction after decoding. */
void float_cons ();
/* A table of pseudo ops (sans .), the function called, and an integer op
that the function is called with. */
const pseudo_typeS md_pseudo_table[] =
{
{"dfloat", float_cons, 'd'},
{"ffloat", float_cons, 'f'},
{0}
};
/*
* For Tahoe, relative addresses of "just the right length" are pretty easy.
* The branch displacement is always the last operand, even in
* synthetic instructions.
* For Tahoe, we encode the relax_substateTs (in e.g. fr_substate) as:
*
* 4 3 2 1 0 bit number
* ---/ /--+-------+-------+-------+-------+-------+
* | what state ? | how long ? |
* ---/ /--+-------+-------+-------+-------+-------+
*
* The "how long" bits are 00=byte, 01=word, 10=long.
* This is a Un*x convention.
* Not all lengths are legit for a given value of (what state).
* The four states are listed below.
* The "how long" refers merely to the displacement length.
* The address usually has some constant bytes in it as well.
*
States for Tahoe address relaxing.
1. TAHOE_WIDTH_ALWAYS_JUMP (-)
Format: "b-"
Tahoe opcodes are: (Hex)
jr 11
jbr 11
Simple branch.
Always, 1 byte opcode, then displacement/absolute.
If word or longword, change opcode to brw or jmp.
2. TAHOE_WIDTH_CONDITIONAL_JUMP (?)
J<cond> where <cond> is a simple flag test.
Format: "b?"
Tahoe opcodes are: (Hex)
jneq/jnequ 21
jeql/jeqlu 31
jgtr 41
jleq 51
jgeq 81
jlss 91
jgtru a1
jlequ b1
jvc c1
jvs d1
jlssu/jcs e1
jgequ/jcc f1
Always, you complement 4th bit to reverse the condition.
Always, 1-byte opcode, then 1-byte displacement.
3. TAHOE_WIDTH_BIG_REV_JUMP (!)
Jbc/Jbs where cond tests a memory bit.
Format: "rlvlb!"
Tahoe opcodes are: (Hex)
jbs 0e
jbc 1e
Always, you complement 4th bit to reverse the condition.
Always, 1-byte opcde, longword, longword-address, 1-word-displacement
4. TAHOE_WIDTH_BIG_NON_REV_JUMP (:)
JaoblXX/Jbssi
Format: "rlmlb:"
Tahoe opcodes are: (Hex)
aojlss 2f
jaoblss 2f
aojleq 3f
jaobleq 3f
jbssi 5f
Always, we cannot reverse the sense of the branch; we have a word
displacement.
We need to modify the opcode is for class 1, 2 and 3 instructions.
After relax() we may complement the 4th bit of 2 or 3 to reverse sense of
branch.
We sometimes store context in the operand literal. This way we can figure out
after relax() what the original addressing mode was. (Was is pc_rel, or
pc_rel_disp? That sort of thing.) */
/* These displacements are relative to the START address of the
displacement which is at the start of the displacement, not the end of
the instruction. The hardware pc_rel is at the end of the instructions.
That's why all the displacements have the length of the displacement added
to them. (WF + length(word))
The first letter is Byte, Word.
2nd letter is Forward, Backward. */
#define BF (1+ 127)
#define BB (1+-128)
#define WF (2+ 32767)
#define WB (2+-32768)
/* Dont need LF, LB because they always reach. [They are coded as 0.] */
#define C(a,b) ENCODE_RELAX(a,b)
/* This macro has no side-effects. */
#define ENCODE_RELAX(what,length) (((what) << 2) + (length))
#define RELAX_STATE(what) ((what) >> 2)
#define RELAX_LENGTH(length) ((length) && 3)
#define STATE_ALWAYS_BRANCH (1)
#define STATE_CONDITIONAL_BRANCH (2)
#define STATE_BIG_REV_BRANCH (3)
#define STATE_BIG_NON_REV_BRANCH (4)
#define STATE_PC_RELATIVE (5)
#define STATE_BYTE (0)
#define STATE_WORD (1)
#define STATE_LONG (2)
#define STATE_UNDF (3) /* Symbol undefined in pass1 */
/* This is the table used by gas to figure out relaxing modes. The fields are
forward_branch reach, backward_branch reach, number of bytes it would take,
where the next biggest branch is. */
const relax_typeS md_relax_table[] =
{
{
1, 1, 0, 0
}, /* error sentinel 0,0 */
{
1, 1, 0, 0
}, /* unused 0,1 */
{
1, 1, 0, 0
}, /* unused 0,2 */
{
1, 1, 0, 0
}, /* unused 0,3 */
/* Unconditional branch cases "jrb"
The relax part is the actual displacement */
{
BF, BB, 1, C (1, 1)
}, /* brb B`foo 1,0 */
{
WF, WB, 2, C (1, 2)
}, /* brw W`foo 1,1 */
{
0, 0, 5, 0
}, /* Jmp L`foo 1,2 */
{
1, 1, 0, 0
}, /* unused 1,3 */
/* Reversible Conditional Branch. If the branch won't reach, reverse
it, and jump over a brw or a jmp that will reach. The relax part is the
actual address. */
{
BF, BB, 1, C (2, 1)
}, /* b<cond> B`foo 2,0 */
{
WF + 2, WB + 2, 4, C (2, 2)
}, /* brev over, brw W`foo, over: 2,1 */
{
0, 0, 7, 0
}, /* brev over, jmp L`foo, over: 2,2 */
{
1, 1, 0, 0
}, /* unused 2,3 */
/* Another type of reversable branch. But this only has a word
displacement. */
{
1, 1, 0, 0
}, /* unused 3,0 */
{
WF, WB, 2, C (3, 2)
}, /* jbX W`foo 3,1 */
{
0, 0, 8, 0
}, /* jrevX over, jmp L`foo, over: 3,2 */
{
1, 1, 0, 0
}, /* unused 3,3 */
/* These are the non reversable branches, all of which have a word
displacement. If I can't reach, branch over a byte branch, to a
jump that will reach. The jumped branch jumps over the reaching
branch, to continue with the flow of the program. It's like playing
leap frog. */
{
1, 1, 0, 0
}, /* unused 4,0 */
{
WF, WB, 2, C (4, 2)
}, /* aobl_ W`foo 4,1 */
{
0, 0, 10, 0
}, /*aobl_ W`hop,br over,hop: jmp L^foo,over 4,2*/
{
1, 1, 0, 0
}, /* unused 4,3 */
/* Normal displacement mode, no jumping or anything like that.
The relax points to one byte before the address, thats why all
the numbers are up by one. */
{
BF + 1, BB + 1, 2, C (5, 1)
}, /* B^"foo" 5,0 */
{
WF + 1, WB + 1, 3, C (5, 2)
}, /* W^"foo" 5,1 */
{
0, 0, 5, 0
}, /* L^"foo" 5,2 */
{
1, 1, 0, 0
}, /* unused 5,3 */
};
#undef C
#undef BF
#undef BB
#undef WF
#undef WB
/* End relax stuff */
/* Handle of the OPCODE hash table. NULL means any use before
md_begin() will crash. */
static struct hash_control *op_hash;
/* Init function. Build the hash table. */
void
md_begin ()
{
struct tot *tP;
char *errorval = 0;
int synthetic_too = 1; /* If 0, just use real opcodes. */
op_hash = hash_new ();
for (tP = totstrs; *tP->name && !errorval; tP++)
errorval = hash_insert (op_hash, tP->name, &tP->detail);
if (synthetic_too)
for (tP = synthetic_totstrs; *tP->name && !errorval; tP++)
errorval = hash_insert (op_hash, tP->name, &tP->detail);
if (errorval)
as_fatal (errorval);
}
CONST char *md_shortopts = "ad:STt:V";
struct option md_longopts[] = {
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof(md_longopts);
int
md_parse_option (c, arg)
int c;
char *arg;
{
switch (c)
{
case 'a':
as_warn ("The -a option doesn't exist. (Despite what the man page says!");
break;
case 'd':
as_warn ("Displacement length %s ignored!", arg);
break;
case 'S':
as_warn ("SYMBOL TABLE not implemented");
break;
case 'T':
as_warn ("TOKEN TRACE not implemented");
break;
case 't':
as_warn ("I don't need or use temp. file \"%s\".", arg);
break;
case 'V':
as_warn ("I don't use an interpass file! -V ignored");
break;
default:
return 0;
}
return 1;
}
void
md_show_usage (stream)
FILE *stream;
{
fprintf(stream, "\
Tahoe options:\n\
-a ignored\n\
-d LENGTH ignored\n\
-J ignored\n\
-S ignored\n\
-t FILE ignored\n\
-T ignored\n\
-V ignored\n");
}
/* The functions in this section take numbers in the machine format, and
munges them into Tahoe byte order.
They exist primarily for cross assembly purpose. */
void /* Knows about order of bytes in address. */
md_number_to_chars (con, value, nbytes)
char con[]; /* Return 'nbytes' of chars here. */
valueT value; /* The value of the bits. */
int nbytes; /* Number of bytes in the output. */
{
number_to_chars_bigendian (con, value, nbytes);
}
#ifdef comment
void /* Knows about order of bytes in address. */
md_number_to_imm (con, value, nbytes)
char con[]; /* Return 'nbytes' of chars here. */
long int value; /* The value of the bits. */
int nbytes; /* Number of bytes in the output. */
{
md_number_to_chars (con, value, nbytes);
}
#endif /* comment */
void
tc_apply_fix (fixP, val)
fixS *fixP;
long val;
{
/* should never be called */
know (0);
}
void /* Knows about order of bytes in address. */
md_number_to_disp (con, value, nbytes)
char con[]; /* Return 'nbytes' of chars here. */
long int value; /* The value of the bits. */
int nbytes; /* Number of bytes in the output. */
{
md_number_to_chars (con, value, nbytes);
}
void /* Knows about order of bytes in address. */
md_number_to_field (con, value, nbytes)
char con[]; /* Return 'nbytes' of chars here. */
long int value; /* The value of the bits. */
int nbytes; /* Number of bytes in the output. */
{
md_number_to_chars (con, value, nbytes);
}
/* Put the bits in an order that a tahoe will understand, despite the ordering
of the native machine.
On Tahoe: first 4 bytes are normal unsigned big endian long,
next three bytes are symbolnum, in kind of 3 byte big endian (least sig. byte last).
The last byte is broken up with bit 7 as pcrel,
bits 6 & 5 as length,
bit 4 as extern and the last nibble as 'undefined'. */
#if comment
void
md_ri_to_chars (ri_p, ri)
struct relocation_info *ri_p, ri;
{
byte the_bytes[sizeof (struct relocation_info)];
/* The reason I can't just encode these directly into ri_p is that
ri_p may point to ri. */
/* This is easy */
md_number_to_chars (the_bytes, ri.r_address, sizeof (ri.r_address));
/* now the fun stuff */
the_bytes[4] = (ri.r_symbolnum >> 16) & 0x0ff;
the_bytes[5] = (ri.r_symbolnum >> 8) & 0x0ff;
the_bytes[6] = ri.r_symbolnum & 0x0ff;
the_bytes[7] = (((ri.r_extern << 4) & 0x10) | ((ri.r_length << 5) & 0x60) |
((ri.r_pcrel << 7) & 0x80)) & 0xf0;
bcopy (the_bytes, (char *) ri_p, sizeof (struct relocation_info));
}
#endif /* comment */
/* Put the bits in an order that a tahoe will understand, despite the ordering
of the native machine.
On Tahoe: first 4 bytes are normal unsigned big endian long,
next three bytes are symbolnum, in kind of 3 byte big endian (least sig. byte last).
The last byte is broken up with bit 7 as pcrel,
bits 6 & 5 as length,
bit 4 as extern and the last nibble as 'undefined'. */
void
tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
char *where;
fixS *fixP;
relax_addressT segment_address_in_file;
{
long r_symbolnum;
know (fixP->fx_addsy != NULL);
md_number_to_chars (where,
fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
4);
r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy)
? S_GET_TYPE (fixP->fx_addsy)
: fixP->fx_addsy->sy_number);
where[4] = (r_symbolnum >> 16) & 0x0ff;
where[5] = (r_symbolnum >> 8) & 0x0ff;
where[6] = r_symbolnum & 0x0ff;
where[7] = (((is_pcrel (fixP) << 7) & 0x80)
| ((((fixP->fx_type == FX_8 || fixP->fx_type == FX_PCREL8
? 0
: (fixP->fx_type == FX_16 || fixP->fx_type == FX_PCREL16
? 1
: (fixP->fx_type == FX_32 || fixP->fx_type == FX_PCREL32
? 2
: 42)))) << 5) & 0x60)
| ((!S_IS_DEFINED (fixP->fx_addsy) << 4) & 0x10));
}
/* Relocate byte stuff */
/* This is for broken word. */
const int md_short_jump_size = 3;
void
md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
char *ptr;
addressT from_addr, to_addr;
fragS *frag;
symbolS *to_symbol;
{
valueT offset;
offset = to_addr - (from_addr + 1);
*ptr++ = TAHOE_BRW;
md_number_to_chars (ptr, offset, 2);
}
const int md_long_jump_size = 6;
const int md_reloc_size = 8; /* Size of relocation record */
void
md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
char *ptr;
addressT from_addr, to_addr;
fragS *frag;
symbolS *to_symbol;
{
valueT offset;
offset = to_addr - (from_addr + 4);
*ptr++ = TAHOE_JMP;
*ptr++ = TAHOE_PC_REL_LONG;
md_number_to_chars (ptr, offset, 4);
}
/*
* md_estimate_size_before_relax()
*
* Called just before relax().
* Any symbol that is now undefined will not become defined, so we assumed
* that it will be resolved by the linker.
* Return the correct fr_subtype in the frag, for relax()
* Return the initial "guess for fr_var" to caller. (How big I think this
* will be.)
* The guess for fr_var is ACTUALLY the growth beyond fr_fix.
* Whatever we do to grow fr_fix or fr_var contributes to our returned value.
* Although it may not be explicit in the frag, pretend fr_var starts with a
* 0 value.
*/
int
md_estimate_size_before_relax (fragP, segment_type)
register fragS *fragP;
segT segment_type; /* N_DATA or N_TEXT. */
{
register char *p;
register int old_fr_fix;
/* int pc_rel; FIXME: remove this */
old_fr_fix = fragP->fr_fix;
switch (fragP->fr_subtype)
{
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF):
if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
{
/* The symbol was in the same segment as the opcode, and it's
a real pc_rel case so it's a relaxable case. */
fragP->fr_subtype = ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE);
}
else
{
/* This case is still undefined, so asume it's a long word for the
linker to fix. */
p = fragP->fr_literal + old_fr_fix;
*p |= TAHOE_PC_OR_LONG;
/* We now know how big it will be, one long word. */
fragP->fr_fix += 1 + 4;
fix_new (fragP, old_fr_fix + 1, fragP->fr_symbol,
fragP->fr_offset, FX_PCREL32, NULL);
frag_wane (fragP);
}
break;
case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF):
if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
{
fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
}
else
{
p = fragP->fr_literal + old_fr_fix;
*fragP->fr_opcode ^= 0x10; /* Reverse sense of branch. */
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = TAHOE_PC_REL_LONG;
fragP->fr_fix += 1 + 1 + 1 + 4;
fix_new (fragP, old_fr_fix + 3, fragP->fr_symbol,
fragP->fr_offset, FX_PCREL32, NULL);
frag_wane (fragP);
}
break;
case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_UNDF):
if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
{
fragP->fr_subtype =
ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_WORD);
}
else
{
p = fragP->fr_literal + old_fr_fix;
*fragP->fr_opcode ^= 0x10; /* Reverse sense of branch. */
*p++ = 0;
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = TAHOE_PC_REL_LONG;
fragP->fr_fix += 2 + 2 + 4;
fix_new (fragP, old_fr_fix + 4, fragP->fr_symbol,
fragP->fr_offset, FX_PCREL32, NULL);
frag_wane (fragP);
}
break;
case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_UNDF):
if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
{
fragP->fr_subtype = ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_WORD);
}
else
{
p = fragP->fr_literal + old_fr_fix;
*p++ = 2;
*p++ = 0;
*p++ = TAHOE_BRB;
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = TAHOE_PC_REL_LONG;
fragP->fr_fix += 2 + 2 + 2 + 4;
fix_new (fragP, old_fr_fix + 6, fragP->fr_symbol,
fragP->fr_offset, FX_PCREL32, NULL);
frag_wane (fragP);
}
break;
case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_UNDF):
if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
{
fragP->fr_subtype = ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE);
}
else
{
p = fragP->fr_literal + old_fr_fix;
*fragP->fr_opcode = TAHOE_JMP;
*p++ = TAHOE_PC_REL_LONG;
fragP->fr_fix += 1 + 4;
fix_new (fragP, old_fr_fix + 1, fragP->fr_symbol,
fragP->fr_offset, FX_PCREL32, NULL);
frag_wane (fragP);
}
break;
default:
break;
}
return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
} /* md_estimate_size_before_relax() */
/*
* md_convert_frag();
*
* Called after relax() is finished.
* In: Address of frag.
* fr_type == rs_machine_dependent.
* fr_subtype is what the address relaxed to.
*
* Out: Any fixSs and constants are set up.
* Caller will turn frag into a ".space 0".
*/
void
md_convert_frag (headers, seg, fragP)
object_headers *headers;
segT seg;
register fragS *fragP;
{
register char *addressP; /* -> _var to change. */
register char *opcodeP; /* -> opcode char(s) to change. */
register short int length_code; /* 2=long 1=word 0=byte */
register short int extension = 0; /* Size of relaxed address.
Added to fr_fix: incl. ALL var chars. */
register symbolS *symbolP;
register long int where;
register long int address_of_var;
/* Where, in file space, is _var of *fragP? */
register long int target_address;
/* Where, in file space, does addr point? */
know (fragP->fr_type == rs_machine_dependent);
length_code = RELAX_LENGTH (fragP->fr_subtype);
know (length_code >= 0 && length_code < 3);
where = fragP->fr_fix;
addressP = fragP->fr_literal + where;
opcodeP = fragP->fr_opcode;
symbolP = fragP->fr_symbol;
know (symbolP);
target_address = S_GET_VALUE (symbolP) + fragP->fr_offset;
address_of_var = fragP->fr_address + where;
switch (fragP->fr_subtype)
{
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE):
/* *addressP holds the registers number, plus 0x10, if it's deferred
mode. To set up the right mode, just OR the size of this displacement */
/* Byte displacement. */
*addressP++ |= TAHOE_PC_OR_BYTE;
*addressP = target_address - (address_of_var + 2);
extension = 2;
break;
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD):
/* Word displacement. */
*addressP++ |= TAHOE_PC_OR_WORD;
md_number_to_chars (addressP, target_address - (address_of_var + 3), 2);
extension = 3;
break;
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_LONG):
/* Long word displacement. */
*addressP++ |= TAHOE_PC_OR_LONG;
md_number_to_chars (addressP, target_address - (address_of_var + 5), 4);
extension = 5;
break;
case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
*addressP = target_address - (address_of_var + 1);
extension = 1;
break;
case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
*opcodeP ^= 0x10; /* Reverse sense of test. */
*addressP++ = 3; /* Jump over word branch */
*addressP++ = TAHOE_BRW;
md_number_to_chars (addressP, target_address - (address_of_var + 4), 2);
extension = 4;
break;
case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_LONG):
*opcodeP ^= 0x10; /* Reverse sense of test. */
*addressP++ = 6;
*addressP++ = TAHOE_JMP;
*addressP++ = TAHOE_PC_REL_LONG;
md_number_to_chars (addressP, target_address, 4);
extension = 7;
break;
case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE):
*addressP = target_address - (address_of_var + 1);
extension = 1;
break;
case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_WORD):
*opcodeP = TAHOE_BRW;
md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
extension = 2;
break;
case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_LONG):
*opcodeP = TAHOE_JMP;
*addressP++ = TAHOE_PC_REL_LONG;
md_number_to_chars (addressP, target_address - (address_of_var + 5), 4);
extension = 5;
break;
case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_WORD):
md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
extension = 2;
break;
case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_LONG):
*opcodeP ^= 0x10;
*addressP++ = 0;
*addressP++ = 6;
*addressP++ = TAHOE_JMP;
*addressP++ = TAHOE_PC_REL_LONG;
md_number_to_chars (addressP, target_address, 4);
extension = 8;
break;
case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_WORD):
md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
extension = 2;
break;
case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_LONG):
*addressP++ = 0;
*addressP++ = 2;
*addressP++ = TAHOE_BRB;
*addressP++ = 6;
*addressP++ = TAHOE_JMP;
*addressP++ = TAHOE_PC_REL_LONG;
md_number_to_chars (addressP, target_address, 4);
extension = 10;
break;
default:
BAD_CASE (fragP->fr_subtype);
break;
}
fragP->fr_fix += extension;
} /* md_convert_frag */
/* This is the stuff for md_assemble. */
#define FP_REG 13
#define SP_REG 14
#define PC_REG 15
#define BIGGESTREG PC_REG
/*
* Parse the string pointed to by START
* If it represents a valid register, point START to the character after
* the last valid register char, and return the register number (0-15).
* If invalid, leave START alone, return -1.
* The format has to be exact. I don't do things like eat leading zeros
* or the like.
* Note: This doesn't check for the next character in the string making
* this invalid. Ex: R123 would return 12, it's the callers job to check
* what start is point to apon return.
*
* Valid registers are R1-R15, %1-%15, FP (13), SP (14), PC (15)
* Case doesn't matter.
*/
int
tahoe_reg_parse (start)
char **start; /* A pointer to the string to parse. */
{
register char *regpoint = *start;
register int regnum = -1;
switch (*regpoint++)
{
case '%': /* Registers can start with a %,
R or r, and then a number. */
case 'R':
case 'r':
if (isdigit (*regpoint))
{
/* Got the first digit. */
regnum = *regpoint++ - '0';
if ((regnum == 1) && isdigit (*regpoint))
{
/* Its a two digit number. */
regnum = 10 + (*regpoint++ - '0');
if (regnum > BIGGESTREG)
{ /* Number too big? */
regnum = -1;
}
}
}
break;
case 'F': /* Is it the FP */
case 'f':
switch (*regpoint++)
{
case 'p':
case 'P':
regnum = FP_REG;
}
break;
case 's': /* How about the SP */
case 'S':
switch (*regpoint++)
{
case 'p':
case 'P':
regnum = SP_REG;
}
break;
case 'p': /* OR the PC even */
case 'P':
switch (*regpoint++)
{
case 'c':
case 'C':
regnum = PC_REG;
}
break;
}
if (regnum != -1)
{ /* No error, so move string pointer */
*start = regpoint;
}
return regnum; /* Return results */
} /* tahoe_reg_parse */
/*
* This chops up an operand and figures out its modes and stuff.
* It's a little touchy about extra characters.
* Optex to start with one extra character so it can be overwritten for
* the backward part of the parsing.
* You can't put a bunch of extra characters in side to
* make the command look cute. ie: * foo ( r1 ) [ r0 ]
* If you like doing a lot of typing, try COBOL!
* Actually, this parser is a little weak all around. It's designed to be
* used with compliers, so I emphisise correct decoding of valid code quickly
* rather that catching every possable error.
* Note: This uses the expression function, so save input_line_pointer before
* calling.
*
* Sperry defines the semantics of address modes (and values)
* by a two-letter code, explained here.
*
* letter 1: access type
*
* a address calculation - no data access, registers forbidden
* b branch displacement
* m read - let go of bus - write back "modify"
* r read
* w write
* v bit field address: like 'a' but registers are OK
*
* letter 2: data type (i.e. width, alignment)
*
* b byte
* w word
* l longword
* q quadword (Even regs < 14 allowed) (if 12, you get a warning)
* - unconditional synthetic jbr operand
* ? simple synthetic reversable branch operand
* ! complex synthetic reversable branch operand
* : complex synthetic non-reversable branch operand
*
* The '-?!:' letter 2's are not for external consumption. They are used
* by GAS for psuedo ops relaxing code.
*
* After parsing topP has:
*
* top_ndx: -1, or the index register. eg 7=[R7]
* top_reg: -1, or register number. eg 7 = R7 or (R7)
* top_mode: The addressing mode byte. This byte, defines which of
* the 11 modes opcode is.
* top_access: Access type wanted for this opperand 'b'branch ' '
* no-instruction 'amrvw'
* top_width: Operand width expected, one of "bwlq?-:!"
* exp_of_operand: The expression as parsed by expression()
* top_dispsize: Number of bytes in the displacement if we can figure it
* out and it's relavent.
*
* Need syntax checks built.
*/
void
tip_op (optex, topP)
char *optex; /* The users text input, with one leading character */
struct top *topP; /* The tahoe instruction with some fields already set:
in: access, width
out: ndx, reg, mode, error, dispsize */
{
int mode = 0; /* This operand's mode. */
char segfault = *optex; /* To keep the back parsing from freaking. */
char *point = optex + 1; /* Parsing from front to back. */
char *end; /* Parsing from back to front. */
int reg = -1; /* major register, -1 means absent */
int imreg = -1; /* Major register in immediate mode */
int ndx = -1; /* index register number, -1 means absent */
char dec_inc = ' '; /* Is the SP auto-incremented '+' or
auto-decremented '-' or neither ' '. */
int immediate = 0; /* 1 if '$' immediate mode */
int call_width = 0; /* If the caller casts the displacement */
int abs_width = 0; /* The width of the absolute displacment */
int com_width = 0; /* Displacement width required by branch */
int deferred = 0; /* 1 if '*' deferral is used */
byte disp_size = 0; /* How big is this operand. 0 == don't know */
char *op_bad = ""; /* Bad operand error */
char *tp, *temp, c; /* Temporary holders */
char access = topP->top_access; /* Save on a deref. */
char width = topP->top_width;
int really_none = 0; /* Empty expressions evaluate to 0
but I need to know if it's there or not */
expressionS *expP; /* -> expression values for this operand */
/* Does this command restrict the displacement size. */
if (access == 'b')
com_width = (width == 'b' ? 1 :
(width == 'w' ? 2 :
(width == 'l' ? 4 : 0)));
*optex = '\0'; /* This is kind of a back stop for all
the searches to fail on if needed.*/
if (*point == '*')
{ /* A dereference? */
deferred = 1;
point++;
}
/* Force words into a certain mode */
/* Bitch, Bitch, Bitch! */
/*
* Using the ^ operator is ambigous. If I have an absolute label
* called 'w' set to, say 2, and I have the expression 'w^1', do I get
* 1, forced to be in word displacement mode, or do I get the value of
* 'w' or'ed with 1 (3 in this case).
* The default is 'w' as an offset, so that's what I use.
* Stick with `, it does the same, and isn't ambig.
*/
if (*point != '\0' && ((point[1] == '^') || (point[1] == '`')))
switch (*point)
{
case 'b':
case 'B':
case 'w':
case 'W':
case 'l':
case 'L':
if (com_width)
as_warn ("Casting a branch displacement is bad form, and is ignored.");
else
{
c = (isupper (*point) ? tolower (*point) : *point);
call_width = ((c == 'b') ? 1 :
((c == 'w') ? 2 : 4));
}
point += 2;
break;
}
/* Setting immediate mode */
if (*point == '$')
{
immediate = 1;
point++;
}
/*
* I've pulled off all the easy stuff off the front, move to the end and
* yank.
*/
for (end = point; *end != '\0'; end++) /* Move to the end. */
;
if (end != point) /* Null string? */
end--;
if (end > point && *end == ' ' && end[-1] != '\'')
end--; /* Hop white space */
/* Is this an index reg. */
if ((*end == ']') && (end[-1] != '\''))
{
temp = end;
/* Find opening brace. */
for (--end; (*end != '[' && end != point); end--)
;
/* If I found the opening brace, get the index register number. */
if (*end == '[')
{
tp = end + 1; /* tp should point to the start of a reg. */
ndx = tahoe_reg_parse (&tp);
if (tp != temp)
{ /* Reg. parse error. */
ndx = -1;
}
else
{
end--; /* Found it, move past brace. */
}
if (ndx == -1)
{
op_bad = "Couldn't parse the [index] in this operand.";
end = point; /* Force all the rest of the tests to fail. */
}
}
else
{
op_bad = "Couldn't find the opening '[' for the index of this operand.";
end = point; /* Force all the rest of the tests to fail. */
}
}
/* Post increment? */
if (*end == '+')
{
dec_inc = '+';
/* was: *end--; */
end--;
}
/* register in parens? */
if ((*end == ')') && (end[-1] != '\''))
{
temp = end;
/* Find opening paren. */
for (--end; (*end != '(' && end != point); end--)
;
/* If I found the opening paren, get the register number. */
if (*end == '(')
{
tp = end + 1;
reg = tahoe_reg_parse (&tp);
if (tp != temp)
{
/* Not a register, but could be part of the expression. */
reg = -1;
end = temp; /* Rest the pointer back */
}
else
{
end--; /* Found the reg. move before opening paren. */
}
}
else
{
op_bad = "Couldn't find the opening '(' for the deref of this operand.";
end = point; /* Force all the rest of the tests to fail. */
}
}
/* Pre decrement? */
if (*end == '-')
{
if (dec_inc != ' ')
{
op_bad = "Operand can't be both pre-inc and post-dec.";
end = point;
}
else
{
dec_inc = '-';
/* was: *end--; */
end--;
}
}
/*
* Everything between point and end is the 'expression', unless it's
* a register name.
*/
c = end[1];
end[1] = '\0';
tp = point;
imreg = tahoe_reg_parse (&point); /* Get the immediate register
if it is there.*/
if (*point != '\0')
{
/* If there is junk after point, then the it's not immediate reg. */
point = tp;
imreg = -1;
}
if (imreg != -1 && reg != -1)
op_bad = "I parsed 2 registers in this operand.";
/*
* Evaluate whats left of the expression to see if it's valid.
* Note again: This assumes that the calling expression has saved
* input_line_pointer. (Nag, nag, nag!)
*/
if (*op_bad == '\0')
{
/* statement has no syntax goofs yet: lets sniff the expression */
input_line_pointer = point;
expP = &(topP->exp_of_operand);
topP->seg_of_operand = expression (expP);
switch (expP->X_op)
{
case O_absent:
/* No expression. For BSD4.2 compatibility, missing expression is
absolute 0 */
expP->X_op = O_constant;
expP->X_add_number = 0;
really_none = 1;
case O_constant:
/* for SEG_ABSOLUTE, we shouldnt need to set X_op_symbol,
X_add_symbol to any particular value. */
/* But, we will program defensively. Since this situation occurs
rarely so it costs us little to do so. */
expP->X_add_symbol = NULL;
expP->X_op_symbol = NULL;
/* How many bytes are needed to express this abs value? */
abs_width =
((((expP->X_add_number & 0xFFFFFF80) == 0) ||
((expP->X_add_number & 0xFFFFFF80) == 0xFFFFFF80)) ? 1 :
(((expP->X_add_number & 0xFFFF8000) == 0) ||
((expP->X_add_number & 0xFFFF8000) == 0xFFFF8000)) ? 2 : 4);
case O_symbol:
break;
default:
/*
* Major bug. We can't handle the case of a operator
* expression in a synthetic opcode variable-length
* instruction. We don't have a frag type that is smart
* enough to relax a operator, and so we just force all
* operators to behave like SEG_PASS1s. Clearly, if there is
* a demand we can invent a new or modified frag type and
* then coding up a frag for this case will be easy.
*/
need_pass_2 = 1;
op_bad = "Can't relocate expression error.";
break;
case O_big:
/* This is an error. Tahoe doesn't allow any expressions
bigger that a 32 bit long word. Any bigger has to be referenced
by address. */
op_bad = "Expression is too large for a 32 bits.";
break;
}
if (*input_line_pointer != '\0')
{
op_bad = "Junk at end of expression.";
}
}
end[1] = c;
/* I'm done, so restore optex */
*optex = segfault;
/*
* At this point in the game, we (in theory) have all the components of
* the operand at least parsed. Now it's time to check for syntax/semantic
* errors, and build the mode.
* This is what I have:
* deferred = 1 if '*'
* call_width = 0,1,2,4
* abs_width = 0,1,2,4
* com_width = 0,1,2,4
* immediate = 1 if '$'
* ndx = -1 or reg num
* dec_inc = '-' or '+' or ' '
* reg = -1 or reg num
* imreg = -1 or reg num
* topP->exp_of_operand
* really_none
*/
/* Is there a displacement size? */
disp_size = (call_width ? call_width :
(com_width ? com_width :
abs_width ? abs_width : 0));
if (*op_bad == '\0')
{
if (imreg != -1)
{
/* Rn */
mode = TAHOE_DIRECT_REG;
if (deferred || immediate || (dec_inc != ' ') ||
(reg != -1) || !really_none)
op_bad = "Syntax error in direct register mode.";
else if (ndx != -1)
op_bad = "You can't index a register in direct register mode.";
else if (imreg == SP_REG && access == 'r')
op_bad =
"SP can't be the source operand with direct register addressing.";
else if (access == 'a')
op_bad = "Can't take the address of a register.";
else if (access == 'b')
op_bad = "Direct Register can't be used in a branch.";
else if (width == 'q' && ((imreg % 2) || (imreg > 13)))
op_bad = "For quad access, the register must be even and < 14.";
else if (call_width)
op_bad = "You can't cast a direct register.";
if (*op_bad == '\0')
{
/* No errors, check for warnings */
if (width == 'q' && imreg == 12)
as_warn ("Using reg 14 for quadwords can tromp the FP register.");
reg = imreg;
}
/* We know: imm = -1 */
}
else if (dec_inc == '-')
{
/* -(SP) */
mode = TAHOE_AUTO_DEC;
if (deferred || immediate || !really_none)
op_bad = "Syntax error in auto-dec mode.";
else if (ndx != -1)
op_bad = "You can't have an index auto dec mode.";
else if (access == 'r')
op_bad = "Auto dec mode cant be used for reading.";
else if (reg != SP_REG)
op_bad = "Auto dec only works of the SP register.";
else if (access == 'b')
op_bad = "Auto dec can't be used in a branch.";
else if (width == 'q')
op_bad = "Auto dec won't work with quadwords.";
/* We know: imm = -1, dec_inc != '-' */
}
else if (dec_inc == '+')
{
if (immediate || !really_none)
op_bad = "Syntax error in one of the auto-inc modes.";
else if (deferred)
{
/* *(SP)+ */
mode = TAHOE_AUTO_INC_DEFERRED;
if (reg != SP_REG)
op_bad = "Auto inc deferred only works of the SP register.";
else if (ndx != -1)
op_bad = "You can't have an index auto inc deferred mode.";
else if (access == 'b')
op_bad = "Auto inc can't be used in a branch.";
}
else
{
/* (SP)+ */
mode = TAHOE_AUTO_INC;
if (access == 'm' || access == 'w')
op_bad = "You can't write to an auto inc register.";
else if (reg != SP_REG)
op_bad = "Auto inc only works of the SP register.";
else if (access == 'b')
op_bad = "Auto inc can't be used in a branch.";
else if (width == 'q')
op_bad = "Auto inc won't work with quadwords.";
else if (ndx != -1)
op_bad = "You can't have an index in auto inc mode.";
}
/* We know: imm = -1, dec_inc == ' ' */
}
else if (reg != -1)
{
if ((ndx != -1) && (reg == SP_REG))
op_bad = "You can't index the sp register.";
if (deferred)
{
/* *<disp>(Rn) */
mode = TAHOE_REG_DISP_DEFERRED;
if (immediate)
op_bad = "Syntax error in register displaced mode.";
}
else if (really_none)
{
/* (Rn) */
mode = TAHOE_REG_DEFERRED;
/* if reg = SP then cant be indexed */
}
else
{
/* <disp>(Rn) */
mode = TAHOE_REG_DISP;
}
/* We know: imm = -1, dec_inc == ' ', Reg = -1 */
}
else
{
if (really_none)
op_bad = "An offest is needed for this operand.";
if (deferred && immediate)
{
/* *$<ADDR> */
mode = TAHOE_ABSOLUTE_ADDR;
disp_size = 4;
}
else if (immediate)
{
/* $<disp> */
mode = TAHOE_IMMEDIATE;
if (ndx != -1)
op_bad = "You can't index a register in immediate mode.";
if (access == 'a')
op_bad = "Immediate access can't be used as an address.";
/* ponder the wisdom of a cast because it doesn't do any good. */
}
else if (deferred)
{
/* *<disp> */
mode = TAHOE_DISP_REL_DEFERRED;
}
else
{
/* <disp> */
mode = TAHOE_DISPLACED_RELATIVE;
}
}
}
/*
* At this point, all the errors we can do have be checked for.
* We can build the 'top'. */
topP->top_ndx = ndx;
topP->top_reg = reg;
topP->top_mode = mode;
topP->top_error = op_bad;
topP->top_dispsize = disp_size;
} /* tip_op */
/*
* t i p ( )
*
* This converts a string into a tahoe instruction.
* The string must be a bare single instruction in tahoe (with BSD4 frobs)
* format.
* It provides at most one fatal error message (which stops the scan)
* some warning messages as it finds them.
* The tahoe instruction is returned in exploded form.
*
* The exploded instruction is returned to a struct tit of your choice.
* #include "tahoe-inst.h" to know what a struct tit is.
*
*/
static void
tip (titP, instring)
struct tit *titP; /* We build an exploded instruction here. */
char *instring; /* Text of a vax instruction: we modify. */
{
register struct tot_wot *twP = NULL; /* How to bit-encode this opcode. */
register char *p; /* 1/skip whitespace.2/scan vot_how */
register char *q; /* */
register unsigned char count; /* counts number of operands seen */
register struct top *operandp;/* scan operands in struct tit */
register char *alloperr = ""; /* error over all operands */
register char c; /* Remember char, (we clobber it
with '\0' temporarily). */
char *save_input_line_pointer;
if (*instring == ' ')
++instring; /* Skip leading whitespace. */
for (p = instring; *p && *p != ' '; p++)
; /* MUST end in end-of-string or
exactly 1 space. */
/* Scanned up to end of operation-code. */
/* Operation-code is ended with whitespace. */
if (p == instring)
{
titP->tit_error = "No operator";
count = 0;
titP->tit_opcode = 0;
}
else
{
c = *p;
*p = '\0';
/*
* Here with instring pointing to what better be an op-name, and p
* pointing to character just past that.
* We trust instring points to an op-name, with no whitespace.
*/
twP = (struct tot_wot *) hash_find (op_hash, instring);
*p = c; /* Restore char after op-code. */
if (twP == 0)
{
titP->tit_error = "Unknown operator";
count = 0;
titP->tit_opcode = 0;
}
else
{
/*
* We found a match! So lets pick up as many operands as the
* instruction wants, and even gripe if there are too many.
* We expect comma to seperate each operand.
* We let instring track the text, while p tracks a part of the
* struct tot.
*/
count = 0; /* no operands seen yet */
instring = p + (*p != '\0'); /* point past the operation code */
/* tip_op() screws with the input_line_pointer, so save it before
I jump in */
save_input_line_pointer = input_line_pointer;
for (p = twP->args, operandp = titP->tit_operand;
!*alloperr && *p;
operandp++, p += 2)
{
/*
* Here to parse one operand. Leave instring pointing just
* past any one ',' that marks the end of this operand.
*/
if (!p[1])
as_fatal ("Compiler bug: ODD number of bytes in arg structure %s.",
twP->args);
else if (*instring)
{
for (q = instring; (*q != ',' && *q != '\0'); q++)
{
if (*q == '\'' && q[1] != '\0') /* Jump quoted characters */
q++;
}
c = *q;
/*
* Q points to ',' or '\0' that ends argument. C is that
* character.
*/
*q = '\0';
operandp->top_access = p[0];
operandp->top_width = p[1];
tip_op (instring - 1, operandp);
*q = c; /* Restore input text. */
if (*(operandp->top_error))
{
alloperr = operandp->top_error;
}
instring = q + (c ? 1 : 0); /* next operand (if any) */
count++; /* won another argument, may have an operr */
}
else
alloperr = "Not enough operands";
}
/* Restore the pointer. */
input_line_pointer = save_input_line_pointer;
if (!*alloperr)
{
if (*instring == ' ')
instring++; /* Skip whitespace. */
if (*instring)
alloperr = "Too many operands";
}
titP->tit_error = alloperr;
}
}
titP->tit_opcode = twP->code; /* The op-code. */
titP->tit_operands = count;
} /* tip */
/* md_assemble() emit frags for 1 instruction */
void
md_assemble (instruction_string)
char *instruction_string; /* A string: assemble 1 instruction. */
{
char *p;
register struct top *operandP;/* An operand. Scans all operands. */
/* char c_save; fixme: remove this line *//* What used to live after an expression. */
/* struct frag *fragP; fixme: remove this line *//* Fragment of code we just made. */
/* register struct top *end_operandP; fixme: remove this line *//* -> slot just after last operand
Limit of the for (each operand). */
register expressionS *expP; /* -> expression values for this operand */
/* These refer to an instruction operand expression. */
segT to_seg; /* Target segment of the address. */
register valueT this_add_number;
register struct symbol *this_add_symbol; /* +ve (minuend) symbol. */
/* tahoe_opcodeT opcode_as_number; fixme: remove this line *//* The opcode as a number. */
char *opcodeP; /* Where it is in a frag. */
/* char *opmodeP; fixme: remove this line *//* Where opcode type is, in a frag. */
int dispsize; /* From top_dispsize: tahoe_operand_width
(in bytes) */
int is_undefined; /* 1 if operand expression's
segment not known yet. */
int pc_rel; /* Is this operand pc relative? */
/* Decode the operand. */
tip (&t, instruction_string);
/*
* Check to see if this operand decode properly.
* Notice that we haven't made any frags yet.
* If it goofed, then this instruction will wedge in any pass,
* and we can safely flush it, without causing interpass symbol phase
* errors. That is, without changing label values in different passes.
*/
if (*t.tit_error)
{
as_warn ("Ignoring statement due to \"%s\"", t.tit_error);
}
else
{
/* We saw no errors in any operands - try to make frag(s) */
/* Emit op-code. */
/* Remember where it is, in case we want to modify the op-code later. */
opcodeP = frag_more (1);
*opcodeP = t.tit_opcode;
/* Now do each operand. */
for (operandP = t.tit_operand;
operandP < t.tit_operand + t.tit_operands;
operandP++)
{ /* for each operand */
expP = &(operandP->exp_of_operand);
if (operandP->top_ndx >= 0)
{
/* Indexed addressing byte
Legality of indexed mode already checked: it is OK */
FRAG_APPEND_1_CHAR (0x40 + operandP->top_ndx);
} /* if(top_ndx>=0) */
/* Here to make main operand frag(s). */
this_add_number = expP->X_add_number;
this_add_symbol = expP->X_add_symbol;
to_seg = operandP->seg_of_operand;
know (to_seg == SEG_UNKNOWN || \
to_seg == SEG_ABSOLUTE || \
to_seg == SEG_DATA || \
to_seg == SEG_TEXT || \
to_seg == SEG_BSS);
is_undefined = (to_seg == SEG_UNKNOWN);
/* Do we know how big this opperand is? */
dispsize = operandP->top_dispsize;
pc_rel = 0;
/* Deal with the branch possabilities. (Note, this doesn't include
jumps.)*/
if (operandP->top_access == 'b')
{
/* Branches must be expressions. A psuedo branch can also jump to
an absolute address. */
if (to_seg == now_seg || is_undefined)
{
/* If is_undefined, then it might BECOME now_seg by relax time. */
if (dispsize)
{
/* I know how big the branch is supposed to be (it's a normal
branch), so I set up the frag, and let GAS do the rest. */
p = frag_more (dispsize);
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
size_to_fx (dispsize, 1),
NULL);
}
else
{
/* (to_seg==now_seg || to_seg == SEG_UNKNOWN) && dispsize==0 */
/* If we don't know how big it is, then its a synthetic branch,
so we set up a simple relax state. */
switch (operandP->top_width)
{
case TAHOE_WIDTH_CONDITIONAL_JUMP:
/* Simple (conditional) jump. I may have to reverse the
condition of opcodeP, and then jump to my destination.
I set 1 byte aside for the branch off set, and could need 6
more bytes for the pc_rel jump */
frag_var (rs_machine_dependent, 7, 1,
ENCODE_RELAX (STATE_CONDITIONAL_BRANCH,
is_undefined ? STATE_UNDF : STATE_BYTE),
this_add_symbol, this_add_number, opcodeP);
break;
case TAHOE_WIDTH_ALWAYS_JUMP:
/* Simple (unconditional) jump. I may have to convert this to
a word branch, or an absolute jump. */
frag_var (rs_machine_dependent, 5, 1,
ENCODE_RELAX (STATE_ALWAYS_BRANCH,
is_undefined ? STATE_UNDF : STATE_BYTE),
this_add_symbol, this_add_number, opcodeP);
break;
/* The smallest size for the next 2 cases is word. */
case TAHOE_WIDTH_BIG_REV_JUMP:
frag_var (rs_machine_dependent, 8, 2,
ENCODE_RELAX (STATE_BIG_REV_BRANCH,
is_undefined ? STATE_UNDF : STATE_WORD),
this_add_symbol, this_add_number,
opcodeP);
break;
case TAHOE_WIDTH_BIG_NON_REV_JUMP:
frag_var (rs_machine_dependent, 10, 2,
ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH,
is_undefined ? STATE_UNDF : STATE_WORD),
this_add_symbol, this_add_number,
opcodeP);
break;
default:
as_fatal ("Compliler bug: Got a case (%d) I wasn't expecting.",
operandP->top_width);
}
}
}
else
{
/* to_seg != now_seg && to_seg != seg_unknown (still in branch)
In other words, I'm jumping out of my segment so extend the
branches to jumps, and let GAS fix them. */
/* These are "branches" what will always be branches around a jump
to the correct addresss in real life.
If to_seg is SEG_ABSOLUTE, just encode the branch in,
else let GAS fix the address. */
switch (operandP->top_width)
{
/* The theory:
For SEG_ABSOLUTE, then mode is ABSOLUTE_ADDR, jump
to that addresss (not pc_rel).
For other segs, address is a long word PC rel jump. */
case TAHOE_WIDTH_CONDITIONAL_JUMP:
/* b<cond> */
/* To reverse the condition in a TAHOE branch,
complement bit 4 */
*opcodeP ^= 0x10;
p = frag_more (7);
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = (operandP->top_mode ==
TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
TAHOE_PC_REL_LONG);
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
(to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
/*
* Now (eg) BLEQ 1f
* JMP foo
* 1:
*/
break;
case TAHOE_WIDTH_ALWAYS_JUMP:
/* br, just turn it into a jump */
*opcodeP = TAHOE_JMP;
p = frag_more (5);
*p++ = (operandP->top_mode ==
TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
TAHOE_PC_REL_LONG);
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
(to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
/* Now (eg) JMP foo */
break;
case TAHOE_WIDTH_BIG_REV_JUMP:
p = frag_more (8);
*opcodeP ^= 0x10;
*p++ = 0;
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = (operandP->top_mode ==
TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
TAHOE_PC_REL_LONG);
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
(to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
/*
* Now (eg) ACBx 1f
* JMP foo
* 1:
*/
break;
case TAHOE_WIDTH_BIG_NON_REV_JUMP:
p = frag_more (10);
*p++ = 0;
*p++ = 2;
*p++ = TAHOE_BRB;
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = (operandP->top_mode ==
TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
TAHOE_PC_REL_LONG);
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
(to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
/*
* Now (eg) xOBxxx 1f
* BRB 2f
* 1: JMP @#foo
* 2:
*/
break;
case 'b':
case 'w':
as_warn ("Real branch displacements must be expressions.");
break;
default:
as_fatal ("Complier error: I got an unknown synthetic branch :%c",
operandP->top_width);
break;
}
}
}
else
{
/* It ain't a branch operand. */
switch (operandP->top_mode)
{
/* Auto-foo access, only works for one reg (SP)
so the only thing needed is the mode. */
case TAHOE_AUTO_DEC:
case TAHOE_AUTO_INC:
case TAHOE_AUTO_INC_DEFERRED:
FRAG_APPEND_1_CHAR (operandP->top_mode);
break;
/* Numbered Register only access. Only thing needed is the
mode + Register number */
case TAHOE_DIRECT_REG:
case TAHOE_REG_DEFERRED:
FRAG_APPEND_1_CHAR (operandP->top_mode + operandP->top_reg);
break;
/* An absolute address. It's size is always 5 bytes.
(mode_type + 4 byte address). */
case TAHOE_ABSOLUTE_ADDR:
know ((this_add_symbol == NULL));
p = frag_more (5);
*p = TAHOE_ABSOLUTE_ADDR;
md_number_to_chars (p + 1, this_add_number, 4);
break;
/* Immediate data. If the size isn't known, then it's an address
+ and offset, which is 4 bytes big. */
case TAHOE_IMMEDIATE:
if (this_add_symbol != NULL)
{
p = frag_more (5);
*p++ = TAHOE_IMMEDIATE_LONGWORD;
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
FX_32, NULL);
}
else
{
/* It's a integer, and I know it's size. */
if ((unsigned) this_add_number < 0x40)
{
/* Will it fit in a literal? */
FRAG_APPEND_1_CHAR ((byte) this_add_number);
}
else
{
p = frag_more (dispsize + 1);
switch (dispsize)
{
case 1:
*p++ = TAHOE_IMMEDIATE_BYTE;
*p = (byte) this_add_number;
break;
case 2:
*p++ = TAHOE_IMMEDIATE_WORD;
md_number_to_chars (p, this_add_number, 2);
break;
case 4:
*p++ = TAHOE_IMMEDIATE_LONGWORD;
md_number_to_chars (p, this_add_number, 4);
break;
}
}
}
break;
/* Distance from the PC. If the size isn't known, we have to relax
into it. The difference between this and disp(sp) is that
this offset is pc_rel, and disp(sp) isn't.
Note the drop through code. */
case TAHOE_DISPLACED_RELATIVE:
case TAHOE_DISP_REL_DEFERRED:
operandP->top_reg = PC_REG;
pc_rel = 1;
/* Register, plus a displacement mode. Save the register number,
and weather its deffered or not, and relax the size if it isn't
known. */
case TAHOE_REG_DISP:
case TAHOE_REG_DISP_DEFERRED:
if (operandP->top_mode == TAHOE_DISP_REL_DEFERRED ||
operandP->top_mode == TAHOE_REG_DISP_DEFERRED)
operandP->top_reg += 0x10; /* deffered mode is always 0x10 higher
than it's non-deffered sibling. */
/* Is this a value out of this segment?
The first part of this conditional is a cludge to make gas
produce the same output as 'as' when there is a lable, in
the current segment, displaceing a register. It's strange,
and no one in their right mind would do it, but it's easy
to cludge. */
if ((dispsize == 0 && !pc_rel) ||
(to_seg != now_seg && !is_undefined && to_seg != SEG_ABSOLUTE))
dispsize = 4;
if (dispsize == 0)
{
/*
* We have a SEG_UNKNOWN symbol, or the size isn't cast.
* It might turn out to be in the same segment as
* the instruction, permitting relaxation.
*/
p = frag_var (rs_machine_dependent, 5, 2,
ENCODE_RELAX (STATE_PC_RELATIVE,
is_undefined ? STATE_UNDF : STATE_BYTE),
this_add_symbol, this_add_number, 0);
*p = operandP->top_reg;
}
else
{
/* Either this is an abs, or a cast. */
p = frag_more (dispsize + 1);
switch (dispsize)
{
case 1:
*p = TAHOE_PC_OR_BYTE + operandP->top_reg;
break;
case 2:
*p = TAHOE_PC_OR_WORD + operandP->top_reg;
break;
case 4:
*p = TAHOE_PC_OR_LONG + operandP->top_reg;
break;
};
fix_new (frag_now, p + 1 - frag_now->fr_literal,
this_add_symbol, this_add_number,
size_to_fx (dispsize, pc_rel), NULL);
}
break;
default:
as_fatal ("Barf, bad mode %x\n", operandP->top_mode);
}
}
} /* for(operandP) */
} /* if(!need_pass_2 && !goofed) */
} /* tahoe_assemble() */
/* We have no need to default values of symbols. */
/* ARGSUSED */
symbolS *
md_undefined_symbol (name)
char *name;
{
return 0;
} /* md_undefined_symbol() */
/* Round up a section size to the appropriate boundary. */
valueT
md_section_align (segment, size)
segT segment;
valueT size;
{
return ((size + 7) & ~7); /* Round all sects to multiple of 8 */
} /* md_section_align() */
/* Exactly what point is a PC-relative offset relative TO?
On the sparc, they're relative to the address of the offset, plus
its size. This gets us to the following instruction.
(??? Is this right? FIXME-SOON) */
long
md_pcrel_from (fixP)
fixS *fixP;
{
return (((fixP->fx_type == FX_8
|| fixP->fx_type == FX_PCREL8)
? 1
: ((fixP->fx_type == FX_16
|| fixP->fx_type == FX_PCREL16)
? 2
: ((fixP->fx_type == FX_32
|| fixP->fx_type == FX_PCREL32)
? 4
: 0))) + fixP->fx_where + fixP->fx_frag->fr_address);
} /* md_pcrel_from() */
int
tc_is_pcrel (fixP)
fixS *fixP;
{
/* should never be called */
know (0);
return (0);
} /* tc_is_pcrel() */
/* end of tc-tahoe.c */
|