2023 NPU Computer System Basic Experiment

Lab1: Data Lab

Notes that are easily overlooked: the constant range that can be used is 0-255, the compilation standard is c89, the latter can be checked through "./dlc bits.c".

15 pure bit operations, all of which are heavyweight. Some questions may not be written in the optimal way (currently there are 207 operators, It can also be written, right /span>), no analysis yet, for reference only.

Post a picture of AC
/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
  return 1<<31;
}
/* 
 * absVal - absolute value of x
 *   Example: absVal(-1) = 1.
 *   You may assume -TMax <= x <= TMax
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 10
 *   Rating: 4
 */
int absVal(int x) {
  int s = x>>31;
  return (x+s)^s;
}
/* 
 * bitAnd - x&y using only ~ and | 
 *   Example: bitAnd(6, 5) = 4
 *   Legal ops: ~ |
 *   Max ops: 8
 *   Rating: 1
 */
int bitAnd(int x, int y) {
  return ~(~x|~y);
}
/* 
 * replaceByte(x,n,c) - Replace byte n in x with c
 *   Bytes numbered from 0 (LSB) to 3 (MSB)
 *   Examples: replaceByte(0x12345678,1,0xab) = 0x1234ab78
 *   You can assume 0 <= n <= 3 and 0 <= c <= 255
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 10
 *   Rating: 3
 */
int replaceByte(int x, int n, int c) {
  int s = n<<3;
  return (c<<s)|(x&~(0xff<<s));
}
/*
 * mult3div2 - multiplies by 3/2 rounding toward 0,
 *   Should exactly duplicate effect of C expression (x*3/2),
 *   including overflow behavior.
 *   Examples: mult3div2(11) = 16
 *             mult3div2(-9) = -13
 *             mult3div2(1073741824) = -536870912(overflow)
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 2
 */
int mult3div2(int x) {
  x += (x<<1);
  return (x+((x>>31)&1))>>1;
}
/*
 * multFiveEighths - multiplies by 5/8 rounding toward 0.
 *   Should exactly duplicate effect of C expression (x*5/8),
 *   including overflow behavior.
 *   Examples: multFiveEighths(77) = 48
 *             multFiveEighths(-22) = -13
 *             multFiveEighths(1073741824) = 13421728 (overflow)
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 3
 */
int multFiveEighths(int x) {
  x += (x<<2);
  return (x+((x>>31)&7))>>3;
}
/* 
 * addOK - Determine if can compute x+y without overflow
 *   Example: addOK(0x80000000,0x80000000) = 0,
 *            addOK(0x80000000,0x70000000) = 1, 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 3
 */
int addOK(int x, int y) {
  return (((x^y)>>31)|~(((x+y)^x)>>31))&1;
}
/*
 * bitCount - returns count of number of 1's in word
 *   Examples: bitCount(5) = 2, bitCount(7) = 3
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 40
 *   Rating: 4
 */
int bitCount(int x) {
  int m2 = (0x55<<8)|0x55;
  int m4 = (0x33<<8)|0x33;
  int m8 = (0x0f<<8)|0x0f;
  m2 |= (m2<<16);
  m4 |= (m4<<16);
  m8 |= (m8<<16);
  x += ~((x>>1)&m2)+1;
  x = ((x>>2)&m4)+(x&m4);
  x = (x+(x>>4))&m8;
  x += (x>>8);
  x += (x>>16);
  return x&0x3f;
}
/* 
 * isLess - if x < y  then return 1, else return 0 
 *   Example: isLess(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */
int isLess(int x, int y) {
  int ny = ~y;
  return ((((x+ny+1)&(x^ny))|(x&ny))>>0x1f)&1;
}
/* 
 * 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 ny = ~y;
  return ((((((x+ny+1)&(x^ny))|(x&ny))>>0x1f))&1)|!(x^y);
}
/*
 * trueFiveEighths - multiplies by 5/8 rounding toward 0,
 *  avoiding errors due to overflow
 *  Examples: trueFiveEighths(11) = 6
 *            trueFiveEighths(-9) = -5
 *            trueFiveEighths(0x30000000) = 0x1E000000 (no overflow)
 *  Legal ops: ! ~ & ^ | + << >>
 *  Max ops: 25
 *  Rating: 4
 */
