第三章
3.58
#include <stdio.h>
long decode2(long x,long y,long z){
long ans=y-z;
return (ans*x)^(ans<<63>>63);
}
int main(){
printf("%d\n",decode2(100,2,2));
}
3.59
原理:
可以看出2128位溢出,因此只需计算后两项即可
即:
store_prod:
movq %rdx, %rax //将y保存在%rax中
cqto //对y进行符号位扩展,rdx=(-1)y_63
movq %rsi, %rcx //将x保存在%rcx中
sarq $63, %rcx //将x算数右移63位,得到x符号位,%rcx=(-1)x_63
imulq %rax, %rcx //用y乘x的符号位,得x63y
imulq %rsi, %rdx //用x乘y的符号位,得y63x
addq %rdx, %rcx //将x63y+y63x保存在%rcx中
mulq %rsi //无符号数乘法uxuy,此时%rdx保存结果的高64位,%rax保存结果的低64位
addq %rcx, %rdx //将x63y+y63x加到uxuy的高64位上
movq %rax, (%rdi) //保存结果的低64位
movq %rdx, 8(%rdi) //保存结果的高64位
ret
3.60
A.x:%rdi, n:%esi, result:%rax, mask:%rdx
B.result=0; mask=1;
C.mask!=0;
D.mask=mask<<n;
E.result|=(x&mask);
F.//补全代码
#include <stdio.h>
long loop(long x,int n){
long result=0;
long mask;
for(mask=1;mask!=0;mask=mask<<n;){
result|=(x&mask);
}
return result;
}
3.61
#include <stdio.h>
long cread_alt(long *xp) {
return (!xp ? 0 : *xp);
}
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:
*p1=*p1+*p2;
result=*p1;
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;
break;
}
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;
case 65:
result=x*x;
default:
result=x+0x4B;
}
return result;
}
3.64
store_ele:
leaq (%rsi, %rsi, 2), %rax // t1 = j*3
leaq (%rsi, %rax, 4), %rax // t1 = j*13
movq %rdi, %rsi // t2 = i
salq $6, %rsi // t2 = i*64
addq %rsi, %rdi // t3 = i*65
addq %rax, %rdi // t3 = i*65 + j*13
addq %rdi, %rdx // t4 = i*65 + j*13 + k
movq A(,%rdx,8), %rax // t1 = *(A + 8*t4)
movq %rax, (%rcx) // *dest = t1
movl $3640, %eax // return 3640
ret
A. &A[i][j][k] = A+ L (S* T * i + T * j + k)
B. 由题目中可知
S * T = 65 ;
T = 13 ;
8 * S * T * R = 3640
解得R = 7 ; S = 5 ; T = 13
3.65
A. %rdx(由第六行可知,每次j加一个字节,因此%rdx为A[i][j]
B. %rax
C.M=120/8=15
3.66
sum_col:
leaq 1(,%rdi,4), %r8 // t1 = n*4 + 1
leaq (%rdi,%rdi,2), %rax // t2 = n*3
movq %rax, %rdi // t3 = n*3
testq %rax, %rax // test n*3
jle .L4 // n*3 <= 0, jump .L4
salq $3, %r8 // t1 = t1*8 = 8*(n*4 + 1)
leaq (%rsi,%rdx,8), %rcx // t4 = j*8 + A
movl $0, %eax // t2 = 0
movl $0, %edx // t5 = 0
.L3:
addq (%rcx), %rax // t2 = *(t4) = *(A + j*8)
addq $1, %rdx // t5 = t5+1
addq %r8, %rcx // t4 = t1+t4 = A + j*8 + 8*(n*4 + 1)
cmpq %rdi, %rdx // cmp t5 & t3
jne .L3 // if t5 != n*3, loop
rep
ret
.L4:
movl $0, %eax // return 0
ret
NR(n) == n3; NC(n) == n4 + 1
由第十六行jne跳转指令可知,
只有当%rdx等于3时才跳出循坏,因此,NR(n) == n*3;
由第十四行addq指令可知,%r8每次加8*(4n+1),所以每行由4n+1个数,因此,NC(n) == n*4 + 1。
3.67
A.
相对于%rsp的偏移量 | 储存再栈上的值 |
---|---|
%rsp+64 | 返回地址 |
– | – |
%rsp+24 | z |
%rsp+16 | s.p=&z |
%rsp+8 | y |
%rsp | x |
B.传递的一个新的地址值%rsp+64给process。
C.通过%rsp+偏移量访问。
D.process从%rsp+64开始存储地址,最终回到这个地址,通过&rdi+偏移量来寻址各个元素。
E.调用函数后,%rsp会减8存储返回地址,即此处%rsp+24=调用前%rsp+16
相对于%rsp的偏移量 | 储存再栈上的值 |
---|---|
%rsp+80 | z |
%rsp+72 | x |
%rsp+64 | y |
– | – |
%rsp+24 | z |
%rsp+16 | s.p=&z |
%rsp+8 | y |
%rsp | x |
F.像结构体这种无法用一个寄存器存储的参数都是用内存传参,传入时,通过%rsp+偏移量将元素存储在栈上,返回时,通过%rdi+偏移量寻址,将元素返回。
3.68
依据汇编代码及数据对齐规则:
q->t = 8(%rsi),即str2的t从第8位开始,按照8位对齐sizeof(array[B])小于等于8,且下边的t是int类型占4个字节,所以sizeof(array[B])大于4,可以得到4<B<=8。
q->u = 32(%rsi),即str2的u从第32位开始,则s占20个字节,得sizeof(s[A])<=20,且下边的u是long类型占8个字节,所以sizeof(s[A])大于20-8=12,可以得到6<A<=10。
p->y = 184(%rdi),即str1的y从第184位开始,所以184-8<AB4<=184,可以得到44<A*B<=46。
由以上三个约束条件,解得A = 9 B = 5。
3.69
A.
由代码第一二行可知,first+a一共占了0x120个字节;0X120的十进制表示为288
由第三四五行可知,&bp->a[i]的地址计算公式为40i+&bp+8;
故int对齐之后占8个字节(而不是int类型4字节),a[i]大小为40;
即CNT=(288-8)/40=7;
B.
typedef struct{
long idx;
long x[4];
}
由代码第七八行可知ap->x[ap->idx]的地址计算公式为&bp+16+idx*8;
+16说明first和idx共占16个字节,idx是a[i]第一个元素,占8个字节;
movslq将int转成long,说明x是long类型;
则数组x的个数为(40-8)/8=4
3.70
A.
e1.p: 0
e1.y: 8
e2.x: 0
e2.next: 8
B. 16
C. up->e2.x = *(up->e2.next->e1.p) - up->e2.next->e1.y
mov 8(%rdi), %rax // rax = up->e2.next
mov (%rax), %rdx // rdx = up->e2.next->e1.p
mov (%rdx), %rdx // rdx = *(up->e2.next->e1.p)
subq 8(%rax), %rdx // rdx -= up->e2.next->e1.y
mov %rdx, (%rdi)
// up->e2.x = *(up->e2.next->e1.p) - up->e2.next->e1.y
代码第二行,偏置为8,且数据为指针,所以只能是up->e2.next
第三行偏置为0,且也为指针,所以为up->e2.next->e1.p
第四行,没有偏置,仍然为指针,为 (up->e2.next->e1.p)
于是,减数为(up->e2.next->e1.p)
第五行,%rax中保存up->e2.next,故8(%rax)为up->e2.next->e1.y
于是,被减数为up->e2.next->e1.y
第六行,结果赋值给e2.x
得等式左侧为up->e2.x
3.71
fgets函数用来从文件中读入字符串。
fgets函数的调用形式如下:fgets(str,n,fp);
此处,fp是文件指针;str是存放在字符串的起始地址;n是一个int类型变量。
#include <stdio.h>
void good_echo(void){
const int SIZE = 100;
char buf[SIZE];
while(1){
char* p=fgets(buf,SIZE,stdin);
if(p==NULL){
break;
}
printf("%s",p);
}
return;
}
int main(){
good_echo();
return 0;
}
3.72
A.s2=s1−[(n∗8+30)&0xFFFFFF0],舍入到最近的16的倍数
若为奇数,则s2=s1−(n∗8+24)
若为偶数,则s2=s1−(n∗8+16)
B.p=(s2+15)&0XFFFFFFF0
确保了p数组的起始地址为16的整数倍
C.
最大 | 最小 |
---|---|
e1=1(此时e2最大等于15) | e1=24(此时e2最小等于0) |
n为偶数 | n为奇数 |
n%16=1 | n%16=0 |
D.
s2保证了能容纳下8*n字节的最小的16的倍数
p保证了自身对齐16
3.73
#include <stdio.h>
#include <assert.h>
typedef enum {NEG, ZERO, POS, OTHER} range_t;
range_t find_range(float x) {
__asm__(
"vxorps %xmm1, %xmm1, %xmm1\n\t"
"vucomiss %xmm1, %xmm0\n\t"
"jp .P\n\t"
"ja .A\n\t"
"jb .B\n\t"
"je .E\n\t"
".A:\n\t"
"movl $2, %eax\n\t"
"jmp .Done\n\t"
".B:\n\t"
"movl $0, %eax\n\t"
"jmp .Done\n\t"
".E:\n\t"
"movl $1, %eax\n\t"
"jmp .Done\n\t"
".P:\n\t"
"movl $3, %eax\n\t"
".Done:\n\t"
);
}
int main(int argc, char* argv[]) {
range_t n = NEG, z = ZERO, p = POS, o = OTHER;
assert(o == find_range(0.0/0.0));
assert(n == find_range(-2.3));
assert(z == find_range(0.0));
assert(p == find_range(3.33));
return 0;
}
3.74
#include <stdio.h>
#include <assert.h>
typedef enum {NEG, ZERO, POS, OTHER} range_t;
range_t find_range(float x) {
__asm__(
"vxorps %xmm1, %xmm1, %xmm1\n\t"
"movq $1, %rax\n\t"
"movq $2, %r8\n\t"
"movq $0, %r9\n\t"
"movq $3, %r10\n\t"
"vucomiss %xmm1, %xmm0\n\t"
"cmovaq %r8, %rax\n\t"
"cmovbq %r9, %rax\n\t"
"cmovpq %r10, %rax\n\t"
);
}
int main(int argc, char* argv[]) {
range_t n = NEG, z = ZERO, p = POS, o = OTHER;
assert(o == find_range(0.0/0.0));
assert(n == find_range(-2.3));
assert(z == find_range(0.0));
assert(p == find_range(3.33));
return 0;
}
3.75
A
n | 实部 | 虚部 |
---|---|---|
1 | %xmm0 | %xmm1 |
2 | %xmm2 | %xmm3 |
3 | %xmm4 | %xmm5 |
n | … | … |
B
%xmm0是实部,%xmm1是虚部