Initial Commit

This commit is contained in:
narnosnes 2017-06-09 13:47:37 +02:00
commit 7aeab42440
1297 changed files with 163139 additions and 0 deletions

18
.travis.yml Normal file
View File

@ -0,0 +1,18 @@
language: c
before_script:
- ./configure --enable-cross
script: make 816-tcc
before_deploy:
- zip -9ry 816-tcc.zip 816-tcc 816-opt.py
deploy:
provider: releases
api-key:
- secure: "wrFShOH6+/tRv/uBJJlITaSPRa1Wh4WT1Sax3TgoohMzCARWS+ly/FyUvOFqBYA0qdInzw3Qhajd+FJxHikI0huyDCzeII/aata7CkuCw8tvteG6ayc2zcFGYDsD1lZovTZ0ryzpv65vnGc+I87jJ15v4sanb7rV0wIsABZ9UrIC1g26qINzSCQpbcLL7Saw3h0jhTOoDzwcSsBT+yVfJhGBgGpNsHOVf/YcJyLx6H+B2HSwcI0GA32k7sGBSM8H7oW37+XtCOi6Yl2kLhOXBuzRcTLkZSnFqBMgZ+kC4hsbLsiBHkbaEur+VqdZ/zihQdDptmV0fW2kYtR9/jxfRsQ/vcLLs9a+fnhmCdruhzoKMJ8NwFDxm9wieQMAyGu0x6mEFq0tCGyn1UsgVMLfCoQOEVSQKB2QZ0XN8Wq3NL1vCWD02qGs/8Klxp8HrslXMOT5uqdddMsUHRA1UcBbKfkmONNy27X7pkXb1owT0d3Tulet3YBaYRGYXNsbECf/MAsV8GUGsbDnXWn4kzwL9B9Sep53jr4QqNRF1o762k8E2ZMRbwF87e2HxE3TEKHDENm813l7p1g3aBu4pakZRVScpNZxJEJ+oLP8nMV+RskwAFygor/VGI/db4o7Jz+boEyq/5gmTU8A1VSqEYwx9GME6I4cE3y6P9TyHAc/6Ls="
file: 816-tcc.zip
skip_cleanup: true
on:
tags: true

1296
816-gen.c Normal file

File diff suppressed because it is too large Load Diff

579
816-opt.py Normal file
View File

@ -0,0 +1,579 @@
#!/usr/bin/python
import sys
import re
import os
#import hotshot
#prof = hotshot.Profile('816-opt.prof')
#prof.start()
verbose = True
if os.getenv('OPT816_QUIET'): verbose = False
# open the assembler file and put lines in array text
text_raw = open(sys.argv[1],'r').readlines()
text = []
for l in text_raw:
if not l.startswith(';'): text += [l.strip()]
# find .bss section symbols
bss = []
bsson = False
for l in text:
if l == '.ramsection ".bss" bank $7e slot 2':
bsson = True
continue
if l == '.ends':
bsson = False
if bsson:
bss += [l.split(' ')[0]]
#print 'bss',bss
# checks if the line alters the control flow
def is_control(line):
if len(line) > 0 and line[0] in 'jb+-' or line.endswith(':'): return True
return False
def changes_accu(line):
if (line[2] == 'a' and not line[:3] in ['pha','sta']) or (len(line) == 5 and line.endswith(' a')): return True
else: return False
totalopt = 0 # total number of optimizations performed
opted = -1 # have we optimized in this pass?
opass = 0 # optimization pass counter
storetopseudo = re.compile('st([axyz]).b tcc__([rf][0-9]*h?)$')
storexytopseudo = re.compile('st([xy]).b tcc__([rf][0-9]*h?)$')
storeatopseudo = re.compile('sta.b tcc__([rf][0-9]*h?)$')
while opted:
opass += 1
if verbose: sys.stderr.write('optimization pass ' + str(opass) + ': ')
opted = 0 # no optimizations performed
text_opt = [] # optimized code array, will be filled in during this pass
i = 0
while i < len(text):
if text[i].startswith('st'):
# stores (accu/x/y/zero) to pseudo-registers
r = storetopseudo.match(text[i])
if r:
# eliminate redundant stores
doopt = False
for j in range(i+1, min(len(text),i+30)):
r1 = re.match('st([axyz]).b tcc__' + r.groups()[1] + '$', text[j])
if r1:
doopt = True # another store to the same pregister
break
if text[j].startswith('jsr.l ') and not text[j].startswith('jsr.l tcc__'):
doopt = True # before function call (will be clobbered anyway)
break
# cases in which we don't pursue optimization further
if is_control(text[j]) or ('tcc__' + r.groups()[1]) in text[j]: break # branch or other use of the preg
if r.groups()[1].endswith('h') and ('[tcc__' + r.groups()[1].rstrip('h')) in text[j]: break # use as a pointer
if doopt:
i += 1 # skip redundant store
opted += 1
continue
# stores (x/y) to pseudo-registers
r = storexytopseudo.match(text[i])
if r:
# store hwreg to preg, push preg, function call -> push hwreg, function call
if text[i+1] == 'pei (tcc__' + r.groups()[1] + ')' and text[i+2].startswith('jsr.l '):
text_opt += ['ph' + r.groups()[0]]
i += 2
opted += 1
continue
# store hwreg to preg, push preg -> store hwreg to preg, push hwreg (shorter)
if text[i+1] == 'pei (tcc__' + r.groups()[1] + ')':
text_opt += [text[i]]
text_opt += ['ph' + r.groups()[0]]
i += 2
opted += 1
continue
# store hwreg to preg, load hwreg from preg -> store hwreg to preg, transfer hwreg/hwreg (shorter)
if text[i+1] == 'lda.b tcc__' + r.groups()[1] or text[i+1] == 'lda.b tcc__' + r.groups()[1] + " ; DON'T OPTIMIZE":
text_opt += [text[i]]
text_opt += ['t' + r.groups()[0] + 'a'] # FIXME: shouldn't this be marked as DON'T OPTIMIZE again?
i += 2
opted += 1
continue
# stores (accu only) to pseudo-registers
r = storeatopseudo.match(text[i])
if r:
#sys.stderr.write('looking for lda.b tcc__r' + r.groups()[0] + ' in ' + text[i+1] + '\n')
# store preg followed by load preg
if text[i+1] == 'lda.b tcc__' + r.groups()[0]:
#sys.stderr.write('found!\n')
text_opt += [text[i]] # keep store
i += 2 # omit load
opted += 1
continue
# store preg followed by load preg with ldx/ldy in between
if (text[i+1].startswith('ldx') or text[i+1].startswith('ldy')) and text[i+2] == 'lda.b tcc__' + r.groups()[0]:
text_opt += [text[i]] # keep store
text_opt += [text[i+1]]
i += 3 # omit load
opted += 1
continue
# store accu to preg, push preg, function call -> push accu, function call
if text[i+1] == 'pei (tcc__' + r.groups()[0] + ')' and text[i+2].startswith('jsr.l '):
text_opt += ['pha']
i += 2
opted += 1
continue
# store accu to preg, push preg -> store accu to preg, push accu (shorter)
if text[i+1] == 'pei (tcc__' + r.groups()[0] + ')':
text_opt += [text[i]]
text_opt += ['pha']
i += 2
opted += 1
continue
# store accu to preg1, push preg2, push preg1 -> store accu to preg1, push preg2, push accu
elif text[i+1].startswith('pei ') and text[i+2] == 'pei (tcc__' + r.groups()[0] + ')':
text_opt += [text[i+1]]
text_opt += [text[i]]
text_opt += ['pha']
i += 3
opted += 1
continue
# convert incs/decs on pregs incs/decs on hwregs
cont = False
for crem in 'inc','dec':
if text[i+1] == crem + '.b tcc__' + r.groups()[0]:
# store to preg followed by crement on preg
if text[i+2] == crem + '.b tcc__' + r.groups()[0] and text[i+3].startswith('lda'):
# store to preg followed by two crements on preg
# increment the accu first, then store it to preg
text_opt += [crem + ' a',crem + ' a','sta.b tcc__' + r.groups()[0]]
# a subsequent load can be omitted (the right value is already in the accu)
if text[i+3] == 'lda.b tcc__' + r.groups()[0]: i += 4
else: i += 3
opted += 1
cont = True
break
elif text[i+2].startswith('lda'): #text[i+2] == 'lda.b tcc__' + r.groups()[0]:
# same thing with only one crement (FIXME: there should be a more clever way to do this...)
text_opt += [crem + ' a','sta.b tcc__' + r.groups()[0]]
if text[i+2] == 'lda.b tcc__' + r.groups()[0]: i += 3
else: i += 2
opted += 1
cont = True
break
if cont: continue
r1 = re.match('lda.b tcc__([rf][0-9]*)',text[i+1])
if r1:
#sys.stderr.write('t '+text[i+2][:3]+'\n')
if text[i+2][:3] in ['and','ora']:
# store to preg1, load from preg2, and/or preg1 -> store to preg1, and/or preg2
#sys.stderr.write('found in line ' + str(i) + '!\n')
if text[i+2][3:] == '.b tcc__' + r.groups()[0]:
text_opt += [text[i]] # store
text_opt += [text[i+2][:3] + '.b tcc__' + r1.groups()[0]]
i += 3
opted += 1
continue
# store to preg, switch to 8 bits, load from preg => skip the load
if text[i+1] == 'sep #$20' and text[i+2] == 'lda.b tcc__' + r.groups()[0]:
text_opt += [text[i]]
text_opt += [text[i+1]]
i += 3 # skip load
opted += 1
continue
# two stores to preg without control flow or other uses of preg => skip first store
if not is_control(text[i+1]) and not ('tcc__' + r.groups()[0]) in text[i+1]:
if text[i+2] == text[i]:
text_opt += [text[i+1]]
text_opt += [text[i+2]]
i += 3 # skip first store
opted += 1
continue
# store hwreg to preg, load hwreg from preg -> store hwreg to preg, transfer hwreg/hwreg (shorter)
r1 = re.match('ld([xy]).b tcc__' + r.groups()[0], text[i+1])
if r1:
text_opt += [text[i]]
text_opt += ['ta' + r1.groups()[0]]
i += 2
opted += 1
continue
# store accu to preg then load accu from preg, with something in-between that does not alter
# control flow or touch accu or preg => skip load
if not (is_control(text[i+1]) or changes_accu(text[i+1]) or 'tcc__' + r.groups()[0] in text[i+1]):
if text[i+2] == 'lda.b tcc__' + r.groups()[0]:
text_opt += [text[i]]
text_opt += [text[i+1]]
i += 3 # skip load
opted += 1
continue
# store preg1, clc, load preg2, add preg1 -> store preg1, clc, add preg2
if text[i+1] == 'clc':
r1 = re.match('lda.b tcc__(r[0-9]*)', text[i+2])
if r1 and text[i+3] == 'adc.b tcc__' + r.groups()[0]:
text_opt += [text[i]]
text_opt += [text[i+1]]
text_opt += ['adc.b tcc__' + r1.groups()[0]]
i += 4 # skip load
opted += 1
continue
# store accu to preg, asl preg => asl accu, store accu to preg
# FIXME: is this safe? can we rely on code not making assumptions about the contents of the accu
# after the shift?
if text[i+1] == 'asl.b tcc__' + r.groups()[0]:
text_opt += ['asl a']
text_opt += [text[i]]
i += 2
opted += 1
continue
r = re.match('sta (.*),s$', text[i])
if r:
if text[i+1] == 'lda ' + r.groups()[0] + ',s':
text_opt += [text[i]]
i += 2 # omit load
opted += 1
continue
# end startswith('st')
if text[i].startswith('ld'):
r = re.match('ldx #0', text[i])
if r:
r1 = re.match('lda.l (.*),x$', text[i+1])
if r1 and not text[i+3].endswith(',x'):
text_opt += ['lda.l ' + r1.groups()[0]]
i += 2
opted += 1
continue
elif r1:
text_opt += ['lda.l ' + r1.groups()[0]]
text_opt += [text[i+2]]
text_opt += [text[i+3].replace(',x','')]
i += 4
opted += 1
continue
if text[i].startswith('lda.w #') and \
text[i+1] == 'sta.b tcc__r9' and \
text[i+2].startswith('lda.w #') and \
text[i+3] == 'sta.b tcc__r9h' and \
text[i+4] == 'sep #$20' and \
text[i+5].startswith('lda.b ') and \
text[i+6] == 'sta.b [tcc__r9]' and \
text[i+7] == 'rep #$20':
text_opt += ['sep #$20']
text_opt += [text[i+5]]
text_opt += ['sta.l ' + str(int(text[i+2][7:]) * 65536 + int(text[i][7:]))]
text_opt += ['rep #$20']
i += 8
opted += 1
#sys.stderr.write('7')
continue
if text[i] == 'lda.w #0':
if text[i+1].startswith('sta.b ') and text[i+2].startswith('lda'):
text_opt += [text[i+1].replace('sta.','stz.')]
i += 2
opted += 1
continue
elif text[i].startswith('lda.w #'):
if text[i+1] == 'sep #$20' and text[i+2].startswith('sta ') and text[i+3] == 'rep #$20' and text[i+4].startswith('lda'):
text_opt += ['sep #$20', text[i].replace('lda.w', 'lda.b'), text[i+2], text[i+3]]
i += 4
opted += 1
continue
if text[i].startswith('lda.b') and not is_control(text[i+1]) and not 'a' in text[i+1] and text[i+2].startswith('lda.b'):
text_opt += [text[i+1],text[i+2]]
i += 3
opted += 1
continue
# don't write preg high back to stack if it hasn't been updated
if text[i+1].endswith('h') and text[i+1].startswith('sta.b tcc__r') and text[i].startswith('lda ') and text[i].endswith(',s'):
#sys.stderr.write('checking lines\n')
#sys.stderr.write(text[i] + '\n' + text[i+1] + '\n')
local = text[i][4:]
reg = text[i+1][6:]
# lda stack ; store high preg ; ... ; load high preg ; sta stack
j = i + 2
while j < len(text) - 2 and not is_control(text[j]) and not reg in text[j]:
j += 1
if text[j] == 'lda.b ' + reg and text[j+1] == 'sta ' + local:
while i < j:
text_opt += [text[i]]
i += 1
i += 2 # skip load high preg ; sta stack
opted += 1
continue
# reorder copying of 32-bit value to preg if it looks as if that could
# allow further optimization
# looking for
# lda something
# sta.b tcc_rX
# lda something
# sta.b tcc_rYh
# ...tcc_rX...
if text[i].startswith('lda') and text[i+1].startswith('sta.b tcc__r'):
reg = text[i+1][6:]
if not reg.endswith('h') and \
text[i+2].startswith('lda') and not text[i+2].endswith(reg) and \
text[i+3].startswith('sta.b tcc__r') and text[i+3].endswith('h') and \
text[i+4].endswith(reg):
text_opt += [text[i+2], text[i+3]]
text_opt += [text[i], text[i+1]]
i += 4
# this is not an optimization per se, so we don't count it
continue
# compare optimizations inspired by optimore
# These opts simplify compare operations, which are monstrous because
# they have to take the long long case into account.
# We try to detect those cases by checking if a tya follows the
# comparison (not sure if this is reliable, but it passes the test suite)
if text[i] == 'ldx #1' and \
text[i+1].startswith('lda.b tcc__') and \
text[i+2] == 'sec' and \
text[i+3].startswith('sbc #') and \
text[i+4] == 'tay' and \
text[i+5] == 'beq +' and \
text[i+6] == 'dex' and \
text[i+7] == '+' and \
text[i+8].startswith('stx.b tcc__') and \
text[i+9] == 'txa' and \
text[i+10] == 'bne +' and \
text[i+11].startswith('brl ') and \
text[i+12] == '+' and \
text[i+13] != 'tya':
text_opt += [text[i+1]]
text_opt += ['cmp #' + text[i+3][5:]]
text_opt += [text[i+5]]
text_opt += [text[i+11]] # brl
text_opt += [text[i+12]] # +
i += 13
opted += 1
#sys.stderr.write('1')
continue
if text[i] == 'ldx #1' and \
text[i+1] == 'sec' and \
text[i+2].startswith('sbc #') and \
text[i+3] == 'tay' and \
text[i+4] == 'beq +' and \
text[i+5] == 'dex' and \
text[i+6] == '+' and \
text[i+7].startswith('stx.b tcc__') and \
text[i+8] == 'txa' and \
text[i+9] == 'bne +' and \
text[i+10].startswith('brl ') and \
text[i+11] == '+' and \
text[i+12] != 'tya':
text_opt += ['cmp #' + text[i+2][5:]]
text_opt += [text[i+4]]
text_opt += [text[i+10]] # brl
text_opt += [text[i+11]] # +
i += 12
opted += 1
#sys.stderr.write('2')
continue
if text[i] == 'ldx #1' and \
text[i+1].startswith('lda.b tcc__r') and \
text[i+2] == 'sec' and \
text[i+3].startswith('sbc.b tcc__r') and \
text[i+4] == 'tay' and \
text[i+5] == 'beq +' and \
text[i+6] == 'bcs ++' and \
text[i+7] == '+ dex' and \
text[i+8] == '++' and \
text[i+9].startswith('stx.b tcc__r') and \
text[i+10] == 'txa' and \
text[i+11] == 'bne +' and \
text[i+12].startswith('brl ') and \
text[i+13] == '+' and \
text[i+14] != 'tya':
text_opt += [text[i+1]]
text_opt += ['cmp.b ' + text[i+3][6:]]
text_opt += [text[i+5]]
text_opt += ['bcc +']
text_opt += ['brl ++']
text_opt += ['+']
text_opt += [text[i+12]]
text_opt += ['++']
i += 14
opted += 1
#sys.stderr.write('3')
continue
if text[i] == 'ldx #1' and \
text[i+1] == 'sec' and \
text[i+2].startswith('sbc.w #') and \
text[i+3] == 'tay' and \
text[i+4] == 'bvc +' and \
text[i+5] == 'eor #$8000' and \
text[i+6] == '+' and \
text[i+7] == 'bmi +++' and \
text[i+8] == '++' and \
text[i+9] == 'dex' and \
text[i+10] == '+++' and \
text[i+11].startswith('stx.b tcc__r') and \
text[i+12] == 'txa' and \
text[i+13] == 'bne +' and \
text[i+14].startswith('brl ') and \
text[i+15] == '+' and \
text[i+16] != 'tya':
text_opt += [text[i+1]]
text_opt += [text[i+2]]
text_opt += [text[i+4]]
text_opt += ['eor #$8000']
text_opt += ['+']
text_opt += ['bmi +']
text_opt += [text[i+14]]
text_opt += ['+']
i += 16
opted += 1
#sys.stderr.write('4')
continue
if text[i] == 'ldx #1' and \
text[i+1].startswith('lda.b tcc__r') and \
text[i+2] == 'sec' and \
text[i+3].startswith('sbc.b tcc__r') and \
text[i+4] == 'tay' and \
text[i+5] == 'bvc +' and \
text[i+6] == 'eor #$8000' and \
text[i+7] == '+' and \
text[i+8] == 'bmi +++' and \
text[i+9] == '++' and \
text[i+10] == 'dex' and \
text[i+11] == '+++' and \
text[i+12].startswith('stx.b tcc__r') and \
text[i+13] == 'txa' and \
text[i+14] == 'bne +' and \
text[i+15].startswith('brl ') and \
text[i+16] == '+' and \
text[i+17] != 'tya':
text_opt += [text[i+1]]
text_opt += [text[i+2]]
text_opt += [text[i+3]]
text_opt += [text[i+5]]
text_opt += [text[i+6]]
text_opt += ['+']
text_opt += ['bmi +']
text_opt += [text[i+15]]
text_opt += ['+']
i += 17
opted += 1
#sys.stderr.write('5')
continue
if text[i] == 'ldx #1' and \
text[i+1] == 'sec' and \
text[i+2].startswith('sbc.b tcc__r') and \
text[i+3] == 'tay' and \
text[i+4] == 'bvc +' and \
text[i+5] == 'eor #$8000' and \
text[i+6] == '+' and \
text[i+7] == 'bmi +++' and \
text[i+8] == '++' and \
text[i+9] == 'dex' and \
text[i+10] == '+++' and \
text[i+11].startswith('stx.b tcc__r') and \
text[i+12] == 'txa' and \
text[i+13] == 'bne +' and \
text[i+14].startswith('brl ') and \
text[i+15] == '+' and \
text[i+16] != 'tya':
text_opt += [text[i+1]]
text_opt += [text[i+2]]
text_opt += [text[i+4]]
text_opt += [text[i+5]]
text_opt += ['+']
text_opt += ['bmi +']
text_opt += [text[i+14]]
text_opt += ['+']
i += 16
opted += 1
#sys.stderr.write('6')
continue
# end startswith('ld')
if text[i] == 'rep #$20' and text[i+1] == 'sep #$20':
i += 2
opted += 1
continue
if text[i] == 'sep #$20' and text[i+1].startswith('lda #') and text[i+2] == 'pha' and text[i+3].startswith('lda #') and text[i+4] == 'pha':
text_opt += ['pea.w (' + text[i+1].split('#')[1] + ' * 256 + ' + text[i+3].split('#')[1] + ')']
text_opt += [text[i]]
i += 5
opted += 1
continue
r = re.match('adc #(.*)$',text[i])
if r:
r1 = re.match('sta.b (tcc__[fr][0-9]*)$', text[i+1])
if r1:
if text[i+2] == 'inc.b ' + r1.groups()[0] and text[i+3] == 'inc.b ' + r1.groups()[0]:
text_opt += ['adc #' + r.groups()[0] + ' + 2']
text_opt += [text[i+1]]
i += 4
opted += 1
continue
if text[i][:6] in ['lda.l ','sta.l ']:
cont = False
for b in bss:
if text[i][2:].startswith('a.l ' + b + ' '):
text_opt += [text[i].replace('lda.l','lda.w').replace('sta.l','sta.w')]
i += 1
opted += 1
cont = True
break
if cont: continue
if text[i].startswith('jmp.w ') or text[i].startswith('bra __'):
j = i + 1
cont = False
while j < len(text) and text[j].endswith(':'):
if text[i].endswith(text[j][:-1]):
# redundant branch, discard it
i += 1
opted += 1
cont = True
break
j += 1
if cont: continue
if text[i].startswith('jmp.w '):
# worst case is a 4-byte instruction, so if the jump target is closer
# than 32 instructions, we can safely substitute a branch
label = text[i][6:] + ':'
cont = False
for lpos in range(max(0, i - 32), min(len(text), i + 32)):
if text[lpos] == label:
text_opt += [text[i].replace('jmp.w','bra')]
i += 1
opted += 1
cont = True
break
if cont: continue
text_opt += [text[i]]
i += 1
text = text_opt
if verbose: sys.stderr.write(str(opted) + ' optimizations performed\n')
totalopt += opted
for l in text_opt: print l
if verbose: sys.stderr.write(str(totalopt) + ' optimizations performed in total\n')
#prof.stop()

504
COPYING Normal file
View File

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

281
Changelog Normal file
View File