int trueFiveEighths(int x) {
  int s = (x>>31)&1;
  int c = (s<<3)+~s+1;
  int h = ((x&(0xFF<<24))+c)>>3;
  int l = (x&~(0xFF<<24));
  return (h<<2)+h+((((l<<2)+l)+c)>>3);
}
/*
 * parityCheck - returns 1 if x contains an odd number of 1's
 *   Examples: parityCheck(5) = 0, parityCheck(7) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 4
 */
int parityCheck(int x) {
  x ^= (x>>16);
  x ^= (x>>8);
  x ^= (x>>4);
  x ^= (x>>2);
  x ^= (x>>1);
  return x&1;
}
/* 
 * rempwr2 - Compute x%(2^n), for 0 <= n <= 30
 *   Negative arguments should yield negative remainders
 *   Examples: rempwr2(15,2) = 3, rempwr2(-35,3) = -3
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 3
 */
int rempwr2(int x, int n) {
  int s = x>>31;
  x = (x+s)^s;
  x &= ((~0)+(1<<n));
  return (x^s)+~s+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) {
  int n = 0;
  x ^= (x<<1);
  n += ((!!(x&((~0)<<(n+16))))<<4);
  n += ((!!(x&((~0)<<(n+8))))<<3);
  n += ((!!(x&((~0)<<(n+4))))<<2);
  n += ((!!(x&((~0)<<(n+2))))<<1);
  n += (!!(x&((~0)<<(n+1))));
  return n+1;
}
/*
 * ilog2 - return floor(log base 2 of x), where x > 0
 *   Example: ilog2(16) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 90
 *   Rating: 4
 */
int ilog2(int x) {
  int n = 0;
  n += ((!!(x&((~0)<<(n+16))))<<4);
  n += ((!!(x&((~0)<<(n+8))))<<3);
  n += ((!!(x&((~0)<<(n+4))))<<2);
  n += ((!!(x&((~0)<<(n+2))))<<1);
  n += (!!(x&((~0)<<(n+1))));
  return n;
}

Lab2: Bomb Lab

It is a very worthwhile assembly exercise. It is still very fulfilling to understand assembly. You can also understand how the compiler translates some structures into assembly language.

Since the questions are different from each other and the answers are different, only the basic ideas are provided. For more details about the IA-32 instruction, please refer to the textbook or official manual, which will not be covered in this article.

Note: Some people may ask questions for 64-bit compilation (the one I got was 32-bit compilation). The main differences are as follows:

  • The pointer size is 64bit (8byte) under 64-bit; and 32bit (4byte) under 32-bit;
  • In 64-bit mode, the stack unit is 8byte, that is, the stack pointer register is added or subtracted by 0x08; while in 32-bit mode, it is 4byte, that is, added or subtracted by 0x04; (it is a tautology with the former, but the former is from the source code perspective)
  • In 64-bit mode, function parameters are passed through registers; in 32-bit mode, function parameters are pushed onto the stack.
set disassbly-flavor att
# gdb 反汇编默认为 Intel 风格, 需改为 AT&T 风格
# AT&T 指令中, 前者为被操作对象, 后者为操作对象
# 如 mov %eax, %edx 是指将 eax 寄存器中值写入到 edx 寄存器中


# gdb常用命令

b <line/func/addr> # 在第 n 行 / func 函数 / addr 地址处打断点

run # 运行, 到断点处停下

continue # 运行到下一个断点

stepi/step # 相当于step into, 对于机器码/源码

nexti/nest # 相当于step over, 对于机器码/源码

x/<n/f/u> <addr/register> # 以 f 格式查看从 addr 开始的 n 个 u 单位内存值 / 寄存器值
# f: x(十六进制形式); d(整数); f(浮点数); c(字符); s(字符串)
# u: b(1 字节); h(2 字节), w(4 字节), g(8 字节)

i r # 查看寄存器值

disas <func> # 查看func对应的汇编指令

 The main test points of the 7 Bomb are as follows:

  • phase_1: string comparison;
  • phase_2: loop and stack;
  • phase_3: conditional branch;
  • phase_4: recursion and stack;
  • phase_5: loop and array;
  • phase_6: loop and linked list;
  • secret_phase: String comparison, recursion and binary search trees.

