⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 misc.c

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 C
字号:
/*
 *  Module for various things:
 *   - host/network order (little/big endian) swapping of bytes.
 *   - initialise peek/poke macros.
 *   - allocate transfer buffer for DOSX targets.
 *   - address validation for DOSX targets.
 *   - simple range limited random routine.
 *   - ffs routine to find the first bit set.
 *   - stack checker exit routine for Watcom.
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <dos.h>

#ifdef __HIGHC__
#include <init.h>  /* _mwlsl(), _msgetcs() */
#endif
#ifdef __DJGPP__
#include <unistd.h>
#endif

#include "wattcp.h"
#include "wdpmi.h"
#include "strings.h"
#include "pcsed.h"
#include "misc.h"

/* These arrays are used several places (save some space)
 */
char hex_chars[] = "0123456789abcdef";
char hex_CHARS[] = "0123456789ABCDEF";

#if (DOSX == 0)
int cpu_type = 86;      /* Detected CPU type; 86,386, ... */
#else
int cpu_type = 386;
#endif

#if !defined(__DJGPP__)
int __bss_count = 0;    /* detect program restarts (!!to-do) */
#endif

#ifdef HAS_FP
FARPTR _watt_dosFp = (FARPTR)0; /* Put in _DATA segment */
#endif

#if (DOSX) && !defined(__DJGPP__)
static void setup_dos_xfer_buf (void);
#endif

#if defined(__WATCOMC__)
extern char cdecl __begtext;    /* label at TEXT start */
extern UINT cdecl _x386_stacklow;

#if defined(__SW_3S)            /* wcc386 -3s, wcc */
  void cdecl _fatal_runtime_error (UINT stk);
  #define FATAL_HANDLER _fatal_runtime_error
#else
  void cdecl _fatal_runtime_error_ (UINT stk);
  #define FATAL_HANDLER _fatal_runtime_error_
#endif

/* Prevent linker (with 'option eliminate') to drop our
 * '_fatal_runtime_error()' function from .exe-image.
 */
char *dummy_fatal_rte = (char*)&FATAL_HANDLER;
#endif /* __WATCOMC__ */


/*
 * Turn off stack-checking to avoid destroying assumptions
 * made in bswap patch code and ffs() below. And also to make
 * this run a bit faster.
 */
#if defined(__HIGHC__) || defined(__WATCOMC__)
#pragma Off(check_stack)
#endif

#if defined(__BORLANDC__)
#pragma option -N-
#endif

#if !defined(BIG_ENDIAN_MACHINE)

#define swap16(p)  ( *p = (*p << 8) | (*p >> 8))
#define swap32(p)  ( swap16 (&((unsigned short*)p)[0]), \
                     swap16 (&((unsigned short*)p)[1]), \
                     *p = (*p << 16) | (*p >> 16) )

/*
 * Convert 32-bit big-endian (network order) to intel (host order) format.
 * Or vice-versa
 */
unsigned long _w32_intel (unsigned long val)
{
  return swap32 (&val);
}

/*
 * Convert 16-bit big-endian (network order) to intel (host order) format.
 * Or vice-versa
 */
unsigned short _w32_intel16 (unsigned short val)
{
  return swap16 (&val);
}

#if (DOSX) && !defined(__WATCOMC__) /* suspect trouble with Watcom */
static BYTE bswap[] = {
            0x8B,0x44,0x24,0x04,       /* mov eax,[esp+4] */
            0x0F,0xC8,                 /* bswap eax       */
            0xC3                       /* ret             */
          };

static BYTE bswap16[] = {
            0x8B,0x44,0x24,0x04,       /* mov eax,[esp+4] */
            0x0F,0xC8,                 /* bswap eax       */
            0xC1,0xE8,0x10,            /* shr eax,16      */
            0xC3                       /* ret             */
          };


/*
 * Modify functions intel/intel16 (htonl/htons) to use the
 * BSWAP instruction on 80486+ CPUs. We don't bother with real-mode
 * targets on a 80486+ CPU. Hope that size of overwritten functions
 * are big enough.
 */