@ -0,0 +1,281 @@
version 0.9.23:
- initial PE executable format for windows version (grischka)
- '#pragma pack' support (grischka)
- '#include_next' support (Bernhard Fischer)
- ignore '-pipe' option
- added -f[no-]leading-underscore
- preprocessor function macro parsing fix (grischka)
version 0.9.22:
- simple memory optimisations: kernel compilation is 30% faster
- linker symbol definitions fixes
- gcc 3.4 fixes
- fixed value stack full error
- 'packed' attribute support for variables and structure fields
- ignore 'const' and 'volatile' in function prototypes
- allow '_Bool' in bit fields
version 0.9.21:
- ARM target support (Daniel Glöckner)
- added '-funsigned-char, '-fsigned-char' and
'-Wimplicit-function-declaration'
- fixed assignment of const struct in struct
- line comment fix (reported by Bertram Felgenhauer)
- initial TMS320C67xx target support (TK)
- win32 configure
- regparm() attribute
- many built-in assembler fixes
- added '.org', '.fill' and '.previous' assembler directives
- '-fno-common' option
- '-Ttext' linker option
- section alignment fixes
- bit fields fixes
- do not generate code for unused inline functions
- '-oformat' linker option.
- added 'binary' output format.
version 0.9.20:
- added '-w' option
- added '.gnu.linkonce' ELF sections support
- fixed libc linking when running in memory (avoid 'stat' function
errors).
- extended '-run' option to be able to give several arguments to a C
script.
version 0.9.19:
- "alacarte" linking (Dave Long)
- simpler function call
- more strict type checks
- added 'const' and 'volatile' support and associated warnings
- added -Werror, -Wunsupported, -Wwrite-strings, -Wall.
- added __builtin_types_compatible_p() and __builtin_constant_p()
- chars support in assembler (Dave Long)
- .string, .globl, .section, .text, .data and .bss asm directive
support (Dave Long)
- man page generated from tcc-doc.texi
- fixed macro argument substitution
- fixed zero argument macro parsing
- changed license to LGPL
- added -rdynamic option support
version 0.9.18:
- header fix (time.h)
- fixed inline asm without operand case
- fixed 'default:' or 'case x:' with '}' after (incorrect C construct accepted
by gcc)
- added 'A' inline asm constraint.
version 0.9.17:
- PLT generation fix
- tcc doc fixes (Peter Lund)
- struct parse fix (signaled by Pedro A. Aranda Gutierrez)
- better _Bool lvalue support (signaled by Alex Measday)
- function parameters must be converted to pointers (signaled by Neil Brown)
- sanitized string and character constant parsing
- fixed comment parse (signaled by Damian M Gryski)
- fixed macro function bug (signaled by Philippe Ribet)
- added configure (initial patch by Mitchell N Charity)
- added '-run' and '-v' options (initial patch by vlindos)
- added real date report in __DATE__ and __TIME__ macros
version 0.9.16:
- added assembler language support
- added GCC inline asm() support
- fixed multiple variable definitions : uninitialized variables are
created as COMMON symbols.
- optimized macro processing
- added GCC statement expressions support
- added GCC local labels support
- fixed array declaration in old style function parameters
- support casts in static structure initializations
- added various __xxx[__] keywords for GCC compatibility
- ignore __extension__ GCC in an expression or in a type (still not perfect)
- added '? :' GCC extension support
version 0.9.15:
- compilation fixes for glibc 2.2, gcc 2.95.3 and gcc 3.2.
- FreeBSD compile fixes. Makefile patches still missing (Carl Drougge).
- fixed file type guessing if '.' is in the path.
- fixed tcc_compile_string()
- add a dummy page in ELF files to fix RX/RW accesses (pageexec at
freemail dot hu).
version 0.9.14:
- added #warning. error message if invalid preprocessing directive.
- added CType structure to ease typing (faster parse).
- suppressed secondary hash tables (faster parse).
- rewrote parser by optimizing common cases (faster parse).
- fixed signed long long comparisons.
- fixed 'int a(), b();' declaration case.
- fixed structure init without '{}'.
- correct alignment support in structures.
- empty structures support.
- gcc testsuite now supported.
- output only warning if implicit integer/pointer conversions.
- added static bitfield init.
version 0.9.13:
- correct preprocessing token pasting (## operator) in all cases (added
preprocessing number token).
- fixed long long register spill.
- fixed signed long long '>>'.
- removed memory leaks.
- better error handling : processing can continue on link errors. A
custom callback can be added to display error messages. Most
errors do not call exit() now.
- ignore -O, -W, -m and -f options
- added old style function declarations
- added GCC __alignof__ support.
- added GCC typeof support.
- added GCC computed gotos support.
- added stack backtrace in runtime error message. Improved runtime
error position display.
version 0.9.12:
- more fixes for || and && handling.
- improved '? :' type handling.
- fixed bound checking generation with structures
- force '#endif' to be in same file as matching '#if'
- #include file optimization with '#ifndef #endif' construct detection
- macro handling optimization
- added tcc_relocate() and tcc_get_symbol() in libtcc.
version 0.9.11:
- stdarg.h fix for double type (thanks to Philippe Ribet).
- correct white space characters and added MSDOS newline support.
- fixed invalid implicit function call type declaration.
- special macros such as __LINE__ are defined if tested with defined().
- fixed '!' operator with relocated address.
- added symbol + offset relocation (fixes some static variable initializers)
- '-l' option can be specified anywhere. '-c' option yields default
output name. added '-r' option for relocatable output.
- fixed '\nnn' octal parsing.
- fixed local extern variables declarations.
version 0.9.10:
- fixed lvalue type when saved in local stack.
- fixed '#include' syntax when using macros.
- fixed '#line' bug.
- removed size limit on strings. Unified string constants handling
with variable declarations.
- added correct support for '\xX' in wchar_t strings.
- added support for bound checking in generated executables
- fixed -I include order.
- fixed incorrect function displayed in runtime error.
version 0.9.9:
- fixed preprocessor expression parsing for #if/#elif.
- relocated debug info (.stab section).
- relocated bounds info (.bounds section).
- fixed cast to char of char constants ('\377' is -1 instead of 255)
- fixed implicit cast for unary plus.
- strings and '__func__' have now 'char[]' type instead of 'char *'
(fixes sizeof() return value).
- added __start_xxx and __stop_xxx symbols in linker.
- better DLL creation support (option -shared begins to work).
- ELF sections and hash tables are resized dynamically.
- executables and DLLs are stripped by default.
version 0.9.8:
- First version of full ELF linking support (generate objects, static
executable, dynamic executable, dynamic libraries). Dynamic library
support is not finished (need PIC support in compiler and some
patches in symbol exporting).
- First version of ELF loader for object (.o) and archive (.a) files.
- Support of simple GNU ld scripts (GROUP and FILE commands)
- Separated runtime library and bound check code from TCC (smaller
compiler core).
- fixed register reload in float compare.
- fixed implicit char/short to int casting.
- allow array type for address of ('&') operator.
- fixed unused || or && result.
- added GCC style variadic macro support.
- optimized bound checking code for array access.
- tcc includes are now in $(prefix)/lib/tcc/include.
- more command line options - more consistent handling of multiple
input files.
- added tcc man page (thanks to Cyril Bouthors).
- uClibc Makefile update
- converted documentation to texinfo format.
- added developper's guide in documentation.
version 0.9.7:
- added library API for easy dynamic compilation (see libtcc.h - first
draft).
- fixed long long register spill bug.
- fixed '? :' register spill bug.
version 0.9.6:
- added floating point constant propagation (fixes negative floating
point constants bug).
version 0.9.5:
- uClibc patches (submitted by Alfonso Martone).
- error reporting fix
- added CONFIG_TCC_BCHECK to get smaller code if needed.
version 0.9.4:
- windows port (currently cannot use -g, -b and dll functions).
- faster and simpler I/O handling.
- '-D' option works in all cases.
- preprocessor fixes (#elif and empty macro args)
- floating point fixes
- first code for CIL generation (does not work yet)
version 0.9.3:
- better and smaller code generator.
- full ISOC99 64 bit 'long long' support.
- full 32 bit 'float', 64 bit 'double' and 96 bit 'long double' support.
- added '-U' option.
- added assembly sections support.
- even faster startup time by mmaping sections instead of mallocing them.
- added GNUC __attribute__ keyword support (currently supports
'section' and 'aligned' attributes).
- added ELF file output (only usable for debugging now)
- added debug symbol generation (STAB format).
- added integrated runtime error analysis ('-g' option: print clear
run time error messages instead of "Segmentation fault").
- added first version of tiny memory and bound checker ('-b' option).
version 0.9.2:
- even faster parsing.
- various syntax parsing fixes.
- fixed external relocation handling for variables or functions pointers.
- better function pointers type handling.
- can compile multiple files (-i option).
- ANSI C bit fields are supported.
- beginning of float/double/long double support.
- beginning of long long support.
version 0.9.1:
- full ISOC99 initializers handling.
- compound literals.
- structures handle in assignments and as function param or return value.
- wide chars and strings.
- macro bug fix
version 0.9:
- initial version.

268
Makefile Normal file
View File

@ -0,0 +1,268 @@
#
# Tiny C Compiler Makefile
#
include config.mak
#CFLAGS=-pg -fprofile-arcs -ftest-coverage -O0 -g -Wall -Wno-pointer-sign
CFLAGS=-O2 -g -Wno-pointer-sign -Wno-sign-compare -Wno-unused-result
ifndef CONFIG_WIN32
BCHECK_O=bcheck.o
endif
CFLAGS_P=$(CFLAGS) -pg -static -DCONFIG_TCC_STATIC
LIBS_P=
CFLAGS+=-mpreferred-stack-boundary=4
ifeq ($(GCC_MAJOR),2)
CFLAGS+=-m386 -malign-functions=0
else
CFLAGS+=-falign-functions=0 -fno-strict-aliasing
endif
DISAS=objdump -d
INSTALL=install
ifdef CONFIG_CROSS
PROGS+=816-tcc$(EXESUF)
endif
# run local version of tcc with local libraries and includes
TCC=./tcc -B. -I.
all: $(PROGS) \
tcc-doc.html tcc.1
Makefile: config.mak
# auto test
test: test.ref test.out
@if diff -u test.ref test.out ; then echo "Auto Test OK"; fi
tcctest.ref: tcctest.c
$(CC) $(CFLAGS) -I. -o $@ $<
test.ref: tcctest.ref
./tcctest.ref > $@
test.out: tcc tcctest.c
$(TCC) -run tcctest.c > $@
run: tcc tcctest.c
$(TCC) -run tcctest.c
# iterated test2 (compile tcc then compile tcctest.c !)
test2: tcc tcc.c tcctest.c test.ref
$(TCC) -run tcc.c -B. -I. -run tcctest.c > test.out2
@if diff -u test.ref test.out2 ; then echo "Auto Test2 OK"; fi
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
test3: tcc tcc.c tcctest.c test.ref
$(TCC) -run tcc.c -B. -I. -run tcc.c -B. -I. -run tcctest.c > test.out3
@if diff -u test.ref test.out3 ; then echo "Auto Test3 OK"; fi
# binary output test
test4: tcc test.ref
# dynamic output
$(TCC) -o tcctest1 tcctest.c
./tcctest1 > test1.out
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
# static output
$(TCC) -static -o tcctest2 tcctest.c
./tcctest2 > test2.out
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
# object + link output
$(TCC) -c -o tcctest3.o tcctest.c
$(TCC) -o tcctest3 tcctest3.o
./tcctest3 > test3.out
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
# dynamic output + bound check
$(TCC) -b -o tcctest4 tcctest.c
./tcctest4 > test4.out
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
# memory and bound check auto test
BOUNDS_OK = 1 4 8 10
BOUNDS_FAIL= 2 5 7 9 11 12 13
btest: boundtest.c tcc
@for i in $(BOUNDS_OK); do \
if $(TCC) -b -run boundtest.c $$i ; then \
/bin/true ; \
else\
echo Failed positive test $$i ; exit 1 ; \
fi ;\
done ;\
for i in $(BOUNDS_FAIL); do \
if $(TCC) -b -run boundtest.c $$i ; then \
echo Failed negative test $$i ; exit 1 ;\
else\
/bin/true ; \
fi\
done ;\
echo Bound test OK
# speed test
speed: tcc ex2 ex3
time ./ex2 1238 2 3 4 10 13 4
time ./tcc -I. ./ex2.c 1238 2 3 4 10 13 4
time ./ex3 35
time ./tcc -I. ./ex3.c 35
ex2: ex2.c
$(CC) $(CFLAGS) -o $@ $<
ex3: ex3.c
$(CC) $(CFLAGS) -o $@ $<
# Host Tiny C Compiler
ifdef CONFIG_WIN32
tcc$(EXESUF): tcc.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h tccpe.c
$(CC) $(CFLAGS) -DTCC_TARGET_PE -o $@ $< $(LIBS)
else
ifeq ($(ARCH),i386)
tcc$(EXESUF): tcc.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
endif
ifeq ($(ARCH),arm)
tcc$(EXESUF): tcc.c arm-gen.c tccelf.c tccasm.c tcctok.h libtcc.h
$(CC) $(CFLAGS) -DTCC_TARGET_ARM -o $@ $< $(LIBS)
endif
endif
# Cross Tiny C Compilers
816-tcc$(EXESUF): tcc.c 816-gen.c tccelf.c tcctok.h
$(CC) $(CFLAGS) -DTCC_TARGET_816 -o $@ $< $(LIBS)
# windows utilities
tiny_impdef$(EXESUF): tiny_impdef.c
$(CC) $(CFLAGS) -o $@ $< -lkernel32
# TinyCC runtime libraries
ifdef CONFIG_WIN32
# for windows, we must use TCC because we generate ELF objects
LIBTCC1_OBJS=$(addprefix win32/lib/, crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o) libtcc1.o
LIBTCC1_CC=./tcc.exe -Bwin32
else
LIBTCC1_OBJS=libtcc1.o
LIBTCC1_CC=$(CC)
endif
%.o: %.c
$(LIBTCC1_CC) -O2 -Wall -c -o $@ $<
%.o: %.S
$(LIBTCC1_CC) -c -o $@ $<
libtcc1.a: $(LIBTCC1_OBJS)
$(AR) rcs $@ $^
bcheck.o: bcheck.c
$(CC) -O2 -Wall -c -o $@ $<
install: tcc_install libinstall
tcc_install: $(PROGS) tcc.1 libtcc1.a $(BCHECK_O) tcc-doc.html tcc.1
mkdir -p "$(bindir)"
$(INSTALL) -s -m755 $(PROGS) "$(bindir)"
ifndef CONFIG_WIN32
mkdir -p "$(mandir)/man1"
$(INSTALL) tcc.1 "$(mandir)/man1"
endif
mkdir -p "$(tccdir)"
mkdir -p "$(tccdir)/include"
ifdef CONFIG_WIN32
mkdir -p "$(tccdir)/lib"
$(INSTALL) -m644 libtcc1.a win32/lib/*.def "$(tccdir)/lib"
cp -r win32/include/. "$(tccdir)/include"
cp -r win32/examples/. "$(tccdir)/examples"
else
$(INSTALL) -m644 libtcc1.a $(BCHECK_O) "$(tccdir)"
$(INSTALL) -m644 stdarg.h stddef.h stdbool.h float.h varargs.h \
tcclib.h "$(tccdir)/include"
endif
mkdir -p "$(docdir)"
$(INSTALL) -m644 tcc-doc.html "$(docdir)"
ifdef CONFIG_WIN32
$(INSTALL) -m644 win32/readme.txt "$(docdir)"
endif
clean:
rm -f *~ *.o *.a tcc tcc1 tcct tcc_g tcctest.ref *.bin *.i ex2 \
core gmon.out test.out test.ref a.out tcc_p \
*.exe *.lib tcc.pod libtcc_test \
tcctest[1234] test[1234].out $(PROGS) win32/lib/*.o test/failtraces/* 816-tcc
distclean: clean
rm -f config.h config.mak config.texi
# profiling version
tcc_p: tcc.c Makefile
$(CC) $(CFLAGS_P) -o $@ $< $(LIBS_P)
# libtcc generation and example
libinstall: libtcc.a
mkdir -p "$(libdir)"
$(INSTALL) -m644 libtcc.a "$(libdir)"
mkdir -p "$(includedir)"
$(INSTALL) -m644 libtcc.h "$(includedir)"
libtcc.o: tcc.c Makefile
$(CC) $(CFLAGS) -DLIBTCC -c -o $@ $<
libtcc.a: libtcc.o
$(AR) rcs $@ $^
libtcc_test$(EXESUF): libtcc_test.c libtcc.a
$(CC) $(CFLAGS) -o $@ $< libtcc.a $(LIBS)
libtest: libtcc_test
./libtcc_test
# targets for development
%.bin: %.c tcc
$(TCC) -g -o $@ $<
$(DISAS) $@
instr: instr.o
objdump -d instr.o
# tiny assembler testing
asmtest.ref: asmtest.S
$(CC) -c -o asmtest.ref.o asmtest.S
objdump -D asmtest.ref.o > $@
# XXX: we compute tcc.c to go faster during development !
asmtest.out: asmtest.S tcc
# ./tcc tcc.c -c asmtest.S
#asmtest.out: asmtest.S tcc
./tcc -c asmtest.S
objdump -D asmtest.o > $@
asmtest: asmtest.out asmtest.ref
@if diff -u --ignore-matching-lines="file format" asmtest.ref asmtest.out ; then echo "ASM Auto Test OK"; fi
instr.o: instr.S
$(CC) -O2 -Wall -g -c -o $@ $<
cache: tcc_g
cachegrind ./tcc_g -o /tmp/linpack -lm bench/linpack.c
vg_annotate tcc.c > /tmp/linpack.cache.log
# documentation and man page
tcc-doc.html: tcc-doc.texi
texi2html -monolithic -number $<
tcc.1: tcc-doc.texi
./texi2pod.pl $< tcc.pod
pod2man --section=1 --center=" " --release=" " tcc.pod > $@
FILE=tcc-$(shell cat VERSION)
# tar release (use 'make -k tar' on a checkouted tree)
tar:
rm -rf /tmp/$(FILE)
cp -r . /tmp/$(FILE)
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
rm -rf /tmp/$(FILE)

91
README Normal file
View File

@ -0,0 +1,91 @@
Tiny C Compiler - C Scripting Everywhere - The Smallest ANSI C compiler
-----------------------------------------------------------------------
Features:
--------
- SMALL! You can compile and execute C code everywhere, for example on
rescue disks.
- FAST! tcc generates optimized x86 code. No byte code
overhead. Compile, assemble and link about 7 times faster than 'gcc
-O0'.
- UNLIMITED! Any C dynamic library can be used directly. TCC is
heading torward full ISOC99 compliance. TCC can of course compile
itself.
- SAFE! tcc includes an optional memory and bound checker. Bound
checked code can be mixed freely with standard code.
- Compile and execute C source directly. No linking or assembly
necessary. Full C preprocessor included.
- C script supported : just add '#!/usr/local/bin/tcc -run' at the first
line of your C source, and execute it directly from the command
line.
Documentation:
-------------
1) Installation on a i386 Linux host (for Windows read win32/readme.txt)
./configure
make
make test
make install
By default, tcc is installed in /usr/local/bin.
./configure --help shows configuration options.
2) Introduction
We assume here that you know ANSI C. Look at the example ex1.c to know
what the programs look like.
The include file <tcclib.h> can be used if you want a small basic libc
include support (especially useful for floppy disks). Of course, you
can also use standard headers, although they are slower to compile.
You can begin your C script with '#!/usr/local/bin/tcc -run' on the first
line and set its execute bits (chmod a+x your_script). Then, you can
launch the C code as a shell or perl script :-) The command line
arguments are put in 'argc' and 'argv' of the main functions, as in
ANSI C.
3) Examples
ex1.c: simplest example (hello world). Can also be launched directly
as a script: './ex1.c'.
ex2.c: more complicated example: find a number with the four
operations given a list of numbers (benchmark).
ex3.c: compute fibonacci numbers (benchmark).
ex4.c: more complicated: X11 program. Very complicated test in fact
because standard headers are being used !
ex5.c: 'hello world' with standard glibc headers.
tcc.c: TCC can of course compile itself. Used to check the code
generator.
tcctest.c: auto test for TCC which tests many subtle possible bugs. Used
when doing 'make test'.
4) Full Documentation
Please read tcc-doc.html to have all the features of TCC.
Additional information is available for the Windows port in
win32/readme.txt.
License:
-------
TCC is distributed under the GNU Lesser General Public License (see
COPYING file).
Fabrice Bellard.

81
TODO Normal file
View File

@ -0,0 +1,81 @@
TODO list:
- bug with defines:
#define spin_lock(lock) do { } while (0)
#define wq_spin_lock spin_lock
#define TEST() wq_spin_lock(a)
- typedefs can be structure fields
- see bugfixes.diff + improvement.diff from Daniel Glockner
- constructors
- cast bug (Peter Wang)
- define incomplete type if defined several times (Peter Wang).
- long long constant evaluation
- configure --cc=tcc (still one bug in libtcc1.c)
- disable-asm and disable-bcheck options
- test binutils/gcc compile
- add alloca(), __builtin_expect()
- gcc '-E' option.
- optimize VT_LOCAL + const
- tci patch + argument.
- '-b' bug.
- atexit (Nigel Horne)
- see -lxxx bug (Michael Charity).
- see transparent union pb in /urs/include/sys/socket.h
- precise behaviour of typeof with arrays ? (__put_user macro)
- #include_next support for /usr/include/limits ?
but should suffice for most cases)
- handle '? x, y : z' in unsized variable initialization (',' is
considered incorrectly as separator in preparser)
- function pointers/lvalues in ? : (linux kernel net/core/dev.c)
- transform functions to function pointers in function parameters (net/ipv4/ip_output.c)
- fix function pointer type display
- fix bound exit on RedHat 7.3
- check lcc test suite -> fix bitfield binary operations
- check section alignment in C
- fix invalid cast in comparison 'if (v == (int8_t)v)'
- packed attribute
- finish varargs.h support (gcc 3.2 testsuite issue)
- fix static functions declared inside block
- C99: add variable size arrays (gcc 3.2 testsuite issue)
- C99: add complex types (gcc 3.2 testsuite issue)
- postfix compound literals (see 20010124-1.c)
- fix multiple unions init
- setjmp is not supported properly in bound checking.
- better local variables handling (needed for other targets)
- fix bound check code with '&' on local variables (currently done
only for local arrays).
- sizeof, alignof, typeof can still generate code in some cases.
- bound checking and float/long long/struct copy code. bound
checking and symbol + offset optimization
- Fix the remaining libtcc memory leaks.
- make libtcc fully reentrant (except for the compilation stage itself).
- '-MD' option
Optimizations:
- suppress specific anonymous symbol handling
- more parse optimizations (=even faster compilation)
- memory alloc optimizations (=even faster compilation)
Not critical:
- C99: fix multiple compound literals inits in blocks (ISOC99
normative example - only relevant when using gotos! -> must add
boolean variable to tell if compound literal was already
initialized).
- add PowerPC or ARM code generator and improve codegen for RISC (need
to suppress VT_LOCAL and use a base register instead).
- interactive mode / integrated debugger
- fix preprocessor symbol redefinition
- better constant opt (&&, ||, ?:)
- add portable byte code generator and interpreter for other
unsupported architectures.
- C++: variable declaration in for, minimal 'class' support.
- win32: add __stdcall, __intxx. use resolve for bchecked malloc et
al. check GetModuleHandle for dlls. check exception code (exception
filter func).
- handle void (__attribute__() *ptr)()

1
VERSION Normal file
View File

@ -0,0 +1 @@
0.9.23

867
bcheck.c Normal file
View File

@ -0,0 +1,867 @@
/*
* Tiny C Memory and bounds checker
*
* Copyright (c) 2002 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#ifndef __FreeBSD__
#include <malloc.h>
#endif
//#define BOUND_DEBUG
/* define so that bound array is static (faster, but use memory if
bound checking not used) */
//#define BOUND_STATIC
/* use malloc hooks. Currently the code cannot be reliable if no hooks */
#define CONFIG_TCC_MALLOC_HOOKS
#define HAVE_MEMALIGN
#if defined(__FreeBSD__) || defined(__dietlibc__)
#warning Bound checking not fully supported on FreeBSD
#undef CONFIG_TCC_MALLOC_HOOKS
#undef HAVE_MEMALIGN
#endif
#define BOUND_T1_BITS 13
#define BOUND_T2_BITS 11
#define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS)
#define BOUND_T1_SIZE (1 << BOUND_T1_BITS)
#define BOUND_T2_SIZE (1 << BOUND_T2_BITS)
#define BOUND_T3_SIZE (1 << BOUND_T3_BITS)
#define BOUND_E_BITS 4
#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
#define BOUND_T23_SIZE (1 << BOUND_T23_BITS)
/* this pointer is generated when bound check is incorrect */
#define INVALID_POINTER ((void *)(-2))
/* size of an empty region */
#define EMPTY_SIZE 0xffffffff
/* size of an invalid region */
#define INVALID_SIZE 0
typedef struct BoundEntry {
unsigned long start;
unsigned long size;
struct BoundEntry *next;
unsigned long is_invalid; /* true if pointers outside region are invalid */
} BoundEntry;
/* external interface */
void __bound_init(void);
void __bound_new_region(void *p, unsigned long size);
int __bound_delete_region(void *p);
#define FASTCALL __attribute__((regparm(3)))
void *__bound_malloc(size_t size, const void *caller);
void *__bound_memalign(size_t size, size_t align, const void *caller);
void __bound_free(void *ptr, const void *caller);
void *__bound_realloc(void *ptr, size_t size, const void *caller);
static void *libc_malloc(size_t size);
static void libc_free(void *ptr);
static void install_malloc_hooks(void);
static void restore_malloc_hooks(void);
#ifdef CONFIG_TCC_MALLOC_HOOKS
static void *saved_malloc_hook;
static void *saved_free_hook;
static void *saved_realloc_hook;
static void *saved_memalign_hook;
#endif
/* linker definitions */
extern char _end;
/* TCC definitions */
extern char __bounds_start; /* start of static bounds table */
/* error message, just for TCC */
const char *__bound_error_msg;
/* runtime error output */
extern void rt_error(unsigned long pc, const char *fmt, ...);
#ifdef BOUND_STATIC
static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
#else
static BoundEntry **__bound_t1; /* page table */
#endif
static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */
static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */
static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
{
unsigned long addr, tmp;
BoundEntry *e;
e = e1;
while (e != NULL) {
addr = (unsigned long)p;
addr -= e->start;
if (addr <= e->size) {
/* put region at the head */
tmp = e1->start;
e1->start = e->start;
e->start = tmp;
tmp = e1->size;
e1->size = e->size;
e->size = tmp;
return e1;
}
e = e->next;
}
/* no entry found: return empty entry or invalid entry */
if (e1->is_invalid)
return __bound_invalid_t2;
else
return __bound_empty_t2;
}
/* print a bound error message */
static void bound_error(const char *fmt, ...)
{
__bound_error_msg = fmt;
*(int *)0 = 0; /* force a runtime error */
}
static void bound_alloc_error(void)
{
bound_error("not enough memory for bound checking code");
}
/* currently, tcc cannot compile that because we use GNUC extensions */
#if !defined(__TINYC__)
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
the end of a region in this case */
void * FASTCALL __bound_ptr_add(void *p, int offset)
{
unsigned long addr = (unsigned long)p;
BoundEntry *e;
#if defined(BOUND_DEBUG)
printf("add: 0x%x %d\n", (int)p, offset);
#endif
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
e = (BoundEntry *)((char *)e +
((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
addr -= e->start;
if (addr > e->size) {
e = __bound_find_region(e, p);
addr = (unsigned long)p - e->start;
}
addr += offset;
if (addr > e->size)
return INVALID_POINTER; /* return an invalid pointer */
return p + offset;
}
/* return '(p + offset)' for pointer indirection (the resulting must
be strictly inside the region */
#define BOUND_PTR_INDIR(dsize) \
void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \
{ \
unsigned long addr = (unsigned long)p; \
BoundEntry *e; \
\
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \
e = (BoundEntry *)((char *)e + \
((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \
((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); \
addr -= e->start; \
if (addr > e->size) { \
e = __bound_find_region(e, p); \
addr = (unsigned long)p - e->start; \
} \
addr += offset + dsize; \
if (addr > e->size) \
return INVALID_POINTER; /* return an invalid pointer */ \
return p + offset; \
}
#ifdef __i386__
/* return the frame pointer of the caller */
#define GET_CALLER_FP(fp)\
{\
unsigned long *fp1;\
__asm__ __volatile__ ("movl %%ebp,%0" :"=g" (fp1));\
fp = fp1[0];\
}
#else
#error put code to extract the calling frame pointer
#endif
/* called when entering a function to add all the local regions */
void FASTCALL __bound_local_new(void *p1)
{
unsigned long addr, size, fp, *p = p1;
GET_CALLER_FP(fp);
for(;;) {
addr = p[0];
if (addr == 0)
break;
addr += fp;
size = p[1];
p += 2;
__bound_new_region((void *)addr, size);
}
}
/* called when leaving a function to delete all the local regions */
void FASTCALL __bound_local_delete(void *p1)
{
unsigned long addr, fp, *p = p1;
GET_CALLER_FP(fp);
for(;;) {
addr = p[0];
if (addr == 0)
break;
addr += fp;
p += 2;
__bound_delete_region((void *)addr);
}
}
#else
void __bound_local_new(void *p)
{
}
void __bound_local_delete(void *p)
{
}
void *__bound_ptr_add(void *p, int offset)
{
return p + offset;
}
#define BOUND_PTR_INDIR(dsize) \
void *__bound_ptr_indir ## dsize (void *p, int offset) \
{ \
return p + offset; \
}
#endif
BOUND_PTR_INDIR(1)
BOUND_PTR_INDIR(2)
BOUND_PTR_INDIR(4)
BOUND_PTR_INDIR(8)
BOUND_PTR_INDIR(12)
BOUND_PTR_INDIR(16)
static BoundEntry *__bound_new_page(void)
{
BoundEntry *page;
int i;
page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
if (!page)
bound_alloc_error();
for(i=0;i<BOUND_T2_SIZE;i++) {
/* put empty entries */
page[i].start = 0;
page[i].size = EMPTY_SIZE;
page[i].next = NULL;
page[i].is_invalid = 0;
}
return page;
}
/* currently we use malloc(). Should use bound_new_page() */
static BoundEntry *bound_new_entry(void)
{
BoundEntry *e;
e = libc_malloc(sizeof(BoundEntry));
return e;
}
static void bound_free_entry(BoundEntry *e)
{
libc_free(e);
}
static inline BoundEntry *get_page(int index)
{
BoundEntry *page;
page = __bound_t1[index];
if (page == __bound_empty_t2 || page == __bound_invalid_t2) {
/* create a new page if necessary */
page = __bound_new_page();
__bound_t1[index] = page;
}
return page;
}
/* mark a region as being invalid (can only be used during init) */
static void mark_invalid(unsigned long addr, unsigned long size)
{
unsigned long start, end;
BoundEntry *page;
int t1_start, t1_end, i, j, t2_start, t2_end;
start = addr;
end = addr + size;
t2_start = (start + BOUND_T3_SIZE - 1) >> BOUND_T3_BITS;
if (end != 0)
t2_end = end >> BOUND_T3_BITS;
else
t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
#if 0
printf("mark_invalid: start = %x %x\n", t2_start, t2_end);
#endif
/* first we handle full pages */
t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS;
t1_end = t2_end >> BOUND_T2_BITS;
i = t2_start & (BOUND_T2_SIZE - 1);
j = t2_end & (BOUND_T2_SIZE - 1);
if (t1_start == t1_end) {
page = get_page(t2_start >> BOUND_T2_BITS);
for(; i < j; i++) {
page[i].size = INVALID_SIZE;
page[i].is_invalid = 1;
}
} else {
if (i > 0) {
page = get_page(t2_start >> BOUND_T2_BITS);
for(; i < BOUND_T2_SIZE; i++) {
page[i].size = INVALID_SIZE;
page[i].is_invalid = 1;
}
}
for(i = t1_start; i < t1_end; i++) {
__bound_t1[i] = __bound_invalid_t2;
}
if (j != 0) {
page = get_page(t1_end);
for(i = 0; i < j; i++) {
page[i].size = INVALID_SIZE;
page[i].is_invalid = 1;
}
}
}
}
void __bound_init(void)
{
int i;
BoundEntry *page;
unsigned long start, size;
int *p;
/* save malloc hooks and install bound check hooks */
install_malloc_hooks();
#ifndef BOUND_STATIC
__bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *));
if (!__bound_t1)
bound_alloc_error();
#endif
__bound_empty_t2 = __bound_new_page();
for(i=0;i<BOUND_T1_SIZE;i++) {
__bound_t1[i] = __bound_empty_t2;
}
page = __bound_new_page();
for(i=0;i<BOUND_T2_SIZE;i++) {
/* put invalid entries */
page[i].start = 0;
page[i].size = INVALID_SIZE;
page[i].next = NULL;
page[i].is_invalid = 1;
}
__bound_invalid_t2 = page;
/* invalid pointer zone */
start = (unsigned long)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
size = BOUND_T23_SIZE;
mark_invalid(start, size);
#if !defined(__TINYC__) && defined(CONFIG_TCC_MALLOC_HOOKS)
/* malloc zone is also marked invalid. can only use that with
hooks because all libs should use the same malloc. The solution
would be to build a new malloc for tcc. */
start = (unsigned long)&_end;
size = 128 * 0x100000;
mark_invalid(start, size);
#endif
/* add all static bound check values */
p = (int *)&__bounds_start;
while (p[0] != 0) {
__bound_new_region((void *)p[0], p[1]);
p += 2;
}
}
static inline void add_region(BoundEntry *e,
unsigned long start, unsigned long size)
{
BoundEntry *e1;
if (e->start == 0) {
/* no region : add it */
e->start = start;
e->size = size;
} else {
/* already regions in the list: add it at the head */
e1 = bound_new_entry();
e1->start = e->start;
e1->size = e->size;
e1->next = e->next;
e->start = start;
e->size = size;
e->next = e1;
}
}
/* create a new region. It should not already exist in the region list */
void __bound_new_region(void *p, unsigned long size)
{
unsigned long start, end;
BoundEntry *page, *e, *e2;
int t1_start, t1_end, i, t2_start, t2_end;
start = (unsigned long)p;
end = start + size;
t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
/* start */
page = get_page(t1_start);
t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
#ifdef BOUND_DEBUG
printf("new %lx %lx %x %x %x %x\n",
start, end, t1_start, t1_end, t2_start, t2_end);
#endif
e = (BoundEntry *)((char *)page + t2_start);
add_region(e, start, size);
if (t1_end == t1_start) {
/* same ending page */
e2 = (BoundEntry *)((char *)page + t2_end);
if (e2 > e) {
e++;
for(;e<e2;e++) {
e->start = start;
e->size = size;
}
add_region(e, start, size);
}
} else {
/* mark until end of page */
e2 = page + BOUND_T2_SIZE;
e++;
for(;e<e2;e++) {
e->start = start;
e->size = size;
}
/* mark intermediate pages, if any */
for(i=t1_start+1;i<t1_end;i++) {
page = get_page(i);
e2 = page + BOUND_T2_SIZE;
for(e=page;e<e2;e++) {
e->start = start;
e->size = size;
}
}
/* last page */
page = get_page(t1_end);
e2 = (BoundEntry *)((char *)page + t2_end);
for(e=page;e<e2;e++) {
e->start = start;
e->size = size;
}
add_region(e, start, size);
}
}
/* delete a region */
static inline void delete_region(BoundEntry *e,
void *p, unsigned long empty_size)
{
unsigned long addr;
BoundEntry *e1;
addr = (unsigned long)p;
addr -= e->start;
if (addr <= e->size) {
/* region found is first one */
e1 = e->next;
if (e1 == NULL) {
/* no more region: mark it empty */
e->start = 0;
e->size = empty_size;
} else {
/* copy next region in head */
e->start = e1->start;
e->size = e1->size;
e->next = e1->next;
bound_free_entry(e1);
}
} else {
/* find the matching region */
for(;;) {
e1 = e;
e = e->next;
/* region not found: do nothing */
if (e == NULL)
break;
addr = (unsigned long)p - e->start;
if (addr <= e->size) {
/* found: remove entry */
e1->next = e->next;
bound_free_entry(e);
break;
}
}
}
}
/* WARNING: 'p' must be the starting point of the region. */
/* return non zero if error */
int __bound_delete_region(void *p)
{
unsigned long start, end, addr, size, empty_size;
BoundEntry *page, *e, *e2;
int t1_start, t1_end, t2_start, t2_end, i;
start = (unsigned long)p;
t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
/* find region size */
page = __bound_t1[t1_start];
e = (BoundEntry *)((char *)page + t2_start);
addr = start - e->start;
if (addr > e->size)
e = __bound_find_region(e, p);
/* test if invalid region */
if (e->size == EMPTY_SIZE || (unsigned long)p != e->start)
return -1;
/* compute the size we put in invalid regions */
if (e->is_invalid)
empty_size = INVALID_SIZE;
else
empty_size = EMPTY_SIZE;
size = e->size;
end = start + size;
/* now we can free each entry */
t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
delete_region(e, p, empty_size);
if (t1_end == t1_start) {
/* same ending page */
e2 = (BoundEntry *)((char *)page + t2_end);
if (e2 > e) {
e++;
for(;e<e2;e++) {
e->start = 0;
e->size = empty_size;
}
delete_region(e, p, empty_size);
}
} else {
/* mark until end of page */
e2 = page + BOUND_T2_SIZE;
e++;
for(;e<e2;e++) {
e->start = 0;
e->size = empty_size;
}
/* mark intermediate pages, if any */
/* XXX: should free them */
for(i=t1_start+1;i<t1_end;i++) {
page = get_page(i);
e2 = page + BOUND_T2_SIZE;
for(e=page;e<e2;e++) {
e->start = 0;
e->size = empty_size;
}
}
/* last page */
page = get_page(t2_end);
e2 = (BoundEntry *)((char *)page + t2_end);
for(e=page;e<e2;e++) {
e->start = 0;
e->size = empty_size;
}
delete_region(e, p, empty_size);
}
return 0;
}
/* return the size of the region starting at p, or EMPTY_SIZE if non
existant region. */
static unsigned long get_region_size(void *p)
{
unsigned long addr = (unsigned long)p;
BoundEntry *e;
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
e = (BoundEntry *)((char *)e +
((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
addr -= e->start;
if (addr > e->size)
e = __bound_find_region(e, p);
if (e->start != (unsigned long)p)
return EMPTY_SIZE;
return e->size;
}
/* patched memory functions */
static void install_malloc_hooks(void)
{
#ifdef CONFIG_TCC_MALLOC_HOOKS
saved_malloc_hook = __malloc_hook;
saved_free_hook = __free_hook;
saved_realloc_hook = __realloc_hook;
saved_memalign_hook = __memalign_hook;
__malloc_hook = __bound_malloc;
__free_hook = __bound_free;
__realloc_hook = __bound_realloc;
__memalign_hook = __bound_memalign;
#endif
}
static void restore_malloc_hooks(void)
{
#ifdef CONFIG_TCC_MALLOC_HOOKS
__malloc_hook = saved_malloc_hook;
__free_hook = saved_free_hook;
__realloc_hook = saved_realloc_hook;
__memalign_hook = saved_memalign_hook;
#endif
}
static void *libc_malloc(size_t size)
{
void *ptr;
restore_malloc_hooks();
ptr = malloc(size);
install_malloc_hooks();
return ptr;
}
static void libc_free(void *ptr)
{
restore_malloc_hooks();
free(ptr);
install_malloc_hooks();
}
/* XXX: we should use a malloc which ensure that it is unlikely that
two malloc'ed data have the same address if 'free' are made in
between. */
void *__bound_malloc(size_t size, const void *caller)
{
void *ptr;
/* we allocate one more byte to ensure the regions will be
separated by at least one byte. With the glibc malloc, it may
be in fact not necessary */
ptr = libc_malloc(size + 1);
if (!ptr)
return NULL;
__bound_new_region(ptr, size);
return ptr;
}
void *__bound_memalign(size_t size, size_t align, const void *caller)
{
void *ptr;
restore_malloc_hooks();
#ifndef HAVE_MEMALIGN
if (align > 4) {
/* XXX: handle it ? */
ptr = NULL;
} else {
/* we suppose that malloc aligns to at least four bytes */
ptr = malloc(size + 1);
}
#else
/* we allocate one more byte to ensure the regions will be
separated by at least one byte. With the glibc malloc, it may
be in fact not necessary */
ptr = memalign(size + 1, align);
#endif
install_malloc_hooks();
if (!ptr)
return NULL;
__bound_new_region(ptr, size);
return ptr;
}
void __bound_free(void *ptr, const void *caller)
{
if (ptr == NULL)
return;
if (__bound_delete_region(ptr) != 0)
bound_error("freeing invalid region");
libc_free(ptr);
}
void *__bound_realloc(void *ptr, size_t size, const void *caller)
{
void *ptr1;
int old_size;
if (size == 0) {
__bound_free(ptr, caller);
return NULL;
} else {
ptr1 = __bound_malloc(size, caller);
if (ptr == NULL || ptr1 == NULL)
return ptr1;
old_size = get_region_size(ptr);
if (old_size == EMPTY_SIZE)
bound_error("realloc'ing invalid pointer");
memcpy(ptr1, ptr, old_size);
__bound_free(ptr, caller);
return ptr1;
}
}
#ifndef CONFIG_TCC_MALLOC_HOOKS
void *__bound_calloc(size_t nmemb, size_t size)
{
void *ptr;
size = size * nmemb;
ptr = __bound_malloc(size, NULL);
if (!ptr)
return NULL;
memset(ptr, 0, size);
return ptr;
}
#endif
#if 0
static void bound_dump(void)
{
BoundEntry *page, *e;
int i, j;
printf("region dump:\n");
for(i=0;i<BOUND_T1_SIZE;i++) {
page = __bound_t1[i];
for(j=0;j<BOUND_T2_SIZE;j++) {
e = page + j;
/* do not print invalid or empty entries */
if (e->size != EMPTY_SIZE && e->start != 0) {
printf("%08x:",
(i << (BOUND_T2_BITS + BOUND_T3_BITS)) +
(j << BOUND_T3_BITS));
do {
printf(" %08lx:%08lx", e->start, e->start + e->size);
e = e->next;
} while (e != NULL);
printf("\n");
}
}
}
}
#endif
/* some useful checked functions */
/* check that (p ... p + size - 1) lies inside 'p' region, if any */
static void __bound_check(const void *p, size_t size)
{
if (size == 0)
return;
p = __bound_ptr_add((void *)p, size);
if (p == INVALID_POINTER)
bound_error("invalid pointer");
}
void *__bound_memcpy(void *dst, const void *src, size_t size)
{
__bound_check(dst, size);
__bound_check(src, size);
/* check also region overlap */
if (src >= dst && src < dst + size)
bound_error("overlapping regions in memcpy()");
return memcpy(dst, src, size);
}
void *__bound_memmove(void *dst, const void *src, size_t size)
{
__bound_check(dst, size);
__bound_check(src, size);
return memmove(dst, src, size);
}
void *__bound_memset(void *dst, int c, size_t size)
{
__bound_check(dst, size);
return memset(dst, c, size);
}
/* XXX: could be optimized */
int __bound_strlen(const char *s)
{
const char *p;
int len;
len = 0;
for(;;) {
p = __bound_ptr_indir1((char *)s, len);
if (p == INVALID_POINTER)
bound_error("bad pointer in strlen()");
if (*p == '\0')
break;
len++;
}
return len;
}
char *__bound_strcpy(char *dst, const char *src)
{
int len;
len = __bound_strlen(src);
return __bound_memcpy(dst, src, len + 1);
}

214
boundtest.c Normal file
View File

@ -0,0 +1,214 @@
#include <stdlib.h>
#include <stdio.h>
#define NB_ITS 1000000
//#define NB_ITS 1
#define TAB_SIZE 100
int tab[TAB_SIZE];
int ret_sum;
char tab3[256];
int test1(void)
{
int i, sum = 0;
for(i=0;i<TAB_SIZE;i++) {
sum += tab[i];
}
return sum;
}
/* error */
int test2(void)
{
int i, sum = 0;
for(i=0;i<TAB_SIZE + 1;i++) {
sum += tab[i];
}
return sum;
}
/* actually, profiling test */
int test3(void)
{
int sum;
int i, it;
sum = 0;
for(it=0;it<NB_ITS;it++) {
for(i=0;i<TAB_SIZE;i++) {
sum += tab[i];
}
}
return sum;
}
/* ok */
int test4(void)
{
int i, sum = 0;
int *tab4;
tab4 = malloc(20 * sizeof(int));
for(i=0;i<20;i++) {
sum += tab4[i];
}
free(tab4);
return sum;
}
/* error */
int test5(void)
{
int i, sum = 0;
int *tab4;
tab4 = malloc(20 * sizeof(int));
for(i=0;i<21;i++) {
sum += tab4[i];
}
free(tab4);
return sum;
}
/* error */
/* XXX: currently: bug */
int test6(void)
{
int i, sum = 0;
int *tab4;
tab4 = malloc(20 * sizeof(int));
free(tab4);
for(i=0;i<21;i++) {
sum += tab4[i];
}
return sum;
}
/* error */
int test7(void)
{
int i, sum = 0;
int *p;
for(i=0;i<TAB_SIZE + 1;i++) {
p = &tab[i];
if (i == TAB_SIZE)
printf("i=%d %x\n", i, p);
sum += *p;
}
return sum;
}
/* ok */
int test8(void)
{
int i, sum = 0;
int tab[10];
for(i=0;i<10;i++) {
sum += tab[i];
}
return sum;
}
/* error */
int test9(void)
{
int i, sum = 0;
char tab[10];
for(i=0;i<11;i++) {
sum += tab[i];
}
return sum;
}
/* ok */
int test10(void)
{
char tab[10];
char tab1[10];
memset(tab, 0, 10);
memcpy(tab, tab1, 10);
memmove(tab, tab1, 10);
return 0;
}
/* error */
int test11(void)
{
char tab[10];
memset(tab, 0, 11);
return 0;
}
/* error */
int test12(void)
{
void *ptr;
ptr = malloc(10);
free(ptr);
free(ptr);
return 0;
}
/* error */
int test13(void)
{
char pad1 = 0;
char tab[10];
char pad2 = 0;
memset(tab, 'a', sizeof(tab));
return strlen(tab);
}
int (*table_test[])(void) = {
test1,
test1,
test2,
test3,
test4,
test5,
test6,
test7,
test8,
test9,
test10,
test11,
test12,
test13,
};
int main(int argc, char **argv)
{
int index;
int (*ftest)(void);
if (argc < 2) {
printf("usage: boundtest n\n"
"test TCC bound checking system\n"
);
exit(1);
}
index = 0;
if (argc >= 2)
index = atoi(argv[1]);
/* well, we also use bounds on this ! */
ftest = table_test[index];
ftest();
return 0;
}
/*
* without bound 0.77 s
* with bounds 4.73
*/

345
configure vendored Executable file
View File

@ -0,0 +1,345 @@
#!/bin/sh
#
# tcc configure script (c) 2003 Fabrice Bellard
#
# set temporary file name
if test ! -z "$TMPDIR" ; then
TMPDIR1="${TMPDIR}"
elif test ! -z "$TEMPDIR" ; then
TMPDIR1="${TEMPDIR}"
else
TMPDIR1="/tmp"
fi
TMPC="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.c"
TMPO="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.o"
TMPE="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}"
TMPS="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.S"
TMPH="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.h"
# default parameters
build_cross="no"
prefix=""
execprefix=""
bindir=""
libdir=""
tccdir=""
includedir=""
mandir=""
cross_prefix=""
cc="gcc"
host_cc="gcc"
ar="ar"
make="make"
strip="strip"
cpu=`uname -m`
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC|x86_64)
cpu="x86"
;;
armv4l)
cpu="armv4l"
;;
alpha)
cpu="alpha"
;;
"Power Macintosh"|ppc|ppc64)
cpu="powerpc"
;;
mips)
cpu="mips"
;;
s390)
cpu="s390"
;;
*)
cpu="unknown"
;;
esac
gprof="no"
bigendian="no"
mingw32="no"
LIBSUF=".a"
EXESUF=""
# OS specific
targetos=`uname -s`
case $targetos in
MINGW32*)
mingw32="yes"
;;
*) ;;
esac
# find source path
# XXX: we assume an absolute path is given when launching configure,
# except in './configure' case.
source_path=${0%configure}
source_path=${source_path%/}
source_path_used="yes"
if test -z "$source_path" -o "$source_path" = "." ; then
source_path=`pwd`
source_path_used="no"
fi
for opt do
case "$opt" in
--prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
;;
--exec-prefix=*) execprefix=`echo $opt | cut -d '=' -f 2`
;;
--bindir=*) bindir=`echo $opt | cut -d '=' -f 2`
;;
--libdir=*) libdir=`echo $opt | cut -d '=' -f 2`
;;
--includedir=*) includedir=`echo $opt | cut -d '=' -f 2`
;;
--mandir=*) mandir=`echo $opt | cut -d '=' -f 2`
;;
--source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
;;
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
;;
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
;;
--make=*) make=`echo $opt | cut -d '=' -f 2`
;;
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
;;
--extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
;;
--extra-libs=*) extralibs=${opt#--extra-libs=}
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--enable-gprof) gprof="yes"
;;
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
;;
--enable-cross) build_cross="yes"
;;
esac
done
# Checking for CFLAGS
if test -z "$CFLAGS"; then
CFLAGS="-O2"
fi
cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
if test "$mingw32" = "yes" ; then
LIBSUF=".lib"
EXESUF=".exe"
fi
if test -z "$cross_prefix" ; then
# ---
# big/little endian test
cat > $TMPC << EOF
#include <inttypes.h>
int main(int argc, char ** argv){
volatile uint32_t i=0x01234567;
return (*((uint8_t*)(&i))) == 0x67;
}
EOF
if $cc -o $TMPE $TMPC 2>/dev/null ; then
$TMPE && bigendian="yes"
else
echo big/little test failed
fi
else
# if cross compiling, cannot launch a program, so make a static guess
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" ; then
bigendian="yes"
fi
fi
# check gcc version
cat > $TMPC <<EOF
int main(void) {
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
return 0;
#else
#error gcc < 3.2
#endif
}
EOF
gcc_major="2"
if $cc -o $TMPO $TMPC 2> /dev/null ; then
gcc_major="3"
fi
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
cat << EOF
Usage: configure [options]
Options: [defaults in brackets after descriptions]
EOF
echo "Standard options:"
echo " --help print this message"
echo " --prefix=PREFIX install in PREFIX [$prefix]"
echo " --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX"
echo " [same as prefix]"
echo " --bindir=DIR user executables in DIR [EPREFIX/bin]"
echo " --libdir=DIR object code libraries in DIR [EPREFIX/lib]"
echo " --includedir=DIR C header files in DIR [PREFIX/include]"
echo " --mandir=DIR man documentation in DIR [PREFIX/man]"
echo " --enable-cross build cross compilers"
echo ""
echo "Advanced options (experts only):"
echo " --source-path=PATH path of source code [$source_path]"
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
echo " --cc=CC use C compiler CC [$cc]"
echo " --make=MAKE use specified make [$make]"
echo ""
#echo "NOTE: The object files are build at the place where configure is launched"
exit 1
fi
if test "$mingw32" = "yes" ; then
if test -z "$prefix" ; then
prefix="/c/Program Files/tcc"
fi
execprefix="$prefix"
bindir="$prefix"
tccdir="$prefix"
docdir="$prefix/doc"
else
if test -z "$prefix" ; then
prefix="/usr/local"
fi
if test x"$execprefix" = x""; then
execprefix="${prefix}"
fi
if test x"$bindir" = x""; then
bindir="${execprefix}/bin"
fi
if test x"$docdir" = x""; then
docdir="$prefix/share/doc/tcc"
fi
fi # mingw32
if test x"$libdir" = x""; then
libdir="${execprefix}/lib"
fi
if test x"$tccdir" = x""; then
tccdir="${execprefix}"
fi
if test x"$mandir" = x""; then
mandir="${prefix}/man"
fi
if test x"$includedir" = x""; then
includedir="${prefix}/include"
fi
echo "Binary directory $bindir"
echo "TinyCC directory $tccdir"
echo "Library directory $libdir"
echo "Include directory $includedir"
echo "Manual directory $mandir"
echo "Doc directory $docdir"
echo "Source path $source_path"
echo "C compiler $cc"
echo "make $make"
echo "CPU $cpu"
echo "Big Endian $bigendian"
echo "gprof enabled $gprof"
echo "cross compilers $build_cross"
echo "Creating config.mak and config.h"
echo "# Automatically generated by configure - do not modify" > config.mak
echo "/* Automatically generated by configure - do not modify */" > $TMPH
echo "prefix=$prefix" >> config.mak
echo "bindir=$bindir" >> config.mak
echo "tccdir=$tccdir" >> config.mak
echo "libdir=$libdir" >> config.mak
echo "includedir=$includedir" >> config.mak
echo "mandir=$mandir" >> config.mak
echo "docdir=$docdir" >> config.mak
echo "#define CONFIG_TCCDIR \"$tccdir\"" >> $TMPH
echo "MAKE=$make" >> config.mak
echo "CC=$cc" >> config.mak
echo "GCC_MAJOR=$gcc_major" >> config.mak
echo "#define GCC_MAJOR $gcc_major" >> $TMPH
echo "HOST_CC=$host_cc" >> config.mak
echo "AR=$ar" >> config.mak
echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
echo "CFLAGS=$CFLAGS" >> config.mak
echo "LDFLAGS=$LDFLAGS" >> config.mak
echo "LIBSUF=$LIBSUF" >> config.mak
echo "EXESUF=$EXESUF" >> config.mak
if test "$cpu" = "x86" -o "$cpu" = "x86_64" ; then
echo "ARCH=i386" >> config.mak
echo "#define HOST_I386 1" >> $TMPH
elif test "$cpu" = "armv4l" ; then
echo "ARCH=arm" >> config.mak
echo "#define HOST_ARM 1" >> $TMPH
elif test "$cpu" = "powerpc" ; then
echo "ARCH=ppc" >> config.mak
echo "#define HOST_PPC 1" >> $TMPH
elif test "$cpu" = "mips" ; then
echo "ARCH=mips" >> config.mak
echo "#define HOST_MIPS 1" >> $TMPH
elif test "$cpu" = "s390" ; then
echo "ARCH=s390" >> config.mak
echo "#define HOST_S390 1" >> $TMPH
elif test "$cpu" = "alpha" ; then
echo "ARCH=alpha" >> config.mak
echo "#define HOST_ALPHA 1" >> $TMPH
else
echo "Unsupported CPU"
exit 1
fi
if test "$mingw32" = "yes" ; then
echo "CONFIG_WIN32=yes" >> config.mak
echo "#define CONFIG_WIN32 1" >> $TMPH
fi
if test "$bigendian" = "yes" ; then
echo "WORDS_BIGENDIAN=yes" >> config.mak
echo "#define WORDS_BIGENDIAN 1" >> $TMPH
fi
if test "$gprof" = "yes" ; then
echo "TARGET_GPROF=yes" >> config.mak
echo "#define HAVE_GPROF 1" >> $TMPH
fi
if test "$build_cross" = "yes" ; then
echo "CONFIG_CROSS=yes" >> config.mak
fi
version=`head $source_path/VERSION`
echo "VERSION=$version" >>config.mak
echo "#define TCC_VERSION \"$version\"" >> $TMPH
echo "@set VERSION $version" > config.texi
# build tree in object directory if source path is different from current one
if test "$source_path_used" = "yes" ; then
DIRS="tests"
FILES="Makefile tests/Makefile"
for dir in $DIRS ; do
mkdir -p $dir
done
for f in $FILES ; do
ln -sf $source_path/$f $f
done
fi
echo "SRC_PATH=$source_path" >> config.mak
diff $TMPH config.h >/dev/null 2>&1
if test $? -ne 0 ; then
mv -f $TMPH config.h
else
echo "config.h is unchanged"
fi
rm -f $TMPO $TMPC $TMPE $TMPS $TMPH

