开工日期:2018年5月10号 完成日期:2018年5月18日 耗时:8日
配置:centOS 7 64位+gcc4.8.5
推荐大家一个网站compiler explore。很方便
3.58
long decode2(long x,long y,long z)
{
//x in %rdi,y in %rsi,z in %rdx
y = y-z;
x = x*y;
long a = y;
a<<=63;
a>>=63;
a = a^x;
return a;
}
dest in rdi,x in rsi,y in rdx
store_prod:
movq %rdx,%rax
cqto //把y的符号位放在rdx
movq %rsi,%rcx
sarq $63,%rcx //把x的符号位放在rcx
imulq %rax,%rcx
imulq %rsi,%rdx
addq %rdx,%rcx
mulq %rsi
addq %rcx,%rdx
movq %rax,(%rdi)
movq %rdx,8(%rdi)
ret
第一个乘法: x符号*y
第二个乘法 : y符号*x
第三个乘法 : x和y的无符号相乘。
由上图可知,x和y的无符号相乘,x和y的有符号相乘相差的是 : 2^64*(x符号*y + y符号*x)
所以第10行把这个加到了rdx。
3.60
A:
值 | 寄存器 |
---|---|
x | %rdi |
n | %esi |
result | rax |
mask | rdx |
B
result | 0 |
---|---|
mask | 1 |
C
mask!=0
D
mask = mask<
F:
long loop(long x,int n)
{
long result = 0;
long mask;
for(mask=1;mask!=0;mask=mask<return result;
}
3.61
从cread()的矛盾里,要使用条件传送指令,就必须算出2种可能性,但是*xp可能是空指针,会产生间接使用空指针的错误。这里,我加一层指针. (大家可以看看linux之父的这个演讲。他在这个演讲里讲了二重指针。很有意思)linux
long cread_alt(long *xp){
int **p=&xp;
int zero=0;
return *(*p?*p:&zero);
}
得到的汇编代码是(要好-O1优化)
cread_alt:
movl $0, -4(%rsp)
leaq -4(%rsp), %rax
testq %rdi, %rdi
cmove %rax, %rdi
movslq (%rdi), %rax
ret
3.62
typedef enum{MODE_A,MODE_B,MODE_C,MODE_D,MODE_E}mode_t;
long switch3(long *p1,long *p2,mode_t action)
{
long result=0;
switch(action){
case MODE_A:
result = *p2;
*p2 = *p1;
break;
case MODE_B:
result = *p1 + *p2;
*p1 = result;
break;
case MODE_C:
*p1=59;
result = *p2;
break
case MODE_D:
*p1 = *p2;
result = 27;
break;
case MODE_E:
result = 27;
break;
default:
result = 12;
}
return result;
}
3.63
long switch_prob(long x,long n)
{
long result = x;
switch(n){
case 60:
case 62:
result = 8*x;
break;
case 63:
result = x>>3;
break;
case 64:
result = (x<<4)-x ; //result = x*15;
x = result;
case 65:
x*=x;
default:
result = x+0x4b;
}
return result;
}
3.64
A:
&A[ i ] [ j ] [ k ] = Xd+L(T*S*i+T*J+k)
B:
从汇编代码可得,①65*i+13*j+k ②R*T*S *8 = 3640
R | 7 |
---|---|
S | 5 |
T | 13 |
3.65
A
&A[i][j] 在%rdx
B
&A[j][i]在%rax
C
M=15
3.66
#define NC(n) 4*n+1
#define NR(n) 3*n
3.67
A
-------------------------------------------
rsp x
+8 | y |
+16 | &z |
+24 | z |
| |
| |
| |
| |
| |
........
+64 | | <-rdi
| |
| |
| |
| |
B
%rdi
C
s.p | 24(%rsp) |
---|---|
s.a[0] | 16(%rsp) |
s.a[1] | 8(%rsp) |
这里大家可能有疑问,访问结构参数s的元素,为什么和栈上的不同。原因是call 调用函数时,会使rsp+8
D
放在了%rsp(旧)+64
E
-------------------------------------------
rsp x
+8 | y |
+16 | &z |
+24 | z |
| |
| |
| |
| |
| |
........
+64 | y | <-rdi
| x |
| z |
| |
| |
F
参数:放在栈上。
返回值:放在栈上.
3.68
为什么这题值3个星呢,难就难在了对齐上。
从会汇编上看,可以得到一些偏移地址。
typedef struct{
int x[A][B];
long y; //偏移地址是184
}str1;
typedef struct{
char array[B];
int t; //偏移地址是8
short s[A];
long u; //偏移地址是32
}str2;
分析:
在str2里,int t的偏移地址是8,证明char array[B]占5~8个字节,也就是说,5≤B≤8
long u的偏移地址是32,证明short s[A]占16~20字节,也就是说,8≤A≤10
在str1里,Long y 的偏移地址是184,证明int x[A][B]占180~184个字节,也就是说,45≤AB≤46.
综上
A | 9 |
---|---|
B | 5 |
3.69
被这题坑了,这题用的数都是十六进制。
mov 0x120(%rsi),%ecx ;把bp->last放在ecx,得到last的偏移量是288
add (%rsi),%ecx ;bp->last+bp->first
lea (%rdi,%rdi,4),%rax ; 5i放在%rax
lea (%rsi,%rax,8),%rax ; (5i*8+bp)
mov 0x8(%rax),%rdx ; (5i*8+bp)+8
movslq %ecx,%rcx
mov %rcx,0x10(%rax,%rdx,8) ;16+%rax是&ap->x,%rdx*8是ap->idx
}
A:
第4行,40i+bp+8。我们可以推测sizeof(a_struct)=40,在b_struct的对齐是8.再加上前面last的偏移量是288,CNT = (288-8)/sizeof(a_struct) = 7;
B:
第6行,movslq %ecx,%rcx 证明ap->x[ ]的类型是long
16+%rax是代表&ap->x 。可以得到idx比x前,且是long类型。
typedef struct{
long idx;
long x[4];
}a_struct;
3.70
A
e1.p | 0 |
---|---|
e1.y | 8 |
e2.x | 0 |
e2.next | 8 |
B
16 bytes
C
void proc(union ele *up){
up->e2.x =*(up->e2.next->e1.p) - (up->e2.next->e1.y);
}
分析:
1 proc:
2 movq 8(%rdi), %rax ;(这里%rax已经是up->e2.next)
3 movq (%rax), %rdx ;访问up->e2.next->e1.p
4 movq (%rdx), %rdx ;访问*(up->e2.next->e1.p)
5 subq 8(%rax), %rdx ;8(%rax)是up->e2.next->e1.y.
6 movq %rdx, (%rdi) ;(%rdi)是ele.e2.x
7 ret
3.71
void good_echo(){、
const int BufSize = 32;
char buf[BufSize];
if(fgets(buf,BufSize-1,stdin) || ferror(stdin))
return;
puts(buf);
}
3.72
A
如果n是奇数
8n+24
如果n是偶数
8n+16
B
(%rsp+15) &(-16)的结果:
%rsp后四位 | __ |
---|---|
0000 | %rsp |
0001 | %rsp+15 |
0010 | %rsp+14 |
0011 | %rsp+13 |
0100 | %rsp+12 |
0101 | %rsp+11 |
0110 | %rsp+10 |
0111 | %rsp+9 |
1000 | %rsp+8 |
1001 | %rsp+7 |
1010 | %rsp+6 |
1011 | %rsp+5 |
1100 | %rsp+4 |
1101 | %rsp+3 |
1110 | %rsp+2 |
1111 | %rsp+1 |
C
– | n | s1 |
---|---|---|
min | 偶 | 0001结尾 |
max | 奇 | 0000结尾 |
D
从B的表格可以看出,P地址的后4位都是0000,也就是保证了16字节对齐
3.73
—— | CF | ZF | PF |
---|---|---|---|
x>0 | 0 | 0 | 0 |
x=0 | 0 | 1 | 0 |
x<0 | 1 | 0 | 0 |
NaN | 1 | 1 | 1 |
find_range:
vxorps %xmm1, %xmm1, %xmm1
vucomiss %xmm1,%xmm0
je .L1
jne .L2
.L1:
jb .NaN
jae .L3
.L2:
jb .L4
jae .L5
.NaN:
movl $2,%eax
ret
.L3:
movl $0,%eax
ret
.L4:
movl $-1,%eax
ret
.L5:
movl $1,%eax
ret
3.74
warning未经测试
在不久后测试
靠书上的条件传送指令根本做不出这道题()
—— | CF | ZF | PF |
---|---|---|---|
x>0 | 0 | 0 | 0 |
x=0 | 0 | 1 | 0 |
x<0 | 1 | 0 | 0 |
NaN | 1 | 1 | 1 |
答案可以参考这个
3.75
A
实部 | 虚部 |
---|---|
%xmm0 | %xmm1 |
%xmm2 | %xmm3 |
… | … |
B
实部放在%xmm0,虚部放在%xmm1