Compare commits

...

No commits in common. 'main' and 'homework2' have entirely different histories.

21 changed files with 1093 additions and 2374 deletions
Split View
  1. +0
    -52
      .gitignore
  2. +0
    -12
      LAB1/Driverhdrs.pm
  3. +0
    -138
      LAB1/Driverlib.pm
  4. +0
    -33
      LAB1/Makefile
  5. +0
    -140
      LAB1/README
  6. +0
    -388
      LAB1/bits.c
  7. +0
    -65
      LAB1/bits.h
  8. +0
    -583
      LAB1/btest.c
  9. +0
    -32
      LAB1/btest.h
  10. +0
    -86
      LAB1/decl.c
  11. +0
    -0
      LAB1/dlc
  12. +0
    -439
      LAB1/driver.pl
  13. +0
    -151
      LAB1/fshow.c
  14. +0
    -75
      LAB1/ishow.c
  15. +0
    -124
      LAB1/tests.c
  16. +0
    -21
      LICENSE
  17. +971
    -0
      README.MD
  18. +0
    -35
      README.md
  19. BIN
      bomb
  20. +115
    -0
      bomb.c
  21. +7
    -0
      password.txt

+ 0
- 52
.gitignore View File

@ -1,52 +0,0 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf

+ 0
- 12
LAB1/Driverhdrs.pm View File

@ -1,12 +0,0 @@
#
# This file contains configuration variables for drivers.
# It was generated by genhdrs.pl. Do not modify it.
#
package Driverhdrs;
$LAB = "datalab";
$SERVER_NAME = "changeme.ics.cs.cmu.edu";
$SERVER_PORT = 8081;
$COURSE_NAME = "csapp";
$AUTOGRADE_TIMEOUT = 0;
1;

+ 0
- 138
LAB1/Driverlib.pm View File

@ -1,138 +0,0 @@
###############################################################
# Driverlib.pm - A package of helper functions for Perl drivers
#
# Copyright (c) 2005 David R. O'Hallaron, All rights reserved.
###############################################################
package Driverlib;
use Socket;
# Autogenerated header file with lab-specific constants
use lib ".";
use Driverhdrs;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(
driver_post
);
use strict;
#####
# Public functions
#
#
# driver_post - This is the routine that a driver calls when
# it needs to transmit an autoresult string to the result server.
#
sub driver_post ($$) {
my $userid = shift; # User id for this submission
my $result = shift; # Autoresult string
my $autograded = shift; # Set if called by an autograder
# Echo the autoresult string to stdout if the driver was called
# by an autograder
if ($autograded) {
print "\n";
print "AUTORESULT_STRING=$result\n";
return;
}
# If the driver was called with a specific userid, then submit
# the autoresult string to the result server over the Internet.
if ($userid) {
my $status = submitr($Driverhdrs::SERVER_NAME,
$Driverhdrs::SERVER_PORT,
$Driverhdrs::COURSE_NAME,
$userid,
$Driverhdrs::LAB,
$result);
# Print the status of the transfer
if (!($status =~ /OK/)) {
print "$status\n";
print "Did not send autoresult string to the result server.\n";
exit(1);
}
print "Success: Sent autoresult string for $userid to the result server.\n";
}
}
#####
# Private functions
#
#
# submitr - Sends an autoresult string to the result server
#
sub submitr ($$$$$$) {
my $hostname = shift;
my $port = shift;
my $course = shift;
my $userid = shift;
my $lab = shift;
my $result = shift;
my $internet_addr;
my $enc_result;
my $paddr;
my $line;
my $http_version;
my $errcode;
my $errmsg;
# Establish the connection to the server
socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
$internet_addr = inet_aton($hostname)
or die "Could not convert $hostname to an internet address: $!\n";
$paddr = sockaddr_in($port, $internet_addr);
connect(SERVER, $paddr)
or die "Could not connect to $hostname:$port:$!\n";
select((select(SERVER), $| = 1)[0]); # enable command buffering
# Send HTTP request to server
$enc_result = url_encode($result);
print SERVER "GET /$course/submitr.pl/?userid=$userid&lab=$lab&result=$enc_result&submit=submit HTTP/1.0\r\n\r\n";
# Get first HTTP response line
$line = <SERVER>;
chomp($line);
($http_version, $errcode, $errmsg) = split(/\s+/, $line);
if ($errcode != 200) {
return "Error: HTTP request failed with error $errcode: $errmsg";
}
# Read the remaining HTTP response header lines
while ($line = <SERVER>) {
if ($line =~ /^\r\n/) {
last;
}
}
# Read and return the response from the result server
$line = <SERVER>;
chomp($line);
close SERVER;
return $line;
}
#
# url_encode - Encode text string so it can be included in URI of GET request
#
sub url_encode ($) {
my $value = shift;
$value =~s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg;
return $value;
}
# Always end a module with a 1 so that it returns TRUE
1;

+ 0
- 33
LAB1/Makefile View File

@ -1,33 +0,0 @@
#
# Makefile that builds btest and other helper programs for the CS:APP data lab
#
CC = gcc
CFLAGS = -O -Wall -m32
LIBS = -lm
all: btest fshow ishow
btest: btest.c bits.c decl.c tests.c btest.h bits.h
$(CC) $(CFLAGS) $(LIBS) -o btest bits.c btest.c decl.c tests.c
fshow: fshow.c
$(CC) $(CFLAGS) -o fshow fshow.c
ishow: ishow.c
$(CC) $(CFLAGS) -o ishow ishow.c
# Forces a recompile. Used by the driver program.
btestexplicit:
$(CC) $(CFLAGS) $(LIBS) -o btest bits.c btest.c decl.c tests.c
clean:
rm -f *.o btest fshow ishow *~
oneshoot:
make clean; \
./dlc bits.c; \
make btest; \
./btest bits.c; \
make clean \

+ 0
- 140
LAB1/README View File

@ -1,140 +0,0 @@
***********************
The CS:APP Data Lab
Directions to Students
***********************
Your goal is to modify your copy of bits.c so that it passes all the
tests in btest without violating any of the coding guidelines.
*********
0. Files:
*********
Makefile - Makes btest, fshow, and ishow
README - This file
bits.c - The file you will be modifying and handing in
bits.h - Header file
btest.c - The main btest program
btest.h - Used to build btest
decl.c - Used to build btest
tests.c - Used to build btest
tests-header.c- Used to build btest
dlc* - Rule checking compiler binary (data lab compiler)
driver.pl* - Driver program that uses btest and dlc to autograde bits.c
Driverhdrs.pm - Header file for optional "Beat the Prof" contest
fshow.c - Utility for examining floating-point representations
ishow.c - Utility for examining integer representations
***********************************************************
1. Modifying bits.c and checking it for compliance with dlc
***********************************************************
IMPORTANT: Carefully read the instructions in the bits.c file before
you start. These give the coding rules that you will need to follow if
you want full credit.
Use the dlc compiler (./dlc) to automatically check your version of
bits.c for compliance with the coding guidelines:
unix> ./dlc bits.c
dlc returns silently if there are no problems with your code.
Otherwise it prints messages that flag any problems. Running dlc with
the -e switch:
unix> ./dlc -e bits.c
causes dlc to print counts of the number of operators used by each function.
Once you have a legal solution, you can test it for correctness using
the ./btest program.
*********************
2. Testing with btest
*********************
The Makefile in this directory compiles your version of bits.c with
additional code to create a program (or test harness) named btest.
To compile and run the btest program, type:
unix> make btest
unix> ./btest [optional cmd line args]
You will need to recompile btest each time you change your bits.c
program. When moving from one platform to another, you will want to
get rid of the old version of btest and generate a new one. Use the
commands:
unix> make clean
unix> make btest
Btest tests your code for correctness by running millions of test
cases on each function. It tests wide swaths around well known corner
cases such as Tmin and zero for integer puzzles, and zero, inf, and
the boundary between denormalized and normalized numbers for floating
point puzzles. When btest detects an error in one of your functions,
it prints out the test that failed, the incorrect result, and the
expected result, and then terminates the testing for that function.
Here are the command line options for btest:
unix> ./btest -h
Usage: ./btest [-hg] [-r <n>] [-f <name> [-1|-2|-3 <val>]*] [-T <time limit>]
-1 <val> Specify first function argument
-2 <val> Specify second function argument
-3 <val> Specify third function argument
-f <name> Test only the named function
-g Format output for autograding with no error messages
-h Print this message
-r <n> Give uniform weight of n for all problems
-T <lim> Set timeout limit to lim
Examples:
Test all functions for correctness and print out error messages:
unix> ./btest
Test all functions in a compact form with no error messages:
unix> ./btest -g
Test function foo for correctness:
unix> ./btest -f foo
Test function foo for correctness with specific arguments:
unix> ./btest -f foo -1 27 -2 0xf
Btest does not check your code for compliance with the coding
guidelines. Use dlc to do that.
*******************
3. Helper Programs
*******************
We have included the ishow and fshow programs to help you decipher
integer and floating point representations respectively. Each takes a
single decimal or hex number as an argument. To build them type:
unix> make
Example usages:
unix> ./ishow 0x27
Hex = 0x00000027, Signed = 39, Unsigned = 39
unix> ./ishow 27
Hex = 0x0000001b, Signed = 27, Unsigned = 27
unix> ./fshow 0x15213243
Floating point value 3.255334057e-26
Bit Representation 0x15213243, sign = 0, exponent = 0x2a, fraction = 0x213243
Normalized. +1.2593463659 X 2^(-85)
linux> ./fshow 15213243
Floating point value 2.131829405e-38
Bit Representation 0x00e822bb, sign = 0, exponent = 0x01, fraction = 0x6822bb
Normalized. +1.8135598898 X 2^(-126)

+ 0
- 388
LAB1/bits.c View File