1628
elf.h Normal file

File diff suppressed because it is too large Load Diff

8
examples/ex1.c Executable file
View File

@ -0,0 +1,8 @@
#! /usr/local/bin/tcc -run
#include <tcclib.h>
int main()
{
printf("Hello World\n");
return 0;
}

97
examples/ex2.c Normal file
View File

@ -0,0 +1,97 @@
#include "tcclib.h"
#define N 20
int nb_num;
int tab[N];
int stack_ptr;
int stack_op[N];
int stack_res[60];
int result;
int find(int n, int i1, int a, int b, int op)
{
int i, j;
int c;
if (stack_ptr >= 0) {
stack_res[3*stack_ptr] = a;
stack_op[stack_ptr] = op;
stack_res[3*stack_ptr+1] = b;
stack_res[3*stack_ptr+2] = n;
if (n == result)
return 1;
tab[i1] = n;
}
for(i=0;i<nb_num;i++) {
for(j=i+1;j<nb_num;j++) {
a = tab[i];
b = tab[j];
if (a != 0 && b != 0) {
tab[j] = 0;
stack_ptr++;
if (find(a + b, i, a, b, '+'))
return 1;
if (find(a - b, i, a, b, '-'))
return 1;
if (find(b - a, i, b, a, '-'))
return 1;
if (find(a * b, i, a, b, '*'))
return 1;
if (b != 0) {
c = a / b;
if (find(c, i, a, b, '/'))
return 1;
}
if (a != 0) {
c = b / a;
if (find(c, i, b, a, '/'))
return 1;
}
stack_ptr--;
tab[i] = a;
tab[j] = b;
}
}
}
return 0;
}
int main(int argc, char **argv)
{
int i, res, p;
if (argc < 3) {
printf("usage: %s: result numbers...\n"
"Try to find result from numbers with the 4 basic operations.\n", argv[0]);
exit(1);
}
p = 1;
result = atoi(argv[p]);
printf("result=%d\n", result);
nb_num = 0;
for(i=p+1;i<argc;i++) {
tab[nb_num++] = atoi(argv[i]);
}
stack_ptr = -1;
res = find(0, 0, 0, 0, ' ');
if (res) {
for(i=0;i<=stack_ptr;i++) {
printf("%d %c %d = %d\n",
stack_res[3*i], stack_op[i],
stack_res[3*i+1], stack_res[3*i+2]);
}
return 0;
} else {
printf("Impossible\n");
return 1;
}
}