static void patch_bswap (void)
{
  /* For Watcom's register calling convention. Argument is in EAX.
   */
#if defined(__WATCOM386__) && defined(__SW_3R) /* -3r/-4r/-5r used */
  memcpy ((void*)_w32_intel,  4+(BYTE*)&bswap,  sizeof(bswap)-4);
  memcpy ((void*)_w32_intel16,4+(BYTE*)&bswap16,sizeof(bswap16)-4);
#else
  memcpy ((void*)_w32_intel,  (const void*)&bswap,  sizeof(bswap));
  memcpy ((void*)_w32_intel16,(const void*)&bswap16,sizeof(bswap16));
#endif
}
#endif  /* DOSX */
#endif  /* BIG_ENDIAN_MACHINE */


void init_misc (void)
{
#if defined(HAS_FP) && (DOSX & PHARLAP)
  /*
   * For 32-bit compilers with 48-bit far-pointers.
   * `init_misc' MUST be called before `peekx()' functions are used.
   */
  FP_SET (_watt_dosFp, 0, SS_DOSMEM);

#elif defined(HAS_FP) /* MSVC + WDOSX */
  UNFINISHED();
#endif

  /* Check if we're running a 80486+ CPU.
   */
#if (DOSX & PHARLAP)
  {
    CONFIG_INF cnf;
    _dx_config_inf (&cnf, (UCHAR*)&cnf);
    if (cnf.c_processor >= 4)
       cpu_type = 486;
  }
#elif (DOSX & DJGPP)
  {
    __dpmi_version_ret cnf;
    __dpmi_get_version (&cnf);
    if (cnf.cpu >= 4)
       cpu_type = 486;
  }
#elif (DOSX & (DOS4GW|WDOSX))
  if (dpmi_cpu_type() >= 4)
     cpu_type = 486;

#elif (DOSX & POWERPAK)
  UNFINISHED();
#endif

#if (DOSX) && !defined(BIG_ENDIAN_MACHINE) && !defined(__WATCOMC__)
  if (cpu_type >= 486)                      /* ^suspect trouble with Watcom */
     patch_bswap();
#endif

#if (DOSX) && !defined(__DJGPP__)
  setup_dos_xfer_buf();
#endif
 
  srand (peekw(0,0x46C)); /* initialize rand using BIOS clock */
  init_timers();
}

/*
 * returns a random integer in range [a..b]
 */
int Random (unsigned a, unsigned b)
{
  if (a == b)
     return (a);

  if (a > b)
  {
    unsigned x = b;
    b = a;
    a = x;
  }
  return (a + (unsigned)(rand() % (b-a+1)));
}

/*
 * Wait for a random period in range [a..b] millisec
 */
void RandomWait (unsigned a, unsigned b)
{
  DWORD t = set_timeout (Random(a, b));

  while (!chk_timeout(t))
        ;
}

#if defined(USE_DEBUG) && defined(NOT_USED)
/*
 * dword_str() - return nicely formatted string " xx,xxx,xxx"
 * with thousand separators.
 */
const char *dword_str (DWORD val)
{
  static char buf[20];
  char   tmp[20];

  if (val < 1000UL)
  {
    sprintf (buf, "%lu", val);
    return (buf);
  }
  if (val < 1000000UL)       /* 1E6 */
  {
    sprintf (buf, "%lu.%03lu", val/1000UL, val % 1000UL);
    return (buf);
  }
  if (val < 1000000000UL)    /* 1E9 */
  {
    sprintf (tmp, "%9lu", val);
    sprintf (buf, "%.3s,%.3s,%.3s", tmp, tmp+3, tmp+6);
    return (buf);
  }
  sprintf (tmp, "%12lu", val);
  sprintf (buf, "%.3s,%.3s,%.3s,%.3s", tmp, tmp+3, tmp+6, tmp+9);
  return (buf);
}
#endif /* USE_DEBUG && NOT_USED */
 