@ -1,388 +0,0 @@
/*
* CS:APP Data Lab
*
* <Please put your name and userid here>
*
* bits.c - Source file with your solutions to the Lab.
* This is the file you will hand in to your instructor.
*
* WARNING: Do not include the <stdio.h> header; it confuses the dlc
* compiler. You can still use printf for debugging without including
* <stdio.h>, although you might get a compiler warning. In general,
* it's not good practice to ignore compiler warnings, but in this
* case it's OK.
*/
#if 0
/*
* Instructions to Students:
*
* STEP 1: Read the following instructions carefully.
*/
You will provide your solution to the Data Lab by
editing the collection of functions in this source file.
INTEGER CODING RULES:
Replace the "return" statement in each function with one
or more lines of C code that implements the function. Your code
must conform to the following style:
int Funct(arg1, arg2, ...) {
/* brief description of how your implementation works */
int var1 = Expr1;
...
int varM = ExprM;
varJ = ExprJ;
...
varN = ExprN;
return ExprR;
}
Each "Expr" is an expression using ONLY the following:
1. Integer constants 0 through 255 (0xFF), inclusive. You are
not allowed to use big constants such as 0xffffffff.
2. Function arguments and local variables (no global variables).
3. Unary integer operations ! ~
4. Binary integer operations & ^ | + << >>
Some of the problems restrict the set of allowed operators even further.
Each "Expr" may consist of multiple operators. You are not restricted to
one operator per line.
You are expressly forbidden to:
1. Use any control constructs such as if, do, while, for, switch, etc.
2. Define or use any macros.
3. Define any additional functions in this file.
4. Call any functions.
5. Use any other operations, such as &&, ||, -, or ?:
6. Use any form of casting.
7. Use any data type other than int. This implies that you
cannot use arrays, structs, or unions.
You may assume that your machine:
1. Uses 2s complement, 32-bit representations of integers.
2. Performs right shifts arithmetically.
3. Has unpredictable behavior when shifting if the shift amount
is less than 0 or greater than 31.
EXAMPLES OF ACCEPTABLE CODING STYLE:
/*
* pow2plus1 - returns 2^x + 1, where 0 <= x <= 31
*/
int pow2plus1(int x) {
/* exploit ability of shifts to compute powers of 2 */
return (1 << x) + 1;
}
/*
* pow2plus4 - returns 2^x + 4, where 0 <= x <= 31
*/
int pow2plus4(int x) {
/* exploit ability of shifts to compute powers of 2 */
int result = (1 << x);
result += 4;
return result;
}
FLOATING POINT CODING RULES
For the problems that require you to implement floating-point operations,
the coding rules are less strict. You are allowed to use looping and
conditional control. You are allowed to use both ints and unsigneds.
You can use arbitrary integer and unsigned constants. You can use any arithmetic,
logical, or comparison operations on int or unsigned data.
You are expressly forbidden to:
1. Define or use any macros.
2. Define any additional functions in this file.
3. Call any functions.
4. Use any form of casting.
5. Use any data type other than int or unsigned. This means that you
cannot use arrays, structs, or unions.
6. Use any floating point data types, operations, or constants.
NOTES:
1. Use the dlc (data lab checker) compiler (described in the handout) to
check the legality of your solutions.
2. Each function has a maximum number of operations (integer, logical,
or comparison) that you are allowed to use for your implementation
of the function. The max operator count is checked by dlc.
Note that assignment ('=') is not counted; you may use as many of
these as you want without penalty.
3. Use the btest test harness to check your functions for correctness.
4. Use the BDD checker to formally verify your functions
5. The maximum number of ops for each function is given in the
header comment for each function. If there are any inconsistencies
between the maximum ops in the writeup and in this file, consider
this file the authoritative source.
/*
* STEP 2: Modify the following functions according the coding rules.
*
* IMPORTANT. TO AVOID GRADING SURPRISES:
* 1. Use the dlc compiler to check that your solutions conform
* to the coding rules.
* 2. Use the BDD checker to formally verify that your solutions produce
* the correct answers.
*/
#endif
/* Copyright (C) 1991-2020 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 Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This header is separate from features.h so that the compiler can
include it implicitly at the start of every compilation. It must
not itself include <features.h> or any other header that includes
<features.h> because the implicit include comes before any feature
test macros that may be defined in a source file before it first
explicitly includes a system header. GCC knows the name of this
header in order to preinclude it. */
/* glibc's intent is to support the IEC 559 math functionality, real
and complex. If the GCC (4.9 and later) predefined macros
specifying compiler intent are available, use them to determine
whether the overall intent is to support these features; otherwise,
presume an older compiler has intent to support these features and
define these macros by default. */
/* wchar_t uses Unicode 10.0.0. Version 10.0 of the Unicode Standard is
synchronized with ISO/IEC 10646:2017, fifth edition, plus
the following additions from Amendment 1 to the fifth edition:
- 56 emoji characters
- 285 hentaigana
- 3 additional Zanabazar Square characters */
//1
/*
* bitXor - x^y using only ~ and &
* Example: bitXor(4, 5) = 1
* Legal ops: ~ &
* Max ops: 14
* Rating: 1
*/
int bitXor(int x, int y) {
return ~(~x&~y)&~(x&y);
}
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return 0x1<<31;
}
//2
/*
* isTmax - returns 1 if x is the maximum, two's complement number,
* and 0 otherwise
* Legal ops: ! ~ & ^ | +
* Max ops: 10
* Rating: 1
*/
int isTmax(int x) {
int i =x+1;
x = x+i;
x = ~x;
i = !i;
x = x+i;
return !x;
}
/*
* allOddBits - return 1 if all odd-numbered bits in word set to 1
* where bits are numbered from 0 (least significant) to 31 (most significant)
* Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 12
* Rating: 2
*/
int allOddBits(int x) {
int a = 0xaaaaaaaa;
return !((a&x)^a);
}
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return ~x+1;
}
//3
/*
* isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
* Example: isAsciiDigit(0x35) = 1.
* isAsciiDigit(0x3a) = 0.
* isAsciiDigit(0x05) = 0.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 3
*/
int isAsciiDigit(int x) {
//
//
int downstream = ~0x30+1;
int upstream = ~0x39;
int leftside = !((downstream+x)>>31); //0x300
int rightside = !!((upstream+x)>>31); //0x391
return leftside&rightside;
}
/*
* conditional - same as x ? y : z
* Example: conditional(2,4,5) = 4
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 16
* Rating: 3
*/
int conditional(int x, int y, int z) {
x = !!(x);
x = ~x+1;
return (x&y)|(~x&z);
}
/*
* isLessOrEqual - if x <= y then return 1, else return 0
* Example: isLessOrEqual(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
int isLessOrEqual(int x, int y) {
int tmp = ~y+1;
tmp = tmp+x-1;
tmp = tmp >> 31;//y大0y小等于1
return !!tmp;
}
//4
/*
* logicalNeg - implement the ! operator, using all of
* the legal operators except !
* Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
* Legal ops: ~ & ^ | + << >>
* Max ops: 12
* Rating: 4
*/
int logicalNeg(int x) {
return ((x|(~x+1))>>31)+1;
}
/* howManyBits - return the minimum number of bits required to represent x in
* two's complement
* Examples: howManyBits(12) = 5
* howManyBits(298) = 10
* howManyBits(-5) = 4
* howManyBits(0) = 1
* howManyBits(-1) = 1
* howManyBits(0x80000000) = 32
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 90
* Rating: 4
*/
int howManyBits(int x) {
x = ((~(x>>31))&x)|(x>>31&~x);//
//
int tf = !!(x>>16); //1601
int b16 = tf << 4; //16b16为16016
x = x>>b16; //b16位16161616
tf = !!(x>>8); //8,
int b8 = tf << 3;//8b8为808
x = x>>b8;
tf = !!(x>>4);
int b4 = tf << 2 ; //84,4b4为404
x = x>>b4;
tf = !!(x>>2);
int b2 = tf << 1; //42,2b2为202
x = x>>b2;
tf = !!(x>>1); //211b1为101
int b1 = tf << 0;
x = x>>b1;
int b0 = x;//,1,0
return b0+b1+b2+b4+b8+b16+1; //+11
}
//float
/*
* floatScale2 - Return bit-level equivalent of expression 2*f for
* floating point argument f.
* Both the argument and result are passed as unsigned int's, but
* they are to be interpreted as the bit-level representation of
* single-precision floating point values.
* When argument is NaN, return argument
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
unsigned floatScale2(unsigned uf) {
unsigned sign = (0x80000000)&uf;
unsigned exp = (0x7f800000)&uf;
unsigned frac = (0x007fffff)&uf;
if(exp == 0x7f800000)
return uf; //exp全为255,frac全是0就是无穷NaNreturn
if(exp == 0x00000000){
if(frac == 0x00000000)
return uf; //exp全为0,frac全为000*2=0
return (frac<<1)|sign|exp;//exp全为0,frac不全为0frac第一位为1时exp变为非全0
}
return (exp+0x00800000)|sign|frac;
}
/*
* floatFloat2Int - Return bit-level equivalent of expression (int) f
* for floating point argument f.
* Argument is passed as unsigned int, but
* it is to be interpreted as the bit-level representation of a
* single-precision floating point value.
* Anything out of range (including NaN and infinity) should return
* 0x80000000u.
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
int floatFloat2Int(unsigned uf) {
unsigned sign = ((0x80000000)&uf)>>31;
unsigned exp = ((0x7f800000)&uf)>>23;
unsigned frac = (0x007fffff)&uf;
unsigned base = (frac+0x00800000);//1
int bias = (exp-127)-23;//
if(sign==0)
sign = 1;
else
sign = -1;
if(exp == 255)
return 0x80000000u;//
if(exp == 0)
return 0;//
if(bias <=0){
if(bias<=-24)
bias = -24;
return sign*(base>>(-bias));
}
else{
if(bias>=9)
return 0x80000000u;
return sign*(base<<bias);
}
}
// #include "floatPower2.c"

+ 0
- 65
LAB1/bits.h View File

@ -1,65 +0,0 @@
/* Copyright (C) 1991-2020 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 Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This header is separate from features.h so that the compiler can
include it implicitly at the start of every compilation. It must
not itself include <features.h> or any other header that includes
<features.h> because the implicit include comes before any feature
test macros that may be defined in a source file before it first
explicitly includes a system header. GCC knows the name of this
header in order to preinclude it. */
/* glibc's intent is to support the IEC 559 math functionality, real
and complex. If the GCC (4.9 and later) predefined macros
specifying compiler intent are available, use them to determine
whether the overall intent is to support these features; otherwise,
presume an older compiler has intent to support these features and
define these macros by default. */
/* wchar_t uses Unicode 10.0.0. Version 10.0 of the Unicode Standard is
synchronized with ISO/IEC 10646:2017, fifth edition, plus
the following additions from Amendment 1 to the fifth edition:
- 56 emoji characters
- 285 hentaigana
- 3 additional Zanabazar Square characters */
//1
int bitXor(int, int);
int test_bitXor(int, int);
int tmin();
int test_tmin();
//2
int isTmax(int);
int test_isTmax(int);
int allOddBits();
int test_allOddBits();
int negate(int);
int test_negate(int);
//3
int isAsciiDigit(int);
int test_isAsciiDigit(int);
int conditional(int, int, int);
int test_conditional(int, int, int);
int isLessOrEqual(int, int);
int test_isLessOrEqual(int, int);
//4
int logicalNeg(int);
int test_logicalNeg(int);
int howManyBits(int);
int test_howManyBits(int);
//float
unsigned floatScale2(unsigned);
unsigned test_floatScale2(unsigned);
int floatFloat2Int(unsigned);
int test_floatFloat2Int(unsigned);
// #include "floatPower2.c"

+ 0
- 583
LAB1/btest.c View File