The general idea is as follows:

  1. Find the input format requirements: function name or formatting character in scanf;
  2. Find the explosion function <explode_bomb> and check the previous judgment condition (cmp or test);
  3. Analyze the function structure part by part and rewrite it into C source code if necessary.

phase_1

Directly view the memory value pushed onto the stack before the <strings_not_equal> function: "x/s <addr>".

phase_2

In the stack structure, the top of the stack is the low address and the bottom of the stack is the high address, that is, -0x04 when pushing into the stack, and +0x04 (32 bits) when popping out of the stack;
test %eax , %eax is used to determine whether the value in the exa register is 0, cmp <val/addr/register> %eax is used to compare the value in the eax register with the former value;
-0xc(%ebp ) is usually used to store the counter of the loop structure;
-0x24(%ebp,%eax,4) means %ebp + 4 * %eax - the memory at 0x24;
Obtain a sequence of 6 numbers by analyzing the loop structure.

jump instruction meaning jump instruction meaning jump instruction meaning
jmp unconditionally is equal etc not equal
and/jnbe unsigned greater than jae/jnb unsigned greater than or equal to jg/jnle signed greater than
jb/jnae unsigned less than jbe/jna Unsigned less than or equal to jl/jnge signed less than
jge/jnl signed greater than or equal to jz is zero jnz Not zero
etc signed less than or equal to js is negative etc not negative
jc carry jnc no carry because overflow
jno No overflow jp/jpe as a couple jnp/jpo Not a couple

 

phase_3

Looking at scanf, the input format is "%d %c %d"; the subsequent series of conditional branches can be restored to if statements. Note that the input order and judgment variables are not the same;
The second input ultimately needs to be converted to ascii characters.

phase_4

View scanf and get the input format as "%d %d"; then enter the function <func4>;
can restore func4 to the source code and get the return value; by This got the answer.

phase_5

It is found that the requirement <string_length> is a certain length;
Let's assume that the input character is "ch[i]" and find that "ch[i] & 0x0f" is taken in the loop structure " (i.e. mod 16) as the array subscript, guess the array size is 16;
View the array "x/16xw <addr>";
Violent loop Get a set of array subscripts that meet the conditions, and look up the ASCII table to convert them into appropriate characters.

phase_6

Found that the function <read_six_numbers> requires the input of 6 numbers;
The first two parts require the input of 6 numbers, each of which is one of 1-6, and let arr[i] = 7 - arr[i];
Find the judgment condition before <explode_bomb>, requiring the former to be greater than the latter;
Find the static area address pushed onto the stack and Check "x/3xw <addr>" and find that it is a linked list node with the structure: "int val; int num; node* next";
Check the next node "x/3xw" in sequence <next>", until next is 0 (that is, the next of the tail node points to NULL);
At the same time, the loop structure requires rearranging the linked list according to the median value of arr[i], and the requirements are obtained comprehensively The linked list is in ascending order;
thus obtains arr[i], arr[i] = 7 - arr[i] is the final input.

secret_phase

Check the <phase_defused> function and find scanf. It is found that the input requirement is "%d %d %s", and the <strings_not_equal> function appears again. At this point, the entry is phase_4 followed by a string;
You can also further verify that it is phase_4 through breakpoint debugging, that is, check the "%d %d" memory value change after running: "x/s <addr>" happens to be the phase_4 answer; a>
The method of obtaining the string is the same as phase_1, and now it enters secret_phase.

View <secret_phase> and find that it enters the function <fun7>;
is also rewritten as source code and is found to be a recursive search function and returns values ​​related to the search process; a>
Find the address of the static area pushed onto the stack and check "x/3xw <addr>". It is found to be a binary tree node with the structure: "int val; node* left; node* right"; < /span> The search process is deduced from the required return value, and the corresponding node value is the answer (remember to convert to decimal). Found The binary tree is a search binary tree with a depth of 4;
Find all nodes "x/3xw <left>" and "x/3xw <right>" in turn, and draw a binary tree;

Guess you like

Origin blog.csdn.net/annesede/article/details/134658321