23
examples/ex3.c Normal file
View File

@ -0,0 +1,23 @@
#include <tcclib.h>
int fib(n)
{
if (n <= 2)
return 1;
else
return fib(n-1) + fib(n-2);
}
int main(int argc, char **argv)
{
int n;
if (argc < 2) {
printf("usage: fib n\n"
"Compute nth Fibonacci number\n");
return 1;
}
n = atoi(argv[1]);
printf("fib(%d) = %d\n", n, fib(n, 2));
return 0;
}

25
examples/ex4.c Executable file
View File

@ -0,0 +1,25 @@
#!./tcc -run -L/usr/X11R6/lib -lX11
#include <stdlib.h>
/* Yes, TCC can use X11 too ! */
#include <stdio.h>
#include <X11/Xlib.h>
int main(int argc, char **argv)
{
Display *display;
Screen *screen;
display = XOpenDisplay("");
if (!display) {
fprintf(stderr, "Could not open X11 display\n");
exit(1);
}
printf("X11 display opened.\n");
screen = XScreenOfDisplay(display, 0);
printf("width = %d\nheight = %d\ndepth = %d\n",
screen->width,
screen->height,
screen->root_depth);
XCloseDisplay(display);
return 0;
}

8
examples/ex5.c Normal file
View File

@ -0,0 +1,8 @@
#include <stdlib.h>
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}

57
float.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef _FLOAT_H_
#define _FLOAT_H_
#define FLT_RADIX 2
/* IEEE float */
#define FLT_MANT_DIG 24
#define FLT_DIG 6
#define FLT_ROUNDS 1
#define FLT_EPSILON 1.19209290e-07F
#define FLT_MIN_EXP (-125)
#define FLT_MIN 1.17549435e-38F
#define FLT_MIN_10_EXP (-37)
#define FLT_MAX_EXP 128
#define FLT_MAX 3.40282347e+38F
#define FLT_MAX_10_EXP 38
/* IEEE double */
#define DBL_MANT_DIG 53
#define DBL_DIG 15
#define DBL_EPSILON 2.2204460492503131e-16
#define DBL_MIN_EXP (-1021)
#define DBL_MIN 2.2250738585072014e-308
#define DBL_MIN_10_EXP (-307)
#define DBL_MAX_EXP 1024
#define DBL_MAX 1.7976931348623157e+308
#define DBL_MAX_10_EXP 308
/* horrible intel long double */
#ifdef __i386__
#define LDBL_MANT_DIG 64
#define LDBL_DIG 18
#define LDBL_EPSILON 1.08420217248550443401e-19L
#define LDBL_MIN_EXP (-16381)
#define LDBL_MIN 3.36210314311209350626e-4932L
#define LDBL_MIN_10_EXP (-4931)
#define LDBL_MAX_EXP 16384
#define LDBL_MAX 1.18973149535723176502e+4932L
#define LDBL_MAX_10_EXP 4932
#else
/* same as IEEE double */
#define LDBL_MANT_DIG 53
#define LDBL_DIG 15
#define LDBL_EPSILON 2.2204460492503131e-16
#define LDBL_MIN_EXP (-1021)
#define LDBL_MIN 2.2250738585072014e-308
#define LDBL_MIN_10_EXP (-307)
#define LDBL_MAX_EXP 1024
#define LDBL_MAX 1.7976931348623157e+308
#define LDBL_MAX_10_EXP 308
#endif
#endif /* _FLOAT_H_ */

33
gcctestsuite.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/sh
TESTSUITE_PATH=$HOME/gcc/gcc-3.2/gcc/testsuite/gcc.c-torture
TCC="./tcc -B. -I. -DNO_TRAMPOLINES"
rm -f tcc.sum tcc.log
nb_failed="0"
for src in $TESTSUITE_PATH/compile/*.c ; do
echo $TCC -o /tmp/test.o -c $src
$TCC -o /tmp/test.o -c $src >> tcc.log 2>&1
if [ "$?" == "0" ] ; then
result="PASS"
else
result="FAIL"
nb_failed=$[ $nb_failed + 1 ]
fi
echo "$result: $src" >> tcc.sum
done
for src in $TESTSUITE_PATH/execute/*.c ; do
echo $TCC $src
$TCC $src >> tcc.log 2>&1
if [ "$?" == "0" ] ; then
result="PASS"
else
result="FAIL"
nb_failed=$[ $nb_failed + 1 ]
fi
echo "$result: $src" >> tcc.sum
done
echo "$nb_failed test(s) failed." >> tcc.sum
echo "$nb_failed test(s) failed."

6
include/ctype.h Normal file
View File

@ -0,0 +1,6 @@
int isdigit(int c);
int isxdigit(int c);
int islower(int c);
int toupper(int c);
int isspace(int c);
int isprint(int c);

4
include/float.h Normal file
View File

@ -0,0 +1,4 @@
#define FLT_MIN __FLT_MIN__
#define FLT_MAX __FLT_MAX__
#define DBL_MIN FLT_MIN
#define DBL_MAX FLT_MAX

13
include/limits.h Normal file
View File

@ -0,0 +1,13 @@
#define INT_MAX 32767
#define INT_MIN -32768
#define UINT_MAX 65535
#define LONG_MAX INT_MAX
#define LONG_MIN INT_MIN
#define SCHAR_MAX 127
#define SCHAR_MIN -128
#define UCHAR_MAX 255
#define SHRT_MAX 32767
#define SHRT_MIN -32768
#define USHRT_MAX 65535
#define ULONG_MAX UINT_MAX
#define CHAR_BIT __CHAR_BIT__

10
include/math.h Normal file
View File

@ -0,0 +1,10 @@
float modf(float x, float *fp);
float ldexp(float x, int exp);
float floor(float d);
float ceil(float d);
float exp(float arg);
float frexp(float x, int *exp);
float log(float arg);
float log10(float arg);
float pow(float arg1, float arg2);
float fabs(float);

4
include/setjmp.h Normal file
View File

@ -0,0 +1,4 @@
typedef int jmp_buf[3];
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);

1
include/stdarg.h Symbolic link
View File

@ -0,0 +1 @@
../stdarg.h

53
include/stdbool.h Normal file
View File

@ -0,0 +1,53 @@
/* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GCC 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
/* As a special exception, if you include this header file into source
files compiled by GCC, this header file does not by itself cause
the resulting executable to be covered by the GNU General Public
License. This exception does not however invalidate any other
reasons why the executable file might be covered by the GNU General
Public License. */
/*
* ISO C Standard: 7.16 Boolean type and values <stdbool.h>
*/
#ifndef _STDBOOL_H
#define _STDBOOL_H
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#else /* __cplusplus */
/* Supporting <stdbool.h> in C++ is a GCC extension. */
#define _Bool bool
#define bool bool
#define false false
#define true true
#endif /* __cplusplus */
/* Signal that all the definitions are present. */
#define __bool_true_false_are_defined 1
#endif /* stdbool.h */

1
include/stddef.h Symbolic link
View File

@ -0,0 +1 @@
../stddef.h

7
include/stdint.h Normal file
View File

@ -0,0 +1,7 @@
typedef unsigned int uint16_t;
typedef unsigned long long uint32_t;
typedef unsigned char uint8_t;
typedef signed int int16_t;
typedef signed long long int32_t;
typedef signed char int8_t;

9
include/stdio.h Normal file
View File

@ -0,0 +1,9 @@
#include "stddef.h"
#include "stdarg.h"
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
int snprintf(char * buf, size_t size, const char *fmt, ...);
int vsprintf(char *buf, const char *fmt, va_list args);
int sprintf(char * buf, const char *fmt, ...);
int vsscanf(const char * buf, const char * fmt, va_list args);
int sscanf(const char * buf, const char * fmt, ...);

13
include/stdlib.h Normal file
View File

@ -0,0 +1,13 @@
#include "stddef.h"
void abort(void);
void exit(int status);
void *malloc(size_t size);
void free(void *ptr);
void *realloc(void *ptr, size_t size);
unsigned long strtoul(const char *cp,char **endp,unsigned int base);
long strtol(const char *cp,char **endp,unsigned int base);
unsigned long long strtoull(const char *cp,char **endp,unsigned int base);
long long strtoll(const char *cp,char **endp,unsigned int base);

20
include/string.h Normal file
View File

@ -0,0 +1,20 @@
#include "stddef.h"
void * memcpy(void *s1, const void *s2, size_t n);
void * mempcpy(void *s1, const void *s2, size_t n);
void * memmove(void *s1, const void *s2, size_t n);
void * memset(void *b, int c, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
char * strcpy(char *s1, const char *s2);
char * strncpy(char *s1, const char *s2, size_t n);
size_t strlen(const char *);
char * strchr(const char *, int);
char * strrchr(const char *, int);
char * strdup(const char *);

5
include/strings.h Normal file
View File

@ -0,0 +1,5 @@
#include "stddef.h"
void bzero(void *s, size_t n);
int ffs(int i);

97
libtcc.h Normal file
View File

@ -0,0 +1,97 @@
#ifndef LIBTCC_H
#define LIBTCC_H
#ifdef __cplusplus
extern "C" {
#endif
struct TCCState;
typedef struct TCCState TCCState;
/* create a new TCC compilation context */
TCCState *tcc_new(void);
/* free a TCC compilation context */
void tcc_delete(TCCState *s);
/* add debug information in the generated code */
void tcc_enable_debug(TCCState *s);
/* set error/warning display callback */
void tcc_set_error_func(TCCState *s, void *error_opaque,
void (*error_func)(void *opaque, const char *msg));
/* set/reset a warning */
int tcc_set_warning(TCCState *s, const char *warning_name, int value);
/*****************************/
/* preprocessor */
/* add include path */
int tcc_add_include_path(TCCState *s, const char *pathname);
/* add in system include path */
int tcc_add_sysinclude_path(TCCState *s, const char *pathname);
/* define preprocessor symbol 'sym'. Can put optional value */
void tcc_define_symbol(TCCState *s, const char *sym, const char *value);
/* undefine preprocess symbol 'sym' */
void tcc_undefine_symbol(TCCState *s, const char *sym);
/*****************************/
/* compiling */
/* add a file (either a C file, dll, an object, a library or an ld
script). Return -1 if error. */
int tcc_add_file(TCCState *s, const char *filename);
/* compile a string containing a C source. Return non zero if
error. */
int tcc_compile_string(TCCState *s, const char *buf);
/*****************************/
/* linking commands */
/* set output type. MUST BE CALLED before any compilation */
#define TCC_OUTPUT_MEMORY 0 /* output will be ran in memory (no
output file) (default) */
#define TCC_OUTPUT_EXE 1 /* executable file */
#define TCC_OUTPUT_DLL 2 /* dynamic library */
#define TCC_OUTPUT_OBJ 3 /* object file */
int tcc_set_output_type(TCCState *s, int output_type);
#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */
#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */
#define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */
/* equivalent to -Lpath option */
int tcc_add_library_path(TCCState *s, const char *pathname);
/* the library name is the same as the argument of the '-l' option */
int tcc_add_library(TCCState *s, const char *libraryname);
/* add a symbol to the compiled program */
int tcc_add_symbol(TCCState *s, const char *name, unsigned long val);
/* output an executable, library or object file. DO NOT call
tcc_relocate() before. */
int tcc_output_file(TCCState *s, const char *filename);
/* link and run main() function and return its value. DO NOT call
tcc_relocate() before. */
int tcc_run(TCCState *s, int argc, char **argv);
/* do all relocations (needed before using tcc_get_symbol()). Return
non zero if link error. */
int tcc_relocate(TCCState *s);
/* return symbol value. return 0 if OK, -1 if symbol not found */
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name);
#ifdef __cplusplus
}
#endif
#endif

234
stab.def Normal file
View File

@ -0,0 +1,234 @@
/* Table of DBX symbol codes for the GNU system.
Copyright (C) 1988, 1997 Free Software Foundation, Inc.
This file is part of the GNU C Library.
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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* This contains contribution from Cygnus Support. */
/* Global variable. Only the name is significant.
To find the address, look in the corresponding external symbol. */
__define_stab (N_GSYM, 0x20, "GSYM")
/* Function name for BSD Fortran. Only the name is significant.
To find the address, look in the corresponding external symbol. */
__define_stab (N_FNAME, 0x22, "FNAME")
/* Function name or text-segment variable for C. Value is its address.
Desc is supposedly starting line number, but GCC doesn't set it
and DBX seems not to miss it. */
__define_stab (N_FUN, 0x24, "FUN")
/* Data-segment variable with internal linkage. Value is its address.
"Static Sym". */
__define_stab (N_STSYM, 0x26, "STSYM")
/* BSS-segment variable with internal linkage. Value is its address. */
__define_stab (N_LCSYM, 0x28, "LCSYM")
/* Name of main routine. Only the name is significant.
This is not used in C. */
__define_stab (N_MAIN, 0x2a, "MAIN")
/* Global symbol in Pascal.
Supposedly the value is its line number; I'm skeptical. */
__define_stab (N_PC, 0x30, "PC")
/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */
__define_stab (N_NSYMS, 0x32, "NSYMS")
/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */
__define_stab (N_NOMAP, 0x34, "NOMAP")
/* New stab from Solaris. I don't know what it means, but it
don't seem to contain useful information. */
__define_stab (N_OBJ, 0x38, "OBJ")
/* New stab from Solaris. I don't know what it means, but it
don't seem to contain useful information. Possibly related to the
optimization flags used in this module. */
__define_stab (N_OPT, 0x3c, "OPT")
/* Register variable. Value is number of register. */
__define_stab (N_RSYM, 0x40, "RSYM")
/* Modula-2 compilation unit. Can someone say what info it contains? */
__define_stab (N_M2C, 0x42, "M2C")
/* Line number in text segment. Desc is the line number;
value is corresponding address. */
__define_stab (N_SLINE, 0x44, "SLINE")
/* Similar, for data segment. */
__define_stab (N_DSLINE, 0x46, "DSLINE")
/* Similar, for bss segment. */
__define_stab (N_BSLINE, 0x48, "BSLINE")
/* Sun's source-code browser stabs. ?? Don't know what the fields are.
Supposedly the field is "path to associated .cb file". THIS VALUE
OVERLAPS WITH N_BSLINE! */
__define_stab (N_BROWS, 0x48, "BROWS")
/* GNU Modula-2 definition module dependency. Value is the modification time
of the definition file. Other is non-zero if it is imported with the
GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there
are enough empty fields? */
__define_stab(N_DEFD, 0x4a, "DEFD")
/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2
and one is for C++. Still,... */
/* GNU C++ exception variable. Name is variable name. */
__define_stab (N_EHDECL, 0x50, "EHDECL")
/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */
__define_stab (N_MOD2, 0x50, "MOD2")
/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if
this entry is immediately followed by a CAUGHT stab saying what exception
was caught. Multiple CAUGHT stabs means that multiple exceptions
can be caught here. If Desc is 0, it means all exceptions are caught
here. */
__define_stab (N_CATCH, 0x54, "CATCH")
/* Structure or union element. Value is offset in the structure. */
__define_stab (N_SSYM, 0x60, "SSYM")
/* Name of main source file.
Value is starting text address of the compilation. */
__define_stab (N_SO, 0x64, "SO")
/* Automatic variable in the stack. Value is offset from frame pointer.
Also used for type descriptions. */
__define_stab (N_LSYM, 0x80, "LSYM")
/* Beginning of an include file. Only Sun uses this.
In an object file, only the name is significant.
The Sun linker puts data into some of the other fields. */
__define_stab (N_BINCL, 0x82, "BINCL")
/* Name of sub-source file (#include file).
Value is starting text address of the compilation. */
__define_stab (N_SOL, 0x84, "SOL")
/* Parameter variable. Value is offset from argument pointer.
(On most machines the argument pointer is the same as the frame pointer. */
__define_stab (N_PSYM, 0xa0, "PSYM")
/* End of an include file. No name.
This and N_BINCL act as brackets around the file's output.
In an object file, there is no significant data in this entry.
The Sun linker puts data into some of the fields. */
__define_stab (N_EINCL, 0xa2, "EINCL")
/* Alternate entry point. Value is its address. */
__define_stab (N_ENTRY, 0xa4, "ENTRY")
/* Beginning of lexical block.
The desc is the nesting level in lexical blocks.
The value is the address of the start of the text for the block.
The variables declared inside the block *precede* the N_LBRAC symbol. */
__define_stab (N_LBRAC, 0xc0, "LBRAC")
/* Place holder for deleted include file. Replaces a N_BINCL and everything
up to the corresponding N_EINCL. The Sun linker generates these when
it finds multiple identical copies of the symbols from an include file.
This appears only in output from the Sun linker. */
__define_stab (N_EXCL, 0xc2, "EXCL")
/* Modula-2 scope information. Can someone say what info it contains? */
__define_stab (N_SCOPE, 0xc4, "SCOPE")
/* End of a lexical block. Desc matches the N_LBRAC's desc.
The value is the address of the end of the text for the block. */
__define_stab (N_RBRAC, 0xe0, "RBRAC")
/* Begin named common block. Only the name is significant. */
__define_stab (N_BCOMM, 0xe2, "BCOMM")
/* End named common block. Only the name is significant
(and it should match the N_BCOMM). */
__define_stab (N_ECOMM, 0xe4, "ECOMM")
/* End common (local name): value is address.
I'm not sure how this is used. */
__define_stab (N_ECOML, 0xe8, "ECOML")
/* These STAB's are used on Gould systems for Non-Base register symbols
or something like that. FIXME. I have assigned the values at random
since I don't have a Gould here. Fixups from Gould folk welcome... */
__define_stab (N_NBTEXT, 0xF0, "NBTEXT")
__define_stab (N_NBDATA, 0xF2, "NBDATA")
__define_stab (N_NBBSS, 0xF4, "NBBSS")
__define_stab (N_NBSTS, 0xF6, "NBSTS")
__define_stab (N_NBLCS, 0xF8, "NBLCS")
/* Second symbol entry containing a length-value for the preceding entry.
The value is the length. */
__define_stab (N_LENG, 0xfe, "LENG")
/* The above information, in matrix format.
STAB MATRIX
_________________________________________________
| 00 - 1F are not dbx stab symbols |
| In most cases, the low bit is the EXTernal bit|
| 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA |
| 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT |
| 08 BSS | 0A INDR | 0C FN_SEQ | 0E |
| 09 |EXT | 0B | 0D | 0F |
| 10 | 12 COMM | 14 SETA | 16 SETT |
| 11 | 13 | 15 | 17 |
| 18 SETD | 1A SETB | 1C SETV | 1E WARNING|
| 19 | 1B | 1D | 1F FN |
|_______________________________________________|
| Debug entries with bit 01 set are unused. |
| 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM |
| 28 LCSYM | 2A MAIN | 2C | 2E |
| 30 PC | 32 NSYMS | 34 NOMAP | 36 |
| 38 OBJ | 3A | 3C OPT | 3E |
| 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE |
| 48 BSLINE*| 4A DEFD | 4C | 4E |
| 50 EHDECL*| 52 | 54 CATCH | 56 |
| 58 | 5A | 5C | 5E |
| 60 SSYM | 62 | 64 SO | 66 |
| 68 | 6A | 6C | 6E |
| 70 | 72 | 74 | 76 |
| 78 | 7A | 7C | 7E |
| 80 LSYM | 82 BINCL | 84 SOL | 86 |
| 88 | 8A | 8C | 8E |
| 90 | 92 | 94 | 96 |
| 98 | 9A | 9C | 9E |
| A0 PSYM | A2 EINCL | A4 ENTRY | A6 |
| A8 | AA | AC | AE |
| B0 | B2 | B4 | B6 |
| B8 | BA | BC | BE |
| C0 LBRAC | C2 EXCL | C4 SCOPE | C6 |
| C8 | CA | CC | CE |
| D0 | D2 | D4 | D6 |
| D8 | DA | DC | DE |
| E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 |
| E8 ECOML | EA | EC | EE |
| F0 | F2 | F4 | F6 |
| F8 | FA | FC | FE LENG |
+-----------------------------------------------+
* 50 EHDECL is also MOD2.
* 48 BSLINE is also BROWS.
*/

17
stab.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef __GNU_STAB__
/* Indicate the GNU stab.h is in use. */
#define __GNU_STAB__
#define __define_stab(NAME, CODE, STRING) NAME=CODE,
enum __stab_debug_code
{
#include "stab.def"
LAST_UNUSED_STAB_CODE
};
#undef __define_stab
#endif /* __GNU_STAB_ */

28
stdarg.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef _STDARG_H
#define _STDARG_H
typedef char *va_list;
typedef va_list __builtin_va_list;
#ifdef __65816__
#define va_start(ap, last) ap = ((char*)&(last)) + sizeof(last)
#define va_arg(ap, type) (ap += sizeof(type), *(type*)(ap - sizeof(type)))
#define va_end(ap)
#define va_copy(aq, ap) ((aq) = (ap))
#else
/* only correct for i386 */
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
#define va_end(ap)
/* fix a buggy dependency on GCC in libio.h */
typedef va_list __gnuc_va_list;
#endif
#define __builtin_va_start va_start
#define __builtin_va_arg va_arg
#define __builtin_va_end va_end
#define _VA_LIST_DEFINED
#endif

10
stdbool.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _STDBOOL_H
#define _STDBOOL_H
/* ISOC99 boolean */
#define bool _Bool
#define true 1
#define false 0
#endif /* _STDBOOL_H */

27
stddef.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef _STDDEF_H
#define _STDDEF_H
#define NULL ((void *)0)
typedef __SIZE_TYPE__ size_t;
typedef __WCHAR_TYPE__ wchar_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#define __builtin_offsetof offsetof
/* need to do that because of glibc 2.1 bug (should have a way to test
presence of 'long long' without __GNUC__, or TCC should define
__GNUC__ ? */
#if !defined(__int8_t_defined) && !defined(__dietlibc__)
#define __int8_t_defined
typedef char int8_t;
typedef short int int16_t;
#ifdef __65816__
typedef int int16_t;
typedef long long int int32_t;
#else
typedef int int32_t;
typedef long long int int64_t;
#endif
#endif
#endif

1809
tcc-doc.html Normal file

File diff suppressed because it is too large Load Diff

1214
tcc-doc.texi Normal file

File diff suppressed because it is too large Load Diff

379
tcc.1 Normal file
View File

@ -0,0 +1,379 @@
.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sh \" Subsection heading
.br
.if t .Sp
.ne 5
.PP
\fB\\$1\fR
.PP
..
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. | will give a
.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to
.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C'
.\" expand to `' in nroff, nothing in troff, for use with C<>.
.tr \(*W-|\(bv\*(Tr
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
'br\}
.\"
.\" If the F register is turned on, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.if \nF \{\
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. nr % 0
. rr F
.\}
.\"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.hy 0
.if n .na
.\"
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
.\" Fear. Run. Save yourself. No user-serviceable parts.
. \" fudge factors for nroff and troff
.if n \{\
. ds #H 0
. ds #V .8m
. ds #F .3m
. ds #[ \f1
. ds #] \fP
.\}
.if t \{\
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
. ds #V .6m
. ds #F 0
. ds #[ \&
. ds #] \&
.\}
. \" simple accents for nroff and troff
.if n \{\
. ds ' \&
. ds ` \&
. ds ^ \&
. ds , \&
. ds ~ ~
. ds /
.\}
.if t \{\
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
.\}
. \" troff and (daisy-wheel) nroff accents
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
.ds ae a\h'-(\w'a'u*4/10)'e
.ds Ae A\h'-(\w'A'u*4/10)'E
. \" corrections for vroff
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
. \" for low resolution devices (crt and lpr)
.if \n(.H>23 .if \n(.V>19 \
\{\
. ds : e
. ds 8 ss
. ds o a
. ds d- d\h'-1'\(ga
. ds D- D\h'-1'\(hy
. ds th \o'bp'
. ds Th \o'LP'
. ds ae ae
. ds Ae AE
.\}
.rm #[ #] #H #V #F C
.\" ========================================================================
.\"
.IX Title "TCC 1"
.TH TCC 1 "2005-06-18" " " " "
.SH "NAME"
tcc \- Tiny C Compiler
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
usage: tcc [options] [\fIinfile1\fR \fIinfile2\fR...] [\fB\-run\fR \fIinfile\fR \fIargs\fR...]
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
\&\s-1TCC\s0 options are a very much like gcc options. The main difference is that \s-1TCC\s0
can also execute directly the resulting program and give it runtime
arguments.
.PP
Here are some examples to understand the logic:
.ie n .IP """\f(CBtcc \-run a.c\f(CW""" 4
.el .IP "\f(CW\f(CBtcc \-run a.c\f(CW\fR" 4
.IX Item "tcc -run a.c"
Compile \fIa.c\fR and execute it directly
.ie n .IP """\f(CBtcc \-run a.c arg1\f(CW""" 4
.el .IP "\f(CW\f(CBtcc \-run a.c arg1\f(CW\fR" 4
.IX Item "tcc -run a.c arg1"
Compile a.c and execute it directly. arg1 is given as first argument to
the \f(CW\*(C`main()\*(C'\fR of a.c.
.ie n .IP """\f(CBtcc a.c \-run b.c arg1\f(CW""" 4
.el .IP "\f(CW\f(CBtcc a.c \-run b.c arg1\f(CW\fR" 4
.IX Item "tcc a.c -run b.c arg1"
Compile \fIa.c\fR and \fIb.c\fR, link them together and execute them. arg1 is given
as first argument to the \f(CW\*(C`main()\*(C'\fR of the resulting program. Because
multiple C files are specified, \fB\-\-\fR are necessary to clearly separate the
program arguments from the \s-1TCC\s0 options.
.ie n .IP """\f(CBtcc \-o myprog a.c b.c\f(CW""" 4
.el .IP "\f(CW\f(CBtcc \-o myprog a.c b.c\f(CW\fR" 4
.IX Item "tcc -o myprog a.c b.c"
Compile \fIa.c\fR and \fIb.c\fR, link them and generate the executable \fImyprog\fR.
.ie n .IP """\f(CBtcc \-o myprog a.o b.o\f(CW""" 4
.el .IP "\f(CW\f(CBtcc \-o myprog a.o b.o\f(CW\fR" 4
.IX Item "tcc -o myprog a.o b.o"
link \fIa.o\fR and \fIb.o\fR together and generate the executable \fImyprog\fR.
.ie n .IP """\f(CBtcc \-c a.c\f(CW""" 4
.el .IP "\f(CW\f(CBtcc \-c a.c\f(CW\fR" 4
.IX Item "tcc -c a.c"
Compile \fIa.c\fR and generate object file \fIa.o\fR.
.ie n .IP """\f(CBtcc \-c asmfile.S\f(CW""" 4
.el .IP "\f(CW\f(CBtcc \-c asmfile.S\f(CW\fR" 4
.IX Item "tcc -c asmfile.S"
Preprocess with C preprocess and assemble \fIasmfile.S\fR and generate
object file \fIasmfile.o\fR.
.ie n .IP """\f(CBtcc \-c asmfile.s\f(CW""" 4
.el .IP "\f(CW\f(CBtcc \-c asmfile.s\f(CW\fR" 4
.IX Item "tcc -c asmfile.s"
Assemble (but not preprocess) \fIasmfile.s\fR and generate object file
\&\fIasmfile.o\fR.
.ie n .IP """\f(CBtcc \-r \-o ab.o a.c b.c\f(CW""" 4
.el .IP "\f(CW\f(CBtcc \-r \-o ab.o a.c b.c\f(CW\fR" 4
.IX Item "tcc -r -o ab.o a.c b.c"
Compile \fIa.c\fR and \fIb.c\fR, link them together and generate the object file \fIab.o\fR.
.PP
Scripting:
.PP
\&\s-1TCC\s0 can be invoked from \fIscripts\fR, just as shell scripts. You just
need to add \f(CW\*(C`#!/usr/local/bin/tcc \-run\*(C'\fR at the start of your C source:
.PP
.Vb 2
\& #!/usr/local/bin/tcc -run
\& #include <stdio.h>
.Ve
.PP
.Vb 5
\& int main()
\& {
\& printf("Hello World\en");
\& return 0;
\& }
.Ve
.SH "OPTIONS"
.IX Header "OPTIONS"
.IP "\fB\-v\fR" 4
.IX Item "-v"
Display current \s-1TCC\s0 version.
.IP "\fB\-c\fR" 4
.IX Item "-c"
Generate an object file (\fB\-o\fR option must also be given).
.IP "\fB\-o outfile\fR" 4
.IX Item "-o outfile"
Put object file, executable, or dll into output file \fIoutfile\fR.
.IP "\fB\-Bdir\fR" 4
.IX Item "-Bdir"
Set the path where the tcc internal libraries can be found (default is
\&\fIPREFIX/lib/tcc\fR).
.IP "\fB\-bench\fR" 4
.IX Item "-bench"
Output compilation statistics.
.IP "\fB\-run source [args...]\fR" 4
.IX Item "-run source [args...]"
Compile file \fIsource\fR and run it with the command line arguments
\&\fIargs\fR. In order to be able to give more than one argument to a
script, several \s-1TCC\s0 options can be given \fIafter\fR the
\&\fB\-run\fR option, separated by spaces. Example:
.Sp
.Vb 1
\& tcc "-run -L/usr/X11R6/lib -lX11" ex4.c
.Ve
.Sp
In a script, it gives the following header:
.Sp
.Vb 6
\& #!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
\& #include <stdlib.h>
\& int main(int argc, char **argv)
\& {
\& ...
\& }
.Ve
.PP
Preprocessor options:
.IP "\fB\-Idir\fR" 4
.IX Item "-Idir"
Specify an additional include path. Include paths are searched in the
order they are specified.
.Sp
System include paths are always searched after. The default system
include paths are: \fI/usr/local/include\fR, \fI/usr/include\fR
and \fIPREFIX/lib/tcc/include\fR. (\fI\s-1PREFIX\s0\fR is usually
\&\fI/usr\fR or \fI/usr/local\fR).
.IP "\fB\-Dsym[=val]\fR" 4
.IX Item "-Dsym[=val]"
Define preprocessor symbol \fBsym\fR to
val. If val is not present, its value is \fB1\fR. Function-like macros can
also be defined: \fB\-DF(a)=a+1\fR
.IP "\fB\-Usym\fR" 4
.IX Item "-Usym"
Undefine preprocessor symbol \fBsym\fR.
.PP
Compilation flags:
.PP
Note: each of the following warning options has a negative form beginning with
\&\fB\-fno\-\fR.
.IP "\fB\-funsigned\-char\fR" 4
.IX Item "-funsigned-char"
Let the \f(CW\*(C`char\*(C'\fR type be unsigned.
.IP "\fB\-fsigned\-char\fR" 4
.IX Item "-fsigned-char"
Let the \f(CW\*(C`char\*(C'\fR type be signed.
.IP "\fB\-fno\-common\fR" 4
.IX Item "-fno-common"
Do not generate common symbols for uninitialized data.
.IP "\fB\-fleading\-underscore\fR" 4
.IX Item "-fleading-underscore"
Add a leading underscore at the beginning of each C symbol.
.PP
Warning options:
.IP "\fB\-w\fR" 4
.IX Item "-w"
Disable all warnings.
.PP
Note: each of the following warning options has a negative form beginning with
\&\fB\-Wno\-\fR.
.IP "\fB\-Wimplicit\-function\-declaration\fR" 4
.IX Item "-Wimplicit-function-declaration"
Warn about implicit function declaration.
.IP "\fB\-Wunsupported\fR" 4
.IX Item "-Wunsupported"
Warn about unsupported \s-1GCC\s0 features that are ignored by \s-1TCC\s0.
.IP "\fB\-Wwrite\-strings\fR" 4
.IX Item "-Wwrite-strings"
Make string constants be of type \f(CW\*(C`const char *\*(C'\fR instead of \f(CW\*(C`char
*\*(C'\fR.
.IP "\fB\-Werror\fR" 4
.IX Item "-Werror"
Abort compilation if warnings are issued.
.IP "\fB\-Wall\fR" 4
.IX Item "-Wall"
Activate all warnings, except \fB\-Werror\fR, \fB\-Wunusupported\fR and
\&\fB\-Wwrite\-strings\fR.
.PP
Linker options:
.IP "\fB\-Ldir\fR" 4
.IX Item "-Ldir"
Specify an additional static library path for the \fB\-l\fR option. The
default library paths are \fI/usr/local/lib\fR, \fI/usr/lib\fR and \fI/lib\fR.
.IP "\fB\-lxxx\fR" 4
.IX Item "-lxxx"
Link your program with dynamic library libxxx.so or static library
libxxx.a. The library is searched in the paths specified by the
\&\fB\-L\fR option.
.IP "\fB\-shared\fR" 4
.IX Item "-shared"
Generate a shared library instead of an executable (\fB\-o\fR option
must also be given).
.IP "\fB\-static\fR" 4
.IX Item "-static"
Generate a statically linked executable (default is a shared linked
executable) (\fB\-o\fR option must also be given).
.IP "\fB\-rdynamic\fR" 4
.IX Item "-rdynamic"
Export global symbols to the dynamic linker. It is useful when a library
opened with \f(CW\*(C`dlopen()\*(C'\fR needs to access executable symbols.
.IP "\fB\-r\fR" 4
.IX Item "-r"
Generate an object file combining all input files (\fB\-o\fR option must
also be given).
.IP "\fB\-Wl,\-Ttext,address\fR" 4
.IX Item "-Wl,-Ttext,address"
Set the start of the .text section to \fIaddress\fR.
.IP "\fB\-Wl,\-\-oformat,fmt\fR" 4
.IX Item "-Wl,--oformat,fmt"
Use \fIfmt\fR as output format. The supported output formats are:
.RS 4
.ie n .IP """elf32\-i386""" 4
.el .IP "\f(CWelf32\-i386\fR" 4
.IX Item "elf32-i386"
\&\s-1ELF\s0 output format (default)
.ie n .IP """binary""" 4
.el .IP "\f(CWbinary\fR" 4
.IX Item "binary"
Binary image (only for executable output)
.ie n .IP """coff""" 4
.el .IP "\f(CWcoff\fR" 4
.IX Item "coff"
\&\s-1COFF\s0 output format (only for executable output for TMS320C67xx target)
.RE
.RS 4
.RE
.PP
Debugger options:
.IP "\fB\-g\fR" 4
.IX Item "-g"
Generate run time debug information so that you get clear run time
error messages: \f(CW\*(C` test.c:68: in function 'test5()': dereferencing
invalid pointer\*(C'\fR instead of the laconic \f(CW\*(C`Segmentation
fault\*(C'\fR.
.IP "\fB\-b\fR" 4
.IX Item "-b"
Generate additional support code to check
memory allocations and array/pointer bounds. \fB\-g\fR is implied. Note
that the generated code is slower and bigger in this case.
.IP "\fB\-bt N\fR" 4
.IX Item "-bt N"
Display N callers in stack traces. This is useful with \fB\-g\fR or
\&\fB\-b\fR.
.PP
Note: \s-1GCC\s0 options \fB\-Ox\fR, \fB\-fx\fR and \fB\-mx\fR are
ignored.
.SH "SEE ALSO"
.IX Header "SEE ALSO"
\&\fIgcc\fR\|(1)
.SH "AUTHOR"
.IX Header "AUTHOR"
Fabrice Bellard

10672
tcc.c Normal file

File diff suppressed because it is too large Load Diff

828
tccelf.c Normal file
View File

@ -0,0 +1,828 @@
/*
* ELF file handling for TCC
*
* Copyright (c) 2001-2004 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
static int put_elf_str(Section *s, const char *sym)
{
int offset, len;
char *ptr;
//fprintf(stderr,"put_elf_str %s\n",sym);
len = strlen(sym) + 1;
offset = s->data_offset;
ptr = section_ptr_add(s, len);
memcpy(ptr, sym, len);
return offset;
}
/* elf symbol hashing function */
static unsigned long elf_hash(const unsigned char *name)
{
unsigned long h = 0, g;
while (*name) {
h = (h << 4) + *name++;
g = h & 0xf0000000;
if (g)
h ^= g >> 24;
h &= ~g;
}
return h;
}
/* rebuild hash table of section s */
/* NOTE: we do factorize the hash table code to go faster */
static void rebuild_hash(Section *s, unsigned int nb_buckets)
{
Elf32_Sym *sym;
int *ptr, *hash, nb_syms, sym_index, h;
char *strtab;
strtab = s->link->data;
nb_syms = s->data_offset / sizeof(Elf32_Sym);
s->hash->data_offset = 0;
ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int));
ptr[0] = nb_buckets;
ptr[1] = nb_syms;
ptr += 2;
hash = ptr;
memset(hash, 0, (nb_buckets + 1) * sizeof(int));
ptr += nb_buckets + 1;
sym = (Elf32_Sym *)s->data + 1;
for(sym_index = 1; sym_index < nb_syms; sym_index++) {
if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) {
h = elf_hash(strtab + sym->st_name) % nb_buckets;
*ptr = hash[h];
hash[h] = sym_index;
} else {
*ptr = 0;
}
ptr++;
sym++;
}
}
/* return the symbol number */
static int put_elf_sym(Section *s,
unsigned long value, unsigned long size,
int info, int other, int shndx, const char *name)
{
int name_offset, sym_index;
int nbuckets, h;
Elf32_Sym *sym;
Section *hs;
//fprintf(stderr,"\\\\\\ putting elf symbol %s in section type %d, section %p, value %ld size %ld info %d other %d\n",name,s->sh_type,s,value,size,info,other);
// HACK
//info |= 0x10;
sym = section_ptr_add(s, sizeof(Elf32_Sym));
if (name)
name_offset = put_elf_str(s->link, name);
else
name_offset = 0;
/* XXX: endianness */
sym->st_name = name_offset;
sym->st_value = value;
sym->st_size = size;
sym->st_info = info;
sym->st_other = other;
sym->st_shndx = shndx;
sym_index = sym - (Elf32_Sym *)s->data;
hs = s->hash;
if (hs) {
int *ptr, *base;
ptr = section_ptr_add(hs, sizeof(int));
base = (int *)hs->data;
/* only add global or weak symbols */
if (ELF32_ST_BIND(info) != STB_LOCAL) {
/* add another hashing entry */
nbuckets = base[0];
h = elf_hash(name) % nbuckets;
*ptr = base[2 + h];
base[2 + h] = sym_index;
base[1]++;
/* we resize the hash table */
hs->nb_hashed_syms++;
if (hs->nb_hashed_syms > 2 * nbuckets) {
rebuild_hash(s, 2 * nbuckets);
}
} else {
*ptr = 0;
base[1]++;
}
}
return sym_index;
}
/* find global ELF symbol 'name' and return its index. Return 0 if not
found. */
static int find_elf_sym(Section *s, const char *name)
{
Elf32_Sym *sym;
Section *hs;
int nbuckets, sym_index, h;
const char *name1;
hs = s->hash;
if (!hs)
return 0;
nbuckets = ((int *)hs->data)[0];
h = elf_hash(name) % nbuckets;
sym_index = ((int *)hs->data)[2 + h];
while (sym_index != 0) {
sym = &((Elf32_Sym *)s->data)[sym_index];
name1 = s->link->data + sym->st_name;
if (!strcmp(name, name1))
return sym_index;
sym_index = ((int *)hs->data)[2 + nbuckets + sym_index];
}
return 0;
}
/* return elf symbol value or error */
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name)
{
int sym_index;
Elf32_Sym *sym;
sym_index = find_elf_sym(symtab_section, name);
if (!sym_index)
return -1;
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
*pval = sym->st_value;
return 0;
}
/* return elf symbol value or error */
Elf32_Sym* tcc_really_get_symbol(TCCState *s, unsigned long *pval, const char *name)
{
int sym_index;
Elf32_Sym *sym;
sym_index = find_elf_sym(symtab_section, name);
if (!sym_index)
return NULL;
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
*pval = sym->st_value;
return sym;
}
void *tcc_get_symbol_err(TCCState *s, const char *name)
{
unsigned long val;
if (tcc_get_symbol(s, &val, name) < 0)
error("%s not defined", name);
return (void *)val;
}
/* add an elf symbol : check if it is already defined and patch
it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */
static int add_elf_sym(Section *s, unsigned long value, unsigned long size,
int info, int other, int sh_num, const char *name)
{
Elf32_Sym *esym;
int sym_bind, sym_index, sym_type, esym_bind;
sym_bind = ELF32_ST_BIND(info);
sym_type = ELF32_ST_TYPE(info);
if (sym_bind != STB_LOCAL) {
/* we search global or weak symbols */
sym_index = find_elf_sym(s, name);
if (!sym_index)
goto do_def;
esym = &((Elf32_Sym *)s->data)[sym_index];
if (esym->st_shndx != SHN_UNDEF) {
esym_bind = ELF32_ST_BIND(esym->st_info);
if (sh_num == SHN_UNDEF) {
/* ignore adding of undefined symbol if the
corresponding symbol is already defined */
} else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) {
/* global overrides weak, so patch */
goto do_patch;
} else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) {
/* weak is ignored if already global */
} else {
#if 0
printf("new_bind=%d new_shndx=%d last_bind=%d old_shndx=%d\n",
sym_bind, sh_num, esym_bind, esym->st_shndx);
#endif
/* NOTE: we accept that two DLL define the same symbol */
if (s != tcc_state->dynsymtab_section)
error_noabort("'%s' defined twice", name);
}
} else {
do_patch:
esym->st_info = ELF32_ST_INFO(sym_bind, sym_type);
esym->st_shndx = sh_num;
esym->st_value = value;
esym->st_size = size;
esym->st_other = other;
}
} else {
do_def:
sym_index = put_elf_sym(s, value, size,
ELF32_ST_INFO(sym_bind, sym_type), other,
sh_num, name);
}
return sym_index;
}
/* put relocation */
static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
int type, int symbol)
{
char buf[256];
Section *sr;
Elf32_Rel *rel;
sr = s->reloc;
if (!sr) {
/* if no relocation section, create it */
snprintf(buf, sizeof(buf), ".rel%s", s->name);
/* if the symtab is allocated, then we consider the relocation
are also */
sr = new_section(tcc_state, buf, SHT_REL, symtab->sh_flags);
sr->sh_entsize = sizeof(Elf32_Rel);
sr->link = symtab;
sr->sh_info = s->sh_num;
s->reloc = sr;
}
rel = section_ptr_add(sr, sizeof(Elf32_Rel));
rel->r_offset = offset;
rel->r_info = ELF32_R_INFO(symbol, type);
}
/* put stab debug information */
typedef struct {
unsigned long n_strx; /* index into string table of name */
unsigned char n_type; /* type of symbol */
unsigned char n_other; /* misc info (usually empty) */
unsigned short n_desc; /* description field */
unsigned long n_value; /* value of symbol */
} Stab_Sym;
static void put_stabs(const char *str, int type, int other, int desc,
unsigned long value)
{
Stab_Sym *sym;
sym = section_ptr_add(stab_section, sizeof(Stab_Sym));
if (str) {
sym->n_strx = put_elf_str(stabstr_section, str);
} else {
sym->n_strx = 0;
}
sym->n_type = type;
sym->n_other = other;
sym->n_desc = desc;
sym->n_value = value;
}
static void put_stabs_r(const char *str, int type, int other, int desc,
unsigned long value, Section *sec, int sym_index)
{
put_stabs(str, type, other, desc, value);
put_elf_reloc(symtab_section, stab_section,
stab_section->data_offset - sizeof(unsigned long),
R_DATA_32, sym_index);
}
static void put_stabn(int type, int other, int desc, int value)
{
put_stabs(NULL, type, other, desc, value);
}
static void put_stabd(int type, int other, int desc)
{
put_stabs(NULL, type, other, desc, 0);
}
char** relocptrs = NULL;
/* relocate a given section (CPU dependent) */
static void relocate_section(TCCState *s1, Section *s)
{
Section *sr;
Elf32_Rel *rel, *rel_end, *qrel;
Elf32_Sym *sym;
int type, sym_index;
unsigned char *ptr;
unsigned long val, addr;
#if defined(TCC_TARGET_I386)
int esym_index;
#endif
if (!relocptrs) {
relocptrs = calloc(0x100000, sizeof(char *));
}
sr = s->reloc;
rel_end = (Elf32_Rel *)(sr->data + sr->data_offset);
qrel = (Elf32_Rel *)sr->data;
for(rel = qrel;
rel < rel_end;
rel++) {
ptr = s->data + rel->r_offset;
sym_index = ELF32_R_SYM(rel->r_info);
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
val = sym->st_value;
type = ELF32_R_TYPE(rel->r_info);
addr = s->sh_addr + rel->r_offset;
/* CPU specific */
switch(type) {
#if defined(TCC_TARGET_816)
case R_DATA_32:
//fprintf(stderr,"___ relocating at 0x%lx to 0x%lx, sr %p, s %p, shndx %d name %s info 0x%x other 0x%x relocindex 0x%x ptr 0x%x\n",addr,val,sr,s,sym->st_shndx,symtab_section->link->data + sym->st_name, sym->st_info, sym->st_other,relocindices[addr],*(unsigned int*)ptr);
if(relocptrs[((unsigned long)ptr)&0xfffff]) error("relocptrs collision");
/* if(ELF32_ST_BIND(sym->st_info) == STB_LOCAL) {
relocptrs[((unsigned int)ptr)&0xfffff] = calloc(1,strlen(static_prefix) + strlen(symtab_section->link->data + sym->st_name) + 1);
sprintf(relocptrs[((unsigned int)ptr)&0xfffff], "%s%s", static_prefix, symtab_section->link->data + sym->st_name);
}
else */ relocptrs[((unsigned long)ptr)&0xfffff] = symtab_section->link->data + sym->st_name;
/* no need to change the value at ptr, we only need the offset, and that's already there */
break;
default:
fprintf(stderr,"FIXME: handle reloc type 0x%x at 0x%lx [%.8lx] to 0x%lx\n",
type, addr, (unsigned long)ptr, val);
break;
#else
#error unsupported processor
#endif
}
}
/* if the relocation is allocated, we change its symbol table */
if (sr->sh_flags & SHF_ALLOC)
sr->link = s1->dynsym;
}
static Section *new_symtab(TCCState *s1,
const char *symtab_name, int sh_type, int sh_flags,
const char *strtab_name,
const char *hash_name, int hash_sh_flags)
{
Section *symtab, *strtab, *hash;
int *ptr, nb_buckets;
symtab = new_section(s1, symtab_name, sh_type, sh_flags);
symtab->sh_entsize = sizeof(Elf32_Sym);
strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags);
put_elf_str(strtab, "");
symtab->link = strtab;
put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL);
nb_buckets = 1;
hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags);
hash->sh_entsize = sizeof(int);
symtab->hash = hash;
hash->link = symtab;
ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int));
ptr[0] = nb_buckets;
ptr[1] = 1;
memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int));
return symtab;
}
static void tcc_output_binary(TCCState *s1, FILE *f,
const int *section_order)
{
Section *s;
int i,j, k, size;
//fprintf(stderr,"outputting binary, %d sections\n",s1->nb_sections);
#if 0
Elf32_Sym* esym;
for(j = 0, esym = (Elf32_Sym*) symtab_section->data; j < symtab_section->sh_size / 4; esym++, j++) {
fprintf(stderr,"symbol st_shndx %d\n", esym->st_shndx);
if(esym->st_shndx == 2) fprintf(stderr,"symbol %s value %d\n", symtab_section->link->data + esym->st_name,esym->st_value);
}
#endif
/* include header */
/* fprintf(f, ".incdir \"" CONFIG_TCCDIR "/include\"\n"); */
fprintf(f, ".include \"hdr.asm\"\n");
fprintf(f, ".accu 16\n.index 16\n");
fprintf(f, ".16bit\n");
/* local variable size constants; used to be generated as part of the
function epilog, but WLA DX barfed once in a while about missing
symbols. putting them at the start of the file works around that. */
for(i=0; i<localno; i++) {
fprintf(f, ".define __%s_locals %d\n", locals[i], localnos[i]);
}
/* relocate sections
this not only rewrites the pointers inside sections (with bogus
data), but, more importantly, saves the names of the symbols we have
to output later in place of this bogus data in the relocptrs[] array. */
for(i=1;i<s1->nb_sections;i++) {
s = s1->sections[section_order[i]];
//fprintf(stderr,"___ relocating section %p (%s) (reloc %p)\n",s,s->name,s->reloc);
if (s->reloc && s != s1->got)
relocate_section(s1, s);
}
/* output sections */
for(i=1;i<s1->nb_sections;i++) {
s = s1->sections[section_order[i]];
//fprintf(stderr,"section %p, sh_size %ld, sh_num %d\n",s,s->sh_size,s->sh_num);
/* these sections are meaningless when writing plain-text assembler output */
if(strcmp(".symtab", s->name) == 0 ||
strcmp(".strtab", s->name) == 0 ||
strcmp(".rel.data", s->name) == 0 ||
strcmp(".shstrtab", s->name) == 0) continue;
//fprintf(f,"\n;.section %p\n",s->reloc);
size = s->sh_size; /* section size in bytes */
//fprintf(stderr,"%d bytes: %s\n",size,s->name);
if(s == text_section) {
/* functions each have their own section (otherwise WLA DX is
not able to allocate ROM space for them efficiently), so we
do not have to print a function header here */
int next_jump_pos = 0; /* the next offset in the text section where we will look for a jump target */
for(j = 0; j < size; j++) {
//Elf32_Sym* esym;
for(k = 0; k < labels; k++) {
//fprintf(stderr,"label %s at %d\n", label[k].name, label[k].pos);
if(label[k].pos == j) fprintf(f, "%s%s:\n", static_prefix /* "__local_" */, label[k].name);
}
/* insert jump labels */
if(next_jump_pos == j) {
next_jump_pos = size;
for(k = 0; k < jumps; k++) {
/* while we're here, look for the next jump target after this one */
if(jump[k][1] > j && jump[k][1] < next_jump_pos) next_jump_pos = jump[k][1];
/* write the jump target label(s) for this position */
//if(jump[k][1] == j) fprintf(f, LOCAL_LABEL ": ; at %d\n", k, j);
if(jump[k][1] == j) fprintf(f, LOCAL_LABEL ":\n", k);
}
}
fputc(s->data[j], f);
}
if(!section_closed) fprintf(f, ".ends\n");
}
else if(s == bss_section) {
/* uninitialized data, we only need a .ramsection */
Elf32_Sym* esym;
int empty = 1;
fprintf(f, ".ramsection \".bss\" bank $7e slot 2\n");
//fprintf(f, "ramsection.bss dsb 0\n");
for(j = 0, esym = (Elf32_Sym*) symtab_section->data; j < symtab_section->sh_size / sizeof(Elf32_Sym); esym++, j++) {
//fprintf(stderr,"%d/%d symbol %p st_shndx %d\n", j, symtab_section->sh_size / sizeof(Elf32_Sym*), esym, esym->st_shndx);
//fprintf(stderr,"esym %p\n", esym);
//if(esym->st_shndx < 3) fprintf(stderr,"symbol %s\n", symtab_section->link->data + esym->st_name);
if(esym->st_shndx == SHN_COMMON
&& strlen(symtab_section->link->data + esym->st_name)) /* omit nameless symbols (fixes 20041218-1.c) */
{
/* looks like these are the symbols that need to go here,
but that is merely an educated guess. works for me, though. */
//fprintf(stderr,"COM symbol %s: value %d size %d\n",get_tok_str(ps->v, NULL),esym->st_value,esym->st_size);
fprintf(f, "%s%s dsb %d\n", /*ELF32_ST_BIND(esym->st_info) == STB_LOCAL ? static_prefix:*/"", symtab_section->link->data + esym->st_name, esym->st_size);
empty = 0;
}
}
#if 0
for(;ps;ps=ps->prev) {
if((esym = tcc_really_get_symbol(s1, &pval, get_tok_str(ps->v, NULL)))) {
if(esym->st_shndx == SHN_COMMON) {
/* looks like these are the symbols that need to go here,
but that is merely an educated guess. works for me, though. */
//fprintf(stderr,"COM symbol %s: value %d size %d\n",get_tok_str(ps->v, NULL),esym->st_value,esym->st_size);
fprintf(f, "%s dsb %d\n", get_tok_str(ps->v, NULL), esym->st_size);
empty = 0;
}
}
}
#endif
if(empty) fprintf(f, "__local_dummybss dsb 1\n");
//fprintf(f, "endsection.bss dsb 0\n");
fprintf(f, ".ends\n");
}
else { /* .data, .rodata, user-defined sections */
int deebeed = 0; /* remembers whether we have printed ".db"
before; reset after a newline or a
different sized prefix, e.g. ".dw" */
int startk = 0; /* 0 == .ramsection, 1 == .section */
int endk = 2; /* do both by default */
if(s != data_section) startk = 1; /* only do .section (.rodata and user sections go to ROM) */
int bytecount = 0; /* how many bytes to reserve in .ramsection */
/* k == 0: output .ramsection; k == 1: output .section */
for(k = startk; k < endk; k++) {
if(k == 0) { /* .ramsection */
fprintf(f, ".ramsection \"ram%s\" bank $7f slot 3\n",s->name);
//fprintf(f, "ramsection%s dsb 0\n", s->name);
}
else { /* (ROM) .section */
fprintf(f, ".section \"%s\" superfree\n", s->name);
//fprintf(f, "startsection%s:", s->name);
}
//int next_symbol_pos = 0; /* position inside the section at which to look for the next symbol */
for(j=0; j<size; j++) {
//Sym* ps = global_stack;
int ps;
/* check if there is a symbol at this position */
Elf32_Sym* esym; /* ELF symbol */
char* lastsym = NULL; /* name of previous symbol (some symbols appear more than once; bug?) */
int symbol_printed = 0; /* have we already printed a symbol in this run? */
for(ps = 0, esym = (Elf32_Sym*) symtab_section->data; ps < symtab_section->sh_size / sizeof(Elf32_Sym); esym++, ps++) {
//if(!find_elf_sym(symtab_section, get_tok_str(ps->v, NULL))) continue;
unsigned long pval;
char* symname = symtab_section->link->data + esym->st_name;
char* symprefix = "";
//fprintf(stderr,"gsym %p name %s type 0x%x num %d reg 0x%x\n",ps,get_tok_str(ps->v,NULL),ps->type.t,ps->c,ps->r);
/* we do not have to care about external references (handled by the linker) or
functions (handled by the code generator */
//if((ps->type.t & VT_EXTERN) || ((ps->type.t & VT_BTYPE) == VT_FUNC)) continue;
/* look up this symbol */
pval = esym->st_value;
//fprintf(stderr,"/// pval %d, j %d esym->st_shndx %d s->sh_num %d\n",pval,j,esym->st_shndx,s->sh_num);
/* look for the next symbol after this one */
//if(pval > j && pval < next_symbol_pos) next_symbol_pos = pval;
/* Is this symbol at this position and in this section? */
if(pval != j || esym->st_shndx != s->sh_num) continue;
/* skip empty symbols (bug?) */
if(strlen(symname) == 0) continue;
/* some symbols appear more than once; avoid defining them more than once (bug?) */
if(lastsym && !strcmp(lastsym, symname)) continue;
/* remember this symbol for the next iteration */
lastsym = symname;
/* if this is a local (static) symbol, prefix it so the assembler knows this
is file-local. */
/* FIXME: breaks for local static variables (name collision) */
//if(ELF32_ST_BIND(esym->st_info) == STB_LOCAL) { symprefix = static_prefix; }
/* if this is a ramsection, we now know how large the _previous_ symbol was; print it. */
/* if we already printed a symbol in this section, define this symbol as size 0 so it
gets the same address as the other ones at this position. */
if(k==0 && (bytecount > 0 || symbol_printed)) {
fprintf(f, "dsb %d", bytecount);
bytecount = 0;
}
/* if there are two sections, print label only in .ramsection */
if(k == 0) fprintf(f, "\n%s%s ", symprefix, symname);
else if(startk == 1) fprintf(f,"\n%s%s: ", symprefix, symname);
else fprintf(f, "\n");
symbol_printed = 1;
}
if(symbol_printed) {
/* pointers and arrays may have a symbolic name. find out if that's the case.
everything else is literal and handled later */
//if((ps->type.t & (VT_PTR|VT_ARRAY)) /* == VT_PTR */) {
unsigned int ptr = *((unsigned int*)&s->data[j]);
unsigned char ptrc = *((unsigned char*)&s->data[j]);
//fprintf(stderr, "%%%%%%%%pointer type 0x%x v 0x%x r 0x%x c 0x%x, value 0x%x\n",ps->type.t,ps->v,ps->r,ps->c,ptr);
if(k == 0) { /* .ramsection, just count bytes */
bytecount ++;
}
else { /* (ROM) .section, need to output data */
if(relocptrs && relocptrs[((unsigned long)&s->data[j])&0xfffff]) {
/* relocated -> print a symbolic pointer */
//fprintf(f,".dw ramsection%s + $%x", s->name, ptr);
char* ptrname = relocptrs[((unsigned long)&s->data[j])&0xfffff];
fprintf(f,".dw %s + %d, :%s", ptrname, ptr, ptrname);
j+=3; /* we have handled 3 more bytes than expected */
deebeed = 0;
}
else {
/* any non-symbolic data; print one byte, then let the generic code take over */
//fprintf(f,"; type 0x%x\n", ps->type.t);
//if(ps->type.t & VT_BYTE) exit(42);
fprintf(f,".db $%x", ptrc);
deebeed = 1;
}
}
continue; /* data has been printed, go ahead */
}
/* no symbol here, just print the data */
if(k == 1 && relocptrs && relocptrs[((unsigned long)&s->data[j])&0xfffff]) {
/* unlabeled data may have been relocated, too */
fprintf(f,"\n.dw %s + %d\n.dw :%s", relocptrs[((unsigned long)&s->data[j])&0xfffff], *(unsigned int*)(&s->data[j]), relocptrs[((unsigned long)&s->data[j])&0xfffff]);
j+=3;
deebeed = 0;
continue;
}
if(!deebeed) {
if(k == 1) fprintf(f, "\n.db ");
deebeed = 1;
}
else if(k==1) fprintf(f,",");
if(k==1) fprintf(f, "$%x",s->data[j]);
bytecount++;
}
if(k==0) { if(!bytecount) { fprintf(f, "__local_dummy%s ", s->name); bytecount++; } fprintf(f, "dsb %d\n", bytecount); bytecount = 0; }
//if(k==1 && deebeed) fprintf(f,"\n");
if(k==1) {
//fprintf(f,"\nendsection%s:", s->name);
if(!size) fprintf(f, "\n__local_dummy%s: .db 0", s->name);
}
fprintf(f,"\n.ends\n\n");
}
}
#if 0
fprintf(stderr,"sh_type %d\n",s->sh_type);
fprintf(stderr,"index of L.0 %d\n",find_elf_sym(s, "L.0"));
if(s->sh_type == SHT_REL) {
for(j = 0; j < s->sh_size; j++) {
fprintf(stderr,"%02x ", s->data[j]);
if(j%4 == 3) fprintf(stderr,"\n");
}
fprintf(stderr,"\n");
//fprintf(stderr,"symtab %s\n",s->data);
}
#endif
}
//fprintf(stderr,"index of L.0 in symtab_section %d\n",find_elf_sym(symtab_section,"L.0"));
}
/* output an ELF file */
/* XXX: suppress unneeded sections */
int tcc_output_file(TCCState *s1, const char *filename)
{
Elf32_Ehdr ehdr;
FILE *f;
int fd, mode, ret;
int *section_order;
int shnum, i, phnum, file_offset, sh_order_index;
Section *strsec, *s;
Elf32_Phdr *phdr;
Section *interp, *dynamic, *dynstr;
unsigned long saved_dynamic_data_offset;
int file_type;
file_type = s1->output_type;
s1->nb_errors = 0;
if (file_type != TCC_OUTPUT_OBJ) {
abort();
}
phdr = NULL;
section_order = NULL;
interp = NULL;
dynamic = NULL;
dynstr = NULL; /* avoid warning */
saved_dynamic_data_offset = 0; /* avoid warning */
if (file_type != TCC_OUTPUT_OBJ) {
abort();
}
memset(&ehdr, 0, sizeof(ehdr));
/* we add a section for symbols */
strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0);
put_elf_str(strsec, "");
/* compute number of sections */
shnum = s1->nb_sections;
/* this array is used to reorder sections in the output file */
section_order = tcc_malloc(sizeof(int) * shnum);
section_order[0] = 0;
sh_order_index = 1;
/* compute number of program headers */
switch(file_type) {
default:
case TCC_OUTPUT_OBJ:
phnum = 0;
break;
case TCC_OUTPUT_EXE:
if (!s1->static_link)
phnum = 4;
else
phnum = 2;
break;
case TCC_OUTPUT_DLL:
phnum = 3;
break;
}
/* allocate strings for section names and decide if an unallocated
section should be output */
/* NOTE: the strsec section comes last, so its size is also
correct ! */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
s->sh_name = put_elf_str(strsec, s->name);
/* when generating a DLL, we include relocations but we may
patch them */
if (file_type == TCC_OUTPUT_DLL &&
s->sh_type == SHT_REL &&
!(s->sh_flags & SHF_ALLOC)) {
abort();
} else if (do_debug ||
file_type == TCC_OUTPUT_OBJ ||
(s->sh_flags & SHF_ALLOC) ||
i == (s1->nb_sections - 1)) {
/* we output all sections if debug or object file */
s->sh_size = s->data_offset;
}
}
/* allocate program segment headers */
phdr = tcc_mallocz(phnum * sizeof(Elf32_Phdr));
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
} else {
file_offset = 0;
}
if (phnum > 0) {
abort();
}
/* all other sections come after */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (phnum > 0 && (s->sh_flags & SHF_ALLOC))
continue;
section_order[sh_order_index++] = i;
file_offset = (file_offset + s->sh_addralign - 1) &
~(s->sh_addralign - 1);
s->sh_offset = file_offset;
if (s->sh_type != SHT_NOBITS)
file_offset += s->sh_size;
}
/* write elf file */
if (file_type == TCC_OUTPUT_OBJ)
mode = 0666;
else
mode = 0777;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
if (fd < 0) {
error_noabort("could not write '%s'", filename);
ret = -1;
goto the_end;
}
f = fdopen(fd, "wb");
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
abort();
} else {
tcc_output_binary(s1, f, section_order);
}
fclose(f);
ret = 0;
the_end:
tcc_free(s1->symtab_to_dynsym);
tcc_free(section_order);
tcc_free(phdr);
tcc_free(s1->got_offsets);
return ret;
}

77
tcclib.h Normal file
View File

@ -0,0 +1,77 @@
/* Simple libc header for TCC
*
* Add any function you want from the libc there. This file is here
* only for your convenience so that you do not need to put the whole
* glibc include files on your floppy disk
*/
#ifndef _TCCLIB_H
#define _TCCLIB_H
#include <stddef.h>
#include <stdarg.h>
/* stdlib.h */
void *calloc(size_t nmemb, size_t size);
void *malloc(size_t size);
void free(void *ptr);
void *realloc(void *ptr, size_t size);
int atoi(const char *nptr);
long int strtol(const char *nptr, char **endptr, int base);
unsigned long int strtoul(const char *nptr, char **endptr, int base);
/* stdio.h */
typedef struct __FILE FILE;
#define EOF (-1)
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
FILE *fopen(const char *path, const char *mode);
FILE *fdopen(int fildes, const char *mode);
FILE *freopen(const char *path, const char *mode, FILE *stream);
int fclose(FILE *stream);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);
int fgetc(FILE *stream);
char *fgets(char *s, int size, FILE *stream);
int getc(FILE *stream);
int getchar(void);
char *gets(char *s);
int ungetc(int c, FILE *stream);
int fflush(FILE *stream);
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
int asprintf(char **strp, const char *format, ...);
int dprintf(int fd, const char *format, ...);
int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
int vasprintf(char **strp, const char *format, va_list ap);
int vdprintf(int fd, const char *format, va_list ap);
void perror(const char *s);
/* string.h */
char *strcat(char *dest, const char *src);
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
char *strcpy(char *dest, const char *src);
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
void *memset(void *s, int c, size_t n);
char *strdup(const char *s);
/* dlfcn.h */
#define RTLD_LAZY 0x001
#define RTLD_NOW 0x002
#define RTLD_GLOBAL 0x100
void *dlopen(const char *filename, int flag);
const char *dlerror(void);
void *dlsym(void *handle, char *symbol);
int dlclose(void *handle);
#endif /* _TCCLIB_H */

1988
tcctest.c Normal file

File diff suppressed because it is too large Load Diff

445
tcctok.h Normal file
View File

@ -0,0 +1,445 @@
/* keywords */
DEF(TOK_INT, "int")
DEF(TOK_VOID, "void")
DEF(TOK_CHAR, "char")
DEF(TOK_IF, "if")
DEF(TOK_ELSE, "else")
DEF(TOK_WHILE, "while")
DEF(TOK_BREAK, "break")
DEF(TOK_RETURN, "return")
DEF(TOK_FOR, "for")
DEF(TOK_EXTERN, "extern")
DEF(TOK_STATIC, "static")
DEF(TOK_UNSIGNED, "unsigned")
DEF(TOK_GOTO, "goto")
DEF(TOK_DO, "do")
DEF(TOK_CONTINUE, "continue")
DEF(TOK_SWITCH, "switch")
DEF(TOK_CASE, "case")
DEF(TOK_CONST1, "const")
DEF(TOK_CONST2, "__const") /* gcc keyword */
DEF(TOK_CONST3, "__const__") /* gcc keyword */
DEF(TOK_VOLATILE1, "volatile")
DEF(TOK_VOLATILE2, "__volatile") /* gcc keyword */
DEF(TOK_VOLATILE3, "__volatile__") /* gcc keyword */
DEF(TOK_LONG, "long")
DEF(TOK_REGISTER, "register")
DEF(TOK_SIGNED1, "signed")
DEF(TOK_SIGNED2, "__signed") /* gcc keyword */
DEF(TOK_SIGNED3, "__signed__") /* gcc keyword */
DEF(TOK_AUTO, "auto")
DEF(TOK_INLINE1, "inline")
DEF(TOK_INLINE2, "__inline") /* gcc keyword */
DEF(TOK_INLINE3, "__inline__") /* gcc keyword */
DEF(TOK_RESTRICT1, "restrict")
DEF(TOK_RESTRICT2, "__restrict")
DEF(TOK_RESTRICT3, "__restrict__")
DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
DEF(TOK_FLOAT, "float")
DEF(TOK_DOUBLE, "double")
DEF(TOK_BOOL, "_Bool")
DEF(TOK_SHORT, "short")
DEF(TOK_STRUCT, "struct")
DEF(TOK_UNION, "union")
DEF(TOK_TYPEDEF, "typedef")
DEF(TOK_DEFAULT, "default")
DEF(TOK_ENUM, "enum")
DEF(TOK_SIZEOF, "sizeof")
DEF(TOK_ATTRIBUTE1, "__attribute")
DEF(TOK_ATTRIBUTE2, "__attribute__")
DEF(TOK_ALIGNOF1, "__alignof")
DEF(TOK_ALIGNOF2, "__alignof__")
DEF(TOK_TYPEOF1, "typeof")
DEF(TOK_TYPEOF2, "__typeof")
DEF(TOK_TYPEOF3, "__typeof__")
DEF(TOK_LABEL, "__label__")
DEF(TOK_ASM1, "asm")
DEF(TOK_ASM2, "__asm")
DEF(TOK_ASM3, "__asm__")
/*********************************************************************/
/* the following are not keywords. They are included to ease parsing */
/* preprocessor only */
DEF(TOK_DEFINE, "define")
DEF(TOK_INCLUDE, "include")
DEF(TOK_INCLUDE_NEXT, "include_next")
DEF(TOK_IFDEF, "ifdef")
DEF(TOK_IFNDEF, "ifndef")
DEF(TOK_ELIF, "elif")
DEF(TOK_ENDIF, "endif")
DEF(TOK_DEFINED, "defined")
DEF(TOK_UNDEF, "undef")
DEF(TOK_ERROR, "error")
DEF(TOK_WARNING, "warning")
DEF(TOK_LINE, "line")
DEF(TOK_PRAGMA, "pragma")
DEF(TOK___LINE__, "__LINE__")
DEF(TOK___FILE__, "__FILE__")
DEF(TOK___DATE__, "__DATE__")
DEF(TOK___TIME__, "__TIME__")
DEF(TOK___FUNCTION__, "__FUNCTION__")
DEF(TOK___VA_ARGS__, "__VA_ARGS__")
/* special identifiers */
DEF(TOK___FUNC__, "__func__")
/* attribute identifiers */
/* XXX: handle all tokens generically since speed is not critical */
DEF(TOK_SECTION1, "section")
DEF(TOK_SECTION2, "__section__")
DEF(TOK_ALIGNED1, "aligned")
DEF(TOK_ALIGNED2, "__aligned__")
DEF(TOK_PACKED1, "packed")
DEF(TOK_PACKED2, "__packed__")
DEF(TOK_UNUSED1, "unused")
DEF(TOK_UNUSED2, "__unused__")
DEF(TOK_CDECL1, "cdecl")
DEF(TOK_CDECL2, "__cdecl")
DEF(TOK_CDECL3, "__cdecl__")
DEF(TOK_STDCALL1, "stdcall")
DEF(TOK_STDCALL2, "__stdcall")
DEF(TOK_STDCALL3, "__stdcall__")
DEF(TOK_DLLEXPORT, "dllexport")
DEF(TOK_NORETURN1, "noreturn")
DEF(TOK_NORETURN2, "__noreturn__")
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
DEF(TOK_REGPARM1, "regparm")
DEF(TOK_REGPARM2, "__regparm__")
/* pragma */
DEF(TOK_pack, "pack")
#if !defined(TCC_TARGET_I386)
/* already defined for assembler */
DEF(TOK_ASM_push, "push")
DEF(TOK_ASM_pop, "pop")
#endif
/* builtin functions or variables */
DEF(TOK_memcpy, "memcpy")
DEF(TOK_memset, "memset")
DEF(TOK_alloca, "alloca")
#if defined(TCC_TARGET_816)
DEF(TOK___divdi3, "tcc__divdi3")
DEF(TOK___moddi3, "tcc__moddi3")
DEF(TOK___udivdi3, "tcc__udivdi3")
DEF(TOK___umoddi3, "tcc__umoddi3")
#else
DEF(TOK___divdi3, "__divdi3")
DEF(TOK___moddi3, "__moddi3")
DEF(TOK___udivdi3, "__udivdi3")
DEF(TOK___umoddi3, "__umoddi3")
#endif
#if defined(TCC_TARGET_ARM)
DEF(TOK___divsi3, "__divsi3")
DEF(TOK___modsi3, "__modsi3")
DEF(TOK___udivsi3, "__udivsi3")
DEF(TOK___umodsi3, "__umodsi3")
DEF(TOK___sardi3, "__ashrdi3")
DEF(TOK___shrdi3, "__lshrdi3")
DEF(TOK___shldi3, "__ashldi3")
DEF(TOK___slltold, "__slltold")
DEF(TOK___fixunssfsi, "__fixunssfsi")
DEF(TOK___fixunsdfsi, "__fixunsdfsi")
DEF(TOK___fixunsxfsi, "__fixunsxfsi")
DEF(TOK___fixsfdi, "__fixsfdi")
DEF(TOK___fixdfdi, "__fixdfdi")
DEF(TOK___fixxfdi, "__fixxfdi")
#elif defined(TCC_TARGET_C67)
DEF(TOK__divi, "_divi")
DEF(TOK__divu, "_divu")
DEF(TOK__divf, "_divf")
DEF(TOK__divd, "_divd")
DEF(TOK__remi, "_remi")
DEF(TOK__remu, "_remu")
DEF(TOK___sardi3, "__sardi3")
DEF(TOK___shrdi3, "__shrdi3")
DEF(TOK___shldi3, "__shldi3")
#elif defined(TCC_TARGET_816)
DEF(TOK___sardi3, "tcc__sardi3")
DEF(TOK___shrdi3, "tcc__shrdi3")
DEF(TOK___shldi3, "tcc__shldi3")
#else
/* XXX: same names on i386 ? */
DEF(TOK___sardi3, "__sardi3")
DEF(TOK___shrdi3, "__shrdi3")
DEF(TOK___shldi3, "__shldi3")
#endif
DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
#ifdef TCC_TARGET_816
DEF(TOK___ulltof, "tcc__ulltof")
DEF(TOK___ulltod, "tcc__ulltod")
DEF(TOK___ulltold, "tcc__ulltold")
DEF(TOK___fixunssfdi, "tcc__fixunssfdi")
DEF(TOK___fixunsdfdi, "tcc__fixunsdfdi")
DEF(TOK___fixunsxfdi, "tcc__fixunsxfdi")
#else
DEF(TOK___ulltof, "__ulltof")
DEF(TOK___ulltod, "__ulltod")
DEF(TOK___ulltold, "__ulltold")
DEF(TOK___fixunssfdi, "__fixunssfdi")
DEF(TOK___fixunsdfdi, "__fixunsdfdi")
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
#endif
DEF(TOK___chkstk, "__chkstk")
/* bound checking symbols */
#ifdef CONFIG_TCC_BCHECK
DEF(TOK___bound_ptr_add, "__bound_ptr_add")
DEF(TOK___bound_ptr_indir1, "__bound_ptr_indir1")
DEF(TOK___bound_ptr_indir2, "__bound_ptr_indir2")
DEF(TOK___bound_ptr_indir4, "__bound_ptr_indir4")
DEF(TOK___bound_ptr_indir8, "__bound_ptr_indir8")
DEF(TOK___bound_ptr_indir12, "__bound_ptr_indir12")
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
DEF(TOK___bound_local_new, "__bound_local_new")
DEF(TOK___bound_local_delete, "__bound_local_delete")
DEF(TOK_malloc, "malloc")
DEF(TOK_free, "free")
DEF(TOK_realloc, "realloc")
DEF(TOK_memalign, "memalign")
DEF(TOK_calloc, "calloc")
DEF(TOK_memmove, "memmove")
DEF(TOK_strlen, "strlen")
DEF(TOK_strcpy, "strcpy")
#endif
/* Tiny Assembler */
DEF_ASM(byte)
DEF_ASM(align)
DEF_ASM(skip)
DEF_ASM(space)
DEF_ASM(string)
DEF_ASM(asciz)
DEF_ASM(ascii)
DEF_ASM(globl)
DEF_ASM(global)
DEF_ASM(text)
DEF_ASM(data)
DEF_ASM(bss)
DEF_ASM(previous)
DEF_ASM(fill)
DEF_ASM(org)
DEF_ASM(quad)
#ifdef TCC_TARGET_I386
/* WARNING: relative order of tokens is important. */
DEF_ASM(al)
DEF_ASM(cl)
DEF_ASM(dl)
DEF_ASM(bl)
DEF_ASM(ah)
DEF_ASM(ch)
DEF_ASM(dh)
DEF_ASM(bh)
DEF_ASM(ax)
DEF_ASM(cx)
DEF_ASM(dx)
DEF_ASM(bx)
DEF_ASM(sp)
DEF_ASM(bp)
DEF_ASM(si)
DEF_ASM(di)
DEF_ASM(eax)
DEF_ASM(ecx)
DEF_ASM(edx)
DEF_ASM(ebx)
DEF_ASM(esp)
DEF_ASM(ebp)
DEF_ASM(esi)
DEF_ASM(edi)
DEF_ASM(mm0)
DEF_ASM(mm1)
DEF_ASM(mm2)
DEF_ASM(mm3)
DEF_ASM(mm4)
DEF_ASM(mm5)
DEF_ASM(mm6)
DEF_ASM(mm7)
DEF_ASM(xmm0)
DEF_ASM(xmm1)
DEF_ASM(xmm2)
DEF_ASM(xmm3)
DEF_ASM(xmm4)
DEF_ASM(xmm5)
DEF_ASM(xmm6)
DEF_ASM(xmm7)
DEF_ASM(cr0)
DEF_ASM(cr1)
DEF_ASM(cr2)
DEF_ASM(cr3)
DEF_ASM(cr4)
DEF_ASM(cr5)
DEF_ASM(cr6)
DEF_ASM(cr7)
DEF_ASM(tr0)
DEF_ASM(tr1)
DEF_ASM(tr2)
DEF_ASM(tr3)
DEF_ASM(tr4)
DEF_ASM(tr5)
DEF_ASM(tr6)
DEF_ASM(tr7)
DEF_ASM(db0)
DEF_ASM(db1)
DEF_ASM(db2)
DEF_ASM(db3)
DEF_ASM(db4)
DEF_ASM(db5)
DEF_ASM(db6)
DEF_ASM(db7)
DEF_ASM(dr0)
DEF_ASM(dr1)
DEF_ASM(dr2)
DEF_ASM(dr3)
DEF_ASM(dr4)
DEF_ASM(dr5)
DEF_ASM(dr6)
DEF_ASM(dr7)
DEF_ASM(es)
DEF_ASM(cs)
DEF_ASM(ss)
DEF_ASM(ds)
DEF_ASM(fs)
DEF_ASM(gs)
DEF_ASM(st)
DEF_BWL(mov)
/* generic two operands */
DEF_BWL(add)
DEF_BWL(or)
DEF_BWL(adc)
DEF_BWL(sbb)
DEF_BWL(and)
DEF_BWL(sub)
DEF_BWL(xor)
DEF_BWL(cmp)
/* unary ops */
DEF_BWL(inc)
DEF_BWL(dec)
DEF_BWL(not)
DEF_BWL(neg)
DEF_BWL(mul)
DEF_BWL(imul)
DEF_BWL(div)
DEF_BWL(idiv)
DEF_BWL(xchg)
DEF_BWL(test)
/* shifts */
DEF_BWL(rol)
DEF_BWL(ror)
DEF_BWL(rcl)
DEF_BWL(rcr)
DEF_BWL(shl)
DEF_BWL(shr)
DEF_BWL(sar)
DEF_ASM(shldw)
DEF_ASM(shldl)
DEF_ASM(shld)
DEF_ASM(shrdw)
DEF_ASM(shrdl)
DEF_ASM(shrd)
DEF_ASM(pushw)
DEF_ASM(pushl)
DEF_ASM(push)
DEF_ASM(popw)
DEF_ASM(popl)
DEF_ASM(pop)
DEF_BWL(in)
DEF_BWL(out)
DEF_WL(movzb)
DEF_ASM(movzwl)
DEF_ASM(movsbw)
DEF_ASM(movsbl)
DEF_ASM(movswl)
DEF_WL(lea)
DEF_ASM(les)
DEF_ASM(lds)
DEF_ASM(lss)
DEF_ASM(lfs)
DEF_ASM(lgs)
DEF_ASM(call)
DEF_ASM(jmp)
DEF_ASM(lcall)
DEF_ASM(ljmp)
DEF_ASMTEST(j)
DEF_ASMTEST(set)
DEF_ASMTEST(cmov)
DEF_WL(bsf)
DEF_WL(bsr)
DEF_WL(bt)
DEF_WL(bts)
DEF_WL(btr)
DEF_WL(btc)
DEF_WL(lsl)
/* generic FP ops */
DEF_FP(add)
DEF_FP(mul)
DEF_ASM(fcom)
DEF_ASM(fcom_1) /* non existant op, just to have a regular table */
DEF_FP1(com)
DEF_FP(comp)
DEF_FP(sub)
DEF_FP(subr)
DEF_FP(div)
DEF_FP(divr)
DEF_BWL(xadd)
DEF_BWL(cmpxchg)
/* string ops */
DEF_BWL(cmps)
DEF_BWL(scmp)
DEF_BWL(ins)
DEF_BWL(outs)
DEF_BWL(lods)
DEF_BWL(slod)
DEF_BWL(movs)
DEF_BWL(smov)
DEF_BWL(scas)
DEF_BWL(ssca)
DEF_BWL(stos)
DEF_BWL(ssto)
/* generic asm ops */
#define ALT(x)
#define DEF_ASM_OP0(name, opcode) DEF_ASM(name)
#define DEF_ASM_OP0L(name, opcode, group, instr_type)
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
#include "i386-asm.h"
#define ALT(x)
#define DEF_ASM_OP0(name, opcode)
#define DEF_ASM_OP0L(name, opcode, group, instr_type) DEF_ASM(name)
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) DEF_ASM(name)
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) DEF_ASM(name)
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) DEF_ASM(name)
#include "i386-asm.h"
#endif

39
test/broken/20020920-1.c Normal file
View File

@ -0,0 +1,39 @@
// serious problem: a.b is not initialized properly; TCC
// does a.b.x, then stops. does not look like it's easy to fix
extern void abort (void);
extern void exit (int);
struct B
{
int x;
int y;
};
struct A
{
int z;
struct B b;
};
struct A
f ()
{
struct B b = { 0, 1 };
struct A a = { 2, b };
return a;
}
int
main (void)
{
struct A a = f ();
#if 0
if (a.z != 2 || a.b.x != 0 || a.b.y != 1)
abort ();
#endif
//if (a.z != 2) exit(1);
//if(a.b.x != 0) exit(2);
if(a.b.y != 1) exit(3);
exit (0);
}

View File

@ -0,0 +1,72 @@
// breaks because of the fat local array in foo
#ifdef __65816__
#else
#define long short
#define int short
#endif
long baz1 (void *a)
{
static long l;
return l++;
}
int baz2 (const char *a)
{
return 0;
}
int baz3 (int i)
{
if (!i)
abort ();
return 1;
}
void **bar;
int foo (void *a, long b, int c)
{
int d = 0, e, f = 0, i;
char g[256];
void **h;
g[0] = '\n';
g[1] = 0;
while (baz1 (a) < b) {
if (g[0] != ' ' && g[0] != '\t') {
f = 1;
e = 0;
if (!d && baz2 (g) == 0) {
if ((c & 0x10) == 0)
continue;
e = d = 1;
}
if (!((c & 0x10) && (c & 0x4000) && e) && (c & 2))
continue;
if ((c & 0x2000) && baz2 (g) == 0)
continue;
if ((c & 0x1408) && baz2 (g) == 0)
continue;
if ((c & 0x200) && baz2 (g) == 0)
continue;
if (c & 0x80) {
for (h = bar, i = 0; h; h = (void **)*h, i++)
if (baz3 (i))
break;
}
f = 0;
}
}
return 0;
}
int main ()
{
void *n = 0;
bar = &n;
foo (&n, 1, 0xc811);
exit (0);
}

View File

@ -0,0 +1,74 @@
/* Testing save/restore of floating point caller-save registers, on ia64
this resulted in bad code. Not all targets will use caller-save regs. */
/* { dg-do run } */
/* { dg-options "-O2" } */
/* { dg-options "-O2 -minline-float-divide-max-throughput" { target ia64-*-* } } */
/* Testing save/restore of floating point caller-save registers on ia64. */
extern void abort (void);
double foo(double a, double b, double c)
{
return (a+b+c);
}
main ()
{
double f1, f2, f3, f4, f5, f6, f7, f8, f9,f10;
double f11,f12,f13,f14,f15,f16,f17,f18,f19,f20;
double f21,f22,f23,f24,f25,f26,f27,f28,f29,f30;
double x;
int i,j,k;
f1 = 0.1; f2 = 0.2; f3 = 0.3; f4 = 0.4; f5 = 0.5;
f6 = 0.6; f7 = 0.7; f8 = 0.8; f9 = 0.9; f10 = 1.0;
f11 = 1.1; f12 = 1.2; f13 = 1.3; f14 = 1.4; f15 = 1.5;
f16 = 1.6; f17 = 1.7; f18 = 1.8; f19 = 1.9; f20 = 2.0;
f21 = 2.1; f22 = 2.2; f23 = 2.3; f24 = 2.4; f25 = 2.5;
f26 = 2.6; f27 = 2.7; f28 = 2.8; f29 = 2.9; f30 = 3.0;
i = (int) foo(1.0,1.0,1.0);
while (i > 0) {
f1 = f2 / f3 * f30;
f2 = f3 / f4 * f30;
f3 = f4 / f5 * f30;
f4 = f5 / f6 * f30;
f5 = f6 / f7 * f30;
f6 = f7 / f8 * f30;
f7 = f8 / f9 * f30;
f8 = f9 / f10 * f30;
f9 = f10 / f11 * f30;
f10 = f11 / f12 * f30;
f11 = f12 / f13 * f30;
f12 = f13 / f14 * f25;
f13 = f14 / f15 * f30;
f14 = f15 / f16 * f30;
f15 = f16 / f17 * f30;
f16 = f17 / f18 * f30;
f17 = f18 / f19 * f30;
f18 = f19 / f20 * f30;
f19 = f20 / f21 * f30;
f20 = f21 / f22 * f20;
f21 = f22 / f23 * f30;
f22 = f23 / f24 * f30;
f23 = f24 / f25 * f30;
f24 = f25 / f26 * f30;
f25 = f26 / f27 * f30;
f26 = f27 / f28 * f30;
f27 = f28 / f29 * f30;
f28 = f29 / f30 * f30;
f29 = f30 / f1 * f30;
f30 = f1 / f2 * f30;
x = foo(f1,f2,f3);
i = i - 1;
}
x = (f1+f2+f3+f4+f5+f6+f7+f8+f9+f10) *
(f11+f12+f13+f14+f15+f16+f17+f18+f19+f20) *
(f21+f22+f23+f24+f25+f26+f27+f28+f29+f30);
/* Exact value is not needed, on IA64 it is massively off. */
if (x < 19503.0 || x > 19504.0) abort();
return 0;
}

View File

@ -0,0 +1,25 @@
// big local array breaks stack access
f()
{
int x = 1;
#if defined(STACK_SIZE)
char big[STACK_SIZE/2];
#else
char big[0x1000];
#endif
({
__label__ mylabel;
mylabel:
x++;
if (x != 3)
goto mylabel;
});
exit(0);
}
main()
{
f();
}

View File

@ -0,0 +1,6 @@
/* using unknown pointer type as the first argument in function implementations caused segfault
because it was mistaken for a K&R-style function declaration */
int main(unknown *x, void *x)
{
return 0;
}

20
test/dg/20000108-1.c Normal file
View File

@ -0,0 +1,20 @@
/* Copyright (C) 2000 Free Software Foundation.
by Alexandre Oliva <oliva@lsd.ic.unicamp.br> */
/* { dg-do run } */
/* { dg-options "-O3" } */
extern void abort (void);
void foo () {} /* unused, but essential to trigger the bug */
int main () {
int i;
/* use asms to prevent optimizations */
i = -1; //*/ asm ("" : "=r" (i) : "0" (-1));
i = 1; //*/ asm ("" : "=r" (i) : "0" (i ? 1 : 2));
if (i != 1)
abort();
return 0;
}

20
test/dg/20000623-1.c Normal file
View File

@ -0,0 +1,20 @@
/* { dg-do run } */
/* { dg-options "-O3 -fno-strict-aliasing" } */
extern void exit (int);
extern void abort (void);
struct foos { int l; };
int foo;
static struct foos *getfoo(void);
int main (void)
{
struct foos *f = getfoo();
f->l = 1;
foo = 2;
if (f->l == 1)
abort();
exit(0);
}
static struct foos *getfoo(void)
{ return (struct foos *)&foo; }

78
test/dg/20000906-1.c Normal file
View File

@ -0,0 +1,78 @@
/* { dg-do run } */
/* Testcase distilled from glibc's nss_parse_service_list in nss/nsswitch.c
It can't be distilled further. Fails with `-O2' for i[3456]86. */
/* this simulates a bounded-pointer type. */
struct ucharp { unsigned char *v, *l, *h; };
/* this simulates bounded-pointer check prior to pointer dereference. */
#define AREF(var, idx) ((((((((var).v+(idx)) < (var).l) \
|| (((var).v+(idx)+1) > (var).h))) \
&& (__builtin_abort (), 0)), \
(var).v)[(idx)])
struct list
{
struct list *next;
};
struct list *
alloc_list (void)
{
static struct list l;
return &l;
}
int one = 1;
void
foo (struct ucharp cp, struct ucharp lp, struct list **nextp)
{
while (1)
{
struct list *list;
while (AREF (lp, 0) && AREF (cp, AREF (lp, 0)))
++lp.v;
list = alloc_list ();
while (AREF (cp, AREF (lp, 0)))
++lp.v;
if (AREF (lp, 0) == one)
do
++lp.v;
while (AREF (lp, 0) && AREF (cp, AREF (lp, 0)));
/* The above AREF (cp, ...) fails because the pseudo created to
hold cp.v holds garbage, having never been set.
The easiest way to see the problem is to compile wiht `-O2 -da'
then look at *.09.loop. Search for something like this:
Hoisted regno 183 r/o from (mem/s:SI (reg:SI 16 argp) 10)
Replaced reg 91, deleting init_insn (213).
Now, look for the use of reg 91, which has no set. */
*nextp = list;
nextp = &list->next;
if (!*lp.v)
break;
}
}
extern void exit (int);
int
main (void)
{
static unsigned char cp0[] = "\0\0\0\0";
struct ucharp cp = { cp0, cp0, cp0 + sizeof (cp0) };
static unsigned char lp0[] = "\1\1\0\0";
struct ucharp lp = { lp0, lp0, lp0 + sizeof (lp0) };
struct list list;
struct list *nextp = &list;
foo (cp, lp, &nextp);
exit (0);
}

18
test/dg/20001012-1.c Normal file
View File

@ -0,0 +1,18 @@
/* { dg-do run { target fpic } } */
/* { dg-options "-O2 -fpic" } */
extern void abort (void);
extern void exit (int);
double
foo (void)
{
return (__extension__ ((union { unsigned long long __l __attribute__((__mode__(__SI__))); float __d; }) { __l: 0x4080UL }).__d);
}
main ()
{
if (foo() != 1.0)
abort ();
exit (0);
}

62
test/dg/20001023-1.c Normal file
View File

@ -0,0 +1,62 @@
/* { dg-do run } */
/* { dg-options "-O2 -fomit-frame-pointer" } */
extern void abort (void);
extern void exit (int);
unsigned char a[256], b[256], c[256], d[256];
void foo(unsigned char *x, int y, unsigned char *z)
{
}
void bar(int x, ...)
{
}
void baz(int y)
{
if (y != 0x10)
abort();
}
void test(int x, unsigned char *y)
{
unsigned char g,h,j, k[5],l[5], m[30];
int i;
bar(x, y[0], y[1], y[2], y[3], y[4], y[5], y[6], y[7], y[8], y[9]);
for (i = 5; --i >= 0; )
k[i] = y[5 + i] ^ a[i] ^ c[i];
foo(&m[29], sizeof m, k);
g = d[x] ^ c[x];
bar(x, d[x], x, c[x]);
baz(g);
for (i = 5, h = 0; --i >= 0; h = y[i])
{
j = m[25 + i] ^ y[i];
j = b[j] ^ g;
k[i] = c[j] ^ h;
}
for (i = 5, h = 0; --i >= 0; h = k[i])
{
j = m[20 + i] ^ k[i];
j = b[j] ^ g;
l[i] = c[j] ^ h;
}
for (i = 5, h = 0; --i >= 0; h = l[i]) {
j = m[15 + i] ^ l[i];
j = b[j] ^ g;
j = c[j] ^ h;
k[i] = a[j] ^ c[j];
}
}
int main()
{
c[4] = 0xdc;
d[4] = 0xcc;
test(4, a);
exit(0);
}

33
test/dg/20001108-1.c Normal file
View File

@ -0,0 +1,33 @@
/* { dg-do run } */
/* { dg-options "-O2 -fomit-frame-pointer" } */
extern void abort (void);
extern void exit (int);
void die (long) __attribute__ ((noreturn));
void die (long e)
{
abort ();
for (;;);
}
long foo (double i)
{
if (i != 2.0)
abort ();
return 26;
}
long bar (long i, double x)
{
if (x < 0) die (1);
return foo (x);
}
main()
{
if (bar (0, 2.0) != 26)
abort ();
exit (0);
}

28
test/dg/20001117-1.c Normal file
View File

@ -0,0 +1,28 @@
/* { dg-do run } */
/* { dg-options "-O2 -finstrument-functions" } */
extern void abort (void);
extern void exit (int);
double
foo (double a, double b)
{
double c;
if (0.0 < a)
c = a;
else if (b > 0.0)
c = 0.0;
else
return 0;
return 2.0 * (b - c);
}
int main ()
{
if (foo (1.0, 4.0) != 6.0)
abort ();
exit (0);
}
void __attribute__((no_instrument_function)) __cyg_profile_func_enter(void *this_fn, void *call_site) { }
void __attribute__((no_instrument_function)) __cyg_profile_func_exit(void *this_fn, void *call_site) { }

44
test/dg/20010822-1.c Normal file
View File

@ -0,0 +1,44 @@
/* { dg-do run } */
/* { dg-options "-Os" } */
extern void abort (void);
void foo (unsigned long x)
{
}
typedef struct a {
volatile unsigned int a1, a2, a3, a4, a5;
} *A;
typedef struct {
volatile unsigned int b1, b2, b3, b4, b5;
} *B;
struct C {
void *c1, *c2;
A c3;
unsigned char c4;
};
void
bar (struct C *c, unsigned int *d)
{
*d = *d | 1;
((c->c4 >= 2)
? (*(volatile unsigned int *) ((void *)(&((A)c->c3)->a5)) = *d)
: (*(volatile unsigned int *) ((void *)(&((B)c->c3)->b5)) = *d));
foo (50);
}
int main (void)
{
struct a a;
struct C c;
unsigned int d = 8;
c.c3 = &a;
c.c4 = 0;
bar (&c, &d);
if (a.a5 != 9)
abort ();
return 0;
}

49
test/dg/20010912-1.c Normal file
View File

@ -0,0 +1,49 @@
/* { dg-do run { target fpic } } */
/* { dg-options "-O2 -fpic" } */
/* { dg-bogus "\[Uu\]nresolved symbol .(_GLOBAL_OFFSET_TABLE_|\[_.A-Za-z\]\[_.0-9A-Za-z\]*@(PLT|GOT|GOTOFF))" "PIC unsupported" { xfail *-*-netware* } 0 } */
extern void abort (void);
extern void exit (int);
int bar (int x, char **y)
{
if (x != 56)
abort ();
if (**y != 'a')
abort ();
*y = "def";
return 1;
}
int baz (int x, char **y)
{
if (x != 56)
abort ();
if (**y != 'a')
abort ();
return 26;
}
int foo (int x, char *y)
{
int a;
char *b = y;
a = bar (x, &y);
if (a)
{
y = b;
a = baz (x, &y);
}
if (a)
return a;
baz (x, &y);
return 0;
}
int main ()
{
if (foo (56, "abc") != 26)
abort ();
exit (0);
}

23
test/dg/20011008-2.c Normal file
View File

@ -0,0 +1,23 @@
/* { dg-do run } */
/* { dg-options "-O0" } */
extern void abort (void);
extern void exit (int);
struct { union {int x; int y;} z; int q; } b;
union { struct {int x;} z; int q; } e;
main()
{
b.z.y = 10;
b.z.x = 15;
if (b.z.y != 15)
abort();
e.z.x = 10;
e.q = 15;
if (e.z.x != 15)
abort();
exit(0);
}

45
test/dg/20020206-1.c Normal file
View File

@ -0,0 +1,45 @@
/* This code is from the beginning of combine_reloads in reload.c in
GCC 3.1-20020117, with simplifications. It compiled incorrectly
for -O2 -fprefetch-loop-arrays for ix86 targets. */
/* { dg-do run } */
/* { dg-options "-O2 -fprefetch-loop-arrays -w" } */
/* { dg-options "-O2 -fprefetch-loop-arrays -mtune=pentium3 -w" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
struct reload
{
int first_member;
int out;
int final_member;
};
int n_reloads;
struct reload rld[10];
static int
combine_reloads ()
{
int i;
int output_reload = -1;
int secondary_out = -1;
for (i = 0; i < n_reloads; i++)
if (rld[i].out != 0)
{
if (output_reload >= 0)
return output_reload;
output_reload = i;
}
return output_reload;
}
int
main ()
{
n_reloads = 4;
rld[2].out = 2;
if (combine_reloads () != 2)
abort ();
exit (0);
}

28
test/dg/20020210-1.c Normal file
View File

@ -0,0 +1,28 @@
/* This used to fail on H8/300 due to incorrect specification of pushi1. */
/* { dg-do run } */
/* { dg-options "-O2" } */
/* { dg-options "-O2 -fomit-frame-pointer" { target h8300-*-* } } */
extern void abort (void);
extern void exit (int);
void
bar (int a, int b, int c, int d, int e)
{
if (d != 1)
abort ();
}
void
foo (int a, int b, int c, int d, int e)
{
bar (a, b, c, d, e);
}
int
main ()
{
foo (0, 0, 0, 1, 2);
exit (0);
}

47
test/dg/20020219-1.c Normal file
View File

@ -0,0 +1,47 @@
/* PR c/4389
This testcase failed because host_integerp (x, 0) was returning
1 even for constants bigger than 2^31. It fails under under hppa
hpux without -mdisable-indexing because the pointer x - 1 is used
as the base address of an indexed load. Because the struct A is not
actually allocated, x - 1 lies in the text segment and this causes
the wrong space register to be selected for the load. It fails on
IA64 hpux in ILP32 mode because extending x - 1 before adding the
array offset gives a different answer then adding first and then
extending. The underlying problem is the same as with hppa, x - 1 is
not a legal data address. */
/* { dg-do run } */
/* { dg-options "-O2" } */
/* { dg-options "-O2 -mdisable-indexing" { target hppa*-*-hpux* } } */
/* { dg-skip-if "" { "ia64-*-hpux*" } "*" "-mlp64" } */
/* Disable the test entirely for 16-bit targets. */
#if __INT_MAX__ > 32767
extern void abort (void);
extern void exit (int);
struct A {
int a[10000][10000];
};
int b[2] = { 213151, 0 };
void foo (struct A *x, int y)
{
if (x->a[9999][9999] != x->a[y][y])
abort ();
if (x->a[9999][9999] != 213151)
abort ();
}
int main (void)
{
struct A *x;
asm ("" : "=r" (x) : "0" (&b[1]));
foo (x - 1, 9999);
exit (0);
}
#else
int main () { return 0; }
#endif /* __INT_MAX__ */

54
test/dg/20020310-1.c Normal file
View File

@ -0,0 +1,54 @@
/* PR optimization/5844
This testcase was miscompiled because of an rtx sharing bug. */
/* { dg-do run } */
/* { dg-options "-O2" } */
/* { dg-options "-O2 -mtune=i586" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
struct A
{
struct A *a;
int b;
};
struct B
{
struct A *c;
unsigned int d;
};
struct A p = { &p, -1 };
struct B q = { &p, 0 };
extern void abort (void);
extern void exit (int);
struct B *
foo (void)
{
return &q;
}
void
bar (void)
{
struct B *e = foo ();
struct A *f = e->c;
int g = f->b;
if (++g == 0)
{
e->d++;
e->c = f->a;
}
f->b = g;
}
int
main ()
{
bar ();
if (p.b != 0 || q.d != 1 || q.c != &p)
abort ();
exit (0);
}

177
test/dg/20020426-2.c Normal file
View File

@ -0,0 +1,177 @@
/* PR optimization/6475
Distilled from zlib sources. */
/* { dg-do run } */
/* { dg-options "-O2" } */
/* { dg-options "-O2 -frename-registers -fomit-frame-pointer -fPIC -mtune=i686" { target { { i?86-*-* x86_64-*-* } && { ilp32 && fpic } } } } */
/* { dg-bogus "\[Uu\]nresolved symbol .(_GLOBAL_OFFSET_TABLE_|\[_.A-Za-z\]\[_.0-9A-Za-z\]*@(PLT|GOT|GOTOFF))" "PIC unsupported" { xfail *-*-netware* } 0 } */
extern void exit (int);
typedef struct
{
union
{
struct
{
unsigned char a3;
unsigned char a4;
} a2;
unsigned int a5;
} a0;
unsigned int a1;
} A;
static int
foo (unsigned int *b, unsigned int n, unsigned int s, const unsigned int *d,
const unsigned int *e, A **t, unsigned int *m, A *hp, unsigned int *hn,
unsigned int *v)
{
unsigned int a, c[15 + 1], f;
int g, h;
unsigned int i, j, k;
int l;
unsigned int ee;
unsigned int *p;
A *q, r, *u[15];
int w;
unsigned int x[15 + 1], *xx;
int y;
unsigned int z;
p = c;
*p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0;
*p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0;
*p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0;
*p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0;
p = b;
i = n;
do
c[*p++]++;
while (--i);
if (c[0] == n)
{
*t = (A *) 0;
*m = 0;
return 0;
}
l = *m;
for (j = 1; j <= 15; j++)
if (c[j])
break;
k = j;
if ((unsigned int) l < j)
l = j;
for (i = 15; i; i--)
if (c[i])
break;
g = i;
if ((unsigned int) l > i)
l = i;
*m = l;
for (y = 1 << j; j < i; j++, y <<= 1)
if ((y -= c[j]) < 0)
return -3;
if ((y -= c[i]) < 0)
return -3;
c[i] += y;
x[1] = j = 0;
p = c + 1;
xx = x + 2;
while (--i)
*xx++ = (j += *p++);
p = b;
i = 0;
do
if ((j = *p++) != 0)
v[x[j]++] = i;
while (++i < n);
n = x[g];
x[0] = i = 0;
p = v;
h = -1;
w = -l;
u[0] = (A *) 0;
q = (A *) 0;
z = 0;
for (; k <= g; k++)
{
a = c[k];
while (a--)
{
while (k > w + l)
{
h++;
w += l;
z = g - w;
z = z > (unsigned int) l ? l : z;
if ((f = 1 << (j = k - w)) > a + 1)
{
f -= a + 1;
xx = c + k;
if (j < z)
while (++j < z)
{
if ((f <<= 1) <= *++xx)
break;
f -= *xx;
}
}
z = 1 << j;
if (*hn + z > 1440)
return -3;
u[h] = q = hp + *hn;
*hn += z;
if (h)
{
x[h] = i;
r.a0.a2.a4 = (unsigned char) l;
r.a0.a2.a3 = (unsigned char) j;
j = i >> (w - l);
r.a1 = (unsigned int) (q - u[h - 1] - j);
u[h - 1][j] = r;
}
else
*t = q;
}
r.a0.a2.a4 = (unsigned char) (k - w);
if (p >= v + n)
r.a0.a2.a3 = 128 + 64;
else if (*p < s)
{
r.a0.a2.a3 = (unsigned char) (*p < 256 ? 0 : 32 + 64);
r.a1 = *p++;
}
else
{
r.a0.a2.a3 = (unsigned char) (e[*p - s] + 16 + 64);
r.a1 = d[*p++ - s];
}
f = 1 << (k - w);
for (j = i >> w; j < z; j += f)
q[j] = r;
for (j = 1 << (k - 1); i & j; j >>= 1)
i ^= j;
i ^= j;
ee = (1 << w) - 1;
while ((i & ee) != x[h])
{
h--;
w -= l;
ee = (1 << w) - 1;
}
}
}
return y != 0 && g != 1 ? (-5) : 0;
}
unsigned int a[19] = { 3, 4, 0, 2, 2, [17] = 3, 3 };
unsigned int d[19];
A h[1440];
int
main (void)
{
unsigned int b = 0, c = 0;
A *e = 0;
foo (a, 19, 19, 0, 0, &e, &b, h, &c, d);
exit (0);
}

28
test/dg/20020517-1.c Normal file
View File

@ -0,0 +1,28 @@
/* This testcase caused ICE in do_SUBST on IA-32, because 0xf6 constant
was not sign-extended for QImode. */
/* { dg-do run } */
/* { dg-options "-O2" } */
/* { dg-options "-O2 -mtune=i686" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
#include <limits.h>
void abort (void);
void exit (int);
void foo (void)
{
int i;
char *p;
p = (char *) &i;
*p = -10;
if (* (unsigned char *) p != 0x100 - 10)
abort ();
}
int main (void)
{
if (UCHAR_MAX == 255)
foo ();
exit (0);
}

24
test/dg/20020525-1.c Normal file
View File

@ -0,0 +1,24 @@
/* PR optimization/6703
Origin: Glen Nakamura <glen@imodulo.com> */
/* { dg-do run } */
/* { dg-options "-O2" } */
extern void abort (void);
extern void exit (int);
void foo (int *x, int y)
{
__builtin_memset (x, 0, y);
}
int main ()
{
int x[2] = { -1, -1 };
if (x[1] != -1)
abort ();
foo (x, sizeof (int) + 1);
if (x[1] == -1)
abort ();
exit (0);
}

40
test/dg/20020607-1.c Normal file
View File

@ -0,0 +1,40 @@
/* PR middle-end/6950
gcc 3.0.4 mistakenly set lhs.low to 0 at the beginning of the num_eq
expansion; it should use a temporary.
/* { dg-do run } */
typedef struct cpp_num cpp_num;
struct cpp_num
{
long high;
long low;
char overflow;
};
#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high)
static cpp_num
num_equality_op (lhs, rhs)
cpp_num lhs, rhs;
{
lhs.low = num_eq (lhs, rhs);
lhs.high = 0;
lhs.overflow = 0;
return lhs;
}
int main()
{
cpp_num a = { 1, 2 };
cpp_num b = { 3, 4 };
cpp_num result = num_equality_op (a, b);
if (result.low)
return 1;
result = num_equality_op (a, a);
if (!result.low)
return 2;
return 0;
}

74
test/dg/20020607-2.c Normal file
View File

@ -0,0 +1,74 @@
/* Copyright (C) 2002 Free Software Foundation.
Test for correctness of floating point comparisons.
Written by Roger Sayle, 3rd June 2002. */
/* { dg-do run } */
/* { dg-options "-O2 -ffast-math" } */
extern void abort (void);
int test1 (double x, int ok)
{
if ((x - 1.0) > 0.0)
{
if (!ok) abort ();
}
else
if (ok) abort ();
}
int test1f (float x, int ok)
{
if ((x - 1.0f) > 0.0f)
{
if (!ok) abort ();
}
else
if (ok) abort ();
}
int test2 (double x, int ok)
{
if ((x + 1.0) < 0.0)
{
if (!ok) abort ();
}
else
if (ok) abort ();
}
int test2f (float x, int ok)
{
if ((x + 1.0f) < 0.0f)
{
if (!ok) abort ();
}
else
if (ok) abort ();
}
int
main ()
{
test1 (-2.0, 0);
test1 ( 0.0, 0);
test1 ( 2.0, 1);
test1f (-2.0f, 0);
test1f ( 0.0f, 0);
test1f ( 2.0f, 1);
test2 (-2.0, 1);
test2 ( 0.0, 0);
test2 ( 2.0, 0);
test2f (-2.0f, 1);
test2f ( 0.0f, 0);
test2f ( 2.0f, 0);
return 0;
}

27
test/dg/20021014-1.c Normal file
View File

@ -0,0 +1,27 @@
/* { dg-do run } */
/* { dg-require-profiling "-p" } */
/* { dg-options "-O2 -p" } */
/* { dg-options "-O2 -p -static" { target hppa*-*-hpux* } } */
/* { dg-error "profiler" "No profiler support" { target xstormy16-*-* } 0 } */
/* { dg-error "" "consider using `-pg' instead of `-p' with gprof(1)" { target *-*-freebsd* } 0 } */
extern void abort (void);
extern void exit (int);
int bar (int x)
{
return x + 3;
}
int foo (void)
{
return bar (1) + bar (2);
}
int main (void)
{
if (foo () != 9)
abort ();
exit (0);
}
/* { dg-final { cleanup-profile-file } } */

30
test/dg/20021018-1.c Normal file
View File

@ -0,0 +1,30 @@
/* { dg-do run { target fpic } } */
/* { dg-options "-O2 -fpic" } */
/* { dg-bogus "\[Uu\]nresolved symbol .(_GLOBAL_OFFSET_TABLE_|\[_.A-Za-z\]\[_.0-9A-Za-z\]*@(PLT|GOT|GOTOFF))" "PIC unsupported" { xfail *-*-netware* } 0 } */
extern void abort (void);
extern void exit (int);
#if __INT_MAX__ >= 2147483647L
static const long foo [10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
long __attribute__((noinline))
bar (int x)
{
return foo [x - 0x6ffffffa];
}
int
main (void)
{
if (bar (0x6ffffffc) != 2)
abort ();
exit (0);
}
#else
int
main (void)
{
exit (0);
}
#endif

102
test/dg/20030225-1.c Normal file
View File

@ -0,0 +1,102 @@
/* PR target/9732
This testcase segfaulted on PPC because PIC_OFFSET_TABLE_REGNUM was no
fixed register.
Distilled from the xvid sources by Guillaume Morin <guillaume@morinfr.org>
and Benjamin Herrenschmidt <benh@kernel.crashing.org>. */
/* { dg-do run { target fpic } } */
/* { dg-options "-O2 -fPIC" } */
/* { dg-bogus "\[Uu\]nresolved symbol .(_GLOBAL_OFFSET_TABLE_|\[_.A-Za-z\]\[_.0-9A-Za-z\]*@(PLT|GOT|GOTOFF))" "PIC unsupported" { xfail *-*-netware* } 0 } */
extern void exit (int);
#define W1 2841 /* 2048*sqrt(2)*cos(1*pi/16) */
#define W2 2676 /* 2048*sqrt(2)*cos(2*pi/16) */
#define W3 2408 /* 2048*sqrt(2)*cos(3*pi/16) */
#define W5 1609 /* 2048*sqrt(2)*cos(5*pi/16) */
#define W6 1108 /* 2048*sqrt(2)*cos(6*pi/16) */
#define W7 565 /* 2048*sqrt(2)*cos(7*pi/16) */
/* private data */
static short iclip[1024]; /* clipping table */
static short *iclp;
void
idct_int32(short *const block)
{
static short *blk;
static long i;
static long X0, X1, X2, X3, X4, X5, X6, X7, X8;
for (i = 0; i < 8; i++) /* idct columns */
{
blk = block + i;
/* shortcut */
if (! ((X1 = (blk[8 * 4] << 8)) | (X2 = blk[8 * 6])
| (X3 = blk[8 * 2]) | (X4 = blk[8 * 1]) | (X5 = blk[8 * 7])
| (X6 = blk[8 * 5]) | (X7 = blk[8 * 3])))
{
blk[8 * 0] = blk[8 * 1] = blk[8 * 2] =
blk[8 * 3] = blk[8 * 4] =
blk[8 * 5] = blk[8 * 6] = blk[8 * 7] =
iclp[(blk[8 * 0] + 32) >> 6];
continue;
}
X0 = (blk[8 * 0] << 8) + 8192;
/* first stage */
X8 = W7 * (X4 + X5) + 4;
X4 = (X8 + (W1 - W7) * X4) >> 3;
X5 = (X8 - (W1 + W7) * X5) >> 3;
X8 = W3 * (X6 + X7) + 4;
X6 = (X8 - (W3 - W5) * X6) >> 3;
X7 = (X8 - (W3 + W5) * X7) >> 3;
/* second stage */
X8 = X0 + X1;
X0 -= X1;
X1 = W6 * (X3 + X2) + 4;
X2 = (X1 - (W2 + W6) * X2) >> 3;
X3 = (X1 + (W2 - W6) * X3) >> 3;
X1 = X4 + X6;
X4 -= X6;
X6 = X5 + X7;
X5 -= X7;
/* third stage */
X7 = X8 + X3;
X8 -= X3;
X3 = X0 + X2;
X0 -= X2;
X2 = (181 * (X4 + X5) + 128) >> 8;
X4 = (181 * (X4 - X5) + 128) >> 8;
/* fourth stage */
blk[8 * 0] = iclp[(X7 + X1) >> 14];
blk[8 * 1] = iclp[(X3 + X2) >> 14];
blk[8 * 2] = iclp[(X0 + X4) >> 14];
blk[8 * 3] = iclp[(X8 + X6) >> 14];
blk[8 * 4] = iclp[(X8 - X6) >> 14];
blk[8 * 5] = iclp[(X0 - X4) >> 14];
blk[8 * 6] = iclp[(X3 - X2) >> 14];
blk[8 * 7] = iclp[(X7 - X1) >> 14];
}
} /* end function idct_int32(block) */
int main(void) {
int i;
unsigned short tab[64];
for (i = 0 ; i < 64 ; ++i)
{
tab[i] = (1+(int) (65535)*8000/(2147483647+1.0));
}
iclp = iclip + 512;
for (i = -512; i < 512; i++)
iclp[i] = (i < -256) ? -256 : ((i > 255) ? 255 : i);
idct_int32((short *) tab);
exit (0);
}

24
test/dg/20030323-1.c Normal file
View File

@ -0,0 +1,24 @@
/* { dg-do run } */
/* PR c/8224 */
/* Contributed by Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz> */
extern void abort (void);
unsigned f (int x)
{
return (unsigned) (x / 2) / 2;
}
unsigned f1 (int x)
{
unsigned xx = x / 2;
return xx / 2;
}
int main ()
{
if (f1 (-5) != f (-5))
abort ();
return 0;
}

39
test/dg/20030324-1.c Normal file
View File

@ -0,0 +1,39 @@
/* { dg-do run } */
/* { dg-options "-O -fstrict-aliasing -fgcse" } */
/* PR optimization/10087 */
/* Contributed by Peter van Hoof <p.van-hoof@qub.ac.uk> */
extern void abort(void);
void b(int*,int*);
typedef struct {
double T1;
char c;
} S;
int main(void)
{
int i,j;
double s;
S x1[2][2];
S *x[2] = { x1[0], x1[1] };
S **E = x;
for( i=0; i < 2; i++ )
for( j=0; j < 2; j++ )
E[j][i].T1 = 1;
for( i=0; i < 2; i++ )
for( j=0; j < 2; j++ )
s = E[j][i].T1;
b(&j,&i);
if (s != 1)
abort ();
return 0;
}
void b(int *i, int *j) {}

39
test/dg/20030414-2.c Normal file
View File

@ -0,0 +1,39 @@
/* Copyright (C) 2003 Free Software Foundation.
Check that constant folding (c1 - x) op c2 into x swap(op) c1-c2
doesn't break anything.
Written by Roger Sayle, 27th March 2003. */
/* { dg-do run } */
/* { dg-options "-O2 -ffast-math" } */
extern void abort (void);
extern float fabs(float);
int foo(double x)
{
return (10.0 - x) > 3.0;
}
int bar (double x)
{
return (10.0 - x) == 5.0;
}
int main()
{
if (foo (8.0))
abort ();
if (! foo (6.0))
abort ();
if (bar (1.0))
exit (1);
if (! bar (5.0))
exit (2);
return 0;
}

24
test/dg/20030612-1.c Normal file
View File

@ -0,0 +1,24 @@
/* { dg-do run } */
/* { dg-options "-O2" } */
extern void abort (void);
int A, B;
void foo()
{
long x = 3;
(void)({
A = B + x + ((1) - 1);
return; /* { dg-warning "statement-expressions should end with a non-void expression" "" { xfail *-*-* } } */
});
}
main()
{
B = 5;
foo();
if (A != 8)
abort ();
return 0;
}

23
test/dg/20030805-1.c Normal file
View File

@ -0,0 +1,23 @@
/* Test that gcc understands that the call to g might clobber i. */
/* { dg-do run } */
/* { dg-options "-O2" } */
__inline int f ()
{
static int i;
int i2 = i;
i = i2 + 1;
return i;
}
int g () { return f (); }
int main ()
{
if (f() != 1
|| g() != 2
|| f() != 3)
return 1;
return 0;
}

33
test/dg/20030826-1.c Normal file
View File

@ -0,0 +1,33 @@
/* Copyright (C) 2003 Free Software Foundation.
Check that constant folding of mathematical expressions doesn't
break anything.
Written by Roger Sayle, 24th August 2003. */
/* { dg-do run } */
/* { dg-options "-O2 -ffast-math" } */
void abort(void);
double foo(double x)
{
return 12.0/(x*3.0);
}
double bar(double x)
{
return (3.0/x)*4.0;
}
int main()
{
if (foo(2.0) != 2.0)
abort ();
if (bar(2.0) != 6.0)
abort ();
return 0;
}

44
test/dg/20031202-1.c Normal file
View File

@ -0,0 +1,44 @@
/* { dg-do run } */
/* { dg-options "-O2" } */
/* { dg-options "-O2 -mtune=i686" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
extern void abort (void);
extern void exit (int);
struct A { char p[6]; } __attribute__((packed));
struct B {
struct A a;
void * const b;
struct A const * const c;
struct A const *d;
};
char v;
int __attribute__((noinline))
foo (struct B *b)
{
int i;
for (i = 0; i < 6; ++i)
if (b->a.p[i])
abort ();
if (b->b != &v || b->c || b->d)
abort ();
return 12;
}
int __attribute__((noinline))
bar (void *x)
{
//__asm __volatile ("" : "=r" (x) : "0" (x));
struct B y = { .b = x, .c = (void *) 0 };
return foo (&y) + 1;
}
int
main (void)
{
if (bar (&v) != 13)
abort ();
exit (0);
}

39
test/dg/20031216-1.c Normal file
View File

@ -0,0 +1,39 @@
/* This used to abort due to a loop bug on s390*. */
/* { dg-do run } */
/* { dg-options "-O2" } */
/* { dg-options "-O2 -fPIC" { target s390*-*-* } } */
extern void abort (void);
int count = 0;
char *str;
void test (int flag)
{
char *p;
for (;;)
{
if (count > 5)
return;
p = "test";
if (flag)
count++;
str = p;
}
}
int main (void)
{
test (1);
if (str[0] != 't')
abort ();
return 0;
}

49
test/dg/20040305-2.c Normal file
View File

@ -0,0 +1,49 @@
/* PR target/14262 */
/* { dg-do run } */
extern void abort (void);
typedef char ACS;
typedef char LSM;
typedef char PANEL;
typedef char DRIVE;
typedef struct {
ACS acs;
LSM lsm;
} LSMID;
typedef struct {
LSMID lsm_id;
PANEL panel;
} PANELID;
typedef struct {
PANELID panel_id;
DRIVE drive;
} DRIVEID;
void sub (DRIVEID driveid)
{
if (driveid.drive != 1)
abort ();
if (driveid.panel_id.panel != 2)
abort ();
if (driveid.panel_id.lsm_id.lsm != 3)
abort ();
if (driveid.panel_id.lsm_id.acs != 4)
abort ();
}
int main(void)
{
DRIVEID driveid;
driveid.drive = 1;
driveid.panel_id.panel = 2;
driveid.panel_id.lsm_id.lsm = 3;
driveid.panel_id.lsm_id.acs = 4;
sub(driveid);
return 0;
}

17
test/dg/20040309-1.c Normal file
View File

@ -0,0 +1,17 @@
/* Test integer mod on ia64. There was a bug in the inline integer
division code. */
/* { dg-do run } */
/* { dg-options "-minline-int-divide-max-throughput" { target ia64-*-* } } */
extern void abort (void);
volatile int i = 10;
volatile int j = 10;
int main()
{
int k = i % j;
if (k != 0) abort();
return 0;
}

14
test/dg/20040331-1.c Normal file
View File

@ -0,0 +1,14 @@
/* { dg-do run } */
/* { dg-options "-O2 -fwrapv" } */
extern void abort (void);
extern void exit (int);
int
main (void)
{
struct { int count: 2; } s = { -2 };
while (s.count-- != -2)
abort ();
exit (0);
}

47
test/dg/20041219-1.c Normal file
View File

@ -0,0 +1,47 @@
/* PR18191 Struct member is not getting default-initialized.
Origin: Grigory Zagorodnev <grigory.zagorodnev@intel.com> */
/* { dg-do run } */
//extern int printf (__const char *__restrict __format, ...);
typedef struct S {
const char* s;
int i;
} S;
void
foo (void)
{
S dummy[2];
unsigned i;
/* Put some garbage on the stack. */
for (i = 0; i < sizeof(dummy); i++)
((char *)&dummy)[i] = -1;
}
int
bar (void)
{
/* Allocate object on the stack. */
S obj[2] = { {"m0"}, {"m1"} };
/* Assume fields those not explicitly initialized
are default initialized to 0 [8.5.1/7 and 8.5/5]. */
if (obj[0].i == 0)
return 0;
else
{
/* printf("Failed: obj[0].i == '%d', expecting '0'\n", obj[0].i); */
return 1;
}
}
int
main (void)
{
foo();
return bar();
}

21
test/dg/20050603-2.c Normal file
View File

@ -0,0 +1,21 @@
/* { dg-do run } */
/* { dg-options "-O2" } */
#include <stdlib.h>
struct s {
unsigned short f: 16;
unsigned short y: 8;
unsigned short g: 2;
unsigned int x;
};
void set (struct s*, int) __attribute__((noinline));
void set (struct s* p, int flags) {
p->g = flags << 1;
}
main() {
struct s foo = {0 , 0, 3, 0};
set (&foo, -1);
if (foo.g != 2)
abort();
return 0;
}

48
test/dg/20050922-1.c Normal file
View File

@ -0,0 +1,48 @@
/* This revealed a bug when rotates are expanded into
two shifts. */
/* { dg-do run } */
/* { dg-options "-O1 -std=c99" } */
#include <stdlib.h>
#if __INT_MAX__ == 2147483647
typedef unsigned int uint32_t;
#elif __LONG_MAX__ == 2147483647
typedef unsigned long uint32_t;
#else
//#error unable to find 32-bit integer type
typedef unsigned long long uint32_t;
#endif
uint32_t
f (uint32_t *S, int j)
{
uint32_t A, B, k, L[2] = {1234, 5678};
int i, m;
A = B = 0;
for (i = 0; i < j; i++)
{
k = (S[i] + A + B) & 0xffffffffL;
A = S[i] =
((k << (3 & 0x1f)) | ((k & 0xffffffff) >> (32 - (3 & 0x1f))));
m = (int) (A + B);
k = (L[i] + A + B) & 0xffffffffL;
B = L[i] =
((k << (m & 0x1f)) | ((k & 0xffffffff) >> (32 - (m & 0x1f))));
}
return L[0] + L[1];
}
int
main ()
{
uint32_t S[2] = {0xffff, 0xffffff};
if (f (S,2)!= 1392607300)
abort();
return 0;
}

34
test/dg/20050922-2.c Normal file
View File

@ -0,0 +1,34 @@
/* 20050922-1.c does not trigger the expand_shift rotate bug on sh4-elf, but
this does. */
/* { dg-do run } */
/* { dg-options "-O1 -std=c99" } */
#include <stdlib.h>
#if __INT_MAX__ == 2147483647
typedef unsigned int uint32_t;
#elif __LONG_MAX__ == 2147483647
typedef unsigned long uint32_t;
#else
//#error unable to find 32-bit integer type
typedef unsigned long long uint32_t;
#endif
#define rotl(x,n) (((x) << ((int)(n))) | ((x) >> (32 - (int)(n))))
uint32_t
f (uint32_t a, uint32_t b)
{
b = rotl (a, b & 31);
return b;
}
int
main ()
{
if (f(2,31) != 1)
abort ();
exit (0);
}

38
test/dg/20060425-1.c Normal file
View File

@ -0,0 +1,38 @@
/* { dg-do run } */
/* { dg-options "-O1" } */
/* This failed because if conversion didn't handle insv patterns properly. */
void abort (void);
union y
{
int a;
unsigned short b;
};
void __attribute__ ((noinline))
bar (unsigned short u, union y v)
{
if (u != 1)
abort ();
}
void __attribute__ ((noinline))
foo (int check)
{
union y x;
if (check != 0)
x.b = 1;
else
x.b = 2;
bar (x.b, x);
}
int
main ()
{
foo (1);
return 0;
}

103
test/dg/20070507-1.c Normal file
View File

@ -0,0 +1,103 @@
/* This failed on s390x due to bug in loop.c.
loop.c failed to remove a REG_EQUAL note when
hoisting an insn from a loop body. */
/* { dg-options "-O3 -fPIC" } */
/* { dg-do run { target fpic } } */
typedef __SIZE_TYPE__ size_t;
int memcmp(const void *s1, const void *s2, size_t n);
typedef struct
{
char name[30];
int a;
} LOCAL;
int global = 0;
int sy = 1;
int subroutine_offset;
LOCAL local = { "local", 0 };
LOCAL keywords = { "keywords", 1 };
int local_table = 0;
int keywords_table = 0;
void __attribute__((noinline)) bar (char *p_buffer)
{
p_buffer[255] = 1;
}
int __attribute__((noinline)) foo (char *p_str1)
{
global = 1;
return 1;
}
int __attribute__((noinline)) loop_next (int *p_table, char *p_table_head)
{
static loop_next = 0;
if (loop_next == 1)
return 1;
loop_next = 1;
return 0;
}
int
main ()
{
char buffer[256];
int ende = 0;
int index;
int local_base = 2;
keywords.a = 1;
for (sy = 0;; sy++)
{
for (index = 1;;)
{
bar (buffer);
if (buffer[sy] != 0)
{
ende = 1;
break;
};
if (foo (buffer))
{
keywords.a += index - 1;
break;
}
index++;
}
if (ende)
break;
}
subroutine_offset = 0;
for (;;)
{
if (loop_next (&keywords_table, (char*)&keywords))
break;
if ((!memcmp (keywords.name, "+++", 3)))
local_base = 100;
else
local_base = 0;
if ((!memcmp (keywords.name, "+++", 3)))
subroutine_offset += local_table;
for (;;)
{
if (loop_next (&local_table, (char*)&local))
break;;
if ((local.a == 0))
continue;;
foo (local.name);
}
}
return 0;
}

64
test/dg/20070725-1.c Normal file
View File

@ -0,0 +1,64 @@
/* This used to fail due to a ifcombine problem wrecking 64bit
checks. Fixed with rev. 126876. */
/* { dg-do run } */
/* { dg-options "-O1" } */
struct tree_base
{
unsigned code:16;
unsigned side_effects_flag:1;
unsigned constant_flag:1;
unsigned addressable_flag:1;
unsigned volatile_flag:1;
unsigned readonly_flag:1;
unsigned unsigned_flag:1;
unsigned asm_written_flag:1;
unsigned nowarning_flag:1;
unsigned used_flag:1;
unsigned nothrow_flag:1;
unsigned static_flag:1;
unsigned public_flag:1;
unsigned private_flag:1;
unsigned protected_flag:1;
unsigned deprecated_flag:1;
unsigned invariant_flag:1;
unsigned lang_flag_0:1;
unsigned lang_flag_1:1;
unsigned lang_flag_2:1;
unsigned lang_flag_3:1;
unsigned lang_flag_4:1;
unsigned lang_flag_5:1;
unsigned lang_flag_6:1;
unsigned visited:1;
unsigned spare1:16;
unsigned spare2:8;
unsigned long a;
};
int
foo (struct tree_base *rhs)
{
if (({const struct tree_base* __t = (rhs); __t;})->readonly_flag
&& (rhs)->static_flag)
return 1;
return 0;
}
extern void abort (void);
int
main ()
{
struct tree_base t;
t.readonly_flag = t.static_flag = 0;
if (foo (&t))
abort ();
return 0;
}

53
test/dg/980523-1.c Normal file
View File

@ -0,0 +1,53 @@
/* { dg-do run { target fpic } } */
/* { dg-options "-O2 -fpic" } */
extern void exit (int);
void foo1(int a, char *b, int c)
{
c =a+c+234;
}
int foo2(int d)
{
return d*d;
}
int bar1, bar2, bar3;
char * bar4;
int main(void) {
int h;
bar1 = foo2(1);
bar2 = foo2(1);
h = foo2(1);
foo1(1, "a", foo2(1));
foo1(bar1, "a", foo2(1));
foo2(1);
h = foo2(1);
bar3 = 1;
bar4 = "a";
foo1(1, "n", foo2(1));
foo1(1, "o", foo2(1));
foo1(1, "p", foo2(1));
foo1(bar1, "a", foo2(1));
bar3 = h;
bar4 = "b"; foo1(bar1, "b", foo2(1));
foo1(1, "q", foo2(1));
bar4 = "c"; foo1(1, "c", foo2(1));
bar4 = "d"; foo1(1, "d", foo2(1));
bar4 = "e"; foo1(1, "e", foo2(1));
bar4 = "f"; foo1(1, "f", foo2(1));
bar4 = "g"; foo1(1, "g", foo2(1));
bar4 = "h"; foo1(1, "h", foo2(1));
bar4 = "i"; foo1(1, "i", foo2(1));
bar4 = "j"; foo1(1, "j", foo2(1));
bar4 = "k"; foo1(1, "k", foo2(1));
bar4 = "l"; foo1(1, "l", foo2(1));
bar4 = "m";
foo1(bar2, "m", foo2(1));
exit(0);
}

View File

@ -0,0 +1,26 @@
/* Test for -Wdeclaration-after-statement emitting warnings when no
standard-specifying option is given. See also c9?-mixdecl-*. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do run } */
/* { dg-options "-Wdeclaration-after-statement" } */
extern void abort (void);
extern void exit (int);
int
main (void)
{
int i = 0;
if (i != 0)
abort ();
i++;
if (i != 1)
abort ();
int j = i; /* { dg-warning "" "declaration after statement" } */
if (j != 1)
abort ();
struct foo { int i0; } k = { 4 }; /* { dg-warning "" "declaration after statement" } */
if (k.i0 != 4)
abort ();
exit (0);
}

View File

@ -0,0 +1,26 @@
/* Test for C99 mixed declarations and code giving warnings, not error with
-Wdeclaration-after-statement. See also c9?-mixdecl-*. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do run } */
/* { dg-options "-std=c99 -pedantic-errors -Wdeclaration-after-statement" } */
extern void abort (void);
extern void exit (int);
int
main (void)
{
int i = 0;
if (i != 0)
abort ();
i++;
if (i != 1)
abort ();
int j = i; /* { dg-warning "" "declaration-after-statement" } */
if (j != 1)
abort ();
struct foo { int i0; } k = { 4 }; /* { dg-warning "" "declaration-after-statement" } */
if (k.i0 != 4)
abort ();
exit (0);
}

28
test/dg/align-1.c Normal file
View File

@ -0,0 +1,28 @@
/* PR java/10145
Test that requesting an alignment of 1 does not increase the alignment
of a long long field.
{ dg-do run }
{ dg-options "" }
*/
extern void abort (void);
struct A
{
char c;
long long i;
};
struct B
{
char c;
long long i __attribute ((__aligned__ (1)));
};
int main ()
{
if (sizeof (struct A) != sizeof (struct B))
abort ();
return 0;
}

51
test/dg/array-init-2.c Normal file
View File

@ -0,0 +1,51 @@
/* Test array initializion by store_by_pieces. */
/* { dg-do run } */
/* { dg-options "-O2" } */
struct A { char c[10]; };
extern void abort (void);
void
__attribute__((noinline))
check (struct A * a, int b)
{
const char *p;
switch (b)
{
case 0:
p = "abcdefghi";
break;
case 1:
p = "j\0\0\0\0\0\0\0\0";
break;
case 2:
p = "kl\0\0\0\0\0\0\0";
break;
case 3:
p = "mnop\0\0\0\0\0";
break;
case 4:
p = "qrstuvwx\0";
break;
default:
abort ();
}
if (__builtin_memcmp (a->c, p, 10) != 0)
abort ();
}
int
main (void)
{
struct A a = { "abcdefghi" };
check (&a, 0);
struct A b = { "j" };
check (&b, 1);
struct A c = { "kl" };
check (&c, 2);
struct A d = { "mnop" };
check (&d, 3);
struct A e = { "qrstuvwx" };
check (&e, 4);
return 0;
}

67
test/dg/bitfld-3.c Normal file
View File

@ -0,0 +1,67 @@
/* Test for bitfield alignment in structs and unions. */
/* { dg-do run { target pcc_bitfield_type_matters } } */
/* { dg-options "-O2" } */
extern void abort (void);
extern void exit (int);
typedef long la __attribute__((aligned (8)));
struct A
{
char a;
union UA
{
char x;
la y : 6;
} b;
char c;
} a;
struct B
{
char a;
union UB
{
char x;
long y : 6 /* __attribute__((aligned (8))) */;
} b;
char c;
} b;
struct C
{
char a;
struct UC
{
la y : 6;
} b;
char c;
} c;
struct D
{
char a;
struct UD
{
long y : 6 /* __attribute__((aligned (8))) */;
} b;
char c;
} d;
int main (void)
{
if (sizeof (a) != sizeof (b))
abort ();
if (sizeof (a) != sizeof (c))
abort ();
if (sizeof (a) != sizeof (d))
abort ();
if ((&a.c - &a.a) != (&b.c - &b.a))
abort ();
if ((&a.c - &a.a) != (&c.c - &c.a))
abort ();
if ((&a.c - &a.a) != (&d.c - &d.a))
abort ();
exit (0);
}

42
test/dg/bitfld-4.c Normal file
View File

@ -0,0 +1,42 @@
/* { dg-do run { target { pcc_bitfield_type_matters || default_packed } } } */
/* { dg-options "" } */
/* Check bitfields and non-bitfields are aligned & sized similarly.
Copyright (C) 2002 Free Software Foundation Inc
Contributed by Nathan Sidwell <nathan@codesourcery.com>
*/
#include <limits.h>
//#include <stdio.h>
static int fail;
#define CHECK1(N, T) do { \
typedef struct Field_##N { char c; T f; } Field_##N; \
typedef struct BitField_##N { char c; T f : sizeof (T) * CHAR_BIT; } BitField_##N; \
if (sizeof (Field_##N) != sizeof (BitField_##N)) { \
fail = 1; /* printf ("sizeof %s failed\n", #T); */ \
} \
if (__alignof__ (Field_##N) != __alignof__ (BitField_##N)) { \
fail = 1; /* printf ("__alignof__ %s failed\n", #T); */ \
} \
} while (0)
#define CHECK(N, T) do { \
CHECK1(N, T); \
CHECK1 (s##N, signed T); \
CHECK1 (u##N, unsigned T); \
} while (0)
int main ()
{
CHECK (c, char);
CHECK (s, short);
CHECK (i, int);
CHECK (l, long);
//CHECK (ll, long long);
return fail;
}

36
test/dg/builtins-24.c Normal file
View File

@ -0,0 +1,36 @@
/* Copyright (C) 2003 Free Software Foundation.
Check that the RTL expansion of floating point exponentiation by
a constant integer doesn't break anything and produces the expected
results.
Written by Roger Sayle, 20th June 2003. */
/* { dg-do run } */
/* { dg-options "-O2 -ffast-math" } */
extern float pow(float,float);
extern void abort(void);
extern float fabs(float);
float foo (float x)
{
return pow (x, 6);
}
float bar (float x)
{
return pow (x, -4);
}
int main()
{
if (fabs(foo(2.0) - 64.0) > .0002) /* no, it doesn't get more exact than that... */
abort ();
if (bar (2.0) != 0.0625)
abort ();
return 0;
}

Some files were not shown because too many files have changed in this diff Show More