CS:APP 第3章 程序的机器级表示 作业

3.58

long decode(long x, long y, long z) 
{
    y -= z;
    x *= y;
    return (y << 63 >> 63) ^ x;
}

3.59

ux=x+x_{63}*2^{64},uy=y+y_{63}*2^{64}
ux*uy=x*y+(x*y_{63}+y*x_{63})*2^{64}+x_{63}*y_{63}*2^{128}
2^{128}溢出了可以不管
x*y=ux*uy-(x*y_{63}+y*x_{63})*2^{64}

3.60

A

x : %rdi
n : %esi
result : %rax
mask : %rdx

B

result = 0
mask = 1

C

mask != 0

D

mask <<= n

E

result |= x & mask;

F
long loop(long x, long n)
{
    long result = 0;
    long mask;
    for (mask = 1; mask; mask <<= n)
    {
        result |= x & mask;
    }
    return result;
}

3.61

看到别人的答案有这样写的:

long cread_alt(long *xp)
{
    return (!xp) ? 0 : *xp;
}

本来我认为也是对的,因为从汇编层面上看,先计算第一条,结果是0,再用条件传送指令判断指针是否为空,从而传送0或者是指向的内容,避免了空指针引用。
然而查询资料得到,条件传送命令不管测试结果为如何,总会两条路径都计算出来,而不是测试结果失败了就不算第二条路径,因此这个代码是有问题的。

答案如下:

long cread_alt(long *xp)
{
    long tem = 0;
    xp = xp ? xp : &tem;
    return *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:
        result = *p1;
        result += *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 = x << 3;
        break;
    case 63:
        result = x >> 3;
        break;
    case 64:
        x *= 15;
    case 65:
        x *= x;
    default:
        result = x + 75;
    }
    return result;
}

3.64

A

假设有数组Type A[R][S][T],那么A[i][j][k]的地址为:
\&A[i][j][k]=x_A+(i*S*T+j*T+k)*sizeof(Type)

B

根据汇编推得:
R*S*T*8=3640
S*T=65
T=13
解得
R=7
S=5
T=13

3.65

A

%rdx

B

%rax

C

M=15

3.66

NR=3*n
NC=4*n+1

3.67

这里画出的栈帧越上面地址越大,和书上保持一致。

A
栈帧 地址 说明
... %rsp+96 栈底
... ... 未被使用
... %rsp+64,%rdi
... ... 未被使用
z %rsp+24
&z %rsp+16
y %rsp+8
x %rsp 栈顶
B

传递了%rdi

C

通过%rsp加上位移量访问
这里有个小细节困惑了我一会,就是调用process%rsp所指向的位置偏移了8个字节,一开始没想明白,后来想到call指令会压入返回地址,所以导致%rsp自动加8

D

通过传递的%rdi加上位移量设置

E
栈帧 地址 说明
... %rsp+96 栈底
... ... 未被使用
r.q %rsp+80,%rdi+16
r.u[1] %rsp+72,%rdi+8
r.u[0] %rsp+64,%rdi
... ... 未被使用
z %rsp+24
&z %rsp+16
y %rsp+8
x %rsp 栈顶

返回后同样依靠%rsp加偏移量访问r的元素。

F

这里的%rdi可以看成一个指针,在传参前预先留好一定的空间给返回值,传入结构体时什么都不用做,子函数通过%rsp访问传入的结构体,通过%rdi指针设置返回的结构体。

3.68

A \in [5,8] , B \in [7,10],A*B \in [44,45]
解得:
A=9,B=5

3.69

这里我犯了个错误,导致思考了比较久。我误认为结构体的对齐是整个大小,其实应该是其中数据大小最大的一个。导致这个偏移量288怎么凑都凑不出来。正确的想法是结构体数组大小为40*7,多出来的8int对结构体对齐的结果。

A

CNT=7

B
typedef struct{
    long idx;
    long x[4];
};

这里的idx不一定为long,实际上intshort,甚至char应该都是可以的,原因是对齐。

3.70

A
字段 偏移量
e1.p 0
e1.y 8
e2.x 0
e2.next 8
B

16

C
union ele
{
    struct{
        long *p;
        long y;
    } e1;
    struct{
        long x;
        union ele *next;
    } e2;
};

void proc(union ele *up)
{
    up->e2.x = *(up->e2.next->e1.p) - up->e2.next->e1.y;
}

3.71

#include <stdio.h>

const int MAX_LENGTH = 16;

void good_echo()
{
    char buffer[MAX_LENGTH];
    while (fgets(buffer, MAX_LENGTH, stdin))
    {
        printf("%s", buffer);
    }
}

int main()
{
    good_echo();
}

3.72

A

不明白啥叫数学语言解释。
s_1=\%rbp-16
s_2=s_1- \lfloor(8*n+30)/16\rfloor*16
用公式写了一下,感觉不太直观,其实分为两部分

  • \%rbp减去16得到s_1,这是给i分配的空间
  • 减去\lfloor(8*n+30)/16\rfloor*16,这一部分是给数组分配空间,因为要对16字节对齐写成这样,在原汇编中体现为:
leaq    30(,%rdi,8), %rax
andq    $-16, %rax
B

p=\lfloor s_2+15\rfloor/16*16
目的是数组首地址对齐16字节。

C
最小 最大
e1 16 40
n 偶数 奇数
s1 16的倍数 16的倍数+1
D

s_2-s_116字节对齐。
p16字节对齐。

3.73

不太想啃那个英文的说明了,网上搜了搜怎么内嵌汇编就直接写了。
代码附带验证。

#include <iostream>
typedef enum
{
    NEG,
    ZERO,
    POS,
    OTHER
} range_t;

range_t find_range(float x)
{
    __asm__(
        "vxorps     %xmm1, %xmm1, %xmm1\n\t"
        "vucomiss   %xmm0, %xmm1\n\t"
        "jp         .OTHER\n\t"
        "je         .ZERO\n\t"
        "ja         .NEG\n\t"
        "movl       $2, %eax\n\t"
        "jmp        .END\n\t"
        ".OTHER:\n\t"
        "movl       $3, %eax\n\t"
        "jmp        .END\n\t"
        ".ZERO:\n\t"
        "movl       $1, %eax\n\t"
        "jmp        .END\n\t"
        ".NEG:\n\t"
        "movl       $0, %eax\n\t"
        ".END:\n\t"
        "rep;ret\n\t");
}

range_t find_range2(float x)
{
    range_t result;
    if (x < 0)
        result = NEG;
    else if (x == 0)
        result = ZERO;
    else if (x > 0)
        result = POS;
    else
        result = OTHER;
    return result;
}

float u2f(unsigned x)
{
    return *(float *)&x;
}

int main()
{
    for (unsigned x = 0; x != 0; x++)
    {
        if (find_range2(x) != find_range(x))
            std::cout << "NO\n";
    }
    std::cout << "YES\n";
}

3.74

心态崩了,第一次知道还有cmovaq这种东西,书上好像没写过啊?浪费了超多时间。。。

#include <iostream>
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");
}

range_t find_range2(float x)
{
    range_t result;
    if (x < 0)
        result = NEG;
    else if (x == 0)
        result = ZERO;
    else if (x > 0)
        result = POS;
    else
        result = OTHER;
    return result;
}

float u2f(unsigned x)
{
    return *(float *)&x;
}

int main()
{
    for (unsigned x = 0; x != 0; x++)
    {
        if (find_range2(x) != find_range(x))
            std::cout << "NO\n";
    }
    std::cout << "YES\n";
}

3.75

A

使用寄存器对,第一个参数为%xmm0:%xmm1,第二个为%xmm2:%xmm3

A

寄存器对%xmm0:%xmm1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容