#if (DOSX)
#if defined(__DJGPP__)
static inline DWORD get_limit (WORD seg)
{
  DWORD lim;
  __asm__ ("lsll %1,%0"
           : "=r" (lim) : "r" (seg));
  return (lim+1);
}
#endif

/*
 * Test for valid read/write data address.
 * We assume linear address 'addr' is both readable and writeable.
 */
BOOL valid_addr (DWORD addr, int len)
{
  if (addr < 0x1000 || (addr >= 0xFFFFFFFFL - len))
     return (FALSE);

#if defined (__DJGPP__)
  if (addr + len > __dpmi_get_segment_limit(_my_ds()))
//if (addr + len > get_limit(_my_ds())) /* 'as 2.8' doesn't understand 'lsll' */
     return (FALSE);

#elif defined (__HIGHC__)
  if (addr + len > _mwlsl(_mwgetcs())) /* DS & CS are aliases */
     return (FALSE);

#elif defined (__WATCOMC__)
  if (addr + len > _get_limit(My_DS()))
     return (FALSE);
#endif

  return (TRUE);
}
#endif  /* DOSX */


/*
 * Pharlap targets:      Determine location of DOS-transfer buffer.
 * DOS4GW/WDOSX targets: Allocate a small (1kB) DOS-transfer buffer.
 * PowerPak targets:     ??
 */
#if (DOSX & PHARLAP)
  REALPTR _watt_dosTbr;          /* rmode-address of transfer buffer */
  FARPTR  _watt_dosTbp;          /* pmode-address of transfer buffer */
  ULONG   _watt_dosTbSize = 0;   /* size of transfer buffer          */
  REALPTR _watt_r2p_addr  = 0;   /* address for real to pmode switch */

  static void setup_dos_xfer_buf (void)
  {
    _dx_rmlink_get (&_watt_r2p_addr,  &_watt_dosTbr,
                    &_watt_dosTbSize, &_watt_dosTbp);
  }

#elif (DOSX & (DOS4GW|WDOSX))
  unsigned short _watt_dosTbSeg = 0; /* paragraph address of xfer buffer */
  unsigned short _watt_dosTbSel = 0; /* selector for transfer buffer     */
  int _watt_dosTbSize = 0;           /* size of transfer buffer          */

  static void free_tb_sel (void)
  {
    if (_watt_dosTbSel)
       dpmi_real_free (_watt_dosTbSel);
    _watt_dosTbSel = 0;
  }
  static void setup_dos_xfer_buf (void)
  {
    _watt_dosTbSize = 1024;
    _watt_dosTbSeg  = dpmi_real_malloc (_watt_dosTbSize, &_watt_dosTbSel);
    if (_watt_dosTbSeg)
         _watt_dosTbSize = 0;
    else atexit (free_tb_sel);
  }

#elif (DOSX & POWERPAK)
  static void setup_dos_xfer_buf (void)
  {
    UNFINISHED();
  }
#endif

#if defined(USE_DEBUG)
  void unfinished (const char *file, unsigned line)
  {
    fprintf (stderr, "%s (%u):\7Help! Unfinished code.\n", file, line);
    _exit (-1);
  }
#endif

/*
 * ffs() isn't needed yet, but should be used in select_s()
 */
#if defined(USE_BSD_FUNC)
#if (DOSX == 0) || defined(OLD_WATCOMC)
/*
 * Copyright (C) 1991, 1992 Free Software Foundation, Inc.
 * Contributed by Torbjorn Granlund (tege@sics.se).
 *
 * The GNU C Library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * The GNU C Library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with the GNU C Library; see the file COPYING.LIB.  If
 * not, write to the Free Software Foundation, Inc., 675 Mass Ave,
 * Cambridge, MA 02139, USA.
 */

/*
 * Find the first bit set in 'i'.
 */
static int ffs_86 (int i)
{
  static BYTE table[] = {
    0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
  };
  DWORD a, x = i & -i;

  a = x <= 0xFFFFUL ? (x <= 0xFF ? 0 : 8) : (x <= 0xFFFFFF ? 16 : 24);
  return (table[x >> a] + a);
}
#endif  /* DOSX == 0 || OLD_WATCOMC */