@ -1,583 +0,0 @@
/*
* CS:APP Data Lab
*
* btest.c - A test harness that checks a student's solution in bits.c
* for correctness.
*
* Copyright (c) 2001-2011, R. Bryant and D. O'Hallaron, All rights
* reserved. May not be used, modified, or copied without permission.
*
* This is an improved version of btest that tests large windows
* around zero and tmin and tmax for integer puzzles, and zero, norm,
* and denorm boundaries for floating point puzzles.
*
* Note: not 64-bit safe. Always compile with gcc -m32 option.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <signal.h>
#include <setjmp.h>
#include <math.h>
#include "btest.h"
/* Not declared in some stdlib.h files, so define here */
float strtof(const char *nptr, char **endptr);
/*************************
* Configuration Constants
*************************/
/* Handle infinite loops by setting upper limit on execution time, in
seconds */
#define TIMEOUT_LIMIT 10
/* For functions with a single argument, generate TEST_RANGE values
above and below the min and max test values, and above and below
zero. Functions with two or three args will use square and cube
roots of this value, respectively, to avoid combinatorial
explosion */
#define TEST_RANGE 500000
/* This defines the maximum size of any test value array. The
gen_vals() routine creates k test values for each value of
TEST_RANGE, thus MAX_TEST_VALS must be at least k*TEST_RANGE */
#define MAX_TEST_VALS 13*TEST_RANGE
/**********************************
* Globals defined in other modules
**********************************/
/* This characterizes the set of puzzles to test.
Defined in decl.c and generated from templates in ./puzzles dir */
extern test_rec test_set[];
/************************************************
* Write-once globals defined by command line args
************************************************/
/* Emit results in a format for autograding, without showing
and counter-examples */
static int grade = 0;
/* Time out after this number of seconds */
static int timeout_limit = TIMEOUT_LIMIT; /* -T */
/* If non-NULL, test only one function (-f) */
static char* test_fname = NULL;
/* Special case when only use fixed argument(s) (-1, -2, or -3) */
static int has_arg[3] = {0,0,0};
static unsigned argval[3] = {0,0,0};
/* Use fixed weight for rating, and if so, what should it be? (-r) */
static int global_rating = 0;
/******************
* Helper functions
******************/
/*
* Signal - installs a signal handler
*/
typedef void handler_t(int);
handler_t *Signal(int signum, handler_t *handler)
{
struct sigaction action, old_action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask); /* block sigs of type being handled */
action.sa_flags = SA_RESTART; /* restart syscalls if possible */
if (sigaction(signum, &action, &old_action) < 0)
perror("Signal error");
return (old_action.sa_handler);
}
/*
* timeout_handler - SIGALARM hander
*/
sigjmp_buf envbuf;
void timeout_handler(int sig) {
siglongjmp(envbuf, 1);
}
/*
* random_val - Return random integer value between min and max
*/
static int random_val(int min, int max)
{
double weight = rand()/(double) RAND_MAX;
int result = min * (1-weight) + max * weight;
return result;
}
/*
* gen_vals - Generate the integer values we'll use to test a function
*/
static int gen_vals(int test_vals[], int min, int max, int test_range, int arg)
{
int i;
int test_count = 0;
/* Special case: If the user has specified a specific function
argument using the -1, -2, or -3 flags, then simply use this
argument and return */
if (has_arg[arg]) {
test_vals[0] = argval[arg];
return 1;
}
/*
* Special case: Generate test vals for floating point functions
* where the input argument is an unsigned bit-level
* representation of a float. For this case we want to test the
* regions around zero, the smallest normalized and largest
* denormalized numbers, one, and the largest normalized number,
* as well as inf and nan.
*/
if ((min == 1 && max == 1)) {
unsigned smallest_norm = 0x00800000;
unsigned one = 0x3f800000;
unsigned largest_norm = 0x7f000000;
unsigned inf = 0x7f800000;
unsigned nan = 0x7fc00000;
unsigned sign = 0x80000000;
/* Test range should be at most 1/2 the range of one exponent
value */
if (test_range > (1 << 23)) {
test_range = 1 << 23;
}
/* Functions where the input argument is an unsigned bit-level
representation of a float. The number of tests generated
inside this loop body is the value k referenced in the
comment for the global variable MAX_TEST_VALS. */
for (i = 0; i < test_range; i++) {
/* Denorms around zero */
test_vals[test_count++] = i;
test_vals[test_count++] = sign | i;
/* Region around norm to denorm transition */
test_vals[test_count++] = smallest_norm + i;
test_vals[test_count++] = smallest_norm - i;
test_vals[test_count++] = sign | (smallest_norm + i);
test_vals[test_count++] = sign | (smallest_norm - i);
/* Region around one */
test_vals[test_count++] = one + i;
test_vals[test_count++] = one - i;
test_vals[test_count++] = sign | (one + i);
test_vals[test_count++] = sign | (one - i);
/* Region below largest norm */
test_vals[test_count++] = largest_norm - i;
test_vals[test_count++] = sign | (largest_norm - i);
}
/* special vals */
test_vals[test_count++] = inf; /* inf */
test_vals[test_count++] = sign | inf; /* -inf */
test_vals[test_count++] = nan; /* nan */
test_vals[test_count++] = sign | nan; /* -nan */
return test_count;
}
/*
* Normal case: Generate test vals for integer functions
*/
/* If the range is small enough, then do exhaustively */
if (max - MAX_TEST_VALS <= min) {
for (i = min; i <= max; i++)
test_vals[test_count++] = i;
return test_count;
}
/* Otherwise, need to sample. Do so near the boundaries, around
zero, and for some random cases. */
for (i = 0; i < test_range; i++) {
/* Test around the boundaries */
test_vals[test_count++] = min + i;
test_vals[test_count++] = max - i;
/* If zero falls between min and max, then also test around zero */
if (i >= min && i <= max)
test_vals[test_count++] = i;
if (-i >= min && -i <= max)
test_vals[test_count++] = -i;
/* Random case between min and max */
test_vals[test_count++] = random_val(min, max);
}
return test_count;
}
/*
* test_0_arg - Test a function with zero arguments
*/
static int test_0_arg(funct_t f, funct_t ft, char *name)
{
int r = f();
int rt = ft();
int error = (r != rt);
if (error && !grade)
printf("ERROR: Test %s() failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, r, r, rt, rt);
return error;
}
/*
* test_1_arg - Test a function with one argument
*/
static int test_1_arg(funct_t f, funct_t ft, int arg1, char *name)
{
funct1_t f1 = (funct1_t) f;
funct1_t f1t = (funct1_t) ft;
int r, rt, error;
r = f1(arg1);
rt = f1t(arg1);
error = (r != rt);
if (error && !grade)
printf("ERROR: Test %s(%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, r, r, rt, rt);
return error;
}
/*
* test_2_arg - Test a function with two arguments
*/
static int test_2_arg(funct_t f, funct_t ft, int arg1, int arg2, char *name)
{
funct2_t f2 = (funct2_t) f;
funct2_t f2t = (funct2_t) ft;
int r = f2(arg1, arg2);
int rt = f2t(arg1, arg2);
int error = (r != rt);
if (error && !grade)
printf("ERROR: Test %s(%d[0x%x],%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, arg2, arg2, r, r, rt, rt);
return error;
}
/*
* test_3_arg - Test a function with three arguments
*/
static int test_3_arg(funct_t f, funct_t ft,
int arg1, int arg2, int arg3, char *name)
{
funct3_t f3 = (funct3_t) f;
funct3_t f3t = (funct3_t) ft;
int r = f3(arg1, arg2, arg3);
int rt = f3t(arg1, arg2, arg3);
int error = (r != rt);
if (error && !grade)
printf("ERROR: Test %s(%d[0x%x],%d[0x%x],%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, arg2, arg2, arg3, arg3, r, r, rt, rt);
return error;
}
/*
* test_function - Test a function. Return number of errors
*/
static int test_function(test_ptr t) {
int test_counts[3]; /* number of test values for each arg */
int args = t->args; /* number of function arguments */
int arg_test_range[3]; /* test range for each argument */
int i, a1, a2, a3;
int errors = 0;
/* These are the test values for each arg. Declared with the
static attribute so that the array will be allocated in bss
rather than the stack */
static int arg_test_vals[3][MAX_TEST_VALS];
/* Sanity check on the number of args */
if (args < 0 || args > 3) {
printf("Configuration error: invalid number of args (%d) for function %s\n", args, t->name);
exit(1);
}
/* Assign range of argument test vals so as to conserve the total
number of tests, independent of the number of arguments */
if (args == 1) {
arg_test_range[0] = TEST_RANGE;
}
else if (args == 2) {
arg_test_range[0] = pow((double)TEST_RANGE, 0.5); /* sqrt */
arg_test_range[1] = arg_test_range[0];
}
else {
arg_test_range[0] = pow((double)TEST_RANGE, 0.333); /* cbrt */
arg_test_range[1] = arg_test_range[0];
arg_test_range[2] = arg_test_range[0];
}
/* Sanity check on the ranges */
if (arg_test_range[0] < 1)
arg_test_range[0] = 1;
if (arg_test_range[1] < 1)
arg_test_range[1] = 1;
if (arg_test_range[2] < 1)
arg_test_range[2] = 1;
/* Create a test set for each argument */
for (i = 0; i < args; i++) {
test_counts[i] = gen_vals(arg_test_vals[i],
t->arg_ranges[i][0], /* min */
t->arg_ranges[i][1], /* max */
arg_test_range[i],
i);
}
/* Handle timeouts in the test code */
if (timeout_limit > 0) {
int rc;
rc = sigsetjmp(envbuf, 1);
if (rc) {
/* control will reach here if there is a timeout */
errors = 1;
printf("ERROR: Test %s failed.\n Timed out after %d secs (probably infinite loop)\n", t->name, timeout_limit);
return errors;
}
alarm(timeout_limit);
}
/* Test function has no arguments */
if (args == 0) {
errors += test_0_arg(t->solution_funct, t->test_funct, t->name);
return errors;
}
/*
* Test function has at least one argument
*/
/* Iterate over the values for first argument */
for (a1 = 0; a1 < test_counts[0]; a1++) {
if (args == 1) {
errors += test_1_arg(t->solution_funct,
t->test_funct,
arg_test_vals[0][a1],
t->name);
/* Stop testing if there is an error */
if (errors)
return errors;
}
else {
/* if necessary, iterate over values for second argument */
for (a2 = 0; a2 < test_counts[1]; a2++) {
if (args == 2) {
errors += test_2_arg(t->solution_funct,
t->test_funct,
arg_test_vals[0][a1],
arg_test_vals[1][a2],
t->name);
/* Stop testing if there is an error */
if (errors)
return errors;
}
else {
/* if necessary, iterate over vals for third arg */
for (a3 = 0; a3 < test_counts[2]; a3++) {
errors += test_3_arg(t->solution_funct,
t->test_funct,
arg_test_vals[0][a1],
arg_test_vals[1][a2],
arg_test_vals[2][a3],
t->name);
/* Stop testing if there is an error */
if (errors)
return errors;
} /* a3 */
}
} /* a2 */
}
} /* a1 */
return errors;
}
/*
* run_tests - Run series of tests. Return number of errors
*/
static int run_tests()
{
int i;
int errors = 0;
double points = 0.0;
double max_points = 0.0;
printf("Score\tRating\tErrors\tFunction\n");
for (i = 0; test_set[i].solution_funct; i++) {
int terrors;
double tscore;
double tpoints;
if (!test_fname || strcmp(test_set[i].name,test_fname) == 0) {
int rating = global_rating ? global_rating : test_set[i].rating;
terrors = test_function(&test_set[i]);
errors += terrors;
tscore = terrors == 0 ? 1.0 : 0.0;
tpoints = rating * tscore;
points += tpoints;
max_points += rating;
if (grade || terrors < 1)
printf(" %.0f\t%d\t%d\t%s\n",
tpoints, rating, terrors, test_set[i].name);
}
}
printf("Total points: %.0f/%.0f\n", points, max_points);
return errors;
}
/*
* get_num_val - Extract hex/decimal/or float value from string
*/
static int get_num_val(char *sval, unsigned *valp) {
char *endp;
/* See if it's an integer or floating point */
int ishex = 0;
int isfloat = 0;
int i;
for (i = 0; sval[i]; i++) {
switch (sval[i]) {
case 'x':
case 'X':
ishex = 1;
break;
case 'e':
case 'E':
if (!ishex)
isfloat = 1;
break;
case '.':
isfloat = 1;
break;
default:
break;
}
}
if (isfloat) {
float fval = strtof(sval, &endp);
if (!*endp) {
*valp = *(unsigned *) &fval;
return 1;
}
return 0;
} else {
long long int llval = strtoll(sval, &endp, 0);
long long int upperbits = llval >> 31;
/* will give -1 for negative, 0 or 1 for positive */
if (!*valp && (upperbits == 0 || upperbits == -1 || upperbits == 1)) {
*valp = (unsigned) llval;
return 1;
}
return 0;
}
}
/*
* usage - Display usage info
*/
static void usage(char *cmd) {
printf("Usage: %s [-hg] [-r <n>] [-f <name> [-1|-2|-3 <val>]*] [-T <time limit>]\n", cmd);
printf(" -1 <val> Specify first function argument\n");
printf(" -2 <val> Specify second function argument\n");
printf(" -3 <val> Specify third function argument\n");
printf(" -f <name> Test only the named function\n");
printf(" -g Compact output for grading (with no error msgs)\n");
printf(" -h Print this message\n");
printf(" -r <n> Give uniform weight of n for all problems\n");
printf(" -T <lim> Set timeout limit to lim\n");
exit(1);
}
/**************
* Main routine
**************/
int main(int argc, char *argv[])
{
char c;
/* parse command line args */
while ((c = getopt(argc, argv, "hgf:r:T:1:2:3:")) != -1)
switch (c) {
case 'h': /* help */
usage(argv[0]);
break;
case 'g': /* grading option for autograder */
grade = 1;
break;
case 'f': /* test only one function */
test_fname = strdup(optarg);
break;
case 'r': /* set global rating for each problem */
global_rating = atoi(optarg);
if (global_rating < 0)
usage(argv[0]);
break;
case '1': /* Get first argument */
has_arg[0] = get_num_val(optarg, &argval[0]);
if (!has_arg[0]) {
printf("Bad argument '%s'\n", optarg);
exit(0);
}
break;
case '2': /* Get first argument */
has_arg[1] = get_num_val(optarg, &argval[1]);
if (!has_arg[1]) {
printf("Bad argument '%s'\n", optarg);
exit(0);
}
break;
case '3': /* Get first argument */
has_arg[2] = get_num_val(optarg, &argval[2]);
if (!has_arg[2]) {
printf("Bad argument '%s'\n", optarg);
exit(0);
}
break;
case 'T': /* Set timeout limit */
timeout_limit = atoi(optarg);
break;
default:
usage(argv[0]);
}
if (timeout_limit > 0) {
Signal(SIGALRM, timeout_handler);
}
/* test each function */
run_tests();
return 0;
}

+ 0
- 32
LAB1/btest.h View File

@ -1,32 +0,0 @@
/*
* CS:APP Data Lab
*/
/* Declare different function types */
typedef int (*funct_t) (void);
typedef int (*funct1_t)(int);
typedef int (*funct2_t)(int, int);
typedef int (*funct3_t)(int, int, int);
/* Combine all the information about a function and its tests as structure */
typedef struct {
char *name; /* String name */
funct_t solution_funct; /* Function */
funct_t test_funct; /* Test function */
int args; /* Number of function arguments */
char *ops; /* List of legal operators. Special case: "$" for floating point */
int op_limit; /* Max number of ops allowed in solution */
int rating; /* Problem rating (1 -- 4) */
int arg_ranges[3][2]; /* Argument ranges. Always defined for 3 args, even if */
/* the function takes fewer. Special case: First arg */
/* must be set to {1,1} for f.p. puzzles */
} test_rec, *test_ptr;
extern test_rec test_set[];

+ 0
- 86
LAB1/decl.c View File

@ -1,86 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define TMin INT_MIN
#define TMax INT_MAX
#include "btest.h"
#include "bits.h"
test_rec test_set[] = {
/* Copyright (C) 1991-2020 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 Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This header is separate from features.h so that the compiler can
include it implicitly at the start of every compilation. It must
not itself include <features.h> or any other header that includes
<features.h> because the implicit include comes before any feature
test macros that may be defined in a source file before it first
explicitly includes a system header. GCC knows the name of this
header in order to preinclude it. */
/* glibc's intent is to support the IEC 559 math functionality, real
and complex. If the GCC (4.9 and later) predefined macros
specifying compiler intent are available, use them to determine
whether the overall intent is to support these features; otherwise,
presume an older compiler has intent to support these features and
define these macros by default. */
/* wchar_t uses Unicode 10.0.0. Version 10.0 of the Unicode Standard is
synchronized with ISO/IEC 10646:2017, fifth edition, plus
the following additions from Amendment 1 to the fifth edition:
- 56 emoji characters
- 285 hentaigana
- 3 additional Zanabazar Square characters */
//1
{"bitXor", (funct_t) bitXor, (funct_t) test_bitXor, 2, "& ~", 14, 1,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"tmin", (funct_t) tmin, (funct_t) test_tmin, 0, "! ~ & ^ | + << >>", 4, 1,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
//2
{"isTmax", (funct_t) isTmax, (funct_t) test_isTmax, 1, "! ~ & ^ | +", 10, 1,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"allOddBits", (funct_t) allOddBits, (funct_t) test_allOddBits, 1,
"! ~ & ^ | + << >>", 12, 2,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"negate", (funct_t) negate, (funct_t) test_negate, 1,
"! ~ & ^ | + << >>", 5, 2,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
//3
{"isAsciiDigit", (funct_t) isAsciiDigit, (funct_t) test_isAsciiDigit, 1,
"! ~ & ^ | + << >>", 15, 3,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"conditional", (funct_t) conditional, (funct_t) test_conditional, 3, "! ~ & ^ | << >>", 16, 3,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"isLessOrEqual", (funct_t) isLessOrEqual, (funct_t) test_isLessOrEqual, 2,
"! ~ & ^ | + << >>", 24, 3,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
//4
{"logicalNeg", (funct_t) logicalNeg, (funct_t) test_logicalNeg, 1,
"~ & ^ | + << >>", 12, 4,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"howManyBits", (funct_t) howManyBits, (funct_t) test_howManyBits, 1, "! ~ & ^ | + << >>", 90, 4,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
//float
{"floatScale2", (funct_t) floatScale2, (funct_t) test_floatScale2, 1,
"$", 30, 4,
{{1, 1},{1,1},{1,1}}},
{"floatFloat2Int", (funct_t) floatFloat2Int, (funct_t) test_floatFloat2Int, 1,
"$", 30, 4,
{{1, 1},{1,1},{1,1}}},
// #include "floatPower2.c"
{"", NULL, NULL, 0, "", 0, 0,
{{0, 0},{0,0},{0,0}}}
};

+ 0
- 0
LAB1/dlc View File


+ 0
- 439
LAB1/driver.pl View File

@ -1,439 +0,0 @@
#!/usr/bin/perl
#######################################################################
# driver.pl - CS:APP Data Lab driver
#
# Copyright (c) 2004-2011, R. Bryant and D. O'Hallaron, All rights
# reserved. May not be used, modified, or copied without permission.
#
# Note: The driver can use either btest or the BDD checker to check
# puzzles for correctness. This version of the lab uses btest, which
# has been extended to do better testing of both integer and
# floating-point puzzles.
#
#######################################################################
use strict 'vars';
use Getopt::Std;
use lib ".";
use Driverlib;
# Set to 1 to use btest, 0 to use the BDD checker.
my $USE_BTEST = 1;
# Generic settings
$| = 1; # Flush stdout each time
umask(0077); # Files created by the user in tmp readable only by that user
$ENV{PATH} = "/usr/local/bin:/usr/bin:/bin";
#
# usage - print help message and terminate
#
sub usage {
printf STDERR "$_[0]\n";
printf STDERR "Usage: $0 [-h] [-u \"nickname\"]\n";
printf STDERR "Options:\n";
printf STDERR " -h Print this message.\n";
printf STDERR " -u \"nickname\" Send autoresult to server, using nickname on scoreboard)\n";
die "\n";
}
##############
# Main routine
##############
my $login = getlogin() || (getpwuid($<))[0] || "unknown";
my $tmpdir = "/var/tmp/datalab.$login.$$";
my $diemsg = "The files are in $tmpdir.";
my $driverfiles;
my $infile;
my $autograded;
my $status;
my $inpuzzles;
my $puzzlecnt;
my $line;
my $blank;
my $name;
my $c_points;
my $c_rating;
my $c_errors;
my $p_points;
my $p_rating;
my $p_errors;
my $total_c_points;
my $total_c_rating;
my $total_p_points;
my $total_p_rating;
my $tops;
my $tpoints;
my $trating;
my $foo;
my $name;
my $msg;
my $nickname;
my $autoresult;
my %puzzle_c_points;
my %puzzle_c_rating;
my %puzzle_c_errors;
my %puzzle_p_points;
my %puzzle_p_ops;
my %puzzle_p_maxops;
my %puzzle_number;
# Parse the command line arguments
no strict;
getopts('hu:f:A');
if ($opt_h) {
usage();
}
# The default input file is bits.c (change with -f)
$infile = "bits.c";
$nickname = "";
#####
# These are command line args that every driver must support
#
# Causes the driver to send an autoresult to the server on behalf of user
if ($opt_u) {
$nickname = $opt_u;
check_nickname($nickname);
}
# Hidden flag that indicates that the driver was invoked by an autograder
if ($opt_A) {
$autograded = $opt_A;
}
#####
# Drivers can also define an arbitary number of other command line args
#
# Optional hidden flag used by the autograder
if ($opt_f) {
$infile = $opt_f;
}
use strict 'vars';
################################################
# Compute the correctness and performance scores
################################################
# Make sure that an executable dlc (data lab compiler) exists
(-e "./dlc" and -x "./dlc")
or die "$0: ERROR: No executable dlc binary.\n";
# If using the bdd checker, then make sure it exists
if (!$USE_BTEST) {
(-e "./bddcheck/cbit/cbit" and -x "./bddcheck/cbit/cbit")
or die "$0: ERROR: No executable cbit binary.\n";
}
#
# Set up the contents of the scratch directory
#
system("mkdir $tmpdir") == 0
or die "$0: Could not make scratch directory $tmpdir.\n";
# Copy the student's work to the scratch directory
unless (system("cp $infile $tmpdir/bits.c") == 0) {
clean($tmpdir);
die "$0: Could not copy file $infile to scratch directory $tmpdir.\n";
}
# Copy the various autograding files to the scratch directory
if ($USE_BTEST) {
$driverfiles = "Makefile dlc btest.c decl.c tests.c btest.h bits.h";
unless (system("cp -r $driverfiles $tmpdir") == 0) {
clean($tmpdir);
die "$0: Could not copy autogradingfiles to $tmpdir.\n";
}
}
else {
$driverfiles = "dlc tests.c bddcheck";
unless (system("cp -r $driverfiles $tmpdir") == 0) {
clean($tmpdir);
die "$0: Could not copy support files to $tmpdir.\n";
}
}
# Change the current working directory to the scratch directory
unless (chdir($tmpdir)) {
clean($tmpdir);
die "$0: Could not change directory to $tmpdir.\n";
}
#
# Generate a zapped (for coding rules) version of bits.c. In this
# zapped version of bits.c, any functions with illegal operators are
# transformed to have empty function bodies.
#
print "1. Running './dlc -z' to identify coding rules violations.\n";
system("cp bits.c save-bits.c") == 0
or die "$0: ERROR: Could not create backup copy of bits.c. $diemsg\n";
system("./dlc -z -o zap-bits.c bits.c") == 0
or die "$0: ERROR: zapped bits.c did not compile. $diemsg\n";
#
# Run btest or BDD checker to determine correctness score
#
if ($USE_BTEST) {
print "\n2. Compiling and running './btest -g' to determine correctness score.\n";
system("cp zap-bits.c bits.c");
# Compile btest
system("make btestexplicit") == 0
or die "$0: Could not make btest in $tmpdir. $diemsg\n";
# Run btest
$status = system("./btest -g > btest-zapped.out 2>&1");
if ($status != 0) {
die "$0: ERROR: btest check failed. $diemsg\n";
}
}
else {
print "\n2. Running './bddcheck/check.pl -g' to determine correctness score.\n";
system("cp zap-bits.c bits.c");
$status = system("./bddcheck/check.pl -g > btest-zapped.out 2>&1");
if ($status != 0) {
die "$0: ERROR: BDD check failed. $diemsg\n";
}
}
#
# Run dlc to identify operator count violations.
#
print "\n3. Running './dlc -Z' to identify operator count violations.\n";
system("./dlc -Z -o Zap-bits.c save-bits.c") == 0
or die "$0: ERROR: dlc unable to generated Zapped bits.c file.\n";
#
# Run btest or the bdd checker to compute performance score
#
if ($USE_BTEST) {
print "\n4. Compiling and running './btest -g -r 2' to determine performance score.\n";
system("cp Zap-bits.c bits.c");
# Compile btest
system("make btestexplicit") == 0
or die "$0: Could not make btest in $tmpdir. $diemsg\n";
print "\n";
# Run btest
$status = system("./btest -g -r 2 > btest-Zapped.out 2>&1");
if ($status != 0) {
die "$0: ERROR: Zapped btest failed. $diemsg\n";
}
}
else {
print "\n4. Running './bddcheck/check.pl -g -r 2' to determine performance score.\n";
system("cp Zap-bits.c bits.c");
$status = system("./bddcheck/check.pl -g -r 2 > btest-Zapped.out 2>&1");
if ($status != 0) {
die "$0: ERROR: Zapped bdd checker failed. $diemsg\n";
}
}
#
# Run dlc to get the operator counts on the zapped input file
#
print "\n5. Running './dlc -e' to get operator count of each function.\n";
$status = system("./dlc -W1 -e zap-bits.c > dlc-opcount.out 2>&1");
if ($status != 0) {
die "$0: ERROR: bits.c did not compile. $diemsg\n";
}
#################################################################
# Collect the correctness and performance results for each puzzle
#################################################################
#
# Collect the correctness results
#
%puzzle_c_points = (); # Correctness score computed by btest
%puzzle_c_errors = (); # Correctness error discovered by btest
%puzzle_c_rating = (); # Correctness puzzle rating (max points)
$inpuzzles = 0; # Becomes true when we start reading puzzle results
$puzzlecnt = 0; # Each puzzle gets a unique number
$total_c_points = 0;
$total_c_rating = 0;
open(INFILE, "$tmpdir/btest-zapped.out")
or die "$0: ERROR: could not open input file $tmpdir/btest-zapped.out\n";
while ($line = <INFILE>) {
chomp($line);
# Notice that we're ready to read the puzzle scores
if ($line =~ /^Score/) {
$inpuzzles = 1;
next;
}
# Notice that we're through reading the puzzle scores
if ($line =~ /^Total/) {
$inpuzzles = 0;
next;
}
# Read and record a puzzle's name and score
if ($inpuzzles) {
($blank, $c_points, $c_rating, $c_errors, $name) = split(/\s+/, $line);
$puzzle_c_points{$name} = $c_points;
$puzzle_c_errors{$name} = $c_errors;
$puzzle_c_rating{$name} = $c_rating;
$puzzle_number{$name} = $puzzlecnt++;
$total_c_points += $c_points;
$total_c_rating += $c_rating;
}
}
close(INFILE);
#
# Collect the performance results
#
%puzzle_p_points = (); # Performance points
$inpuzzles = 0; # Becomes true when we start reading puzzle results
$total_p_points = 0;
$total_p_rating = 0;
open(INFILE, "$tmpdir/btest-Zapped.out")
or die "$0: ERROR: could not open input file $tmpdir/btest-Zapped.out\n";
while ($line = <INFILE>) {
chomp($line);
# Notice that we're ready to read the puzzle scores
if ($line =~ /^Score/) {
$inpuzzles = 1;
next;
}
# Notice that we're through reading the puzzle scores
if ($line =~ /^Total/) {
$inpuzzles = 0;
next;
}
# Read and record a puzzle's name and score
if ($inpuzzles) {
($blank, $p_points, $p_rating, $p_errors, $name) = split(/\s+/, $line);
$puzzle_p_points{$name} = $p_points;
$total_p_points += $p_points;
$total_p_rating += $p_rating;
}
}
close(INFILE);
#
# Collect the operator counts generated by dlc
#
open(INFILE, "$tmpdir/dlc-opcount.out")
or die "$0: ERROR: could not open input file $tmpdir/dlc-opcount.out\n";
$tops = 0;
while ($line = <INFILE>) {
chomp($line);
if ($line =~ /(\d+) operators/) {
($foo, $foo, $foo, $name, $msg) = split(/:/, $line);
$puzzle_p_ops{$name} = $1;
$tops += $1;
}
}
close(INFILE);
#
# Print a table of results sorted by puzzle number
#
print "\n";
printf("%s\t%s\n", "Correctness Results", "Perf Results");
printf("%s\t%s\t%s\t%s\t%s\t%s\n", "Points", "Rating", "Errors",
"Points", "Ops", "Puzzle");
foreach $name (sort {$puzzle_number{$a} <=> $puzzle_number{$b}}
keys %puzzle_number) {
printf("%d\t%d\t%d\t%d\t%d\t\%s\n",
$puzzle_c_points{$name},
$puzzle_c_rating{$name},
$puzzle_c_errors{$name},
$puzzle_p_points{$name},
$puzzle_p_ops{$name},
$name);
}
$tpoints = $total_c_points + $total_p_points;
$trating = $total_c_rating + $total_p_rating;
print "\nScore = $tpoints/$trating [$total_c_points/$total_c_rating Corr + $total_p_points/$total_p_rating Perf] ($tops total operators)\n";
#
# Optionally send the autoresult to the contest server if the driver
# was called with the -u command line flag.
#
if ($nickname) {
# Generate the autoresult
$autoresult = "$tpoints|$total_c_points|$total_p_points|$tops";
foreach $name (sort {$puzzle_number{$a} <=> $puzzle_number{$b}}
keys %puzzle_number) {
$autoresult .= " |$name:$puzzle_c_points{$name}:$puzzle_c_rating{$name}:$puzzle_p_points{$name}:$puzzle_p_ops{$name}";
}
# Post the autoresult to the server. The Linux login id is
# concatenated with the user-supplied nickname for some (very) loose
# authentication of submissions.
&Driverlib::driver_post("$login:$nickname", $autoresult, $autograded);
}
# Clean up and exit
clean ($tmpdir);
exit;
##################
# Helper functions
#
#
# check_nickname - Check a nickname for legality
#
sub check_nickname {
my $nickname = shift;
# Nicknames can't be empty
if (length($nickname) < 1) {
die "$0: Error: Empty nickname.\n";
}
# Nicknames can't be too long
if (length($nickname) > 35) {
die "$0: Error: Nickname exceeds 35 characters.\n";
}
# Nicknames can have restricted set of metacharacters (e.g., no #
# HTML tags)
if (!($nickname =~ /^[_-\w.,'@ ]+$/)) {
die "$0: Error: Illegal character in nickname. Only alphanumerics, apostrophes, commas, periods, dashes, underscores, and ampersands are allowed.\n";
}
# Nicknames can't be all whitespace
if ($nickname =~ /^\s*$/) {
die "$0: Error: Nickname is all whitespace.\n";
}
}
#
# clean - remove the scratch directory
#
sub clean {
my $tmpdir = shift;
system("rm -rf $tmpdir");
}

+ 0
- 151
LAB1/fshow.c View File

@ -1,151 +0,0 @@
/* Display structure of floating-point numbers */
#include <stdio.h>
#include <stdlib.h>
float strtof(const char *nptr, char **endptr);
#define FLOAT_SIZE 32
#define FRAC_SIZE 23
#define EXP_SIZE 8
#define BIAS ((1<<(EXP_SIZE-1))-1)
#define FRAC_MASK ((1<<FRAC_SIZE)-1)
#define EXP_MASK ((1<<EXP_SIZE)-1)
/* Floating point helpers */
unsigned f2u(float f)
{
union {
unsigned u;
float f;
} v;
v.u = 0;
v.f = f;
return v.u;
}
static float u2f(unsigned u)
{
union {
unsigned u;
float f;
} v;
v.u = u;
return v.f;
}
/* Get exponent */
unsigned get_exp(unsigned uf)
{
return (uf>>FRAC_SIZE) & EXP_MASK;
}
/* Get fraction */
unsigned get_frac(unsigned uf)
{
return uf & FRAC_MASK;
}
/* Get sign */
unsigned get_sign(unsigned uf)
{
return (uf>>(FLOAT_SIZE-1)) & 0x1;
}
void show_float(unsigned uf)
{
float f = u2f(uf);
unsigned exp = get_exp(uf);
unsigned frac = get_frac(uf);
unsigned sign = get_sign(uf);
printf("\nFloating point value %.10g\n", f);
printf("Bit Representation 0x%.8x, sign = %x, exponent = 0x%.2x, fraction = 0x%.6x\n",
uf, sign, exp, frac);
if (exp == EXP_MASK) {
if (frac == 0) {
printf("%cInfinity\n", sign ? '-' : '+');
} else
printf("Not-A-Number\n");
} else {
int denorm = (exp == 0);
int uexp = denorm ? 1-BIAS : exp - BIAS;
int mantissa = denorm ? frac : frac + (1<<FRAC_SIZE);
float fman = (float) mantissa / (float) (1<<FRAC_SIZE);
printf("%s. %c%.10f X 2^(%d)\n",
denorm ? "Denormalized" : "Normalized",
sign ? '-' : '+',
fman, uexp);
}
}
/* Extract hex/decimal/or float value from string */
static int get_num_val(char *sval, unsigned *valp) {
char *endp;
/* See if it's an integer or floating point */
int ishex = 0;
int isfloat = 0;
int i;
for (i = 0; sval[i]; i++) {
switch (sval[i]) {
case 'x':
case 'X':
ishex = 1;
break;
case 'e':
case 'E':
if (!ishex)
isfloat = 1;
break;
case '.':
isfloat = 1;
break;
default:
break;
}
}
if (isfloat) {
float fval = strtof(sval, &endp);
if (!*endp) {
*valp = *(unsigned *) &fval;
return 1;
}
return 0;
} else {
long long int llval = strtoll(sval, &endp, 0);
long long int upperbits = llval >> 31;
/* will give -1 for negative, 0 or 1 for positive */
if (valp && (upperbits == 0 || upperbits == -1 || upperbits == 1)) {
*valp = (unsigned) llval;
return 1;
}
return 0;
}
}
void usage(char *fname) {
printf("Usage: %s val1 val2 ...\n", fname);
printf("Values may be given as hex patterns or as floating point numbers\n");
exit(0);
}
int main(int argc, char *argv[])
{
int i;
unsigned uf;
if (argc < 2)
usage(argv[0]);
for (i = 1; i < argc; i++) {
char *sval = argv[i];
if (get_num_val(sval, &uf)) {
show_float(uf);
} else {
printf("Invalid 32-bit number: '%s'\n", sval);
usage(argv[0]);
}
}
return 0;
}

+ 0
- 75
LAB1/ishow.c View File

@ -1,75 +0,0 @@
/* Display value of fixed point numbers */
#include <stdlib.h>
#include <stdio.h>
/* Extract hex/decimal/or float value from string */
static int get_num_val(char *sval, unsigned *valp) {
char *endp;
/* See if it's an integer or floating point */
int ishex = 0;
int isfloat = 0;
int i;
for (i = 0; sval[i]; i++) {
switch (sval[i]) {
case 'x':
case 'X':
ishex = 1;
break;
case 'e':
case 'E':
if (!ishex)
isfloat = 1;
break;
case '.':
isfloat = 1;
break;
default:
break;
}
}
if (isfloat) {
return 0; /* Not supposed to have a float here */
} else {
long long int llval = strtoll(sval, &endp, 0);
long long int upperbits = llval >> 31;
/* will give -1 for negative, 0 or 1 for positive */
if (valp && (upperbits == 0 || upperbits == -1 || upperbits == 1)) {
*valp = (unsigned) llval;
return 1;
}
return 0;
}
}
void show_int(unsigned uf)
{
printf("Hex = 0x%.8x,\tSigned = %d,\tUnsigned = %u\n",
uf, (int) uf, uf);
}
void usage(char *fname) {
printf("Usage: %s val1 val2 ...\n", fname);
printf("Values may be given in hex or decimal\n");
exit(0);
}
int main(int argc, char *argv[])
{
int i;
unsigned uf;
if (argc < 2)
usage(argv[0]);
for (i = 1; i < argc; i++) {
char *sval = argv[i];
if (get_num_val(sval, &uf)) {
show_int(uf);
} else {
printf("Cannot convert '%s' to 32-bit number\n", sval);
}
}
return 0;
}

+ 0
- 124
LAB1/tests.c View File

@ -1,124 +0,0 @@
/* Testing Code */
#include <limits.h>
#include <math.h>
/* Routines used by floation point test code */
/* Convert from bit level representation to floating point number */
float u2f(unsigned u) {
union {
unsigned u;
float f;
} a;
a.u = u;
return a.f;
}
/* Convert from floating point number to bit-level representation */
unsigned f2u(float f) {
union {
unsigned u;
float f;
} a;
a.f = f;
return a.u;
}
/* Copyright (C) 1991-2020 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 Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This header is separate from features.h so that the compiler can
include it implicitly at the start of every compilation. It must
not itself include <features.h> or any other header that includes
<features.h> because the implicit include comes before any feature
test macros that may be defined in a source file before it first
explicitly includes a system header. GCC knows the name of this
header in order to preinclude it. */
/* glibc's intent is to support the IEC 559 math functionality, real
and complex. If the GCC (4.9 and later) predefined macros
specifying compiler intent are available, use them to determine
whether the overall intent is to support these features; otherwise,
presume an older compiler has intent to support these features and
define these macros by default. */
/* wchar_t uses Unicode 10.0.0. Version 10.0 of the Unicode Standard is
synchronized with ISO/IEC 10646:2017, fifth edition, plus
the following additions from Amendment 1 to the fifth edition:
- 56 emoji characters
- 285 hentaigana
- 3 additional Zanabazar Square characters */
//1
int test_bitXor(int x, int y)
{
return x^y;
}
int test_tmin(void) {
return 0x80000000;
}
//2
int test_isTmax(int x) {
return x == 0x7FFFFFFF;
}
int test_allOddBits(int x) {
int i;
for (i = 1; i < 32; i+=2)
if ((x & (1<<i)) == 0)
return 0;
return 1;
}
int test_negate(int x) {
return -x;
}
//3
int test_isAsciiDigit(int x) {
return (0x30 <= x) && (x <= 0x39);
}
int test_conditional(int x, int y, int z)
{
return x?y:z;
}
int test_isLessOrEqual(int x, int y)
{
return x <= y;
}
//4
int test_logicalNeg(int x)
{
return !x;
}
int test_howManyBits(int x) {
unsigned int a, cnt;
x = x<0 ? -x-1 : x;
a = (unsigned int)x;
for (cnt=0; a; a>>=1, cnt++)
;
return (int)(cnt + 1);
}
//float
unsigned test_floatScale2(unsigned uf) {
float f = u2f(uf);
float tf = 2*f;
if (isnan(f))
return uf;
else
return f2u(tf);
}
int test_floatFloat2Int(unsigned uf) {
float f = u2f(uf);
int x = (int) f;
return x;
}
// #include "floatPower2.c"

+ 0
- 21
LICENSE View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 AquaOH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 971
- 0
README.MD View File

@ -0,0 +1,971 @@
# All
This is bomb 121.
It belongs to 10225501432 (10225501432@stu.ecnu.edu.cn)
# phase_1
## 查看phase_1汇编
~~~python
=> 0x0000555555401204 <+0>: sub $0x8,%rsp
0x0000555555401208 <+4>: lea 0x1801(%rip),%rsi # 0x555555402a10
0x000055555540120f <+11>: call 0x55555540172b <strings_not_equal>
0x0000555555401214 <+16>: test %eax,%eax
0x0000555555401216 <+18>: jne 0x55555540121d <phase_1+25>
0x0000555555401218 <+20>: add $0x8,%rsp
0x000055555540121c <+24>: ret
0x000055555540121d <+25>: call 0x5555554019e6 <explode_bomb>
0x0000555555401222 <+30>: jmp 0x555555401218 <phase_1+20>
~~~
<+0>行进行了压栈操作
<+4>行将内存地址0x555555402a10赋予了寄存器%rsi
<+11>行调用了函数<strings_not_equal>,从名称来看,是用于判断字符串是否相等,这串字符串就是密码
进入函数<strings_not_equal>查看,只看前几行
## 查看strings_not_equal汇编
~~~python
=> 0x000055555540172b <+0>: push %r12
0x000055555540172d <+2>: push %rbp
0x000055555540172e <+3>: push %rbx
0x000055555540172f <+4>: mov %rdi,%rbx
0x0000555555401732 <+7>: mov %rsi,%rbp
0x0000555555401735 <+10>: call 0x55555540170e <string_length>
~~~
发现调用了函数<string_length>,进入查看
## 查看string_length汇编
~~~python
=> 0x000055555540170e <+0>: cmpb $0x0,(%rdi)
0x0000555555401711 <+3>: je 0x555555401725 <string_length+23>
0x0000555555401713 <+5>: mov %rdi,%rdx
0x0000555555401716 <+8>: add $0x1,%rdx
0x000055555540171a <+12>: mov %edx,%eax
0x000055555540171c <+14>: sub %edi,%eax
0x000055555540171e <+16>: cmpb $0x0,(%rdx)
0x0000555555401721 <+19>: jne 0x555555401716 <string_length+8>
0x0000555555401723 <+21>: repz ret
0x0000555555401725 <+23>: mov $0x0,%eax
0x000055555540172a <+28>: ret
~~~
<0> <3>行用于判断是否是空地址,是的话返回0并退出
<5> 到 <19>行使用了循环的方式判断字符串有几位
首先将%rdi地址赋予%rdx,并且进入循环
随后进入循环,每次循环%rdx地址后后移一位
每完成一次循环,%eax就加一
跳出条件是 %rdx的地址指向的内存位置所储存的数据为0
故%rdi寄存器储存的是用户输入字符串的起始地址
## 继续查看strings_not_equal的后续部分
~~~python
=> 0x000055555540172b <+0>: push %r12
0x000055555540172d <+2>: push %rbp
0x000055555540172e <+3>: push %rbx
0x000055555540172f <+4>: mov %rdi,%rbx
0x0000555555401732 <+7>: mov %rsi,%rbp
0x0000555555401735 <+10>: call 0x55555540170e <string_length>
0x000055555540173a <+15>: mov %eax,%r12d
0x000055555540173d <+18>: mov %rbp,%rdi
0x0000555555401740 <+21>: call 0x55555540170e <string_length>
0x0000555555401745 <+26>: mov $0x1,%edx
0x000055555540174a <+31>: cmp %eax,%r12d
0x000055555540174d <+34>: je 0x555555401756 <strings_not_equal+43>
0x000055555540174f <+36>: mov %edx,%eax
0x0000555555401751 <+38>: pop %rbx
0x0000555555401752 <+39>: pop %rbp
0x0000555555401753 <+40>: pop %r12
0x0000555555401755 <+42>: ret
~~~
这一段实现了检查输入字符串和密码字符串的长度是否相等
可以锁定进入<strings_not_equal>函数前的%rsi寄存器就是密码部分
## 结论
使用命令'x/s 0x555555402a10'直接查看
发现密码为"I am not part of the problem. I am a Republican."
# phase_2
## 查看phase_2汇编
首先查看部分汇编
~~~python
=> 0x0000555555401224 <+0>: push %rbp
0x0000555555401225 <+1>: push %rbx
0x0000555555401226 <+2>: sub $0x28,%rsp
0x000055555540122a <+6>: mov %fs:0x28,%rax
0x0000555555401233 <+15>: mov %rax,0x18(%rsp)
0x0000555555401238 <+20>: xor %eax,%eax
0x000055555540123a <+22>: mov %rsp,%rsi
0x000055555540123d <+25>: call 0x555555401a22 <read_six_numbers>
~~~
可以发现其中途调用了函数<read_six_numbers>,其密码必然是六个数字
进入函数<read_six_numbers>查看
## 查看read_six_numbers汇编
~~~python
=> 0x0000555555401a22 <+0>: sub $0x8,%rsp
0x0000555555401a26 <+4>: mov %rsi,%rdx
0x0000555555401a29 <+7>: lea 0x4(%rsi),%rcx
0x0000555555401a2d <+11>: lea 0x14(%rsi),%rax
0x0000555555401a31 <+15>: push %rax
0x0000555555401a32 <+16>: lea 0x10(%rsi),%rax
0x0000555555401a36 <+20>: push %rax
0x0000555555401a37 <+21>: lea 0xc(%rsi),%r9
0x0000555555401a3b <+25>: lea 0x8(%rsi),%r8
0x0000555555401a3f <+29>: lea 0x12a3(%rip),%rsi # 0x555555402ce9
0x0000555555401a46 <+36>: mov $0x0,%eax
0x0000555555401a4b <+41>: call 0x555555400ee0 <__isoc99_sscanf@plt>
0x0000555555401a50 <+46>: add $0x10,%rsp
0x0000555555401a54 <+50>: cmp $0x5,%eax
0x0000555555401a57 <+53>: jle 0x555555401a5e <read_six_numbers+60>
0x0000555555401a59 <+55>: add $0x8,%rsp
0x0000555555401a5d <+59>: ret
0x0000555555401a5e <+60>: call 0x5555554019e6 <explode_bomb>
~~~
显然其判断起始地址储存在%rsi的数组中的数据
而由phase_2汇编可知,%rsi储存的地址由%rsp赋值而来
则%rsp含有用户输入数组的储存地址
## 继续查看phase_2汇编
### 进入循环
~~~python
0x0000555555401242 <+30>: cmpl $0x0,(%rsp)
0x0000555555401246 <+34>: jne 0x55555540124f <phase_2+43>
0x0000555555401248 <+36>: cmpl $0x1,0x4(%rsp)
0x000055555540124d <+41>: je 0x555555401254 <phase_2+48>
0x000055555540124f <+43>: call 0x5555554019e6 <explode_bomb>
~~~
判断数组第一位是否为0,不是则引爆炸弹
判断数组第二位是否为1,是则跳转至<48>行
~~~python
0x0000555555401254 <+48>: mov %rsp,%rbx
0x0000555555401257 <+51>: lea 0x10(%rbx),%rbp
0x000055555540125b <+55>: jmp 0x555555401266 <phase_2+66>
0x000055555540125d <+57>: add $0x4,%rbx
0x0000555555401261 <+61>: cmp %rbp,%rbx
0x0000555555401264 <+64>: je 0x555555401277 <phase_2+83>
0x0000555555401266 <+66>: mov 0x4(%rbx),%eax
0x0000555555401269 <+69>: add (%rbx),%eax
0x000055555540126b <+71>: cmp %eax,0x8(%rbx)
0x000055555540126e <+74>: je 0x55555540125d <phase_2+57>
0x0000555555401270 <+76>: call 0x5555554019e6 <explode_bomb>
0x0000555555401275 <+81>: jmp 0x55555540125d <phase_2+57>
~~~
将%rsp的地址赋予%rbx,%rsp地址+16赋予%rbp
随后跳转至<66>行
%eax储存%rbx+4地址所指向的值,并将其与%rbx所指向的值相加
随后%eax与%rbx+8地址所指向的值比较
相等则跳转至<57>行,%rbx的地址+4,如果%rsp+16与%rbx+4相等,则跳转至83行
从实际效果看,循环执行4次
每次将三元组,前两位相加与最后一位比较
相等则继续循环,不相等则爆炸
由上文可知,前两位分别为 0 1
~~~python
第一次循环: 0 + 1 = 1
第二次循环: 1 + 1 = 2
第三次循环: 1 + 2 = 3
第四次循环: 2 + 3 = 5
~~~
故整个六位数字应该为 0 1 1 2 3 5
### 跳出循环&返回数值
~~~python
0x0000555555401277 <+83>: mov 0x18(%rsp),%rax
0x000055555540127c <+88>: xor %fs:0x28,%rax
0x0000555555401285 <+97>: jne 0x55555540128e <phase_2+106>
0x0000555555401287 <+99>: add $0x28,%rsp
0x000055555540128b <+103>: pop %rbx
0x000055555540128c <+104>: pop %rbp
0x000055555540128d <+105>: ret
0x000055555540128e <+106>: call 0x555555400e40 <__stack_chk_fail@plt>
~~~
实际效果来看,跳转到<83>行后,循环跳出,函数收尾并正常返回
### 结论
故整个六位数字应该为 0 1 1 2 3 5
# phase_3
## 查看部分汇编
~~~python
0x0000555555401293 <+0>: sub $0x18,%rsp
0x0000555555401297 <+4>: mov %fs:0x28,%rax
0x00005555554012a0 <+13>: mov %rax,0x8(%rsp)
0x00005555554012a5 <+18>: xor %eax,%eax
0x00005555554012a7 <+20>: lea 0x4(%rsp),%rcx
0x00005555554012ac <+25>: mov %rsp,%rdx
0x00005555554012af <+28>: lea 0x1a3f(%rip),%rsi # 0x555555402cf5
0x00005555554012b6 <+35>: call 0x555555400ee0 <__isoc99_sscanf@plt>
0x00005555554012bb <+40>: cmp $0x1,%eax
0x00005555554012be <+43>: jle 0x5555554012dd <phase_3+74>
0x00005555554012c0 <+45>: cmpl $0x7,(%rsp)
0x00005555554012c4 <+49>: ja 0x555555401363 <phase_3+208>
~~~
可以看出phase_3调用了函数sscanf,其返回值为输入字符的个数
输入命令 `x/s 0x555555402cf5`显示"%d %d",可知sscanf输入两个字符,其返回值为2
<45><49>判断第一个数字是否小于0x7,故第一个数字应设置小于7
## 随意设置数字并带入
设置输入数据为5 32
随后断点设置在phase_3,使用nexti单步调试
查看汇编,并一路nexti
~~~python
0x00005555554012ca <+55>: mov (%rsp),%eax
0x00005555554012cd <+58>: lea 0x17ac(%rip),%rdx # 0x555555402a80
0x00005555554012d4 <+65>: movslq (%rdx,%rax,4),%rax
0x00005555554012d8 <+69>: add %rdx,%rax
0x00005555554012db <+72>: jmp *%rax
0x00005555554012dd <+74>: call 0x5555554019e6 <explode_bomb>
~~~
发现执行完`jmp *%rax`后,跳转至`0x000055555540134e`
## 继续查看汇编
继续nexti
~~~python
0x00005555554012e2 <+79>: jmp 0x5555554012c0 <phase_3+45>
0x00005555554012e4 <+81>: mov $0x2ca,%eax
0x00005555554012e9 <+86>: jmp 0x5555554012f0 <phase_3+93>
0x00005555554012eb <+88>: mov $0x0,%eax
0x00005555554012f0 <+93>: sub $0xf2,%eax
0x00005555554012f5 <+98>: add $0x14a,%eax
0x00005555554012fa <+103>: sub $0x162,%eax
0x00005555554012ff <+108>: add $0x162,%eax
0x0000555555401304 <+113>: sub $0x162,%eax
0x0000555555401309 <+118>: add $0x162,%eax
0x000055555540130e <+123>: sub $0x162,%eax
0x0000555555401313 <+128>: cmpl $0x5,(%rsp)
0x0000555555401317 <+132>: jg 0x55555540131f <phase_3+140>
0x0000555555401319 <+134>: cmp %eax,0x4(%rsp)
0x000055555540131d <+138>: je 0x555555401324 <phase_3+145>
0x000055555540131f <+140>: call 0x5555554019e6 <explode_bomb>
0x0000555555401324 <+145>: mov 0x8(%rsp),%rax
0x0000555555401329 <+150>: xor %fs:0x28,%rax
0x0000555555401332 <+159>: jne 0x55555540136f <phase_3+220>
0x0000555555401334 <+161>: add $0x18,%rsp
0x0000555555401338 <+165>: ret
0x0000555555401339 <+166>: mov $0x0,%eax
0x000055555540133e <+171>: jmp 0x5555554012f5 <phase_3+98>
0x0000555555401340 <+173>: mov $0x0,%eax
0x0000555555401345 <+178>: jmp 0x5555554012fa <phase_3+103>
0x0000555555401347 <+180>: mov $0x0,%eax
0x000055555540134c <+185>: jmp 0x5555554012ff <phase_3+108>
0x000055555540134e <+187>: mov $0x0,%eax
0x0000555555401353 <+192>: jmp 0x555555401304 <phase_3+113>
0x0000555555401355 <+194>: mov $0x0,%eax
0x000055555540135a <+199>: jmp 0x555555401309 <phase_3+118>
0x000055555540135c <+201>: mov $0x0,%eax
0x0000555555401361 <+206>: jmp 0x55555540130e <phase_3+123>
0x0000555555401363 <+208>: call 0x5555554019e6 <explode_bomb>
0x0000555555401368 <+213>: mov $0x0,%eax
0x000055555540136d <+218>: jmp 0x555555401313 <phase_3+128>
0x000055555540136f <+220>: call 0x555555400e40 <__stack_chk_fail@plt>
~~~
发现其跳转至`0x0000555555401304`
~~~python
0x0000555555401313 <+128>: cmpl $0x5,(%rsp)
0x0000555555401317 <+132>: jg 0x55555540131f <phase_3+140>
~~~
判断第一个数字是否小于等于5,不是则引爆
~~~python
0x0000555555401319 <+134>: cmp %eax,0x4(%rsp)
0x000055555540131d <+138>: je 0x555555401324 <phase_3+145>
0x000055555540131f <+140>: call 0x5555554019e6 <explode_bomb>
~~~
判断第二个数字是否和eax寄存器中数据相等
此时查看寄存器eax中数值`p $eax`,返回数据为-354,故第二个数据为-354
## 结论
phase_3第一个数据要求小于等于5,第二个数据要求为-354
# phase_4
## 查看部分汇编代码
~~~python
0x00005555554013ad <+0>: sub $0x18,%rsp
0x00005555554013b1 <+4>: mov %fs:0x28,%rax
0x00005555554013ba <+13>: mov %rax,0x8(%rsp)
0x00005555554013bf <+18>: xor %eax,%eax
0x00005555554013c1 <+20>: mov %rsp,%rcx
0x00005555554013c4 <+23>: lea 0x4(%rsp),%rdx
0x00005555554013c9 <+28>: lea 0x1925(%rip),%rsi # 0x555555402cf5
0x00005555554013d0 <+35>: call 0x555555400ee0 <__isoc99_sscanf@plt>
0x00005555554013d5 <+40>: cmp $0x2,%eax
0x00005555554013d8 <+43>: jne 0x5555554013e5 <phase_4+56>
~~~
可以看到`0x00005555554013c9 <+28>: lea 0x1925(%rip),%rsi # 0x555555402cf5`
输入`x/s 0x555555402cf5`,显示为`%d %d`,因此输入数据为两个整形
随意输入两个整数,例如`114 514`
~~~python
p *(int*)$rsp
p *(int*)($rsp+4)
$1 = 514
$2 = 114
~~~
所以rsp存储第二个数字的地址,rsp+4存储第一个数字的地址
## 继续查看部分汇编代码
~~~python
0x00005555554013da <+45>: mov (%rsp),%eax
0x00005555554013dd <+48>: sub $0x2,%eax
0x00005555554013e0 <+51>: cmp $0x2,%eax
0x00005555554013e3 <+54>: jbe 0x5555554013ea <phase_4+61>
0x00005555554013e5 <+56>: call 0x5555554019e6 <explode_bomb>
0x00005555554013ea <+61>: mov (%rsp),%esi
0x00005555554013ed <+64>: mov $0x9,%edi
0x00005555554013f2 <+69>: call 0x555555401374 <func4>
0x00005555554013f7 <+74>: cmp %eax,0x4(%rsp)
0x00005555554013fb <+78>: je 0x555555401402 <phase_4+85>
0x00005555554013fd <+80>: call 0x5555554019e6 <explode_bomb>
0x0000555555401402 <+85>: mov 0x8(%rsp),%rax
0x0000555555401407 <+90>: xor %fs:0x28,%rax
0x0000555555401410 <+99>: jne 0x555555401417 <phase_4+106>
0x0000555555401412 <+101>: add $0x18,%rsp
0x0000555555401416 <+105>: ret
0x0000555555401417 <+106>: call 0x555555400e40 <__stack_chk_fail@plt>
~~~
<+45> <+48> <+51> <+54> 要求输入的第二个数据小于等于4
不妨让输入数据变为`114 4`再次单步调试
一路nexti,直至,<+69>执行完毕
显然<+74> <+78>判断第一个数据是否和函数 func4 返回值是否相同
输入`p $eax`查看,显示为352
## 结论
因此,可行的一组数据为`352 4`
# phase_5
## 查看部分汇编代码
~~~python
0x000055555540141c <+0>: sub $0x18,%rsp
0x0000555555401420 <+4>: mov %fs:0x28,%rax
0x0000555555401429 <+13>: mov %rax,0x8(%rsp)
0x000055555540142e <+18>: xor %eax,%eax
0x0000555555401430 <+20>: lea 0x4(%rsp),%rcx
0x0000555555401435 <+25>: mov %rsp,%rdx
0x0000555555401438 <+28>: lea 0x18b6(%rip),%rsi # 0x555555402cf5
0x000055555540143f <+35>: call 0x555555400ee0 <__isoc99_sscanf@plt>
0x0000555555401444 <+40>: cmp $0x1,%eax
0x0000555555401447 <+43>: jle 0x5555554014a3 <phase_5+135>
~~~
<+28>行可以看到`0x555555402cf5`
输入`x/s 0x555555402cf5`显示`%d %d`
故输入两个十进制整数
## 进入循环
### 循环起点
~~~python
0x0000555555401449 <+45>: mov (%rsp),%eax
0x000055555540144c <+48>: and $0xf,%eax
0x000055555540144f <+51>: mov %eax,(%rsp)
0x0000555555401452 <+54>: cmp $0xf,%eax
0x0000555555401455 <+57>: je 0x555555401489 <phase_5+109>
0x0000555555401457 <+59>: mov $0x0,%ecx
0x000055555540145c <+64>: mov $0x0,%edx
0x0000555555401461 <+69>: lea 0x1638(%rip),%rsi # 0x555555402aa0 <array.3415>
~~~
发现有一个数组array.3415
查看后发现数组为{10, 2, 14, 7, 8, 12, 15, 11, 0, 4, 1, 13, 3, 9, 6, 5}
### 进入循环
~~~python
0x0000555555401468 <+76>: add $0x1,%edx
0x000055555540146b <+79>: cltq
0x000055555540146d <+81>: mov (%rsi,%rax,4),%eax
0x0000555555401470 <+84>: add %eax,%ecx
0x0000555555401472 <+86>: cmp $0xf,%eax
0x0000555555401475 <+89>: jne 0x555555401468 <phase_5+76>
0x0000555555401477 <+91>: movl $0xf,(%rsp)
0x000055555540147e <+98>: cmp $0xf,%edx
=> 0x0000555555401481 <+101>: jne 0x555555401489 <phase_5+109>
0x0000555555401483 <+103>: cmp %ecx,0x4(%rsp)
0x0000555555401487 <+107>: je 0x55555540148e <phase_5+114>
~~~
当寄存器%edx与%eax同时为0xf时,循环跳出
因为%edx初始值为0,进入循环加1,则循环必定15次
故可逆推最开始进入循环时%eax的值
逆推得%eax为5
此时输入%ecx计算得结果为115
### 退出循环
正常检查栈金丝雀值
~~~python
0x0000555555401489 <+109>: call 0x5555554019e6 <explode_bomb>
0x000055555540148e <+114>: mov 0x8(%rsp),%rax
0x0000555555401493 <+119>: xor %fs:0x28,%rax
0x000055555540149c <+128>: jne 0x5555554014aa <phase_5+142>
0x000055555540149e <+130>: add $0x18,%rsp
0x00005555554014a2 <+134>: ret
0x00005555554014a3 <+135>: call 0x5555554019e6 <explode_bomb>
0x00005555554014a8 <+140>: jmp 0x555555401449 <phase_5+45>
0x00005555554014aa <+142>: call 0x555555400e40 <__stack_chk_fail@plt>
~~~
## 结论
密码为`5 115`
# phase_6
## 读取数据
~~~python
=> 0x00005555554014af <+0>: push %r14
0x00005555554014b1 <+2>: push %r13
0x00005555554014b3 <+4>: push %r12
0x00005555554014b5 <+6>: push %rbp
0x00005555554014b6 <+7>: push %rbx
0x00005555554014b7 <+8>: sub $0x60,%rsp
0x00005555554014bb <+12>: mov %fs:0x28,%rax
0x00005555554014c4 <+21>: mov %rax,0x58(%rsp)
0x00005555554014c9 <+26>: xor %eax,%eax
0x00005555554014cb <+28>: mov %rsp,%r13
0x00005555554014ce <+31>: mov %r13,%rsi
0x00005555554014d1 <+34>: call 0x555555401a22 <read_six_numbers>
0x00005555554014d6 <+39>: mov %r13,%r12
0x00005555554014d9 <+42>: mov $0x0,%r14d
0x00005555554014df <+48>: jmp 0x555555401506 <phase_6+87>
~~~
这段开辟了一个栈空间并且设置了一个金丝雀值
将%rsp赋予%r13,%rsi,%r12
将0x0赋予%r14d
随后跳转到87行
## 第一个循环
~~~python
0x00005555554014e1 <+50>: call 0x5555554019e6 <explode_bomb>
0x00005555554014e6 <+55>: jmp 0x555555401515 <phase_6+102>
0x00005555554014e8 <+57>: add $0x1,%ebx
0x00005555554014eb <+60>: cmp $0x5,%ebx
0x00005555554014ee <+63>: jg 0x555555401502 <phase_6+83>
0x00005555554014f0 <+65>: movslq %ebx,%rax
0x00005555554014f3 <+68>: mov (%rsp,%rax,4),%eax
0x00005555554014f6 <+71>: cmp %eax,0x0(%rbp)
0x00005555554014f9 <+74>: jne 0x5555554014e8 <phase_6+57>
0x00005555554014fb <+76>: call 0x5555554019e6 <explode_bomb>
0x0000555555401500 <+81>: jmp 0x5555554014e8 <phase_6+57>
0x0000555555401502 <+83>: add $0x4,%r13
0x0000555555401506 <+87>: mov %r13,%rbp
0x0000555555401509 <+90>: mov 0x0(%r13),%eax
0x000055555540150d <+94>: sub $0x1,%eax
0x0000555555401510 <+97>: cmp $0x5,%eax
0x0000555555401513 <+100>: ja 0x5555554014e1 <phase_6+50>
0x0000555555401515 <+102>: add $0x1,%r14d
0x0000555555401519 <+106>: cmp $0x6,%r14d
0x000055555540151d <+110>: je 0x555555401524 <phase_6+117>
0x000055555540151f <+112>: mov %r14d,%ebx
0x0000555555401522 <+115>: jmp 0x5555554014f0 <phase_6+65>
~~~
分析可知,进入循环得初始处理是将%r13存储的%rsp地址赋给%rbp
随后比较(%rsp)即第一个数字,减去1后与0x5比较,如果小于等于5才不会引爆
相当于每个输入的数据都必须小于等于6
并且由于是ja,故数字还必须-1后大于等于0,故数字大于等于1
%r14d初始值为0x0,每完成一次循环都+1,等于6的时候跳出,则循环执行6次,恰好遍历六个数字
%r14d未达到0x6时,会将当前值给%ebx,随后跳转到65行
执行等价于%eax等于第n个数字的操作
随后%eax与%rbp指向的数字比较,不相等则%ebx+1,继续判断%eax与%rbp指向的数字,直到%ebx大于5
随后%r13后移一位,继续进入最开始的循环
### 第一个循环结论
等效于数组各数字不能相等,并且都需要大于等于1,小于等于6
## 第二个与第三个循环
~~~python
0x0000555555401524 <+117>: lea 0x18(%r12),%rcx
0x0000555555401529 <+122>: mov $0x7,%edx
0x000055555540152e <+127>: mov %edx,%eax
0x0000555555401530 <+129>: sub (%r12),%eax
0x0000555555401534 <+133>: mov %eax,(%r12)
0x0000555555401538 <+137>: add $0x4,%r12
0x000055555540153c <+141>: cmp %r12,%rcx
0x000055555540153f <+144>: jne 0x55555540152e <phase_6+127>
0x0000555555401541 <+146>: mov $0x0,%esi
0x0000555555401546 <+151>: jmp 0x555555401562 <phase_6+179>
0x0000555555401548 <+153>: mov 0x8(%rdx),%rdx
0x000055555540154c <+157>: add $0x1,%eax
0x000055555540154f <+160>: cmp %ecx,%eax
0x0000555555401551 <+162>: jne 0x555555401548 <phase_6+153>
0x0000555555401553 <+164>: mov %rdx,0x20(%rsp,%rsi,8)
0x0000555555401558 <+169>: add $0x1,%rsi
0x000055555540155c <+173>: cmp $0x6,%rsi
0x0000555555401560 <+177>: je 0x555555401578 <phase_6+201>
0x0000555555401562 <+179>: mov (%rsp,%rsi,4),%ecx
0x0000555555401565 <+182>: mov $0x1,%eax
0x000055555540156a <+187>: lea 0x202cbf(%rip),%rdx # 0x555555604230 <node1>
0x0000555555401571 <+194>: cmp $0x1,%ecx
0x0000555555401574 <+197>: jg 0x555555401548 <phase_6+153>
0x0000555555401576 <+199>: jmp 0x555555401553 <phase_6+164>
~~~
跳出第一个循环后,进入第二个循环
%rcx被赋予等价为%rsp+0x18的地址,这个地址并不存放数组的数据
%edx被赋予0x7的值
令%eax = 7,随后7-(%rsp)
%r12储存地址+4,等价%rsp+4
比较%r12与%rcx的地址,不一致则跳转到127行,127行继续进行上述操作
最终结果是%r12地址移动至%rsp+0x18,数组内每个数字都变为7-该数字,随后将%esi置0x0,跳转至179行
进入第三个循环
%ecx被赋予(%rsp)的值
%eax被置1
%rdx被赋予一个节点地址
并且判断%ecx的值是否大于1
如果是跳转到153行,(%rdx地址+0x8)赋给rdx,可以猜测,%rdx原先赋给的node1是个结构体,前八字节储存的是数据,后八字节储存的是地址
输入`x/128x 0x555555604230`即可查看
因此应该为一个链表,并且每次循环都向后移动一位
随后%eax+1,使得%ecx和%eax比较
循环,直至%ecx与%eax相等
如果不是大于1
跳转到164行
将节点地址赋给%rsp对应位置
最终效果为
数字为7-n对应第n个节点
节点地址在栈中存储顺序和数字输入顺序一致
完成后跳转到201行
## 第四个循环
~~~python
0x0000555555401578 <+201>: mov 0x20(%rsp),%rbx
0x000055555540157d <+206>: mov 0x28(%rsp),%rax
0x0000555555401582 <+211>: mov %rax,0x8(%rbx)
0x0000555555401586 <+215>: mov 0x30(%rsp),%rdx
0x000055555540158b <+220>: mov %rdx,0x8(%rax)
0x000055555540158f <+224>: mov 0x38(%rsp),%rax
0x0000555555401594 <+229>: mov %rax,0x8(%rdx)
0x0000555555401598 <+233>: mov 0x40(%rsp),%rdx
0x000055555540159d <+238>: mov %rdx,0x8(%rax)
0x00005555554015a1 <+242>: mov 0x48(%rsp),%rax
0x00005555554015a6 <+247>: mov %rax,0x8(%rdx)
0x00005555554015aa <+251>: movq $0x0,0x8(%rax)
0x00005555554015b2 <+259>: mov $0x5,%ebp
0x00005555554015b7 <+264>: jmp 0x5555554015c2 <phase_6+275>
0x00005555554015b9 <+266>: mov 0x8(%rbx),%rbx
0x00005555554015bd <+270>: sub $0x1,%ebp
0x00005555554015c0 <+273>: je 0x5555554015d3 <phase_6+292>
0x00005555554015c2 <+275>: mov 0x8(%rbx),%rax
0x00005555554015c6 <+279>: mov (%rax),%eax
0x00005555554015c8 <+281>: cmp %eax,(%rbx)
0x00005555554015ca <+283>: jge 0x5555554015b9 <phase_6+266>
0x00005555554015cc <+285>: call 0x5555554019e6 <explode_bomb>
0x00005555554015d1 <+290>: jmp 0x5555554015b9 <phase_6+266>
~~~
显然%rbx存储第一个数字对应的节点地址
%rax存储第二个数字对应的节点地址
0x8(%rbx)取出第一个数字对应节点储存的下一个节点的地址,这个地址被%rax中的地址取代
%rdx储存第三个数字对应的节点地址
0x8(%rax)取出第二个数字对应节点储存的下一个节点的地址,这个地址被%rdx中的地址取代
%rax被第四个数字对应的节点地址覆盖
0x8(%rdx)取出第三个数字对应节点储存的下一个节点的地址,这个地址被%rax中的地址取代,即第四个数字对应的节点地址
%rdx被第五个数字对应的节点地址覆盖
0x8(%rax)取出第四个数字对应下一个节点的地址,这个地址被%rdx中的地址取代,即第五个数字对应的节点地址
%rax被第六个数字对应节点的地址覆盖
0x8(%rdx)取出第五个数字对应下一个节点的地址,这个地址被%rdx中的地址取代,即第六个数字对应的节点地址
随后给%rax储存地址处赋予Null指针
综合结果即将原有链表顺序重新排列
效果为输入顺序为i,数值为k的一组数据
第7-k个节点被移动至第i位
然后置%ebp为5,跳转至275行
%rbx储存第一个节点的地址,赋予%rax第二个节点的地址
将第二个节点的数据赋给%eax
比较第二个节点的数据b和第一个节点的数据a
如果a>=b
则继续循环,跳转到266行,%rbx移动至下一个节点,同时%ebp-1,并且如果%ebp = 1时,就跳出循环到292行
故进行了5次循环,每次效果都是判断相邻节点是否上一个的数据大于下一个
## 收尾
~~~python
0x00005555554015d1 <+290>: jmp 0x5555554015b9 <phase_6+266>
0x00005555554015d3 <+292>: mov 0x58(%rsp),%rax
0x00005555554015d8 <+297>: xor %fs:0x28,%rax
0x00005555554015e1 <+306>: jne 0x5555554015f0 <phase_6+321>
0x00005555554015e3 <+308>: add $0x60,%rsp
0x00005555554015e7 <+312>: pop %rbx
0x00005555554015e8 <+313>: pop %rbp
0x00005555554015e9 <+314>: pop %r12
0x00005555554015eb <+316>: pop %r13
0x00005555554015ed <+318>: pop %r14
0x00005555554015ef <+320>: ret
0x00005555554015f0 <+321>: call 0x555555400e40 <__stack_chk_fail@plt>
~~~
简单的探测金丝雀值变化并返回
## 安排密码
输入`x/128x 0x555555604230`查看各个节点
~~~python
0x555555604230 <node1>: 0x3b 0x03 0x00 0x00 0x01 0x00 0x00 0x00
0x555555604238 <node1+8>: 0x40 0x42 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604240 <node2>: 0x1c 0x02 0x00 0x00 0x02 0x00 0x00 0x00
0x555555604248 <node2+8>: 0x50 0x42 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604250 <node3>: 0x0f 0x02 0x00 0x00 0x03 0x00 0x00 0x00
0x555555604258 <node3+8>: 0x60 0x42 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604260 <node4>: 0xea 0x00 0x00 0x00 0x04 0x00 0x00 0x00
0x555555604268 <node4+8>: 0x70 0x42 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604270 <node5>: 0x83 0x00 0x00 0x00 0x05 0x00 0x00 0x00
0x555555604278 <node5+8>: 0x10 0x41 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604280 <host_table>: 0x4f 0x2d 0x40 0x55 0x55 0x55 0x00 0x00
0x555555604288 <host_table+8>: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555604290 <host_table+16>: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555604298 <host_table+24>: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555556042a0 <host_table+32>: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555556042a8 <host_table+40>: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
~~~
node1的数据是0x0000033b
node2的数据是0x0000021c
node3的数据是0x0000020f
node4的数据时0x000000ea
node5的数据是0x00000083
注意到node6储存在node5的地址处,和这五个node不是连续储存
输入`x/64x 0x555555604110`
node6的数据是0x000001e2
按照需要的,相邻数据成降序
则是 node1 node2 node3 node6 node4 node5
对应为 1 2 3 6 4 5
但是是用7-n得到的
所以实际顺序是 6 5 4 1 3 2
# secret_phase
查询资料得其在phase_defused中被调用
## 查看phase_defused汇编
~~~python
=> 0x0000555555401ba7 <+0>: sub $0x78,%rsp
0x0000555555401bab <+4>: mov %fs:0x28,%rax
0x0000555555401bb4 <+13>: mov %rax,0x68(%rsp)
0x0000555555401bb9 <+18>: xor %eax,%eax
0x0000555555401bbb <+20>: mov $0x1,%edi
0x0000555555401bc0 <+25>: call 0x5555554018c2 <send_msg>
0x0000555555401bc5 <+30>: cmpl $0x6,0x202ae0(%rip) # 0x5555556046ac <num_input_strings>
0x0000555555401bcc <+37>: je 0x555555401be7 <phase_defused+64>
0x0000555555401bce <+39>: mov 0x68(%rsp),%rax
0x0000555555401bd3 <+44>: xor %fs:0x28,%rax
0x0000555555401bdc <+53>: jne 0x555555401c66 <phase_defused+191>
0x0000555555401be2 <+59>: add $0x78,%rsp
0x0000555555401be6 <+63>: ret
0x0000555555401be7 <+64>: lea 0xc(%rsp),%rcx
0x0000555555401bec <+69>: lea 0x8(%rsp),%rdx
0x0000555555401bf1 <+74>: lea 0x10(%rsp),%r8
0x0000555555401bf6 <+79>: lea 0x1142(%rip),%rsi # 0x555555402d3f
0x0000555555401bfd <+86>: lea 0x202bac(%rip),%rdi # 0x5555556047b0 <input_strings+240>
0x0000555555401c04 <+93>: mov $0x0,%eax
0x0000555555401c09 <+98>: call 0x555555400ee0 <__isoc99_sscanf@plt>
0x0000555555401c0e <+103>: cmp $0x3,%eax
0x0000555555401c11 <+106>: je 0x555555401c2d <phase_defused+134>
0x0000555555401c13 <+108>: lea 0xfe6(%rip),%rdi # 0x555555402c00
0x0000555555401c1a <+115>: call 0x555555400e20 <puts@plt>
0x0000555555401c1f <+120>: lea 0x100a(%rip),%rdi # 0x555555402c30
0x0000555555401c26 <+127>: call 0x555555400e20 <puts@plt>
0x0000555555401c2b <+132>: jmp 0x555555401bce <phase_defused+39>
0x0000555555401c2d <+134>: lea 0x10(%rsp),%rdi
0x0000555555401c32 <+139>: lea 0x110f(%rip),%rsi # 0x555555402d48
0x0000555555401c39 <+146>: call 0x55555540172b <strings_not_equal>
0x0000555555401c3e <+151>: test %eax,%eax
0x0000555555401c40 <+153>: jne 0x555555401c13 <phase_defused+108>
0x0000555555401c42 <+155>: lea 0xf57(%rip),%rdi # 0x555555402ba0
0x0000555555401c49 <+162>: call 0x555555400e20 <puts@plt>
0x0000555555401c4e <+167>: lea 0xf73(%rip),%rdi # 0x555555402bc8
0x0000555555401c55 <+174>: call 0x555555400e20 <puts@plt>
0x0000555555401c5a <+179>: mov $0x0,%eax
0x0000555555401c5f <+184>: call 0x555555401634 <secret_phase>
0x0000555555401c64 <+189>: jmp 0x555555401c13 <phase_defused+108>
0x0000555555401c66 <+191>: call 0x555555400e40 <__stack_chk_fail@plt>
~~~
直奔`secret_phase`,向上寻找跳转,发现只有当`test %eax %eax`设置`ZF=1`时才能执行到`secret_phase`
而%eax的值由`strings_not_equal`决定,从phase_1中可知,`strings_not_equal`使用的用来当“标准”的字符串储存在寄存器%rsi的地址指向的地方
而上一步%rsi储存地址为`0x555555402d48`
输入`x/s 0x555555402d48`显示为`DrEvil`
下一步是寻找触发条件
继续向上看,发现<+93> <+98> <+103> <+106>行出现
~~~python
0x0000555555401c04 <+93>: mov $0x0,%eax
0x0000555555401c09 <+98>: call 0x555555400ee0 <__isoc99_sscanf@plt>
0x0000555555401c0e <+103>: cmp $0x3,%eax
0x0000555555401c11 <+106>: je 0x555555401c2d <phase_defused+134>
~~~
即判断sscanf函数接收的字符串是否为3个,是才能跳转到`strings_not_equal`
继续向上看,能跳转到`__isoc99_sscanf@plt`部分,而非ret退出,需要一个jmp指令
~~~python
0x0000555555401bc5 <+30>: cmpl $0x6,0x202ae0(%rip) # 0x5555556046ac <num_input_strings>
~~~
这段意思为完成六个phase,先决条件
只能在`__isoc99_sscanf@plt`上面和`ret`下面寻找,即
~~~python
0x0000555555401be7 <+64>: lea 0xc(%rsp),%rcx
0x0000555555401bec <+69>: lea 0x8(%rsp),%rdx
0x0000555555401bf1 <+74>: lea 0x10(%rsp),%r8
0x0000555555401bf6 <+79>: lea 0x1142(%rip),%rsi # 0x555555402d3f
0x0000555555401bfd <+86>: lea 0x202bac(%rip),%rdi # 0x5555556047b0 <input_strings+240>
~~~
输入`x/s 0x555555402d3f`得`"%d %d %s"`,结合之前拆弹经历,这是表示sscanf字符串的输入顺序
输入`x/s 0x5555556047b0`得`352 4`
显然为phase_4触发
故在phase_4输入时改为`352 4 DrEvil`
## 正式拆弹
### 查看secret_phase汇编
~~~python
=> 0x0000555555401634 <+0>: push %rbx
0x0000555555401635 <+1>: call 0x555555401a63 <read_line>
0x000055555540163a <+6>: mov $0xa,%edx
0x000055555540163f <+11>: mov $0x0,%esi
0x0000555555401644 <+16>: mov %rax,%rdi
0x0000555555401647 <+19>: call 0x555555400ec0 <strtol@plt>
0x000055555540164c <+24>: mov %rax,%rbx
0x000055555540164f <+27>: lea -0x1(%rax),%eax
0x0000555555401652 <+30>: cmp $0x3e8,%eax
0x0000555555401657 <+35>: ja 0x555555401684 <secret_phase+80>
0x0000555555401659 <+37>: mov %ebx,%esi
0x000055555540165b <+39>: lea 0x202aee(%rip),%rdi # 0x555555604150 <n1>
0x0000555555401662 <+46>: call 0x5555554015f5 <fun7>
0x0000555555401667 <+51>: cmp $0x2,%eax
0x000055555540166a <+54>: je 0x555555401671 <secret_phase+61>
0x000055555540166c <+56>: call 0x5555554019e6 <explode_bomb>
0x0000555555401671 <+61>: lea 0x13d0(%rip),%rdi # 0x555555402a48
0x0000555555401678 <+68>: call 0x555555400e20 <puts@plt>
0x000055555540167d <+73>: call 0x555555401ba7 <phase_defused>
0x0000555555401682 <+78>: pop %rbx
0x0000555555401683 <+79>: ret
0x0000555555401684 <+80>: call 0x5555554019e6 <explode_bomb>
0x0000555555401689 <+85>: jmp 0x555555401659 <secret_phase+37>
~~~
strtol函数将字符串里的10进制整数提取出来
其返回值为对应的整数
将返回值减1后于0x3e8比较,如果小于等于就不引爆炸弹
随后令%esi也等于%ebx,即%rax最开始返回的整数
然后给%rdi赋给一个地址,从注释名称来看也为一个节点
随后进入`fun7`函数
查看`fun7`函数前先看看节点的结构
输入`x/256x 0x555555604150`
~~~python
0x555555604150 <n1>: 0x24 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555604158 <n1+8>: 0x70 0x41 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604160 <n1+16>: 0x90 0x41 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604168: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555604170 <n21>: 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555604178 <n21+8>: 0xf0 0x41 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604180 <n21+16>: 0xb0 0x41 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604188: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555604190 <n22>: 0x32 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555604198 <n22+8>: 0xd0 0x41 0x60 0x55 0x55 0x55 0x00 0x00
0x5555556041a0 <n22+16>: 0x10 0x42 0x60 0x55 0x55 0x55 0x00 0x00
0x5555556041a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555556041b0 <n32>: 0x16 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555556041b8 <n32+8>: 0xb0 0x40 0x60 0x55 0x55 0x55 0x00 0x00
0x5555556041c0 <n32+16>: 0x70 0x40 0x60 0x55 0x55 0x55 0x00 0x00
0x5555556041c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555556041d0 <n33>: 0x2d 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555556041d8 <n33+8>: 0x10 0x40 0x60 0x55 0x55 0x55 0x00 0x00
0x5555556041e0 <n33+16>: 0xd0 0x40 0x60 0x55 0x55 0x55 0x00 0x00
0x5555556041e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555556041f0 <n31>: 0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555556041f8 <n31+8>: 0x30 0x40 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604200 <n31+16>: 0x90 0x40 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604208: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555604210 <n34>: 0x6b 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555604218 <n34+8>: 0x50 0x40 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604220 <n34+16>: 0xf0 0x40 0x60 0x55 0x55 0x55 0x00 0x00
0x555555604228: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
~~~
显然这是一棵二叉树
前8字节储存数据
中8字节储存左子节点地址
后8字节储存右子节点地址
则%rdi的地址实际上是二叉树的根的地址
## 查看fun7函数汇编
~~~python
=> 0x00005555554015f5 <+0>: test %rdi,%rdi
0x00005555554015f8 <+3>: je 0x55555540162e <fun7+57>
0x00005555554015fa <+5>: sub $0x8,%rsp
0x00005555554015fe <+9>: mov (%rdi),%edx
0x0000555555401600 <+11>: cmp %esi,%edx
0x0000555555401602 <+13>: jg 0x555555401612 <fun7+29>
0x0000555555401604 <+15>: mov $0x0,%eax
0x0000555555401609 <+20>: cmp %esi,%edx
0x000055555540160b <+22>: jne 0x55555540161f <fun7+42>
0x000055555540160d <+24>: add $0x8,%rsp
0x0000555555401611 <+28>: ret
0x0000555555401612 <+29>: mov 0x8(%rdi),%rdi
0x0000555555401616 <+33>: call 0x5555554015f5 <fun7>
0x000055555540161b <+38>: add %eax,%eax
0x000055555540161d <+40>: jmp 0x55555540160d <fun7+24>
0x000055555540161f <+42>: mov 0x10(%rdi),%rdi
0x0000555555401623 <+46>: call 0x5555554015f5 <fun7>
0x0000555555401628 <+51>: lea 0x1(%rax,%rax,1),%eax
0x000055555540162c <+55>: jmp 0x55555540160d <fun7+24>
0x000055555540162e <+57>: mov $0xffffffff,%eax
0x0000555555401633 <+62>: ret
~~~
<+0> <+3>行判断%rdi是否等于0,是的话就跳转至<+57>行,让%eax等于-1并返回,不是则继续
<+5> 行压栈
<+9> 行读取根节点数据,赋给%edx
<+11> <+13>行比较%esi和%edx,%esi即提取的整数,如果%edx大于%esi,则跳转至<+29>行
看看<+29>行结果
<+29> 行即读取左子节点数据并赋给%rdi自身
<+33> 行调用自身`fun7`函数
<+38> 行如果`fun7`函数执行完毕,令%eax*2
随后jmp至<+24>行,弹出栈并返回%eax
如果%edx小于等于%esi
<+15> 行令%eax为0
<+20> 行比较%esi %edx是否相等,相等则让%rsp+8,弹出栈,并返回,不相等则跳转到<+42行>
顺着分支
<+42> 行即读取右子节点数据并赋给%rdi自身
<+46> 行调用自身`fun7`函数
<+51> 行如果`fun7`函数执行完毕,令%eax = 2*%eax + 1
随后jmp至<+24>行,弹出栈并返回%eax
整体运行效果是提取出的整数%esi
大于该节点数据,则向左子节点找
等于就弹出
小于该节点数据,就向右子节点找
并且如果节点数据有0立刻返回-1
## 回看secret_phase汇编
~~~python
0x0000555555401662 <+46>: call 0x5555554015f5 <fun7>
0x0000555555401667 <+51>: cmp $0x2,%eax
0x000055555540166a <+54>: je 0x555555401671 <secret_phase+61>
0x000055555540166c <+56>: call 0x5555554019e6 <explode_bomb>
0x0000555555401671 <+61>: lea 0x13d0(%rip),%rdi # 0x555555402a48
0x0000555555401678 <+68>: call 0x555555400e20 <puts@plt>
0x000055555540167d <+73>: call 0x555555401ba7 <phase_defused>
0x0000555555401682 <+78>: pop %rbx
0x0000555555401683 <+79>: ret
0x0000555555401684 <+80>: call 0x5555554019e6 <explode_bomb>
0x0000555555401689 <+85>: jmp 0x555555401659 <secret_phase+37>
~~~
如果`fun7`最终返回数据为2就收尾并解除炸弹
如果不是就引爆炸弹
## 逆推数据
### 什么样才能返回2
显然,改变%rax只有四种方式
1. 节点储存数据为0,返回-1
2. 节点右子节点等于该输入数据,返回2*%eax+1
3. 节点左子节点等于该输入数据,返回2*%eax
4. 当节点数据小于等于输入数据时,令%eax = 0
故组合一下,有
1. 最后一次搜索: 当节点数据小于等于输入数据时,令%eax = 0,此时恰好相等,返回,完成一次搜索
2. 倒数第二次搜索: 最后一次搜索由右子节点搜索进入,返回的是%eax = 0,随后返回2*%eax+1 = 1
3. 倒数第三次搜索: 倒数第二次搜索由左子节点搜索进入,返回的是%eax = 1,随后返回2*%eax = 2
4. 进入左子节点搜索是因为父节点数据大于用户输入的数据
推测进入方式为 n1->n21->n32
n32数据为0x16,转换成10进制为22
可以推测用户输入字段包括22即可
### 总结
输入22+string即可,如22nn

+ 0
- 35
README.md View File

@ -1,35 +0,0 @@
### All
A CSAPP LAB
### 2023/10/7 Update:
1. Create A Repo
2. Finish bitXor
3. Finish tmin
### 2023/10/8 Update:
1. Finish isTmax
2. Finish allOddBits
3. Finish negate
4. Finish isAsciiDigit
5. Finish isLessOrEqual
6. Finish logicalNeg
7. Update Makefile
### 2023/10/9 Update:
1. Finish howManyBits
### 2023/10/9 Update:
1. Finish floatScale2
2. Finish floatFloat2Int
3. Congratulations!Finish datalab!

BIN
bomb View File


+ 115
- 0
bomb.c View File

@ -0,0 +1,115 @@
/***************************************************************************
* Dr. Evil's Insidious Bomb, Version 1.1
* Copyright 2011, Dr. Evil Incorporated. All rights reserved.
*
* LICENSE:
*
* Dr. Evil Incorporated (the PERPETRATOR) hereby grants you (the
* VICTIM) explicit permission to use this bomb (the BOMB). This is a
* time limited license, which expires on the death of the VICTIM.
* The PERPETRATOR takes no responsibility for damage, frustration,
* insanity, bug-eyes, carpal-tunnel syndrome, loss of sleep, or other
* harm to the VICTIM. Unless the PERPETRATOR wants to take credit,
* that is. The VICTIM may not distribute this bomb source code to
* any enemies of the PERPETRATOR. No VICTIM may debug,
* reverse-engineer, run "strings" on, decompile, decrypt, or use any
* other technique to gain knowledge of and defuse the BOMB. BOMB
* proof clothing may not be worn when handling this program. The
* PERPETRATOR will not apologize for the PERPETRATOR's poor sense of
* humor. This license is null and void where the BOMB is prohibited
* by law.
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "support.h"
#include "phases.h"
/*
* Note to self: Remember to erase this file so my victims will have no
* idea what is going on, and so they will all blow up in a
* spectaculary fiendish explosion. -- Dr. Evil
*/
FILE *infile;
int main(int argc, char *argv[])
{
char *input;
/* Note to self: remember to port this bomb to Windows and put a
* fantastic GUI on it. */
/* When run with no arguments, the bomb reads its input lines
* from standard input. */
if (argc == 1) {
infile = stdin;
}
/* When run with one argument <file>, the bomb reads from <file>
* until EOF, and then switches to standard input. Thus, as you
* defuse each phase, you can add its defusing string to <file> and
* avoid having to retype it. */
else if (argc == 2) {
if (!(infile = fopen(argv[1], "r"))) {
printf("%s: Error: Couldn't open %s\n", argv[0], argv[1]);
exit(8);
}
}
/* You can't call the bomb with more than 1 command line argument. */
else {
printf("Usage: %s [<input_file>]\n", argv[0]);
exit(8);
}
/* Do all sorts of secret stuff that makes the bomb harder to defuse. */
initialize_bomb();
printf("Welcome to my fiendish little bomb. You have 6 phases with\n");
printf("which to blow yourself up. Have a nice day!\n");
/* Hmm... Six phases must be more secure than one phase! */
input = read_line(); /* Get input */
phase_1(input); /* Run the phase */
phase_defused(); /* Drat! They figured it out!
* Let me know how they did it. */
printf("Phase 1 defused. How about the next one?\n");
/* The second phase is harder. No one will ever figure out
* how to defuse this... */
input = read_line();
phase_2(input);
phase_defused();
printf("That's number 2. Keep going!\n");
/* I guess this is too easy so far. Some more complex code will
* confuse people. */
input = read_line();
phase_3(input);
phase_defused();
printf("Halfway there!\n");
/* Oh yeah? Well, how good is your math? Try on this saucy problem! */
input = read_line();
phase_4(input);
phase_defused();
printf("So you got that one. Try this one.\n");
/* Round and 'round in memory we go, where we stop, the bomb blows! */
input = read_line();
phase_5(input);
phase_defused();
printf("Good work! On to the next...\n");
/* This phase will never be used, since no one will get past the
* earlier ones. But just in case, make this one extra hard. */
input = read_line();
phase_6(input);
phase_defused();
/* Wow, they got it! But isn't something... missing? Perhaps
* something they overlooked? Mua ha ha ha ha! */
return 0;
}

+ 7
- 0
password.txt View File

@ -0,0 +1,7 @@
I am not part of the problem. I am a Republican.
0 1 1 2 3 5
5 -354info
352 4 DrEvil
5 115
6 5 4 1 3 2
22nn

Loading…
Cancel
Save