#ifndef __cdecl
#define __cdecl  /* prevent register calls */
#endif

int __cdecl ffs (int val)
{
 /* Calling code in data-segment, but this is flat model remember.
  * The "data-array" code crashes the BCC32 and Watcom 10.6 compilers!
  */
#if defined(__BORLAND386__)
  __asm bsf eax, val
  __asm jz zero

    val = _EAX;
    return (++val);
  zero:
    return (0);

#elif (DOSX) && !defined(OLD_WATCOMC)
  return ((int __cdecl (*)())
         "\x0F\xBC\x44\x24\4"    /*     bsf eax, [esp+4] */
         "\x75\5"                /*     jnz @f           */
         "\xB8\xFF\xFF\xFF\xFF"  /*     mov eax,-1       */
         "\x40"                  /* @f: inc eax          */
         "\xC3") (val);          /*     ret              */
#else
  return ffs_86 (val);
#endif
}
#endif  /* USE_BSD_FUNC */


/*
 * Checks for bugs when compiling in large model C compiler
 *
 * Borland C uses a 4K stack by default. In all memory models the
 * stack grows down toward the heap.
 *
 * If you accidentally place tcp_Socket onto the stack, then you
 * will have already used up that whole 4K and then some!
 *
 * In large model, this will mess up the data space in a major way
 * because the stack starts at SS:_stklen, or SS:1000, so you will
 * wrap the SP pointer back around to FFFE and start writing over
 * the far heap.  Yuck.
 *
 * In small model it usually doesn't kill your application because
 * you would have to be down to your last 4K of memory and this is
 * not as common.
 *
 * The solutions: declare your sockets as static, or put them on the
 * heap, or bump up your stack size by using the global special variable:
 *
 * unsigned _stklen = 16536;
 */

#if defined(__LARGE__)
void watt_largecheck (void *s, int size, char *file, unsigned line)
{
  if ((unsigned)(FP_OFF(s)) > (unsigned)(-size))
  {
    printf ("%s (%d): user stack size error", file, line);
    exit (3);
  }
}
#endif


#if defined(__WATCOMC__) && defined(USE_DEBUG)

/*
 * For tracking down stack overflow bugs.
 * Stack checker __CHK is pascal-style with stack-size at [esp+4].
 * __CHK calls __STK which in turn may call _fatal_runtime_error()
 *
 * Compiling with stack-checking on, this prologue is in every function:
 *  (*) push <stack size needed>   <- 68h, dword size at EIP-9
 *      call __CHK                 <- 5 bytes
 *      ...                        <- extracted EIP of return
 */
static void stk_overflow (WORD cs, UINT eip)
{
  UINT size = *(UINT*)(eip-9);
  static char buf[12];
  eip -= (UINT)&__begtext - 9; /* print .map-file address of (*) */

#if 1
  outs ("Stack overflow (");
  itoa (size, buf, 10);
  outs (buf);
  outs (" bytes) detected at ");
  itoa (cs, buf, 16);
  outs (buf);
  buf[0] = ':';
  itoa (eip, buf+1, 16);
  outsnl (buf);
#else
  fprintf (stderr, "Stack overflow (%u bytes) detected at %X:%08lXh\n",
           size, cs, (DWORD)eip);
#endif

  _eth_release();
  _exit (1);     /* do minimal work, no atexit() functions */
}

void FATAL_HANDLER (UINT stk)
{
#if defined(__SMALL__)
  _x386_stacklow = stk + 2;
  stk_overflow (My_CS(), *(UINT*)(&stk+3));

#elif defined(__LARGE__)
  _x386_stacklow = stk + 4;
  stk_overflow (*(WORD*)(&stk+5), *(UINT*)(&stk+3)); /* far-call */

#else     /* wcc386 */
  _x386_stacklow = stk + 4;
  stk_overflow (My_CS(), *(UINT*)(&stk+3));
#endif
}

#endif  /* __WATCOMC__ && USE_DEBUG */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -